feat(ext): base32 encode/decode for TOTP secret parse
This commit is contained in:
44
extension/src/shared/base32.ts
Normal file
44
extension/src/shared/base32.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/// Minimal RFC 4648 base32 encode/decode for TOTP secret parsing.
|
||||
///
|
||||
/// Mirrors the encoder in crates/relicario-core/src/item.rs:base32_encode.
|
||||
/// Decode is case-insensitive, tolerates whitespace and `=` padding.
|
||||
|
||||
const ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
||||
|
||||
export function base32Encode(bytes: Uint8Array): string {
|
||||
let out = '';
|
||||
let buffer = 0;
|
||||
let bits = 0;
|
||||
for (const b of bytes) {
|
||||
buffer = (buffer << 8) | b;
|
||||
bits += 8;
|
||||
while (bits >= 5) {
|
||||
const idx = (buffer >> (bits - 5)) & 0x1f;
|
||||
out += ALPHA[idx];
|
||||
bits -= 5;
|
||||
}
|
||||
}
|
||||
if (bits > 0) {
|
||||
const idx = (buffer << (5 - bits)) & 0x1f;
|
||||
out += ALPHA[idx];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
export function base32Decode(input: string): Uint8Array {
|
||||
const cleaned = input.replace(/\s+/g, '').replace(/=+$/g, '').toUpperCase();
|
||||
const out: number[] = [];
|
||||
let buffer = 0;
|
||||
let bits = 0;
|
||||
for (const ch of cleaned) {
|
||||
const idx = ALPHA.indexOf(ch);
|
||||
if (idx === -1) throw new Error(`base32: invalid character "${ch}"`);
|
||||
buffer = (buffer << 5) | idx;
|
||||
bits += 5;
|
||||
if (bits >= 8) {
|
||||
out.push((buffer >> (bits - 8)) & 0xff);
|
||||
bits -= 8;
|
||||
}
|
||||
}
|
||||
return new Uint8Array(out);
|
||||
}
|
||||
Reference in New Issue
Block a user