/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { DateTime } from 'luxon'; const gen_salt = (l: number): string => { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; const charLength = chars.length; let result = ''; for (let i = 0; i < l; i++) { result += chars.charAt(Math.floor(Math.random() * charLength)); } return result; }; export const mint = async ( resource: string, bits = 16, // now = null, ext = '', saltchars = 8, stamp_seconds = false ): Promise => { bits = 8; const ver = '1'; let ts; if (stamp_seconds) { ts = DateTime.now().toFormat('yyMMddHHmmss'); } else { ts = DateTime.now().toFormat('yyMMdd'); } const hex_digits = Math.ceil(bits / 4); const zeros = '0'.repeat(hex_digits); const salt = gen_salt(saltchars); const challenge = `${ver}:${bits}:${ts}:${resource}:${ext}:${salt}`; let counter = 0; let result: string; const t1 = performance.now(); // eslint-disable-next-line no-constant-condition while (true) { const data = new TextEncoder().encode(`${challenge}:${counter.toString(16)}`); const hashBuffer = await crypto.subtle.digest('SHA-1', data); const hashArray = Array.from(new Uint8Array(hashBuffer)); const digest = hashArray.map((b) => b.toString(16).padStart(2, '0')).join(''); if (digest.slice(0, hex_digits) == zeros) { result = counter.toString(16); break; } counter += 1; } const t2 = performance.now(); // eslint-disable-next-line no-undef plausible('Hashcash', { props: { ms_taken: t2 - t1 } }); return `${challenge}:${result}`; };