diff options
author | Sebastian <sebasjm@gmail.com> | 2024-03-08 14:09:31 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2024-03-08 14:09:31 -0300 |
commit | ddd32a690bd13b1eb1aef1356a1d59fd64e254bf (patch) | |
tree | 44126872f6e8195a3617e2002c696c0afa13fb0d /packages/demobank-ui/src/utils.ts | |
parent | e0e82cdf07930d766081e42203c5a4e66d43191f (diff) |
demobank => bank
Diffstat (limited to 'packages/demobank-ui/src/utils.ts')
-rw-r--r-- | packages/demobank-ui/src/utils.ts | 447 |
1 files changed, 0 insertions, 447 deletions
diff --git a/packages/demobank-ui/src/utils.ts b/packages/demobank-ui/src/utils.ts deleted file mode 100644 index 8b0febe42..000000000 --- a/packages/demobank-ui/src/utils.ts +++ /dev/null @@ -1,447 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022-2024 Taler Systems S.A. - - 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 { - AmountString, - PaytoString, - TalerError, - TalerErrorCode, - TranslatedString, -} from "@gnu-taler/taler-util"; -import { - ErrorNotification, - InternationalizationAPI, - notify, - notifyError, - useTranslationContext, -} from "@gnu-taler/web-util/browser"; - -/** - * Validate (the number part of) an amount. If needed, - * replace comma with a dot. Returns 'false' whenever - * the input is invalid, the valid amount otherwise. - */ -const amountRegex = /^[0-9]+(.[0-9]+)?$/; -export function validateAmount( - maybeAmount: string | undefined, -): string | undefined { - if (!maybeAmount || !amountRegex.test(maybeAmount)) { - return; - } - return maybeAmount; -} - -/** - * Extract IBAN from a Payto URI. - */ -export function getIbanFromPayto(url: string): string { - const pathSplit = new URL(url).pathname.split("/"); - let lastIndex = pathSplit.length - 1; - // Happens if the path ends with "/". - if (pathSplit[lastIndex] === "") lastIndex--; - const iban = pathSplit[lastIndex]; - return iban; -} - -export function undefinedIfEmpty<T extends object>(obj: T): T | undefined { - return Object.keys(obj).some( - (k) => (obj as Record<string, T>)[k] !== undefined, - ) - ? obj - : undefined; -} - -export type PartialButDefined<T> = { - [P in keyof T]: T[P] | undefined; -}; - -/** - * every non-map field can be undefined - */ -export type WithIntermediate<Type> = { - [prop in keyof Type]: Type[prop] extends PaytoString - ? Type[prop] | undefined - : Type[prop] extends AmountString - ? Type[prop] | undefined - : Type[prop] extends TranslatedString - ? Type[prop] | undefined - : Type[prop] extends object - ? WithIntermediate<Type[prop]> - : Type[prop] | undefined; -}; -export type RecursivePartial<Type> = { - [P in keyof Type]?: Type[P] extends (infer U)[] - ? RecursivePartial<U>[] - : Type[P] extends object - ? RecursivePartial<Type[P]> - : Type[P]; -}; -export type ErrorMessageMappingFor<Type> = { - [prop in keyof Type]+?: Exclude<Type[prop], undefined> extends PaytoString // enumerate known object - ? TranslatedString - : Exclude<Type[prop], undefined> extends AmountString - ? TranslatedString - : Exclude<Type[prop], undefined> extends TranslatedString - ? TranslatedString - : // arrays: every element - Exclude<Type[prop], undefined> extends (infer U)[] - ? ErrorMessageMappingFor<U>[] - : // map: every field - Exclude<Type[prop], undefined> extends object - ? ErrorMessageMappingFor<Type[prop]> - : TranslatedString; -}; - -export enum TanChannel { - SMS = "sms", - EMAIL = "email", -} -export enum CashoutStatus { - // The payment was initiated after a valid - // TAN was received by the bank. - CONFIRMED = "confirmed", - - // The cashout was created and now waits - // for the TAN by the author. - PENDING = "pending", -} - -export const PAGE_SIZE = 5; - -type Translator = ReturnType<typeof useTranslationContext>["i18n"]; - -export async function withRuntimeErrorHandling<T>( - i18n: Translator, - cb: () => Promise<T>, -): Promise<void> { - try { - await cb(); - } catch (error: unknown) { - if (error instanceof TalerError) { - notify(buildRequestErrorMessage(i18n, error)); - } else { - notifyError( - i18n.str`Operation failed, please report`, - (error instanceof Error - ? error.message - : JSON.stringify(error)) as TranslatedString, - ); - } - } -} - -export function buildRequestErrorMessage( - i18n: Translator, - cause: TalerError, -): ErrorNotification { - let result: ErrorNotification; - switch (cause.errorDetail.code) { - case TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT: { - result = { - type: "error", - title: i18n.str`Request timeout`, - description: cause.message as TranslatedString, - debug: JSON.stringify(cause.errorDetail, undefined, 2), - }; - break; - } - case TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED: { - result = { - type: "error", - title: i18n.str`Request throttled`, - description: cause.message as TranslatedString, - debug: JSON.stringify(cause.errorDetail, undefined, 2), - }; - break; - } - case TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE: { - result = { - type: "error", - title: i18n.str`Malformed response`, - description: cause.message as TranslatedString, - debug: JSON.stringify(cause.errorDetail, undefined, 2), - }; - break; - } - case TalerErrorCode.WALLET_NETWORK_ERROR: { - result = { - type: "error", - title: i18n.str`Network error`, - description: cause.message as TranslatedString, - debug: JSON.stringify(cause.errorDetail, undefined, 2), - }; - break; - } - case TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR: { - result = { - type: "error", - title: i18n.str`Unexpected request error`, - description: cause.message as TranslatedString, - debug: JSON.stringify(cause.errorDetail, undefined, 2), - }; - break; - } - default: { - result = { - type: "error", - title: i18n.str`Unexpected error`, - description: cause.message as TranslatedString, - debug: JSON.stringify(cause.errorDetail, undefined, 2), - }; - break; - } - } - return result; -} - -export const COUNTRY_TABLE = { - AE: "U.A.E.", - AF: "Afghanistan", - AL: "Albania", - AM: "Armenia", - AN: "Netherlands Antilles", - AR: "Argentina", - AT: "Austria", - AU: "Australia", - AZ: "Azerbaijan", - BA: "Bosnia and Herzegovina", - BD: "Bangladesh", - BE: "Belgium", - BG: "Bulgaria", - BH: "Bahrain", - BN: "Brunei Darussalam", - BO: "Bolivia", - BR: "Brazil", - BT: "Bhutan", - BY: "Belarus", - BZ: "Belize", - CA: "Canada", - CG: "Congo", - CH: "Switzerland", - CI: "Cote d'Ivoire", - CL: "Chile", - CM: "Cameroon", - CN: "People's Republic of China", - CO: "Colombia", - CR: "Costa Rica", - CS: "Serbia and Montenegro", - CZ: "Czech Republic", - DE: "Germany", - DK: "Denmark", - DO: "Dominican Republic", - DZ: "Algeria", - EC: "Ecuador", - EE: "Estonia", - EG: "Egypt", - ER: "Eritrea", - ES: "Spain", - ET: "Ethiopia", - FI: "Finland", - FO: "Faroe Islands", - FR: "France", - GB: "United Kingdom", - GD: "Caribbean", - GE: "Georgia", - GL: "Greenland", - GR: "Greece", - GT: "Guatemala", - HK: "Hong Kong", - // HK: "Hong Kong S.A.R.", - HN: "Honduras", - HR: "Croatia", - HT: "Haiti", - HU: "Hungary", - ID: "Indonesia", - IE: "Ireland", - IL: "Israel", - IN: "India", - IQ: "Iraq", - IR: "Iran", - IS: "Iceland", - IT: "Italy", - JM: "Jamaica", - JO: "Jordan", - JP: "Japan", - KE: "Kenya", - KG: "Kyrgyzstan", - KH: "Cambodia", - KR: "South Korea", - KW: "Kuwait", - KZ: "Kazakhstan", - LA: "Laos", - LB: "Lebanon", - LI: "Liechtenstein", - LK: "Sri Lanka", - LT: "Lithuania", - LU: "Luxembourg", - LV: "Latvia", - LY: "Libya", - MA: "Morocco", - MC: "Principality of Monaco", - MD: "Moldava", - // MD: "Moldova", - ME: "Montenegro", - MK: "Former Yugoslav Republic of Macedonia", - ML: "Mali", - MM: "Myanmar", - MN: "Mongolia", - MO: "Macau S.A.R.", - MT: "Malta", - MV: "Maldives", - MX: "Mexico", - MY: "Malaysia", - NG: "Nigeria", - NI: "Nicaragua", - NL: "Netherlands", - NO: "Norway", - NP: "Nepal", - NZ: "New Zealand", - OM: "Oman", - PA: "Panama", - PE: "Peru", - PH: "Philippines", - PK: "Islamic Republic of Pakistan", - PL: "Poland", - PR: "Puerto Rico", - PT: "Portugal", - PY: "Paraguay", - QA: "Qatar", - RE: "Reunion", - RO: "Romania", - RS: "Serbia", - RU: "Russia", - RW: "Rwanda", - SA: "Saudi Arabia", - SE: "Sweden", - SG: "Singapore", - SI: "Slovenia", - SK: "Slovak", - SN: "Senegal", - SO: "Somalia", - SR: "Suriname", - SV: "El Salvador", - SY: "Syria", - TH: "Thailand", - TJ: "Tajikistan", - TM: "Turkmenistan", - TN: "Tunisia", - TR: "Turkey", - TT: "Trinidad and Tobago", - TW: "Taiwan", - TZ: "Tanzania", - UA: "Ukraine", - US: "United States", - UY: "Uruguay", - VA: "Vatican", - VE: "Venezuela", - VN: "Viet Nam", - YE: "Yemen", - ZA: "South Africa", - ZW: "Zimbabwe", -}; - -/** - * An IBAN is validated by converting it into an integer and performing a - * basic mod-97 operation (as described in ISO 7064) on it. - * If the IBAN is valid, the remainder equals 1. - * - * The algorithm of IBAN validation is as follows: - * 1.- Check that the total IBAN length is correct as per the country. If not, the IBAN is invalid - * 2.- Move the four initial characters to the end of the string - * 3.- Replace each letter in the string with two digits, thereby expanding the string, where A = 10, B = 11, ..., Z = 35 - * 4.- Interpret the string as a decimal integer and compute the remainder of that number on division by 97 - * - * If the remainder is 1, the check digit test is passed and the IBAN might be valid. - * - */ -const IBAN_REGEX = /^[A-Z][A-Z0-9]*$/; -export function validateIBAN( - account: string, - i18n: InternationalizationAPI, -): TranslatedString | undefined { - if (!IBAN_REGEX.test(account)) { - return i18n.str`IBAN only have uppercased letters and numbers` - } - // Check total length - if (account.length < 4) - return i18n.str`IBAN numbers have more that 4 digits`; - if (account.length > 34) - return i18n.str`IBAN numbers have less that 34 digits`; - - const A_code = "A".charCodeAt(0); - const Z_code = "Z".charCodeAt(0); - const IBAN = account.toUpperCase(); - // check supported country - const code = IBAN.substring(0, 2); - const found = code in COUNTRY_TABLE; - if (!found) return i18n.str`IBAN country code not found`; - - // 2.- Move the four initial characters to the end of the string - const step2 = IBAN.substring(4) + account.substring(0, 4); - const step3 = Array.from(step2) - .map((letter) => { - const code = letter.charCodeAt(0); - if (code < A_code || code > Z_code) return letter; - return `${letter.charCodeAt(0) - "A".charCodeAt(0) + 10}`; - }) - .join(""); - - const checksum = calculate_iban_checksum(step3); - if (checksum !== 1) - return i18n.str`IBAN number is not valid, checksum is wrong`; - return undefined; -} - -function calculate_iban_checksum(str: string): number { - const numberStr = str.substring(0, 5); - const rest = str.substring(5); - const number = parseInt(numberStr, 10); - const result = number % 97; - if (rest.length > 0) { - return calculate_iban_checksum(`${result}${rest}`); - } - return result; -} - -const USERNAME_REGEX = /^[A-Za-z][A-Za-z0-9]*$/; - -export function validateTalerBank( - account: string, - i18n: InternationalizationAPI, -): TranslatedString | undefined { - if (!USERNAME_REGEX.test(account)) { - return i18n.str`Account only have letters and numbers` - } - return undefined -} - -export function validateRawIBAN( - payto: string, - i18n: InternationalizationAPI, -): TranslatedString | undefined { - return undefined -} - - - -export function validateRawTalerBank( - payto: string, - currentHost: string, - i18n: InternationalizationAPI, -): TranslatedString | undefined { - return undefined -} - |