UNPKG

11.2 kBJavaScriptView Raw
1const Ledger = require('../index.js')
2const crypto = require('brave-crypto')
3const test = require('tape')
4
5const options = { debugP: true, version: 'v2' }
6
7const msecs = {
8 day: 24 * 60 * 60 * 1000,
9 hour: 60 * 60 * 1000,
10 minute: 60 * 1000,
11 second: 1000
12}
13
14/**
15 * assert that values v1 and v2 differ by no more than tol
16 **/
17const assertWithinBounds = (t, v1, v2, tol, msg) => {
18 if (v1 > v2) {
19 t.true((v1 - v2) <= tol, msg)
20 } else {
21 t.true((v2 - v1) <= tol, msg)
22 }
23}
24
25test('getWalletPassphrase', (t) => {
26 t.plan(2)
27 const client = new Ledger(null, options)
28
29 client.generateKeypair()
30
31 const bip39PassPhrase = client.getWalletPassphrase()
32 t.equal(bip39PassPhrase.length, 24, 'bip39 passphrase should be 24 words')
33
34 const nicewarePassPhrase = client.getWalletPassphrase(undefined, {useNiceware: true})
35 t.equal(nicewarePassPhrase.length, 16, 'niceware passphrase should be 16 words')
36})
37
38test('getKeypair', (t) => {
39 t.plan(2)
40
41 const client = new Ledger(null, options)
42
43 const signingKey = client.generateKeypair()
44 const signingKey2 = client.getKeypair()
45
46 t.equal(crypto.uint8ToHex(signingKey.secretKey), crypto.uint8ToHex(signingKey2.secretKey))
47 t.equal(crypto.uint8ToHex(signingKey.publicKey), crypto.uint8ToHex(signingKey2.publicKey))
48})
49
50test('recoverKeypair', (t) => {
51 t.plan(4)
52
53 const client = new Ledger(null, options)
54
55 // test with bip39 passphrase
56 const signingKey = client.generateKeypair()
57 const bip39PassPhrase = client.getWalletPassphrase().join(' ')
58
59 const client2 = new Ledger(null, options)
60 t.equal(crypto.uint8ToHex(client2.recoverKeypair(bip39PassPhrase).secretKey), crypto.uint8ToHex(signingKey.secretKey))
61 t.equal(crypto.uint8ToHex(client2.recoverKeypair(bip39PassPhrase).publicKey), crypto.uint8ToHex(signingKey.publicKey))
62
63 // test with niceware passphrase
64 const nicewarePassPhrase = client.getWalletPassphrase(undefined, {useNiceware: true}).join(' ')
65
66 const client3 = new Ledger(null, options)
67 t.equal(crypto.uint8ToHex(client3.recoverKeypair(nicewarePassPhrase).secretKey), crypto.uint8ToHex(signingKey.secretKey))
68 t.equal(crypto.uint8ToHex(client3.recoverKeypair(nicewarePassPhrase).publicKey), crypto.uint8ToHex(signingKey.publicKey))
69})
70
71// Tests workaround for #20
72test('initWithDeserializedState', (t) => {
73 t.plan(2)
74
75 const client = new Ledger(null, options)
76
77 const signingKey = client.generateKeypair()
78 const state = JSON.parse(JSON.stringify(client.state))
79
80 const client2 = new Ledger(null, options, state)
81 const signingKey2 = client2.getKeypair()
82
83 t.equal(crypto.uint8ToHex(signingKey.secretKey), crypto.uint8ToHex(signingKey2.secretKey))
84 t.equal(crypto.uint8ToHex(signingKey.publicKey), crypto.uint8ToHex(signingKey2.publicKey))
85})
86
87test('initWithFixupState', (t) => {
88 t.plan(2)
89
90 const client = new Ledger(null, options)
91
92 const signingKey = client.generateKeypair()
93 const state = JSON.parse(JSON.stringify(client.state))
94
95 if (state && state.properties && state.properties.wallet && state.properties.wallet.keyinfo) {
96 let seed = state.properties.wallet.keyinfo.seed
97 if (!(seed instanceof Uint8Array)) {
98 seed = new Uint8Array(Object.values(seed))
99 }
100
101 state.properties.wallet.keyinfo.seed = seed
102 }
103
104 const client2 = new Ledger(null, options, state)
105 const signingKey2 = client2.getKeypair()
106
107 t.equal(crypto.uint8ToHex(signingKey.secretKey), crypto.uint8ToHex(signingKey2.secretKey))
108 t.equal(crypto.uint8ToHex(signingKey.publicKey), crypto.uint8ToHex(signingKey2.publicKey))
109})
110
111test('isValidPassPhrase', (t) => {
112 t.plan(6)
113
114 const client = new Ledger(null, options)
115
116 client.generateKeypair()
117 const bip39PassPhrase = client.getWalletPassphrase().join(' ')
118 t.equal(client.isValidPassPhrase(bip39PassPhrase), true, 'Should return true for valid passphrase')
119 t.equal(client.isValidPassPhrase(123), false, 'Should return false for number')
120 t.equal(client.isValidPassPhrase(null), false, 'Should return false for null')
121 t.equal(client.isValidPassPhrase(), false, 'Should return false for empty param')
122 t.equal(client.isValidPassPhrase('asdfasfsadf'), false, 'Should return false for random string')
123
124 const nicewarePassPhrase = client.getWalletPassphrase(undefined, {useNiceware: true}).join(' ')
125 t.equal(client.isValidPassPhrase(nicewarePassPhrase), true, 'Should return true for legacy niceware passphrase')
126})
127
128test('sync', (t) => {
129 t.plan(3)
130 let client = new Ledger(null, options)
131 const days14 = 1209600000
132
133 t.equal(client.state.reconcileStamp, undefined, 'Should be undefined at start')
134
135 client.sync(() => {})
136
137 const now = new Date().getTime()
138 const newStamp = now + days14
139
140 assertWithinBounds(t, client.state.reconcileStamp, newStamp, 1000, 'Should set new reconcileStamp')
141 console.log(client.state.reconcileStamp)
142
143 client = new Ledger(null, options)
144 client.setTimeUntilReconcile(null, () => {})
145 const time = client.state.reconcileStamp
146 client.sync(() => {})
147 t.equal(client.state.reconcileStamp, time, 'Should not change timestamp if is set')
148})
149
150test('setTimeUntilReconcile', (t) => {
151 t.plan(3)
152
153 const client = new Ledger(null, options)
154 const newTimestamp = new Date().getTime() + 10000000
155 const now = new Date().getTime() + 2592000000
156
157 t.equal(client.state.reconcileStamp, undefined, 'Should be undefined at start')
158
159 client.setTimeUntilReconcile(newTimestamp, () => {})
160 t.equal(client.state.reconcileStamp, newTimestamp, 'Should set provided timestamp')
161
162 client.setTimeUntilReconcile(null, () => {})
163 assertWithinBounds(t, client.state.reconcileStamp, now, 1000, 'Should set new timestamp to now + 30 days')
164})
165
166test('_fuzzing', (t) => {
167 t.plan(8)
168 const client = new Ledger(null, options, {properties: {days: 30}})
169
170 const synopsis = {
171 prune: () => {},
172 publishers: {
173 'site.com': {
174 duration: 10
175 }
176 },
177 options: {
178 numFrames: 30,
179 frameSize: 86400000
180 }
181 }
182
183 const synopsisTime = {
184 prune: () => {},
185 publishers: {
186 'site.com': {
187 duration: 31 * msecs.minute
188 }
189 },
190 options: {
191 numFrames: 30,
192 frameSize: 86400000
193 }
194 }
195 t.equal(client.state.reconcileStamp, undefined, 'Should be undefined at start')
196
197 const fiveDays = new Date().getTime() + (5 * msecs.day)
198 client.setTimeUntilReconcile(fiveDays, () => {})
199 t.equal(client.state.reconcileStamp, fiveDays, 'Should set time now+5days stamp')
200 client._fuzzing(synopsis, () => {})
201 t.equal(client.state.reconcileStamp, fiveDays, 'Should not be changed if stamp is in the near future (5days)')
202
203 const tomorrow = new Date().getTime() + (1 * msecs.day)
204 client.setTimeUntilReconcile(tomorrow, () => {})
205 t.equal(client.state.reconcileStamp, tomorrow, 'Should set time now+1day stamp')
206 client._fuzzing(synopsis, () => {})
207 assertWithinBounds(t, client.state.reconcileStamp, (new Date().getTime() + (3 * msecs.day)), ((2 * msecs.day) + 1000), 'Should be changed if stamp is tomorrow and browsing time is bellow 30min')
208
209 const past = new Date().getTime() - (5 * msecs.day)
210 const pastClient = new Ledger(null, options, {properties: {days: 30}, reconcileStamp: past})
211 pastClient._fuzzing(synopsis, () => {})
212 assertWithinBounds(t, pastClient.state.reconcileStamp, new Date().getTime() + (3 * msecs.day), ((2 * msecs.day) + 1000), 'Should be changed if stamp is in the past and browsing time is bellow 30min')
213
214 client.setTimeUntilReconcile(tomorrow, () => {})
215 t.equal(client.state.reconcileStamp, tomorrow, 'Should set time now+1day stamp')
216 client._fuzzing(synopsisTime, () => {})
217 t.equal(client.state.reconcileStamp, tomorrow, 'Should not change if stamp is in tomorrow and browsing time is above 30min')
218})
219
220test('_prepareVoteBatch', (t) => {
221 t.plan(8)
222 const client = new Ledger(null, options)
223 const callback = () => {}
224
225 client._prepareVoteBatch(callback)
226 t.deepEqual(client.state.batch, {}, 'Should be empty for null case')
227
228 client.state = {
229 batch: {},
230 ballots: null
231 }
232 client._prepareVoteBatch(callback)
233 t.deepEqual(client.state.batch, {}, 'Should be empty when we do not have ballots')
234
235 client.state = {
236 batch: {},
237 ballots: null
238 }
239 client._prepareVoteBatch(callback)
240 t.deepEqual(client.state.batch, {}, 'Should be empty for null case')
241
242 client.state = {
243 batch: {},
244 ballots: [{
245 surveyorId: '12323',
246 publisher: 'clifton.io',
247 viewingId: '123a',
248 prepareBallot: {
249 surveyorId: '12323'
250 },
251 proofBallot: 'dfdsfsd'
252 }],
253 transactions: []
254 }
255 client._prepareVoteBatch(callback)
256 t.deepEqual(client.state.batch, {}, 'Should be empty when there is no transaction')
257
258 client.state = {
259 batch: {},
260 ballots: [{
261 publisher: 'clifton.io',
262 viewingId: '123a'
263 }],
264 transactions: [{
265 viewingId: '123a',
266 credential: '12'
267 }]
268 }
269 client._prepareVoteBatch(callback)
270 t.deepEqual(client.state.batch, {}, 'Should be empty when ballot is missing proof and prepare')
271
272 client.state = {
273 batch: {},
274 ballots: [{
275 surveyorId: '12323',
276 publisher: 'clifton.io',
277 viewingId: '123a',
278 prepareBallot: {
279 surveyorId: '12323'
280 },
281 proofBallot: 'dfdsfsd'
282 }],
283 transactions: [{
284 viewingId: '123a',
285 credential: '12'
286 }]
287 }
288 client._prepareVoteBatch(callback)
289 t.deepEqual(client.state.batch, {
290 'clifton.io': [{
291 surveyorId: '12323',
292 proof: 'dfdsfsd'
293 }]
294 }, 'Should have one batch')
295 t.deepEqual(client.state.ballots, [], 'Should not have any ballots when we move it into the batch')
296
297 client.state = {
298 batch: {},
299 ballots: [
300 {
301 surveyorId: '1',
302 publisher: 'clifton.io',
303 viewingId: '123a',
304 prepareBallot: {
305 surveyorId: '1'
306 },
307 proofBallot: '2'
308 },
309 {
310 surveyorId: '2',
311 publisher: 'clifton.io',
312 viewingId: '123a',
313 prepareBallot: {
314 surveyorId: '2'
315 },
316 proofBallot: '3'
317 },
318 {
319 surveyorId: '3',
320 publisher: 'clifton.io',
321 viewingId: '123a',
322 prepareBallot: {
323 surveyorId: '3'
324 },
325 proofBallot: '4'
326 },
327 {
328 surveyorId: '4',
329 publisher: 'brianbondy.com',
330 viewingId: '123a',
331 prepareBallot: {
332 surveyorId: '4'
333 },
334 proofBallot: '1'
335 },
336 {
337 surveyorId: '5',
338 publisher: 'brianbondy.com',
339 viewingId: '123a',
340 prepareBallot: {
341 surveyorId: '5'
342 },
343 proofBallot: '2'
344 }],
345 transactions: [{
346 viewingId: '123a',
347 credential: '12'
348 }]
349 }
350 const expectedResult = {
351 'brianbondy.com': [
352 {
353 surveyorId: '5',
354 proof: '2'
355 },
356 {
357 surveyorId: '4',
358 proof: '1'
359 }
360 ],
361 'clifton.io': [
362 {
363 surveyorId: '3',
364 proof: '4'
365 },
366 {
367 surveyorId: '2',
368 proof: '3'
369 },
370 {
371 surveyorId: '1',
372 proof: '2'
373 }
374 ]
375 }
376 client._prepareVoteBatch(callback)
377 t.deepEqual(client.state.batch, expectedResult, 'Should have multiple publishers in the batch')
378})