wallet-core: fix deposit with age restrictions

This commit is contained in:
Florian Dold 2022-10-31 16:50:54 +01:00
parent 6d08ed0680
commit 780eb20227
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
5 changed files with 72 additions and 7 deletions

View File

@ -289,6 +289,8 @@ export interface CoinDepositPermission {
minimum_age_sig?: EddsaSignatureString; minimum_age_sig?: EddsaSignatureString;
age_commitment?: Edx25519PublicKeyEnc[]; age_commitment?: Edx25519PublicKeyEnc[];
h_age_commitment?: string;
} }
/** /**
@ -1972,3 +1974,65 @@ export interface ExchangePurseDeposits {
// Array of coins to deposit into the purse. // Array of coins to deposit into the purse.
deposits: PurseDeposit[]; deposits: PurseDeposit[];
} }
export interface ExchangeDepositRequest {
// Amount to be deposited, can be a fraction of the
// coin's total value.
contribution: AmountString;
// The merchant's account details.
// In case of an auction policy, it refers to the seller.
merchant_payto_uri: string;
// The salt is used to hide the payto_uri from customers
// when computing the h_wire of the merchant.
wire_salt: string;
// SHA-512 hash of the contract of the merchant with the customer. Further
// details are never disclosed to the exchange.
h_contract_terms: HashCodeString;
// Hash of denomination RSA key with which the coin is signed.
denom_pub_hash: HashCodeString;
// Exchange's unblinded RSA signature of the coin.
ub_sig: UnblindedSignature;
// Timestamp when the contract was finalized.
timestamp: TalerProtocolTimestamp;
// Indicative time by which the exchange undertakes to transfer the funds to
// the merchant, in case of successful payment. A wire transfer deadline of 'never'
// is not allowed.
wire_transfer_deadline: TalerProtocolTimestamp;
// EdDSA public key of the merchant, so that the client can identify the
// merchant for refund requests.
//
// THIS FIELD WILL BE DEPRECATED, once the refund mechanism becomes a
// policy via extension.
merchant_pub: EddsaPublicKeyString;
// Date until which the merchant can issue a refund to the customer via the
// exchange, to be omitted if refunds are not allowed.
//
// THIS FIELD WILL BE DEPRECATED, once the refund mechanism becomes a
// policy via extension.
refund_deadline?: TalerProtocolTimestamp;
// CAVEAT: THIS IS WORK IN PROGRESS
// (Optional) policy for the deposit.
// This might be a refund, auction or escrow policy.
//
// Note that support for policies is an optional feature of the exchange.
// Optional features are so called "extensions" in Taler. The exchange
// provides the list of supported extensions, including policies, in the
// ExtensionsManifestsResponse response to the /keys endpoint.
policy?: any;
// Signature over TALER_DepositRequestPS, made by the customer with the
// coin's private key.
coin_sig: EddsaSignatureString;
h_age_commitment?: string;
}

View File

@ -15,7 +15,7 @@ warn-noprefix:
install: warn-noprefix install: warn-noprefix
else else
install_target = $(prefix)/lib/taler-wallet-cli install_target = $(prefix)/lib/taler-wallet-cli
.PHONY: install .PHONY: install install-nodeps
install: install:
pnpm install --frozen-lockfile --filter @gnu-taler/taler-wallet-cli... pnpm install --frozen-lockfile --filter @gnu-taler/taler-wallet-cli...
install -d $(prefix)/bin install -d $(prefix)/bin

View File

@ -1074,13 +1074,11 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
// FIXME: put extensions here if used // FIXME: put extensions here if used
const hExt = new Uint8Array(64); const hExt = new Uint8Array(64);
let hAgeCommitment: Uint8Array; let hAgeCommitment: Uint8Array;
let maybeAgeCommitmentHash: string | undefined = undefined;
let minimumAgeSig: string | undefined = undefined; let minimumAgeSig: string | undefined = undefined;
if (depositInfo.ageCommitmentProof) { if (depositInfo.ageCommitmentProof) {
const ach = AgeRestriction.hashCommitment( const ach = AgeRestriction.hashCommitment(
depositInfo.ageCommitmentProof.commitment, depositInfo.ageCommitmentProof.commitment,
); );
maybeAgeCommitmentHash = ach;
hAgeCommitment = decodeCrock(ach); hAgeCommitment = decodeCrock(ach);
if (depositInfo.requiredMinimumAge != null) { if (depositInfo.requiredMinimumAge != null) {
minimumAgeSig = encodeCrock( minimumAgeSig = encodeCrock(
@ -1130,11 +1128,12 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
}; };
if (depositInfo.requiredMinimumAge != null) { if (depositInfo.requiredMinimumAge != null) {
// These are only required by the merchant
s.minimum_age_sig = minimumAgeSig; s.minimum_age_sig = minimumAgeSig;
s.age_commitment = s.age_commitment =
depositInfo.ageCommitmentProof?.commitment.publicKeys; depositInfo.ageCommitmentProof?.commitment.publicKeys;
} else if (depositInfo.ageCommitmentProof) { } else if (depositInfo.ageCommitmentProof) {
(s as any).h_age_commitment = encodeCrock(hAgeCommitment); s.h_age_commitment = encodeCrock(hAgeCommitment);
} }
return s; return s;

View File

@ -19,6 +19,7 @@
*/ */
import { Logger } from "@gnu-taler/taler-util"; import { Logger } from "@gnu-taler/taler-util";
import os from "os"; import os from "os";
import url from "url";
import { nativeCryptoR } from "../cryptoImplementation.js"; import { nativeCryptoR } from "../cryptoImplementation.js";
import { CryptoWorkerFactory } from "./cryptoDispatcher.js"; import { CryptoWorkerFactory } from "./cryptoDispatcher.js";
import { CryptoWorker } from "./cryptoWorkerInterface.js"; import { CryptoWorker } from "./cryptoWorkerInterface.js";
@ -26,7 +27,7 @@ import { processRequestWithImpl } from "./worker-common.js";
const logger = new Logger("nodeThreadWorker.ts"); const logger = new Logger("nodeThreadWorker.ts");
const f = import.meta.url; const f = url.fileURLToPath(import.meta.url);
const workerCode = ` const workerCode = `
// Try loading the glue library for embedded // Try loading the glue library for embedded

View File

@ -30,6 +30,7 @@ import {
DepositGroupFees, DepositGroupFees,
durationFromSpec, durationFromSpec,
encodeCrock, encodeCrock,
ExchangeDepositRequest,
GetFeeForDepositRequest, GetFeeForDepositRequest,
getRandomBytes, getRandomBytes,
hashWire, hashWire,
@ -112,8 +113,7 @@ export async function processDepositGroup(
continue; continue;
} }
const perm = depositPermissions[i]; const perm = depositPermissions[i];
let requestBody: any; const requestBody: ExchangeDepositRequest = {
requestBody = {
contribution: Amounts.stringify(perm.contribution), contribution: Amounts.stringify(perm.contribution),
merchant_payto_uri: depositGroup.wire.payto_uri, merchant_payto_uri: depositGroup.wire.payto_uri,
wire_salt: depositGroup.wire.salt, wire_salt: depositGroup.wire.salt,
@ -126,6 +126,7 @@ export async function processDepositGroup(
coin_sig: perm.coin_sig, coin_sig: perm.coin_sig,
denom_pub_hash: perm.h_denom, denom_pub_hash: perm.h_denom,
merchant_pub: depositGroup.merchantPub, merchant_pub: depositGroup.merchantPub,
h_age_commitment: perm.h_age_commitment,
}; };
// Check for cancellation before making network request. // Check for cancellation before making network request.
options.cancellationToken?.throwIfCancelled(); options.cancellationToken?.throwIfCancelled();