Files
skills/docs/security-stack/security/license/src/codec/base32/base32.md
2026-05-29 08:20:56 +01:00

2.4 KiB

@suaveplan/license — codec/base32

(no submodules)

Purpose

Crockford-style Base32 codec used to serialise the packed payload and signature into a printable license-key string. The alphabet (0-9 A-Z minus I, L, O, U) is shared with upstream so any key generated by upstream parses under suaveplan and vice versa. The encoder inserts - separators every 5 characters for legibility; the decoder ignores them.

Features

  • 32-character Crockford alphabet, omitting I/L/O/U.
  • Dash-grouped output, XXXXX-XXXXX-....
  • Case-insensitive decode (uppercase canonical).
  • Round-trips arbitrary Uint8Array data.
  • Raises LicenseError(LICENSE.INVALID_ENCODING) on any non-alphabet character, with the offending character in error.context.character.

Usage: Basic

import { base32Decode, base32Encode } from "@suaveplan/license/codec/base32/base32";

const encoded = base32Encode(new Uint8Array([1, 2, 3, 4, 5]));
// e.g. "0426-1850-A"
const decoded = base32Decode(encoded);

Usage: Advanced

Catching invalid input:

import { LicenseError } from "@suaveplan/license";
import { base32Decode } from "@suaveplan/license/codec/base32/base32";

try {
    base32Decode("INVALID-CHAR-!");
} catch (e) {
    if (e instanceof LicenseError && e.code === "LICENSE.INVALID_ENCODING") {
        console.warn("Bad character:", e.context?.character);
    }
}

API Reference

base32Encode(buf: Uint8Array): string

Returns the Base32 encoding of buf, grouped into 5-character chunks separated by -. Empty input returns the empty string.

base32Decode(str: string): Uint8Array

Strips -, uppercases, and decodes the resulting characters. Throws LicenseError(LICENSE.INVALID_ENCODING) for any unknown character. Input is trimmed to a byte boundary — trailing partial-byte bits are discarded (matching upstream behaviour).

Implementation Notes

The implementation uses string concatenation of binary digits rather than bit shifts because the 5-bit-to-8-bit boundary makes manual shifting verbose; the perf cost is negligible for license-key-sized inputs (≤73 bytes). For larger inputs, prefer @suaveplan/crypto-utils' base32 implementation. The trailing-bit truncation in base32Decode matches upstream's Math.floor(bits / 8) so identical inputs decode to identical bytes across both codebases.