diff options
author | Florian Dold <florian.dold@gmail.com> | 2020-08-14 00:13:51 +0530 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2020-08-14 00:13:51 +0530 |
commit | cbe325cb0f3e492e28ee148106c6c81e4db7d6bf (patch) | |
tree | d78440a7cc4dc94fa1cb90a2d210d4c16ef7d779 | |
parent | 599c8380f23584c24633927cafe8277fb9e41579 (diff) |
web extension WIP
9 files changed, 98 insertions, 388 deletions
diff --git a/packages/taler-wallet-webextension/src/pageEntryPoint.ts b/packages/taler-wallet-webextension/src/pageEntryPoint.ts index 9fd1d36f1..216cb83c3 100644 --- a/packages/taler-wallet-webextension/src/pageEntryPoint.ts +++ b/packages/taler-wallet-webextension/src/pageEntryPoint.ts @@ -26,6 +26,7 @@ import { createWithdrawPage } from "./pages/withdraw"; import { createWelcomePage } from "./pages/welcome"; import { createPayPage } from "./pages/pay"; import { createRefundPage } from "./pages/refund"; +import { setupI18n } from "taler-wallet-core"; function main(): void { try { @@ -65,6 +66,8 @@ function main(): void { } } +setupI18n("en-US"); + if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", main); } else { diff --git a/packages/taler-wallet-webextension/src/pages/popup.tsx b/packages/taler-wallet-webextension/src/pages/popup.tsx index 61edcfe50..e833f5950 100644 --- a/packages/taler-wallet-webextension/src/pages/popup.tsx +++ b/packages/taler-wallet-webextension/src/pages/popup.tsx @@ -397,19 +397,19 @@ function actionForTalerUri(talerUri: string): string | undefined { const uriType = classifyTalerUri(talerUri); switch (uriType) { case TalerUriType.TalerWithdraw: - return makeExtensionUrlWithParams("withdraw.html", { + return makeExtensionUrlWithParams("static/withdraw.html", { talerWithdrawUri: talerUri, }); case TalerUriType.TalerPay: - return makeExtensionUrlWithParams("pay.html", { + return makeExtensionUrlWithParams("static/pay.html", { talerPayUri: talerUri, }); case TalerUriType.TalerTip: - return makeExtensionUrlWithParams("tip.html", { + return makeExtensionUrlWithParams("static/tip.html", { talerTipUri: talerUri, }); case TalerUriType.TalerRefund: - return makeExtensionUrlWithParams("refund.html", { + return makeExtensionUrlWithParams("static/refund.html", { talerRefundUri: talerUri, }); case TalerUriType.TalerNotifyReserve: diff --git a/packages/taler-wallet-webextension/src/pages/withdraw.tsx b/packages/taler-wallet-webextension/src/pages/withdraw.tsx index 4a92704b3..1637176a9 100644 --- a/packages/taler-wallet-webextension/src/pages/withdraw.tsx +++ b/packages/taler-wallet-webextension/src/pages/withdraw.tsx @@ -29,11 +29,13 @@ import React, { useState, useEffect } from "react"; import { acceptWithdrawal, onUpdateNotification, + getWithdrawalDetailsForUri, } from "../wxApi"; +import { WithdrawUriInfoResponse } from "taler-wallet-core"; function WithdrawalDialog(props: { talerWithdrawUri: string }): JSX.Element { const [details, setDetails] = useState< - any | undefined + WithdrawUriInfoResponse | undefined >(); const [selectedExchange, setSelectedExchange] = useState< string | undefined @@ -54,55 +56,12 @@ function WithdrawalDialog(props: { talerWithdrawUri: string }): JSX.Element { useEffect(() => { const fetchData = async (): Promise<void> => { - // 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); + const res = await getWithdrawalDetailsForUri({talerWithdrawUri: props.talerWithdrawUri}); + setDetails(res); }; fetchData(); }, [selectedExchange, errMsg, selecting, talerWithdrawUri, updateCounter]); - if (errMsg) { - return ( - <div> - <i18n.Translate wrap="p"> - Could not get details for withdraw operation: - </i18n.Translate> - <p style={{ color: "red" }}>{errMsg}</p> - <p> - <span - role="button" - tabIndex={0} - style={{ textDecoration: "underline", cursor: "pointer" }} - onClick={() => { - setSelecting(true); - setErrMsg(undefined); - setSelectedExchange(undefined); - setDetails(undefined); - }} - > - {i18n.str`Chose different exchange provider`} - </span> - </p> - </div> - ); - } - if (!details) { return <span>Loading...</span>; } @@ -111,51 +70,6 @@ function WithdrawalDialog(props: { talerWithdrawUri: string }): JSX.Element { return <span>Withdraw operation has been cancelled.</span>; } - if (selecting) { - const bankSuggestion = - details && details.bankWithdrawDetails.suggestedExchange; - return ( - <div> - {i18n.str`Please select an exchange. You can review the details before after your selection.`} - {bankSuggestion && ( - <div> - <h2>Bank Suggestion</h2> - <button - className="pure-button button-success" - onClick={() => { - setDetails(undefined); - setSelectedExchange(bankSuggestion); - setSelecting(false); - }} - > - <i18n.Translate wrap="span"> - Select <strong>{bankSuggestion}</strong> - </i18n.Translate> - </button> - </div> - )} - <h2>Custom Selection</h2> - <p> - <input - type="text" - onChange={(e) => setCustomUrl(e.target.value)} - value={customUrl} - /> - </p> - <button - className="pure-button button-success" - onClick={() => { - setDetails(undefined); - setSelectedExchange(customUrl); - setSelecting(false); - }} - > - <i18n.Translate wrap="span">Select custom exchange</i18n.Translate> - </button> - </div> - ); - } - const accept = async (): Promise<void> => { if (!selectedExchange) { throw Error("can't accept, no exchange selected"); @@ -173,7 +87,7 @@ function WithdrawalDialog(props: { talerWithdrawUri: string }): JSX.Element { <h1>Digital Cash Withdrawal</h1> <i18n.Translate wrap="p"> You are about to withdraw{" "} - <strong>{renderAmount(details.bankWithdrawDetails.amount)}</strong> from + <strong>{renderAmount(details.amount)}</strong> from your bank account into your wallet. </i18n.Translate> {selectedExchange ? ( @@ -211,9 +125,9 @@ function WithdrawalDialog(props: { talerWithdrawUri: string }): JSX.Element { </span> </p> - {details.exchangeWithdrawDetails ? ( + {/* {details.exchangeWithdrawDetails ? ( <WithdrawDetailView rci={details.exchangeWithdrawDetails} /> - ) : null} + ) : null} */} </div> </div> ); diff --git a/packages/taler-wallet-webextension/src/wxApi.ts b/packages/taler-wallet-webextension/src/wxApi.ts index 1bcee1285..836466ff3 100644 --- a/packages/taler-wallet-webextension/src/wxApi.ts +++ b/packages/taler-wallet-webextension/src/wxApi.ts @@ -21,14 +21,26 @@ /** * Imports. */ -import { AmountJson, ConfirmPayResult, BalancesResponse, PurchaseDetails, TipStatus, BenchmarkResult, PreparePayResult, AcceptWithdrawalResponse, WalletDiagnostics } from "taler-wallet-core"; - +import { + AmountJson, + ConfirmPayResult, + BalancesResponse, + PurchaseDetails, + TipStatus, + BenchmarkResult, + PreparePayResult, + AcceptWithdrawalResponse, + WalletDiagnostics, + CoreApiResponse, + OperationFailedError, + GetWithdrawalDetailsForUriRequest, + WithdrawUriInfoResponse, +} from "taler-wallet-core"; export interface ExtendedPermissionsResponse { newValue: boolean; } - /** * Response with information about available version upgrades. */ @@ -50,23 +62,9 @@ export interface UpgradeResponse { oldDbVersion: string; } -/** - * Error thrown when the function from the backend (via RPC) threw an error. - */ -export class WalletApiError extends Error { - constructor(message: string, public detail: any) { - super(message); - // restore prototype chain - Object.setPrototypeOf(this, new.target.prototype); - } -} - -async function callBackend( - type: string, - detail: any, -): Promise<any> { +async function callBackend(operation: string, payload: any): Promise<any> { return new Promise<any>((resolve, reject) => { - chrome.runtime.sendMessage({ type, detail }, (resp) => { + chrome.runtime.sendMessage({ operation, payload, id: "(none)" }, (resp) => { if (chrome.runtime.lastError) { console.log("Error calling backend"); reject( @@ -75,19 +73,17 @@ async function callBackend( ), ); } - if (typeof resp === "object" && resp && resp.error) { - console.warn("response error:", resp); - const e = new WalletApiError(resp.error.message, resp.error); - reject(e); - } else { - resolve(resp); + 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. */ @@ -123,7 +119,7 @@ export function resetDb(): Promise<void> { * Get balances for all currencies/exchanges. */ export function getBalance(): Promise<BalancesResponse> { - return callBackend("balances", {}); + return callBackend("getBalances", {}); } /** @@ -227,6 +223,15 @@ export function getExtendedPermissions(): Promise<ExtendedPermissionsResponse> { return callBackend("get-extended-permissions", {}); } +/** + * Get diagnostics information + */ +export function getWithdrawalDetailsForUri( + req: GetWithdrawalDetailsForUriRequest, +): Promise<WithdrawUriInfoResponse> { + return callBackend("getWithdrawalDetailsForUri", req); +} + export function onUpdateNotification(f: () => void): () => void { const port = chrome.runtime.connect({ name: "notifications" }); const listener = (): void => { diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts index ce024e096..86008dd99 100644 --- a/packages/taler-wallet-webextension/src/wxBackend.ts +++ b/packages/taler-wallet-webextension/src/wxBackend.ts @@ -28,7 +28,21 @@ import * as wxApi from "./wxApi"; import MessageSender = chrome.runtime.MessageSender; import { extendedPermissions } from "./permissions"; -import { Wallet, OpenedPromise, openPromise, deleteTalerDatabase, WALLET_DB_MINOR_VERSION, WalletDiagnostics, openTalerDatabase, Database, classifyTalerUri, TalerUriType } from "taler-wallet-core"; +import { + Wallet, + OpenedPromise, + openPromise, + deleteTalerDatabase, + WALLET_DB_MINOR_VERSION, + WalletDiagnostics, + openTalerDatabase, + Database, + classifyTalerUri, + TalerUriType, + makeErrorDetails, + TalerErrorCode, + handleCoreApiRequest, +} from "taler-wallet-core"; import { BrowserHttpLib } from "./browserHttpLib"; import { BrowserCryptoWorkerFactory } from "./browserCryptoWorkerFactory"; @@ -51,254 +65,28 @@ const walletInit: OpenedPromise<void> = openPromise<void>(); const notificationPorts: chrome.runtime.Port[] = []; -async function handleMessage( - sender: MessageSender, - type: string, - detail: any, -): Promise<any> { - function needsWallet(): Wallet { - if (!currentWallet) { - throw NeedsWallet; - } - return currentWallet; - } - switch (type) { - case "balances": { - return needsWallet().getBalances(); - } - case "dump-db": { - const db = needsWallet().db; - return db.exportDatabase(); - } - case "import-db": { - const db = needsWallet().db; - return db.importDatabase(detail.dump); - } - case "ping": { - return Promise.resolve(); - } - case "reset-db": { - deleteTalerDatabase(indexedDB); - setBadgeText({ text: "" }); - console.log("reset done"); - if (!currentWallet) { - reinitWallet(); - } - return Promise.resolve({}); - } - case "confirm-pay": { - if (typeof detail.proposalId !== "string") { - throw Error("proposalId must be string"); - } - return needsWallet().confirmPay(detail.proposalId, detail.sessionId); - } - case "exchange-info": { - if (!detail.baseUrl) { - return Promise.resolve({ error: "bad url" }); - } - return needsWallet().updateExchangeFromUrl(detail.baseUrl); - } - case "get-exchanges": { - return needsWallet().getExchangeRecords(); - } - case "get-currencies": { - return needsWallet().getCurrencies(); - } - case "update-currency": { - return needsWallet().updateCurrency(detail.currencyRecord); - } - case "get-reserves": { - if (typeof detail.exchangeBaseUrl !== "string") { - return Promise.reject(Error("exchangeBaseUrl missing")); - } - return needsWallet().getReserves(detail.exchangeBaseUrl); - } - case "get-coins": { - if (typeof detail.exchangeBaseUrl !== "string") { - return Promise.reject(Error("exchangBaseUrl missing")); - } - return needsWallet().getCoinsForExchange(detail.exchangeBaseUrl); - } - case "get-denoms": { - if (typeof detail.exchangeBaseUrl !== "string") { - return Promise.reject(Error("exchangBaseUrl missing")); - } - return needsWallet().getDenoms(detail.exchangeBaseUrl); - } - case "refresh-coin": { - if (typeof detail.coinPub !== "string") { - return Promise.reject(Error("coinPub missing")); - } - return needsWallet().refresh(detail.coinPub); - } - case "get-sender-wire-infos": { - return needsWallet().getSenderWireInfos(); - } - case "return-coins": { - const d = { - amount: detail.amount, - exchange: detail.exchange, - senderWire: detail.senderWire, - }; - return needsWallet().returnCoins(d); - } - case "check-upgrade": { - let dbResetRequired = false; - if (!currentWallet) { - dbResetRequired = true; - } - const resp: wxApi.UpgradeResponse = { - currentDbVersion: WALLET_DB_MINOR_VERSION.toString(), - dbResetRequired, - oldDbVersion: (outdatedDbVersion || "unknown").toString(), - }; - return resp; - } - case "get-purchase-details": { - const proposalId = detail.proposalId; - if (!proposalId) { - throw Error("proposalId missing"); - } - if (typeof proposalId !== "string") { - throw Error("proposalId must be a string"); - } - return needsWallet().getPurchaseDetails(proposalId); - } - case "accept-refund": - return needsWallet().applyRefund(detail.refundUrl); - case "get-tip-status": { - return needsWallet().getTipStatus(detail.talerTipUri); - } - case "accept-tip": { - return needsWallet().acceptTip(detail.talerTipUri); - } - case "abort-failed-payment": { - if (!detail.contractTermsHash) { - throw Error("contracTermsHash not given"); - } - return needsWallet().abortFailedPayment(detail.contractTermsHash); - } - case "benchmark-crypto": { - if (!detail.repetitions) { - throw Error("repetitions not given"); - } - return needsWallet().benchmarkCrypto(detail.repetitions); - } - case "accept-withdrawal": { - return needsWallet().acceptWithdrawal( - detail.talerWithdrawUri, - detail.selectedExchange, - ); - } - case "get-diagnostics": { - const manifestData = chrome.runtime.getManifest(); - const errors: string[] = []; - let firefoxIdbProblem = false; - let dbOutdated = false; - try { - await walletInit.promise; - } catch (e) { - errors.push("Error during wallet initialization: " + e); - if ( - currentDatabase === undefined && - outdatedDbVersion === undefined && - isFirefox() - ) { - firefoxIdbProblem = true; - } - } - if (!currentWallet) { - errors.push("Could not create wallet backend."); - } - if (!currentDatabase) { - errors.push("Could not open database"); - } - if (outdatedDbVersion !== undefined) { - errors.push(`Outdated DB version: ${outdatedDbVersion}`); - dbOutdated = true; - } - const diagnostics: WalletDiagnostics = { - walletManifestDisplayVersion: - manifestData.version_name || "(undefined)", - walletManifestVersion: manifestData.version, - errors, - firefoxIdbProblem, - dbOutdated, - }; - return diagnostics; - } - case "prepare-pay": - return needsWallet().preparePayForUri(detail.talerPayUri); - case "set-extended-permissions": { - const newVal = detail.value; - console.log("new extended permissions value", newVal); - if (newVal) { - setupHeaderListener(); - return { newValue: true }; - } else { - await new Promise((resolve, reject) => { - getPermissionsApi().remove(extendedPermissions, (rem) => { - console.log("permissions removed:", rem); - resolve(); - }); - }); - return { newVal: false }; - } - } - case "get-extended-permissions": { - const res = await new Promise((resolve, reject) => { - getPermissionsApi().contains(extendedPermissions, (result: boolean) => { - resolve(result); - }); - }); - return { newValue: res }; - } - default: - console.error(`Request type ${type} unknown`); - console.error(`Request detail was ${detail}`); - return { - error: { - message: `request type ${type} unknown`, - requestType: type, - }, - }; - } -} - async function dispatch( req: any, sender: any, sendResponse: any, ): Promise<void> { + const w = currentWallet; + if (!w) { + sendResponse( + makeErrorDetails( + TalerErrorCode.WALLET_CORE_NOT_AVAILABLE, + "wallet core not available", + {}, + ), + ); + return; + } + + const r = await handleCoreApiRequest(w, req.operation, req.id, req.payload); try { - const p = handleMessage(sender, req.type, req.detail); - const r = await p; - try { - sendResponse(r); - } catch (e) { - // might fail if tab disconnected - } + sendResponse(r); } catch (e) { - console.log(`exception during wallet handler for '${req.type}'`); - console.log("request", req); - console.error(e); - let stack; - try { - stack = e.stack.toString(); - } catch (e) { - // might fail - } - try { - sendResponse({ - error: { - message: e.message, - stack, - }, - }); - } catch (e) { - console.log(e); - // might fail if tab disconnected - } + // might fail if tab disconnected } } @@ -436,7 +224,7 @@ function headerListener( switch (uriType) { case TalerUriType.TalerWithdraw: return makeSyncWalletRedirect( - "withdraw.html", + "/static/withdraw.html", details.tabId, details.url, { @@ -445,7 +233,7 @@ function headerListener( ); case TalerUriType.TalerPay: return makeSyncWalletRedirect( - "pay.html", + "/static/pay.html", details.tabId, details.url, { @@ -454,7 +242,7 @@ function headerListener( ); case TalerUriType.TalerTip: return makeSyncWalletRedirect( - "tip.html", + "/static/tip.html", details.tabId, details.url, { @@ -463,7 +251,7 @@ function headerListener( ); case TalerUriType.TalerRefund: return makeSyncWalletRedirect( - "refund.html", + "/static/refund.html", details.tabId, details.url, { diff --git a/packages/taler-wallet-webextension/static/benchmark.html b/packages/taler-wallet-webextension/static/benchmark.html index a29fe0725..d0ca32aeb 100644 --- a/packages/taler-wallet-webextension/static/benchmark.html +++ b/packages/taler-wallet-webextension/static/benchmark.html @@ -3,9 +3,9 @@ <head> <meta charset="UTF-8" /> <title>Taler Wallet: Benchmarks</title> - <link rel="stylesheet" type="text/css" href="/style/wallet.css" /> - <link rel="icon" href="/img/icon.png" /> - <script src="/pageEntryPoint.js"></script> + <link rel="stylesheet" type="text/css" href="/static/style/wallet.css" /> + <link rel="icon" href="/static/img/icon.png" /> + <script src="/dist/pageEntryPoint.js"></script> </head> <body> <section id="main"> diff --git a/packages/taler-wallet-webextension/static/pay.html b/packages/taler-wallet-webextension/static/pay.html index 452c56df0..129765815 100644 --- a/packages/taler-wallet-webextension/static/pay.html +++ b/packages/taler-wallet-webextension/static/pay.html @@ -4,10 +4,10 @@ <meta charset="UTF-8" /> <title>Taler Wallet: Confirm Contract</title> - <link rel="stylesheet" type="text/css" href="/style/pure.css" /> - <link rel="stylesheet" type="text/css" href="/style/wallet.css" /> - <link rel="icon" href="/img/icon.png" /> - <script src="/pageEntryPoint.js"></script> + <link rel="stylesheet" type="text/css" href="/static/style/pure.css" /> + <link rel="stylesheet" type="text/css" href="/static/style/wallet.css" /> + <link rel="icon" href="/static/img/icon.png" /> + <script src="/dist/pageEntryPoint.js"></script> <style> button.accept { diff --git a/packages/taler-wallet-webextension/static/popup.html b/packages/taler-wallet-webextension/static/popup.html index 83f2f2861..024a0d182 100644 --- a/packages/taler-wallet-webextension/static/popup.html +++ b/packages/taler-wallet-webextension/static/popup.html @@ -2,11 +2,11 @@ <html> <head> <meta charset="utf-8" /> - <link rel="stylesheet" type="text/css" href="/style/pure.css" /> - <link rel="stylesheet" type="text/css" href="/style/wallet.css" /> - <link rel="stylesheet" type="text/css" href="/style/popup.css" /> - <link rel="icon" href="/img/icon.png" /> - <script src="/pageEntryPoint.js"></script> + <link rel="stylesheet" type="text/css" href="/static/style/pure.css" /> + <link rel="stylesheet" type="text/css" href="/static/style/wallet.css" /> + <link rel="stylesheet" type="text/css" href="/static/style/popup.css" /> + <link rel="icon" href="/static/img/icon.png" /> + <script src="/dist/pageEntryPoint.js"></script> </head> <body> diff --git a/packages/taler-wallet-webextension/static/withdraw.html b/packages/taler-wallet-webextension/static/withdraw.html index 5137204bd..b2b837658 100644 --- a/packages/taler-wallet-webextension/static/withdraw.html +++ b/packages/taler-wallet-webextension/static/withdraw.html @@ -3,10 +3,10 @@ <head> <meta charset="UTF-8" /> <title>Taler Wallet: Withdraw</title> - <link rel="icon" href="/img/icon.png" /> - <link rel="stylesheet" type="text/css" href="/style/pure.css" /> - <link rel="stylesheet" type="text/css" href="/style/wallet.css" /> - <script src="/pageEntryPoint.js"></script> + <link rel="icon" href="/static/img/icon.png" /> + <link rel="stylesheet" type="text/css" href="/static/style/pure.css" /> + <link rel="stylesheet" type="text/css" href="/static/style/wallet.css" /> + <script src="/dist/pageEntryPoint.js"></script> </head> <body> |