88 lines
2.9 KiB
JavaScript
88 lines
2.9 KiB
JavaScript
// Generated, do not edit. sha256:09721f6e6374d0297156a1b8af0d4578d0bbb9c98d4ea7c96458dafbb2d56dcc
|
|||
|
|
import { createHmac } from 'node:crypto';
|
||
|
|
|
||
|
|
const HANDLE_TEKENS = 6;
|
||
|
|
|
||
|
|
const BECH32 = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
|
||
|
|
const BASE58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
||
|
|
const HEX = '0123456789abcdef';
|
||
|
|
|
||
|
|
const SOORTEN = Object.freeze({
|
||
|
|
address: Object.freeze({ prefix: 'bc1q', lengte: 42, alfabet: BECH32, onmogelijk: 'o' }),
|
||
|
|
xpub: Object.freeze({ prefix: 'xpub', lengte: 111, alfabet: BASE58, onmogelijk: '0' }),
|
||
|
|
txid: Object.freeze({ prefix: '', lengte: 64, alfabet: HEX, onmogelijk: 'z' }),
|
||
|
|
});
|
||
|
|
|
||
|
|
export const ALIAS_SOORTEN = Object.freeze(Object.keys(SOORTEN));
|
||
|
|
|
||
|
|
function vul(alfabet, lengte, zaad) {
|
||
|
|
let s = '';
|
||
|
|
for (let i = 0; i < lengte; i++) {
|
||
|
|
const paar = parseInt(zaad.slice((i * 2) % zaad.length, (i * 2) % zaad.length + 2) || '0', 16);
|
||
|
|
s += alfabet[(paar + i) % alfabet.length];
|
||
|
|
}
|
||
|
|
return s;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function schijnwaarde(soort, zaad) {
|
||
|
|
const s = SOORTEN[soort];
|
||
|
|
if (!s) throw new Error(`unknown alias kind: ${soort}`);
|
||
|
|
const romp = vul(s.alfabet, s.lengte - s.prefix.length, String(zaad));
|
||
|
|
const met = `${romp.slice(0, 2)}${s.onmogelijk}${romp.slice(3)}`;
|
||
|
|
return `${s.prefix}${met}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function isSchijnwaarde(tekst) {
|
||
|
|
if (typeof tekst !== 'string') return false;
|
||
|
|
for (const [, s] of Object.entries(SOORTEN)) {
|
||
|
|
if (s.prefix && !tekst.startsWith(s.prefix)) continue;
|
||
|
|
if (tekst.length !== s.lengte) continue;
|
||
|
|
const data = tekst.slice(s.prefix.length);
|
||
|
|
if (data.includes(s.onmogelijk)) return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function createAliasRegistry({ secret } = {}) {
|
||
|
|
if (typeof secret !== 'string' || secret.length < 32) {
|
||
|
|
throw new Error('An alias registry without a secret is not allowed.');
|
||
|
|
}
|
||
|
|
const heen = new Map();
|
||
|
|
const terug = new Map();
|
||
|
|
|
||
|
|
const afgeleid = (soort, waarde) =>
|
||
|
|
createHmac('sha256', secret).update(`${soort}\0${waarde}`).digest('hex');
|
||
|
|
|
||
|
|
function onthoud(sleutel, uit, soort, waarde) {
|
||
|
|
const bestaand = terug.get(uit);
|
||
|
|
if (bestaand && bestaand.waarde !== waarde) {
|
||
|
|
throw new Error(`Handle collision on '${uit}': two different values yield the same handle.`);
|
||
|
|
}
|
||
|
|
heen.set(sleutel, uit);
|
||
|
|
terug.set(uit, { soort, waarde });
|
||
|
|
return uit;
|
||
|
|
}
|
||
|
|
|
||
|
|
return {
|
||
|
|
alias(soort, waarde) {
|
||
|
|
const sleutel = `${soort} ${waarde}`;
|
||
|
|
if (heen.has(sleutel)) return heen.get(sleutel);
|
||
|
|
return onthoud(sleutel, schijnwaarde(soort, afgeleid(soort, waarde)), soort, waarde);
|
||
|
|
},
|
||
|
|
|
||
|
|
handle(soort, waarde) {
|
||
|
|
const sleutel = `${soort} ${waarde}`;
|
||
|
|
if (heen.has(sleutel)) return heen.get(sleutel);
|
||
|
|
return onthoud(sleutel, `${soort}:${afgeleid(soort, waarde).slice(0, HANDLE_TEKENS)}`, soort, waarde);
|
||
|
|
},
|
||
|
|
|
||
|
|
resolve(uit) {
|
||
|
|
const r = terug.get(uit);
|
||
|
|
return r ? r.waarde : null;
|
||
|
|
},
|
||
|
|
|
||
|
|
uitgegeven() {
|
||
|
|
return [...terug.entries()].map(([uit, r]) => ({ uit, soort: r.soort }));
|
||
|
|
},
|
||
|
|
};
|
||
|
|
}
|