gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: bank: handles 2fa response


From: gnunet
Subject: [taler-wallet-core] branch master updated: bank: handles 2fa response
Date: Wed, 10 Jan 2024 18:25:47 +0100

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new 2c7db170a bank: handles 2fa response
2c7db170a is described below

commit 2c7db170a45fcb82deae3892d610b6b2805ee46c
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Wed Jan 10 14:25:39 2024 -0300

    bank: handles 2fa response
---
 .../demobank-ui/src/pages/OperationState/views.tsx |  35 +++--
 .../src/pages/PaytoWireTransferForm.tsx            |  39 ++---
 .../demobank-ui/src/pages/RegistrationPage.tsx     | 159 ++++++++++++---------
 .../src/pages/WithdrawalConfirmationQuestion.tsx   |   7 +
 .../src/pages/account/ShowAccountDetails.tsx       |  15 ++
 .../src/pages/account/UpdateAccountPassword.tsx    |   7 +
 .../src/pages/admin/CreateNewAccount.tsx           |  18 +++
 .../demobank-ui/src/pages/admin/RemoveAccount.tsx  |   7 +
 .../src/pages/business/CreateCashout.tsx           |   8 ++
 packages/taler-harness/src/index.ts                |   6 +-
 packages/taler-util/src/http-client/bank-core.ts   |  17 ++-
 packages/taler-util/src/http-client/types.ts       |   7 +-
 packages/taler-util/src/operation.ts               |  68 ++++-----
 packages/taler-util/src/taler-error-codes.ts       |   8 ++
 14 files changed, 250 insertions(+), 151 deletions(-)

diff --git a/packages/demobank-ui/src/pages/OperationState/views.tsx 
b/packages/demobank-ui/src/pages/OperationState/views.tsx
index a02bb3bbd..98eb7169f 100644
--- a/packages/demobank-ui/src/pages/OperationState/views.tsx
+++ b/packages/demobank-ui/src/pages/OperationState/views.tsx
@@ -96,45 +96,52 @@ export function NeedConfirmationView({ error, onAbort: 
doAbort, onConfirm: doCon
   async function onConfirm() {
     errorHandler(async () => {
       if (!doConfirm) return;
-      const hasError = await doConfirm()
-      if (!hasError) {
+      const resp = await doConfirm()
+      if (!resp) {
         if (!settings.showWithdrawalSuccess) {
           notifyInfo(i18n.str`Wire transfer completed!`)
         }
         return
       }
-      switch (hasError.case) {
+      switch (resp.case) {
         case TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT: return notify({
           type: "error",
           title: i18n.str`The withdrawal has been aborted previously and can't 
be confirmed`,
-          description: hasError.detail.hint as TranslatedString,
-          debug: hasError.detail,
+          description: resp.detail.hint as TranslatedString,
+          debug: resp.detail,
         })
         case TalerErrorCode.BANK_CONFIRM_INCOMPLETE: return notify({
           type: "error",
           title: i18n.str`The withdraw operation cannot be confirmed because 
no exchange and reserve public key selection happened before`,
-          description: hasError.detail.hint as TranslatedString,
-          debug: hasError.detail,
+          description: resp.detail.hint as TranslatedString,
+          debug: resp.detail,
         })
         case HttpStatusCode.BadRequest: return notify({
           type: "error",
           title: i18n.str`The operation id is invalid.`,
-          description: hasError.detail.hint as TranslatedString,
-          debug: hasError.detail,
+          description: resp.detail.hint as TranslatedString,
+          debug: resp.detail,
         });
         case HttpStatusCode.NotFound: return notify({
           type: "error",
           title: i18n.str`The operation was not found.`,
-          description: hasError.detail.hint as TranslatedString,
-          debug: hasError.detail,
+          description: resp.detail.hint as TranslatedString,
+          debug: resp.detail,
         });
         case TalerErrorCode.BANK_UNALLOWED_DEBIT: return notify({
           type: "error",
           title: i18n.str`Your balance is not enough.`,
-          description: hasError.detail.hint as TranslatedString,
-          debug: hasError.detail,
+          description: resp.detail.hint as TranslatedString,
+          debug: resp.detail,
         });
-        default: assertUnreachable(hasError)
+        case HttpStatusCode.Accepted: {
+          resp.body.challenge_id;
+          return notify({
+            type: "info",
+            title: i18n.str`The operation needs a confirmation to complete.`,
+          });
+        }
+        default: assertUnreachable(resp)
       }
     })
   }
diff --git a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx 
b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
index 7a94f5486..2ef93d35c 100644
--- a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
+++ b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
@@ -146,50 +146,57 @@ export function PaytoWireTransferForm({
     const puri = payto_uri;
 
     await handleError(async () => {
-      const res = await api.createTransaction(credentials, {
+      const resp = await api.createTransaction(credentials, {
         payto_uri: puri,
         amount: sendingAmount,
       });
       mutate(() => true)
-      if (res.type === "fail") {
-        switch (res.case) {
+      if (resp.type === "fail") {
+        switch (resp.case) {
           case HttpStatusCode.BadRequest: return notify({
             type: "error",
             title: i18n.str`The request was invalid or the payto://-URI used 
unacceptable features.`,
-            description: res.detail.hint as TranslatedString,
-            debug: res.detail,
+            description: resp.detail.hint as TranslatedString,
+            debug: resp.detail,
           })
           case HttpStatusCode.Unauthorized: return notify({
             type: "error",
             title: i18n.str`Not enough permission to complete the operation.`,
-            description: res.detail.hint as TranslatedString,
-            debug: res.detail,
+            description: resp.detail.hint as TranslatedString,
+            debug: resp.detail,
           })
           case TalerErrorCode.BANK_UNKNOWN_CREDITOR: return notify({
             type: "error",
             title: i18n.str`The destination account "${puri}" was not found.`,
-            description: res.detail.hint as TranslatedString,
-            debug: res.detail,
+            description: resp.detail.hint as TranslatedString,
+            debug: resp.detail,
           })
           case TalerErrorCode.BANK_SAME_ACCOUNT: return notify({
             type: "error",
             title: i18n.str`The origin and the destination of the transfer 
can't be the same.`,
-            description: res.detail.hint as TranslatedString,
-            debug: res.detail,
+            description: resp.detail.hint as TranslatedString,
+            debug: resp.detail,
           })
           case TalerErrorCode.BANK_UNALLOWED_DEBIT: return notify({
             type: "error",
             title: i18n.str`Your balance is not enough.`,
-            description: res.detail.hint as TranslatedString,
-            debug: res.detail,
+            description: resp.detail.hint as TranslatedString,
+            debug: resp.detail,
           })
           case HttpStatusCode.NotFound: return notify({
             type: "error",
             title: i18n.str`The origin account "${puri}" was not found.`,
-            description: res.detail.hint as TranslatedString,
-            debug: res.detail,
+            description: resp.detail.hint as TranslatedString,
+            debug: resp.detail,
           })
-          default: assertUnreachable(res)
+          case HttpStatusCode.Accepted: {
+            resp.body.challenge_id;
+            return notify({
+              type: "info",
+              title: i18n.str`The operation needs a confirmation to complete.`,
+            });
+          }
+          default: assertUnreachable(resp)
         }
       }
       onSuccess();
diff --git a/packages/demobank-ui/src/pages/RegistrationPage.tsx 
b/packages/demobank-ui/src/pages/RegistrationPage.tsx
index 89bfbcb35..e7ed8a2b8 100644
--- a/packages/demobank-ui/src/pages/RegistrationPage.tsx
+++ b/packages/demobank-ui/src/pages/RegistrationPage.tsx
@@ -98,78 +98,101 @@ function RegistrationForm({ onComplete, onCancel }: { 
onComplete: () => void, on
 
   async function doRegistrationAndLogin(name: string, username: string, 
password: string, onComplete: () => void) {
     await handleError(async () => {
-      const creationResponse = await api.createAccount("" as AccessToken, { 
name, username, password });
-      if (creationResponse.type === "fail") {
-        switch (creationResponse.case) {
-          case HttpStatusCode.BadRequest: return notify({
-            type: "error",
-            title: i18n.str`Server replied with invalid phone or email.`,
-            description: creationResponse.detail.hint as TranslatedString,
-            debug: creationResponse.detail,
-          })
-          case TalerErrorCode.BANK_UNALLOWED_DEBIT: return notify({
-            type: "error",
-            title: i18n.str`Registration is disabled because the bank ran out 
of bonus credit.`,
-            description: creationResponse.detail.hint as TranslatedString,
-            debug: creationResponse.detail,
-          })
-          case HttpStatusCode.Unauthorized: return notify({
-            type: "error",
-            title: i18n.str`No enough permission to create that account.`,
-            description: creationResponse.detail.hint as TranslatedString,
-            debug: creationResponse.detail,
-          })
-          case TalerErrorCode.BANK_REGISTER_PAYTO_URI_REUSE: return notify({
-            type: "error",
-            title: i18n.str`That account id is already taken.`,
-            description: creationResponse.detail.hint as TranslatedString,
-            debug: creationResponse.detail,
-          })
-          case TalerErrorCode.BANK_REGISTER_USERNAME_REUSE: return notify({
-            type: "error",
-            title: i18n.str`That username is already taken.`,
-            description: creationResponse.detail.hint as TranslatedString,
-            debug: creationResponse.detail,
-          })
-          case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT: return notify({
-            type: "error",
-            title: i18n.str`That username can't be used because is reserved.`,
-            description: creationResponse.detail.hint as TranslatedString,
-            debug: creationResponse.detail,
-          })
-          case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT: return notify({
-            type: "error",
-            title: i18n.str`Only admin is allow to set debt limit.`,
-            description: creationResponse.detail.hint as TranslatedString,
-            debug: creationResponse.detail,
-          })
-          default: assertUnreachable(creationResponse)
+      createAccount: {
+        const resp = await api.createAccount("" as AccessToken, { name, 
username, password });
+        if (resp.type === "fail") {
+          switch (resp.case) {
+            case HttpStatusCode.BadRequest: return notify({
+              type: "error",
+              title: i18n.str`Server replied with invalid phone or email.`,
+              description: resp.detail.hint as TranslatedString,
+              debug: resp.detail,
+            })
+            case TalerErrorCode.BANK_UNALLOWED_DEBIT: return notify({
+              type: "error",
+              title: i18n.str`Registration is disabled because the bank ran 
out of bonus credit.`,
+              description: resp.detail.hint as TranslatedString,
+              debug: resp.detail,
+            })
+            case HttpStatusCode.Unauthorized: return notify({
+              type: "error",
+              title: i18n.str`No enough permission to create that account.`,
+              description: resp.detail.hint as TranslatedString,
+              debug: resp.detail,
+            })
+            case TalerErrorCode.BANK_REGISTER_PAYTO_URI_REUSE: return notify({
+              type: "error",
+              title: i18n.str`That account id is already taken.`,
+              description: resp.detail.hint as TranslatedString,
+              debug: resp.detail,
+            })
+            case TalerErrorCode.BANK_REGISTER_USERNAME_REUSE: return notify({
+              type: "error",
+              title: i18n.str`That username is already taken.`,
+              description: resp.detail.hint as TranslatedString,
+              debug: resp.detail,
+            })
+            case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT: return 
notify({
+              type: "error",
+              title: i18n.str`That username can't be used because is 
reserved.`,
+              description: resp.detail.hint as TranslatedString,
+              debug: resp.detail,
+            })
+            case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT: return 
notify({
+              type: "error",
+              title: i18n.str`Only admin is allow to set debt limit.`,
+              description: resp.detail.hint as TranslatedString,
+              debug: resp.detail,
+            })
+            case TalerErrorCode.BANK_MISSING_TAN_INFO: return notify({
+              type: "error",
+              title: i18n.str`No information for the selected authentication 
channel.`,
+              description: resp.detail.hint as TranslatedString,
+              debug: resp.detail,
+            })
+            case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED: return notify({
+              type: "error",
+              title: i18n.str`Authentication channel is not supported.`,
+              description: resp.detail.hint as TranslatedString,
+              debug: resp.detail,
+            })
+            case TalerErrorCode.BANK_NON_ADMIN_SET_TAN_CHANNEL: return notify({
+              type: "error",
+              title: i18n.str`Only admin can create accounts with second 
factor authentication.`,
+              description: resp.detail.hint as TranslatedString,
+              debug: resp.detail,
+            })
+            default: assertUnreachable(resp)
+          }
         }
       }
-      const resp = await 
api.getAuthenticationAPI(username).createAccessToken(password, {
-        scope: "readwrite",
-        duration: { d_us: "forever" },
-        refreshable: true,
-      })
+      login: {
+        const resp = await 
api.getAuthenticationAPI(username).createAccessToken(password, {
+          scope: "readwrite",
+          duration: { d_us: "forever" },
+          refreshable: true,
+        })
 
-      if (resp.type === "ok") {
-        backend.logIn({ username, token: resp.body.access_token });
-      } else {
-        switch (resp.case) {
-          case "wrong-credentials": return notify({
-            type: "error",
-            title: i18n.str`Wrong credentials for "${username}"`,
-            description: resp.detail.hint as TranslatedString,
-            debug: resp.detail,
-          })
-          case "not-found": return notify({
-            type: "error",
-            title: i18n.str`Account not found`,
-            description: resp.detail.hint as TranslatedString,
-            debug: resp.detail,
-          })
-          default: assertUnreachable(resp)
+        if (resp.type === "ok") {
+          backend.logIn({ username, token: resp.body.access_token });
+        } else {
+          switch (resp.case) {
+            case "wrong-credentials": return notify({
+              type: "error",
+              title: i18n.str`Wrong credentials for "${username}"`,
+              description: resp.detail.hint as TranslatedString,
+              debug: resp.detail,
+            })
+            case "not-found": return notify({
+              type: "error",
+              title: i18n.str`Account not found`,
+              description: resp.detail.hint as TranslatedString,
+              debug: resp.detail,
+            })
+            default: assertUnreachable(resp)
+          }
         }
+
       }
       onComplete()
     })
diff --git a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx 
b/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx
index ed1db854a..6f18e1283 100644
--- a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx
+++ b/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx
@@ -153,6 +153,13 @@ export function WithdrawalConfirmationQuestion({
             description: resp.detail.hint as TranslatedString,
             debug: resp.detail,
           })
+          case HttpStatusCode.Accepted: {
+            resp.body.challenge_id;
+            return notify({
+              type: "info",
+              title: i18n.str`The operation needs a confirmation to complete.`,
+            });
+          }
           default: assertUnreachable(resp)
         }
       }
diff --git a/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx 
b/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx
index 98fb72283..1bf21f62e 100644
--- a/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx
+++ b/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx
@@ -96,6 +96,21 @@ export function ShowAccountDetails({
             description: resp.detail.hint as TranslatedString,
             debug: resp.detail,
           })
+          case HttpStatusCode.Accepted: {
+            resp.body.challenge_id;
+            return notify({
+              type: "info",
+              title: i18n.str`Cashout created but confirmation is required.`,
+            });
+          }
+          case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED: {
+            return notify({
+              type: "error",
+              title: i18n.str`Authentication channel is not supported.`,
+              description: resp.detail.hint as TranslatedString,
+              debug: resp.detail,
+            });
+          }
           default: assertUnreachable(resp)
         }
       }
diff --git a/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx 
b/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx
index 95c425dc7..ed074b9c4 100644
--- a/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx
+++ b/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx
@@ -74,6 +74,13 @@ export function UpdateAccountPassword({
             type: "error",
             title: i18n.str`Your current password doesn't match, can't change 
to a new password.`
           })
+          case HttpStatusCode.Accepted: {
+            resp.body.challenge_id;
+            return notify({
+              type: "info",
+              title: i18n.str`Cashout created but confirmation is required.`,
+            });
+          }
           default: assertUnreachable(resp)
         }
       }
diff --git a/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx 
b/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx
index d6b7d5b1e..1cfbd8234 100644
--- a/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx
+++ b/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx
@@ -90,6 +90,24 @@ export function CreateNewAccount({
             description: resp.detail.hint as TranslatedString,
             debug: resp.detail,
           })
+          case TalerErrorCode.BANK_MISSING_TAN_INFO: return notify({
+            type: "error",
+            title: i18n.str`No information for the selected authentication 
channel.`,
+            description: resp.detail.hint as TranslatedString,
+            debug: resp.detail,
+          })
+          case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED: return notify({
+            type: "error",
+            title: i18n.str`Authentication channel is not supported.`,
+            description: resp.detail.hint as TranslatedString,
+            debug: resp.detail,
+          })
+          case TalerErrorCode.BANK_NON_ADMIN_SET_TAN_CHANNEL: return notify({
+            type: "error",
+            title: i18n.str`Only admin can create accounts with second factor 
authentication.`,
+            description: resp.detail.hint as TranslatedString,
+            debug: resp.detail,
+          })
           default: assertUnreachable(resp)
         }
       }
diff --git a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx 
b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
index d47f48dd9..330ebf3a9 100644
--- a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
+++ b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
@@ -89,6 +89,13 @@ export function RemoveAccount({
             description: resp.detail.hint as TranslatedString,
             debug: resp.detail,
           })
+          case HttpStatusCode.Accepted: {
+            resp.body.challenge_id;
+            return notify({
+              type: "info",
+              title: i18n.str`The operation needs a confirmation to complete.`,
+            });
+          }
           default: {
             assertUnreachable(resp)
           }
diff --git a/packages/demobank-ui/src/pages/business/CreateCashout.tsx 
b/packages/demobank-ui/src/pages/business/CreateCashout.tsx
index c3921cbd0..9ee5cbeaf 100644
--- a/packages/demobank-ui/src/pages/business/CreateCashout.tsx
+++ b/packages/demobank-ui/src/pages/business/CreateCashout.tsx
@@ -16,6 +16,7 @@
 import {
   Amounts,
   HttpStatusCode,
+  TalerCorebankApi,
   TalerError,
   TalerErrorCode,
   TranslatedString,
@@ -197,6 +198,13 @@ export function CreateCashout({
         notifyInfo(i18n.str`Cashout created`)
       } else {
         switch (resp.case) {
+          case HttpStatusCode.Accepted: {
+            resp.body.challenge_id;
+            return notify({
+              type: "info",
+              title: i18n.str`Cashout created but confirmation is required.`,
+            });
+          }
           case HttpStatusCode.NotFound: return notify({
             type: "error",
             title: i18n.str`Account not found`,
diff --git a/packages/taler-harness/src/index.ts 
b/packages/taler-harness/src/index.ts
index 7234f84d0..84d2d60f0 100644
--- a/packages/taler-harness/src/index.ts
+++ b/packages/taler-harness/src/index.ts
@@ -27,17 +27,13 @@ import {
   MerchantApiClient,
   MerchantInstanceConfig,
   RegisterAccountRequest,
-  TalerCoreBankHttpClient,
   TalerCorebankApiClient,
-  TalerError,
-  TestForApi,
   addPaytoQueryParams,
   decodeCrock,
   generateIban,
   j2s,
   rsaBlind,
-  setGlobalLogLevelFromString,
-  setPrintHttpRequestAsCurl,
+  setGlobalLogLevelFromString
 } from "@gnu-taler/taler-util";
 import { clk } from "@gnu-taler/taler-util/clk";
 import {
diff --git a/packages/taler-util/src/http-client/bank-core.ts 
b/packages/taler-util/src/http-client/bank-core.ts
index dd0948250..50cedefa9 100644
--- a/packages/taler-util/src/http-client/bank-core.ts
+++ b/packages/taler-util/src/http-client/bank-core.ts
@@ -21,6 +21,7 @@ import {
   codecForChallenge,
   codecForTalerErrorDetail,
   codecForTanTransmission,
+  opKnownAlternativeFailure,
   opKnownHttpFailure,
   opKnownTalerFailure
 } from "@gnu-taler/taler-util";
@@ -108,6 +109,9 @@ export class TalerCoreBankHttpClient {
           case TalerErrorCode.BANK_UNALLOWED_DEBIT: return 
opKnownTalerFailure(details.code, resp);
           case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT: return 
opKnownTalerFailure(details.code, resp);
           case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT: return 
opKnownTalerFailure(details.code, resp);
+          case TalerErrorCode.BANK_NON_ADMIN_SET_TAN_CHANNEL: return 
opKnownTalerFailure(details.code, resp);
+          case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED: return 
opKnownTalerFailure(details.code, resp);
+          case TalerErrorCode.BANK_MISSING_TAN_INFO: return 
opKnownTalerFailure(details.code, resp);
           default: return opUnknownFailure(resp, body)
         }
       }
@@ -127,7 +131,7 @@ export class TalerCoreBankHttpClient {
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.Accepted: return opSuccess(resp, codecForChallenge())
+      case HttpStatusCode.Accepted: return opKnownAlternativeFailure(resp, 
resp.status, codecForChallenge())
       case HttpStatusCode.NoContent: return opEmptySuccess()
       case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
       case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
@@ -158,7 +162,7 @@ export class TalerCoreBankHttpClient {
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.Accepted: return opSuccess(resp, codecForChallenge())
+      case HttpStatusCode.Accepted: return opKnownAlternativeFailure(resp, 
resp.status, codecForChallenge())
       case HttpStatusCode.NoContent: return opEmptySuccess()
       case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
       case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
@@ -170,6 +174,7 @@ export class TalerCoreBankHttpClient {
           case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT: return 
opKnownTalerFailure(details.code, resp);
           case TalerErrorCode.BANK_NON_ADMIN_PATCH_CASHOUT: return 
opKnownTalerFailure(details.code, resp);
           case TalerErrorCode.BANK_NON_ADMIN_PATCH_CONTACT: return 
opKnownTalerFailure(details.code, resp);
+          case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED: return 
opKnownTalerFailure(details.code, resp);
           default: return opUnknownFailure(resp, body)
         }
       }
@@ -191,7 +196,7 @@ export class TalerCoreBankHttpClient {
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.Accepted: return opSuccess(resp, codecForChallenge())
+      case HttpStatusCode.Accepted: return opKnownAlternativeFailure(resp, 
resp.status, codecForChallenge())
       case HttpStatusCode.NoContent: return opEmptySuccess()
       case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp);
       case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
@@ -333,7 +338,7 @@ export class TalerCoreBankHttpClient {
       body,
     });
     switch (resp.status) {
-      case HttpStatusCode.Accepted: return opSuccess(resp, codecForChallenge())
+      case HttpStatusCode.Accepted: return opKnownAlternativeFailure(resp, 
resp.status, codecForChallenge())
       case HttpStatusCode.Ok: return opSuccess(resp, 
codecForCreateTransactionResponse())
       case HttpStatusCode.BadRequest: return opKnownHttpFailure(resp.status, 
resp);
       case HttpStatusCode.Unauthorized: return opKnownHttpFailure(resp.status, 
resp);
@@ -413,7 +418,7 @@ export class TalerCoreBankHttpClient {
       },
     });
     switch (resp.status) {
-      case HttpStatusCode.Accepted: return opSuccess(resp, codecForChallenge())
+      case HttpStatusCode.Accepted: return opKnownAlternativeFailure(resp, 
resp.status, codecForChallenge())
       case HttpStatusCode.NoContent: return opEmptySuccess()
       //FIXME: missing in docs
       case HttpStatusCode.BadRequest: return opKnownHttpFailure(resp.status, 
resp)
@@ -475,7 +480,7 @@ export class TalerCoreBankHttpClient {
       body,
     });
     switch (resp.status) {
-      case HttpStatusCode.Accepted: return opSuccess(resp, codecForChallenge())
+      case HttpStatusCode.Accepted: return opKnownAlternativeFailure(resp, 
resp.status, codecForChallenge())
       case HttpStatusCode.Ok: return opSuccess(resp, codecForCashoutPending())
       case HttpStatusCode.NotFound: return opKnownHttpFailure(resp.status, 
resp)
       case HttpStatusCode.Conflict: {
diff --git a/packages/taler-util/src/http-client/types.ts 
b/packages/taler-util/src/http-client/types.ts
index f43a0a3a1..740d4204e 100644
--- a/packages/taler-util/src/http-client/types.ts
+++ b/packages/taler-util/src/http-client/types.ts
@@ -1469,8 +1469,13 @@ export namespace TalerCorebankApi {
     payto_uri?: PaytoString;
 
     // If present, set the max debit allowed for this user
-    // Only admin can change this property.
+    // Only admin can set this property.
     debit_threshold?: AmountString;
+
+    // If present, enables 2FA and set the TAN channel used for challenges
+    // Only admin can set this property, other user can reconfig their account
+    // after creation.
+    tan_channel?: TanChannel;
   }
 
   export interface ChallengeContactData {
diff --git a/packages/taler-util/src/operation.ts 
b/packages/taler-util/src/operation.ts
index 8b264d905..fd31fce39 100644
--- a/packages/taler-util/src/operation.ts
+++ b/packages/taler-util/src/operation.ts
@@ -3,23 +3,40 @@ import { Codec, HttpStatusCode, TalerError, TalerErrorCode, 
TalerErrorDetail } f
 
 export type OperationResult<Body, ErrorEnum> =
   | OperationOk<Body>
+  | OperationAlternative<ErrorEnum, Body>
   | OperationFail<ErrorEnum>;
 
-export interface OperationOk<T> {
-  type: "ok",
-  body: T;
-}
 export function isOperationOk<T, E>(c: OperationResult<T, E>): c is 
OperationOk<T> {
   return c.type === "ok"
 }
 export function isOperationFail<T, E>(c: OperationResult<T, E>): c is 
OperationFail<E> {
   return c.type === "fail"
 }
+
+/**
+ * succesful operation
+ */
+export interface OperationOk<T> {
+  type: "ok",
+  body: T;
+}
+
+/**
+ * unsuccesful operation, see details
+ */
 export interface OperationFail<T> {
   type: "fail",
   case: T,
   detail: TalerErrorDetail,
 }
+/**
+ * unsuccesful operation, see body
+ */
+export interface OperationAlternative<T, B> {
+  type: "fail",
+  case: T,
+  body: B,
+}
 
 export async function opSuccess<T>(resp: HttpResponse, codec: Codec<T>): 
Promise<OperationOk<T>> {
   const body = await readSuccessResponseJsonOrThrow(resp, codec)
@@ -31,6 +48,11 @@ export function opFixedSuccess<T>(body: T): OperationOk<T> {
 export function opEmptySuccess(): OperationOk<void> {
   return { type: "ok" as const, body: void 0 }
 }
+
+export async function opKnownAlternativeFailure<T extends HttpStatusCode, 
B>(resp: HttpResponse, s: T, codec: Codec<B>): Promise<OperationAlternative<T, 
B>> {
+  const body = await readSuccessResponseJsonOrThrow(resp, codec)
+  return { type: "fail", case: s, body }
+}
 export async function opKnownHttpFailure<T extends HttpStatusCode>(s: T, resp: 
HttpResponse): Promise<OperationFail<T>> {
   const detail = await readTalerErrorResponse(resp)
   return { type: "fail", case: s, detail }
@@ -43,6 +65,7 @@ export async function opKnownFailure<T extends string>(s: T, 
resp: HttpResponse)
   const detail = await readTalerErrorResponse(resp)
   return { type: "fail", case: s, detail }
 }
+
 export function opUnknownFailure(resp: HttpResponse, text: string): never {
   throw TalerError.fromDetail(
     TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR,
@@ -55,23 +78,6 @@ export function opUnknownFailure(resp: HttpResponse, text: 
string): never {
     `Unexpected HTTP status ${resp.status} in response`,
   );
 }
-export async function succeedOrThrow<R, E>(cb: () => 
Promise<OperationResult<R, E>>): Promise<R> {
-  const resp = await cb()
-  if (resp.type === "ok") return resp.body
-  throw TalerError.fromUncheckedDetail({ ...resp.detail, case: resp.case })
-}
-export async function failOrThrow<E>(s: E, cb: () => 
Promise<OperationResult<unknown, E>>): Promise<TalerErrorDetail> {
-  const resp = await cb()
-  if (resp.type === "ok") {
-    throw TalerError.fromException(new Error(`request succeed but failure 
"${s}" was expected`))
-  }
-  if (resp.case === s) {
-    return resp.detail
-  }
-  throw TalerError.fromException(new Error(`request failed with "${resp.case}" 
but case "${s}" was expected`))
-}
-
-
 
 export type ResultByMethod<TT extends object, p extends keyof TT> = TT[p] 
extends (...args: any[]) => infer Ret ?
   Ret extends Promise<infer Result> ?
@@ -81,23 +87,3 @@ export type ResultByMethod<TT extends object, p extends 
keyof TT> = TT[p] extend
 
 export type FailCasesByMethod<TT extends object, p extends keyof TT> = 
Exclude<ResultByMethod<TT, p>, OperationOk<any>>
 
-type MethodsOfOperations<T extends object> = keyof {
-  [P in keyof T as
-  //when the property is a function
-  T[P] extends (...args: any[]) => infer Ret ?
-  // that returns a promise
-  Ret extends Promise<infer Result> ?
-  // of an operation
-  Result extends OperationResult<any, any> ?
-  P : never
-  : never
-  : never]: any
-}
-
-type AllKnownCases<t extends object, d extends keyof t> = "success" | 
FailCasesByMethod<t, d>["case"]
-
-export type TestForApi<ApiType extends object> = {
-  [OpType in MethodsOfOperations<ApiType> as `test_${OpType & string}`]: {
-    [c in AllKnownCases<ApiType, OpType>]: undefined | (() => Promise<void>);
-  };
-};
diff --git a/packages/taler-util/src/taler-error-codes.ts 
b/packages/taler-util/src/taler-error-codes.ts
index 2361b6d73..9dd965d1b 100644
--- a/packages/taler-util/src/taler-error-codes.ts
+++ b/packages/taler-util/src/taler-error-codes.ts
@@ -3512,6 +3512,14 @@ export enum TalerErrorCode {
   BANK_TAN_CHALLENGE_EXPIRED = 5144,
 
 
+  /**
+   * A non-admin user has tried to create an account with 2fa.
+   * Returned with an HTTP status code of #MHD_HTTP_CONFLICT (409).
+   * (A value of 0 indicates that the error is generated client-side).
+   */
+  BANK_NON_ADMIN_SET_TAN_CHANNEL = 5145,
+
+
   /**
    * The sync service failed find the account in its database.
    * Returned with an HTTP status code of #MHD_HTTP_NOT_FOUND (404).

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]