aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/wallet.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-core/src/wallet.ts')
-rw-r--r--packages/taler-wallet-core/src/wallet.ts233
1 files changed, 98 insertions, 135 deletions
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index 626409dd6..1a60b148c 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -34,7 +34,6 @@ import {
Duration,
ExchangeDetailedResponse,
ExchangeListItem,
- ExchangeTosStatusDetails,
ExchangesListResponse,
FeeDescription,
GetExchangeTosResult,
@@ -121,11 +120,16 @@ import {
GetCurrencyInfoResponse,
codecForGetCurrencyInfoRequest,
CreateStoredBackupResponse,
+ StoredBackupList,
+ codecForDeleteStoredBackupRequest,
+ DeleteStoredBackupRequest,
+ RecoverStoredBackupRequest,
+ codecForRecoverStoredBackupRequest,
+ codecForTestingSetTimetravelRequest,
+ setDangerousTimetravel,
} from "@gnu-taler/taler-util";
-import {
- HttpRequestLibrary,
- readSuccessResponseJsonOrThrow,
-} from "@gnu-taler/taler-util/http";
+import type { HttpRequestLibrary } from "@gnu-taler/taler-util/http";
+import { readSuccessResponseJsonOrThrow } from "@gnu-taler/taler-util/http";
import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
import {
CryptoDispatcher,
@@ -194,11 +198,9 @@ import {
downloadTosFromAcceptedFormat,
getExchangeDetails,
getExchangeRequestTimeout,
- getExchangeTrust,
provideExchangeRecordInTx,
updateExchangeFromUrl,
updateExchangeFromUrlHandler,
- updateExchangeTermsOfService,
} from "./operations/exchanges.js";
import { getMerchantInfo } from "./operations/merchants.js";
import {
@@ -352,9 +354,9 @@ async function callOperationHandler(
case PendingTaskType.PeerPullCredit:
return await processPeerPullCredit(ws, pending.pursePub);
case PendingTaskType.PeerPullDebit:
- return await processPeerPullDebit(ws, pending.peerPullPaymentIncomingId);
+ return await processPeerPullDebit(ws, pending.peerPullDebitId);
case PendingTaskType.PeerPushCredit:
- return await processPeerPushCredit(ws, pending.peerPushPaymentIncomingId);
+ return await processPeerPushCredit(ws, pending.peerPushCreditId);
default:
return assertUnreachable(pending);
}
@@ -522,7 +524,7 @@ async function runTaskLoop(
*/
async function fillDefaults(ws: InternalWalletState): Promise<void> {
await ws.db
- .mktx((x) => [x.config, x.auditorTrust, x.exchanges, x.exchangeDetails])
+ .mktx((x) => [x.config, x.exchanges, x.exchangeDetails])
.runReadWrite(async (tx) => {
const appliedRec = await tx.config.get("currencyDefaultsApplied");
let alreadyApplied = appliedRec ? !!appliedRec.value : false;
@@ -530,10 +532,6 @@ async function fillDefaults(ws: InternalWalletState): Promise<void> {
logger.trace("defaults already applied");
return;
}
- logger.info("importing default exchanges and auditors");
- for (const c of ws.config.builtin.auditors) {
- await tx.auditorTrust.put(c);
- }
for (const baseUrl of ws.config.builtin.exchanges) {
await addPresetExchangeEntry(tx, baseUrl);
const now = AbsoluteTime.now();
@@ -557,33 +555,6 @@ async function getExchangeTos(
): Promise<GetExchangeTosResult> {
// FIXME: download ToS in acceptable format if passed!
const { exchangeDetails } = await updateExchangeFromUrl(ws, exchangeBaseUrl);
- const tosDetails = await ws.db
- .mktx((x) => [x.exchangeTos])
- .runReadOnly(async (tx) => {
- return await getExchangeTosStatusDetails(tx, exchangeDetails);
- });
- const content = tosDetails.content;
- const currentEtag = tosDetails.currentVersion;
- const contentType = tosDetails.contentType;
- if (
- content === undefined ||
- currentEtag === undefined ||
- contentType === undefined
- ) {
- throw Error("exchange is in invalid state");
- }
- if (
- acceptedFormat &&
- acceptedFormat.findIndex((f) => f === contentType) !== -1
- ) {
- return {
- acceptedEtag: exchangeDetails.tosAccepted?.etag,
- currentEtag,
- content,
- contentType,
- tosStatus: getExchangeTosStatus(exchangeDetails),
- };
- }
const tosDownload = await downloadTosFromAcceptedFormat(
ws,
@@ -592,17 +563,15 @@ async function getExchangeTos(
acceptedFormat,
);
- if (tosDownload.tosContentType === contentType) {
- return {
- acceptedEtag: exchangeDetails.tosAccepted?.etag,
- currentEtag,
- content,
- contentType,
- tosStatus: getExchangeTosStatus(exchangeDetails),
- };
- }
-
- await updateExchangeTermsOfService(ws, exchangeBaseUrl, tosDownload);
+ await ws.db
+ .mktx((x) => [x.exchanges, x.exchangeDetails])
+ .runReadWrite(async (tx) => {
+ const d = await getExchangeDetails(tx, exchangeBaseUrl);
+ if (d) {
+ d.tosCurrentEtag = tosDownload.tosEtag;
+ await tx.exchangeDetails.put(d);
+ }
+ });
return {
acceptedEtag: exchangeDetails.tosAccepted?.etag,
@@ -683,32 +652,6 @@ async function forgetKnownBankAccounts(
return;
}
-async function getExchangeTosStatusDetails(
- tx: GetReadOnlyAccess<{ exchangeTos: typeof WalletStoresV1.exchangeTos }>,
- exchangeDetails: ExchangeDetailsRecord,
-): Promise<ExchangeTosStatusDetails> {
- let exchangeTos = await tx.exchangeTos.get([
- exchangeDetails.exchangeBaseUrl,
- exchangeDetails.tosCurrentEtag,
- ]);
-
- if (!exchangeTos) {
- exchangeTos = {
- etag: "not-available",
- termsOfServiceContentType: "text/plain",
- termsOfServiceText: "terms of service unavailable",
- exchangeBaseUrl: exchangeDetails.exchangeBaseUrl,
- };
- }
-
- return {
- acceptedVersion: exchangeDetails.tosAccepted?.etag,
- content: exchangeTos.termsOfServiceText,
- contentType: exchangeTos.termsOfServiceContentType,
- currentVersion: exchangeTos.etag,
- };
-}
-
async function getExchanges(
ws: InternalWalletState,
): Promise<ExchangesListResponse> {
@@ -717,7 +660,6 @@ async function getExchanges(
.mktx((x) => [
x.exchanges,
x.exchangeDetails,
- x.exchangeTos,
x.denominations,
x.operationRetries,
])
@@ -742,12 +684,7 @@ async function getExchangeDetailedInfo(
): Promise<ExchangeDetailedResponse> {
//TODO: should we use the forceUpdate parameter?
const exchange = await ws.db
- .mktx((x) => [
- x.exchanges,
- x.exchangeTos,
- x.exchangeDetails,
- x.denominations,
- ])
+ .mktx((x) => [x.exchanges, x.exchangeDetails, x.denominations])
.runReadOnly(async (tx) => {
const ex = await tx.exchanges.get(exchangeBaseurl);
const dp = ex?.detailsPointer;
@@ -769,8 +706,6 @@ async function getExchangeDetailedInfo(
return;
}
- const tos = await getExchangeTosStatusDetails(tx, exchangeDetails);
-
const denominations: DenominationInfo[] = denominationRecords.map((x) =>
DenominationRecord.toDenomInfo(x),
);
@@ -779,7 +714,6 @@ async function getExchangeDetailedInfo(
info: {
exchangeBaseUrl: ex.baseUrl,
currency,
- tos,
paytoUris: exchangeDetails.wireInfo.accounts.map((x) => x.payto_uri),
auditors: exchangeDetails.auditors,
wireInfo: exchangeDetails.wireInfo,
@@ -981,11 +915,7 @@ async function dumpCoins(ws: InternalWalletState): Promise<CoinDumpJson> {
coin_pub: c.coinPub,
denom_pub: denomInfo.denomPub,
denom_pub_hash: c.denomPubHash,
- denom_value: Amounts.stringify({
- value: denom.amountVal,
- currency: denom.currency,
- fraction: denom.amountFrac,
- }),
+ denom_value: denom.value,
exchange_base_url: c.exchangeBaseUrl,
refresh_parent_coin_pub: refreshParentCoinPub,
withdrawal_reserve_pub: withdrawalReservePub,
@@ -1041,6 +971,57 @@ async function createStoredBackup(
};
}
+async function listStoredBackups(
+ ws: InternalWalletState,
+): Promise<StoredBackupList> {
+ const storedBackups: StoredBackupList = {
+ storedBackups: [],
+ };
+ const backupsDb = await openStoredBackupsDatabase(ws.idb);
+ await backupsDb.mktxAll().runReadWrite(async (tx) => {
+ await tx.backupMeta.iter().forEach((x) => {
+ storedBackups.storedBackups.push({
+ name: x.name,
+ });
+ });
+ });
+ return storedBackups;
+}
+
+async function deleteStoredBackup(
+ ws: InternalWalletState,
+ req: DeleteStoredBackupRequest,
+): Promise<void> {
+ const backupsDb = await openStoredBackupsDatabase(ws.idb);
+ await backupsDb.mktxAll().runReadWrite(async (tx) => {
+ await tx.backupData.delete(req.name);
+ await tx.backupMeta.delete(req.name);
+ });
+}
+
+async function recoverStoredBackup(
+ ws: InternalWalletState,
+ req: RecoverStoredBackupRequest,
+): Promise<void> {
+ logger.info(`Recovering stored backup ${req.name}`);
+ const { name } = req;
+ const backupsDb = await openStoredBackupsDatabase(ws.idb);
+ const bd = await backupsDb.mktxAll().runReadWrite(async (tx) => {
+ const backupMeta = tx.backupMeta.get(name);
+ if (!backupMeta) {
+ throw Error("backup not found");
+ }
+ const backupData = await tx.backupData.get(name);
+ if (!backupData) {
+ throw Error("no backup data (DB corrupt)");
+ }
+ return backupData;
+ });
+ logger.info(`backup found, now importing`);
+ await importDb(ws.db.idbHandle(), bd);
+ logger.info(`import done`);
+}
+
/**
* Implementation of the "wallet-core" API.
*/
@@ -1059,12 +1040,18 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
switch (operation) {
case WalletApiOperation.CreateStoredBackup:
return createStoredBackup(ws);
- case WalletApiOperation.DeleteStoredBackup:
+ case WalletApiOperation.DeleteStoredBackup: {
+ const req = codecForDeleteStoredBackupRequest().decode(payload);
+ await deleteStoredBackup(ws, req);
return {};
+ }
case WalletApiOperation.ListStoredBackups:
+ return listStoredBackups(ws);
+ case WalletApiOperation.RecoverStoredBackup: {
+ const req = codecForRecoverStoredBackupRequest().decode(payload);
+ await recoverStoredBackup(ws, req);
return {};
- case WalletApiOperation.RecoverStoredBackup:
- return {};
+ }
case WalletApiOperation.InitWallet: {
logger.trace("initializing wallet");
ws.initCalled = true;
@@ -1496,24 +1483,11 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
return {};
}
case WalletApiOperation.ListCurrencies: {
- return await ws.db
- .mktx((x) => [x.auditorTrust, x.exchangeTrust])
- .runReadOnly(async (tx) => {
- const trustedAuditors = await tx.auditorTrust.iter().toArray();
- const trustedExchanges = await tx.exchangeTrust.iter().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,
- })),
- };
- });
+ // FIXME: Remove / change to scoped currency approach.
+ return {
+ trustedAuditors: [],
+ trustedExchanges: [],
+ };
}
case WalletApiOperation.WithdrawFakebank: {
const req = codecForWithdrawFakebankRequest().decode(payload);
@@ -1612,6 +1586,12 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
return await waitUntilDone(ws);
case WalletApiOperation.TestingWaitRefreshesFinal:
return await waitUntilRefreshesDone(ws);
+ case WalletApiOperation.TestingSetTimetravel: {
+ const req = codecForTestingSetTimetravelRequest().decode(payload);
+ setDangerousTimetravel(req.offsetMs);
+ ws.workAvailable.trigger();
+ return {};
+ }
// default:
// assertUnreachable(operation);
}
@@ -1712,14 +1692,6 @@ export class Wallet {
public static defaultConfig: Readonly<WalletConfig> = {
builtin: {
exchanges: ["https://exchange.demo.taler.net/"],
- auditors: [
- {
- currency: "KUDOS",
- auditorPub: "BW9DC48PHQY4NH011SHHX36DZZ3Q22Y6X7FZ1VD1CMZ2PTFZ6PN0",
- auditorBaseUrl: "https://auditor.demo.taler.net/",
- uids: ["5P25XF8TVQP9AW6VYGY2KV47WT5Y3ZXFSJAA570GJPX5SVJXKBVG"],
- },
- ],
},
features: {
allowHttp: false,
@@ -1792,7 +1764,6 @@ class InternalWalletStateImpl implements InternalWalletState {
exchangeOps: ExchangeOperations = {
getExchangeDetails,
- getExchangeTrust,
updateExchangeFromUrl,
};
@@ -1901,35 +1872,27 @@ class InternalWalletStateImpl implements InternalWalletState {
return computeRefundTransactionState(rec);
}
case TransactionType.PeerPullCredit:
- const rec = await tx.peerPullPaymentInitiations.get(
- parsedTxId.pursePub,
- );
+ const rec = await tx.peerPullCredit.get(parsedTxId.pursePub);
if (!rec) {
return undefined;
}
return computePeerPullCreditTransactionState(rec);
case TransactionType.PeerPullDebit: {
- const rec = await tx.peerPullPaymentIncoming.get(
- parsedTxId.peerPullPaymentIncomingId,
- );
+ const rec = await tx.peerPullDebit.get(parsedTxId.peerPullDebitId);
if (!rec) {
return undefined;
}
return computePeerPullDebitTransactionState(rec);
}
case TransactionType.PeerPushCredit: {
- const rec = await tx.peerPushPaymentIncoming.get(
- parsedTxId.peerPushPaymentIncomingId,
- );
+ const rec = await tx.peerPushCredit.get(parsedTxId.peerPushCreditId);
if (!rec) {
return undefined;
}
return computePeerPushCreditTransactionState(rec);
}
case TransactionType.PeerPushDebit: {
- const rec = await tx.peerPushPaymentInitiations.get(
- parsedTxId.pursePub,
- );
+ const rec = await tx.peerPushDebit.get(parsedTxId.pursePub);
if (!rec) {
return undefined;
}