@enbox/dwn-sdk-js 0.1.1 → 0.1.2

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 (126) hide show
  1. package/dist/browser.mjs +6 -6
  2. package/dist/browser.mjs.map +3 -3
  3. package/dist/esm/src/utils/protocols.js +2 -2
  4. package/dist/esm/src/utils/protocols.js.map +1 -1
  5. package/dist/esm/tests/fuzz/arbitraries/dwn-message.arbitrary.js +72 -0
  6. package/dist/esm/tests/fuzz/arbitraries/dwn-message.arbitrary.js.map +1 -0
  7. package/dist/esm/tests/fuzz/arbitraries/filter.arbitrary.js +53 -0
  8. package/dist/esm/tests/fuzz/arbitraries/filter.arbitrary.js.map +1 -0
  9. package/dist/esm/tests/fuzz/arbitraries/jws.arbitrary.js +55 -0
  10. package/dist/esm/tests/fuzz/arbitraries/jws.arbitrary.js.map +1 -0
  11. package/dist/esm/tests/fuzz/arbitraries/protocol-definition.arbitrary.js +106 -0
  12. package/dist/esm/tests/fuzz/arbitraries/protocol-definition.arbitrary.js.map +1 -0
  13. package/dist/esm/tests/fuzz/arbitraries/store.arbitrary.js +139 -0
  14. package/dist/esm/tests/fuzz/arbitraries/store.arbitrary.js.map +1 -0
  15. package/dist/esm/tests/fuzz/cid.fuzz.spec.js +74 -0
  16. package/dist/esm/tests/fuzz/cid.fuzz.spec.js.map +1 -0
  17. package/dist/esm/tests/fuzz/compound-index.fuzz.spec.js +203 -0
  18. package/dist/esm/tests/fuzz/compound-index.fuzz.spec.js.map +1 -0
  19. package/dist/esm/tests/fuzz/data-store.fuzz.spec.js +146 -0
  20. package/dist/esm/tests/fuzz/data-store.fuzz.spec.js.map +1 -0
  21. package/dist/esm/tests/fuzz/data-stream.fuzz.spec.js +44 -0
  22. package/dist/esm/tests/fuzz/data-stream.fuzz.spec.js.map +1 -0
  23. package/dist/esm/tests/fuzz/encoder.fuzz.spec.js +76 -0
  24. package/dist/esm/tests/fuzz/encoder.fuzz.spec.js.map +1 -0
  25. package/dist/esm/tests/fuzz/encryption.fuzz.spec.js +132 -0
  26. package/dist/esm/tests/fuzz/encryption.fuzz.spec.js.map +1 -0
  27. package/dist/esm/tests/fuzz/filter.fuzz.spec.js +149 -0
  28. package/dist/esm/tests/fuzz/filter.fuzz.spec.js.map +1 -0
  29. package/dist/esm/tests/fuzz/get-rule-set-at-path.fuzz.spec.js +82 -0
  30. package/dist/esm/tests/fuzz/get-rule-set-at-path.fuzz.spec.js.map +1 -0
  31. package/dist/esm/tests/fuzz/hd-key.fuzz.spec.js +77 -0
  32. package/dist/esm/tests/fuzz/hd-key.fuzz.spec.js.map +1 -0
  33. package/dist/esm/tests/fuzz/immutable-properties.fuzz.spec.js +86 -0
  34. package/dist/esm/tests/fuzz/immutable-properties.fuzz.spec.js.map +1 -0
  35. package/dist/esm/tests/fuzz/index-level.fuzz.spec.js +195 -0
  36. package/dist/esm/tests/fuzz/index-level.fuzz.spec.js.map +1 -0
  37. package/dist/esm/tests/fuzz/jws.fuzz.spec.js +100 -0
  38. package/dist/esm/tests/fuzz/jws.fuzz.spec.js.map +1 -0
  39. package/dist/esm/tests/fuzz/message-store.fuzz.spec.js +154 -0
  40. package/dist/esm/tests/fuzz/message-store.fuzz.spec.js.map +1 -0
  41. package/dist/esm/tests/fuzz/object.fuzz.spec.js +82 -0
  42. package/dist/esm/tests/fuzz/object.fuzz.spec.js.map +1 -0
  43. package/dist/esm/tests/fuzz/process-message.fuzz.spec.js +85 -0
  44. package/dist/esm/tests/fuzz/process-message.fuzz.spec.js.map +1 -0
  45. package/dist/esm/tests/fuzz/protocol-definition.fuzz.spec.js +145 -0
  46. package/dist/esm/tests/fuzz/protocol-definition.fuzz.spec.js.map +1 -0
  47. package/dist/esm/tests/fuzz/protocol-validation.fuzz.spec.js +146 -0
  48. package/dist/esm/tests/fuzz/protocol-validation.fuzz.spec.js.map +1 -0
  49. package/dist/esm/tests/fuzz/protocols-utils.fuzz.spec.js +41 -0
  50. package/dist/esm/tests/fuzz/protocols-utils.fuzz.spec.js.map +1 -0
  51. package/dist/esm/tests/fuzz/records-utils.fuzz.spec.js +81 -0
  52. package/dist/esm/tests/fuzz/records-utils.fuzz.spec.js.map +1 -0
  53. package/dist/esm/tests/fuzz/resumable-task-store.fuzz.spec.js +106 -0
  54. package/dist/esm/tests/fuzz/resumable-task-store.fuzz.spec.js.map +1 -0
  55. package/dist/esm/tests/fuzz/schema-validation.fuzz.spec.js +126 -0
  56. package/dist/esm/tests/fuzz/schema-validation.fuzz.spec.js.map +1 -0
  57. package/dist/esm/tests/fuzz/secp256k1.fuzz.spec.js +74 -0
  58. package/dist/esm/tests/fuzz/secp256k1.fuzz.spec.js.map +1 -0
  59. package/dist/esm/tests/fuzz/secp256r1.fuzz.spec.js +60 -0
  60. package/dist/esm/tests/fuzz/secp256r1.fuzz.spec.js.map +1 -0
  61. package/dist/esm/tests/fuzz/time.fuzz.spec.js +82 -0
  62. package/dist/esm/tests/fuzz/time.fuzz.spec.js.map +1 -0
  63. package/dist/esm/tests/fuzz/url.fuzz.spec.js +118 -0
  64. package/dist/esm/tests/fuzz/url.fuzz.spec.js.map +1 -0
  65. package/dist/types/tests/fuzz/arbitraries/dwn-message.arbitrary.d.ts +31 -0
  66. package/dist/types/tests/fuzz/arbitraries/dwn-message.arbitrary.d.ts.map +1 -0
  67. package/dist/types/tests/fuzz/arbitraries/filter.arbitrary.d.ts +27 -0
  68. package/dist/types/tests/fuzz/arbitraries/filter.arbitrary.d.ts.map +1 -0
  69. package/dist/types/tests/fuzz/arbitraries/jws.arbitrary.d.ts +26 -0
  70. package/dist/types/tests/fuzz/arbitraries/jws.arbitrary.d.ts.map +1 -0
  71. package/dist/types/tests/fuzz/arbitraries/protocol-definition.arbitrary.d.ts +31 -0
  72. package/dist/types/tests/fuzz/arbitraries/protocol-definition.arbitrary.d.ts.map +1 -0
  73. package/dist/types/tests/fuzz/arbitraries/store.arbitrary.d.ts +71 -0
  74. package/dist/types/tests/fuzz/arbitraries/store.arbitrary.d.ts.map +1 -0
  75. package/dist/types/tests/fuzz/cid.fuzz.spec.d.ts +2 -0
  76. package/dist/types/tests/fuzz/cid.fuzz.spec.d.ts.map +1 -0
  77. package/dist/types/tests/fuzz/compound-index.fuzz.spec.d.ts +2 -0
  78. package/dist/types/tests/fuzz/compound-index.fuzz.spec.d.ts.map +1 -0
  79. package/dist/types/tests/fuzz/data-store.fuzz.spec.d.ts +2 -0
  80. package/dist/types/tests/fuzz/data-store.fuzz.spec.d.ts.map +1 -0
  81. package/dist/types/tests/fuzz/data-stream.fuzz.spec.d.ts +2 -0
  82. package/dist/types/tests/fuzz/data-stream.fuzz.spec.d.ts.map +1 -0
  83. package/dist/types/tests/fuzz/encoder.fuzz.spec.d.ts +2 -0
  84. package/dist/types/tests/fuzz/encoder.fuzz.spec.d.ts.map +1 -0
  85. package/dist/types/tests/fuzz/encryption.fuzz.spec.d.ts +2 -0
  86. package/dist/types/tests/fuzz/encryption.fuzz.spec.d.ts.map +1 -0
  87. package/dist/types/tests/fuzz/filter.fuzz.spec.d.ts +2 -0
  88. package/dist/types/tests/fuzz/filter.fuzz.spec.d.ts.map +1 -0
  89. package/dist/types/tests/fuzz/get-rule-set-at-path.fuzz.spec.d.ts +2 -0
  90. package/dist/types/tests/fuzz/get-rule-set-at-path.fuzz.spec.d.ts.map +1 -0
  91. package/dist/types/tests/fuzz/hd-key.fuzz.spec.d.ts +2 -0
  92. package/dist/types/tests/fuzz/hd-key.fuzz.spec.d.ts.map +1 -0
  93. package/dist/types/tests/fuzz/immutable-properties.fuzz.spec.d.ts +2 -0
  94. package/dist/types/tests/fuzz/immutable-properties.fuzz.spec.d.ts.map +1 -0
  95. package/dist/types/tests/fuzz/index-level.fuzz.spec.d.ts +2 -0
  96. package/dist/types/tests/fuzz/index-level.fuzz.spec.d.ts.map +1 -0
  97. package/dist/types/tests/fuzz/jws.fuzz.spec.d.ts +2 -0
  98. package/dist/types/tests/fuzz/jws.fuzz.spec.d.ts.map +1 -0
  99. package/dist/types/tests/fuzz/message-store.fuzz.spec.d.ts +2 -0
  100. package/dist/types/tests/fuzz/message-store.fuzz.spec.d.ts.map +1 -0
  101. package/dist/types/tests/fuzz/object.fuzz.spec.d.ts +2 -0
  102. package/dist/types/tests/fuzz/object.fuzz.spec.d.ts.map +1 -0
  103. package/dist/types/tests/fuzz/process-message.fuzz.spec.d.ts +2 -0
  104. package/dist/types/tests/fuzz/process-message.fuzz.spec.d.ts.map +1 -0
  105. package/dist/types/tests/fuzz/protocol-definition.fuzz.spec.d.ts +2 -0
  106. package/dist/types/tests/fuzz/protocol-definition.fuzz.spec.d.ts.map +1 -0
  107. package/dist/types/tests/fuzz/protocol-validation.fuzz.spec.d.ts +2 -0
  108. package/dist/types/tests/fuzz/protocol-validation.fuzz.spec.d.ts.map +1 -0
  109. package/dist/types/tests/fuzz/protocols-utils.fuzz.spec.d.ts +2 -0
  110. package/dist/types/tests/fuzz/protocols-utils.fuzz.spec.d.ts.map +1 -0
  111. package/dist/types/tests/fuzz/records-utils.fuzz.spec.d.ts +2 -0
  112. package/dist/types/tests/fuzz/records-utils.fuzz.spec.d.ts.map +1 -0
  113. package/dist/types/tests/fuzz/resumable-task-store.fuzz.spec.d.ts +2 -0
  114. package/dist/types/tests/fuzz/resumable-task-store.fuzz.spec.d.ts.map +1 -0
  115. package/dist/types/tests/fuzz/schema-validation.fuzz.spec.d.ts +2 -0
  116. package/dist/types/tests/fuzz/schema-validation.fuzz.spec.d.ts.map +1 -0
  117. package/dist/types/tests/fuzz/secp256k1.fuzz.spec.d.ts +2 -0
  118. package/dist/types/tests/fuzz/secp256k1.fuzz.spec.d.ts.map +1 -0
  119. package/dist/types/tests/fuzz/secp256r1.fuzz.spec.d.ts +2 -0
  120. package/dist/types/tests/fuzz/secp256r1.fuzz.spec.d.ts.map +1 -0
  121. package/dist/types/tests/fuzz/time.fuzz.spec.d.ts +2 -0
  122. package/dist/types/tests/fuzz/time.fuzz.spec.d.ts.map +1 -0
  123. package/dist/types/tests/fuzz/url.fuzz.spec.d.ts +2 -0
  124. package/dist/types/tests/fuzz/url.fuzz.spec.d.ts.map +1 -0
  125. package/package.json +8 -5
  126. package/src/utils/protocols.ts +2 -2
@@ -0,0 +1,132 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+ import fc from 'fast-check';
3
+ import { ContentEncryptionAlgorithm, Encryption } from '../../src/utils/encryption.js';
4
+ const numRuns = Number(process.env.FAST_CHECK_NUM_RUNS) || 200;
5
+ /** Generates a random 32-byte key (256-bit) for AES-256-GCM or XChaCha20. */
6
+ function aes256Key() {
7
+ return fc.uint8Array({ minLength: 32, maxLength: 32 });
8
+ }
9
+ /** Generates a random 12-byte IV for AES-256-GCM. */
10
+ function aesGcmIv() {
11
+ return fc.uint8Array({ minLength: 12, maxLength: 12 });
12
+ }
13
+ /** Generates a random 24-byte nonce for XChaCha20-Poly1305. */
14
+ function xchachaIv() {
15
+ return fc.uint8Array({ minLength: 24, maxLength: 24 });
16
+ }
17
+ describe('Encryption — fuzz', () => {
18
+ describe('AES-256-GCM — encrypt/decrypt roundtrip', () => {
19
+ it('should roundtrip arbitrary plaintext through AES-256-GCM', async () => {
20
+ await fc.assert(fc.asyncProperty(aes256Key(), aesGcmIv(), fc.uint8Array({ minLength: 0, maxLength: 1024 }), async (key, iv, plaintext) => {
21
+ const { ciphertext, tag } = await Encryption.aeadEncrypt(ContentEncryptionAlgorithm.A256GCM, key, iv, plaintext);
22
+ const decrypted = await Encryption.aeadDecrypt(ContentEncryptionAlgorithm.A256GCM, key, iv, ciphertext, tag);
23
+ expect(decrypted).toEqual(plaintext);
24
+ }), { numRuns });
25
+ });
26
+ });
27
+ describe('XChaCha20-Poly1305 — encrypt/decrypt roundtrip', () => {
28
+ it('should roundtrip arbitrary plaintext through XChaCha20-Poly1305', async () => {
29
+ await fc.assert(fc.asyncProperty(aes256Key(), xchachaIv(), fc.uint8Array({ minLength: 0, maxLength: 1024 }), async (key, iv, plaintext) => {
30
+ const { ciphertext, tag } = await Encryption.aeadEncrypt(ContentEncryptionAlgorithm.XC20P, key, iv, plaintext);
31
+ const decrypted = await Encryption.aeadDecrypt(ContentEncryptionAlgorithm.XC20P, key, iv, ciphertext, tag);
32
+ expect(decrypted).toEqual(plaintext);
33
+ }), { numRuns });
34
+ });
35
+ });
36
+ describe('AES-256-GCM — authenticated output differs from plaintext', () => {
37
+ it('should produce authenticated output (ciphertext + tag) that differs from the plaintext', async () => {
38
+ await fc.assert(fc.asyncProperty(aes256Key(), aesGcmIv(), fc.uint8Array({ minLength: 1, maxLength: 512 }), async (key, iv, plaintext) => {
39
+ const { ciphertext, tag } = await Encryption.aeadEncrypt(ContentEncryptionAlgorithm.A256GCM, key, iv, plaintext);
40
+ // The full AEAD output is ciphertext || tag. The 16-byte tag
41
+ // guarantees the output is always longer than the input, so a
42
+ // byte-level match is impossible — unlike comparing raw
43
+ // ciphertext bytes alone, which can coincide for short inputs.
44
+ const authenticatedOutput = new Uint8Array([...ciphertext, ...tag]);
45
+ const areEqual = plaintext.length === authenticatedOutput.length &&
46
+ plaintext.every((byte, i) => byte === authenticatedOutput[i]);
47
+ expect(areEqual).toBe(false);
48
+ }), { numRuns });
49
+ });
50
+ });
51
+ describe('AES-256-GCM — wrong key fails decryption', () => {
52
+ it('should fail to decrypt with a different key', async () => {
53
+ await fc.assert(fc.asyncProperty(aes256Key(), aes256Key(), aesGcmIv(), fc.uint8Array({ minLength: 1, maxLength: 256 }), async (key1, key2, iv, plaintext) => {
54
+ // Skip if keys are identical
55
+ if (key1.every((byte, i) => byte === key2[i])) {
56
+ return;
57
+ }
58
+ const { ciphertext, tag } = await Encryption.aeadEncrypt(ContentEncryptionAlgorithm.A256GCM, key1, iv, plaintext);
59
+ try {
60
+ await Encryption.aeadDecrypt(ContentEncryptionAlgorithm.A256GCM, key2, iv, ciphertext, tag);
61
+ // If decryption somehow succeeds, the result should differ from plaintext
62
+ // (astronomically unlikely with AEAD)
63
+ }
64
+ catch {
65
+ // Expected: AEAD authentication should fail with wrong key
66
+ }
67
+ }), { numRuns });
68
+ });
69
+ });
70
+ describe('XChaCha20-Poly1305 — wrong key fails decryption', () => {
71
+ it('should fail to decrypt with a different key', async () => {
72
+ await fc.assert(fc.asyncProperty(aes256Key(), aes256Key(), xchachaIv(), fc.uint8Array({ minLength: 1, maxLength: 256 }), async (key1, key2, iv, plaintext) => {
73
+ // Skip if keys are identical
74
+ if (key1.every((byte, i) => byte === key2[i])) {
75
+ return;
76
+ }
77
+ const { ciphertext, tag } = await Encryption.aeadEncrypt(ContentEncryptionAlgorithm.XC20P, key1, iv, plaintext);
78
+ try {
79
+ await Encryption.aeadDecrypt(ContentEncryptionAlgorithm.XC20P, key2, iv, ciphertext, tag);
80
+ }
81
+ catch {
82
+ // Expected: AEAD authentication should fail with wrong key
83
+ }
84
+ }), { numRuns });
85
+ });
86
+ });
87
+ describe('AES-256-GCM — tampered ciphertext fails decryption', () => {
88
+ it('should fail to decrypt when ciphertext is modified', async () => {
89
+ await fc.assert(fc.asyncProperty(aes256Key(), aesGcmIv(), fc.uint8Array({ minLength: 1, maxLength: 256 }), fc.nat(), async (key, iv, plaintext, flipIndex) => {
90
+ const { ciphertext, tag } = await Encryption.aeadEncrypt(ContentEncryptionAlgorithm.A256GCM, key, iv, plaintext);
91
+ if (ciphertext.length === 0) {
92
+ return; // skip empty ciphertext
93
+ }
94
+ // Flip a bit in the ciphertext
95
+ const tampered = new Uint8Array(ciphertext);
96
+ const idx = flipIndex % tampered.length;
97
+ tampered[idx] ^= 0xFF;
98
+ try {
99
+ await Encryption.aeadDecrypt(ContentEncryptionAlgorithm.A256GCM, key, iv, tampered, tag);
100
+ // If decryption somehow succeeds, data integrity has been compromised
101
+ // (astronomically unlikely with AEAD)
102
+ }
103
+ catch {
104
+ // Expected: AEAD authentication should fail on tampered ciphertext
105
+ }
106
+ }), { numRuns });
107
+ });
108
+ });
109
+ describe('encrypt — deterministic output for same inputs', () => {
110
+ it('should produce the same ciphertext and tag for the same key, IV, and plaintext', async () => {
111
+ await fc.assert(fc.asyncProperty(aes256Key(), aesGcmIv(), fc.uint8Array({ minLength: 0, maxLength: 256 }), async (key, iv, plaintext) => {
112
+ const result1 = await Encryption.aeadEncrypt(ContentEncryptionAlgorithm.A256GCM, key, iv, plaintext);
113
+ const result2 = await Encryption.aeadEncrypt(ContentEncryptionAlgorithm.A256GCM, key, iv, plaintext);
114
+ expect(result1.ciphertext).toEqual(result2.ciphertext);
115
+ expect(result1.tag).toEqual(result2.tag);
116
+ }), { numRuns });
117
+ });
118
+ });
119
+ describe('aeadDecrypt — crash resistance with malformed inputs', () => {
120
+ it('should throw (not crash) on wrong-length IVs for AES-GCM', async () => {
121
+ await fc.assert(fc.asyncProperty(aes256Key(), fc.uint8Array({ minLength: 0, maxLength: 50 }).filter((iv) => iv.length !== 12), fc.uint8Array({ minLength: 1, maxLength: 64 }), fc.uint8Array({ minLength: 16, maxLength: 16 }), async (key, badIv, ciphertext, tag) => {
122
+ try {
123
+ await Encryption.aeadDecrypt(ContentEncryptionAlgorithm.A256GCM, key, badIv, ciphertext, tag);
124
+ }
125
+ catch {
126
+ // Expected: wrong IV length should throw
127
+ }
128
+ }), { numRuns: Math.min(numRuns, 50) });
129
+ });
130
+ });
131
+ });
132
+ //# sourceMappingURL=encryption.fuzz.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.fuzz.spec.js","sourceRoot":"","sources":["../../../../tests/fuzz/encryption.fuzz.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,149 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+ import fc from 'fast-check';
3
+ import { equalFilter, filter, keyValues, oneOfFilter, rangeFilter } from './arbitraries/filter.arbitrary.js';
4
+ import { FilterSelector, FilterUtility } from '../../src/utils/filter.js';
5
+ const numRuns = Number(process.env.FAST_CHECK_NUM_RUNS) || 200;
6
+ describe('FilterUtility — fuzz', () => {
7
+ describe('matchFilter — empty filter matches everything', () => {
8
+ it('should return true for any keyValues when filter is empty', () => {
9
+ fc.assert(fc.property(keyValues(), (kv) => {
10
+ const result = FilterUtility.matchFilter(kv, {});
11
+ expect(result).toBe(true);
12
+ }), { numRuns });
13
+ });
14
+ });
15
+ describe('matchFilter — crash resistance', () => {
16
+ it('should not crash on arbitrary filter and keyValues combinations', () => {
17
+ fc.assert(fc.property(keyValues(), filter(), (kv, f) => {
18
+ // Should return a boolean without crashing
19
+ const result = FilterUtility.matchFilter(kv, f);
20
+ expect(typeof result).toBe('boolean');
21
+ }), { numRuns });
22
+ });
23
+ });
24
+ describe('matchAnyFilter — empty array matches everything', () => {
25
+ it('should return true when the filter array is empty', () => {
26
+ fc.assert(fc.property(keyValues(), (kv) => {
27
+ const result = FilterUtility.matchAnyFilter(kv, []);
28
+ expect(result).toBe(true);
29
+ }), { numRuns });
30
+ });
31
+ });
32
+ describe('matchFilter — equal filter consistency', () => {
33
+ it('should match when the indexed value equals the filter value', () => {
34
+ fc.assert(fc.property(fc.string({ minLength: 1, maxLength: 10 }), equalFilter(), (key, value) => {
35
+ const kv = { [key]: value };
36
+ const f = { [key]: value };
37
+ expect(FilterUtility.matchFilter(kv, f)).toBe(true);
38
+ }), { numRuns });
39
+ });
40
+ });
41
+ describe('matchFilter — oneOf filter contains value', () => {
42
+ it('should match when the indexed value is in the OneOfFilter array', () => {
43
+ fc.assert(fc.property(fc.string({ minLength: 1, maxLength: 10 }), oneOfFilter(), (key, values) => {
44
+ // Use the first value from the OneOf array as the indexed value
45
+ const indexValue = values[0];
46
+ const kv = { [key]: indexValue };
47
+ const f = { [key]: values };
48
+ expect(FilterUtility.matchFilter(kv, f)).toBe(true);
49
+ }), { numRuns });
50
+ });
51
+ });
52
+ describe('matchFilter — range filter within bounds', () => {
53
+ it('should match when a numeric value falls within the range', () => {
54
+ fc.assert(fc.property(fc.string({ minLength: 1, maxLength: 10 }), fc.integer({ min: -500, max: 500 }), (key, value) => {
55
+ // Create a range that definitely includes the value
56
+ const f = { [key]: { gte: value - 1, lt: value + 2 } };
57
+ const kv = { [key]: value };
58
+ expect(FilterUtility.matchFilter(kv, f)).toBe(true);
59
+ }), { numRuns });
60
+ });
61
+ });
62
+ describe('matchFilter — missing key returns false', () => {
63
+ it('should return false when the filter references a key not in keyValues', () => {
64
+ fc.assert(fc.property(fc.string({ minLength: 1, maxLength: 10 }), equalFilter(), (key, value) => {
65
+ // Empty keyValues, so any filter property should fail
66
+ const kv = {};
67
+ const f = { [key]: value };
68
+ expect(FilterUtility.matchFilter(kv, f)).toBe(false);
69
+ }), { numRuns });
70
+ });
71
+ });
72
+ describe('constructPrefixFilterAsRangeFilter — prefix match property', () => {
73
+ it('should match strings that start with the prefix', () => {
74
+ fc.assert(fc.property(fc.string({ minLength: 1, maxLength: 20 }), fc.string({ minLength: 0, maxLength: 20 }), (prefix, suffix) => {
75
+ const rangeFilterResult = FilterUtility.constructPrefixFilterAsRangeFilter(prefix);
76
+ const value = prefix + suffix;
77
+ // The value should be >= prefix and < prefix + \uffff
78
+ expect(value >= rangeFilterResult.gte).toBe(true);
79
+ expect(value < rangeFilterResult.lt).toBe(true);
80
+ }), { numRuns });
81
+ });
82
+ });
83
+ describe('isEqualFilter / isRangeFilter / isOneOfFilter — mutual exclusivity', () => {
84
+ it('should classify each filter value into exactly one category', () => {
85
+ fc.assert(fc.property(fc.oneof(equalFilter(), rangeFilter(), oneOfFilter()), (filterValue) => {
86
+ const isEqual = FilterUtility.isEqualFilter(filterValue);
87
+ const isRange = FilterUtility.isRangeFilter(filterValue);
88
+ const isOneOf = FilterUtility.isOneOfFilter(filterValue);
89
+ // Exactly one should be true
90
+ const trueCount = [isEqual, isRange, isOneOf].filter(Boolean).length;
91
+ expect(trueCount).toBe(1);
92
+ }), { numRuns });
93
+ });
94
+ });
95
+ describe('convertRangeCriterion — consistency', () => {
96
+ it('should produce a valid RangeFilter or undefined for any input', () => {
97
+ fc.assert(fc.property(fc.record({
98
+ from: fc.option(fc.string({ minLength: 1, maxLength: 30 }), { nil: undefined }),
99
+ to: fc.option(fc.string({ minLength: 1, maxLength: 30 }), { nil: undefined }),
100
+ }), (criterion) => {
101
+ const result = FilterUtility.convertRangeCriterion(criterion);
102
+ if (criterion.from === undefined && criterion.to === undefined) {
103
+ expect(result).toBeUndefined();
104
+ }
105
+ else {
106
+ expect(result).toBeDefined();
107
+ if (criterion.from !== undefined) {
108
+ expect(result.gte).toBe(criterion.from);
109
+ }
110
+ if (criterion.to !== undefined) {
111
+ expect(result.lt).toBe(criterion.to);
112
+ }
113
+ }
114
+ }), { numRuns });
115
+ });
116
+ });
117
+ });
118
+ describe('FilterSelector — fuzz', () => {
119
+ describe('reduceFilter — returns a subset', () => {
120
+ it('should return a filter with at most 1 property', () => {
121
+ fc.assert(fc.property(filter(), (f) => {
122
+ const reduced = FilterSelector.reduceFilter(f);
123
+ const reducedKeys = Object.keys(reduced);
124
+ // If input had 0 or 1 keys, reduced should be the same
125
+ const inputKeys = Object.keys(f);
126
+ if (inputKeys.length <= 1) {
127
+ expect(reduced).toEqual(f);
128
+ }
129
+ else {
130
+ // Otherwise, reduced should have exactly 1 key
131
+ expect(reducedKeys.length).toBe(1);
132
+ }
133
+ }), { numRuns });
134
+ });
135
+ });
136
+ describe('reduceFilter — reduced key is from original filter', () => {
137
+ it('should select a key that exists in the original filter', () => {
138
+ fc.assert(fc.property(filter(), (f) => {
139
+ const reduced = FilterSelector.reduceFilter(f);
140
+ const reducedKeys = Object.keys(reduced);
141
+ const originalKeys = Object.keys(f);
142
+ for (const key of reducedKeys) {
143
+ expect(originalKeys).toContain(key);
144
+ }
145
+ }), { numRuns });
146
+ });
147
+ });
148
+ });
149
+ //# sourceMappingURL=filter.fuzz.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.fuzz.spec.js","sourceRoot":"","sources":["../../../../tests/fuzz/filter.fuzz.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+ import fc from 'fast-check';
3
+ import { getRuleSetAtPath } from '../../src/utils/protocols.js';
4
+ const numRuns = Number(process.env.FAST_CHECK_NUM_RUNS) || 100;
5
+ describe('getRuleSetAtPath — fuzz', () => {
6
+ /**
7
+ * Arbitrary for a valid type name segment (no slashes, non-empty, no $ prefix).
8
+ * Deliberately includes Object.prototype names like "toString" and "valueOf"
9
+ * to verify that the function is immune to prototype pollution.
10
+ */
11
+ const arbTypeName = fc.string({ minLength: 1, maxLength: 10 })
12
+ .filter((s) => !s.includes('/') && !s.startsWith('$'));
13
+ describe('single-level path resolution', () => {
14
+ it('should return the rule set for a root-level type', () => {
15
+ fc.assert(fc.property(arbTypeName, (typeName) => {
16
+ const ruleSet = { $size: { min: 0, max: 100 } };
17
+ const structure = { [typeName]: ruleSet };
18
+ const result = getRuleSetAtPath(typeName, structure);
19
+ expect(result).toBe(ruleSet);
20
+ }), { numRuns });
21
+ });
22
+ });
23
+ describe('nested path resolution', () => {
24
+ it('should walk nested structure segments correctly', () => {
25
+ fc.assert(fc.property(fc.array(arbTypeName, { minLength: 2, maxLength: 4 })
26
+ .filter((segs) => new Set(segs).size === segs.length), // unique segments
27
+ (segments) => {
28
+ // Build a nested structure: segments[0] > segments[1] > ... > leaf
29
+ const leafRuleSet = { $role: true };
30
+ let current = { [segments[segments.length - 1]]: leafRuleSet };
31
+ for (let i = segments.length - 2; i >= 0; i--) {
32
+ current = { [segments[i]]: current };
33
+ }
34
+ const protocolPath = segments.join('/');
35
+ const result = getRuleSetAtPath(protocolPath, current);
36
+ expect(result).toBe(leafRuleSet);
37
+ }), { numRuns });
38
+ });
39
+ });
40
+ describe('missing path returns undefined', () => {
41
+ it('should return undefined for a path that does not exist', () => {
42
+ fc.assert(fc.property(arbTypeName, arbTypeName.filter((s) => s !== 'existing'), (missingName, _otherName) => {
43
+ const structure = { existing: { $size: { min: 0 } } };
44
+ // Only if missingName !== 'existing' will this be undefined
45
+ if (missingName === 'existing') {
46
+ return;
47
+ }
48
+ const result = getRuleSetAtPath(missingName, structure);
49
+ expect(result).toBeUndefined();
50
+ }), { numRuns });
51
+ });
52
+ });
53
+ describe('deep missing path returns undefined', () => {
54
+ it('should return undefined when an intermediate segment is missing', () => {
55
+ fc.assert(fc.property(arbTypeName, arbTypeName, arbTypeName, (seg1, seg2, missing) => {
56
+ // Only test when 'missing' differs from seg2 to guarantee the path doesn't exist
57
+ if (missing === seg2) {
58
+ return;
59
+ }
60
+ const structure = {
61
+ [seg1]: {
62
+ [seg2]: { $role: true },
63
+ },
64
+ };
65
+ const result = getRuleSetAtPath(`${seg1}/${missing}`, structure);
66
+ expect(result).toBeUndefined();
67
+ }), { numRuns });
68
+ });
69
+ });
70
+ describe('prototype pollution immunity', () => {
71
+ it('should return undefined for Object.prototype property names not in the structure', () => {
72
+ const prototypeNames = Object.getOwnPropertyNames(Object.prototype)
73
+ .filter((name) => /^[a-zA-Z]+$/.test(name)); // only names valid as protocolPath segments
74
+ const structure = { message: { $size: { min: 0 } } };
75
+ for (const name of prototypeNames) {
76
+ const result = getRuleSetAtPath(name, structure);
77
+ expect(result).toBeUndefined();
78
+ }
79
+ });
80
+ });
81
+ });
82
+ //# sourceMappingURL=get-rule-set-at-path.fuzz.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-rule-set-at-path.fuzz.spec.js","sourceRoot":"","sources":["../../../../tests/fuzz/get-rule-set-at-path.fuzz.spec.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAEhD,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEhE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,GAAG,CAAC;AAE/D,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IAEvC;;;;OAIG;IACH,MAAM,WAAW,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;SAC3D,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAEzD,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;QAC5C,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;YAC1D,EAAE,CAAC,MAAM,CACP,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,EAAE;gBACpC,MAAM,OAAO,GAAoB,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC;gBACjE,MAAM,SAAS,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;gBAC1C,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;gBACrD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC,CAAC,EACF,EAAE,OAAO,EAAE,CACZ,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;QACtC,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;YACzD,EAAE,CAAC,MAAM,CACP,EAAE,CAAC,QAAQ,CACT,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;iBAClD,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,EAAE,kBAAkB;YAC3E,CAAC,QAAQ,EAAE,EAAE;gBACX,mEAAmE;gBACnE,MAAM,WAAW,GAAoB,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;gBAErD,IAAI,OAAO,GAAuC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;gBACnG,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC9C,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,OAAqC,EAAE,CAAC;gBACrE,CAAC;gBAED,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACxC,MAAM,MAAM,GAAG,gBAAgB,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;gBACvD,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACnC,CAAC,CACF,EACD,EAAE,OAAO,EAAE,CACZ,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;QAC9C,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;YAChE,EAAE,CAAC,MAAM,CACP,EAAE,CAAC,QAAQ,CACT,WAAW,EACX,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,UAAU,CAAC,EAC3C,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE;gBAC1B,MAAM,SAAS,GAAG,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,EAAqB,EAAE,CAAC;gBACzE,4DAA4D;gBAC5D,IAAI,WAAW,KAAK,UAAU,EAAE,CAAC;oBAC/B,OAAO;gBACT,CAAC;gBACD,MAAM,MAAM,GAAG,gBAAgB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;gBACxD,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;YACjC,CAAC,CACF,EACD,EAAE,OAAO,EAAE,CACZ,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,qCAAqC,EAAE,GAAG,EAAE;QACnD,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;YACzE,EAAE,CAAC,MAAM,CACP,EAAE,CAAC,QAAQ,CACT,WAAW,EACX,WAAW,EACX,WAAW,EACX,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;gBACtB,iFAAiF;gBACjF,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;oBACrB,OAAO;gBACT,CAAC;gBACD,MAAM,SAAS,GAAG;oBAChB,CAAC,IAAI,CAAC,EAAE;wBACN,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAqB;qBACb;iBAChC,CAAC;gBACF,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,IAAI,IAAI,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;gBACjE,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;YACjC,CAAC,CACF,EACD,EAAE,OAAO,EAAE,CACZ,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;QAC5C,EAAE,CAAC,kFAAkF,EAAE,GAAG,EAAE;YAC1F,MAAM,cAAc,GAAG,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,SAAS,CAAC;iBAChE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,4CAA4C;YAE3F,MAAM,SAAS,GAAG,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,EAAqB,EAAE,CAAC;YAExE,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;gBAClC,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;gBACjD,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,EAAE,CAAC;YACjC,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,77 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+ import fc from 'fast-check';
3
+ import { DwnErrorCode } from '../../src/core/dwn-error.js';
4
+ import { Encoder } from '../../src/utils/encoder.js';
5
+ import { HdKey } from '../../src/utils/hd-key.js';
6
+ const numRuns = Number(process.env.FAST_CHECK_NUM_RUNS) || 100;
7
+ describe('HdKey — fuzz', () => {
8
+ /**
9
+ * Generate a valid 32-byte key for use as base key material.
10
+ */
11
+ const arbPrivateKey = fc.uint8Array({ minLength: 32, maxLength: 32 });
12
+ /**
13
+ * A non-empty derivation path segment (no empty strings allowed).
14
+ */
15
+ const arbSegment = fc.string({ minLength: 1, maxLength: 20 });
16
+ /**
17
+ * A valid derivation path (1–5 non-empty segments).
18
+ */
19
+ const arbPath = fc.array(arbSegment, { minLength: 1, maxLength: 5 });
20
+ describe('derivePrivateKeyBytes — determinism', () => {
21
+ it('should produce identical output for identical inputs', async () => {
22
+ await fc.assert(fc.asyncProperty(arbPrivateKey, arbPath, async (key, path) => {
23
+ const result1 = await HdKey.derivePrivateKeyBytes(key, path);
24
+ const result2 = await HdKey.derivePrivateKeyBytes(key, path);
25
+ expect(Encoder.bytesToBase64Url(result1)).toBe(Encoder.bytesToBase64Url(result2));
26
+ }), { numRuns });
27
+ });
28
+ });
29
+ describe('derivePrivateKeyBytes — output size', () => {
30
+ it('should always produce a 32-byte derived key', async () => {
31
+ await fc.assert(fc.asyncProperty(arbPrivateKey, arbPath, async (key, path) => {
32
+ const result = await HdKey.derivePrivateKeyBytes(key, path);
33
+ expect(result.byteLength).toBe(32);
34
+ }), { numRuns });
35
+ });
36
+ });
37
+ describe('derivePrivateKeyBytes — path order sensitivity', () => {
38
+ it('should produce different keys for reversed non-palindrome paths', async () => {
39
+ await fc.assert(fc.asyncProperty(arbPrivateKey, fc.array(arbSegment, { minLength: 2, maxLength: 5 }).filter((segs) => {
40
+ // ensure path is NOT a palindrome so reversing changes it
41
+ const reversed = [...segs].reverse();
42
+ return segs.some((s, i) => s !== reversed[i]);
43
+ }), async (key, path) => {
44
+ const forward = await HdKey.derivePrivateKeyBytes(key, path);
45
+ const reversed = await HdKey.derivePrivateKeyBytes(key, [...path].reverse());
46
+ // different path order should produce different key (with overwhelming probability)
47
+ const forwardB64 = Encoder.bytesToBase64Url(forward);
48
+ const reversedB64 = Encoder.bytesToBase64Url(reversed);
49
+ expect(forwardB64).not.toBe(reversedB64);
50
+ }), { numRuns });
51
+ });
52
+ });
53
+ describe('derivePrivateKeyBytes — incremental derivation equivalence', () => {
54
+ it('should produce the same key whether derived all at once or incrementally', async () => {
55
+ await fc.assert(fc.asyncProperty(arbPrivateKey, fc.array(arbSegment, { minLength: 2, maxLength: 5 }), fc.integer({ min: 1 }).chain((splitCandidate) => fc.constant(splitCandidate)), async (key, path, splitCandidate) => {
56
+ // Split the path at an arbitrary point
57
+ const splitIndex = (splitCandidate % (path.length - 1)) + 1;
58
+ const prefix = path.slice(0, splitIndex);
59
+ const suffix = path.slice(splitIndex);
60
+ // Derive all at once
61
+ const allAtOnce = await HdKey.derivePrivateKeyBytes(key, path);
62
+ // Derive incrementally: first prefix, then suffix from intermediate key
63
+ const intermediate = await HdKey.derivePrivateKeyBytes(key, prefix);
64
+ const incremental = await HdKey.derivePrivateKeyBytes(intermediate, suffix);
65
+ expect(Encoder.bytesToBase64Url(allAtOnce)).toBe(Encoder.bytesToBase64Url(incremental));
66
+ }), { numRuns });
67
+ });
68
+ });
69
+ describe('derivePrivateKeyBytes — empty segment rejection', () => {
70
+ it('should throw HdKeyDerivationPathInvalid when any segment is empty', async () => {
71
+ await fc.assert(fc.asyncProperty(arbPrivateKey, fc.array(fc.string({ maxLength: 10 }), { minLength: 1, maxLength: 5 }).filter((segs) => segs.some((s) => s === '')), async (key, pathWithEmpty) => {
72
+ await expect(HdKey.derivePrivateKeyBytes(key, pathWithEmpty)).rejects.toThrow(DwnErrorCode.HdKeyDerivationPathInvalid);
73
+ }), { numRuns });
74
+ });
75
+ });
76
+ });
77
+ //# sourceMappingURL=hd-key.fuzz.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hd-key.fuzz.spec.js","sourceRoot":"","sources":["../../../../tests/fuzz/hd-key.fuzz.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+ import fc from 'fast-check';
3
+ import { DwnErrorCode } from '../../src/core/dwn-error.js';
4
+ import { verifyEqualityOfImmutableProperties } from '../../src/interfaces/records-write-query.js';
5
+ const numRuns = Number(process.env.FAST_CHECK_NUM_RUNS) || 100;
6
+ /** The properties that verifyEqualityOfImmutableProperties treats as mutable. */
7
+ const mutableProps = ['dataCid', 'dataSize', 'dataFormat', 'datePublished', 'published', 'messageTimestamp', 'tags'];
8
+ /** Generates a minimal RecordsWrite descriptor with all immutable and mutable fields. */
9
+ function recordsWriteDescriptor() {
10
+ return fc.record({
11
+ // Immutable fields
12
+ interface: fc.constant('Records'),
13
+ method: fc.constant('Write'),
14
+ protocol: fc.string({ minLength: 5, maxLength: 30 }),
15
+ protocolPath: fc.string({ minLength: 3, maxLength: 20 }),
16
+ schema: fc.string({ minLength: 5, maxLength: 30 }),
17
+ dateCreated: fc.constant('2024-01-01T00:00:00.000000Z'),
18
+ // Mutable fields
19
+ dataCid: fc.string({ minLength: 10, maxLength: 40 }),
20
+ dataSize: fc.integer({ min: 0, max: 100000 }),
21
+ dataFormat: fc.string({ minLength: 3, maxLength: 20 }),
22
+ messageTimestamp: fc.constant('2024-06-01T00:00:00.000000Z'),
23
+ });
24
+ }
25
+ /** Wraps a descriptor in a minimal RecordsWriteMessage shape. */
26
+ function wrapMessage(descriptor) {
27
+ return { descriptor };
28
+ }
29
+ describe('verifyEqualityOfImmutableProperties — fuzz', () => {
30
+ describe('reflexivity', () => {
31
+ it('should never throw when comparing a message with itself', () => {
32
+ fc.assert(fc.property(recordsWriteDescriptor(), (descriptor) => {
33
+ const msg = wrapMessage(descriptor);
34
+ expect(verifyEqualityOfImmutableProperties(msg, msg)).toBe(true);
35
+ }), { numRuns });
36
+ });
37
+ });
38
+ describe('symmetry', () => {
39
+ it('should succeed in both directions when only mutable fields differ', () => {
40
+ fc.assert(fc.property(recordsWriteDescriptor(), recordsWriteDescriptor(), (desc1, desc2) => {
41
+ // Copy immutable fields from desc1 to desc2 so only mutable fields differ
42
+ for (const key of Object.keys(desc1)) {
43
+ if (!mutableProps.includes(key)) {
44
+ desc2[key] = desc1[key];
45
+ }
46
+ }
47
+ const msg1 = wrapMessage(desc1);
48
+ const msg2 = wrapMessage(desc2);
49
+ expect(verifyEqualityOfImmutableProperties(msg1, msg2)).toBe(true);
50
+ expect(verifyEqualityOfImmutableProperties(msg2, msg1)).toBe(true);
51
+ }), { numRuns });
52
+ });
53
+ });
54
+ describe('mutable properties are free', () => {
55
+ it('should not throw when only mutable properties are changed', () => {
56
+ fc.assert(fc.property(recordsWriteDescriptor(), fc.string({ minLength: 5, maxLength: 40 }), fc.integer({ min: 0, max: 100000 }), fc.string({ minLength: 3, maxLength: 20 }), (descriptor, newDataCid, newDataSize, newDataFormat) => {
57
+ const modified = {
58
+ ...descriptor,
59
+ dataCid: newDataCid,
60
+ dataSize: newDataSize,
61
+ dataFormat: newDataFormat,
62
+ messageTimestamp: '2025-01-01T00:00:00.000000Z',
63
+ };
64
+ const msg1 = wrapMessage(descriptor);
65
+ const msg2 = wrapMessage(modified);
66
+ expect(verifyEqualityOfImmutableProperties(msg1, msg2)).toBe(true);
67
+ }), { numRuns });
68
+ });
69
+ });
70
+ describe('immutable properties are strict', () => {
71
+ it('should throw when any immutable property is changed', () => {
72
+ const immutableProps = ['interface', 'method', 'protocol', 'protocolPath', 'schema', 'dateCreated'];
73
+ fc.assert(fc.property(recordsWriteDescriptor(), fc.constantFrom(...immutableProps), fc.string({ minLength: 1, maxLength: 10 }), (descriptor, propToChange, newValue) => {
74
+ // Ensure the new value is actually different
75
+ if (descriptor[propToChange] === newValue) {
76
+ return;
77
+ }
78
+ const modified = { ...descriptor, [propToChange]: newValue };
79
+ const msg1 = wrapMessage(descriptor);
80
+ const msg2 = wrapMessage(modified);
81
+ expect(() => verifyEqualityOfImmutableProperties(msg1, msg2)).toThrow(DwnErrorCode.RecordsWriteImmutablePropertyChanged);
82
+ }), { numRuns });
83
+ });
84
+ });
85
+ });
86
+ //# sourceMappingURL=immutable-properties.fuzz.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"immutable-properties.fuzz.spec.js","sourceRoot":"","sources":["../../../../tests/fuzz/immutable-properties.fuzz.spec.ts"],"names":[],"mappings":"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"}