aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2021-05-20 13:14:47 +0200
committerFlorian Dold <florian@dold.me>2021-05-20 13:15:11 +0200
commit851ac5602cea0beb7b3e29dc9a95c2093a0ed906 (patch)
tree294e00a40e752c52706b65c86807028ffc450938 /packages
parent0299e719ce4c97748090fa238cb5f68303fb4abf (diff)
add UIDs for deletion tombstones to auditor/exchange trust management
Diffstat (limited to 'packages')
-rw-r--r--packages/taler-util/src/walletTypes.ts13
-rw-r--r--packages/taler-wallet-core/src/db.ts80
-rw-r--r--packages/taler-wallet-core/src/operations/currencies.ts68
-rw-r--r--packages/taler-wallet-core/src/operations/exchanges.ts37
-rw-r--r--packages/taler-wallet-core/src/operations/reserves.ts34
-rw-r--r--packages/taler-wallet-core/src/operations/transactions.ts1
-rw-r--r--packages/taler-wallet-core/src/operations/withdraw.ts14
-rw-r--r--packages/taler-wallet-core/src/wallet.ts54
8 files changed, 174 insertions, 127 deletions
diff --git a/packages/taler-util/src/walletTypes.ts b/packages/taler-util/src/walletTypes.ts
index d1453658b..657e6568c 100644
--- a/packages/taler-util/src/walletTypes.ts
+++ b/packages/taler-util/src/walletTypes.ts
@@ -933,3 +933,16 @@ export const codecForWithdrawUriInfoResponse = (): Codec<WithdrawUriInfoResponse
.property("defaultExchangeBaseUrl", codecOptional(codecForString()))
.property("possibleExchanges", codecForList(codecForExchangeListItem()))
.build("WithdrawUriInfoResponse");
+
+export interface WalletCurrencyInfo {
+ trustedAuditors: {
+ currency: string;
+ auditorPub: string;
+ auditorBaseUrl: string;
+ }[];
+ trustedExchanges: {
+ currency: string;
+ exchangeMasterPub: string;
+ exchangeBaseUrl: string;
+ }[];
+} \ No newline at end of file
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts
index b0da0733b..52fe5c3dc 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -357,7 +357,12 @@ export interface AuditorRecord {
expirationStamp: number;
}
-export interface AuditorTrustInfo {
+export interface AuditorTrustRecord {
+ /**
+ * Currency that we trust this auditor for.
+ */
+ currency: string;
+
/**
* Base URL of the auditor.
*/
@@ -375,7 +380,12 @@ export interface AuditorTrustInfo {
uids: string[];
}
-export interface ExchangeTrustInfo {
+export interface ExchangeTrustRecord {
+ /**
+ * Currency that we trust this exchange for.
+ */
+ currency: string;
+
/**
* Canonicalized exchange base URL.
*/
@@ -394,31 +404,6 @@ export interface ExchangeTrustInfo {
}
/**
- * Information about a currency as displayed in the wallet's database.
- */
-export interface CurrencyRecord {
- /**
- * Name of the currency.
- */
- name: string;
-
- /**
- * Number of fractional digits to show when rendering the currency.
- */
- fractionalDigits: number;
-
- /**
- * Auditors that the wallet trusts for this currency.
- */
- auditors: AuditorTrustInfo[];
-
- /**
- * Exchanges that the wallet trusts for this currency.
- */
- exchanges: ExchangeTrustInfo[];
-}
-
-/**
* Status of a denomination.
*/
export enum DenominationStatus {
@@ -1775,10 +1760,44 @@ class DenominationsStore extends Store<"denominations", DenominationRecord> {
>(this, "exchangeBaseUrlIndex", "exchangeBaseUrl");
}
-class CurrenciesStore extends Store<"currencies", CurrencyRecord> {
+class AuditorTrustStore extends Store<"auditorTrust", AuditorTrustRecord> {
constructor() {
- super("currencies", { keyPath: "name" });
+ super("auditorTrust", {
+ keyPath: ["currency", "auditorBaseUrl", "auditorPub"],
+ });
}
+ auditorPubIndex = new Index<
+ "auditorTrust",
+ "auditorPubIndex",
+ string,
+ AuditorTrustRecord
+ >(this, "auditorPubIndex", "auditorPub");
+ uidIndex = new Index<"auditorTrust", "uidIndex", string, AuditorTrustRecord>(
+ this,
+ "uidIndex",
+ "uids",
+ { multiEntry: true },
+ );
+}
+
+class ExchangeTrustStore extends Store<"exchangeTrust", ExchangeTrustRecord> {
+ constructor() {
+ super("exchangeTrust", {
+ keyPath: ["currency", "exchangeBaseUrl", "exchangePub"],
+ });
+ }
+ exchangeMasterPubIndex = new Index<
+ "exchangeTrust",
+ "exchangeMasterPubIndex",
+ string,
+ ExchangeTrustRecord
+ >(this, "exchangeMasterPubIndex", "exchangePub");
+ uidIndex = new Index<
+ "exchangeTrust",
+ "uidIndex",
+ string,
+ ExchangeTrustRecord
+ >(this, "uidIndex", "uids", { multiEntry: true });
}
class ConfigStore extends Store<"config", ConfigRecord<any>> {
@@ -1891,7 +1910,8 @@ class TombstonesStore extends Store<"tombstones", TombstoneRecord> {
export const Stores = {
coins: new CoinsStore(),
config: new ConfigStore(),
- currencies: new CurrenciesStore(),
+ auditorTrustStore: new AuditorTrustStore(),
+ exchangeTrustStore: new ExchangeTrustStore(),
denominations: new DenominationsStore(),
exchanges: new ExchangesStore(),
proposals: new ProposalsStore(),
diff --git a/packages/taler-wallet-core/src/operations/currencies.ts b/packages/taler-wallet-core/src/operations/currencies.ts
new file mode 100644
index 000000000..1af30dfb5
--- /dev/null
+++ b/packages/taler-wallet-core/src/operations/currencies.ts
@@ -0,0 +1,68 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * Imports.
+ */
+import { ExchangeRecord, Stores } from "../db.js";
+import { Logger } from "../index.js";
+import { InternalWalletState } from "./state.js";
+
+const logger = new Logger("currencies.ts");
+
+export interface TrustInfo {
+ isTrusted: boolean;
+ isAudited: boolean;
+}
+
+/**
+ * Check if and how an exchange is trusted and/or audited.
+ */
+export async function getExchangeTrust(
+ ws: InternalWalletState,
+ exchangeInfo: ExchangeRecord,
+): Promise<TrustInfo> {
+ let isTrusted = false;
+ let isAudited = false;
+ const exchangeDetails = exchangeInfo.details;
+ if (!exchangeDetails) {
+ throw Error(`exchange ${exchangeInfo.baseUrl} details not available`);
+ }
+ const exchangeTrustRecord = await ws.db.getIndexed(
+ Stores.exchangeTrustStore.exchangeMasterPubIndex,
+ exchangeDetails.masterPublicKey,
+ );
+ if (
+ exchangeTrustRecord &&
+ exchangeTrustRecord.uids.length > 0 &&
+ exchangeTrustRecord.currency === exchangeDetails.currency
+ ) {
+ isTrusted = true;
+ }
+
+ for (const auditor of exchangeDetails.auditors) {
+ const auditorTrustRecord = await ws.db.getIndexed(
+ Stores.auditorTrustStore.auditorPubIndex,
+ auditor.auditor_pub,
+ );
+ if (auditorTrustRecord && auditorTrustRecord.uids.length > 0) {
+ isAudited = true;
+ break;
+ }
+ }
+
+ return { isTrusted, isAudited };
+}
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts
index f48b08ff7..e8833699d 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -527,43 +527,6 @@ async function updateExchangeFromUrlImpl(
return updatedExchange;
}
-/**
- * Check if and how an exchange is trusted and/or audited.
- */
-export async function getExchangeTrust(
- ws: InternalWalletState,
- exchangeInfo: ExchangeRecord,
-): Promise<{ isTrusted: boolean; isAudited: boolean }> {
- let isTrusted = false;
- let isAudited = false;
- const exchangeDetails = exchangeInfo.details;
- if (!exchangeDetails) {
- throw Error(`exchange ${exchangeInfo.baseUrl} details not available`);
- }
- const currencyRecord = await ws.db.get(
- Stores.currencies,
- exchangeDetails.currency,
- );
- if (currencyRecord) {
- for (const trustedExchange of currencyRecord.exchanges) {
- if (
- trustedExchange.exchangeMasterPub === exchangeDetails.masterPublicKey
- ) {
- isTrusted = true;
- break;
- }
- }
- for (const trustedAuditor of currencyRecord.auditors) {
- for (const exchangeAuditor of exchangeDetails.auditors) {
- if (trustedAuditor.auditorPub === exchangeAuditor.auditor_pub) {
- isAudited = true;
- break;
- }
- }
- }
- }
- return { isTrusted, isAudited };
-}
export async function getExchangePaytoUri(
ws: InternalWalletState,
diff --git a/packages/taler-wallet-core/src/operations/reserves.ts b/packages/taler-wallet-core/src/operations/reserves.ts
index 9a479427e..9addca975 100644
--- a/packages/taler-wallet-core/src/operations/reserves.ts
+++ b/packages/taler-wallet-core/src/operations/reserves.ts
@@ -38,7 +38,6 @@ import {
ReserveRecordStatus,
ReserveBankInfo,
ReserveRecord,
- CurrencyRecord,
WithdrawalGroupRecord,
} from "../db.js";
import {
@@ -158,31 +157,9 @@ export async function createReserve(
throw Error("exchange not updated");
}
const { isAudited, isTrusted } = await getExchangeTrust(ws, exchangeInfo);
- let currencyRecord = await ws.db.get(
- Stores.currencies,
- exchangeDetails.currency,
- );
- if (!currencyRecord) {
- currencyRecord = {
- auditors: [],
- exchanges: [],
- fractionalDigits: 2,
- name: exchangeDetails.currency,
- };
- }
-
- if (!isAudited && !isTrusted) {
- currencyRecord.exchanges.push({
- exchangeBaseUrl: req.exchange,
- exchangeMasterPub: exchangeDetails.masterPublicKey,
- uids: [encodeCrock(getRandomBytes(32))],
- });
- }
-
- const cr: CurrencyRecord = currencyRecord;
const resp = await ws.db.runWithWriteTransaction(
- [Stores.currencies, Stores.reserves, Stores.bankWithdrawUris],
+ [Stores.exchangeTrustStore, Stores.reserves, Stores.bankWithdrawUris],
async (tx) => {
// Check if we have already created a reserve for that bankWithdrawStatusUrl
if (reserveRecord.bankInfo?.statusUrl) {
@@ -207,7 +184,14 @@ export async function createReserve(
talerWithdrawUri: reserveRecord.bankInfo.statusUrl,
});
}
- await tx.put(Stores.currencies, cr);
+ if (!isAudited && !isAudited) {
+ await tx.put(Stores.exchangeTrustStore, {
+ currency: reserveRecord.currency,
+ exchangeBaseUrl: reserveRecord.exchangeBaseUrl,
+ exchangeMasterPub: exchangeDetails.masterPublicKey,
+ uids: [encodeCrock(getRandomBytes(32))],
+ });
+ }
await tx.put(Stores.reserves, reserveRecord);
const r: CreateReserveResponse = {
exchange: canonExchange,
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts
index 8ee02c059..dcd3ddbd9 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -82,7 +82,6 @@ export async function getTransactions(
await ws.db.runWithReadTransaction(
[
- Stores.currencies,
Stores.coins,
Stores.denominations,
Stores.exchanges,
diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts
index 237ef9fc6..0ff69cb5a 100644
--- a/packages/taler-wallet-core/src/operations/withdraw.ts
+++ b/packages/taler-wallet-core/src/operations/withdraw.ts
@@ -51,7 +51,7 @@ import {
} from "@gnu-taler/taler-util";
import { InternalWalletState } from "./state";
import { Logger } from "../util/logging";
-import { updateExchangeFromUrl, getExchangeTrust } from "./exchanges";
+import { updateExchangeFromUrl } from "./exchanges";
import {
WALLET_EXCHANGE_PROTOCOL_VERSION,
WALLET_BANK_INTEGRATION_PROTOCOL_VERSION,
@@ -76,6 +76,7 @@ import { TalerErrorCode } from "@gnu-taler/taler-util";
import { updateRetryInfoTimeout, initRetryInfo } from "../util/retries";
import { compare } from "@gnu-taler/taler-util";
import { walletCoreDebugFlags } from "../util/debugFlags.js";
+import { getExchangeTrust } from "./currencies.js";
/**
* Logger for this file.
@@ -882,14 +883,6 @@ export async function getExchangeWithdrawalInfo(
.iterIndex(Stores.denominations.exchangeBaseUrlIndex, baseUrl)
.filter((d) => d.isOffered);
- const trustedAuditorPubs = [];
- const currencyRecord = await ws.db.get(Stores.currencies, amount.currency);
- if (currencyRecord) {
- trustedAuditorPubs.push(
- ...currencyRecord.auditors.map((a) => a.auditorPub),
- );
- }
-
let versionMatch;
if (exchangeDetails.protocolVersion) {
versionMatch = LibtoolVersion.compare(
@@ -935,7 +928,8 @@ export async function getExchangeWithdrawalInfo(
numOfferedDenoms: possibleDenoms.length,
overhead: Amounts.sub(amount, selectedDenoms.totalWithdrawCost).amount,
selectedDenoms,
- trustedAuditorPubs,
+ // FIXME: delete this field / replace by something we can display to the user
+ trustedAuditorPubs: [],
versionMatch,
walletVersion: WALLET_EXCHANGE_PROTOCOL_VERSION,
wireFees: exchangeWireInfo,
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index f69d26e84..192b54926 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -26,6 +26,7 @@ import {
BackupRecovery,
codecForAny,
TalerErrorCode,
+ WalletCurrencyInfo,
} from "@gnu-taler/taler-util";
import { CryptoWorkerFactory } from "./crypto/workers/cryptoApi";
import {
@@ -56,7 +57,6 @@ import {
import {
acceptExchangeTermsOfService,
getExchangePaytoUri,
- getExchangeTrust,
updateExchangeFromUrl,
} from "./operations/exchanges";
import {
@@ -99,9 +99,9 @@ import {
processWithdrawGroup,
} from "./operations/withdraw";
import {
+ AuditorTrustRecord,
CoinRecord,
CoinSourceType,
- CurrencyRecord,
DenominationRecord,
ExchangeRecord,
PurchaseRecord,
@@ -179,19 +179,14 @@ import { AsyncCondition } from "./util/promiseUtils";
import { Database } from "./util/query";
import { Duration, durationMin } from "@gnu-taler/taler-util";
import { TimerGroup } from "./util/timer";
+import { getExchangeTrust } from "./operations/currencies.js";
-const builtinCurrencies: CurrencyRecord[] = [
+const builtinAuditors: AuditorTrustRecord[] = [
{
- auditors: [
- {
- auditorPub: "BW9DC48PHQY4NH011SHHX36DZZ3Q22Y6X7FZ1VD1CMZ2PTFZ6PN0",
- auditorBaseUrl: "https://auditor.demo.taler.net/",
- uids: ["5P25XF8TVQP9AW6VYGY2KV47WT5Y3ZXFSJAA570GJPX5SVJXKBVG"],
- },
- ],
- exchanges: [],
- fractionalDigits: 2,
- name: "KUDOS",
+ currency: "KUDOS",
+ auditorPub: "BW9DC48PHQY4NH011SHHX36DZZ3Q22Y6X7FZ1VD1CMZ2PTFZ6PN0",
+ auditorBaseUrl: "https://auditor.demo.taler.net/",
+ uids: ["5P25XF8TVQP9AW6VYGY2KV47WT5Y3ZXFSJAA570GJPX5SVJXKBVG"],
},
];
@@ -484,7 +479,7 @@ export class Wallet {
*/
async fillDefaults(): Promise<void> {
await this.db.runWithWriteTransaction(
- [Stores.config, Stores.currencies],
+ [Stores.config, Stores.auditorTrustStore],
async (tx) => {
let applied = false;
await tx.iter(Stores.config).forEach((x) => {
@@ -493,8 +488,8 @@ export class Wallet {
}
});
if (!applied) {
- for (const c of builtinCurrencies) {
- await tx.put(Stores.currencies, c);
+ for (const c of builtinAuditors) {
+ await tx.put(Stores.auditorTrustStore, c);
}
}
},
@@ -676,7 +671,6 @@ export class Wallet {
return await this.db.iter(Stores.exchanges).toArray();
}
-
async getExchanges(): Promise<ExchangesListRespose> {
const exchanges: (ExchangeListItem | undefined)[] = await this.db
.iter(Stores.exchanges)
@@ -702,13 +696,25 @@ export class Wallet {
};
}
- async getCurrencies(): Promise<CurrencyRecord[]> {
- return await this.db.iter(Stores.currencies).toArray();
- }
-
- async updateCurrency(currencyRecord: CurrencyRecord): Promise<void> {
- logger.trace("updating currency to", currencyRecord);
- await this.db.put(Stores.currencies, currencyRecord);
+ async getCurrencies(): Promise<WalletCurrencyInfo> {
+ const trustedAuditors = await this.db
+ .iter(Stores.auditorTrustStore)
+ .toArray();
+ const trustedExchanges = await this.db
+ .iter(Stores.exchangeTrustStore)
+ .toArray();
+ return {
+ trustedAuditors: trustedAuditors.map((x) => ({
+ currency: x.currency,
+ auditorBaseUrl: x.auditorBaseUrl,
+ auditorPub: x.auditorPub,
+ })),
+ trustedExchanges: trustedExchanges.map((x) => ({
+ currency: x.currency,
+ exchangeBaseUrl: x.exchangeBaseUrl,
+ exchangeMasterPub: x.exchangeMasterPub,
+ })),
+ };
}
async getReserves(exchangeBaseUrl?: string): Promise<ReserveRecord[]> {