aicq-chat-plugin 3.8.1 → 3.9.1

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/lib/handshake.js CHANGED
@@ -1,147 +1,147 @@
1
- /**
2
- * AICQ Handshake Manager — P2P handshake via temp numbers
3
- */
4
- const { computeFingerprint } = require('./crypto');
5
- const crypto = require('crypto');
6
-
7
- class HandshakeManager {
8
- constructor(identityManager, serverClient, db) {
9
- this.identity = identityManager;
10
- this.server = serverClient;
11
- this.db = db;
12
- }
13
-
14
- /**
15
- * Generate a temp number and return it for sharing
16
- */
17
- async generateFriendCode(agentId) {
18
- await this.server.ensureAuth(agentId);
19
- const result = await this.server.generateTempNumber();
20
- if (result.number) {
21
- this.db.saveTempNumber({
22
- agent_id: agentId,
23
- number: result.number,
24
- expires_at: result.expiresAt || result.expires_at,
25
- });
26
- }
27
- return result;
28
- }
29
-
30
- /**
31
- * Add a friend using their temp number / friend code
32
- */
33
- async addFriendByCode(agentId, tempNumber) {
34
- await this.server.ensureAuth(agentId);
35
- // Resolve the temp number
36
- const resolved = await this.server.resolveTempNumber(tempNumber);
37
- if (!resolved) throw new Error('Invalid or expired friend code');
38
-
39
- // Initiate handshake
40
- const result = await this.server.initiateHandshake(tempNumber);
41
-
42
- // If we got the peer's public key, derive session and add friend
43
- if (resolved.node_id || resolved.public_key) {
44
- const peerId = resolved.node_id || resolved.id;
45
- const peerPublicKey = resolved.public_key;
46
-
47
- // Derive session key
48
- let sessionKey = null;
49
- try {
50
- const identity = this.identity.loadAgent(agentId);
51
- if (identity && peerPublicKey) {
52
- const { deriveSessionKey } = require('./crypto');
53
- sessionKey = deriveSessionKey(identity.exchange_secret_key, peerPublicKey);
54
- }
55
- } catch (e) {
56
- console.error('[Handshake] Session key derivation failed:', e.message);
57
- }
58
-
59
- // Add friend locally
60
- if (peerId) {
61
- this.db.addFriend({
62
- agent_id: agentId,
63
- id: peerId,
64
- public_key: peerPublicKey || '',
65
- fingerprint: peerPublicKey ? computeFingerprint(peerPublicKey) : '',
66
- friend_type: 'ai',
67
- });
68
-
69
- // Save session if we have a key
70
- if (sessionKey) {
71
- this.db.saveSession({
72
- agent_id: agentId,
73
- peer_id: peerId,
74
- session_key: sessionKey,
75
- });
76
- }
77
- }
78
- }
79
-
80
- return result;
81
- }
82
-
83
- /**
84
- * List pending handshake requests
85
- */
86
- async getPendingRequests(agentId) {
87
- return this.db.getPendingRequests(agentId);
88
- }
89
-
90
- /**
91
- * Accept a pending handshake request
92
- */
93
- async acceptRequest(agentId, sessionId) {
94
- const request = this.db.getPendingRequests(agentId).find(r => r.session_id === sessionId);
95
- if (!request) throw new Error('Request not found');
96
-
97
- // Derive session key
98
- let sessionKey = null;
99
- try {
100
- const identity = this.identity.loadAgent(agentId);
101
- if (identity && request.requester_public_key) {
102
- const { deriveSessionKey } = require('./crypto');
103
- sessionKey = deriveSessionKey(identity.exchange_secret_key, request.requester_public_key);
104
- }
105
- } catch (e) {
106
- console.error('[Handshake] Session key derivation failed:', e.message);
107
- }
108
-
109
- // Add friend
110
- this.db.addFriend({
111
- agent_id: agentId,
112
- id: request.requester_id,
113
- public_key: request.requester_public_key,
114
- fingerprint: computeFingerprint(request.requester_public_key),
115
- friend_type: 'ai',
116
- });
117
-
118
- // Save session
119
- if (sessionKey) {
120
- this.db.saveSession({
121
- agent_id: agentId,
122
- peer_id: request.requester_id,
123
- session_key: sessionKey,
124
- });
125
- }
126
-
127
- // Respond to server
128
- await this.server.respondHandshake(sessionId, {
129
- public_key: this.identity.loadAgent(agentId).exchange_public_key,
130
- });
131
-
132
- // Remove pending request
133
- this.db.removePendingRequest(agentId, sessionId);
134
-
135
- return { success: true, friend_id: request.requester_id };
136
- }
137
-
138
- /**
139
- * Reject a pending handshake request
140
- */
141
- async rejectRequest(agentId, sessionId) {
142
- this.db.removePendingRequest(agentId, sessionId);
143
- return { success: true };
144
- }
145
- }
146
-
147
- module.exports = HandshakeManager;
1
+ /**
2
+ * AICQ Handshake Manager — P2P handshake via temp numbers
3
+ */
4
+ const { computeFingerprint } = require('./crypto');
5
+ const crypto = require('crypto');
6
+
7
+ class HandshakeManager {
8
+ constructor(identityManager, serverClient, db) {
9
+ this.identity = identityManager;
10
+ this.server = serverClient;
11
+ this.db = db;
12
+ }
13
+
14
+ /**
15
+ * Generate a temp number and return it for sharing
16
+ */
17
+ async generateFriendCode(agentId) {
18
+ await this.server.ensureAuth(agentId);
19
+ const result = await this.server.generateTempNumber();
20
+ if (result.number) {
21
+ this.db.saveTempNumber({
22
+ agent_id: agentId,
23
+ number: result.number,
24
+ expires_at: result.expiresAt || result.expires_at,
25
+ });
26
+ }
27
+ return result;
28
+ }
29
+
30
+ /**
31
+ * Add a friend using their temp number / friend code
32
+ */
33
+ async addFriendByCode(agentId, tempNumber) {
34
+ await this.server.ensureAuth(agentId);
35
+ // Resolve the temp number
36
+ const resolved = await this.server.resolveTempNumber(tempNumber);
37
+ if (!resolved) throw new Error('Invalid or expired friend code');
38
+
39
+ // Initiate handshake
40
+ const result = await this.server.initiateHandshake(tempNumber);
41
+
42
+ // If we got the peer's public key, derive session and add friend
43
+ if (resolved.node_id || resolved.public_key) {
44
+ const peerId = resolved.node_id || resolved.id;
45
+ const peerPublicKey = resolved.public_key;
46
+
47
+ // Derive session key
48
+ let sessionKey = null;
49
+ try {
50
+ const identity = this.identity.loadAgent(agentId);
51
+ if (identity && peerPublicKey) {
52
+ const { deriveSessionKey } = require('./crypto');
53
+ sessionKey = deriveSessionKey(identity.exchange_secret_key, peerPublicKey);
54
+ }
55
+ } catch (e) {
56
+ console.error('[Handshake] Session key derivation failed:', e.message);
57
+ }
58
+
59
+ // Add friend locally
60
+ if (peerId) {
61
+ this.db.addFriend({
62
+ agent_id: agentId,
63
+ id: peerId,
64
+ public_key: peerPublicKey || '',
65
+ fingerprint: peerPublicKey ? computeFingerprint(peerPublicKey) : '',
66
+ friend_type: 'ai',
67
+ });
68
+
69
+ // Save session if we have a key
70
+ if (sessionKey) {
71
+ this.db.saveSession({
72
+ agent_id: agentId,
73
+ peer_id: peerId,
74
+ session_key: sessionKey,
75
+ });
76
+ }
77
+ }
78
+ }
79
+
80
+ return result;
81
+ }
82
+
83
+ /**
84
+ * List pending handshake requests
85
+ */
86
+ async getPendingRequests(agentId) {
87
+ return this.db.getPendingRequests(agentId);
88
+ }
89
+
90
+ /**
91
+ * Accept a pending handshake request
92
+ */
93
+ async acceptRequest(agentId, sessionId) {
94
+ const request = this.db.getPendingRequests(agentId).find(r => r.session_id === sessionId);
95
+ if (!request) throw new Error('Request not found');
96
+
97
+ // Derive session key
98
+ let sessionKey = null;
99
+ try {
100
+ const identity = this.identity.loadAgent(agentId);
101
+ if (identity && request.requester_public_key) {
102
+ const { deriveSessionKey } = require('./crypto');
103
+ sessionKey = deriveSessionKey(identity.exchange_secret_key, request.requester_public_key);
104
+ }
105
+ } catch (e) {
106
+ console.error('[Handshake] Session key derivation failed:', e.message);
107
+ }
108
+
109
+ // Add friend
110
+ this.db.addFriend({
111
+ agent_id: agentId,
112
+ id: request.requester_id,
113
+ public_key: request.requester_public_key,
114
+ fingerprint: computeFingerprint(request.requester_public_key),
115
+ friend_type: 'ai',
116
+ });
117
+
118
+ // Save session
119
+ if (sessionKey) {
120
+ this.db.saveSession({
121
+ agent_id: agentId,
122
+ peer_id: request.requester_id,
123
+ session_key: sessionKey,
124
+ });
125
+ }
126
+
127
+ // Respond to server
128
+ await this.server.respondHandshake(sessionId, {
129
+ public_key: this.identity.loadAgent(agentId).exchange_public_key,
130
+ });
131
+
132
+ // Remove pending request
133
+ this.db.removePendingRequest(agentId, sessionId);
134
+
135
+ return { success: true, friend_id: request.requester_id };
136
+ }
137
+
138
+ /**
139
+ * Reject a pending handshake request
140
+ */
141
+ async rejectRequest(agentId, sessionId) {
142
+ this.db.removePendingRequest(agentId, sessionId);
143
+ return { success: true };
144
+ }
145
+ }
146
+
147
+ module.exports = HandshakeManager;
package/lib/identity.js CHANGED
@@ -1,165 +1,165 @@
1
- /**
2
- * AICQ Identity Manager — Ed25519 + X25519 key management
3
- */
4
- const crypto = require('./crypto');
5
-
6
- class IdentityManager {
7
- constructor(db) {
8
- this.db = db;
9
- this._cache = {}; // agent_id -> identity
10
- }
11
-
12
- /**
13
- * Create a new agent identity
14
- */
15
- createAgent(agentId, nickname = '') {
16
- const signing = crypto.generateSigningKeypair();
17
- const exchange = crypto.generateExchangeKeypair();
18
- const fingerprint = crypto.computeFingerprint(signing.publicKey);
19
-
20
- this.db.saveIdentity({
21
- agent_id: agentId,
22
- nickname: nickname || agentId,
23
- signing_public_key: signing.publicKey,
24
- signing_secret_key: signing.secretKey,
25
- exchange_public_key: exchange.publicKey,
26
- exchange_secret_key: exchange.secretKey,
27
- });
28
-
29
- this._cache[agentId] = {
30
- agent_id: agentId,
31
- nickname: nickname || agentId,
32
- signing_public_key: signing.publicKey,
33
- signing_secret_key: signing.secretKey,
34
- exchange_public_key: exchange.publicKey,
35
- exchange_secret_key: exchange.secretKey,
36
- fingerprint,
37
- };
38
-
39
- return this._cache[agentId];
40
- }
41
-
42
- /**
43
- * Load an existing identity into cache
44
- */
45
- loadAgent(agentId) {
46
- if (this._cache[agentId]) return this._cache[agentId];
47
- const row = this.db.loadIdentity(agentId);
48
- if (!row) return null;
49
- row.fingerprint = crypto.computeFingerprint(row.signing_public_key);
50
- this._cache[agentId] = row;
51
- return row;
52
- }
53
-
54
- /**
55
- * Get current identity (load first one if agentId not specified)
56
- */
57
- getCurrent(agentId) {
58
- if (agentId) return this.loadAgent(agentId);
59
- const identities = this.db.listIdentities();
60
- if (identities.length === 0) return null;
61
- return this.loadAgent(identities[0].agent_id);
62
- }
63
-
64
- /**
65
- * List all agent identities
66
- */
67
- listAgents() {
68
- return this.db.listIdentities();
69
- }
70
-
71
- /**
72
- * Delete an agent identity
73
- */
74
- deleteAgent(agentId) {
75
- delete this._cache[agentId];
76
- this.db.deleteIdentity(agentId);
77
- }
78
-
79
- /**
80
- * Update agent nickname
81
- */
82
- updateNickname(agentId, nickname) {
83
- this.db.updateNickname(agentId, nickname);
84
- if (this._cache[agentId]) {
85
- this._cache[agentId].nickname = nickname;
86
- }
87
- }
88
-
89
- /**
90
- * Sign a message with the agent's signing key
91
- */
92
- sign(agentId, message) {
93
- const identity = this.loadAgent(agentId);
94
- if (!identity) throw new Error('Identity not found');
95
- return crypto.signMessage(message, identity.signing_secret_key);
96
- }
97
-
98
- /**
99
- * Derive a session key with a peer
100
- */
101
- deriveSessionKey(agentId, peerExchangePublicKeyB64) {
102
- const identity = this.loadAgent(agentId);
103
- if (!identity) throw new Error('Identity not found');
104
- return crypto.deriveSessionKey(identity.exchange_secret_key, peerExchangePublicKeyB64);
105
- }
106
-
107
- /**
108
- * Rotate keys for an agent
109
- */
110
- rotateKeys(agentId) {
111
- const oldIdentity = this.loadAgent(agentId);
112
- if (!oldIdentity) throw new Error('Identity not found');
113
-
114
- const signing = crypto.generateSigningKeypair();
115
- const exchange = crypto.generateExchangeKeypair();
116
-
117
- this.db.saveIdentity({
118
- agent_id: agentId,
119
- nickname: oldIdentity.nickname,
120
- signing_public_key: signing.publicKey,
121
- signing_secret_key: signing.secretKey,
122
- exchange_public_key: exchange.publicKey,
123
- exchange_secret_key: exchange.secretKey,
124
- });
125
-
126
- this._cache[agentId] = {
127
- ...oldIdentity,
128
- signing_public_key: signing.publicKey,
129
- signing_secret_key: signing.secretKey,
130
- exchange_public_key: exchange.publicKey,
131
- exchange_secret_key: exchange.secretKey,
132
- fingerprint: crypto.computeFingerprint(signing.publicKey),
133
- };
134
-
135
- return this._cache[agentId];
136
- }
137
-
138
- /**
139
- * Update agent avatar
140
- */
141
- updateAvatar(agentId, avatarUrl) {
142
- this.db.updateAvatar(agentId, avatarUrl);
143
- if (this._cache[agentId]) {
144
- this._cache[agentId].avatar = avatarUrl;
145
- }
146
- }
147
-
148
- /**
149
- * Get identity info (public keys only, no secrets)
150
- */
151
- getInfo(agentId) {
152
- const identity = this.loadAgent(agentId);
153
- if (!identity) return null;
154
- return {
155
- agent_id: identity.agent_id,
156
- nickname: identity.nickname,
157
- avatar: identity.avatar || null,
158
- signing_public_key: identity.signing_public_key,
159
- exchange_public_key: identity.exchange_public_key,
160
- fingerprint: identity.fingerprint,
161
- };
162
- }
163
- }
164
-
165
- module.exports = IdentityManager;
1
+ /**
2
+ * AICQ Identity Manager — Ed25519 + X25519 key management
3
+ */
4
+ const crypto = require('./crypto');
5
+
6
+ class IdentityManager {
7
+ constructor(db) {
8
+ this.db = db;
9
+ this._cache = {}; // agent_id -> identity
10
+ }
11
+
12
+ /**
13
+ * Create a new agent identity
14
+ */
15
+ createAgent(agentId, nickname = '') {
16
+ const signing = crypto.generateSigningKeypair();
17
+ const exchange = crypto.generateExchangeKeypair();
18
+ const fingerprint = crypto.computeFingerprint(signing.publicKey);
19
+
20
+ this.db.saveIdentity({
21
+ agent_id: agentId,
22
+ nickname: nickname || agentId,
23
+ signing_public_key: signing.publicKey,
24
+ signing_secret_key: signing.secretKey,
25
+ exchange_public_key: exchange.publicKey,
26
+ exchange_secret_key: exchange.secretKey,
27
+ });
28
+
29
+ this._cache[agentId] = {
30
+ agent_id: agentId,
31
+ nickname: nickname || agentId,
32
+ signing_public_key: signing.publicKey,
33
+ signing_secret_key: signing.secretKey,
34
+ exchange_public_key: exchange.publicKey,
35
+ exchange_secret_key: exchange.secretKey,
36
+ fingerprint,
37
+ };
38
+
39
+ return this._cache[agentId];
40
+ }
41
+
42
+ /**
43
+ * Load an existing identity into cache
44
+ */
45
+ loadAgent(agentId) {
46
+ if (this._cache[agentId]) return this._cache[agentId];
47
+ const row = this.db.loadIdentity(agentId);
48
+ if (!row) return null;
49
+ row.fingerprint = crypto.computeFingerprint(row.signing_public_key);
50
+ this._cache[agentId] = row;
51
+ return row;
52
+ }
53
+
54
+ /**
55
+ * Get current identity (load first one if agentId not specified)
56
+ */
57
+ getCurrent(agentId) {
58
+ if (agentId) return this.loadAgent(agentId);
59
+ const identities = this.db.listIdentities();
60
+ if (identities.length === 0) return null;
61
+ return this.loadAgent(identities[0].agent_id);
62
+ }
63
+
64
+ /**
65
+ * List all agent identities
66
+ */
67
+ listAgents() {
68
+ return this.db.listIdentities();
69
+ }
70
+
71
+ /**
72
+ * Delete an agent identity
73
+ */
74
+ deleteAgent(agentId) {
75
+ delete this._cache[agentId];
76
+ this.db.deleteIdentity(agentId);
77
+ }
78
+
79
+ /**
80
+ * Update agent nickname
81
+ */
82
+ updateNickname(agentId, nickname) {
83
+ this.db.updateNickname(agentId, nickname);
84
+ if (this._cache[agentId]) {
85
+ this._cache[agentId].nickname = nickname;
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Sign a message with the agent's signing key
91
+ */
92
+ sign(agentId, message) {
93
+ const identity = this.loadAgent(agentId);
94
+ if (!identity) throw new Error('Identity not found');
95
+ return crypto.signMessage(message, identity.signing_secret_key);
96
+ }
97
+
98
+ /**
99
+ * Derive a session key with a peer
100
+ */
101
+ deriveSessionKey(agentId, peerExchangePublicKeyB64) {
102
+ const identity = this.loadAgent(agentId);
103
+ if (!identity) throw new Error('Identity not found');
104
+ return crypto.deriveSessionKey(identity.exchange_secret_key, peerExchangePublicKeyB64);
105
+ }
106
+
107
+ /**
108
+ * Rotate keys for an agent
109
+ */
110
+ rotateKeys(agentId) {
111
+ const oldIdentity = this.loadAgent(agentId);
112
+ if (!oldIdentity) throw new Error('Identity not found');
113
+
114
+ const signing = crypto.generateSigningKeypair();
115
+ const exchange = crypto.generateExchangeKeypair();
116
+
117
+ this.db.saveIdentity({
118
+ agent_id: agentId,
119
+ nickname: oldIdentity.nickname,
120
+ signing_public_key: signing.publicKey,
121
+ signing_secret_key: signing.secretKey,
122
+ exchange_public_key: exchange.publicKey,
123
+ exchange_secret_key: exchange.secretKey,
124
+ });
125
+
126
+ this._cache[agentId] = {
127
+ ...oldIdentity,
128
+ signing_public_key: signing.publicKey,
129
+ signing_secret_key: signing.secretKey,
130
+ exchange_public_key: exchange.publicKey,
131
+ exchange_secret_key: exchange.secretKey,
132
+ fingerprint: crypto.computeFingerprint(signing.publicKey),
133
+ };
134
+
135
+ return this._cache[agentId];
136
+ }
137
+
138
+ /**
139
+ * Update agent avatar
140
+ */
141
+ updateAvatar(agentId, avatarUrl) {
142
+ this.db.updateAvatar(agentId, avatarUrl);
143
+ if (this._cache[agentId]) {
144
+ this._cache[agentId].avatar = avatarUrl;
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Get identity info (public keys only, no secrets)
150
+ */
151
+ getInfo(agentId) {
152
+ const identity = this.loadAgent(agentId);
153
+ if (!identity) return null;
154
+ return {
155
+ agent_id: identity.agent_id,
156
+ nickname: identity.nickname,
157
+ avatar: identity.avatar || null,
158
+ signing_public_key: identity.signing_public_key,
159
+ exchange_public_key: identity.exchange_public_key,
160
+ fingerprint: identity.fingerprint,
161
+ };
162
+ }
163
+ }
164
+
165
+ module.exports = IdentityManager;
package/lib/package.json CHANGED
@@ -1,3 +1,3 @@
1
- {
2
- "type": "commonjs"
3
- }
1
+ {
2
+ "type": "commonjs"
3
+ }