Skip to content

feat: userAuth key reset SDK support and per-recipient reshare results - #10108

Draft
davidkaplanbitgo wants to merge 2 commits into
masterfrom
davidkaplan/wcn-3893-userauth-reset-sdk
Draft

davidkaplanbitgo wants to merge 2 commits into
masterfrom
davidkaplan/wcn-3893-userauth-reset-sdk

Conversation

@davidkaplanbitgo

Copy link
Copy Markdown
Contributor

Summary

SDK support for a customer-initiated userAuth key reset on custody lightning wallets (a customer who forgot their wallet password replaces the key that password encrypts, with BitGo support approving the request).

WCN-3893 - abstract-lightning

  • computeUserAuthResetVerificationCode(walletId, newUserAuthKeyPub) and compareUserAuthResetVerificationCodes: SHA-256 of lightning-userauth-reset:v1:<walletId>:<pub>, RFC 4648 base32, first 10 chars, displayed as XXXXX-XXXXX. Compare ignores case, dashes and spaces.
  • Codecs: UserAuthKeyResetSignedRequest (exact: rejects extra and missing fields), UserAuthKeyResetStatus (requested | canceled | expired | pending | dnr_held | wp_swapped | completed | failed), request/response codecs. The GET response carries completedAt and releasedAt (nullable); "released" is releasedAt !== null, not a status.
  • CustodialLightningWallet.requestUserAuthKeyReset({ passphrase, encryptionVersion }), getUserAuthKeyResetRequest(), cancelUserAuthKeyResetRequest(requestId). The new key is generated and encrypted locally and registered with the same shape wallet creation uses (purpose: 'userAuth', no passcode encryption code). The proof is signed with the new key. The private key and passphrase are never sent, and the returned verification code is computed locally, never taken from the server.
  • createMessageSignature / verifyMessageSignature now parse xpub/xprv keys with bitcoin version bytes even when a testnet network is passed. tlnbtc keys are generated with the default network, so signing with getUtxolibNetwork('tlnbtc') threw before. Existing callers pass no network and are unaffected; tpub/tprv keys still use the given network. Signatures are identical on both networks (same message prefix).

WCN-3894 - sdk-core

  • Wallets.reshareWalletWithSpenders(walletId, userPassword, encryptionVersion?, opts?) with opts: { includeAdmins?, onlyNeedsRecovery? }, returning { shared: string[], failed: { userId, error }[] }.
  • A failure for one recipient (for example an existing active or pending share) no longer aborts the rest; it is returned in failed. Selected spenders who are not enterprise users are also returned in failed instead of being skipped silently. Setup and key-decryption errors still reject.
  • Without options the recipients are unchanged. bulkUpdateWalletShare keeps logging recipient failures; acceptShare still ignores the result as before.
  • The method is now declared on IWallets. needsRecovery is typed inline on WalletData.users until @bitgo/public-types carries it.

Notes for review

  • The route these methods call (POST/GET/DELETE /api/v2/:coin/wallet/:walletId/lightning/userAuthKey/resetRequest) is being built in wallet-platform; response shapes are defined here and must match its spec.
  • Both changes ship in the same beta so lightning-services, wallet-platform, bitgo-admin and retail can bump once.
  • No CHANGELOG edit: it is generated from the commit messages.

Testing

  • modules/abstract-lightning: 77 passing (mocha --recursive test), including verification-code vectors checked independently against Python's base64.b32encode(sha256(...)), codec exactness, nock tests for lnbtc and tlnbtc asserting the proof verifies, the private key and passphrase are absent from every request body, and the server's verificationCode is ignored. Four of these fail without the signature.ts change.
  • modules/bitgo wallets.ts: the reshareWalletWithSpenders and bulkUpdateWalletShare tests pass (33), including new cases for includeAdmins, onlyNeedsRecovery, defaults, per-recipient failures and non-enterprise users.
  • eslint --quiet and prettier --check pass on the changed files.
  • In my local environment 18 tests in modules/bitgo/test/v2/unit/wallets.ts fail with and without these changes (nock mismatches, shielded wallets, v2-encrypted shares, keycard). Two of them, in the accept-share reshare cases, assert the old abort-on-first-failure behaviour; I updated that expectation to the new behaviour but could not run it locally, so please check it in CI.

@linear-code

linear-code Bot commented Oct 31, 2026

Copy link
Copy Markdown
Contributor

WCN-3893

@github-actions

github-actions Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

⚠️ Compatibility checks are failing on Node.js 27-nightly (experimental, non-blocking). This does not block merge, but it signals an incompatibility to fix before this release becomes supported.

View run

Add the SDK pieces for a customer-initiated userAuth key reset on custody
lightning wallets:

- computeUserAuthResetVerificationCode and a compare helper, computed
  locally and never taken from a server response
- UserAuthKeyResetSignedRequest codec (rejects extra and missing fields)
  and typed request, status and response codecs
- CustodialLightningWallet.requestUserAuthKeyReset, getUserAuthKeyResetRequest
  and cancelUserAuthKeyResetRequest; the new private key and passphrase are
  never sent
- createMessageSignature and verifyMessageSignature parse xpub/xprv keys with
  bitcoin version bytes on testnet, since tlnbtc keys are generated that way

TICKET: WCN-3893
reshareWalletWithSpenders takes an optional fourth argument and now returns
the outcome per recipient:

- includeAdmins also reshares to admins who can spend
- onlyNeedsRecovery only reshares to users flagged needsRecovery, which is
  how other spenders regain access after a lightning userAuth key reset
- a failure for one recipient (for example an existing active or pending
  share) no longer aborts the rest; it is returned in `failed`
- spenders who are not enterprise users are returned in `failed` instead of
  being skipped silently
- returns { shared, failed } instead of void; setup and key decryption
  errors still reject

Without options the recipients are unchanged. bulkUpdateWalletShare keeps
logging recipient failures. The method is now declared on IWallets.

TICKET: WCN-3894
@davidkaplanbitgo
davidkaplanbitgo force-pushed the davidkaplan/wcn-3893-userauth-reset-sdk branch from ac75cf1 to a098c59 Compare October 31, 2026 12:16

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant