add merchant instances/auth test case

This commit is contained in:
Florian Dold 2021-03-02 20:03:39 +01:00
parent 98ab998a1e
commit 81be4aacd8
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
4 changed files with 206 additions and 2 deletions

View File

@ -94,6 +94,7 @@ import {
TippingReserveStatus, TippingReserveStatus,
TipCreateConfirmation, TipCreateConfirmation,
TipCreateRequest, TipCreateRequest,
MerchantInstancesResponse,
} from "./merchantApiTypes"; } from "./merchantApiTypes";
import { ApplyRefundResponse } from "@gnu-taler/taler-wallet-core"; import { ApplyRefundResponse } from "@gnu-taler/taler-wallet-core";
import { PendingOperationsResponse } from "@gnu-taler/taler-wallet-core"; import { PendingOperationsResponse } from "@gnu-taler/taler-wallet-core";
@ -1171,6 +1172,40 @@ export interface MerchantServiceInterface {
readonly name: string; readonly name: string;
} }
export class MerchantApiClient {
constructor(
private baseUrl: string,
private auth: MerchantAuthConfiguration,
) {}
async changeAuth(auth: MerchantAuthConfiguration): Promise<void> {
const baseUrl = this.baseUrl;
const url = new URL("private/auth", baseUrl);
await axios.post(url.href, auth, {
headers: this.makeAuthHeader(),
});
}
async getInstances(): Promise<MerchantInstancesResponse> {
const url = new URL("private/instances", this.baseUrl);
const resp = await axios.get(url.href, {
headers: this.makeAuthHeader(),
});
return resp.data;
}
makeAuthHeader(): Record<string, string> {
switch (this.auth.method) {
case "external":
return {};
case "token":
return {
Authorization: `Bearer ${this.auth.token}`,
};
}
}
}
export namespace MerchantPrivateApi { export namespace MerchantPrivateApi {
export async function createOrder( export async function createOrder(
merchantService: MerchantServiceInterface, merchantService: MerchantServiceInterface,
@ -1407,8 +1442,9 @@ export class MerchantService implements MerchantServiceInterface {
} }
console.log("adding instance"); console.log("adding instance");
const url = `http://localhost:${this.merchantConfig.httpPort}/private/instances`; const url = `http://localhost:${this.merchantConfig.httpPort}/private/instances`;
const auth = instanceConfig.auth ?? { method: "external" };
await axios.post(url, { await axios.post(url, {
auth: { method: "external" }, auth,
payto_uris: instanceConfig.paytoUris, payto_uris: instanceConfig.paytoUris,
id: instanceConfig.id, id: instanceConfig.id,
name: instanceConfig.name, name: instanceConfig.name,
@ -1443,8 +1479,13 @@ export class MerchantService implements MerchantServiceInterface {
} }
} }
export interface MerchantAuthConfiguration {
method: "external" | "token";
token?: string;
}
export interface MerchantInstanceConfig { export interface MerchantInstanceConfig {
authToken?: string; auth?: MerchantAuthConfiguration;
id: string; id: string;
name: string; name: string;
paytoUris: string[]; paytoUris: string[];

View File

@ -40,6 +40,7 @@ import {
AmountString, AmountString,
Timestamp, Timestamp,
CoinPublicKeyString, CoinPublicKeyString,
EddsaPublicKeyString,
} from "@gnu-taler/taler-wallet-core"; } from "@gnu-taler/taler-wallet-core";
import { codecForAmountString } from "@gnu-taler/taler-wallet-core/lib/util/amounts"; import { codecForAmountString } from "@gnu-taler/taler-wallet-core/lib/util/amounts";
@ -294,3 +295,25 @@ export interface TipCreateRequest {
// will be included in the tip_token. // will be included in the tip_token.
next_url: string; next_url: string;
} }
export interface MerchantInstancesResponse {
// List of instances that are present in the backend (see Instance)
instances: MerchantInstanceDetail[];
}
export interface MerchantInstanceDetail {
// Merchant name corresponding to this instance.
name: string;
// Merchant instance this response is about ($INSTANCE)
id: string;
// Public key of the merchant/instance, in Crockford Base32 encoding.
merchant_pub: EddsaPublicKeyString;
// List of the payment targets supported by this instance. Clients can
// specify the desired payment target in /order requests. Note that
// front-ends do not have to support wallets selecting payment targets.
payment_targets: string[];
}

View File

@ -0,0 +1,138 @@
/*
This file is part of GNU Taler
(C) 2021 Taler Systems S.A.
GNU Taler is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* Imports.
*/
import { URL } from "@gnu-taler/taler-wallet-core";
import axios from "axios";
import {
ExchangeService,
GlobalTestState,
MerchantApiClient,
MerchantService,
setupDb,
} from "./harness";
/**
* Do basic checks on instance management and authentication.
*/
export async function runMerchantInstancesTest(t: GlobalTestState) {
// Set up test environment
const db = await setupDb(t);
const exchange = ExchangeService.create(t, {
name: "testexchange-1",
currency: "TESTKUDOS",
httpPort: 8081,
database: db.connStr,
});
const merchant = await MerchantService.create(t, {
name: "testmerchant-1",
currency: "TESTKUDOS",
httpPort: 8083,
database: db.connStr,
});
// We add the exchange to the config, but note that the exchange won't be started.
merchant.addExchange(exchange);
await merchant.start();
await merchant.pingUntilAvailable();
// Base URL for the default instance.
const baseUrl = merchant.makeInstanceBaseUrl();
{
const r = await axios.get(new URL("config", baseUrl).href);
console.log(r.data);
t.assertDeepEqual(r.data.currency, "TESTKUDOS");
}
// Instances should initially be empty
{
const r = await axios.get(new URL("private/instances", baseUrl).href);
t.assertDeepEqual(r.data.instances, []);
}
// Add an instance, no auth!
await merchant.addInstance({
id: "default",
name: "Default Instance",
paytoUris: [`payto://x-taler-bank/merchant-default`],
auth: {
method: "external",
},
});
let merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl(), {
method: "external",
});
{
const r = await merchantClient.getInstances();
t.assertDeepEqual(r.instances.length, 1);
}
// Check that a "malformed" bearer Authorization header gets ignored
{
const url = merchant.makeInstanceBaseUrl();
const resp = await axios.get(new URL("private/instances", url).href, {
headers: {
"Authorization": "foo bar-baz",
},
});
t.assertDeepEqual(resp.status, 200);
}
await merchantClient.changeAuth({
method: "token",
token: "secret-token:foobar",
});
// Now this should fail, as we didn't change the auth of the client yet.
const exc = await t.assertThrowsAsync(async () => {
await merchantClient.getInstances();
});
t.assertAxiosError(exc);
t.assertAxiosError(exc.response?.status === 401);
merchantClient = new MerchantApiClient(merchant.makeInstanceBaseUrl(), {
method: "token",
token: "secret-token:foobar",
});
// With the new client auth settings, request should work again.
await merchantClient.getInstances();
// Now, try some variations.
{
const url = merchant.makeInstanceBaseUrl();
const resp = await axios.get(new URL("private/instances", url).href, {
headers: {
// Note the spaces
"Authorization": "Bearer secret-token:foobar",
}
});
t.assertDeepEqual(resp.status, 200);
}
}
runMerchantInstancesTest.suites = ["merchant"];

View File

@ -59,6 +59,7 @@ import { runLibeufinRefundTest } from "./test-libeufin-refund";
import { runLibeufinTutorialTest } from "./test-libeufin-tutorial"; import { runLibeufinTutorialTest } from "./test-libeufin-tutorial";
import { runDepositTest } from "./test-deposit"; import { runDepositTest } from "./test-deposit";
import CancellationToken from "cancellationtoken"; import CancellationToken from "cancellationtoken";
import { runMerchantInstancesTest } from "./test-merchant-instances";
/** /**
* Test runner. * Test runner.
@ -83,6 +84,7 @@ const allTests: TestMainFunction[] = [
runLibeufinTutorialTest, runLibeufinTutorialTest,
runLibeufinRefundTest, runLibeufinRefundTest,
runMerchantExchangeConfusionTest, runMerchantExchangeConfusionTest,
runMerchantInstancesTest,
runMerchantLongpollingTest, runMerchantLongpollingTest,
runMerchantRefundApiTest, runMerchantRefundApiTest,
runPayAbortTest, runPayAbortTest,