From 202d51c6a2aea6c24af00605dd76b4fc37e42630 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 4 Jan 2018 11:35:04 +0100 Subject: refactor / put some types where they belong --- src/dbTypes.ts | 258 ++++++++++++++++++++++++------- src/helpers.ts | 17 +++ src/talerTypes.ts | 140 +++++++++++++++++ src/wallet.ts | 389 ++--------------------------------------------- src/walletTypes.ts | 26 ++++ src/webex/chromeBadge.ts | 2 +- src/webex/wxBackend.ts | 7 +- 7 files changed, 402 insertions(+), 437 deletions(-) diff --git a/src/dbTypes.ts b/src/dbTypes.ts index 264f81dd5..b5040bee4 100644 --- a/src/dbTypes.ts +++ b/src/dbTypes.ts @@ -37,6 +37,20 @@ import { WireDetail, } from "./talerTypes"; +import { + Index, + Store, +} from "./query"; + + +/** + * Current database version, should be incremented + * each time we do incompatible schema changes on the database. + * In the future we might consider adding migration functions for + * each version increment. + */ +export const WALLET_DB_VERSION = 24; + /** * A reserve record as stored in the wallet's database. @@ -377,60 +391,6 @@ export interface RefreshPreCoinRecord { } -/** - * State of returning a list of coins - * to the customer's bank account. - */ -export interface CoinsReturnRecord { - /** - * Coins that we're returning. - */ - coins: CoinPaySig[]; - - /** - * Responses to the deposit requests. - */ - responses: any; - - /** - * Ephemeral dummy merchant key for - * the coins returns operation. - */ - dummyMerchantPub: string; - - /** - * Ephemeral dummy merchant key for - * the coins returns operation. - */ - dummyMerchantPriv: string; - - /** - * Contract terms. - */ - contractTerms: string; - - /** - * Hash of contract terms. - */ - contractTermsHash: string; - - /** - * Wire info to send the money for the coins to. - */ - wire: object; - - /** - * Hash of the wire object. - */ - wireHash: string; - - /** - * All coins were deposited. - */ - finished: boolean; -} - - /** * Status of a coin. */ @@ -826,3 +786,193 @@ export interface SenderWireRecord { */ id: number; } + + +/** + * Nonce record as stored in the wallet's database. + */ +export interface NonceRecord { + priv: string; + pub: string; +} + + +/** + * Configuration key/value entries to configure + * the wallet. + */ +export interface ConfigRecord { + key: string; + value: any; +} + + +/** + * Coin that we're depositing ourselves. + */ +export interface DepositCoin { + coinPaySig: CoinPaySig; + + /** + * Undefined if coin not deposited, otherwise signature + * from the exchange confirming the deposit. + */ + depositedSig?: string; +} + + +/** + * Record stored in the wallet's database when the user sends coins back to + * their own bank account. Stores the status of coins that are deposited to + * the wallet itself, where the wallet acts as a "merchant" for the customer. + */ +export interface CoinsReturnRecord { + /** + * Hash of the contract for sending coins to our own bank account. + */ + contractTermsHash: string; + + contractTerms: ContractTerms; + + /** + * Private key where corresponding + * public key is used in the contract terms + * as merchant pub. + */ + merchantPriv: string; + + coins: DepositCoin[]; + + /** + * Exchange base URL to deposit coins at. + */ + exchange: string; + + /** + * Our own wire information for the deposit. + */ + wire: any; +} + + +/* tslint:disable:completed-docs */ + +/** + * The stores and indices for the wallet database. + */ +export namespace Stores { + class ExchangeStore extends Store { + constructor() { + super("exchanges", { keyPath: "baseUrl" }); + } + + pubKeyIndex = new Index(this, "pubKeyIndex", "masterPublicKey"); + } + + class NonceStore extends Store { + constructor() { + super("nonces", { keyPath: "pub" }); + } + } + + class CoinsStore extends Store { + constructor() { + super("coins", { keyPath: "coinPub" }); + } + + exchangeBaseUrlIndex = new Index(this, "exchangeBaseUrl", "exchangeBaseUrl"); + denomPubIndex = new Index(this, "denomPubIndex", "denomPub"); + } + + class ProposalsStore extends Store { + constructor() { + super("proposals", { + autoIncrement: true, + keyPath: "id", + }); + } + timestampIndex = new Index(this, "timestampIndex", "timestamp"); + } + + class PurchasesStore extends Store { + constructor() { + super("purchases", { keyPath: "contractTermsHash" }); + } + + fulfillmentUrlIndex = new Index(this, + "fulfillmentUrlIndex", + "contractTerms.fulfillment_url"); + orderIdIndex = new Index(this, "orderIdIndex", "contractTerms.order_id"); + timestampIndex = new Index(this, "timestampIndex", "timestamp"); + } + + class DenominationsStore extends Store { + constructor() { + // cast needed because of bug in type annotations + super("denominations", + {keyPath: ["exchangeBaseUrl", "denomPub"] as any as IDBKeyPath}); + } + + denomPubHashIndex = new Index(this, "denomPubHashIndex", "denomPubHash"); + exchangeBaseUrlIndex = new Index(this, "exchangeBaseUrlIndex", "exchangeBaseUrl"); + denomPubIndex = new Index(this, "denomPubIndex", "denomPub"); + } + + class CurrenciesStore extends Store { + constructor() { + super("currencies", { keyPath: "name" }); + } + } + + class ConfigStore extends Store { + constructor() { + super("config", { keyPath: "key" }); + } + } + + class ExchangeWireFeesStore extends Store { + constructor() { + super("exchangeWireFees", { keyPath: "exchangeBaseUrl" }); + } + } + + class ReservesStore extends Store { + constructor() { + super("reserves", { keyPath: "reserve_pub" }); + } + timestampCreatedIndex = new Index(this, "timestampCreatedIndex", "created"); + timestampConfirmedIndex = new Index(this, "timestampConfirmedIndex", "timestamp_confirmed"); + timestampDepletedIndex = new Index(this, "timestampDepletedIndex", "timestamp_depleted"); + } + + class TipsStore extends Store { + constructor() { + super("tips", { keyPath: ["tipId", "merchantDomain"] as any as IDBKeyPath }); + } + coinPubIndex = new Index(this, "coinPubIndex", "coinPubs", { multiEntry: true }); + } + + class SenderWiresStore extends Store { + constructor() { + super("senderWires", { keyPath: "id" }); + } + } + + export const coins = new CoinsStore(); + export const coinsReturns = new Store("coinsReturns", {keyPath: "contractTermsHash"}); + 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 nonces = new NonceStore(); + export const precoins = new Store("precoins", {keyPath: "coinPub"}); + export const proposals = new ProposalsStore(); + export const refresh = new Store("refresh", {keyPath: "id", autoIncrement: true}); + export const reserves = new ReservesStore(); + export const purchases = new PurchasesStore(); + export const tips = new TipsStore(); + export const senderWires = new SenderWiresStore(); +} + +/* tslint:enable:completed-docs */ diff --git a/src/helpers.ts b/src/helpers.ts index 42863c65b..3b7cd36f5 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -138,6 +138,9 @@ export function getTalerStampDate(stamp: string): Date | null { return new Date(sec * 1000); } +/** + * Compute the hash function of a JSON object. + */ export function hash(val: any): number { const str = canonicalJson(val); // https://github.com/darkskyapp/string-hash @@ -152,3 +155,17 @@ export function hash(val: any): number { * signed int to an unsigned by doing an unsigned bitshift. */ return h >>> 0; } + + +/** + * Lexically compare two strings. + */ +export function strcmp(s1: string, s2: string): number { + if (s1 < s2) { + return -1; + } + if (s1 > s2) { + return 1; + } + return 0; +} diff --git a/src/talerTypes.ts b/src/talerTypes.ts index e83a0b6b6..5ba5af17f 100644 --- a/src/talerTypes.ts +++ b/src/talerTypes.ts @@ -631,6 +631,146 @@ export class TipToken { static checked: (obj: any) => TipToken; } + +/** + * Element of the payback list that the + * exchange gives us in /keys. + */ +@Checkable.Class() +export class Payback { + /** + * The hash of the denomination public key for which the payback is offered. + */ + @Checkable.String + h_denom_pub: string; +} + + +/** + * Structure that the exchange gives us in /keys. + */ +@Checkable.Class({extra: true}) +export class KeysJson { + /** + * List of offered denominations. + */ + @Checkable.List(Checkable.Value(Denomination)) + denoms: Denomination[]; + + /** + * The exchange's master public key. + */ + @Checkable.String + master_public_key: string; + + /** + * The list of auditors (partially) auditing the exchange. + */ + @Checkable.List(Checkable.Value(Auditor)) + auditors: Auditor[]; + + /** + * Timestamp when this response was issued. + */ + @Checkable.String + list_issue_date: string; + + /** + * List of paybacks for compromised denominations. + */ + @Checkable.Optional(Checkable.List(Checkable.Value(Payback))) + payback?: Payback[]; + + /** + * Short-lived signing keys used to sign online + * responses. + */ + @Checkable.Any + signkeys: any; + + /** + * Protocol version. + */ + @Checkable.Optional(Checkable.String) + version?: string; + + /** + * Verify that a value matches the schema of this class and convert it into a + * member. + */ + static checked: (obj: any) => KeysJson; +} + + +/** + * Wire fees as anounced by the exchange. + */ +@Checkable.Class() +export class WireFeesJson { + /** + * Cost of a wire transfer. + */ + @Checkable.Value(AmountJson) + wire_fee: AmountJson; + + /** + * Cost of clising a reserve. + */ + @Checkable.Value(AmountJson) + closing_fee: AmountJson; + + /** + * Signature made with the exchange's master key. + */ + @Checkable.String + sig: string; + + /** + * Date from which the fee applies. + */ + @Checkable.String + start_date: string; + + /** + * Data after which the fee doesn't apply anymore. + */ + @Checkable.String + end_date: string; + + /** + * Verify that a value matches the schema of this class and convert it into a + * member. + */ + static checked: (obj: any) => WireFeesJson; +} + + +/** + * Information about wire transfer methods supported + * by the exchange. + */ +@Checkable.Class({extra: true}) +export class WireDetailJson { + /** + * Name of the wire transfer method. + */ + @Checkable.String + type: string; + + /** + * Fees associated with the wire transfer method. + */ + @Checkable.List(Checkable.Value(WireFeesJson)) + fees: WireFeesJson[]; + + /** + * Verify that a value matches the schema of this class and convert it into a + * member. + */ + static checked: (obj: any) => WireDetailJson; +} + + /** * Wire detail, arbitrary object that must at least * contain a "type" key. diff --git a/src/wallet.ts b/src/wallet.ts index 6ad9964c5..b3ef3bf31 100644 --- a/src/wallet.ts +++ b/src/wallet.ts @@ -22,14 +22,14 @@ /** * Imports. */ -import {Checkable} from "./checkable"; -import {CryptoApi} from "./crypto/cryptoApi"; +import { CryptoApi } from "./crypto/cryptoApi"; import { amountToPretty, canonicalJson, canonicalizeBaseUrl, getTalerStampSec, hash, + strcmp, } from "./helpers"; import { HttpRequestLibrary, @@ -38,20 +38,21 @@ import { import * as LibtoolVersion from "./libtoolVersion"; import { AbortTransaction, - Index, JoinLeftResult, JoinResult, QueryRoot, - Store, } from "./query"; import { TimerGroup } from "./timer"; import { AmountJson } from "./amounts"; import * as Amounts from "./amounts"; +import URI = require("urijs"); + import { CoinRecord, CoinStatus, + CoinsReturnRecord, CurrencyRecord, DenominationRecord, DenominationStatus, @@ -63,27 +64,26 @@ import { RefreshPreCoinRecord, RefreshSessionRecord, ReserveRecord, - SenderWireRecord, + Stores, TipRecord, WireFee, } from "./dbTypes"; - -import URI = require("urijs"); - import { Auditor, - CoinPaySig, ContractTerms, Denomination, ExchangeHandle, + KeysJson, PayReq, PaybackConfirmation, RefundPermission, TipPlanchetDetail, TipResponse, + WireDetailJson, isWireDetail, } from "./talerTypes"; import { + Badge, CheckPayResult, CoinSelectionResult, CoinWithDenom, @@ -102,239 +102,9 @@ import { WalletBalance, WalletBalanceEntry, WireInfo, - } from "./walletTypes"; -/** - * Element of the payback list that the - * exchange gives us in /keys. - */ -@Checkable.Class() -export class Payback { - /** - * The hash of the denomination public key for which the payback is offered. - */ - @Checkable.String - h_denom_pub: string; -} - - -/** - * Structure that the exchange gives us in /keys. - */ -@Checkable.Class({extra: true}) -export class KeysJson { - /** - * List of offered denominations. - */ - @Checkable.List(Checkable.Value(Denomination)) - denoms: Denomination[]; - - /** - * The exchange's master public key. - */ - @Checkable.String - master_public_key: string; - - /** - * The list of auditors (partially) auditing the exchange. - */ - @Checkable.List(Checkable.Value(Auditor)) - auditors: Auditor[]; - - /** - * Timestamp when this response was issued. - */ - @Checkable.String - list_issue_date: string; - - /** - * List of paybacks for compromised denominations. - */ - @Checkable.Optional(Checkable.List(Checkable.Value(Payback))) - payback?: Payback[]; - - /** - * Short-lived signing keys used to sign online - * responses. - */ - @Checkable.Any - signkeys: any; - - /** - * Protocol version. - */ - @Checkable.Optional(Checkable.String) - version?: string; - - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => KeysJson; -} - - -/** - * Wire fees as anounced by the exchange. - */ -@Checkable.Class() -class WireFeesJson { - /** - * Cost of a wire transfer. - */ - @Checkable.Value(AmountJson) - wire_fee: AmountJson; - - /** - * Cost of clising a reserve. - */ - @Checkable.Value(AmountJson) - closing_fee: AmountJson; - - /** - * Signature made with the exchange's master key. - */ - @Checkable.String - sig: string; - - /** - * Date from which the fee applies. - */ - @Checkable.String - start_date: string; - - /** - * Data after which the fee doesn't apply anymore. - */ - @Checkable.String - end_date: string; - - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => WireFeesJson; -} - - -/** - * Information about wire transfer methods supported - * by the exchange. - */ -@Checkable.Class({extra: true}) -class WireDetailJson { - /** - * Name of the wire transfer method. - */ - @Checkable.String - type: string; - - /** - * Fees associated with the wire transfer method. - */ - @Checkable.List(Checkable.Value(WireFeesJson)) - fees: WireFeesJson[]; - - /** - * Verify that a value matches the schema of this class and convert it into a - * member. - */ - static checked: (obj: any) => WireDetailJson; -} - - -/** - * Badge that shows activity for the wallet. - */ -export interface Badge { - /** - * Start indicating background activity. - */ - startBusy(): void; - - /** - * Stop indicating background activity. - */ - stopBusy(): void; - - /** - * Show the notification in the badge. - */ - showNotification(): void; - - /** - * Stop showing the notification. - */ - clearNotification(): void; -} - - -/** - * Nonce record as stored in the wallet's database. - */ -export interface NonceRecord { - priv: string; - pub: string; -} - -/** - * Configuration key/value entries to configure - * the wallet. - */ -export interface ConfigRecord { - key: string; - value: any; -} - - -/** - * Coin that we're depositing ourselves. - */ -export interface DepositCoin { - coinPaySig: CoinPaySig; - - /** - * Undefined if coin not deposited, otherwise signature - * from the exchange confirming the deposit. - */ - depositedSig?: string; -} - -/** - * Record stored in the wallet's database when the user sends coins back to - * their own bank account. Stores the status of coins that are deposited to - * the wallet itself, where the wallet acts as a "merchant" for the customer. - */ -export interface CoinsReturnRecord { - /** - * Hash of the contract for sending coins to our own bank account. - */ - contractTermsHash: string; - - contractTerms: ContractTerms; - - /** - * Private key where corresponding - * public key is used in the contract terms - * as merchant pub. - */ - merchantPriv: string; - - coins: DepositCoin[]; - - /** - * Exchange base URL to deposit coins at. - */ - exchange: string; - - /** - * Our own wire information for the deposit. - */ - wire: any; -} - interface SpeculativePayData { payCoinInfo: PayCoinInfo; exchangeUrl: string; @@ -351,14 +121,6 @@ interface SpeculativePayData { */ export const WALLET_PROTOCOL_VERSION = "2:0:0"; -/** - * Current database version, should be incremented - * each time we do incompatible schema changes on the database. - * In the future we might consider adding migration functions for - * each version increment. - */ -export const WALLET_DB_VERSION = 24; - const builtinCurrencies: CurrencyRecord[] = [ { auditors: [ @@ -393,17 +155,6 @@ function isWithdrawableDenom(d: DenominationRecord) { } -function strcmp(s1: string, s2: string): number { - if (s1 < s2) { - return -1; - } - if (s1 > s2) { - return 1; - } - return 0; -} - - interface SelectPayCoinsResult { cds: CoinWithDenom[]; totalFees: AmountJson; @@ -528,128 +279,6 @@ function getWithdrawDenomList(amountAvailable: AmountJson, return ds; } -/* tslint:disable:completed-docs */ - -/** - * The stores and indices for the wallet database. - */ -export namespace Stores { - class ExchangeStore extends Store { - constructor() { - super("exchanges", { keyPath: "baseUrl" }); - } - - pubKeyIndex = new Index(this, "pubKeyIndex", "masterPublicKey"); - } - - class NonceStore extends Store { - constructor() { - super("nonces", { keyPath: "pub" }); - } - } - - class CoinsStore extends Store { - constructor() { - super("coins", { keyPath: "coinPub" }); - } - - exchangeBaseUrlIndex = new Index(this, "exchangeBaseUrl", "exchangeBaseUrl"); - denomPubIndex = new Index(this, "denomPubIndex", "denomPub"); - } - - class ProposalsStore extends Store { - constructor() { - super("proposals", { - autoIncrement: true, - keyPath: "id", - }); - } - timestampIndex = new Index(this, "timestampIndex", "timestamp"); - } - - class PurchasesStore extends Store { - constructor() { - super("purchases", { keyPath: "contractTermsHash" }); - } - - fulfillmentUrlIndex = new Index(this, - "fulfillmentUrlIndex", - "contractTerms.fulfillment_url"); - orderIdIndex = new Index(this, "orderIdIndex", "contractTerms.order_id"); - timestampIndex = new Index(this, "timestampIndex", "timestamp"); - } - - class DenominationsStore extends Store { - constructor() { - // cast needed because of bug in type annotations - super("denominations", - {keyPath: ["exchangeBaseUrl", "denomPub"] as any as IDBKeyPath}); - } - - denomPubHashIndex = new Index(this, "denomPubHashIndex", "denomPubHash"); - exchangeBaseUrlIndex = new Index(this, "exchangeBaseUrlIndex", "exchangeBaseUrl"); - denomPubIndex = new Index(this, "denomPubIndex", "denomPub"); - } - - class CurrenciesStore extends Store { - constructor() { - super("currencies", { keyPath: "name" }); - } - } - - class ConfigStore extends Store { - constructor() { - super("config", { keyPath: "key" }); - } - } - - class ExchangeWireFeesStore extends Store { - constructor() { - super("exchangeWireFees", { keyPath: "exchangeBaseUrl" }); - } - } - - class ReservesStore extends Store { - constructor() { - super("reserves", { keyPath: "reserve_pub" }); - } - timestampCreatedIndex = new Index(this, "timestampCreatedIndex", "created"); - timestampConfirmedIndex = new Index(this, "timestampConfirmedIndex", "timestamp_confirmed"); - timestampDepletedIndex = new Index(this, "timestampDepletedIndex", "timestamp_depleted"); - } - - class TipsStore extends Store { - constructor() { - super("tips", { keyPath: ["tipId", "merchantDomain"] as any as IDBKeyPath }); - } - coinPubIndex = new Index(this, "coinPubIndex", "coinPubs", { multiEntry: true }); - } - - class SenderWiresStore extends Store { - constructor() { - super("senderWires", { keyPath: "id" }); - } - } - - export const coins = new CoinsStore(); - export const coinsReturns = new Store("coinsReturns", {keyPath: "contractTermsHash"}); - 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 nonces = new NonceStore(); - export const precoins = new Store("precoins", {keyPath: "coinPub"}); - export const proposals = new ProposalsStore(); - export const refresh = new Store("refresh", {keyPath: "id", autoIncrement: true}); - export const reserves = new ReservesStore(); - export const purchases = new PurchasesStore(); - export const tips = new TipsStore(); - export const senderWires = new SenderWiresStore(); -} - -/* tslint:enable:completed-docs */ - interface CoinsForPaymentArgs { allowedAuditors: Auditor[]; diff --git a/src/walletTypes.ts b/src/walletTypes.ts index 15c004c62..3c7bff1eb 100644 --- a/src/walletTypes.ts +++ b/src/walletTypes.ts @@ -570,3 +570,29 @@ export class GetTipPlanchetsRequest { */ static checked: (obj: any) => GetTipPlanchetsRequest; } + + +/** + * Badge that shows activity for the wallet. + */ +export interface Badge { + /** + * Start indicating background activity. + */ + startBusy(): void; + + /** + * Stop indicating background activity. + */ + stopBusy(): void; + + /** + * Show the notification in the badge. + */ + showNotification(): void; + + /** + * Stop showing the notification. + */ + clearNotification(): void; +} diff --git a/src/webex/chromeBadge.ts b/src/webex/chromeBadge.ts index 3dfe94518..beb1dc444 100644 --- a/src/webex/chromeBadge.ts +++ b/src/webex/chromeBadge.ts @@ -16,7 +16,7 @@ import { Badge, -} from "../wallet"; +} from "../walletTypes"; /** diff --git a/src/webex/wxBackend.ts b/src/webex/wxBackend.ts index a8ce5eebc..02a1543e5 100644 --- a/src/webex/wxBackend.ts +++ b/src/webex/wxBackend.ts @@ -46,11 +46,14 @@ import { } from "../walletTypes"; import { - Stores, - WALLET_DB_VERSION, Wallet, } from "../wallet"; +import { + Stores, + WALLET_DB_VERSION, +} from "../dbTypes"; + import { ChromeBadge } from "./chromeBadge"; import { MessageType } from "./messages"; -- cgit v1.2.3