diff options
author | Florian Dold <florian@dold.me> | 2020-12-07 20:24:16 +0100 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2020-12-07 20:24:16 +0100 |
commit | bd88f3f44304f0389322b99ff62572f3f1d7c5c1 (patch) | |
tree | 6bf09d809afa44dce6ebcd6f00d20a2d913e2f6b /packages/taler-wallet-core/src/types/backupTypes.ts | |
parent | bbd65fc4b78bf4b61142417fda44d43d955cb28d (diff) | |
download | wallet-core-bd88f3f44304f0389322b99ff62572f3f1d7c5c1.tar.xz |
backup schema WIP
Diffstat (limited to 'packages/taler-wallet-core/src/types/backupTypes.ts')
-rw-r--r-- | packages/taler-wallet-core/src/types/backupTypes.ts | 780 |
1 files changed, 713 insertions, 67 deletions
diff --git a/packages/taler-wallet-core/src/types/backupTypes.ts b/packages/taler-wallet-core/src/types/backupTypes.ts index 72d0486b1..cfbfdc49b 100644 --- a/packages/taler-wallet-core/src/types/backupTypes.ts +++ b/packages/taler-wallet-core/src/types/backupTypes.ts @@ -14,6 +14,7 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ +import { Timestamp } from "../util/time"; /** * Type declarations for backup. @@ -21,6 +22,23 @@ * Contains some redundancy with the other type declarations, * as the backup schema must be very stable. * + * Current limitations: + * 1. Contracts that are claimed but not accepted aren't + * exported yet. + * 2. There is no garbage collection mechanism for the export yet. + * (But this should actually become the main GC mechanism!) + * 3. Reserve history isn't backed up yet. + * 4. Recoup metadata isn't exported yet. + * + * General considerations / decisions: + * 1. Information about previously occurring errors and + * retries is never backed up. + * 2. The ToS text of an exchange is never backed up. + * 3. Public keys are always exported in the backup + * and never recomputed (this allows the import to + * complete within a DB transaction that can't access + * the crypto worker). + * * @author Florian Dold <dold@taler.net> */ @@ -51,19 +69,566 @@ export interface WalletBackupContentV1 { */ exchanges: BackupExchangeData[]; - reserves: ReserveBackupData[]; + denominations: BackupDenomination[]; + + reserves: BackupReserveData[]; + + withdrawalGroups: BackupWithdrawalGroup[]; + + refreshGroups: BackupRefreshGroup[]; coins: BackupCoin[]; - planchets: BackupWithdrawalPlanchet[]; + purchases: BackupPurchase[]; +} + +export enum BackupCoinSourceType { + Withdraw = "withdraw", + Refresh = "refresh", + Tip = "tip", +} + +export interface BackupWithdrawCoinSource { + type: BackupCoinSourceType.Withdraw; + + /** + * Can be the empty string for orphaned coins. + */ + withdrawalGroupId: string; + + /** + * Index of the coin in the withdrawal session. + */ + coinIndex: number; + + /** + * Reserve public key for the reserve we got this coin from. + */ + reservePub: string; +} + +export interface BackupRefreshCoinSource { + type: BackupCoinSourceType.Refresh; + oldCoinPub: string; +} + +export interface BackupTipCoinSource { + type: BackupCoinSourceType.Tip; + walletTipId: string; + coinIndex: number; +} + +export type BackupCoinSource = + | BackupWithdrawCoinSource + | BackupRefreshCoinSource + | BackupTipCoinSource; + +export interface BackupCoin { + /** + * Where did the coin come from? Used for recouping coins. + */ + coinSource: BackupCoinSource; + + /** + * Public key of the coin. + */ + coinPub: string; + + /** + * Private key to authorize operations on the coin. + */ + coinPriv: string; + + /** + * Key used by the exchange used to sign the coin. + */ + denomPub: string; + + /** + * Hash of the public key that signs the coin. + */ + denomPubHash: string; + + /** + * Unblinded signature by the exchange. + */ + denomSig: string; + + /** + * Amount that's left on the coin. + */ + currentAmount: BackupAmountString; + + /** + * Base URL that identifies the exchange from which we got the + * coin. + */ + exchangeBaseUrl: string; + + /** + * Blinding key used when withdrawing the coin. + * Potentionally used again during payback. + */ + blindingKey: string; + + fresh: boolean; +} + +/** + * Status of a tip we got from a merchant. + */ +export interface BackupTip { + /** + * Tip ID chosen by the wallet. + */ + walletTipId: string; + + /** + * The merchant's identifier for this tip. + */ + merchantTipId: string; + + /** + * Has the user accepted the tip? Only after the tip has been accepted coins + * withdrawn from the tip may be used. + */ + acceptedTimestamp: Timestamp | undefined; + + createdTimestamp: Timestamp; + + /** + * Timestamp for when the wallet finished picking up the tip + * from the merchant. + */ + pickedUpTimestamp: Timestamp | undefined; + + /** + * The tipped amount. + */ + tipAmountRaw: BackupAmountString; + + tipAmountEffective: BackupAmountString; + + /** + * Timestamp, the tip can't be picked up anymore after this deadline. + */ + tipExpiration: Timestamp; + + /** + * The exchange that will sign our coins, chosen by the merchant. + */ + exchangeBaseUrl: string; + + /** + * Base URL of the merchant that is giving us the tip. + */ + merchantBaseUrl: string; + + /** + * Planchets, the members included in TipPlanchetDetail will be sent to the + * merchant. + */ + planchets?: { + blindingKey: string; + coinEv: string; + coinPriv: string; + coinPub: string; + }[]; + + totalCoinValue: BackupAmountString; + totalWithdrawCost: BackupAmountString; + + selectedDenoms: { + denomPubHash: string; + count: number; + }[]; +} + +/** + * Reasons for why a coin is being refreshed. + */ +export enum BackupRefreshReason { + Manual = "manual", + Pay = "pay", + Refund = "refund", + AbortPay = "abort-pay", + Recoup = "recoup", + BackupRestored = "backup-restored", + Scheduled = "scheduled", +} + +/** + * Planchet for a coin during refrehs. + */ +export interface BackupRefreshPlanchet { + /** + * Public key for the coin. + */ + publicKey: string; + /** + * Private key for the coin. + */ + privateKey: string; + /** + * Blinded public key. + */ + coinEv: string; + /** + * Blinding key used. + */ + blindingKey: string; +} + +export interface BackupRefreshSessionRecord { + /** + * Public key that's being melted in this session. + */ + meltCoinPub: string; + + /** + * How much of the coin's value is melted away + * with this refresh session? + */ + amountRefreshInput: BackupAmountString; + + /** + * Sum of the value of denominations we want + * to withdraw in this session, without fees. + */ + amountRefreshOutput: BackupAmountString; + + /** + * Signature to confirm the melting. + */ + confirmSig: string; + + /** + * Hased denominations of the newly requested coins. + */ + newDenomHashes: string[]; + + /** + * Denominations of the newly requested coins. + */ + newDenoms: string[]; + + /** + * Planchets for each cut-and-choose instance. + */ + planchetsForGammas: BackupRefreshPlanchet[][]; + + /** + * The transfer keys, kappa of them. + */ + transferPubs: string[]; + + /** + * Private keys for the transfer public keys. + */ + transferPrivs: string[]; + + /** + * The no-reveal-index after we've done the melting. + */ + norevealIndex?: number; + + /** + * Hash of the session. + */ + hash: string; + + /** + * Timestamp when the refresh session finished. + */ + finishedTimestamp: Timestamp | undefined; + + /** + * When has this refresh session been created? + */ + timestampCreated: Timestamp; + + /** + * Base URL for the exchange we're doing the refresh with. + */ + exchangeBaseUrl: string; +} + +export interface BackupRefreshGroup { + refreshGroupId: string; + + reason: BackupRefreshReason; + + oldCoinPubs: string[]; + + refreshSessionPerCoin: (BackupRefreshSessionRecord | undefined)[]; + + inputPerCoin: BackupAmountString[]; + + estimatedOutputPerCoin: BackupAmountString[]; + + /** + * Timestamp when the refresh session finished. + */ + timestampFinished: Timestamp | undefined; +} + +export interface BackupWithdrawalGroup { + withdrawalGroupId: string; + + reservePub: string; + + /** + * When was the withdrawal operation started started? + * Timestamp in milliseconds. + */ + timestampStart: Timestamp; + + /** + * When was the withdrawal operation completed? + */ + timestampFinish?: Timestamp; + + /** + * Amount including fees (i.e. the amount subtracted from the + * reserve to withdraw all coins in this withdrawal session). + */ + rawWithdrawalAmount: BackupAmountString; + + totalCoinValue: BackupAmountString; + totalWithdrawCost: BackupAmountString; + + selectedDenoms: { + denomPubHash: string; + count: number; + }[]; - refreshSessions: BackupRefreshSession[]; + /** + * One planchet/coin for each selected denomination. + */ + planchets: { + blindingKey: string; + coinPriv: string; + coinPub: string; + }[]; +} + +export enum BackupRefundState { + Failed = "failed", + Applied = "applied", + Pending = "pending", } -export interface BackupRefreshSession { +export interface BackupRefundItemCommon { + // Execution time as claimed by the merchant + executionTime: Timestamp; + + /** + * Time when the wallet became aware of the refund. + */ + obtainedTime: Timestamp; + + refundAmount: BackupAmountString; + refundFee: BackupAmountString; + /** + * Upper bound on the refresh cost incurred by + * applying this refund. + * + * Might be lower in practice when two refunds on the same + * coin are refreshed in the same refresh operation. + */ + totalRefreshCostBound: BackupAmountString; +} + +/** + * Failed refund, either because the merchant did + * something wrong or it expired. + */ +export interface BackupRefundFailedItem extends BackupRefundItemCommon { + type: BackupRefundState.Failed; } +export interface BackupRefundPendingItem extends BackupRefundItemCommon { + type: BackupRefundState.Pending; +} + +export interface BackupRefundAppliedItem extends BackupRefundItemCommon { + type: BackupRefundState.Applied; +} + +/** + * State of one refund from the merchant, maintained by the wallet. + */ +export type BackupRefundItem = + | BackupRefundFailedItem + | BackupRefundPendingItem + | BackupRefundAppliedItem; + +export interface BackupPurchase { + /** + * Proposal ID for this purchase. Uniquely identifies the + * purchase and the proposal. + */ + proposalId: string; + + /** + * Contract terms we got from the merchant. + */ + contractTermsRaw: string; + + /** + * Amount requested by the merchant. + */ + paymentAmount: BackupAmountString; + + /** + * Public keys of the coins that were selected. + */ + coinPubs: string[]; + + /** + * Deposit permission signature of each coin. + */ + coinSigs: string[]; + + /** + * Amount that each coin contributes. + */ + coinContributions: BackupAmountString[]; + + /** + * How much of the wire fees is the customer paying? + */ + customerWireFees: BackupAmountString; + + /** + * How much of the deposit fees is the customer paying? + */ + customerDepositFees: BackupAmountString; + + totalPayCost: BackupAmountString; + + /** + * Timestamp of the first time that sending a payment to the merchant + * for this purchase was successful. + */ + timestampFirstSuccessfulPay: Timestamp | undefined; + + merchantPaySig: string | undefined; + + /** + * When was the purchase made? + * Refers to the time that the user accepted. + */ + timestampAccept: Timestamp; + + /** + * Pending refunds for the purchase. A refund is pending + * when the merchant reports a transient error from the exchange. + */ + refunds: { [refundKey: string]: BackupRefundItem }; + + /** + * When was the last refund made? + * Set to 0 if no refund was made on the purchase. + */ + timestampLastRefundStatus: Timestamp | undefined; + + abortStatus?: "abort-refund" | "abort-finished"; + + /** + * Continue querying the refund status until this deadline has expired. + */ + autoRefundDeadline: Timestamp | undefined; +} + +/** + * Info about one denomination in the backup. + * + * Note that the wallet only backs up validated denominations. + */ +export interface BackupDenomination { + /** + * Value of one coin of the denomination. + */ + value: BackupAmountString; + + /** + * The denomination public key. + */ + denomPub: string; + + /** + * Hash of the denomination public key. + * Stored in the database for faster lookups. + */ + denomPubHash: string; + + /** + * Fee for withdrawing. + */ + feeWithdraw: BackupAmountString; + + /** + * Fee for depositing. + */ + feeDeposit: BackupAmountString; + + /** + * Fee for refreshing. + */ + feeRefresh: BackupAmountString; + + /** + * Fee for refunding. + */ + feeRefund: BackupAmountString; + + /** + * Validity start date of the denomination. + */ + stampStart: Timestamp; + + /** + * Date after which the currency can't be withdrawn anymore. + */ + stampExpireWithdraw: Timestamp; + + /** + * Date after the denomination officially doesn't exist anymore. + */ + stampExpireLegal: Timestamp; + + /** + * Data after which coins of this denomination can't be deposited anymore. + */ + stampExpireDeposit: Timestamp; + + /** + * Signature by the exchange's master key over the denomination + * information. + */ + masterSig: string; + + /** + * Was this denomination still offered by the exchange the last time + * we checked? + * Only false when the exchange redacts a previously published denomination. + */ + isOffered: boolean; + + /** + * Did the exchange revoke the denomination? + * When this field is set to true in the database, the same transaction + * should also mark all affected coins as revoked. + */ + isRevoked: boolean; + + /** + * Base URL of the exchange. + */ + exchangeBaseUrl: string; +} export interface BackupReserve { reservePub: string; @@ -82,7 +647,7 @@ export interface BackupReserve { senderWire?: string; } -export interface ReserveBackupData { +export interface BackupReserveData { /** * The reserve public key. */ @@ -98,118 +663,199 @@ export interface ReserveBackupData { */ exchangeBaseUrl: string; - instructedAmount: string; + /** + * Time when the reserve was created. + */ + timestampCreated: Timestamp; + + /** + * Time when the information about this reserve was posted to the bank. + * + * Only applies if bankWithdrawStatusUrl is defined. + * + * Set to 0 if that hasn't happened yet. + */ + timestampReserveInfoPosted: Timestamp | undefined; + + /** + * Time when the reserve was confirmed by the bank. + * + * Set to undefined if not confirmed yet. + */ + timestampBankConfirmed: Timestamp | undefined; /** * Wire information (as payto URI) for the bank account that * transfered funds for this reserve. */ senderWire?: string; -} -export interface BackupExchangeData { - exchangeBaseUrl: string; - exchangeMasterPub: string; + /** + * Amount that was sent by the user to fund the reserve. + */ + instructedAmount: BackupAmountString; /** - * ETag for last terms of service download. + * Extra state for when this is a withdrawal involving + * a Taler-integrated bank. */ - termsOfServiceAcceptedEtag: string | undefined; + bankInfo?: { + /** + * Status URL that the wallet will use to query the status + * of the Taler withdrawal operation on the bank's side. + */ + statusUrl: string; + + confirmUrl?: string; + + /** + * Exchange payto URI that the bank will use to fund the reserve. + */ + exchangePaytoUri: string; + + /** + * Do we still need to register the reserve with the bank? + */ + registerPending: boolean; + }; + + initialWithdrawalGroupId: string; + + initialTotalCoinValue: BackupAmountString; + + initialTotalWithdrawCost: BackupAmountString; + initialSelectedDenoms: { + denomPubHash: string; + count: number; + }[]; } +export interface ExchangeBankAccount { + paytoUri: string; +} -export interface BackupWithdrawalPlanchet { - coinSource: BackupWithdrawCoinSource | BackupTipCoinSource; - blindingKey: string; - coinPriv: string; - coinPub: string; - denomPubHash: string; +/** + * Wire fee for one wire method as stored in the + * wallet's database. + */ +export interface BackupExchangeWireFee { + wireType: string; /** - * Base URL that identifies the exchange from which we are getting the - * coin. + * Fee for wire transfers. */ - exchangeBaseUrl: string; -} + wireFee: string; + /** + * Fees to close and refund a reserve. + */ + closingFee: string; -export enum BackupCoinSourceType { - Withdraw = "withdraw", - Refresh = "refresh", - Tip = "tip", -} - -export interface BackupWithdrawCoinSource { - type: BackupCoinSourceType.Withdraw; - withdrawalGroupId: string; + /** + * Start date of the fee. + */ + startStamp: Timestamp; /** - * Index of the coin in the withdrawal session. + * End date of the fee. */ - coinIndex: number; + endStamp: Timestamp; /** - * Reserve public key for the reserve we got this coin from. + * Signature made by the exchange master key. */ - reservePub: string; + sig: string; } -export interface BackupRefreshCoinSource { - type: BackupCoinSourceType.Refresh; - oldCoinPub: string; +/** + * Structure of one exchange signing key in the /keys response. + */ +export class BackupExchangeSignKey { + stampStart: Timestamp; + stampExpire: Timestamp; + stampEnd: Timestamp; + key: string; + masterSig: string; } -export interface BackupTipCoinSource { - type: BackupCoinSourceType.Tip; - walletTipId: string; - coinIndex: number; -} +/** + * Signature by the auditor that a particular denomination key is audited. + */ +export class AuditorDenomSig { + /** + * Denomination public key's hash. + */ + denom_pub_h: string; -export type BackupCoinSource = - | BackupWithdrawCoinSource - | BackupRefreshCoinSource - | BackupTipCoinSource; + /** + * The signature. + */ + auditor_sig: string; +} /** - * Coin that has been withdrawn and might have been - * (partially) spent. + * Auditor information as given by the exchange in /keys. */ -export interface BackupCoin { +export class BackupExchangeAuditor { /** - * Public key of the coin. + * Auditor's public key. */ - coinPub: string; + auditorPub: string; /** - * Private key of the coin. + * Base URL of the auditor. */ - coinPriv: string; + auditorUrl: string; /** - * Where did the coin come from (withdrawal/refresh/tip)? - * Used for recouping coins. + * List of signatures for denominations by the auditor. */ - coinSource: BackupCoinSource; + denominationKeys: AuditorDenomSig[]; +} + +export interface BackupExchangeData { + /** + * Base url of the exchange. + */ + baseUrl: string; /** - * Is the coin still fresh + * Master public key of the exchange. */ - fresh: boolean; + masterPublicKey: string; /** - * Blinding key used when withdrawing the coin. - * Potentionally used again during payback. + * Auditors (partially) auditing the exchange. */ - blindingKey: string; + auditors: BackupExchangeAuditor[]; /** - * Amount that's left on the coin. + * Currency that the exchange offers. */ - currentAmount: BackupAmountString; + currency: string; /** - * Base URL that identifies the exchange from which we got the - * coin. + * Last observed protocol version. */ - exchangeBaseUrl: string; + protocolVersion: string; + + /** + * Signing keys we got from the exchange, can also contain + * older signing keys that are not returned by /keys anymore. + */ + signingKeys: BackupExchangeSignKey[]; + + wireFees: BackupExchangeWireFee[]; + + accounts: ExchangeBankAccount[]; + + /** + * ETag for last terms of service download. + */ + termsOfServiceLastEtag: string | undefined; + + /** + * ETag for last terms of service download. + */ + termsOfServiceAcceptedEtag: string | undefined; } |