/* 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 */ /** * Imports. */ import { base64FromArrayBuffer } from "../base64.js"; import { encodeCrock, getRandomBytes, stringToBytes } from "../taler-crypto.js"; import { AccessToken, LongPollParams, PaginationParams } from "./types.js"; /** * Helper function to generate the "Authorization" HTTP header. */ export function makeBasicAuthHeader( username: string, password: string, ): string { const auth = `${username}:${password}`; const authEncoded: string = base64FromArrayBuffer(stringToBytes(auth)); return `Basic ${authEncoded}`; } /** * rfc8959 * @param token * @returns */ export function makeBearerTokenAuthHeader(token: AccessToken): string { return `Bearer secret-token:${token}`; } /** * https://bugs.gnunet.org/view.php?id=7949 */ export function addPaginationParams(url: URL, pagination?: PaginationParams) { if (!pagination) return; if (pagination.offset) { url.searchParams.set("start", pagination.offset); } const order = !pagination || pagination.order === "asc" ? 1 : -1; const limit = !pagination || !pagination.limit || pagination.limit === 0 ? 5 : Math.abs(pagination.limit); //always send delta url.searchParams.set("delta", String(order * limit)); } export function addMerchantPaginationParams( url: URL, pagination?: PaginationParams, ) { if (!pagination) return; if (pagination.offset) { url.searchParams.set("offset", pagination.offset); } const order = !pagination || pagination.order === "asc" ? 1 : -1; const limit = !pagination || !pagination.limit || pagination.limit === 0 ? 5 : Math.abs(pagination.limit); //always send delta url.searchParams.set("limit", String(order * limit)); } export function addLongPollingParam(url: URL, param?: LongPollParams) { if (!param) return; if (param.timeoutMs) { url.searchParams.set("long_poll_ms", String(param.timeoutMs)); } } export interface CacheEvictor { notifySuccess: (op: T) => Promise; } export const nullEvictor: CacheEvictor = { notifySuccess: () => Promise.resolve(), }; export class IdempotencyRetry { public readonly uid: string; public readonly timesLeft: number; public readonly maxTries: number; private constructor(timesLeft: number, maxTimesLeft: number) { this.timesLeft = timesLeft; this.maxTries = maxTimesLeft; this.uid = encodeCrock(getRandomBytes(32)) } static tryFiveTimes() { return new IdempotencyRetry(5, 5) } next(): IdempotencyRetry | undefined { const left = this.timesLeft -1 if (left <= 0) { return undefined } return new IdempotencyRetry(left, this.maxTries); } }