summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2024-01-30 22:25:54 +0100
committerFlorian Dold <florian@dold.me>2024-01-30 22:25:54 +0100
commitc5f97c8f493b52f9e083548d0ac71592c56a2b79 (patch)
treed45ed40257d77880157a61919140d6e972bc60f1
parentd4429ff5acac01c5a7ef32efa3b3f2402627a71a (diff)
downloadwallet-core-c5f97c8f493b52f9e083548d0ac71592c56a2b79.tar.gz
wallet-core-c5f97c8f493b52f9e083548d0ac71592c56a2b79.tar.bz2
wallet-core-c5f97c8f493b52f9e083548d0ac71592c56a2b79.zip
harness: work on otp test
-rw-r--r--packages/taler-harness/src/integrationtests/test-otp.ts77
-rw-r--r--packages/taler-harness/src/integrationtests/test-payment-template.ts6
-rw-r--r--packages/taler-util/src/MerchantApiClient.ts29
-rw-r--r--packages/taler-util/src/merchant-api-types.ts38
-rw-r--r--packages/taler-util/src/operation.ts26
5 files changed, 152 insertions, 24 deletions
diff --git a/packages/taler-harness/src/integrationtests/test-otp.ts b/packages/taler-harness/src/integrationtests/test-otp.ts
index dd6c45e4c..d4dee12ad 100644
--- a/packages/taler-harness/src/integrationtests/test-otp.ts
+++ b/packages/taler-harness/src/integrationtests/test-otp.ts
@@ -17,14 +17,22 @@
/**
* Imports.
*/
+import {
+ ConfirmPayResultType,
+ Duration,
+ MerchantApiClient,
+ PreparePayResultType,
+ encodeCrock,
+ getRandomBytes,
+ j2s,
+ narrowOpSuccessOrThrow,
+} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { GlobalTestState } from "../harness/harness.js";
import {
createSimpleTestkudosEnvironmentV2,
withdrawViaBankV2,
- makeTestPaymentV2,
} from "../harness/helpers.js";
-import { MerchantApiClient, j2s } from "@gnu-taler/taler-util";
/**
* Run test for basic, bank-integrated withdrawal and payment.
@@ -36,6 +44,71 @@ export async function runOtpTest(t: GlobalTestState) {
await createSimpleTestkudosEnvironmentV2(t);
const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl());
+ const createOtpRes = await merchantClient.createOtpDevice({
+ otp_algorithm: 1,
+ otp_device_description: "Hello",
+ otp_device_id: "mydevice",
+ otp_key: encodeCrock(getRandomBytes(16)),
+ });
+ narrowOpSuccessOrThrow(createOtpRes);
+
+ const createTemplateRes = await merchantClient.createTemplate({
+ template_description: "my template",
+ template_id: "tpl1",
+ otp_id: "mydevice",
+ template_contract: {
+ summary: "test",
+ amount: "TESTKUDOS:1",
+ minimum_age: 0,
+ pay_duration: Duration.toTalerProtocolDuration(
+ Duration.fromSpec({ hours: 1 }),
+ ),
+ },
+ });
+ narrowOpSuccessOrThrow(createTemplateRes);
+
+ const getTemplateResp = await merchantClient.getTemplate("tpl1");
+ narrowOpSuccessOrThrow(getTemplateResp);
+ console.log(`template: ${j2s(getTemplateResp.body)}`);
+
+ const wres = await withdrawViaBankV2(t, {
+ walletClient,
+ bank,
+ exchange,
+ amount: "TESTKUDOS:20",
+ });
+ await wres.withdrawalFinishedCond;
+
+ const preparePayResult = await walletClient.call(
+ WalletApiOperation.PreparePayForTemplate,
+ {
+ talerPayTemplateUri: `taler+http://pay-template/localhost:${merchant.port}/tpl1`,
+ templateParams: {},
+ },
+ );
+
+ console.log(preparePayResult);
+
+ t.assertTrue(
+ preparePayResult.status === PreparePayResultType.PaymentPossible,
+ );
+
+ // Pay for it
+
+ const r2 = await walletClient.call(WalletApiOperation.ConfirmPay, {
+ transactionId: preparePayResult.transactionId,
+ });
+
+ t.assertTrue(r2.type === ConfirmPayResultType.Done);
+
+ const transaction = await walletClient.call(
+ WalletApiOperation.GetTransactionById,
+ {
+ transactionId: preparePayResult.transactionId,
+ },
+ );
+
+ console.log(j2s(transaction));
}
runOtpTest.suites = ["wallet"];
diff --git a/packages/taler-harness/src/integrationtests/test-payment-template.ts b/packages/taler-harness/src/integrationtests/test-payment-template.ts
index e77236a9a..c9f1caacd 100644
--- a/packages/taler-harness/src/integrationtests/test-payment-template.ts
+++ b/packages/taler-harness/src/integrationtests/test-payment-template.ts
@@ -22,6 +22,7 @@ import {
Duration,
MerchantApiClient,
PreparePayResultType,
+ narrowOpSuccessOrThrow,
} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { GlobalTestState } from "../harness/harness.js";
@@ -41,7 +42,7 @@ export async function runPaymentTemplateTest(t: GlobalTestState) {
const merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl());
- await merchantClient.createTemplate({
+ const createTemplateRes = await merchantClient.createTemplate({
template_id: "template1",
template_description: "my test template",
template_contract: {
@@ -54,6 +55,7 @@ export async function runPaymentTemplateTest(t: GlobalTestState) {
summary: "hello, I'm a summary",
},
});
+ narrowOpSuccessOrThrow(createTemplateRes);
// Withdraw digital cash into the wallet.
@@ -84,7 +86,7 @@ export async function runPaymentTemplateTest(t: GlobalTestState) {
// Pay for it
const r2 = await walletClient.call(WalletApiOperation.ConfirmPay, {
- proposalId: preparePayResult.proposalId,
+ transactionId: preparePayResult.transactionId,
});
t.assertTrue(r2.type === ConfirmPayResultType.Done);
diff --git a/packages/taler-util/src/MerchantApiClient.ts b/packages/taler-util/src/MerchantApiClient.ts
index 561226ba9..db1ffef4e 100644
--- a/packages/taler-util/src/MerchantApiClient.ts
+++ b/packages/taler-util/src/MerchantApiClient.ts
@@ -362,8 +362,30 @@ export class MerchantApiClient {
body: req,
headers: this.makeAuthHeader(),
});
- if (resp.status !== 204) {
- throw Error("failed to create template");
+ switch (resp.status) {
+ case HttpStatusCode.Ok:
+ case HttpStatusCode.NoContent:
+ return opEmptySuccess(resp);
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await resp.text());
+ }
+ }
+
+ async getTemplate(templateId: string) {
+ let url = new URL(`private/templates/${templateId}`, this.baseUrl);
+ const resp = await this.httpClient.fetch(url.href, {
+ method: "GET",
+ headers: this.makeAuthHeader(),
+ });
+ switch (resp.status) {
+ case HttpStatusCode.Ok:
+ return opSuccess(resp, codecForAny());
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownFailure(resp, await resp.text());
}
}
@@ -391,7 +413,7 @@ export class MerchantApiClient {
async createOtpDevice(
req: OtpDeviceAddDetails,
): Promise<OperationOk<void> | OperationFail<HttpStatusCode.NotFound>> {
- let url = new URL("private/templates", this.baseUrl);
+ let url = new URL("private/otp-devices", this.baseUrl);
const resp = await this.httpClient.fetch(url.href, {
method: "POST",
body: req,
@@ -399,6 +421,7 @@ export class MerchantApiClient {
});
switch (resp.status) {
case HttpStatusCode.Ok:
+ case HttpStatusCode.NoContent:
return opEmptySuccess(resp);
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
diff --git a/packages/taler-util/src/merchant-api-types.ts b/packages/taler-util/src/merchant-api-types.ts
index 999246597..724e99b55 100644
--- a/packages/taler-util/src/merchant-api-types.ts
+++ b/packages/taler-util/src/merchant-api-types.ts
@@ -25,29 +25,29 @@
* Imports.
*/
import {
- MerchantContractTerms,
- Codec,
- buildCodecForObject,
- codecForString,
- codecOptional,
- codecForConstString,
- codecForBoolean,
- codecForNumber,
- codecForMerchantContractTerms,
- codecForAny,
- buildCodecForUnion,
- AmountString,
AbsoluteTime,
+ AmountString,
+ Codec,
CoinPublicKeyString,
EddsaPublicKeyString,
- codecForAmountString,
+ ExchangeWireAccount,
+ FacadeCredentials,
+ MerchantContractTerms,
TalerProtocolDuration,
- codecForTimestamp,
TalerProtocolTimestamp,
- ExchangeWireAccount,
+ buildCodecForObject,
+ buildCodecForUnion,
+ codecForAmountString,
+ codecForAny,
+ codecForBoolean,
+ codecForConstString,
codecForExchangeWireAccount,
codecForList,
- FacadeCredentials,
+ codecForMerchantContractTerms,
+ codecForNumber,
+ codecForString,
+ codecForTimestamp,
+ codecOptional,
} from "@gnu-taler/taler-util";
export interface MerchantPostOrderRequest {
@@ -345,7 +345,7 @@ export interface MerchantTemplateContractDetails {
// The price is imposed by the merchant and cannot be changed by the customer.
// This parameter is optional.
- amount?: AmountString;
+ amount?: string;
// Minimum age buyer must have (in years). Default is 0.
minimum_age: number;
@@ -369,6 +369,10 @@ export interface MerchantTemplateAddDetails {
// Additional information in a separate template.
template_contract: MerchantTemplateContractDetails;
+
+ // OTP device ID.
+ // This parameter is optional.
+ otp_id?: string;
}
export interface MerchantReserveCreateConfirmation {
diff --git a/packages/taler-util/src/operation.ts b/packages/taler-util/src/operation.ts
index 213bfeecd..a554e1f31 100644
--- a/packages/taler-util/src/operation.ts
+++ b/packages/taler-util/src/operation.ts
@@ -147,6 +147,32 @@ export function opUnknownFailure(resp: HttpResponse, text: string): never {
);
}
+/**
+ * Convenience function to throw an error if the operation is not a success.
+ */
+export function narrowOpSuccessOrThrow<Body, ErrorEnum>(
+ opRes: OperationResult<Body, ErrorEnum>,
+): asserts opRes is OperationOk<Body> {
+ const httpResponse = opRes.httpResp;
+ if (opRes.type !== "ok") {
+ throw TalerError.fromDetail(
+ TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR,
+ {
+ requestUrl: httpResponse.requestUrl,
+ requestMethod: httpResponse.requestMethod,
+ httpStatusCode: httpResponse.status,
+ errorResponse:
+ "detail" in opRes
+ ? opRes.detail
+ : "body" in opRes
+ ? opRes.body
+ : undefined,
+ },
+ `Unexpected HTTP status ${httpResponse.status} in response`,
+ );
+ }
+}
+
export type ResultByMethod<
TT extends object,
p extends keyof TT,