diff options
14 files changed, 87 insertions, 177 deletions
diff --git a/packages/taler-util/src/backupTypes.ts b/packages/taler-util/src/backupTypes.ts index 97fbcebcc..70e52e63b 100644 --- a/packages/taler-util/src/backupTypes.ts +++ b/packages/taler-util/src/backupTypes.ts @@ -897,6 +897,12 @@ export interface BackupDenomination { * Coins of this denomination. */ coins: BackupCoin[]; + + /** + * The list issue date of the exchange "/keys" response + * that this denomination was last seen in. + */ + list_issue_date: Timestamp; } /** diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts index 673bfab2a..796b6ae14 100644 --- a/packages/taler-wallet-cli/src/index.ts +++ b/packages/taler-wallet-cli/src/index.ts @@ -901,12 +901,12 @@ deploymentCli .action(async (args) => { let out = ""; - const stamp = Math.floor((new Date()).getTime() / 1000); + const stamp = Math.floor(new Date().getTime() / 1000); const min = Amounts.parseOrThrow(args.coincfg.minAmount); const max = Amounts.parseOrThrow(args.coincfg.maxAmount); if (min.currency != max.currency) { - console.error("currency mismatch") + console.error("currency mismatch"); process.exit(1); } const currency = min.currency; @@ -961,7 +961,14 @@ testCli .subcommand("listIntegrationtests", "list-integrationtests") .action(async (args) => { for (const t of getTestInfo()) { - console.log(t.name); + let s = t.name; + if (t.suites.length > 0) { + s += ` (suites: ${t.suites.join(",")})`; + } + if (t.excludeByDefault) { + s += ` [excluded by default]`; + } + console.log(s); } }); diff --git a/packages/taler-wallet-cli/src/integrationtests/test-pay-paid.ts b/packages/taler-wallet-cli/src/integrationtests/test-pay-paid.ts index bf8ed7a33..64645dce2 100644 --- a/packages/taler-wallet-cli/src/integrationtests/test-pay-paid.ts +++ b/packages/taler-wallet-cli/src/integrationtests/test-pay-paid.ts @@ -145,10 +145,10 @@ export async function runPayPaidTest(t: GlobalTestState) { console.log(publicOrderStatusResp.data); - if (publicOrderStatusResp.status != 202) { + if (publicOrderStatusResp.status != 200) { console.log(publicOrderStatusResp.data); throw Error( - `expected status 202 (after paying), but got ${publicOrderStatusResp.status}`, + `expected status 200 (after paying), but got ${publicOrderStatusResp.status}`, ); } diff --git a/packages/taler-wallet-cli/src/integrationtests/test-payment-on-demo.ts b/packages/taler-wallet-cli/src/integrationtests/test-payment-on-demo.ts index d490a8c1b..0dabc9ca5 100644 --- a/packages/taler-wallet-cli/src/integrationtests/test-payment-on-demo.ts +++ b/packages/taler-wallet-cli/src/integrationtests/test-payment-on-demo.ts @@ -24,8 +24,6 @@ import { BankAccessApi } from "./harness"; import { - createSimpleTestkudosEnvironment, - withdrawViaBank, makeTestPayment, } from "./helpers"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; @@ -96,4 +94,6 @@ export async function runPaymentDemoTest(t: GlobalTestState) { t.assertTrue(balanceAfter["balances"].length == 1); t.assertTrue(balanceBefore["balances"][0]["available"] > balanceAfter["balances"][0]["available"]); } + +runPaymentDemoTest.excludeByDefault = true; runPaymentDemoTest.suites = ["buildbot"]; diff --git a/packages/taler-wallet-cli/src/integrationtests/test-payment-transient.ts b/packages/taler-wallet-cli/src/integrationtests/test-payment-transient.ts index 2c417e715..b171ff66a 100644 --- a/packages/taler-wallet-cli/src/integrationtests/test-payment-transient.ts +++ b/packages/taler-wallet-cli/src/integrationtests/test-payment-transient.ts @@ -169,16 +169,17 @@ export async function runPaymentTransientTest(t: GlobalTestState) { // Now ask the merchant if paid + console.log("requesting", publicOrderStatusUrl); publicOrderStatusResp = await axios.get(publicOrderStatusUrl, { validateStatus: () => true, }); console.log(publicOrderStatusResp.data); - if (publicOrderStatusResp.status != 202) { + if (publicOrderStatusResp.status != 200) { console.log(publicOrderStatusResp.data); throw Error( - `expected status 202 (after paying), but got ${publicOrderStatusResp.status}`, + `expected status 200 (after paying), but got ${publicOrderStatusResp.status}`, ); } } diff --git a/packages/taler-wallet-cli/src/integrationtests/testrunner.ts b/packages/taler-wallet-cli/src/integrationtests/testrunner.ts index cb1d621b6..1c090881e 100644 --- a/packages/taler-wallet-cli/src/integrationtests/testrunner.ts +++ b/packages/taler-wallet-cli/src/integrationtests/testrunner.ts @@ -90,6 +90,7 @@ import { runMerchantSpecPublicOrdersTest } from "./test-merchant-spec-public-ord interface TestMainFunction { (t: GlobalTestState): Promise<void>; timeoutMs?: number; + excludeByDefault?: boolean; suites?: string[]; } @@ -157,6 +158,8 @@ export interface TestRunSpec { export interface TestInfo { name: string; + suites: string[]; + excludeByDefault: boolean; } function updateCurrentSymlink(testDir: string): void { @@ -236,6 +239,10 @@ export async function runTests(spec: TestRunSpec) { if (intersection.size === 0) { continue; } + } else { + if (testCase.excludeByDefault) { + continue; + } } if (spec.dryRun) { @@ -389,6 +396,8 @@ export function reportAndQuit( export function getTestInfo(): TestInfo[] { return allTests.map((x) => ({ name: getTestName(x), + suites: x.suites ?? [], + excludeByDefault: x.excludeByDefault ?? false, })); } diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index 437d2e7bd..65a874ea0 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -18,17 +18,10 @@ * Imports. */ import { - openDatabase, describeStore, describeContents, describeIndex, - DbAccess, - StoreDescriptor, - StoreWithIndexes, - IndexDescriptor, } from "./util/query.js"; -import { IDBFactory, IDBDatabase, IDBTransaction } from "@gnu-taler/idb-bridge"; -import { Logger } from "@gnu-taler/taler-util"; import { AmountJson, AmountString, @@ -53,11 +46,17 @@ import { PayCoinSelection } from "./util/coinSelection.js"; * for all previous versions must be written, which should be * avoided. */ -const TALER_DB_NAME = "taler-wallet-main-v2"; +export const TALER_DB_NAME = "taler-wallet-main-v2"; -const TALER_META_DB_NAME = "taler-wallet-meta"; +/** + * Name of the metadata database. This database is used + * to track major migrations of the main Taler database. + * + * (Minor migrations are handled via upgrade transactions.) + */ +export const TALER_META_DB_NAME = "taler-wallet-meta"; -const CURRENT_DB_CONFIG_KEY = "currentMainDbName"; +export const CURRENT_DB_CONFIG_KEY = "currentMainDbName"; /** * Current database minor version, should be incremented @@ -68,124 +67,6 @@ const CURRENT_DB_CONFIG_KEY = "currentMainDbName"; */ export const WALLET_DB_MINOR_VERSION = 1; -const logger = new Logger("db.ts"); - -function upgradeFromStoreMap( - storeMap: any, - db: IDBDatabase, - oldVersion: number, - newVersion: number, - upgradeTransaction: IDBTransaction, -): void { - if (oldVersion === 0) { - for (const n in storeMap) { - const swi: StoreWithIndexes<StoreDescriptor<unknown>, any> = storeMap[n]; - const storeDesc: StoreDescriptor<unknown> = swi.store; - const s = db.createObjectStore(storeDesc.name, { - autoIncrement: storeDesc.autoIncrement, - keyPath: storeDesc.keyPath, - }); - for (const indexName in swi.indexMap as any) { - const indexDesc: IndexDescriptor = swi.indexMap[indexName]; - s.createIndex(indexDesc.name, indexDesc.keyPath, { - multiEntry: indexDesc.multiEntry, - }); - } - } - return; - } - if (oldVersion === newVersion) { - return; - } - logger.info(`upgrading database from ${oldVersion} to ${newVersion}`); - throw Error("upgrade not supported"); -} - -function onTalerDbUpgradeNeeded( - db: IDBDatabase, - oldVersion: number, - newVersion: number, - upgradeTransaction: IDBTransaction, -) { - upgradeFromStoreMap( - WalletStoresV1, - db, - oldVersion, - newVersion, - upgradeTransaction, - ); -} - -function onMetaDbUpgradeNeeded( - db: IDBDatabase, - oldVersion: number, - newVersion: number, - upgradeTransaction: IDBTransaction, -) { - upgradeFromStoreMap( - walletMetadataStore, - db, - oldVersion, - newVersion, - upgradeTransaction, - ); -} - -/** - * Return a promise that resolves - * to the taler wallet db. - */ -export async function openTalerDatabase( - idbFactory: IDBFactory, - onVersionChange: () => void, -): Promise<DbAccess<typeof WalletStoresV1>> { - const metaDbHandle = await openDatabase( - idbFactory, - TALER_META_DB_NAME, - 1, - () => {}, - onMetaDbUpgradeNeeded, - ); - - const metaDb = new DbAccess(metaDbHandle, walletMetadataStore); - let currentMainVersion: string | undefined; - await metaDb - .mktx((x) => ({ - metaConfig: x.metaConfig, - })) - .runReadWrite(async (tx) => { - const dbVersionRecord = await tx.metaConfig.get(CURRENT_DB_CONFIG_KEY); - if (!dbVersionRecord) { - currentMainVersion = TALER_DB_NAME; - await tx.metaConfig.put({ - key: CURRENT_DB_CONFIG_KEY, - value: TALER_DB_NAME, - }); - } else { - currentMainVersion = dbVersionRecord.value; - } - }); - - if (currentMainVersion !== TALER_DB_NAME) { - // In the future, the migration logic will be implemented here. - throw Error(`migration from database ${currentMainVersion} not supported`); - } - - const mainDbHandle = await openDatabase( - idbFactory, - TALER_DB_NAME, - WALLET_DB_MINOR_VERSION, - onVersionChange, - onTalerDbUpgradeNeeded, - ); - - return new DbAccess(mainDbHandle, WalletStoresV1); -} - -export function deleteTalerDatabase(idbFactory: IDBFactory): void { - idbFactory.deleteDatabase(TALER_DB_NAME); -} - export enum ReserveRecordStatus { /** * Reserve must be registered with the bank. @@ -217,6 +98,10 @@ export enum ReserveRecordStatus { BANK_ABORTED = "bank-aborted", } +/** + * Extra info about a reserve that is used + * with a bank-integrated withdrawal. + */ export interface ReserveBankInfo { /** * Status URL that the wallet will use to query the status @@ -224,6 +109,10 @@ export interface ReserveBankInfo { */ statusUrl: string; + /** + * URL that the user can be redirected to, and allows + * them to confirm (or abort) the bank-integrated withdrawal. + */ confirmUrl?: string; /** @@ -339,25 +228,9 @@ export interface ReserveRecord { } /** - * Auditor record as stored with currencies in the exchange database. + * Record that indicates the wallet trusts + * a particular auditor. */ -export interface AuditorRecord { - /** - * Base url of the auditor. - */ - baseUrl: string; - - /** - * Public signing key of the auditor. - */ - auditorPub: string; - - /** - * Time when the auditing expires. - */ - expirationStamp: number; -} - export interface AuditorTrustRecord { /** * Currency that we trust this auditor for. @@ -381,6 +254,9 @@ export interface AuditorTrustRecord { uids: string[]; } +/** + * Record to indicate trust for a particular exchange. + */ export interface ExchangeTrustRecord { /** * Currency that we trust this exchange for. @@ -519,8 +395,17 @@ export interface DenominationRecord { * on the denomination. */ exchangeMasterPub: string; + + /** + * Latest list issue date of the "/keys" response + * that includes this denomination. + */ + listIssueDate: Timestamp; } +/** + * Information about one of the exchange's bank accounts. + */ export interface ExchangeBankAccount { payto_uri: string; master_sig: string; @@ -554,6 +439,8 @@ export interface ExchangeDetailsRecord { /** * Signing keys we got from the exchange, can also contain * older signing keys that are not returned by /keys anymore. + * + * FIXME: Should this be put into a separate object store? */ signingKeys: ExchangeSignKeyJson[]; @@ -610,6 +497,9 @@ export interface ExchangeRecord { */ baseUrl: string; + /** + * Pointer to the current exchange details. + */ detailsPointer: ExchangeDetailsPointer | undefined; /** @@ -701,7 +591,9 @@ export interface PlanchetRecord { } /** - * Planchet for a coin during refrehs. + * Planchet for a coin during refresh. + * + * FIXME: Not used in DB? */ export interface RefreshPlanchet { /** @@ -1040,6 +932,8 @@ export interface RefreshGroupRecord { oldCoinPubs: string[]; + // FIXME: Should this go into a separate + // object store for faster updates? refreshSessionPerCoin: (RefreshSessionRecord | undefined)[]; inputPerCoin: AmountJson[]; @@ -1126,21 +1020,6 @@ export interface WireFee { sig: string; } -/** - * Record to store information about a refund event. - * - * All information about a refund is stored with the purchase, - * this event is just for the history. - * - * The event is only present for completed refunds. - */ -export interface RefundEventRecord { - timestamp: Timestamp; - merchantExecutionTimestamp: Timestamp; - refundGroupId: string; - proposalId: string; -} - export enum RefundState { Failed = "failed", Applied = "applied", @@ -1381,7 +1260,6 @@ export const WALLET_BACKUP_STATE_KEY = "walletBackupState"; /** * Configuration key/value entries to configure * the wallet. - * */ export type ConfigRecord = | { diff --git a/packages/taler-wallet-core/src/headless/helpers.ts b/packages/taler-wallet-core/src/headless/helpers.ts index f29dfd69c..a862dab4a 100644 --- a/packages/taler-wallet-core/src/headless/helpers.ts +++ b/packages/taler-wallet-core/src/headless/helpers.ts @@ -27,7 +27,7 @@ import { BridgeIDBFactory, shimIndexedDB, } from "@gnu-taler/idb-bridge"; -import { openTalerDatabase } from "../db.js"; +import { openTalerDatabase } from "../db-utils.js"; import { HttpRequestLibrary } from "../util/http.js"; import { NodeThreadCryptoWorkerFactory } from "../crypto/workers/nodeThreadWorker.js"; import { NodeHttpLib } from "./NodeHttpLib.js"; @@ -35,7 +35,6 @@ import { Logger } from "@gnu-taler/taler-util"; import { SynchronousCryptoWorkerFactory } from "../crypto/workers/synchronousWorker.js"; import type { IDBFactory } from "@gnu-taler/idb-bridge"; import { WalletNotification } from "@gnu-taler/taler-util"; -import { InternalWalletState } from "../common.js"; import { Wallet } from "../wallet.js"; const logger = new Logger("headless/helpers.ts"); diff --git a/packages/taler-wallet-core/src/index.ts b/packages/taler-wallet-core/src/index.ts index a14894741..ccd3488d9 100644 --- a/packages/taler-wallet-core/src/index.ts +++ b/packages/taler-wallet-core/src/index.ts @@ -29,6 +29,7 @@ export * from "./util/http.js"; export * from "./versions.js"; export * from "./db.js"; +export * from "./db-utils.js"; // Crypto and crypto workers // export * from "./crypto/workers/nodeThreadWorker.js"; @@ -44,4 +45,4 @@ export { InternalWalletState } from "./common.js"; export * from "./wallet-api-types.js"; export * from "./wallet.js"; -export * from "./operations/backup/index.js"
\ No newline at end of file +export * from "./operations/backup/index.js"; diff --git a/packages/taler-wallet-core/src/operations/backup/export.ts b/packages/taler-wallet-core/src/operations/backup/export.ts index eae7995ca..4d9ca6697 100644 --- a/packages/taler-wallet-core/src/operations/backup/export.ts +++ b/packages/taler-wallet-core/src/operations/backup/export.ts @@ -260,6 +260,7 @@ export async function exportBackup( stamp_expire_withdraw: denom.stampExpireWithdraw, stamp_start: denom.stampStart, value: Amounts.stringify(denom.value), + list_issue_date: denom.listIssueDate, }); }); diff --git a/packages/taler-wallet-core/src/operations/backup/import.ts b/packages/taler-wallet-core/src/operations/backup/import.ts index e2064a80f..8ba4e4db3 100644 --- a/packages/taler-wallet-core/src/operations/backup/import.ts +++ b/packages/taler-wallet-core/src/operations/backup/import.ts @@ -360,6 +360,7 @@ export async function importBackup( stampStart: backupDenomination.stamp_start, status: DenominationStatus.VerifiedGood, value: Amounts.parseOrThrow(backupDenomination.value), + listIssueDate: backupDenomination.list_issue_date, }); } for (const backupCoin of backupDenomination.coins) { diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts index 64821a7b1..0670c8a61 100644 --- a/packages/taler-wallet-core/src/operations/exchanges.ts +++ b/packages/taler-wallet-core/src/operations/exchanges.ts @@ -31,7 +31,6 @@ import { ExchangeWireJson, getTimestampNow, isTimestampExpired, - j2s, Logger, NotificationType, parsePaytoUri, @@ -76,6 +75,7 @@ const logger = new Logger("exchanges.ts"); function denominationRecordFromKeys( exchangeBaseUrl: string, exchangeMasterPub: string, + listIssueDate: Timestamp, denomIn: Denomination, ): DenominationRecord { const denomPubHash = encodeCrock(hash(decodeCrock(denomIn.denom_pub))); @@ -97,6 +97,7 @@ function denominationRecordFromKeys( stampStart: denomIn.stamp_start, status: DenominationStatus.Unverified, value: Amounts.parseOrThrow(denomIn.value), + listIssueDate, }; return d; } @@ -380,6 +381,7 @@ async function downloadKeysInfo( denominationRecordFromKeys( baseUrl, exchangeKeysJson.master_public_key, + exchangeKeysJson.list_issue_date, d, ), ), diff --git a/packages/taler-wallet-core/src/operations/withdraw.test.ts b/packages/taler-wallet-core/src/operations/withdraw.test.ts index c6de0a321..061a42227 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.test.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.test.ts @@ -76,6 +76,7 @@ test("withdrawal selection bug repro", (t) => { fraction: 0, value: 1000, }, + listIssueDate: { t_ms: 0 }, }, { denomPub: @@ -126,6 +127,7 @@ test("withdrawal selection bug repro", (t) => { fraction: 0, value: 10, }, + listIssueDate: { t_ms: 0 }, }, { denomPub: @@ -176,6 +178,7 @@ test("withdrawal selection bug repro", (t) => { fraction: 0, value: 5, }, + listIssueDate: { t_ms: 0 }, }, { denomPub: @@ -226,6 +229,7 @@ test("withdrawal selection bug repro", (t) => { fraction: 0, value: 1, }, + listIssueDate: { t_ms: 0 }, }, { denomPub: @@ -276,6 +280,7 @@ test("withdrawal selection bug repro", (t) => { fraction: 10000000, value: 0, }, + listIssueDate: { t_ms: 0 }, }, { denomPub: @@ -326,6 +331,7 @@ test("withdrawal selection bug repro", (t) => { fraction: 0, value: 2, }, + listIssueDate: { t_ms: 0 }, }, ]; diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts index c474c940c..c41dd4fba 100644 --- a/packages/taler-wallet-webextension/src/wxBackend.ts +++ b/packages/taler-wallet-webextension/src/wxBackend.ts @@ -34,7 +34,6 @@ import { DbAccess, WalletStoresV1, Wallet, - WalletApiOperation, } from "@gnu-taler/taler-wallet-core"; import { classifyTalerUri, |