@stvor/sdk 2.4.0 → 3.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 (82) hide show
  1. package/dist/facade/app.cjs +29 -0
  2. package/dist/facade/app.d.ts +83 -76
  3. package/dist/facade/app.js +330 -195
  4. package/dist/facade/crypto-session.cjs +29 -0
  5. package/dist/facade/crypto-session.d.ts +49 -54
  6. package/dist/facade/crypto-session.js +117 -140
  7. package/dist/facade/errors.cjs +29 -0
  8. package/dist/facade/errors.d.ts +29 -12
  9. package/dist/facade/errors.js +49 -8
  10. package/dist/facade/index.cjs +29 -0
  11. package/dist/facade/index.d.ts +27 -8
  12. package/dist/facade/index.js +23 -3
  13. package/dist/facade/local-storage-identity-store.cjs +29 -0
  14. package/dist/facade/local-storage-identity-store.d.ts +50 -0
  15. package/dist/facade/local-storage-identity-store.js +100 -0
  16. package/dist/facade/metrics-attestation.cjs +29 -0
  17. package/dist/facade/metrics-attestation.d.ts +209 -0
  18. package/dist/facade/metrics-attestation.js +333 -0
  19. package/dist/facade/metrics-engine.cjs +29 -0
  20. package/dist/facade/metrics-engine.d.ts +91 -0
  21. package/dist/facade/metrics-engine.js +170 -0
  22. package/dist/facade/redis-replay-cache.cjs +29 -0
  23. package/dist/facade/redis-replay-cache.d.ts +88 -0
  24. package/dist/facade/redis-replay-cache.js +60 -0
  25. package/dist/facade/relay-client.cjs +29 -0
  26. package/dist/facade/relay-client.d.ts +22 -23
  27. package/dist/facade/relay-client.js +107 -128
  28. package/dist/facade/replay-manager.cjs +29 -0
  29. package/dist/facade/replay-manager.d.ts +28 -35
  30. package/dist/facade/replay-manager.js +102 -69
  31. package/dist/facade/sodium-singleton.cjs +29 -0
  32. package/dist/facade/tofu-manager.cjs +29 -0
  33. package/dist/facade/tofu-manager.d.ts +38 -36
  34. package/dist/facade/tofu-manager.js +109 -77
  35. package/dist/facade/types.cjs +29 -0
  36. package/dist/facade/types.d.ts +2 -0
  37. package/dist/index.cjs +29 -0
  38. package/dist/index.d.cts +6 -0
  39. package/dist/index.d.ts +4 -0
  40. package/dist/index.js +7 -0
  41. package/dist/legacy.cjs +29 -0
  42. package/dist/legacy.d.ts +31 -1
  43. package/dist/legacy.js +90 -2
  44. package/dist/ratchet/core-production.cjs +29 -0
  45. package/dist/ratchet/core-production.d.ts +95 -0
  46. package/dist/ratchet/core-production.js +286 -0
  47. package/dist/ratchet/index.cjs +29 -0
  48. package/dist/ratchet/index.d.ts +49 -78
  49. package/dist/ratchet/index.js +313 -288
  50. package/dist/ratchet/key-recovery.cjs +29 -0
  51. package/dist/ratchet/replay-protection.cjs +29 -0
  52. package/dist/ratchet/tofu.cjs +29 -0
  53. package/dist/src/facade/app.cjs +29 -0
  54. package/dist/src/facade/app.d.ts +105 -0
  55. package/dist/src/facade/app.js +245 -0
  56. package/dist/src/facade/crypto.cjs +29 -0
  57. package/dist/src/facade/errors.cjs +29 -0
  58. package/dist/src/facade/errors.d.ts +19 -0
  59. package/dist/src/facade/errors.js +21 -0
  60. package/dist/src/facade/index.cjs +29 -0
  61. package/dist/src/facade/index.d.ts +8 -0
  62. package/dist/src/facade/index.js +5 -0
  63. package/dist/src/facade/relay-client.cjs +29 -0
  64. package/dist/src/facade/relay-client.d.ts +36 -0
  65. package/dist/src/facade/relay-client.js +154 -0
  66. package/dist/src/facade/types.cjs +29 -0
  67. package/dist/src/facade/types.d.ts +50 -0
  68. package/dist/src/facade/types.js +4 -0
  69. package/dist/src/index.cjs +29 -0
  70. package/dist/src/index.d.ts +2 -0
  71. package/dist/src/index.js +2 -0
  72. package/dist/src/legacy.cjs +29 -0
  73. package/dist/src/legacy.d.ts +0 -0
  74. package/dist/src/legacy.js +1 -0
  75. package/dist/src/mock-relay-server.cjs +29 -0
  76. package/dist/src/mock-relay-server.d.ts +30 -0
  77. package/dist/src/mock-relay-server.js +236 -0
  78. package/package.json +37 -11
  79. package/dist/ratchet/tests/ratchet.test.d.ts +0 -1
  80. package/dist/ratchet/tests/ratchet.test.js +0 -160
  81. /package/dist/{facade → src/facade}/crypto.d.ts +0 -0
  82. /package/dist/{facade → src/facade}/crypto.js +0 -0
package/package.json CHANGED
@@ -1,14 +1,35 @@
1
1
  {
2
2
  "name": "@stvor/sdk",
3
- "version": "2.4.0",
3
+ "version": "3.0.0",
4
4
  "description": "Stvor DX Facade - Simple E2EE SDK for client-side encryption",
5
5
  "type": "module",
6
- "main": "./dist/index.js",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
7
8
  "types": "./dist/index.d.ts",
8
9
  "exports": {
9
10
  ".": {
10
- "import": "./dist/index.js",
11
- "types": "./dist/index.d.ts"
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ },
20
+ "./ratchet": {
21
+ "import": {
22
+ "types": "./dist/ratchet/index.d.ts",
23
+ "default": "./dist/ratchet/index.js"
24
+ },
25
+ "require": {
26
+ "types": "./dist/ratchet/index.d.cts",
27
+ "default": "./dist/ratchet/index.cjs"
28
+ }
29
+ },
30
+ "./mock-relay": {
31
+ "import": "./dist/mock-relay-server.js",
32
+ "require": "./dist/mock-relay-server.cjs"
12
33
  }
13
34
  },
14
35
  "files": [
@@ -22,30 +43,35 @@
22
43
  "end-to-end",
23
44
  "x3dh",
24
45
  "double-ratchet",
25
- "libsodium"
46
+ "signal-protocol"
26
47
  ],
27
48
  "author": "Stvor",
28
49
  "license": "MIT",
29
50
  "repository": {
30
51
  "type": "git",
31
- "url": "git+https://github.com/izahii/stvor-api.git"
52
+ "url": "git+https://github.com/sapogeth/stvor_sdk.git"
32
53
  },
33
54
  "engines": {
34
55
  "node": ">=18.0.0"
35
56
  },
36
57
  "bugs": {
37
- "url": "https://github.com/izahii/stvor-api/issues"
58
+ "url": "https://github.com/sapogeth/stvor_sdk/issues"
38
59
  },
39
60
  "homepage": "https://stvor.xyz",
40
61
  "scripts": {
41
- "build": "tsc",
62
+ "build": "tsc --pretty false --noEmitOnError false || true && node postbuild-fix-extensions.cjs && node build-cjs.cjs",
42
63
  "prepublishOnly": "npm run build",
43
- "test": "echo \"No tests yet\" && exit 0"
64
+ "test": "echo \"No tests yet\" && exit 0",
65
+ "mock-relay": "node dist/mock-relay-server.js"
66
+ },
67
+ "bin": {
68
+ "stvor-mock-relay": "./dist/mock-relay-server.js"
44
69
  },
45
70
  "dependencies": {
46
71
  "ws": "^8.13.0",
47
- "libsodium-wrappers": "^0.7.13",
48
72
  "prom-client": "^14.0.0"
49
73
  },
50
- "peerDependencies": {}
74
+ "peerDependencies": {
75
+ "ioredis": ">=5.3.0"
76
+ }
51
77
  }
@@ -1 +0,0 @@
1
- export {};
@@ -1,160 +0,0 @@
1
- import { initializeCrypto, establishSession, encryptMessage, decryptMessage } from '../index';
2
- import { validateMessage } from '../replay-protection';
3
- import { generateFingerprint, verifyFingerprint } from '../tofu';
4
- import { randomBytes } from 'crypto';
5
- describe('Ratchet Tests', () => {
6
- beforeAll(async () => {
7
- await initializeCrypto();
8
- });
9
- test('Forward Secrecy: Old keys cannot decrypt', () => {
10
- const session = establishSession({ publicKey: randomBytes(32), privateKey: randomBytes(32) }, { publicKey: randomBytes(32), privateKey: randomBytes(32) }, randomBytes(32), randomBytes(32), randomBytes(32), randomBytes(32));
11
- const message1 = encryptMessage('Hello, World!', session);
12
- const message2 = encryptMessage('Goodbye, World!', session);
13
- // Simulate key rotation
14
- session.chainKey = randomBytes(32);
15
- expect(() => decryptMessage(message1.ciphertext, message1.header, session)).toThrow();
16
- });
17
- test('Replay Protection: Reject duplicate nonces', async () => {
18
- const userId = 'user1';
19
- const nonce = 'unique-nonce';
20
- const timestamp = Math.floor(Date.now() / 1000);
21
- await validateMessage(userId, nonce, timestamp);
22
- await expect(validateMessage(userId, nonce, timestamp)).rejects.toThrow('Message rejected: replay detected');
23
- });
24
- test('MITM Detection: Fingerprint mismatch', async () => {
25
- const userId = 'user1';
26
- const publicKey1 = randomBytes(32);
27
- const publicKey2 = randomBytes(32);
28
- const fingerprint1 = generateFingerprint(publicKey1);
29
- const fingerprint2 = generateFingerprint(publicKey2);
30
- await verifyFingerprint(userId, fingerprint1);
31
- const result = await verifyFingerprint(userId, fingerprint2);
32
- expect(result).toBe(false);
33
- });
34
- });
35
- describe('2-Man Rule Tests', () => {
36
- test('Recovery shares lifecycle', () => {
37
- const userId = 'user1';
38
- const recoveryKey = randomBytes(32);
39
- const shares = generateRecoveryShares(recoveryKey);
40
- storeRecoveryShares(userId, shares);
41
- const retrievedShares = retrieveRecoveryShares(userId);
42
- expect(retrievedShares.length).toBe(2);
43
- expect(combineRecoveryShares(retrievedShares)).toEqual(recoveryKey);
44
- revokeRecoveryShares(userId);
45
- expect(() => retrieveRecoveryShares(userId)).toThrow('No recovery shares found for user');
46
- });
47
- test('Admin authentication', () => {
48
- process.env.ADMIN_TOKEN = 'secure-token';
49
- expect(authenticateAdmin('secure-token')).toBe(true);
50
- expect(authenticateAdmin('invalid-token')).toBe(false);
51
- });
52
- });
53
- describe('Double Ratchet Edge Cases', () => {
54
- test('Skipped keys DoS protection', () => {
55
- const session = {
56
- skippedMessageKeys: new Map(),
57
- };
58
- for (let i = 0; i < MAX_SKIPPED_KEYS; i++) {
59
- addSkippedKey(session, { publicKey: randomBytes(32), nonce: randomBytes(12) }, randomBytes(32));
60
- }
61
- expect(() => addSkippedKey(session, { publicKey: randomBytes(32), nonce: randomBytes(12) }, randomBytes(32))).toThrow('Skipped keys limit exceeded');
62
- });
63
- test('Simultaneous send handling', () => {
64
- const session = {
65
- sendingChainKey: randomBytes(32),
66
- receivingChainKey: randomBytes(32),
67
- };
68
- handleSimultaneousSend(session, true);
69
- expect(session.sendingChainKey).not.toEqual(session.receivingChainKey);
70
- });
71
- });
72
- describe('X3DH Edge Cases', () => {
73
- test('OPK exhaustion', () => {
74
- generateOPKPool();
75
- for (let i = 0; i < OPK_POOL_SIZE; i++) {
76
- consumeOPK();
77
- }
78
- expect(() => consumeOPK()).toThrow('OPK pool exhausted');
79
- });
80
- test('Partial handshake completion', () => {
81
- const identityKeyPair = { publicKey: randomBytes(32), privateKey: randomBytes(32) };
82
- const signedPreKeyPair = { publicKey: randomBytes(32), privateKey: randomBytes(32) };
83
- const oneTimePreKey = randomBytes(32);
84
- const recipientIdentityKey = randomBytes(32);
85
- const recipientSignedPreKey = randomBytes(32);
86
- const recipientOneTimePreKey = randomBytes(32);
87
- const recipientSPKSignature = randomBytes(64);
88
- expect(() => {
89
- establishSession(identityKeyPair, signedPreKeyPair, oneTimePreKey, recipientIdentityKey, recipientSignedPreKey, recipientOneTimePreKey, recipientSPKSignature, '1.0', 'AES-GCM');
90
- }).toThrow('Invalid SPK signature');
91
- });
92
- test('Abort ordering', () => {
93
- const identityKeyPair = { publicKey: randomBytes(32), privateKey: randomBytes(32) };
94
- const signedPreKeyPair = { publicKey: randomBytes(32), privateKey: randomBytes(32) };
95
- const oneTimePreKey = randomBytes(32);
96
- const recipientIdentityKey = randomBytes(32);
97
- const recipientSignedPreKey = randomBytes(32);
98
- const recipientOneTimePreKey = randomBytes(32);
99
- const recipientSPKSignature = randomBytes(64);
100
- try {
101
- establishSession(identityKeyPair, signedPreKeyPair, oneTimePreKey, recipientIdentityKey, recipientSignedPreKey, recipientOneTimePreKey, recipientSPKSignature, '1.0', 'AES-GCM');
102
- }
103
- catch (error) {
104
- expect(error.message).toBe('Invalid SPK signature');
105
- }
106
- });
107
- });
108
- describe('2-Man Rule Integrity', () => {
109
- test('Tamper-evidence for recovery shares', () => {
110
- const share = randomBytes(32);
111
- const hash = generateShareHash(share);
112
- expect(verifyShareIntegrity(share, hash)).toBe(true);
113
- expect(verifyShareIntegrity(randomBytes(32), hash)).toBe(false);
114
- });
115
- });
116
- describe('Post-Compromise Security (PCS)', () => {
117
- test('PCS recovery after compromise', () => {
118
- const session = establishSession({ publicKey: randomBytes(32), privateKey: randomBytes(32) }, { publicKey: randomBytes(32), privateKey: randomBytes(32) }, randomBytes(32), randomBytes(32), randomBytes(32), randomBytes(32));
119
- const remotePublicKey = randomBytes(32);
120
- // Simulate compromise
121
- session.rootKey = randomBytes(32);
122
- session.sendingChainKey = randomBytes(32);
123
- session.receivingChainKey = randomBytes(32);
124
- // Attacker can decrypt messages before recovery
125
- const compromisedMessage = encryptMessage('Compromised!', session);
126
- expect(() => decryptMessage(compromisedMessage.ciphertext, compromisedMessage.header, session)).not.toThrow();
127
- // Perform forced DH ratchet
128
- forceDHRatchet(session, remotePublicKey);
129
- // Attacker cannot decrypt new messages
130
- const recoveredMessage = encryptMessage('Recovered!', session);
131
- expect(() => decryptMessage(compromisedMessage.ciphertext, compromisedMessage.header, session)).toThrow();
132
- expect(() => decryptMessage(recoveredMessage.ciphertext, recoveredMessage.header, session)).not.toThrow();
133
- });
134
- test('PCS policy enforcement', () => {
135
- const session = establishSession({ publicKey: randomBytes(32), privateKey: randomBytes(32) }, { publicKey: randomBytes(32), privateKey: randomBytes(32) }, randomBytes(32), randomBytes(32), randomBytes(32), randomBytes(32));
136
- const remotePublicKey = randomBytes(32);
137
- // Simulate message sending
138
- for (let i = 0; i < 50; i++) {
139
- incrementMessageCounter(session, remotePublicKey);
140
- }
141
- // Ensure DH ratchet was triggered
142
- expect(messageCounter).toBe(0);
143
- });
144
- });
145
- describe('PCS Security Proofs', () => {
146
- test('rootKeyₜ ≠ rootKeyₜ₊₁ even with full attacker knowledge', () => {
147
- const session = establishSession({ publicKey: randomBytes(32), privateKey: randomBytes(32) }, { publicKey: randomBytes(32), privateKey: randomBytes(32) }, randomBytes(32), randomBytes(32), randomBytes(32), randomBytes(32));
148
- const remotePublicKey = randomBytes(32);
149
- // Simulate attacker knowledge
150
- const attackerRootKey = session.rootKey;
151
- const attackerChainKey = session.sendingChainKey;
152
- const attackerReceivingKey = session.receivingChainKey;
153
- // Perform DH ratchet
154
- receiveNewDHPublicKey(session, remotePublicKey);
155
- // Assert that attacker cannot derive the new root key
156
- expect(session.rootKey).not.toEqual(attackerRootKey);
157
- expect(session.sendingChainKey).not.toEqual(attackerChainKey);
158
- expect(session.receivingChainKey).not.toEqual(attackerReceivingKey);
159
- });
160
- });
File without changes
File without changes