vouchsafe
Version:
Self-verifying identity and offline trust verification for JWTs, including attestations, vouches, revocations, and multi-hop trust chains.
98 lines (82 loc) • 2.46 kB
JavaScript
const ALPHABET = 'abcdefghijklmnopqrstuvwxyz234567';
/**
* Encode a byte array into base32 (RFC 4648, lowercase, no padding)
* @param {Uint8Array} bytes
* @returns {string}
*/
export function base32Encode(bytes) {
let bits = 0;
let value = 0;
let output = '';
for (let i = 0; i < bytes.length; i++) {
value = (value << 8) | bytes[i];
bits += 8;
while (bits >= 5) {
output += ALPHABET[(value >>> (bits - 5)) & 31];
bits -= 5;
}
}
if (bits > 0) {
output += ALPHABET[(value << (5 - bits)) & 31];
}
return output;
}
/**
* Decode a base32 string (RFC 4648, lowercase, no padding) into a byte array
* @param {string} str
* @returns {Uint8Array}
*/
export function base32Decode(str) {
const clean = str.toLowerCase().replace(/=+$/, '');
let bits = 0;
let value = 0;
const output = [];
for (let i = 0; i < clean.length; i++) {
const idx = ALPHABET.indexOf(clean[i]);
if (idx === -1) throw new Error(`Invalid base32 character: ${clean[i]}`);
value = (value << 5) | idx;
bits += 5;
if (bits >= 8) {
output.push((value >>> (bits - 8)) & 0xff);
bits -= 8;
}
}
return new Uint8Array(output);
}
export function toBase64(input) {
if (typeof input === 'string') {
// Assume it's already base64 (classic or url-safe) — return as-is
return input;
}
if (!(input instanceof Uint8Array)) {
throw new Error('Expected Uint8Array or base64 string');
}
if (typeof window === 'undefined') {
// Node.js
return Buffer.from(input).toString('base64');
} else {
// Browser
return btoa(String.fromCharCode(...input));
}
}
export function fromBase64(input) {
if (typeof input !== 'string') {
throw new Error('Expected base64-encoded string');
}
if (typeof window === 'undefined') {
// Node.js
return new Uint8Array(Buffer.from(input, 'base64'));
} else {
// Browser
const binaryStr = atob(input);
const len = binaryStr.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binaryStr.charCodeAt(i);
}
return bytes;
}
}
export function isValidUUID(input) {
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(input);
}