society-protocol 1.0.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 (271) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/dist/adapters.d.ts +101 -0
  4. package/dist/adapters.d.ts.map +1 -0
  5. package/dist/adapters.js +764 -0
  6. package/dist/adapters.js.map +1 -0
  7. package/dist/agents-md.d.ts +59 -0
  8. package/dist/agents-md.d.ts.map +1 -0
  9. package/dist/agents-md.js +204 -0
  10. package/dist/agents-md.js.map +1 -0
  11. package/dist/autoconfig.d.ts +137 -0
  12. package/dist/autoconfig.d.ts.map +1 -0
  13. package/dist/autoconfig.js +452 -0
  14. package/dist/autoconfig.js.map +1 -0
  15. package/dist/bootstrap.d.ts +68 -0
  16. package/dist/bootstrap.d.ts.map +1 -0
  17. package/dist/bootstrap.js +304 -0
  18. package/dist/bootstrap.js.map +1 -0
  19. package/dist/bridges/a2a-bridge.d.ts +156 -0
  20. package/dist/bridges/a2a-bridge.d.ts.map +1 -0
  21. package/dist/bridges/a2a-bridge.js +337 -0
  22. package/dist/bridges/a2a-bridge.js.map +1 -0
  23. package/dist/bridges/mcp-bridge.d.ts +87 -0
  24. package/dist/bridges/mcp-bridge.d.ts.map +1 -0
  25. package/dist/bridges/mcp-bridge.js +332 -0
  26. package/dist/bridges/mcp-bridge.js.map +1 -0
  27. package/dist/cache.d.ts +130 -0
  28. package/dist/cache.d.ts.map +1 -0
  29. package/dist/cache.js +257 -0
  30. package/dist/cache.js.map +1 -0
  31. package/dist/capsules.d.ts +23 -0
  32. package/dist/capsules.d.ts.map +1 -0
  33. package/dist/capsules.js +75 -0
  34. package/dist/capsules.js.map +1 -0
  35. package/dist/cli/commands.d.ts +8 -0
  36. package/dist/cli/commands.d.ts.map +1 -0
  37. package/dist/cli/commands.js +263 -0
  38. package/dist/cli/commands.js.map +1 -0
  39. package/dist/coc.d.ts +121 -0
  40. package/dist/coc.d.ts.map +1 -0
  41. package/dist/coc.js +629 -0
  42. package/dist/coc.js.map +1 -0
  43. package/dist/coc.test.d.ts +2 -0
  44. package/dist/coc.test.d.ts.map +1 -0
  45. package/dist/coc.test.js +80 -0
  46. package/dist/coc.test.js.map +1 -0
  47. package/dist/compression.d.ts +125 -0
  48. package/dist/compression.d.ts.map +1 -0
  49. package/dist/compression.js +573 -0
  50. package/dist/compression.js.map +1 -0
  51. package/dist/cot-stream.d.ts +220 -0
  52. package/dist/cot-stream.d.ts.map +1 -0
  53. package/dist/cot-stream.js +673 -0
  54. package/dist/cot-stream.js.map +1 -0
  55. package/dist/crypto-wasm.d.ts +100 -0
  56. package/dist/crypto-wasm.d.ts.map +1 -0
  57. package/dist/crypto-wasm.js +229 -0
  58. package/dist/crypto-wasm.js.map +1 -0
  59. package/dist/federation.d.ts +200 -0
  60. package/dist/federation.d.ts.map +1 -0
  61. package/dist/federation.js +691 -0
  62. package/dist/federation.js.map +1 -0
  63. package/dist/federation.test.d.ts +2 -0
  64. package/dist/federation.test.d.ts.map +1 -0
  65. package/dist/federation.test.js +71 -0
  66. package/dist/federation.test.js.map +1 -0
  67. package/dist/gateway/capability-router.d.ts +77 -0
  68. package/dist/gateway/capability-router.d.ts.map +1 -0
  69. package/dist/gateway/capability-router.js +222 -0
  70. package/dist/gateway/capability-router.js.map +1 -0
  71. package/dist/gateway/demand-spawner.d.ts +155 -0
  72. package/dist/gateway/demand-spawner.d.ts.map +1 -0
  73. package/dist/gateway/demand-spawner.js +426 -0
  74. package/dist/gateway/demand-spawner.js.map +1 -0
  75. package/dist/identity.d.ts +46 -0
  76. package/dist/identity.d.ts.map +1 -0
  77. package/dist/identity.js +102 -0
  78. package/dist/identity.js.map +1 -0
  79. package/dist/identity.test.d.ts +2 -0
  80. package/dist/identity.test.d.ts.map +1 -0
  81. package/dist/identity.test.js +45 -0
  82. package/dist/identity.test.js.map +1 -0
  83. package/dist/index.d.ts +36 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +1572 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/integration.d.ts +210 -0
  88. package/dist/integration.d.ts.map +1 -0
  89. package/dist/integration.js +1105 -0
  90. package/dist/integration.js.map +1 -0
  91. package/dist/integration.test.d.ts +2 -0
  92. package/dist/integration.test.d.ts.map +1 -0
  93. package/dist/integration.test.js +155 -0
  94. package/dist/integration.test.js.map +1 -0
  95. package/dist/knowledge.d.ts +219 -0
  96. package/dist/knowledge.d.ts.map +1 -0
  97. package/dist/knowledge.js +543 -0
  98. package/dist/knowledge.js.map +1 -0
  99. package/dist/knowledge.test.d.ts +2 -0
  100. package/dist/knowledge.test.d.ts.map +1 -0
  101. package/dist/knowledge.test.js +72 -0
  102. package/dist/knowledge.test.js.map +1 -0
  103. package/dist/latent-space.d.ts +178 -0
  104. package/dist/latent-space.d.ts.map +1 -0
  105. package/dist/latent-space.js +385 -0
  106. package/dist/latent-space.js.map +1 -0
  107. package/dist/lib.d.ts +30 -0
  108. package/dist/lib.d.ts.map +1 -0
  109. package/dist/lib.js +30 -0
  110. package/dist/lib.js.map +1 -0
  111. package/dist/mcp/server.d.ts +74 -0
  112. package/dist/mcp/server.d.ts.map +1 -0
  113. package/dist/mcp/server.js +1392 -0
  114. package/dist/mcp/server.js.map +1 -0
  115. package/dist/metrics.d.ts +98 -0
  116. package/dist/metrics.d.ts.map +1 -0
  117. package/dist/metrics.js +222 -0
  118. package/dist/metrics.js.map +1 -0
  119. package/dist/p2p.d.ts +87 -0
  120. package/dist/p2p.d.ts.map +1 -0
  121. package/dist/p2p.js +606 -0
  122. package/dist/p2p.js.map +1 -0
  123. package/dist/persona/capabilities.d.ts +17 -0
  124. package/dist/persona/capabilities.d.ts.map +1 -0
  125. package/dist/persona/capabilities.js +224 -0
  126. package/dist/persona/capabilities.js.map +1 -0
  127. package/dist/persona/domains.d.ts +22 -0
  128. package/dist/persona/domains.d.ts.map +1 -0
  129. package/dist/persona/domains.js +176 -0
  130. package/dist/persona/domains.js.map +1 -0
  131. package/dist/persona/embeddings.d.ts +40 -0
  132. package/dist/persona/embeddings.d.ts.map +1 -0
  133. package/dist/persona/embeddings.js +265 -0
  134. package/dist/persona/embeddings.js.map +1 -0
  135. package/dist/persona/engine.d.ts +79 -0
  136. package/dist/persona/engine.d.ts.map +1 -0
  137. package/dist/persona/engine.js +1087 -0
  138. package/dist/persona/engine.js.map +1 -0
  139. package/dist/persona/index.d.ts +11 -0
  140. package/dist/persona/index.d.ts.map +1 -0
  141. package/dist/persona/index.js +11 -0
  142. package/dist/persona/index.js.map +1 -0
  143. package/dist/persona/lifecycle.d.ts +17 -0
  144. package/dist/persona/lifecycle.d.ts.map +1 -0
  145. package/dist/persona/lifecycle.js +36 -0
  146. package/dist/persona/lifecycle.js.map +1 -0
  147. package/dist/persona/retrieval.d.ts +6 -0
  148. package/dist/persona/retrieval.d.ts.map +1 -0
  149. package/dist/persona/retrieval.js +122 -0
  150. package/dist/persona/retrieval.js.map +1 -0
  151. package/dist/persona/sync.d.ts +15 -0
  152. package/dist/persona/sync.d.ts.map +1 -0
  153. package/dist/persona/sync.js +92 -0
  154. package/dist/persona/sync.js.map +1 -0
  155. package/dist/persona/types.d.ts +283 -0
  156. package/dist/persona/types.d.ts.map +1 -0
  157. package/dist/persona/types.js +2 -0
  158. package/dist/persona/types.js.map +1 -0
  159. package/dist/persona/zkp/engine.d.ts +26 -0
  160. package/dist/persona/zkp/engine.d.ts.map +1 -0
  161. package/dist/persona/zkp/engine.js +370 -0
  162. package/dist/persona/zkp/engine.js.map +1 -0
  163. package/dist/persona/zkp/types.d.ts +39 -0
  164. package/dist/persona/zkp/types.d.ts.map +1 -0
  165. package/dist/persona/zkp/types.js +2 -0
  166. package/dist/persona/zkp/types.js.map +1 -0
  167. package/dist/planner.d.ts +114 -0
  168. package/dist/planner.d.ts.map +1 -0
  169. package/dist/planner.js +522 -0
  170. package/dist/planner.js.map +1 -0
  171. package/dist/proactive/checkpoints.d.ts +9 -0
  172. package/dist/proactive/checkpoints.d.ts.map +1 -0
  173. package/dist/proactive/checkpoints.js +20 -0
  174. package/dist/proactive/checkpoints.js.map +1 -0
  175. package/dist/proactive/engine.d.ts +59 -0
  176. package/dist/proactive/engine.d.ts.map +1 -0
  177. package/dist/proactive/engine.js +406 -0
  178. package/dist/proactive/engine.js.map +1 -0
  179. package/dist/proactive/scheduler.d.ts +11 -0
  180. package/dist/proactive/scheduler.d.ts.map +1 -0
  181. package/dist/proactive/scheduler.js +45 -0
  182. package/dist/proactive/scheduler.js.map +1 -0
  183. package/dist/proactive/swarm-controller.d.ts +189 -0
  184. package/dist/proactive/swarm-controller.d.ts.map +1 -0
  185. package/dist/proactive/swarm-controller.js +477 -0
  186. package/dist/proactive/swarm-controller.js.map +1 -0
  187. package/dist/proactive/swarm-registry.d.ts +13 -0
  188. package/dist/proactive/swarm-registry.d.ts.map +1 -0
  189. package/dist/proactive/swarm-registry.js +122 -0
  190. package/dist/proactive/swarm-registry.js.map +1 -0
  191. package/dist/proactive/types.d.ts +145 -0
  192. package/dist/proactive/types.d.ts.map +1 -0
  193. package/dist/proactive/types.js +25 -0
  194. package/dist/proactive/types.js.map +1 -0
  195. package/dist/registry.d.ts +35 -0
  196. package/dist/registry.d.ts.map +1 -0
  197. package/dist/registry.js +88 -0
  198. package/dist/registry.js.map +1 -0
  199. package/dist/reputation.d.ts +123 -0
  200. package/dist/reputation.d.ts.map +1 -0
  201. package/dist/reputation.js +366 -0
  202. package/dist/reputation.js.map +1 -0
  203. package/dist/reputation.test.d.ts +5 -0
  204. package/dist/reputation.test.d.ts.map +1 -0
  205. package/dist/reputation.test.js +265 -0
  206. package/dist/reputation.test.js.map +1 -0
  207. package/dist/rooms.d.ts +96 -0
  208. package/dist/rooms.d.ts.map +1 -0
  209. package/dist/rooms.js +410 -0
  210. package/dist/rooms.js.map +1 -0
  211. package/dist/sdk/client.d.ts +290 -0
  212. package/dist/sdk/client.d.ts.map +1 -0
  213. package/dist/sdk/client.js +1287 -0
  214. package/dist/sdk/client.js.map +1 -0
  215. package/dist/sdk/index.d.ts +32 -0
  216. package/dist/sdk/index.d.ts.map +1 -0
  217. package/dist/sdk/index.js +70 -0
  218. package/dist/sdk/index.js.map +1 -0
  219. package/dist/security.d.ts +230 -0
  220. package/dist/security.d.ts.map +1 -0
  221. package/dist/security.js +652 -0
  222. package/dist/security.js.map +1 -0
  223. package/dist/skills/engine.d.ts +262 -0
  224. package/dist/skills/engine.d.ts.map +1 -0
  225. package/dist/skills/engine.js +788 -0
  226. package/dist/skills/engine.js.map +1 -0
  227. package/dist/skills/engine.test.d.ts +2 -0
  228. package/dist/skills/engine.test.d.ts.map +1 -0
  229. package/dist/skills/engine.test.js +134 -0
  230. package/dist/skills/engine.test.js.map +1 -0
  231. package/dist/skills/parser.d.ts +129 -0
  232. package/dist/skills/parser.d.ts.map +1 -0
  233. package/dist/skills/parser.js +318 -0
  234. package/dist/skills/parser.js.map +1 -0
  235. package/dist/social.d.ts +149 -0
  236. package/dist/social.d.ts.map +1 -0
  237. package/dist/social.js +401 -0
  238. package/dist/social.js.map +1 -0
  239. package/dist/storage-optimized.d.ts +116 -0
  240. package/dist/storage-optimized.d.ts.map +1 -0
  241. package/dist/storage-optimized.js +264 -0
  242. package/dist/storage-optimized.js.map +1 -0
  243. package/dist/storage.d.ts +584 -0
  244. package/dist/storage.d.ts.map +1 -0
  245. package/dist/storage.js +2703 -0
  246. package/dist/storage.js.map +1 -0
  247. package/dist/storage.test.d.ts +2 -0
  248. package/dist/storage.test.d.ts.map +1 -0
  249. package/dist/storage.test.js +78 -0
  250. package/dist/storage.test.js.map +1 -0
  251. package/dist/swp.d.ts +443 -0
  252. package/dist/swp.d.ts.map +1 -0
  253. package/dist/swp.js +223 -0
  254. package/dist/swp.js.map +1 -0
  255. package/dist/swp.test.d.ts +5 -0
  256. package/dist/swp.test.d.ts.map +1 -0
  257. package/dist/swp.test.js +127 -0
  258. package/dist/swp.test.js.map +1 -0
  259. package/dist/templates.d.ts +25 -0
  260. package/dist/templates.d.ts.map +1 -0
  261. package/dist/templates.js +1048 -0
  262. package/dist/templates.js.map +1 -0
  263. package/dist/test-e2e.d.ts +14 -0
  264. package/dist/test-e2e.d.ts.map +1 -0
  265. package/dist/test-e2e.js +266 -0
  266. package/dist/test-e2e.js.map +1 -0
  267. package/dist/workers/research-worker.d.ts +19 -0
  268. package/dist/workers/research-worker.d.ts.map +1 -0
  269. package/dist/workers/research-worker.js +141 -0
  270. package/dist/workers/research-worker.js.map +1 -0
  271. package/package.json +110 -0
@@ -0,0 +1,652 @@
1
+ /**
2
+ * Society Protocol - Advanced Security Layer v1.0
3
+ *
4
+ * Camada de segurança aprimorada:
5
+ * - End-to-end encryption (E2EE)
6
+ * - Key rotation automático
7
+ * - Permission system granular
8
+ * - Audit logging
9
+ * - Rate limiting avançado
10
+ * - Content sanitization
11
+ * - DDoS protection
12
+ * - Threat detection
13
+ */
14
+ import { createHash, randomBytes, createCipheriv, createDecipheriv } from 'crypto';
15
+ import { promisify } from 'util';
16
+ import { sign as identitySign, verify as identityVerify } from './identity.js';
17
+ const randomBytesAsync = promisify(randomBytes);
18
+ // ─── End-to-End Encryption ───────────────────────────────────────
19
+ export class E2EEncryption {
20
+ keys = new Map();
21
+ sharedSecrets = new Map();
22
+ config;
23
+ constructor(config) {
24
+ this.config = {
25
+ algorithm: config?.algorithm || 'aes-256-gcm',
26
+ keyRotationInterval: config?.keyRotationInterval || 24 * 60 * 60 * 1000, // 24h
27
+ forwardSecrecy: config?.forwardSecrecy ?? true
28
+ };
29
+ // Rotacionar chaves periodicamente
30
+ setInterval(() => this.rotateKeys(), this.config.keyRotationInterval);
31
+ }
32
+ /**
33
+ * Gerar par de chaves X25519 para Diffie-Hellman
34
+ */
35
+ async generateKeyPair(identityId) {
36
+ // Usar Web Crypto API
37
+ const keyPair = await crypto.subtle.generateKey({
38
+ name: 'X25519'
39
+ }, true, // extractable
40
+ ['deriveBits']);
41
+ this.keys.set(identityId, keyPair);
42
+ return keyPair;
43
+ }
44
+ /**
45
+ * Derivar segredo compartilhado com outro participante
46
+ */
47
+ async deriveSharedSecret(myId, theirPublicKey) {
48
+ const myKeyPair = this.keys.get(myId);
49
+ if (!myKeyPair) {
50
+ throw new Error('Key pair not found');
51
+ }
52
+ // Importar chave pública do outro
53
+ const theirKey = await crypto.subtle.importKey('raw', theirPublicKey, { name: 'X25519' }, false, []);
54
+ // Derivar segredo
55
+ const sharedSecret = await crypto.subtle.deriveBits({
56
+ name: 'X25519',
57
+ public: theirKey
58
+ }, myKeyPair.privateKey, 256);
59
+ const secret = new Uint8Array(sharedSecret);
60
+ // Derivar chave de criptografia
61
+ const key = await this.deriveEncryptionKey(secret);
62
+ const cacheKey = `${myId}:${Buffer.from(theirPublicKey).toString('hex')}`;
63
+ this.sharedSecrets.set(cacheKey, key);
64
+ return key;
65
+ }
66
+ /**
67
+ * Criptografar mensagem
68
+ */
69
+ async encrypt(plaintext, recipientPublicKey, senderId) {
70
+ const key = await this.deriveSharedSecret(senderId, recipientPublicKey);
71
+ // Gerar nonce
72
+ const nonce = await randomBytesAsync(12);
73
+ // Criptografar
74
+ const data = new TextEncoder().encode(plaintext);
75
+ let ciphertext;
76
+ if (this.config.algorithm === 'aes-256-gcm') {
77
+ // Usar AES-256-GCM via Node.js crypto
78
+ const cipher = createCipheriv('aes-256-gcm', key.slice(0, 32), nonce);
79
+ const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
80
+ const authTag = cipher.getAuthTag();
81
+ ciphertext = new Uint8Array(Buffer.concat([encrypted, authTag]));
82
+ }
83
+ else {
84
+ throw new Error(`Unsupported encryption algorithm: ${this.config.algorithm}`);
85
+ }
86
+ return { ciphertext, nonce };
87
+ }
88
+ /**
89
+ * Descriptografar mensagem
90
+ */
91
+ async decrypt(ciphertext, nonce, senderPublicKey, recipientId) {
92
+ const key = await this.deriveSharedSecret(recipientId, senderPublicKey);
93
+ let plaintext;
94
+ if (this.config.algorithm === 'aes-256-gcm') {
95
+ const decipher = createDecipheriv('aes-256-gcm', key.slice(0, 32), nonce);
96
+ const authTag = ciphertext.slice(-16);
97
+ decipher.setAuthTag(authTag);
98
+ const encrypted = ciphertext.slice(0, -16);
99
+ plaintext = new Uint8Array(Buffer.concat([
100
+ decipher.update(encrypted),
101
+ decipher.final()
102
+ ]));
103
+ }
104
+ else {
105
+ throw new Error(`Unsupported encryption algorithm: ${this.config.algorithm}`);
106
+ }
107
+ return new TextDecoder().decode(plaintext);
108
+ }
109
+ async deriveEncryptionKey(sharedSecret) {
110
+ // HKDF via Web Crypto API (RFC 5869)
111
+ // Use a deterministic salt derived from the shared secret itself,
112
+ // so both sides derive the same key from the same DH output.
113
+ const ikm = await crypto.subtle.importKey('raw', sharedSecret, 'HKDF', false, ['deriveBits']);
114
+ const salt = createHash('sha256').update('society-hkdf-salt-v1').digest();
115
+ const info = new TextEncoder().encode('society-protocol-e2e-v1');
116
+ const derived = await crypto.subtle.deriveBits({
117
+ name: 'HKDF',
118
+ hash: 'SHA-256',
119
+ salt,
120
+ info,
121
+ }, ikm, 256 // 32 bytes
122
+ );
123
+ return new Uint8Array(derived);
124
+ }
125
+ async xorWithKey(data, key) {
126
+ const result = new Uint8Array(data.length);
127
+ for (let i = 0; i < data.length; i++) {
128
+ result[i] = data[i] ^ key[i % key.length];
129
+ }
130
+ return result;
131
+ }
132
+ rotateKeys() {
133
+ // Implementar rotação de chaves
134
+ console.log('[security] Rotating encryption keys...');
135
+ if (this.config.forwardSecrecy) {
136
+ // Limpar segredos antigos
137
+ this.sharedSecrets.clear();
138
+ }
139
+ }
140
+ }
141
+ // ─── Permission System ───────────────────────────────────────────
142
+ export class PermissionManager {
143
+ roles = new Map();
144
+ userPermissions = new Map();
145
+ acl = new Map(); // resource -> Set<did>
146
+ constructor() {
147
+ this.setupDefaultRoles();
148
+ }
149
+ setupDefaultRoles() {
150
+ this.roles.set('guest', [
151
+ { resource: 'room:*', action: 'read' },
152
+ { resource: 'message:*', action: 'read' }
153
+ ]);
154
+ this.roles.set('member', [
155
+ { resource: 'room:*', action: 'read' },
156
+ { resource: 'room:*', action: 'write' },
157
+ { resource: 'message:*', action: 'read' },
158
+ { resource: 'message:*', action: 'write' },
159
+ { resource: 'coc:*', action: 'execute' }
160
+ ]);
161
+ this.roles.set('moderator', [
162
+ { resource: '*', action: 'read' },
163
+ { resource: 'room:*', action: 'admin' },
164
+ { resource: 'member:*', action: 'admin' },
165
+ { resource: 'message:*', action: 'admin' }
166
+ ]);
167
+ this.roles.set('admin', [
168
+ { resource: '*', action: 'admin' }
169
+ ]);
170
+ }
171
+ /**
172
+ * Verificar se usuário tem permissão
173
+ */
174
+ checkPermission(context, resource, action) {
175
+ // Verificar permissões diretas
176
+ const userPerms = this.userPermissions.get(context.identity.did) || [];
177
+ if (this.hasMatchingPermission(userPerms, resource, action)) {
178
+ return this.checkConditions(context, userPerms, resource, action);
179
+ }
180
+ // Verificar via roles
181
+ // TODO: Implementar sistema de roles vinculado ao context
182
+ return false;
183
+ }
184
+ /**
185
+ * Conceder permissão a usuário
186
+ */
187
+ grantPermission(did, permission) {
188
+ if (!this.userPermissions.has(did)) {
189
+ this.userPermissions.set(did, []);
190
+ }
191
+ this.userPermissions.get(did).push(permission);
192
+ }
193
+ /**
194
+ * Revogar permissão
195
+ */
196
+ revokePermission(did, resource, action) {
197
+ const perms = this.userPermissions.get(did);
198
+ if (!perms)
199
+ return;
200
+ const filtered = perms.filter(p => !(p.resource === resource && p.action === action));
201
+ this.userPermissions.set(did, filtered);
202
+ }
203
+ /**
204
+ * Verificar ACL de recurso
205
+ */
206
+ checkACL(resource, did) {
207
+ const allowed = this.acl.get(resource);
208
+ if (!allowed)
209
+ return true; // Sem ACL = aberto
210
+ return allowed.has(did) || allowed.has('*');
211
+ }
212
+ /**
213
+ * Adicionar entrada ACL
214
+ */
215
+ addToACL(resource, did) {
216
+ if (!this.acl.has(resource)) {
217
+ this.acl.set(resource, new Set());
218
+ }
219
+ this.acl.get(resource).add(did);
220
+ }
221
+ hasMatchingPermission(permissions, resource, action) {
222
+ return permissions.some(p => {
223
+ const resourceMatch = this.matchResource(p.resource, resource);
224
+ const actionMatch = p.action === action || p.action === 'admin';
225
+ return resourceMatch && actionMatch;
226
+ });
227
+ }
228
+ matchPermission(pattern, resource) {
229
+ // Suportar wildcards: room:*:message → room:abc123:message
230
+ const regex = new RegExp('^' + pattern.replace(/\*/g, '[^:]*') + '$');
231
+ return regex.test(resource);
232
+ }
233
+ matchResource(pattern, resource) {
234
+ if (pattern === '*')
235
+ return true;
236
+ if (pattern === resource)
237
+ return true;
238
+ // Wildcard: room:*:message
239
+ const regex = new RegExp('^' + pattern.replace(/\*/g, '[^:]*') + '$');
240
+ return regex.test(resource);
241
+ }
242
+ checkConditions(context, permissions, resource, action) {
243
+ const perm = permissions.find(p => this.matchResource(p.resource, resource) &&
244
+ (p.action === action || p.action === 'admin'));
245
+ if (!perm?.conditions)
246
+ return true;
247
+ const cond = perm.conditions;
248
+ // Verificar time window
249
+ if (cond.timeWindow) {
250
+ const now = Date.now();
251
+ if (now < cond.timeWindow.start || now > cond.timeWindow.end) {
252
+ return false;
253
+ }
254
+ }
255
+ // Verificar IP whitelist
256
+ if (cond.ipWhitelist && context.ip) {
257
+ if (!cond.ipWhitelist.includes(context.ip)) {
258
+ return false;
259
+ }
260
+ }
261
+ // Verificar reputação mínima
262
+ if (cond.reputationMin && context.reputation < cond.reputationMin) {
263
+ return false;
264
+ }
265
+ // Verificar MFA
266
+ if (cond.mfaRequired && !context.mfaVerified) {
267
+ return false;
268
+ }
269
+ return true;
270
+ }
271
+ }
272
+ // ─── Audit Logger ────────────────────────────────────────────────
273
+ export class AuditLogger {
274
+ events = [];
275
+ maxSize;
276
+ listeners = [];
277
+ constructor(maxSize = 10000) {
278
+ this.maxSize = maxSize;
279
+ }
280
+ async log(event) {
281
+ const fullEvent = {
282
+ id: `audit_${Date.now()}_${randomBytes(4).toString('hex')}`,
283
+ timestamp: Date.now(),
284
+ ...event
285
+ };
286
+ // Assinar evento para integridade
287
+ fullEvent.signature = await this.signEvent(fullEvent);
288
+ this.events.push(fullEvent);
289
+ // Manter tamanho limitado
290
+ if (this.events.length > this.maxSize) {
291
+ this.events = this.events.slice(-this.maxSize);
292
+ }
293
+ // Notificar listeners
294
+ for (const listener of this.listeners) {
295
+ listener(fullEvent);
296
+ }
297
+ }
298
+ query(filters) {
299
+ let results = this.events;
300
+ if (filters.type) {
301
+ results = results.filter(e => e.type === filters.type);
302
+ }
303
+ if (filters.actor) {
304
+ results = results.filter(e => e.actor === filters.actor);
305
+ }
306
+ if (filters.resource) {
307
+ results = results.filter(e => e.resource === filters.resource);
308
+ }
309
+ if (filters.severity) {
310
+ results = results.filter(e => e.severity === filters.severity);
311
+ }
312
+ if (filters.startTime) {
313
+ results = results.filter(e => e.timestamp >= filters.startTime);
314
+ }
315
+ if (filters.endTime) {
316
+ results = results.filter(e => e.timestamp <= filters.endTime);
317
+ }
318
+ // Ordenar por timestamp decrescente
319
+ results.sort((a, b) => b.timestamp - a.timestamp);
320
+ return results.slice(0, filters.limit || 100);
321
+ }
322
+ onEvent(listener) {
323
+ this.listeners.push(listener);
324
+ }
325
+ async signEvent(event) {
326
+ const data = JSON.stringify({
327
+ type: event.type,
328
+ actor: event.actor,
329
+ resource: event.resource,
330
+ action: event.action,
331
+ timestamp: event.timestamp
332
+ });
333
+ return createHash('sha256').update(data).digest('hex');
334
+ }
335
+ }
336
+ // ─── Threat Detection ────────────────────────────────────────────
337
+ export class ThreatDetector {
338
+ threatIntel = new Map();
339
+ patterns = new Map();
340
+ behaviorScores = new Map();
341
+ constructor() {
342
+ this.setupPatterns();
343
+ }
344
+ setupPatterns() {
345
+ // Padrões de ameaça
346
+ this.patterns.set('spam', /\b(viagra|casino|lottery|winner)\b/gi);
347
+ this.patterns.set('suspicious_links', /https?:\/\/[^\s]{100,}/gi);
348
+ this.patterns.set('credential_harvest', /\b(password|login|credential)\s*=\s*/gi);
349
+ }
350
+ /**
351
+ * Analisar envelope para ameaças
352
+ */
353
+ analyzeEnvelope(envelope) {
354
+ const checks = [
355
+ this.checkKnownThreats(envelope.from.did),
356
+ this.checkContentPatterns(envelope),
357
+ this.checkBehaviorAnomalies(envelope.from.did),
358
+ this.checkRateAnomalies(envelope.from.did)
359
+ ];
360
+ const highestThreat = checks
361
+ .filter(c => c.threat)
362
+ .sort((a, b) => this.severityRank(b.severity) - this.severityRank(a.severity))[0];
363
+ return highestThreat || { threat: false, severity: 'low' };
364
+ }
365
+ /**
366
+ * Reportar ameaça
367
+ */
368
+ reportThreat(threat) {
369
+ const existing = this.threatIntel.get(threat.value);
370
+ if (existing) {
371
+ existing.lastSeen = Date.now();
372
+ existing.occurrences++;
373
+ existing.confidence = Math.min(1, existing.confidence + 0.1);
374
+ }
375
+ else {
376
+ const newThreat = {
377
+ ...threat,
378
+ firstSeen: Date.now(),
379
+ lastSeen: Date.now(),
380
+ occurrences: 1
381
+ };
382
+ this.threatIntel.set(threat.value, newThreat);
383
+ }
384
+ }
385
+ /**
386
+ * Verificar se está na lista de ameaças
387
+ */
388
+ isThreat(value) {
389
+ return this.threatIntel.get(value);
390
+ }
391
+ checkKnownThreats(did) {
392
+ const threat = this.threatIntel.get(did);
393
+ if (threat) {
394
+ return {
395
+ threat: true,
396
+ severity: threat.severity,
397
+ category: threat.category,
398
+ reason: `Known threat: ${threat.category}`
399
+ };
400
+ }
401
+ return { threat: false, severity: 'low' };
402
+ }
403
+ checkContentPatterns(envelope) {
404
+ const bodyStr = JSON.stringify(envelope.body);
405
+ for (const [category, pattern] of this.patterns) {
406
+ if (pattern.test(bodyStr)) {
407
+ return {
408
+ threat: true,
409
+ severity: 'medium',
410
+ category: category,
411
+ reason: `Pattern match: ${category}`
412
+ };
413
+ }
414
+ }
415
+ return { threat: false, severity: 'low' };
416
+ }
417
+ checkBehaviorAnomalies(did) {
418
+ const behavior = this.behaviorScores.get(did);
419
+ if (!behavior)
420
+ return { threat: false, severity: 'low' };
421
+ // Score anormalmente alto = possível Sybil ou ataque
422
+ if (behavior.score > 100) {
423
+ return {
424
+ threat: true,
425
+ severity: 'high',
426
+ category: 'sybil',
427
+ reason: 'Behavioral anomaly detected'
428
+ };
429
+ }
430
+ return { threat: false, severity: 'low' };
431
+ }
432
+ checkRateAnomalies(did) {
433
+ const behavior = this.behaviorScores.get(did);
434
+ if (!behavior)
435
+ return { threat: false, severity: 'low' };
436
+ // Muitos eventos em curto período
437
+ const recentEvents = behavior.events.filter(t => Date.now() - t < 60000);
438
+ if (recentEvents.length > 100) {
439
+ return {
440
+ threat: true,
441
+ severity: 'high',
442
+ category: 'ddos',
443
+ reason: 'Rate limit exceeded'
444
+ };
445
+ }
446
+ return { threat: false, severity: 'low' };
447
+ }
448
+ updateBehaviorScore(did, delta) {
449
+ if (!this.behaviorScores.has(did)) {
450
+ this.behaviorScores.set(did, { score: 0, events: [] });
451
+ }
452
+ const behavior = this.behaviorScores.get(did);
453
+ behavior.score += delta;
454
+ behavior.events.push(Date.now());
455
+ // Limpar eventos antigos
456
+ behavior.events = behavior.events.filter(t => Date.now() - t < 3600000);
457
+ }
458
+ severityRank(severity) {
459
+ const ranks = { low: 1, medium: 2, high: 3, critical: 4 };
460
+ return ranks[severity];
461
+ }
462
+ }
463
+ // ─── Content Sanitizer ───────────────────────────────────────────
464
+ export class ContentSanitizer {
465
+ allowedTags = new Set(['b', 'i', 'u', 'code', 'pre', 'a']);
466
+ allowedSchemes = new Set(['http', 'https', 'mailto']);
467
+ /**
468
+ * Sanitizar conteúdo HTML/Markdown
469
+ */
470
+ sanitize(input) {
471
+ let sanitized = input;
472
+ // Remover scripts e eventos
473
+ sanitized = sanitized.replace(/<script[^>]*>.*?<\/script>/gi, '');
474
+ sanitized = sanitized.replace(/on\w+\s*=\s*["'][^"']*["']/gi, '');
475
+ sanitized = sanitized.replace(/javascript:/gi, '');
476
+ // Validar links
477
+ sanitized = sanitized.replace(/href=["']([^"']*)["']/gi, (match, url) => {
478
+ try {
479
+ const parsed = new URL(url);
480
+ if (this.allowedSchemes.has(parsed.protocol.slice(0, -1))) {
481
+ return match;
482
+ }
483
+ }
484
+ catch {
485
+ // URL relativa - permitir
486
+ return match;
487
+ }
488
+ return 'href="#"';
489
+ });
490
+ // Limitar tamanho
491
+ if (sanitized.length > 10000) {
492
+ sanitized = sanitized.slice(0, 10000) + '... [truncated]';
493
+ }
494
+ return sanitized;
495
+ }
496
+ /**
497
+ * Validar e normalizar input
498
+ */
499
+ normalize(input) {
500
+ // Normalizar Unicode
501
+ let normalized = input.normalize('NFC');
502
+ // Remover caracteres de controle (exceto whitespace)
503
+ normalized = normalized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '');
504
+ // Normalizar whitespace
505
+ normalized = normalized.replace(/\s+/g, ' ').trim();
506
+ return normalized;
507
+ }
508
+ }
509
+ // ─── Security Manager ────────────────────────────────────────────
510
+ export class SecurityManager {
511
+ encryption;
512
+ permissions;
513
+ audit;
514
+ threats;
515
+ sanitizer;
516
+ identity;
517
+ localEncryptionId;
518
+ localEncryptionPublicKey;
519
+ localKeyGenerated = false;
520
+ constructor(identityOrConfig) {
521
+ const hasIdentity = this.isIdentity(identityOrConfig);
522
+ this.identity = hasIdentity ? identityOrConfig : undefined;
523
+ const config = hasIdentity ? undefined : identityOrConfig;
524
+ this.encryption = new E2EEncryption(config?.encryption);
525
+ this.permissions = new PermissionManager();
526
+ this.audit = new AuditLogger();
527
+ this.threats = new ThreatDetector();
528
+ this.sanitizer = new ContentSanitizer();
529
+ if (this.identity) {
530
+ this.localEncryptionId = this.identity.did;
531
+ }
532
+ }
533
+ /**
534
+ * Pipeline completo de segurança para mensagem
535
+ */
536
+ async processIncoming(envelope) {
537
+ // 1. Verificar ameaças
538
+ const threatCheck = this.threats.analyzeEnvelope(envelope);
539
+ if (threatCheck.threat && threatCheck.severity === 'critical') {
540
+ await this.audit.log({
541
+ type: 'violation',
542
+ severity: 'critical',
543
+ actor: envelope.from.did,
544
+ resource: 'network',
545
+ action: 'receive',
546
+ result: 'blocked',
547
+ details: { threat: threatCheck }
548
+ });
549
+ return { allowed: false, reason: threatCheck.reason };
550
+ }
551
+ // 2. Sanitizar conteúdo
552
+ const sanitizedBody = this.sanitizer.sanitize(JSON.stringify(envelope.body));
553
+ const sanitized = {
554
+ ...envelope,
555
+ body: JSON.parse(sanitizedBody)
556
+ };
557
+ // 3. Auditar
558
+ await this.audit.log({
559
+ type: 'access',
560
+ severity: 'info',
561
+ actor: envelope.from.did,
562
+ resource: `room:${envelope.room}`,
563
+ action: 'receive',
564
+ result: 'success',
565
+ details: { messageType: envelope.t }
566
+ });
567
+ return { allowed: true, sanitized };
568
+ }
569
+ /**
570
+ * Verificar permissão completa
571
+ */
572
+ async checkAccess(context, resource, action) {
573
+ // Verificar permissão
574
+ const hasPermission = this.permissions.checkPermission(context, resource, action);
575
+ if (!hasPermission) {
576
+ await this.audit.log({
577
+ type: 'access',
578
+ severity: 'warning',
579
+ actor: context.identity.did,
580
+ resource,
581
+ action,
582
+ result: 'blocked',
583
+ details: { reason: 'permission_denied' }
584
+ });
585
+ return false;
586
+ }
587
+ return true;
588
+ }
589
+ // ─── Compatibility Wrappers ───────────────────────────────────
590
+ async generateKeyPair(identityId) {
591
+ const id = identityId || this.localEncryptionId || this.identity?.did || `sec_${Date.now()}`;
592
+ const keyPair = await this.encryption.generateKeyPair(id);
593
+ if (!this.localEncryptionId) {
594
+ this.localEncryptionId = id;
595
+ }
596
+ if (id === this.localEncryptionId) {
597
+ this.localEncryptionId = id;
598
+ const exported = await crypto.subtle.exportKey('raw', keyPair.publicKey);
599
+ this.localEncryptionPublicKey = new Uint8Array(exported);
600
+ this.localKeyGenerated = true;
601
+ }
602
+ return keyPair;
603
+ }
604
+ async sign(message) {
605
+ if (!this.identity) {
606
+ throw new Error('Identity is required for signing');
607
+ }
608
+ const msgBase64 = Buffer.from(message).toString('base64');
609
+ const signatureBase64 = identitySign(this.identity, msgBase64);
610
+ return new Uint8Array(Buffer.from(signatureBase64, 'base64'));
611
+ }
612
+ async verify(message, signature, publicKey) {
613
+ const msgBase64 = Buffer.from(message).toString('base64');
614
+ const signatureBase64 = Buffer.from(signature).toString('base64');
615
+ return identityVerify(publicKey, msgBase64, signatureBase64);
616
+ }
617
+ async encrypt(plaintext, recipientPublicKey) {
618
+ const senderId = await this.ensureEncryptionIdentity();
619
+ const encodedPlaintext = Buffer.from(plaintext).toString('base64');
620
+ const encrypted = await this.encryption.encrypt(encodedPlaintext, recipientPublicKey, senderId);
621
+ if (!this.localEncryptionPublicKey) {
622
+ throw new Error('Missing sender public key');
623
+ }
624
+ return {
625
+ ...encrypted,
626
+ senderPublicKey: this.localEncryptionPublicKey
627
+ };
628
+ }
629
+ async decrypt(message) {
630
+ const recipientId = await this.ensureEncryptionIdentity();
631
+ const decoded = await this.encryption.decrypt(message.ciphertext, message.nonce, message.senderPublicKey, recipientId);
632
+ return new Uint8Array(Buffer.from(decoded, 'base64'));
633
+ }
634
+ isIdentity(value) {
635
+ if (!value || typeof value !== 'object')
636
+ return false;
637
+ const candidate = value;
638
+ return (typeof candidate.did === 'string' &&
639
+ candidate.privateKey instanceof Uint8Array &&
640
+ candidate.publicKey instanceof Uint8Array);
641
+ }
642
+ async ensureEncryptionIdentity() {
643
+ const senderId = this.localEncryptionId || this.identity?.did || `sec_${Date.now()}`;
644
+ this.localEncryptionId = senderId;
645
+ if (!this.localKeyGenerated) {
646
+ await this.generateKeyPair(senderId);
647
+ }
648
+ return senderId;
649
+ }
650
+ }
651
+ // Classes already exported via 'export class'
652
+ //# sourceMappingURL=security.js.map