Files
drop/server/internal/auth/base32/index.js
DecDuck 63ac2b8ffc Depot API & v4 (#298)
* feat: nginx + torrential basics & services system

* fix: lint + i18n

* fix: update torrential to remove openssl

* feat: add torrential to Docker build

* feat: move to self hosted runner

* fix: move off self-hosted runner

* fix: update nginx.conf

* feat: torrential cache invalidation

* fix: update torrential for cache invalidation

* feat: integrity check task

* fix: lint

* feat: move to version ids

* fix: client fixes and client-side checks

* feat: new depot apis and version id fixes

* feat: update torrential

* feat: droplet bump and remove unsafe update functions

* fix: lint

* feat: v4 featureset: emulators, multi-launch commands

* fix: lint

* fix: mobile ui for game editor

* feat: launch options

* fix: lint

* fix: remove axios, use $fetch

* feat: metadata and task api improvements

* feat: task actions

* fix: slight styling issue

* feat: fix style and lints

* feat: totp backend routes

* feat: oidc groups

* fix: update drop-base

* feat: creation of passkeys & totp

* feat: totp signin

* feat: webauthn mfa/signin

* feat: launch selecting ui

* fix: manually running tasks

* feat: update add company game modal to use new SelectorGame

* feat: executor selector

* fix(docker): update rust to rust nightly for torrential build (#305)

* feat: new version ui

* feat: move package lookup to build time to allow for deno dev

* fix: lint

* feat: localisation cleanup

* feat: apply localisation cleanup

* feat: potential i18n refactor logic

* feat: remove args from commands

* fix: lint

* fix: lockfile

---------

Co-authored-by: Aden Lindsay <140392385+AdenMGB@users.noreply.github.com>
2026-01-13 15:32:39 +11:00

70 lines
2.3 KiB
JavaScript

// base32 elements
//RFC4648: why include 2? Z and 2 looks similar than 8 and O
const b32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
console.assert(b32.length === 32, b32.length);
const b32r = new Map(Array.from(b32, (ch, i) => [ch, i])).set("=", 0);
//[constants derived from character table size]
//cbit = 5 (as 32 == 2 ** 5), ubit = 8 (as byte)
//ccount = 8 (= cbit / gcd(cbit, ubit)), ucount = 5 (= ubit / gcd(cbit, ubit))
//cmask = 0x1f (= 2 ** cbit - 1), umask = 0xff (= 2 ** ubit - 1)
//const b32pad = [0, 6, 4, 3, 1];
const b32pad = Array.from(Array(5), (_, i) => ((8 - (i * 8) / 5) | 0) % 8);
function b32e5(u1, u2 = 0, u3 = 0, u4 = 0, u5 = 0) {
const u40 = u1 * 2 ** 32 + u2 * 2 ** 24 + u3 * 2 ** 16 + u4 * 2 ** 8 + u5;
return [
b32[(u40 / 2 ** 35) & 0x1f],
b32[(u40 / 2 ** 30) & 0x1f],
b32[(u40 / 2 ** 25) & 0x1f],
b32[(u40 / 2 ** 20) & 0x1f],
b32[(u40 / 2 ** 15) & 0x1f],
b32[(u40 / 2 ** 10) & 0x1f],
b32[(u40 / 2 ** 5) & 0x1f],
b32[u40 & 0x1f],
];
}
function b32d8(b1, b2, b3, b4, b5, b6, b7, b8) {
const u40 =
b32r.get(b1) * 2 ** 35 +
b32r.get(b2) * 2 ** 30 +
b32r.get(b3) * 2 ** 25 +
b32r.get(b4) * 2 ** 20 +
b32r.get(b5) * 2 ** 15 +
b32r.get(b6) * 2 ** 10 +
b32r.get(b7) * 2 ** 5 +
b32r.get(b8);
return [
(u40 / 2 ** 32) & 0xff,
(u40 / 2 ** 24) & 0xff,
(u40 / 2 ** 16) & 0xff,
(u40 / 2 ** 8) & 0xff,
u40 & 0xff,
];
}
// base32 encode/decode: Uint8Array <=> string
export function b32e(u8a) {
console.assert(u8a instanceof Uint8Array, u8a.constructor);
const len = u8a.length,
rem = len % 5;
const u5s = Array.from(Array((len - rem) / 5), (_, i) =>
u8a.subarray(i * 5, i * 5 + 5),
);
const pad = b32pad[rem];
const br = rem === 0 ? [] : b32e5(...u8a.subarray(-rem)).slice(0, 8 - pad);
return []
.concat(...u5s.map((u5) => b32e5(...u5)), br, ["=".repeat(pad)])
.join("");
}
export function b32d(bs) {
const len = bs.length;
if (len === 0) return new Uint8Array([]);
console.assert(len % 8 === 0, len);
const pad = len - bs.indexOf("="),
rem = b32pad.indexOf(pad);
console.assert(rem >= 0, pad);
console.assert(/^[A-Z2-7+/]*$/.test(bs.slice(0, len - pad)), bs);
const u8s = [].concat(...bs.match(/.{8}/g).map((b8) => b32d8(...b8)));
return new Uint8Array(rem > 0 ? u8s.slice(0, rem - 5) : u8s);
}