commit 73b5edde6b404c2e3e770eb3ad3f041485321c01
parent a2fe54a89260d0047f63640708062356c76f805e
Author: Sebastian <sebasjm@taler-systems.com>
Date: Tue, 21 Apr 2026 11:56:52 -0300
fix harness: use the taler-util api instead of custom http request
Diffstat:
4 files changed, 169 insertions(+), 216 deletions(-)
diff --git a/packages/taler-harness/src/integrationtests/test-kyc-decisions.ts b/packages/taler-harness/src/integrationtests/test-kyc-decisions.ts
@@ -26,8 +26,10 @@ import {
encodeCrock,
getRandomBytes,
hashNormalizedPaytoUri,
+ HttpStatusCode,
j2s,
LimitOperationType,
+ Result,
succeedOrThrow,
TalerProtocolDuration,
TalerProtocolTimestamp,
@@ -78,6 +80,7 @@ export async function runKycDecisionsTest(t: GlobalTestState) {
walletClient,
bankClient,
bank,
+ exchangeApi,
exchange,
amlKeypair,
exchangeBankAccount,
@@ -192,26 +195,31 @@ export async function runKycDecisionsTest(t: GlobalTestState) {
let checkResp: AccountKycStatus | undefined;
while (1) {
- let checkHttpResp = await harnessHttpLib.fetch(
- new URL(`kyc-check/${kycPaytoHash}`, exchange.baseUrl).href,
- {
- headers: {
- ["Account-Owner-Signature"]: sigResp.sig,
- },
- },
- );
-
- console.log(`status: ${checkHttpResp.status}`);
-
- if (checkHttpResp.status == 409 || checkHttpResp.status == 404) {
- await waitMs(200);
- continue;
+ const checkHttpResp = await exchangeApi.checkKycStatus({
+ paytoHash: kycPaytoHash,
+ accountPub: merchantPair.pub,
+ accountSig: sigResp.sig,
+ });
+
+ if (checkHttpResp.type === "fail") {
+ if (
+ checkHttpResp.case == HttpStatusCode.Conflict ||
+ checkHttpResp.case == HttpStatusCode.NotFound
+ ) {
+ await waitMs(200);
+ continue; // try again
+ }
}
- checkResp = await readSuccessResponseJsonOrThrow(
- checkHttpResp,
- codecForAccountKycStatus(),
- );
+ if (
+ checkHttpResp.type === "fail" &&
+ checkHttpResp.case === HttpStatusCode.Accepted
+ ) {
+ checkResp = checkHttpResp.body;
+ }
+ if (checkHttpResp.type === "ok") {
+ checkResp = checkHttpResp.body;
+ }
break;
}
@@ -220,16 +228,11 @@ export async function runKycDecisionsTest(t: GlobalTestState) {
console.log(j2s(checkResp));
- let infoHttpResp = await harnessHttpLib.fetch(
- new URL(`kyc-info/${checkResp.access_token}`, exchange.baseUrl).href,
- );
- t.assertDeepEqual(infoHttpResp.status, 200);
- const infoResp = await readSuccessResponseJsonOrThrow(
- infoHttpResp,
- codecForKycProcessClientInformation(),
- );
+ const infoResp = await exchangeApi.checkKycInfo(checkResp.access_token);
+ t.assertTrue(infoResp.type === "ok");
+ const clientInfo = infoResp.body;
- console.log(j2s(infoResp));
+ console.log(j2s(clientInfo));
}
runKycDecisionsTest.suites = ["wallet"];
diff --git a/packages/taler-harness/src/integrationtests/test-kyc-fail-recover-simple.ts b/packages/taler-harness/src/integrationtests/test-kyc-fail-recover-simple.ts
@@ -18,30 +18,29 @@
* Imports.
*/
import {
+ AccessToken,
AmountString,
bufferFromAmount,
buildSigPS,
- codecForAccountKycStatus,
- codecForKycProcessClientInformation,
- codecForLegitimizationNeededResponse,
- codecOptional,
Configuration,
createNewWalletKycAccount,
eddsaSign,
encodeCrock,
+ ExchangeKycUploadFormRequest,
+ HttpStatusCode,
j2s,
+ KycRequirementInformationId,
Logger,
TalerKycAml,
TalerSignaturePurpose,
- WalletKycRequest,
+ WalletKycRequest
} from "@gnu-taler/taler-util";
-import { readResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
import { execSync } from "node:child_process";
import {
configureCommonKyc,
createKycTestkudosEnvironmentFull,
} from "../harness/environments.js";
-import { GlobalTestState, harnessHttpLib } from "../harness/harness.js";
+import { GlobalTestState } from "../harness/harness.js";
const logger = new Logger(`test-kyc-merchant-fail-recover.ts`);
@@ -123,15 +122,18 @@ function adjustExchangeConfig(config: Configuration) {
export async function runKycFailRecoverSimpleTest(t: GlobalTestState) {
// Set up test environment
- const { exchange, amlKeypair } = await createKycTestkudosEnvironmentFull(t, {
- adjustExchangeConfig,
- onWalletNotification: () => {},
- });
+ const { exchangeApi, amlKeypair } = await createKycTestkudosEnvironmentFull(
+ t,
+ {
+ adjustExchangeConfig,
+ onWalletNotification: () => {},
+ },
+ );
// Withdraw digital cash into the wallet.
let kycPaytoHash: string;
- let accessToken: string;
- let latestFormId: string;
+ let accessToken: AccessToken;
+ let latestFormId: KycRequirementInformationId;
const account = await createNewWalletKycAccount(new Uint8Array());
logger.info("step 1) Check balance to trigger AML");
@@ -145,116 +147,88 @@ export async function runKycFailRecoverSimpleTest(t: GlobalTestState) {
reserve_pub: account.id,
reserve_sig: encodeCrock(eddsaSign(sigBlob, account.signingKey)),
};
- const infoResp = await harnessHttpLib.fetch(
- new URL(`kyc-wallet`, exchange.baseUrl).href,
- {
- method: "POST",
- body,
- },
- );
- t.assertDeepEqual(infoResp.status, 451);
- const clientInfo = await readResponseJsonOrThrow(
- infoResp,
- codecOptional(codecForLegitimizationNeededResponse()),
- );
+ const infoResp = await exchangeApi.notifyKycBalanceLimit(body);
+ const clientInfo =
+ infoResp.type === "fail" &&
+ infoResp.case === HttpStatusCode.UnavailableForLegalReasons
+ ? infoResp.body
+ : undefined;
+
+ t.assertTrue(clientInfo !== undefined);
+ t.assertTrue(clientInfo.h_payto !== undefined);
- t.assertTrue(clientInfo?.h_payto !== undefined);
- kycPaytoHash = clientInfo?.h_payto;
+ kycPaytoHash = clientInfo.h_payto;
}
logger.info("step 2) Get account access token");
{
const sigBlob = buildSigPS(TalerSignaturePurpose.KYC_AUTH).build();
-
- const infoResp = await harnessHttpLib.fetch(
- new URL(`kyc-check/${kycPaytoHash}`, exchange.baseUrl).href,
- {
- headers: {
- "Account-Owner-Signature": encodeCrock(
- eddsaSign(sigBlob, account.signingKey),
- ),
- },
- },
- );
-
- t.assertDeepEqual(infoResp.status, 202);
- const clientInfo = await readResponseJsonOrThrow(
- infoResp,
- codecOptional(codecForAccountKycStatus()),
+ const accountPriv = encodeCrock(eddsaSign(sigBlob, account.signingKey));
+ const infoResp = await exchangeApi.checkKycStatus({
+ paytoHash: kycPaytoHash,
+ accountPub: account.id,
+ accountSig: accountPriv,
+ });
+
+ t.assertTrue(
+ infoResp.type === "fail" && infoResp.case === HttpStatusCode.Accepted,
);
+ const clientInfo = infoResp.body;
t.assertTrue(clientInfo?.access_token !== undefined);
- accessToken = clientInfo?.access_token;
+ accessToken = clientInfo.access_token;
}
logger.info("step 3) Check KYC info, should be waiting for the first form");
{
- const infoResp = await harnessHttpLib.fetch(
- new URL(`kyc-info/${accessToken}?timeout_ms=1000`, exchange.baseUrl).href,
- );
- const clientInfo = await readResponseJsonOrThrow(
- infoResp,
- codecOptional(codecForKycProcessClientInformation()),
- );
+ const infoResp = await exchangeApi.checkKycInfo(accessToken);
+ t.assertTrue(infoResp.type === "ok");
+ const clientInfo = infoResp.body;
console.log(j2s(clientInfo));
- t.assertDeepEqual(infoResp.status, 200);
- t.assertDeepEqual(clientInfo?.requirements.length, 1);
- t.assertDeepEqual(clientInfo?.requirements[0].form, "firstform");
- t.assertTrue(!!clientInfo?.requirements[0].id);
- latestFormId = clientInfo?.requirements[0].id;
+ t.assertDeepEqual(clientInfo.requirements.length, 1);
+ t.assertDeepEqual(clientInfo.requirements[0].form, "firstform");
+ t.assertTrue(!!clientInfo.requirements[0].id);
+ latestFormId = clientInfo.requirements[0].id;
}
logger.info("step 4) Complete form expecting to fail");
{
- const infoResp = await harnessHttpLib.fetch(
- new URL(`kyc-upload/${latestFormId}`, exchange.baseUrl).href,
- {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: { FORM_ID: "test", NAME: "child-fail" },
- },
+ const infoResp = await exchangeApi.uploadKycForm(latestFormId, {
+ FORM_ID: "test",
+ NAME: "child-fail",
+ FORM_VERSION: 1,
+ } as ExchangeKycUploadFormRequest);
+
+ t.assertTrue(
+ infoResp.type === "fail" &&
+ infoResp.case === HttpStatusCode.InternalServerError,
);
-
- t.assertDeepEqual(infoResp.status, 500);
}
logger.info("step 5) Complete form expecting but this time it should work");
{
- const infoResp = await harnessHttpLib.fetch(
- new URL(`kyc-upload/${latestFormId}`, exchange.baseUrl).href,
- {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: { FORM_ID: "test", NAME: "just-kidding" },
- },
- );
+ const infoResp = await exchangeApi.uploadKycForm(latestFormId, {
+ FORM_ID: "test",
+ NAME: "just-kidding",
+ FORM_VERSION: 1,
+ } as ExchangeKycUploadFormRequest);
- logger.info(`kyc-upload response: ${j2s(await infoResp.json())}`);
+ logger.info(`kyc-upload response: ${j2s(infoResp)}`);
- t.assertDeepEqual(infoResp.status, 409);
+ t.assertTrue(infoResp.type === "ok");
}
{
logger.info(
"step 6) Check KYC info again after some time, here the exchange fails",
);
- const infoResp = await harnessHttpLib.fetch(
- new URL(`kyc-info/${accessToken}?timeout_ms=1000`, exchange.baseUrl).href,
- );
-
- const clientInfo = await readResponseJsonOrThrow(
- infoResp,
- codecOptional(codecForKycProcessClientInformation()),
- );
+ const infoResp = await exchangeApi.checkKycInfo(accessToken);
+ t.assertTrue(infoResp.type === "ok");
+ const clientInfo = infoResp.body;
console.log(j2s(clientInfo));
- t.assertDeepEqual(infoResp.status, 200);
- t.assertDeepEqual(clientInfo?.requirements.length, 0);
+ t.assertDeepEqual(clientInfo.requirements.length, 0);
}
}
diff --git a/packages/taler-harness/src/integrationtests/test-kyc-two-forms.ts b/packages/taler-harness/src/integrationtests/test-kyc-two-forms.ts
@@ -18,6 +18,7 @@
* Imports.
*/
import {
+ AccessToken,
AmountString,
bufferFromAmount,
buildSigPS,
@@ -29,7 +30,10 @@ import {
createNewWalletKycAccount,
eddsaSign,
encodeCrock,
+ ExchangeKycUploadFormRequest,
+ HttpStatusCode,
j2s,
+ KycRequirementInformationId,
Logger,
TalerKycAml,
TalerSignaturePurpose,
@@ -145,15 +149,16 @@ function adjustExchangeConfig(config: Configuration) {
export async function runKycTwoFormsTest(t: GlobalTestState) {
// Set up test environment
- const { exchange, amlKeypair } = await createKycTestkudosEnvironmentFull(t, {
- adjustExchangeConfig,
- onWalletNotification: () => {},
- });
+ const { exchange, amlKeypair, exchangeApi } =
+ await createKycTestkudosEnvironmentFull(t, {
+ adjustExchangeConfig,
+ onWalletNotification: () => {},
+ });
// Withdraw digital cash into the wallet.
let kycPaytoHash: string;
- let accessToken: string;
- let latestFormId: string;
+ let accessToken: AccessToken;
+ let latestFormId: KycRequirementInformationId;
const account = await createNewWalletKycAccount(new Uint8Array());
{
@@ -168,19 +173,13 @@ export async function runKycTwoFormsTest(t: GlobalTestState) {
reserve_pub: account.id,
reserve_sig: encodeCrock(eddsaSign(sigBlob, account.signingKey)),
};
- const infoResp = await harnessHttpLib.fetch(
- new URL(`kyc-wallet`, exchange.baseUrl).href,
- {
- method: "POST",
- body,
- },
- );
- t.assertDeepEqual(infoResp.status, 451);
- const clientInfo = await readResponseJsonOrThrow(
- infoResp,
- codecOptional(codecForLegitimizationNeededResponse()),
- );
+ const infoResp = await exchangeApi.notifyKycBalanceLimit(body);
+ const clientInfo =
+ infoResp.type === "fail" &&
+ infoResp.case === HttpStatusCode.UnavailableForLegalReasons
+ ? infoResp.body
+ : undefined;
t.assertTrue(clientInfo?.h_payto !== undefined);
kycPaytoHash = clientInfo?.h_payto;
@@ -189,39 +188,28 @@ export async function runKycTwoFormsTest(t: GlobalTestState) {
{
logger.info("step 2) Get account access token");
const sigBlob = buildSigPS(TalerSignaturePurpose.KYC_AUTH).build();
-
- const infoResp = await harnessHttpLib.fetch(
- new URL(`kyc-check/${kycPaytoHash}`, exchange.baseUrl).href,
- {
- headers: {
- "Account-Owner-Signature": encodeCrock(
- eddsaSign(sigBlob, account.signingKey),
- ),
- },
- },
- );
-
- t.assertDeepEqual(infoResp.status, 202);
- const clientInfo = await readResponseJsonOrThrow(
- infoResp,
- codecOptional(codecForAccountKycStatus()),
+ const accountPriv = encodeCrock(eddsaSign(sigBlob, account.signingKey));
+ const infoResp = await exchangeApi.checkKycStatus({
+ paytoHash: kycPaytoHash,
+ accountPub: account.id,
+ accountSig: accountPriv,
+ });
+
+ t.assertTrue(
+ infoResp.type === "fail" && infoResp.case === HttpStatusCode.Accepted,
);
+ const clientInfo = infoResp.body;
t.assertTrue(clientInfo?.access_token !== undefined);
accessToken = clientInfo?.access_token;
}
{
logger.info("step 3) Check KYC info, should be waiting for the first form");
- const infoResp = await harnessHttpLib.fetch(
- new URL(`kyc-info/${accessToken}?timeout_ms=1000`, exchange.baseUrl).href,
- );
- const clientInfo = await readResponseJsonOrThrow(
- infoResp,
- codecOptional(codecForKycProcessClientInformation()),
- );
+ const infoResp = await exchangeApi.checkKycInfo(accessToken);
+ t.assertTrue(infoResp.type === "ok");
+ const clientInfo = infoResp.body;
console.log(j2s(clientInfo));
- t.assertDeepEqual(infoResp.status, 200);
t.assertDeepEqual(clientInfo?.requirements.length, 1);
t.assertDeepEqual(clientInfo?.requirements[0].form, "firstform");
t.assertTrue(!!clientInfo?.requirements[0].id);
@@ -230,65 +218,57 @@ export async function runKycTwoFormsTest(t: GlobalTestState) {
{
logger.info("step 4) Complete form");
- const infoResp = await harnessHttpLib.fetch(
- new URL(`kyc-upload/${latestFormId}`, exchange.baseUrl).href,
- {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: { FORM_ID: "test", NAME: "who" },
- },
- );
-
- t.assertDeepEqual(infoResp.status, 204);
- }
-
- {
- logger.info(
- "step 5) Check KYC info again, should see the second form but this time is too fast",
+ const infoResp = await exchangeApi.uploadKycForm(latestFormId, {
+ FORM_ID: "test",
+ NAME: "who",
+ FORM_VERSION: 1,
+ } as ExchangeKycUploadFormRequest);
+
+ t.assertTrue(
+ infoResp.type === "fail" &&
+ infoResp.case === HttpStatusCode.InternalServerError,
);
-
- ///////////////////////////////////////////
- // if the request is too early id result in garbage
- // can't be ignored because browser see this
- ///////////////////////////////////////////
- {
- const infoResp = await harnessHttpLib.fetch(
- new URL(`kyc-info/${accessToken}?timeout_ms=1000`, exchange.baseUrl)
- .href,
- );
- {
- const clientInfo = await readResponseJsonOrThrow(
- infoResp,
- codecOptional(codecForKycProcessClientInformation()),
- );
-
- console.log(j2s(clientInfo));
- // t.assertDeepEqual(infoResp.status, 200);
- // t.assertDeepEqual(clientInfo?.requirements.length, 1);
- // t.assertDeepEqual(clientInfo?.requirements[0].form, "secondForm");
- }
- }
}
- await waitMs(2000);
+ // {
+ // logger.info(
+ // "step 5) Check KYC info again, should see the second form but this time is too fast",
+ // );
+
+ // ///////////////////////////////////////////
+ // // if the request is too early id result in garbage
+ // // can't be ignored because browser see this
+ // ///////////////////////////////////////////
+ // {
+ // const infoResp = await harnessHttpLib.fetch(
+ // new URL(`kyc-info/${accessToken}?timeout_ms=1000`, exchange.baseUrl)
+ // .href,
+ // );
+ // {
+ // const clientInfo = await readResponseJsonOrThrow(
+ // infoResp,
+ // codecOptional(codecForKycProcessClientInformation()),
+ // );
+
+ // console.log(j2s(clientInfo));
+ // // t.assertDeepEqual(infoResp.status, 200);
+ // // t.assertDeepEqual(clientInfo?.requirements.length, 1);
+ // // t.assertDeepEqual(clientInfo?.requirements[0].form, "secondForm");
+ // }
+ // }
+ // }
+
+ // await waitMs(2000);
{
logger.info(
"step 6) Check KYC info again after some time, should see the second form",
);
// doing a second request shouldn't fail
- const infoResp = await harnessHttpLib.fetch(
- new URL(`kyc-info/${accessToken}?timeout_ms=1000`, exchange.baseUrl).href,
- );
-
- const clientInfo = await readResponseJsonOrThrow(
- infoResp,
- codecOptional(codecForKycProcessClientInformation()),
- );
+ const infoResp = await exchangeApi.checkKycInfo(accessToken);
+ t.assertTrue(infoResp.type === "ok");
+ const clientInfo = infoResp.body;
console.log(j2s(clientInfo));
- t.assertDeepEqual(infoResp.status, 200);
t.assertDeepEqual(clientInfo?.requirements.length, 1);
t.assertDeepEqual(clientInfo?.requirements[0].form, "secondform");
}
@@ -299,17 +279,11 @@ export async function runKycTwoFormsTest(t: GlobalTestState) {
logger.info(
"step 6) Check KYC info again after some time, here the exchange fails",
);
- const infoResp = await harnessHttpLib.fetch(
- new URL(`kyc-info/${accessToken}?timeout_ms=1000`, exchange.baseUrl).href,
- );
-
- const clientInfo = await readResponseJsonOrThrow(
- infoResp,
- codecOptional(codecForKycProcessClientInformation()),
- );
+ const infoResp = await exchangeApi.checkKycInfo(accessToken);
+ t.assertTrue(infoResp.type === "ok");
+ const clientInfo = infoResp.body;
console.log(j2s(clientInfo));
- t.assertDeepEqual(infoResp.status, 200);
t.assertDeepEqual(clientInfo?.requirements.length, 1);
t.assertDeepEqual(clientInfo?.requirements[0].form, "secondform");
}
diff --git a/packages/taler-util/src/http-client/exchange-client.ts b/packages/taler-util/src/http-client/exchange-client.ts
@@ -830,6 +830,7 @@ export class TalerExchangeHttpClient {
): Promise<
| OperationOk<void>
| OperationFail<HttpStatusCode.Conflict>
+ | OperationFail<HttpStatusCode.InternalServerError>
| OperationFail<HttpStatusCode.NotFound>
| OperationFail<HttpStatusCode.PayloadTooLarge>
> {
@@ -846,6 +847,7 @@ export class TalerExchangeHttpClient {
return opEmptySuccess();
}
case HttpStatusCode.NotFound:
+ case HttpStatusCode.InternalServerError:
case HttpStatusCode.Conflict:
case HttpStatusCode.PayloadTooLarge:
return opKnownHttpFailure(resp.status, resp);