wallet-core: CLI improvements, ToS fetching fixes
This commit is contained in:
parent
fbb7dd9e7e
commit
8d4a7d6103
@ -314,23 +314,13 @@ walletCli
|
|||||||
logger.info("finished handling API request");
|
logger.info("finished handling API request");
|
||||||
});
|
});
|
||||||
|
|
||||||
walletCli
|
const transactionsCli = walletCli
|
||||||
.subcommand("", "pending", { help: "Show pending operations." })
|
.subcommand("transactions", "transactions", { help: "Manage transactions." })
|
||||||
.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." })
|
|
||||||
.maybeOption("currency", ["--currency"], clk.STRING)
|
.maybeOption("currency", ["--currency"], clk.STRING)
|
||||||
.maybeOption("search", ["--search"], clk.STRING)
|
.maybeOption("search", ["--search"], clk.STRING);
|
||||||
.action(async (args) => {
|
|
||||||
|
// Default action
|
||||||
|
transactionsCli.action(async (args) => {
|
||||||
await withWallet(args, async (wallet) => {
|
await withWallet(args, async (wallet) => {
|
||||||
const pending = await wallet.client.call(
|
const pending = await wallet.client.call(
|
||||||
WalletApiOperation.GetTransactions,
|
WalletApiOperation.GetTransactions,
|
||||||
@ -341,21 +331,25 @@ walletCli
|
|||||||
);
|
);
|
||||||
console.log(JSON.stringify(pending, undefined, 2));
|
console.log(JSON.stringify(pending, undefined, 2));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
walletCli
|
transactionsCli
|
||||||
.subcommand("runPendingOpt", "run-pending", {
|
.subcommand("deleteTransaction", "delete", {
|
||||||
help: "Run pending operations.",
|
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) => {
|
.action(async (args) => {
|
||||||
await withWallet(args, async (wallet) => {
|
await withWallet(args, async (wallet) => {
|
||||||
await wallet.ws.runPending(args.runPendingOpt.forceNow);
|
await wallet.client.call(WalletApiOperation.DeleteTransaction, {
|
||||||
|
transactionId: args.deleteTransaction.transactionId,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
walletCli
|
transactionsCli
|
||||||
.subcommand("retryTransaction", "retry-transaction", {
|
.subcommand("retryTransaction", "retry", {
|
||||||
help: "Retry a transaction.",
|
help: "Retry a transaction.",
|
||||||
})
|
})
|
||||||
.requiredArgument("transactionId", clk.STRING)
|
.requiredArgument("transactionId", clk.STRING)
|
||||||
@ -387,21 +381,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
|
walletCli
|
||||||
.subcommand("withdraw", "withdraw", {
|
.subcommand("withdraw", "withdraw", {
|
||||||
help: "Withdraw with a taler://withdraw/ URI",
|
help: "Withdraw with a taler://withdraw/ URI",
|
||||||
@ -604,17 +583,26 @@ exchangesCli
|
|||||||
|
|
||||||
exchangesCli
|
exchangesCli
|
||||||
.subcommand("exchangesTosCmd", "tos", {
|
.subcommand("exchangesTosCmd", "tos", {
|
||||||
help: "Show terms of service.",
|
help: "Show/request terms of service.",
|
||||||
})
|
})
|
||||||
.requiredArgument("url", clk.STRING, {
|
.requiredArgument("url", clk.STRING, {
|
||||||
help: "Base URL of the exchange.",
|
help: "Base URL of the exchange.",
|
||||||
})
|
})
|
||||||
|
.maybeOption("contentTypes", ["--content-type"], clk.STRING)
|
||||||
.action(async (args) => {
|
.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) => {
|
await withWallet(args, async (wallet) => {
|
||||||
const tosResult = await wallet.client.call(
|
const tosResult = await wallet.client.call(
|
||||||
WalletApiOperation.GetExchangeTos,
|
WalletApiOperation.GetExchangeTos,
|
||||||
{
|
{
|
||||||
exchangeBaseUrl: args.exchangesTosCmd.url,
|
exchangeBaseUrl: args.exchangesTosCmd.url,
|
||||||
|
acceptedFormat,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
console.log(JSON.stringify(tosResult, undefined, 2));
|
console.log(JSON.stringify(tosResult, undefined, 2));
|
||||||
@ -764,6 +752,29 @@ advancedCli
|
|||||||
await withWallet(args, async () => {});
|
await withWallet(args, async () => {});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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
|
advancedCli
|
||||||
.subcommand("bench1", "bench1", {
|
.subcommand("bench1", "bench1", {
|
||||||
help: "Run the 'bench1' benchmark",
|
help: "Run the 'bench1' benchmark",
|
||||||
|
@ -134,6 +134,7 @@ export async function downloadExchangeWithTermsOfService(
|
|||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
contentType: string,
|
contentType: string,
|
||||||
): Promise<ExchangeTosDownloadResult> {
|
): Promise<ExchangeTosDownloadResult> {
|
||||||
|
logger.info(`downloading exchange tos (type ${contentType})`);
|
||||||
const reqUrl = new URL("terms", exchangeBaseUrl);
|
const reqUrl = new URL("terms", exchangeBaseUrl);
|
||||||
const headers = {
|
const headers = {
|
||||||
Accept: contentType,
|
Accept: contentType,
|
||||||
@ -524,7 +525,9 @@ export async function downloadTosFromAcceptedFormat(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tosFound !== undefined) return tosFound;
|
if (tosFound !== undefined) {
|
||||||
|
return tosFound;
|
||||||
|
}
|
||||||
// If none of the specified format was found try text/plain
|
// If none of the specified format was found try text/plain
|
||||||
return await downloadExchangeWithTermsOfService(
|
return await downloadExchangeWithTermsOfService(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
@ -557,7 +560,7 @@ export async function updateExchangeFromUrl(
|
|||||||
*/
|
*/
|
||||||
export async function updateExchangeFromUrlHandler(
|
export async function updateExchangeFromUrlHandler(
|
||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
baseUrl: string,
|
exchangeBaseUrl: string,
|
||||||
options: {
|
options: {
|
||||||
forceNow?: boolean;
|
forceNow?: boolean;
|
||||||
cancellationToken?: CancellationToken;
|
cancellationToken?: CancellationToken;
|
||||||
@ -569,19 +572,21 @@ export async function updateExchangeFromUrlHandler(
|
|||||||
}>
|
}>
|
||||||
> {
|
> {
|
||||||
const forceNow = options.forceNow ?? false;
|
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();
|
const now = AbsoluteTime.now();
|
||||||
baseUrl = canonicalizeBaseUrl(baseUrl);
|
exchangeBaseUrl = canonicalizeBaseUrl(exchangeBaseUrl);
|
||||||
let isNewExchange = true;
|
let isNewExchange = true;
|
||||||
const { exchange, exchangeDetails } = await ws.db
|
const { exchange, exchangeDetails } = await ws.db
|
||||||
.mktx((x) => [x.exchanges, x.exchangeDetails])
|
.mktx((x) => [x.exchanges, x.exchangeDetails])
|
||||||
.runReadWrite(async (tx) => {
|
.runReadWrite(async (tx) => {
|
||||||
let oldExch = await tx.exchanges.get(baseUrl);
|
let oldExch = await tx.exchanges.get(exchangeBaseUrl);
|
||||||
if (oldExch) {
|
if (oldExch) {
|
||||||
isNewExchange = false;
|
isNewExchange = false;
|
||||||
}
|
}
|
||||||
return provideExchangeRecordInTx(ws, tx, baseUrl, now);
|
return provideExchangeRecordInTx(ws, tx, exchangeBaseUrl, now);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -600,11 +605,15 @@ export async function updateExchangeFromUrlHandler(
|
|||||||
|
|
||||||
const timeout = getExchangeRequestTimeout();
|
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");
|
logger.info("updating exchange /wire info");
|
||||||
const wireInfoDownload = await downloadExchangeWireInfo(
|
const wireInfoDownload = await downloadExchangeWireInfo(
|
||||||
baseUrl,
|
exchangeBaseUrl,
|
||||||
ws.http,
|
ws.http,
|
||||||
timeout,
|
timeout,
|
||||||
);
|
);
|
||||||
@ -632,15 +641,15 @@ export async function updateExchangeFromUrlHandler(
|
|||||||
|
|
||||||
logger.info("finished validating exchange /wire info");
|
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(
|
const tosDownload = await downloadTosFromAcceptedFormat(
|
||||||
ws,
|
ws,
|
||||||
baseUrl,
|
exchangeBaseUrl,
|
||||||
timeout,
|
timeout,
|
||||||
["text/plain"],
|
["text/plain"],
|
||||||
);
|
);
|
||||||
const tosHasBeenAccepted =
|
|
||||||
exchangeDetails?.tosAccepted &&
|
|
||||||
exchangeDetails.tosAccepted.etag === tosDownload.tosEtag;
|
|
||||||
|
|
||||||
let recoupGroupId: string | undefined;
|
let recoupGroupId: string | undefined;
|
||||||
|
|
||||||
@ -651,6 +660,7 @@ export async function updateExchangeFromUrlHandler(
|
|||||||
const updated = await ws.db
|
const updated = await ws.db
|
||||||
.mktx((x) => [
|
.mktx((x) => [
|
||||||
x.exchanges,
|
x.exchanges,
|
||||||
|
x.exchangeTos,
|
||||||
x.exchangeDetails,
|
x.exchangeDetails,
|
||||||
x.exchangeSignkeys,
|
x.exchangeSignkeys,
|
||||||
x.denominations,
|
x.denominations,
|
||||||
@ -659,13 +669,13 @@ export async function updateExchangeFromUrlHandler(
|
|||||||
x.recoupGroups,
|
x.recoupGroups,
|
||||||
])
|
])
|
||||||
.runReadWrite(async (tx) => {
|
.runReadWrite(async (tx) => {
|
||||||
const r = await tx.exchanges.get(baseUrl);
|
const r = await tx.exchanges.get(exchangeBaseUrl);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
logger.warn(`exchange ${baseUrl} no longer present`);
|
logger.warn(`exchange ${exchangeBaseUrl} no longer present`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let existingDetails = await getExchangeDetails(tx, r.baseUrl);
|
let existingDetails = await getExchangeDetails(tx, r.baseUrl);
|
||||||
let acceptedTosEtag = undefined;
|
let acceptedTosEtag: string | undefined = undefined;
|
||||||
if (!existingDetails) {
|
if (!existingDetails) {
|
||||||
detailsPointerChanged = true;
|
detailsPointerChanged = true;
|
||||||
}
|
}
|
||||||
@ -708,6 +718,21 @@ export async function updateExchangeFromUrlHandler(
|
|||||||
const drRowId = await tx.exchangeDetails.put(newDetails);
|
const drRowId = await tx.exchangeDetails.put(newDetails);
|
||||||
checkDbInvariant(typeof drRowId.key === "number");
|
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) {
|
for (const sk of keysInfo.signingKeys) {
|
||||||
// FIXME: validate signing keys before inserting them
|
// FIXME: validate signing keys before inserting them
|
||||||
await tx.exchangeSignKeys.put({
|
await tx.exchangeSignKeys.put({
|
||||||
@ -726,7 +751,7 @@ export async function updateExchangeFromUrlHandler(
|
|||||||
);
|
);
|
||||||
for (const currentDenom of keysInfo.currentDenominations) {
|
for (const currentDenom of keysInfo.currentDenominations) {
|
||||||
const oldDenom = await tx.denominations.get([
|
const oldDenom = await tx.denominations.get([
|
||||||
baseUrl,
|
exchangeBaseUrl,
|
||||||
currentDenom.denomPubHash,
|
currentDenom.denomPubHash,
|
||||||
]);
|
]);
|
||||||
if (oldDenom) {
|
if (oldDenom) {
|
||||||
@ -802,6 +827,7 @@ export async function updateExchangeFromUrlHandler(
|
|||||||
newlyRevokedCoinPubs,
|
newlyRevokedCoinPubs,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
exchange: r,
|
exchange: r,
|
||||||
exchangeDetails: newDetails,
|
exchangeDetails: newDetails,
|
||||||
|
@ -631,7 +631,7 @@ async function getExchangeTosStatusDetails(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
acceptedVersion: exchangeDetails.tosAccepted?.etag,
|
acceptedVersion: exchangeDetails.tosAccepted?.etag,
|
||||||
content: exchangeTos.termsOfServiceContentType,
|
content: exchangeTos.termsOfServiceText,
|
||||||
contentType: exchangeTos.termsOfServiceContentType,
|
contentType: exchangeTos.termsOfServiceContentType,
|
||||||
currentVersion: exchangeTos.etag,
|
currentVersion: exchangeTos.etag,
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user