ident
All repositories: gitoria
2.7 KB
// lib/login-helpers.hl — what lib/login.hl looks up: making a six-digit code and its hash, and the client's IP// BUCKET of the per-IP limit. No table access. Statics only.import { randomBytes, sha256 } from 'hl:crypto'// ---- codes --------------------------------------------------------------------------// six digits from the kernel CSPRNG (randomBytes answers hex)static newOtp = () => {hex = randomBytes(8)let n = 0let i = 0while (i < 12) {n = (n * 16 + '0123456789abcdef'.indexOf(hex[i])) % 1000000i = i + 1}let s = '' + nwhile (s.length < 6) { s = '0' + s }return s}static otpHash = (email, code) => { return sha256(email + ':' + code) }// ---- the client's IP bucket (mission 006 (old 010)) -------------------------------------------// `ip` is the X-Client-IP header nginx sets on Byrodin (CF-Connecting-IP when the request// really came through Cloudflare, else the TCP peer; nginx OVERWRITES what a client sent),// or null when there is none (dev without nginx: hl:web's req.remoteAddress would be nginx's; hl:http1 did not expose the// connection's peer address). The bucket:// no header / empty → 'direct' ONE SHARED BUCKET for every header-less request// IPv4 (also ::ffff:a.b.c.d) → the address// IPv6 → its /64 prefix ('2a01:4f9:3080:1126::/64'): one client// usually owns a whole /64, so per-address would not limit it// anything else → the text itself (lowercased, cut to 64 chars)static hexDigits = '0123456789abcdef'static stripZeros = (g) => {let t = gwhile (t.length > 1 && t[0] == '0') { t = t.slice(1, t.length) }return t}static ipBucket = (ip) => {if (ip == null || hlTypeName(ip) != 'String') { return 'direct' }let t = ip.trim().toLowerCase()if (t == '') { return 'direct' }if (t.length > 64) { t = t.slice(0, 64) }if (!t.includes(':')) { return t }// an IPv4-mapped IPv6 address counts as its IPv4 addressif (t.includes('.')) { return t.slice(t.lastIndexOf(':') + 1, t.length) }let head = tlet tail = ''gap = t.indexOf('::')if (gap >= 0) {head = t.slice(0, gap)tail = t.slice(gap + 2, t.length)}groups = head == '' ? [] : head.split(':')rest = tail == '' ? [] : tail.split(':')if (gap >= 0) {let fill = 8 - groups.length - rest.lengthwhile (fill > 0) {groups.push('0')fill = fill - 1}}for (g of rest) { groups.push(g) }if (groups.length != 8) { return t }out = []let i = 0while (i < 4) {let g = groups[i]if (g == '' || g.length > 4) { return t }let j = 0while (j < g.length) {if (!hexDigits.includes(g[j])) { return t }j = j + 1}out.push(stripZeros(g))i = i + 1}return out.join(':') + '::/64'}
Branches
- mainmain branch
Latest commits
- 5fdbb6b2ident mission 009: report — scratch folder notemre
- 74235815ident mission 009 (4/4): docs (README files map + same-output test, STATUS, LOG), report, tests/letcount.py + realdata-baseline/comparemre
- fe183516ident mission 009 (3/4): let only where reassigned — 293 never-reassigned lets are plain declarations; kept: reassigned, loop bodies, names of a file member, a name declared twice in one function; same outputmre
- d2e7f91bident mission 009 (2/4): one lib file per topic (login, accounts, identities, apps, invites, selector, notify + helpers, util), function routes as thin wrappers in lib/api.hl, project.hl = the map; same outputmre
- 91017164ident mission 009 (1/4): file moves — the root .hl files into lib/ (api.hl → lib/api-helpers.hl), styles.hl → components/styles.hl; imports adjusted, no other changemre
- f8bdcbc2ident: Hybriel master 06617221 (plugin allocators 3a781359 + 413f60e4, mpackdb 2cb7ae5e, http1 773de63e); all gates greenmre
- ff78726cident: Hybriel master 190aa11d (fc838894 GC correctness, #127, #126 closure scopes); gates all greenmre
- a3a7d21aident: Hybriel master 8efba065 (#126 GC by bytes, #48 lambda params copy); session-writing lambdas take &sessionmre
- 98226b41antcolony#40: mission references point to the moved missionsmre
- ff805b9aantcolony#40: history (LOG.md), worker briefs (missions/) and reports moved here from antcolony, numbered per project; old numbers in antcolony docs/mission-map.mdmre
- 51a7bcdfident: Hybriel master 73267707 (#122); /code uses the new page() signature; pending address passed as parameter; once-checksmre
- 836f644fident#24: installable app (manifest, service worker, data-free offline /start), own iconmre
- 8bebbbf2deploy.sh: back up live storage/.sessions/.env before every deploy (newest 5 kept)mre
- cc063ea2deploy.sh: never send .git or .gitignore to Byrodinmre
- 81b15b7bState of 2026-09-27, before the move to gitoriamre