Files
bare-operating-system/packages/bare-os-booter/lib/bare-os-peer-admission.js
T
Raven Scott c15e8fa5be feat(booter): POSIX/P2P roadmap — profile 1.0.14, ctx 1.50.0, docs & tests
- Sync declared POSIX profile, compliance matrix, syscalls examples, dashboard
- Extend holepunch clone sync reporting; bump protomux/hyperswarm lock fixture schema
- Optional shell read builtin (BARE_OS_SHELL_READ_*); host env passthrough
- Expand bareOsGetconfSysconf / getconf; pathconf for acct/union/mirror
- Wasm optional bare_os_monotonic_ms; replication live snapshot hints schema
- Socket bridge SO_RCVBUF/SO_SNDBUF; mq priority + FIFO ordering + tests
- Extract cooperative fcntl lock helpers; FIFO waiter drain tests
- Peer admission audit helpers, rate limit + redaction tests; security_posture schema
- CI: verify-ctx requires CHANGELOG row, d.ts version mention, compatibility matrix
- Warm-cache microbench (vfs suite); boot budget / metrics cohesion (prior work)
- Handbook, KERNEL_CONTRACT, kernel-program, env appendix, README, users-manual, schemas

Kernel bundle + seeder rsync + coreutils build verified via npm test.
2026-04-05 13:50:07 -04:00

222 lines
6.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Optional peer admission gate from **`BARE_OS_PEER_ALLOWLIST_HEX`**
* (comma-separated hex public keys; empty = allow all).
*
* **`BARE_OS_PEER_DENYLIST_HEX`** — comma-separated hex keys; if the peer matches,
* verdict is **`deny`** before allowlist evaluation (denylist wins).
*
* **`BARE_OS_PEER_REQUIRE_CAPS_JSON`** — JSON array of capability strings; when set,
* **`meta.caps`** must include every required token (hosts pass peer caps when known).
*
* When **`BARE_OS_DHT_ADDRESS_CLASS_ALLOWLIST`** is set and callers pass
* **`dhtAddressClass`** (hyperdht-addressstyle hint), the class must appear in
* the allow list after the key gate passes.
*
* Admission results use **`schema: 2`** (v1 was **`schema: 1`** only).
*
* @param {Record<string, unknown> | null | undefined} env
* @param {string} peerKeyHex
* @param {{ dhtAddressClass?: string, caps?: string[] } | null | undefined} [meta]
*/
const ADMISSION_SCHEMA = 2
/** @param {string} s */
function normKeyHex(s) {
return String(s || '')
.trim()
.toLowerCase()
.replace(/^0x/, '')
}
/** @param {string} raw */
function keySetFromCommaHex(raw) {
return new Set(
raw
.split(/[\s,]+/)
.map((s) => normKeyHex(s))
.filter(Boolean)
)
}
/**
* @param {Record<string, unknown> | null | undefined} env
* @returns {string[] | null}
*/
function parseRequireCaps(env) {
const raw = String(env?.BARE_OS_PEER_REQUIRE_CAPS_JSON || '').trim()
if (!raw) return null
try {
const j = JSON.parse(raw)
if (!Array.isArray(j)) return null
const caps = j
.map((x) => String(x).trim())
.filter(Boolean)
.slice(0, 32)
return caps.length ? caps : null
} catch {
return null
}
}
export function evaluateBareOsPeerAdmission(env, peerKeyHex, meta = undefined) {
const want = normKeyHex(peerKeyHex)
const atMs = () => Date.now()
const denyRaw = String(env?.BARE_OS_PEER_DENYLIST_HEX || '').trim()
if (denyRaw) {
const denySet = keySetFromCommaHex(denyRaw)
if (want && denySet.has(want)) {
return {
schema: ADMISSION_SCHEMA,
verdict: 'deny',
reason: 'peer_denylist',
denylistSize: denySet.size,
atMs: atMs()
}
}
}
const requireCaps = parseRequireCaps(env)
if (requireCaps && requireCaps.length > 0) {
const peerCapsRaw = meta && Array.isArray(meta.caps) ? meta.caps : []
const peerSet = new Set(
peerCapsRaw.map((c) => String(c).trim()).filter(Boolean)
)
for (const c of requireCaps) {
if (!peerSet.has(c)) {
return {
schema: ADMISSION_SCHEMA,
verdict: 'deny',
reason: 'peer_missing_cap',
requiredCaps: [...requireCaps],
atMs: atMs()
}
}
}
}
const raw = String(env?.BARE_OS_PEER_ALLOWLIST_HEX || '').trim()
const strict =
env?.BARE_OS_PEER_ALLOWLIST_STRICT === '1' ||
env?.BARE_OS_PEER_ALLOWLIST_STRICT === 'true'
/** @type {{ schema: number, verdict: string, note?: string, allowlistSize?: number, strictProfile?: boolean, atMs?: number, dhtAddressClassGate?: Record<string, unknown> }} */
let base
if (!raw) {
if (strict) {
base = {
schema: ADMISSION_SCHEMA,
verdict: 'deny',
note:
'BARE_OS_PEER_ALLOWLIST_STRICT is set but BARE_OS_PEER_ALLOWLIST_HEX is empty — no peers admitted.'
}
} else {
base = {
schema: ADMISSION_SCHEMA,
verdict: 'allow',
note: 'No allowlist; all peers admitted (subject to Hyperswarm topic).'
}
}
} else {
const set = keySetFromCommaHex(raw)
const ok = want && set.has(want)
base = {
schema: ADMISSION_SCHEMA,
verdict: ok ? 'allow' : 'deny',
allowlistSize: set.size,
strictProfile: strict || undefined,
atMs: atMs()
}
}
const classRaw = String(env?.BARE_OS_DHT_ADDRESS_CLASS_ALLOWLIST || '').trim()
if (!classRaw) {
if (base.atMs == null) base.atMs = atMs()
return base
}
const allowClasses = new Set(
classRaw.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean)
)
if (allowClasses.size === 0) {
if (base.atMs == null) base.atMs = atMs()
return base
}
const cls = String(meta?.dhtAddressClass || '')
.trim()
.toLowerCase()
if (!cls) {
return {
...base,
atMs: base.atMs ?? atMs(),
dhtAddressClassGate: {
schema: 1,
mode: 'no_peer_class_hint',
note: 'BARE_OS_DHT_ADDRESS_CLASS_ALLOWLIST is set but caller did not supply dhtAddressClass — stock Hyperswarm path does not classify peers; allow key verdict only.'
}
}
}
if (!allowClasses.has(cls)) {
return {
schema: ADMISSION_SCHEMA,
verdict: 'deny',
reason: 'dht_address_class',
dhtAddressClass: cls,
allowedClasses: [...allowClasses],
note: 'Peer DHT address class not listed in BARE_OS_DHT_ADDRESS_CLASS_ALLOWLIST.',
atMs: atMs()
}
}
if (base.verdict === 'deny') return base
return {
...base,
atMs: base.atMs ?? atMs(),
dhtAddressClassGate: { schema: 1, mode: 'allow', class: cls }
}
}
/**
* Build an event-bus row for **`peer_admission`** audit (**never** includes full peer keys).
*
* @param {string} peerKeyHex
* @param {{ verdict: string, reason?: string, schema: number }} result
* @param {{ dhtAddressClass?: string } | null | undefined} [meta]
*/
export function bareOsFormatPeerAdmissionAuditEvent(peerKeyHex, result, meta) {
const norm = String(peerKeyHex || '')
.trim()
.toLowerCase()
.replace(/^0x/, '')
const keyShort = norm ? norm.slice(0, 16) : ''
return {
type: 'peer_admission',
verdict: result.verdict,
reason: result.reason,
peerKeyHexPrefix: keyShort || undefined,
admissionSchema: result.schema,
dhtAddressClass:
meta && typeof meta === 'object'
? String(meta.dhtAddressClass || '').trim() || undefined
: undefined
}
}
/**
* Per-bucket rate gate for admission audit (**mutates** **`lastMap`** on allow).
*
* @param {string} bucket
* @param {number} now
* @param {number} rateMs
* @param {Map<string, number>} lastMap
*/
export function bareOsPeerAdmissionAuditRateAllow(bucket, now, rateMs, lastMap) {
if (rateMs <= 0) return true
const last = lastMap.get(bucket) ?? 0
if (now - last < rateMs) return false
lastMap.set(bucket, now)
return true
}