aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dbTypes.ts17
-rw-r--r--src/i18n/de.po2
-rw-r--r--src/i18n/en-US.po2
-rw-r--r--src/i18n/fr.po2
-rw-r--r--src/i18n/it.po2
-rw-r--r--src/i18n/sv.po2
-rw-r--r--src/i18n/taler-wallet-webex.pot2
-rw-r--r--src/talerTypes.ts42
-rw-r--r--src/wallet.ts62
-rw-r--r--src/walletTypes.ts23
-rw-r--r--src/webex/pages/confirm-create-reserve.tsx40
-rw-r--r--src/webex/wxApi.ts2
-rw-r--r--webpack.config.js2
13 files changed, 82 insertions, 118 deletions
diff --git a/src/dbTypes.ts b/src/dbTypes.ts
index 6369cd92a..3cb9a0d32 100644
--- a/src/dbTypes.ts
+++ b/src/dbTypes.ts
@@ -34,7 +34,6 @@ import {
MerchantRefundPermission,
PayReq,
TipResponse,
- WireDetail,
} from "./talerTypes";
import {
@@ -114,10 +113,10 @@ export interface ReserveRecord {
hasPayback: boolean;
/**
- * Wire information for the bank account that
+ * Wire information (as payto URI) for the bank account that
* transfered funds for this reserve.
*/
- senderWire?: object;
+ senderWire?: string;
}
@@ -837,15 +836,7 @@ export interface PurchaseRecord {
* Information about wire information for bank accounts we withdrew coins from.
*/
export interface SenderWireRecord {
- /**
- * Wire details.
- */
- senderWire: WireDetail;
-
- /**
- * Identifier, hash code of canonicalized senderWire.
- */
- id: number;
+ paytoUri: string;
}
@@ -1001,7 +992,7 @@ export namespace Stores {
class SenderWiresStore extends Store<SenderWireRecord> {
constructor() {
- super("senderWires", { keyPath: "id" });
+ super("senderWires", { keyPath: "paytoUri" });
}
}
diff --git a/src/i18n/de.po b/src/i18n/de.po
index ea98099c3..70d7069cd 100644
--- a/src/i18n/de.po
+++ b/src/i18n/de.po
@@ -235,7 +235,7 @@ msgstr ""
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
#. TODO:generic error reporting function or component.
-#: src/webex/pages/confirm-create-reserve.tsx:511 src/webex/pages/tip.tsx:180
+#: src/webex/pages/confirm-create-reserve.tsx:515 src/webex/pages/tip.tsx:180
#, c-format
msgid "Fatal error: \"%1$s\"."
msgstr ""
diff --git a/src/i18n/en-US.po b/src/i18n/en-US.po
index 5d68c6167..2bd3e0f59 100644
--- a/src/i18n/en-US.po
+++ b/src/i18n/en-US.po
@@ -235,7 +235,7 @@ msgstr ""
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
#. TODO:generic error reporting function or component.
-#: src/webex/pages/confirm-create-reserve.tsx:511 src/webex/pages/tip.tsx:180
+#: src/webex/pages/confirm-create-reserve.tsx:515 src/webex/pages/tip.tsx:180
#, c-format
msgid "Fatal error: \"%1$s\"."
msgstr ""
diff --git a/src/i18n/fr.po b/src/i18n/fr.po
index f097767a8..e62328a9c 100644
--- a/src/i18n/fr.po
+++ b/src/i18n/fr.po
@@ -235,7 +235,7 @@ msgstr ""
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
#. TODO:generic error reporting function or component.
-#: src/webex/pages/confirm-create-reserve.tsx:511 src/webex/pages/tip.tsx:180
+#: src/webex/pages/confirm-create-reserve.tsx:515 src/webex/pages/tip.tsx:180
#, c-format
msgid "Fatal error: \"%1$s\"."
msgstr ""
diff --git a/src/i18n/it.po b/src/i18n/it.po
index f097767a8..e62328a9c 100644
--- a/src/i18n/it.po
+++ b/src/i18n/it.po
@@ -235,7 +235,7 @@ msgstr ""
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
#. TODO:generic error reporting function or component.
-#: src/webex/pages/confirm-create-reserve.tsx:511 src/webex/pages/tip.tsx:180
+#: src/webex/pages/confirm-create-reserve.tsx:515 src/webex/pages/tip.tsx:180
#, c-format
msgid "Fatal error: \"%1$s\"."
msgstr ""
diff --git a/src/i18n/sv.po b/src/i18n/sv.po
index 902f5cf1f..36cde50c7 100644
--- a/src/i18n/sv.po
+++ b/src/i18n/sv.po
@@ -239,7 +239,7 @@ msgstr ""
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
#. TODO:generic error reporting function or component.
-#: src/webex/pages/confirm-create-reserve.tsx:511 src/webex/pages/tip.tsx:180
+#: src/webex/pages/confirm-create-reserve.tsx:515 src/webex/pages/tip.tsx:180
#, c-format
msgid "Fatal error: \"%1$s\"."
msgstr ""
diff --git a/src/i18n/taler-wallet-webex.pot b/src/i18n/taler-wallet-webex.pot
index f097767a8..e62328a9c 100644
--- a/src/i18n/taler-wallet-webex.pot
+++ b/src/i18n/taler-wallet-webex.pot
@@ -235,7 +235,7 @@ msgstr ""
#. #-#-#-#-# - (PACKAGE VERSION) #-#-#-#-#
#. TODO:generic error reporting function or component.
-#: src/webex/pages/confirm-create-reserve.tsx:511 src/webex/pages/tip.tsx:180
+#: src/webex/pages/confirm-create-reserve.tsx:515 src/webex/pages/tip.tsx:180
#, c-format
msgid "Fatal error: \"%1$s\"."
msgstr ""
diff --git a/src/talerTypes.ts b/src/talerTypes.ts
index f8fb72b93..db49b0747 100644
--- a/src/talerTypes.ts
+++ b/src/talerTypes.ts
@@ -852,29 +852,25 @@ export class WireFeesJson {
}
-/**
- * Information about wire transfer methods supported
- * by the exchange.
- */
-@Checkable.Class({extra: true})
-export class WireDetailJson {
- /**
- * Name of the wire transfer method.
- */
+@Checkable.Class()
+export class AccountInfo {
@Checkable.String()
- type: string;
+ url: string;
- /**
- * Fees associated with the wire transfer method.
- */
- @Checkable.List(Checkable.Value(() => WireFeesJson))
- fees: WireFeesJson[];
+ @Checkable.String()
+ master_sig: string;
+}
- /**
- * Verify that a value matches the schema of this class and convert it into a
- * member.
- */
- static checked: (obj: any) => WireDetailJson;
+
+@Checkable.Class({extra: true})
+export class ExchangeWireJson {
+ @Checkable.Map(Checkable.String(), Checkable.List(Checkable.Value(() => WireFeesJson)))
+ fees: { [methodName: string]: WireFeesJson[] };
+
+ @Checkable.List(Checkable.Value(() => AccountInfo))
+ accounts: AccountInfo[];
+
+ static checked: (obj: any) => ExchangeWireJson;
}
@@ -884,12 +880,6 @@ export class WireDetailJson {
*/
export type WireDetail = object & { type: string };
-/**
- * Type guard for wire details.
- */
-export function isWireDetail(x: any): x is WireDetail {
- return x && typeof x === "object" && typeof x.type === "string";
-}
/**
* Proposal returned from the contract URL.
diff --git a/src/wallet.ts b/src/wallet.ts
index 434eb8b8c..58c69d79c 100644
--- a/src/wallet.ts
+++ b/src/wallet.ts
@@ -28,7 +28,6 @@ import {
canonicalJson,
canonicalizeBaseUrl,
getTalerStampSec,
- hash,
strcmp,
} from "./helpers";
import {
@@ -75,6 +74,7 @@ import {
ContractTerms,
Denomination,
ExchangeHandle,
+ ExchangeWireJson,
KeysJson,
MerchantRefundPermission,
MerchantRefundResponse,
@@ -86,8 +86,6 @@ import {
TipPlanchetDetail,
TipResponse,
TipToken,
- WireDetailJson,
- isWireDetail,
} from "./talerTypes";
import {
Badge,
@@ -109,7 +107,6 @@ import {
TipStatus,
WalletBalance,
WalletBalanceEntry,
- WireInfo,
} from "./walletTypes";
@@ -1133,10 +1130,9 @@ export class Wallet {
};
const senderWire = req.senderWire;
- if (isWireDetail(senderWire)) {
+ if (senderWire) {
const rec = {
- id: hash(senderWire),
- senderWire,
+ paytoUri: senderWire,
};
await this.q().put(Stores.senderWires, rec).finish();
}
@@ -1327,7 +1323,7 @@ export class Wallet {
/**
* Get the wire information for the exchange with the given base URL.
*/
- async getWireInfo(exchangeBaseUrl: string): Promise<WireInfo> {
+ async getWireInfo(exchangeBaseUrl: string): Promise<ExchangeWireJson> {
exchangeBaseUrl = canonicalizeBaseUrl(exchangeBaseUrl);
const reqUrl = new URI("wire").absoluteTo(exchangeBaseUrl);
const resp = await this.http.get(reqUrl.href());
@@ -1340,7 +1336,7 @@ export class Wallet {
if (!wiJson) {
throw Error("/wire response malformed");
}
- return wiJson;
+ return ExchangeWireJson.checked(wiJson)
}
@@ -1500,6 +1496,11 @@ export class Wallet {
throw Error(`no wire fees found for exchange ${baseUrl}`);
}
+ const exchangeWireAccounts: string[] = [];
+ for (let account of wireInfo.accounts) {
+ exchangeWireAccounts.push(account.url);
+ }
+
const {isTrusted, isAudited} = await this.getExchangeTrust(exchangeInfo);
let earliestDepositExpiration = Infinity;
@@ -1534,10 +1535,10 @@ export class Wallet {
}
}
-
const ret: ReserveCreationInfo = {
earliestDepositExpiration,
exchangeInfo,
+ exchangeWireAccounts,
exchangeVersion: exchangeInfo.protocolVersion || "unknown",
isAudited,
isTrusted,
@@ -1548,7 +1549,6 @@ export class Wallet {
versionMatch,
walletVersion: WALLET_PROTOCOL_VERSION,
wireFees,
- wireInfo,
withdrawFee: acc,
};
return ret;
@@ -1563,26 +1563,13 @@ export class Wallet {
async updateExchangeFromUrl(baseUrl: string): Promise<ExchangeRecord> {
baseUrl = canonicalizeBaseUrl(baseUrl);
const keysUrl = new URI("keys").absoluteTo(baseUrl);
- const wireUrl = new URI("wire").absoluteTo(baseUrl);
const keysResp = await this.http.get(keysUrl.href());
if (keysResp.status !== 200) {
throw Error("/keys request failed");
}
- const wireResp = await this.http.get(wireUrl.href());
- if (wireResp.status !== 200) {
- throw Error("/wire request failed");
- }
const exchangeKeysJson = KeysJson.checked(JSON.parse(keysResp.responseText));
- const wireRespJson = JSON.parse(wireResp.responseText);
- if (typeof wireRespJson !== "object") {
- throw Error("/wire response is not an object");
- }
- console.log("exchange wire", wireRespJson);
- const wireMethodDetails: WireDetailJson[] = [];
- for (const methodName in wireRespJson) {
- wireMethodDetails.push(WireDetailJson.checked(wireRespJson[methodName]));
- }
- return this.updateExchangeFromJson(baseUrl, exchangeKeysJson, wireMethodDetails);
+ const exchangeWire = await this.getWireInfo(baseUrl);
+ return this.updateExchangeFromJson(baseUrl, exchangeKeysJson, exchangeWire);
}
@@ -1614,7 +1601,7 @@ export class Wallet {
private async updateExchangeFromJson(baseUrl: string,
exchangeKeysJson: KeysJson,
- wireMethodDetails: WireDetailJson[]): Promise<ExchangeRecord> {
+ wireMethodDetails: ExchangeWireJson): Promise<ExchangeRecord> {
// FIXME: all this should probably be commited atomically
const updateTimeSec = getTalerStampSec(exchangeKeysJson.list_issue_date);
@@ -1667,16 +1654,17 @@ export class Wallet {
};
}
- for (const detail of wireMethodDetails) {
+ for (const paytoTargetType in wireMethodDetails.fees) {
let latestFeeStamp = 0;
- const fees = oldWireFees.feesForType[detail.type] || [];
- oldWireFees.feesForType[detail.type] = fees;
- for (const oldFee of fees) {
+ const newFeeDetails = wireMethodDetails.fees[paytoTargetType];
+ const oldFeeDetails = oldWireFees.feesForType[paytoTargetType] || [];
+ oldWireFees.feesForType[paytoTargetType] = oldFeeDetails;
+ for (const oldFee of oldFeeDetails) {
if (oldFee.endStamp > latestFeeStamp) {
latestFeeStamp = oldFee.endStamp;
}
}
- for (const fee of detail.fees) {
+ for (const fee of newFeeDetails) {
const start = getTalerStampSec(fee.start_date);
if (start === null) {
console.error("invalid start stamp in fee", fee);
@@ -1697,12 +1685,12 @@ export class Wallet {
startStamp: start,
wireFee: Amounts.parseOrThrow(fee.wire_fee),
};
- const valid: boolean = await this.cryptoApi.isValidWireFee(detail.type, wf, exchangeInfo.masterPublicKey);
+ const valid: boolean = await this.cryptoApi.isValidWireFee(paytoTargetType, wf, exchangeInfo.masterPublicKey);
if (!valid) {
console.error("fee signature invalid", fee);
throw Error("fee signature invalid");
}
- fees.push(wf);
+ oldFeeDetails.push(wf);
}
}
@@ -2434,11 +2422,9 @@ export class Wallet {
const senderWiresSet = new Set();
await this.q().iter(Stores.senderWires).map((x) => {
- if (x.senderWire) {
- senderWiresSet.add(canonicalJson(x.senderWire));
- }
+ senderWiresSet.add(x.paytoUri);
}).run();
- const senderWires = Array.from(senderWiresSet).map((x) => JSON.parse(x));
+ const senderWires = Array.from(senderWiresSet);
return {
exchangeWireTypes,
diff --git a/src/walletTypes.ts b/src/walletTypes.ts
index b6355db0d..73a72bbbf 100644
--- a/src/walletTypes.ts
+++ b/src/walletTypes.ts
@@ -71,19 +71,6 @@ export class CreateReserveResponse {
/**
- * Wire info, sent to the bank when creating a reserve. Fee information will
- * be filtered out. Only methods that the bank also supports should be sent.
- */
-export interface WireInfo {
- /**
- * Mapping from wire method type to the exchange's wire info,
- * excluding fees.
- */
- [type: string]: any;
-}
-
-
-/**
* Information about what will happen when creating a reserve.
*
* Sent to the wallet frontend to be rendered and shown to the user.
@@ -97,7 +84,7 @@ export interface ReserveCreationInfo {
/**
* Filtered wire info to send to the bank.
*/
- wireInfo: WireInfo;
+ exchangeWireAccounts: string[];
/**
* Selected denominations for withdraw.
@@ -139,6 +126,7 @@ export interface ReserveCreationInfo {
* Number of currently offered denominations.
*/
numOfferedDenoms: number;
+
/**
* Public keys of trusted auditors for the currency we're withdrawing.
*/
@@ -337,10 +325,11 @@ export class CreateReserveRequest {
exchange: string;
/**
- * Wire details for the bank account that sent the funds to the exchange.
+ * Wire details (as a payto URI) for the bank account that sent the funds to
+ * the exchange.
*/
- @Checkable.Optional(Checkable.Any())
- senderWire?: object;
+ @Checkable.Optional(Checkable.String())
+ senderWire?: string;
/**
* Verify that a value matches the schema of this class and convert it into a
diff --git a/src/webex/pages/confirm-create-reserve.tsx b/src/webex/pages/confirm-create-reserve.tsx
index cef647163..2d4f41dfe 100644
--- a/src/webex/pages/confirm-create-reserve.tsx
+++ b/src/webex/pages/confirm-create-reserve.tsx
@@ -92,7 +92,7 @@ interface ExchangeSelectionProps {
callback_url: string;
wt_types: string[];
currencyRecord: CurrencyRecord|null;
- sender_wire: object | undefined;
+ sender_wire: string | undefined;
}
interface ManualSelectionProps {
@@ -410,7 +410,7 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
exchange: string,
amount: AmountJson,
callback_url: string,
- sender_wire: object | undefined) {
+ sender_wire: string | undefined) {
const rawResp = await createReserve({
amount,
exchange: canonicalizeBaseUrl(exchange),
@@ -420,21 +420,25 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
throw Error("empty response");
}
// FIXME: filter out types that bank/exchange don't have in common
- const wireDetails = rci.wireInfo;
- const filteredWireDetails: any = {};
- for (const wireType in wireDetails) {
- if (this.props.wt_types.findIndex((x) => x.toLowerCase() === wireType.toLowerCase()) < 0) {
+ const exchangeWireAccounts = [];
+
+ for (let acct of rci.exchangeWireAccounts) {
+ const payto = new URI(acct);
+ if (payto.scheme() != "payto") {
+ console.warn("unknown wire account URI scheme", acct);
continue;
}
- const obj = Object.assign({}, wireDetails[wireType]);
- // The bank doesn't need to know about fees
- delete obj.fees;
- // Consequently the bank can't verify signatures anyway, so
- // we delete this extra data, to make the request URL shorter.
- delete obj.salt;
- delete obj.sig;
- filteredWireDetails[wireType] = obj;
+ if (this.props.wt_types.includes(payto.authority())) {
+ exchangeWireAccounts.push(acct);
+ }
}
+
+ const chosenAcct = exchangeWireAccounts[0];
+
+ if (!chosenAcct) {
+ throw Error("no exchange account matches the bank's supported types");
+ }
+
if (!rawResp.error) {
const resp = CreateReserveResponse.checked(rawResp);
const q: {[name: string]: string|number} = {
@@ -442,7 +446,7 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
amount_fraction: amount.fraction,
amount_value: amount.value,
exchange: resp.exchange,
- exchange_wire_details: JSON.stringify(filteredWireDetails),
+ exchange_wire_details: chosenAcct,
reserve_pub: resp.reservePub,
};
const url = new URI(callback_url).addQuery(q);
@@ -487,7 +491,11 @@ async function main() {
let sender_wire;
if (query.sender_wire) {
- sender_wire = JSON.parse(query.sender_wire);
+ let senderWireUri = new URI(query.sender_wire);
+ if (senderWireUri.scheme() != "payto") {
+ throw Error("sender wire info must be a payto URI");
+ }
+ sender_wire = query.sender_wire;
}
const suggestedExchangeUrl = query.suggested_exchange_url;
diff --git a/src/webex/wxApi.ts b/src/webex/wxApi.ts
index fde7b8c35..4f7500368 100644
--- a/src/webex/wxApi.ts
+++ b/src/webex/wxApi.ts
@@ -273,7 +273,7 @@ export function checkUpgrade(): Promise<UpgradeResponse> {
/**
* Create a reserve.
*/
-export function createReserve(args: { amount: AmountJson, exchange: string, senderWire?: object }): Promise<any> {
+export function createReserve(args: { amount: AmountJson, exchange: string, senderWire?: string }): Promise<any> {
return callBackend("create-reserve", args);
}
diff --git a/webpack.config.js b/webpack.config.js
index 68e8b3cac..845b56fe2 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -18,7 +18,7 @@ module.exports = function (env) {
const base = {
output: {
filename: '[name]-bundle.js',
- chunkFilename: "[id]-bundle.js",
+ chunkFilename: "[name]-bundle.js",
path: path.resolve(__dirname, "dist"),
},
module: {