summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/taler-util/src/taleruri.ts80
-rw-r--r--packages/taler-util/src/wallet-types.ts2
-rw-r--r--packages/taler-wallet-core/src/operations/pay-merchant.ts48
-rw-r--r--packages/taler-wallet-core/src/operations/refresh.ts57
-rw-r--r--packages/taler-wallet-core/src/util/promiseUtils.ts5
-rw-r--r--packages/taler-wallet-core/src/wallet.ts95
-rw-r--r--packages/taler-wallet-webextension/src/wallet/BackupPage.tsx9
7 files changed, 130 insertions, 166 deletions
diff --git a/packages/taler-util/src/taleruri.ts b/packages/taler-util/src/taleruri.ts
index ff164dbbd..8f37dfe76 100644
--- a/packages/taler-util/src/taleruri.ts
+++ b/packages/taler-util/src/taleruri.ts
@@ -14,11 +14,23 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
+/**
+ * @fileoverview
+ * Construction and parsing of taler:// URIs.
+ * Specification: https://lsd.gnunet.org/lsd0006/
+ */
+
+/**
+ * Imports.
+ */
import { Codec, Context, DecodingError, renderContext } from "./codec.js";
import { canonicalizeBaseUrl } from "./helpers.js";
import { AmountString } from "./taler-types.js";
-import { URLSearchParams, URL } from "./url.js";
+import { URL, URLSearchParams } from "./url.js";
+/**
+ * A parsed taler URI.
+ */
export type TalerUri =
| PayUriResult
| PayTemplateUriResult
@@ -181,10 +193,6 @@ export enum TalerUriType {
Unknown = "unknown",
}
-const talerActionPayPull = "pay-pull";
-const talerActionPayPush = "pay-push";
-const talerActionPayTemplate = "pay-template";
-
export enum TalerUriAction {
Pay = "pay",
Withdraw = "withdraw",
@@ -332,7 +340,7 @@ export function parsePayUri(s: string): PayUriResult | undefined {
export function parsePayTemplateUri(
uriString: string,
): PayTemplateUriResult | undefined {
- const pi = parseProtoInfo(uriString, talerActionPayTemplate);
+ const pi = parseProtoInfo(uriString, TalerUriAction.PayTemplate);
if (!pi) {
return undefined;
}
@@ -366,7 +374,7 @@ export function parsePayTemplateUri(
}
export function parsePayPushUri(s: string): PayPushUriResult | undefined {
- const pi = parseProtoInfo(s, talerActionPayPush);
+ const pi = parseProtoInfo(s, TalerUriAction.PayPush);
if (!pi) {
return undefined;
}
@@ -391,7 +399,7 @@ export function parsePayPushUri(s: string): PayPushUriResult | undefined {
}
export function parsePayPullUri(s: string): PayPullUriResult | undefined {
- const pi = parseProtoInfo(s, talerActionPayPull);
+ const pi = parseProtoInfo(s, TalerUriAction.PayPull);
if (!pi) {
return undefined;
}
@@ -598,56 +606,6 @@ export function parseRestoreUri(uri: string): BackupRestoreUri | undefined {
// To string functions
// ================================================
-/**
- * @deprecated use stringifyRecoveryUri
- */
-export function constructRecoveryUri(args: {
- walletRootPriv: string;
- providers: string[];
-}): string {
- return stringifyRestoreUri(args);
-}
-
-/**
- * @deprecated stringifyPayPullUri
- */
-export function constructPayPullUri(args: {
- exchangeBaseUrl: string;
- contractPriv: string;
-}): string {
- return stringifyPayPullUri(args);
-}
-
-/**
- * @deprecated use stringifyPayPushUri
- */
-export function constructPayPushUri(args: {
- exchangeBaseUrl: string;
- contractPriv: string;
-}): string {
- return stringifyPayPushUri(args);
-}
-
-/**
- *
- * @deprecated use stringifyPayUri
- */
-export function constructPayUri(
- merchantBaseUrl: string,
- orderId: string,
- sessionId: string,
- claimToken?: string,
- noncePriv?: string,
-): string {
- return stringifyPayUri({
- merchantBaseUrl,
- orderId,
- sessionId,
- claimToken,
- noncePriv,
- });
-}
-
export function stringifyPayUri({
merchantBaseUrl,
orderId,
@@ -714,6 +672,7 @@ export function stringifyPayTemplateUri({
const { proto, path, query } = getUrlInfo(merchantBaseUrl, templateParams);
return `${proto}://pay-template/${path}${templateId}${query}`;
}
+
export function stringifyRefundUri({
merchantBaseUrl,
orderId,
@@ -721,6 +680,7 @@ export function stringifyRefundUri({
const { proto, path } = getUrlInfo(merchantBaseUrl);
return `${proto}://refund/${path}${orderId}/`;
}
+
export function stringifyRewardUri({
merchantBaseUrl,
merchantRewardId,
@@ -757,10 +717,6 @@ export function stringifyWithdrawUri({
* Use baseUrl to defined http or https
* create path using host+port+pathname
* use params to create a query parameter string or empty
- *
- * @param baseUrl
- * @param params
- * @returns
*/
function getUrlInfo(
baseUrl: string,
diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts
index a11d858fa..8ccc93c38 100644
--- a/packages/taler-util/src/wallet-types.ts
+++ b/packages/taler-util/src/wallet-types.ts
@@ -1046,6 +1046,8 @@ export interface CoinRefreshRequest {
/**
* Wrapper for refresh group IDs.
+ *
+ * @deprecated use types instead
*/
export interface RefreshGroupId {
readonly refreshGroupId: string;
diff --git a/packages/taler-wallet-core/src/operations/pay-merchant.ts b/packages/taler-wallet-core/src/operations/pay-merchant.ts
index 5d58f4c2f..a81311702 100644
--- a/packages/taler-wallet-core/src/operations/pay-merchant.ts
+++ b/packages/taler-wallet-core/src/operations/pay-merchant.ts
@@ -30,11 +30,13 @@ import {
AbsoluteTime,
AmountJson,
Amounts,
+ AmountString,
codecForAbortResponse,
codecForMerchantContractTerms,
codecForMerchantOrderRefundPickupResponse,
codecForMerchantOrderStatusPaid,
codecForMerchantPayResponse,
+ codecForMerchantPostOrderResponse,
codecForProposal,
CoinDepositPermission,
CoinRefreshRequest,
@@ -53,12 +55,15 @@ import {
MerchantCoinRefundStatus,
MerchantContractTerms,
MerchantPayResponse,
+ MerchantUsingTemplateDetails,
NotificationType,
+ parsePayTemplateUri,
parsePayUri,
parseTalerUri,
PayCoinSelection,
PreparePayResult,
PreparePayResultType,
+ PreparePayTemplateRequest,
randomBytes,
RefreshReason,
SharePaymentResult,
@@ -1209,6 +1214,49 @@ export async function preparePayForUri(
return checkPaymentByProposalId(ws, proposalId, uriResult.sessionId);
}
+export async function preparePayForTemplate(
+ ws: InternalWalletState,
+ req: PreparePayTemplateRequest,
+): Promise<PreparePayResult> {
+ const url = parsePayTemplateUri(req.talerPayTemplateUri);
+ const templateDetails: MerchantUsingTemplateDetails = {};
+ if (!url) {
+ throw Error("invalid taler-template URI");
+ }
+ if (
+ url.templateParams.amount !== undefined &&
+ typeof url.templateParams.amount === "string"
+ ) {
+ templateDetails.amount = (req.templateParams.amount ??
+ url.templateParams.amount) as AmountString | undefined;
+ }
+ if (
+ url.templateParams.summary !== undefined &&
+ typeof url.templateParams.summary === "string"
+ ) {
+ templateDetails.summary =
+ req.templateParams.summary ?? url.templateParams.summary;
+ }
+ const reqUrl = new URL(`templates/${url.templateId}`, url.merchantBaseUrl);
+ const httpReq = await ws.http.fetch(reqUrl.href, {
+ method: "POST",
+ body: templateDetails,
+ });
+ const resp = await readSuccessResponseJsonOrThrow(
+ httpReq,
+ codecForMerchantPostOrderResponse(),
+ );
+
+ const payUri = stringifyPayUri({
+ merchantBaseUrl: url.merchantBaseUrl,
+ orderId: resp.order_id,
+ sessionId: "",
+ claimToken: resp.token,
+ });
+
+ return await preparePayForUri(ws, payUri);
+}
+
/**
* Generate deposit permissions for a purchase.
*
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts b/packages/taler-wallet-core/src/operations/refresh.ts
index a8bcb28d1..390433f66 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -36,6 +36,7 @@ import {
ExchangeProtocolVersion,
ExchangeRefreshRevealRequest,
fnutil,
+ ForceRefreshRequest,
getErrorDetailFromException,
getRandomBytes,
HashCodeString,
@@ -79,8 +80,6 @@ import {
} from "../db.js";
import {
getCandidateWithdrawalDenomsTx,
- isWithdrawableDenom,
- PendingTaskType,
RefreshSessionRecord,
timestampPreciseToDb,
timestampProtocolFromDb,
@@ -93,13 +92,8 @@ import {
import { assertUnreachable } from "../util/assertUnreachable.js";
import { selectWithdrawalDenominations } from "../util/coinSelection.js";
import { checkDbInvariant } from "../util/invariants.js";
+import { GetReadOnlyAccess, GetReadWriteAccess } from "../util/query.js";
import {
- DbReadWriteTransaction,
- GetReadOnlyAccess,
- GetReadWriteAccess,
-} from "../util/query.js";
-import {
- constructTaskIdentifier,
makeCoinAvailable,
makeCoinsVisible,
TaskRunResult,
@@ -1449,3 +1443,50 @@ export async function abortRefreshGroup(
ws.workAvailable.trigger();
notifyTransition(ws, transactionId, transitionInfo);
}
+
+export async function forceRefresh(
+ ws: InternalWalletState,
+ req: ForceRefreshRequest,
+): Promise<{ refreshGroupId: RefreshGroupId }> {
+ if (req.coinPubList.length == 0) {
+ throw Error("refusing to create empty refresh group");
+ }
+ const refreshGroupId = await ws.db
+ .mktx((x) => [
+ x.refreshGroups,
+ x.coinAvailability,
+ x.denominations,
+ x.coins,
+ ])
+ .runReadWrite(async (tx) => {
+ let coinPubs: CoinRefreshRequest[] = [];
+ for (const c of req.coinPubList) {
+ const coin = await tx.coins.get(c);
+ if (!coin) {
+ throw Error(`coin (pubkey ${c}) not found`);
+ }
+ const denom = await ws.getDenomInfo(
+ ws,
+ tx,
+ coin.exchangeBaseUrl,
+ coin.denomPubHash,
+ );
+ checkDbInvariant(!!denom);
+ coinPubs.push({
+ coinPub: c,
+ amount: denom?.value,
+ });
+ }
+ return await createRefreshGroup(
+ ws,
+ tx,
+ Amounts.currencyOf(coinPubs[0].amount),
+ coinPubs,
+ RefreshReason.Manual,
+ );
+ });
+
+ return {
+ refreshGroupId,
+ };
+}
diff --git a/packages/taler-wallet-core/src/util/promiseUtils.ts b/packages/taler-wallet-core/src/util/promiseUtils.ts
index 23f1c06a5..df4cc343b 100644
--- a/packages/taler-wallet-core/src/util/promiseUtils.ts
+++ b/packages/taler-wallet-core/src/util/promiseUtils.ts
@@ -14,6 +14,11 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
+/**
+ * An opened promise.
+ *
+ * @see {@link openPromise}
+ */
export interface OpenedPromise<T> {
promise: Promise<T>;
resolve: (val: T) => void;
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index ff1f991dd..da34ff37f 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -28,7 +28,6 @@ import {
AmountString,
Amounts,
CoinDumpJson,
- CoinRefreshRequest,
CoinStatus,
CoreApiResponse,
CreateStoredBackupResponse,
@@ -41,12 +40,10 @@ import {
KnownBankAccounts,
KnownBankAccountsInfo,
Logger,
- MerchantUsingTemplateDetails,
NotificationType,
PrepareWithdrawExchangeRequest,
PrepareWithdrawExchangeResponse,
RecoverStoredBackupRequest,
- RefreshReason,
ScopeType,
StoredBackupList,
TalerError,
@@ -56,7 +53,6 @@ import {
TestingWaitTransactionRequest,
TransactionState,
TransactionType,
- URL,
ValidateIbanResponse,
WalletCoreVersion,
WalletNotification,
@@ -97,7 +93,6 @@ import {
codecForIntegrationTestV2Args,
codecForListExchangesForScopedCurrencyRequest,
codecForListKnownBankAccounts,
- codecForMerchantPostOrderResponse,
codecForPrepareDepositRequest,
codecForPreparePayRequest,
codecForPreparePayTemplateRequest,
@@ -123,12 +118,10 @@ import {
codecForUserAttentionsRequest,
codecForValidateIbanRequest,
codecForWithdrawTestBalance,
- constructPayUri,
durationFromSpec,
durationMin,
getErrorDetailFromException,
j2s,
- parsePayTemplateUri,
parsePaytoUri,
parseTalerUri,
sampleWalletCoreTransactions,
@@ -136,7 +129,6 @@ import {
validateIban,
} from "@gnu-taler/taler-util";
import type { HttpRequestLibrary } from "@gnu-taler/taler-util/http";
-import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
import {
CryptoDispatcher,
@@ -211,6 +203,7 @@ import {
computeRefundTransactionState,
confirmPay,
getContractTermsDetails,
+ preparePayForTemplate,
preparePayForUri,
processPurchase,
sharePayment,
@@ -247,6 +240,7 @@ import {
autoRefresh,
computeRefreshTransactionState,
createRefreshGroup,
+ forceRefresh,
processRefreshGroup,
} from "./operations/refresh.js";
import {
@@ -1115,46 +1109,7 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
}
case WalletApiOperation.PreparePayForTemplate: {
const req = codecForPreparePayTemplateRequest().decode(payload);
- const url = parsePayTemplateUri(req.talerPayTemplateUri);
- const templateDetails: MerchantUsingTemplateDetails = {};
- if (!url) {
- throw Error("invalid taler-template URI");
- }
- if (
- url.templateParams.amount !== undefined &&
- typeof url.templateParams.amount === "string"
- ) {
- templateDetails.amount = (req.templateParams.amount ??
- url.templateParams.amount) as AmountString | undefined;
- }
- if (
- url.templateParams.summary !== undefined &&
- typeof url.templateParams.summary === "string"
- ) {
- templateDetails.summary =
- req.templateParams.summary ?? url.templateParams.summary;
- }
- const reqUrl = new URL(
- `templates/${url.templateId}`,
- url.merchantBaseUrl,
- );
- const httpReq = await ws.http.fetch(reqUrl.href, {
- method: "POST",
- body: templateDetails,
- });
- const resp = await readSuccessResponseJsonOrThrow(
- httpReq,
- codecForMerchantPostOrderResponse(),
- );
-
- const payUri = constructPayUri(
- url.merchantBaseUrl,
- resp.order_id,
- "",
- resp.token,
- );
-
- return await preparePayForUri(ws, payUri);
+ return preparePayForTemplate(ws, req);
}
case WalletApiOperation.ConfirmPay: {
const req = codecForConfirmPayRequest().decode(payload);
@@ -1205,49 +1160,7 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
return { transactions: sampleWalletCoreTransactions };
case WalletApiOperation.ForceRefresh: {
const req = codecForForceRefreshRequest().decode(payload);
- if (req.coinPubList.length == 0) {
- throw Error("refusing to create empty refresh group");
- }
- const refreshGroupId = await ws.db
- .mktx((x) => [
- x.refreshGroups,
- x.coinAvailability,
- x.denominations,
- x.coins,
- ])
- .runReadWrite(async (tx) => {
- let coinPubs: CoinRefreshRequest[] = [];
- for (const c of req.coinPubList) {
- const coin = await tx.coins.get(c);
- if (!coin) {
- throw Error(`coin (pubkey ${c}) not found`);
- }
- const denom = await ws.getDenomInfo(
- ws,
- tx,
- coin.exchangeBaseUrl,
- coin.denomPubHash,
- );
- checkDbInvariant(!!denom);
- coinPubs.push({
- coinPub: c,
- amount: denom?.value,
- });
- }
- return await createRefreshGroup(
- ws,
- tx,
- Amounts.currencyOf(coinPubs[0].amount),
- coinPubs,
- RefreshReason.Manual,
- );
- });
- processRefreshGroup(ws, refreshGroupId.refreshGroupId).catch((x) => {
- logger.error(x);
- });
- return {
- refreshGroupId,
- };
+ return await forceRefresh(ws, req);
}
case WalletApiOperation.PrepareReward: {
const req = codecForPrepareRewardRequest().decode(payload);
diff --git a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
index 5ae52db6f..b460d9f88 100644
--- a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
@@ -16,8 +16,7 @@
import {
AbsoluteTime,
- constructRecoveryUri,
- stringifyRestoreUri,
+ stringifyRestoreUri
} from "@gnu-taler/taler-util";
import {
ProviderInfo,
@@ -26,13 +25,15 @@ import {
ProviderPaymentType,
WalletApiOperation,
} from "@gnu-taler/taler-wallet-core";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
import {
differenceInMonths,
formatDuration,
intervalToDuration,
} from "date-fns";
-import { Fragment, h, VNode } from "preact";
+import { Fragment, VNode, h } from "preact";
import { useEffect, useState } from "preact/hooks";
+import { Pages } from "../NavigationBar.js";
import { ErrorAlertView } from "../components/CurrentAlerts.js";
import { Loading } from "../components/Loading.js";
import { QR } from "../components/QR.js";
@@ -48,10 +49,8 @@ import {
} from "../components/styled/index.js";
import { alertFromError } from "../context/alert.js";
import { useBackendContext } from "../context/backend.js";
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
import { Button } from "../mui/Button.js";
-import { Pages } from "../NavigationBar.js";
interface Props {
onAddProvider: () => Promise<void>;