diff options
Diffstat (limited to 'packages/taler-wallet-core/src/operations/exchanges.ts')
-rw-r--r-- | packages/taler-wallet-core/src/operations/exchanges.ts | 170 |
1 files changed, 76 insertions, 94 deletions
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts index 8bf70fa27..c6b46e360 100644 --- a/packages/taler-wallet-core/src/operations/exchanges.ts +++ b/packages/taler-wallet-core/src/operations/exchanges.ts @@ -19,12 +19,14 @@ */ import { AbsoluteTime, + AccountInfo, Amounts, CancellationToken, canonicalizeBaseUrl, codecForExchangeKeysJson, - codecForExchangeWireJson, + DenomGroup, DenominationPubKey, + DenomKeyType, Duration, durationFromSpec, encodeCrock, @@ -51,6 +53,7 @@ import { URL, WireFee, WireFeeMap, + WireFeesJson, WireInfo, } from "@gnu-taler/taler-util"; import { @@ -84,43 +87,6 @@ import { const logger = new Logger("exchanges.ts"); -function denominationRecordFromKeys( - exchangeBaseUrl: string, - exchangeMasterPub: string, - listIssueDate: TalerProtocolTimestamp, - denomIn: ExchangeDenomination, -): DenominationRecord { - let denomPub: DenominationPubKey; - denomPub = denomIn.denom_pub; - const denomPubHash = encodeCrock(hashDenomPub(denomPub)); - const value = Amounts.parseOrThrow(denomIn.value); - const d: DenominationRecord = { - denomPub, - denomPubHash, - exchangeBaseUrl, - exchangeMasterPub, - fees: { - feeDeposit: Amounts.stringify(denomIn.fee_deposit), - feeRefresh: Amounts.stringify(denomIn.fee_refresh), - feeRefund: Amounts.stringify(denomIn.fee_refund), - feeWithdraw: Amounts.stringify(denomIn.fee_withdraw), - }, - isOffered: true, - isRevoked: false, - masterSig: denomIn.master_sig, - stampExpireDeposit: denomIn.stamp_expire_deposit, - stampExpireLegal: denomIn.stamp_expire_legal, - stampExpireWithdraw: denomIn.stamp_expire_withdraw, - stampStart: denomIn.stamp_start, - verificationStatus: DenominationVerificationStatus.Unverified, - amountFrac: value.fraction, - amountVal: value.value, - currency: value.currency, - listIssueDate, - }; - return d; -} - export function getExchangeRequestTimeout(): Duration { return Duration.fromSpec({ seconds: 5, @@ -145,7 +111,7 @@ export async function downloadExchangeWithTermsOfService( Accept: contentType, }; - const resp = await http.get(reqUrl.href, { + const resp = await http.fetch(reqUrl.href, { headers, timeout, }); @@ -241,7 +207,7 @@ export async function acceptExchangeTermsOfService( async function validateWireInfo( ws: InternalWalletState, versionCurrent: number, - wireInfo: ExchangeWireJson, + wireInfo: ExchangeKeysDownloadResult, masterPublicKey: string, ): Promise<WireInfo> { for (const a of wireInfo.accounts) { @@ -267,9 +233,9 @@ async function validateWireInfo( } logger.trace("account validation done"); const feesForType: WireFeeMap = {}; - for (const wireMethod of Object.keys(wireInfo.fees)) { + for (const wireMethod of Object.keys(wireInfo.wireFees)) { const feeList: WireFee[] = []; - for (const x of wireInfo.fees[wireMethod]) { + for (const x of wireInfo.wireFees[wireMethod]) { const startStamp = x.start_date; const endStamp = x.end_date; const fee: WireFee = { @@ -343,7 +309,6 @@ async function validateGlobalFees( } export interface ExchangeInfo { - wire: ExchangeWireJson; keys: ExchangeKeysDownloadResult; } @@ -351,11 +316,6 @@ export async function downloadExchangeInfo( exchangeBaseUrl: string, http: HttpRequestLibrary, ): Promise<ExchangeInfo> { - const wireInfo = await downloadExchangeWireInfo( - exchangeBaseUrl, - http, - Duration.getForever(), - ); const keysInfo = await downloadExchangeKeysInfo( exchangeBaseUrl, http, @@ -363,33 +323,9 @@ export async function downloadExchangeInfo( ); return { keys: keysInfo, - wire: wireInfo, }; } -/** - * Fetch wire information for an exchange. - * - * @param exchangeBaseUrl Exchange base URL, assumed to be already normalized. - */ -async function downloadExchangeWireInfo( - exchangeBaseUrl: string, - http: HttpRequestLibrary, - timeout: Duration, -): Promise<ExchangeWireJson> { - const reqUrl = new URL("wire", exchangeBaseUrl); - - const resp = await http.get(reqUrl.href, { - timeout, - }); - const wireInfo = await readSuccessResponseJsonOrThrow( - resp, - codecForExchangeWireJson(), - ); - - return wireInfo; -} - export async function provideExchangeRecordInTx( ws: InternalWalletState, tx: GetReadWriteAccess<{ @@ -434,6 +370,8 @@ interface ExchangeKeysDownloadResult { recoup: Recoup[]; listIssueDate: TalerProtocolTimestamp; globalFees: GlobalFees[]; + accounts: AccountInfo[]; + wireFees: { [methodName: string]: WireFeesJson[] }; } /** @@ -446,7 +384,7 @@ async function downloadExchangeKeysInfo( ): Promise<ExchangeKeysDownloadResult> { const keysUrl = new URL("keys", baseUrl); - const resp = await http.get(keysUrl.href, { + const resp = await http.fetch(keysUrl.href, { timeout, }); const exchangeKeysJsonUnchecked = await readSuccessResponseJsonOrThrow( @@ -454,7 +392,7 @@ async function downloadExchangeKeysInfo( codecForExchangeKeysJson(), ); - if (exchangeKeysJsonUnchecked.denoms.length === 0) { + if (exchangeKeysJsonUnchecked.denominations.length === 0) { throw TalerError.fromDetail( TalerErrorCode.WALLET_EXCHANGE_DENOMINATIONS_INSUFFICIENT, { @@ -481,23 +419,72 @@ async function downloadExchangeKeysInfo( ); } - const currency = Amounts.parseOrThrow( - exchangeKeysJsonUnchecked.denoms[0].value, - ).currency.toUpperCase(); + const currency = exchangeKeysJsonUnchecked.currency; + + const currentDenominations: DenominationRecord[] = []; + + for (const denomGroup of exchangeKeysJsonUnchecked.denominations) { + switch (denomGroup.cipher) { + case "RSA": + case "RSA+age_restricted": { + let ageMask = 0; + if (denomGroup.cipher === "RSA+age_restricted") { + ageMask = denomGroup.age_mask; + } + for (const denomIn of denomGroup.denoms) { + const denomPub: DenominationPubKey = { + age_mask: ageMask, + cipher: DenomKeyType.Rsa, + rsa_public_key: denomIn.rsa_pub, + }; + const denomPubHash = encodeCrock(hashDenomPub(denomPub)); + const value = Amounts.parseOrThrow(denomGroup.value); + const rec: DenominationRecord = { + denomPub, + denomPubHash, + exchangeBaseUrl: baseUrl, + exchangeMasterPub: exchangeKeysJsonUnchecked.master_public_key, + isOffered: true, + isRevoked: false, + amountFrac: value.fraction, + amountVal: value.value, + currency: value.currency, + stampExpireDeposit: denomIn.stamp_expire_deposit, + stampExpireLegal: denomIn.stamp_expire_legal, + stampExpireWithdraw: denomIn.stamp_expire_withdraw, + stampStart: denomIn.stamp_start, + verificationStatus: DenominationVerificationStatus.Unverified, + masterSig: denomIn.master_sig, + listIssueDate: exchangeKeysJsonUnchecked.list_issue_date, + fees: { + feeDeposit: Amounts.stringify(denomGroup.fee_deposit), + feeRefresh: Amounts.stringify(denomGroup.fee_refresh), + feeRefund: Amounts.stringify(denomGroup.fee_refund), + feeWithdraw: Amounts.stringify(denomGroup.fee_withdraw), + }, + }; + currentDenominations.push(rec); + } + break; + } + case "CS+age_restricted": + case "CS": + logger.warn("Clause-Schnorr denominations not supported"); + continue; + default: + logger.warn( + `denomination type ${(denomGroup as any).cipher} not supported`, + ); + continue; + } + } return { masterPublicKey: exchangeKeysJsonUnchecked.master_public_key, currency, baseUrl: exchangeKeysJsonUnchecked.base_url, auditors: exchangeKeysJsonUnchecked.auditors, - currentDenominations: exchangeKeysJsonUnchecked.denoms.map((d) => - denominationRecordFromKeys( - baseUrl, - exchangeKeysJsonUnchecked.master_public_key, - exchangeKeysJsonUnchecked.list_issue_date, - d, - ), - ), + currentDenominations, protocolVersion: exchangeKeysJsonUnchecked.version, signingKeys: exchangeKeysJsonUnchecked.signkeys, reserveClosingDelay: exchangeKeysJsonUnchecked.reserve_closing_delay, @@ -509,6 +496,8 @@ async function downloadExchangeKeysInfo( recoup: exchangeKeysJsonUnchecked.recoup ?? [], listIssueDate: exchangeKeysJsonUnchecked.list_issue_date, globalFees: exchangeKeysJsonUnchecked.global_fees, + accounts: exchangeKeysJsonUnchecked.accounts, + wireFees: exchangeKeysJsonUnchecked.wire_fees, }; } @@ -654,14 +643,7 @@ export async function updateExchangeFromUrlHandler( } } - logger.trace("updating exchange /wire info"); - const wireInfoDownload = await downloadExchangeWireInfo( - exchangeBaseUrl, - ws.http, - timeout, - ); - - logger.trace("validating exchange /wire info"); + logger.trace("validating exchange wire info"); const version = LibtoolVersion.parseVersion(keysInfo.protocolVersion); if (!version) { @@ -672,7 +654,7 @@ export async function updateExchangeFromUrlHandler( const wireInfo = await validateWireInfo( ws, version.current, - wireInfoDownload, + keysInfo, keysInfo.masterPublicKey, ); |