import type { SqlExecutor } from "./storage.ts";
import type { AddressRow, OwnerRef } from "./types.ts";
const ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
const LOCAL_PART_LENGTH = 10;
const MAX_CREATE_ATTEMPTS = 5;
// Addresses must not be predictable: users can mint addresses and see the
// results, and Math.random()'s PRNG state is recoverable from observed
// output, which would let one user guess another's addresses. Uses rejection
// sampling: bytes at or above the largest multiple of the alphabet length
// are discarded rather than folded in with %, which would bias the low
// characters of the alphabet.
const REJECTION_LIMIT = 256 - (256 % ALPHABET.length);
// Exported since other receivers (mail.tm) need their own random strings
// (a local part, an account password) with the same guarantee.
export function randomAlphanumeric(length: number): string {
let out = "";
while (out.length < length) {
const bytes = new Uint8Array(length);
crypto.getRandomValues(bytes);
for (const byte of bytes) {
if (byte >= REJECTION_LIMIT) {
continue;
}
out += ALPHABET[byte % ALPHABET.length];
if (out.length === length) {
break;
}
}
}
return out;
}
// 5-digit id shown alongside the address in /list, so /note, /extend, and
// /torch can take this instead of the full string. Not security-sensitive
// the way the address itself is: every lookup by short_id is still scoped to
// the invoking owner, so guessing one does nothing without also owning the
// match, hence plain Math.random() rather than the rejection-sampling