diff options
| author | Florian Dold <florian@dold.me> | 2022-02-21 12:40:51 +0100 | 
|---|---|---|
| committer | Florian Dold <florian@dold.me> | 2022-02-21 12:40:57 +0100 | 
| commit | 5c93f15157b4fc9d0fefb6bb2a9956592ebb1ec9 (patch) | |
| tree | cd7e7500376f0b0ee560348e792ac4cbbb576925 /packages/taler-wallet-core/src | |
| parent | 606be7577be2bd249f19204d0c80b3b48e3065ca (diff) | |
towards implementing breaking exchange protocol changes
Diffstat (limited to 'packages/taler-wallet-core/src')
14 files changed, 224 insertions, 387 deletions
diff --git a/packages/taler-wallet-core/src/crypto/cryptoTypes.ts b/packages/taler-wallet-core/src/crypto/cryptoTypes.ts index 93a7cd1c4..94abb8f7c 100644 --- a/packages/taler-wallet-core/src/crypto/cryptoTypes.ts +++ b/packages/taler-wallet-core/src/crypto/cryptoTypes.ts @@ -30,8 +30,10 @@  import {    AmountJson,    AmountString, +  CoinEnvelope,    DenominationPubKey,    ExchangeProtocolVersion, +  RefreshPlanchetInfo,    UnblindedSignature,  } from "@gnu-taler/taler-util"; @@ -74,32 +76,7 @@ export interface DerivedRefreshSession {    /**     * Planchets for each cut-and-choose instance.     */ -  planchetsForGammas: { -    /** -     * Public key for the coin. -     */ -    publicKey: string; - -    /** -     * Private key for the coin. -     */ -    privateKey: string; - -    /** -     * Blinded public key. -     */ -    coinEv: string; - -    /** -     * Hash of the blinded public key. -     */ -    coinEvHash: string; - -    /** -     * Blinding key used. -     */ -    blindingKey: string; -  }[][]; +  planchetsForGammas: RefreshPlanchetInfo[][];    /**     * The transfer keys, kappa of them. diff --git a/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts b/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts index 29c2553a5..16446bb9e 100644 --- a/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts +++ b/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts @@ -28,6 +28,7 @@ import { CryptoWorker } from "./cryptoWorkerInterface.js";  import {    CoinDepositPermission, +  CoinEnvelope,    RecoupRefreshRequest,    RecoupRequest,  } from "@gnu-taler/taler-util"; @@ -452,7 +453,7 @@ export class CryptoApi {      newDenomHash: string,      oldCoinPub: string,      transferPub: string, -    coinEv: string, +    coinEv: CoinEnvelope,    ): Promise<string> {      return this.doRpc<string>(        "signCoinLink", diff --git a/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts b/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts index bff2e0eb5..9f6d82348 100644 --- a/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts +++ b/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts @@ -26,19 +26,49 @@  // FIXME: Crypto should not use DB Types!  import { -  AmountJson, Amounts, BenchmarkResult, buildSigPS, -  CoinDepositPermission, createEddsaKeyPair, createHashContext, decodeCrock, -  DenomKeyType, DepositInfo, eddsaGetPublic, eddsaSign, eddsaVerify, -  encodeCrock, ExchangeProtocolVersion, -  FreshCoin, hash, hashDenomPub, kdf, keyExchangeEcdheEddsa, -  // Logger, -  MakeSyncSignatureRequest, PlanchetCreationRequest, PlanchetCreationResult, -  randomBytes, RecoupRefreshRequest, +  AmountJson, +  Amounts, +  BenchmarkResult, +  buildSigPS, +  CoinDepositPermission, +  CoinEnvelope, +  createEddsaKeyPair, +  createHashContext, +  decodeCrock, +  DenomKeyType, +  DepositInfo, +  eddsaGetPublic, +  eddsaSign, +  eddsaVerify, +  encodeCrock, +  ExchangeProtocolVersion, +  FreshCoin, +  hash, +  HashCodeString, +  hashCoinEv, +  hashCoinEvInner, +  hashDenomPub, +  keyExchangeEcdheEddsa, +  Logger, +  MakeSyncSignatureRequest, +  PlanchetCreationRequest, +  PlanchetCreationResult, +  randomBytes, +  RecoupRefreshRequest,    RecoupRequest, -  RefreshPlanchetInfo, rsaBlind, rsaUnblind, rsaVerify, setupRefreshPlanchet, +  RefreshPlanchetInfo, +  rsaBlind, +  rsaUnblind, +  rsaVerify, +  setupRefreshPlanchet,    setupRefreshTransferPub,    setupTipPlanchet, -  setupWithdrawPlanchet, stringToBytes, TalerSignaturePurpose, Timestamp, timestampTruncateToSecond +  setupWithdrawPlanchet, +  stringToBytes, +  TalerSignaturePurpose, +  Timestamp, +  timestampTruncateToSecond, +  typedArrayConcat,  } from "@gnu-taler/taler-util";  import bigint from "big-integer";  import { DenominationRecord, WireFee } from "../../db.js"; @@ -50,10 +80,10 @@ import {    DerivedTipPlanchet,    DeriveRefreshSessionRequest,    DeriveTipRequest, -  SignTrackTransactionRequest +  SignTrackTransactionRequest,  } from "../cryptoTypes.js"; -// const logger = new Logger("cryptoImplementation.ts"); +const logger = new Logger("cryptoImplementation.ts");  function amountToBuffer(amount: AmountJson): Uint8Array {    const buffer = new ArrayBuffer(8 + 4 + 12); @@ -130,7 +160,7 @@ async function myEddsaSign(  export class CryptoImplementation {    static enableTracing = false; -  constructor(private primitiveWorker?: PrimitiveWorker) { } +  constructor(private primitiveWorker?: PrimitiveWorker) {}    /**     * Create a pre-coin of the given denomination to be withdrawn from then given @@ -139,26 +169,26 @@ export class CryptoImplementation {    async createPlanchet(      req: PlanchetCreationRequest,    ): Promise<PlanchetCreationResult> { -    if ( -      req.denomPub.cipher === DenomKeyType.Rsa || -      req.denomPub.cipher === DenomKeyType.LegacyRsa -    ) { +    const denomPub = req.denomPub; +    if (denomPub.cipher === DenomKeyType.Rsa) {        const reservePub = decodeCrock(req.reservePub); -      const denomPubRsa = decodeCrock(req.denomPub.rsa_public_key); +      const denomPubRsa = decodeCrock(denomPub.rsa_public_key);        const derivedPlanchet = setupWithdrawPlanchet(          decodeCrock(req.secretSeed),          req.coinIndex,        );        const coinPubHash = hash(derivedPlanchet.coinPub);        const ev = rsaBlind(coinPubHash, derivedPlanchet.bks, denomPubRsa); +      const coinEv: CoinEnvelope = { +        cipher: DenomKeyType.Rsa, +        rsa_blinded_planchet: encodeCrock(ev), +      };        const amountWithFee = Amounts.add(req.value, req.feeWithdraw).amount;        const denomPubHash = hashDenomPub(req.denomPub); -      const evHash = hash(ev); - +      const evHash = hashCoinEv(coinEv, encodeCrock(denomPubHash));        const withdrawRequest = buildSigPS(          TalerSignaturePurpose.WALLET_RESERVE_WITHDRAW,        ) -        .put(reservePub)          .put(amountToBuffer(amountWithFee))          .put(denomPubHash)          .put(evHash) @@ -171,14 +201,11 @@ export class CryptoImplementation {        const planchet: PlanchetCreationResult = {          blindingKey: encodeCrock(derivedPlanchet.bks), -        coinEv: encodeCrock(ev), +        coinEv,          coinPriv: encodeCrock(derivedPlanchet.coinPriv),          coinPub: encodeCrock(derivedPlanchet.coinPub),          coinValue: req.value, -        denomPub: { -          cipher: req.denomPub.cipher, -          rsa_public_key: encodeCrock(denomPubRsa), -        }, +        denomPub,          denomPubHash: encodeCrock(denomPubHash),          reservePub: encodeCrock(reservePub),          withdrawSig: sigResult.sig, @@ -194,11 +221,8 @@ export class CryptoImplementation {     * Create a planchet used for tipping, including the private keys.     */    createTipPlanchet(req: DeriveTipRequest): DerivedTipPlanchet { -    if ( -      req.denomPub.cipher !== DenomKeyType.Rsa && -      req.denomPub.cipher !== DenomKeyType.LegacyRsa -    ) { -      throw Error("unsupported cipher"); +    if (req.denomPub.cipher !== DenomKeyType.Rsa) { +      throw Error(`unsupported cipher (${req.denomPub.cipher})`);      }      const fc = setupTipPlanchet(decodeCrock(req.secretSeed), req.planchetIndex);      const denomPub = decodeCrock(req.denomPub.rsa_public_key); @@ -236,15 +260,7 @@ export class CryptoImplementation {      const coinPriv = decodeCrock(req.coinPriv);      const coinSig = eddsaSign(p, coinPriv); -    if (req.denomPub.cipher === DenomKeyType.LegacyRsa) { -      const paybackRequest: RecoupRequest = { -        coin_blind_key_secret: req.blindingKey, -        coin_sig: encodeCrock(coinSig), -        denom_pub_hash: req.denomPubHash, -        denom_sig: req.denomSig.rsa_signature, -      }; -      return paybackRequest; -    } else { +    if (req.denomPub.cipher === DenomKeyType.Rsa) {        const paybackRequest: RecoupRequest = {          coin_blind_key_secret: req.blindingKey,          coin_sig: encodeCrock(coinSig), @@ -252,6 +268,8 @@ export class CryptoImplementation {          denom_sig: req.denomSig,        };        return paybackRequest; +    } else { +      throw new Error();      }    } @@ -268,15 +286,7 @@ export class CryptoImplementation {      const coinPriv = decodeCrock(req.coinPriv);      const coinSig = eddsaSign(p, coinPriv); -    if (req.denomPub.cipher === DenomKeyType.LegacyRsa) { -      const recoupRequest: RecoupRefreshRequest = { -        coin_blind_key_secret: req.blindingKey, -        coin_sig: encodeCrock(coinSig), -        denom_pub_hash: req.denomPubHash, -        denom_sig: req.denomSig.rsa_signature, -      }; -      return recoupRequest; -    } else { +    if (req.denomPub.cipher === DenomKeyType.Rsa) {        const recoupRequest: RecoupRefreshRequest = {          coin_blind_key_secret: req.blindingKey,          coin_sig: encodeCrock(coinSig), @@ -284,6 +294,8 @@ export class CryptoImplementation {          denom_sig: req.denomSig,        };        return recoupRequest; +    } else { +      throw new Error();      }    } @@ -364,26 +376,11 @@ export class CryptoImplementation {      sig: string,      masterPub: string,    ): boolean { -    if (versionCurrent === ExchangeProtocolVersion.V12) { -      const paytoHash = hash(stringToBytes(paytoUri + "\0")); -      const p = buildSigPS(TalerSignaturePurpose.MASTER_WIRE_DETAILS) -        .put(paytoHash) -        .build(); -      return eddsaVerify(p, decodeCrock(sig), decodeCrock(masterPub)); -    } else if (versionCurrent === ExchangeProtocolVersion.V9) { -      const h = kdf( -        64, -        stringToBytes("exchange-wire-signature"), -        stringToBytes(paytoUri + "\0"), -        new Uint8Array(0), -      ); -      const p = buildSigPS(TalerSignaturePurpose.MASTER_WIRE_DETAILS) -        .put(h) -        .build(); -      return eddsaVerify(p, decodeCrock(sig), decodeCrock(masterPub)); -    } else { -      throw Error(`unsupported version (${versionCurrent})`); -    } +    const paytoHash = hash(stringToBytes(paytoUri + "\0")); +    const p = buildSigPS(TalerSignaturePurpose.MASTER_WIRE_DETAILS) +      .put(paytoHash) +      .build(); +    return eddsaVerify(p, decodeCrock(sig), decodeCrock(masterPub));    }    isValidContractTermsSignature( @@ -444,10 +441,12 @@ export class CryptoImplementation {    ): Promise<CoinDepositPermission> {      // FIXME: put extensions here if used      const hExt = new Uint8Array(64); +    const hAgeCommitment = new Uint8Array(32);      let d: Uint8Array;      if (depositInfo.denomKeyType === DenomKeyType.Rsa) {        d = buildSigPS(TalerSignaturePurpose.WALLET_COIN_DEPOSIT)          .put(decodeCrock(depositInfo.contractTermsHash)) +        .put(hAgeCommitment)          .put(hExt)          .put(decodeCrock(depositInfo.wireInfoHash))          .put(decodeCrock(depositInfo.denomPubHash)) @@ -457,18 +456,6 @@ export class CryptoImplementation {          .put(amountToBuffer(depositInfo.feeDeposit))          .put(decodeCrock(depositInfo.merchantPub))          .build(); -    } else if (depositInfo.denomKeyType === DenomKeyType.LegacyRsa) { -      d = buildSigPS(TalerSignaturePurpose.WALLET_COIN_DEPOSIT) -        .put(decodeCrock(depositInfo.contractTermsHash)) -        .put(decodeCrock(depositInfo.wireInfoHash)) -        .put(decodeCrock(depositInfo.denomPubHash)) -        .put(timestampRoundedToBuffer(depositInfo.timestamp)) -        .put(timestampRoundedToBuffer(depositInfo.refundDeadline)) -        .put(amountToBuffer(depositInfo.spendAmount)) -        .put(amountToBuffer(depositInfo.feeDeposit)) -        .put(decodeCrock(depositInfo.merchantPub)) -        .put(decodeCrock(depositInfo.coinPub)) -        .build();      } else {        throw Error("unsupported exchange protocol version");      } @@ -490,18 +477,10 @@ export class CryptoImplementation {          },        };        return s; -    } else if (depositInfo.denomKeyType === DenomKeyType.LegacyRsa) { -      const s: CoinDepositPermission = { -        coin_pub: depositInfo.coinPub, -        coin_sig: coinSigRes.sig, -        contribution: Amounts.stringify(depositInfo.spendAmount), -        h_denom: depositInfo.denomPubHash, -        exchange_url: depositInfo.exchangeBaseUrl, -        ub_sig: depositInfo.denomSig.rsa_signature, -      }; -      return s;      } else { -      throw Error("unsupported merchant protocol version"); +      throw Error( +        `unsupported denomination cipher (${depositInfo.denomKeyType})`, +      );      }    } @@ -551,17 +530,18 @@ export class CryptoImplementation {      for (const denomSel of newCoinDenoms) {        for (let i = 0; i < denomSel.count; i++) { -        if (denomSel.denomPub.cipher === DenomKeyType.LegacyRsa) { -          const r = decodeCrock(denomSel.denomPub.rsa_public_key); -          sessionHc.update(r); +        if (denomSel.denomPub.cipher === DenomKeyType.Rsa) { +          const denomPubHash = hashDenomPub(denomSel.denomPub); +          sessionHc.update(denomPubHash);          } else { -          sessionHc.update(hashDenomPub(denomSel.denomPub)); +          throw new Error();          }        }      }      sessionHc.update(decodeCrock(meltCoinPub));      sessionHc.update(amountToBuffer(valueWithFee)); +      for (let i = 0; i < kappa; i++) {        const planchets: RefreshPlanchetInfo[] = [];        for (let j = 0; j < newCoinDenoms.length; j++) { @@ -594,24 +574,29 @@ export class CryptoImplementation {              coinPub = fresh.coinPub;              blindingFactor = fresh.bks;            } -          const pubHash = hash(coinPub); -          if ( -            denomSel.denomPub.cipher !== DenomKeyType.Rsa && -            denomSel.denomPub.cipher !== DenomKeyType.LegacyRsa -          ) { +          const coinPubHash = hash(coinPub); +          if (denomSel.denomPub.cipher !== DenomKeyType.Rsa) {              throw Error("unsupported cipher, can't create refresh session");            } -          const denomPub = decodeCrock(denomSel.denomPub.rsa_public_key); -          const ev = rsaBlind(pubHash, blindingFactor, denomPub); +          const rsaDenomPub = decodeCrock(denomSel.denomPub.rsa_public_key); +          const ev = rsaBlind(coinPubHash, blindingFactor, rsaDenomPub); +          const coinEv: CoinEnvelope = { +            cipher: DenomKeyType.Rsa, +            rsa_blinded_planchet: encodeCrock(ev), +          }; +          const coinEvHash = hashCoinEv( +            coinEv, +            encodeCrock(hashDenomPub(denomSel.denomPub)), +          );            const planchet: RefreshPlanchetInfo = {              blindingKey: encodeCrock(blindingFactor), -            coinEv: encodeCrock(ev), -            privateKey: encodeCrock(coinPriv), -            publicKey: encodeCrock(coinPub), -            coinEvHash: encodeCrock(hash(ev)), +            coinEv, +            coinPriv: encodeCrock(coinPriv), +            coinPub: encodeCrock(coinPub), +            coinEvHash: encodeCrock(coinEvHash),            };            planchets.push(planchet); -          sessionHc.update(ev); +          hashCoinEvInner(coinEv, sessionHc);          }        }        planchetsForGammas.push(planchets); @@ -619,26 +604,15 @@ export class CryptoImplementation {      const sessionHash = sessionHc.finish();      let confirmData: Uint8Array; -    if (req.exchangeProtocolVersion === ExchangeProtocolVersion.V9) { -      confirmData = buildSigPS(TalerSignaturePurpose.WALLET_COIN_MELT) -        .put(sessionHash) -        .put(decodeCrock(meltCoinDenomPubHash)) -        .put(amountToBuffer(valueWithFee)) -        .put(amountToBuffer(meltFee)) -        .put(decodeCrock(meltCoinPub)) -        .build(); -    } else if (req.exchangeProtocolVersion === ExchangeProtocolVersion.V12) { -      confirmData = buildSigPS(TalerSignaturePurpose.WALLET_COIN_MELT) -        .put(sessionHash) -        .put(decodeCrock(meltCoinDenomPubHash)) -        .put(amountToBuffer(valueWithFee)) -        .put(amountToBuffer(meltFee)) -        .build(); -    } else { -      throw Error( -        `Exchange protocol version (${req.exchangeProtocolVersion}) not supported`, -      ); -    } +    // FIXME: fill in age commitment +    const hAgeCommitment = new Uint8Array(32); +    confirmData = buildSigPS(TalerSignaturePurpose.WALLET_COIN_MELT) +      .put(sessionHash) +      .put(decodeCrock(meltCoinDenomPubHash)) +      .put(hAgeCommitment) +      .put(amountToBuffer(valueWithFee)) +      .put(amountToBuffer(meltFee)) +      .build();      const confirmSigResp = await myEddsaSign(this.primitiveWorker, {        msg: encodeCrock(confirmData), @@ -678,12 +652,15 @@ export class CryptoImplementation {      newDenomHash: string,      oldCoinPub: string,      transferPub: string, -    coinEv: string, +    coinEv: CoinEnvelope,    ): Promise<string> { -    const coinEvHash = hash(decodeCrock(coinEv)); +    const coinEvHash = hashCoinEv(coinEv, newDenomHash); +    // FIXME: fill in +    const hAgeCommitment = new Uint8Array(32);      const coinLink = buildSigPS(TalerSignaturePurpose.WALLET_COIN_LINK)        .put(decodeCrock(newDenomHash))        .put(decodeCrock(transferPub)) +      .put(hAgeCommitment)        .put(coinEvHash)        .build();      const sig = await myEddsaSign(this.primitiveWorker, { diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index 7f7dd10ff..410311530 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -38,6 +38,7 @@ import {    TalerErrorDetails,    Timestamp,    UnblindedSignature, +  CoinEnvelope,  } from "@gnu-taler/taler-util";  import { RetryInfo } from "./util/retries.js";  import { PayCoinSelection } from "./util/coinSelection.js"; @@ -602,7 +603,7 @@ export interface PlanchetRecord {    withdrawSig: string; -  coinEv: string; +  coinEv: CoinEnvelope;    coinEvHash: string; @@ -1154,7 +1155,6 @@ export interface WalletContractData {    timestamp: Timestamp;    wireMethod: string;    wireInfoHash: string; -  wireInfoLegacyHash?: string;    maxDepositFee: AmountJson;  } @@ -1294,9 +1294,9 @@ export const WALLET_BACKUP_STATE_KEY = "walletBackupState";   */  export type ConfigRecord =    | { -    key: typeof WALLET_BACKUP_STATE_KEY; -    value: WalletBackupConfState; -  } +      key: typeof WALLET_BACKUP_STATE_KEY; +      value: WalletBackupConfState; +    }    | { key: "currencyDefaultsApplied"; value: boolean };  export interface WalletBackupConfState { @@ -1392,9 +1392,9 @@ export interface WithdrawalGroupRecord {    /**     * UID of the denomination selection. -   *  +   *     * Used for merging backups. -   *  +   *     * FIXME: Should this not also include a timestamp for more logical merging?     */    denomSelUid: string; @@ -1480,17 +1480,17 @@ export enum BackupProviderStateTag {  export type BackupProviderState =    | { -    tag: BackupProviderStateTag.Provisional; -  } +      tag: BackupProviderStateTag.Provisional; +    }    | { -    tag: BackupProviderStateTag.Ready; -    nextBackupTimestamp: Timestamp; -  } +      tag: BackupProviderStateTag.Ready; +      nextBackupTimestamp: Timestamp; +    }    | { -    tag: BackupProviderStateTag.Retrying; -    retryInfo: RetryInfo; -    lastError?: TalerErrorDetails; -  }; +      tag: BackupProviderStateTag.Retrying; +      retryInfo: RetryInfo; +      lastError?: TalerErrorDetails; +    };  export interface BackupProviderTerms {    supportedProtocolVersion: string; @@ -1875,9 +1875,9 @@ export function exportDb(db: IDBDatabase): Promise<any> {  }  export interface DatabaseDump { -  name: string, -  stores: { [s: string]: any }, -  version: string, +  name: string; +  stores: { [s: string]: any }; +  version: string;  }  export function importDb(db: IDBDatabase, dump: DatabaseDump): Promise<any> { @@ -1891,12 +1891,11 @@ export function importDb(db: IDBDatabase, dump: DatabaseDump): Promise<any> {        const name = db.objectStoreNames[i];        const storeDump = dump.stores[name];        if (!storeDump) continue; -      Object.keys(storeDump).forEach(async key => { -        const value = storeDump[key] +      Object.keys(storeDump).forEach(async (key) => { +        const value = storeDump[key];          if (!value) return; -        tx.objectStore(name).put(value) -      }) - +        tx.objectStore(name).put(value); +      });      }    });  } diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts b/packages/taler-wallet-core/src/operations/backup/import.ts index 9f63441dd..21b10a945 100644 --- a/packages/taler-wallet-core/src/operations/backup/import.ts +++ b/packages/taler-wallet-core/src/operations/backup/import.ts @@ -337,8 +337,7 @@ export async function importBackup(          for (const backupDenomination of backupExchangeDetails.denominations) {            if ( -            backupDenomination.denom_pub.cipher !== DenomKeyType.Rsa && -            backupDenomination.denom_pub.cipher !== DenomKeyType.LegacyRsa +            backupDenomination.denom_pub.cipher !== DenomKeyType.Rsa            ) {              throw Error("unsupported cipher");            } diff --git a/packages/taler-wallet-core/src/operations/backup/index.ts b/packages/taler-wallet-core/src/operations/backup/index.ts index e3950ef90..5eb248611 100644 --- a/packages/taler-wallet-core/src/operations/backup/index.ts +++ b/packages/taler-wallet-core/src/operations/backup/index.ts @@ -168,10 +168,7 @@ async function computeBackupCryptoData(    };    for (const backupExchangeDetails of backupContent.exchange_details) {      for (const backupDenom of backupExchangeDetails.denominations) { -      if ( -        backupDenom.denom_pub.cipher !== DenomKeyType.Rsa && -        backupDenom.denom_pub.cipher !== DenomKeyType.LegacyRsa -      ) { +      if (backupDenom.denom_pub.cipher !== DenomKeyType.Rsa) {          throw Error("unsupported cipher");        }        for (const backupCoin of backupDenom.coins) { @@ -192,18 +189,14 @@ async function computeBackupCryptoData(          LibtoolVersion.compare(backupExchangeDetails.protocol_version, "9")            ?.compatible        ) { -        cryptoData.rsaDenomPubToHash[ -          backupDenom.denom_pub.rsa_public_key -        ] = encodeCrock( -          hash(decodeCrock(backupDenom.denom_pub.rsa_public_key)), -        ); +        cryptoData.rsaDenomPubToHash[backupDenom.denom_pub.rsa_public_key] = +          encodeCrock(hash(decodeCrock(backupDenom.denom_pub.rsa_public_key)));        } else if (          LibtoolVersion.compare(backupExchangeDetails.protocol_version, "10")            ?.compatible        ) { -        cryptoData.rsaDenomPubToHash[ -          backupDenom.denom_pub.rsa_public_key -        ] = encodeCrock(hashDenomPub(backupDenom.denom_pub)); +        cryptoData.rsaDenomPubToHash[backupDenom.denom_pub.rsa_public_key] = +          encodeCrock(hashDenomPub(backupDenom.denom_pub));        } else {          throw Error("unsupported exchange protocol version");        } @@ -220,9 +213,8 @@ async function computeBackupCryptoData(      );      const noncePub = encodeCrock(eddsaGetPublic(decodeCrock(prop.nonce_priv)));      cryptoData.proposalNoncePrivToPub[prop.nonce_priv] = noncePub; -    cryptoData.proposalIdToContractTermsHash[ -      prop.proposal_id -    ] = contractTermsHash; +    cryptoData.proposalIdToContractTermsHash[prop.proposal_id] = +      contractTermsHash;    }    for (const purch of backupContent.purchases) {      const contractTermsHash = await cryptoApi.hashString( @@ -230,9 +222,8 @@ async function computeBackupCryptoData(      );      const noncePub = encodeCrock(eddsaGetPublic(decodeCrock(purch.nonce_priv)));      cryptoData.proposalNoncePrivToPub[purch.nonce_priv] = noncePub; -    cryptoData.proposalIdToContractTermsHash[ -      purch.proposal_id -    ] = contractTermsHash; +    cryptoData.proposalIdToContractTermsHash[purch.proposal_id] = +      contractTermsHash;    }    return cryptoData;  } @@ -548,10 +539,11 @@ export interface RemoveBackupProviderRequest {    provider: string;  } -export const codecForRemoveBackupProvider = (): Codec<RemoveBackupProviderRequest> => -  buildCodecForObject<RemoveBackupProviderRequest>() -    .property("provider", codecForString()) -    .build("RemoveBackupProviderRequest"); +export const codecForRemoveBackupProvider = +  (): Codec<RemoveBackupProviderRequest> => +    buildCodecForObject<RemoveBackupProviderRequest>() +      .property("provider", codecForString()) +      .build("RemoveBackupProviderRequest");  export async function removeBackupProvider(    ws: InternalWalletState, @@ -619,12 +611,13 @@ interface SyncTermsOfServiceResponse {    version: string;  } -const codecForSyncTermsOfServiceResponse = (): Codec<SyncTermsOfServiceResponse> => -  buildCodecForObject<SyncTermsOfServiceResponse>() -    .property("storage_limit_in_megabytes", codecForNumber()) -    .property("annual_fee", codecForAmountString()) -    .property("version", codecForString()) -    .build("SyncTermsOfServiceResponse"); +const codecForSyncTermsOfServiceResponse = +  (): Codec<SyncTermsOfServiceResponse> => +    buildCodecForObject<SyncTermsOfServiceResponse>() +      .property("storage_limit_in_megabytes", codecForNumber()) +      .property("annual_fee", codecForAmountString()) +      .property("version", codecForString()) +      .build("SyncTermsOfServiceResponse");  export interface AddBackupProviderRequest {    backupProviderBaseUrl: string; @@ -637,12 +630,13 @@ export interface AddBackupProviderRequest {    activate?: boolean;  } -export const codecForAddBackupProviderRequest = (): Codec<AddBackupProviderRequest> => -  buildCodecForObject<AddBackupProviderRequest>() -    .property("backupProviderBaseUrl", codecForString()) -    .property("name", codecForString()) -    .property("activate", codecOptional(codecForBoolean())) -    .build("AddBackupProviderRequest"); +export const codecForAddBackupProviderRequest = +  (): Codec<AddBackupProviderRequest> => +    buildCodecForObject<AddBackupProviderRequest>() +      .property("backupProviderBaseUrl", codecForString()) +      .property("name", codecForString()) +      .property("activate", codecOptional(codecForBoolean())) +      .build("AddBackupProviderRequest");  export async function addBackupProvider(    ws: InternalWalletState, diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts index 8a5b35732..25b9cb92d 100644 --- a/packages/taler-wallet-core/src/operations/deposits.ts +++ b/packages/taler-wallet-core/src/operations/deposits.ts @@ -27,7 +27,11 @@ import {    CreateDepositGroupRequest,    CreateDepositGroupResponse,    DenomKeyType, -  durationFromSpec, encodeCrock, GetFeeForDepositRequest, getRandomBytes, getTimestampNow, +  durationFromSpec, +  encodeCrock, +  GetFeeForDepositRequest, +  getRandomBytes, +  getTimestampNow,    Logger,    NotificationType,    parsePaytoUri, @@ -38,7 +42,7 @@ import {    timestampTruncateToSecond,    TrackDepositGroupRequest,    TrackDepositGroupResponse, -  URL +  URL,  } from "@gnu-taler/taler-util";  import { InternalWalletState } from "../common.js";  import { DepositGroupRecord, OperationStatus } from "../db.js"; @@ -54,7 +58,7 @@ import {    getCandidatePayCoins,    getTotalPaymentCost,    hashWire, -  hashWireLegacy +  hashWireLegacy,  } from "./pay.js";  import { getTotalRefreshCost } from "./refresh.js"; @@ -199,47 +203,21 @@ async function processDepositGroupImpl(      }      const perm = depositPermissions[i];      let requestBody: any; -    if ( -      typeof perm.ub_sig === "string" || -      perm.ub_sig.cipher === DenomKeyType.LegacyRsa -    ) { -      // Legacy request -      logger.info("creating legacy deposit request"); -      const wireHash = hashWireLegacy( -        depositGroup.wire.payto_uri, -        depositGroup.wire.salt, -      ); -      requestBody = { -        contribution: Amounts.stringify(perm.contribution), -        wire: depositGroup.wire, -        h_wire: wireHash, -        h_contract_terms: depositGroup.contractTermsHash, -        ub_sig: perm.ub_sig, -        timestamp: depositGroup.contractTermsRaw.timestamp, -        wire_transfer_deadline: -          depositGroup.contractTermsRaw.wire_transfer_deadline, -        refund_deadline: depositGroup.contractTermsRaw.refund_deadline, -        coin_sig: perm.coin_sig, -        denom_pub_hash: perm.h_denom, -        merchant_pub: depositGroup.merchantPub, -      }; -    } else { -      logger.info("creating v10 deposit request"); -      requestBody = { -        contribution: Amounts.stringify(perm.contribution), -        merchant_payto_uri: depositGroup.wire.payto_uri, -        wire_salt: depositGroup.wire.salt, -        h_contract_terms: depositGroup.contractTermsHash, -        ub_sig: perm.ub_sig, -        timestamp: depositGroup.contractTermsRaw.timestamp, -        wire_transfer_deadline: -          depositGroup.contractTermsRaw.wire_transfer_deadline, -        refund_deadline: depositGroup.contractTermsRaw.refund_deadline, -        coin_sig: perm.coin_sig, -        denom_pub_hash: perm.h_denom, -        merchant_pub: depositGroup.merchantPub, -      }; -    } +    logger.info("creating v10 deposit request"); +    requestBody = { +      contribution: Amounts.stringify(perm.contribution), +      merchant_payto_uri: depositGroup.wire.payto_uri, +      wire_salt: depositGroup.wire.salt, +      h_contract_terms: depositGroup.contractTermsHash, +      ub_sig: perm.ub_sig, +      timestamp: depositGroup.contractTermsRaw.timestamp, +      wire_transfer_deadline: +        depositGroup.contractTermsRaw.wire_transfer_deadline, +      refund_deadline: depositGroup.contractTermsRaw.refund_deadline, +      coin_sig: perm.coin_sig, +      denom_pub_hash: perm.h_denom, +      merchant_pub: depositGroup.merchantPub, +    };      const url = new URL(`coins/${perm.coin_pub}/deposit`, perm.exchange_url);      logger.info(`depositing to ${url}`);      const httpResp = await ws.http.postJson(url.href, requestBody); diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts index 87200c2f9..c50afc215 100644 --- a/packages/taler-wallet-core/src/operations/exchanges.ts +++ b/packages/taler-wallet-core/src/operations/exchanges.ts @@ -83,15 +83,7 @@ function denominationRecordFromKeys(    denomIn: ExchangeDenomination,  ): DenominationRecord {    let denomPub: DenominationPubKey; -  // We support exchange protocol v9 and v10. -  if (typeof denomIn.denom_pub === "string") { -    denomPub = { -      cipher: DenomKeyType.LegacyRsa, -      rsa_public_key: denomIn.denom_pub, -    }; -  } else { -    denomPub = denomIn.denom_pub; -  } +  denomPub = denomIn.denom_pub;    const denomPubHash = encodeCrock(hashDenomPub(denomPub));    const d: DenominationRecord = {      denomPub, diff --git a/packages/taler-wallet-core/src/operations/pay.ts b/packages/taler-wallet-core/src/operations/pay.ts index 8f0727c8b..4870d446a 100644 --- a/packages/taler-wallet-core/src/operations/pay.ts +++ b/packages/taler-wallet-core/src/operations/pay.ts @@ -606,7 +606,6 @@ export function extractContractData(      timestamp: parsedContractTerms.timestamp,      wireMethod: parsedContractTerms.wire_method,      wireInfoHash: parsedContractTerms.h_wire, -    wireInfoLegacyHash: parsedContractTerms.h_wire_legacy,      maxDepositFee: Amounts.parseOrThrow(parsedContractTerms.max_fee),      merchant: parsedContractTerms.merchant,      products: parsedContractTerms.products, @@ -1515,14 +1514,7 @@ export async function generateDepositPermissions(    for (let i = 0; i < payCoinSel.coinPubs.length; i++) {      const { coin, denom } = coinWithDenom[i];      let wireInfoHash: string; -    if ( -      coin.denomPub.cipher === DenomKeyType.LegacyRsa && -      contractData.wireInfoLegacyHash -    ) { -      wireInfoHash = contractData.wireInfoLegacyHash; -    } else { -      wireInfoHash = contractData.wireInfoHash; -    } +    wireInfoHash = contractData.wireInfoHash;      const dp = await ws.cryptoApi.signDepositPermission({        coinPriv: coin.coinPriv,        coinPub: coin.coinPub, diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts index 1e5dd68a8..ba4cb697d 100644 --- a/packages/taler-wallet-core/src/operations/refresh.ts +++ b/packages/taler-wallet-core/src/operations/refresh.ts @@ -18,8 +18,10 @@ import {    DenomKeyType,    encodeCrock,    ExchangeProtocolVersion, +  ExchangeRefreshRevealRequest,    getRandomBytes,    HttpStatusCode, +  j2s,  } from "@gnu-taler/taler-util";  import {    CoinRecord, @@ -369,10 +371,6 @@ async function refreshMelt(    let exchangeProtocolVersion: ExchangeProtocolVersion;    switch (d.oldDenom.denomPub.cipher) { -    case DenomKeyType.LegacyRsa: { -      exchangeProtocolVersion = ExchangeProtocolVersion.V9; -      break; -    }      case DenomKeyType.Rsa: {        exchangeProtocolVersion = ExchangeProtocolVersion.V12;        break; @@ -397,16 +395,7 @@ async function refreshMelt(      oldCoin.exchangeBaseUrl,    );    let meltReqBody: any; -  if (oldCoin.denomPub.cipher === DenomKeyType.LegacyRsa) { -    meltReqBody = { -      coin_pub: oldCoin.coinPub, -      confirm_sig: derived.confirmSig, -      denom_pub_hash: oldCoin.denomPubHash, -      denom_sig: oldCoin.denomSig.rsa_signature, -      rc: derived.hash, -      value_with_fee: Amounts.stringify(derived.meltValueWithFee), -    }; -  } else { +  if (oldCoin.denomPub.cipher === DenomKeyType.Rsa) {      meltReqBody = {        coin_pub: oldCoin.coinPub,        confirm_sig: derived.confirmSig, @@ -569,10 +558,6 @@ async function refreshReveal(    let exchangeProtocolVersion: ExchangeProtocolVersion;    switch (d.oldDenom.denomPub.cipher) { -    case DenomKeyType.LegacyRsa: { -      exchangeProtocolVersion = ExchangeProtocolVersion.V9; -      break; -    }      case DenomKeyType.Rsa: {        exchangeProtocolVersion = ExchangeProtocolVersion.V12;        break; @@ -600,7 +585,6 @@ async function refreshReveal(      throw Error("refresh index error");    } -  const evs = planchets.map((x: RefreshPlanchetInfo) => x.coinEv);    const newDenomsFlat: string[] = [];    const linkSigs: string[] = []; @@ -620,10 +604,9 @@ async function refreshReveal(      }    } -  const req = { -    coin_evs: evs, +  const req: ExchangeRefreshRevealRequest = { +    coin_evs: planchets.map((x) => x.coinEv),      new_denoms_h: newDenomsFlat, -    rc: derived.hash,      transfer_privs: privs,      transfer_pub: derived.transferPubs[norevealIndex],      link_sigs: linkSigs, @@ -666,20 +649,14 @@ async function refreshReveal(          continue;        }        const pc = derived.planchetsForGammas[norevealIndex][newCoinIndex]; -      if ( -        denom.denomPub.cipher !== DenomKeyType.Rsa && -        denom.denomPub.cipher !== DenomKeyType.LegacyRsa -      ) { +      if (denom.denomPub.cipher !== DenomKeyType.Rsa) {          throw Error("cipher unsupported");        }        const evSig = reveal.ev_sigs[newCoinIndex].ev_sig;        let rsaSig: string;        if (typeof evSig === "string") {          rsaSig = evSig; -      } else if ( -        evSig.cipher === DenomKeyType.Rsa || -        evSig.cipher === DenomKeyType.LegacyRsa -      ) { +      } else if (evSig.cipher === DenomKeyType.Rsa) {          rsaSig = evSig.blinded_rsa_signature;        } else {          throw Error("unsupported cipher"); @@ -691,8 +668,8 @@ async function refreshReveal(        );        const coin: CoinRecord = {          blindingKey: pc.blindingKey, -        coinPriv: pc.privateKey, -        coinPub: pc.publicKey, +        coinPriv: pc.coinPriv, +        coinPub: pc.coinPub,          currentAmount: denom.value,          denomPub: denom.denomPub,          denomPubHash: denom.denomPubHash, @@ -707,7 +684,7 @@ async function refreshReveal(            oldCoinPub: refreshGroup.oldCoinPubs[coinIndex],          },          suspended: false, -        coinEvHash: pc.coinEv, +        coinEvHash: pc.coinEvHash,        };        coins.push(coin); diff --git a/packages/taler-wallet-core/src/operations/tip.ts b/packages/taler-wallet-core/src/operations/tip.ts index f985d8aad..039fb64a1 100644 --- a/packages/taler-wallet-core/src/operations/tip.ts +++ b/packages/taler-wallet-core/src/operations/tip.ts @@ -306,37 +306,13 @@ async function processTipImpl(      // FIXME: Maybe we want to signal to the caller that the transient error happened?      return;    } - -  // FIXME: Do this earlier? -  const merchantInfo = await ws.merchantOps.getMerchantInfo( -    ws, -    tipRecord.merchantBaseUrl, -  ); -    let blindedSigs: BlindedDenominationSignature[] = []; -  if (merchantInfo.protocolVersionCurrent === MerchantProtocolVersion.V3) { -    const response = await readSuccessResponseJsonOrThrow( -      merchantResp, -      codecForMerchantTipResponseV2(), -    ); -    blindedSigs = response.blind_sigs.map((x) => x.blind_sig); -  } else if ( -    merchantInfo.protocolVersionCurrent === MerchantProtocolVersion.V1 -  ) { -    const response = await readSuccessResponseJsonOrThrow( -      merchantResp, -      codecForMerchantTipResponseV1(), -    ); -    blindedSigs = response.blind_sigs.map((x) => ({ -      cipher: DenomKeyType.Rsa, -      blinded_rsa_signature: x.blind_sig, -    })); -  } else { -    throw Error( -      `unsupported merchant protocol version (${merchantInfo.protocolVersionCurrent})`, -    ); -  } +  const response = await readSuccessResponseJsonOrThrow( +    merchantResp, +    codecForMerchantTipResponseV2(), +  ); +  blindedSigs = response.blind_sigs.map((x) => x.blind_sig);    if (blindedSigs.length !== planchets.length) {      throw Error("number of tip responses does not match requested planchets"); @@ -352,17 +328,11 @@ async function processTipImpl(      const planchet = planchets[i];      checkLogicInvariant(!!planchet); -    if ( -      denom.denomPub.cipher !== DenomKeyType.Rsa && -      denom.denomPub.cipher !== DenomKeyType.LegacyRsa -    ) { +    if (denom.denomPub.cipher !== DenomKeyType.Rsa) {        throw Error("unsupported cipher");      } -    if ( -      blindedSig.cipher !== DenomKeyType.Rsa && -      blindedSig.cipher !== DenomKeyType.LegacyRsa -    ) { +    if (blindedSig.cipher !== DenomKeyType.Rsa) {        throw Error("unsupported cipher");      } diff --git a/packages/taler-wallet-core/src/operations/withdraw.test.ts b/packages/taler-wallet-core/src/operations/withdraw.test.ts index 2c890a121..02540848a 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.test.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.test.ts @@ -14,7 +14,7 @@   GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>   */ -import { Amounts } from "@gnu-taler/taler-util"; +import { Amounts, DenomKeyType } from "@gnu-taler/taler-util";  import test from "ava";  import { DenominationRecord, DenominationVerificationStatus } from "../db.js";  import { selectWithdrawalDenominations } from "./withdraw.js"; @@ -29,7 +29,7 @@ test("withdrawal selection bug repro", (t) => {    const denoms: DenominationRecord[] = [      {        denomPub: { -        cipher: 1, +        cipher: DenomKeyType.Rsa,          rsa_public_key:            "040000XT67C8KBD6B75TTQ3SK8FWXMNQW4372T3BDDGPAMB9RFCA03638W8T3F71WFEFK9NP32VKYVNFXPYRWQ1N1HDKV5J0DFEKHBPJCYSWCBJDRNWD7G8BN8PT97FA9AMV75MYEK4X54D1HGJ207JSVJBGFCATSPNTEYNHEQF1F220W00TBZR1HNPDQFD56FG0DJQ9KGHM8EC33H6AY9YN9CNX5R3Z4TZ4Q23W47SBHB13H6W74FQJG1F50X38VRSC4SR8RWBAFB7S4K8D2H4NMRFSQT892A3T0BTBW7HM5C0H2CK6FRKG31F7W9WP1S29013K5CXYE55CT8TH6N8J9B780R42Y5S3ZB6J6E9H76XBPSGH4TGYSR2VZRB98J417KCQMZKX1BB67E7W5KVE37TC9SJ904002",        }, @@ -83,7 +83,7 @@ test("withdrawal selection bug repro", (t) => {      },      {        denomPub: { -        cipher: 1, +        cipher: DenomKeyType.Rsa,          rsa_public_key:            "040000Y63CF78QFPKRY77BRK9P557Q1GQWX3NCZ3HSYSK0Z7TT0KGRA7N4SKBKEHSTVHX1Z9DNXMJR4EXSY1TXCKV0GJ3T3YYC6Z0JNMJFVYQAV4FX5J90NZH1N33MZTV8HS9SMNAA9S6K73G4P99GYBB01B0P6M1KXZ5JRDR7VWBR3MEJHHGJ6QBMCJR3NWJRE3WJW9PRY8QPQ2S7KFWTWRESH2DBXCXWBD2SRN6P9YX8GRAEMFEGXC9V5GVJTEMH6ZDGNXFPWZE3JVJ2Q4N9GDYKBCHZCJ7M7M2RJ9ZV4Y64NAN9BT6XDC68215GKKRHTW1BBF1MYY6AR3JCTT9HYAM923RMVQR3TAEB7SDX8J76XRZWYH3AGJCZAQGMN5C8SSH9AHQ9RNQJQ15CN45R37X4YNFJV904002",        }, @@ -138,7 +138,7 @@ test("withdrawal selection bug repro", (t) => {      },      {        denomPub: { -        cipher: 1, +        cipher: DenomKeyType.Rsa,          rsa_public_key:            "040000YDESWC2B962DA4WK356SC50MA3N9KV0ZSGY3RC48JCTY258W909C7EEMT5BTC5KZ5T4CERCZ141P9QF87EK2BD1XEEM5GB07MB3H19WE4CQGAS8X84JBWN83PQGQXVMWE5HFA992KMGHC566GT9ZS2QPHZB6X89C4A80Z663PYAAPXP728VHAKATGNNBQ01ZZ2XD1CH9Y38YZBSPJ4K7GB2J76GBCYAVD9ENHDVWXJAXYRPBX4KSS5TXRR3K5NEN9ZV3AJD2V65K7ABRZDF5D5V1FJZZMNJ5XZ4FEREEKEBV9TDFPGJTKDEHEC60K3DN24DAATRESDJ1ZYYSYSRCAT4BT2B62ARGVMJTT5N2R126DRW9TGRWCW0ZAF2N2WET1H4NJEW77X0QT46Z5R3MZ0XPHD04002",        }, @@ -192,7 +192,7 @@ test("withdrawal selection bug repro", (t) => {      },      {        denomPub: { -        cipher: 1, +        cipher: DenomKeyType.Rsa,          rsa_public_key:            "040000YG3T1ADB8DVA6BD3EPV6ZHSHTDW35DEN4VH1AE6CSB7P1PSDTNTJG866PHF6QB1CCWYCVRGA0FVBJ9Q0G7KV7AD9010GDYBQH0NNPHW744MTNXVXWBGGGRGQGYK4DTYN1DSWQ1FZNDSZZPB5BEKG2PDJ93NX2JTN06Y8QMS2G734Z9XHC10EENBG2KVB7EJ3CM8PV1T32RC7AY62F3496E8D8KRHJQQTT67DSGMNKK86QXVDTYW677FG27DP20E8XY3M6FQD53NDJ1WWES91401MV1A3VXVPGC76GZVDD62W3WTJ1YMKHTTA3MRXX3VEAAH3XTKDN1ER7X6CZPMYTF8VK735VP2B2TZGTF28TTW4FZS32SBS64APCDF6SZQ427N5538TJC7SRE71YSP5ET8GS904002",        }, @@ -247,7 +247,7 @@ test("withdrawal selection bug repro", (t) => {      },      {        denomPub: { -        cipher: 1, +        cipher: DenomKeyType.Rsa,          rsa_public_key:            "040000ZC0G60E9QQ5PD81TSDWD9GV5Y6P8Z05NSPA696DP07NGQQVSRQXBA76Q6PRB0YFX295RG4MTQJXAZZ860ET307HSC2X37XAVGQXRVB8Q4F1V7NP5ZEVKTX75DZK1QRAVHEZGQYKSSH6DBCJNQF6V9WNQF3GEYVA4KCBHA7JF772KHXM9642C28Z0AS4XXXV2PABAN5C8CHYD5H7JDFNK3920W5Q69X0BS84XZ4RE2PW6HM1WZ6KGZ3MKWWWCPKQ1FSFABRBWKAB09PF563BEBXKY6M38QETPH5EDWGANHD0SC3QV0WXYVB7BNHNNQ0J5BNV56K563SYHM4E5ND260YRJSYA1GN5YSW2B1J5T1A1EBNYF2DN6JNJKWXWEQ42G5YS17ZSZ5EWDRA9QKV8EGTCNAD04002",        }, @@ -301,7 +301,7 @@ test("withdrawal selection bug repro", (t) => {      },      {        denomPub: { -        cipher: 1, +        cipher: DenomKeyType.Rsa,          rsa_public_key:            "040000ZSK2PMVY6E3NBQ52KXMW029M60F4BWYTDS0FZSD0PE53CNZ9H6TM3GQK1WRTEKQ5GRWJ1J9DY6Y42SP47QVT1XD1G0W05SQ5F3F7P5KSWR0FJBJ9NZBXQEVN8Q4JRC94X3JJ3XV3KBYTZ2HTDFV28C3H2SRR0XGNZB4FY85NDZF1G4AEYJJ9QB3C0V8H70YB8RV3FKTNH7XS4K4HFNZHJ5H9VMX5SM9Z2DX37HA5WFH0E2MJBVVF2BWWA5M0HPPSB365RAE2AMD42Q65A96WD80X27SB2ZNQZ8WX0K13FWF85GZ6YNYAJGE1KGN06JDEKE9QD68Z651D7XE8V6664TVVC8M68S7WD0DSXMJQKQ0BNJXNDE29Q7MRX6DA3RW0PZ44B3TKRK0294FPVZTNSTA6XF04002",        }, diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index 79220089b..731e9b3aa 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -43,6 +43,7 @@ import {    DenomKeyType,    LibtoolVersion,    UnblindedSignature, +  ExchangeWithdrawRequest,  } from "@gnu-taler/taler-util";  import {    CoinRecord, @@ -497,9 +498,8 @@ async function processPlanchetExchangeRequest(          `processing planchet #${coinIdx} in withdrawal ${withdrawalGroup.withdrawalGroupId}`,        ); -      const reqBody: any = { +      const reqBody: ExchangeWithdrawRequest = {          denom_pub_hash: planchet.denomPubHash, -        reserve_pub: planchet.reservePub,          reserve_sig: planchet.withdrawSig,          coin_ev: planchet.coinEv,        }; @@ -580,28 +580,12 @@ async function processPlanchetVerifyAndStoreCoin(    const { planchet, exchangeBaseUrl } = d;    const planchetDenomPub = planchet.denomPub; -  if ( -    planchetDenomPub.cipher !== DenomKeyType.Rsa && -    planchetDenomPub.cipher !== DenomKeyType.LegacyRsa -  ) { +  if (planchetDenomPub.cipher !== DenomKeyType.Rsa) {      throw Error(`cipher (${planchetDenomPub.cipher}) not supported`);    }    let evSig = resp.ev_sig; -  if (typeof resp.ev_sig === "string") { -    evSig = { -      cipher: DenomKeyType.LegacyRsa, -      blinded_rsa_signature: resp.ev_sig, -    }; -  } else { -    evSig = resp.ev_sig; -  } -  if ( -    !( -      evSig.cipher === DenomKeyType.Rsa || -      evSig.cipher === DenomKeyType.LegacyRsa -    ) -  ) { +  if (!(evSig.cipher === DenomKeyType.Rsa)) {      throw Error("unsupported cipher");    } @@ -639,10 +623,7 @@ async function processPlanchetVerifyAndStoreCoin(    }    let denomSig: UnblindedSignature; -  if ( -    planchet.denomPub.cipher === DenomKeyType.LegacyRsa || -    planchet.denomPub.cipher === DenomKeyType.Rsa -  ) { +  if (planchet.denomPub.cipher === DenomKeyType.Rsa) {      denomSig = {        cipher: planchet.denomPub.cipher,        rsa_signature: denomSigRsa, diff --git a/packages/taler-wallet-core/src/util/coinSelection.test.ts b/packages/taler-wallet-core/src/util/coinSelection.test.ts index 49f8d1635..1675a9a35 100644 --- a/packages/taler-wallet-core/src/util/coinSelection.test.ts +++ b/packages/taler-wallet-core/src/util/coinSelection.test.ts @@ -18,7 +18,7 @@   * Imports.   */  import test from "ava"; -import { AmountJson, Amounts } from "@gnu-taler/taler-util"; +import { AmountJson, Amounts, DenomKeyType } from "@gnu-taler/taler-util";  import { AvailableCoinInfo, selectPayCoins } from "./coinSelection.js";  function a(x: string): AmountJson { @@ -34,7 +34,7 @@ function fakeAci(current: string, feeDeposit: string): AvailableCoinInfo {      availableAmount: a(current),      coinPub: "foobar",      denomPub: { -      cipher: 1, +      cipher: DenomKeyType.Rsa,        rsa_public_key: "foobar",      },      feeDeposit: a(feeDeposit), @@ -47,7 +47,7 @@ test("it should be able to pay if merchant takes the fees", (t) => {      fakeAci("EUR:1.0", "EUR:0.1"),      fakeAci("EUR:1.0", "EUR:0.0"),    ]; -  acis.forEach((x, i) => x.coinPub = String(i)); +  acis.forEach((x, i) => (x.coinPub = String(i)));    const res = selectPayCoins({      candidates: { @@ -75,7 +75,7 @@ test("it should take the last two coins if it pays less fees", (t) => {      // Merchant covers the fee, this one shouldn't be used      fakeAci("EUR:1.0", "EUR:0.0"),    ]; -  acis.forEach((x, i) => x.coinPub = String(i)); +  acis.forEach((x, i) => (x.coinPub = String(i)));    const res = selectPayCoins({      candidates: { @@ -102,8 +102,8 @@ test("it should take the last coins if the merchant doest not take all the fee",      fakeAci("EUR:1.0", "EUR:0.5"),      // this coin should be selected instead of previous one with fee      fakeAci("EUR:1.0", "EUR:0.0"), -  ] -  acis.forEach((x, i) => x.coinPub = String(i)); +  ]; +  acis.forEach((x, i) => (x.coinPub = String(i)));    const res = selectPayCoins({      candidates: { @@ -221,7 +221,7 @@ test("it should use the coins that spent less relative fee", (t) => {      fakeAci("EUR:0.05", "EUR:0.05"),      fakeAci("EUR:0.05", "EUR:0.05"),    ]; -  acis.forEach((x, i) => x.coinPub = String(i)); +  acis.forEach((x, i) => (x.coinPub = String(i)));    const res = selectPayCoins({      candidates: {  | 
