diff options
-rw-r--r-- | packages/demobank-ui/src/pages/OperationState/views.tsx | 6 | ||||
-rw-r--r-- | packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx | 7 | ||||
-rw-r--r-- | packages/demobank-ui/src/pages/WalletWithdrawForm.tsx | 11 | ||||
-rw-r--r-- | packages/taler-harness/src/http-client/bank-core.ts | 1006 | ||||
-rw-r--r-- | packages/taler-util/src/http-client/bank-core.ts | 2 | ||||
-rw-r--r-- | packages/taler-util/src/operation.ts | 2 |
6 files changed, 534 insertions, 500 deletions
diff --git a/packages/demobank-ui/src/pages/OperationState/views.tsx b/packages/demobank-ui/src/pages/OperationState/views.tsx index 4001fd093..ea38525b9 100644 --- a/packages/demobank-ui/src/pages/OperationState/views.tsx +++ b/packages/demobank-ui/src/pages/OperationState/views.tsx @@ -338,6 +338,12 @@ export function FailedView({ error }: State.Failed) { {error.detail.hint} </div> </Attention> + case "account-not-found": return <Attention type="danger" + title={i18n.str`The operation was rejected due to insufficient funds.`}> + <div class="mt-2 text-sm text-red-700"> + {error.detail.hint} + </div> + </Attention> default: assertUnreachable(error) } } diff --git a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx index 6649d224e..97e38d75e 100644 --- a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx +++ b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx @@ -122,6 +122,7 @@ export function PaytoWireTransferForm({ async function doSend() { let payto_uri: PaytoString | undefined; let sendingAmount: AmountString | undefined; + if (credentials.status !== "loggedIn") return; if (rawPaytoInput) { const p = parsePaytoUri(rawPaytoInput) @@ -159,6 +160,12 @@ export function PaytoWireTransferForm({ description: res.detail.hint as TranslatedString, debug: res.detail, }) + case "account-not-found": return notify({ + type: "error", + title: i18n.str`The destination account "${puri}" was not found.`, + description: res.detail.hint as TranslatedString, + debug: res.detail, + }) default: assertUnreachable(res) } } diff --git a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx index abdebf9bf..e3a713fdd 100644 --- a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx +++ b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx @@ -121,6 +121,15 @@ function OldWithdrawalForm({ goToConfirmOperation, limit, onCancel, focus }: { }) break; } + case "account-not-found": { + notify({ + type: "error", + title: i18n.str`Account not found`, + description: resp.detail.hint as TranslatedString, + debug: resp.detail, + }) + break; + } default: assertUnreachable(resp) } } @@ -135,7 +144,7 @@ function OldWithdrawalForm({ goToConfirmOperation, limit, onCancel, focus }: { e.preventDefault() }} > - <ShowLocalNotification notification={notification} /> + <ShowLocalNotification notification={notification} /> <div class="px-4 py-6 "> <div class="grid max-w-xs grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6"> diff --git a/packages/taler-harness/src/http-client/bank-core.ts b/packages/taler-harness/src/http-client/bank-core.ts index 25e67b031..6f9641dc9 100644 --- a/packages/taler-harness/src/http-client/bank-core.ts +++ b/packages/taler-harness/src/http-client/bank-core.ts @@ -1,530 +1,540 @@ -import { AccessToken, Amounts, TalerCoreBankHttpClient, TalerCorebankApi, encodeCrock, failOrThrow, getRandomBytes, parsePaytoUri, stringifyPaytoUri, succeedOrThrow } from "@gnu-taler/taler-util" +import { AccessToken, Amounts, TalerCoreBankHttpClient, TalerCorebankApi, buildPayto, encodeCrock, failOrThrow, getRandomBytes, parsePaytoUri, stringifyPaytoUri, succeedOrThrow } from "@gnu-taler/taler-util" export class BankCoreSmokeTest { - constructor(readonly api:TalerCoreBankHttpClient) { + constructor(readonly api: TalerCoreBankHttpClient) { } -async testConfig() { - const config = await this.api.getConfig() - if (!this.api.isCompatible(config.body.version)) { - throw Error(`not compatible with server ${config.body.version}`) + async testConfig() { + const config = await this.api.getConfig() + if (!this.api.isCompatible(config.body.version)) { + throw Error(`not compatible with server ${config.body.version}`) + } + return config.body } - return config.body -} - -async testCashouts(adminPassword: string) { -} -async testMonitor(adminPassword: string) { - const { access_token: adminToken } = await succeedOrThrow(() => - this.api.getAuthenticationAPI("admin").createAccessToken(adminPassword, { - scope: "readwrite" - }) - ) - - await succeedOrThrow(() => ( - this.api.getMonitor() - )) - - await succeedOrThrow(() => ( - this.api.getMonitor({ - timeframe: TalerCorebankApi.MonitorTimeframeParam.day, - which: (new Date()).getDate() -1 - }) - )) -} - -async testAccountManagement(adminPassword: string) { - - const { access_token: adminToken } = await succeedOrThrow(() => - this.api.getAuthenticationAPI("admin").createAccessToken(adminPassword, { - scope: "readwrite" - }) - ) - - /** - * Create account - */ - { - const username = "harness-" + encodeCrock(getRandomBytes(10)).toLowerCase(); - - // await failOrThrow("invalid-input",() => - // this.api.createAccount(adminToken, { - // name: username, - // username, password: "123", - // challenge_contact_data: { - // email: "invalid email", - // phone: "invalid phone", - // } - // }) - // ) - - // await failOrThrow("unable-to-create",() => - // this.api.createAccount(adminToken, { - // name: "admin", - // username, password: "123" - // }) - // ) - - // await failOrThrow("unable-to-create",() => - // this.api.createAccount(adminToken, { - // name: "bank", - // username, password: "123" - // }) - // ) - - await succeedOrThrow(() => - this.api.createAccount(adminToken, { - name: username, - username, password: "123" - }) - ) - - await failOrThrow("already-exist", () => - this.api.createAccount(adminToken, { - name: username, - username, password: "123" - }) - ); - } - - /** - * Delete account - */ - { - const { username, token } = await createRandomTestUser(this.api, adminToken) - - await failOrThrow("not-found", () => - this.api.deleteAccount({ username: "not-found", token: adminToken }) - ) - await failOrThrow("unable-to-delete", () => - this.api.deleteAccount({ username: "admin", token: adminToken }) - ) - await failOrThrow("unable-to-delete", () => - this.api.deleteAccount({ username: "bank", token: adminToken }) - ) - - await failOrThrow("balance-not-zero", () => - this.api.deleteAccount({ username, token: adminToken }) - ) - - const userInfo = await succeedOrThrow(() => - this.api.getAccount({ username, token }) - ) - - const adminInfo = await succeedOrThrow(() => - this.api.getAccount({ username: "admin", token: adminToken }) - ) - - const adminAccount = parsePaytoUri(adminInfo.payto_uri)! - adminAccount.params["message"] = "all my money" - const withSubject = stringifyPaytoUri(adminAccount) - - await succeedOrThrow(() => - this.api.createTransaction({ username, token }, { - payto_uri: withSubject, - amount: userInfo.balance.amount - }) - ) - - - const otherUsername = "harness-" + encodeCrock(getRandomBytes(10)).toLowerCase(); - - await succeedOrThrow(() => - this.api.createAccount(adminToken, { - name: otherUsername, - username: otherUsername, password: "123" - }) - ) - - await failOrThrow("unauthorized", () => - this.api.deleteAccount({ username: otherUsername, token }) - ) - - await succeedOrThrow(() => - this.api.deleteAccount({ username, token: adminToken }) - ) - } - - /** - * Update account - */ - { - const { username, token } = await createRandomTestUser(this.api, adminToken) - - await failOrThrow("cant-change-legal-name-or-admin", () => - this.api.updateAccount({ username, token }, { - name: "something else", - }) - ) - - // await failOrThrow("not-found", () => - // this.api.updateAccount({ username: "notfound", token }, { - // challenge_contact_data: { - // email: "asd@Aasd.com" - // } - // }) - // ) - - await failOrThrow("unauthorized", () => - this.api.updateAccount({ username: "notfound", token: "wrongtoken" as AccessToken }, { - challenge_contact_data: { - email: "asd@Aasd.com" - } - }) - ) - - await succeedOrThrow(() => - this.api.updateAccount({ username, token }, { - challenge_contact_data: { - email: "asd@Aasd.com" - } - }) - ) - } - - /** - * Update password - */ - { - const { username, token } = await createRandomTestUser(this.api, adminToken) - - await succeedOrThrow(() => - this.api.updatePassword({ username, token }, { - old_password: "123", - new_password: "234" - }) - ) - // await failOrThrow("not-found",() => - // this.api.updatePassword({ username:"notfound", token: userTempToken }, { - // old_password: "123", - // new_password: "234" - // }) - // ) - await failOrThrow("unauthorized", () => - this.api.updatePassword({ username: "admin", token }, { - old_password: "123", - new_password: "234" - }) - ) - // await failOrThrow("old-password-invalid-or-not-allowed",() => - // this.api.updatePassword({ username, token: userTempToken }, { - // old_password: "123", - // new_password: "234" - // }) - // ) - - } - - /** - * public accounts - */ - { - const acs = await succeedOrThrow(() => this.api.getPublicAccounts()) - - } - /** - * get accounts - */ - { - const { username, token } = await createRandomTestUser(this.api, adminToken) - // await failOrThrow("no-rights",() => - // this.api.getAccounts(token) - // ) - await failOrThrow("unauthorized", () => - this.api.getAccounts("ASDASD" as AccessToken) - ) - - const acs = await succeedOrThrow(() => - this.api.getAccounts(adminToken) - ) - } - -} - -async testWithdrawals(adminPassword: string) { - const { access_token: adminToken } = await succeedOrThrow(() => - this.api.getAuthenticationAPI("admin").createAccessToken(adminPassword, { - scope: "readwrite" - }) - ) - /** - * create withdrawals - */ - { - const { username, token } = await createRandomTestUser(this.api, adminToken) - - const userInfo = await succeedOrThrow(() => - this.api.getAccount({ username, token }) - ) - - const balance = Amounts.parseOrThrow(userInfo.balance.amount) - const moreThanBalance = Amounts.stringify(Amounts.mult(balance, 5).amount) - await failOrThrow("insufficient-funds", () => - this.api.createWithdrawal({ username, token }, { - amount: moreThanBalance - }) - ) - - await failOrThrow("unauthorized", () => - this.api.createWithdrawal({ username, token: "wrongtoken" as AccessToken }, { - amount: userInfo.balance.amount - }) - ) - await succeedOrThrow(() => - this.api.createWithdrawal({ username, token }, { - amount: userInfo.balance.amount - }) - ) + async testCashouts(adminPassword: string) { } - - /** - * get withdrawal - */ - { - const { username, token } = await createRandomTestUser(this.api, adminToken) - - const userInfo = await succeedOrThrow(() => - this.api.getAccount({ username, token }) - ) - - const { withdrawal_id } = await succeedOrThrow(() => - this.api.createWithdrawal({ username, token }, { - amount: userInfo.balance.amount + async testMonitor(adminPassword: string) { + const { access_token: adminToken } = await succeedOrThrow(() => + this.api.getAuthenticationAPI("admin").createAccessToken(adminPassword, { + scope: "readwrite" }) ) - await succeedOrThrow(() => - this.api.getWithdrawalById(withdrawal_id) - ) - - await failOrThrow("invalid-id", () => - this.api.getWithdrawalById("invalid") - ) - await failOrThrow("not-found", () => - this.api.getWithdrawalById("11111111-1111-1111-1111-111111111111") - ) - } - - /** - * abort withdrawal - */ - { - const { username:exchangeUser, token: exchangeToken } = await createRandomTestUser(this.api, adminToken, {is_taler_exchange: true}) - const { username, token } = await createRandomTestUser(this.api, adminToken) + await succeedOrThrow(() => ( + this.api.getMonitor() + )) - const userInfo = await succeedOrThrow(() => - this.api.getAccount({ username, token }) - ) - const exchangeInfo = await succeedOrThrow(() => - this.api.getAccount({ username:exchangeUser, token:exchangeToken }) - ) - - await failOrThrow("invalid-id", () => - this.api.abortWithdrawalById("invalid") - ) - await failOrThrow("not-found", () => - this.api.abortWithdrawalById("11111111-1111-1111-1111-111111111111") - ) - - const { withdrawal_id:firstWithdrawal } = await succeedOrThrow(() => - this.api.createWithdrawal({ username, token }, { - amount: userInfo.balance.amount - }) - ) - - await succeedOrThrow(() => - this.api.abortWithdrawalById(firstWithdrawal) - ) - - const { taler_withdraw_uri: uri, withdrawal_id:secondWithdrawal } = await succeedOrThrow(() => - this.api.createWithdrawal({ username, token }, { - amount: userInfo.balance.amount + await succeedOrThrow(() => ( + this.api.getMonitor({ + timeframe: TalerCorebankApi.MonitorTimeframeParam.day, + which: (new Date()).getDate() - 1 }) - ) - - await succeedOrThrow(() => - this.api.getIntegrationAPI().completeWithdrawalOperationById(secondWithdrawal, { - reserve_pub: encodeCrock(getRandomBytes(32)), - selected_exchange: exchangeInfo.payto_uri, - }) - ) - await succeedOrThrow(() => - this.api.confirmWithdrawalById(secondWithdrawal) - ) - await failOrThrow("previously-confirmed", () => - this.api.abortWithdrawalById(secondWithdrawal) - ) + )) } - /** - * confirm withdrawal - */ - { - const { username:exchangeUser, token: exchangeToken } = await createRandomTestUser(this.api, adminToken, {is_taler_exchange: true}) - const { username, token } = await createRandomTestUser(this.api, adminToken) - - const userInfo = await succeedOrThrow(() => - this.api.getAccount({ username, token }) - ) - const exchangeInfo = await succeedOrThrow(() => - this.api.getAccount({ username:exchangeUser, token:exchangeToken }) - ) - - await failOrThrow("invalid-id", () => - this.api.confirmWithdrawalById("invalid") - ) - await failOrThrow("not-found", () => - this.api.confirmWithdrawalById("11111111-1111-1111-1111-111111111111") - ) - - const { withdrawal_id:firstWithdrawal } = await succeedOrThrow(() => - this.api.createWithdrawal({ username, token }, { - amount: userInfo.balance.amount - }) - ) - - await failOrThrow("no-exchange-or-reserve-selected", () => - this.api.confirmWithdrawalById(firstWithdrawal) - ) - - await succeedOrThrow(() => - this.api.getIntegrationAPI().completeWithdrawalOperationById(firstWithdrawal, { - reserve_pub: encodeCrock(getRandomBytes(32)), - selected_exchange: exchangeInfo.payto_uri, - }) - ) - - await succeedOrThrow(() => - this.api.confirmWithdrawalById(firstWithdrawal) - ) + async testAccountManagement(adminPassword: string) { - const { withdrawal_id:secondWithdrawal } = await succeedOrThrow(() => - this.api.createWithdrawal({ username, token }, { - amount: userInfo.balance.amount + const { access_token: adminToken } = await succeedOrThrow(() => + this.api.getAuthenticationAPI("admin").createAccessToken(adminPassword, { + scope: "readwrite" }) ) - await succeedOrThrow(() => - this.api.abortWithdrawalById(secondWithdrawal) - ) - await failOrThrow("previously-aborted", () => - this.api.confirmWithdrawalById(secondWithdrawal) - ) - } -} + /** + * Create account + */ + { + const username = "harness-" + encodeCrock(getRandomBytes(10)).toLowerCase(); + + // await failOrThrow("invalid-input",() => + // this.api.createAccount(adminToken, { + // name: username, + // username, password: "123", + // challenge_contact_data: { + // email: "invalid email", + // phone: "invalid phone", + // } + // }) + // ) + + // await failOrThrow("unable-to-create",() => + // this.api.createAccount(adminToken, { + // name: "admin", + // username, password: "123" + // }) + // ) + + // await failOrThrow("unable-to-create",() => + // this.api.createAccount(adminToken, { + // name: "bank", + // username, password: "123" + // }) + // ) + + await succeedOrThrow(() => + this.api.createAccount(adminToken, { + name: username, + username, password: "123" + }) + ) + + await failOrThrow("already-exist", () => + this.api.createAccount(adminToken, { + name: username, + username, password: "123" + }) + ); + } + + /** + * Delete account + */ + { + const { username, token } = await createRandomTestUser(this.api, adminToken) + + await failOrThrow("not-found", () => + this.api.deleteAccount({ username: "not-found", token: adminToken }) + ) + await failOrThrow("unable-to-delete", () => + this.api.deleteAccount({ username: "admin", token: adminToken }) + ) + await failOrThrow("unable-to-delete", () => + this.api.deleteAccount({ username: "bank", token: adminToken }) + ) + + await failOrThrow("balance-not-zero", () => + this.api.deleteAccount({ username, token: adminToken }) + ) + + const userInfo = await succeedOrThrow(() => + this.api.getAccount({ username, token }) + ) + + const adminInfo = await succeedOrThrow(() => + this.api.getAccount({ username: "admin", token: adminToken }) + ) + + const adminAccount = parsePaytoUri(adminInfo.payto_uri)! + adminAccount.params["message"] = "all my money" + const withSubject = stringifyPaytoUri(adminAccount) + + await succeedOrThrow(() => + this.api.createTransaction({ username, token }, { + payto_uri: withSubject, + amount: userInfo.balance.amount + }) + ) + + + const otherUsername = "harness-" + encodeCrock(getRandomBytes(10)).toLowerCase(); + + await succeedOrThrow(() => + this.api.createAccount(adminToken, { + name: otherUsername, + username: otherUsername, password: "123" + }) + ) + + await failOrThrow("unauthorized", () => + this.api.deleteAccount({ username: otherUsername, token }) + ) + + await succeedOrThrow(() => + this.api.deleteAccount({ username, token: adminToken }) + ) + } + + /** + * Update account + */ + { + const { username, token } = await createRandomTestUser(this.api, adminToken) + + await failOrThrow("cant-change-legal-name-or-admin", () => + this.api.updateAccount({ username, token }, { + name: "something else", + }) + ) + + // await failOrThrow("not-found", () => + // this.api.updateAccount({ username: "notfound", token }, { + // challenge_contact_data: { + // email: "asd@Aasd.com" + // } + // }) + // ) + + await failOrThrow("unauthorized", () => + this.api.updateAccount({ username: "notfound", token: "wrongtoken" as AccessToken }, { + challenge_contact_data: { + email: "asd@Aasd.com" + } + }) + ) + + await succeedOrThrow(() => + this.api.updateAccount({ username, token }, { + challenge_contact_data: { + email: "asd@Aasd.com" + } + }) + ) + } + + /** + * Update password + */ + { + const { username, token } = await createRandomTestUser(this.api, adminToken) + + await succeedOrThrow(() => + this.api.updatePassword({ username, token }, { + old_password: "123", + new_password: "234" + }) + ) + // await failOrThrow("not-found",() => + // this.api.updatePassword({ username:"notfound", token: userTempToken }, { + // old_password: "123", + // new_password: "234" + // }) + // ) + await failOrThrow("unauthorized", () => + this.api.updatePassword({ username: "admin", token }, { + old_password: "123", + new_password: "234" + }) + ) + // await failOrThrow("old-password-invalid-or-not-allowed",() => + // this.api.updatePassword({ username, token: userTempToken }, { + // old_password: "123", + // new_password: "234" + // }) + // ) + + } + + /** + * public accounts + */ + { + const acs = await succeedOrThrow(() => this.api.getPublicAccounts()) + + } + /** + * get accounts + */ + { + const { username, token } = await createRandomTestUser(this.api, adminToken) + // await failOrThrow("no-rights",() => + // this.api.getAccounts(token) + // ) + await failOrThrow("unauthorized", () => + this.api.getAccounts("ASDASD" as AccessToken) + ) + + const acs = await succeedOrThrow(() => + this.api.getAccounts(adminToken) + ) + } -async testTransactions(adminPassword: string) { - const { access_token: adminToken } = await succeedOrThrow(() => - this.api.getAuthenticationAPI("admin").createAccessToken(adminPassword, { - scope: "readwrite" - }) - ) - // get transactions - { - const { username, token } = await createRandomTestUser(this.api, adminToken) - // await succeedOrThrow(() => this.api.getTransactions(creds)) - const txs = await succeedOrThrow(() => this.api.getTransactions({ username, token }, { - limit: 5, - order: "asc" - })) - // await failOrThrow("not-found",() => this.api.getTransactions({ - // username:"not-found", - // token: creds.token, - // })) - await failOrThrow("unauthorized", () => this.api.getTransactions({ - username: username, - token: "wrongtoken" as AccessToken, - })) } - /** - * getTxby id - */ - { - const { username, token } = await createRandomTestUser(this.api, adminToken) - const { username: otherUser, token: otherToken } = await createRandomTestUser(this.api, adminToken) - - const userInfo = await succeedOrThrow(() => - this.api.getAccount({ username, token }) - ) - const otherInfo = await succeedOrThrow(() => - this.api.getAccount({ username: otherUser, token: otherToken }) - ) - const otherAccount = parsePaytoUri(otherInfo.payto_uri)! - otherAccount.params["message"] = "all" - - await succeedOrThrow(() => - this.api.createTransaction({ username, token }, { - payto_uri: stringifyPaytoUri(otherAccount), - amount: userInfo.balance.amount + async testWithdrawals(adminPassword: string) { + const { access_token: adminToken } = await succeedOrThrow(() => + this.api.getAuthenticationAPI("admin").createAccessToken(adminPassword, { + scope: "readwrite" }) ) - - const txs = await succeedOrThrow(() => this.api.getTransactions({ username, token }, { - limit: 5, - order: "asc" - })) - const rowId = txs.transactions[0].row_id - - await succeedOrThrow(() => - this.api.getTransactionById({ username, token }, rowId) - ) - - await failOrThrow("not-found", () => - this.api.getTransactionById({ username, token }, 123123123) - ) - - await failOrThrow("unauthorized", () => - this.api.getTransactionById({ username, token: "wrongtoken" as AccessToken }, 123123123) - ) + /** + * create withdrawals + */ + { + const { username, token } = await createRandomTestUser(this.api, adminToken) + + const userInfo = await succeedOrThrow(() => + this.api.getAccount({ username, token }) + ) + + const balance = Amounts.parseOrThrow(userInfo.balance.amount) + const moreThanBalance = Amounts.stringify(Amounts.mult(balance, 5).amount) + await failOrThrow("insufficient-funds", () => + this.api.createWithdrawal({ username, token }, { + amount: moreThanBalance + }) + ) + + await failOrThrow("unauthorized", () => + this.api.createWithdrawal({ username, token: "wrongtoken" as AccessToken }, { + amount: userInfo.balance.amount + }) + ) + + await succeedOrThrow(() => + this.api.createWithdrawal({ username, token }, { + amount: userInfo.balance.amount + }) + ) + } + + /** + * get withdrawal + */ + { + const { username, token } = await createRandomTestUser(this.api, adminToken) + + const userInfo = await succeedOrThrow(() => + this.api.getAccount({ username, token }) + ) + + const { withdrawal_id } = await succeedOrThrow(() => + this.api.createWithdrawal({ username, token }, { + amount: userInfo.balance.amount + }) + ) + + await succeedOrThrow(() => + this.api.getWithdrawalById(withdrawal_id) + ) + + await failOrThrow("invalid-id", () => + this.api.getWithdrawalById("invalid") + ) + await failOrThrow("not-found", () => + this.api.getWithdrawalById("11111111-1111-1111-1111-111111111111") + ) + } + + /** + * abort withdrawal + */ + { + const { username: exchangeUser, token: exchangeToken } = await createRandomTestUser(this.api, adminToken, { is_taler_exchange: true }) + const { username, token } = await createRandomTestUser(this.api, adminToken) + + const userInfo = await succeedOrThrow(() => + this.api.getAccount({ username, token }) + ) + const exchangeInfo = await succeedOrThrow(() => + this.api.getAccount({ username: exchangeUser, token: exchangeToken }) + ) + + await failOrThrow("invalid-id", () => + this.api.abortWithdrawalById("invalid") + ) + await failOrThrow("not-found", () => + this.api.abortWithdrawalById("11111111-1111-1111-1111-111111111111") + ) + + const { withdrawal_id: firstWithdrawal } = await succeedOrThrow(() => + this.api.createWithdrawal({ username, token }, { + amount: userInfo.balance.amount + }) + ) + + await succeedOrThrow(() => + this.api.abortWithdrawalById(firstWithdrawal) + ) + + const { taler_withdraw_uri: uri, withdrawal_id: secondWithdrawal } = await succeedOrThrow(() => + this.api.createWithdrawal({ username, token }, { + amount: userInfo.balance.amount + }) + ) + + await succeedOrThrow(() => + this.api.getIntegrationAPI().completeWithdrawalOperationById(secondWithdrawal, { + reserve_pub: encodeCrock(getRandomBytes(32)), + selected_exchange: exchangeInfo.payto_uri, + }) + ) + await succeedOrThrow(() => + this.api.confirmWithdrawalById(secondWithdrawal) + ) + await failOrThrow("previously-confirmed", () => + this.api.abortWithdrawalById(secondWithdrawal) + ) + } + + /** + * confirm withdrawal + */ + { + const { username: exchangeUser, token: exchangeToken } = await createRandomTestUser(this.api, adminToken, { is_taler_exchange: true }) + const { username, token } = await createRandomTestUser(this.api, adminToken) + + const userInfo = await succeedOrThrow(() => + this.api.getAccount({ username, token }) + ) + const exchangeInfo = await succeedOrThrow(() => + this.api.getAccount({ username: exchangeUser, token: exchangeToken }) + ) + + await failOrThrow("invalid-id", () => + this.api.confirmWithdrawalById("invalid") + ) + await failOrThrow("not-found", () => + this.api.confirmWithdrawalById("11111111-1111-1111-1111-111111111111") + ) + + const { withdrawal_id: firstWithdrawal } = await succeedOrThrow(() => + this.api.createWithdrawal({ username, token }, { + amount: userInfo.balance.amount + }) + ) + + await failOrThrow("no-exchange-or-reserve-selected", () => + this.api.confirmWithdrawalById(firstWithdrawal) + ) + + await succeedOrThrow(() => + this.api.getIntegrationAPI().completeWithdrawalOperationById(firstWithdrawal, { + reserve_pub: encodeCrock(getRandomBytes(32)), + selected_exchange: exchangeInfo.payto_uri, + }) + ) + + await succeedOrThrow(() => + this.api.confirmWithdrawalById(firstWithdrawal) + ) + + const { withdrawal_id: secondWithdrawal } = await succeedOrThrow(() => + this.api.createWithdrawal({ username, token }, { + amount: userInfo.balance.amount + }) + ) + + await succeedOrThrow(() => + this.api.abortWithdrawalById(secondWithdrawal) + ) + //FIXME: skip + // await failOrThrow("previously-aborted", () => + // this.api.confirmWithdrawalById(secondWithdrawal) + // ) + } } - /** - * create transactions - */ - { - const { username, token } = await createRandomTestUser(this.api, adminToken) - const { username: otherUser, token: otherToken } = await createRandomTestUser(this.api, adminToken) - - const userInfo = await succeedOrThrow(() => - this.api.getAccount({ username, token }) - ) - const otherInfo = await succeedOrThrow(() => - this.api.getAccount({ username: otherUser, token: otherToken }) - ) - const otherAccount = parsePaytoUri(otherInfo.payto_uri)! - otherAccount.params["message"] = "all" - - await succeedOrThrow(() => - this.api.createTransaction({ username, token }, { - payto_uri: stringifyPaytoUri(otherAccount), - amount: userInfo.balance.amount - }) - ) - //missing amount - await failOrThrow("invalid-input", () => - this.api.createTransaction({ username, token }, { - payto_uri: stringifyPaytoUri(otherAccount), - // amount: userInfo.balance.amount - }) - ) - //missing subject - await failOrThrow("invalid-input", () => - this.api.createTransaction({ username, token }, { - payto_uri: otherInfo.payto_uri, - amount: userInfo.balance.amount - }) - ) - await failOrThrow("unauthorized", () => - this.api.createTransaction({ username, token: "wrongtoken" as AccessToken }, { - payto_uri: otherInfo.payto_uri, - amount: userInfo.balance.amount + async testTransactions(adminPassword: string) { + const { access_token: adminToken } = await succeedOrThrow(() => + this.api.getAuthenticationAPI("admin").createAccessToken(adminPassword, { + scope: "readwrite" }) ) + // get transactions + { + const { username, token } = await createRandomTestUser(this.api, adminToken) + // await succeedOrThrow(() => this.api.getTransactions(creds)) + const txs = await succeedOrThrow(() => this.api.getTransactions({ username, token }, { + limit: 5, + order: "asc" + })) + // await failOrThrow("not-found",() => this.api.getTransactions({ + // username:"not-found", + // token: creds.token, + // })) + await failOrThrow("unauthorized", () => this.api.getTransactions({ + username: username, + token: "wrongtoken" as AccessToken, + })) + } + + /** + * getTxby id + */ + { + const { username, token } = await createRandomTestUser(this.api, adminToken) + const { username: otherUser, token: otherToken } = await createRandomTestUser(this.api, adminToken) + + const userInfo = await succeedOrThrow(() => + this.api.getAccount({ username, token }) + ) + const otherInfo = await succeedOrThrow(() => + this.api.getAccount({ username: otherUser, token: otherToken }) + ) + const otherAccount = parsePaytoUri(otherInfo.payto_uri)! + otherAccount.params["message"] = "all" + + await succeedOrThrow(() => + this.api.createTransaction({ username, token }, { + payto_uri: stringifyPaytoUri(otherAccount), + amount: userInfo.balance.amount + }) + ) + + const txs = await succeedOrThrow(() => this.api.getTransactions({ username, token }, { + limit: 5, + order: "asc" + })) + const rowId = txs.transactions[0].row_id + + await succeedOrThrow(() => + this.api.getTransactionById({ username, token }, rowId) + ) + + await failOrThrow("not-found", () => + this.api.getTransactionById({ username, token }, 123123123) + ) + + await failOrThrow("unauthorized", () => + this.api.getTransactionById({ username, token: "wrongtoken" as AccessToken }, 123123123) + ) + } + + /** + * create transactions + */ + { + const { username, token } = await createRandomTestUser(this.api, adminToken) + const { username: otherUser, token: otherToken } = await createRandomTestUser(this.api, adminToken) + + const userInfo = await succeedOrThrow(() => + this.api.getAccount({ username, token }) + ) + const otherInfo = await succeedOrThrow(() => + this.api.getAccount({ username: otherUser, token: otherToken }) + ) + const otherAccount = parsePaytoUri(otherInfo.payto_uri)! + otherAccount.params["message"] = "all" + + await succeedOrThrow(() => + this.api.createTransaction({ username, token }, { + payto_uri: stringifyPaytoUri(otherAccount), + amount: userInfo.balance.amount + }) + ) + //missing amount + await failOrThrow("invalid-input", () => + this.api.createTransaction({ username, token }, { + payto_uri: stringifyPaytoUri(otherAccount), + // amount: userInfo.balance.amount + }) + ) + //missing subject + await failOrThrow("invalid-input", () => + this.api.createTransaction({ username, token }, { + payto_uri: otherInfo.payto_uri, + amount: userInfo.balance.amount + }) + ) + await failOrThrow("unauthorized", () => + this.api.createTransaction({ username, token: "wrongtoken" as AccessToken }, { + payto_uri: otherInfo.payto_uri, + amount: userInfo.balance.amount + }) + ) + + const notFoundAccount = buildPayto("iban", "DE1231231231", undefined) + notFoundAccount.params["message"] = "not-found" + await failOrThrow("account-not-found", () => + this.api.createTransaction({ username, token }, { + payto_uri: stringifyPaytoUri(notFoundAccount), + amount: userInfo.balance.amount + }) + ) + } } -} } diff --git a/packages/taler-util/src/http-client/bank-core.ts b/packages/taler-util/src/http-client/bank-core.ts index e214f6dcd..35f216220 100644 --- a/packages/taler-util/src/http-client/bank-core.ts +++ b/packages/taler-util/src/http-client/bank-core.ts @@ -316,6 +316,7 @@ export class TalerCoreBankHttpClient { //FIXME: remove this after server has been updated case HttpStatusCode.Ok: return opEmptySuccess() case HttpStatusCode.NoContent: return opEmptySuccess() + case HttpStatusCode.NotFound: return opKnownFailure("account-not-found", resp); //FIXME: check when the server add codes spec case HttpStatusCode.BadRequest: return opKnownFailure("invalid-input", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); @@ -344,6 +345,7 @@ export class TalerCoreBankHttpClient { case HttpStatusCode.Ok: return opSuccess(resp, codecForBankAccountCreateWithdrawalResponse()) case HttpStatusCode.Conflict: return opKnownFailure("insufficient-funds", resp); case HttpStatusCode.Unauthorized: return opKnownFailure("unauthorized", resp); + case HttpStatusCode.NotFound: return opKnownFailure("account-not-found", resp); //FIXME: remove when server is updated case HttpStatusCode.Forbidden: return opKnownFailure("insufficient-funds", resp); default: return opUnknownFailure(resp, await resp.text()) diff --git a/packages/taler-util/src/operation.ts b/packages/taler-util/src/operation.ts index aab5dc022..8adbbb0e2 100644 --- a/packages/taler-util/src/operation.ts +++ b/packages/taler-util/src/operation.ts @@ -60,7 +60,7 @@ export async function failOrThrow<E>(s: E, cb: () => Promise<OperationResult<unk if (resp.case === s) { return resp.detail } - throw TalerError.fromException(new Error(`request failed but case "${s}" was expected`)) + throw TalerError.fromException(new Error(`request failed with "${resp.case}" but case "${s}" was expected`)) } |