@invictus-z/attp 0.1.0-alpha.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/dist/index.cjs +550 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +296 -0
- package/dist/index.d.ts +296 -0
- package/dist/index.js +513 -0
- package/dist/index.js.map +1 -0
- package/package.json +40 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
// attp/core/authentication/signatures.ts
|
|
2
|
+
async function signHash(entryHash, privateKey) {
|
|
3
|
+
try {
|
|
4
|
+
const data = new TextEncoder().encode(entryHash);
|
|
5
|
+
let signature;
|
|
6
|
+
const algorithm = privateKey.algorithm;
|
|
7
|
+
if (algorithm.name === "RSA-PSS") {
|
|
8
|
+
signature = await crypto.subtle.sign(
|
|
9
|
+
{
|
|
10
|
+
name: "RSA-PSS",
|
|
11
|
+
saltLength: 32
|
|
12
|
+
// PSS.MAX_LENGTH 在浏览器端无法直接获取,使用 32 (SHA-256 摘要长度)
|
|
13
|
+
},
|
|
14
|
+
privateKey,
|
|
15
|
+
data
|
|
16
|
+
);
|
|
17
|
+
} else if (algorithm.name === "ECDSA") {
|
|
18
|
+
signature = await crypto.subtle.sign(
|
|
19
|
+
{
|
|
20
|
+
name: "ECDSA",
|
|
21
|
+
hash: "SHA-256"
|
|
22
|
+
},
|
|
23
|
+
privateKey,
|
|
24
|
+
data
|
|
25
|
+
);
|
|
26
|
+
} else {
|
|
27
|
+
console.error(`[signatures] Unsupported key type: ${algorithm.name}`);
|
|
28
|
+
return "";
|
|
29
|
+
}
|
|
30
|
+
return arrayBufferToBase64(signature);
|
|
31
|
+
} catch (e) {
|
|
32
|
+
console.error("[signatures] signHash error:", e);
|
|
33
|
+
return "";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function verifySignature(entryHash, signatureB64, publicKey) {
|
|
37
|
+
try {
|
|
38
|
+
const sigBytes = base64ToArrayBuffer(signatureB64);
|
|
39
|
+
const data = new TextEncoder().encode(entryHash);
|
|
40
|
+
const algorithm = publicKey.algorithm;
|
|
41
|
+
if (algorithm.name === "RSA-PSS") {
|
|
42
|
+
return await crypto.subtle.verify(
|
|
43
|
+
{
|
|
44
|
+
name: "RSA-PSS",
|
|
45
|
+
saltLength: 32
|
|
46
|
+
},
|
|
47
|
+
publicKey,
|
|
48
|
+
sigBytes,
|
|
49
|
+
data
|
|
50
|
+
);
|
|
51
|
+
} else if (algorithm.name === "ECDSA") {
|
|
52
|
+
return await crypto.subtle.verify(
|
|
53
|
+
{
|
|
54
|
+
name: "ECDSA",
|
|
55
|
+
hash: "SHA-256"
|
|
56
|
+
},
|
|
57
|
+
publicKey,
|
|
58
|
+
sigBytes,
|
|
59
|
+
data
|
|
60
|
+
);
|
|
61
|
+
} else {
|
|
62
|
+
console.error(`[signatures] Unsupported key type: ${algorithm.name}`);
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
} catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function arrayBufferToBase64(buffer) {
|
|
70
|
+
const bytes = new Uint8Array(buffer);
|
|
71
|
+
let binary = "";
|
|
72
|
+
for (let i = 0; i < bytes.byteLength; i++) {
|
|
73
|
+
binary += String.fromCharCode(bytes[i]);
|
|
74
|
+
}
|
|
75
|
+
return btoa(binary);
|
|
76
|
+
}
|
|
77
|
+
function base64ToArrayBuffer(base64) {
|
|
78
|
+
const binary = atob(base64);
|
|
79
|
+
const bytes = new Uint8Array(binary.length);
|
|
80
|
+
for (let i = 0; i < binary.length; i++) {
|
|
81
|
+
bytes[i] = binary.charCodeAt(i);
|
|
82
|
+
}
|
|
83
|
+
return bytes.buffer;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// attp/core/message/event.ts
|
|
87
|
+
var RecordedHop = class _RecordedHop {
|
|
88
|
+
constructor(data) {
|
|
89
|
+
this.sessionId = data.sessionId;
|
|
90
|
+
this.senderDid = data.senderDid;
|
|
91
|
+
this.targetDid = data.targetDid;
|
|
92
|
+
this.content = data.content;
|
|
93
|
+
this.timestamp = data.timestamp;
|
|
94
|
+
this.hopCount = data.hopCount;
|
|
95
|
+
this.sigContent = data.sigContent ?? "";
|
|
96
|
+
}
|
|
97
|
+
/** 计算除 sigContent 外所有字段的 SHA-256 哈希。 */
|
|
98
|
+
async contentHash() {
|
|
99
|
+
const obj = {
|
|
100
|
+
session_id: this.sessionId,
|
|
101
|
+
sender_did: this.senderDid,
|
|
102
|
+
target_did: this.targetDid,
|
|
103
|
+
content: this.content,
|
|
104
|
+
timestamp: this.timestamp,
|
|
105
|
+
hop_count: this.hopCount
|
|
106
|
+
};
|
|
107
|
+
const sorted = {};
|
|
108
|
+
for (const key of Object.keys(obj).sort()) {
|
|
109
|
+
sorted[key] = obj[key];
|
|
110
|
+
}
|
|
111
|
+
const raw = JSON.stringify(sorted);
|
|
112
|
+
const buffer = new TextEncoder().encode(raw);
|
|
113
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
|
|
114
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
115
|
+
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
116
|
+
}
|
|
117
|
+
toDict() {
|
|
118
|
+
return {
|
|
119
|
+
session_id: this.sessionId,
|
|
120
|
+
sender_did: this.senderDid,
|
|
121
|
+
target_did: this.targetDid,
|
|
122
|
+
content: this.content,
|
|
123
|
+
timestamp: this.timestamp,
|
|
124
|
+
hop_count: this.hopCount,
|
|
125
|
+
sig_content: this.sigContent
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
static fromDict(data) {
|
|
129
|
+
return new _RecordedHop({
|
|
130
|
+
sessionId: data["session_id"],
|
|
131
|
+
senderDid: data["sender_did"],
|
|
132
|
+
targetDid: data["target_did"],
|
|
133
|
+
content: data["content"],
|
|
134
|
+
timestamp: data["timestamp"],
|
|
135
|
+
hopCount: data["hop_count"],
|
|
136
|
+
sigContent: data["sig_content"] ?? ""
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
var NodeMessage = class _NodeMessage {
|
|
141
|
+
constructor(data) {
|
|
142
|
+
this.protocolUrl = data.protocolUrl;
|
|
143
|
+
this.nonce = data.nonce;
|
|
144
|
+
this.recordedHop = data.recordedHop;
|
|
145
|
+
}
|
|
146
|
+
/** 发送方私钥对 recordedHop 内容签名,写入 sigContent。 */
|
|
147
|
+
async signContent(privateKey) {
|
|
148
|
+
const hash = await this.recordedHop.contentHash();
|
|
149
|
+
this.recordedHop.sigContent = await signHash(hash, privateKey);
|
|
150
|
+
}
|
|
151
|
+
/** 验证 recordedHop.sigContent 是否由对应公钥签署。 */
|
|
152
|
+
async verifyContent(publicKey) {
|
|
153
|
+
if (!this.recordedHop.sigContent) return false;
|
|
154
|
+
const hash = await this.recordedHop.contentHash();
|
|
155
|
+
return verifySignature(hash, this.recordedHop.sigContent, publicKey);
|
|
156
|
+
}
|
|
157
|
+
toDict() {
|
|
158
|
+
return {
|
|
159
|
+
protocol_url: this.protocolUrl,
|
|
160
|
+
nonce: this.nonce,
|
|
161
|
+
recorded_hop: this.recordedHop.toDict()
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
static fromDict(data) {
|
|
165
|
+
return new _NodeMessage({
|
|
166
|
+
protocolUrl: data["protocol_url"],
|
|
167
|
+
nonce: data["nonce"],
|
|
168
|
+
recordedHop: RecordedHop.fromDict(data["recorded_hop"])
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
async function identityHash(nodeDid, nonce) {
|
|
173
|
+
const obj = { node_did: nodeDid, nonce };
|
|
174
|
+
const sorted = {};
|
|
175
|
+
for (const key of Object.keys(obj).sort()) {
|
|
176
|
+
sorted[key] = obj[key];
|
|
177
|
+
}
|
|
178
|
+
const raw = JSON.stringify(sorted);
|
|
179
|
+
const buffer = new TextEncoder().encode(raw);
|
|
180
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
|
|
181
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
182
|
+
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
183
|
+
}
|
|
184
|
+
var BackMessage = class _BackMessage {
|
|
185
|
+
constructor(data) {
|
|
186
|
+
this.protocolUrl = data.protocolUrl;
|
|
187
|
+
this.nodeDid = data.nodeDid;
|
|
188
|
+
this.nonce = data.nonce;
|
|
189
|
+
this.sigIdentity = data.sigIdentity ?? "";
|
|
190
|
+
this.recordedHop = data.recordedHop;
|
|
191
|
+
}
|
|
192
|
+
// -- 身份签名 --
|
|
193
|
+
/** 使用回传节点私钥对 nodeDid+nonce 签名,写入 sigIdentity。 */
|
|
194
|
+
async signIdentity(privateKey) {
|
|
195
|
+
this.sigIdentity = await signHash(
|
|
196
|
+
await identityHash(this.nodeDid, this.nonce),
|
|
197
|
+
privateKey
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
/** 验证 sigIdentity 是否合法。 */
|
|
201
|
+
async verifyIdentity(publicKey) {
|
|
202
|
+
if (!this.sigIdentity) return false;
|
|
203
|
+
return verifySignature(
|
|
204
|
+
await identityHash(this.nodeDid, this.nonce),
|
|
205
|
+
this.sigIdentity,
|
|
206
|
+
publicKey
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
// -- 内容签名(发送方签名,由 recordedHop.sigContent 承载)--
|
|
210
|
+
/** 使用发送方私钥对 recordedHop 内容签名。 */
|
|
211
|
+
async signContent(privateKey) {
|
|
212
|
+
const hash = await this.recordedHop.contentHash();
|
|
213
|
+
this.recordedHop.sigContent = await signHash(hash, privateKey);
|
|
214
|
+
}
|
|
215
|
+
/** 验证 recordedHop 内容签名(发送方签名)。 */
|
|
216
|
+
async verifyContent(publicKey) {
|
|
217
|
+
if (!this.recordedHop.sigContent) return false;
|
|
218
|
+
const hash = await this.recordedHop.contentHash();
|
|
219
|
+
return verifySignature(hash, this.recordedHop.sigContent, publicKey);
|
|
220
|
+
}
|
|
221
|
+
toDict() {
|
|
222
|
+
return {
|
|
223
|
+
protocol_url: this.protocolUrl,
|
|
224
|
+
node_did: this.nodeDid,
|
|
225
|
+
nonce: this.nonce,
|
|
226
|
+
sig_identity: this.sigIdentity,
|
|
227
|
+
recorded_hop: this.recordedHop.toDict()
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
static fromDict(data) {
|
|
231
|
+
return new _BackMessage({
|
|
232
|
+
protocolUrl: data["protocol_url"],
|
|
233
|
+
nodeDid: data["node_did"],
|
|
234
|
+
nonce: data["nonce"],
|
|
235
|
+
sigIdentity: data["sig_identity"] ?? "",
|
|
236
|
+
recordedHop: RecordedHop.fromDict(data["recorded_hop"])
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// attp/core/authentication/keys.ts
|
|
242
|
+
var KeyStore = class {
|
|
243
|
+
constructor() {
|
|
244
|
+
this._cache = /* @__PURE__ */ new Map();
|
|
245
|
+
this._privateKeyCache = /* @__PURE__ */ new Map();
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* 注入公钥到缓存。
|
|
249
|
+
*/
|
|
250
|
+
cachePublicKey(nodeDid, publicKey) {
|
|
251
|
+
this._cache.set(nodeDid, publicKey);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* 获取缓存的公钥,不存在返回 undefined。
|
|
255
|
+
*/
|
|
256
|
+
get(nodeDid) {
|
|
257
|
+
return this._cache.get(nodeDid);
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* 暴露内部缓存 Map 引用,维持兼容性。
|
|
261
|
+
*/
|
|
262
|
+
get cacheDict() {
|
|
263
|
+
return this._cache;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* 缓存私钥,后续调用相同标识直接返回缓存。
|
|
267
|
+
*/
|
|
268
|
+
cachePrivateKey(keyId, privateKey) {
|
|
269
|
+
this._privateKeyCache.set(keyId, privateKey);
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* 获取缓存的私钥。
|
|
273
|
+
*/
|
|
274
|
+
getPrivateKey(keyId) {
|
|
275
|
+
return this._privateKeyCache.get(keyId);
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* 检查是否已有缓存的私钥。
|
|
279
|
+
*/
|
|
280
|
+
hasPrivateKey(keyId) {
|
|
281
|
+
return this._privateKeyCache.has(keyId);
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
// attp/core/provenance/hashing.ts
|
|
286
|
+
async function sha256Sorted(obj) {
|
|
287
|
+
const sorted = {};
|
|
288
|
+
for (const key of Object.keys(obj).sort()) {
|
|
289
|
+
sorted[key] = obj[key];
|
|
290
|
+
}
|
|
291
|
+
const raw = JSON.stringify(sorted);
|
|
292
|
+
const buffer = new TextEncoder().encode(raw);
|
|
293
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
|
|
294
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
295
|
+
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
296
|
+
}
|
|
297
|
+
async function calculateGenesisHash(sessionId, protocolNodeAddress) {
|
|
298
|
+
return sha256Sorted({
|
|
299
|
+
session_id: sessionId,
|
|
300
|
+
protocol_node_address: protocolNodeAddress
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
async function calculateHopHash(content, nodeDid, targetDid, hopCount, timestamp, sessionId, protocolNodeAddress) {
|
|
304
|
+
return sha256Sorted({
|
|
305
|
+
content,
|
|
306
|
+
node_did: nodeDid,
|
|
307
|
+
target_did: targetDid,
|
|
308
|
+
hop_count: hopCount,
|
|
309
|
+
timestamp,
|
|
310
|
+
session_id: sessionId,
|
|
311
|
+
protocol_node_address: protocolNodeAddress
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// attp/core/sessions/node_message.ts
|
|
316
|
+
var BehaviorEntry = class _BehaviorEntry {
|
|
317
|
+
constructor(data) {
|
|
318
|
+
this.fieldType = data.fieldType;
|
|
319
|
+
this.content = data.content;
|
|
320
|
+
this.timestamp = data.timestamp ?? Date.now() / 1e3;
|
|
321
|
+
this.target = data.target ?? "";
|
|
322
|
+
this.extra = data.extra ?? {};
|
|
323
|
+
}
|
|
324
|
+
toDict() {
|
|
325
|
+
return {
|
|
326
|
+
field_type: this.fieldType,
|
|
327
|
+
content: this.content,
|
|
328
|
+
timestamp: this.timestamp,
|
|
329
|
+
target: this.target,
|
|
330
|
+
extra: this.extra
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
static fromDict(data) {
|
|
334
|
+
return new _BehaviorEntry({
|
|
335
|
+
fieldType: data["field_type"],
|
|
336
|
+
content: data["content"],
|
|
337
|
+
timestamp: data["timestamp"] ?? 0,
|
|
338
|
+
target: data["target"] ?? "",
|
|
339
|
+
extra: data["extra"] ?? {}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
// attp/core/sessions/user_session.ts
|
|
345
|
+
var TRACE_KEYS = ["Hop", "Session_ID", "Protocol_Node_Address"];
|
|
346
|
+
var UserSession = class _UserSession {
|
|
347
|
+
constructor(data) {
|
|
348
|
+
this.key = data.key;
|
|
349
|
+
this.metadata = data.metadata ?? {};
|
|
350
|
+
this.updatedAt = data.updatedAt ?? Date.now() / 1e3;
|
|
351
|
+
}
|
|
352
|
+
// -- 追踪路由元数据 --
|
|
353
|
+
/** 提取追踪相关的元数据。 */
|
|
354
|
+
getTraceMetadata() {
|
|
355
|
+
const result = {};
|
|
356
|
+
for (const k of TRACE_KEYS) {
|
|
357
|
+
if (k in this.metadata) {
|
|
358
|
+
result[k] = this.metadata[k];
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return result;
|
|
362
|
+
}
|
|
363
|
+
/** 合并追踪元数据。 */
|
|
364
|
+
setTraceMetadata(traceData) {
|
|
365
|
+
for (const k of TRACE_KEYS) {
|
|
366
|
+
if (k in traceData) {
|
|
367
|
+
this.metadata[k] = traceData[k];
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
this.updatedAt = Date.now() / 1e3;
|
|
371
|
+
}
|
|
372
|
+
// -- 便捷访问器 --
|
|
373
|
+
get sessionId() {
|
|
374
|
+
return this.metadata["Session_ID"];
|
|
375
|
+
}
|
|
376
|
+
set sessionId(value) {
|
|
377
|
+
if (value !== void 0) this.metadata["Session_ID"] = value;
|
|
378
|
+
}
|
|
379
|
+
get protocolNodeAddress() {
|
|
380
|
+
return this.metadata["Protocol_Node_Address"];
|
|
381
|
+
}
|
|
382
|
+
set protocolNodeAddress(value) {
|
|
383
|
+
if (value !== void 0) this.metadata["Protocol_Node_Address"] = value;
|
|
384
|
+
}
|
|
385
|
+
get hop() {
|
|
386
|
+
return this.metadata["Hop"];
|
|
387
|
+
}
|
|
388
|
+
get hopCount() {
|
|
389
|
+
return this.hop?.Hop_Count ?? -1;
|
|
390
|
+
}
|
|
391
|
+
/** 用户 DID 标识 */
|
|
392
|
+
get userDid() {
|
|
393
|
+
return this.metadata["user_did"];
|
|
394
|
+
}
|
|
395
|
+
set userDid(value) {
|
|
396
|
+
if (value !== void 0) this.metadata["user_did"] = value;
|
|
397
|
+
}
|
|
398
|
+
/** 密钥标识(用于从 KeyStore 查找私钥) */
|
|
399
|
+
get keyId() {
|
|
400
|
+
return this.metadata["key_id"];
|
|
401
|
+
}
|
|
402
|
+
set keyId(value) {
|
|
403
|
+
if (value !== void 0) this.metadata["key_id"] = value;
|
|
404
|
+
}
|
|
405
|
+
// -- 通用元数据 --
|
|
406
|
+
setMetadata(key, value) {
|
|
407
|
+
this.metadata[key] = value;
|
|
408
|
+
this.updatedAt = Date.now() / 1e3;
|
|
409
|
+
}
|
|
410
|
+
getMetadata(key, defaultValue) {
|
|
411
|
+
return this.metadata[key] ?? defaultValue;
|
|
412
|
+
}
|
|
413
|
+
updateMetadata(data) {
|
|
414
|
+
Object.assign(this.metadata, data);
|
|
415
|
+
this.updatedAt = Date.now() / 1e3;
|
|
416
|
+
}
|
|
417
|
+
// -- 序列化 --
|
|
418
|
+
toDict() {
|
|
419
|
+
return {
|
|
420
|
+
key: this.key,
|
|
421
|
+
metadata: { ...this.metadata },
|
|
422
|
+
updated_at: this.updatedAt
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
static fromDict(data) {
|
|
426
|
+
return new _UserSession({
|
|
427
|
+
key: data["key"],
|
|
428
|
+
metadata: data["metadata"] ?? {},
|
|
429
|
+
updatedAt: data["updated_at"] ?? Date.now() / 1e3
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
var UserSessionManager = class {
|
|
434
|
+
constructor() {
|
|
435
|
+
this._sessions = /* @__PURE__ */ new Map();
|
|
436
|
+
}
|
|
437
|
+
/** 获取或创建会话。 */
|
|
438
|
+
getOrCreate(chatId) {
|
|
439
|
+
if (!this._sessions.has(chatId)) {
|
|
440
|
+
this._sessions.set(chatId, new UserSession({ key: chatId }));
|
|
441
|
+
}
|
|
442
|
+
return this._sessions.get(chatId);
|
|
443
|
+
}
|
|
444
|
+
/** 获取已有会话,不存在返回 undefined。 */
|
|
445
|
+
get(chatId) {
|
|
446
|
+
return this._sessions.get(chatId);
|
|
447
|
+
}
|
|
448
|
+
/** 保存/更新会话。 */
|
|
449
|
+
save(session) {
|
|
450
|
+
this._sessions.set(session.key, session);
|
|
451
|
+
}
|
|
452
|
+
/** 删除会话。 */
|
|
453
|
+
delete(chatId) {
|
|
454
|
+
this._sessions.delete(chatId);
|
|
455
|
+
}
|
|
456
|
+
/** 所有会话条目。 */
|
|
457
|
+
entries() {
|
|
458
|
+
return this._sessions.entries();
|
|
459
|
+
}
|
|
460
|
+
/** 会话数量。 */
|
|
461
|
+
get size() {
|
|
462
|
+
return this._sessions.size;
|
|
463
|
+
}
|
|
464
|
+
// -- 持久化 --
|
|
465
|
+
/** 序列化所有会话为 JSON 字符串。 */
|
|
466
|
+
serialize() {
|
|
467
|
+
const obj = {};
|
|
468
|
+
for (const [key, session] of this._sessions) {
|
|
469
|
+
obj[key] = session.toDict();
|
|
470
|
+
}
|
|
471
|
+
return JSON.stringify(obj);
|
|
472
|
+
}
|
|
473
|
+
/** 从 JSON 字符串反序列化恢复所有会话。 */
|
|
474
|
+
deserialize(json) {
|
|
475
|
+
try {
|
|
476
|
+
const obj = JSON.parse(json);
|
|
477
|
+
this._sessions.clear();
|
|
478
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
479
|
+
this._sessions.set(key, UserSession.fromDict(value));
|
|
480
|
+
}
|
|
481
|
+
} catch {
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
/** 保存到 localStorage。 */
|
|
485
|
+
saveToStorage(storageKey = "attp_user_sessions") {
|
|
486
|
+
try {
|
|
487
|
+
localStorage.setItem(storageKey, this.serialize());
|
|
488
|
+
} catch {
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
/** 从 localStorage 加载。 */
|
|
492
|
+
loadFromStorage(storageKey = "attp_user_sessions") {
|
|
493
|
+
try {
|
|
494
|
+
const raw = localStorage.getItem(storageKey);
|
|
495
|
+
if (raw) this.deserialize(raw);
|
|
496
|
+
} catch {
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
export {
|
|
501
|
+
BackMessage,
|
|
502
|
+
BehaviorEntry,
|
|
503
|
+
KeyStore,
|
|
504
|
+
NodeMessage,
|
|
505
|
+
RecordedHop,
|
|
506
|
+
UserSession,
|
|
507
|
+
UserSessionManager,
|
|
508
|
+
calculateGenesisHash,
|
|
509
|
+
calculateHopHash,
|
|
510
|
+
signHash,
|
|
511
|
+
verifySignature
|
|
512
|
+
};
|
|
513
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../attp/core/authentication/signatures.ts","../attp/core/message/event.ts","../attp/core/authentication/keys.ts","../attp/core/provenance/hashing.ts","../attp/core/sessions/node_message.ts","../attp/core/sessions/user_session.ts"],"sourcesContent":["/**\r\n * 签名与验签引擎。\r\n *\r\n * 从 python/attp/core/authentication/signatures.py 翻译而来。\r\n * 使用 Web Crypto API 实现,支持:\r\n * - RSA-PSS (对应 Python rsa.RSAPrivateKey/RSAPublicKey)\r\n * - ECDSA P-256/384/521 (对应 Python ec.EllipticCurvePrivateKey)\r\n *\r\n * 注意:Python 端对 entry_hash 字符串直接签名(UTF-8 编码后),\r\n * Web Crypto API 签名时也对 UTF-8 编码的字符串签名,保持一致。\r\n */\r\n\r\n/**\r\n * 使用私钥对 entryHash 签名,返回 Base64 编码的签名字符串。\r\n *\r\n * @param entryHash SHA-256 hex 字符串\r\n * @param privateKey CryptoKey 私钥对象 (RSA 或 EC)\r\n * @returns Base64 编码的签名字符串,失败返回空字符串\r\n */\r\nexport async function signHash(\r\n entryHash: string,\r\n privateKey: CryptoKey,\r\n): Promise<string> {\r\n try {\r\n const data = new TextEncoder().encode(entryHash);\r\n\r\n let signature: ArrayBuffer;\r\n\r\n const algorithm = privateKey.algorithm;\r\n if (algorithm.name === 'RSA-PSS') {\r\n signature = await crypto.subtle.sign(\r\n {\r\n name: 'RSA-PSS',\r\n saltLength: 32, // PSS.MAX_LENGTH 在浏览器端无法直接获取,使用 32 (SHA-256 摘要长度)\r\n },\r\n privateKey,\r\n data,\r\n );\r\n } else if (algorithm.name === 'ECDSA') {\r\n signature = await crypto.subtle.sign(\r\n {\r\n name: 'ECDSA',\r\n hash: 'SHA-256',\r\n },\r\n privateKey,\r\n data,\r\n );\r\n } else {\r\n console.error(`[signatures] Unsupported key type: ${algorithm.name}`);\r\n return '';\r\n }\r\n\r\n // 转为 Base64\r\n return arrayBufferToBase64(signature);\r\n } catch (e) {\r\n console.error('[signatures] signHash error:', e);\r\n return '';\r\n }\r\n}\r\n\r\n/**\r\n * 用公钥验证 entryHash 的签名。\r\n *\r\n * @param entryHash SHA-256 hex 字符串\r\n * @param signatureB64 Base64 编码的签名\r\n * @param publicKey CryptoKey 公钥对象\r\n * @returns true 签名合法,false 验证失败\r\n */\r\nexport async function verifySignature(\r\n entryHash: string,\r\n signatureB64: string,\r\n publicKey: CryptoKey,\r\n): Promise<boolean> {\r\n try {\r\n const sigBytes = base64ToArrayBuffer(signatureB64);\r\n const data = new TextEncoder().encode(entryHash);\r\n\r\n const algorithm = publicKey.algorithm;\r\n if (algorithm.name === 'RSA-PSS') {\r\n return await crypto.subtle.verify(\r\n {\r\n name: 'RSA-PSS',\r\n saltLength: 32,\r\n },\r\n publicKey,\r\n sigBytes,\r\n data,\r\n );\r\n } else if (algorithm.name === 'ECDSA') {\r\n return await crypto.subtle.verify(\r\n {\r\n name: 'ECDSA',\r\n hash: 'SHA-256',\r\n },\r\n publicKey,\r\n sigBytes,\r\n data,\r\n );\r\n } else {\r\n console.error(`[signatures] Unsupported key type: ${algorithm.name}`);\r\n return false;\r\n }\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n// ---- 辅助函数 ----\r\n\r\nfunction arrayBufferToBase64(buffer: ArrayBuffer): string {\r\n const bytes = new Uint8Array(buffer);\r\n let binary = '';\r\n for (let i = 0; i < bytes.byteLength; i++) {\r\n binary += String.fromCharCode(bytes[i]);\r\n }\r\n return btoa(binary);\r\n}\r\n\r\nfunction base64ToArrayBuffer(base64: string): ArrayBuffer {\r\n const binary = atob(base64);\r\n const bytes = new Uint8Array(binary.length);\r\n for (let i = 0; i < binary.length; i++) {\r\n bytes[i] = binary.charCodeAt(i);\r\n }\r\n return bytes.buffer;\r\n}","/**\r\n * 消息格式规范化 — RecordedHop / NodeMessage / BackMessage。\r\n *\r\n * 从 python/attp/core/message/event.py 翻译而来。\r\n * 序列化格式 (to_dict/from_dict) 与 Python 端完全一致,\r\n * 确保跨语言通信时的数据兼容性。\r\n */\r\n\r\nimport { signHash, verifySignature } from '../authentication/signatures';\r\n\r\n// ---------------------------------------------------------------------------\r\n// RecordedHop — 单跳记录\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * 单跳记录内容,嵌入在 NodeMessage 和 BackMessage 中。\r\n *\r\n * sigContent 是对其余字段哈希后的签名,\r\n * 由发送方私钥签署,用于内容完整性验证。\r\n */\r\nexport class RecordedHop {\r\n sessionId: string;\r\n senderDid: string;\r\n targetDid: string;\r\n content: string;\r\n timestamp: number;\r\n hopCount: number;\r\n sigContent: string;\r\n\r\n constructor(data: {\r\n sessionId: string;\r\n senderDid: string;\r\n targetDid: string;\r\n content: string;\r\n timestamp: number;\r\n hopCount: number;\r\n sigContent?: string;\r\n }) {\r\n this.sessionId = data.sessionId;\r\n this.senderDid = data.senderDid;\r\n this.targetDid = data.targetDid;\r\n this.content = data.content;\r\n this.timestamp = data.timestamp;\r\n this.hopCount = data.hopCount;\r\n this.sigContent = data.sigContent ?? '';\r\n }\r\n\r\n /** 计算除 sigContent 外所有字段的 SHA-256 哈希。 */\r\n async contentHash(): Promise<string> {\r\n const obj: Record<string, unknown> = {\r\n session_id: this.sessionId,\r\n sender_did: this.senderDid,\r\n target_did: this.targetDid,\r\n content: this.content,\r\n timestamp: this.timestamp,\r\n hop_count: this.hopCount,\r\n };\r\n // 排序键后序列化,与 Python sort_keys=True 一致\r\n const sorted: Record<string, unknown> = {};\r\n for (const key of Object.keys(obj).sort()) {\r\n sorted[key] = obj[key];\r\n }\r\n const raw = JSON.stringify(sorted);\r\n const buffer = new TextEncoder().encode(raw);\r\n const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);\r\n const hashArray = Array.from(new Uint8Array(hashBuffer));\r\n return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');\r\n }\r\n\r\n toDict(): Record<string, unknown> {\r\n return {\r\n session_id: this.sessionId,\r\n sender_did: this.senderDid,\r\n target_did: this.targetDid,\r\n content: this.content,\r\n timestamp: this.timestamp,\r\n hop_count: this.hopCount,\r\n sig_content: this.sigContent,\r\n };\r\n }\r\n\r\n static fromDict(data: Record<string, unknown>): RecordedHop {\r\n return new RecordedHop({\r\n sessionId: data['session_id'] as string,\r\n senderDid: data['sender_did'] as string,\r\n targetDid: data['target_did'] as string,\r\n content: data['content'] as string,\r\n timestamp: data['timestamp'] as number,\r\n hopCount: data['hop_count'] as number,\r\n sigContent: (data['sig_content'] as string) ?? '',\r\n });\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// NodeMessage — 节点间转发消息 (A → B)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * 转发消息:A 向 B 发送。\r\n *\r\n * protocolUrl: 协议节点地址\r\n * nonce: 唯一标识,用于匹配回传消息\r\n * recordedHop: 单跳记录内容\r\n */\r\nexport class NodeMessage {\r\n protocolUrl: string;\r\n nonce: string;\r\n recordedHop: RecordedHop;\r\n\r\n constructor(data: {\r\n protocolUrl: string;\r\n nonce: string;\r\n recordedHop: RecordedHop;\r\n }) {\r\n this.protocolUrl = data.protocolUrl;\r\n this.nonce = data.nonce;\r\n this.recordedHop = data.recordedHop;\r\n }\r\n\r\n /** 发送方私钥对 recordedHop 内容签名,写入 sigContent。 */\r\n async signContent(privateKey: CryptoKey): Promise<void> {\r\n const hash = await this.recordedHop.contentHash();\r\n this.recordedHop.sigContent = await signHash(hash, privateKey);\r\n }\r\n\r\n /** 验证 recordedHop.sigContent 是否由对应公钥签署。 */\r\n async verifyContent(publicKey: CryptoKey): Promise<boolean> {\r\n if (!this.recordedHop.sigContent) return false;\r\n const hash = await this.recordedHop.contentHash();\r\n return verifySignature(hash, this.recordedHop.sigContent, publicKey);\r\n }\r\n\r\n toDict(): Record<string, unknown> {\r\n return {\r\n protocol_url: this.protocolUrl,\r\n nonce: this.nonce,\r\n recorded_hop: this.recordedHop.toDict(),\r\n };\r\n }\r\n\r\n static fromDict(data: Record<string, unknown>): NodeMessage {\r\n return new NodeMessage({\r\n protocolUrl: data['protocol_url'] as string,\r\n nonce: data['nonce'] as string,\r\n recordedHop: RecordedHop.fromDict(data['recorded_hop'] as Record<string, unknown>),\r\n });\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// BackMessage — 节点回传消息\r\n// ---------------------------------------------------------------------------\r\n\r\n/** 计算 nodeDid + nonce 的身份哈希。 */\r\nasync function identityHash(nodeDid: string, nonce: string): Promise<string> {\r\n const obj: Record<string, unknown> = { node_did: nodeDid, nonce };\r\n const sorted: Record<string, unknown> = {};\r\n for (const key of Object.keys(obj).sort()) {\r\n sorted[key] = obj[key];\r\n }\r\n const raw = JSON.stringify(sorted);\r\n const buffer = new TextEncoder().encode(raw);\r\n const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);\r\n const hashArray = Array.from(new Uint8Array(hashBuffer));\r\n return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');\r\n}\r\n\r\n/**\r\n * 节点回传消息:节点(A 或 B)向协议节点回传。\r\n *\r\n * protocolUrl: 协议节点地址\r\n * nodeDid: 回传节点的 DID 身份\r\n * nonce: 唯一标识,用于匹配回传消息\r\n * sigIdentity: nodeDid + nonce 的私钥签名,用于身份确认\r\n * recordedHop: 单跳记录内容\r\n */\r\nexport class BackMessage {\r\n protocolUrl: string;\r\n nodeDid: string;\r\n nonce: string;\r\n sigIdentity: string;\r\n recordedHop: RecordedHop;\r\n\r\n constructor(data: {\r\n protocolUrl: string;\r\n nodeDid: string;\r\n nonce: string;\r\n sigIdentity?: string;\r\n recordedHop: RecordedHop;\r\n }) {\r\n this.protocolUrl = data.protocolUrl;\r\n this.nodeDid = data.nodeDid;\r\n this.nonce = data.nonce;\r\n this.sigIdentity = data.sigIdentity ?? '';\r\n this.recordedHop = data.recordedHop;\r\n }\r\n\r\n // -- 身份签名 --\r\n\r\n /** 使用回传节点私钥对 nodeDid+nonce 签名,写入 sigIdentity。 */\r\n async signIdentity(privateKey: CryptoKey): Promise<void> {\r\n this.sigIdentity = await signHash(\r\n await identityHash(this.nodeDid, this.nonce),\r\n privateKey,\r\n );\r\n }\r\n\r\n /** 验证 sigIdentity 是否合法。 */\r\n async verifyIdentity(publicKey: CryptoKey): Promise<boolean> {\r\n if (!this.sigIdentity) return false;\r\n return verifySignature(\r\n await identityHash(this.nodeDid, this.nonce),\r\n this.sigIdentity,\r\n publicKey,\r\n );\r\n }\r\n\r\n // -- 内容签名(发送方签名,由 recordedHop.sigContent 承载)--\r\n\r\n /** 使用发送方私钥对 recordedHop 内容签名。 */\r\n async signContent(privateKey: CryptoKey): Promise<void> {\r\n const hash = await this.recordedHop.contentHash();\r\n this.recordedHop.sigContent = await signHash(hash, privateKey);\r\n }\r\n\r\n /** 验证 recordedHop 内容签名(发送方签名)。 */\r\n async verifyContent(publicKey: CryptoKey): Promise<boolean> {\r\n if (!this.recordedHop.sigContent) return false;\r\n const hash = await this.recordedHop.contentHash();\r\n return verifySignature(hash, this.recordedHop.sigContent, publicKey);\r\n }\r\n\r\n toDict(): Record<string, unknown> {\r\n return {\r\n protocol_url: this.protocolUrl,\r\n node_did: this.nodeDid,\r\n nonce: this.nonce,\r\n sig_identity: this.sigIdentity,\r\n recorded_hop: this.recordedHop.toDict(),\r\n };\r\n }\r\n\r\n static fromDict(data: Record<string, unknown>): BackMessage {\r\n return new BackMessage({\r\n protocolUrl: data['protocol_url'] as string,\r\n nodeDid: data['node_did'] as string,\r\n nonce: data['nonce'] as string,\r\n sigIdentity: (data['sig_identity'] as string) ?? '',\r\n recordedHop: RecordedHop.fromDict(data['recorded_hop'] as Record<string, unknown>),\r\n });\r\n }\r\n}","/**\r\n * 密钥管理 — KeyStore 用于缓存公钥/私钥。\r\n *\r\n * 从 python/attp/core/authentication/keys.py 翻译而来。\r\n * 浏览器端使用 CryptoKey 对象替代 Python cryptography 库的密钥对象。\r\n */\r\n\r\n/**\r\n * 密钥存储:管理公钥缓存 (nodeDid → publicKey) 和私钥缓存 (path → privateKey)。\r\n *\r\n * 在浏览器环境中,私钥通过 CryptoKey 对象表示,\r\n * 公钥同样为 CryptoKey 对象。\r\n */\r\nexport class KeyStore {\r\n private _cache: Map<string, CryptoKey> = new Map();\r\n private _privateKeyCache: Map<string, CryptoKey> = new Map();\r\n\r\n /**\r\n * 注入公钥到缓存。\r\n */\r\n cachePublicKey(nodeDid: string, publicKey: CryptoKey): void {\r\n this._cache.set(nodeDid, publicKey);\r\n }\r\n\r\n /**\r\n * 获取缓存的公钥,不存在返回 undefined。\r\n */\r\n get(nodeDid: string): CryptoKey | undefined {\r\n return this._cache.get(nodeDid);\r\n }\r\n\r\n /**\r\n * 暴露内部缓存 Map 引用,维持兼容性。\r\n */\r\n get cacheDict(): Map<string, CryptoKey> {\r\n return this._cache;\r\n }\r\n\r\n /**\r\n * 缓存私钥,后续调用相同标识直接返回缓存。\r\n */\r\n cachePrivateKey(keyId: string, privateKey: CryptoKey): void {\r\n this._privateKeyCache.set(keyId, privateKey);\r\n }\r\n\r\n /**\r\n * 获取缓存的私钥。\r\n */\r\n getPrivateKey(keyId: string): CryptoKey | undefined {\r\n return this._privateKeyCache.get(keyId);\r\n }\r\n\r\n /**\r\n * 检查是否已有缓存的私钥。\r\n */\r\n hasPrivateKey(keyId: string): boolean {\r\n return this._privateKeyCache.has(keyId);\r\n }\r\n}","/**\r\n * 哈希计算:genesis 标识哈希和每跳签名哈希。\r\n *\r\n * 从 python/attp/core/provenance/hashing.py 翻译而来。\r\n * 使用 Web Crypto API (crypto.subtle.digest) 实现 SHA-256,\r\n * 保证输出与 Python 端 hashlib.sha256 完全一致。\r\n */\r\n\r\n/**\r\n * 计算 JSON 对象的 SHA-256 哈希。\r\n * 使用 JSON.stringify + sort_keys 语义:先对键排序再序列化。\r\n */\r\nasync function sha256Sorted(obj: Record<string, unknown>): Promise<string> {\r\n const sorted: Record<string, unknown> = {};\r\n for (const key of Object.keys(obj).sort()) {\r\n sorted[key] = obj[key];\r\n }\r\n const raw = JSON.stringify(sorted);\r\n const buffer = new TextEncoder().encode(raw);\r\n const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);\r\n const hashArray = Array.from(new Uint8Array(hashBuffer));\r\n return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');\r\n}\r\n\r\n/**\r\n * 计算创世标识的 SHA-256 哈希,用于防篡改验证。\r\n */\r\nexport async function calculateGenesisHash(\r\n sessionId: string,\r\n protocolNodeAddress: string,\r\n): Promise<string> {\r\n return sha256Sorted({\r\n session_id: sessionId,\r\n protocol_node_address: protocolNodeAddress,\r\n });\r\n}\r\n\r\n/**\r\n * 计算单跳消息字段的 SHA-256 哈希,用于身份验证签名。\r\n */\r\nexport async function calculateHopHash(\r\n content: string,\r\n nodeDid: string,\r\n targetDid: string,\r\n hopCount: number,\r\n timestamp: number,\r\n sessionId: string,\r\n protocolNodeAddress: string,\r\n): Promise<string> {\r\n return sha256Sorted({\r\n content,\r\n node_did: nodeDid,\r\n target_did: targetDid,\r\n hop_count: hopCount,\r\n timestamp,\r\n session_id: sessionId,\r\n protocol_node_address: protocolNodeAddress,\r\n });\r\n}","/**\r\n * BehaviorEntry — 单条行为记录。\r\n *\r\n * 从 python/attp/core/sessions/node_message.py 翻译而来。\r\n *\r\n * fieldType 取值:\r\n * A2T — Agent → Tool (Agent 调用工具)\r\n * A2U — Agent → User (Agent 发给用户)\r\n * U2A — User → Agent (用户发给 Agent)\r\n * A2A — Agent → Agent (Agent 间通信)\r\n * T2A — Tool → Agent (工具返回结果,预留)\r\n */\r\n\r\n/** 行为类型枚举 */\r\nexport type FieldType = 'A2T' | 'A2U' | 'U2A' | 'A2A' | 'T2A';\r\n\r\nexport class BehaviorEntry {\r\n fieldType: FieldType;\r\n content: string;\r\n timestamp: number;\r\n target: string; // A2T: tool; A2A: target_did; 其他: \"\"\r\n extra: Record<string, unknown>;\r\n\r\n constructor(data: {\r\n fieldType: FieldType;\r\n content: string;\r\n timestamp?: number;\r\n target?: string;\r\n extra?: Record<string, unknown>;\r\n }) {\r\n this.fieldType = data.fieldType;\r\n this.content = data.content;\r\n this.timestamp = data.timestamp ?? Date.now() / 1000;\r\n this.target = data.target ?? '';\r\n this.extra = data.extra ?? {};\r\n }\r\n\r\n toDict(): Record<string, unknown> {\r\n return {\r\n field_type: this.fieldType,\r\n content: this.content,\r\n timestamp: this.timestamp,\r\n target: this.target,\r\n extra: this.extra,\r\n };\r\n }\r\n\r\n static fromDict(data: Record<string, unknown>): BehaviorEntry {\r\n return new BehaviorEntry({\r\n fieldType: data['field_type'] as FieldType,\r\n content: data['content'] as string,\r\n timestamp: (data['timestamp'] as number) ?? 0.0,\r\n target: (data['target'] as string) ?? '',\r\n extra: (data['extra'] as Record<string, unknown>) ?? {},\r\n });\r\n }\r\n}","/**\r\n * UserSession / UserSessionManager — 用户端会话管理。\r\n *\r\n * 面向 User 客户端,管理 ATTP 协议层的会话元数据:\r\n * - session_id / protocol_node_address / hop 元数据\r\n * - 用户身份 (userDid) 和密钥标识\r\n *\r\n * 参考 Python 端 AppSession 的结构,但针对用户端场景简化。\r\n */\r\n\r\n/** Hop 记录的元数据结构 */\r\nexport interface HopMetadata {\r\n Hop_Count: number;\r\n Timestamp: number;\r\n Signature: string;\r\n Content: string;\r\n node_did: string;\r\n target_did: string;\r\n session_id?: string;\r\n protocol_node_address?: string;\r\n}\r\n\r\n/** 追踪相关元数据的键集合 */\r\nconst TRACE_KEYS = ['Hop', 'Session_ID', 'Protocol_Node_Address'] as const;\r\n\r\n/**\r\n * UserSession — 用户端单个会话的协议层状态容器。\r\n */\r\nexport class UserSession {\r\n /** 会话标识(通常是 chatId) */\r\n key: string;\r\n /** ATTP 协议层元数据 */\r\n metadata: Record<string, unknown>;\r\n /** 最后更新时间(Unix 时间戳,秒) */\r\n updatedAt: number;\r\n\r\n constructor(data: { key: string; metadata?: Record<string, unknown>; updatedAt?: number }) {\r\n this.key = data.key;\r\n this.metadata = data.metadata ?? {};\r\n this.updatedAt = data.updatedAt ?? Date.now() / 1000;\r\n }\r\n\r\n // -- 追踪路由元数据 --\r\n\r\n /** 提取追踪相关的元数据。 */\r\n getTraceMetadata(): Record<string, unknown> {\r\n const result: Record<string, unknown> = {};\r\n for (const k of TRACE_KEYS) {\r\n if (k in this.metadata) {\r\n result[k] = this.metadata[k];\r\n }\r\n }\r\n return result;\r\n }\r\n\r\n /** 合并追踪元数据。 */\r\n setTraceMetadata(traceData: Record<string, unknown>): void {\r\n for (const k of TRACE_KEYS) {\r\n if (k in traceData) {\r\n this.metadata[k] = traceData[k];\r\n }\r\n }\r\n this.updatedAt = Date.now() / 1000;\r\n }\r\n\r\n // -- 便捷访问器 --\r\n\r\n get sessionId(): string | undefined {\r\n return this.metadata['Session_ID'] as string | undefined;\r\n }\r\n\r\n set sessionId(value: string | undefined) {\r\n if (value !== undefined) this.metadata['Session_ID'] = value;\r\n }\r\n\r\n get protocolNodeAddress(): string | undefined {\r\n return this.metadata['Protocol_Node_Address'] as string | undefined;\r\n }\r\n\r\n set protocolNodeAddress(value: string | undefined) {\r\n if (value !== undefined) this.metadata['Protocol_Node_Address'] = value;\r\n }\r\n\r\n get hop(): HopMetadata | undefined {\r\n return this.metadata['Hop'] as HopMetadata | undefined;\r\n }\r\n\r\n get hopCount(): number {\r\n return this.hop?.Hop_Count ?? -1;\r\n }\r\n\r\n /** 用户 DID 标识 */\r\n get userDid(): string | undefined {\r\n return this.metadata['user_did'] as string | undefined;\r\n }\r\n\r\n set userDid(value: string | undefined) {\r\n if (value !== undefined) this.metadata['user_did'] = value;\r\n }\r\n\r\n /** 密钥标识(用于从 KeyStore 查找私钥) */\r\n get keyId(): string | undefined {\r\n return this.metadata['key_id'] as string | undefined;\r\n }\r\n\r\n set keyId(value: string | undefined) {\r\n if (value !== undefined) this.metadata['key_id'] = value;\r\n }\r\n\r\n // -- 通用元数据 --\r\n\r\n setMetadata(key: string, value: unknown): void {\r\n this.metadata[key] = value;\r\n this.updatedAt = Date.now() / 1000;\r\n }\r\n\r\n getMetadata(key: string, defaultValue?: unknown): unknown {\r\n return this.metadata[key] ?? defaultValue;\r\n }\r\n\r\n updateMetadata(data: Record<string, unknown>): void {\r\n Object.assign(this.metadata, data);\r\n this.updatedAt = Date.now() / 1000;\r\n }\r\n\r\n // -- 序列化 --\r\n\r\n toDict(): Record<string, unknown> {\r\n return {\r\n key: this.key,\r\n metadata: { ...this.metadata },\r\n updated_at: this.updatedAt,\r\n };\r\n }\r\n\r\n static fromDict(data: Record<string, unknown>): UserSession {\r\n return new UserSession({\r\n key: data['key'] as string,\r\n metadata: (data['metadata'] as Record<string, unknown>) ?? {},\r\n updatedAt: (data['updated_at'] as number) ?? Date.now() / 1000,\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * UserSessionManager — 用户端会话存储,按 chatId 索引。\r\n *\r\n * 内存中维护所有活跃会话,可选持久化到 localStorage。\r\n */\r\nexport class UserSessionManager {\r\n private _sessions: Map<string, UserSession> = new Map();\r\n\r\n /** 获取或创建会话。 */\r\n getOrCreate(chatId: string): UserSession {\r\n if (!this._sessions.has(chatId)) {\r\n this._sessions.set(chatId, new UserSession({ key: chatId }));\r\n }\r\n return this._sessions.get(chatId)!;\r\n }\r\n\r\n /** 获取已有会话,不存在返回 undefined。 */\r\n get(chatId: string): UserSession | undefined {\r\n return this._sessions.get(chatId);\r\n }\r\n\r\n /** 保存/更新会话。 */\r\n save(session: UserSession): void {\r\n this._sessions.set(session.key, session);\r\n }\r\n\r\n /** 删除会话。 */\r\n delete(chatId: string): void {\r\n this._sessions.delete(chatId);\r\n }\r\n\r\n /** 所有会话条目。 */\r\n entries(): IterableIterator<[string, UserSession]> {\r\n return this._sessions.entries();\r\n }\r\n\r\n /** 会话数量。 */\r\n get size(): number {\r\n return this._sessions.size;\r\n }\r\n\r\n // -- 持久化 --\r\n\r\n /** 序列化所有会话为 JSON 字符串。 */\r\n serialize(): string {\r\n const obj: Record<string, unknown> = {};\r\n for (const [key, session] of this._sessions) {\r\n obj[key] = session.toDict();\r\n }\r\n return JSON.stringify(obj);\r\n }\r\n\r\n /** 从 JSON 字符串反序列化恢复所有会话。 */\r\n deserialize(json: string): void {\r\n try {\r\n const obj = JSON.parse(json);\r\n this._sessions.clear();\r\n for (const [key, value] of Object.entries(obj)) {\r\n this._sessions.set(key, UserSession.fromDict(value as Record<string, unknown>));\r\n }\r\n } catch {\r\n // 反序列化失败时保持空状态\r\n }\r\n }\r\n\r\n /** 保存到 localStorage。 */\r\n saveToStorage(storageKey: string = 'attp_user_sessions'): void {\r\n try {\r\n localStorage.setItem(storageKey, this.serialize());\r\n } catch {\r\n // localStorage 不可用时静默失败\r\n }\r\n }\r\n\r\n /** 从 localStorage 加载。 */\r\n loadFromStorage(storageKey: string = 'attp_user_sessions'): void {\r\n try {\r\n const raw = localStorage.getItem(storageKey);\r\n if (raw) this.deserialize(raw);\r\n } catch {\r\n // localStorage 不可用时静默失败\r\n }\r\n }\r\n}"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@invictus-z/attp",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "ATTP SDK for TypeScript — authentication, provenance & session management",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"prepublishOnly": "npm run build"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"attp",
|
|
30
|
+
"authentication",
|
|
31
|
+
"provenance",
|
|
32
|
+
"session",
|
|
33
|
+
"nanobot"
|
|
34
|
+
],
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"tsup": "^8.0.0",
|
|
38
|
+
"typescript": "^5.2.0"
|
|
39
|
+
}
|
|
40
|
+
}
|