aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-core')
-rw-r--r--packages/taler-wallet-core/src/crypto/cryptoTypes.ts34
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts22
-rw-r--r--packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts73
-rw-r--r--packages/taler-wallet-core/src/operations/exchanges.ts4
-rw-r--r--packages/taler-wallet-core/src/operations/recoup.ts37
-rw-r--r--packages/taler-wallet-core/src/operations/reserves.ts10
6 files changed, 144 insertions, 36 deletions
diff --git a/packages/taler-wallet-core/src/crypto/cryptoTypes.ts b/packages/taler-wallet-core/src/crypto/cryptoTypes.ts
index 9b72dfbe2..5351815a7 100644
--- a/packages/taler-wallet-core/src/crypto/cryptoTypes.ts
+++ b/packages/taler-wallet-core/src/crypto/cryptoTypes.ts
@@ -27,7 +27,13 @@
/**
* Imports.
*/
-import { AmountJson, DenominationPubKey, ExchangeProtocolVersion } from "@gnu-taler/taler-util";
+import {
+ AmountJson,
+ AmountString,
+ DenominationPubKey,
+ ExchangeProtocolVersion,
+ UnblindedSignature,
+} from "@gnu-taler/taler-util";
export interface RefreshNewDenomInfo {
count: number;
@@ -140,3 +146,29 @@ export interface SignTrackTransactionRequest {
merchantPriv: string;
merchantPub: string;
}
+
+/**
+ * Request to create a recoup request payload.
+ */
+export interface CreateRecoupReqRequest {
+ coinPub: string;
+ coinPriv: string;
+ blindingKey: string;
+ denomPub: DenominationPubKey;
+ denomPubHash: string;
+ denomSig: UnblindedSignature;
+ recoupAmount: AmountJson;
+}
+
+/**
+ * Request to create a recoup-refresh request payload.
+ */
+export interface CreateRecoupRefreshReqRequest {
+ coinPub: string;
+ coinPriv: string;
+ blindingKey: string;
+ denomPub: DenominationPubKey;
+ denomPubHash: string;
+ denomSig: UnblindedSignature;
+ recoupAmount: AmountJson;
+}
diff --git a/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts b/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts
index e88b64c3c..29c2553a5 100644
--- a/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/cryptoApi.ts
@@ -26,7 +26,11 @@ import { CoinRecord, DenominationRecord, WireFee } from "../../db.js";
import { CryptoWorker } from "./cryptoWorkerInterface.js";
-import { RecoupRequest, CoinDepositPermission } from "@gnu-taler/taler-util";
+import {
+ CoinDepositPermission,
+ RecoupRefreshRequest,
+ RecoupRequest,
+} from "@gnu-taler/taler-util";
import {
BenchmarkResult,
@@ -39,6 +43,8 @@ import {
import * as timer from "../../util/timer.js";
import { Logger } from "@gnu-taler/taler-util";
import {
+ CreateRecoupRefreshReqRequest,
+ CreateRecoupReqRequest,
DerivedRefreshSession,
DerivedTipPlanchet,
DeriveRefreshSessionRequest,
@@ -421,8 +427,18 @@ export class CryptoApi {
);
}
- createRecoupRequest(coin: CoinRecord): Promise<RecoupRequest> {
- return this.doRpc<RecoupRequest>("createRecoupRequest", 1, coin);
+ createRecoupRequest(req: CreateRecoupReqRequest): Promise<RecoupRequest> {
+ return this.doRpc<RecoupRequest>("createRecoupRequest", 1, req);
+ }
+
+ createRecoupRefreshRequest(
+ req: CreateRecoupRefreshReqRequest,
+ ): Promise<RecoupRefreshRequest> {
+ return this.doRpc<RecoupRefreshRequest>(
+ "createRecoupRefreshRequest",
+ 1,
+ req,
+ );
}
deriveRefreshSession(
diff --git a/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts b/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts
index 9e2dc18f3..b366fa9ec 100644
--- a/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts
+++ b/packages/taler-wallet-core/src/crypto/workers/cryptoImplementation.ts
@@ -25,12 +25,7 @@
*/
// FIXME: Crypto should not use DB Types!
-import {
- CoinRecord,
- DenominationRecord,
- WireFee,
- CoinSourceType,
-} from "../../db.js";
+import { DenominationRecord, WireFee } from "../../db.js";
import {
buildSigPS,
@@ -39,6 +34,7 @@ import {
ExchangeProtocolVersion,
FreshCoin,
hashDenomPub,
+ RecoupRefreshRequest,
RecoupRequest,
RefreshPlanchetInfo,
TalerSignaturePurpose,
@@ -78,6 +74,8 @@ import { Timestamp, timestampTruncateToSecond } from "@gnu-taler/taler-util";
import { Logger } from "@gnu-taler/taler-util";
import {
+ CreateRecoupRefreshReqRequest,
+ CreateRecoupReqRequest,
DerivedRefreshSession,
DerivedTipPlanchet,
DeriveRefreshSessionRequest,
@@ -261,33 +259,64 @@ export class CryptoImplementation {
/**
* Create and sign a message to recoup a coin.
*/
- createRecoupRequest(coin: CoinRecord): RecoupRequest {
+ createRecoupRequest(req: CreateRecoupReqRequest): RecoupRequest {
const p = buildSigPS(TalerSignaturePurpose.WALLET_COIN_RECOUP)
- .put(decodeCrock(coin.coinPub))
- .put(decodeCrock(coin.denomPubHash))
- .put(decodeCrock(coin.blindingKey))
+ .put(decodeCrock(req.denomPubHash))
+ .put(decodeCrock(req.blindingKey))
+ .put(amountToBuffer(Amounts.jsonifyAmount(req.recoupAmount)))
.build();
- const coinPriv = decodeCrock(coin.coinPriv);
+ const coinPriv = decodeCrock(req.coinPriv);
const coinSig = eddsaSign(p, coinPriv);
- if (coin.denomPub.cipher === DenomKeyType.LegacyRsa) {
+ if (req.denomPub.cipher === DenomKeyType.LegacyRsa) {
const paybackRequest: RecoupRequest = {
- coin_blind_key_secret: coin.blindingKey,
- coin_pub: coin.coinPub,
+ coin_blind_key_secret: req.blindingKey,
coin_sig: encodeCrock(coinSig),
- denom_pub_hash: coin.denomPubHash,
- denom_sig: coin.denomSig.rsa_signature,
- refreshed: coin.coinSource.type === CoinSourceType.Refresh,
+ denom_pub_hash: req.denomPubHash,
+ denom_sig: req.denomSig.rsa_signature,
+ amount: Amounts.stringify(req.recoupAmount),
};
return paybackRequest;
} else {
const paybackRequest: RecoupRequest = {
- coin_blind_key_secret: coin.blindingKey,
- coin_pub: coin.coinPub,
+ coin_blind_key_secret: req.blindingKey,
+ coin_sig: encodeCrock(coinSig),
+ denom_pub_hash: req.denomPubHash,
+ denom_sig: req.denomSig,
+ amount: Amounts.stringify(req.recoupAmount),
+ };
+ return paybackRequest;
+ }
+ }
+
+ /**
+ * Create and sign a message to recoup a coin.
+ */
+ createRecoupRefreshRequest(req: CreateRecoupRefreshReqRequest): RecoupRefreshRequest {
+ const p = buildSigPS(TalerSignaturePurpose.WALLET_COIN_RECOUP_REFRESH)
+ .put(decodeCrock(req.denomPubHash))
+ .put(decodeCrock(req.blindingKey))
+ .put(amountToBuffer(Amounts.jsonifyAmount(req.recoupAmount)))
+ .build();
+
+ const coinPriv = decodeCrock(req.coinPriv);
+ const coinSig = eddsaSign(p, coinPriv);
+ if (req.denomPub.cipher === DenomKeyType.LegacyRsa) {
+ const paybackRequest: RecoupRefreshRequest = {
+ coin_blind_key_secret: req.blindingKey,
+ coin_sig: encodeCrock(coinSig),
+ denom_pub_hash: req.denomPubHash,
+ denom_sig: req.denomSig.rsa_signature,
+ amount: Amounts.stringify(req.recoupAmount),
+ };
+ return paybackRequest;
+ } else {
+ const paybackRequest: RecoupRefreshRequest = {
+ coin_blind_key_secret: req.blindingKey,
coin_sig: encodeCrock(coinSig),
- denom_pub_hash: coin.denomPubHash,
- denom_sig: coin.denomSig,
- refreshed: coin.coinSource.type === CoinSourceType.Refresh,
+ denom_pub_hash: req.denomPubHash,
+ denom_sig: req.denomSig,
+ amount: Amounts.stringify(req.recoupAmount),
};
return paybackRequest;
}
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts
index 987031810..2975c860f 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -651,7 +651,7 @@ async function updateExchangeFromUrlImpl(
logger.trace("denom already revoked");
continue;
}
- logger.trace("revoking denom", recoupInfo.h_denom_pub);
+ logger.info("revoking denom", recoupInfo.h_denom_pub);
oldDenom.isRevoked = true;
await tx.denominations.put(oldDenom);
const affectedCoins = await tx.coins.indexes.byDenomPubHash
@@ -662,7 +662,7 @@ async function updateExchangeFromUrlImpl(
}
}
if (newlyRevokedCoinPubs.length != 0) {
- logger.trace("recouping coins", newlyRevokedCoinPubs);
+ logger.info("recouping coins", newlyRevokedCoinPubs);
recoupGroupId = await ws.recoupOps.createRecoupGroup(
ws,
tx,
diff --git a/packages/taler-wallet-core/src/operations/recoup.ts b/packages/taler-wallet-core/src/operations/recoup.ts
index 8a4c2242a..559513d44 100644
--- a/packages/taler-wallet-core/src/operations/recoup.ts
+++ b/packages/taler-wallet-core/src/operations/recoup.ts
@@ -28,6 +28,7 @@ import {
Amounts,
codecForRecoupConfirmation,
getTimestampNow,
+ j2s,
NotificationType,
RefreshReason,
TalerErrorDetails,
@@ -107,7 +108,7 @@ async function putGroupAsFinished(
}
}
if (allFinished) {
- logger.trace("all recoups of recoup group are finished");
+ logger.info("all recoups of recoup group are finished");
recoupGroup.timestampFinished = getTimestampNow();
recoupGroup.retryInfo = initRetryInfo();
recoupGroup.lastError = undefined;
@@ -178,8 +179,17 @@ async function recoupWithdrawCoin(
type: NotificationType.RecoupStarted,
});
- const recoupRequest = await ws.cryptoApi.createRecoupRequest(coin);
+ const recoupRequest = await ws.cryptoApi.createRecoupRequest({
+ blindingKey: coin.blindingKey,
+ coinPriv: coin.coinPriv,
+ coinPub: coin.coinPub,
+ denomPub: coin.denomPub,
+ denomPubHash: coin.denomPubHash,
+ denomSig: coin.denomSig,
+ recoupAmount: coin.currentAmount,
+ });
const reqUrl = new URL(`/coins/${coin.coinPub}/recoup`, coin.exchangeBaseUrl);
+ logger.trace(`requesting recoup via ${reqUrl.href}`);
const resp = await ws.http.postJson(reqUrl.href, recoupRequest, {
timeout: getReserveRequestTimeout(reserve),
});
@@ -188,6 +198,8 @@ async function recoupWithdrawCoin(
codecForRecoupConfirmation(),
);
+ logger.trace(`got recoup confirmation ${j2s(recoupConfirmation)}`);
+
if (recoupConfirmation.reserve_pub !== reservePub) {
throw Error(`Coin's reserve doesn't match reserve on recoup`);
}
@@ -249,7 +261,15 @@ async function recoupRefreshCoin(
type: NotificationType.RecoupStarted,
});
- const recoupRequest = await ws.cryptoApi.createRecoupRequest(coin);
+ const recoupRequest = await ws.cryptoApi.createRecoupRefreshRequest({
+ blindingKey: coin.blindingKey,
+ coinPriv: coin.coinPriv,
+ coinPub: coin.coinPub,
+ denomPub: coin.denomPub,
+ denomPubHash: coin.denomPubHash,
+ denomSig: coin.denomSig,
+ recoupAmount: coin.currentAmount,
+ });
const reqUrl = new URL(`/coins/${coin.coinPub}/recoup`, coin.exchangeBaseUrl);
logger.trace(`making recoup request for ${coin.coinPub}`);
@@ -359,9 +379,14 @@ async function processRecoupGroupImpl(
logger.trace("recoup group finished");
return;
}
- const ps = recoupGroup.coinPubs.map((x, i) =>
- processRecoup(ws, recoupGroupId, i),
- );
+ const ps = recoupGroup.coinPubs.map(async (x, i) => {
+ try {
+ processRecoup(ws, recoupGroupId, i);
+ } catch (e) {
+ logger.warn(`processRecoup failed: ${e}`);
+ throw e;
+ }
+ });
await Promise.all(ps);
const reserveSet = new Set<string>();
diff --git a/packages/taler-wallet-core/src/operations/reserves.ts b/packages/taler-wallet-core/src/operations/reserves.ts
index 5a9fbb405..75d517d68 100644
--- a/packages/taler-wallet-core/src/operations/reserves.ts
+++ b/packages/taler-wallet-core/src/operations/reserves.ts
@@ -30,6 +30,7 @@ import {
encodeCrock,
getRandomBytes,
getTimestampNow,
+ j2s,
Logger,
NotificationType,
randomBytes,
@@ -538,6 +539,7 @@ async function updateReserve(
resp,
codecForReserveStatus(),
);
+
if (result.isError) {
if (
resp.status === 404 &&
@@ -555,6 +557,8 @@ async function updateReserve(
}
}
+ logger.trace(`got reserve status ${j2s(result.response)}`);
+
const reserveInfo = result.response;
const balance = Amounts.parseOrThrow(reserveInfo.balance);
const currency = balance.currency;
@@ -635,8 +639,10 @@ async function updateReserve(
}
}
- const remainingAmount = Amounts.sub(amountReservePlus, amountReserveMinus)
- .amount;
+ const remainingAmount = Amounts.sub(
+ amountReservePlus,
+ amountReserveMinus,
+ ).amount;
const denomSelInfo = selectWithdrawalDenominations(
remainingAmount,
denoms,