From 613a14c14f969bf21ff7569f93cde3a7a35ce96a Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 31 May 2017 16:04:14 +0200 Subject: fix messaging, small issues and safer types --- src/crypto/cryptoApi.ts | 6 +- src/crypto/cryptoWorker.ts | 18 +-- src/i18n/de.po | 36 +++--- src/i18n/en-US.po | 36 +++--- src/i18n/fr.po | 36 +++--- src/i18n/it.po | 36 +++--- src/i18n/taler-wallet-webex.pot | 36 +++--- src/types.ts | 18 +-- src/wallet.ts | 121 +++++++++++--------- src/webex/messages.ts | 28 +++-- src/webex/notify.ts | 10 +- src/webex/pages/confirm-contract.html | 2 +- src/webex/pages/confirm-contract.tsx | 41 +++---- src/webex/wxApi.ts | 44 ++++---- src/webex/wxBackend.ts | 202 ++++++++++++---------------------- 15 files changed, 310 insertions(+), 360 deletions(-) diff --git a/src/crypto/cryptoApi.ts b/src/crypto/cryptoApi.ts index c3c1f508a..139f8ae88 100644 --- a/src/crypto/cryptoApi.ts +++ b/src/crypto/cryptoApi.ts @@ -27,7 +27,7 @@ import { AmountJson, CoinRecord, DenominationRecord, - OfferRecord, + ProposalRecord, PayCoinInfo, PaybackRequest, PreCoinRecord, @@ -277,9 +277,9 @@ export class CryptoApi { return this.doRpc("isValidPaymentSignature", 1, sig, contractHash, merchantPub); } - signDeposit(offer: OfferRecord, + signDeposit(proposal: ProposalRecord, cds: CoinWithDenom[]): Promise { - return this.doRpc("signDeposit", 3, offer, cds); + return this.doRpc("signDeposit", 3, proposal, cds); } createEddsaKeypair(): Promise<{priv: string, pub: string}> { diff --git a/src/crypto/cryptoWorker.ts b/src/crypto/cryptoWorker.ts index 85a0425b3..507a080ac 100644 --- a/src/crypto/cryptoWorker.ts +++ b/src/crypto/cryptoWorker.ts @@ -29,7 +29,7 @@ import { CoinRecord, CoinStatus, DenominationRecord, - OfferRecord, + ProposalRecord, PayCoinInfo, PaybackRequest, PreCoinRecord, @@ -227,7 +227,7 @@ namespace RpcFunctions { * Generate updated coins (to store in the database) * and deposit permissions for each given coin. */ - export function signDeposit(offer: OfferRecord, + export function signDeposit(proposal: ProposalRecord, cds: CoinWithDenom[]): PayCoinInfo { const ret: PayCoinInfo = []; @@ -235,8 +235,8 @@ namespace RpcFunctions { const feeList: AmountJson[] = cds.map((x) => x.denom.feeDeposit); let fees = Amounts.add(Amounts.getZero(feeList[0].currency), ...feeList).amount; // okay if saturates - fees = Amounts.sub(fees, offer.contract.max_fee).amount; - const total = Amounts.add(fees, offer.contract.amount).amount; + fees = Amounts.sub(fees, proposal.contractTerms.max_fee).amount; + const total = Amounts.add(fees, proposal.contractTerms.amount).amount; const amountSpent = native.Amount.getZero(cds[0].coin.currentAmount.currency); const amountRemaining = new native.Amount(total); @@ -273,11 +273,11 @@ namespace RpcFunctions { amount_with_fee: coinSpend.toNbo(), coin_pub: native.EddsaPublicKey.fromCrock(cd.coin.coinPub), deposit_fee: new native.Amount(cd.denom.feeDeposit).toNbo(), - h_contract: native.HashCode.fromCrock(offer.H_contract), - h_wire: native.HashCode.fromCrock(offer.contract.H_wire), - merchant: native.EddsaPublicKey.fromCrock(offer.contract.merchant_pub), - refund_deadline: native.AbsoluteTimeNbo.fromTalerString(offer.contract.refund_deadline), - timestamp: native.AbsoluteTimeNbo.fromTalerString(offer.contract.timestamp), + h_contract: native.HashCode.fromCrock(proposal.contractTermsHash), + h_wire: native.HashCode.fromCrock(proposal.contractTerms.H_wire), + merchant: native.EddsaPublicKey.fromCrock(proposal.contractTerms.merchant_pub), + refund_deadline: native.AbsoluteTimeNbo.fromTalerString(proposal.contractTerms.refund_deadline), + timestamp: native.AbsoluteTimeNbo.fromTalerString(proposal.contractTerms.timestamp), }); const coinSig = native.eddsaSign(d.toPurpose(), diff --git a/src/i18n/de.po b/src/i18n/de.po index 1578830b5..d90a9340e 100644 --- a/src/i18n/de.po +++ b/src/i18n/de.po @@ -42,13 +42,13 @@ msgstr "" msgid "Exchanges in the wallet:" msgstr "" -#: src/webex/pages/confirm-contract.tsx:146 +#: src/webex/pages/confirm-contract.tsx:141 #, c-format msgid "You have insufficient funds of the requested currency in your wallet." msgstr "" #. tslint:disable-next-line:max-line-length -#: src/webex/pages/confirm-contract.tsx:148 +#: src/webex/pages/confirm-contract.tsx:143 #, c-format msgid "" "You do not have any funds from an exchange that is accepted by this " @@ -193,90 +193,90 @@ msgstr "" msgid "Fatal error: \"%1$s\"." msgstr "" -#: src/webex/pages/popup.tsx:163 +#: src/webex/pages/popup.tsx:161 #, c-format msgid "Balance" msgstr "Saldo" -#: src/webex/pages/popup.tsx:166 +#: src/webex/pages/popup.tsx:164 #, c-format msgid "History" msgstr "Verlauf" -#: src/webex/pages/popup.tsx:169 +#: src/webex/pages/popup.tsx:167 #, c-format msgid "Debug" msgstr "Debug" -#: src/webex/pages/popup.tsx:245 +#: src/webex/pages/popup.tsx:243 #, c-format msgid "help" msgstr "" -#: src/webex/pages/popup.tsx:250 +#: src/webex/pages/popup.tsx:248 #, fuzzy, c-format msgid "" "You have no balance to show. Need some\n" " %1$s getting started?\n" msgstr "Sie haben kein Digitalgeld. Wollen Sie %1$s? abheben?" -#: src/webex/pages/popup.tsx:267 +#: src/webex/pages/popup.tsx:265 #, c-format msgid "%1$s incoming\n" msgstr "" -#: src/webex/pages/popup.tsx:280 +#: src/webex/pages/popup.tsx:278 #, c-format msgid "%1$s being spent\n" msgstr "" -#: src/webex/pages/popup.tsx:306 +#: src/webex/pages/popup.tsx:304 #, c-format msgid "Error: could not retrieve balance information." msgstr "" -#: src/webex/pages/popup.tsx:345 +#: src/webex/pages/popup.tsx:343 #, fuzzy, c-format msgid "" "Bank requested reserve (%1$s) for\n" " %2$s.\n" msgstr "Bank bestätig anlegen der Reserve (%1$s) bei %2$s" -#: src/webex/pages/popup.tsx:356 +#: src/webex/pages/popup.tsx:354 #, fuzzy, c-format msgid "" "Started to withdraw\n" " %1$s from%2$s(%3$s).\n" msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt" -#: src/webex/pages/popup.tsx:366 +#: src/webex/pages/popup.tsx:364 #, c-format msgid "Merchant%1$soffered contract%2$s;\n" msgstr "" -#: src/webex/pages/popup.tsx:376 +#: src/webex/pages/popup.tsx:374 #, fuzzy, c-format msgid "Withdrew%1$sfrom%2$s(%3$s).\n" msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt" -#: src/webex/pages/popup.tsx:386 +#: src/webex/pages/popup.tsx:384 #, fuzzy, c-format msgid "" "Paid%1$sto merchant%2$s.\n" " (%3$s)\n" msgstr "Reserve (%1$s) mit %2$s bei %3$s erzeugt" -#: src/webex/pages/popup.tsx:395 +#: src/webex/pages/popup.tsx:393 #, c-format msgid "Unknown event (%1$s)" msgstr "" -#: src/webex/pages/popup.tsx:438 +#: src/webex/pages/popup.tsx:436 #, c-format msgid "Error: could not retrieve event history" msgstr "" -#: src/webex/pages/popup.tsx:472 +#: src/webex/pages/popup.tsx:470 #, c-format msgid "Your wallet has no events recorded." msgstr "Ihre Geldbörse verzeichnet keine Vorkommnisse." diff --git a/src/i18n/en-US.po b/src/i18n/en-US.po index f7faad5fd..f45591db6 100644 --- a/src/i18n/en-US.po +++ b/src/i18n/en-US.po @@ -42,13 +42,13 @@ msgstr "" msgid "Exchanges in the wallet:" msgstr "" -#: src/webex/pages/confirm-contract.tsx:146 +#: src/webex/pages/confirm-contract.tsx:141 #, c-format msgid "You have insufficient funds of the requested currency in your wallet." msgstr "" #. tslint:disable-next-line:max-line-length -#: src/webex/pages/confirm-contract.tsx:148 +#: src/webex/pages/confirm-contract.tsx:143 #, c-format msgid "" "You do not have any funds from an exchange that is accepted by this " @@ -193,90 +193,90 @@ msgstr "" msgid "Fatal error: \"%1$s\"." msgstr "" -#: src/webex/pages/popup.tsx:163 +#: src/webex/pages/popup.tsx:161 #, c-format msgid "Balance" msgstr "" -#: src/webex/pages/popup.tsx:166 +#: src/webex/pages/popup.tsx:164 #, c-format msgid "History" msgstr "" -#: src/webex/pages/popup.tsx:169 +#: src/webex/pages/popup.tsx:167 #, c-format msgid "Debug" msgstr "" -#: src/webex/pages/popup.tsx:245 +#: src/webex/pages/popup.tsx:243 #, c-format msgid "help" msgstr "" -#: src/webex/pages/popup.tsx:250 +#: src/webex/pages/popup.tsx:248 #, c-format msgid "" "You have no balance to show. Need some\n" " %1$s getting started?\n" msgstr "" -#: src/webex/pages/popup.tsx:267 +#: src/webex/pages/popup.tsx:265 #, c-format msgid "%1$s incoming\n" msgstr "" -#: src/webex/pages/popup.tsx:280 +#: src/webex/pages/popup.tsx:278 #, c-format msgid "%1$s being spent\n" msgstr "" -#: src/webex/pages/popup.tsx:306 +#: src/webex/pages/popup.tsx:304 #, c-format msgid "Error: could not retrieve balance information." msgstr "" -#: src/webex/pages/popup.tsx:345 +#: src/webex/pages/popup.tsx:343 #, c-format msgid "" "Bank requested reserve (%1$s) for\n" " %2$s.\n" msgstr "" -#: src/webex/pages/popup.tsx:356 +#: src/webex/pages/popup.tsx:354 #, c-format msgid "" "Started to withdraw\n" " %1$s from%2$s(%3$s).\n" msgstr "" -#: src/webex/pages/popup.tsx:366 +#: src/webex/pages/popup.tsx:364 #, c-format msgid "Merchant%1$soffered contract%2$s;\n" msgstr "" -#: src/webex/pages/popup.tsx:376 +#: src/webex/pages/popup.tsx:374 #, c-format msgid "Withdrew%1$sfrom%2$s(%3$s).\n" msgstr "" -#: src/webex/pages/popup.tsx:386 +#: src/webex/pages/popup.tsx:384 #, c-format msgid "" "Paid%1$sto merchant%2$s.\n" " (%3$s)\n" msgstr "" -#: src/webex/pages/popup.tsx:395 +#: src/webex/pages/popup.tsx:393 #, c-format msgid "Unknown event (%1$s)" msgstr "" -#: src/webex/pages/popup.tsx:438 +#: src/webex/pages/popup.tsx:436 #, c-format msgid "Error: could not retrieve event history" msgstr "" -#: src/webex/pages/popup.tsx:472 +#: src/webex/pages/popup.tsx:470 #, c-format msgid "Your wallet has no events recorded." msgstr "" diff --git a/src/i18n/fr.po b/src/i18n/fr.po index 2011e1bb8..17f596b2f 100644 --- a/src/i18n/fr.po +++ b/src/i18n/fr.po @@ -42,13 +42,13 @@ msgstr "" msgid "Exchanges in the wallet:" msgstr "" -#: src/webex/pages/confirm-contract.tsx:146 +#: src/webex/pages/confirm-contract.tsx:141 #, c-format msgid "You have insufficient funds of the requested currency in your wallet." msgstr "" #. tslint:disable-next-line:max-line-length -#: src/webex/pages/confirm-contract.tsx:148 +#: src/webex/pages/confirm-contract.tsx:143 #, c-format msgid "" "You do not have any funds from an exchange that is accepted by this " @@ -193,90 +193,90 @@ msgstr "" msgid "Fatal error: \"%1$s\"." msgstr "" -#: src/webex/pages/popup.tsx:163 +#: src/webex/pages/popup.tsx:161 #, c-format msgid "Balance" msgstr "" -#: src/webex/pages/popup.tsx:166 +#: src/webex/pages/popup.tsx:164 #, c-format msgid "History" msgstr "" -#: src/webex/pages/popup.tsx:169 +#: src/webex/pages/popup.tsx:167 #, c-format msgid "Debug" msgstr "" -#: src/webex/pages/popup.tsx:245 +#: src/webex/pages/popup.tsx:243 #, c-format msgid "help" msgstr "" -#: src/webex/pages/popup.tsx:250 +#: src/webex/pages/popup.tsx:248 #, c-format msgid "" "You have no balance to show. Need some\n" " %1$s getting started?\n" msgstr "" -#: src/webex/pages/popup.tsx:267 +#: src/webex/pages/popup.tsx:265 #, c-format msgid "%1$s incoming\n" msgstr "" -#: src/webex/pages/popup.tsx:280 +#: src/webex/pages/popup.tsx:278 #, c-format msgid "%1$s being spent\n" msgstr "" -#: src/webex/pages/popup.tsx:306 +#: src/webex/pages/popup.tsx:304 #, c-format msgid "Error: could not retrieve balance information." msgstr "" -#: src/webex/pages/popup.tsx:345 +#: src/webex/pages/popup.tsx:343 #, c-format msgid "" "Bank requested reserve (%1$s) for\n" " %2$s.\n" msgstr "" -#: src/webex/pages/popup.tsx:356 +#: src/webex/pages/popup.tsx:354 #, c-format msgid "" "Started to withdraw\n" " %1$s from%2$s(%3$s).\n" msgstr "" -#: src/webex/pages/popup.tsx:366 +#: src/webex/pages/popup.tsx:364 #, c-format msgid "Merchant%1$soffered contract%2$s;\n" msgstr "" -#: src/webex/pages/popup.tsx:376 +#: src/webex/pages/popup.tsx:374 #, c-format msgid "Withdrew%1$sfrom%2$s(%3$s).\n" msgstr "" -#: src/webex/pages/popup.tsx:386 +#: src/webex/pages/popup.tsx:384 #, c-format msgid "" "Paid%1$sto merchant%2$s.\n" " (%3$s)\n" msgstr "" -#: src/webex/pages/popup.tsx:395 +#: src/webex/pages/popup.tsx:393 #, c-format msgid "Unknown event (%1$s)" msgstr "" -#: src/webex/pages/popup.tsx:438 +#: src/webex/pages/popup.tsx:436 #, c-format msgid "Error: could not retrieve event history" msgstr "" -#: src/webex/pages/popup.tsx:472 +#: src/webex/pages/popup.tsx:470 #, c-format msgid "Your wallet has no events recorded." msgstr "" diff --git a/src/i18n/it.po b/src/i18n/it.po index 2011e1bb8..17f596b2f 100644 --- a/src/i18n/it.po +++ b/src/i18n/it.po @@ -42,13 +42,13 @@ msgstr "" msgid "Exchanges in the wallet:" msgstr "" -#: src/webex/pages/confirm-contract.tsx:146 +#: src/webex/pages/confirm-contract.tsx:141 #, c-format msgid "You have insufficient funds of the requested currency in your wallet." msgstr "" #. tslint:disable-next-line:max-line-length -#: src/webex/pages/confirm-contract.tsx:148 +#: src/webex/pages/confirm-contract.tsx:143 #, c-format msgid "" "You do not have any funds from an exchange that is accepted by this " @@ -193,90 +193,90 @@ msgstr "" msgid "Fatal error: \"%1$s\"." msgstr "" -#: src/webex/pages/popup.tsx:163 +#: src/webex/pages/popup.tsx:161 #, c-format msgid "Balance" msgstr "" -#: src/webex/pages/popup.tsx:166 +#: src/webex/pages/popup.tsx:164 #, c-format msgid "History" msgstr "" -#: src/webex/pages/popup.tsx:169 +#: src/webex/pages/popup.tsx:167 #, c-format msgid "Debug" msgstr "" -#: src/webex/pages/popup.tsx:245 +#: src/webex/pages/popup.tsx:243 #, c-format msgid "help" msgstr "" -#: src/webex/pages/popup.tsx:250 +#: src/webex/pages/popup.tsx:248 #, c-format msgid "" "You have no balance to show. Need some\n" " %1$s getting started?\n" msgstr "" -#: src/webex/pages/popup.tsx:267 +#: src/webex/pages/popup.tsx:265 #, c-format msgid "%1$s incoming\n" msgstr "" -#: src/webex/pages/popup.tsx:280 +#: src/webex/pages/popup.tsx:278 #, c-format msgid "%1$s being spent\n" msgstr "" -#: src/webex/pages/popup.tsx:306 +#: src/webex/pages/popup.tsx:304 #, c-format msgid "Error: could not retrieve balance information." msgstr "" -#: src/webex/pages/popup.tsx:345 +#: src/webex/pages/popup.tsx:343 #, c-format msgid "" "Bank requested reserve (%1$s) for\n" " %2$s.\n" msgstr "" -#: src/webex/pages/popup.tsx:356 +#: src/webex/pages/popup.tsx:354 #, c-format msgid "" "Started to withdraw\n" " %1$s from%2$s(%3$s).\n" msgstr "" -#: src/webex/pages/popup.tsx:366 +#: src/webex/pages/popup.tsx:364 #, c-format msgid "Merchant%1$soffered contract%2$s;\n" msgstr "" -#: src/webex/pages/popup.tsx:376 +#: src/webex/pages/popup.tsx:374 #, c-format msgid "Withdrew%1$sfrom%2$s(%3$s).\n" msgstr "" -#: src/webex/pages/popup.tsx:386 +#: src/webex/pages/popup.tsx:384 #, c-format msgid "" "Paid%1$sto merchant%2$s.\n" " (%3$s)\n" msgstr "" -#: src/webex/pages/popup.tsx:395 +#: src/webex/pages/popup.tsx:393 #, c-format msgid "Unknown event (%1$s)" msgstr "" -#: src/webex/pages/popup.tsx:438 +#: src/webex/pages/popup.tsx:436 #, c-format msgid "Error: could not retrieve event history" msgstr "" -#: src/webex/pages/popup.tsx:472 +#: src/webex/pages/popup.tsx:470 #, c-format msgid "Your wallet has no events recorded." msgstr "" diff --git a/src/i18n/taler-wallet-webex.pot b/src/i18n/taler-wallet-webex.pot index 2011e1bb8..17f596b2f 100644 --- a/src/i18n/taler-wallet-webex.pot +++ b/src/i18n/taler-wallet-webex.pot @@ -42,13 +42,13 @@ msgstr "" msgid "Exchanges in the wallet:" msgstr "" -#: src/webex/pages/confirm-contract.tsx:146 +#: src/webex/pages/confirm-contract.tsx:141 #, c-format msgid "You have insufficient funds of the requested currency in your wallet." msgstr "" #. tslint:disable-next-line:max-line-length -#: src/webex/pages/confirm-contract.tsx:148 +#: src/webex/pages/confirm-contract.tsx:143 #, c-format msgid "" "You do not have any funds from an exchange that is accepted by this " @@ -193,90 +193,90 @@ msgstr "" msgid "Fatal error: \"%1$s\"." msgstr "" -#: src/webex/pages/popup.tsx:163 +#: src/webex/pages/popup.tsx:161 #, c-format msgid "Balance" msgstr "" -#: src/webex/pages/popup.tsx:166 +#: src/webex/pages/popup.tsx:164 #, c-format msgid "History" msgstr "" -#: src/webex/pages/popup.tsx:169 +#: src/webex/pages/popup.tsx:167 #, c-format msgid "Debug" msgstr "" -#: src/webex/pages/popup.tsx:245 +#: src/webex/pages/popup.tsx:243 #, c-format msgid "help" msgstr "" -#: src/webex/pages/popup.tsx:250 +#: src/webex/pages/popup.tsx:248 #, c-format msgid "" "You have no balance to show. Need some\n" " %1$s getting started?\n" msgstr "" -#: src/webex/pages/popup.tsx:267 +#: src/webex/pages/popup.tsx:265 #, c-format msgid "%1$s incoming\n" msgstr "" -#: src/webex/pages/popup.tsx:280 +#: src/webex/pages/popup.tsx:278 #, c-format msgid "%1$s being spent\n" msgstr "" -#: src/webex/pages/popup.tsx:306 +#: src/webex/pages/popup.tsx:304 #, c-format msgid "Error: could not retrieve balance information." msgstr "" -#: src/webex/pages/popup.tsx:345 +#: src/webex/pages/popup.tsx:343 #, c-format msgid "" "Bank requested reserve (%1$s) for\n" " %2$s.\n" msgstr "" -#: src/webex/pages/popup.tsx:356 +#: src/webex/pages/popup.tsx:354 #, c-format msgid "" "Started to withdraw\n" " %1$s from%2$s(%3$s).\n" msgstr "" -#: src/webex/pages/popup.tsx:366 +#: src/webex/pages/popup.tsx:364 #, c-format msgid "Merchant%1$soffered contract%2$s;\n" msgstr "" -#: src/webex/pages/popup.tsx:376 +#: src/webex/pages/popup.tsx:374 #, c-format msgid "Withdrew%1$sfrom%2$s(%3$s).\n" msgstr "" -#: src/webex/pages/popup.tsx:386 +#: src/webex/pages/popup.tsx:384 #, c-format msgid "" "Paid%1$sto merchant%2$s.\n" " (%3$s)\n" msgstr "" -#: src/webex/pages/popup.tsx:395 +#: src/webex/pages/popup.tsx:393 #, c-format msgid "Unknown event (%1$s)" msgstr "" -#: src/webex/pages/popup.tsx:438 +#: src/webex/pages/popup.tsx:436 #, c-format msgid "Error: could not retrieve event history" msgstr "" -#: src/webex/pages/popup.tsx:472 +#: src/webex/pages/popup.tsx:470 #, c-format msgid "Your wallet has no events recorded." msgstr "" diff --git a/src/types.ts b/src/types.ts index 4dee93a10..82777f96b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1047,33 +1047,27 @@ export class Contract { /** - * Offer record, stored in the wallet's database. + * Proposal record, stored in the wallet's database. */ @Checkable.Class() -export class OfferRecord { +export class ProposalRecord { /** * The contract that was offered by the merchant. */ @Checkable.Value(Contract) - contract: Contract; + contractTerms: Contract; /** * Signature by the merchant over the contract details. */ @Checkable.String - merchant_sig: string; + merchantSig: string; /** * Hash of the contract terms. */ @Checkable.String - H_contract: string; - - /** - * Time when the offer was made. - */ - @Checkable.Number - offer_time: number; + contractTermsHash: string; /** * Serial ID when the offer is stored in the wallet DB. @@ -1085,7 +1079,7 @@ export class OfferRecord { * Verify that a value matches the schema of this class and convert it into a * member. */ - static checked: (obj: any) => OfferRecord; + static checked: (obj: any) => ProposalRecord; } diff --git a/src/wallet.ts b/src/wallet.ts index 51c99e805..4aa2329d8 100644 --- a/src/wallet.ts +++ b/src/wallet.ts @@ -63,7 +63,7 @@ import { HistoryLevel, HistoryRecord, Notifier, - OfferRecord, + ProposalRecord, PayCoinInfo, PaybackConfirmation, PreCoinRecord, @@ -507,9 +507,9 @@ export namespace Stores { timestampIndex = new Index(this, "timestamp", "timestamp"); } - class OffersStore extends Store { + class ProposalsStore extends Store { constructor() { - super("offers", { + super("proposals", { autoIncrement: true, keyPath: "id", }); @@ -555,19 +555,19 @@ export namespace Stores { } } - export const exchanges = new ExchangeStore(); - export const exchangeWireFees = new ExchangeWireFeesStore(); - export const nonces = new NonceStore(); - export const transactions = new TransactionsStore(); - export const reserves = new Store("reserves", {keyPath: "reserve_pub"}); export const coins = new CoinsStore(); - export const refresh = new Store("refresh", {keyPath: "meltCoinPub"}); + export const config = new ConfigStore(); + export const currencies = new CurrenciesStore(); + export const denominations = new DenominationsStore(); + export const exchangeWireFees = new ExchangeWireFeesStore(); + export const exchanges = new ExchangeStore(); export const history = new HistoryStore(); - export const offers = new OffersStore(); + export const nonces = new NonceStore(); export const precoins = new Store("precoins", {keyPath: "coinPub"}); - export const denominations = new DenominationsStore(); - export const currencies = new CurrenciesStore(); - export const config = new ConfigStore(); + export const proposals = new ProposalsStore(); + export const refresh = new Store("refresh", {keyPath: "meltCoinPub"}); + export const reserves = new Store("reserves", {keyPath: "reserve_pub"}); + export const transactions = new TransactionsStore(); } /* tslint:enable:completed-docs */ @@ -834,32 +834,32 @@ export class Wallet { * Record all information that is necessary to * pay for a contract in the wallet's database. */ - private async recordConfirmPay(offer: OfferRecord, + private async recordConfirmPay(proposal: ProposalRecord, payCoinInfo: PayCoinInfo, chosenExchange: string): Promise { const payReq: PayReq = { coins: payCoinInfo.map((x) => x.sig), exchange: chosenExchange, - merchant_pub: offer.contract.merchant_pub, - order_id: offer.contract.order_id, + merchant_pub: proposal.contractTerms.merchant_pub, + order_id: proposal.contractTerms.order_id, }; const t: TransactionRecord = { - contract: offer.contract, - contractHash: offer.H_contract, + contract: proposal.contractTerms, + contractHash: proposal.contractTermsHash, finished: false, - merchantSig: offer.merchant_sig, + merchantSig: proposal.merchantSig, payReq, }; const historyEntry: HistoryRecord = { detail: { - amount: offer.contract.amount, - contractHash: offer.H_contract, - fulfillmentUrl: offer.contract.fulfillment_url, - merchantName: offer.contract.merchant.name, + amount: proposal.contractTerms.amount, + contractHash: proposal.contractTermsHash, + fulfillmentUrl: proposal.contractTerms.fulfillment_url, + merchantName: proposal.contractTerms.merchant.name, }, level: HistoryLevel.User, - subjectId: `contract-${offer.H_contract}`, + subjectId: `contract-${proposal.contractTermsHash}`, timestamp: (new Date()).getTime(), type: "pay", }; @@ -880,11 +880,13 @@ export class Wallet { } - async saveOffer(offer: OfferRecord): Promise { - console.log(`saving offer in wallet.ts`); - const id = await this.q().putWithResult(Stores.offers, offer); + /** + * Save a proposal in the database and return an id for it to + * retrieve it later. + */ + async saveProposal(proposal: ProposalRecord): Promise { + const id = await this.q().putWithResult(Stores.proposals, proposal); this.notifier.notify(); - console.log(`saved offer with id ${id}`); if (typeof id !== "number") { throw Error("db schema wrong"); } @@ -896,10 +898,15 @@ export class Wallet { * Add a contract to the wallet and sign coins, * but do not send them yet. */ - async confirmPay(offer: OfferRecord): Promise { + async confirmPay(proposalId: number): Promise { console.log("executing confirmPay"); + const proposal = await this.q().get(Stores.proposals, proposalId); + + if (!proposal) { + throw Error(`proposal with id ${proposalId} not found`); + } - const transaction = await this.q().get(Stores.transactions, offer.H_contract); + const transaction = await this.q().get(Stores.transactions, proposal.contractTermsHash); if (transaction) { // Already payed ... @@ -907,17 +914,17 @@ export class Wallet { } const res = await this.getCoinsForPayment({ - allowedAuditors: offer.contract.auditors, - allowedExchanges: offer.contract.exchanges, - depositFeeLimit: offer.contract.max_fee, - paymentAmount: offer.contract.amount, - wireFeeAmortization: offer.contract.wire_fee_amortization || 1, - wireFeeLimit: offer.contract.max_wire_fee || Amounts.getZero(offer.contract.amount.currency), - wireFeeTime: getTalerStampSec(offer.contract.timestamp) || 0, - wireMethod: offer.contract.wire_method, + allowedAuditors: proposal.contractTerms.auditors, + allowedExchanges: proposal.contractTerms.exchanges, + depositFeeLimit: proposal.contractTerms.max_fee, + paymentAmount: proposal.contractTerms.amount, + wireFeeAmortization: proposal.contractTerms.wire_fee_amortization || 1, + wireFeeLimit: proposal.contractTerms.max_wire_fee || Amounts.getZero(proposal.contractTerms.amount.currency), + wireFeeTime: getTalerStampSec(proposal.contractTerms.timestamp) || 0, + wireMethod: proposal.contractTerms.wire_method, }); - console.log("max_fee", offer.contract.max_fee); + console.log("max_fee", proposal.contractTerms.max_fee); console.log("coin selection result", res); if (!res) { @@ -926,8 +933,8 @@ export class Wallet { } const {exchangeUrl, cds} = res; - const ds = await this.cryptoApi.signDeposit(offer, cds); - await this.recordConfirmPay(offer, ds, exchangeUrl); + const ds = await this.cryptoApi.signDeposit(proposal, cds); + await this.recordConfirmPay(proposal, ds, exchangeUrl); return "paid"; } @@ -936,23 +943,29 @@ export class Wallet { * Check if payment for an offer is possible, or if the offer has already * been payed for. */ - async checkPay(offer: OfferRecord): Promise { + async checkPay(proposalId: number): Promise { + const proposal = await this.q().get(Stores.proposals, proposalId); + + if (!proposal) { + throw Error(`proposal with id ${proposalId} not found`); + } + // First check if we already payed for it. - const transaction = await this.q().get(Stores.transactions, offer.H_contract); + const transaction = await this.q().get(Stores.transactions, proposal.contractTermsHash); if (transaction) { return "insufficient-balance"; } // If not already payed, check if we could pay for it. const res = await this.getCoinsForPayment({ - allowedAuditors: offer.contract.auditors, - allowedExchanges: offer.contract.exchanges, - depositFeeLimit: offer.contract.max_fee, - paymentAmount: offer.contract.amount, - wireFeeAmortization: offer.contract.wire_fee_amortization || 1, - wireFeeLimit: offer.contract.max_wire_fee || Amounts.getZero(offer.contract.amount.currency), - wireFeeTime: getTalerStampSec(offer.contract.timestamp) || 0, - wireMethod: offer.contract.wire_method, + allowedAuditors: proposal.contractTerms.auditors, + allowedExchanges: proposal.contractTerms.exchanges, + depositFeeLimit: proposal.contractTerms.max_fee, + paymentAmount: proposal.contractTerms.amount, + wireFeeAmortization: proposal.contractTerms.wire_fee_amortization || 1, + wireFeeLimit: proposal.contractTerms.max_wire_fee || Amounts.getZero(proposal.contractTerms.amount.currency), + wireFeeTime: getTalerStampSec(proposal.contractTerms.timestamp) || 0, + wireMethod: proposal.contractTerms.wire_method, }); if (!res) { @@ -2110,9 +2123,9 @@ export class Wallet { return denoms; } - async getOffer(offerId: number): Promise { - const offer = await this.q() .get(Stores.offers, offerId); - return offer; + async getProposal(proposalId: number): Promise { + const proposal = await this.q().get(Stores.proposals, proposalId); + return proposal; } async getExchanges(): Promise { diff --git a/src/webex/messages.ts b/src/webex/messages.ts index 21acfc1d5..27ff9a5b6 100644 --- a/src/webex/messages.ts +++ b/src/webex/messages.ts @@ -69,11 +69,11 @@ export interface MessageMap { response: string; }; "confirm-pay": { - request: { offer: types.OfferRecord; }; + request: { proposalId: number; }; response: types.ConfirmPayResult; }; "check-pay": { - request: { offer: types.OfferRecord; }; + request: { proposalId: number; }; response: types.CheckPayResult; }; "query-payment": { @@ -96,21 +96,29 @@ export interface MessageMap { request: { historyEntry: types.HistoryRecord }; response: void; }; - "safe-offer": { - request: { offer: types.OfferRecord }; + "save-proposal": { + request: { proposal: types.ProposalRecord }; response: void; }; "reserve-creation-info": { - request: { baseUrl: string }; + request: { baseUrl: string, amount: types.AmountJson }; response: types.ReserveCreationInfo; } "get-history": { request: { }; response: types.HistoryRecord[]; }; - "get-offer": { - request: { offerId: number }; - response: types.OfferRecord | undefined; + "get-proposal": { + request: { proposalId: number }; + response: types.ProposalRecord | undefined; + }; + "get-coins": { + request: { exchangeBaseUrl: string }; + response: any; + }; + "refresh-coin": { + request: { coinPub: string }; + response: any; }; "get-currencies": { request: { }; @@ -120,6 +128,10 @@ export interface MessageMap { request: { currencyRecord: types.CurrencyRecord }; response: void; }; + "get-exchanges": { + request: { }; + response: types.ExchangeRecord[]; + }; "get-reserves": { request: { exchangeBaseUrl: string }; response: types.ReserveRecord[]; diff --git a/src/webex/notify.ts b/src/webex/notify.ts index 81bc6808d..2f38658bd 100644 --- a/src/webex/notify.ts +++ b/src/webex/notify.ts @@ -280,7 +280,8 @@ async function processProposal(proposal: any) { const contractHash = await wxApi.hashContract(proposal.data); if (contractHash !== proposal.hash) { - console.error("merchant-supplied contract hash is wrong"); + console.error(`merchant-supplied contract hash is wrong (us: ${contractHash}, merchant: ${proposal.hash})`); + console.dir(proposal.data); return; } @@ -301,12 +302,11 @@ async function processProposal(proposal: any) { type: "offer-contract", }; await wxApi.putHistory(historyEntry); - const offerId = await wxApi.saveOffer(proposal); + let proposalId = await wxApi.saveProposal(proposal); - const uri = new URI(chrome.extension.getURL( - "/src/webex/pages/confirm-contract.html")); + const uri = new URI(chrome.extension.getURL("/src/webex/pages/confirm-contract.html")); const params = { - offerId: offerId.toString(), + proposalId: proposalId.toString(), }; const target = uri.query(params).href(); document.location.replace(target); diff --git a/src/webex/pages/confirm-contract.html b/src/webex/pages/confirm-contract.html index 6713b2e2c..e5ba68404 100644 --- a/src/webex/pages/confirm-contract.html +++ b/src/webex/pages/confirm-contract.html @@ -5,7 +5,7 @@ Taler Wallet: Confirm Reserve Creation - + diff --git a/src/webex/pages/confirm-contract.tsx b/src/webex/pages/confirm-contract.tsx index 9b4c93334..c5513f7c6 100644 --- a/src/webex/pages/confirm-contract.tsx +++ b/src/webex/pages/confirm-contract.tsx @@ -27,7 +27,7 @@ import * as i18n from "../../i18n"; import { Contract, ExchangeRecord, - OfferRecord, + ProposalRecord, } from "../../types"; import { renderContract } from "../renderHtml"; @@ -98,11 +98,11 @@ class Details extends React.Component { } interface ContractPromptProps { - offerId: number; + proposalId: number; } interface ContractPromptState { - offer: OfferRecord|null; + proposal: ProposalRecord|null; error: string|null; payDisabled: boolean; exchanges: null|ExchangeRecord[]; @@ -114,7 +114,7 @@ class ContractPrompt extends React.Component e.master_pub); + if (this.state.exchanges && this.state.proposal) { + const acceptedExchangePubs = this.state.proposal.contractTerms.exchanges.map((e) => e.master_pub); const ex = this.state.exchanges.find((e) => acceptedExchangePubs.indexOf(e.masterPublicKey) >= 0); if (ex) { this.setState({error: msgInsufficient}); @@ -165,28 +160,28 @@ class ContractPrompt extends React.Component...; } - const c = this.state.offer.contract; + const c = this.state.proposal.contractTerms; return (
@@ -210,8 +205,8 @@ class ContractPrompt extends React.Component { const url = new URI(document.location.href); const query: any = URI.parseQuery(url.query()); - const offerId = JSON.parse(query.offerId); + const proposalId = JSON.parse(query.proposalId); - ReactDOM.render(, document.getElementById( + ReactDOM.render(, document.getElementById( "contract")!); }); diff --git a/src/webex/wxApi.ts b/src/webex/wxApi.ts index ff601b6f7..4babb2a79 100644 --- a/src/webex/wxApi.ts +++ b/src/webex/wxApi.ts @@ -30,15 +30,16 @@ import { CurrencyRecord, DenominationRecord, ExchangeRecord, - OfferRecord, PreCoinRecord, ReserveCreationInfo, ReserveRecord, } from "../types"; +import { MessageType, MessageMap } from "./messages"; -async function callBackend(type: string, detail?: any): Promise { + +async function callBackend(type: T, detail: MessageMap[T]["request"]): Promise { return new Promise((resolve, reject) => { chrome.runtime.sendMessage({ type, detail }, (resp) => { if (resp && resp.error) { @@ -65,7 +66,7 @@ export function getReserveCreationInfo(baseUrl: string, * Get all exchanges the wallet knows about. */ export function getExchanges(): Promise { - return callBackend("get-exchanges"); + return callBackend("get-exchanges", { }); } @@ -73,7 +74,7 @@ export function getExchanges(): Promise { * Get all currencies the exchange knows about. */ export function getCurrencies(): Promise { - return callBackend("get-currencies"); + return callBackend("get-currencies", { }); } @@ -114,7 +115,7 @@ export function getReserves(exchangeBaseUrl: string): Promise { * Get all reserves for which a payback is available. */ export function getPaybackReserves(): Promise { - return callBackend("get-payback-reserves"); + return callBackend("get-payback-reserves", { }); } @@ -166,41 +167,40 @@ export function payback(coinPub: string): Promise { } /** - * Get an offer stored in the wallet by its offer id. - * Note that the numeric offer id is not to be confused with - * the string order_id from the contract terms. + * Get a proposal stored in the wallet by its proposal id. */ -export function getOffer(offerId: number) { - return callBackend("get-offer", { offerId }); +export function getProposal(proposalId: number) { + return callBackend("get-proposal", { proposalId }); } /** * Check if payment is possible or already done. */ -export function checkPay(offer: OfferRecord): Promise { - return callBackend("check-pay", { offer }); +export function checkPay(proposalId: number): Promise { + return callBackend("check-pay", { proposalId }); } /** - * Pay for an offer. + * Pay for a proposal. */ -export function confirmPay(offer: OfferRecord): Promise { - return callBackend("confirm-pay", { offer }); +export function confirmPay(proposalId: number): Promise { + return callBackend("confirm-pay", { proposalId }); } /** * Hash a contract. Throws if its not a valid contract. */ export function hashContract(contract: object): Promise { - return callBackend("confirm-pay", { contract }); + return callBackend("hash-contract", { contract }); } + /** - * Save an offer in the wallet. Returns the offer id that - * the offer is stored under. + * Save a proposal in the wallet. Returns the proposal id that + * the proposal is stored under. */ -export function saveOffer(offer: object): Promise { - return callBackend("save-offer", { offer }); +export function saveProposal(proposal: any): Promise { + return callBackend("save-proposal", proposal); } /** @@ -243,7 +243,7 @@ export function paymentFailed(contractTermsHash: string): Promise { * cookie was set. */ export function getTabCookie(contractTermsHash: string, merchantSig: string): Promise { - return callBackend("get-tab-cookie"); + return callBackend("get-tab-cookie", { }); } /** @@ -251,5 +251,5 @@ export function getTabCookie(contractTermsHash: string, merchantSig: string): Pr * database and return the public key. */ export function generateNonce(): Promise { - return callBackend("generate-nonce"); + return callBackend("generate-nonce", { }); } diff --git a/src/webex/wxBackend.ts b/src/webex/wxBackend.ts index 816ce0251..356b2af6e 100644 --- a/src/webex/wxBackend.ts +++ b/src/webex/wxBackend.ts @@ -24,7 +24,6 @@ /** * Imports. */ -import { Checkable } from "../checkable"; import { BrowserHttpLib } from "../http"; import * as logging from "../logging"; import { @@ -34,7 +33,7 @@ import { import { AmountJson, Notifier, - OfferRecord, + ProposalRecord, } from "../types"; import { ConfirmReserveRequest, @@ -44,6 +43,7 @@ import { } from "../wallet"; import { ChromeBadge } from "./chromeBadge"; +import { MessageType } from "./messages"; import URI = require("urijs"); import Port = chrome.runtime.Port; @@ -60,21 +60,23 @@ const DB_NAME = "taler"; */ const DB_VERSION = 17; -type Handler = (detail: any, sender: MessageSender) => Promise; - -function makeHandlers(db: IDBDatabase, - wallet: Wallet): { [msg: string]: Handler } { - return { - ["balances"]: (detail, sender) => { +function handleMessage(db: IDBDatabase, + wallet: Wallet, + sender: MessageSender, + type: MessageType, detail: any): any { + function assertNotFound(t: never): never { + console.error(`Request type ${t as string} unknown`); + console.error(`Request detail was ${detail}`); + return { error: "request unknown", requestType: type } as never; + } + switch (type) { + case "balances": return wallet.getBalances(); - }, - ["dump-db"]: (detail, sender) => { + case "dump-db": return exportDb(db); - }, - ["import-db"]: (detail, sender) => { + case "import-db": return importDb(db, detail.dump); - }, - ["get-tab-cookie"]: (detail, sender) => { + case "get-tab-cookie": if (!sender || !sender.tab || !sender.tab.id) { return Promise.resolve(); } @@ -82,11 +84,9 @@ function makeHandlers(db: IDBDatabase, const info: any = paymentRequestCookies[id] as any; delete paymentRequestCookies[id]; return Promise.resolve(info); - }, - ["ping"]: (detail, sender) => { + case "ping": return Promise.resolve(); - }, - ["reset"]: (detail, sender) => { + case "reset": if (db) { const tx = db.transaction(Array.from(db.objectStoreNames), "readwrite"); // tslint:disable-next-line:prefer-for-of @@ -95,69 +95,36 @@ function makeHandlers(db: IDBDatabase, } } deleteDb(); - chrome.browserAction.setBadgeText({ text: "" }); console.log("reset done"); - // Response is synchronous return Promise.resolve({}); - }, - ["create-reserve"]: (detail, sender) => { + case "create-reserve": { const d = { amount: detail.amount, exchange: detail.exchange, }; const req = CreateReserveRequest.checked(d); return wallet.createReserve(req); - }, - ["confirm-reserve"]: (detail, sender) => { - // TODO: make it a checkable + } + case "confirm-reserve": const d = { reservePub: detail.reservePub, }; const req = ConfirmReserveRequest.checked(d); return wallet.confirmReserve(req); - }, - ["generate-nonce"]: (detail, sender) => { + case "generate-nonce": return wallet.generateNonce(); - }, - ["confirm-pay"]: (detail, sender) => { - let offer: OfferRecord; - try { - offer = OfferRecord.checked(detail.offer); - } catch (e) { - if (e instanceof Checkable.SchemaError) { - console.error("schema error:", e.message); - return Promise.resolve({ - detail, - error: "invalid contract", - hint: e.message, - }); - } else { - throw e; - } + case "confirm-pay": + if (typeof detail.proposalId !== "number") { + throw Error("proposalId must be number"); } - - return wallet.confirmPay(offer); - }, - ["check-pay"]: (detail, sender) => { - let offer: OfferRecord; - try { - offer = OfferRecord.checked(detail.offer); - } catch (e) { - if (e instanceof Checkable.SchemaError) { - console.error("schema error:", e.message); - return Promise.resolve({ - detail, - error: "invalid contract", - hint: e.message, - }); - } else { - throw e; - } + return wallet.confirmPay(detail.proposalId); + case "check-pay": + if (typeof detail.proposalId !== "number") { + throw Error("proposalId must be number"); } - return wallet.checkPay(offer); - }, - ["query-payment"]: (detail: any, sender: MessageSender) => { + return wallet.checkPay(detail.proposalId); + case "query-payment": if (sender.tab && sender.tab.id) { rateLimitCache[sender.tab.id]++; if (rateLimitCache[sender.tab.id] > 10) { @@ -171,120 +138,98 @@ function makeHandlers(db: IDBDatabase, } } return wallet.queryPayment(detail.url); - }, - ["exchange-info"]: (detail) => { + case "exchange-info": if (!detail.baseUrl) { return Promise.resolve({ error: "bad url" }); } return wallet.updateExchangeFromUrl(detail.baseUrl); - }, - ["currency-info"]: (detail) => { + case "currency-info": if (!detail.name) { return Promise.resolve({ error: "name missing" }); } return wallet.getCurrencyRecord(detail.name); - }, - ["hash-contract"]: (detail) => { + case "hash-contract": if (!detail.contract) { return Promise.resolve({ error: "contract missing" }); } return wallet.hashContract(detail.contract).then((hash) => { - return { hash }; + return hash; }); - }, - ["put-history-entry"]: (detail: any) => { + case "put-history-entry": if (!detail.historyEntry) { return Promise.resolve({ error: "historyEntry missing" }); } return wallet.putHistory(detail.historyEntry); - }, - ["save-offer"]: (detail: any) => { - const offer = detail.offer; - if (!offer) { - return Promise.resolve({ error: "offer missing" }); - } - console.log("handling safe-offer", detail); - // FIXME: fully migrate to new terminology - const checkedOffer = OfferRecord.checked(offer); - return wallet.saveOffer(checkedOffer); - }, - ["reserve-creation-info"]: (detail, sender) => { + case "save-proposal": + console.log("handling save-proposal", detail); + const checkedRecord = ProposalRecord.checked({ + contractTerms: detail.data, + contractTermsHash: detail.hash, + merchantSig: detail.sig, + }); + return wallet.saveProposal(checkedRecord); + case "reserve-creation-info": if (!detail.baseUrl || typeof detail.baseUrl !== "string") { return Promise.resolve({ error: "bad url" }); } const amount = AmountJson.checked(detail.amount); return wallet.getReserveCreationInfo(detail.baseUrl, amount); - }, - ["get-history"]: (detail, sender) => { + case "get-history": // TODO: limit history length return wallet.getHistory(); - }, - ["get-offer"]: (detail, sender) => { - return wallet.getOffer(detail.offerId); - }, - ["get-exchanges"]: (detail, sender) => { + case "get-proposal": + return wallet.getProposal(detail.proposalId); + case "get-exchanges": return wallet.getExchanges(); - }, - ["get-currencies"]: (detail, sender) => { + case "get-currencies": return wallet.getCurrencies(); - }, - ["update-currency"]: (detail, sender) => { + case "update-currency": return wallet.updateCurrency(detail.currencyRecord); - }, - ["get-reserves"]: (detail, sender) => { + case "get-reserves": if (typeof detail.exchangeBaseUrl !== "string") { return Promise.reject(Error("exchangeBaseUrl missing")); } return wallet.getReserves(detail.exchangeBaseUrl); - }, - ["get-payback-reserves"]: (detail, sender) => { + case "get-payback-reserves": return wallet.getPaybackReserves(); - }, - ["withdraw-payback-reserve"]: (detail, sender) => { + case "withdraw-payback-reserve": if (typeof detail.reservePub !== "string") { return Promise.reject(Error("reservePub missing")); } return wallet.withdrawPaybackReserve(detail.reservePub); - }, - ["get-coins"]: (detail, sender) => { + case "get-coins": if (typeof detail.exchangeBaseUrl !== "string") { return Promise.reject(Error("exchangBaseUrl missing")); } return wallet.getCoins(detail.exchangeBaseUrl); - }, - ["get-precoins"]: (detail, sender) => { + case "get-precoins": if (typeof detail.exchangeBaseUrl !== "string") { return Promise.reject(Error("exchangBaseUrl missing")); } return wallet.getPreCoins(detail.exchangeBaseUrl); - }, - ["get-denoms"]: (detail, sender) => { + case "get-denoms": if (typeof detail.exchangeBaseUrl !== "string") { return Promise.reject(Error("exchangBaseUrl missing")); } return wallet.getDenoms(detail.exchangeBaseUrl); - }, - ["refresh-coin"]: (detail, sender) => { + case "refresh-coin": if (typeof detail.coinPub !== "string") { return Promise.reject(Error("coinPub missing")); } return wallet.refresh(detail.coinPub); - }, - ["payback-coin"]: (detail, sender) => { + case "payback-coin": if (typeof detail.coinPub !== "string") { return Promise.reject(Error("coinPub missing")); } return wallet.payback(detail.coinPub); - }, - ["payment-failed"]: (detail, sender) => { + case "payment-failed": // For now we just update exchanges (maybe the exchange did something // wrong and the keys were messed up). // FIXME: in the future we should look at what actually went wrong. console.error("payment reported as failed"); wallet.updateExchanges(); return Promise.resolve(); - }, - ["payment-succeeded"]: (detail, sender) => { + case "payment-succeeded": const contractTermsHash = detail.contractTermsHash; const merchantSig = detail.merchantSig; if (!contractTermsHash) { @@ -294,24 +239,16 @@ function makeHandlers(db: IDBDatabase, return Promise.reject(Error("merchantSig missing")); } return wallet.paymentSucceeded(contractTermsHash, merchantSig); - }, - }; -} - - -async function dispatch(handlers: any, req: any, sender: any, sendResponse: any): Promise { - if (!(req.type in handlers)) { - console.error(`Request type ${req.type} unknown`); - console.error(`Request was ${req}`); - try { - sendResponse({ error: "request unknown", requestType: req.type }); - } catch (e) { - // might fail if tab disconnected - } + default: + // Exhaustiveness check. + // See https://www.typescriptlang.org/docs/handbook/advanced-types.html + return assertNotFound(type); } +} +async function dispatch(db: IDBDatabase, wallet: Wallet, req: any, sender: any, sendResponse: any): Promise { try { - const p = handlers[req.type](req.detail, sender); + const p = handleMessage(db, wallet, sender, req.type, req.detail); const r = await p; try { sendResponse(r); @@ -587,9 +524,8 @@ export async function wxMain() { // Handlers for messages coming directly from the content // script on the page - const handlers = makeHandlers(db, wallet!); chrome.runtime.onMessage.addListener((req, sender, sendResponse) => { - dispatch(handlers, req, sender, sendResponse); + dispatch(db, wallet, req, sender, sendResponse); return true; }); -- cgit v1.2.3