diff options
Diffstat (limited to 'packages/taler-wallet-core')
3 files changed, 32 insertions, 5 deletions
diff --git a/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts b/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts index da92e83c6..6bace01a3 100644 --- a/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts +++ b/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts @@ -213,7 +213,7 @@ export class CryptoApi { ws.w = null; } } catch (e) { - logger.error(e); + logger.error(e as string); } if (ws.currentWorkItem !== null) { ws.currentWorkItem.reject(e); @@ -379,6 +379,10 @@ export class CryptoApi { return this.doRpc<{ priv: string; pub: string }>("createEddsaKeypair", 1); } + eddsaGetPublic(key: string): Promise<{ priv: string; pub: string }> { + return this.doRpc<{ priv: string; pub: string }>("eddsaGetPublic", 1, key); + } + rsaUnblind(sig: string, bk: string, pk: string): Promise<string> { return this.doRpc<string>("rsaUnblind", 4, sig, bk, pk); } diff --git a/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts b/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts index e1580a7d1..7112964db 100644 --- a/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts +++ b/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts @@ -62,6 +62,7 @@ import { setupRefreshTransferPub, setupTipPlanchet, setupWithdrawPlanchet, + eddsaGetPublic, } from "../talerCrypto.js"; import { randomBytes } from "../primitives/nacl-fast.js"; import { kdf } from "../primitives/kdf.js"; @@ -141,7 +142,7 @@ function timestampRoundedToBuffer(ts: Timestamp): Uint8Array { class SignaturePurposeBuilder { private chunks: Uint8Array[] = []; - constructor(private purposeNum: number) {} + constructor(private purposeNum: number) { } put(bytes: Uint8Array): SignaturePurposeBuilder { this.chunks.push(Uint8Array.from(bytes)); @@ -170,7 +171,6 @@ class SignaturePurposeBuilder { function buildSigPS(purposeNum: number): SignaturePurposeBuilder { return new SignaturePurposeBuilder(purposeNum); } - export class CryptoImplementation { static enableTracing = false; @@ -361,6 +361,13 @@ export class CryptoImplementation { }; } + eddsaGetPublic(key: string): { priv: string; pub: string } { + return { + priv: key, + pub: encodeCrock(eddsaGetPublic(decodeCrock(key))) + } + } + /** * Unblind a blindly signed value. */ diff --git a/packages/taler-wallet-core/src/operations/pay.ts b/packages/taler-wallet-core/src/operations/pay.ts index 9a7b0d069..970aa46ff 100644 --- a/packages/taler-wallet-core/src/operations/pay.ts +++ b/packages/taler-wallet-core/src/operations/pay.ts @@ -875,7 +875,9 @@ async function startDownloadProposal( orderId: string, sessionId: string | undefined, claimToken: string | undefined, + noncePriv: string | undefined, ): Promise<string> { + const oldProposal = await ws.db .mktx((x) => ({ proposals: x.proposals })) .runReadOnly(async (tx) => { @@ -884,12 +886,20 @@ async function startDownloadProposal( orderId, ]); }); - if (oldProposal) { + + /** + * If we have already claimed this proposal with the same sessionId + * nonce and claim token, reuse it. + */ + if (oldProposal && + oldProposal.downloadSessionId === sessionId && + oldProposal.noncePriv === noncePriv && + oldProposal.claimToken === claimToken) { await processDownloadProposal(ws, oldProposal.proposalId); return oldProposal.proposalId; } - const { priv, pub } = await ws.cryptoApi.createEddsaKeypair(); + const { priv, pub } = await (noncePriv ? ws.cryptoApi.eddsaGetPublic(noncePriv) : ws.cryptoApi.createEddsaKeypair()); const proposalId = encodeCrock(getRandomBytes(32)); const proposalRecord: ProposalRecord = { @@ -1405,6 +1415,7 @@ export async function checkPaymentByProposalId( status: PreparePayResultType.InsufficientBalance, contractTerms: d.contractTermsRaw, proposalId: proposal.proposalId, + noncePriv: proposal.noncePriv, amountRaw: Amounts.stringify(d.contractData.amount), }; } @@ -1417,6 +1428,7 @@ export async function checkPaymentByProposalId( status: PreparePayResultType.PaymentPossible, contractTerms: d.contractTermsRaw, proposalId: proposal.proposalId, + noncePriv: proposal.noncePriv, amountEffective: Amounts.stringify(totalCost), amountRaw: Amounts.stringify(res.paymentAmount), contractTermsHash: d.contractData.contractTermsHash, @@ -1453,6 +1465,7 @@ export async function checkPaymentByProposalId( amountRaw: Amounts.stringify(purchase.download.contractData.amount), amountEffective: Amounts.stringify(purchase.totalPayCost), proposalId, + noncePriv: proposal.noncePriv, }; } else if (!purchase.timestampFirstSuccessfulPay) { return { @@ -1463,6 +1476,7 @@ export async function checkPaymentByProposalId( amountRaw: Amounts.stringify(purchase.download.contractData.amount), amountEffective: Amounts.stringify(purchase.totalPayCost), proposalId, + noncePriv: proposal.noncePriv, }; } else { const paid = !purchase.paymentSubmitPending; @@ -1475,6 +1489,7 @@ export async function checkPaymentByProposalId( amountEffective: Amounts.stringify(purchase.totalPayCost), ...(paid ? { nextUrl: purchase.download.contractData.orderId } : {}), proposalId, + noncePriv: proposal.noncePriv, }; } } @@ -1507,6 +1522,7 @@ export async function preparePayForUri( uriResult.orderId, uriResult.sessionId, uriResult.claimToken, + uriResult.noncePriv, ); return checkPaymentByProposalId(ws, proposalId, uriResult.sessionId); |