@@ -1146,9 +1146,13 @@ export class WalletService implements IWalletService {
11461146 if ( err ) return cb ( err ) ;
11471147 if ( ! wallet ) return cb ( Errors . NOT_AUTHORIZED ) ;
11481148
1149- const xPubKey = wallet . copayers . find ( c => c . id === opts . copayerId ) . xPubKey ;
1149+ const target = wallet . copayers . find ( c => c . id === opts . copayerId ) ;
1150+ if ( ! target ?. xPubKey ) return cb ( Errors . NOT_AUTHORIZED ) ;
11501151
1151- if ( ! this . _verifyRequestPubKey ( opts . requestPubKey , opts . signature , xPubKey ) ) {
1152+ try {
1153+ const isValid = this . _verifyRequestPubKey ( opts . requestPubKey , opts . signature , target . xPubKey ) ;
1154+ if ( ! isValid ) return cb ( Errors . NOT_AUTHORIZED ) ;
1155+ } catch ( e ) {
11521156 return cb ( Errors . NOT_AUTHORIZED ) ;
11531157 }
11541158
@@ -1209,7 +1213,17 @@ export class WalletService implements IWalletService {
12091213 * @param {boolean } [opts.dryRun] Simulate the action but do not change server state.
12101214 */
12111215 joinWallet ( opts , cb ) {
1212- if ( ! checkRequired ( opts , [ 'walletId' , 'name' , 'requestPubKey' , 'copayerSignature' ] , cb ) ) return ;
1216+ // xPubKey is the canonical copayer identity in the current protocol. Alternate public-key
1217+ // fields are ancillary metadata; supporting an xPubKey-less copayer requires a versioned
1218+ // end-to-end identity protocol rather than a local identity fallback.
1219+ // SECURITY: xPubKey is required for every join, including hardwareSourcePublicKey/
1220+ // clientDerivedPublicKey ones. Copayer.xPubToCopayerId() (called below both for the TSS
1221+ // participant check and inside Copayer.create()) now throws on a missing xpub for every
1222+ // coin (see its own guard), so an xPubKey-less join can no longer derive a copayer id at
1223+ // all. bitcore-wallet-client's only join path (_doJoinWallet) always sends a real
1224+ // xPubKey regardless of these two fields, so this doesn't restrict any flow this repo's
1225+ // own client exercises - see the TSS-participant comment below for how that was confirmed.
1226+ if ( ! checkRequired ( opts , [ 'walletId' , 'name' , 'requestPubKey' , 'copayerSignature' , 'xPubKey' ] , cb ) ) return ;
12131227 if ( ! opts . name ) return cb ( new ClientError ( 'Invalid copayer name' ) ) ;
12141228
12151229 opts . coin = opts . coin || Defaults . COIN ;
@@ -1218,17 +1232,17 @@ export class WalletService implements IWalletService {
12181232 }
12191233 if ( ! Utils . checkValueInCollection ( opts . chain , Constants . CHAINS ) ) return cb ( new ClientError ( 'Invalid coin' ) ) ;
12201234
1235+ // xPubKey is parsed and validated for every join; ancillary fields never suppress it.
1236+ // A future update will re-add conditional logic which allows opts.hardwareSourcePublicKey
1237+ // or opts.clientDerivedPublicKey to circumvent this requirement
12211238 let xPubKey ;
1222- if ( ! opts . hardwareSourcePublicKey && ! opts . clientDerivedPublicKey ) {
1223- if ( ! checkRequired ( opts , [ 'xPubKey' ] , cb ) ) return ;
1224- try {
1225- xPubKey = Bitcore_ [ opts . chain ] . HDPublicKey ( opts . xPubKey ) ;
1226- } catch {
1227- return cb ( new ClientError ( 'Invalid extended public key' ) ) ;
1228- }
1229- if ( xPubKey . network == null ) {
1230- return cb ( new ClientError ( 'Invalid extended public key' ) ) ;
1231- }
1239+ try {
1240+ xPubKey = Bitcore_ [ opts . chain ] . HDPublicKey ( opts . xPubKey ) ;
1241+ } catch {
1242+ return cb ( new ClientError ( 'Invalid extended public key' ) ) ;
1243+ }
1244+ if ( xPubKey . network == null ) {
1245+ return cb ( new ClientError ( 'Invalid extended public key' ) ) ;
12321246 }
12331247
12341248 this . walletId = opts . walletId ;
@@ -1237,10 +1251,9 @@ export class WalletService implements IWalletService {
12371251 if ( err ) return cb ( err ) ;
12381252 if ( ! wallet ) return cb ( Errors . WALLET_NOT_FOUND ) ;
12391253
1240- if ( ( opts . hardwareSourcePublicKey || opts . clientDerivedPublicKey ) && ! opts . tssKeyId ) {
1241- this . _addCopayerToWallet ( wallet , opts , cb ) ;
1242- return ;
1243- }
1254+ // SECURITY: opts.hardwareSourcePublicKey or opts.clientDerivedPublicKey may not
1255+ // circumvent the required checks below. A future update may enable either to replace xPubKey
1256+ // That is currently not supported
12441257
12451258 if ( this . _upgradeNeeded ( UPGRADES . BCH_bwc_$lt_8_3_multisig , { chain : opts . chain , n : wallet . n } ) ) {
12461259 return cb ( Errors . UPGRADE_NEEDED . withMessage ( 'BWC clients < 8.3 are no longer supported for multisig BCH wallets.' ) ) ;
0 commit comments