aap-agent-client 3.1.0 → 3.2.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.
Files changed (2) hide show
  1. package/index.js +61 -13
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1,13 +1,38 @@
1
1
  /**
2
- * @aap/client v3.1.0
2
+ * @aap/client v3.2.0
3
3
  *
4
- * WebSocket client for Agent Attestation Protocol.
5
- * Batch mode: receive all challenges, solve, submit.
4
+ * WebSocket client with mandatory signature.
5
+ * Proves cryptographic identity via secp256k1.
6
6
  */
7
7
 
8
8
  import WebSocket from 'ws';
9
+ import { generateKeyPairSync, createSign, createHash, randomBytes } from 'crypto';
9
10
 
10
- export const PROTOCOL_VERSION = '3.1.0';
11
+ export const PROTOCOL_VERSION = '3.2.0';
12
+
13
+ /**
14
+ * Generate secp256k1 key pair for agent identity
15
+ */
16
+ export function generateIdentity() {
17
+ const { publicKey, privateKey } = generateKeyPairSync('ec', {
18
+ namedCurve: 'secp256k1',
19
+ publicKeyEncoding: { type: 'spki', format: 'pem' },
20
+ privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
21
+ });
22
+
23
+ const publicId = createHash('sha256').update(publicKey).digest('hex').slice(0, 16);
24
+
25
+ return { publicKey, privateKey, publicId };
26
+ }
27
+
28
+ /**
29
+ * Sign data with private key
30
+ */
31
+ export function sign(data, privateKey) {
32
+ const signer = createSign('SHA256');
33
+ signer.update(data);
34
+ return signer.sign(privateKey, 'base64');
35
+ }
11
36
 
12
37
  /**
13
38
  * AAP WebSocket Client
@@ -15,21 +40,26 @@ export const PROTOCOL_VERSION = '3.1.0';
15
40
  export class AAPClient {
16
41
  constructor(options = {}) {
17
42
  this.serverUrl = options.serverUrl || 'ws://localhost:3000/aap';
18
- this.publicId = options.publicId || null;
43
+ this.identity = options.identity || generateIdentity();
19
44
  this.solver = options.solver || null;
20
45
  }
21
46
 
47
+ get publicKey() { return this.identity.publicKey; }
48
+ get publicId() { return this.identity.publicId; }
49
+
22
50
  /**
23
- * Connect and verify
51
+ * Connect and verify with signature
24
52
  * @param {Function} [solver] - async (challenges) => answers[]
25
53
  * @returns {Promise<Object>} Verification result
26
54
  */
27
55
  async verify(solver) {
28
56
  const solve = solver || this.solver;
57
+ const { publicKey, privateKey, publicId } = this.identity;
29
58
 
30
59
  return new Promise((resolve, reject) => {
31
60
  const ws = new WebSocket(this.serverUrl);
32
61
  let result = null;
62
+ let nonce = null;
33
63
 
34
64
  ws.on('open', () => {});
35
65
 
@@ -39,23 +69,41 @@ export class AAPClient {
39
69
 
40
70
  switch (msg.type) {
41
71
  case 'handshake':
72
+ // Send ready with public key
42
73
  ws.send(JSON.stringify({
43
74
  type: 'ready',
44
- publicId: this.publicId
75
+ publicKey
45
76
  }));
46
77
  break;
47
78
 
48
79
  case 'challenges':
80
+ nonce = msg.nonce;
81
+
49
82
  if (!solve) {
50
- ws.send(JSON.stringify({ type: 'answers', answers: [] }));
83
+ // No solver - will fail
84
+ const timestamp = Date.now();
85
+ const answers = [];
86
+ const proofData = JSON.stringify({ nonce, answers, publicId, timestamp });
87
+ const signature = sign(proofData, privateKey);
88
+ ws.send(JSON.stringify({ type: 'answers', answers, signature, timestamp }));
51
89
  break;
52
90
  }
53
91
 
54
92
  try {
55
93
  const answers = await solve(msg.challenges);
56
- ws.send(JSON.stringify({ type: 'answers', answers }));
94
+ const timestamp = Date.now();
95
+
96
+ // Sign the proof
97
+ const proofData = JSON.stringify({ nonce, answers, publicId, timestamp });
98
+ const signature = sign(proofData, privateKey);
99
+
100
+ ws.send(JSON.stringify({ type: 'answers', answers, signature, timestamp }));
57
101
  } catch (e) {
58
- ws.send(JSON.stringify({ type: 'answers', answers: [] }));
102
+ const timestamp = Date.now();
103
+ const answers = [];
104
+ const proofData = JSON.stringify({ nonce, answers, publicId, timestamp });
105
+ const signature = sign(proofData, privateKey);
106
+ ws.send(JSON.stringify({ type: 'answers', answers, signature, timestamp }));
59
107
  }
60
108
  break;
61
109
 
@@ -107,8 +155,8 @@ Respond with ONLY a JSON array like: [{...}, {...}, ...]`;
107
155
  /**
108
156
  * Quick verify helper
109
157
  */
110
- export async function verify(serverUrl, solver, publicId) {
111
- const client = new AAPClient({ serverUrl, solver, publicId });
158
+ export async function verify(serverUrl, solver, identity) {
159
+ const client = new AAPClient({ serverUrl, solver, identity });
112
160
  return client.verify();
113
161
  }
114
162
 
@@ -116,4 +164,4 @@ export function createClient(options) {
116
164
  return new AAPClient(options);
117
165
  }
118
166
 
119
- export default { AAPClient, createClient, createSolver, verify, PROTOCOL_VERSION };
167
+ export default { AAPClient, createClient, createSolver, verify, generateIdentity, sign, PROTOCOL_VERSION };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aap-agent-client",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "WebSocket client for Agent Attestation Protocol - prove your AI agent identity",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",