diff options
Diffstat (limited to 'packages/taler-wallet-core/src/errors.ts')
-rw-r--r-- | packages/taler-wallet-core/src/errors.ts | 248 |
1 files changed, 0 insertions, 248 deletions
diff --git a/packages/taler-wallet-core/src/errors.ts b/packages/taler-wallet-core/src/errors.ts deleted file mode 100644 index 038bdbc7c..000000000 --- a/packages/taler-wallet-core/src/errors.ts +++ /dev/null @@ -1,248 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2019-2020 Taler Systems SA - - 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/> - */ - -/** - * Classes and helpers for error handling specific to wallet operations. - * - * @author Florian Dold <dold@taler.net> - */ - -/** - * Imports. - */ -import { - AbsoluteTime, - PayMerchantInsufficientBalanceDetails, - PayPeerInsufficientBalanceDetails, - TalerErrorCode, - TalerErrorDetail, - TransactionType, -} from "@gnu-taler/taler-util"; - -type empty = Record<string, never>; - -export interface DetailsMap { - [TalerErrorCode.WALLET_PENDING_OPERATION_FAILED]: { - innerError: TalerErrorDetail; - transactionId?: string; - }; - [TalerErrorCode.WALLET_EXCHANGE_DENOMINATIONS_INSUFFICIENT]: { - exchangeBaseUrl: string; - }; - [TalerErrorCode.WALLET_EXCHANGE_PROTOCOL_VERSION_INCOMPATIBLE]: { - exchangeProtocolVersion: string; - walletProtocolVersion: string; - }; - [TalerErrorCode.WALLET_WITHDRAWAL_OPERATION_ABORTED_BY_BANK]: empty; - [TalerErrorCode.WALLET_TIPPING_COIN_SIGNATURE_INVALID]: empty; - [TalerErrorCode.WALLET_ORDER_ALREADY_CLAIMED]: { - orderId: string; - claimUrl: string; - }; - [TalerErrorCode.WALLET_CONTRACT_TERMS_MALFORMED]: empty; - [TalerErrorCode.WALLET_CONTRACT_TERMS_SIGNATURE_INVALID]: { - merchantPub: string; - orderId: string; - }; - [TalerErrorCode.WALLET_CONTRACT_TERMS_BASE_URL_MISMATCH]: { - baseUrlForDownload: string; - baseUrlFromContractTerms: string; - }; - [TalerErrorCode.WALLET_INVALID_TALER_PAY_URI]: { - talerPayUri: string; - }; - [TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR]: { - requestUrl: string; - requestMethod: string; - httpStatusCode: number; - errorResponse?: any; - }; - [TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION]: { - stack?: string; - }; - [TalerErrorCode.WALLET_BANK_INTEGRATION_PROTOCOL_VERSION_INCOMPATIBLE]: { - exchangeProtocolVersion: string; - walletProtocolVersion: string; - }; - [TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN]: { - operation: string; - }; - [TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED]: { - requestUrl: string; - requestMethod: string; - throttleStats: Record<string, unknown>; - }; - [TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT]: empty; - [TalerErrorCode.WALLET_NETWORK_ERROR]: { - requestUrl: string; - requestMethod: string; - }; - [TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE]: { - requestUrl: string; - requestMethod: string; - httpStatusCode: number; - validationError?: string; - }; - [TalerErrorCode.WALLET_EXCHANGE_COIN_SIGNATURE_INVALID]: empty; - [TalerErrorCode.WALLET_WITHDRAWAL_GROUP_INCOMPLETE]: { - errorsPerCoin: Record<number, TalerErrorDetail>; - }; - [TalerErrorCode.WALLET_CORE_NOT_AVAILABLE]: empty; - [TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR]: { - httpStatusCode: number; - }; - [TalerErrorCode.WALLET_PAY_MERCHANT_SERVER_ERROR]: { - requestError: TalerErrorDetail; - }; - [TalerErrorCode.WALLET_CRYPTO_WORKER_ERROR]: { - innerError: TalerErrorDetail; - }; - [TalerErrorCode.WALLET_CRYPTO_WORKER_BAD_REQUEST]: { - detail: string; - }; - [TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED]: { - kycUrl: string; - }; - [TalerErrorCode.WALLET_DEPOSIT_GROUP_INSUFFICIENT_BALANCE]: { - insufficientBalanceDetails: PayMerchantInsufficientBalanceDetails; - }; - [TalerErrorCode.WALLET_PEER_PUSH_PAYMENT_INSUFFICIENT_BALANCE]: { - insufficientBalanceDetails: PayPeerInsufficientBalanceDetails; - }; -} - -type ErrBody<Y> = Y extends keyof DetailsMap ? DetailsMap[Y] : empty; - -export function makeErrorDetail<C extends TalerErrorCode>( - code: C, - detail: ErrBody<C>, - hint?: string, -): TalerErrorDetail { - if (!hint && !(detail as any).hint) { - hint = getDefaultHint(code); - } - const when = AbsoluteTime.now(); - return { code, when, hint, ...detail }; -} - -export function makePendingOperationFailedError( - innerError: TalerErrorDetail, - tag: TransactionType, - uid: string, -): TalerError { - return TalerError.fromDetail(TalerErrorCode.WALLET_PENDING_OPERATION_FAILED, { - innerError, - transactionId: `${tag}:${uid}`, - }); -} - -export function summarizeTalerErrorDetail(ed: TalerErrorDetail): string { - const errName = TalerErrorCode[ed.code] ?? "<unknown>"; - return `Error (${ed.code}/${errName})`; -} - -function getDefaultHint(code: number): string { - const errName = TalerErrorCode[code]; - if (errName) { - return `Error (${errName})`; - } else { - return `Error (<unknown>)`; - } -} - -export class TalerProtocolViolationError extends Error { - constructor(hint?: string) { - let msg: string; - if (hint) { - msg = `Taler protocol violation error (${hint})`; - } else { - msg = `Taler protocol violation error`; - } - super(msg); - Object.setPrototypeOf(this, TalerProtocolViolationError.prototype); - } -} - -export class TalerError<T = any> extends Error { - errorDetail: TalerErrorDetail & T; - private constructor(d: TalerErrorDetail & T) { - super(d.hint ?? `Error (code ${d.code})`); - this.errorDetail = d; - Object.setPrototypeOf(this, TalerError.prototype); - } - - static fromDetail<C extends TalerErrorCode>( - code: C, - detail: ErrBody<C>, - hint?: string, - ): TalerError { - if (!hint) { - hint = getDefaultHint(code); - } - const when = AbsoluteTime.now(); - return new TalerError<unknown>({ code, when, hint, ...detail }); - } - - static fromUncheckedDetail(d: TalerErrorDetail): TalerError { - return new TalerError<unknown>({ ...d }); - } - - static fromException(e: any): TalerError { - const errDetail = getErrorDetailFromException(e); - return new TalerError(errDetail); - } - - hasErrorCode<C extends keyof DetailsMap>( - code: C, - ): this is TalerError<DetailsMap[C]> { - return this.errorDetail.code === code; - } -} - -/** - * Convert an exception (or anything that was thrown) into - * a TalerErrorDetail object. - */ -export function getErrorDetailFromException(e: any): TalerErrorDetail { - if (e instanceof TalerError) { - return e.errorDetail; - } - if (e instanceof Error) { - const err = makeErrorDetail( - TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION, - { - stack: e.stack, - }, - `unexpected exception (message: ${e.message})`, - ); - return err; - } - // Something was thrown that is not even an exception! - // Try to stringify it. - let excString: string; - try { - excString = e.toString(); - } catch (e) { - // Something went horribly wrong. - excString = "can't stringify exception"; - } - const err = makeErrorDetail( - TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION, - {}, - `unexpected exception (not an exception, ${excString})`, - ); - return err; -} |