diff options
author | Florian Dold <florian@dold.me> | 2024-08-08 16:49:37 +0200 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2024-08-14 13:22:41 +0200 |
commit | 3c86bfb1435deba091771ca4e6135fbfd29b70ec (patch) | |
tree | 1f7833e9a903deb90f040f8e73663e5f104e945a /packages/taler-util | |
parent | 947aa424ca0bc214c3e175221636fe6193c939c2 (diff) |
wallet-core: implement basic wallet KYC for balance thresholds
Diffstat (limited to 'packages/taler-util')
-rw-r--r-- | packages/taler-util/src/http-client/exchange.ts | 10 | ||||
-rw-r--r-- | packages/taler-util/src/http-common.ts | 10 | ||||
-rw-r--r-- | packages/taler-util/src/index.ts | 108 | ||||
-rw-r--r-- | packages/taler-util/src/operation.ts | 4 | ||||
-rw-r--r-- | packages/taler-util/src/payto.ts | 7 | ||||
-rw-r--r-- | packages/taler-util/src/taler-crypto.ts | 17 | ||||
-rw-r--r-- | packages/taler-util/src/taler-signatures.ts | 63 | ||||
-rw-r--r-- | packages/taler-util/src/types-taler-exchange.ts | 208 | ||||
-rw-r--r-- | packages/taler-util/src/types-taler-wallet-transactions.ts | 1 | ||||
-rw-r--r-- | packages/taler-util/src/types-taler-wallet.ts | 46 |
10 files changed, 281 insertions, 193 deletions
diff --git a/packages/taler-util/src/http-client/exchange.ts b/packages/taler-util/src/http-client/exchange.ts index 4a27c824f..0539319c3 100644 --- a/packages/taler-util/src/http-client/exchange.ts +++ b/packages/taler-util/src/http-client/exchange.ts @@ -298,7 +298,6 @@ export class TalerExchangeHttpClient { async uploadKycForm(requirement: KycRequirementInformationId, body: object) { const url = new URL(`kyc-upload/${requirement}`, this.baseUrl); - const resp = await this.httpLib.fetch(url.href, { method: "POST", body, @@ -627,8 +626,7 @@ export class TalerExchangeHttpClient { function buildKYCQuerySignature(key: SigningKey): string { const sigBlob = buildSigPS( - TalerSignaturePurpose.TALER_SIGNATURE_AML_QUERY, - // TalerSignaturePurpose.TALER_SIGNATURE_WALLET_ACCOUNT_SETUP, + TalerSignaturePurpose.AML_QUERY, ).build(); return encodeCrock(eddsaSign(sigBlob, key)); @@ -636,7 +634,7 @@ function buildKYCQuerySignature(key: SigningKey): string { function buildAMLQuerySignature(key: SigningKey): string { const sigBlob = buildSigPS( - TalerSignaturePurpose.TALER_SIGNATURE_AML_QUERY, + TalerSignaturePurpose.AML_QUERY, ).build(); return encodeCrock(eddsaSign(sigBlob, key)); @@ -648,7 +646,7 @@ function buildAMLDecisionSignature( ): AmlDecisionRequest { const zero = new Uint8Array(new ArrayBuffer(64)); - const sigBlob = buildSigPS(TalerSignaturePurpose.TALER_SIGNATURE_AML_DECISION) + const sigBlob = buildSigPS(TalerSignaturePurpose.AML_DECISION) //TODO: new need the null terminator, also in the exchange .put(hash(stringToBytes(decision.justification))) //check null .put(timestampRoundedToBuffer(decision.decision_time)) @@ -664,5 +662,3 @@ function buildAMLDecisionSignature( officer_sig, }; } - - diff --git a/packages/taler-util/src/http-common.ts b/packages/taler-util/src/http-common.ts index 20ac9dddd..6f537dda2 100644 --- a/packages/taler-util/src/http-common.ts +++ b/packages/taler-util/src/http-common.ts @@ -274,10 +274,10 @@ export async function readSuccessResponseJsonOrErrorCode<T>( }; } -export async function readResponseJsonOrErrorCode<T>( +export async function readResponseJsonOrThrow<T>( httpResponse: HttpResponse, codec: Codec<T>, -): Promise<{ isError: boolean; response: T }> { +): Promise<T> { let respJson; try { respJson = await httpResponse.json(); @@ -310,13 +310,9 @@ export async function readResponseJsonOrErrorCode<T>( "Response invalid", ); } - return { - isError: !(httpResponse.status >= 200 && httpResponse.status < 300), - response: parsedResponse, - }; + return parsedResponse; } - type HttpErrorDetails = { requestUrl: string; requestMethod: string; diff --git a/packages/taler-util/src/index.ts b/packages/taler-util/src/index.ts index 025ce0183..d6a2fa614 100644 --- a/packages/taler-util/src/index.ts +++ b/packages/taler-util/src/index.ts @@ -2,59 +2,59 @@ import { TalerErrorCode } from "./taler-error-codes.js"; export { TalerErrorCode }; -export * from "./CancellationToken.js"; -export * from "./MerchantApiClient.js"; -export { RequestThrottler } from "./RequestThrottler.js"; -export * from "./ReserveStatus.js"; -export * from "./ReserveTransaction.js"; -export { TaskThrottler } from "./TaskThrottler.js"; -export * from "./amounts.js"; -export * from "./bank-api-client.js"; -export * from "./base64.js"; -export * from "./bitcoin.js"; -export * from "./codec.js"; -export * from "./contract-terms.js"; -export * from "./errors.js"; -export { fnutil } from "./fnutils.js"; -export * from "./helpers.js"; -export * from "./http-client/authentication.js"; -export * from "./http-client/bank-conversion.js"; -export * from "./http-client/bank-core.js"; -export * from "./http-client/bank-integration.js"; -export * from "./http-client/bank-revenue.js"; -export * from "./http-client/bank-wire.js"; -export * from "./http-client/challenger.js"; -export * from "./http-client/exchange.js"; -export * from "./http-client/merchant.js"; -export * from "./http-client/officer-account.js"; -export { CacheEvictor } from "./http-client/utils.js"; -export * from "./http-status-codes.js"; -export * from "./i18n.js"; -export * from "./iban.js"; -export * from "./invariants.js"; -export * from "./kdf.js"; -export * from "./libtool-version.js"; -export * from "./logging.js"; -export { - crypto_sign_keyPair_fromSeed, - randomBytes, - secretbox, - secretbox_open, - setPRNG, -} from "./nacl-fast.js"; -export * from "./notifications.js"; -export * from "./observability.js"; -export * from "./operation.js"; -export * from "./payto.js"; -export * from "./promises.js"; -export * from "./qr.js"; -export * from "./rfc3548.js"; -export * from "./taler-crypto.js"; -export * from "./taleruri.js"; -export * from "./time.js"; -export * from "./timer.js"; -export * from "./transaction-test-data.js"; -export * from "./url.js"; + export * from "./amounts.js"; + export * from "./bank-api-client.js"; + export * from "./base64.js"; + export * from "./bitcoin.js"; + export * from "./CancellationToken.js"; + export * from "./codec.js"; + export * from "./contract-terms.js"; + export * from "./errors.js"; + export { fnutil } from "./fnutils.js"; + export * from "./helpers.js"; + export * from "./http-client/authentication.js"; + export * from "./http-client/bank-conversion.js"; + export * from "./http-client/bank-core.js"; + export * from "./http-client/bank-integration.js"; + export * from "./http-client/bank-revenue.js"; + export * from "./http-client/bank-wire.js"; + export * from "./http-client/challenger.js"; + export * from "./http-client/exchange.js"; + export * from "./http-client/merchant.js"; + export * from "./http-client/officer-account.js"; + export { CacheEvictor } from "./http-client/utils.js"; + export * from "./http-status-codes.js"; + export * from "./i18n.js"; + export * from "./iban.js"; + export * from "./invariants.js"; + export * from "./kdf.js"; + export * from "./libtool-version.js"; + export * from "./logging.js"; + export * from "./MerchantApiClient.js"; + export { + crypto_sign_keyPair_fromSeed, + randomBytes, + secretbox, + secretbox_open, + setPRNG + } from "./nacl-fast.js"; + export * from "./notifications.js"; + export * from "./observability.js"; + export * from "./operation.js"; + export * from "./payto.js"; + export * from "./promises.js"; + export * from "./qr.js"; + export { RequestThrottler } from "./RequestThrottler.js"; + export * from "./ReserveStatus.js"; + export * from "./ReserveTransaction.js"; + export * from "./rfc3548.js"; + export * from "./taler-crypto.js"; + export * from "./taleruri.js"; + export { TaskThrottler } from "./TaskThrottler.js"; + export * from "./time.js"; + export * from "./timer.js"; + export * from "./transaction-test-data.js"; + export * from "./url.js"; export * from "./types-taler-bank-conversion.js"; export * from "./types-taler-bank-integration.js"; @@ -74,3 +74,5 @@ export * as TalerExchangeApi from "./types-taler-exchange.js"; export * as TalerMerchantApi from "./types-taler-merchant.js"; export * as TalerRevenueApi from "./types-taler-revenue.js"; export * as TalerWireGatewayApi from "./types-taler-wire-gateway.js"; + +export * from "./taler-signatures.js"; diff --git a/packages/taler-util/src/operation.ts b/packages/taler-util/src/operation.ts index 2d17238dc..6b5eb61a6 100644 --- a/packages/taler-util/src/operation.ts +++ b/packages/taler-util/src/operation.ts @@ -19,7 +19,7 @@ */ import { HttpResponse, - readResponseJsonOrErrorCode, + readResponseJsonOrThrow, readSuccessResponseJsonOrThrow, readTalerErrorResponse, } from "./http-common.js"; @@ -127,7 +127,7 @@ export async function opKnownAlternativeFailure<T extends HttpStatusCode, B>( s: T, codec: Codec<B>, ): Promise<OperationAlternative<T, B>> { - const body = (await readResponseJsonOrErrorCode(resp, codec)).response; + const body = await readResponseJsonOrThrow(resp, codec); return { type: "fail", case: s, body }; } diff --git a/packages/taler-util/src/payto.ts b/packages/taler-util/src/payto.ts index 3a332b37e..f50f97e58 100644 --- a/packages/taler-util/src/payto.ts +++ b/packages/taler-util/src/payto.ts @@ -25,7 +25,6 @@ import { } from "./codec.js"; import { AccessToken, - bytesToString, codecForAccessToken, codecOptional, hashTruncate32, @@ -214,9 +213,9 @@ export function stringifyPaytoUri(p: PaytoUri): PaytoString { return url.href as PaytoString; } -export function hashPaytoUri(p: PaytoUri): string { - const paytoUri = stringifyPaytoUri(p); - return bytesToString(hashTruncate32(stringToBytes(paytoUri + "\0"))); +export function hashPaytoUri(p: PaytoUri | string): Uint8Array { + const paytoUri = typeof p === "string" ? p : stringifyPaytoUri(p); + return hashTruncate32(stringToBytes(paytoUri + "\0")); } /** diff --git a/packages/taler-util/src/taler-crypto.ts b/packages/taler-util/src/taler-crypto.ts index d4e21e646..ca57e22e2 100644 --- a/packages/taler-util/src/taler-crypto.ts +++ b/packages/taler-util/src/taler-crypto.ts @@ -31,11 +31,12 @@ import { Logger } from "./logging.js"; import * as nacl from "./nacl-fast.js"; import { secretbox } from "./nacl-fast.js"; import { TalerProtocolDuration, TalerProtocolTimestamp } from "./time.js"; +import { CoinPublicKeyString, HashCodeString } from "./types-taler-common.js"; import { - CoinPublicKeyString, - HashCodeString, -} from "./types-taler-common.js"; -import { CoinEnvelope, DenomKeyType, DenominationPubKey } from "./types-taler-exchange.js"; + CoinEnvelope, + DenomKeyType, + DenominationPubKey, +} from "./types-taler-exchange.js"; export type Flavor<T, FlavorT extends string> = T & { _flavor?: `taler.${FlavorT}`; @@ -985,6 +986,7 @@ export enum TalerSignaturePurpose { MERCHANT_REFUND = 1102, WALLET_COIN_RECOUP = 1203, WALLET_COIN_LINK = 1204, + WALLET_ACCOUNT_SETUP = 1205, WALLET_COIN_RECOUP_REFRESH = 1206, WALLET_AGE_ATTESTATION = 1207, WALLET_PURSE_CREATE = 1210, @@ -996,9 +998,10 @@ export enum TalerSignaturePurpose { WALLET_COIN_HISTORY = 1209, EXCHANGE_CONFIRM_RECOUP = 1039, EXCHANGE_CONFIRM_RECOUP_REFRESH = 1041, - TALER_SIGNATURE_AML_DECISION = 1350, - TALER_SIGNATURE_AML_QUERY = 1351, - TALER_SIGNATURE_MASTER_AML_KEY = 1017, + AML_DECISION = 1350, + AML_QUERY = 1351, + MASTER_AML_KEY = 1017, + KYC_AUTH = 1360, ANASTASIS_POLICY_UPLOAD = 1400, ANASTASIS_POLICY_DOWNLOAD = 1401, SYNC_BACKUP_UPLOAD = 1450, diff --git a/packages/taler-util/src/taler-signatures.ts b/packages/taler-util/src/taler-signatures.ts new file mode 100644 index 000000000..81b7c242e --- /dev/null +++ b/packages/taler-util/src/taler-signatures.ts @@ -0,0 +1,63 @@ +/* + This file is part of GNU Taler + (C) 2024 GNUnet e.V. + + 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/> + */ + +import { canonicalJson } from "./index.js"; +import { + bufferForUint64, + buildSigPS, + decodeCrock, + eddsaSign, + hash, + stringToBytes, + TalerSignaturePurpose, + timestampRoundedToBuffer, +} from "./taler-crypto.js"; +import { AmlDecisionRequestWithoutSignature } from "./types-taler-exchange.js"; + +/** + * Implementation of Taler protocol signatures. + * + * In this file, we have implementations of signatures that are not used in the wallet, + * but in other places (tests, SPAs, ...). + */ + +/** + * Signature for the POST /aml/$OFFICER_PUB/decisions endpoint. + */ +export function signAmlDecision( + priv: Uint8Array, + decision: AmlDecisionRequestWithoutSignature, +): Uint8Array { + const builder = buildSigPS(TalerSignaturePurpose.AML_DECISION); + + const flags: number = decision.keep_investigating ? 1 : 0; + + builder.put(timestampRoundedToBuffer(decision.decision_time)); + builder.put(decodeCrock(decision.h_payto)); + builder.put(hash(stringToBytes(decision.justification))); + builder.put(hash(stringToBytes(canonicalJson(decision.properties) + "\0"))); + builder.put(hash(stringToBytes(canonicalJson(decision.new_rules) + "\0"))); + if (decision.new_measure != null) { + builder.put(hash(stringToBytes(decision.new_measure))); + } else { + builder.put(new Uint8Array(64)); + } + builder.put(bufferForUint64(flags)); + + const sigBlob = builder.build(); + + return eddsaSign(sigBlob, priv); +} diff --git a/packages/taler-util/src/types-taler-exchange.ts b/packages/taler-util/src/types-taler-exchange.ts index b71f302f5..2e13b4024 100644 --- a/packages/taler-util/src/types-taler-exchange.ts +++ b/packages/taler-util/src/types-taler-exchange.ts @@ -42,7 +42,6 @@ import { Edx25519PublicKeyEnc } from "./taler-crypto.js"; import { TalerProtocolDuration, TalerProtocolTimestamp, - codecForAbsoluteTime, codecForDuration, codecForTimestamp, } from "./time.js"; @@ -51,9 +50,6 @@ import { AmlOfficerPublicKeyP, AmountString, Base32String, - codecForAccessToken, - codecForInternationalizedString, - codecForURLString, CoinPublicKeyString, Cs25519Point, CurrencySpecification, @@ -69,6 +65,9 @@ import { RsaPublicKeySring, Timestamp, WireSalt, + codecForAccessToken, + codecForInternationalizedString, + codecForURLString, } from "./types-taler-common.js"; export type DenominationPubKey = RsaDenominationPubKey | CsDenominationPubKey; @@ -1387,21 +1386,18 @@ export interface BatchDepositRequestCoin { } export interface AvailableMeasureSummary { - // Available original measures that can be // triggered directly by default rules. - roots: { [measure_name: string]: MeasureInformation; }; + roots: { [measure_name: string]: MeasureInformation }; // Available AML programs. - programs: { [prog_name: string]: AmlProgramRequirement; }; + programs: { [prog_name: string]: AmlProgramRequirement }; // Available KYC checks. - checks: { [check_name: string]: KycCheckInformation; }; - + checks: { [check_name: string]: KycCheckInformation }; } export interface MeasureInformation { - // Name of a KYC check. check_name: string; @@ -1410,11 +1406,9 @@ export interface MeasureInformation { // Context for the check. Optional. context?: Object; - } export interface AmlProgramRequirement { - // Description of what the AML program does. description: string; @@ -1428,11 +1422,9 @@ export interface AmlProgramRequirement { // are the minimum that the check must produce // (it may produce more). inputs: string[]; - } export interface KycCheckInformation { - // Description of the KYC check. Should be shown // to the AML staff but will also be shown to the // client when they initiate the check in the KYC SPA. @@ -1459,7 +1451,6 @@ export interface KycCheckInformation { fallback: string; } - export interface AmlDecisionDetails { // Array of AML decisions made for this account. Possibly // contains only the most recent decision if "history" was @@ -1469,6 +1460,7 @@ export interface AmlDecisionDetails { // Array of KYC attributes obtained for this account. kyc_attributes: KycDetail[]; } + export interface AmlDecisionDetail { // What was the justification given? justification: string; @@ -1485,6 +1477,7 @@ export interface AmlDecisionDetail { // Who made the decision? decider_pub: AmlOfficerPublicKeyP; } + export interface KycDetail { // Name of the configuration section that specifies the provider // which was used to collect the KYC details @@ -1502,6 +1495,10 @@ export interface KycDetail { expiration_time: Timestamp; } +export type AmlDecisionRequestWithoutSignature = Omit< + AmlDecisionRequest, + "officer_sig" +>; export interface ExchangeVersionResponse { // libtool-style representation of the Exchange protocol version, see @@ -1553,7 +1550,6 @@ export interface WireAccount { } export interface WalletKycRequest { - // Balance threshold (not necessarily exact balance) // to be crossed by the wallet that (may) trigger // additional KYC requirements. @@ -1570,7 +1566,6 @@ export interface WalletKycRequest { } export interface WalletKycCheckResponse { - // Next balance limit above which a KYC check // may be required. Optional, not given if no // threshold exists (assume infinity). @@ -1580,14 +1575,11 @@ export interface WalletKycCheckResponse { // expire and the wallet needs to check again // for updated thresholds. expiration_time: Timestamp; - } - // Implemented in this style since exchange // protocol **v20**. export interface LegitimizationNeededResponse { - // Numeric error code unique to the condition. // Should always be TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED. code: number; @@ -1619,11 +1611,9 @@ export interface LegitimizationNeededResponse { // should use the number to check for the account's AML/KYC status // using the /kyc-check/$REQUIREMENT_ROW endpoint. requirement_row: Integer; - } export interface AccountKycStatus { - // Current AML state for the target account. True if // operations are not happening due to staff processing // paperwork *or* due to legal requirements (so the @@ -1661,10 +1651,8 @@ export interface AccountKycStatus { // much or even prevent the user from generating a // request that would cause it to exceed hard limits). limits?: AccountLimit[]; - } export interface AccountLimit { - // Operation that is limited. // Must be one of "WITHDRAW", "DEPOSIT", "P2P-RECEIVE" // or "WALLET-BALANCE". @@ -1688,13 +1676,12 @@ export interface AccountLimit { } export interface KycProcessClientInformation { - // Array of requirements. requirements: KycRequirementInformation[]; // True if the client is expected to eventually satisfy all requirements. // Default (if missing) is false. - is_and_combinator?: boolean + is_and_combinator?: boolean; // List of available voluntary checks the client could pay for. // Since **vATTEST**. @@ -1702,10 +1689,9 @@ export interface KycProcessClientInformation { } declare const opaque_kycReq: unique symbol; -export type KycRequirementInformationId = string & { [opaque_kycReq]: true } +export type KycRequirementInformationId = string & { [opaque_kycReq]: true }; export interface KycRequirementInformation { - // Which form should be used? Common values include "INFO" // (to just show the descriptions but allow no action), // "LINK" (to enable the user to obtain a link via @@ -1730,7 +1716,6 @@ export interface KycRequirementInformation { // Since **vATTEST**. export interface KycCheckPublicInformation { - // English description of the check. description: string; @@ -1743,7 +1728,6 @@ export interface KycCheckPublicInformation { // something more??!? } - export interface EventCounter { // Number of events of the specified type in // the given range. @@ -1751,13 +1735,11 @@ export interface EventCounter { } export interface AmlDecisionsResponse { - // Array of AML decisions matching the query. records: AmlDecision[]; } export interface AmlDecision { - // Which payto-address is this record about. // Identifies a GNU Taler wallet or an affected bank account. h_payto: PaytoHash; @@ -1788,7 +1770,6 @@ export interface AmlDecision { // True if this is the active decision for the // account. is_active: boolean; - } // All fields in this object are optional. The actual @@ -1797,7 +1778,6 @@ export interface AmlDecision { // however, some common fields are standardized // and thus described here. export interface AccountProperties { - // True if this is a politically exposed account. // Rules for classifying accounts as politically // exposed are country-dependent. @@ -1824,10 +1804,13 @@ export interface AccountProperties { // Was the client's account reported to the authorities? was_reported?: boolean; + /** + * Additional free-form properties. + */ + [x: string]: any; } export interface LegitimizationRuleSet { - // When does this set of rules expire and // we automatically transition to the successor // measure? @@ -1844,12 +1827,10 @@ export interface LegitimizationRuleSet { // Custom measures that KYC rules and the // successor_measure may refer to. - custom_measures: { [measure_name: string]: MeasureInformation; }; - + custom_measures: { [measure_name: string]: MeasureInformation }; } export interface AmlDecisionRequest { - // Human-readable justification for the decision. justification: string; @@ -1884,12 +1865,9 @@ export interface AmlDecisionRequest { // When was the decision made? decision_time: Timestamp; - } - export interface KycRule { - // Type of operation to which the rule applies. operation_type: string; @@ -1932,18 +1910,13 @@ export interface KycRule { // measure what to do next. // Default (if missing) is false. is_and_combinator?: boolean; - } - export interface KycAttributes { - // Matching KYC attribute history of the account. details: KycAttributeCollectionEvent[]; - } export interface KycAttributeCollectionEvent { - // Row ID of the record. Used to filter by offset. rowid: Integer; @@ -1959,7 +1932,6 @@ export interface KycAttributeCollectionEvent { // Time when the KYC data was collected collection_time: Timestamp; - } export enum AmlState { @@ -2295,18 +2267,18 @@ export const codecForEventCounter = (): Codec<EventCounter> => .property("counter", codecForNumber()) .build("TalerExchangeApi.EventCounter"); - export const codecForAmlDecisionsResponse = (): Codec<AmlDecisionsResponse> => buildCodecForObject<AmlDecisionsResponse>() .property("records", codecForList(codecForAmlDecision())) .build("TalerExchangeApi.AmlDecisionsResponse"); -export const codecForAvailableMeasureSummary = (): Codec<AvailableMeasureSummary> => - buildCodecForObject<AvailableMeasureSummary>() - .property("checks", codecForMap(codecForKycCheckInformation())) - .property("programs", codecForMap(codecForAmlProgramRequirement())) - .property("roots", codecForMap(codecForMeasureInformation())) - .build("TalerExchangeApi.AvailableMeasureSummary"); +export const codecForAvailableMeasureSummary = + (): Codec<AvailableMeasureSummary> => + buildCodecForObject<AvailableMeasureSummary>() + .property("checks", codecForMap(codecForKycCheckInformation())) + .property("programs", codecForMap(codecForAmlProgramRequirement())) + .property("roots", codecForMap(codecForMeasureInformation())) + .build("TalerExchangeApi.AvailableMeasureSummary"); export const codecForAmlProgramRequirement = (): Codec<AmlProgramRequirement> => buildCodecForObject<AmlProgramRequirement>() @@ -2376,10 +2348,9 @@ export const codecForAccountProperties = (): Codec<AccountProperties> => .property("was_reported", codecOptional(codecForBoolean())) .build("TalerExchangeApi.AccountProperties"); - export const codecForLegitimizationRuleSet = (): Codec<LegitimizationRuleSet> => buildCodecForObject<LegitimizationRuleSet>() - .property("expiration_time", (codecForTimestamp)) + .property("expiration_time", codecForTimestamp) .property("successor_measure", codecOptional(codecForString())) .property("rules", codecForList(codecForKycRules())) .property("custom_measures", codecForMap(codecForMeasureInformation())) @@ -2396,35 +2367,36 @@ export const codecForKycRules = (): Codec<KycRule> => .property("is_and_combinator", codecOptional(codecForBoolean())) .build("TalerExchangeApi.KycRule"); - - export const codecForAmlKycAttributes = (): Codec<KycAttributes> => buildCodecForObject<KycAttributes>() .property("details", codecForList(codecForKycAttributeCollectionEvent())) .build("TalerExchangeApi.KycAttributes"); -export const codecForKycAttributeCollectionEvent = (): Codec<KycAttributeCollectionEvent> => - buildCodecForObject<KycAttributeCollectionEvent>() - .property("rowid", codecForNumber()) - .property("provider_name", codecOptional(codecForString())) - .property("collection_time", codecForTimestamp) - .property("attributes", codecOptional(codecForAny())) - .build("TalerExchangeApi.KycAttributeCollectionEvent"); - -export const codecForAmlWalletKycCheckResponse = (): Codec<WalletKycCheckResponse> => - buildCodecForObject<WalletKycCheckResponse>() - .property("next_threshold", codecOptional(codecForAmountString())) - .property("expiration_time", codecForTimestamp) - .build("TalerExchangeApi.WalletKycCheckResponse"); - -export const codecForLegitimizationNeededResponse = (): Codec<LegitimizationNeededResponse> => - buildCodecForObject<LegitimizationNeededResponse>() - .property("code", (codecForNumber())) - .property("hint", codecOptional(codecForString())) - .property("h_payto", (codecForString())) - .property("account_pub", codecOptional(codecForString())) - .property("requirement_row", (codecForNumber())) - .build("TalerExchangeApi.LegitimizationNeededResponse"); +export const codecForKycAttributeCollectionEvent = + (): Codec<KycAttributeCollectionEvent> => + buildCodecForObject<KycAttributeCollectionEvent>() + .property("rowid", codecForNumber()) + .property("provider_name", codecOptional(codecForString())) + .property("collection_time", codecForTimestamp) + .property("attributes", codecOptional(codecForAny())) + .build("TalerExchangeApi.KycAttributeCollectionEvent"); + +export const codecForAmlWalletKycCheckResponse = + (): Codec<WalletKycCheckResponse> => + buildCodecForObject<WalletKycCheckResponse>() + .property("next_threshold", codecOptional(codecForAmountString())) + .property("expiration_time", codecForTimestamp) + .build("TalerExchangeApi.WalletKycCheckResponse"); + +export const codecForLegitimizationNeededResponse = + (): Codec<LegitimizationNeededResponse> => + buildCodecForObject<LegitimizationNeededResponse>() + .property("code", codecForNumber()) + .property("hint", codecOptional(codecForString())) + .property("h_payto", codecForString()) + .property("account_pub", codecOptional(codecForString())) + .property("requirement_row", codecForNumber()) + .build("TalerExchangeApi.LegitimizationNeededResponse"); export const codecForAccountKycStatus = (): Codec<AccountKycStatus> => buildCodecForObject<AccountKycStatus>() @@ -2435,49 +2407,61 @@ export const codecForAccountKycStatus = (): Codec<AccountKycStatus> => export const codecForAccountLimit = (): Codec<AccountLimit> => buildCodecForObject<AccountLimit>() - .property("operation_type", codecForEither( - codecForConstString("WITHDRAW"), - codecForConstString("DEPOSIT"), - codecForConstString("P2P-RECEIVE"), - codecForConstString("WALLET-BALANCE")) + .property( + "operation_type", + codecForEither( + codecForConstString("WITHDRAW"), + codecForConstString("DEPOSIT"), + codecForConstString("P2P-RECEIVE"), + codecForConstString("WALLET-BALANCE"), + ), ) .property("timeframe", codecForDuration) .property("threshold", codecForAmountString()) .property("soft_limit", codecForBoolean()) .build("TalerExchangeApi.AccountLimit"); - -export const codecForKycCheckPublicInformation = (): Codec<KycCheckPublicInformation> => - buildCodecForObject<KycCheckPublicInformation>() - .property("description", codecForString()) - .property("description_i18n", codecForInternationalizedString()) - .build("TalerExchangeApi.KycCheckPublicInformation"); +export const codecForKycCheckPublicInformation = + (): Codec<KycCheckPublicInformation> => + buildCodecForObject<KycCheckPublicInformation>() + .property("description", codecForString()) + .property("description_i18n", codecForInternationalizedString()) + .build("TalerExchangeApi.KycCheckPublicInformation"); export const codecForKycRequirementInformationId = - (): Codec<KycRequirementInformationId> => codecForString() as Codec<KycRequirementInformationId>; - -export const codecForKycRequirementInformation = (): Codec<KycRequirementInformation> => - buildCodecForObject<KycRequirementInformation>() - .property("form", codecForString()) - .property("description", codecForString()) - .property("description_i18n", codecForInternationalizedString()) - .property("id", codecOptional(codecForKycRequirementInformationId())) - .build("TalerExchangeApi.KycRequirementInformation"); - -export const codecForKycProcessClientInformation = (): Codec<KycProcessClientInformation> => - buildCodecForObject<KycProcessClientInformation>() - .property("requirements", codecForList(codecForKycRequirementInformation())) - .property("is_and_combinator", codecOptional(codecForBoolean())) - .property("voluntary_checks", codecForMap(codecForKycCheckPublicInformation())) - .build("TalerExchangeApi.KycProcessClientInformation"); + (): Codec<KycRequirementInformationId> => + codecForString() as Codec<KycRequirementInformationId>; + +export const codecForKycRequirementInformation = + (): Codec<KycRequirementInformation> => + buildCodecForObject<KycRequirementInformation>() + .property("form", codecForString()) + .property("description", codecForString()) + .property("description_i18n", codecForInternationalizedString()) + .property("id", codecOptional(codecForKycRequirementInformationId())) + .build("TalerExchangeApi.KycRequirementInformation"); + +export const codecForKycProcessClientInformation = + (): Codec<KycProcessClientInformation> => + buildCodecForObject<KycProcessClientInformation>() + .property( + "requirements", + codecForList(codecForKycRequirementInformation()), + ) + .property("is_and_combinator", codecOptional(codecForBoolean())) + .property( + "voluntary_checks", + codecForMap(codecForKycCheckPublicInformation()), + ) + .build("TalerExchangeApi.KycProcessClientInformation"); interface KycProcessStartInformation { - // URL to open. redirect_url: string; } -export const codecForKycProcessStartInformation = (): Codec<KycProcessStartInformation> => - buildCodecForObject<KycProcessStartInformation>() - .property("redirect_url", codecForURLString()) - .build("TalerExchangeApi.KycProcessStartInformation"); +export const codecForKycProcessStartInformation = + (): Codec<KycProcessStartInformation> => + buildCodecForObject<KycProcessStartInformation>() + .property("redirect_url", codecForURLString()) + .build("TalerExchangeApi.KycProcessStartInformation"); diff --git a/packages/taler-util/src/types-taler-wallet-transactions.ts b/packages/taler-util/src/types-taler-wallet-transactions.ts index da3aaca2d..0a46071ca 100644 --- a/packages/taler-util/src/types-taler-wallet-transactions.ts +++ b/packages/taler-util/src/types-taler-wallet-transactions.ts @@ -127,7 +127,6 @@ export enum TransactionMinorState { Unknown = "unknown", Deposit = "deposit", KycRequired = "kyc", - AmlRequired = "aml", MergeKycRequired = "merge-kyc", Track = "track", SubmitPayment = "submit-payment", diff --git a/packages/taler-util/src/types-taler-wallet.ts b/packages/taler-util/src/types-taler-wallet.ts index a57b355a0..f135e7882 100644 --- a/packages/taler-util/src/types-taler-wallet.ts +++ b/packages/taler-util/src/types-taler-wallet.ts @@ -1445,6 +1445,18 @@ export enum ExchangeUpdateStatus { OutdatedUpdate = "outdated-update", } +export enum ExchangeWalletKycStatus { + Done = "done", + /** + * Wallet needs to request KYC status. + */ + LegiInit = "legi-init", + /** + * User requires KYC or AML. + */ + Legi = "legi", +} + export interface OperationErrorInfo { error: TalerErrorDetail; } @@ -1466,6 +1478,9 @@ export interface ExchangeListItem { exchangeUpdateStatus: ExchangeUpdateStatus; ageRestrictionOptions: number[]; + walletKycStatus?: ExchangeWalletKycStatus; + walletKycReservePub?: string; + /** * P2P payments are disabled with this exchange * (e.g. because no global fees are configured). @@ -3583,3 +3598,34 @@ export type EmptyObject = Record<string, never>; export const codecForEmptyObject = (): Codec<EmptyObject> => buildCodecForObject<EmptyObject>().build("EmptyObject"); + +export interface TestingWaitWalletKycRequest { + exchangeBaseUrl: string; + amount: AmountString; + /** + * Do we wait for the KYC to be passed (true), + * or do we already return if legitimization is + * required (false). + */ + passed: boolean; +} + +export const codecForTestingWaitWalletKycRequest = + (): Codec<TestingWaitWalletKycRequest> => + buildCodecForObject<TestingWaitWalletKycRequest>() + .property("exchangeBaseUrl", codecForString()) + .property("amount", codecForAmountString()) + .property("passed", codecForBoolean()) + .build("TestingWaitWalletKycRequest"); + +export interface StartExchangeWalletKycRequest { + exchangeBaseUrl: string; + amount: AmountString; +} + +export const codecForStartExchangeWalletKycRequest = + (): Codec<StartExchangeWalletKycRequest> => + buildCodecForObject<StartExchangeWalletKycRequest>() + .property("exchangeBaseUrl", codecForString()) + .property("amount", codecForAmountString()) + .build("StartExchangeWalletKycRequest"); |