@agentunion/fastaun-browser 0.2.19 → 0.3.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/CHANGELOG.md +50 -0
- package/_packed_docs/CHANGELOG.md +50 -0
- package/_packed_docs/agent.md/SCHEMA.md +173 -0
- package/_packed_docs/agent.md/examples/codeagent-claudecode.md +61 -0
- package/_packed_docs/agent.md/examples/human-developer.md +60 -0
- package/_packed_docs/agent.md/examples/openclaw-lobster.md +52 -0
- package/_packed_docs/agent.md/examples/signed-openclaw-lobster.md +43 -0
- package/_packed_docs/protocol/00-/346/200/273/350/247/210/344/270/216/345/210/206/345/261/202.md +205 -0
- package/_packed_docs/protocol/00A-/350/256/276/350/256/241/345/216/237/345/210/231-/344/270/272Agent/350/200/214/347/224/237.md +197 -0
- package/_packed_docs/protocol/01-/350/272/253/344/273/275/344/270/216/345/207/255/350/257/201/345/215/217/350/256/256-auth.md +549 -0
- package/_packed_docs/protocol/02-/350/257/201/344/271/246/344/270/216/344/277/241/344/273/273/344/275/223/347/263/273.md +810 -0
- package/_packed_docs/protocol/03-Gateway-/350/277/236/346/216/245/346/250/241/345/274/217.md +262 -0
- package/_packed_docs/protocol/04-Peer-/345/255/220/345/215/217/350/256/256.md +180 -0
- package/_packed_docs/protocol/05-Relay-/345/255/220/345/215/217/350/256/256.md +164 -0
- package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +1135 -0
- package/_packed_docs/protocol/07-/351/224/231/350/257/257/347/240/201/344/270/216/347/212/266/346/200/201/346/234/272.md +234 -0
- package/_packed_docs/protocol/08-AUN-E2EE-Group.md +900 -0
- package/_packed_docs/protocol/08-AUN-E2EE.md +413 -0
- package/_packed_docs/protocol/09-/345/256/211/345/205/250/350/200/203/350/231/221.md +316 -0
- package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +804 -0
- package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +271 -0
- package/_packed_docs/protocol/12-Stream-/345/255/220/345/215/217/350/256/256.md +329 -0
- package/_packed_docs/protocol/13-Agent/350/241/214/344/270/272/350/247/204/350/214/203.md +141 -0
- package/_packed_docs/protocol/14-/344/272/244/344/272/222/346/234/272/345/210/266-/345/223/215/345/272/224/346/250/241/345/274/217/344/270/216/350/207/252/344/270/273/346/250/241/345/274/217.md +170 -0
- package/_packed_docs/protocol/15-/347/246/273/347/272/277/346/216/250/351/200/201/351/200/232/347/237/245/345/215/217/350/256/256.md +419 -0
- package/_packed_docs/protocol/README.md +71 -0
- package/_packed_docs/protocol/agent.md/SCHEMA.md +118 -0
- package/_packed_docs/protocol/agent.md/examples/codeagent-claudecode.md +61 -0
- package/_packed_docs/protocol/agent.md/examples/human-developer.md +60 -0
- package/_packed_docs/protocol/agent.md/examples/openclaw-lobster.md +52 -0
- package/_packed_docs/protocol/aun-docs-guide.md +49 -0
- package/_packed_docs/protocol/index.md +124 -0
- package/_packed_docs/protocol//350/215/211/346/241/210-agent.md/347/255/276/345/220/215/345/215/217/350/256/256.md +205 -0
- package/_packed_docs/protocol//350/215/211/346/241/210-/346/213/222/347/273/235/344/277/241/345/217/267/345/215/217/350/256/256.md +249 -0
- package/_packed_docs/protocol//351/231/204/345/275/225A-/346/234/257/350/257/255/350/241/250.md +337 -0
- package/_packed_docs/protocol//351/231/204/345/275/225B-/346/211/251/345/261/225/346/200/247/346/214/207/345/215/227.md +80 -0
- package/_packed_docs/protocol//351/231/204/345/275/225C-/347/247/201/351/222/245/347/256/241/347/220/206/344/270/216/350/272/253/344/273/275/346/201/242/345/244/215.md +704 -0
- package/_packed_docs/protocol//351/231/204/345/275/225D-Root_CA_/346/262/273/347/220/206/346/234/272/345/210/266.md +620 -0
- package/_packed_docs/protocol//351/231/204/345/275/225E-Root_CA_/345/207/206/345/205/245/346/265/201/347/250/213.md +605 -0
- package/_packed_docs/protocol//351/231/204/345/275/225F-Issuer_CA_/347/224/263/350/257/267/346/265/201/347/250/213.md +548 -0
- package/_packed_docs/protocol//351/231/204/345/275/225G-AID_/345/255/244/345/204/277/351/242/204/351/230/262/344/270/216/346/225/221/346/217/264/346/234/272/345/210/266.md +513 -0
- package/_packed_docs/protocol//351/231/204/345/275/225H-Identity/346/234/215/345/212/241/345/256/236/347/216/260/346/214/207/345/215/227.md +619 -0
- package/_packed_docs/protocol//351/231/204/345/275/225I-/350/267/250/345/237/237/346/266/210/346/201/257/350/267/257/347/224/261/345/256/236/347/216/260/346/214/207/345/215/227.md +492 -0
- package/_packed_docs/protocol//351/231/204/345/275/225J-/345/256/242/346/210/267/347/253/257/346/216/245/345/205/245/347/244/272/344/276/213.md +402 -0
- package/_packed_docs/protocol//351/231/204/345/275/225K-Agent_Web/345/217/221/347/216/260/345/215/217/350/256/256.md +130 -0
- package/_packed_docs/protocol//351/231/204/345/275/225L-E2EE/345/256/236/347/216/260/346/214/207/345/215/227.md +267 -0
- package/_packed_docs/protocol//351/231/204/345/275/225M-JWT/350/256/244/350/257/201/345/256/236/347/216/260/346/214/207/345/215/227.md +367 -0
- package/_packed_docs/python-sdk-v2-only-changelog.md +189 -0
- package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +223 -0
- package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +354 -0
- package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +172 -0
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +396 -0
- package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +611 -0
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +1203 -0
- package/_packed_docs/sdk/07-/351/224/231/350/257/257/345/244/204/347/220/206.md +150 -0
- package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +89 -0
- package/_packed_docs/sdk/09-custody-api-manual.md +445 -0
- package/_packed_docs/sdk/09-group-rpc-manual.md +1895 -0
- package/_packed_docs/sdk/09-message-rpc-manual.md +597 -0
- package/_packed_docs/sdk/09-meta-rpc-manual.md +142 -0
- package/_packed_docs/sdk/09-payload-reference.md +702 -0
- package/_packed_docs/sdk/09-storage-rpc-manual.md +408 -0
- package/_packed_docs/sdk/09-stream-rpc-manual.md +275 -0
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +72 -0
- package/_packed_docs/sdk/INDEX.md +131 -0
- package/_packed_docs/sdk/README.md +307 -0
- package/dist/auth.d.ts +2 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +33 -14
- package/dist/auth.js.map +1 -1
- package/dist/bundle.js +14300 -0
- package/dist/client.d.ts +200 -178
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +3096 -4019
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +0 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -4
- package/dist/config.js.map +1 -1
- package/dist/crypto.d.ts +8 -1
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +114 -1
- package/dist/crypto.js.map +1 -1
- package/dist/e2ee.d.ts +5 -210
- package/dist/e2ee.d.ts.map +1 -1
- package/dist/e2ee.js +4 -1379
- package/dist/e2ee.js.map +1 -1
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/namespaces/auth.d.ts +1 -0
- package/dist/namespaces/auth.d.ts.map +1 -1
- package/dist/namespaces/auth.js +23 -8
- package/dist/namespaces/auth.js.map +1 -1
- package/dist/protected-headers.d.ts +14 -0
- package/dist/protected-headers.d.ts.map +1 -0
- package/dist/protected-headers.js +47 -0
- package/dist/protected-headers.js.map +1 -0
- package/dist/seq-tracker.d.ts +7 -2
- package/dist/seq-tracker.d.ts.map +1 -1
- package/dist/seq-tracker.js +31 -10
- package/dist/seq-tracker.js.map +1 -1
- package/dist/transport.d.ts +9 -1
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +24 -0
- package/dist/transport.js.map +1 -1
- package/dist/v2/crypto/aead.d.ts +26 -0
- package/dist/v2/crypto/aead.d.ts.map +1 -0
- package/dist/v2/crypto/aead.js +63 -0
- package/dist/v2/crypto/aead.js.map +1 -0
- package/dist/v2/crypto/canonical.d.ts +21 -0
- package/dist/v2/crypto/canonical.d.ts.map +1 -0
- package/dist/v2/crypto/canonical.js +111 -0
- package/dist/v2/crypto/canonical.js.map +1 -0
- package/dist/v2/crypto/dh-path.d.ts +21 -0
- package/dist/v2/crypto/dh-path.d.ts.map +1 -0
- package/dist/v2/crypto/dh-path.js +50 -0
- package/dist/v2/crypto/dh-path.js.map +1 -0
- package/dist/v2/crypto/ecdh.d.ts +19 -0
- package/dist/v2/crypto/ecdh.d.ts.map +1 -0
- package/dist/v2/crypto/ecdh.js +101 -0
- package/dist/v2/crypto/ecdh.js.map +1 -0
- package/dist/v2/crypto/ecdsa.d.ts +16 -0
- package/dist/v2/crypto/ecdsa.d.ts.map +1 -0
- package/dist/v2/crypto/ecdsa.js +52 -0
- package/dist/v2/crypto/ecdsa.js.map +1 -0
- package/dist/v2/crypto/hkdf.d.ts +21 -0
- package/dist/v2/crypto/hkdf.d.ts.map +1 -0
- package/dist/v2/crypto/hkdf.js +32 -0
- package/dist/v2/crypto/hkdf.js.map +1 -0
- package/dist/v2/crypto/index.d.ts +9 -0
- package/dist/v2/crypto/index.d.ts.map +1 -0
- package/dist/v2/crypto/index.js +8 -0
- package/dist/v2/crypto/index.js.map +1 -0
- package/dist/v2/crypto/recipients.d.ts +43 -0
- package/dist/v2/crypto/recipients.d.ts.map +1 -0
- package/dist/v2/crypto/recipients.js +188 -0
- package/dist/v2/crypto/recipients.js.map +1 -0
- package/dist/v2/e2ee/decrypt.d.ts +13 -0
- package/dist/v2/e2ee/decrypt.d.ts.map +1 -0
- package/dist/v2/e2ee/decrypt.js +176 -0
- package/dist/v2/e2ee/decrypt.js.map +1 -0
- package/dist/v2/e2ee/encrypt-group.d.ts +14 -0
- package/dist/v2/e2ee/encrypt-group.d.ts.map +1 -0
- package/dist/v2/e2ee/encrypt-group.js +196 -0
- package/dist/v2/e2ee/encrypt-group.js.map +1 -0
- package/dist/v2/e2ee/encrypt-p2p.d.ts +15 -0
- package/dist/v2/e2ee/encrypt-p2p.d.ts.map +1 -0
- package/dist/v2/e2ee/encrypt-p2p.js +240 -0
- package/dist/v2/e2ee/encrypt-p2p.js.map +1 -0
- package/dist/v2/e2ee/index.d.ts +9 -0
- package/dist/v2/e2ee/index.d.ts.map +1 -0
- package/dist/v2/e2ee/index.js +9 -0
- package/dist/v2/e2ee/index.js.map +1 -0
- package/dist/v2/e2ee/metadata-auth.d.ts +9 -0
- package/dist/v2/e2ee/metadata-auth.d.ts.map +1 -0
- package/dist/v2/e2ee/metadata-auth.js +60 -0
- package/dist/v2/e2ee/metadata-auth.js.map +1 -0
- package/dist/v2/e2ee/types.d.ts +57 -0
- package/dist/v2/e2ee/types.d.ts.map +1 -0
- package/dist/v2/e2ee/types.js +7 -0
- package/dist/v2/e2ee/types.js.map +1 -0
- package/dist/v2/session/index.d.ts +4 -0
- package/dist/v2/session/index.d.ts.map +1 -0
- package/dist/v2/session/index.js +3 -0
- package/dist/v2/session/index.js.map +1 -0
- package/dist/v2/session/keystore.d.ts +48 -0
- package/dist/v2/session/keystore.d.ts.map +1 -0
- package/dist/v2/session/keystore.js +184 -0
- package/dist/v2/session/keystore.js.map +1 -0
- package/dist/v2/session/session.d.ts +98 -0
- package/dist/v2/session/session.d.ts.map +1 -0
- package/dist/v2/session/session.js +270 -0
- package/dist/v2/session/session.js.map +1 -0
- package/dist/v2/state/commitment.d.ts +10 -0
- package/dist/v2/state/commitment.d.ts.map +1 -0
- package/dist/v2/state/commitment.js +86 -0
- package/dist/v2/state/commitment.js.map +1 -0
- package/dist/v2/state/index.d.ts +2 -0
- package/dist/v2/state/index.d.ts.map +1 -0
- package/dist/v2/state/index.js +2 -0
- package/dist/v2/state/index.js.map +1 -0
- package/package.json +43 -37
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
## 12. 完整示例
|
|
2
|
+
|
|
3
|
+
> 以下示例以说明协议顺序和字段结构为主,属于最小接入样例。辅助函数如 `loadCert()`、`verifyPeerHelloReply()`、`signWithPrivateKey()` 仅为伪代码占位,实际 SDK 或生产实现需补充错误处理、超时控制、证书校验策略与连接重试。
|
|
4
|
+
|
|
5
|
+
### 12.1 Gateway 模式:浏览器应用完整流程
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
// 1. 连接 Gateway
|
|
9
|
+
const ws = new WebSocket('wss://gateway.example.com/aun');
|
|
10
|
+
let msgId = 1;
|
|
11
|
+
let token = null;
|
|
12
|
+
let gatewayNonce = null;
|
|
13
|
+
let savedClientNonce = null; // 保存 client_nonce 用于验证 Auth 服务签名
|
|
14
|
+
let savedRequestId = null;
|
|
15
|
+
|
|
16
|
+
ws.onopen = () => {
|
|
17
|
+
// Gateway 会先推送 challenge;收到后再发 auth.* / auth.connect
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// 处理响应和事件
|
|
21
|
+
ws.onmessage = async (event) => {
|
|
22
|
+
const msg = JSON.parse(event.data);
|
|
23
|
+
|
|
24
|
+
// challenge:保存 Gateway nonce,然后开始 auth.* 两阶段登录
|
|
25
|
+
if (msg.method === 'challenge') {
|
|
26
|
+
gatewayNonce = msg.params.nonce;
|
|
27
|
+
|
|
28
|
+
// 步骤1:发送 login_aid1(必需字段:aid, cert, request_id, client_nonce)
|
|
29
|
+
savedRequestId = `req-${Date.now()}`;
|
|
30
|
+
savedClientNonce = crypto.randomUUID();
|
|
31
|
+
ws.send(JSON.stringify({
|
|
32
|
+
jsonrpc: '2.0',
|
|
33
|
+
id: msgId++,
|
|
34
|
+
method: 'auth.aid_login1',
|
|
35
|
+
params: {
|
|
36
|
+
aid: 'alice.aid.pub',
|
|
37
|
+
cert: loadCert(), // PEM 格式证书(必需)
|
|
38
|
+
request_id: savedRequestId, // 关联两阶段登录(必需)
|
|
39
|
+
client_nonce: savedClientNonce // 客户端随机 nonce(必需)
|
|
40
|
+
}
|
|
41
|
+
}));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// login_aid1 响应:返回 nonce + client_nonce_signature + auth_cert
|
|
46
|
+
if (msg.result && msg.result.nonce && msg.result.client_nonce_signature) {
|
|
47
|
+
// 验证 Auth 服务身份:用 auth_cert 公钥验证 client_nonce_signature
|
|
48
|
+
const authVerified = await verifyAuthSignature(
|
|
49
|
+
msg.result.auth_cert, savedClientNonce, msg.result.client_nonce_signature
|
|
50
|
+
);
|
|
51
|
+
if (!authVerified) throw new Error('Auth 服务身份验证失败');
|
|
52
|
+
|
|
53
|
+
// 步骤2:对 server nonce 签名,提交 login_aid2
|
|
54
|
+
const signature = await signWithPrivateKey(msg.result.nonce);
|
|
55
|
+
ws.send(JSON.stringify({
|
|
56
|
+
jsonrpc: '2.0',
|
|
57
|
+
id: msgId++,
|
|
58
|
+
method: 'auth.aid_login2',
|
|
59
|
+
params: {
|
|
60
|
+
aid: 'alice.aid.pub',
|
|
61
|
+
request_id: savedRequestId,
|
|
62
|
+
nonce: msg.result.nonce,
|
|
63
|
+
signature: signature,
|
|
64
|
+
cert: loadCert()
|
|
65
|
+
}
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// login_aid2 响应(获得 token,但连接状态未变)
|
|
70
|
+
if (msg.result && msg.result.token && !msg.result.authenticated) {
|
|
71
|
+
token = msg.result.token;
|
|
72
|
+
|
|
73
|
+
// 步骤3:用 token 调用 auth.connect 完成 Gateway 模式会话初始化
|
|
74
|
+
ws.send(JSON.stringify({
|
|
75
|
+
jsonrpc: '2.0',
|
|
76
|
+
id: msgId++,
|
|
77
|
+
method: 'auth.connect',
|
|
78
|
+
params: {
|
|
79
|
+
nonce: gatewayNonce,
|
|
80
|
+
auth: { method: 'kite_token', token },
|
|
81
|
+
protocol: {min: '1.0', max: '1.0'},
|
|
82
|
+
device: {id: 'browser-dev-001', type: 'browser'},
|
|
83
|
+
client: {name: 'MyApp', version: '1.0.0'},
|
|
84
|
+
capabilities: {e2ee: true, group_e2ee: true}
|
|
85
|
+
}
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// auth.connect 响应(连接已认证)
|
|
90
|
+
if (msg.result && msg.result.authenticated) {
|
|
91
|
+
console.log('Authenticated as:', msg.result.identity.aid);
|
|
92
|
+
|
|
93
|
+
// 现在可以调用所有方法
|
|
94
|
+
ws.send(JSON.stringify({
|
|
95
|
+
jsonrpc: '2.0',
|
|
96
|
+
id: msgId++,
|
|
97
|
+
method: 'message.send',
|
|
98
|
+
params: {
|
|
99
|
+
to: 'bob.aid.pub',
|
|
100
|
+
type: 'text',
|
|
101
|
+
payload: {type: 'text', text: 'Hello Bob!'}
|
|
102
|
+
}
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 收到消息事件
|
|
107
|
+
if (msg.method === 'event/message.received') {
|
|
108
|
+
console.log('Message from', msg.params.from, ':', msg.params.payload?.text);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
发送附件时,不应在 `payload` 中直接嵌入文件二进制,而应携带 `storage.*` 返回的对象引用:
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
ws.send(JSON.stringify({
|
|
117
|
+
jsonrpc: '2.0',
|
|
118
|
+
id: msgId++,
|
|
119
|
+
method: 'message.send',
|
|
120
|
+
params: {
|
|
121
|
+
to: 'bob.aid.pub',
|
|
122
|
+
payload: {
|
|
123
|
+
type: 'file',
|
|
124
|
+
text: '请查收附件',
|
|
125
|
+
attachments: [
|
|
126
|
+
{
|
|
127
|
+
url: 'https://storage.example.com/objects/default/docs/report.pdf',
|
|
128
|
+
bucket: 'default',
|
|
129
|
+
object_key: 'docs/report.pdf',
|
|
130
|
+
filename: 'report.pdf',
|
|
131
|
+
size: 245678,
|
|
132
|
+
sha256: '3d8e577bddb17db339eae0b3d9bcf180f48c3f1a12f5f7ddce9f4ea7d3c1af4a',
|
|
133
|
+
content_type: 'application/pdf'
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}));
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 12.2 Gateway 模式:移动应用完整流程(iOS)
|
|
142
|
+
|
|
143
|
+
```swift
|
|
144
|
+
// 1. 连接 Gateway
|
|
145
|
+
var request = URLRequest(url: URL(string: "wss://gateway.example.com/aun")!)
|
|
146
|
+
let ws = WebSocket(request: request)
|
|
147
|
+
var msgId = 1
|
|
148
|
+
var token: String?
|
|
149
|
+
var gatewayNonce: String?
|
|
150
|
+
var savedClientNonce: String?
|
|
151
|
+
var savedRequestId: String?
|
|
152
|
+
|
|
153
|
+
// 2. 连接成功后,等待 Gateway challenge,再调用 auth.* 获取 token
|
|
154
|
+
ws.onConnected = {
|
|
155
|
+
// no-op: Gateway 会主动推送 challenge
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 3. 处理响应和事件
|
|
159
|
+
ws.onMessage = { message in
|
|
160
|
+
if let challenge = message as? ChallengeMessage {
|
|
161
|
+
gatewayNonce = challenge.nonce
|
|
162
|
+
savedRequestId = UUID().uuidString
|
|
163
|
+
savedClientNonce = UUID().uuidString
|
|
164
|
+
ws.send(jsonrpc: "2.0", id: msgId, method: "auth.aid_login1",
|
|
165
|
+
params: [
|
|
166
|
+
"aid": "alice.aid.pub",
|
|
167
|
+
"cert": loadCert(), // PEM 格式证书(必需)
|
|
168
|
+
"request_id": savedRequestId!, // 关联两阶段登录(必需)
|
|
169
|
+
"client_nonce": savedClientNonce! // 客户端随机 nonce(必需)
|
|
170
|
+
])
|
|
171
|
+
msgId += 1
|
|
172
|
+
return
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// login_aid1 响应:返回 nonce + client_nonce_signature + auth_cert
|
|
176
|
+
if let loginResp = message as? LoginAid1Response {
|
|
177
|
+
// 验证 Auth 服务身份:用 auth_cert 公钥验证 client_nonce_signature
|
|
178
|
+
guard verifyAuthSignature(
|
|
179
|
+
authCert: loginResp.authCert,
|
|
180
|
+
clientNonce: savedClientNonce!,
|
|
181
|
+
signature: loginResp.clientNonceSignature
|
|
182
|
+
) else { fatalError("Auth 服务身份验证失败") }
|
|
183
|
+
|
|
184
|
+
// 对 server nonce 签名,提交 login_aid2
|
|
185
|
+
let signature = signWithPrivateKey(loginResp.nonce)
|
|
186
|
+
ws.send(jsonrpc: "2.0", id: msgId, method: "auth.aid_login2",
|
|
187
|
+
params: [
|
|
188
|
+
"aid": "alice.aid.pub",
|
|
189
|
+
"request_id": savedRequestId!,
|
|
190
|
+
"nonce": loginResp.nonce,
|
|
191
|
+
"signature": signature,
|
|
192
|
+
"cert": loadCert()
|
|
193
|
+
])
|
|
194
|
+
msgId += 1
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// login_aid2 响应(获得 token,但连接状态未变)
|
|
198
|
+
if let loginResp = message as? LoginAid2Response {
|
|
199
|
+
token = loginResp.token
|
|
200
|
+
|
|
201
|
+
// 用 token 调用 auth.connect 完成 Gateway 模式会话初始化
|
|
202
|
+
let connectParams: [String: Any] = [
|
|
203
|
+
"nonce": gatewayNonce!,
|
|
204
|
+
"auth": ["method": "kite_token", "token": token!],
|
|
205
|
+
"protocol": ["min": "1.0", "max": "1.0"],
|
|
206
|
+
"device": ["id": "ios-dev-001", "type": "mobile"],
|
|
207
|
+
"client": ["name": "MyApp", "version": "1.0.0"],
|
|
208
|
+
"capabilities": ["e2ee": true, "group_e2ee": true]
|
|
209
|
+
]
|
|
210
|
+
ws.send(jsonrpc: "2.0", id: msgId, method: "auth.connect", params: connectParams)
|
|
211
|
+
msgId += 1
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// auth.connect 响应(连接已认证)
|
|
215
|
+
if let response = message as? AuthConnectResponse, response.authenticated {
|
|
216
|
+
print("Authenticated as: \(response.identity.aid)")
|
|
217
|
+
|
|
218
|
+
// 现在可以调用所有方法
|
|
219
|
+
ws.send(jsonrpc: "2.0", id: msgId, method: "message.send",
|
|
220
|
+
params: [
|
|
221
|
+
"to": "bob.aid.pub",
|
|
222
|
+
"payload": ["type": "text", "text": "Hello Bob!"]
|
|
223
|
+
])
|
|
224
|
+
msgId += 1
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// 收到消息事件
|
|
228
|
+
if let event = message as? MessageReceivedEvent {
|
|
229
|
+
print("Message from \(event.from): \(event.payload["text"] ?? "")")
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### 12.3 Peer 模式:最小直连接入示例
|
|
235
|
+
|
|
236
|
+
```javascript
|
|
237
|
+
const ws = new WebSocket('wss://bob.company.com:9900/acp');
|
|
238
|
+
let msgId = 1;
|
|
239
|
+
let localNonce = crypto.randomUUID();
|
|
240
|
+
|
|
241
|
+
ws.onopen = () => {
|
|
242
|
+
ws.send(JSON.stringify({
|
|
243
|
+
jsonrpc: '2.0',
|
|
244
|
+
id: msgId++,
|
|
245
|
+
method: 'initialize',
|
|
246
|
+
params: {
|
|
247
|
+
mode: 'peer',
|
|
248
|
+
protocol: {min: '1.0', max: '1.0'},
|
|
249
|
+
clientInfo: {name: 'PeerClient', version: '1.0.0'}
|
|
250
|
+
}
|
|
251
|
+
}));
|
|
252
|
+
|
|
253
|
+
ws.send(JSON.stringify({
|
|
254
|
+
jsonrpc: '2.0',
|
|
255
|
+
id: msgId++,
|
|
256
|
+
method: 'peer.hello',
|
|
257
|
+
params: {
|
|
258
|
+
aid: 'alice.aid.pub',
|
|
259
|
+
cert: loadCert(),
|
|
260
|
+
nonce: localNonce,
|
|
261
|
+
protocol: {min: '1.0', max: '1.0'}
|
|
262
|
+
}
|
|
263
|
+
}));
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
ws.onmessage = async (event) => {
|
|
267
|
+
const msg = JSON.parse(event.data);
|
|
268
|
+
|
|
269
|
+
if (msg.result?.nonce && msg.result?.nonce_signature && msg.result?.cert) {
|
|
270
|
+
const peerOk = await verifyPeerHelloReply(
|
|
271
|
+
msg.result.cert,
|
|
272
|
+
localNonce,
|
|
273
|
+
msg.result.nonce_signature
|
|
274
|
+
);
|
|
275
|
+
if (!peerOk) throw new Error('Peer 身份验证失败');
|
|
276
|
+
|
|
277
|
+
const replySignature = await signWithPrivateKey(msg.result.nonce);
|
|
278
|
+
ws.send(JSON.stringify({
|
|
279
|
+
jsonrpc: '2.0',
|
|
280
|
+
id: msgId++,
|
|
281
|
+
method: 'peer.confirm',
|
|
282
|
+
params: {
|
|
283
|
+
nonce_signature: replySignature
|
|
284
|
+
}
|
|
285
|
+
}));
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (msg.result?.authenticated) {
|
|
289
|
+
ws.send(JSON.stringify({
|
|
290
|
+
jsonrpc: '2.0',
|
|
291
|
+
id: msgId++,
|
|
292
|
+
method: 'message.send',
|
|
293
|
+
params: {
|
|
294
|
+
to: 'bob.company.com',
|
|
295
|
+
type: 'text',
|
|
296
|
+
payload: {type: 'text', text: 'Hello from peer mode'}
|
|
297
|
+
}
|
|
298
|
+
}));
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### 12.4 Relay 模式:最小中继接入示例
|
|
304
|
+
|
|
305
|
+
```javascript
|
|
306
|
+
const ws = new WebSocket('wss://relay.aun.network:9800/relay');
|
|
307
|
+
let msgId = 1;
|
|
308
|
+
let localNonce = crypto.randomUUID();
|
|
309
|
+
|
|
310
|
+
ws.onopen = () => {
|
|
311
|
+
ws.send(JSON.stringify({
|
|
312
|
+
jsonrpc: '2.0',
|
|
313
|
+
id: msgId++,
|
|
314
|
+
method: 'initialize',
|
|
315
|
+
params: {
|
|
316
|
+
mode: 'relay',
|
|
317
|
+
protocol: {min: '1.0', max: '1.0'},
|
|
318
|
+
clientInfo: {name: 'RelayClient', version: '1.0.0'}
|
|
319
|
+
}
|
|
320
|
+
}));
|
|
321
|
+
|
|
322
|
+
ws.send(JSON.stringify({
|
|
323
|
+
jsonrpc: '2.0',
|
|
324
|
+
id: msgId++,
|
|
325
|
+
method: 'relay.register',
|
|
326
|
+
params: {
|
|
327
|
+
aid: 'alice.aid.pub'
|
|
328
|
+
}
|
|
329
|
+
}));
|
|
330
|
+
|
|
331
|
+
ws.send(JSON.stringify({
|
|
332
|
+
jsonrpc: '2.0',
|
|
333
|
+
id: msgId++,
|
|
334
|
+
method: 'relay.forward',
|
|
335
|
+
params: {
|
|
336
|
+
to: 'bob.company.com',
|
|
337
|
+
message: {
|
|
338
|
+
jsonrpc: '2.0',
|
|
339
|
+
id: msgId++,
|
|
340
|
+
method: 'peer.hello',
|
|
341
|
+
params: {
|
|
342
|
+
aid: 'alice.aid.pub',
|
|
343
|
+
cert: loadCert(),
|
|
344
|
+
nonce: localNonce,
|
|
345
|
+
protocol: {min: '1.0', max: '1.0'}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}));
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
ws.onmessage = async (event) => {
|
|
353
|
+
const msg = JSON.parse(event.data);
|
|
354
|
+
|
|
355
|
+
if (msg.method === 'event/relay.message' && msg.params?.message?.result?.nonce_signature) {
|
|
356
|
+
const inner = msg.params.message.result;
|
|
357
|
+
const peerOk = await verifyPeerHelloReply(inner.cert, localNonce, inner.nonce_signature);
|
|
358
|
+
if (!peerOk) throw new Error('Relay 上的对端身份验证失败');
|
|
359
|
+
|
|
360
|
+
const replySignature = await signWithPrivateKey(inner.nonce);
|
|
361
|
+
ws.send(JSON.stringify({
|
|
362
|
+
jsonrpc: '2.0',
|
|
363
|
+
id: msgId++,
|
|
364
|
+
method: 'relay.forward',
|
|
365
|
+
params: {
|
|
366
|
+
to: 'bob.company.com',
|
|
367
|
+
message: {
|
|
368
|
+
jsonrpc: '2.0',
|
|
369
|
+
id: msgId++,
|
|
370
|
+
method: 'peer.confirm',
|
|
371
|
+
params: {
|
|
372
|
+
nonce_signature: replySignature
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}));
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (msg.method === 'event/relay.message' && msg.params?.message?.result?.authenticated) {
|
|
380
|
+
ws.send(JSON.stringify({
|
|
381
|
+
jsonrpc: '2.0',
|
|
382
|
+
id: msgId++,
|
|
383
|
+
method: 'relay.forward',
|
|
384
|
+
params: {
|
|
385
|
+
to: 'bob.company.com',
|
|
386
|
+
message: {
|
|
387
|
+
jsonrpc: '2.0',
|
|
388
|
+
id: msgId++,
|
|
389
|
+
method: 'message.send',
|
|
390
|
+
params: {
|
|
391
|
+
to: 'bob.company.com',
|
|
392
|
+
type: 'text',
|
|
393
|
+
payload: {type: 'text', text: 'Hello from relay mode'}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}));
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
---
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# 13. 泛域名与 Agent Web 访问约定
|
|
2
|
+
|
|
3
|
+
本章说明 Issuer 配置泛域名解析(`*.{issuer_domain}`)的作用,以及 `https://{aid}.{issuer_domain}` 的默认访问行为。
|
|
4
|
+
|
|
5
|
+
> **术语说明**:
|
|
6
|
+
> - `{issuer_domain}`:Issuer 的域名,如 `aid.pub`
|
|
7
|
+
> - `{aid}`:完整的 Agent Identifier,如 `alice.aid.pub`
|
|
8
|
+
> - `https://{aid}.{issuer_domain}`:本文用于描述 Agent 的标准 Web 入口;具体主机名生成规则由 Issuer 的 AID 编排方式决定
|
|
9
|
+
|
|
10
|
+
## 13.1 设计目标
|
|
11
|
+
|
|
12
|
+
Issuer CA 申请流程要求配置泛域名解析 `*.{issuer_domain}`,其核心目的不是证书签发本身,而是为 Issuer 下的每个 Agent 提供统一、稳定、可预测的 Web 访问入口。
|
|
13
|
+
|
|
14
|
+
这样做有几个直接收益:
|
|
15
|
+
|
|
16
|
+
- **统一入口**:每个 Agent 天然拥有一个可访问的专属 URL,无需额外登记路由
|
|
17
|
+
- **发现友好**:人类用户和其他 Agent 可以直接通过 AID 对应的域名访问 Agent 描述或首页
|
|
18
|
+
- **实现简化**:服务端只需接收所有 `*.{issuer_domain}` 请求,再按 Host 头解析目标 Agent
|
|
19
|
+
- **扩展友好**:在不改变 AID 和基础路由规则的前提下,可为 Agent 挂载更多页面和内置服务
|
|
20
|
+
|
|
21
|
+
## 13.2 泛域名的作用
|
|
22
|
+
|
|
23
|
+
泛域名解析的主要作用是让 Issuer 统一承接所有 Agent 子域名请求:
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
*.{issuer_domain} -> Agent Web Gateway / 站点入口 / 反向代理
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
请求到达入口服务后,实现者通常按以下步骤处理:
|
|
30
|
+
|
|
31
|
+
1. 从 HTTP Host 提取目标主机名
|
|
32
|
+
2. 将主机名映射到目标 AID 或目标 Agent 资源
|
|
33
|
+
3. 根据访问路径、访问方类型和部署策略返回 `agent.md`、`index.html` 或某个内置服务页面
|
|
34
|
+
|
|
35
|
+
## 13.3 实现建议(非规范性)
|
|
36
|
+
|
|
37
|
+
以下内容主要是实现建议,不是协议强制要求:
|
|
38
|
+
|
|
39
|
+
- **DNS**:推荐将 `*.{issuer_domain}` 解析到统一的入口层(CDN、LB、反向代理或 Web Gateway)
|
|
40
|
+
- **TLS**:推荐为 `*.{issuer_domain}` 配置泛域名证书,或在入口层统一终止 TLS
|
|
41
|
+
- **路由**:推荐由统一入口按 Host 头解析目标 Agent,而不是为每个 Agent 单独配置站点
|
|
42
|
+
- **静态资源**:推荐将 `agent.md` 和 `index.html` 视为 Agent 的两个标准 Web 资源
|
|
43
|
+
- **访问方识别**:如需区分“Agent 访问”和“人类访问”,推荐基于 User-Agent、Accept 头、显式客户端标识或上层调用约定实现
|
|
44
|
+
- **缓存**:推荐对 `agent.md` 使用较短缓存时间,避免 Agent 描述信息长期陈旧;首页可按产品需求设置缓存策略
|
|
45
|
+
|
|
46
|
+
## 13.4 标准访问路径与默认行为(规范性)
|
|
47
|
+
|
|
48
|
+
本节定义 Agent Web 访问的**强制行为**。
|
|
49
|
+
|
|
50
|
+
### 13.4.1 根路径访问
|
|
51
|
+
|
|
52
|
+
当访问:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
https://{aid}.{issuer_domain}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
服务端必须根据访问方类型返回不同的默认资源:
|
|
59
|
+
|
|
60
|
+
- **Agent(无头浏览器、程序化客户端、协议消费者)访问时**:
|
|
61
|
+
- **必须**等价于访问:
|
|
62
|
+
```text
|
|
63
|
+
https://{aid}.{issuer_domain}/agent.md
|
|
64
|
+
```
|
|
65
|
+
- 返回该 Agent 的 `agent.md` 文档内容
|
|
66
|
+
|
|
67
|
+
- **人类用户(有头浏览器)访问时**:
|
|
68
|
+
- **必须**等价于访问:
|
|
69
|
+
```text
|
|
70
|
+
https://{aid}.{issuer_domain}/index.html
|
|
71
|
+
```
|
|
72
|
+
- 返回该 Agent 的首页内容
|
|
73
|
+
|
|
74
|
+
这里的 `agent.md` 指 Agent 的标准描述文档,其格式和字段定义已提升到主协议 [06-服务协议](06-服务协议.md) 的 `search.*` 章节统一规定。完整规格见 [agent.md/SCHEMA.md](agent.md/SCHEMA.md),示例见 [human-developer.md](agent.md/examples/human-developer.md)、[openclaw-lobster.md](agent.md/examples/openclaw-lobster.md)、[codeagent-claudecode.md](agent.md/examples/codeagent-claudecode.md)。附录 K 只负责定义 Web 访问入口和默认路径行为,不再重复承载 `agent.md` 结构规范。
|
|
75
|
+
|
|
76
|
+
### 13.4.2 显式访问 `agent.md`
|
|
77
|
+
|
|
78
|
+
当显式访问:
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
https://{aid}.{issuer_domain}/agent.md
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
无论访问方是人还是 Agent,服务端都**必须**返回该 Agent 的 `agent.md` 内容,不得再根据访问方类型改写为其他资源。
|
|
85
|
+
|
|
86
|
+
### 13.4.3 显式访问 `index.html`
|
|
87
|
+
|
|
88
|
+
当显式访问:
|
|
89
|
+
|
|
90
|
+
```text
|
|
91
|
+
https://{aid}.{issuer_domain}/index.html
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
无论访问方是人还是 Agent,服务端都**必须**返回该 Agent 的首页内容,不得再根据访问方类型改写为 `agent.md`。
|
|
95
|
+
|
|
96
|
+
> 说明:协议的规范 URL 为 HTTPS。如部署方额外开放 HTTP 入口,可返回相同内容,或重定向到对应的 HTTPS URL。
|
|
97
|
+
|
|
98
|
+
### 13.4.4 内置服务页面
|
|
99
|
+
|
|
100
|
+
当访问:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
https://{aid}.{issuer_domain}/{svc}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
表示访问该 Agent 的某个内置服务页面,其中 `{svc}` 代表系统内置服务标识。
|
|
107
|
+
|
|
108
|
+
此时:
|
|
109
|
+
|
|
110
|
+
- 该路径**必须**被解释为“指定 Agent 的指定内置服务页面”
|
|
111
|
+
- 页面或资源的具体内容**由实现者决定**
|
|
112
|
+
- 如该服务不存在,服务端应返回标准 HTTP 错误(如 `404 Not Found`)
|
|
113
|
+
|
|
114
|
+
### 13.4.5 路径优先级
|
|
115
|
+
|
|
116
|
+
服务端处理优先级必须如下:
|
|
117
|
+
|
|
118
|
+
1. 显式路径优先:`/agent.md`、`/index.html`、`/{svc}` 按显式路径处理
|
|
119
|
+
2. 仅当访问根路径 `/` 或无路径时,才根据访问方类型选择默认资源
|
|
120
|
+
|
|
121
|
+
## 13.5 与 AID 和 Issuer 的关系
|
|
122
|
+
|
|
123
|
+
该约定意味着:
|
|
124
|
+
|
|
125
|
+
- 每个 AID 不只是一个通信身份,也是一个标准 Web 可访问对象
|
|
126
|
+
- Issuer 不仅负责证书签发和身份管理,也通常负责该 AID 对应 Web 入口的承接
|
|
127
|
+
- `agent.md` 是 Agent 面向其他 Agent 的默认公开描述文档,也是 `search.*` 的基础索引对象
|
|
128
|
+
- `index.html` 是 Agent 面向人类用户的默认首页
|
|
129
|
+
|
|
130
|
+
这使 AUN 在保持去中心化身份体系的同时,也为 Agent 的公开发现、说明页、服务页和后续生态扩展提供了统一入口。
|