/* This file is part of GNU Taler (C) 2022 Taler Systems S.A. 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. 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 GNU Taler; see the file COPYING. If not, see */ /** * Interface to the wallet through WebExtension messaging. */ /** * Imports. */ import { AcceptExchangeTosRequest, AcceptManualWithdrawalResult, AcceptPeerPullPaymentRequest, AcceptPeerPullPaymentResponse, AcceptPeerPushPaymentRequest, AcceptPeerPushPaymentResponse, AcceptTipRequest, AcceptTipResponse, AcceptWithdrawalResponse, AddExchangeRequest, AddKnownBankAccountsRequest, AmountString, ApplyRefundResponse, BalancesResponse, CheckPeerPullPaymentRequest, CheckPeerPullPaymentResponse, CheckPeerPushPaymentRequest, CheckPeerPushPaymentResponse, CoinDumpJson, ConfirmPayResult, CoreApiResponse, CreateDepositGroupRequest, CreateDepositGroupResponse, DeleteTransactionRequest, DepositGroupFees, ExchangeFullDetails, ExchangesListResponse, ForgetKnownBankAccountsRequest, GetExchangeTosResult, GetFeeForDepositRequest, GetWithdrawalDetailsForAmountRequest, GetWithdrawalDetailsForUriRequest, InitiatePeerPullPaymentRequest, InitiatePeerPullPaymentResponse, InitiatePeerPushPaymentRequest, InitiatePeerPushPaymentResponse, KnownBankAccounts, Logger, ManualWithdrawalDetails, NotificationType, PaytoUri, PrepareDepositRequest, PrepareDepositResponse, PreparePayResult, PrepareRefundRequest, PrepareRefundResult, PrepareTipRequest, PrepareTipResult, RetryTransactionRequest, SetWalletDeviceIdRequest, stringifyPaytoUri, Transaction, TransactionsResponse, WalletCoreVersion, WalletDiagnostics, WithdrawUriInfoResponse, } from "@gnu-taler/taler-util"; import { AddBackupProviderRequest, BackupInfo, PendingOperationsResponse, RemoveBackupProviderRequest, TalerError, WalletApiOperation, WalletContractData, WalletCoreApiClient, WalletCoreOpKeys, WalletCoreRequestType, WalletCoreResponseType, } from "@gnu-taler/taler-wallet-core"; import { MessageFromBackend, platform } from "./platform/api.js"; /** * * @author Florian Dold * @author sebasjm */ export interface ExtendedPermissionsResponse { newValue: boolean; } const logger = new Logger("wxApi"); /** * 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; } /** * @deprecated Use {@link WxWalletCoreApiClient} instead. */ async function callBackend(operation: string, payload: any): Promise { let response: CoreApiResponse; try { response = await platform.sendMessageToWalletBackground(operation, payload); } catch (e) { console.log("Error calling backend"); throw new Error(`Error contacting backend: ${e}`); } logger.info("got response", response); if (response.type === "error") { throw TalerError.fromUncheckedDetail(response.error); } return response.result; } export class WxWalletCoreApiClient implements WalletCoreApiClient { async call( operation: Op, payload: WalletCoreRequestType, ): Promise> { let response: CoreApiResponse; try { response = await platform.sendMessageToWalletBackground( operation, payload, ); } catch (e) { console.log("Error calling backend"); throw new Error(`Error contacting backend: ${e}`); } logger.info("got response", response); if (response.type === "error") { throw TalerError.fromUncheckedDetail(response.error); } return response.result as any; } } const wxClient = new WxWalletCoreApiClient(); /** * Pay for a proposal. */ export function confirmPay( proposalId: string, sessionId: string | undefined, ): Promise { return wxClient.call(WalletApiOperation.ConfirmPay, { proposalId, sessionId, }); } /** * Check upgrade information */ export function checkUpgrade(): Promise { return callBackend("check-upgrade", {}); } /** * Reset database */ export function resetDb(): Promise { return callBackend("reset-db", {}); } /** * Reset database */ export function runGarbageCollector(): Promise { return callBackend("run-gc", {}); } export function getFeeForDeposit( depositPaytoUri: string, amount: AmountString, ): Promise { return callBackend("getFeeForDeposit", { depositPaytoUri, amount, } as GetFeeForDepositRequest); } export function prepareDeposit( depositPaytoUri: string, amount: AmountString, ): Promise { return callBackend("prepareDeposit", { depositPaytoUri, amount, } as PrepareDepositRequest); } export function createDepositGroup( depositPaytoUri: string, amount: AmountString, ): Promise { return callBackend("createDepositGroup", { depositPaytoUri, amount, } as CreateDepositGroupRequest); } /** * Get balances for all currencies/exchanges. */ export function getBalance(): Promise { return callBackend("getBalances", {}); } export function getContractTermsDetails( proposalId: string, ): Promise { return callBackend("getContractTermsDetails", { proposalId }); } /** * Retrieve the full event history for this wallet. */ export function getTransactions(): Promise { 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 { return callBackend("listCurrencies", {}).then((result) => { const auditors = result.trustedAuditors.map( (a: Record) => ({ name: a.currency, baseUrl: a.auditorBaseUrl, pub: a.auditorPub, }), ); const exchanges = result.trustedExchanges.map( (a: Record) => ({ name: a.currency, baseUrl: a.exchangeBaseUrl, pub: a.exchangeMasterPub, }), ); return { auditors, exchanges }; }); } export function listExchanges(): Promise { return callBackend("listExchanges", {}); } export function getExchangeDetailedInfo( exchangeBaseUrl: string, ): Promise { return callBackend("getExchangeDetailedInfo", { exchangeBaseUrl, }); } export function getVersion(): Promise { return callBackend("getVersion", {}); } export function listKnownBankAccounts( currency?: string, ): Promise { return callBackend("listKnownBankAccounts", { currency }); } export function addKnownBankAccounts( payto: PaytoUri, currency: string, alias: string, ): Promise { return callBackend("addKnownBankAccounts", { payto: stringifyPaytoUri(payto), currency, alias, } as AddKnownBankAccountsRequest); } export function forgetKnownBankAccounts(payto: string): Promise { return callBackend("forgetKnownBankAccounts", { payto, } as ForgetKnownBankAccountsRequest); } /** * Get information about the current state of wallet backups. */ export function getBackupInfo(): Promise { return callBackend("getBackupInfo", {}); } /** * Add a backup provider and activate it */ export function addBackupProvider( backupProviderBaseUrl: string, name: string, ): Promise { return callBackend("addBackupProvider", { backupProviderBaseUrl, activate: true, name, } as AddBackupProviderRequest); } export function setWalletDeviceId(walletDeviceId: string): Promise { return callBackend("setWalletDeviceId", { walletDeviceId, } as SetWalletDeviceIdRequest); } export function syncAllProviders(): Promise { return callBackend("runBackupCycle", {}); } export function syncOneProvider(url: string): Promise { return callBackend("runBackupCycle", { providers: [url] }); } export function removeProvider(url: string): Promise { return callBackend("removeBackupProvider", { provider: url, } as RemoveBackupProviderRequest); } export function extendedProvider(url: string): Promise { return callBackend("extendBackupProvider", { provider: url }); } /** * Retry a transaction * @param transactionId * @returns */ export function retryTransaction(transactionId: string): Promise { return callBackend("retryTransaction", { transactionId, } as RetryTransactionRequest); } /** * Permanently delete a transaction from the transaction list */ export function deleteTransaction(transactionId: string): Promise { return callBackend("deleteTransaction", { transactionId, } as DeleteTransactionRequest); } /** * Download a refund and accept it. */ export function applyRefund( talerRefundUri: string, ): Promise { return callBackend("applyRefund", { talerRefundUri }); } /** * Do refund for purchase. */ export function applyRefundFromPurchaseId( purchaseId: string, ): Promise { return callBackend("applyRefundFromPurchaseId", { purchaseId }); } /** * Get details about a pay operation. */ export function preparePay(talerPayUri: string): Promise { return callBackend("preparePayForUri", { talerPayUri }); } /** * Get details about a withdraw operation. */ export function acceptWithdrawal( talerWithdrawUri: string, selectedExchange: string, restrictAge?: number, ): Promise { return callBackend("acceptBankIntegratedWithdrawal", { talerWithdrawUri, exchangeBaseUrl: selectedExchange, restrictAge, }); } /** * Create a reserve into the exchange that expect the amount indicated * @param exchangeBaseUrl * @param amount * @returns */ export function acceptManualWithdrawal( exchangeBaseUrl: string, amount: string, restrictAge?: number, ): Promise { return callBackend("acceptManualWithdrawal", { amount, exchangeBaseUrl, restrictAge, }); } export function setExchangeTosAccepted( exchangeBaseUrl: string, etag: string | undefined, ): Promise { return callBackend("setExchangeTosAccepted", { exchangeBaseUrl, etag, } as AcceptExchangeTosRequest); } /** * Get diagnostics information */ export function getDiagnostics(): Promise { return callBackend("wxGetDiagnostics", {}); } /** * Get diagnostics information */ export function toggleHeaderListener( value: boolean, ): Promise { return callBackend("toggleHeaderListener", { value }); } /** * Get diagnostics information */ export function containsHeaderListener(): Promise { return callBackend("containsHeaderListener", {}); } /** * Get diagnostics information */ export function getWithdrawalDetailsForUri( req: GetWithdrawalDetailsForUriRequest, ): Promise { return callBackend("getWithdrawalDetailsForUri", req); } export function getWithdrawalDetailsForAmount( req: GetWithdrawalDetailsForAmountRequest, ): Promise { return callBackend("getWithdrawalDetailsForAmount", req); } export function getExchangeTos( exchangeBaseUrl: string, acceptedFormat: string[], ): Promise { return callBackend("getExchangeTos", { exchangeBaseUrl, acceptedFormat, }); } export function dumpCoins(): Promise { return callBackend("dumpCoins", {}); } export function getPendingOperations(): Promise { return callBackend("getPendingOperations", {}); } export function addExchange(req: AddExchangeRequest): Promise { return callBackend("addExchange", req); } export function prepareRefund( req: PrepareRefundRequest, ): Promise { return callBackend("prepareRefund", req); } export function prepareTip(req: PrepareTipRequest): Promise { return callBackend("prepareTip", req); } export function acceptTip(req: AcceptTipRequest): Promise { return callBackend("acceptTip", req); } export function exportDB(): Promise { return callBackend("exportDb", {}); } export function importDB(dump: any): Promise { return callBackend("importDb", { dump }); } export function onUpdateNotification( messageTypes: Array, doCallback: () => void, ): () => void { const onNewMessage = (message: MessageFromBackend): void => { const shouldNotify = messageTypes.includes(message.type); if (shouldNotify) { doCallback(); } }; return platform.listenToWalletBackground(onNewMessage); } export function initiatePeerPushPayment( req: InitiatePeerPushPaymentRequest, ): Promise { return callBackend("initiatePeerPushPayment", req); } export function checkPeerPushPayment( req: CheckPeerPushPaymentRequest, ): Promise { return callBackend("checkPeerPushPayment", req); } export function acceptPeerPushPayment( req: AcceptPeerPushPaymentRequest, ): Promise { return callBackend("acceptPeerPushPayment", req); } export function initiatePeerPullPayment( req: InitiatePeerPullPaymentRequest, ): Promise { return callBackend("initiatePeerPullPayment", req); } export function checkPeerPullPayment( req: CheckPeerPullPaymentRequest, ): Promise { return callBackend("checkPeerPullPayment", req); } export function acceptPeerPullPayment( req: AcceptPeerPullPaymentRequest, ): Promise { return callBackend("acceptPeerPullPayment", req); } export function getTransactionById(tid: string): Promise { return callBackend("getTransactionById", { transactionId: tid, }); }