summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-03-26 16:54:35 -0300
committerSebastian <sebasjm@gmail.com>2024-03-26 16:54:35 -0300
commitb674422840041f8cdba0ad52be17bd0c527ffecb (patch)
treeed58e348933af7429685e3aaff648c926418d1eb
parentaa33015b1e83885d07beb1220207f0cecd0dd9dc (diff)
downloadwallet-core-dev/sebasjm/refactor-merchant.tar.gz
wallet-core-dev/sebasjm/refactor-merchant.tar.bz2
wallet-core-dev/sebasjm/refactor-merchant.zip
-rw-r--r--packages/bank-ui/src/Routing.tsx2
-rw-r--r--packages/bank-ui/src/context/config.ts23
-rw-r--r--packages/bank-ui/src/pages/LoginForm.tsx3
-rw-r--r--packages/bank-ui/src/pages/RegistrationPage.tsx2
-rw-r--r--packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx6
-rw-r--r--packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx4
-rw-r--r--packages/merchant-backoffice-ui/src/paths/login/index.tsx6
-rw-r--r--packages/taler-harness/create_merchantAndBankAccount_pdf.sh23
-rw-r--r--packages/taler-harness/pdf-template.html65
-rw-r--r--packages/taler-harness/src/index.ts393
-rw-r--r--packages/taler-util/src/http-client/authentication.ts12
-rw-r--r--packages/taler-util/src/http-client/bank-core.ts10
-rw-r--r--packages/taler-util/src/http-client/merchant.ts6
-rw-r--r--packages/taler-util/src/http-common.ts1
-rw-r--r--packages/taler-util/src/http-impl.node.ts9
-rw-r--r--packages/taler-util/src/http-impl.qtart.ts8
-rw-r--r--packages/web-util/src/context/bank-api.ts1
-rw-r--r--packages/web-util/src/context/merchant-api.ts2
18 files changed, 481 insertions, 95 deletions
diff --git a/packages/bank-ui/src/Routing.tsx b/packages/bank-ui/src/Routing.tsx
index 489dbe30b..3ec5f0c77 100644
--- a/packages/bank-ui/src/Routing.tsx
+++ b/packages/bank-ui/src/Routing.tsx
@@ -113,7 +113,7 @@ function PublicRounting({
async function doAutomaticLogin(username: string, password: string) {
await handleError(async () => {
- const resp = await lib.auth(username).createAccessToken(password, {
+ const resp = await lib.auth(username).createAccessTokenBasic(username, password, {
scope: "readwrite",
duration: { d_us: "forever" },
refreshable: true,
diff --git a/packages/bank-ui/src/context/config.ts b/packages/bank-ui/src/context/config.ts
index 55b21d0da..86b6df5f3 100644
--- a/packages/bank-ui/src/context/config.ts
+++ b/packages/bank-ui/src/context/config.ts
@@ -218,7 +218,6 @@ function buildApiClient(url: URL) {
const authClient = (user: string) =>
new TalerAuthenticationHttpClient(
bankClient.getAuthenticationAPI(user).href,
- user,
httpLib,
);
@@ -305,15 +304,15 @@ const evictBankSwrCache: CacheEvictor<TalerCoreBankCacheEviction> = {
};
const evictConversionSwrCache: CacheEvictor<TalerBankConversionCacheEviction> =
- {
- async notifySuccess(op) {
- switch (op) {
- case TalerBankConversionCacheEviction.UPDATE_RATE: {
- await revalidateConversionInfo();
- return;
- }
- default:
- assertUnreachable(op);
+{
+ async notifySuccess(op) {
+ switch (op) {
+ case TalerBankConversionCacheEviction.UPDATE_RATE: {
+ await revalidateConversionInfo();
+ return;
}
- },
- };
+ default:
+ assertUnreachable(op);
+ }
+ },
+};
diff --git a/packages/bank-ui/src/pages/LoginForm.tsx b/packages/bank-ui/src/pages/LoginForm.tsx
index 904cd39d2..7eed0cd9e 100644
--- a/packages/bank-ui/src/pages/LoginForm.tsx
+++ b/packages/bank-ui/src/pages/LoginForm.tsx
@@ -79,8 +79,7 @@ export function LoginForm({
? undefined
: withErrorHandler(
async () =>
- authenticator(username).createAccessToken(password, {
- // scope: "readwrite" as "write", // FIX: different than merchant
+ authenticator(username).createAccessTokenBasic(username, password, {
scope: "readwrite",
duration: { d_us: "forever" },
refreshable: true,
diff --git a/packages/bank-ui/src/pages/RegistrationPage.tsx b/packages/bank-ui/src/pages/RegistrationPage.tsx
index d7093d973..dc08ce0fa 100644
--- a/packages/bank-ui/src/pages/RegistrationPage.tsx
+++ b/packages/bank-ui/src/pages/RegistrationPage.tsx
@@ -114,7 +114,7 @@ function RegistrationForm({
onComplete: () => void,
) {
await handleError(async (onError) => {
- const resp = await api.createAccount("" as AccessToken, {
+ const resp = await api.createAccount(undefined, {
name,
username,
password,
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx
index 3db38acc3..0e8ea1f5b 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/create/index.tsx
@@ -57,7 +57,7 @@ export default function Create({ onBack, onConfirm, forceId }: Props): VNode {
try {
await createInstance(d);
if (d.auth.token) {
- const result = await lib.authenticate.createAccessToken(
+ const result = await lib.authenticate.createAccessTokenBearer(
d.auth.token,
{
scope: "write",
@@ -68,8 +68,8 @@ export default function Create({ onBack, onConfirm, forceId }: Props): VNode {
},
);
if (result.type === "ok") {
- const { access_token } = result.body;
- logIn({ token: access_token });
+ const { token } = result.body;
+ logIn({ token });
}
}
onConfirm();
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx
index 889ef6f5d..13b5c45f1 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/token/index.tsx
@@ -85,11 +85,11 @@ export default function Token({
}}
onNewToken={async (currentToken, newToken): Promise<void> => {
try {
- await lib.management.updateInstanceAuthentication(currentToken, {
+ await lib.management.updateCurrentInstanceAuthentication(currentToken, {
token: newToken,
method: "token"
})
- const resp = await lib.authenticate.createAccessTokenMerchant(newToken, {
+ const resp = await lib.authenticate.createAccessTokenBearer(newToken, {
scope: "write",
duration: {
d_us: "forever"
diff --git a/packages/merchant-backoffice-ui/src/paths/login/index.tsx b/packages/merchant-backoffice-ui/src/paths/login/index.tsx
index 14322f079..6a698186a 100644
--- a/packages/merchant-backoffice-ui/src/paths/login/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/login/index.tsx
@@ -34,7 +34,7 @@ import {
} from "../../context/session.js";
import { Notification } from "../../utils/types.js";
-interface Props {}
+interface Props { }
const tokenRequest = {
scope: "write",
@@ -55,7 +55,7 @@ export function LoginPage(_p: Props): VNode {
async function doImpersonateImpl(instanceId: string) {
const result = await lib
.impersonate(instanceId)
- .createAccessTokenMerchant(token, tokenRequest);
+ .createAccessTokenBearer(token, tokenRequest);
if (result.type === "ok") {
const { token } = result.body;
logIn({ token });
@@ -80,7 +80,7 @@ export function LoginPage(_p: Props): VNode {
}
}
async function doLoginImpl() {
- const result = await lib.authenticate.createAccessTokenMerchant(
+ const result = await lib.authenticate.createAccessTokenBearer(
token,
tokenRequest,
);
diff --git a/packages/taler-harness/create_merchantAndBankAccount_pdf.sh b/packages/taler-harness/create_merchantAndBankAccount_pdf.sh
new file mode 100644
index 000000000..4593cc9a0
--- /dev/null
+++ b/packages/taler-harness/create_merchantAndBankAccount_pdf.sh
@@ -0,0 +1,23 @@
+DATA=$(mktemp)
+set -e
+
+[ -z "$1" ] && echo First parameter must be the json file result from \'taler-harness deployment provision-bank-and-merchant\'. Alternative \'-\' can be used if the file is provided from stdin. && exit 1
+
+cat $1 > $DATA
+
+[ -z "$(jq -r '.bankUser//empty' $DATA)" ] && echo the json file is not complete: missing bankUser && exit 1
+[ -z "$(jq -r '.bankURL//empty' $DATA)" ] && echo the json file is not complete: missing bankURL && exit 1
+[ -z "$(jq -r '.merchantURL//empty' $DATA)" ] && echo the json file is not complete: missing merchantURL && exit 1
+[ -z "$(jq -r '.templateURI//empty' $DATA)" ] && echo the json file is not complete: missing templateURI && exit 1
+[ -z "$(jq -r '.password//empty' $DATA)" ] && echo the json file is not complete: missing password && exit 1
+
+add_qr_image(){
+ jq -r $1 $DATA | qrencode -l Q -m 2 -s 5 -o - | base64 -w 0 | jq -Rn '{"'$2'":inputs}' | jq -s add - $DATA | sponge $DATA
+}
+
+add_qr_image .templateURI templateQR
+add_qr_image .bankURL bankQR
+add_qr_image .merchantURL merchantQR
+
+chevron pdf-template.html -d $DATA | wkhtmltopdf - out.pdf
+
diff --git a/packages/taler-harness/pdf-template.html b/packages/taler-harness/pdf-template.html
new file mode 100644
index 000000000..d308d67c4
--- /dev/null
+++ b/packages/taler-harness/pdf-template.html
@@ -0,0 +1,65 @@
+<html>
+
+<body style="padding: 3em">
+ <h1 id="account-information">Account information</h1>
+
+ <p>The information in this page is confidentail, do not share with others.</p>
+
+ <h2 style="margin-top: 4em;" id="bank-account">Bank</h2>
+ <p>
+ In your bank account you will be able to see how much revenue
+ has been consolidated.
+ </p>
+ <div style="display: flex; justify-content: space-between;">
+
+ <div>
+ <p>URL: {{bankURL}}</p>
+ <p>accounts id: {{bankUser}}</p>
+ <p>password: {{password}}</p>
+ </div>
+
+ <div>
+ <figure style="text-align: center;">
+ <img src="data:image/png;base64,{{bankQR}}" alt="" />
+ <figcaption>bank URL</figcaption>
+ </figure>
+ </div>
+ </div>
+
+ <hr />
+
+ <h2 style="margin-top: 4em;" id="merchant-instance">Backoffice</h2>
+ <p>
+ In this site you will be able to see how much are you selling,
+ make refunds or create new QR codes.
+ </p>
+
+ <div style="display: flex; justify-content: space-between;">
+ <div>
+ <p>URL: {{merchantURL}}</p>
+ <p>password: {{password}}</p>
+ </div>
+ <div>
+ <figure style="text-align: center;">
+ <img src="data:image/png;base64,{{merchantQR}}" alt="" />
+ <figcaption>merchant URL</figcaption>
+ </figure>
+ </div>
+ </div>
+
+ <hr />
+ <div style="page-break-after: always;">
+
+ </div>
+ <h1 style="margin-top: 4em;" id="template">Payme QR code</h1>
+ <p>
+ The following QR code can be utilized in
+ public settings to request payments.
+ </p>
+ <figure style="text-align: center;">
+ <img src="data:image/png;base64,{{templateQR}}" alt="" />
+ <figcaption>{{templateURI}}</figcaption>
+ </figure>
+</body>
+
+</html> \ No newline at end of file
diff --git a/packages/taler-harness/src/index.ts b/packages/taler-harness/src/index.ts
index 3bec1698a..4b0319a3e 100644
--- a/packages/taler-harness/src/index.ts
+++ b/packages/taler-harness/src/index.ts
@@ -18,6 +18,7 @@
* Imports.
*/
import {
+ AccessToken,
AmountString,
Amounts,
BalancesResponse,
@@ -25,14 +26,23 @@ import {
Duration,
HttpStatusCode,
Logger,
- MerchantInstanceConfig,
- RegisterAccountRequest,
+ PaytoString,
+ TalerAuthenticationHttpClient,
+ TalerBankConversionHttpClient,
+ TalerCoreBankHttpClient,
+ TalerErrorCode,
+ TalerMerchantInstanceHttpClient,
+ TalerMerchantManagementHttpClient,
TransactionsResponse,
decodeCrock,
+ encodeCrock,
generateIban,
j2s,
+ randomBytes,
rsaBlind,
setGlobalLogLevelFromString,
+ setPrintHttpRequestAsCurl,
+ stringifyPayTemplateUri
} from "@gnu-taler/taler-util";
import { clk } from "@gnu-taler/taler-util/clk";
import {
@@ -69,6 +79,7 @@ import {
} from "./harness/helpers.js";
import { getTestInfo, runTests } from "./integrationtests/testrunner.js";
import { lintExchangeDeployment } from "./lint.js";
+import { randomUUID } from "crypto";
const logger = new Logger("taler-harness:index.ts");
@@ -586,6 +597,291 @@ deploymentCli
});
deploymentCli
+ .subcommand("provisionBankMerchant", "provision-bank-and-merchant", {
+ help: "Provision a bank account, merchant instance and link them together.",
+ })
+ .requiredArgument("merchantApiBaseUrl", clk.STRING, {
+ help: "URL location of the merchant backend"
+ })
+ .requiredArgument("corebankApiBaseUrl", clk.STRING, {
+ help: "URL location of the libeufin bank backend"
+ })
+ .requiredOption("merchantToken", ["--merchant-management-token"], clk.STRING, {
+ help: "acces token of the default instance in the merchant backend"
+ })
+ .maybeOption("bankToken", ["--bank-admin-token"], clk.STRING, {
+ help: "libeufin bank admin's password if the account creation is restricted"
+ })
+ .requiredOption("name", ["--legal-name"], clk.STRING, {
+ help: "legal name of the merchant"
+ })
+ .maybeOption("email", ["--email"], clk.STRING, {
+ help: "email contact of the merchant"
+ })
+ .maybeOption("phone", ["--phone"], clk.STRING, {
+ help: "phone contact of the merchant"
+ })
+ .requiredOption("id", ["--id"], clk.STRING, {
+ help: "login id for the bank account and instance id of the merchant backend"
+ })
+ .flag("template", ["--create-template"], {
+ help: "use this flag to create a default template for the merchant with fixed summary"
+ })
+ .requiredOption("password", ["--password"], clk.STRING, {
+ help: "password of the accounts in libeufin bank and merchant backend"
+ })
+ .flag("randomPassword", ["--set-random-password"], {
+ help: "if everything worked ok, change the password of the accounts at the end"
+ })
+ .action(async (args) => {
+ const managementToken = args.provisionBankMerchant.merchantToken as AccessToken;
+ const bankAdminPassword = args.provisionBankMerchant.bankToken as AccessToken;
+ const id = args.provisionBankMerchant.id;
+ const name = args.provisionBankMerchant.name;
+ const email = args.provisionBankMerchant.email;
+ const phone = args.provisionBankMerchant.phone;
+ const password = args.provisionBankMerchant.password;
+
+
+ const httpLib = createPlatformHttpLib({});
+ const merchantManager = new TalerMerchantManagementHttpClient(args.provisionBankMerchant.merchantApiBaseUrl, httpLib);
+ const bank = new TalerCoreBankHttpClient(args.provisionBankMerchant.corebankApiBaseUrl, httpLib);
+ const instanceURL = merchantManager.getSubInstanceAPI(id).href
+ const merchantInstance = new TalerMerchantInstanceHttpClient(instanceURL, httpLib);
+ const conv = new TalerBankConversionHttpClient(bank.getConversionInfoAPI().href, httpLib)
+ const bankAuth = new TalerAuthenticationHttpClient(bank.getAuthenticationAPI(id).href, httpLib)
+
+
+ const bc = await bank.getConfig()
+ if (!bank.isCompatible(bc.body.version)) {
+ logger.error(
+ `bank server version is not compatible: ${bc.body.version}, client version: ${bank.PROTOCOL_VERSION}`,
+ );
+ return;
+ }
+ const mc = await merchantManager.getConfig()
+ if (!merchantManager.isCompatible(mc.body.version)) {
+ logger.error(
+ `merchant server version is not compatible: ${mc.body.version}, client version: ${merchantManager.PROTOCOL_VERSION}`,
+ );
+ return;
+ }
+
+ /**
+ * create bank account
+ */
+ let accountPayto: PaytoString;
+ {
+ const resp = await bank.createAccount(bankAdminPassword, {
+ name: name,
+ password: password,
+ username: id,
+ contact_data: email || phone ? {
+ email: email,
+ phone: phone,
+ } : undefined,
+ })
+
+ if (resp.type === "fail") {
+ logger.error(`unable to provision bank account, HTTP response status ${resp.case}`);
+ process.exit(2);
+ }
+ logger.info(`account ${id} successfully provisioned`);
+ accountPayto = resp.body.internal_payto_uri
+ }
+
+ /**
+ * create merchant account
+ */
+ {
+ const resp = await merchantManager.createInstance(managementToken, {
+ address: {},
+ auth: {
+ method: "token",
+ token: `secret-token:${password}`,
+ },
+ default_pay_delay: Duration.toTalerProtocolDuration(
+ Duration.fromSpec({ hours: 1 }),
+ ),
+ default_wire_transfer_delay: Duration.toTalerProtocolDuration(
+ Duration.fromSpec({ hours: 1 }),
+ ),
+ id: id,
+ jurisdiction: {},
+ name: name,
+ use_stefan: true,
+ })
+
+ if (resp.type === "ok") {
+ logger.info(`instance ${id} created successfully`);
+ } else if (resp.case === HttpStatusCode.Conflict) {
+ logger.info(`instance ${id} already exists`);
+ } else {
+ logger.error(
+ `unable to create instance ${id}, HTTP status ${resp.case}`,
+ );
+ process.exit(2);
+ }
+ }
+
+ let wireAccount: string;
+ /**
+ * link bank account and merchant
+ */
+ {
+ const resp = await merchantInstance.addAccount(password as AccessToken, {
+ payto_uri: accountPayto,
+ credit_facade_url: bank.getRevenueAPI(id).href,
+ credit_facade_credentials: {
+ type: "basic",
+ username: id,
+ password: password,
+ }
+ })
+ if (resp.type === "fail") {
+ console.error(`unable to configure bank account for instance ${id}, status ${resp.case}`)
+ console.error(j2s(resp.detail));
+ process.exit(2);
+ }
+ wireAccount = resp.body.h_wire
+ }
+
+ logger.info(`successfully configured bank account for ${id}`);
+
+ let templateURI;
+ /**
+ * create template
+ */
+ if (args.provisionBankMerchant.template) {
+ let currency = bc.body.currency;
+ if (bc.body.allow_conversion) {
+ const cc = await conv.getConfig();
+ if (cc.type === "ok") {
+ currency = cc.body.fiat_currency
+ } else {
+ console.error(
+ `could not get fiat currency status ${cc.case}`,
+ );
+ console.error(j2s(cc.detail));
+ }
+ } else {
+ console.log(`conversion is disabled, using bank currency`)
+ }
+
+ {
+ const resp = await merchantInstance.addTemplate(password as AccessToken, {
+ template_id: "default",
+ template_description: "First template",
+ template_contract: {
+ pay_duration: Duration.toTalerProtocolDuration(
+ Duration.fromSpec({ hours: 1 }),
+ ),
+ minimum_age: 0,
+ currency,
+ summary: "Pay me!"
+ }
+ })
+ if (resp.type === "fail") {
+ console.error(`unable to create template for insntaince ${id}, status ${resp.case}`)
+ console.error(j2s(resp.detail));
+ process.exit(2);
+ }
+ }
+
+ logger.info(`template default successfully created`);
+ templateURI = stringifyPayTemplateUri({
+ merchantBaseUrl: instanceURL,
+ templateId: "default",
+ templateParams: {
+ amount: currency
+ }
+ })
+ }
+
+ let finalPassword = password;
+ if (args.provisionBankMerchant.randomPassword) {
+ const prevPassword = password as AccessToken
+ const randomPassword = encodeCrock(randomBytes(16));
+ logger.info("random password: ", randomPassword)
+ let token: AccessToken;
+ {
+ const resp = await bankAuth.createAccessTokenBasic(id, prevPassword, {
+ scope: "readwrite",
+ duration: Duration.toTalerProtocolDuration(Duration.fromSpec({ minutes: 1 })),
+ refreshable: false,
+ })
+ if (resp.type === "fail") {
+ console.error(`unable to login into bank accountfor user ${id}, status ${resp.case}`)
+ console.error(j2s(resp.detail));
+ process.exit(2);
+ }
+ token = resp.body.access_token;
+ }
+
+ {
+ const resp = await bank.updatePassword({ username: id, token }, {
+ old_password: prevPassword,
+ new_password: randomPassword,
+ });
+ if (resp.type === "fail") {
+ console.error(`unable to change bank pasword for user ${id}, status ${resp.case}`)
+ if (resp.case !== HttpStatusCode.Accepted) {
+ console.error(j2s(resp.detail));
+ } else {
+ console.error("2FA required")
+ }
+ process.exit(2);
+ }
+ }
+
+ {
+ const resp = await merchantInstance.updateCurrentInstanceAuthentication(prevPassword, {
+ method: "token",
+ token: `secret-token:${randomPassword}` as AccessToken
+ })
+ if (resp.type === "fail") {
+ console.error(`unable to change merchant password for instance ${id}, status ${resp.case}`)
+ console.error(j2s(resp.detail));
+ process.exit(2);
+ }
+ }
+
+ {
+ const resp = await merchantInstance.updateAccount(randomPassword as AccessToken, wireAccount, {
+ credit_facade_url: bank.getRevenueAPI(id).href,
+ credit_facade_credentials: {
+ type: "basic",
+ username: id,
+ password: randomPassword,
+ }
+ })
+ if (resp.type != "ok") {
+ console.error(
+ `unable to update bank account for instance ${id}, status ${resp.case}`,
+ );
+ console.error(j2s(resp.detail));
+ process.exit(2);
+ }
+ }
+ finalPassword = randomPassword;
+ }
+ logger.info(`successfully configured bank account for ${id}`);
+
+ /**
+ * show result
+ */
+ console.log(JSON.stringify({
+ bankUser: id,
+ bankURL: args.provisionBankMerchant.corebankApiBaseUrl,
+ merchantURL: instanceURL,
+ templateURI,
+ password: finalPassword,
+ }, undefined, 2))
+
+ });
+
+
+deploymentCli
.subcommand("provisionMerchantInstance", "provision-merchant-instance", {
help: "Provision a merchant backend instance.",
})
@@ -595,17 +891,27 @@ deploymentCli
.requiredOption("name", ["--name"], clk.STRING)
.requiredOption("id", ["--id"], clk.STRING)
.requiredOption("payto", ["--payto"], clk.STRING)
+ .maybeOption("bankURL", ["--bankURL"], clk.STRING)
+ .maybeOption("bankUser", ["--bankUser"], clk.STRING)
+ .maybeOption("bankPassword", ["--bankPassword"], clk.STRING)
.action(async (args) => {
- const httpLib = createPlatformHttpLib();
+ const httpLib = createPlatformHttpLib({});
const baseUrl = args.provisionMerchantInstance.merchantApiBaseUrl;
- const managementToken = args.provisionMerchantInstance.managementToken;
- const instanceToken = args.provisionMerchantInstance.instanceToken;
+ const api = new TalerMerchantManagementHttpClient(baseUrl, httpLib)
+ const managementToken = args.provisionMerchantInstance.managementToken as AccessToken;
+ const instanceToken = args.provisionMerchantInstance.instanceToken as AccessToken;
const instanceId = args.provisionMerchantInstance.id;
- const body: MerchantInstanceConfig = {
+ const instancceName = args.provisionMerchantInstance.name;
+ const bankURL = args.provisionMerchantInstance.bankURL;
+ const bankUser = args.provisionMerchantInstance.bankUser;
+ const bankPassword = args.provisionMerchantInstance.bankPassword;
+ const accountPayto = args.provisionMerchantInstance.payto as PaytoString;
+
+ const createResp = await api.createInstance(managementToken, {
address: {},
auth: {
method: "token",
- token: args.provisionMerchantInstance.instanceToken,
+ token: `secret-token:${instanceToken}`,
},
default_pay_delay: Duration.toTalerProtocolDuration(
Duration.fromSpec({ hours: 1 }),
@@ -613,48 +919,35 @@ deploymentCli
default_wire_transfer_delay: { d_us: 1 },
id: instanceId,
jurisdiction: {},
- name: args.provisionMerchantInstance.name,
+ name: instancceName,
use_stefan: true,
- };
- const url = new URL("management/instances", baseUrl);
- const createResp = await httpLib.fetch(url.href, {
- method: "POST",
- body,
- headers: {
- Authorization: `Bearer ${managementToken}`,
- },
- });
- if (createResp.status >= 200 && createResp.status <= 299) {
+ })
+
+ if (createResp.type === "ok") {
logger.info(`instance ${instanceId} created successfully`);
- } else if (createResp.status === HttpStatusCode.Conflict) {
+ } else if (createResp.case === HttpStatusCode.Conflict) {
logger.info(`instance ${instanceId} already exists`);
} else {
logger.error(
- `unable to create instance ${instanceId}, HTTP status ${createResp.status}`,
+ `unable to create instance ${instanceId}, HTTP status ${createResp.case}`,
);
process.exit(2);
}
- const accountsUrl = new URL(
- `instances/${instanceId}/private/accounts`,
- baseUrl,
- );
- const accountBody = {
- payto_uri: args.provisionMerchantInstance.payto,
- };
- const createAccountResp = await httpLib.fetch(accountsUrl.href, {
- method: "POST",
- body: accountBody,
- headers: {
- Authorization: `Bearer ${instanceToken}`,
- },
- });
- if (createAccountResp.status != 200) {
+ const createAccountResp = await api.addAccount(instanceToken, {
+ payto_uri: accountPayto,
+ credit_facade_url: bankURL,
+ credit_facade_credentials: bankUser && bankPassword ? {
+ type: "basic",
+ username: bankUser,
+ password: bankPassword,
+ } : undefined
+ })
+ if (createAccountResp.type != "ok") {
console.error(
- `unable to configure bank account for instance ${instanceId}, status ${createAccountResp.status}`,
+ `unable to configure bank account for instance ${instanceId}, status ${createAccountResp.case}`,
);
- const resp = await createAccountResp.json();
- console.error(j2s(resp));
+ console.error(j2s(createAccountResp.detail));
process.exit(2);
}
logger.info(`successfully configured bank account for ${instanceId}`);
@@ -673,31 +966,25 @@ deploymentCli
.maybeOption("internalPayto", ["--payto"], clk.STRING)
.action(async (args) => {
const httpLib = createPlatformHttpLib();
- const corebankApiBaseUrl = args.provisionBankAccount.corebankApiBaseUrl;
- const url = new URL("accounts", corebankApiBaseUrl);
+ const baseUrl = args.provisionBankAccount.corebankApiBaseUrl;
+ const api = new TalerCoreBankHttpClient(baseUrl, httpLib);
+
const accountLogin = args.provisionBankAccount.login;
- const body: RegisterAccountRequest = {
+ const resp = await api.createAccount(undefined, {
name: args.provisionBankAccount.name,
password: args.provisionBankAccount.password,
username: accountLogin,
is_public: !!args.provisionBankAccount.public,
is_taler_exchange: !!args.provisionBankAccount.exchange,
- payto_uri: args.provisionBankAccount.internalPayto,
- };
- const resp = await httpLib.fetch(url.href, {
- method: "POST",
- body,
- });
- if (resp.status >= 200 && resp.status <= 299) {
+ payto_uri: args.provisionBankAccount.internalPayto as PaytoString,
+ })
+
+ if (resp.type === "ok") {
logger.info(`account ${accountLogin} successfully provisioned`);
return;
}
- if (resp.status === HttpStatusCode.Conflict) {
- logger.info(`account ${accountLogin} already provisioned`);
- return;
- }
logger.error(
- `unable to provision bank account, HTTP response status ${resp.status}`,
+ `unable to provision bank account, HTTP response status ${resp.case}`,
);
process.exit(2);
});
diff --git a/packages/taler-util/src/http-client/authentication.ts b/packages/taler-util/src/http-client/authentication.ts
index 00ef21a06..f77df2ed0 100644
--- a/packages/taler-util/src/http-client/authentication.ts
+++ b/packages/taler-util/src/http-client/authentication.ts
@@ -45,7 +45,6 @@ export class TalerAuthenticationHttpClient {
constructor(
readonly baseUrl: string,
- readonly username: string,
httpClient?: HttpRequestLibrary,
) {
this.httpLib = httpClient ?? createPlatformHttpLib();
@@ -61,7 +60,8 @@ export class TalerAuthenticationHttpClient {
*
* @returns
*/
- async createAccessToken(
+ async createAccessTokenBasic(
+ username: string,
password: string,
body: TalerAuthentication.TokenRequest,
) {
@@ -69,7 +69,7 @@ export class TalerAuthenticationHttpClient {
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
headers: {
- Authorization: makeBasicAuthHeader(this.username, password),
+ Authorization: makeBasicAuthHeader(username, password),
},
body,
});
@@ -90,15 +90,15 @@ export class TalerAuthenticationHttpClient {
*
* @returns
*/
- async createAccessTokenMerchant(
- password: string,
+ async createAccessTokenBearer(
+ token: string,
body: TalerAuthentication.TokenRequest,
) {
const url = new URL(`token`, this.baseUrl);
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
headers: {
- Authorization: makeBearerTokenAuthHeader(password as AccessToken),
+ Authorization: makeBearerTokenAuthHeader(token as AccessToken),
},
body,
});
diff --git a/packages/taler-util/src/http-client/bank-core.ts b/packages/taler-util/src/http-client/bank-core.ts
index b544d56fe..7a98b6281 100644
--- a/packages/taler-util/src/http-client/bank-core.ts
+++ b/packages/taler-util/src/http-client/bank-core.ts
@@ -140,16 +140,18 @@ export class TalerCoreBankHttpClient {
*
*/
async createAccount(
- auth: AccessToken,
+ auth: AccessToken | undefined,
body: TalerCorebankApi.RegisterAccountRequest,
) {
const url = new URL(`accounts`, this.baseUrl);
+ const headers: Record<string, string> = {}
+ if (auth) {
+ headers.Authorization = makeBearerTokenAuthHeader(auth)
+ }
const resp = await this.httpLib.fetch(url.href, {
method: "POST",
body,
- headers: {
- Authorization: makeBearerTokenAuthHeader(auth),
- },
+ headers: headers,
});
switch (resp.status) {
case HttpStatusCode.Ok: {
diff --git a/packages/taler-util/src/http-client/merchant.ts b/packages/taler-util/src/http-client/merchant.ts
index 1b1a7b4a8..394625e38 100644
--- a/packages/taler-util/src/http-client/merchant.ts
+++ b/packages/taler-util/src/http-client/merchant.ts
@@ -354,10 +354,11 @@ export class TalerMerchantInstanceHttpClient {
headers,
});
- //
switch (resp.status) {
case HttpStatusCode.Ok:
return opEmptySuccess(resp);
+ case HttpStatusCode.NoContent: // FIXME: missing in docs
+ return opEmptySuccess(resp);
case HttpStatusCode.NotFound:
return opKnownHttpFailure(resp.status, resp);
default:
@@ -1778,9 +1779,10 @@ export class TalerMerchantManagementHttpClient extends TalerMerchantInstanceHttp
*/
async updateInstanceAuthentication(
token: AccessToken | undefined,
+ instanceId: string,
body: TalerMerchantApi.InstanceAuthConfigurationMessage,
) {
- const url = new URL(`management/instances`, this.baseUrl);
+ const url = new URL(`management/instances/${instanceId}/auth`, this.baseUrl);
const headers: Record<string, string> = {}
if (token) {
diff --git a/packages/taler-util/src/http-common.ts b/packages/taler-util/src/http-common.ts
index 3973e66fb..cc75debd5 100644
--- a/packages/taler-util/src/http-common.ts
+++ b/packages/taler-util/src/http-common.ts
@@ -440,6 +440,7 @@ export interface HttpLibArgs {
* Only allow HTTPS connections, not plain http.
*/
requireTls?: boolean;
+ printAsCurl?: boolean;
}
export function encodeBody(body: any): ArrayBuffer {
diff --git a/packages/taler-util/src/http-impl.node.ts b/packages/taler-util/src/http-impl.node.ts
index b5c87843f..8606bc451 100644
--- a/packages/taler-util/src/http-impl.node.ts
+++ b/packages/taler-util/src/http-impl.node.ts
@@ -119,8 +119,13 @@ export class HttpLibImpl implements HttpRequestLibrary {
timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS;
}
- const requestHeadersMap = { ...getDefaultHeaders(method), ...opt?.headers };
-
+ const requestHeadersMap = getDefaultHeaders(method);
+ if (opt?.headers) {
+ Object.entries(opt?.headers).forEach(([key, value]) => {
+ if (value === undefined) return;
+ requestHeadersMap[key] = value
+ })
+ }
logger.trace(`request timeout ${timeoutMs} ms`);
let reqBody: ArrayBuffer | undefined;
diff --git a/packages/taler-util/src/http-impl.qtart.ts b/packages/taler-util/src/http-impl.qtart.ts
index 0be9f2c23..b4e4ebbe7 100644
--- a/packages/taler-util/src/http-impl.qtart.ts
+++ b/packages/taler-util/src/http-impl.qtart.ts
@@ -98,7 +98,13 @@ export class HttpLibImpl implements HttpRequestLibrary {
}
let data: ArrayBuffer | undefined = undefined;
- const requestHeadersMap = { ...getDefaultHeaders(method), ...opt?.headers };
+ const requestHeadersMap = getDefaultHeaders(method);
+ if (opt?.headers) {
+ Object.entries(opt?.headers).forEach(([key, value]) => {
+ if (value === undefined) return;
+ requestHeadersMap[key] = value
+ })
+ }
let headersList: string[] = [];
for (let headerName of Object.keys(requestHeadersMap)) {
headersList.push(`${headerName}: ${requestHeadersMap[headerName]}`);
diff --git a/packages/web-util/src/context/bank-api.ts b/packages/web-util/src/context/bank-api.ts
index 645eda183..bd0653451 100644
--- a/packages/web-util/src/context/bank-api.ts
+++ b/packages/web-util/src/context/bank-api.ts
@@ -167,7 +167,6 @@ function buildBankApiClient(url: URL, evictors: Evictors,
const auth = (user: string) =>
new TalerAuthenticationHttpClient(
bank.getAuthenticationAPI(user).href,
- user,
httpLib,
);
diff --git a/packages/web-util/src/context/merchant-api.ts b/packages/web-util/src/context/merchant-api.ts
index 79c79ee9c..a531a5958 100644
--- a/packages/web-util/src/context/merchant-api.ts
+++ b/packages/web-util/src/context/merchant-api.ts
@@ -183,13 +183,11 @@ function buildMerchantApiClient(
);
const authenticate = new TalerAuthenticationHttpClient(
management.getAuthenticationAPI().href,
- "default",
httpLib,
);
const impersonate = (instanceId: string) =>
new TalerAuthenticationHttpClient(
instance(instanceId).getAuthenticationAPI().href,
- instanceId,
httpLib,
);