aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/taler-wallet-cli/src/index.ts109
-rw-r--r--packages/taler-wallet-core/src/db.ts4
-rw-r--r--packages/taler-wallet-core/src/operations/exchanges.ts58
-rw-r--r--packages/taler-wallet-core/src/wallet.ts2
4 files changed, 105 insertions, 68 deletions
diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts
index 249198e3c..b50e11883 100644
--- a/packages/taler-wallet-cli/src/index.ts
+++ b/packages/taler-wallet-cli/src/index.ts
@@ -314,48 +314,42 @@ walletCli
logger.info("finished handling API request");
});
-walletCli
- .subcommand("", "pending", { help: "Show pending operations." })
- .action(async (args) => {
- await withWallet(args, async (wallet) => {
- const pending = await wallet.client.call(
- WalletApiOperation.GetPendingOperations,
- {},
- );
- console.log(JSON.stringify(pending, undefined, 2));
- });
- });
-
-walletCli
- .subcommand("transactions", "transactions", { help: "Show transactions." })
+const transactionsCli = walletCli
+ .subcommand("transactions", "transactions", { help: "Manage transactions." })
.maybeOption("currency", ["--currency"], clk.STRING)
- .maybeOption("search", ["--search"], clk.STRING)
- .action(async (args) => {
- await withWallet(args, async (wallet) => {
- const pending = await wallet.client.call(
- WalletApiOperation.GetTransactions,
- {
- currency: args.transactions.currency,
- search: args.transactions.search,
- },
- );
- console.log(JSON.stringify(pending, undefined, 2));
- });
+ .maybeOption("search", ["--search"], clk.STRING);
+
+// Default action
+transactionsCli.action(async (args) => {
+ await withWallet(args, async (wallet) => {
+ const pending = await wallet.client.call(
+ WalletApiOperation.GetTransactions,
+ {
+ currency: args.transactions.currency,
+ search: args.transactions.search,
+ },
+ );
+ console.log(JSON.stringify(pending, undefined, 2));
});
+});
-walletCli
- .subcommand("runPendingOpt", "run-pending", {
- help: "Run pending operations.",
+transactionsCli
+ .subcommand("deleteTransaction", "delete", {
+ help: "Permanently delete a transaction from the transaction list.",
+ })
+ .requiredArgument("transactionId", clk.STRING, {
+ help: "Identifier of the transaction to delete",
})
- .flag("forceNow", ["-f", "--force-now"])
.action(async (args) => {
await withWallet(args, async (wallet) => {
- await wallet.ws.runPending(args.runPendingOpt.forceNow);
+ await wallet.client.call(WalletApiOperation.DeleteTransaction, {
+ transactionId: args.deleteTransaction.transactionId,
+ });
});
});
-walletCli
- .subcommand("retryTransaction", "retry-transaction", {
+transactionsCli
+ .subcommand("retryTransaction", "retry", {
help: "Retry a transaction.",
})
.requiredArgument("transactionId", clk.STRING)
@@ -388,21 +382,6 @@ walletCli
});
walletCli
- .subcommand("deleteTransaction", "delete-transaction", {
- help: "Permanently delete a transaction from the transaction list.",
- })
- .requiredArgument("transactionId", clk.STRING, {
- help: "Identifier of the transaction to delete",
- })
- .action(async (args) => {
- await withWallet(args, async (wallet) => {
- await wallet.client.call(WalletApiOperation.DeleteTransaction, {
- transactionId: args.deleteTransaction.transactionId,
- });
- });
- });
-
-walletCli
.subcommand("withdraw", "withdraw", {
help: "Withdraw with a taler://withdraw/ URI",
})
@@ -604,17 +583,26 @@ exchangesCli
exchangesCli
.subcommand("exchangesTosCmd", "tos", {
- help: "Show terms of service.",
+ help: "Show/request terms of service.",
})
.requiredArgument("url", clk.STRING, {
help: "Base URL of the exchange.",
})
+ .maybeOption("contentTypes", ["--content-type"], clk.STRING)
.action(async (args) => {
+ let acceptedFormat: string[] | undefined = undefined;
+ if (args.exchangesTosCmd.contentTypes) {
+ const split = args.exchangesTosCmd.contentTypes
+ .split(",")
+ .map((x) => x.trim());
+ acceptedFormat = split;
+ }
await withWallet(args, async (wallet) => {
const tosResult = await wallet.client.call(
WalletApiOperation.GetExchangeTos,
{
exchangeBaseUrl: args.exchangesTosCmd.url,
+ acceptedFormat,
},
);
console.log(JSON.stringify(tosResult, undefined, 2));
@@ -765,6 +753,29 @@ advancedCli
});
advancedCli
+ .subcommand("runPendingOpt", "run-pending", {
+ help: "Run pending operations.",
+ })
+ .flag("forceNow", ["-f", "--force-now"])
+ .action(async (args) => {
+ await withWallet(args, async (wallet) => {
+ await wallet.ws.runPending(args.runPendingOpt.forceNow);
+ });
+ });
+
+advancedCli
+ .subcommand("", "pending", { help: "Show pending operations." })
+ .action(async (args) => {
+ await withWallet(args, async (wallet) => {
+ const pending = await wallet.client.call(
+ WalletApiOperation.GetPendingOperations,
+ {},
+ );
+ console.log(JSON.stringify(pending, undefined, 2));
+ });
+ });
+
+advancedCli
.subcommand("bench1", "bench1", {
help: "Run the 'bench1' benchmark",
})
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index 59980621f..aa74e327f 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -521,7 +521,7 @@ export interface ExchangeRecord {
* Should usually not change. Only changes when the
* exchange advertises a different master public key and/or
* currency.
- *
+ *
* FIXME: Use a rowId here?
*/
detailsPointer: ExchangeDetailsPointer | undefined;
@@ -1364,7 +1364,7 @@ export interface WithdrawalGroupRecord {
/**
* Wire information (as payto URI) for the bank account that
* transferred funds for this reserve.
- *
+ *
* FIXME: Doesn't this belong to the bankAccounts object store?
*/
senderWire?: string;
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts
index 142bedd83..d0da2e948 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -134,6 +134,7 @@ export async function downloadExchangeWithTermsOfService(
timeout: Duration,
contentType: string,
): Promise<ExchangeTosDownloadResult> {
+ logger.info(`downloading exchange tos (type ${contentType})`);
const reqUrl = new URL("terms", exchangeBaseUrl);
const headers = {
Accept: contentType,
@@ -524,7 +525,9 @@ export async function downloadTosFromAcceptedFormat(
break;
}
}
- if (tosFound !== undefined) return tosFound;
+ if (tosFound !== undefined) {
+ return tosFound;
+ }
// If none of the specified format was found try text/plain
return await downloadExchangeWithTermsOfService(
baseUrl,
@@ -557,7 +560,7 @@ export async function updateExchangeFromUrl(
*/
export async function updateExchangeFromUrlHandler(
ws: InternalWalletState,
- baseUrl: string,
+ exchangeBaseUrl: string,
options: {
forceNow?: boolean;
cancellationToken?: CancellationToken;
@@ -569,19 +572,21 @@ export async function updateExchangeFromUrlHandler(
}>
> {
const forceNow = options.forceNow ?? false;
- logger.info(`updating exchange info for ${baseUrl}, forced: ${forceNow}`);
+ logger.info(
+ `updating exchange info for ${exchangeBaseUrl}, forced: ${forceNow}`,
+ );
const now = AbsoluteTime.now();
- baseUrl = canonicalizeBaseUrl(baseUrl);
+ exchangeBaseUrl = canonicalizeBaseUrl(exchangeBaseUrl);
let isNewExchange = true;
const { exchange, exchangeDetails } = await ws.db
.mktx((x) => [x.exchanges, x.exchangeDetails])
.runReadWrite(async (tx) => {
- let oldExch = await tx.exchanges.get(baseUrl);
+ let oldExch = await tx.exchanges.get(exchangeBaseUrl);
if (oldExch) {
isNewExchange = false;
}
- return provideExchangeRecordInTx(ws, tx, baseUrl, now);
+ return provideExchangeRecordInTx(ws, tx, exchangeBaseUrl, now);
});
if (
@@ -600,11 +605,15 @@ export async function updateExchangeFromUrlHandler(
const timeout = getExchangeRequestTimeout();
- const keysInfo = await downloadExchangeKeysInfo(baseUrl, ws.http, timeout);
+ const keysInfo = await downloadExchangeKeysInfo(
+ exchangeBaseUrl,
+ ws.http,
+ timeout,
+ );
logger.info("updating exchange /wire info");
const wireInfoDownload = await downloadExchangeWireInfo(
- baseUrl,
+ exchangeBaseUrl,
ws.http,
timeout,
);
@@ -632,15 +641,15 @@ export async function updateExchangeFromUrlHandler(
logger.info("finished validating exchange /wire info");
+ // We download the text/plain version here,
+ // because that one needs to exist, and we
+ // will get the current etag from the response.
const tosDownload = await downloadTosFromAcceptedFormat(
ws,
- baseUrl,
+ exchangeBaseUrl,
timeout,
["text/plain"],
);
- const tosHasBeenAccepted =
- exchangeDetails?.tosAccepted &&
- exchangeDetails.tosAccepted.etag === tosDownload.tosEtag;
let recoupGroupId: string | undefined;
@@ -651,6 +660,7 @@ export async function updateExchangeFromUrlHandler(
const updated = await ws.db
.mktx((x) => [
x.exchanges,
+ x.exchangeTos,
x.exchangeDetails,
x.exchangeSignkeys,
x.denominations,
@@ -659,13 +669,13 @@ export async function updateExchangeFromUrlHandler(
x.recoupGroups,
])
.runReadWrite(async (tx) => {
- const r = await tx.exchanges.get(baseUrl);
+ const r = await tx.exchanges.get(exchangeBaseUrl);
if (!r) {
- logger.warn(`exchange ${baseUrl} no longer present`);
+ logger.warn(`exchange ${exchangeBaseUrl} no longer present`);
return;
}
let existingDetails = await getExchangeDetails(tx, r.baseUrl);
- let acceptedTosEtag = undefined;
+ let acceptedTosEtag: string | undefined = undefined;
if (!existingDetails) {
detailsPointerChanged = true;
}
@@ -708,6 +718,21 @@ export async function updateExchangeFromUrlHandler(
const drRowId = await tx.exchangeDetails.put(newDetails);
checkDbInvariant(typeof drRowId.key === "number");
+ let tosRecord = await tx.exchangeTos.get([
+ exchangeBaseUrl,
+ tosDownload.tosEtag,
+ ]);
+
+ if (!tosRecord || tosRecord.etag !== existingTosAccepted?.etag) {
+ tosRecord = {
+ etag: tosDownload.tosEtag,
+ exchangeBaseUrl,
+ termsOfServiceContentType: tosDownload.tosContentType,
+ termsOfServiceText: tosDownload.tosText,
+ };
+ await tx.exchangeTos.put(tosRecord);
+ }
+
for (const sk of keysInfo.signingKeys) {
// FIXME: validate signing keys before inserting them
await tx.exchangeSignKeys.put({
@@ -726,7 +751,7 @@ export async function updateExchangeFromUrlHandler(
);
for (const currentDenom of keysInfo.currentDenominations) {
const oldDenom = await tx.denominations.get([
- baseUrl,
+ exchangeBaseUrl,
currentDenom.denomPubHash,
]);
if (oldDenom) {
@@ -802,6 +827,7 @@ export async function updateExchangeFromUrlHandler(
newlyRevokedCoinPubs,
);
}
+
return {
exchange: r,
exchangeDetails: newDetails,
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index 7839f3dab..d97e5ba80 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -631,7 +631,7 @@ async function getExchangeTosStatusDetails(
return {
acceptedVersion: exchangeDetails.tosAccepted?.etag,
- content: exchangeTos.termsOfServiceContentType,
+ content: exchangeTos.termsOfServiceText,
contentType: exchangeTos.termsOfServiceContentType,
currentVersion: exchangeTos.etag,
};