evolclaw 3.1.2 → 3.1.4
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/CHANGELOG.md +38 -0
- package/README.md +2 -6
- package/assets/.env.template +4 -0
- package/assets/config.json.template +6 -0
- package/assets/wechat-group-qr.jpeg +0 -0
- package/dist/agents/claude-runner.js +1 -1
- package/dist/agents/codex-runner.js +75 -19
- package/dist/agents/gemini-runner.js +0 -2
- package/dist/agents/kit-renderer.js +85 -22
- package/dist/aun/aid/agentmd.js +67 -74
- package/dist/aun/aid/client.js +22 -7
- package/dist/aun/aid/identity.js +314 -28
- package/dist/aun/aid/index.js +2 -2
- package/dist/aun/rpc/connection.js +8 -10
- package/dist/channels/aun.js +53 -41
- package/dist/cli/agent.js +28 -28
- package/dist/cli/bench.js +8 -14
- package/dist/cli/help.js +23 -0
- package/dist/cli/index.js +398 -73
- package/dist/cli/init-channel.js +2 -3
- package/dist/cli/init.js +13 -6
- package/dist/cli/link-rules.js +2 -1
- package/dist/cli/net-check.js +10 -11
- package/dist/core/command-handler.js +621 -541
- package/dist/core/evolagent.js +31 -0
- package/dist/core/message/im-renderer.js +10 -0
- package/dist/core/message/message-bridge.js +123 -24
- package/dist/core/message/message-processor.js +61 -31
- package/dist/core/relation/peer-identity.js +64 -21
- package/dist/core/session/session-manager.js +191 -44
- package/dist/core/trigger/manager.js +37 -0
- package/dist/index.js +4 -1
- package/dist/paths.js +87 -16
- package/dist/utils/npm-ops.js +18 -11
- package/kits/eck_manifest.json +9 -9
- package/kits/rules/02-navigation.md +1 -0
- package/kits/rules/05-venue.md +2 -2
- package/kits/rules/06-channel.md +2 -18
- package/kits/templates/system-fragments/baseagent.md +8 -2
- package/kits/templates/system-fragments/channel.md +20 -8
- package/kits/templates/system-fragments/identity.md +5 -6
- package/kits/templates/system-fragments/relation.md +10 -5
- package/kits/templates/system-fragments/session.md +20 -0
- package/kits/templates/system-fragments/venue.md +5 -3
- package/package.json +4 -2
- package/dist/net-check.js +0 -640
- package/dist/watch-msg.js +0 -544
- package/kits/templates/system-fragments/runtime.md +0 -19
package/dist/aun/aid/identity.js
CHANGED
|
@@ -1,56 +1,193 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import os from 'os';
|
|
4
3
|
import crypto from 'crypto';
|
|
5
|
-
import { getAunClient, downloadCaRoot } from './client.js';
|
|
6
|
-
import { resolvePaths,
|
|
4
|
+
import { getAunClient, createAunClient, downloadCaRoot } from './client.js';
|
|
5
|
+
import { resolvePaths, agentMdPath, aunPath as defaultAunPath } from '../../paths.js';
|
|
7
6
|
// ==================== Validation ====================
|
|
8
7
|
export function isValidAid(name) {
|
|
9
8
|
const labels = name.split('.');
|
|
10
9
|
return labels.length >= 3 && labels.every(l => /^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/.test(l));
|
|
11
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* 根据扫描得到的状态推断 AID 分类。
|
|
13
|
+
* - hasPrivateKey + signVerified=true → mine
|
|
14
|
+
* - hasPrivateKey + (signVerified=false 或未实测) → broken
|
|
15
|
+
* - !hasPrivateKey + hasCert → peer-cert
|
|
16
|
+
* - !hasPrivateKey + !hasCert → no-cert
|
|
17
|
+
*/
|
|
18
|
+
function categorizeAid(info) {
|
|
19
|
+
if (info.hasPrivateKey) {
|
|
20
|
+
if (info.signVerified === true)
|
|
21
|
+
return 'mine';
|
|
22
|
+
return 'broken';
|
|
23
|
+
}
|
|
24
|
+
return info.hasCert ? 'peer-cert' : 'no-cert';
|
|
25
|
+
}
|
|
12
26
|
// ==================== AID Operations ====================
|
|
13
27
|
export function aidList(aunPath) {
|
|
14
|
-
const
|
|
15
|
-
const
|
|
28
|
+
const root = aunPath ?? defaultAunPath();
|
|
29
|
+
const aunAidsDir = path.join(root, 'AIDs');
|
|
16
30
|
const seen = new Map();
|
|
17
|
-
// Scan ~/.aun/AIDs (private keys live here)
|
|
18
31
|
if (fs.existsSync(aunAidsDir)) {
|
|
19
32
|
for (const e of fs.readdirSync(aunAidsDir, { withFileTypes: true })) {
|
|
20
33
|
if (!e.isDirectory())
|
|
21
34
|
continue;
|
|
35
|
+
const aidDir = path.join(aunAidsDir, e.name);
|
|
36
|
+
const keyJsonPath = path.join(aidDir, 'private', 'key.json');
|
|
37
|
+
const hasPrivateKey = fs.existsSync(path.join(aidDir, 'private'));
|
|
38
|
+
const certPath = path.join(aidDir, 'public', 'cert.pem');
|
|
39
|
+
let hasCert = false;
|
|
40
|
+
let certExpired = false;
|
|
41
|
+
let keyMatchesCert = null;
|
|
42
|
+
if (fs.existsSync(certPath)) {
|
|
43
|
+
hasCert = true;
|
|
44
|
+
try {
|
|
45
|
+
const certPem = fs.readFileSync(certPath, 'utf-8');
|
|
46
|
+
const x509 = new crypto.X509Certificate(certPem);
|
|
47
|
+
certExpired = new Date(x509.validTo) < new Date();
|
|
48
|
+
if (hasPrivateKey && fs.existsSync(keyJsonPath)) {
|
|
49
|
+
try {
|
|
50
|
+
const kp = JSON.parse(fs.readFileSync(keyJsonPath, 'utf-8'));
|
|
51
|
+
const localPubB64 = typeof kp?.public_key_der_b64 === 'string' ? kp.public_key_der_b64 : '';
|
|
52
|
+
if (localPubB64) {
|
|
53
|
+
const certPubDer = x509.publicKey.export({ type: 'spki', format: 'der' });
|
|
54
|
+
const localPubDer = Buffer.from(localPubB64, 'base64');
|
|
55
|
+
keyMatchesCert = certPubDer.equals(localPubDer);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch { /* key.json 不可解析视作不匹配 */
|
|
59
|
+
keyMatchesCert = false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// 证书无法解析视为过期 / 不可用
|
|
65
|
+
certExpired = true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
22
68
|
seen.set(e.name, {
|
|
23
69
|
aid: e.name,
|
|
24
|
-
|
|
70
|
+
category: categorizeAid({
|
|
71
|
+
hasPrivateKey,
|
|
72
|
+
hasCert,
|
|
73
|
+
// 静态扫描没跑实测,用 canSign 作为 mine/broken 的近似判定
|
|
74
|
+
signVerified: hasPrivateKey ? (hasCert && !certExpired && keyMatchesCert === true) : null,
|
|
75
|
+
canSign: hasPrivateKey && hasCert && !certExpired && keyMatchesCert === true,
|
|
76
|
+
}),
|
|
77
|
+
hasPrivateKey,
|
|
25
78
|
hasAgentMd: fs.existsSync(agentMdPath(e.name)),
|
|
79
|
+
hasCert,
|
|
80
|
+
certExpired,
|
|
81
|
+
keyMatchesCert,
|
|
82
|
+
canSign: hasPrivateKey && hasCert && !certExpired && keyMatchesCert === true,
|
|
83
|
+
signVerified: null,
|
|
26
84
|
});
|
|
27
85
|
}
|
|
28
86
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
87
|
+
return [...seen.values()];
|
|
88
|
+
}
|
|
89
|
+
// ==================== Sign Self-Test ====================
|
|
90
|
+
/**
|
|
91
|
+
* 实跑一次本地 sign + verify,验证 AID 是否真能签名/验签。
|
|
92
|
+
* 全本地(不联网):用 SDK 解密私钥 → ECDSA 签 payload → 用本地 cert 公钥验。
|
|
93
|
+
* 任一环节失败都视为不可签——包括私钥 passphrase 解不开、cert 被 SDK 主动 discard 等。
|
|
94
|
+
*/
|
|
95
|
+
export async function verifySignAbility(aid, opts) {
|
|
96
|
+
const aunPath = opts?.aunPath ?? defaultAunPath();
|
|
97
|
+
let ownClient = null;
|
|
98
|
+
try {
|
|
99
|
+
let client = opts?.client;
|
|
100
|
+
if (!client) {
|
|
101
|
+
client = await createAunClient({ aunPath });
|
|
102
|
+
ownClient = client;
|
|
103
|
+
}
|
|
104
|
+
const probe = `# probe\naid: "${aid}"\n`;
|
|
105
|
+
let signed;
|
|
106
|
+
try {
|
|
107
|
+
signed = await client.auth.signAgentMd(probe, { aid });
|
|
108
|
+
}
|
|
109
|
+
catch (e) {
|
|
110
|
+
return { ok: false, reason: `sign failed: ${String(e?.message || e).slice(0, 120)}` };
|
|
111
|
+
}
|
|
112
|
+
const certPath = path.join(aunPath, 'AIDs', aid, 'public', 'cert.pem');
|
|
113
|
+
const certPem = fs.existsSync(certPath) ? fs.readFileSync(certPath, 'utf-8') : '';
|
|
114
|
+
if (!certPem)
|
|
115
|
+
return { ok: false, reason: 'cert.pem missing' };
|
|
116
|
+
let result;
|
|
117
|
+
try {
|
|
118
|
+
result = await client.auth.verifyAgentMd(signed, { aid, certPem });
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
return { ok: false, reason: `verify threw: ${String(e?.message || e).slice(0, 120)}` };
|
|
122
|
+
}
|
|
123
|
+
const verified = result?.status === 'verified' || result?.verified === true;
|
|
124
|
+
if (verified)
|
|
125
|
+
return { ok: true };
|
|
126
|
+
return { ok: false, reason: `verify failed: ${result?.status ?? 'unknown'}${result?.reason ? ' — ' + result.reason : ''}` };
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
if (ownClient) {
|
|
130
|
+
try {
|
|
131
|
+
await ownClient.close();
|
|
132
|
+
}
|
|
133
|
+
catch { /* ignore */ }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* aidList 的"实测版":先做静态扫描,再对每个 AID 跑一次本地 sign+verify。
|
|
139
|
+
* 共用同一个 AUNClient 实例,避免重复初始化 secret-store / sqlite。
|
|
140
|
+
*/
|
|
141
|
+
export async function aidListVerified(aunPath) {
|
|
142
|
+
const list = aidList(aunPath);
|
|
143
|
+
const root = aunPath ?? defaultAunPath();
|
|
144
|
+
const client = await createAunClient({ aunPath: root });
|
|
145
|
+
try {
|
|
146
|
+
for (const a of list) {
|
|
147
|
+
// canSign=false 的 AID 不必跑实测,结论已经明确
|
|
148
|
+
if (!a.canSign) {
|
|
149
|
+
a.signVerified = false;
|
|
150
|
+
if (!a.hasPrivateKey)
|
|
151
|
+
a.signError = 'no private key';
|
|
152
|
+
else if (!a.hasCert)
|
|
153
|
+
a.signError = 'no cert';
|
|
154
|
+
else if (a.certExpired)
|
|
155
|
+
a.signError = 'cert expired';
|
|
156
|
+
else if (a.keyMatchesCert === false)
|
|
157
|
+
a.signError = 'key/cert public-key mismatch';
|
|
158
|
+
a.category = categorizeAid({
|
|
159
|
+
hasPrivateKey: a.hasPrivateKey, hasCert: a.hasCert,
|
|
160
|
+
signVerified: a.signVerified, canSign: a.canSign,
|
|
161
|
+
});
|
|
35
162
|
continue;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
163
|
+
}
|
|
164
|
+
const r = await verifySignAbility(a.aid, { aunPath: root, client });
|
|
165
|
+
a.signVerified = r.ok;
|
|
166
|
+
if (!r.ok)
|
|
167
|
+
a.signError = r.reason;
|
|
168
|
+
a.category = categorizeAid({
|
|
169
|
+
hasPrivateKey: a.hasPrivateKey, hasCert: a.hasCert,
|
|
170
|
+
signVerified: a.signVerified, canSign: a.canSign,
|
|
40
171
|
});
|
|
41
172
|
}
|
|
42
173
|
}
|
|
43
|
-
|
|
174
|
+
finally {
|
|
175
|
+
try {
|
|
176
|
+
await client.close();
|
|
177
|
+
}
|
|
178
|
+
catch { /* ignore */ }
|
|
179
|
+
}
|
|
180
|
+
return list;
|
|
44
181
|
}
|
|
45
182
|
export async function aidCreate(aid, opts) {
|
|
46
|
-
const aunPath = opts?.aunPath ??
|
|
183
|
+
const aunPath = opts?.aunPath ?? defaultAunPath();
|
|
47
184
|
const aidDir = path.join(aunPath, 'AIDs', aid);
|
|
48
185
|
if (fs.existsSync(aidDir) && fs.existsSync(path.join(aidDir, 'private'))) {
|
|
49
186
|
const client = await getAunClient(aid, { aunPath });
|
|
50
187
|
return { aid, alreadyExisted: true, gateway: '', client };
|
|
51
188
|
}
|
|
52
|
-
const {
|
|
53
|
-
let client =
|
|
189
|
+
const { GatewayDiscovery } = await import('@agentunion/fastaun');
|
|
190
|
+
let client = await createAunClient({ aunPath });
|
|
54
191
|
try {
|
|
55
192
|
const result = await client.auth.createAid({ aid });
|
|
56
193
|
const gateway = result.gateway || '';
|
|
@@ -61,7 +198,7 @@ export async function aidCreate(aid, opts) {
|
|
|
61
198
|
await client.close();
|
|
62
199
|
}
|
|
63
200
|
catch { /* ignore */ }
|
|
64
|
-
client =
|
|
201
|
+
client = await createAunClient({ aunPath });
|
|
65
202
|
await client.auth.createAid({ aid });
|
|
66
203
|
}
|
|
67
204
|
let gatewayUrl = gateway;
|
|
@@ -86,34 +223,183 @@ export async function aidCreate(aid, opts) {
|
|
|
86
223
|
}
|
|
87
224
|
}
|
|
88
225
|
// ==================== Show ====================
|
|
89
|
-
export function aidShow(aid, opts) {
|
|
90
|
-
const aunPath = opts?.aunPath ??
|
|
226
|
+
export async function aidShow(aid, opts) {
|
|
227
|
+
const aunPath = opts?.aunPath ?? defaultAunPath();
|
|
91
228
|
const aidDir = path.join(aunPath, 'AIDs', aid);
|
|
92
229
|
const hasPrivateKey = fs.existsSync(path.join(aidDir, 'private'));
|
|
93
230
|
const hasAgentMd = fs.existsSync(agentMdPath(aid));
|
|
94
231
|
let certExpiresAt = null;
|
|
95
232
|
let certSubject = null;
|
|
233
|
+
let certExpired = false;
|
|
234
|
+
let certPem = null;
|
|
235
|
+
let keyMatchesCert = null;
|
|
96
236
|
const certPath = path.join(aidDir, 'public', 'cert.pem');
|
|
97
237
|
if (fs.existsSync(certPath)) {
|
|
98
238
|
try {
|
|
99
|
-
|
|
100
|
-
const x509 = new crypto.X509Certificate(
|
|
239
|
+
certPem = fs.readFileSync(certPath, 'utf-8');
|
|
240
|
+
const x509 = new crypto.X509Certificate(certPem);
|
|
101
241
|
certExpiresAt = x509.validTo;
|
|
102
242
|
certSubject = x509.subject;
|
|
243
|
+
certExpired = new Date(x509.validTo) < new Date();
|
|
244
|
+
const keyJsonPath = path.join(aidDir, 'private', 'key.json');
|
|
245
|
+
if (hasPrivateKey && fs.existsSync(keyJsonPath)) {
|
|
246
|
+
try {
|
|
247
|
+
const kp = JSON.parse(fs.readFileSync(keyJsonPath, 'utf-8'));
|
|
248
|
+
const localPubB64 = typeof kp?.public_key_der_b64 === 'string' ? kp.public_key_der_b64 : '';
|
|
249
|
+
if (localPubB64) {
|
|
250
|
+
const certPubDer = x509.publicKey.export({ type: 'spki', format: 'der' });
|
|
251
|
+
const localPubDer = Buffer.from(localPubB64, 'base64');
|
|
252
|
+
keyMatchesCert = certPubDer.equals(localPubDer);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
keyMatchesCert = false;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
103
259
|
}
|
|
104
260
|
catch { /* ignore parse errors */ }
|
|
105
261
|
}
|
|
106
|
-
|
|
262
|
+
let agentMdSignature = 'unknown';
|
|
263
|
+
let agentMdSignatureReason;
|
|
264
|
+
let signVerified = null;
|
|
265
|
+
let signError;
|
|
266
|
+
// 先做一次签名自检(共享 client,避免重复起 SDK)
|
|
267
|
+
const client = await createAunClient({ aunPath });
|
|
268
|
+
try {
|
|
269
|
+
if (hasPrivateKey && certPem && !certExpired && keyMatchesCert !== false) {
|
|
270
|
+
const r = await verifySignAbility(aid, { aunPath, client });
|
|
271
|
+
signVerified = r.ok;
|
|
272
|
+
if (!r.ok)
|
|
273
|
+
signError = r.reason;
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
signVerified = false;
|
|
277
|
+
if (!hasPrivateKey)
|
|
278
|
+
signError = 'no private key';
|
|
279
|
+
else if (!certPem)
|
|
280
|
+
signError = 'no cert';
|
|
281
|
+
else if (certExpired)
|
|
282
|
+
signError = 'cert expired';
|
|
283
|
+
else if (keyMatchesCert === false)
|
|
284
|
+
signError = 'key/cert public-key mismatch';
|
|
285
|
+
}
|
|
286
|
+
if (hasAgentMd) {
|
|
287
|
+
try {
|
|
288
|
+
const content = fs.readFileSync(agentMdPath(aid), 'utf-8');
|
|
289
|
+
if (!content.includes('AUN-SIGNATURE')) {
|
|
290
|
+
agentMdSignature = 'unsigned';
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
const result = await client.auth.verifyAgentMd(content, { aid, ...(certPem ? { certPem } : {}) });
|
|
294
|
+
if (result.status === 'verified' || result.verified) {
|
|
295
|
+
agentMdSignature = 'verified';
|
|
296
|
+
}
|
|
297
|
+
else if (result.status === 'unsigned') {
|
|
298
|
+
agentMdSignature = 'unsigned';
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
agentMdSignature = 'invalid';
|
|
302
|
+
agentMdSignatureReason = result.reason;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
catch (e) {
|
|
307
|
+
agentMdSignature = 'unknown';
|
|
308
|
+
agentMdSignatureReason = String(e?.message || e).slice(0, 100);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
finally {
|
|
313
|
+
try {
|
|
314
|
+
await client.close();
|
|
315
|
+
}
|
|
316
|
+
catch { }
|
|
317
|
+
}
|
|
318
|
+
return { aid, hasPrivateKey, hasAgentMd, certExpiresAt, certSubject, certExpired, keyMatchesCert, signVerified, signError, agentMdSignature, agentMdSignatureReason };
|
|
107
319
|
}
|
|
108
320
|
// ==================== Delete ====================
|
|
109
321
|
export function aidDelete(aid, opts) {
|
|
110
|
-
const aunPath = opts?.aunPath ??
|
|
322
|
+
const aunPath = opts?.aunPath ?? defaultAunPath();
|
|
111
323
|
const aidDir = path.join(aunPath, 'AIDs', aid);
|
|
112
324
|
if (!fs.existsSync(aidDir))
|
|
113
325
|
return false;
|
|
114
326
|
fs.rmSync(aidDir, { recursive: true, force: true });
|
|
115
327
|
return true;
|
|
116
328
|
}
|
|
329
|
+
export async function probePkiRecoverability(aid, opts) {
|
|
330
|
+
const aunPath = opts?.aunPath ?? defaultAunPath();
|
|
331
|
+
const timeoutMs = opts?.timeoutMs ?? 8000;
|
|
332
|
+
const keyJsonPath = path.join(aunPath, 'AIDs', aid, 'private', 'key.json');
|
|
333
|
+
if (!fs.existsSync(keyJsonPath))
|
|
334
|
+
return { kind: 'no-key' };
|
|
335
|
+
let localPubB64 = '';
|
|
336
|
+
try {
|
|
337
|
+
const kp = JSON.parse(fs.readFileSync(keyJsonPath, 'utf-8'));
|
|
338
|
+
if (typeof kp?.public_key_der_b64 !== 'string' || !kp.public_key_der_b64) {
|
|
339
|
+
return { kind: 'unknown', reason: 'key.json missing public_key_der_b64' };
|
|
340
|
+
}
|
|
341
|
+
localPubB64 = kp.public_key_der_b64;
|
|
342
|
+
}
|
|
343
|
+
catch (e) {
|
|
344
|
+
return { kind: 'unknown', reason: `key.json parse failed: ${String(e?.message || e).slice(0, 80)}` };
|
|
345
|
+
}
|
|
346
|
+
// 1. 发现网关
|
|
347
|
+
let gateway = '';
|
|
348
|
+
try {
|
|
349
|
+
const ctl = AbortSignal.timeout(timeoutMs);
|
|
350
|
+
const gwResp = await fetch(`https://${aid}/.well-known/aun-gateway`, { redirect: 'follow', signal: ctl });
|
|
351
|
+
if (gwResp.ok) {
|
|
352
|
+
const text = (await gwResp.text()).trim();
|
|
353
|
+
try {
|
|
354
|
+
const parsed = JSON.parse(text);
|
|
355
|
+
gateway = parsed?.gateways?.[0]?.url || text;
|
|
356
|
+
}
|
|
357
|
+
catch {
|
|
358
|
+
gateway = text;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
catch (e) {
|
|
363
|
+
return { kind: 'no-server-record', reason: `gateway discovery failed: ${String(e?.message || e).slice(0, 80)}` };
|
|
364
|
+
}
|
|
365
|
+
if (!gateway)
|
|
366
|
+
return { kind: 'no-server-record', reason: 'no gateway for AID' };
|
|
367
|
+
// 2. 拉云端 cert
|
|
368
|
+
let certPem = '';
|
|
369
|
+
try {
|
|
370
|
+
const parsed = new URL(gateway);
|
|
371
|
+
const scheme = parsed.protocol === 'wss:' ? 'https:' : 'http:';
|
|
372
|
+
const certUrl = `${scheme}//${parsed.host}/pki/cert/${encodeURIComponent(aid)}`;
|
|
373
|
+
const ctl = AbortSignal.timeout(timeoutMs);
|
|
374
|
+
const resp = await fetch(certUrl, { redirect: 'follow', signal: ctl });
|
|
375
|
+
if (!resp.ok) {
|
|
376
|
+
return { kind: 'no-server-record', reason: `pki/cert HTTP ${resp.status}` };
|
|
377
|
+
}
|
|
378
|
+
certPem = (await resp.text()).trim();
|
|
379
|
+
if (!certPem.includes('BEGIN CERTIFICATE')) {
|
|
380
|
+
return { kind: 'no-server-record', reason: 'pki/cert returned non-cert content' };
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
catch (e) {
|
|
384
|
+
return { kind: 'no-server-record', reason: `pki/cert fetch failed: ${String(e?.message || e).slice(0, 80)}` };
|
|
385
|
+
}
|
|
386
|
+
// 3. 比对公钥
|
|
387
|
+
try {
|
|
388
|
+
const x509 = new crypto.X509Certificate(certPem);
|
|
389
|
+
const certPubDer = x509.publicKey.export({ type: 'spki', format: 'der' });
|
|
390
|
+
const localPubDer = Buffer.from(localPubB64, 'base64');
|
|
391
|
+
if (certPubDer.equals(localPubDer)) {
|
|
392
|
+
return { kind: 'recoverable', serverCertPubB64: certPubDer.toString('base64') };
|
|
393
|
+
}
|
|
394
|
+
return {
|
|
395
|
+
kind: 'unrecoverable',
|
|
396
|
+
reason: 'server has different public key registered, current local private key cannot be used',
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
catch (e) {
|
|
400
|
+
return { kind: 'unknown', reason: `cert parse failed: ${String(e?.message || e).slice(0, 80)}` };
|
|
401
|
+
}
|
|
402
|
+
}
|
|
117
403
|
// ==================== Lookup ====================
|
|
118
404
|
export async function aidLookup(aid) {
|
|
119
405
|
let gateway = '';
|
package/dist/aun/aid/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { isValidAid, aidList, aidCreate, aidShow, aidDelete, aidLookup, appendAidLifecycle, readAidLifecycle } from './identity.js';
|
|
2
|
-
export { buildInitialAgentMd, agentmdGet, agentmdPut } from './agentmd.js';
|
|
1
|
+
export { isValidAid, aidList, aidListVerified, aidCreate, aidShow, aidDelete, aidLookup, verifySignAbility, probePkiRecoverability, appendAidLifecycle, readAidLifecycle } from './identity.js';
|
|
2
|
+
export { buildInitialAgentMd, agentmdGet, agentmdPut, agentmdSync } from './agentmd.js';
|
|
3
3
|
export { MIN_AUN_CORE_SDK, AUN_CORE_SDK_PKG, isAunSdkVersionOk, resolveAunCoreSdkPkg, ensureAunSdk, isAunSdkReady, downloadCaRoot, getAunClient, suppressSdkLogs, } from './client.js';
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import { aunPath as defaultAunPath } from '../../paths.js';
|
|
2
|
+
import { createAunClient } from '../aid/client.js';
|
|
3
|
+
import { loadProcessConfig } from '../../config-store.js';
|
|
4
4
|
export async function createShortConnection(aid, opts) {
|
|
5
|
-
const aunPath = opts?.aunPath ??
|
|
5
|
+
const aunPath = opts?.aunPath ?? defaultAunPath();
|
|
6
6
|
const slotId = opts?.slotId ?? '';
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
clientOpts.root_ca_path = caCertPath;
|
|
12
|
-
const client = new AUNClient(clientOpts);
|
|
7
|
+
const encryptionSeed = loadProcessConfig().aun?.encryptionSeed
|
|
8
|
+
|| process.env.AUN_ENCRYPTION_SEED
|
|
9
|
+
|| 'evol';
|
|
10
|
+
const client = await createAunClient({ aunPath, encryptionSeed });
|
|
13
11
|
await client.auth.createAid({ aid });
|
|
14
12
|
const authResult = await client.auth.authenticate({ aid });
|
|
15
13
|
const accessToken = authResult?.access_token ?? client._access_token;
|