taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit c6d64e20bd90d81504c4e64b01b8c07cf944da9f
parent eeea26dd11a76719b3acec034a613a36cc4b3456
Author: Florian Dold <florian@dold.me>
Date:   Fri, 13 Feb 2026 12:19:43 +0100

util: fix handling of ETag header in kyc-info request

Diffstat:
Mpackages/taler-util/src/http-client/exchange-client.ts | 101+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
1 file changed, 60 insertions(+), 41 deletions(-)

diff --git a/packages/taler-util/src/http-client/exchange-client.ts b/packages/taler-util/src/http-client/exchange-client.ts @@ -114,6 +114,7 @@ import { AmountJson, Amounts, CancellationToken, + Logger, LongpollQueue, PaytoHash, signAmlDecision, @@ -129,6 +130,8 @@ export type TalerExchangeErrorsByMethod2< prop extends keyof TalerExchangeHttpClient, > = FailCasesByMethod<TalerExchangeHttpClient, prop>; +const logger = new Logger("exchange-client.ts"); + export enum TalerExchangeCacheEviction { UPLOAD_KYC_FORM, MAKE_AML_DECISION, @@ -387,13 +390,13 @@ export class TalerExchangeHttpClient { ): Promise< | OperationOk<ExchangeMergeSuccessResponse> | OperationAlternative< - HttpStatusCode.UnavailableForLegalReasons, - LegitimizationNeededResponse - > + HttpStatusCode.UnavailableForLegalReasons, + LegitimizationNeededResponse + > | OperationAlternative< - HttpStatusCode.Conflict, - ExchangeMergeConflictResponse - > + HttpStatusCode.Conflict, + ExchangeMergeConflictResponse + > | OperationFail<HttpStatusCode.Forbidden> | OperationFail<HttpStatusCode.NotFound> | OperationFail<HttpStatusCode.Gone> @@ -440,9 +443,9 @@ export class TalerExchangeHttpClient { | OperationFail<HttpStatusCode.NotFound> | OperationAlternative<HttpStatusCode.Conflict, PurseConflictPartial> | OperationAlternative< - HttpStatusCode.UnavailableForLegalReasons, - LegitimizationNeededResponse - > + HttpStatusCode.UnavailableForLegalReasons, + LegitimizationNeededResponse + > > { const resp = await this.fetch(`reserves/${pursePub}/purse`, { method: "POST", @@ -695,7 +698,9 @@ export class TalerExchangeHttpClient { { method: "GET", headers: { - "If-None-Match": known.length ? known.map(d => `"${d}"`).join(",") : undefined, + "If-None-Match": known.length + ? known.map((d) => `"${d}"`).join(",") + : undefined, }, }, longpoll, @@ -719,6 +724,8 @@ export class TalerExchangeHttpClient { /** * SPA-Specific version of checkKycInfo + * + * FIXME: Unify with checkKycInfo */ async checkKycInfoSpa( token: AccessToken, @@ -740,7 +747,20 @@ export class TalerExchangeHttpClient { // we need to add the etag to the response because the // client needs it to repeat the request and // do the long polling - const etag = resp.headers.get("etag") ?? undefined; + const etagRaw = resp.headers.get("etag") ?? undefined; + let etag: string | undefined; + if ( + etagRaw != null && + etagRaw.startsWith('"') && + etagRaw.endsWith('"') + ) { + etag = etagRaw.substring(1, etagRaw.length - 1); + } else if (etagRaw == null) { + // No ETag, fine. + etag = etagRaw; + } else { + logger.warn(`malformed ETag header in kyc-info response`); + } const body = await readSuccessResponseJsonOrThrow( resp, codecForKycProcessClientInformation(), @@ -805,10 +825,10 @@ export class TalerExchangeHttpClient { body: object = {}, ): Promise< | OperationFail< - | HttpStatusCode.NotFound - | HttpStatusCode.Conflict - | HttpStatusCode.PayloadTooLarge - > + | HttpStatusCode.NotFound + | HttpStatusCode.Conflict + | HttpStatusCode.PayloadTooLarge + > | OperationOk<KycProcessStartInformation> > { const resp = await this.fetch(`kyc-start/${requirement}`, { @@ -867,10 +887,10 @@ export class TalerExchangeHttpClient { ): Promise< | OperationOk<AvailableMeasureSummary> | OperationFail< - | HttpStatusCode.Forbidden - | HttpStatusCode.NotFound - | HttpStatusCode.Conflict - > + | HttpStatusCode.Forbidden + | HttpStatusCode.NotFound + | HttpStatusCode.Conflict + > > { const resp = await this.fetch(`aml/${auth.id}/measures`, { method: "GET", @@ -1052,7 +1072,6 @@ export class TalerExchangeHttpClient { } } - /** * https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-decisions * @@ -1066,10 +1085,10 @@ export class TalerExchangeHttpClient { } = {}, ): Promise< | OperationFail< - | HttpStatusCode.Forbidden - | HttpStatusCode.NotFound - | HttpStatusCode.Conflict - > + | HttpStatusCode.Forbidden + | HttpStatusCode.NotFound + | HttpStatusCode.Conflict + > | OperationOk<AmlDecisionsResponse> > { const url = new URL(`aml/${auth.id}/decisions`, this.baseUrl); @@ -1161,10 +1180,10 @@ export class TalerExchangeHttpClient { ): Promise< | OperationOk<KycAttributes> | OperationFail< - | HttpStatusCode.Forbidden - | HttpStatusCode.NotFound - | HttpStatusCode.Conflict - > + | HttpStatusCode.Forbidden + | HttpStatusCode.NotFound + | HttpStatusCode.Conflict + > > { const url = new URL(`aml/${auth.id}/attributes/${account}`, this.baseUrl); @@ -1193,7 +1212,7 @@ export class TalerExchangeHttpClient { /** * https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-attributes-$H_NORMALIZED_PAYTO - * + * */ async getAmlAttributesForAccountAsPdf( auth: OfficerSession, @@ -1281,10 +1300,10 @@ export class TalerExchangeHttpClient { ): Promise< | OperationOk<ExchangeTransferList> | OperationFail< - | HttpStatusCode.Forbidden - | HttpStatusCode.NotFound - | HttpStatusCode.Conflict - > + | HttpStatusCode.Forbidden + | HttpStatusCode.NotFound + | HttpStatusCode.Conflict + > > { const url = new URL(`aml/${auth.id}/transfers-credit`, this.baseUrl); @@ -1332,10 +1351,10 @@ export class TalerExchangeHttpClient { ): Promise< | OperationOk<ExchangeTransferList> | OperationFail< - | HttpStatusCode.Forbidden - | HttpStatusCode.NotFound - | HttpStatusCode.Conflict - > + | HttpStatusCode.Forbidden + | HttpStatusCode.NotFound + | HttpStatusCode.Conflict + > > { const url = new URL(`aml/${auth.id}/transfers-debit`, this.baseUrl); @@ -1383,10 +1402,10 @@ export class TalerExchangeHttpClient { ): Promise< | OperationOk<ExchangeTransferList> | OperationFail< - | HttpStatusCode.Forbidden - | HttpStatusCode.NotFound - | HttpStatusCode.Conflict - > + | HttpStatusCode.Forbidden + | HttpStatusCode.NotFound + | HttpStatusCode.Conflict + > > { const url = new URL(`aml/${auth.id}/transfers-kycauth`, this.baseUrl);