Skip to content

Commit c0bf801

Browse files
committed
Offline licencing working
1 parent 7370b9f commit c0bf801

12 files changed

Lines changed: 860 additions & 595 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,7 @@ docs/
1212
agents/
1313
AGENTS.md
1414
.agentkanban/
15+
16+
# No node modules at workspace root, but added in case accidentally created
17+
18+
node_modules

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"env": {
1717
"AS_NOTES_DEBUG": "1",
1818
// Uncomment to use test licence server
19-
// "AS_NOTES_LICENCE_SERVER_URL": "http://localhost:5173",
19+
"AS_NOTES_LICENCE_SERVER_URL": "http://localhost:5173",
2020
// Uncomment to simulate licence type
2121
// "AS_NOTES_LICENCE_OVERRIDE": "pro_editor"
2222
// "AS_NOTES_LICENCE_OVERRIDE": "pro_ai_sync"

node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Crockford Base32 encoding/decoding
2+
// Alphabet: 0123456789ABCDEFGHJKMNPQRSTVWXYZ (excludes I, L, O, U to avoid ambiguity)
3+
4+
const ALPHABET = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
5+
const DECODE_MAP = new Map<string, number>();
6+
7+
// Build decode map (case-insensitive, with common substitutions)
8+
for (let i = 0; i < ALPHABET.length; i++) {
9+
DECODE_MAP.set(ALPHABET[i]!, i);
10+
DECODE_MAP.set(ALPHABET[i]!.toLowerCase(), i);
11+
}
12+
// Common misreadings
13+
DECODE_MAP.set('O', 0);
14+
DECODE_MAP.set('o', 0);
15+
DECODE_MAP.set('I', 1);
16+
DECODE_MAP.set('i', 1);
17+
DECODE_MAP.set('L', 1);
18+
DECODE_MAP.set('l', 1);
19+
20+
export function encode(data: Uint8Array): string {
21+
if (data.length === 0) { return ''; }
22+
23+
let result = '';
24+
let buffer = 0;
25+
let bitsInBuffer = 0;
26+
27+
for (const byte of data) {
28+
buffer = (buffer << 8) | byte;
29+
bitsInBuffer += 8;
30+
31+
while (bitsInBuffer >= 5) {
32+
bitsInBuffer -= 5;
33+
const index = (buffer >> bitsInBuffer) & 0x1f;
34+
result += ALPHABET[index];
35+
}
36+
}
37+
38+
// Encode remaining bits (pad with zeros on the right)
39+
if (bitsInBuffer > 0) {
40+
const index = (buffer << (5 - bitsInBuffer)) & 0x1f;
41+
result += ALPHABET[index];
42+
}
43+
44+
return result;
45+
}
46+
47+
export function decode(encoded: string): Uint8Array {
48+
if (encoded.length === 0) { return new Uint8Array(0); }
49+
50+
// Strip hyphens and whitespace
51+
const cleaned = encoded.replace(/[-\s]/g, '');
52+
53+
let buffer = 0;
54+
let bitsInBuffer = 0;
55+
const bytes: number[] = [];
56+
57+
for (const char of cleaned) {
58+
const value = DECODE_MAP.get(char);
59+
if (value === undefined) {
60+
throw new Error(`Invalid Crockford Base32 character: '${char}'`);
61+
}
62+
buffer = (buffer << 5) | value;
63+
bitsInBuffer += 5;
64+
65+
while (bitsInBuffer >= 8) {
66+
bitsInBuffer -= 8;
67+
bytes.push((buffer >> bitsInBuffer) & 0xff);
68+
}
69+
}
70+
71+
return new Uint8Array(bytes);
72+
}

0 commit comments

Comments
 (0)