summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/wxApi.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-webextension/src/wxApi.ts')
-rw-r--r--packages/taler-wallet-webextension/src/wxApi.ts510
1 files changed, 191 insertions, 319 deletions
diff --git a/packages/taler-wallet-webextension/src/wxApi.ts b/packages/taler-wallet-webextension/src/wxApi.ts
index 92597cbd2..195efecd4 100644
--- a/packages/taler-wallet-webextension/src/wxApi.ts
+++ b/packages/taler-wallet-webextension/src/wxApi.ts
@@ -1,17 +1,17 @@
/*
- This file is part of TALER
- (C) 2016 GNUnet e.V.
+ This file is part of GNU Taler
+ (C) 2022 Taler Systems S.A.
- TALER is free software; you can redistribute it and/or modify it under the
+ 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.
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ 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
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
@@ -22,343 +22,215 @@
* Imports.
*/
import {
+ AbsoluteTime,
CoreApiResponse,
- ConfirmPayResult,
- BalancesResponse,
- TransactionsResponse,
- ApplyRefundResponse,
- PreparePayResult,
- AcceptWithdrawalResponse,
- WalletDiagnostics,
- GetWithdrawalDetailsForUriRequest,
- WithdrawUriInfoResponse,
- PrepareTipRequest,
- PrepareTipResult,
- AcceptTipRequest,
- DeleteTransactionRequest,
- RetryTransactionRequest,
- SetWalletDeviceIdRequest,
- GetExchangeWithdrawalInfo,
- AcceptExchangeTosRequest,
- AcceptManualWithdrawalResult,
- AcceptManualWithdrawalRequest,
- AmountJson,
- ExchangesListRespose,
- AddExchangeRequest,
- GetExchangeTosResult,
+ DetailsMap,
+ Logger,
+ LogLevel,
+ NotificationType,
+ TalerError,
+ TalerErrorCode,
+ TalerErrorDetail,
+ WalletNotification
} from "@gnu-taler/taler-util";
-import { AddBackupProviderRequest, BackupProviderState, OperationFailedError, RemoveBackupProviderRequest } from "@gnu-taler/taler-wallet-core";
-import { BackupInfo } from "@gnu-taler/taler-wallet-core";
-import { ExchangeWithdrawDetails } from "@gnu-taler/taler-wallet-core/src/operations/withdraw";
-
-export interface ExtendedPermissionsResponse {
- newValue: boolean;
-}
-
-/**
- * Response with information about available version upgrades.
- */
-export interface UpgradeResponse {
- /**
- * Is a reset required because of a new DB version
- * that can't be automatically upgraded?
- */
- dbResetRequired: boolean;
-
- /**
- * Current database version.
- */
- currentDbVersion: string;
-
- /**
- * Old db version (if applicable).
- */
- oldDbVersion: string;
-}
-
-async function callBackend(operation: string, payload: any): Promise<any> {
- return new Promise<any>((resolve, reject) => {
- chrome.runtime.sendMessage({ operation, payload, id: "(none)" }, (resp) => {
- if (chrome.runtime.lastError) {
- console.log("Error calling backend");
- reject(
- new Error(
- `Error contacting backend: chrome.runtime.lastError.message`,
- ),
- );
- }
- console.log("got response", resp);
- const r = resp as CoreApiResponse;
- if (r.type === "error") {
- reject(new OperationFailedError(r.error));
- return;
- }
- resolve(r.result);
- });
- });
-}
-
-/**
- * Start refreshing a coin.
- */
-export function refresh(coinPub: string): Promise<void> {
- return callBackend("refresh-coin", { coinPub });
-}
-
-/**
- * Pay for a proposal.
- */
-export function confirmPay(
- proposalId: string,
- sessionId: string | undefined,
-): Promise<ConfirmPayResult> {
- return callBackend("confirmPay", { proposalId, sessionId });
-}
-
-/**
- * Check upgrade information
- */
-export function checkUpgrade(): Promise<UpgradeResponse> {
- return callBackend("check-upgrade", {});
-}
-
-/**
- * Reset database
- */
-export function resetDb(): Promise<void> {
- return callBackend("reset-db", {});
-}
-
-/**
- * Get balances for all currencies/exchanges.
- */
-export function getBalance(): Promise<BalancesResponse> {
- return callBackend("getBalances", {});
-}
-
-/**
- * Retrieve the full event history for this wallet.
- */
-export function getTransactions(): Promise<TransactionsResponse> {
- return callBackend("getTransactions", {});
-}
-
-interface CurrencyInfo {
- name: string;
- baseUrl: string;
- pub: string;
-}
-interface ListOfKnownCurrencies {
- auditors: CurrencyInfo[],
- exchanges: CurrencyInfo[],
-}
-
-/**
- * Get a list of currencies from known auditors and exchanges
- */
-export function listKnownCurrencies(): Promise<ListOfKnownCurrencies> {
- return callBackend("listCurrencies", {}).then(result => {
- console.log("result list", result)
- const auditors = result.trustedAuditors.map((a: Record<string, string>) => ({
- name: a.currency,
- baseUrl: a.auditorBaseUrl,
- pub: a.auditorPub,
- }))
- const exchanges = result.trustedExchanges.map((a: Record<string, string>) => ({
- name: a.currency,
- baseUrl: a.exchangeBaseUrl,
- pub: a.exchangeMasterPub,
- }))
- return { auditors, exchanges }
- });
-}
-
-export function listExchanges(): Promise<ExchangesListRespose> {
- return callBackend("listExchanges", {})
-}
-
-/**
- * Get information about the current state of wallet backups.
- */
-export function getBackupInfo(): Promise<BackupInfo> {
- return callBackend("getBackupInfo", {})
-}
-
-/**
- * Add a backup provider and activate it
- */
-export function addBackupProvider(backupProviderBaseUrl: string, name: string): Promise<void> {
- return callBackend("addBackupProvider", {
- backupProviderBaseUrl, activate: true, name
- } as AddBackupProviderRequest)
-}
-
-export function setWalletDeviceId(walletDeviceId: string): Promise<void> {
- return callBackend("setWalletDeviceId", {
- walletDeviceId
- } as SetWalletDeviceIdRequest)
-}
-
-export function syncAllProviders(): Promise<void> {
- return callBackend("runBackupCycle", {})
-}
-
-export function syncOneProvider(url: string): Promise<void> {
- return callBackend("runBackupCycle", { providers: [url] })
-}
-export function removeProvider(url: string): Promise<void> {
- return callBackend("removeBackupProvider", { provider: url } as RemoveBackupProviderRequest)
-}
-export function extendedProvider(url: string): Promise<void> {
- return callBackend("extendBackupProvider", { provider: url })
-}
-
-/**
- * Retry a transaction
- * @param transactionId
- * @returns
- */
-export function retryTransaction(transactionId: string): Promise<void> {
- return callBackend("retryTransaction", {
- transactionId
- } as RetryTransactionRequest);
-}
-
-/**
- * Permanently delete a transaction from the transaction list
- */
-export function deleteTransaction(transactionId: string): Promise<void> {
- return callBackend("deleteTransaction", {
- transactionId
- } as DeleteTransactionRequest);
-}
+import {
+ WalletCoreApiClient,
+ WalletCoreOpKeys,
+ WalletCoreRequestType,
+ WalletCoreResponseType,
+} from "@gnu-taler/taler-wallet-core";
+import {
+ ExtensionNotification,
+ MessageFromBackend,
+ MessageFromFrontendBackground,
+ MessageFromFrontendWallet,
+} from "./platform/api.js";
+import { platform } from "./platform/foreground.js";
/**
- * Download a refund and accept it.
+ *
+ * @author sebasjm
*/
-export function applyRefund(
- talerRefundUri: string,
-): Promise<ApplyRefundResponse> {
- return callBackend("applyRefund", { talerRefundUri });
-}
-/**
- * Get details about a pay operation.
- */
-export function preparePay(talerPayUri: string): Promise<PreparePayResult> {
- return callBackend("preparePay", { talerPayUri });
-}
+const logger = new Logger("wxApi");
-/**
- * Get details about a withdraw operation.
- */
-export function acceptWithdrawal(
- talerWithdrawUri: string,
- selectedExchange: string,
-): Promise<AcceptWithdrawalResponse> {
- return callBackend("acceptBankIntegratedWithdrawal", {
- talerWithdrawUri,
- exchangeBaseUrl: selectedExchange,
- });
-}
+export const WALLET_CORE_SUPPORTED_VERSION = "4:0:0"
-/**
- * Create a reserve into the exchange that expect the amount indicated
- * @param exchangeBaseUrl
- * @param amount
- * @returns
- */
-export function acceptManualWithdrawal(
- exchangeBaseUrl: string,
- amount: string,
-): Promise<AcceptManualWithdrawalResult> {
- return callBackend("acceptManualWithdrawal", {
- amount, exchangeBaseUrl
- });
+export interface ExtendedPermissionsResponse {
+ newValue: boolean;
}
-export function setExchangeTosAccepted(
- exchangeBaseUrl: string,
- etag: string | undefined
-): Promise<void> {
- return callBackend("setExchangeTosAccepted", {
- exchangeBaseUrl, etag
- } as AcceptExchangeTosRequest)
+export interface BackgroundOperations {
+ resetDb: {
+ request: void;
+ response: void;
+ };
+ runGarbageCollector: {
+ request: void;
+ response: void;
+ };
+ reinitWallet: {
+ request: void;
+ response: void;
+ };
+ getNotifications: {
+ request: void;
+ response: WalletEvent[];
+ };
+ clearNotifications: {
+ request: void;
+ response: void;
+ };
+ setLoggingLevel: {
+ request: {
+ tag?: string;
+ level: LogLevel;
+ };
+ response: void;
+ };
}
+export type WalletEvent = { notification: WalletNotification, when: AbsoluteTime }
-/**
- * Get diagnostics information
- */
-export function getDiagnostics(): Promise<WalletDiagnostics> {
- return callBackend("wxGetDiagnostics", {});
+export interface BackgroundApiClient {
+ call<Op extends keyof BackgroundOperations>(
+ operation: Op,
+ payload: BackgroundOperations[Op]["request"],
+ ): Promise<BackgroundOperations[Op]["response"]>;
}
-/**
- * Get diagnostics information
- */
-export function setExtendedPermissions(
- value: boolean,
-): Promise<ExtendedPermissionsResponse> {
- return callBackend("wxSetExtendedPermissions", { value });
-}
+export class BackgroundError<T = any> extends Error {
+ public readonly errorDetail: TalerErrorDetail & T;
+ public readonly cause: Error;
-/**
- * Get diagnostics information
- */
-export function getExtendedPermissions(): Promise<ExtendedPermissionsResponse> {
- return callBackend("wxGetExtendedPermissions", {});
-}
+ constructor(title: string, e: TalerErrorDetail & T, cause: Error) {
+ super(title);
+ this.errorDetail = e;
+ this.cause = cause;
+ }
-/**
- * Get diagnostics information
- */
-export function getWithdrawalDetailsForUri(
- req: GetWithdrawalDetailsForUriRequest,
-): Promise<WithdrawUriInfoResponse> {
- return callBackend("getWithdrawalDetailsForUri", req);
+ hasErrorCode<C extends keyof DetailsMap>(
+ code: C,
+ ): this is BackgroundError<DetailsMap[C]> {
+ return this.errorDetail.code === code;
+ }
}
-
/**
- * Get diagnostics information
+ * BackgroundApiClient integration with browser platform
*/
-export function getExchangeWithdrawalInfo(
- req: GetExchangeWithdrawalInfo,
-): Promise<ExchangeWithdrawDetails> {
- return callBackend("getExchangeWithdrawalInfo", req);
-}
-export function getExchangeTos(
- exchangeBaseUrl: string,
- acceptedFormat: string[],
-): Promise<GetExchangeTosResult> {
- return callBackend("getExchangeTos", {
- exchangeBaseUrl, acceptedFormat
- });
-}
-
-export function addExchange(
- req: AddExchangeRequest,
-): Promise<void> {
- return callBackend("addExchange", req);
-}
+class BackgroundApiClientImpl implements BackgroundApiClient {
+ async call<Op extends keyof BackgroundOperations>(
+ operation: Op,
+ payload: BackgroundOperations[Op]["request"],
+ ): Promise<BackgroundOperations[Op]["response"]> {
+ let response: CoreApiResponse;
+ const message: MessageFromFrontendBackground<Op> = {
+ channel: "background",
+ operation,
+ payload,
+ };
-export function prepareTip(req: PrepareTipRequest): Promise<PrepareTipResult> {
- return callBackend("prepareTip", req);
-}
-
-export function acceptTip(req: AcceptTipRequest): Promise<void> {
- return callBackend("acceptTip", req);
+ try {
+ response = await platform.sendMessageToBackground(message);
+ } catch (error) {
+ if (error instanceof Error) {
+ throw new BackgroundError(operation, {
+ code: TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR,
+ when: AbsoluteTime.now(),
+ }, error);
+ }
+ throw error;
+ }
+ if (response.type === "error") {
+ throw new BackgroundError(
+ `Background operation "${operation}" failed`,
+ response.error,
+ TalerError.fromUncheckedDetail(response.error),
+ );
+ }
+ logger.trace("response", response);
+ return response.result as any;
+ }
+}
+
+/**
+ * WalletCoreApiClient integration with browser platform
+ */
+class WalletApiClientImpl implements WalletCoreApiClient {
+ async call<Op extends WalletCoreOpKeys>(
+ operation: Op,
+ payload: WalletCoreRequestType<Op>,
+ ): Promise<WalletCoreResponseType<Op>> {
+ let response: CoreApiResponse;
+ try {
+ const message: MessageFromFrontendWallet<Op> = {
+ channel: "wallet",
+ operation,
+ payload,
+ };
+ response = await platform.sendMessageToBackground(message);
+ } catch (error) {
+ if (error instanceof Error) {
+ throw new BackgroundError(operation, {
+ code: TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR,
+ when: AbsoluteTime.now(),
+ }, error);
+ }
+ throw error;
+ }
+ if (response.type === "error") {
+ throw new BackgroundError(
+ `Wallet operation "${operation}" failed`,
+ response.error,
+ TalerError.fromUncheckedDetail(response.error)
+ );
+ }
+ logger.trace("got response", response);
+ return response.result as any;
+ }
+}
+
+function onUpdateNotification(
+ messageTypes: Array<NotificationType>,
+ doCallback: undefined | ((n: WalletNotification) => void),
+): () => void {
+ //if no callback, then ignore
+ if (!doCallback)
+ return () => {
+ return;
+ };
+ const onNewMessage = (message: MessageFromBackend): void => {
+ const shouldNotify = message.type === "wallet" && messageTypes.includes(message.notification.type);
+ if (shouldNotify) {
+ doCallback(message.notification);
+ }
+ };
+ return platform.listenToWalletBackground(onNewMessage);
}
-export function onUpdateNotification(f: () => void): () => void {
- const port = chrome.runtime.connect({ name: "notifications" });
- const listener = (): void => {
- f();
- };
- port.onMessage.addListener(listener);
- return () => {
- port.onMessage.removeListener(listener);
+export type WxApiType = {
+ wallet: WalletCoreApiClient;
+ background: BackgroundApiClient;
+ listener: {
+ trigger: (d: ExtensionNotification) => void;
+ onUpdateNotification: typeof onUpdateNotification;
};
-}
+};
+
+function trigger(w: ExtensionNotification) {
+ platform.triggerWalletEvent({
+ type: "web-extension",
+ notification: w,
+ })
+}
+
+export const wxApi = {
+ wallet: new WalletApiClientImpl(),
+ background: new BackgroundApiClientImpl(),
+ listener: {
+ trigger,
+ onUpdateNotification,
+ },
+};