@steve02081504/fount-p2p 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -0
- package/core/bytes_codec.mjs +51 -0
- package/core/canonical_json.mjs +21 -0
- package/core/composite_key.mjs +91 -0
- package/core/constants.mjs +53 -0
- package/core/entity_id.mjs +53 -0
- package/core/entity_id_parse.mjs +40 -0
- package/core/evfs_logical_path.mjs +15 -0
- package/core/hexIds.mjs +73 -0
- package/core/hlc.mjs +114 -0
- package/core/random_id.mjs +9 -0
- package/crypto/channel.mjs +101 -0
- package/crypto/checkpoint_sign.mjs +67 -0
- package/crypto/crypto.mjs +158 -0
- package/crypto/key.mjs +431 -0
- package/dag/canonicalize_row.mjs +65 -0
- package/dag/event_query.mjs +15 -0
- package/dag/index.mjs +335 -0
- package/dag/storage.mjs +333 -0
- package/dag/strip_extensions.mjs +18 -0
- package/dag/tunables.json +6 -0
- package/discovery/bt.mjs +260 -0
- package/discovery/index.mjs +134 -0
- package/discovery/mdns.mjs +138 -0
- package/discovery/nostr.mjs +273 -0
- package/entity/files/acl.mjs +38 -0
- package/entity/files/evfs.mjs +189 -0
- package/entity/files/evfs_ref.mjs +37 -0
- package/entity/files/manifest_acl_registry.mjs +93 -0
- package/entity/files/replica_host_cache.mjs +46 -0
- package/entity/files/url.mjs +19 -0
- package/entity/hosting_registry.mjs +47 -0
- package/entity/localized_core.mjs +141 -0
- package/entity/logical_entity.mjs +25 -0
- package/entity/logical_entity_id_registry.mjs +40 -0
- package/entity/node_hash.mjs +15 -0
- package/entity/presentation_registry.mjs +44 -0
- package/entity/profile.mjs +256 -0
- package/entity/replica.mjs +20 -0
- package/entity/session_snapshot_registry.mjs +38 -0
- package/federation/chunk_fetch_pending.mjs +128 -0
- package/federation/chunk_fetch_scheduler.mjs +97 -0
- package/federation/dag_order_cache.mjs +124 -0
- package/federation/dedupe_slot.mjs +33 -0
- package/federation/message_rate_limit.mjs +23 -0
- package/federation/operator_key_chain.mjs +200 -0
- package/federation/topo_order_memo.mjs +44 -0
- package/federation/volatile_streams.mjs +52 -0
- package/federation/want_ids.mjs +158 -0
- package/files/assemble.mjs +220 -0
- package/files/assemble_stream.mjs +129 -0
- package/files/chunk_fetch.mjs +113 -0
- package/files/chunk_fetch_verify.mjs +23 -0
- package/files/chunk_provider_registry.mjs +70 -0
- package/files/chunk_responder.mjs +79 -0
- package/files/chunk_store.mjs +87 -0
- package/files/manifest.mjs +99 -0
- package/files/transfer_key.mjs +87 -0
- package/files/transfer_key_registry.mjs +108 -0
- package/governance/branch.mjs +230 -0
- package/governance/join_pow.mjs +165 -0
- package/governance/owner_succession_ballot.mjs +57 -0
- package/governance/tunables.json +7 -0
- package/index.mjs +39 -0
- package/link/channel_mux.mjs +222 -0
- package/link/frame.mjs +246 -0
- package/link/handshake.mjs +175 -0
- package/link/link.mjs +617 -0
- package/link/rtc.mjs +109 -0
- package/link/sdp_fingerprint.mjs +25 -0
- package/mailbox/consumer_registry.mjs +71 -0
- package/mailbox/deliver_or_store.mjs +190 -0
- package/mailbox/importance.mjs +72 -0
- package/mailbox/parse.mjs +73 -0
- package/mailbox/prune.mjs +106 -0
- package/mailbox/rate.mjs +86 -0
- package/mailbox/settings.mjs +53 -0
- package/mailbox/store.mjs +256 -0
- package/mailbox/tunables.json +12 -0
- package/mailbox/wire.mjs +40 -0
- package/node/denylist.mjs +309 -0
- package/node/entity_store.mjs +214 -0
- package/node/identity.mjs +99 -0
- package/node/instance.mjs +115 -0
- package/node/network.mjs +306 -0
- package/node/personal_block.mjs +286 -0
- package/node/reputation_store.mjs +326 -0
- package/node/retention_policy.mjs +82 -0
- package/node/signaling_config.mjs +32 -0
- package/node/storage.mjs +30 -0
- package/node/storage_plugins.mjs +71 -0
- package/node/user_paths.mjs +10 -0
- package/overlay/index.mjs +191 -0
- package/package.json +73 -0
- package/permissions/bitmask.mjs +35 -0
- package/permissions/evaluator.mjs +90 -0
- package/permissions/index.mjs +12 -0
- package/permissions/layered.mjs +39 -0
- package/registries/action.mjs +94 -0
- package/registries/event_type.mjs +75 -0
- package/registries/inbound.mjs +90 -0
- package/registries/p2p_viewer.mjs +35 -0
- package/registries/part_path.mjs +35 -0
- package/registries/room_provider.mjs +47 -0
- package/reputation/engine.mjs +458 -0
- package/reputation/math.mjs +73 -0
- package/reputation/pick_score.mjs +11 -0
- package/reputation/relay_dedupe.mjs +22 -0
- package/reputation/tunables.json +36 -0
- package/rooms/scoped_link.mjs +185 -0
- package/schemas/discovery.mjs +110 -0
- package/schemas/federation_pull.mjs +102 -0
- package/schemas/mailbox.mjs +37 -0
- package/schemas/remote_event.mjs +17 -0
- package/timeline/append_core.mjs +54 -0
- package/timeline/materialize_runner.mjs +26 -0
- package/timeline/prune.mjs +39 -0
- package/timeline/retention.mjs +54 -0
- package/timeline/retention_runner.mjs +35 -0
- package/timeline/verify_remote.mjs +25 -0
- package/transport/group_link_set.mjs +324 -0
- package/transport/ice_servers.mjs +72 -0
- package/transport/link_registry.mjs +749 -0
- package/transport/peer_identity_maps.mjs +94 -0
- package/transport/peer_pool.mjs +355 -0
- package/transport/remote_user_room.mjs +109 -0
- package/transport/room_scopes.mjs +2 -0
- package/transport/room_wire_action.mjs +19 -0
- package/transport/rtc_connection_budget.mjs +180 -0
- package/transport/rtc_mdns_filter.mjs +118 -0
- package/transport/stale_peer_log.mjs +50 -0
- package/transport/user_room.mjs +263 -0
- package/trust_graph/build.mjs +99 -0
- package/trust_graph/cache.mjs +44 -0
- package/trust_graph/engine.mjs +184 -0
- package/trust_graph/registry.mjs +38 -0
- package/trust_graph/resolve.mjs +105 -0
- package/trust_graph/send.mjs +88 -0
- package/trust_graph/tunables.json +13 -0
- package/utils/async_mutex.mjs +69 -0
- package/utils/debug_log.mjs +16 -0
- package/utils/duration.mjs +28 -0
- package/utils/json_io.mjs +57 -0
- package/utils/lru.mjs +22 -0
- package/utils/map_pool.mjs +27 -0
- package/wire/group_part.mjs +43 -0
- package/wire/ingress.mjs +58 -0
- package/wire/part_common.mjs +55 -0
- package/wire/part_fanout.mjs +71 -0
- package/wire/part_ingress.mjs +172 -0
- package/wire/part_invoke.mjs +81 -0
- package/wire/rate_bucket.mjs +49 -0
- package/wire/volatile_signature.mjs +76 -0
- package/wire/wait.mjs +127 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VOLATILE 流式分片签名域(§6.4):`pendingStreamId + chunkSeq + slices`。
|
|
3
|
+
*/
|
|
4
|
+
import { Buffer } from 'node:buffer'
|
|
5
|
+
import { createHash } from 'node:crypto'
|
|
6
|
+
|
|
7
|
+
import { isHex64, isSignatureHex128 } from '../core/hexIds.mjs'
|
|
8
|
+
import { keyPairFromSeed, sign, verify } from '../crypto/crypto.mjs'
|
|
9
|
+
|
|
10
|
+
const CHUNK_DOMAIN = 'fount-volatile-chunk'
|
|
11
|
+
|
|
12
|
+
/** 入站 stream_chunk 切片数量上限。 */
|
|
13
|
+
export const MAX_STREAM_VOLATILE_SLICES = 256
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {unknown} slices 入站切片
|
|
17
|
+
* @returns {object[] | null} 合法切片或 null
|
|
18
|
+
*/
|
|
19
|
+
export function boundStreamSlices(slices) {
|
|
20
|
+
if (!Array.isArray(slices) || slices.length > MAX_STREAM_VOLATILE_SLICES) return null
|
|
21
|
+
return slices
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {string} pendingStreamId 逻辑流 id
|
|
26
|
+
* @param {number} chunkSeq 分片序号(从 1 递增)
|
|
27
|
+
* @param {object[]} slices 差异切片数组
|
|
28
|
+
* @returns {Uint8Array} 验签消息字节
|
|
29
|
+
*/
|
|
30
|
+
export function streamChunkSignBytes(pendingStreamId, chunkSeq, slices) {
|
|
31
|
+
const streamId = String(pendingStreamId ?? '')
|
|
32
|
+
const sequence = Number.isFinite(Number(chunkSeq)) ? String(chunkSeq) : '0'
|
|
33
|
+
const body = JSON.stringify(slices ?? [])
|
|
34
|
+
return new TextEncoder().encode(`${CHUNK_DOMAIN}\0${streamId}\0${sequence}\0${body}`)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {Uint8Array} bytes 签名域
|
|
39
|
+
* @param {Uint8Array} secretKey 私钥种子(32 字节)
|
|
40
|
+
* @returns {Promise<string>} 128 位 hex 签名
|
|
41
|
+
*/
|
|
42
|
+
export async function signStreamSignatureHex(bytes, secretKey) {
|
|
43
|
+
const signatureBytes = await sign(bytes, secretKey)
|
|
44
|
+
return Buffer.from(signatureBytes).toString('hex')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @param {Uint8Array} bytes 签名域
|
|
49
|
+
* @param {string} signatureHex 128 位十六进制 签名
|
|
50
|
+
* @param {string} publicKeyHex 64 位十六进制 公钥
|
|
51
|
+
* @returns {Promise<boolean>} 验签是否通过
|
|
52
|
+
*/
|
|
53
|
+
export async function verifyStreamSignatureHex(bytes, signatureHex, publicKeyHex) {
|
|
54
|
+
const signature = String(signatureHex || '').trim().toLowerCase()
|
|
55
|
+
const publicKey = String(publicKeyHex || '').trim().toLowerCase()
|
|
56
|
+
if (!isSignatureHex128(signature) || !isHex64(publicKey)) return false
|
|
57
|
+
try {
|
|
58
|
+
return await verify(Buffer.from(signature, 'hex'), bytes, Buffer.from(publicKey, 'hex'))
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 本节点出站 VOLATILE 签名密钥(由用户名 + 联邦口令材料确定性派生)。
|
|
67
|
+
* @param {string} username 用户
|
|
68
|
+
* @param {string} seedMaterial 口令或回退材料
|
|
69
|
+
* @returns {{ publicKey: Uint8Array, secretKey: Uint8Array }} 密钥对
|
|
70
|
+
*/
|
|
71
|
+
export function streamKeyPairFromUserSeed(username, seedMaterial) {
|
|
72
|
+
const user = String(username ?? '')
|
|
73
|
+
const material = String(seedMaterial ?? '')
|
|
74
|
+
const seed = createHash('sha256').update(`fount-stream-sign\0${user}\0${material}`).digest()
|
|
75
|
+
return keyPairFromSeed(seed)
|
|
76
|
+
}
|
package/wire/wait.mjs
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trystero 请求-响应等待表(gossip、channel history 等共用)。
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {{ resolve: (value?: unknown) => void, timer: ReturnType<typeof setTimeout> }} WireWaiter
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {Map<string, unknown>} pending 等待表
|
|
11
|
+
* @param {string} key 等待键
|
|
12
|
+
* @param {number} timeoutMs 超时毫秒
|
|
13
|
+
* @param {() => unknown} onTimeout 超时回调值
|
|
14
|
+
* @returns {{ resolve: (value: unknown) => void, promise: Promise<unknown> }} 等待句柄
|
|
15
|
+
*/
|
|
16
|
+
export function registerWireWait(pending, key, timeoutMs, onTimeout) {
|
|
17
|
+
const waitPromise = new Promise(resolve => {
|
|
18
|
+
const timer = setTimeout(() => {
|
|
19
|
+
pending.delete(key)
|
|
20
|
+
resolve(onTimeout())
|
|
21
|
+
}, timeoutMs)
|
|
22
|
+
pending.set(key, {
|
|
23
|
+
/** @param {unknown} value 应答值 */
|
|
24
|
+
resolve: value => {
|
|
25
|
+
clearTimeout(timer)
|
|
26
|
+
pending.delete(key)
|
|
27
|
+
resolve(value)
|
|
28
|
+
},
|
|
29
|
+
timer,
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
const entry = pending.get(key)
|
|
33
|
+
return {
|
|
34
|
+
resolve: entry.resolve,
|
|
35
|
+
promise: waitPromise,
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {Map<string, Map<string, WireWaiter[]>>} pending 按前缀分桶的多 waiter 表
|
|
41
|
+
* @param {string} keyPrefix 键前缀(如 `user\0group\0`)
|
|
42
|
+
* @param {string} suffixKey 后缀键
|
|
43
|
+
* @returns {Map<string, WireWaiter[]>} 后缀桶
|
|
44
|
+
*/
|
|
45
|
+
function ensurePrefixBucket(pending, keyPrefix, suffixKey) {
|
|
46
|
+
let bucket = pending.get(keyPrefix)
|
|
47
|
+
if (!bucket) {
|
|
48
|
+
bucket = new Map()
|
|
49
|
+
pending.set(keyPrefix, bucket)
|
|
50
|
+
}
|
|
51
|
+
return bucket
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 多 waiter 注册(gossip 等同键并发等待)。
|
|
56
|
+
* @param {Map<string, Map<string, WireWaiter[]>>} pending 多 waiter 表
|
|
57
|
+
* @param {string} keyPrefix 键前缀
|
|
58
|
+
* @param {string} suffixKey 后缀键
|
|
59
|
+
* @param {number} timeoutMs 超时毫秒
|
|
60
|
+
* @param {() => unknown} [onTimeout] 超时返回值
|
|
61
|
+
* @returns {Promise<unknown>} 完成 promise
|
|
62
|
+
*/
|
|
63
|
+
export function registerMultiWireWait(pending, keyPrefix, suffixKey, timeoutMs, onTimeout = () => undefined) {
|
|
64
|
+
return new Promise(resolve => {
|
|
65
|
+
const timer = setTimeout(() => {
|
|
66
|
+
finishMultiWireWaiters(pending, keyPrefix, suffixKey)
|
|
67
|
+
resolve(onTimeout())
|
|
68
|
+
}, timeoutMs)
|
|
69
|
+
const bucket = ensurePrefixBucket(pending, keyPrefix, suffixKey)
|
|
70
|
+
let waiters = bucket.get(suffixKey)
|
|
71
|
+
if (!waiters) {
|
|
72
|
+
waiters = []
|
|
73
|
+
bucket.set(suffixKey, waiters)
|
|
74
|
+
}
|
|
75
|
+
waiters.push({ resolve, timer })
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param {Map<string, Map<string, WireWaiter[]>>} pending 多 waiter 表
|
|
81
|
+
* @param {string} keyPrefix 键前缀
|
|
82
|
+
* @param {string} suffixKey 后缀键
|
|
83
|
+
* @returns {void}
|
|
84
|
+
*/
|
|
85
|
+
export function finishMultiWireWaiters(pending, keyPrefix, suffixKey) {
|
|
86
|
+
const bucket = pending.get(keyPrefix)
|
|
87
|
+
const waiters = bucket?.get(suffixKey)
|
|
88
|
+
if (!waiters?.length) return
|
|
89
|
+
bucket.delete(suffixKey)
|
|
90
|
+
if (!bucket.size) pending.delete(keyPrefix)
|
|
91
|
+
for (const waiter of waiters) {
|
|
92
|
+
clearTimeout(waiter.timer)
|
|
93
|
+
waiter.resolve()
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* 前缀桶内按 want id 命中唤醒 waiter。
|
|
99
|
+
* @param {Map<string, Map<string, WireWaiter[]>>} pending 多 waiter 表
|
|
100
|
+
* @param {string} keyPrefix 键前缀
|
|
101
|
+
* @param {ReadonlySet<string>} hitIds 命中 id 集合
|
|
102
|
+
* @param {(suffixKey: string) => string[] | null} parseWantIds 从后缀键解析 want id 列表
|
|
103
|
+
* @returns {void}
|
|
104
|
+
*/
|
|
105
|
+
export function notifyMultiWireWaitersByPrefix(pending, keyPrefix, hitIds, parseWantIds) {
|
|
106
|
+
if (!hitIds.size) return
|
|
107
|
+
const bucket = pending.get(keyPrefix)
|
|
108
|
+
if (!bucket) return
|
|
109
|
+
for (const [suffixKey, waiters] of bucket) {
|
|
110
|
+
const wanted = parseWantIds(suffixKey)
|
|
111
|
+
if (!wanted?.length) continue
|
|
112
|
+
let hit = false
|
|
113
|
+
for (const id of hitIds)
|
|
114
|
+
if (wanted.includes(id)) {
|
|
115
|
+
hit = true
|
|
116
|
+
break
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!hit) continue
|
|
120
|
+
bucket.delete(suffixKey)
|
|
121
|
+
for (const waiter of waiters) {
|
|
122
|
+
clearTimeout(waiter.timer)
|
|
123
|
+
waiter.resolve()
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (!bucket.size) pending.delete(keyPrefix)
|
|
127
|
+
}
|