OverviewFilesCommitsIssuesDocsReleasesPeers

trust-map commits / c6c6506

Initial commit — trust-map
Pubkey → permissions store with optional hyperident chain verification via keet-identity-key. Maps master identity public keys to permission sets (e.g. ['owner', 'writer']); checkChain({ proof, data }) extracts the identityPublicKey from a hyperident-produced chain via IdentityKey.verify() before looking it up in the map. Backed by a single-writer Hyperbee on a Hypercore; read-only secondary replicas open by key. 11 tests / all passing, including real keet-identity-key chain verification. Phase 2 of the pear-git-v3 bottom-up rebuild. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
c6c650679c4ddd954e1c19ddbbe20bb4e00b797c
by plankatron <fleeky@gmail.com> · 2026-04-15T03:28:06.000Z

Changed files (8) +2342 -0

.gitignore +15 -0
……@@ -0,0 +1,15 @@
1# Dependencies
2node_modules/
3
4# Storage directories created by example CLIs
5.trust-map-*/
6
7# Editor and OS cruft
8.DS_Store
9*.log
10*.swp
11.vscode/
12.idea/
13
14# Test artifacts
15coverage/
examples/cli.js +183 -0
……@@ -0,0 +1,183 @@
1#!/usr/bin/env node
2/**
3 * Mini CLI example for trust-map
4 *
5 * Usage:
6 * node examples/cli.js init Init storage
7 * node examples/cli.js grant <pubkey> <resource> <perms,...> Grant perms
8 * node examples/cli.js revoke <pubkey> <resource> [perms,...] Revoke
9 * node examples/cli.js check <pubkey> <resource> <perm> Check
10 * node examples/cli.js list List all
11 * node examples/cli.js for <pubkey> List for one pubkey
12 * node examples/cli.js demo Generate keypairs and play
13 *
14 * Storage path: TRUST_MAP_STORE env var, default ./.trust-map-cli/
15 *
16 * NOTE: this CLI uses its OWN storage path by default. The web example
17 * (examples/web.js) uses ./.trust-map-web/ — they don't share state.
18 * RocksDB has a single-writer lock, so two processes can't open the same
19 * Corestore at once. For shared state across CLI/web/native interfaces in
20 * production, embed trust-map in a single daemon (e.g. pear-git-v3) and
21 * have all clients talk to the daemon via hyper-svc (planned).
22 */
23
24import Corestore from 'corestore'
25import crypto from 'hypercore-crypto'
26import b4a from 'b4a'
27import { TrustMap } from '../index.js'
28
29const args = process.argv.slice(2)
30const cmd = args[0]
31const storagePath = process.env.TRUST_MAP_STORE || './.trust-map-cli'
32
33async function open () {
34 const store = new Corestore(storagePath)
35 await store.ready()
36 const core = store.get({ name: 'trust-map' })
37 await core.ready()
38 const tm = new TrustMap({ core })
39 await tm.ready()
40 return { tm, store, core }
41}
42
43async function close ({ tm, store, core }) {
44 await tm.close()
45 await core.close()
46 await store.close()
47}
48
49async function main () {
50 if (cmd === 'init') {
51 const ctx = await open()
52 console.log('Initialized trust map at: %s', storagePath)
53 await close(ctx)
54 return
55 }
56
57 if (cmd === 'grant') {
58 const [, pubkey, resource, permsStr] = args
59 if (!pubkey || !resource || !permsStr) {
60 console.error('Usage: cli.js grant <pubkey> <resource> <perm1,perm2,...>')
61 process.exit(1)
62 }
63 const perms = permsStr.split(',').map(s => s.trim())
64 const ctx = await open()
65 await ctx.tm.grant(pubkey, resource, perms)
66 console.log('Granted %s on %s to %s', perms.join(','), resource, pubkey.slice(0, 16) + '...')
67 await close(ctx)
68 return
69 }
70
71 if (cmd === 'revoke') {
72 const [, pubkey, resource, permsStr] = args
73 if (!pubkey || !resource) {
74 console.error('Usage: cli.js revoke <pubkey> <resource> [perm1,perm2,...]')
75 process.exit(1)
76 }
77 const perms = permsStr ? permsStr.split(',').map(s => s.trim()) : undefined
78 const ctx = await open()
79 await ctx.tm.revoke(pubkey, resource, perms)
80 console.log('Revoked %s on %s for %s', perms ? perms.join(',') : '(all)', resource, pubkey.slice(0, 16) + '...')
81 await close(ctx)
82 return
83 }
84
85 if (cmd === 'check') {
86 const [, pubkey, resource, perm] = args
87 if (!pubkey || !resource || !perm) {
88 console.error('Usage: cli.js check <pubkey> <resource> <perm>')
89 process.exit(1)
90 }
91 const ctx = await open()
92 const ok = await ctx.tm.check(pubkey, resource, perm)
93 console.log('check(%s, %s, %s) = %s', pubkey.slice(0, 16) + '...', resource, perm, ok ? 'YES' : 'NO')
94 await close(ctx)
95 return
96 }
97
98 if (cmd === 'list') {
99 const ctx = await open()
100 const all = await ctx.tm.list()
101 if (all.length === 0) {
102 console.log('(empty)')
103 } else {
104 console.log('Trust map (%d entries):', all.length)
105 for (const e of all) {
106 console.log(' %s %s %s', e.pubkey.slice(0, 16) + '...', e.resource.padEnd(20), e.perms.join(','))
107 }
108 }
109 await close(ctx)
110 return
111 }
112
113 if (cmd === 'for') {
114 const pubkey = args[1]
115 if (!pubkey) { console.error('Usage: cli.js for <pubkey>'); process.exit(1) }
116 const ctx = await open()
117 const entries = await ctx.tm.listForPubkey(pubkey)
118 if (entries.length === 0) {
119 console.log('No entries for %s', pubkey.slice(0, 16) + '...')
120 } else {
121 console.log('Entries for %s:', pubkey.slice(0, 16) + '...')
122 for (const e of entries) {
123 console.log(' %s: %s', e.resource, e.perms.join(','))
124 }
125 }
126 await close(ctx)
127 return
128 }
129
130 if (cmd === 'demo') {
131 const ctx = await open()
132 console.log('--- trust-map demo ---\n')
133
134 const alice = b4a.toString(crypto.randomBytes(32), 'hex')
135 const bob = b4a.toString(crypto.randomBytes(32), 'hex')
136 const ci = b4a.toString(crypto.randomBytes(32), 'hex')
137
138 console.log('Alice: %s', alice)
139 console.log('Bob: %s', bob)
140 console.log('CI bot: %s\n', ci)
141
142 console.log('1. Grant alice admin on repo-x')
143 await ctx.tm.grant(alice, 'repo-x', ['read', 'write', 'admin'])
144
145 console.log('2. Grant bob read+write on repo-x')
146 await ctx.tm.grant(bob, 'repo-x', ['read', 'write'])
147
148 console.log('3. Grant CI bot read on ALL repos (wildcard)')
149 await ctx.tm.grant(ci, '*', ['read'])
150 console.log()
151
152 console.log('Checks:')
153 console.log(' alice can admin repo-x: %s', await ctx.tm.check(alice, 'repo-x', 'admin'))
154 console.log(' bob can write repo-x: %s', await ctx.tm.check(bob, 'repo-x', 'write'))
155 console.log(' bob can admin repo-x: %s (should be NO)', await ctx.tm.check(bob, 'repo-x', 'admin'))
156 console.log(' ci can read repo-y: %s (via wildcard)', await ctx.tm.check(ci, 'repo-y', 'read'))
157 console.log(' ci can write repo-y: %s (should be NO)', await ctx.tm.check(ci, 'repo-y', 'write'))
158 console.log()
159
160 console.log('4. Revoke bob\'s write on repo-x')
161 await ctx.tm.revoke(bob, 'repo-x', ['write'])
162 console.log(' bob can write repo-x: %s (should be NO now)', await ctx.tm.check(bob, 'repo-x', 'write'))
163 console.log(' bob can read repo-x: %s (still YES)', await ctx.tm.check(bob, 'repo-x', 'read'))
164
165 await close(ctx)
166 return
167 }
168
169 console.log('trust-map example CLI')
170 console.log(' init Initialize storage')
171 console.log(' grant <pubkey> <resource> <perms,...> Grant permissions')
172 console.log(' revoke <pubkey> <resource> [perms,...] Revoke permissions')
173 console.log(' check <pubkey> <resource> <perm> Check a permission')
174 console.log(' list List all entries')
175 console.log(' for <pubkey> List entries for one pubkey')
176 console.log(' demo Run a full demo with random keypairs')
177 console.log('')
178 console.log('Storage: TRUST_MAP_STORE env var (default: ./.trust-map-cli)')
179 console.log('Note: this CLI does NOT share state with examples/web.js — they use')
180 console.log('different storage paths because RocksDB only allows one writer.')
181}
182
183main().catch((err) => { console.error(err.message); process.exit(1) })
examples/web.js +195 -0
……@@ -0,0 +1,195 @@
1#!/usr/bin/env node
2/**
3 * Mini web example for trust-map
4 *
5 * SSR dashboard for browsing and managing the trust map. CLI ↔ Web operate
6 * on the same Hyperbee, so changes from the CLI show up in the web UI on
7 * refresh (and vice versa).
8 *
9 * Usage: node examples/web.js [--port 9094] [--storage <path>]
10 */
11
12import http from 'http'
13import Corestore from 'corestore'
14import { TrustMap } from '../index.js'
15import b4a from 'b4a'
16
17const args = process.argv.slice(2)
18function getFlag (name) {
19 const i = args.indexOf('--' + name)
20 return i !== -1 && args[i + 1] ? args[i + 1] : null
21}
22
23const port = parseInt(getFlag('port')) || 9094
24// NOTE: distinct default from examples/cli.js — they don't share state.
25// See cli.js header for the rationale (RocksDB single-writer lock).
26const storagePath = getFlag('storage') || './.trust-map-web'
27
28const store = new Corestore(storagePath)
29await store.ready()
30const core = store.get({ name: 'trust-map' })
31await core.ready()
32const tm = new TrustMap({ core })
33await tm.ready()
34
35function escapeHtml (s) {
36 return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;')
37}
38
39function collectBody (req) {
40 return new Promise((resolve, reject) => {
41 const parts = []
42 req.on('data', chunk => parts.push(chunk))
43 req.on('end', () => resolve(b4a.concat(parts).toString('utf8')))
44 req.on('error', reject)
45 })
46}
47
48const httpServer = http.createServer(async (req, res) => {
49 const url = req.url.split('?')[0]
50
51 try {
52 if (req.method === 'GET' && url === '/') {
53 const entries = await tm.list()
54 res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })
55 res.end(renderPage(entries))
56 return
57 }
58
59 if (req.method === 'POST' && url === '/grant') {
60 const body = await collectBody(req)
61 const params = new URLSearchParams(body)
62 const pubkey = params.get('pubkey')
63 const resource = params.get('resource')
64 const permsStr = params.get('perms')
65 if (pubkey && resource && permsStr) {
66 const perms = permsStr.split(',').map(s => s.trim()).filter(Boolean)
67 if (perms.length) await tm.grant(pubkey, resource, perms)
68 }
69 res.writeHead(303, { Location: '/' })
70 res.end()
71 return
72 }
73
74 if (req.method === 'POST' && url === '/revoke') {
75 const body = await collectBody(req)
76 const params = new URLSearchParams(body)
77 const pubkey = params.get('pubkey')
78 const resource = params.get('resource')
79 if (pubkey && resource) {
80 await tm.revoke(pubkey, resource)
81 }
82 res.writeHead(303, { Location: '/' })
83 res.end()
84 return
85 }
86
87 res.writeHead(404, { 'Content-Type': 'text/plain' })
88 res.end('Not found')
89 } catch (err) {
90 console.error(err)
91 res.writeHead(500, { 'Content-Type': 'text/plain' })
92 res.end(err.message)
93 }
94})
95
96function renderPage (entries) {
97 const grouped = {}
98 for (const e of entries) {
99 if (!grouped[e.pubkey]) grouped[e.pubkey] = []
100 grouped[e.pubkey].push(e)
101 }
102 const pubkeys = Object.keys(grouped).sort()
103
104 return `<!DOCTYPE html>
105<html><head><title>trust-map</title>
106<style>
107 body { font-family: monospace; background: #0d1117; color: #c9d1d9; padding: 2rem; max-width: 900px; margin: 0 auto; }
108 h1 { color: #58a6ff; }
109 h2 { font-size: 1rem; color: #58a6ff; margin-top: 1.5rem; }
110 .card { background: #161b22; border: 1px solid #30363d; border-radius: 6px; padding: 1rem; margin: 1rem 0; }
111 .card h2 { margin: 0 0 0.5rem; font-size: 0.75rem; text-transform: uppercase; color: #8b949e; }
112 table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
113 th { text-align: left; color: #8b949e; padding: 0.4rem 0.5rem; border-bottom: 1px solid #30363d; }
114 td { padding: 0.4rem 0.5rem; border-bottom: 1px solid #21262d; }
115 .pubkey { font-family: monospace; color: #79c0ff; font-size: 0.8rem; }
116 .perm { display: inline-block; background: #1f6feb22; border: 1px solid #1f6feb44; color: #58a6ff; padding: 0.1rem 0.4rem; border-radius: 3px; font-size: 0.75rem; margin-right: 0.3rem; }
117 .perm-admin { background: #f8514922; border-color: #f8514944; color: #f85149; }
118 .perm-write { background: #d29922aa; border-color: #d2992244; color: #d29922; }
119 input, button { background: #0d1117; color: #c9d1d9; border: 1px solid #30363d; padding: 0.4rem 0.6rem; border-radius: 4px; font-family: monospace; font-size: 0.85rem; }
120 input { margin-right: 0.3rem; }
121 input.long { width: 30rem; }
122 button { background: #21262d; cursor: pointer; }
123 button:hover { background: #30363d; }
124 button.btn-primary { background: #1f6feb; border-color: #1f6feb; color: white; }
125 button.btn-primary:hover { background: #1158c7; }
126 button.btn-danger { border-color: #f8514966; color: #f85149; padding: 0.2rem 0.5rem; font-size: 0.75rem; }
127 .empty { color: #484f58; font-style: italic; padding: 1rem; }
128</style></head><body>
129<h1>trust-map</h1>
130
131<div class="card">
132 <h2>Stats</h2>
133 <div>${pubkeys.length} pubkey(s) · ${entries.length} grant(s)</div>
134</div>
135
136<div class="card">
137 <h2>Grant permissions</h2>
138 <form method="POST" action="/grant">
139 <div style="margin-bottom: 0.5rem">
140 <input class="long" name="pubkey" placeholder="pubkey (hex or base64)" required>
141 </div>
142 <div style="margin-bottom: 0.5rem">
143 <input name="resource" placeholder="resource name (or *)" required>
144 <input name="perms" placeholder="perms (comma-separated, e.g. read,write)" required>
145 <button class="btn-primary" type="submit">Grant</button>
146 </div>
147 </form>
148</div>
149
150<div class="card">
151 <h2>Trust map (${entries.length} entries)</h2>
152 ${pubkeys.length === 0 ? '<div class="empty">(empty — grant something to get started)</div>' : pubkeys.map(pk => `
153 <h2 style="margin-top: 1rem">${escapeHtml(pk)}</h2>
154 <table>
155 <thead><tr><th>Resource</th><th>Permissions</th><th></th></tr></thead>
156 <tbody>
157 ${grouped[pk].map(e => `
158 <tr>
159 <td>${escapeHtml(e.resource)}</td>
160 <td>${e.perms.map(p => `<span class="perm ${p === 'admin' ? 'perm-admin' : p === 'write' ? 'perm-write' : ''}">${escapeHtml(p)}</span>`).join('')}</td>
161 <td>
162 <form method="POST" action="/revoke" style="margin: 0">
163 <input type="hidden" name="pubkey" value="${escapeHtml(pk)}">
164 <input type="hidden" name="resource" value="${escapeHtml(e.resource)}">
165 <button class="btn-danger" type="submit">revoke</button>
166 </form>
167 </td>
168 </tr>`).join('')}
169 </tbody>
170 </table>`).join('')}
171</div>
172
173<div class="card">
174 <h2>How this works</h2>
175 <p style="font-size: 0.85rem; line-height: 1.6">
176 This dashboard manages a <code>trust-map</code> instance backed by a Hyperbee.
177 It shares storage with the CLI example — anything you grant here is visible
178 to <code>cli.js list</code>, and vice versa. Wildcard resource <code>*</code>
179 grants apply to all resources for that pubkey.
180 </p>
181 <p style="font-size: 0.85rem; line-height: 1.6">
182 For chain verification (hyperident attestations), the trust-map module's
183 <code>checkChain()</code> method is exercised by the unit tests. The web
184 UI shows direct grants only.
185 </p>
186</div>
187
188</body></html>`
189}
190
191httpServer.listen(port, () => {
192 console.log('trust-map dashboard:')
193 console.log(' http://localhost:%d', port)
194 console.log(' storage: %s', storagePath)
195})
index.js +10 -0
……@@ -0,0 +1,10 @@
1/**
2 * trust-map — pubkey → permissions store with optional chain verification
3 *
4 * Bridges the gap between hyperident's device chains and the node's
5 * permission system. The node stores ROOTS (master pubkeys); when a peer
6 * presents a hyperident-signed proof, trust-map verifies the chain via
7 * keet-identity-key and looks up the root.
8 */
9
10export { TrustMap } from './lib/trust-map.js'
lib/trust-map.js +222 -0
……@@ -0,0 +1,222 @@
1/**
2 * TrustMap — pubkey → permissions store backed by Hyperbee.
3 *
4 * Two modes of access checking:
5 *
6 * 1. DIRECT: a peer's pubkey is directly registered with permissions.
7 * Used by services, CI runners, single-keypair clients.
8 *
9 * tm.grant(pubkey, 'repo-x', ['read', 'write'])
10 * tm.check(pubkey, 'repo-x', 'write') // → true
11 *
12 * 2. CHAIN: a peer presents a hyperident-style attestation chain (signed
13 * by their master identity via keet-identity-key). Trust-map verifies
14 * the chain, extracts the master (identityPublicKey), and looks it up.
15 * Devices inherit permissions from their master.
16 *
17 * tm.grant(masterPubkey, 'repo-y', ['admin'])
18 * tm.checkChain({ proof, data, resource: 'repo-y', perm: 'admin' })
19 *
20 * The check() functions accept either Buffer or hex string pubkeys.
21 *
22 * Storage layout (Hyperbee, JSON values):
23 * trust:{pubkey-hex}:{resource} → { perms: [...] }
24 *
25 * Wildcard resource '*' grants apply to ALL resources.
26 */
27
28import ReadyResource from 'ready-resource'
29import Hyperbee from 'hyperbee'
30import b4a from 'b4a'
31
32export class TrustMap extends ReadyResource {
33 /**
34 * @param {object} opts
35 * @param {Hypercore|Hyperbee} opts.core - hypercore to wrap (or pass `bee`)
36 * @param {Hyperbee} [opts.bee] - existing hyperbee
37 * @param {object} [opts.identityKey] - keet-identity-key module for chain verify
38 */
39 constructor (opts = {}) {
40 super()
41 this._bee = opts.bee || null
42 this._core = opts.core || null
43 this._identityKey = opts.identityKey || null
44 }
45
46 async _open () {
47 if (!this._bee && this._core) {
48 this._bee = new Hyperbee(this._core, {
49 keyEncoding: 'utf-8',
50 valueEncoding: 'json'
51 })
52 }
53 if (!this._bee) throw new Error('TrustMap requires `core` or `bee` opt')
54 await this._bee.ready()
55 }
56
57 async _close () {
58 // Don't close the bee/core — caller owns them
59 }
60
61 // ── Helpers ──────────────────────────────────────────────────
62
63 static _toHex (pubkey) {
64 if (typeof pubkey === 'string') return pubkey
65 return b4a.toString(pubkey, 'hex')
66 }
67
68 _key (pubkey, resource) {
69 return `trust:${TrustMap._toHex(pubkey)}:${resource}`
70 }
71
72 // ── Direct grants ────────────────────────────────────────────
73
74 /**
75 * Grant permissions to a pubkey for a resource.
76 * @param {string|Buffer} pubkey
77 * @param {string} resource - resource name, or '*' for all resources
78 * @param {string[]} perms - e.g. ['read', 'write', 'admin']
79 */
80 async grant (pubkey, resource, perms) {
81 if (!Array.isArray(perms) || perms.length === 0) {
82 throw new Error('perms must be a non-empty array')
83 }
84 const key = this._key(pubkey, resource)
85 const existing = await this._bee.get(key)
86 const merged = existing
87 ? Array.from(new Set([...existing.value.perms, ...perms]))
88 : [...perms]
89 await this._bee.put(key, { perms: merged })
90 }
91
92 /**
93 * Revoke specific permissions (or all if perms omitted) for a pubkey/resource.
94 * @param {string|Buffer} pubkey
95 * @param {string} resource
96 * @param {string[]} [perms] - if omitted, removes all perms for this resource
97 */
98 async revoke (pubkey, resource, perms) {
99 const key = this._key(pubkey, resource)
100 const existing = await this._bee.get(key)
101 if (!existing) return
102
103 if (!perms || perms.length === 0) {
104 await this._bee.del(key)
105 return
106 }
107 const remaining = existing.value.perms.filter(p => !perms.includes(p))
108 if (remaining.length === 0) {
109 await this._bee.del(key)
110 } else {
111 await this._bee.put(key, { perms: remaining })
112 }
113 }
114
115 /**
116 * Check if a pubkey has a specific permission on a resource.
117 * Falls back to wildcard '*' resource if exact match has no entry or
118 * lacks the requested permission.
119 * @param {string|Buffer} pubkey
120 * @param {string} resource
121 * @param {string} perm
122 * @returns {Promise<boolean>}
123 */
124 async check (pubkey, resource, perm) {
125 const exact = await this._bee.get(this._key(pubkey, resource))
126 if (exact && exact.value.perms.includes(perm)) return true
127
128 const wildcard = await this._bee.get(this._key(pubkey, '*'))
129 if (wildcard && wildcard.value.perms.includes(perm)) return true
130
131 return false
132 }
133
134 /**
135 * List all entries for a pubkey across resources.
136 * @param {string|Buffer} pubkey
137 * @returns {Promise<Array<{ resource: string, perms: string[] }>>}
138 */
139 async listForPubkey (pubkey) {
140 const hex = TrustMap._toHex(pubkey)
141 const prefix = `trust:${hex}:`
142 const out = []
143 for await (const entry of this._bee.createReadStream({
144 gte: prefix,
145 lt: prefix + '\xff'
146 })) {
147 out.push({
148 resource: entry.key.slice(prefix.length),
149 perms: entry.value.perms
150 })
151 }
152 return out
153 }
154
155 /**
156 * List all trust map entries.
157 * @returns {Promise<Array<{ pubkey: string, resource: string, perms: string[] }>>}
158 */
159 async list () {
160 const out = []
161 for await (const entry of this._bee.createReadStream({
162 gte: 'trust:',
163 lt: 'trust:\xff'
164 })) {
165 const parts = entry.key.split(':')
166 // key format: trust:{pubkey-hex}:{resource}
167 // resource may contain colons, so rejoin from index 2
168 const pubkey = parts[1]
169 const resource = parts.slice(2).join(':')
170 out.push({ pubkey, resource, perms: entry.value.perms })
171 }
172 return out
173 }
174
175 // ── Chain verification (via keet-identity-key) ───────────────
176
177 /**
178 * Verify a hyperident attestation chain and check permissions for the
179 * MASTER identity (root of the chain).
180 *
181 * Caller passes the proof bytes and the data that was signed. We use
182 * keet-identity-key to verify the proof and extract the identityPublicKey
183 * (master). We then look up the master in the trust map.
184 *
185 * @param {object} args
186 * @param {Buffer} args.proof - the attestation proof from hyperident
187 * @param {Buffer} args.data - the data that was signed
188 * @param {string} args.resource - the resource being accessed
189 * @param {string} args.perm - the permission being checked
190 * @returns {Promise<{ ok: boolean, masterPubkey?: string, devicePubkey?: string, reason?: string }>}
191 */
192 async checkChain ({ proof, data, resource, perm }) {
193 if (!this._identityKey) {
194 return { ok: false, reason: 'no identityKey module configured' }
195 }
196 if (!proof || !data) {
197 return { ok: false, reason: 'proof and data required' }
198 }
199
200 let verification
201 try {
202 verification = this._identityKey.verify(proof, data)
203 } catch (err) {
204 return { ok: false, reason: 'verify threw: ' + err.message }
205 }
206
207 if (!verification) {
208 return { ok: false, reason: 'invalid attestation' }
209 }
210
211 const masterPubkey = TrustMap._toHex(verification.identityPublicKey)
212 const devicePubkey = TrustMap._toHex(verification.devicePublicKey)
213
214 // Look up the master in the trust map (devices inherit master's permissions)
215 const allowed = await this.check(masterPubkey, resource, perm)
216 if (!allowed) {
217 return { ok: false, masterPubkey, devicePubkey, reason: 'master not authorized for ' + perm + ' on ' + resource }
218 }
219
220 return { ok: true, masterPubkey, devicePubkey }
221 }
222}
package-lock.json +1454 -0
……@@ -0,0 +1,1454 @@
1{
2 "name": "trust-map",
3 "version": "0.1.0",
4 "lockfileVersion": 3,
5 "requires": true,
6 "packages": {
7 "": {
8 "name": "trust-map",
9 "version": "0.1.0",
10 "dependencies": {
11 "b4a": "^1.6.0",
12 "hyperbee": "^2.20.0",
13 "hypercore": "^11.0.0",
14 "ready-resource": "^1.1.0"
15 },
16 "devDependencies": {
17 "brittle": "^3.0.0",
18 "corestore": "^7.0.0",
19 "hypercore-crypto": "^3.4.0",
20 "keet-identity-key": "^3.0.0"
21 }
22 },
23 "node_modules/@hyperswarm/secret-stream": {
24 "version": "6.9.1",
25 "resolved": "https://registry.npmjs.org/@hyperswarm/secret-stream/-/secret-stream-6.9.1.tgz",
26 "integrity": "sha512-xb0S5y3YJwBakD77JOGBHlBxdp63mHClZoXBYoLv+9wH8e054ESKlmQptWqjJK5dv5VMUIVYOJB4MaOpB0JdGw==",
27 "license": "Apache-2.0",
28 "dependencies": {
29 "b4a": "^1.1.0",
30 "hypercore-crypto": "^3.3.1",
31 "noise-curve-ed": "^2.0.1",
32 "noise-handshake": "^4.0.0",
33 "sodium-secretstream": "^1.1.0",
34 "sodium-universal": "^5.0.0",
35 "streamx": "^2.14.0",
36 "timeout-refresh": "^2.0.0",
37 "unslab": "^1.3.0"
38 }
39 },
40 "node_modules/@jridgewell/resolve-uri": {
41 "version": "3.1.2",
42 "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
43 "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
44 "dev": true,
45 "license": "MIT",
46 "engines": {
47 "node": ">=6.0.0"
48 }
49 },
50 "node_modules/@jridgewell/sourcemap-codec": {
51 "version": "1.5.5",
52 "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
53 "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
54 "dev": true,
55 "license": "MIT"
56 },
57 "node_modules/@jridgewell/trace-mapping": {
58 "version": "0.3.31",
59 "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
60 "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
61 "dev": true,
62 "license": "MIT",
63 "dependencies": {
64 "@jridgewell/resolve-uri": "^3.1.0",
65 "@jridgewell/sourcemap-codec": "^1.4.14"
66 }
67 },
68 "node_modules/@types/istanbul-lib-coverage": {
69 "version": "2.0.6",
70 "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
71 "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
72 "dev": true,
73 "license": "MIT"
74 },
75 "node_modules/b4a": {
76 "version": "1.8.0",
77 "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz",
78 "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==",
79 "license": "Apache-2.0",
80 "peerDependencies": {
81 "react-native-b4a": "*"
82 },
83 "peerDependenciesMeta": {
84 "react-native-b4a": {
85 "optional": true
86 }
87 }
88 },
89 "node_modules/bare-abort": {
90 "version": "2.0.13",
91 "resolved": "https://registry.npmjs.org/bare-abort/-/bare-abort-2.0.13.tgz",
92 "integrity": "sha512-zdc8l88eB11Jsz5rDd6sCAgv2kUFXgdrZWoMlgU6JMkfAi1/uuGFC3IEHswKbIRQTk5H3T5CMuechsXYxiaHlQ==",
93 "dev": true,
94 "license": "Apache-2.0"
95 },
96 "node_modules/bare-addon-resolve": {
97 "version": "1.10.0",
98 "resolved": "https://registry.npmjs.org/bare-addon-resolve/-/bare-addon-resolve-1.10.0.tgz",
99 "integrity": "sha512-sSd0jieRJlDaODOzj0oe0RjFVC1QI0ZIjGIdPkbrTXsdVVtENg14c+lHHAhHwmWCZ2nQlMhy8jA3Y5LYPc/isA==",
100 "license": "Apache-2.0",
101 "dependencies": {
102 "bare-module-resolve": "^1.10.0",
103 "bare-semver": "^1.0.0"
104 },
105 "peerDependencies": {
106 "bare-url": "*"
107 },
108 "peerDependenciesMeta": {
109 "bare-url": {
110 "optional": true
111 }
112 }
113 },
114 "node_modules/bare-ansi-escapes": {
115 "version": "2.2.3",
116 "resolved": "https://registry.npmjs.org/bare-ansi-escapes/-/bare-ansi-escapes-2.2.3.tgz",
117 "integrity": "sha512-02ES4/E2RbrtZSnHJ9LntBhYkLA6lPpSEeP8iqS3MccBIVhVBlEmruF1I7HZqx5Q8aiTeYfQVeqmrU9YO2yYoQ==",
118 "license": "Apache-2.0",
119 "dependencies": {
120 "bare-stream": "^2.6.5"
121 },
122 "peerDependencies": {
123 "bare-buffer": "*"
124 },
125 "peerDependenciesMeta": {
126 "bare-buffer": {
127 "optional": true
128 }
129 }
130 },
131 "node_modules/bare-assert": {
132 "version": "1.2.0",
133 "resolved": "https://registry.npmjs.org/bare-assert/-/bare-assert-1.2.0.tgz",
134 "integrity": "sha512-c6uvgvTJBspTDxtVnPgrBKmLgcpW3Fp72NVKDLg6oT4QjQbhGtvrkHMhGYMK1sh4vjBHOBmuUalyt9hSzV37fQ==",
135 "license": "Apache-2.0",
136 "dependencies": {
137 "bare-inspect": "^3.1.2"
138 }
139 },
140 "node_modules/bare-bundle": {
141 "version": "1.10.0",
142 "resolved": "https://registry.npmjs.org/bare-bundle/-/bare-bundle-1.10.0.tgz",
143 "integrity": "sha512-4LVlnJAHr00Hh6Vu6ZUJS38rcEtJT3b3vChXSsBsJ2mk1TN0lQ+gzd+Dw5L0aV7uqDZv84smuwW+O02X7PfDlw==",
144 "dev": true,
145 "license": "Apache-2.0",
146 "peerDependencies": {
147 "bare-buffer": "*",
148 "bare-url": "*"
149 },
150 "peerDependenciesMeta": {
151 "bare-buffer": {
152 "optional": true
153 },
154 "bare-url": {
155 "optional": true
156 }
157 }
158 },
159 "node_modules/bare-cov": {
160 "version": "1.2.1",
161 "resolved": "https://registry.npmjs.org/bare-cov/-/bare-cov-1.2.1.tgz",
162 "integrity": "sha512-SHNqb/WG9udUEj8m5qGSehoUQ9o0Xzv8nrf4HIdmG+KNU/XdhPLhTP5VPrHnSAMAXhAzEB4Q+2IYZ0x9qPzN1g==",
163 "dev": true,
164 "license": "Apache-2.0",
165 "dependencies": {
166 "bare-fs": "^4.1.2",
167 "bare-inspector": "^4.0.1",
168 "bare-path": "^3.0.0",
169 "bare-process": "^4.2.1",
170 "bare-url": "^2.1.5",
171 "bare-v8-to-istanbul": "^1.0.2",
172 "picomatch": "^4.0.2",
173 "which-runtime": "^1.2.1"
174 }
175 },
176 "node_modules/bare-crypto": {
177 "version": "1.13.4",
178 "resolved": "https://registry.npmjs.org/bare-crypto/-/bare-crypto-1.13.4.tgz",
179 "integrity": "sha512-JiCZ5l2YOG1y8J7yy1BCAKTCZrPnHLb7pDRIdurBTOn5oIwBQDIv8iH5Pl2V85vzjl1NZXRfNY4HZLsE942jJA==",
180 "dev": true,
181 "license": "Apache-2.0",
182 "dependencies": {
183 "bare-assert": "^1.2.0",
184 "bare-stream": "^2.6.3"
185 },
186 "peerDependencies": {
187 "bare-buffer": "*"
188 },
189 "peerDependenciesMeta": {
190 "bare-buffer": {
191 "optional": true
192 }
193 }
194 },
195 "node_modules/bare-debug-log": {
196 "version": "2.0.0",
197 "resolved": "https://registry.npmjs.org/bare-debug-log/-/bare-debug-log-2.0.0.tgz",
198 "integrity": "sha512-Vi42PkMQsNV9PUpx2Gl1hikshx5O9FzMJ6o9Nnopseg7qLBBK7Nl31d0RHcfwLEAfmcPApytpc0ZFfq68u22FQ==",
199 "dev": true,
200 "license": "Apache-2.0",
201 "dependencies": {
202 "bare-os": "^3.0.1"
203 }
204 },
205 "node_modules/bare-dns": {
206 "version": "2.1.4",
207 "resolved": "https://registry.npmjs.org/bare-dns/-/bare-dns-2.1.4.tgz",
208 "integrity": "sha512-abwjHmpWqSRNB7V5615QxPH92L71AVzFm/kKTs8VYiNTAi2xVdonpv0BjJ0hwXLwomoW+xsSOPjW6PZPO14asg==",
209 "dev": true,
210 "license": "Apache-2.0",
211 "engines": {
212 "bare": ">=1.7.0"
213 }
214 },
215 "node_modules/bare-encoding": {
216 "version": "1.0.3",
217 "resolved": "https://registry.npmjs.org/bare-encoding/-/bare-encoding-1.0.3.tgz",
218 "integrity": "sha512-Kqf+t/azs13lUeyK4Tb7ha4wdLRXKWCXQ8w1rVmt7KtoPCPdHD/Xwt7LBIsCSwwGglrcmblo5VOLa5avkJqULA==",
219 "dev": true,
220 "license": "Apache-2.0",
221 "peerDependencies": {
222 "bare-buffer": "*"
223 },
224 "peerDependenciesMeta": {
225 "bare-buffer": {
226 "optional": true
227 }
228 }
229 },
230 "node_modules/bare-env": {
231 "version": "3.0.0",
232 "resolved": "https://registry.npmjs.org/bare-env/-/bare-env-3.0.0.tgz",
233 "integrity": "sha512-0u964P5ZLAxTi+lW4Kjp7YRJQ5gZr9ycYOtjLxsSrupgMz3sn5Z9n4SH/JIifHwvadsf1brA2JAjP+9IOWwTiw==",
234 "dev": true,
235 "license": "Apache-2.0",
236 "dependencies": {
237 "bare-os": "^3.0.1"
238 }
239 },
240 "node_modules/bare-events": {
241 "version": "2.8.2",
242 "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz",
243 "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==",
244 "license": "Apache-2.0",
245 "peerDependencies": {
246 "bare-abort-controller": "*"
247 },
248 "peerDependenciesMeta": {
249 "bare-abort-controller": {
250 "optional": true
251 }
252 }
253 },
254 "node_modules/bare-format": {
255 "version": "1.0.2",
256 "resolved": "https://registry.npmjs.org/bare-format/-/bare-format-1.0.2.tgz",
257 "integrity": "sha512-GswdhnOnP9QtwRbrf4wLApw5widkaLMsLe2XOs35fQD2YfEN1ApoGka+cZ7PfvzxMgfYXmMhj/2OGlVn5/Dxgw==",
258 "dev": true,
259 "license": "Apache-2.0",
260 "dependencies": {
261 "bare-inspect": "^3.0.0"
262 }
263 },
264 "node_modules/bare-fs": {
265 "version": "4.7.0",
266 "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.0.tgz",
267 "integrity": "sha512-xzqKsCFxAek9aezYhjJuJRXBIaYlg/0OGDTZp+T8eYmYMlm66cs6cYko02drIyjN2CBbi+I6L7YfXyqpqtKRXA==",
268 "license": "Apache-2.0",
269 "dependencies": {
270 "bare-events": "^2.5.4",
271 "bare-path": "^3.0.0",
272 "bare-stream": "^2.6.4",
273 "bare-url": "^2.2.2",
274 "fast-fifo": "^1.3.2"
275 },
276 "engines": {
277 "bare": ">=1.16.0"
278 },
279 "peerDependencies": {
280 "bare-buffer": "*"
281 },
282 "peerDependenciesMeta": {
283 "bare-buffer": {
284 "optional": true
285 }
286 }
287 },
288 "node_modules/bare-hrtime": {
289 "version": "2.1.1",
290 "resolved": "https://registry.npmjs.org/bare-hrtime/-/bare-hrtime-2.1.1.tgz",
291 "integrity": "sha512-VMb3tHo05gsnbu3OXTmkDiwTjMlOsbQmKoysKqKEyR09m77TuDrYFbj3Q5GGk10dAKsUHrnXmwCaeJqzVpB5ZA==",
292 "dev": true,
293 "license": "Apache-2.0"
294 },
295 "node_modules/bare-http-parser": {
296 "version": "1.1.3",
297 "resolved": "https://registry.npmjs.org/bare-http-parser/-/bare-http-parser-1.1.3.tgz",
298 "integrity": "sha512-+dhVvQi6brHq14L/XHNRQ+TLuVE76VjRmMt61wVEtS+Od8xUslfMHWJN/ZjIIt3RtTG6vPuA+x9cOh7KrkBJsA==",
299 "dev": true,
300 "license": "Apache-2.0"
301 },
302 "node_modules/bare-http1": {
303 "version": "4.5.6",
304 "resolved": "https://registry.npmjs.org/bare-http1/-/bare-http1-4.5.6.tgz",
305 "integrity": "sha512-31OAwMkSU+z1VuUOCk65hx3aWQgzCfH/zQ6LGxbJtmiy2Czsw0+uvOBM9YkqaL6zUSTSYG2pLbL0v/TjME3Buw==",
306 "dev": true,
307 "license": "Apache-2.0",
308 "dependencies": {
309 "bare-events": "^2.6.0",
310 "bare-http-parser": "^1.1.1",
311 "bare-stream": "^2.10.0",
312 "bare-tcp": "^2.2.0"
313 },
314 "peerDependencies": {
315 "bare-buffer": "*",
316 "bare-url": "*"
317 },
318 "peerDependenciesMeta": {
319 "bare-buffer": {
320 "optional": true
321 },
322 "bare-url": {
323 "optional": true
324 }
325 }
326 },
327 "node_modules/bare-https": {
328 "version": "2.1.3",
329 "resolved": "https://registry.npmjs.org/bare-https/-/bare-https-2.1.3.tgz",
330 "integrity": "sha512-0TI/mJXQGYXmG7UUyWEG+KCJusayIAQLywUjFAskDoKuxfqVnGF+M/mTMrEV8J64DaIdU+5x761FvgmT7M68tA==",
331 "dev": true,
332 "license": "Apache-2.0",
333 "dependencies": {
334 "bare-http1": "^4.4.0",
335 "bare-tcp": "^2.2.0",
336 "bare-tls": "^2.0.0"
337 }
338 },
339 "node_modules/bare-inspect": {
340 "version": "3.1.4",
341 "resolved": "https://registry.npmjs.org/bare-inspect/-/bare-inspect-3.1.4.tgz",
342 "integrity": "sha512-jfW5KRA84o3REpI6Vr4nbvMn+hqVAw8GU1mMdRwUsY5yJovQamxYeKGVKGqdzs+8ZbG4jRzGUXP/3Ji/DnqfPg==",
343 "license": "Apache-2.0",
344 "dependencies": {
345 "bare-ansi-escapes": "^2.1.0",
346 "bare-type": "^1.0.0"
347 },
348 "engines": {
349 "bare": ">=1.18.0"
350 }
351 },
352 "node_modules/bare-inspector": {
353 "version": "4.0.3",
354 "resolved": "https://registry.npmjs.org/bare-inspector/-/bare-inspector-4.0.3.tgz",
355 "integrity": "sha512-yYk6+7tTVKJKHOja5+QBn989ETv8oVsmwoH0nCM+QYC6w5MC03GC4aQNK+lipAZSz1EaAj42WZ8Wewjpy0L9TA==",
356 "dev": true,
357 "license": "Apache-2.0",
358 "dependencies": {
359 "bare-events": "^2.1.0",
360 "bare-http1": "^4.0.0",
361 "bare-stream": "^2.0.0",
362 "bare-url": "^2.0.0",
363 "bare-ws": "^2.0.0"
364 },
365 "engines": {
366 "bare": ">=1.2.0"
367 },
368 "peerDependencies": {
369 "bare-tcp": "*"
370 },
371 "peerDependenciesMeta": {
372 "bare-tcp": {
373 "optional": true
374 }
375 }
376 },
377 "node_modules/bare-module": {
378 "version": "6.1.3",
379 "resolved": "https://registry.npmjs.org/bare-module/-/bare-module-6.1.3.tgz",
380 "integrity": "sha512-5XWsVHsvtWMH4tK4DQWgpNTV0t/sg3ZrAaQLIxrwjrS5+u8Q9vEgc/zQ4QaDPWDse/y/5h+d+YG1Q0JfSMt0zA==",
381 "dev": true,
382 "license": "Apache-2.0",
383 "dependencies": {
384 "bare-bundle": "^1.3.0",
385 "bare-module-lexer": "^1.0.0",
386 "bare-module-resolve": "^1.8.0",
387 "bare-path": "^3.0.0",
388 "bare-url": "^2.0.1"
389 },
390 "engines": {
391 "bare": ">=1.23.0"
392 },
393 "peerDependencies": {
394 "bare-buffer": "*"
395 },
396 "peerDependenciesMeta": {
397 "bare-buffer": {
398 "optional": true
399 }
400 }
401 },
402 "node_modules/bare-module-lexer": {
403 "version": "1.4.7",
404 "resolved": "https://registry.npmjs.org/bare-module-lexer/-/bare-module-lexer-1.4.7.tgz",
405 "integrity": "sha512-0klU4eMsjh/wcxi8FdHmNom2j2F4kmkXOhyJFL9qTaSFp2lE3m6BtbKgMHY8R5miqC9r8/IfA8wzXnC5Os14WA==",
406 "dev": true,
407 "license": "Apache-2.0",
408 "dependencies": {
409 "require-addon": "^1.0.2"
410 },
411 "peerDependencies": {
412 "bare-buffer": "*"
413 },
414 "peerDependenciesMeta": {
415 "bare-buffer": {
416 "optional": true
417 }
418 }
419 },
420 "node_modules/bare-module-resolve": {
421 "version": "1.12.1",
422 "resolved": "https://registry.npmjs.org/bare-module-resolve/-/bare-module-resolve-1.12.1.tgz",
423 "integrity": "sha512-hbmAPyFpEq8FoZMd5sFO3u6MC5feluWoGE8YKlA8fCrl6mNtx68Wjg4DTiDJcqRJaovTvOYKfYngoBUnbaT7eg==",
424 "license": "Apache-2.0",
425 "dependencies": {
426 "bare-semver": "^1.0.0"
427 },
428 "peerDependencies": {
429 "bare-url": "*"
430 },
431 "peerDependenciesMeta": {
432 "bare-url": {
433 "optional": true
434 }
435 }
436 },
437 "node_modules/bare-net": {
438 "version": "2.3.1",
439 "resolved": "https://registry.npmjs.org/bare-net/-/bare-net-2.3.1.tgz",
440 "integrity": "sha512-MypSqDKpDU2Xt7FIfazn5yGvRnV09gFcIPHGWstW0gxuzA4tucTcwJSZeos97C4F89vtU5oGwXDN/HrGN6Y4Jw==",
441 "dev": true,
442 "license": "Apache-2.0",
443 "dependencies": {
444 "bare-events": "^2.2.2",
445 "bare-pipe": "^4.0.0",
446 "bare-stream": "^2.0.0",
447 "bare-tcp": "^2.0.0"
448 }
449 },
450 "node_modules/bare-os": {
451 "version": "3.8.7",
452 "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.8.7.tgz",
453 "integrity": "sha512-G4Gr1UsGeEy2qtDTZwL7JFLo2wapUarz7iTMcYcMFdS89AIQuBoyjgXZz0Utv7uHs3xA9LckhVbeBi8lEQrC+w==",
454 "license": "Apache-2.0",
455 "engines": {
456 "bare": ">=1.14.0"
457 }
458 },
459 "node_modules/bare-path": {
460 "version": "3.0.0",
461 "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz",
462 "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==",
463 "license": "Apache-2.0",
464 "dependencies": {
465 "bare-os": "^3.0.1"
466 }
467 },
468 "node_modules/bare-pipe": {
469 "version": "4.1.5",
470 "resolved": "https://registry.npmjs.org/bare-pipe/-/bare-pipe-4.1.5.tgz",
471 "integrity": "sha512-6OfxaG8JSkRh3Gc4hzHRsxNt+yu2PpN7lrv1V+T78GdknWQkVGwiEvu4m+1nbfk8cMVQ0TGxRvQ90XA4rhnTuw==",
472 "dev": true,
473 "license": "Apache-2.0",
474 "dependencies": {
475 "bare-events": "^2.0.0",
476 "bare-stream": "^2.0.0"
477 },
478 "engines": {
479 "bare": ">=1.16.0"
480 }
481 },
482 "node_modules/bare-process": {
483 "version": "4.4.1",
484 "resolved": "https://registry.npmjs.org/bare-process/-/bare-process-4.4.1.tgz",
485 "integrity": "sha512-JfcTtymq6akqM2bdyTsP4A4GYJceBzb91k/ECmFps75uFf6uO33SM1bOZsRAqyRXExabsQJLn5S41NBl8HTM4A==",
486 "dev": true,
487 "license": "Apache-2.0",
488 "dependencies": {
489 "bare-abort": "^2.0.13",
490 "bare-env": "^3.0.0",
491 "bare-events": "^2.3.1",
492 "bare-hrtime": "^2.0.0",
493 "bare-os": "^3.7.1",
494 "bare-signals": "^4.0.0",
495 "bare-stdio": "^1.0.1"
496 }
497 },
498 "node_modules/bare-semver": {
499 "version": "1.0.3",
500 "resolved": "https://registry.npmjs.org/bare-semver/-/bare-semver-1.0.3.tgz",
501 "integrity": "sha512-HS/A30bi2+PiRJfU6R4+Kp+6KeLSCSByjYM2iiobOKzLAvtu1CT+S8xWfiU7wz0erknjkUoC+yXy108tzIuP5Q==",
502 "license": "Apache-2.0"
503 },
504 "node_modules/bare-signals": {
505 "version": "4.2.0",
506 "resolved": "https://registry.npmjs.org/bare-signals/-/bare-signals-4.2.0.tgz",
507 "integrity": "sha512-fNHMOdQIlYuTvMB3Oh9Apk99hLKn351+Ir8vz+khiPTcOqIyGG4uWWjdLTzxWdYGsA0eT+We3y0K74hjj2nq7A==",
508 "dev": true,
509 "license": "Apache-2.0",
510 "dependencies": {
511 "bare-events": "^2.5.3",
512 "bare-os": "^3.3.1"
513 },
514 "engines": {
515 "bare": ">=1.7.0"
516 }
517 },
518 "node_modules/bare-stdio": {
519 "version": "1.0.2",
520 "resolved": "https://registry.npmjs.org/bare-stdio/-/bare-stdio-1.0.2.tgz",
521 "integrity": "sha512-3WJDqtvVGP4f+j68kyEC05umOYNwKJ1xG+YAXL8yZ605WgNqiRhVaFq+mVIhBt2eKNp7pa5vCQdhOt1pNh79SA==",
522 "dev": true,
523 "license": "Apache-2.0",
524 "dependencies": {
525 "bare-fs": "^4.5.2",
526 "bare-pipe": "^4.1.5",
527 "bare-tty": "^5.0.3"
528 }
529 },
530 "node_modules/bare-stream": {
531 "version": "2.13.0",
532 "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.0.tgz",
533 "integrity": "sha512-3zAJRZMDFGjdn+RVnNpF9kuELw+0Fl3lpndM4NcEOhb9zwtSo/deETfuIwMSE5BXanA0FrN1qVjffGwAg2Y7EA==",
534 "license": "Apache-2.0",
535 "dependencies": {
536 "streamx": "^2.25.0",
537 "teex": "^1.0.1"
538 },
539 "peerDependencies": {
540 "bare-abort-controller": "*",
541 "bare-buffer": "*",
542 "bare-events": "*"
543 },
544 "peerDependenciesMeta": {
545 "bare-abort-controller": {
546 "optional": true
547 },
548 "bare-buffer": {
549 "optional": true
550 },
551 "bare-events": {
552 "optional": true
553 }
554 }
555 },
556 "node_modules/bare-stylize": {
557 "version": "0.0.1",
558 "resolved": "https://registry.npmjs.org/bare-stylize/-/bare-stylize-0.0.1.tgz",
559 "integrity": "sha512-l3MjmIl476bWijYWf3RbE+osl4iuXSOMudzp0vAqzIK7gPgn/+G3oAxp8Oin9CFF911KBP0LO9kts8Ci8mGZaQ==",
560 "dev": true,
561 "license": "Apache-2.0",
562 "dependencies": {
563 "bare-ansi-escapes": "^2.2.3",
564 "bare-process": "^4.2.1"
565 }
566 },
567 "node_modules/bare-subprocess": {
568 "version": "5.2.3",
569 "resolved": "https://registry.npmjs.org/bare-subprocess/-/bare-subprocess-5.2.3.tgz",
570 "integrity": "sha512-07wwswlV7M3sC9IykbZRZ/jHAkrXFWVLqdBWGv1y0ojCimtRD9hGwxdHmR5FUFmDUZLNsBmTYJNQqgio5+A85Q==",
571 "dev": true,
572 "license": "Apache-2.0",
573 "dependencies": {
574 "bare-env": "^3.0.0",
575 "bare-events": "^2.5.4",
576 "bare-os": "^3.0.1",
577 "bare-pipe": "^4.0.0",
578 "bare-url": "^2.2.2"
579 },
580 "engines": {
581 "bare": ">=1.7.0"
582 },
583 "peerDependencies": {
584 "bare-buffer": "*"
585 },
586 "peerDependenciesMeta": {
587 "bare-buffer": {
588 "optional": true
589 }
590 }
591 },
592 "node_modules/bare-tcp": {
593 "version": "2.2.7",
594 "resolved": "https://registry.npmjs.org/bare-tcp/-/bare-tcp-2.2.7.tgz",
595 "integrity": "sha512-rjpqNQ2cOCkNo3NeYA/W4GTK3DRkl8sDHO3uos+AEswUjLC8XXMQF8WrJCSjlIowCbS6NUVxKE92X5RGXjyefg==",
596 "dev": true,
597 "license": "Apache-2.0",
598 "dependencies": {
599 "bare-dns": "^2.0.4",
600 "bare-events": "^2.5.4",
601 "bare-stream": "^2.6.4"
602 },
603 "engines": {
604 "bare": ">=1.16.0"
605 }
606 },
607 "node_modules/bare-tls": {
608 "version": "2.2.3",
609 "resolved": "https://registry.npmjs.org/bare-tls/-/bare-tls-2.2.3.tgz",
610 "integrity": "sha512-dPYBGEXtgLceRFMfGaF2/rqR86/xMxMyrM9ootO/gaRKL/z2uNHJs7aP7IOBtnJF8eUCt5qwMzbKfrKgDIxPLg==",
611 "dev": true,
612 "license": "Apache-2.0",
613 "dependencies": {
614 "bare-net": "^2.0.1",
615 "bare-stream": "^2.6.4"
616 },
617 "engines": {
618 "bare": ">=1.7.0"
619 }
620 },
621 "node_modules/bare-tty": {
622 "version": "5.1.0",
623 "resolved": "https://registry.npmjs.org/bare-tty/-/bare-tty-5.1.0.tgz",
624 "integrity": "sha512-EZLvW4A+XiJgI3TW+e1pMME9PIJsfEXe/DA/WSKzIkq/v7Yarpv/rvG6Z5pGnpo4V/Bd+qopwnCLSR71hMMBYA==",
625 "dev": true,
626 "license": "Apache-2.0",
627 "dependencies": {
628 "bare-events": "^2.2.0",
629 "bare-signals": "^4.0.0",
630 "bare-stream": "^2.0.0"
631 },
632 "engines": {
633 "bare": ">=1.16.0"
634 }
635 },
636 "node_modules/bare-type": {
637 "version": "1.1.0",
638 "resolved": "https://registry.npmjs.org/bare-type/-/bare-type-1.1.0.tgz",
639 "integrity": "sha512-LdtnnEEYldOc87Dr4GpsKnStStZk3zfgoEMXy8yvEZkXrcCv9RtYDrUYWFsBQHtaB0s1EUWmcvS6XmEZYIj3Bw==",
640 "license": "Apache-2.0",
641 "engines": {
642 "bare": ">=1.2.0"
643 }
644 },
645 "node_modules/bare-url": {
646 "version": "2.4.0",
647 "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.0.tgz",
648 "integrity": "sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==",
649 "license": "Apache-2.0",
650 "peer": true,
651 "dependencies": {
652 "bare-path": "^3.0.0"
653 }
654 },
655 "node_modules/bare-utils": {
656 "version": "1.6.0",
657 "resolved": "https://registry.npmjs.org/bare-utils/-/bare-utils-1.6.0.tgz",
658 "integrity": "sha512-WhQEIkkAxkSnW7u1QgrI0AfNm5JpMruETXeYsb5qnkBJ0TTfNKygZmsh6rkoHBANaV+C/7Jed7bJP9OmEHG7rQ==",
659 "dev": true,
660 "license": "Apache-2.0",
661 "dependencies": {
662 "bare-debug-log": "^2.0.0",
663 "bare-encoding": "^1.0.0",
664 "bare-format": "^1.0.0",
665 "bare-inspect": "^3.0.0",
666 "bare-stylize": "^0.0.1",
667 "bare-type": "^1.0.6"
668 }
669 },
670 "node_modules/bare-v8-to-istanbul": {
671 "version": "1.0.2",
672 "resolved": "https://registry.npmjs.org/bare-v8-to-istanbul/-/bare-v8-to-istanbul-1.0.2.tgz",
673 "integrity": "sha512-CM0wPgyQtXTQ7h4q8NjbTZ/FH5he0Jkiwgpq0lFZZA5tkVZzmQ/9ul4R7E+cNlGZJIZlQZ9v4CwbgVaFG3zOAA==",
674 "dev": true,
675 "license": "Apache-2.0",
676 "dependencies": {
677 "bare-assert": "^1.0.2",
678 "bare-fs": "^4.1.2",
679 "bare-module": "^6.1.2",
680 "bare-path": "^3.0.0",
681 "bare-process": "^4.2.0",
682 "bare-url": "^2.1.5",
683 "bare-utils": "^1.2.0",
684 "v8-to-istanbul": "^9.3.0",
685 "which-runtime": "^1.2.1"
686 }
687 },
688 "node_modules/bare-ws": {
689 "version": "2.1.0",
690 "resolved": "https://registry.npmjs.org/bare-ws/-/bare-ws-2.1.0.tgz",
691 "integrity": "sha512-2gEWlPK9iyBchACdIY6oQXgmDz3KLrChdwrPgmU3IVXOFTnxTqSUT27WE/+izd4QojHj/SsqDkQiD2HDvuTdAA==",
692 "dev": true,
693 "license": "Apache-2.0",
694 "dependencies": {
695 "bare-crypto": "^1.2.0",
696 "bare-events": "^2.3.1",
697 "bare-http1": "^4.0.0",
698 "bare-https": "^2.0.0",
699 "bare-stream": "^2.1.2"
700 },
701 "peerDependencies": {
702 "bare-buffer": "*",
703 "bare-url": "*"
704 },
705 "peerDependenciesMeta": {
706 "bare-buffer": {
707 "optional": true
708 },
709 "bare-url": {
710 "optional": true
711 }
712 }
713 },
714 "node_modules/big-sparse-array": {
715 "version": "1.0.3",
716 "resolved": "https://registry.npmjs.org/big-sparse-array/-/big-sparse-array-1.0.3.tgz",
717 "integrity": "sha512-6RjV/3mSZORlMdpUaQ6rUSpG637cZm0//E54YYGtQg1c1O+AbZP8UTdJ/TchsDZcTVLmyWZcseBfp2HBeXUXOQ==",
718 "license": "MIT"
719 },
720 "node_modules/bip39-mnemonic": {
721 "version": "2.5.0",
722 "resolved": "https://registry.npmjs.org/bip39-mnemonic/-/bip39-mnemonic-2.5.0.tgz",
723 "integrity": "sha512-hgCxFHN129ta0bHl9VPykoqCPagBUr2oaXjfSbfeXAPe+y/byxwjPFFEFTMNO/1T/GSoMP1cOXHa2ZaprHG1kg==",
724 "dev": true,
725 "license": "Apache-2.0",
726 "dependencies": {
727 "b4a": "^1.6.6",
728 "nanoassert": "^2.0.0",
729 "sodium-universal": "^5.0.1"
730 }
731 },
732 "node_modules/brittle": {
733 "version": "3.19.1",
734 "resolved": "https://registry.npmjs.org/brittle/-/brittle-3.19.1.tgz",
735 "integrity": "sha512-4Ted1Mt9o9B6oIA6ImJJCtB/Fv++ZO3IDNQgRcHOXWSYGRUidgxchaGrUBaRn+4mlneXrgInPkCPzi0jO8qKbA==",
736 "dev": true,
737 "license": "Apache-2.0",
738 "dependencies": {
739 "b4a": "^1.6.0",
740 "bare-assert": "^1.0.2",
741 "bare-cov": "^1.1.0",
742 "bare-fs": "^4.1.6",
743 "bare-os": "^3.6.1",
744 "bare-path": "^3.0.0",
745 "bare-process": "^4.2.1",
746 "bare-subprocess": "^5.0.0",
747 "bare-url": "^2.1.6",
748 "error-stack-parser": "^2.1.4",
749 "globbie": "^1.0.2",
750 "paparam": "^1.6.2",
751 "same-object": "^1.0.2",
752 "test-tmp": "^1.4.0",
753 "tmatch": "^5.0.0"
754 },
755 "bin": {
756 "brittle": "bin/node.js",
757 "brittle-bare": "bin/bare.js",
758 "brittle-node": "bin/node.js",
759 "brittle-pear": "bin/pear.js"
760 }
761 },
762 "node_modules/codecs": {
763 "version": "3.1.0",
764 "resolved": "https://registry.npmjs.org/codecs/-/codecs-3.1.0.tgz",
765 "integrity": "sha512-Dqx8NwvBvnMeuPQdVKy/XEF71igjR5apxBvCGeV0pP1tXadOiaLvDTXt7xh+/5wI1ASB195mXQGJbw3Ml4YDWQ==",
766 "license": "MIT",
767 "dependencies": {
768 "b4a": "^1.6.3"
769 }
770 },
771 "node_modules/compact-encoding": {
772 "version": "2.19.2",
773 "resolved": "https://registry.npmjs.org/compact-encoding/-/compact-encoding-2.19.2.tgz",
774 "integrity": "sha512-/YjhHQE/5L4F7l5Bht69dRbP9RV6zoJPeowi8bMKQxNKe3Nh6hOY8pBGoVE9fz5GaWfEd8fWJ2aU9sB4KZuMYg==",
775 "license": "Apache-2.0",
776 "dependencies": {
777 "b4a": "^1.3.0"
778 }
779 },
780 "node_modules/convert-source-map": {
781 "version": "2.0.0",
782 "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
783 "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
784 "dev": true,
785 "license": "MIT"
786 },
787 "node_modules/corestore": {
788 "version": "7.9.2",
789 "resolved": "https://registry.npmjs.org/corestore/-/corestore-7.9.2.tgz",
790 "integrity": "sha512-dyIktVSVLu0skZ1UM4yODbNbZ46dBpTHypzwlwET1btVuS3YIf66Zz8Tx8h3Xa8nbLO2USGqrYtvPYzSRj2wCA==",
791 "dev": true,
792 "license": "MIT",
793 "dependencies": {
794 "b4a": "^1.6.7",
795 "hypercore": "^11.19.0",
796 "hypercore-crypto": "^3.4.2",
797 "hypercore-errors": "^1.4.0",
798 "hypercore-id-encoding": "^1.3.0",
799 "ready-resource": "^1.1.1",
800 "sodium-universal": "^5.0.1",
801 "which-runtime": "^1.2.1"
802 }
803 },
804 "node_modules/debounceify": {
805 "version": "1.1.0",
806 "resolved": "https://registry.npmjs.org/debounceify/-/debounceify-1.1.0.tgz",
807 "integrity": "sha512-eKuHDVfJVg+u/0nPy8P+fhnLgbyuTgVxuCRrS/R7EpDSMMkBDgSes41MJtSAY1F1hcqfHz3Zy/qpqHHIp/EhdA==",
808 "license": "MIT"
809 },
810 "node_modules/device-file": {
811 "version": "2.3.1",
812 "resolved": "https://registry.npmjs.org/device-file/-/device-file-2.3.1.tgz",
813 "integrity": "sha512-bmON44lwxJPle9N2OcH4tqM44pMGZKT8G6OkzXkz0urvqQ9LKkoQdTS6w0ztYfmLdUE27R4UUmx0+y2gEz4Jug==",
814 "license": "Apache-2.0",
815 "dependencies": {
816 "b4a": "^1.6.7",
817 "bare-fs": "^4.0.1",
818 "bare-path": "^3.0.0",
819 "fd-lock": "^2.1.0",
820 "fs-native-extensions": "^1.4.0",
821 "ready-resource": "^1.2.0"
822 }
823 },
824 "node_modules/error-stack-parser": {
825 "version": "2.1.4",
826 "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
827 "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==",
828 "dev": true,
829 "license": "MIT",
830 "dependencies": {
831 "stackframe": "^1.3.4"
832 }
833 },
834 "node_modules/events-universal": {
835 "version": "1.0.1",
836 "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
837 "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==",
838 "license": "Apache-2.0",
839 "dependencies": {
840 "bare-events": "^2.7.0"
841 }
842 },
843 "node_modules/fast-fifo": {
844 "version": "1.3.2",
845 "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
846 "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
847 "license": "MIT"
848 },
849 "node_modules/fd-lock": {
850 "version": "2.1.1",
851 "resolved": "https://registry.npmjs.org/fd-lock/-/fd-lock-2.1.1.tgz",
852 "integrity": "sha512-H3VkcWFl39Rk0xBokDcUyBcVs6VrYTUo/DhDWMzJOF99wXWDAvmvq/GlLTS2NTehsznZhp3fXVyrtB2ldDXhwg==",
853 "license": "Apache-2.0",
854 "dependencies": {
855 "bare-fs": "^4.5.0",
856 "fs-native-extensions": "^1.4.4",
857 "ready-resource": "^1.2.0",
858 "resource-on-exit": "^1.0.0"
859 }
860 },
861 "node_modules/flat-tree": {
862 "version": "1.13.0",
863 "resolved": "https://registry.npmjs.org/flat-tree/-/flat-tree-1.13.0.tgz",
864 "integrity": "sha512-fT3HIuCPwHhFgJ20QYzDHgUG0zMmFg5cHvFiFo5h+QMSJ28TihsEVY0f8HGliuO+pOzmvjMx1odToeaEWkTnyQ==",
865 "license": "MIT"
866 },
867 "node_modules/fs-native-extensions": {
868 "version": "1.4.5",
869 "resolved": "https://registry.npmjs.org/fs-native-extensions/-/fs-native-extensions-1.4.5.tgz",
870 "integrity": "sha512-ekV0T//iDm4AvhOcuPaHpxub4DI7HvY5ucLJVDvi7T2J+NZkQ9S6MuvgP0yeQvoqNUaAGyLjVYb1905BF9bpmg==",
871 "license": "Apache-2.0",
872 "dependencies": {
873 "require-addon": "^1.1.0",
874 "which-runtime": "^1.2.0"
875 }
876 },
877 "node_modules/generate-object-property": {
878 "version": "2.0.0",
879 "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-2.0.0.tgz",
880 "integrity": "sha512-KwuURPyqn2Mz8DdV29pJwQu0Y7tcsbkULr82eeOcY/ZllFK6I9Wm8dsRByIu7CKWlFi9BdW1b3mcXMp/kQBQsw==",
881 "license": "MIT",
882 "dependencies": {
883 "is-property": "^1.0.0"
884 }
885 },
886 "node_modules/generate-string": {
887 "version": "1.0.1",
888 "resolved": "https://registry.npmjs.org/generate-string/-/generate-string-1.0.1.tgz",
889 "integrity": "sha512-IfTY0dKZM43ACyGvXkbG7De7WY7MxTS5VO6Juhe8oJKpCmrYYXoqp/cJMskkpi0k9H8wuXq0H+eI898/BCqvXg==",
890 "license": "MIT"
891 },
892 "node_modules/globbie": {
893 "version": "1.0.3",
894 "resolved": "https://registry.npmjs.org/globbie/-/globbie-1.0.3.tgz",
895 "integrity": "sha512-hcryJmKcftf82xfBWTWxuUITWIIoYO3ec104V17SMHGFl6VLbm1d1Ju9LX9L+jyJTwICpemX/dmPI/HGYoKr1A==",
896 "dev": true,
897 "license": "Apache-2.0",
898 "dependencies": {
899 "bare-fs": "^4.1.2",
900 "bare-path": "^3.0.0",
901 "bare-process": "^4.2.1",
902 "picomatch": "^4.0.2"
903 }
904 },
905 "node_modules/hyperbee": {
906 "version": "2.27.3",
907 "resolved": "https://registry.npmjs.org/hyperbee/-/hyperbee-2.27.3.tgz",
908 "integrity": "sha512-PXURH2U4juUZyJRKHTrY5z1zX851pmI1Q0jfv5F/hCIErDt/ND8jOZuxc3hfOLM9f0W3qJEDTMlV5AJBkVPy8w==",
909 "license": "MIT",
910 "dependencies": {
911 "b4a": "^1.6.0",
912 "codecs": "^3.0.0",
913 "debounceify": "^1.0.0",
914 "hypercore-errors": "^1.0.0",
915 "mutexify": "^1.4.0",
916 "protocol-buffers-encodings": "^1.2.0",
917 "rache": "^1.0.0",
918 "ready-resource": "^1.0.0",
919 "resolve-reject-promise": "^1.1.0",
920 "safety-catch": "^1.0.2",
921 "streamx": "^2.12.4",
922 "unslab": "^1.2.0"
923 }
924 },
925 "node_modules/hypercore": {
926 "version": "11.28.1",
927 "resolved": "https://registry.npmjs.org/hypercore/-/hypercore-11.28.1.tgz",
928 "integrity": "sha512-d8jqUilG7Gri8wT+sRdkFTYRPMHGyvBz/NCYHf5rX7+LoivRNRxQm5nWChT7caiUKbcsDak6h7IiEQ5wbD1wCg==",
929 "license": "MIT",
930 "dependencies": {
931 "@hyperswarm/secret-stream": "^6.0.0",
932 "b4a": "^1.1.0",
933 "bare-events": "^2.2.0",
934 "big-sparse-array": "^1.0.3",
935 "compact-encoding": "^2.11.0",
936 "fast-fifo": "^1.3.0",
937 "flat-tree": "^1.9.0",
938 "hypercore-crypto": "^3.2.1",
939 "hypercore-errors": "^1.5.0",
940 "hypercore-id-encoding": "^1.2.0",
941 "hypercore-storage": "^2.8.0",
942 "is-options": "^1.0.1",
943 "nanoassert": "^2.0.0",
944 "protomux": "^3.5.0",
945 "quickbit-universal": "^2.2.0",
946 "random-array-iterator": "^1.0.0",
947 "safety-catch": "^1.0.1",
948 "sodium-universal": "^5.0.1",
949 "streamx": "^2.12.4",
950 "unslab": "^1.3.0",
951 "z32": "^1.0.0"
952 }
953 },
954 "node_modules/hypercore-crypto": {
955 "version": "3.6.1",
956 "resolved": "https://registry.npmjs.org/hypercore-crypto/-/hypercore-crypto-3.6.1.tgz",
957 "integrity": "sha512-ltIz2uDwy9pO/ZGTvqcjzyBkvt6O4cVm4r/nNxh0GFs/RbQtqP/i4wCvLEdmU7ptgtnw7fI67WYD1aHPuv4OVA==",
958 "license": "MIT",
959 "dependencies": {
960 "b4a": "^1.6.6",
961 "compact-encoding": "^2.15.0",
962 "sodium-universal": "^5.0.0"
963 }
964 },
965 "node_modules/hypercore-errors": {
966 "version": "1.5.0",
967 "resolved": "https://registry.npmjs.org/hypercore-errors/-/hypercore-errors-1.5.0.tgz",
968 "integrity": "sha512-5KQ/SuDxsvet+7qWA35Ay6zdD9WyAHQoyWHGcPUTbmJBd300gvNIJoi3oma7kp4TTCSzii6qYumNZe/s0j/saQ==",
969 "license": "Apache-2.0",
970 "dependencies": {
971 "hypercore-id-encoding": "^1.3.0"
972 }
973 },
974 "node_modules/hypercore-id-encoding": {
975 "version": "1.3.0",
976 "resolved": "https://registry.npmjs.org/hypercore-id-encoding/-/hypercore-id-encoding-1.3.0.tgz",
977 "integrity": "sha512-W6sHdGo5h7LXEsoWfKf/KfuROZmZRQDlGqJF2EPHW+noCK66Vvr0+zE6cL0vqQi18s0kQPeN7Sq3QyR0Ytc2VQ==",
978 "license": "Apache-2.0",
979 "dependencies": {
980 "b4a": "^1.5.3",
981 "z32": "^1.0.0"
982 }
983 },
984 "node_modules/hypercore-storage": {
985 "version": "2.8.0",
986 "resolved": "https://registry.npmjs.org/hypercore-storage/-/hypercore-storage-2.8.0.tgz",
987 "integrity": "sha512-s35HllFMYvrkSHvkIIklVFmCI/bRVNO7H3pi4mKvWl0XLyhGGGM+NtJ7fpsh82oPRCmL9XtMRO+pT6LiMAO8MA==",
988 "license": "Apache-2.0",
989 "dependencies": {
990 "b4a": "^1.6.7",
991 "bare-fs": "^4.0.1",
992 "bare-path": "^3.0.0",
993 "compact-encoding": "^2.16.0",
994 "device-file": "^2.1.2",
995 "flat-tree": "^1.12.1",
996 "hypercore-crypto": "^3.4.2",
997 "hyperschema": "^1.7.0",
998 "index-encoder": "^3.3.2",
999 "resolve-reject-promise": "^1.0.0",
1000 "rocksdb-native": "^3.11.0",
1001 "scope-lock": "^1.2.4",
1002 "streamx": "^2.21.1"
1003 }
1004 },
1005 "node_modules/hyperschema": {
1006 "version": "1.20.1",
1007 "resolved": "https://registry.npmjs.org/hyperschema/-/hyperschema-1.20.1.tgz",
1008 "integrity": "sha512-7gnvaTNUs8FqdrU3NNE6nzhOneGyDlUlpROu9YFlHA61fE8ppKKf2gLZjZjsx/enNt+VFN4ITxy8ijypfyWBLw==",
1009 "license": "Apache-2.0",
1010 "dependencies": {
1011 "bare-fs": "^4.0.1",
1012 "compact-encoding": "^2.19.0",
1013 "generate-object-property": "^2.0.0",
1014 "generate-string": "^1.0.1"
1015 }
1016 },
1017 "node_modules/index-encoder": {
1018 "version": "3.5.0",
1019 "resolved": "https://registry.npmjs.org/index-encoder/-/index-encoder-3.5.0.tgz",
1020 "integrity": "sha512-idZ1cxtZz2dRV6rUiaP9Xo99UjXbSzjcMacoQmxUMu/A7fEQcNPngvwDJYeWelQUS5XFlY71/or70lKn6XnwbQ==",
1021 "license": "Apache-2.0",
1022 "dependencies": {
1023 "b4a": "^1.6.4"
1024 }
1025 },
1026 "node_modules/is-options": {
1027 "version": "1.0.2",
1028 "resolved": "https://registry.npmjs.org/is-options/-/is-options-1.0.2.tgz",
1029 "integrity": "sha512-u+Ai74c8Q74aS8BuHwPdI1jptGOT1FQXgCq8/zv0xRuE+wRgSMEJLj8lVO8Zp9BeGb29BXY6AsNPinfqjkr7Fg==",
1030 "license": "MIT",
1031 "dependencies": {
1032 "b4a": "^1.1.1"
1033 }
1034 },
1035 "node_modules/is-property": {
1036 "version": "1.0.2",
1037 "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
1038 "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
1039 "license": "MIT"
1040 },
1041 "node_modules/keet-identity-key": {
1042 "version": "3.1.0",
1043 "resolved": "https://registry.npmjs.org/keet-identity-key/-/keet-identity-key-3.1.0.tgz",
1044 "integrity": "sha512-DaY14agJKDKjrxYSd2cxyM0lYnsnh+ZaQjziRQTgTOFCIJbBPOCYUfZwHAXcD+EHu/W3G+r7CtxGEXNsCuB56g==",
1045 "dev": true,
1046 "license": "Apache-2.0",
1047 "dependencies": {
1048 "b4a": "^1.6.4",
1049 "bip39-mnemonic": "^2.2.0",
1050 "compact-encoding": "^2.13.0",
1051 "nanoassert": "^2.0.0",
1052 "sodium-hmac": "^2.0.1",
1053 "sodium-universal": "^5.0.1"
1054 }
1055 },
1056 "node_modules/mutexify": {
1057 "version": "1.4.0",
1058 "resolved": "https://registry.npmjs.org/mutexify/-/mutexify-1.4.0.tgz",
1059 "integrity": "sha512-pbYSsOrSB/AKN5h/WzzLRMFgZhClWccf2XIB4RSMC8JbquiB0e0/SH5AIfdQMdyHmYtv4seU7yV/TvAwPLJ1Yg==",
1060 "license": "MIT",
1061 "dependencies": {
1062 "queue-tick": "^1.0.0"
1063 }
1064 },
1065 "node_modules/nanoassert": {
1066 "version": "2.0.0",
1067 "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz",
1068 "integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==",
1069 "license": "ISC"
1070 },
1071 "node_modules/noise-curve-ed": {
1072 "version": "2.1.0",
1073 "resolved": "https://registry.npmjs.org/noise-curve-ed/-/noise-curve-ed-2.1.0.tgz",
1074 "integrity": "sha512-zAzJx+VwZM3w6EA1hTmDhJfvAnCeBQn/1FAeZ0LtGxCcCtlAK/uJXQVF/eDVUOaAZ286lHlx77WJ+qj9SmsRRg==",
1075 "license": "ISC",
1076 "dependencies": {
1077 "b4a": "^1.1.0",
1078 "nanoassert": "^2.0.0",
1079 "sodium-universal": "^5.0.0"
1080 }
1081 },
1082 "node_modules/noise-handshake": {
1083 "version": "4.2.0",
1084 "resolved": "https://registry.npmjs.org/noise-handshake/-/noise-handshake-4.2.0.tgz",
1085 "integrity": "sha512-9O/VTNX/E2/AToyMTTDU0J/4WhaXMTdqc2DHs9vf+snoZ0cenSBq0dNYTVV1snYYEkmo6QeRrYMxtqtoYnY+LA==",
1086 "license": "Apache-2.0",
1087 "dependencies": {
1088 "b4a": "^1.1.0",
1089 "nanoassert": "^2.0.0",
1090 "sodium-universal": "^5.0.0"
1091 }
1092 },
1093 "node_modules/paparam": {
1094 "version": "1.10.1",
1095 "resolved": "https://registry.npmjs.org/paparam/-/paparam-1.10.1.tgz",
1096 "integrity": "sha512-viyQI64VIja0Za3njIzhoEP8ZVkgPowhZPuG0E96NwBfYJ6ZIyrrlhWGtFPkdN7eYLl2L8CTWL+wla0evm1KKQ==",
1097 "dev": true,
1098 "license": "Apache-2.0"
1099 },
1100 "node_modules/picomatch": {
1101 "version": "4.0.4",
1102 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
1103 "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
1104 "dev": true,
1105 "license": "MIT",
1106 "engines": {
1107 "node": ">=12"
1108 },
1109 "funding": {
1110 "url": "https://github.com/sponsors/jonschlinkert"
1111 }
1112 },
1113 "node_modules/protocol-buffers-encodings": {
1114 "version": "1.2.0",
1115 "resolved": "https://registry.npmjs.org/protocol-buffers-encodings/-/protocol-buffers-encodings-1.2.0.tgz",
1116 "integrity": "sha512-daeNPuKh1NlLD1uDfbLpD+xyUTc07nEtfHwmBZmt/vH0B7VOM+JOCOpDcx9ZRpqHjAiIkGqyTDi+wfGSl17R9w==",
1117 "license": "MIT",
1118 "dependencies": {
1119 "b4a": "^1.6.0",
1120 "signed-varint": "^2.0.1",
1121 "varint": "5.0.0"
1122 }
1123 },
1124 "node_modules/protomux": {
1125 "version": "3.10.1",
1126 "resolved": "https://registry.npmjs.org/protomux/-/protomux-3.10.1.tgz",
1127 "integrity": "sha512-jgBqx8ZyaBWea/DFG4eOu1scOaeBwcnagiRC1XFVrjeGt7oAb0Pk5udPpBUpJ4DJBRjra50jD6YcZiQQTRqaaA==",
1128 "license": "MIT",
1129 "dependencies": {
1130 "b4a": "^1.3.1",
1131 "compact-encoding": "^2.5.1",
1132 "queue-tick": "^1.0.0",
1133 "safety-catch": "^1.0.1",
1134 "unslab": "^1.3.0"
1135 }
1136 },
1137 "node_modules/queue-tick": {
1138 "version": "1.0.1",
1139 "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
1140 "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==",
1141 "license": "MIT"
1142 },
1143 "node_modules/quickbit-native": {
1144 "version": "2.4.8",
1145 "resolved": "https://registry.npmjs.org/quickbit-native/-/quickbit-native-2.4.8.tgz",
1146 "integrity": "sha512-FcCcqI+nIAWGknqhtrYT5TSD7t/N+Xd8ctM+2PrIIBuwOi5hx0SxAvuPtzLIEMfT/2h9+fhBakUe2uALOHX6yw==",
1147 "license": "Apache-2.0",
1148 "optional": true,
1149 "dependencies": {
1150 "require-addon": "^1.1.0"
1151 }
1152 },
1153 "node_modules/quickbit-universal": {
1154 "version": "2.2.0",
1155 "resolved": "https://registry.npmjs.org/quickbit-universal/-/quickbit-universal-2.2.0.tgz",
1156 "integrity": "sha512-w02i1R8n7+6pEKTud8DfF8zbFY9o7RtPlUc3jWbtCkDKvhbx/AvV7oNnz4/TcmsPGpSJS+fq5Ud6RH6+YPvSGg==",
1157 "license": "ISC",
1158 "dependencies": {
1159 "b4a": "^1.6.0",
1160 "simdle-universal": "^1.1.0"
1161 },
1162 "optionalDependencies": {
1163 "quickbit-native": "^2.2.0"
1164 }
1165 },
1166 "node_modules/rache": {
1167 "version": "1.0.0",
1168 "resolved": "https://registry.npmjs.org/rache/-/rache-1.0.0.tgz",
1169 "integrity": "sha512-e0k0g0w/8jOCB+7YqCIlOa+OJ38k0wrYS4x18pMSmqOvLKoyhmMhmQyCcvfY6VaP8D75cqkEnlakXs+RYYLqNg==",
1170 "license": "Apache-2.0"
1171 },
1172 "node_modules/random-array-iterator": {
1173 "version": "1.0.0",
1174 "resolved": "https://registry.npmjs.org/random-array-iterator/-/random-array-iterator-1.0.0.tgz",
1175 "integrity": "sha512-u7xCM93XqKEvPTP6xZp2ehttcAemKnh73oKNf1FvzuVCfpt6dILDt1Kxl1LeBjm2iNIeR49VGFhy4Iz3yOun+Q==",
1176 "license": "MIT"
1177 },
1178 "node_modules/ready-resource": {
1179 "version": "1.2.0",
1180 "resolved": "https://registry.npmjs.org/ready-resource/-/ready-resource-1.2.0.tgz",
1181 "integrity": "sha512-nfcco/8iAFV0M+2PYnmIc+/xY0iRb35d42HFHQ7AfjulbGEAFa+XWpByfwSyeVeiBoMLLFVMv1HixxNCqzSQ1g==",
1182 "license": "MIT",
1183 "dependencies": {
1184 "bare-events": "^2.2.0"
1185 }
1186 },
1187 "node_modules/refcounter": {
1188 "version": "1.0.0",
1189 "resolved": "https://registry.npmjs.org/refcounter/-/refcounter-1.0.0.tgz",
1190 "integrity": "sha512-1WosVzUy0kPUaPMEtlNDwm99UsteALIhXXR8rerELoa63WkYIXAl0hxgwPFrIYBRWZPGUyekQ04FRtPJ7dHk9w==",
1191 "license": "Apache-2.0"
1192 },
1193 "node_modules/require-addon": {
1194 "version": "1.2.0",
1195 "resolved": "https://registry.npmjs.org/require-addon/-/require-addon-1.2.0.tgz",
1196 "integrity": "sha512-VNPDZlYgIYQwWp9jMTzljx+k0ZtatKlcvOhktZ/anNPI3dQ9NXk7cq2U4iJ1wd9IrytRnYhyEocFWbkdPb+MYA==",
1197 "license": "Apache-2.0",
1198 "dependencies": {
1199 "bare-addon-resolve": "^1.3.0"
1200 },
1201 "engines": {
1202 "bare": ">=1.10.0"
1203 }
1204 },
1205 "node_modules/resolve-reject-promise": {
1206 "version": "1.1.0",
1207 "resolved": "https://registry.npmjs.org/resolve-reject-promise/-/resolve-reject-promise-1.1.0.tgz",
1208 "integrity": "sha512-LWsTOA91AqzBTjSGgX79Tc130pwcBK6xjpJEO+qRT5IKZ6bGnHKcc8QL3upUBcWuU8OTIDzKK2VNSwmmlqvAVg==",
1209 "license": "MIT"
1210 },
1211 "node_modules/resource-on-exit": {
1212 "version": "1.0.0",
1213 "resolved": "https://registry.npmjs.org/resource-on-exit/-/resource-on-exit-1.0.0.tgz",
1214 "integrity": "sha512-ViJwJAknCkLRJRPR+9SISQQ7R5eRgtdIHLJsM2hHx1MweAJbJxJ5XnMjjq0Lc7ZGv44ufzAqds1nKxiVkdy4ag==",
1215 "license": "Apache-2.0"
1216 },
1217 "node_modules/rocksdb-native": {
1218 "version": "3.15.0",
1219 "resolved": "https://registry.npmjs.org/rocksdb-native/-/rocksdb-native-3.15.0.tgz",
1220 "integrity": "sha512-czYx0hOzKAy+HYmJROZm7thvJ1tHFWHNkGI3nomumXWzrJghJdrWo4MIhehGX4OTff0lnOCoB2zu6ekzIKY0rQ==",
1221 "license": "Apache-2.0",
1222 "dependencies": {
1223 "compact-encoding": "^2.15.0",
1224 "ready-resource": "^1.0.0",
1225 "refcounter": "^1.0.0",
1226 "require-addon": "^1.0.2",
1227 "resolve-reject-promise": "^1.1.0",
1228 "signal-promise": "^1.0.3",
1229 "streamx": "^2.16.1"
1230 },
1231 "engines": {
1232 "bare": ">=1.16.0"
1233 }
1234 },
1235 "node_modules/safety-catch": {
1236 "version": "1.0.3",
1237 "resolved": "https://registry.npmjs.org/safety-catch/-/safety-catch-1.0.3.tgz",
1238 "integrity": "sha512-Zq+J1TefpoEq/HTUabo0YXX5MNvttjWYODGohgPBO2jfko8Wqx3JYMgE823szDFVamdH5PlpByvfiWScTdSYDA==",
1239 "license": "MIT"
1240 },
1241 "node_modules/same-object": {
1242 "version": "1.0.2",
1243 "resolved": "https://registry.npmjs.org/same-object/-/same-object-1.0.2.tgz",
1244 "integrity": "sha512-csHWhvUsLbIOHDM/nP+KHWM+BLPsIzWkFa8HbzaI0G7BqKXgx+7FJpKTGgLXyz5amfdY2OVBcmXTqYOMEk04og==",
1245 "dev": true,
1246 "license": "MIT"
1247 },
1248 "node_modules/scope-lock": {
1249 "version": "1.2.4",
1250 "resolved": "https://registry.npmjs.org/scope-lock/-/scope-lock-1.2.4.tgz",
1251 "integrity": "sha512-BpSd8VCuCxW9ZitcdIC/vjs3gMaP9bRBL5nkHcyfX2VrS52n13/rHuBA2xJ/S/4DPuRdAO/Bk8pWd8eD/gHCIA==",
1252 "license": "Apache-2.0"
1253 },
1254 "node_modules/signal-promise": {
1255 "version": "1.0.3",
1256 "resolved": "https://registry.npmjs.org/signal-promise/-/signal-promise-1.0.3.tgz",
1257 "integrity": "sha512-WBgv0UnIq2C+Aeh0/n+IRpP6967eIx9WpynTUoiW3isPpfe1zu2LJzyfXdo9Tgef8yR/sGjcMvoUXD7EYdiz+g==",
1258 "license": "MIT"
1259 },
1260 "node_modules/signed-varint": {
1261 "version": "2.0.1",
1262 "resolved": "https://registry.npmjs.org/signed-varint/-/signed-varint-2.0.1.tgz",
1263 "integrity": "sha512-abgDPg1106vuZZOvw7cFwdCABddfJRz5akcCcchzTbhyhYnsG31y4AlZEgp315T7W3nQq5P4xeOm186ZiPVFzw==",
1264 "license": "MIT",
1265 "dependencies": {
1266 "varint": "~5.0.0"
1267 }
1268 },
1269 "node_modules/simdle-native": {
1270 "version": "1.3.9",
1271 "resolved": "https://registry.npmjs.org/simdle-native/-/simdle-native-1.3.9.tgz",
1272 "integrity": "sha512-Isc8sP4OiiIU0mpslD4GHEnR0VQWvR/54WN7YtwEDkNdTJVWtpmvsSvsgRlw5BNGxdYXlVRegdnrSu10H/PhvA==",
1273 "license": "Apache-2.0",
1274 "optional": true,
1275 "dependencies": {
1276 "b4a": "^1.6.0",
1277 "require-addon": "^1.1.0"
1278 }
1279 },
1280 "node_modules/simdle-universal": {
1281 "version": "1.1.2",
1282 "resolved": "https://registry.npmjs.org/simdle-universal/-/simdle-universal-1.1.2.tgz",
1283 "integrity": "sha512-3n3w1bs+uwgHKQjt6arez83EywNlhZzYvNOhvAASTl/8KqNIcqr6aHyGt3JRlfuUC7iB0tomJRPlJ2cRGIpBzA==",
1284 "license": "ISC",
1285 "dependencies": {
1286 "b4a": "^1.6.0"
1287 },
1288 "optionalDependencies": {
1289 "simdle-native": "^1.1.1"
1290 }
1291 },
1292 "node_modules/sodium-hmac": {
1293 "version": "2.1.0",
1294 "resolved": "https://registry.npmjs.org/sodium-hmac/-/sodium-hmac-2.1.0.tgz",
1295 "integrity": "sha512-1g7d7v+/0g/XXSX9sp0++X1QB6M1knhomnsFiN7B42b+rV0VhQeyiRzoWtp7vYGLkzmLY77tWNnCef3juGRwfQ==",
1296 "dev": true,
1297 "license": "Apache-2.0",
1298 "dependencies": {
1299 "b4a": "^1.6.6",
1300 "sodium-universal": "^5.0.1"
1301 }
1302 },
1303 "node_modules/sodium-native": {
1304 "version": "5.1.0",
1305 "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-5.1.0.tgz",
1306 "integrity": "sha512-3RxgyWyJlhTsABPnJVpCI5CoTDANZTqqFrEPqr+kjfnRaBihpVtMUE3yTF40ukdoB1APXeoBNKF3MzZAIHg39g==",
1307 "license": "MIT",
1308 "dependencies": {
1309 "bare-assert": "^1.2.0",
1310 "require-addon": "^1.1.0",
1311 "which-runtime": "^1.2.1"
1312 },
1313 "engines": {
1314 "bare": ">=1.16.0"
1315 }
1316 },
1317 "node_modules/sodium-secretstream": {
1318 "version": "1.2.0",
1319 "resolved": "https://registry.npmjs.org/sodium-secretstream/-/sodium-secretstream-1.2.0.tgz",
1320 "integrity": "sha512-q/DbraNFXm1KfCiiZvapmz5UC3OlpirYFIvBK2MhGaOFSb3gRyk8OXTi17UI9SGfshQNCpsVvlopogbzZNyW6Q==",
1321 "license": "MIT",
1322 "dependencies": {
1323 "b4a": "^1.1.1",
1324 "sodium-universal": "^5.0.0"
1325 }
1326 },
1327 "node_modules/sodium-universal": {
1328 "version": "5.0.1",
1329 "resolved": "https://registry.npmjs.org/sodium-universal/-/sodium-universal-5.0.1.tgz",
1330 "integrity": "sha512-rv+aH+tnKB5H0MAc2UadHShLMslpJsc4wjdnHRtiSIEYpOetCgu8MS4ExQRia+GL/MK3uuCyZPeEsi+J3h+Q+Q==",
1331 "license": "MIT",
1332 "dependencies": {
1333 "sodium-native": "^5.0.1"
1334 },
1335 "peerDependencies": {
1336 "sodium-javascript": "~0.8.0"
1337 },
1338 "peerDependenciesMeta": {
1339 "sodium-javascript": {
1340 "optional": true
1341 }
1342 }
1343 },
1344 "node_modules/stackframe": {
1345 "version": "1.3.4",
1346 "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
1347 "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==",
1348 "dev": true,
1349 "license": "MIT"
1350 },
1351 "node_modules/streamx": {
1352 "version": "2.25.0",
1353 "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz",
1354 "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==",
1355 "license": "MIT",
1356 "dependencies": {
1357 "events-universal": "^1.0.0",
1358 "fast-fifo": "^1.3.2",
1359 "text-decoder": "^1.1.0"
1360 }
1361 },
1362 "node_modules/teex": {
1363 "version": "1.0.1",
1364 "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz",
1365 "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==",
1366 "license": "MIT",
1367 "dependencies": {
1368 "streamx": "^2.12.5"
1369 }
1370 },
1371 "node_modules/test-tmp": {
1372 "version": "1.4.0",
1373 "resolved": "https://registry.npmjs.org/test-tmp/-/test-tmp-1.4.0.tgz",
1374 "integrity": "sha512-GVggxGg+jXqP2Wbju50JVLo+9E+nIOPPyWqgr63EbOnNItIKu1cEbJpTWAJeflnyGqXOtcMI7ijHRp88GUkfDA==",
1375 "dev": true,
1376 "license": "MIT",
1377 "dependencies": {
1378 "bare-fs": "^4.0.1",
1379 "bare-os": "^3.3.0",
1380 "bare-path": "^3.0.0"
1381 }
1382 },
1383 "node_modules/text-decoder": {
1384 "version": "1.2.7",
1385 "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz",
1386 "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==",
1387 "license": "Apache-2.0",
1388 "dependencies": {
1389 "b4a": "^1.6.4"
1390 }
1391 },
1392 "node_modules/timeout-refresh": {
1393 "version": "2.0.1",
1394 "resolved": "https://registry.npmjs.org/timeout-refresh/-/timeout-refresh-2.0.1.tgz",
1395 "integrity": "sha512-SVqEcMZBsZF9mA78rjzCrYrUs37LMJk3ShZ851ygZYW1cMeIjs9mL57KO6Iv5mmjSQnOe/29/VAfGXo+oRCiVw==",
1396 "license": "MIT"
1397 },
1398 "node_modules/tmatch": {
1399 "version": "5.0.0",
1400 "resolved": "https://registry.npmjs.org/tmatch/-/tmatch-5.0.0.tgz",
1401 "integrity": "sha512-Ib9OtBkpHn07tXP04SlN1SYRxFgTk6wSM2EBmjjxug4u5RXPRVLkdFJSS1PmrQidaSB8Lru9nRtViQBsbxzE5Q==",
1402 "dev": true,
1403 "license": "ISC",
1404 "engines": {
1405 "node": ">=8"
1406 }
1407 },
1408 "node_modules/unslab": {
1409 "version": "1.3.0",
1410 "resolved": "https://registry.npmjs.org/unslab/-/unslab-1.3.0.tgz",
1411 "integrity": "sha512-YATkfKAFj47kTzmiQrWXMyRvaVrHsW6MEALa4bm+FhiA2YG4oira+Z3DXN6LrYOYn2Y8eO94Lwl9DOHjs1FpoQ==",
1412 "license": "Apache-2.0",
1413 "dependencies": {
1414 "b4a": "^1.6.6"
1415 }
1416 },
1417 "node_modules/v8-to-istanbul": {
1418 "version": "9.3.0",
1419 "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
1420 "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==",
1421 "dev": true,
1422 "license": "ISC",
1423 "dependencies": {
1424 "@jridgewell/trace-mapping": "^0.3.12",
1425 "@types/istanbul-lib-coverage": "^2.0.1",
1426 "convert-source-map": "^2.0.0"
1427 },
1428 "engines": {
1429 "node": ">=10.12.0"
1430 }
1431 },
1432 "node_modules/varint": {
1433 "version": "5.0.0",
1434 "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz",
1435 "integrity": "sha512-gC13b/bWrqQoKY2EmROCZ+AR0jitc6DnDGaQ6Ls9QpKmuSgJB1eQ7H3KETtQm7qSdMWMKCmsshyCmUwMLh3OAA==",
1436 "license": "MIT"
1437 },
1438 "node_modules/which-runtime": {
1439 "version": "1.3.2",
1440 "resolved": "https://registry.npmjs.org/which-runtime/-/which-runtime-1.3.2.tgz",
1441 "integrity": "sha512-5kwCfWml7+b2NO7KrLMhYihjRx0teKkd3yGp1Xk5Vaf2JGdSh+rgVhEALAD9c/59dP+YwJHXoEO7e8QPy7gOkw==",
1442 "license": "Apache-2.0"
1443 },
1444 "node_modules/z32": {
1445 "version": "1.1.0",
1446 "resolved": "https://registry.npmjs.org/z32/-/z32-1.1.0.tgz",
1447 "integrity": "sha512-1WUHy+VS6d0HPNspDxvLssBbeQjXMjSnpv0vH82vRAUfg847NmX3OXozp/hRP5jPhxBbrVzrgvAt+UsGNzRFQQ==",
1448 "license": "MIT",
1449 "dependencies": {
1450 "b4a": "^1.5.3"
1451 }
1452 }
1453 }
1454}
package.json +22 -0
……@@ -0,0 +1,22 @@
1{
2 "name": "trust-map",
3 "version": "0.1.0",
4 "description": "Pubkey → permissions store with optional hyperident chain verification",
5 "type": "module",
6 "main": "index.js",
7 "scripts": {
8 "test": "brittle test/*.test.js"
9 },
10 "dependencies": {
11 "b4a": "^1.6.0",
12 "hyperbee": "^2.20.0",
13 "hypercore": "^11.0.0",
14 "ready-resource": "^1.1.0"
15 },
16 "devDependencies": {
17 "brittle": "^3.0.0",
18 "corestore": "^7.0.0",
19 "hypercore-crypto": "^3.4.0",
20 "keet-identity-key": "^3.0.0"
21 }
22}
test/trust-map.test.js +241 -0
……@@ -0,0 +1,241 @@
1import test from 'brittle'
2import Corestore from 'corestore'
3import IdentityKey from 'keet-identity-key'
4import crypto from 'hypercore-crypto'
5import b4a from 'b4a'
6import { TrustMap } from '../index.js'
7
8async function makeTrustMap (t, opts = {}) {
9 const store = new Corestore('/tmp/trust-map-test-' + Math.random().toString(36).slice(2))
10 await store.ready()
11 const core = store.get({ name: 'trust-map' })
12 await core.ready()
13 const tm = new TrustMap({ core, identityKey: opts.identityKey })
14 await tm.ready()
15 t.teardown(async () => {
16 await tm.close()
17 await store.close()
18 })
19 return tm
20}
21
22// ── Direct grants (no chain) ─────────────────────────────────
23
24test('grant + check + revoke (direct pubkey)', async (t) => {
25 const tm = await makeTrustMap(t)
26 const pk = b4a.toString(crypto.randomBytes(32), 'hex')
27
28 await tm.grant(pk, 'repo-x', ['read', 'write'])
29 t.ok(await tm.check(pk, 'repo-x', 'read'), 'has read')
30 t.ok(await tm.check(pk, 'repo-x', 'write'), 'has write')
31 t.absent(await tm.check(pk, 'repo-x', 'admin'), 'no admin')
32
33 await tm.revoke(pk, 'repo-x', ['write'])
34 t.ok(await tm.check(pk, 'repo-x', 'read'), 'still has read')
35 t.absent(await tm.check(pk, 'repo-x', 'write'), 'write revoked')
36
37 await tm.revoke(pk, 'repo-x')
38 t.absent(await tm.check(pk, 'repo-x', 'read'), 'all perms revoked')
39})
40
41test('grant accepts Buffer pubkey too', async (t) => {
42 const tm = await makeTrustMap(t)
43 const pkBuf = crypto.randomBytes(32)
44 const pkHex = b4a.toString(pkBuf, 'hex')
45
46 await tm.grant(pkBuf, 'repo-y', ['read'])
47 t.ok(await tm.check(pkBuf, 'repo-y', 'read'), 'check by Buffer')
48 t.ok(await tm.check(pkHex, 'repo-y', 'read'), 'check by hex string')
49})
50
51test('multiple grants merge perms (no duplicates)', async (t) => {
52 const tm = await makeTrustMap(t)
53 const pk = b4a.toString(crypto.randomBytes(32), 'hex')
54
55 await tm.grant(pk, 'repo-x', ['read'])
56 await tm.grant(pk, 'repo-x', ['write'])
57 await tm.grant(pk, 'repo-x', ['read', 'admin']) // re-adds 'read'
58
59 const entries = await tm.listForPubkey(pk)
60 t.is(entries.length, 1)
61 t.alike(entries[0].perms.sort(), ['admin', 'read', 'write'])
62})
63
64test('wildcard resource grants apply to all resources', async (t) => {
65 const tm = await makeTrustMap(t)
66 const pk = b4a.toString(crypto.randomBytes(32), 'hex')
67
68 await tm.grant(pk, '*', ['read'])
69 t.ok(await tm.check(pk, 'repo-a', 'read'), 'wildcard grants read on repo-a')
70 t.ok(await tm.check(pk, 'repo-b', 'read'), 'wildcard grants read on repo-b')
71 t.absent(await tm.check(pk, 'repo-a', 'write'), 'wildcard does not grant write')
72
73 // Specific grant overlays wildcard
74 await tm.grant(pk, 'repo-a', ['write'])
75 t.ok(await tm.check(pk, 'repo-a', 'write'), 'specific resource grant works')
76 t.ok(await tm.check(pk, 'repo-a', 'read'), 'wildcard still grants read')
77})
78
79test('listForPubkey + list', async (t) => {
80 const tm = await makeTrustMap(t)
81 const pk1 = b4a.toString(crypto.randomBytes(32), 'hex')
82 const pk2 = b4a.toString(crypto.randomBytes(32), 'hex')
83
84 await tm.grant(pk1, 'repo-a', ['read', 'write'])
85 await tm.grant(pk1, 'repo-b', ['read'])
86 await tm.grant(pk2, 'repo-a', ['admin'])
87
88 const pk1Entries = await tm.listForPubkey(pk1)
89 t.is(pk1Entries.length, 2)
90
91 const all = await tm.list()
92 t.is(all.length, 3)
93})
94
95test('persistence across reopen', async (t) => {
96 const dir = '/tmp/trust-map-persist-' + Math.random().toString(36).slice(2)
97 const store1 = new Corestore(dir)
98 await store1.ready()
99 const core1 = store1.get({ name: 'tm' })
100 await core1.ready()
101 const tm1 = new TrustMap({ core: core1 })
102 await tm1.ready()
103
104 const pk = b4a.toString(crypto.randomBytes(32), 'hex')
105 await tm1.grant(pk, 'repo-x', ['read'])
106 await tm1.close()
107 await store1.close()
108
109 // Reopen
110 const store2 = new Corestore(dir)
111 await store2.ready()
112 const core2 = store2.get({ name: 'tm' })
113 await core2.ready()
114 const tm2 = new TrustMap({ core: core2 })
115 await tm2.ready()
116
117 t.ok(await tm2.check(pk, 'repo-x', 'read'), 'state persisted across reopen')
118
119 await tm2.close()
120 await store2.close()
121})
122
123// ── Chain verification (via keet-identity-key) ───────────────
124
125test('checkChain: verifies a real hyperident-style attestation chain', async (t) => {
126 const tm = await makeTrustMap(t, { identityKey: IdentityKey })
127
128 // Create a master identity from a mnemonic
129 const mnemonic = IdentityKey.generateMnemonic()
130 const masterIdentity = await IdentityKey.from({ mnemonic })
131
132 // Create a device keypair
133 const deviceKeyPair = crypto.keyPair()
134
135 // Master attests the device (this is what hyperident does internally)
136 const deviceProof = await masterIdentity.bootstrap(deviceKeyPair.publicKey)
137
138 // Sign some data with the device chain
139 const data = b4a.from('hello, trust-map')
140 const proof = IdentityKey.attestData(data, deviceKeyPair, deviceProof)
141
142 // Get the master pubkey (this is what trust-map looks up)
143 const masterPubkey = b4a.toString(masterIdentity.identityKeyPair.publicKey, 'hex')
144
145 // Grant permissions to the master, NOT the device
146 await tm.grant(masterPubkey, 'repo-x', ['read', 'write'])
147
148 // The peer presents the proof + data — trust-map should accept
149 const result = await tm.checkChain({
150 proof,
151 data,
152 resource: 'repo-x',
153 perm: 'write'
154 })
155
156 t.ok(result.ok, 'chain accepted')
157 t.is(result.masterPubkey, masterPubkey, 'extracted correct master')
158 t.is(result.devicePubkey, b4a.toString(deviceKeyPair.publicKey, 'hex'), 'extracted device pubkey')
159})
160
161test('checkChain: rejects when master is not in trust map', async (t) => {
162 const tm = await makeTrustMap(t, { identityKey: IdentityKey })
163
164 const masterIdentity = await IdentityKey.from({ mnemonic: IdentityKey.generateMnemonic() })
165 const deviceKeyPair = crypto.keyPair()
166 const deviceProof = await masterIdentity.bootstrap(deviceKeyPair.publicKey)
167
168 const data = b4a.from('hello')
169 const proof = IdentityKey.attestData(data, deviceKeyPair, deviceProof)
170
171 // No grant for the master — should be rejected
172 const result = await tm.checkChain({
173 proof, data, resource: 'repo-x', perm: 'read'
174 })
175
176 t.absent(result.ok)
177 t.ok(result.reason.includes('not authorized'), 'reason explains failure')
178})
179
180test('checkChain: rejects tampered data', async (t) => {
181 const tm = await makeTrustMap(t, { identityKey: IdentityKey })
182
183 const masterIdentity = await IdentityKey.from({ mnemonic: IdentityKey.generateMnemonic() })
184 const deviceKeyPair = crypto.keyPair()
185 const deviceProof = await masterIdentity.bootstrap(deviceKeyPair.publicKey)
186
187 const data = b4a.from('original data')
188 const proof = IdentityKey.attestData(data, deviceKeyPair, deviceProof)
189
190 const masterPubkey = b4a.toString(masterIdentity.identityKeyPair.publicKey, 'hex')
191 await tm.grant(masterPubkey, 'repo-x', ['write'])
192
193 // Try to verify with TAMPERED data
194 const result = await tm.checkChain({
195 proof,
196 data: b4a.from('tampered data'),
197 resource: 'repo-x',
198 perm: 'write'
199 })
200
201 t.absent(result.ok)
202 t.ok(result.reason.includes('invalid attestation'), 'rejected as invalid')
203})
204
205test('checkChain: device key NOT in trust map (only master matters)', async (t) => {
206 const tm = await makeTrustMap(t, { identityKey: IdentityKey })
207
208 const masterIdentity = await IdentityKey.from({ mnemonic: IdentityKey.generateMnemonic() })
209 const deviceKeyPair = crypto.keyPair()
210 const deviceProof = await masterIdentity.bootstrap(deviceKeyPair.publicKey)
211
212 const data = b4a.from('test')
213 const proof = IdentityKey.attestData(data, deviceKeyPair, deviceProof)
214
215 const masterPubkey = b4a.toString(masterIdentity.identityKeyPair.publicKey, 'hex')
216 const devicePubkeyHex = b4a.toString(deviceKeyPair.publicKey, 'hex')
217
218 // Only grant to master
219 await tm.grant(masterPubkey, 'repo-x', ['admin'])
220
221 // Direct check on the device pubkey should FAIL (device not in map)
222 t.absent(await tm.check(devicePubkeyHex, 'repo-x', 'admin'), 'device not directly authorized')
223
224 // Chain check should SUCCEED (device inherits from master)
225 const result = await tm.checkChain({ proof, data, resource: 'repo-x', perm: 'admin' })
226 t.ok(result.ok, 'chain check inherits from master')
227})
228
229test('checkChain: returns useful error when identityKey not configured', async (t) => {
230 const tm = await makeTrustMap(t) // no identityKey
231
232 const result = await tm.checkChain({
233 proof: b4a.from('fake'),
234 data: b4a.from('fake'),
235 resource: 'r',
236 perm: 'p'
237 })
238
239 t.absent(result.ok)
240 t.ok(result.reason.includes('no identityKey'))
241})