From 4365cd6401713b2e207d8c032c0558487e860154 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Tue, 28 Jul 2020 14:22:35 +0530 Subject: towards the new withdrawal API (temporarily breaks WebExtension wallet) --- src/headless/taler-wallet-cli.ts | 5 +- src/operations/withdraw.ts | 59 +++++++++++---- src/types/talerTypes.ts | 9 ++- src/types/walletTypes.ts | 5 -- src/wallet.ts | 16 +--- src/walletCoreApiHandler.ts | 17 ++--- src/webex/messages.ts | 159 --------------------------------------- src/webex/pages/withdraw.tsx | 42 +++++------ src/webex/wxApi.ts | 28 ++----- src/webex/wxBackend.ts | 32 +++----- 10 files changed, 101 insertions(+), 271 deletions(-) delete mode 100644 src/webex/messages.ts (limited to 'src') diff --git a/src/headless/taler-wallet-cli.ts b/src/headless/taler-wallet-cli.ts index 63698bf69..4bae298a0 100644 --- a/src/headless/taler-wallet-cli.ts +++ b/src/headless/taler-wallet-cli.ts @@ -306,9 +306,8 @@ walletCli break; case TalerUriType.TalerWithdraw: { - const withdrawInfo = await wallet.getWithdrawDetailsForUri(uri); - const selectedExchange = - withdrawInfo.bankWithdrawDetails.suggestedExchange; + const withdrawInfo = await wallet.getWithdrawalDetailsForUri(uri); + const selectedExchange = withdrawInfo.defaultExchangeBaseUrl; if (!selectedExchange) { console.error("no suggested exchange!"); process.exit(1); diff --git a/src/operations/withdraw.ts b/src/operations/withdraw.ts index 6f591602d..486375300 100644 --- a/src/operations/withdraw.ts +++ b/src/operations/withdraw.ts @@ -32,12 +32,13 @@ import { import { BankWithdrawDetails, ExchangeWithdrawDetails, - WithdrawalDetailsResponse, OperationErrorDetails, + ExchangeListItem, } from "../types/walletTypes"; import { codecForWithdrawOperationStatusResponse, codecForWithdrawResponse, + WithdrawUriInfoResponse, } from "../types/talerTypes"; import { InternalWalletState } from "./state"; import { parseWithdrawUri } from "../util/taleruri"; @@ -154,7 +155,7 @@ export async function getBankWithdrawalInfo( return { amount: Amounts.parseOrThrow(status.amount), confirmTransferUrl: status.confirm_transfer_url, - extractedStatusUrl: uriResult.bankIntegrationApiBaseUrl, + extractedStatusUrl: reqUrl.href, selectionDone: status.selection_done, senderWire: status.sender_wire, suggestedExchange: status.suggested_exchange, @@ -706,22 +707,50 @@ export async function getExchangeWithdrawalInfo( return ret; } -export async function getWithdrawDetailsForUri( +export async function getWithdrawalDetailsForUri( ws: InternalWalletState, talerWithdrawUri: string, - maybeSelectedExchange?: string, -): Promise { +): Promise { const info = await getBankWithdrawalInfo(ws, talerWithdrawUri); - let rci: ExchangeWithdrawDetails | undefined = undefined; - if (maybeSelectedExchange) { - rci = await getExchangeWithdrawalInfo( - ws, - maybeSelectedExchange, - info.amount, - ); + if (info.suggestedExchange) { + // FIXME: right now the exchange gets permanently added, + // we might want to only temporarily add it. + try { + await updateExchangeFromUrl(ws, info.suggestedExchange); + } catch (e) { + // We still continued if it failed, as other exchanges might be available. + // We don't want to fail if the bank-suggested exchange is broken/offline. + logger.trace(`querying bank-suggested exchange (${info.suggestedExchange}) failed`) + } } + + const exchangesRes: (ExchangeListItem | undefined)[] = await ws.db + .iter(Stores.exchanges) + .map((x) => { + const details = x.details; + if (!details) { + return undefined; + } + if (!x.addComplete) { + return undefined; + } + if (!x.wireInfo) { + return undefined; + } + if (details.currency !== info.amount.currency) { + return undefined; + } + return { + exchangeBaseUrl: x.baseUrl, + currency: details.currency, + paytoUris: x.wireInfo.accounts.map((x) => x.payto_uri), + }; + }); + const exchanges = exchangesRes.filter((x) => !!x) as ExchangeListItem[]; + return { - bankWithdrawDetails: info, - exchangeWithdrawDetails: rci, - }; + amount: Amounts.stringify(info.amount), + defaultExchangeBaseUrl: info.suggestedExchange, + possibleExchanges: exchanges, + } } diff --git a/src/types/talerTypes.ts b/src/types/talerTypes.ts index 1dfcd80a2..823f437b5 100644 --- a/src/types/talerTypes.ts +++ b/src/types/talerTypes.ts @@ -39,8 +39,6 @@ import { Codec, makeCodecForConstNumber, makeCodecForUnion, - makeCodecForConstTrue, - makeCodecForConstFalse, makeCodecForConstString, } from "../util/codec"; import { @@ -49,6 +47,7 @@ import { Duration, codecForDuration, } from "../util/time"; +import { ExchangeListItem } from "./walletTypes"; /** * Denomination as found in the /keys response from the exchange. @@ -935,6 +934,12 @@ export interface MerchantOrderStatusUnpaid { already_paid_order_id?: string; } +export interface WithdrawUriInfoResponse { + amount: AmountString; + defaultExchangeBaseUrl?: string; + possibleExchanges: ExchangeListItem[]; +} + export type AmountString = string; export type Base32String = string; export type EddsaSignatureString = string; diff --git a/src/types/walletTypes.ts b/src/types/walletTypes.ts index 95ec47b67..2ca95bf48 100644 --- a/src/types/walletTypes.ts +++ b/src/types/walletTypes.ts @@ -146,11 +146,6 @@ export interface ExchangeWithdrawDetails { walletVersion: string; } -export interface WithdrawalDetailsResponse { - bankWithdrawDetails: BankWithdrawDetails; - exchangeWithdrawDetails: ExchangeWithdrawDetails | undefined; -} - /** * Mapping from currency/exchange to detailed balance * information. diff --git a/src/wallet.ts b/src/wallet.ts index c47acbace..2abd6c0c8 100644 --- a/src/wallet.ts +++ b/src/wallet.ts @@ -29,8 +29,8 @@ import { Database } from "./util/query"; import { Amounts, AmountJson } from "./util/amounts"; import { - getWithdrawDetailsForUri, getExchangeWithdrawalInfo, + getWithdrawalDetailsForUri, } from "./operations/withdraw"; import { @@ -53,7 +53,7 @@ import { CoinSourceType, RefundState, } from "./types/dbTypes"; -import { CoinDumpJson } from "./types/talerTypes"; +import { CoinDumpJson, WithdrawUriInfoResponse } from "./types/talerTypes"; import { BenchmarkResult, ConfirmPayResult, @@ -62,7 +62,6 @@ import { TipStatus, WalletBalance, PreparePayResult, - WithdrawalDetailsResponse, AcceptWithdrawalResponse, PurchaseDetails, RefreshReason, @@ -479,15 +478,8 @@ export class Wallet { return getExchangeTrust(this.ws, exchangeInfo); } - async getWithdrawDetailsForUri( - talerWithdrawUri: string, - maybeSelectedExchange?: string, - ): Promise { - return getWithdrawDetailsForUri( - this.ws, - talerWithdrawUri, - maybeSelectedExchange, - ); + async getWithdrawalDetailsForUri(talerWithdrawUri: string): Promise { + return getWithdrawalDetailsForUri(this.ws, talerWithdrawUri); } /** diff --git a/src/walletCoreApiHandler.ts b/src/walletCoreApiHandler.ts index 6c32fd888..64039c0c1 100644 --- a/src/walletCoreApiHandler.ts +++ b/src/walletCoreApiHandler.ts @@ -108,16 +108,16 @@ const codecForApplyRefundRequest = (): Codec => .property("talerRefundUri", codecForString) .build("ApplyRefundRequest"); -interface GetWithdrawUriInfoRequest { +interface GetWithdrawalDetailsForUriRequest { talerWithdrawUri: string; } -const codecForGetWithdrawUriInfoRequest = (): Codec< - GetWithdrawUriInfoRequest +const codecForGetWithdrawalDetailsForUri = (): Codec< + GetWithdrawalDetailsForUriRequest > => - makeCodecForObject() + makeCodecForObject() .property("talerWithdrawUri", codecForString) - .build("GetWithdrawUriInfoRequest"); + .build("GetWithdrawalDetailsForUriRequest"); interface AbortProposalRequest { proposalId: string; @@ -172,10 +172,9 @@ async function dispatchRequestInternal( case "listExchanges": { return await wallet.getExchanges(); } - case "getWithdrawUriInfo": { - const req = codecForGetWithdrawUriInfoRequest().decode(payload); - // FIXME: implement "natively" - throw Error("not implemented"); + case "getWithdrawalDetailsForUri": { + const req = codecForGetWithdrawalDetailsForUri().decode(payload); + return await wallet.getWithdrawalDetailsForUri(req.talerWithdrawUri); } case "acceptManualWithdrawal": { const req = codecForAcceptManualWithdrawalRequet().decode(payload); diff --git a/src/webex/messages.ts b/src/webex/messages.ts deleted file mode 100644 index 5f63697c1..000000000 --- a/src/webex/messages.ts +++ /dev/null @@ -1,159 +0,0 @@ -/* - This file is part of TALER - (C) 2017 Inria and GNUnet e.V. - - 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 - 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 - */ - -/** - * Type definitions for messages between content scripts/pages and backend. - */ - -// Messages are already documented in wxApi. -/* tslint:disable:completed-docs */ - -import * as dbTypes from "../types/dbTypes"; -import * as walletTypes from "../types/walletTypes"; - -import { UpgradeResponse } from "./wxApi"; - -/** - * Message type information. - */ -export interface MessageMap { - balances: { - request: {}; - response: walletTypes.WalletBalance; - }; - "dump-db": { - request: {}; - response: any; - }; - "import-db": { - request: { - dump: object; - }; - response: void; - }; - ping: { - request: {}; - response: void; - }; - "reset-db": { - request: {}; - response: void; - }; - "confirm-pay": { - request: { proposalId: string; sessionId?: string }; - response: walletTypes.ConfirmPayResult; - }; - "exchange-info": { - request: { baseUrl: string }; - response: dbTypes.ExchangeRecord; - }; - "get-coins": { - request: { exchangeBaseUrl: string }; - response: any; - }; - "refresh-coin": { - request: { coinPub: string }; - response: any; - }; - "get-currencies": { - request: {}; - response: dbTypes.CurrencyRecord[]; - }; - "update-currency": { - request: { currencyRecord: dbTypes.CurrencyRecord }; - response: void; - }; - "get-exchanges": { - request: {}; - response: dbTypes.ExchangeRecord[]; - }; - "get-reserves": { - request: { exchangeBaseUrl: string }; - response: dbTypes.ReserveRecord[]; - }; - "get-denoms": { - request: { exchangeBaseUrl: string }; - response: dbTypes.DenominationRecord[]; - }; - "check-upgrade": { - request: {}; - response: UpgradeResponse; - }; - "get-sender-wire-infos": { - request: {}; - response: walletTypes.SenderWireInfos; - }; - "return-coins": { - request: {}; - response: void; - }; - "get-purchase-details": { - request: { proposalId: string }; - response: walletTypes.PurchaseDetails; - }; - "accept-tip": { - request: { talerTipUri: string }; - response: void; - }; - "get-tip-status": { - request: { talerTipUri: string }; - response: walletTypes.TipStatus; - }; - "accept-refund": { - request: { refundUrl: string }; - response: { contractTermsHash: string; proposalId: string }; - }; - "abort-failed-payment": { - request: { contractTermsHash: string }; - response: void; - }; - "benchmark-crypto": { - request: { repetitions: number }; - response: walletTypes.BenchmarkResult; - }; - "get-withdraw-details": { - request: { - talerWithdrawUri: string; - maybeSelectedExchange: string | undefined; - }; - response: walletTypes.WithdrawalDetailsResponse; - }; - "accept-withdrawal": { - request: { talerWithdrawUri: string; selectedExchange: string }; - response: walletTypes.AcceptWithdrawalResponse; - }; - "prepare-pay": { - request: { talerPayUri: string }; - response: walletTypes.PreparePayResult; - }; - "get-diagnostics": { - request: {}; - response: walletTypes.WalletDiagnostics; - }; - "set-extended-permissions": { - request: { value: boolean }; - response: walletTypes.ExtendedPermissionsResponse; - }; - "get-extended-permissions": { - request: {}; - response: walletTypes.ExtendedPermissionsResponse; - }; -} - -/** - * String literal types for messages. - */ -export type MessageType = keyof MessageMap; diff --git a/src/webex/pages/withdraw.tsx b/src/webex/pages/withdraw.tsx index 0216cdb4f..4a92704b3 100644 --- a/src/webex/pages/withdraw.tsx +++ b/src/webex/pages/withdraw.tsx @@ -23,20 +23,17 @@ import * as i18n from "../i18n"; -import { WithdrawalDetailsResponse } from "../../types/walletTypes"; - import { WithdrawDetailView, renderAmount } from "../renderHtml"; import React, { useState, useEffect } from "react"; import { - getWithdrawDetails, acceptWithdrawal, onUpdateNotification, } from "../wxApi"; function WithdrawalDialog(props: { talerWithdrawUri: string }): JSX.Element { const [details, setDetails] = useState< - WithdrawalDetailsResponse | undefined + any | undefined >(); const [selectedExchange, setSelectedExchange] = useState< string | undefined @@ -57,24 +54,25 @@ function WithdrawalDialog(props: { talerWithdrawUri: string }): JSX.Element { useEffect(() => { const fetchData = async (): Promise => { - console.log("getting from", talerWithdrawUri); - let d: WithdrawalDetailsResponse | undefined = undefined; - try { - d = await getWithdrawDetails(talerWithdrawUri, selectedExchange); - } catch (e) { - console.error( - `error getting withdraw details for uri ${talerWithdrawUri}, exchange ${selectedExchange}`, - e, - ); - setErrMsg(e.message); - return; - } - console.log("got withdrawDetails", d); - if (!selectedExchange && d.bankWithdrawDetails.suggestedExchange) { - console.log("setting selected exchange"); - setSelectedExchange(d.bankWithdrawDetails.suggestedExchange); - } - setDetails(d); + // FIXME: re-implement with new API + // console.log("getting from", talerWithdrawUri); + // let d: WithdrawalDetailsResponse | undefined = undefined; + // try { + // d = await getWithdrawDetails(talerWithdrawUri, selectedExchange); + // } catch (e) { + // console.error( + // `error getting withdraw details for uri ${talerWithdrawUri}, exchange ${selectedExchange}`, + // e, + // ); + // setErrMsg(e.message); + // return; + // } + // console.log("got withdrawDetails", d); + // if (!selectedExchange && d.bankWithdrawDetails.suggestedExchange) { + // console.log("setting selected exchange"); + // setSelectedExchange(d.bankWithdrawDetails.suggestedExchange); + // } + // setDetails(d); }; fetchData(); }, [selectedExchange, errMsg, selecting, talerWithdrawUri, updateCounter]); diff --git a/src/webex/wxApi.ts b/src/webex/wxApi.ts index de37b3639..99a581007 100644 --- a/src/webex/wxApi.ts +++ b/src/webex/wxApi.ts @@ -37,14 +37,11 @@ import { WalletBalance, PurchaseDetails, WalletDiagnostics, - WithdrawalDetailsResponse, PreparePayResult, AcceptWithdrawalResponse, ExtendedPermissionsResponse, } from "../types/walletTypes"; -import { MessageMap, MessageType } from "./messages"; - /** * Response with information about available version upgrades. */ @@ -77,11 +74,11 @@ export class WalletApiError extends Error { } } -async function callBackend( - type: T, - detail: MessageMap[T]["request"], -): Promise { - return new Promise((resolve, reject) => { +async function callBackend( + type: string, + detail: any, +): Promise { + return new Promise((resolve, reject) => { chrome.runtime.sendMessage({ type, detail }, (resp) => { if (chrome.runtime.lastError) { console.log("Error calling backend"); @@ -206,7 +203,7 @@ export function getSenderWireInfos(): Promise { export function returnCoins(args: { amount: AmountJson; exchange: string; - senderWire: object; + senderWire: string; }): Promise { return callBackend("return-coins", args); } @@ -258,19 +255,6 @@ export function benchmarkCrypto(repetitions: number): Promise { return callBackend("benchmark-crypto", { repetitions }); } -/** - * Get details about a withdraw operation. - */ -export function getWithdrawDetails( - talerWithdrawUri: string, - maybeSelectedExchange: string | undefined, -): Promise { - return callBackend("get-withdraw-details", { - talerWithdrawUri, - maybeSelectedExchange, - }); -} - /** * Get details about a pay operation. */ diff --git a/src/webex/wxBackend.ts b/src/webex/wxBackend.ts index 793f4b5d3..39fcf899e 100644 --- a/src/webex/wxBackend.ts +++ b/src/webex/wxBackend.ts @@ -35,7 +35,6 @@ import { OpenedPromise, openPromise } from "../util/promiseUtils"; import { classifyTalerUri, TalerUriType } from "../util/taleruri"; import { Wallet } from "../wallet"; import { isFirefox, getPermissionsApi } from "./compat"; -import { MessageType } from "./messages"; import * as wxApi from "./wxApi"; import MessageSender = chrome.runtime.MessageSender; import { Database } from "../util/query"; @@ -62,19 +61,9 @@ const notificationPorts: chrome.runtime.Port[] = []; async function handleMessage( sender: MessageSender, - type: MessageType, + type: string, detail: any, ): Promise { - function assertNotFound(t: never): never { - console.error(`Request type ${t as string} unknown`); - console.error(`Request detail was ${detail}`); - return { - error: { - message: `request type ${t as string} unknown`, - requestType: type, - }, - } as never; - } function needsWallet(): Wallet { if (!currentWallet) { throw NeedsWallet; @@ -204,12 +193,6 @@ async function handleMessage( } return needsWallet().benchmarkCrypto(detail.repetitions); } - case "get-withdraw-details": { - return needsWallet().getWithdrawDetailsForUri( - detail.talerWithdrawUri, - detail.maybeSelectedExchange, - ); - } case "accept-withdrawal": { return needsWallet().acceptWithdrawal( detail.talerWithdrawUri, @@ -280,9 +263,14 @@ async function handleMessage( return { newValue: res }; } default: - // Exhaustiveness check. - // See https://www.typescriptlang.org/docs/handbook/advanced-types.html - return assertNotFound(type); + console.error(`Request type ${type} unknown`); + console.error(`Request detail was ${detail}`); + return { + error: { + message: `request type ${type} unknown`, + requestType: type, + }, + }; } } @@ -354,7 +342,7 @@ function makeSyncWalletRedirect( tabId: number, oldUrl: string, params?: { [name: string]: string | undefined }, -): object { +): Record { const innerUrl = new URL(chrome.extension.getURL("/" + url)); if (params) { for (const key in params) { -- cgit v1.2.3