@beclab/olaresid 0.1.13 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLI-TREE.md +107 -0
- package/CLI.md +122 -1340
- package/README.md +30 -12
- package/SDK-TREE.md +151 -0
- package/TAG.md +95 -41
- package/config.json +6 -4
- package/dist/abi/TerminusDIDQueryABI.d.ts +397 -0
- package/dist/abi/TerminusDIDQueryABI.d.ts.map +1 -0
- package/dist/abi/TerminusDIDQueryABI.js +519 -0
- package/dist/abi/TerminusDIDQueryABI.js.map +1 -0
- package/dist/business/index.d.ts.map +1 -1
- package/dist/business/index.js +9 -23
- package/dist/business/index.js.map +1 -1
- package/dist/business/tag-context.d.ts +1 -0
- package/dist/business/tag-context.d.ts.map +1 -1
- package/dist/business/tag-context.js +13 -7
- package/dist/business/tag-context.js.map +1 -1
- package/dist/cli.js +177 -76
- package/dist/cli.js.map +1 -1
- package/dist/config/index.d.ts +16 -4
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +28 -14
- package/dist/config/index.js.map +1 -1
- package/dist/domain/core.d.ts +65 -0
- package/dist/domain/core.d.ts.map +1 -0
- package/dist/domain/core.js +317 -0
- package/dist/domain/core.js.map +1 -0
- package/dist/domain/index.d.ts +104 -57
- package/dist/domain/index.d.ts.map +1 -1
- package/dist/domain/index.js +188 -428
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/types.d.ts +56 -0
- package/dist/domain/types.d.ts.map +1 -0
- package/dist/domain/types.js +3 -0
- package/dist/domain/types.js.map +1 -0
- package/dist/index.d.ts +81 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +158 -143
- package/dist/index.js.map +1 -1
- package/dist/utils/crypto-utils.d.ts +110 -0
- package/dist/utils/crypto-utils.d.ts.map +1 -1
- package/dist/utils/crypto-utils.js +127 -8
- package/dist/utils/crypto-utils.js.map +1 -1
- package/dist/utils/error-parser.d.ts.map +1 -1
- package/dist/utils/error-parser.js +2 -1
- package/dist/utils/error-parser.js.map +1 -1
- package/dist/utils/event-parser.d.ts +161 -0
- package/dist/utils/event-parser.d.ts.map +1 -0
- package/dist/utils/event-parser.js +140 -0
- package/dist/utils/event-parser.js.map +1 -0
- package/dist/utils/tag-type-builder.d.ts +43 -0
- package/dist/utils/tag-type-builder.d.ts.map +1 -1
- package/dist/utils/tag-type-builder.js +122 -0
- package/dist/utils/tag-type-builder.js.map +1 -1
- package/dist/utils/tag-type-parser.d.ts +70 -0
- package/dist/utils/tag-type-parser.d.ts.map +1 -0
- package/dist/utils/tag-type-parser.js +190 -0
- package/dist/utils/tag-type-parser.js.map +1 -0
- package/examples/create-with-rpc-demo.ts +142 -0
- package/examples/fetch-all-flat-demo.ts +159 -0
- package/examples/fetch-by-indices-demo.ts +235 -0
- package/examples/fetch-domain-demo.ts +137 -0
- package/examples/fetch-domains-demo.ts +221 -0
- package/examples/frontend-demo/index.html +2 -2
- package/examples/frontend-demo/package-lock.json +4 -1
- package/examples/index.ts +3 -5
- package/jest.config.js +25 -0
- package/package.json +6 -2
- package/src/abi/TerminusDIDQueryABI.ts +516 -0
- package/src/business/index.ts +9 -33
- package/src/business/tag-context.ts +35 -7
- package/src/cli.ts +253 -90
- package/src/config/index.ts +34 -19
- package/src/domain/core.ts +382 -0
- package/src/domain/index.ts +271 -641
- package/src/domain/types.ts +59 -0
- package/src/index.ts +230 -207
- package/src/utils/crypto-utils.ts +205 -2
- package/src/utils/error-parser.ts +2 -1
- package/src/utils/event-parser.ts +353 -0
- package/src/utils/tag-type-builder.ts +138 -0
- package/src/utils/tag-type-parser.ts +246 -0
- package/tests/unit/crypto-utils.test.ts +338 -0
- package/tests/unit/ed25519-jwk.test.ts +201 -0
- package/tests/unit/event-parser.test.ts +690 -0
- package/tests/unit/generate-mnemonic.test.ts +268 -0
- package/tests/unit/olares-id-format.test.ts +321 -0
- package/tests/unit/tag-type-parser.test.ts +802 -0
- package/tests/unit/tag-types.test.ts +821 -0
- package/tests/unit/version.test.ts +14 -0
- package/tsconfig.json +3 -2
- package/dist/abi/ABITypeABI.d.ts +0 -88
- package/dist/abi/ABITypeABI.d.ts.map +0 -1
- package/dist/abi/ABITypeABI.js +0 -382
- package/dist/abi/ABITypeABI.js.map +0 -1
- package/dist/abi/RegistryABI.d.ts +0 -77
- package/dist/abi/RegistryABI.d.ts.map +0 -1
- package/dist/abi/RegistryABI.js +0 -462
- package/dist/abi/RegistryABI.js.map +0 -1
- package/dist/tag/address.d.ts +0 -11
- package/dist/tag/address.d.ts.map +0 -1
- package/dist/tag/address.js +0 -44
- package/dist/tag/address.js.map +0 -1
- package/dist/tag/array.d.ts +0 -14
- package/dist/tag/array.d.ts.map +0 -1
- package/dist/tag/array.js +0 -72
- package/dist/tag/array.js.map +0 -1
- package/dist/tag/bool.d.ts +0 -11
- package/dist/tag/bool.d.ts.map +0 -1
- package/dist/tag/bool.js +0 -43
- package/dist/tag/bool.js.map +0 -1
- package/dist/tag/bytes.d.ts +0 -11
- package/dist/tag/bytes.d.ts.map +0 -1
- package/dist/tag/bytes.js +0 -37
- package/dist/tag/bytes.js.map +0 -1
- package/dist/tag/flarray.d.ts +0 -15
- package/dist/tag/flarray.d.ts.map +0 -1
- package/dist/tag/flarray.js +0 -81
- package/dist/tag/flarray.js.map +0 -1
- package/dist/tag/flbytes.d.ts +0 -11
- package/dist/tag/flbytes.d.ts.map +0 -1
- package/dist/tag/flbytes.js +0 -47
- package/dist/tag/flbytes.js.map +0 -1
- package/dist/tag/index.d.ts +0 -32
- package/dist/tag/index.d.ts.map +0 -1
- package/dist/tag/index.js +0 -121
- package/dist/tag/index.js.map +0 -1
- package/dist/tag/int.d.ts +0 -12
- package/dist/tag/int.d.ts.map +0 -1
- package/dist/tag/int.js +0 -49
- package/dist/tag/int.js.map +0 -1
- package/dist/tag/string.d.ts +0 -11
- package/dist/tag/string.d.ts.map +0 -1
- package/dist/tag/string.js +0 -37
- package/dist/tag/string.js.map +0 -1
- package/dist/tag/tag.d.ts +0 -67
- package/dist/tag/tag.d.ts.map +0 -1
- package/dist/tag/tag.js +0 -157
- package/dist/tag/tag.js.map +0 -1
- package/dist/tag/tuple.d.ts +0 -17
- package/dist/tag/tuple.d.ts.map +0 -1
- package/dist/tag/tuple.js +0 -162
- package/dist/tag/tuple.js.map +0 -1
- package/dist/tag/uint.d.ts +0 -12
- package/dist/tag/uint.d.ts.map +0 -1
- package/dist/tag/uint.js +0 -49
- package/dist/tag/uint.js.map +0 -1
- package/dist/test/did.d.ts +0 -2
- package/dist/test/did.d.ts.map +0 -1
- package/dist/test/did.js +0 -177
- package/dist/test/did.js.map +0 -1
- package/dist/utils/tag-abi-codec.d.ts +0 -69
- package/dist/utils/tag-abi-codec.d.ts.map +0 -1
- package/dist/utils/tag-abi-codec.js +0 -144
- package/dist/utils/tag-abi-codec.js.map +0 -1
- package/examples/crypto-utilities.ts +0 -140
- package/examples/ed25519-jwk.ts +0 -73
- package/examples/generate-mnemonic.ts +0 -149
- package/examples/legacy.ts +0 -33
- package/examples/olares-id-format.ts +0 -197
- package/examples/tag-builder.ts +0 -235
- package/examples/tag-nested-tuple.ts +0 -190
- package/examples/tag-simple.ts +0 -149
- package/examples/tag-tagger.ts +0 -217
- package/examples/test-nested-tuple-conversion.ts +0 -143
- package/examples/test-type-bytes-parser.ts +0 -70
- package/src/abi/ABITypeABI.ts +0 -379
- package/src/abi/RegistryABI.ts +0 -459
- package/src/tag/address.ts +0 -48
- package/src/tag/array.ts +0 -80
- package/src/tag/bool.ts +0 -43
- package/src/tag/bytes.ts +0 -38
- package/src/tag/flarray.ts +0 -99
- package/src/tag/flbytes.ts +0 -48
- package/src/tag/index.ts +0 -170
- package/src/tag/int.ts +0 -51
- package/src/tag/string.ts +0 -38
- package/src/tag/tag.ts +0 -229
- package/src/tag/tuple.ts +0 -193
- package/src/tag/uint.ts +0 -51
- package/src/test/did.ts +0 -346
- package/src/utils/tag-abi-codec.ts +0 -158
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for mnemonic generation and key derivation
|
|
3
|
+
*
|
|
4
|
+
* Tests the integration with Trust Wallet Core for:
|
|
5
|
+
* - Mnemonic generation (12 and 24 words)
|
|
6
|
+
* - Ethereum address derivation
|
|
7
|
+
* - DID derivation
|
|
8
|
+
* - Combined key generation
|
|
9
|
+
* - Compatibility with TermiPass
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
generateMnemonic,
|
|
14
|
+
getEthereumAddressFromMnemonic,
|
|
15
|
+
getDIDFromMnemonic,
|
|
16
|
+
generateDIDKeyData,
|
|
17
|
+
deriveDIDFromMnemonic
|
|
18
|
+
} from '../../src/index';
|
|
19
|
+
|
|
20
|
+
describe('Mnemonic Generation', () => {
|
|
21
|
+
describe('generateMnemonic', () => {
|
|
22
|
+
test('should generate 12-word mnemonic', () => {
|
|
23
|
+
const mnemonic = generateMnemonic(12);
|
|
24
|
+
const words = mnemonic.split(' ');
|
|
25
|
+
|
|
26
|
+
expect(words.length).toBe(12);
|
|
27
|
+
expect(mnemonic).toBeTruthy();
|
|
28
|
+
expect(typeof mnemonic).toBe('string');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('should generate 24-word mnemonic', () => {
|
|
32
|
+
const mnemonic = generateMnemonic(24);
|
|
33
|
+
const words = mnemonic.split(' ');
|
|
34
|
+
|
|
35
|
+
expect(words.length).toBe(24);
|
|
36
|
+
expect(mnemonic).toBeTruthy();
|
|
37
|
+
expect(typeof mnemonic).toBe('string');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('should generate different mnemonics each time', () => {
|
|
41
|
+
const mnemonic1 = generateMnemonic(12);
|
|
42
|
+
const mnemonic2 = generateMnemonic(12);
|
|
43
|
+
|
|
44
|
+
expect(mnemonic1).not.toBe(mnemonic2);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('generated mnemonic should be valid BIP39', () => {
|
|
48
|
+
const mnemonic = generateMnemonic(12);
|
|
49
|
+
// Validate format: lowercase words separated by spaces
|
|
50
|
+
expect(mnemonic).toMatch(/^[a-z]+( [a-z]+)*$/);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('Key Derivation from Mnemonic', () => {
|
|
55
|
+
test('should derive Ethereum address from 12-word mnemonic', async () => {
|
|
56
|
+
const mnemonic = generateMnemonic(12);
|
|
57
|
+
const address = await getEthereumAddressFromMnemonic(mnemonic);
|
|
58
|
+
|
|
59
|
+
expect(address).toBeTruthy();
|
|
60
|
+
expect(address).toMatch(/^0x[a-fA-F0-9]{40}$/);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('should derive Ethereum address from 24-word mnemonic', async () => {
|
|
64
|
+
const mnemonic = generateMnemonic(24);
|
|
65
|
+
const address = await getEthereumAddressFromMnemonic(mnemonic);
|
|
66
|
+
|
|
67
|
+
expect(address).toBeTruthy();
|
|
68
|
+
expect(address).toMatch(/^0x[a-fA-F0-9]{40}$/);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('should derive DID from 12-word mnemonic', async () => {
|
|
72
|
+
const mnemonic = generateMnemonic(12);
|
|
73
|
+
const did = await getDIDFromMnemonic(mnemonic);
|
|
74
|
+
|
|
75
|
+
expect(did).toBeTruthy();
|
|
76
|
+
expect(did).toMatch(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test('should derive DID from 24-word mnemonic', async () => {
|
|
80
|
+
const mnemonic = generateMnemonic(24);
|
|
81
|
+
const did = await getDIDFromMnemonic(mnemonic);
|
|
82
|
+
|
|
83
|
+
expect(did).toBeTruthy();
|
|
84
|
+
expect(did).toMatch(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('same mnemonic should produce same keys', async () => {
|
|
88
|
+
const mnemonic = generateMnemonic(12);
|
|
89
|
+
|
|
90
|
+
const address1 = await getEthereumAddressFromMnemonic(mnemonic);
|
|
91
|
+
const address2 = await getEthereumAddressFromMnemonic(mnemonic);
|
|
92
|
+
|
|
93
|
+
const did1 = await getDIDFromMnemonic(mnemonic);
|
|
94
|
+
const did2 = await getDIDFromMnemonic(mnemonic);
|
|
95
|
+
|
|
96
|
+
expect(address1).toBe(address2);
|
|
97
|
+
expect(did1).toBe(did2);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('different mnemonics should produce different keys', async () => {
|
|
101
|
+
const mnemonic1 = generateMnemonic(12);
|
|
102
|
+
const mnemonic2 = generateMnemonic(12);
|
|
103
|
+
|
|
104
|
+
const address1 = await getEthereumAddressFromMnemonic(mnemonic1);
|
|
105
|
+
const address2 = await getEthereumAddressFromMnemonic(mnemonic2);
|
|
106
|
+
|
|
107
|
+
const did1 = await getDIDFromMnemonic(mnemonic1);
|
|
108
|
+
const did2 = await getDIDFromMnemonic(mnemonic2);
|
|
109
|
+
|
|
110
|
+
expect(address1).not.toBe(address2);
|
|
111
|
+
expect(did1).not.toBe(did2);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe('generateDIDKeyData', () => {
|
|
116
|
+
test('should generate complete key data with 12-word mnemonic', async () => {
|
|
117
|
+
const keyData = await generateDIDKeyData(12);
|
|
118
|
+
|
|
119
|
+
expect(keyData).toBeDefined();
|
|
120
|
+
expect(keyData.mnemonic).toBeTruthy();
|
|
121
|
+
expect(keyData.owner).toMatch(/^0x[a-fA-F0-9]{40}$/);
|
|
122
|
+
expect(keyData.did).toMatch(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/);
|
|
123
|
+
|
|
124
|
+
const words = keyData.mnemonic.split(' ');
|
|
125
|
+
expect(words.length).toBe(12);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('should generate complete key data with 24-word mnemonic', async () => {
|
|
129
|
+
const keyData = await generateDIDKeyData(24);
|
|
130
|
+
|
|
131
|
+
expect(keyData).toBeDefined();
|
|
132
|
+
expect(keyData.mnemonic).toBeTruthy();
|
|
133
|
+
expect(keyData.owner).toMatch(/^0x[a-fA-F0-9]{40}$/);
|
|
134
|
+
expect(keyData.did).toMatch(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/);
|
|
135
|
+
|
|
136
|
+
const words = keyData.mnemonic.split(' ');
|
|
137
|
+
expect(words.length).toBe(24);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test('generated keys should match individual derivation', async () => {
|
|
141
|
+
const keyData = await generateDIDKeyData(12);
|
|
142
|
+
|
|
143
|
+
const ownerFromMnemonic = await getEthereumAddressFromMnemonic(
|
|
144
|
+
keyData.mnemonic
|
|
145
|
+
);
|
|
146
|
+
const didFromMnemonic = await getDIDFromMnemonic(keyData.mnemonic);
|
|
147
|
+
|
|
148
|
+
expect(keyData.owner).toBe(ownerFromMnemonic);
|
|
149
|
+
expect(keyData.did).toBe(didFromMnemonic);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe('deriveDIDFromMnemonic', () => {
|
|
154
|
+
test('should derive both owner and DID in one call', async () => {
|
|
155
|
+
const mnemonic = generateMnemonic(12);
|
|
156
|
+
const { owner, did } = await deriveDIDFromMnemonic(mnemonic);
|
|
157
|
+
|
|
158
|
+
expect(owner).toMatch(/^0x[a-fA-F0-9]{40}$/);
|
|
159
|
+
expect(did).toMatch(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test('should match individual derivation results', async () => {
|
|
163
|
+
const mnemonic = generateMnemonic(12);
|
|
164
|
+
|
|
165
|
+
const { owner, did } = await deriveDIDFromMnemonic(mnemonic);
|
|
166
|
+
const ownerIndividual = await getEthereumAddressFromMnemonic(
|
|
167
|
+
mnemonic
|
|
168
|
+
);
|
|
169
|
+
const didIndividual = await getDIDFromMnemonic(mnemonic);
|
|
170
|
+
|
|
171
|
+
expect(owner).toBe(ownerIndividual);
|
|
172
|
+
expect(did).toBe(didIndividual);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test('should be performant (complete in reasonable time)', async () => {
|
|
176
|
+
const mnemonic = generateMnemonic(12);
|
|
177
|
+
const startTime = Date.now();
|
|
178
|
+
|
|
179
|
+
await deriveDIDFromMnemonic(mnemonic);
|
|
180
|
+
|
|
181
|
+
const duration = Date.now() - startTime;
|
|
182
|
+
// Should complete in less than 5 seconds
|
|
183
|
+
expect(duration).toBeLessThan(5000);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe('TermiPass Compatibility', () => {
|
|
188
|
+
test('should derive correct keys from standard test mnemonic', async () => {
|
|
189
|
+
// Standard BIP39 test mnemonic
|
|
190
|
+
const testMnemonic =
|
|
191
|
+
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about';
|
|
192
|
+
|
|
193
|
+
const { owner, did } = await deriveDIDFromMnemonic(testMnemonic);
|
|
194
|
+
|
|
195
|
+
// These values should remain consistent with TermiPass
|
|
196
|
+
expect(owner).toBeTruthy();
|
|
197
|
+
expect(owner).toMatch(/^0x[a-fA-F0-9]{40}$/);
|
|
198
|
+
expect(did).toBeTruthy();
|
|
199
|
+
expect(did).toMatch(/^did:key:z[1-9A-HJ-NP-Za-km-z]+$/);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test('derived keys should be deterministic for test mnemonic', async () => {
|
|
203
|
+
const testMnemonic =
|
|
204
|
+
'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about';
|
|
205
|
+
|
|
206
|
+
const result1 = await deriveDIDFromMnemonic(testMnemonic);
|
|
207
|
+
const result2 = await deriveDIDFromMnemonic(testMnemonic);
|
|
208
|
+
|
|
209
|
+
expect(result1.owner).toBe(result2.owner);
|
|
210
|
+
expect(result1.did).toBe(result2.did);
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
describe('Edge Cases and Error Handling', () => {
|
|
215
|
+
test('should handle whitespace in mnemonic', async () => {
|
|
216
|
+
const mnemonic = generateMnemonic(12);
|
|
217
|
+
const mnemonicWithSpaces = ` ${mnemonic} `;
|
|
218
|
+
|
|
219
|
+
const address1 = await getEthereumAddressFromMnemonic(
|
|
220
|
+
mnemonic.trim()
|
|
221
|
+
);
|
|
222
|
+
const address2 = await getEthereumAddressFromMnemonic(
|
|
223
|
+
mnemonicWithSpaces.trim()
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
expect(address1).toBe(address2);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
test('should generate mnemonic with various valid word counts', () => {
|
|
230
|
+
// BIP39 supports 12, 15, 18, 21, 24 word mnemonics
|
|
231
|
+
const validCounts = [12, 15, 18, 21, 24];
|
|
232
|
+
|
|
233
|
+
validCounts.forEach((count) => {
|
|
234
|
+
const mnemonic = generateMnemonic(count);
|
|
235
|
+
const words = mnemonic.split(' ');
|
|
236
|
+
expect(words.length).toBe(count);
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
describe('Performance Tests', () => {
|
|
242
|
+
test('should generate multiple mnemonics efficiently', () => {
|
|
243
|
+
const startTime = Date.now();
|
|
244
|
+
|
|
245
|
+
for (let i = 0; i < 10; i++) {
|
|
246
|
+
generateMnemonic(12);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const duration = Date.now() - startTime;
|
|
250
|
+
// Should generate 10 mnemonics in less than 1 second
|
|
251
|
+
expect(duration).toBeLessThan(1000);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test('batch key derivation should be reasonably fast', async () => {
|
|
255
|
+
const mnemonics = Array.from({ length: 3 }, () =>
|
|
256
|
+
generateMnemonic(12)
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
const startTime = Date.now();
|
|
260
|
+
|
|
261
|
+
await Promise.all(mnemonics.map((m) => deriveDIDFromMnemonic(m)));
|
|
262
|
+
|
|
263
|
+
const duration = Date.now() - startTime;
|
|
264
|
+
// Should derive 3 sets of keys in less than 10 seconds
|
|
265
|
+
expect(duration).toBeLessThan(10000);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
});
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for Olares ID format support
|
|
3
|
+
*
|
|
4
|
+
* Tests the Olares ID format conversion utilities:
|
|
5
|
+
* - normalizeToDomain: Converts Olares ID (alice@example.com) to domain (alice.example.com)
|
|
6
|
+
* - normalizeToOlaresId: Converts domain (alice.example.com) to Olares ID (alice@example.com)
|
|
7
|
+
*
|
|
8
|
+
* The Olares ID format uses @ instead of the first dot, making it look like an email address.
|
|
9
|
+
* Both formats should work identically throughout the SDK.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
normalizeToDomain,
|
|
14
|
+
normalizeToOlaresId
|
|
15
|
+
} from '../../src/utils/olares-id';
|
|
16
|
+
|
|
17
|
+
describe('Olares ID Format', () => {
|
|
18
|
+
describe('normalizeToDomain', () => {
|
|
19
|
+
test('should convert Olares ID to standard domain format', () => {
|
|
20
|
+
expect(normalizeToDomain('alice@example.com')).toBe(
|
|
21
|
+
'alice.example.com'
|
|
22
|
+
);
|
|
23
|
+
expect(normalizeToDomain('bob@sub.example.com')).toBe(
|
|
24
|
+
'bob.sub.example.com'
|
|
25
|
+
);
|
|
26
|
+
expect(normalizeToDomain('user@olares.com')).toBe(
|
|
27
|
+
'user.olares.com'
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('should handle already normalized domain format', () => {
|
|
32
|
+
expect(normalizeToDomain('alice.example.com')).toBe(
|
|
33
|
+
'alice.example.com'
|
|
34
|
+
);
|
|
35
|
+
expect(normalizeToDomain('bob.sub.example.com')).toBe(
|
|
36
|
+
'bob.sub.example.com'
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('should only convert the first @ symbol', () => {
|
|
41
|
+
// If there are multiple @, only the first one is converted
|
|
42
|
+
expect(normalizeToDomain('user@domain@example.com')).toBe(
|
|
43
|
+
'user.domain@example.com'
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('should handle multi-level domains', () => {
|
|
48
|
+
expect(normalizeToDomain('alice@example.com')).toBe(
|
|
49
|
+
'alice.example.com'
|
|
50
|
+
);
|
|
51
|
+
expect(normalizeToDomain('bob@sub.example.com')).toBe(
|
|
52
|
+
'bob.sub.example.com'
|
|
53
|
+
);
|
|
54
|
+
expect(normalizeToDomain('user@deep.nested.domain.com')).toBe(
|
|
55
|
+
'user.deep.nested.domain.com'
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('should be idempotent', () => {
|
|
60
|
+
const domain = 'alice.example.com';
|
|
61
|
+
expect(normalizeToDomain(normalizeToDomain(domain))).toBe(domain);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('normalizeToOlaresId', () => {
|
|
66
|
+
test('should convert domain to Olares ID format', () => {
|
|
67
|
+
expect(normalizeToOlaresId('alice.example.com')).toBe(
|
|
68
|
+
'alice@example.com'
|
|
69
|
+
);
|
|
70
|
+
expect(normalizeToOlaresId('bob.sub.example.com')).toBe(
|
|
71
|
+
'bob@sub.example.com'
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('should only convert the first dot', () => {
|
|
76
|
+
expect(normalizeToOlaresId('user.sub.example.com')).toBe(
|
|
77
|
+
'user@sub.example.com'
|
|
78
|
+
);
|
|
79
|
+
expect(normalizeToOlaresId('deep.level.domain.com')).toBe(
|
|
80
|
+
'deep@level.domain.com'
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('should convert first dot even if @ already exists', () => {
|
|
85
|
+
// If input already has @, it will still replace the first dot with @
|
|
86
|
+
expect(normalizeToOlaresId('alice@example.com')).toBe(
|
|
87
|
+
'alice@example@com'
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('should not be idempotent if applied to Olares ID format', () => {
|
|
92
|
+
// Applying twice to a domain will double-convert
|
|
93
|
+
const domain = 'alice.example.com';
|
|
94
|
+
const olaresId = normalizeToOlaresId(domain); // alice@example.com
|
|
95
|
+
expect(olaresId).toBe('alice@example.com');
|
|
96
|
+
// Applying again will replace the dot in "example.com" with @
|
|
97
|
+
expect(normalizeToOlaresId(olaresId)).toBe('alice@example@com');
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('Round-trip Conversion', () => {
|
|
102
|
+
test('should convert back and forth without data loss', () => {
|
|
103
|
+
const originalDomain = 'alice.example.com';
|
|
104
|
+
const olaresId = normalizeToOlaresId(originalDomain);
|
|
105
|
+
const backToDomain = normalizeToDomain(olaresId);
|
|
106
|
+
|
|
107
|
+
expect(backToDomain).toBe(originalDomain);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('should handle multi-level domains in round-trip', () => {
|
|
111
|
+
const domains = [
|
|
112
|
+
'alice.example.com',
|
|
113
|
+
'bob.sub.example.com',
|
|
114
|
+
'user.deep.nested.domain.com'
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
domains.forEach((domain) => {
|
|
118
|
+
const olaresId = normalizeToOlaresId(domain);
|
|
119
|
+
const backToDomain = normalizeToDomain(olaresId);
|
|
120
|
+
expect(backToDomain).toBe(domain);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test('should start with domain, convert to Olares ID, then back', () => {
|
|
125
|
+
const domain = 'user.example.com';
|
|
126
|
+
expect(normalizeToDomain(normalizeToOlaresId(domain))).toBe(domain);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('should start with Olares ID, convert to domain, then back', () => {
|
|
130
|
+
const olaresId = 'user@example.com';
|
|
131
|
+
expect(normalizeToOlaresId(normalizeToDomain(olaresId))).toBe(
|
|
132
|
+
olaresId
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe('Edge Cases', () => {
|
|
138
|
+
test('should handle empty string', () => {
|
|
139
|
+
expect(normalizeToDomain('')).toBe('');
|
|
140
|
+
expect(normalizeToOlaresId('')).toBe('');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test('should handle string with no dot or @', () => {
|
|
144
|
+
expect(normalizeToDomain('nodot')).toBe('nodot');
|
|
145
|
+
expect(normalizeToOlaresId('nodot')).toBe('nodot');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test('should handle string starting with dot', () => {
|
|
149
|
+
expect(normalizeToDomain('.startswithdot')).toBe('.startswithdot');
|
|
150
|
+
// normalizeToOlaresId replaces first dot, even if it's at the start
|
|
151
|
+
expect(normalizeToOlaresId('.startswithdot')).toBe(
|
|
152
|
+
'@startswithdot'
|
|
153
|
+
);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test('should handle string starting with @', () => {
|
|
157
|
+
expect(normalizeToDomain('@startswithat')).toBe('.startswithat');
|
|
158
|
+
expect(normalizeToOlaresId('@startswithat')).toBe('@startswithat');
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test('should handle single character domains', () => {
|
|
162
|
+
expect(normalizeToDomain('1@com')).toBe('1.com');
|
|
163
|
+
expect(normalizeToOlaresId('1.com')).toBe('1@com');
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test('should handle multiple @ signs (only first is converted)', () => {
|
|
167
|
+
expect(normalizeToDomain('multiple@at@signs.com')).toBe(
|
|
168
|
+
'multiple.at@signs.com'
|
|
169
|
+
);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test('should handle domains with numbers', () => {
|
|
173
|
+
expect(normalizeToDomain('user123@example456.com')).toBe(
|
|
174
|
+
'user123.example456.com'
|
|
175
|
+
);
|
|
176
|
+
expect(normalizeToOlaresId('user123.example456.com')).toBe(
|
|
177
|
+
'user123@example456.com'
|
|
178
|
+
);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test('should handle domains with hyphens', () => {
|
|
182
|
+
expect(normalizeToDomain('my-user@my-domain.com')).toBe(
|
|
183
|
+
'my-user.my-domain.com'
|
|
184
|
+
);
|
|
185
|
+
expect(normalizeToOlaresId('my-user.my-domain.com')).toBe(
|
|
186
|
+
'my-user@my-domain.com'
|
|
187
|
+
);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe('Common Test Cases', () => {
|
|
192
|
+
test('should handle typical Olares domain names', () => {
|
|
193
|
+
const testCases = [
|
|
194
|
+
{ olaresId: 'alice@olares.com', domain: 'alice.olares.com' },
|
|
195
|
+
{ olaresId: 'bob@terminus.io', domain: 'bob.terminus.io' },
|
|
196
|
+
{
|
|
197
|
+
olaresId: 'charlie@example.org',
|
|
198
|
+
domain: 'charlie.example.org'
|
|
199
|
+
}
|
|
200
|
+
];
|
|
201
|
+
|
|
202
|
+
testCases.forEach(({ olaresId, domain }) => {
|
|
203
|
+
expect(normalizeToDomain(olaresId)).toBe(domain);
|
|
204
|
+
expect(normalizeToOlaresId(domain)).toBe(olaresId);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test('should handle subdomains correctly', () => {
|
|
209
|
+
const testCases = [
|
|
210
|
+
{
|
|
211
|
+
olaresId: 'user@sub.example.com',
|
|
212
|
+
domain: 'user.sub.example.com'
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
olaresId: 'app@service.sub.example.com',
|
|
216
|
+
domain: 'app.service.sub.example.com'
|
|
217
|
+
}
|
|
218
|
+
];
|
|
219
|
+
|
|
220
|
+
testCases.forEach(({ olaresId, domain }) => {
|
|
221
|
+
expect(normalizeToDomain(olaresId)).toBe(domain);
|
|
222
|
+
expect(normalizeToOlaresId(domain)).toBe(olaresId);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
describe('Format Validation', () => {
|
|
228
|
+
test('normalizeToDomain should always return dot-separated format', () => {
|
|
229
|
+
const inputs = [
|
|
230
|
+
'alice@example.com',
|
|
231
|
+
'bob@sub.example.com',
|
|
232
|
+
'user.domain.com',
|
|
233
|
+
'test@deep.nested.domain.com'
|
|
234
|
+
];
|
|
235
|
+
|
|
236
|
+
inputs.forEach((input) => {
|
|
237
|
+
const result = normalizeToDomain(input);
|
|
238
|
+
// Result should not contain @ as the first separator
|
|
239
|
+
if (result.includes('@')) {
|
|
240
|
+
// If @ exists, it should not be in the position of first separator
|
|
241
|
+
const firstDotIndex = result.indexOf('.');
|
|
242
|
+
const firstAtIndex = result.indexOf('@');
|
|
243
|
+
expect(firstAtIndex).toBeGreaterThan(firstDotIndex);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
test('normalizeToOlaresId should convert first dot to @', () => {
|
|
249
|
+
const inputs = [
|
|
250
|
+
'alice.example.com',
|
|
251
|
+
'bob.sub.example.com',
|
|
252
|
+
'user.domain.com'
|
|
253
|
+
];
|
|
254
|
+
|
|
255
|
+
inputs.forEach((input) => {
|
|
256
|
+
const result = normalizeToOlaresId(input);
|
|
257
|
+
// If input had a dot, result should have @ at that position
|
|
258
|
+
if (input.includes('.')) {
|
|
259
|
+
const firstDotIndex = input.indexOf('.');
|
|
260
|
+
expect(result.charAt(firstDotIndex)).toBe('@');
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
describe('Consistency', () => {
|
|
267
|
+
test('same input should always produce same output', () => {
|
|
268
|
+
const domain = 'alice.example.com';
|
|
269
|
+
const olaresId = 'alice@example.com';
|
|
270
|
+
|
|
271
|
+
// Call multiple times to ensure consistency
|
|
272
|
+
for (let i = 0; i < 10; i++) {
|
|
273
|
+
expect(normalizeToDomain(olaresId)).toBe(domain);
|
|
274
|
+
expect(normalizeToOlaresId(domain)).toBe(olaresId);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
test('batch conversion should be consistent', () => {
|
|
279
|
+
const domains = [
|
|
280
|
+
'user1.example.com',
|
|
281
|
+
'user2.example.com',
|
|
282
|
+
'user3.example.com'
|
|
283
|
+
];
|
|
284
|
+
|
|
285
|
+
const olaresIds = domains.map((d) => normalizeToOlaresId(d));
|
|
286
|
+
const backToDomains = olaresIds.map((o) => normalizeToDomain(o));
|
|
287
|
+
|
|
288
|
+
expect(backToDomains).toEqual(domains);
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
describe('Real-world Scenarios', () => {
|
|
293
|
+
test('should handle common TLD formats', () => {
|
|
294
|
+
const tlds = ['com', 'org', 'net', 'io', 'dev'];
|
|
295
|
+
|
|
296
|
+
tlds.forEach((tld) => {
|
|
297
|
+
const domain = `user.example.${tld}`;
|
|
298
|
+
const olaresId = `user@example.${tld}`;
|
|
299
|
+
|
|
300
|
+
expect(normalizeToDomain(olaresId)).toBe(domain);
|
|
301
|
+
expect(normalizeToOlaresId(domain)).toBe(olaresId);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
test('should handle deeply nested domains', () => {
|
|
306
|
+
const depth5 = 'user.level1.level2.level3.example.com';
|
|
307
|
+
const olaresId5 = 'user@level1.level2.level3.example.com';
|
|
308
|
+
|
|
309
|
+
expect(normalizeToDomain(olaresId5)).toBe(depth5);
|
|
310
|
+
expect(normalizeToOlaresId(depth5)).toBe(olaresId5);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
test('should work with real testnet domain format', () => {
|
|
314
|
+
const testDomain = '1.com';
|
|
315
|
+
const testOlaresId = '1@com';
|
|
316
|
+
|
|
317
|
+
expect(normalizeToDomain(testOlaresId)).toBe(testDomain);
|
|
318
|
+
expect(normalizeToOlaresId(testDomain)).toBe(testOlaresId);
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
});
|