diff options
author | Florian Dold <florian@dold.me> | 2023-01-10 17:31:01 +0100 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2023-01-10 17:31:36 +0100 |
commit | a82d8fab696d3fca24c2f1c48a1646107e38cef8 (patch) | |
tree | cb493f6072ec4a761df214db920d709629a1eee1 /packages/taler-wallet-core/src | |
parent | 688518ec7311ea0dc68e1cce6d363a00609ef9f8 (diff) | |
download | wallet-core-a82d8fab696d3fca24c2f1c48a1646107e38cef8.tar.xz |
wallet-core: KYC mvp
Only hard withdrawal KYC is supporte so far, and no long-polling is done
yet.
Diffstat (limited to 'packages/taler-wallet-core/src')
-rw-r--r-- | packages/taler-wallet-core/src/db.ts | 7 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/operations/withdraw.ts | 73 |
2 files changed, 73 insertions, 7 deletions
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index 04fee9495..c56c3a9b5 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -1327,6 +1327,11 @@ export type WgInfo = | WgInfoBankPeerPush | WgInfoBankRecoup; + +export interface WithdrawalKycPendingInfo { + paytoHash: string; + requirementRow: number; +} /** * Group of withdrawal operations that need to be executed. * (Either for a normal withdrawal or from a tip.) @@ -1342,6 +1347,8 @@ export interface WithdrawalGroupRecord { wgInfo: WgInfo; + kycPending?: WithdrawalKycPendingInfo; + /** * Secret seed used to derive planchets. * Stored since planchets are created lazily. diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index 76bbec416..368cf3510 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -33,6 +33,7 @@ import { codecForBankWithdrawalOperationPostResponse, codecForReserveStatus, codecForTalerConfigResponse, + codecForWalletKycUuid, codecForWithdrawBatchResponse, codecForWithdrawOperationStatusResponse, codecForWithdrawResponse, @@ -75,6 +76,7 @@ import { WgInfo, WithdrawalGroupRecord, WithdrawalGroupStatus, + WithdrawalKycPendingInfo, WithdrawalRecordType, } from "../db.js"; import { @@ -530,8 +532,11 @@ async function processPlanchetExchangeRequest( const resp = await ws.http.postJson(reqUrl, reqBody); if (resp.status === HttpStatusCode.UnavailableForLegalReasons) { logger.info("withdrawal requires KYC"); + const respJson = await resp.json(); + const uuidResp = codecForWalletKycUuid().decode(respJson); + logger.info(`kyc uuid response: ${j2s(uuidResp)}`); await ws.db - .mktx((x) => [x.planchets]) + .mktx((x) => [x.planchets, x.withdrawalGroups]) .runReadWrite(async (tx) => { let planchet = await tx.planchets.indexes.byGroupAndIndex.get([ withdrawalGroup.withdrawalGroupId, @@ -541,7 +546,18 @@ async function processPlanchetExchangeRequest( return; } planchet.planchetStatus = PlanchetStatus.KycRequired; + const wg2 = await tx.withdrawalGroups.get( + withdrawalGroup.withdrawalGroupId, + ); + if (!wg2) { + return; + } + wg2.kycPending = { + paytoHash: uuidResp.h_payto, + requirementRow: uuidResp.requirement_row, + }; await tx.planchets.put(planchet); + await tx.withdrawalGroups.put(wg2); }); return; } @@ -1148,7 +1164,7 @@ export async function processWithdrawalGroup( let finishedForFirstTime = false; let errorsPerCoin: Record<number, TalerErrorDetail> = {}; - await ws.db + let res = await ws.db .mktx((x) => [x.coins, x.withdrawalGroups, x.planchets]) .runReadWrite(async (tx) => { const wg = await tx.withdrawalGroups.get(withdrawalGroupId); @@ -1177,13 +1193,56 @@ export async function processWithdrawalGroup( } await tx.withdrawalGroups.put(wg); + + return { + kycInfo: wg.kycPending, + }; }); + + if (!res) { + throw Error("withdrawal group does not exist anymore"); + } + + const { kycInfo } = res; + if (numKycRequired > 0) { - throw TalerError.fromDetail( - TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED, - {}, - `KYC check required for withdrawal (not yet implemented in wallet-core)`, - ); + if (kycInfo) { + const url = new URL( + `kyc-check/${kycInfo.requirementRow}/${kycInfo.paytoHash}/individual`, + withdrawalGroup.exchangeBaseUrl, + ); + logger.info(`kyc url ${url.href}`); + const kycStatusReq = await ws.http.fetch(url.href, { + method: "GET", + }); + logger.warn("kyc requested, but already fulfilled"); + if (kycStatusReq.status === HttpStatusCode.Ok) { + return { + type: OperationAttemptResultType.Pending, + result: undefined, + }; + } else if (kycStatusReq.status === HttpStatusCode.Accepted) { + const kycStatus = await kycStatusReq.json(); + logger.info(`kyc status: ${j2s(kycStatus)}`); + throw TalerError.fromDetail( + TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED, + { + kycUrl: kycStatus.kyc_url, + }, + `KYC check required for withdrawal`, + ); + } else { + throw Error( + `unexpected response from kyc-check (${kycStatusReq.status})`, + ); + } + } else { + throw TalerError.fromDetail( + TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED, + {}, + `KYC check required for withdrawal (not yet implemented in wallet-core)`, + ); + } } if (numFinished != numTotalCoins) { throw TalerError.fromDetail( |