shogun-core 6.2.3 → 6.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.
Files changed (233) hide show
  1. package/dist/browser/defaultVendors-node_modules_noble_curves_esm_ed448_js.shogun-core.js +93 -341
  2. package/dist/browser/defaultVendors-node_modules_noble_curves_esm_ed448_js.shogun-core.js.map +1 -1
  3. package/dist/browser/shogun-core.js +138850 -146638
  4. package/dist/browser/shogun-core.js.map +1 -1
  5. package/dist/{core.js → src/core.js} +167 -107
  6. package/dist/src/crypto/asymmetric.js +168 -0
  7. package/dist/src/crypto/double-ratchet.js +908 -0
  8. package/dist/src/crypto/file-encryption.js +352 -0
  9. package/dist/src/crypto/hashing.js +160 -0
  10. package/dist/src/crypto/index.js +18 -0
  11. package/dist/{crypto → src/crypto}/mls-codec.js +24 -34
  12. package/dist/src/crypto/mls.js +734 -0
  13. package/dist/src/crypto/pgp.js +619 -0
  14. package/dist/{crypto → src/crypto}/random-generation.js +125 -103
  15. package/dist/src/crypto/sframe.js +466 -0
  16. package/dist/src/crypto/signal-protocol.js +943 -0
  17. package/dist/src/crypto/symmetric.js +165 -0
  18. package/dist/src/crypto/utils.js +220 -0
  19. package/dist/src/examples/auth-test.js +535 -0
  20. package/dist/src/examples/crypto-identity-example.js +294 -0
  21. package/dist/src/examples/crypto-working-test.js +149 -0
  22. package/dist/src/examples/double-ratchet-test.js +240 -0
  23. package/dist/src/examples/mls-3-member-test.js +183 -0
  24. package/dist/src/examples/mls-multi-member.js +439 -0
  25. package/dist/src/examples/mls-sframe-test.js +491 -0
  26. package/dist/src/examples/mls-simple-test.js +122 -0
  27. package/dist/src/examples/pgp-example.js +354 -0
  28. package/dist/src/examples/random-generation-test.js +191 -0
  29. package/dist/src/examples/shogun-core-example.js +204 -0
  30. package/dist/src/examples/signal-protocol-test.js +82 -0
  31. package/dist/src/examples/zkproof-credentials-example.js +357 -0
  32. package/dist/src/examples/zkproof-example.js +357 -0
  33. package/dist/src/gundb/crypto.js +420 -0
  34. package/dist/src/gundb/db.js +728 -0
  35. package/dist/src/gundb/derive.js +327 -0
  36. package/dist/src/gundb/errors.js +115 -0
  37. package/dist/src/gundb/gun-es.js +8 -0
  38. package/dist/src/gundb/index.js +5 -0
  39. package/dist/{gundb → src/gundb}/rxjs.js +147 -111
  40. package/dist/{gundb → src/gundb}/types.js +1 -2
  41. package/dist/src/index.js +19 -0
  42. package/dist/src/interfaces/events.js +57 -0
  43. package/dist/{interfaces → src/interfaces}/shogun.js +4 -7
  44. package/dist/src/managers/AuthManager.js +301 -0
  45. package/dist/src/managers/CoreInitializer.js +304 -0
  46. package/dist/src/managers/CryptoIdentityManager.js +230 -0
  47. package/dist/{managers → src/managers}/EventManager.js +19 -21
  48. package/dist/{managers → src/managers}/PluginManager.js +123 -89
  49. package/dist/src/plugins/base.js +90 -0
  50. package/dist/src/plugins/index.js +17 -0
  51. package/dist/src/plugins/nostr/index.js +4 -0
  52. package/dist/src/plugins/nostr/nostrConnector.js +539 -0
  53. package/dist/src/plugins/nostr/nostrConnectorPlugin.js +663 -0
  54. package/dist/src/plugins/nostr/nostrSigner.js +414 -0
  55. package/dist/src/plugins/smartwallet/index.js +2 -0
  56. package/dist/src/plugins/smartwallet/smartWalletPlugin.js +824 -0
  57. package/dist/src/plugins/web3/index.js +4 -0
  58. package/dist/src/plugins/web3/types.js +1 -0
  59. package/dist/src/plugins/web3/web3Connector.js +738 -0
  60. package/dist/src/plugins/web3/web3ConnectorPlugin.js +639 -0
  61. package/dist/src/plugins/web3/web3Signer.js +432 -0
  62. package/dist/src/plugins/webauthn/index.js +3 -0
  63. package/dist/{plugins → src/plugins}/webauthn/types.js +2 -5
  64. package/dist/src/plugins/webauthn/webauthn.js +647 -0
  65. package/dist/src/plugins/webauthn/webauthnPlugin.js +689 -0
  66. package/dist/src/plugins/webauthn/webauthnSigner.js +419 -0
  67. package/dist/{plugins → src/plugins}/zkproof/index.js +3 -10
  68. package/dist/src/plugins/zkproof/types.js +1 -0
  69. package/dist/src/plugins/zkproof/zkCredentials.js +287 -0
  70. package/dist/src/plugins/zkproof/zkProofConnector.js +267 -0
  71. package/dist/src/plugins/zkproof/zkProofPlugin.js +405 -0
  72. package/dist/src/storage/storage.js +189 -0
  73. package/dist/src/utils/errorHandler.js +339 -0
  74. package/dist/{utils → src/utils}/eventEmitter.js +26 -26
  75. package/dist/{utils → src/utils}/seedPhrase.js +23 -32
  76. package/dist/{utils → src/utils}/validation.js +14 -21
  77. package/dist/tsconfig.tsbuildinfo +1 -0
  78. package/dist/types/{crypto → src/crypto}/double-ratchet.d.ts +1 -1
  79. package/dist/types/{crypto → src/crypto}/signal-protocol.d.ts +25 -0
  80. package/dist/types/{crypto → src/crypto}/types.d.ts +3 -1
  81. package/dist/types/src/examples/crypto-working-test.d.ts +1 -0
  82. package/dist/types/src/examples/double-ratchet-test.d.ts +1 -0
  83. package/dist/types/src/examples/mls-sframe-test.d.ts +1 -0
  84. package/dist/types/src/examples/random-generation-test.d.ts +1 -0
  85. package/dist/types/src/examples/signal-protocol-test.d.ts +1 -0
  86. package/dist/types/{gundb → src/gundb}/db.d.ts +14 -1
  87. package/dist/types/src/gundb/gun-es.d.ts +8 -0
  88. package/dist/types/src/gundb/min.d.ts +3 -0
  89. package/dist/types/{index.d.ts → src/index.d.ts} +1 -0
  90. package/package.json +14 -11
  91. package/dist/browser/defaultVendors-node_modules_noble_curves_esm_abstract_curve_js-node_modules_noble_curves_esm_-1ce4ed.shogun-core.js +0 -1651
  92. package/dist/browser/defaultVendors-node_modules_noble_curves_esm_abstract_curve_js-node_modules_noble_curves_esm_-1ce4ed.shogun-core.js.map +0 -1
  93. package/dist/browser/defaultVendors-node_modules_noble_curves_esm_nist_js.shogun-core.js +0 -1608
  94. package/dist/browser/defaultVendors-node_modules_noble_curves_esm_nist_js.shogun-core.js.map +0 -1
  95. package/dist/crypto/asymmetric.js +0 -99
  96. package/dist/crypto/double-ratchet.js +0 -370
  97. package/dist/crypto/file-encryption.js +0 -213
  98. package/dist/crypto/hashing.js +0 -87
  99. package/dist/crypto/index.js +0 -34
  100. package/dist/crypto/mls.js +0 -569
  101. package/dist/crypto/pgp.js +0 -390
  102. package/dist/crypto/sframe.js +0 -352
  103. package/dist/crypto/signal-protocol.js +0 -456
  104. package/dist/crypto/symmetric.js +0 -91
  105. package/dist/crypto/types.js +0 -2
  106. package/dist/crypto/utils.js +0 -140
  107. package/dist/examples/auth-test.js +0 -453
  108. package/dist/examples/crypto-identity-example.js +0 -196
  109. package/dist/examples/crypto-working-test.js +0 -83
  110. package/dist/examples/double-ratchet-test.js +0 -155
  111. package/dist/examples/mls-3-member-test.js +0 -97
  112. package/dist/examples/mls-multi-member.js +0 -153
  113. package/dist/examples/mls-sframe-test.js +0 -307
  114. package/dist/examples/mls-simple-test.js +0 -58
  115. package/dist/examples/pgp-example.js +0 -200
  116. package/dist/examples/random-generation-test.js +0 -151
  117. package/dist/examples/shogun-core-example.js +0 -150
  118. package/dist/examples/signal-protocol-test.js +0 -38
  119. package/dist/examples/zkproof-credentials-example.js +0 -217
  120. package/dist/examples/zkproof-example.js +0 -242
  121. package/dist/gundb/crypto.js +0 -306
  122. package/dist/gundb/db.js +0 -485
  123. package/dist/gundb/derive.js +0 -232
  124. package/dist/gundb/errors.js +0 -76
  125. package/dist/gundb/gun-es.js +0 -12
  126. package/dist/gundb/index.js +0 -21
  127. package/dist/gundb/min.js +0 -10
  128. package/dist/index.esm.js +0 -22
  129. package/dist/index.js +0 -47
  130. package/dist/interfaces/common.js +0 -2
  131. package/dist/interfaces/events.js +0 -40
  132. package/dist/interfaces/plugin.js +0 -2
  133. package/dist/managers/AuthManager.js +0 -226
  134. package/dist/managers/CoreInitializer.js +0 -250
  135. package/dist/managers/CryptoIdentityManager.js +0 -138
  136. package/dist/plugins/base.js +0 -50
  137. package/dist/plugins/index.js +0 -32
  138. package/dist/plugins/nostr/index.js +0 -20
  139. package/dist/plugins/nostr/nostrConnector.js +0 -419
  140. package/dist/plugins/nostr/nostrConnectorPlugin.js +0 -453
  141. package/dist/plugins/nostr/nostrSigner.js +0 -319
  142. package/dist/plugins/nostr/types.js +0 -2
  143. package/dist/plugins/smartwallet/index.js +0 -18
  144. package/dist/plugins/smartwallet/smartWalletPlugin.js +0 -511
  145. package/dist/plugins/smartwallet/types.js +0 -2
  146. package/dist/plugins/web3/index.js +0 -20
  147. package/dist/plugins/web3/types.js +0 -2
  148. package/dist/plugins/web3/web3Connector.js +0 -533
  149. package/dist/plugins/web3/web3ConnectorPlugin.js +0 -455
  150. package/dist/plugins/web3/web3Signer.js +0 -314
  151. package/dist/plugins/webauthn/index.js +0 -19
  152. package/dist/plugins/webauthn/webauthn.js +0 -496
  153. package/dist/plugins/webauthn/webauthnPlugin.js +0 -490
  154. package/dist/plugins/webauthn/webauthnSigner.js +0 -310
  155. package/dist/plugins/zkproof/types.js +0 -2
  156. package/dist/plugins/zkproof/zkCredentials.js +0 -216
  157. package/dist/plugins/zkproof/zkProofConnector.js +0 -198
  158. package/dist/plugins/zkproof/zkProofPlugin.js +0 -272
  159. package/dist/storage/storage.js +0 -145
  160. package/dist/types/gundb/gun-es.d.ts +0 -8
  161. package/dist/utils/errorHandler.js +0 -246
  162. /package/dist/{types/examples/crypto-working-test.d.ts → src/crypto/types.js} +0 -0
  163. /package/dist/{types/gundb/min.d.ts → src/gundb/min.js} +0 -0
  164. /package/dist/{types/examples/double-ratchet-test.d.ts → src/interfaces/common.js} +0 -0
  165. /package/dist/{types/examples/mls-sframe-test.d.ts → src/interfaces/plugin.js} +0 -0
  166. /package/dist/{types/examples/random-generation-test.d.ts → src/plugins/nostr/types.js} +0 -0
  167. /package/dist/{types/examples/signal-protocol-test.d.ts → src/plugins/smartwallet/types.js} +0 -0
  168. /package/dist/types/{core.d.ts → src/core.d.ts} +0 -0
  169. /package/dist/types/{crypto → src/crypto}/asymmetric.d.ts +0 -0
  170. /package/dist/types/{crypto → src/crypto}/file-encryption.d.ts +0 -0
  171. /package/dist/types/{crypto → src/crypto}/hashing.d.ts +0 -0
  172. /package/dist/types/{crypto → src/crypto}/index.d.ts +0 -0
  173. /package/dist/types/{crypto → src/crypto}/mls-codec.d.ts +0 -0
  174. /package/dist/types/{crypto → src/crypto}/mls.d.ts +0 -0
  175. /package/dist/types/{crypto → src/crypto}/pgp.d.ts +0 -0
  176. /package/dist/types/{crypto → src/crypto}/random-generation.d.ts +0 -0
  177. /package/dist/types/{crypto → src/crypto}/sframe.d.ts +0 -0
  178. /package/dist/types/{crypto → src/crypto}/symmetric.d.ts +0 -0
  179. /package/dist/types/{crypto → src/crypto}/utils.d.ts +0 -0
  180. /package/dist/types/{examples → src/examples}/auth-test.d.ts +0 -0
  181. /package/dist/types/{examples → src/examples}/crypto-identity-example.d.ts +0 -0
  182. /package/dist/types/{examples → src/examples}/mls-3-member-test.d.ts +0 -0
  183. /package/dist/types/{examples → src/examples}/mls-multi-member.d.ts +0 -0
  184. /package/dist/types/{examples → src/examples}/mls-simple-test.d.ts +0 -0
  185. /package/dist/types/{examples → src/examples}/pgp-example.d.ts +0 -0
  186. /package/dist/types/{examples → src/examples}/shogun-core-example.d.ts +0 -0
  187. /package/dist/types/{examples → src/examples}/zkproof-credentials-example.d.ts +0 -0
  188. /package/dist/types/{examples → src/examples}/zkproof-example.d.ts +0 -0
  189. /package/dist/types/{gundb → src/gundb}/crypto.d.ts +0 -0
  190. /package/dist/types/{gundb → src/gundb}/derive.d.ts +0 -0
  191. /package/dist/types/{gundb → src/gundb}/errors.d.ts +0 -0
  192. /package/dist/types/{gundb → src/gundb}/index.d.ts +0 -0
  193. /package/dist/types/{gundb → src/gundb}/rxjs.d.ts +0 -0
  194. /package/dist/types/{gundb → src/gundb}/types.d.ts +0 -0
  195. /package/dist/types/{interfaces → src/interfaces}/common.d.ts +0 -0
  196. /package/dist/types/{interfaces → src/interfaces}/events.d.ts +0 -0
  197. /package/dist/types/{interfaces → src/interfaces}/plugin.d.ts +0 -0
  198. /package/dist/types/{interfaces → src/interfaces}/shogun.d.ts +0 -0
  199. /package/dist/types/{managers → src/managers}/AuthManager.d.ts +0 -0
  200. /package/dist/types/{managers → src/managers}/CoreInitializer.d.ts +0 -0
  201. /package/dist/types/{managers → src/managers}/CryptoIdentityManager.d.ts +0 -0
  202. /package/dist/types/{managers → src/managers}/EventManager.d.ts +0 -0
  203. /package/dist/types/{managers → src/managers}/PluginManager.d.ts +0 -0
  204. /package/dist/types/{plugins → src/plugins}/base.d.ts +0 -0
  205. /package/dist/types/{plugins → src/plugins}/index.d.ts +0 -0
  206. /package/dist/types/{plugins → src/plugins}/nostr/index.d.ts +0 -0
  207. /package/dist/types/{plugins → src/plugins}/nostr/nostrConnector.d.ts +0 -0
  208. /package/dist/types/{plugins → src/plugins}/nostr/nostrConnectorPlugin.d.ts +0 -0
  209. /package/dist/types/{plugins → src/plugins}/nostr/nostrSigner.d.ts +0 -0
  210. /package/dist/types/{plugins → src/plugins}/nostr/types.d.ts +0 -0
  211. /package/dist/types/{plugins → src/plugins}/smartwallet/index.d.ts +0 -0
  212. /package/dist/types/{plugins → src/plugins}/smartwallet/smartWalletPlugin.d.ts +0 -0
  213. /package/dist/types/{plugins → src/plugins}/smartwallet/types.d.ts +0 -0
  214. /package/dist/types/{plugins → src/plugins}/web3/index.d.ts +0 -0
  215. /package/dist/types/{plugins → src/plugins}/web3/types.d.ts +0 -0
  216. /package/dist/types/{plugins → src/plugins}/web3/web3Connector.d.ts +0 -0
  217. /package/dist/types/{plugins → src/plugins}/web3/web3ConnectorPlugin.d.ts +0 -0
  218. /package/dist/types/{plugins → src/plugins}/web3/web3Signer.d.ts +0 -0
  219. /package/dist/types/{plugins → src/plugins}/webauthn/index.d.ts +0 -0
  220. /package/dist/types/{plugins → src/plugins}/webauthn/types.d.ts +0 -0
  221. /package/dist/types/{plugins → src/plugins}/webauthn/webauthn.d.ts +0 -0
  222. /package/dist/types/{plugins → src/plugins}/webauthn/webauthnPlugin.d.ts +0 -0
  223. /package/dist/types/{plugins → src/plugins}/webauthn/webauthnSigner.d.ts +0 -0
  224. /package/dist/types/{plugins → src/plugins}/zkproof/index.d.ts +0 -0
  225. /package/dist/types/{plugins → src/plugins}/zkproof/types.d.ts +0 -0
  226. /package/dist/types/{plugins → src/plugins}/zkproof/zkCredentials.d.ts +0 -0
  227. /package/dist/types/{plugins → src/plugins}/zkproof/zkProofConnector.d.ts +0 -0
  228. /package/dist/types/{plugins → src/plugins}/zkproof/zkProofPlugin.d.ts +0 -0
  229. /package/dist/types/{storage → src/storage}/storage.d.ts +0 -0
  230. /package/dist/types/{utils → src/utils}/errorHandler.d.ts +0 -0
  231. /package/dist/types/{utils → src/utils}/eventEmitter.d.ts +0 -0
  232. /package/dist/types/{utils → src/utils}/seedPhrase.d.ts +0 -0
  233. /package/dist/types/{utils → src/utils}/validation.d.ts +0 -0
@@ -1,352 +0,0 @@
1
- "use strict";
2
- /**
3
- * SFrame (Secure Frame) Manager
4
- * End-to-end encryption for real-time media frames (audio/video)
5
- * Designed for low overhead and high performance
6
- *
7
- * SFrame adds ~10 bytes per frame overhead
8
- * Compatible with WebRTC Insertable Streams API
9
- */
10
- Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.SFrameManager = void 0;
12
- class SFrameManager {
13
- constructor() {
14
- this.keys = new Map();
15
- this.currentKeyId = 0;
16
- this.frameCounter = 0;
17
- this.initialized = false;
18
- console.log("🎥 [SFrame] Manager created");
19
- }
20
- /**
21
- * Initialize the SFrame manager
22
- */
23
- async initialize() {
24
- if (this.initialized) {
25
- console.warn("[SFrame] Already initialized");
26
- return;
27
- }
28
- try {
29
- console.log("🔐 [SFrame] Initializing...");
30
- // Generate initial key
31
- await this.generateKey(0);
32
- this.initialized = true;
33
- console.log("✅ [SFrame] Initialized successfully");
34
- }
35
- catch (error) {
36
- console.error("❌ [SFrame] Initialization failed:", error);
37
- throw new Error(`SFrame initialization failed: ${error instanceof Error ? error.message : String(error)}`);
38
- }
39
- }
40
- /**
41
- * Generate a new SFrame encryption key
42
- */
43
- async generateKey(keyId) {
44
- try {
45
- console.log(`🔑 [SFrame] Generating key ${keyId}...`);
46
- // Generate AES-GCM key (128-bit for low overhead)
47
- const key = await crypto.subtle.generateKey({
48
- name: "AES-GCM",
49
- length: 128, // 128-bit for performance, 256-bit for maximum security
50
- }, false, // Not extractable for security
51
- ["encrypt", "decrypt"]);
52
- // Generate salt for key derivation
53
- const salt = crypto.getRandomValues(new Uint8Array(16));
54
- const sframeKey = {
55
- keyId,
56
- key,
57
- salt,
58
- };
59
- this.keys.set(keyId, sframeKey);
60
- console.log(`✅ [SFrame] Key ${keyId} generated`);
61
- return sframeKey;
62
- }
63
- catch (error) {
64
- console.error(`❌ [SFrame] Key generation failed:`, error);
65
- throw new Error(`SFrame key generation failed: ${error instanceof Error ? error.message : String(error)}`);
66
- }
67
- }
68
- /**
69
- * Derive an SFrame key from MLS shared secret
70
- * This allows SFrame to use keys derived from MLS for media encryption
71
- * RFC 9605 Section 5.2: MLS-based key management
72
- */
73
- async deriveKeyFromMLSSecret(mlsSecret, keyId, context = "SFrame") {
74
- try {
75
- console.log(`🔗 [SFrame] Deriving key ${keyId} from MLS secret (RFC 9605 Section 5.2)...`);
76
- // RFC 9605 Section 5.2: Use specific labels for MLS-based derivation
77
- const secretLabel = new TextEncoder().encode("SFrame 1.0 Secret");
78
- const saltLabel = new TextEncoder().encode("SFrame 1.0 Salt");
79
- // Import MLS secret as key material
80
- const baseKey = await crypto.subtle.importKey("raw", mlsSecret, "HKDF", false, ["deriveKey", "deriveBits"]);
81
- // Derive salt using HKDF (RFC 9605)
82
- const derivedSaltBits = await crypto.subtle.deriveBits({
83
- name: "HKDF",
84
- hash: "SHA-256",
85
- salt: new Uint8Array(0), // Empty salt for salt derivation
86
- info: saltLabel,
87
- }, baseKey, 128);
88
- const salt = new Uint8Array(derivedSaltBits);
89
- // Derive AES-GCM key using HKDF with RFC 9605 label
90
- const key = await crypto.subtle.deriveKey({
91
- name: "HKDF",
92
- hash: "SHA-256",
93
- salt: new Uint8Array(0), // Empty salt for key derivation
94
- info: secretLabel,
95
- }, baseKey, {
96
- name: "AES-GCM",
97
- length: 128,
98
- }, false, ["encrypt", "decrypt"]);
99
- const sframeKey = {
100
- keyId,
101
- key,
102
- salt,
103
- };
104
- this.keys.set(keyId, sframeKey);
105
- console.log(`✅ [SFrame] Key ${keyId} derived from MLS (RFC 9605 compliant)`);
106
- return sframeKey;
107
- }
108
- catch (error) {
109
- console.error(`❌ [SFrame] Key derivation failed:`, error);
110
- throw new Error(`SFrame key derivation failed: ${error instanceof Error ? error.message : String(error)}`);
111
- }
112
- }
113
- /**
114
- * Set a shared SFrame key (e.g., from another member)
115
- */
116
- async setSharedKey(sframeKey) {
117
- this.keys.set(sframeKey.keyId, sframeKey);
118
- console.log(`✅ [SFrame] Shared key ${sframeKey.keyId} set.`);
119
- }
120
- /**
121
- * Set the active encryption key
122
- */
123
- setActiveKey(keyId) {
124
- if (!this.keys.has(keyId)) {
125
- throw new Error(`SFrame key ${keyId} not found`);
126
- }
127
- this.currentKeyId = keyId;
128
- console.log(`🔄 [SFrame] Active key set to ${keyId}`);
129
- }
130
- /**
131
- * Encrypt a media frame using SFrame
132
- */
133
- async encryptFrame(frameData) {
134
- this.ensureInitialized();
135
- try {
136
- const sframeKey = this.keys.get(this.currentKeyId);
137
- if (!sframeKey) {
138
- throw new Error(`SFrame key ${this.currentKeyId} not found`);
139
- }
140
- // RFC 9605: IV = salt XOR counter
141
- // Generate counter bytes (96-bit/12-byte)
142
- const counterBytes = new Uint8Array(12);
143
- const counterView = new DataView(counterBytes.buffer);
144
- // Store frame counter in last 8 bytes (big-endian uint64-like)
145
- counterView.setUint32(4, Math.floor(this.frameCounter / 0x100000000), false);
146
- counterView.setUint32(8, this.frameCounter & 0xffffffff, false);
147
- // SFrame header: 1 byte for key ID + frame counter encoding
148
- // Simplified header: 1 byte key ID + 4 bytes frame counter
149
- const header = new Uint8Array(5);
150
- header[0] = this.currentKeyId;
151
- new DataView(header.buffer).setUint32(1, this.frameCounter, false);
152
- // XOR salt with counter to create IV (RFC 9605 Section 4.3)
153
- const iv = new Uint8Array(12);
154
- for (let i = 0; i < 12; i++) {
155
- iv[i] = sframeKey.salt[i] ^ counterBytes[i];
156
- }
157
- // Encrypt the frame with header authentication (RFC 9605 Section 4.3)
158
- const ciphertext = await crypto.subtle.encrypt({
159
- name: "AES-GCM",
160
- iv,
161
- additionalData: header, // RFC 9605: Header included in AAD
162
- tagLength: 128, // 128-bit authentication tag
163
- }, sframeKey.key, frameData);
164
- // RFC 9605: SFrame format = header + ciphertext (IV is derived, not transmitted)
165
- const encrypted = new Uint8Array(header.length + ciphertext.byteLength);
166
- encrypted.set(header, 0);
167
- encrypted.set(new Uint8Array(ciphertext), header.length);
168
- // Increment frame counter
169
- this.frameCounter++;
170
- return encrypted;
171
- }
172
- catch (error) {
173
- console.error("❌ [SFrame] Frame encryption failed:", error);
174
- throw new Error(`SFrame encryption failed: ${error instanceof Error ? error.message : String(error)}`);
175
- }
176
- }
177
- /**
178
- * Decrypt a media frame using SFrame
179
- */
180
- async decryptFrame(encryptedFrame) {
181
- this.ensureInitialized();
182
- try {
183
- // Parse SFrame header (5 bytes: 1 byte key ID + 4 bytes frame counter)
184
- const header = encryptedFrame.slice(0, 5);
185
- const keyId = header[0];
186
- const frameCount = new DataView(header.buffer, header.byteOffset).getUint32(1, false);
187
- // Get the key
188
- const sframeKey = this.keys.get(keyId);
189
- if (!sframeKey) {
190
- throw new Error(`SFrame key ${keyId} not found`);
191
- }
192
- // RFC 9605: IV is derived from frame count and salt (not transmitted)
193
- const counterBytes = new Uint8Array(12);
194
- const counterView = new DataView(counterBytes.buffer);
195
- counterView.setUint32(4, Math.floor(frameCount / 0x100000000), false);
196
- counterView.setUint32(8, frameCount & 0xffffffff, false);
197
- const iv = new Uint8Array(12);
198
- for (let i = 0; i < 12; i++) {
199
- iv[i] = sframeKey.salt[i] ^ counterBytes[i];
200
- }
201
- // Extract ciphertext (rest of the data)
202
- const ciphertext = encryptedFrame.slice(header.length);
203
- // Decrypt the frame with header authentication (RFC 9605 Section 4.3)
204
- const plaintext = await crypto.subtle.decrypt({
205
- name: "AES-GCM",
206
- iv,
207
- additionalData: header, // RFC 9605: Header included in AAD
208
- tagLength: 128,
209
- }, sframeKey.key, ciphertext);
210
- return plaintext;
211
- }
212
- catch (error) {
213
- console.error("❌ [SFrame] Frame decryption failed:", error);
214
- throw new Error(`SFrame decryption failed: ${error instanceof Error ? error.message : String(error)}`);
215
- }
216
- }
217
- /**
218
- * Encrypt transform function for Insertable Streams
219
- * Use this with RTCRtpSender.createEncodedStreams()
220
- */
221
- createEncryptTransform() {
222
- const manager = this;
223
- return new TransformStream({
224
- async transform(encodedFrame, controller) {
225
- try {
226
- // Get frame data
227
- const frameData = encodedFrame.data;
228
- // Encrypt the frame
229
- const encrypted = await manager.encryptFrame(frameData);
230
- // Create new encoded frame with encrypted data
231
- encodedFrame.data = encrypted.buffer;
232
- // Forward the encrypted frame
233
- controller.enqueue(encodedFrame);
234
- }
235
- catch (error) {
236
- console.error("[SFrame] Encrypt transform error:", error);
237
- // Forward unencrypted frame on error (fallback)
238
- controller.enqueue(encodedFrame);
239
- }
240
- },
241
- });
242
- }
243
- /**
244
- * Decrypt transform function for Insertable Streams
245
- * Use this with RTCRtpReceiver.createEncodedStreams()
246
- */
247
- createDecryptTransform() {
248
- const manager = this;
249
- return new TransformStream({
250
- async transform(encodedFrame, controller) {
251
- try {
252
- // Get encrypted frame data
253
- const encryptedData = new Uint8Array(encodedFrame.data);
254
- // Decrypt the frame
255
- const decrypted = await manager.decryptFrame(encryptedData);
256
- // Create new encoded frame with decrypted data
257
- encodedFrame.data = decrypted;
258
- // Forward the decrypted frame
259
- controller.enqueue(encodedFrame);
260
- }
261
- catch (error) {
262
- console.error("[SFrame] Decrypt transform error:", error);
263
- // Skip frame on decryption error
264
- // (better to drop frame than show corrupted video)
265
- }
266
- },
267
- });
268
- }
269
- /**
270
- * Rotate encryption keys
271
- * RFC 9605: Frame counter should be reset on key rotation to prevent exhaustion
272
- */
273
- async rotateKey() {
274
- try {
275
- const newKeyId = this.currentKeyId + 1;
276
- console.log(`🔄 [SFrame] Rotating to key ${newKeyId}...`);
277
- await this.generateKey(newKeyId);
278
- this.setActiveKey(newKeyId);
279
- // RFC 9605: Reset frame counter on key rotation
280
- this.resetFrameCounter();
281
- console.log(`🔄 [SFrame] Frame counter reset to 0 for new key`);
282
- console.log(`✅ [SFrame] Key rotated to ${newKeyId}`);
283
- return newKeyId;
284
- }
285
- catch (error) {
286
- console.error("❌ [SFrame] Key rotation failed:", error);
287
- throw new Error(`SFrame key rotation failed: ${error instanceof Error ? error.message : String(error)}`);
288
- }
289
- }
290
- /**
291
- * Get current key ID
292
- */
293
- getCurrentKeyId() {
294
- return this.currentKeyId;
295
- }
296
- /**
297
- * Get frame counter (for debugging)
298
- */
299
- getFrameCounter() {
300
- return this.frameCounter;
301
- }
302
- /**
303
- * Reset frame counter (use when rotating keys)
304
- */
305
- resetFrameCounter() {
306
- this.frameCounter = 0;
307
- console.log("🔄 [SFrame] Frame counter reset");
308
- }
309
- /**
310
- * Remove old keys to prevent memory bloat
311
- */
312
- cleanupOldKeys(keepLast = 2) {
313
- const keyIds = Array.from(this.keys.keys()).sort((a, b) => b - a);
314
- if (keyIds.length > keepLast) {
315
- const toDelete = keyIds.slice(keepLast);
316
- toDelete.forEach((keyId) => {
317
- this.keys.delete(keyId);
318
- console.log(`🧹 [SFrame] Deleted old key ${keyId}`);
319
- });
320
- }
321
- }
322
- /**
323
- * Get statistics
324
- */
325
- getStats() {
326
- return {
327
- keyCount: this.keys.size,
328
- currentKeyId: this.currentKeyId,
329
- frameCounter: this.frameCounter,
330
- initialized: this.initialized,
331
- };
332
- }
333
- /**
334
- * Clean up resources
335
- */
336
- destroy() {
337
- this.keys.clear();
338
- this.initialized = false;
339
- this.frameCounter = 0;
340
- console.log("✅ [SFrame] Manager destroyed");
341
- }
342
- /**
343
- * Ensure the manager is initialized
344
- */
345
- ensureInitialized() {
346
- if (!this.initialized) {
347
- throw new Error("SFrame Manager not initialized. Call initialize() first.");
348
- }
349
- }
350
- }
351
- exports.SFrameManager = SFrameManager;
352
- exports.default = SFrameManager;