1
+ interface TestCase {
2
+ name : string ;
3
+ data : {
4
+ /* tslint:disable-next-line:no-any */
5
+ [ hash : string ] : {
6
+ /* tslint:disable-next-line:no-any */
7
+ [ key : string ] : any
8
+ } ;
9
+ } ;
10
+ }
11
+
12
+ const cases : TestCase [ ] = [
13
+ {
14
+ name : 'Missing fields' ,
15
+ data : { '7733be61632fa6af88d31218e6c4afb2' : { 'secret' : 'abcd2345' } }
16
+ } ,
17
+ {
18
+ name : 'Bad hash in key' ,
19
+ data : {
20
+ 'badhash' : {
21
+ 'account' : 'test' ,
22
+ 'counter' : 0 ,
23
+ 'encrypted' : false ,
24
+ 'hash' : '7733be61632fa6af88d31218e6c4afb2' ,
25
+ 'index' : 0 ,
26
+ 'issuer' : '' ,
27
+ 'secret' : 'abcd2345' ,
28
+ 'type' : 'totp'
29
+ }
30
+ }
31
+ } ,
32
+ {
33
+ name : 'Bad hash' ,
34
+ data : {
35
+ 'badhash' : {
36
+ 'account' : 'test' ,
37
+ 'counter' : 0 ,
38
+ 'encrypted' : false ,
39
+ 'hash' : 'badhash' ,
40
+ 'index' : 0 ,
41
+ 'issuer' : '' ,
42
+ 'secret' : 'abcd2345' ,
43
+ 'type' : 'totp'
44
+ }
45
+ }
46
+ } ,
47
+ {
48
+ name : 'Bad type for HEX' ,
49
+ data : {
50
+ 'e19d5cd5af0378da05f63f891c7467af' : {
51
+ 'account' : 'test' ,
52
+ 'counter' : 0 ,
53
+ 'encrypted' : false ,
54
+ 'hash' : 'e19d5cd5af0378da05f63f891c7467af' ,
55
+ 'index' : 0 ,
56
+ 'issuer' : '' ,
57
+ 'secret' : 'abcd1234' ,
58
+ 'type' : 'totp'
59
+ }
60
+ }
61
+ } ,
62
+ {
63
+ name : 'Unicode in issuer' ,
64
+ data : {
65
+ '7733be61632fa6af88d31218e6c4afb2' : {
66
+ 'account' : 'test' ,
67
+ 'counter' : 0 ,
68
+ 'encrypted' : false ,
69
+ 'hash' : '7733be61632fa6af88d31218e6c4afb2' ,
70
+ 'index' : 0 ,
71
+ 'issuer' : '✓ à la mode' ,
72
+ 'secret' : 'abcd2345' ,
73
+ 'type' : 'totp'
74
+ }
75
+ }
76
+ } ,
77
+ {
78
+ name : 'Battle migrate' ,
79
+ data : {
80
+ '95c869de1221960c7f7e6892f78d7062' : {
81
+ 'account' : 'test' ,
82
+ 'counter' : 0 ,
83
+ 'encrypted' : false ,
84
+ 'hash' : '95c869de1221960c7f7e6892f78d7062' ,
85
+ 'index' : 0 ,
86
+ 'issuer' : '' ,
87
+ 'secret' : 'blz-abcd2345' ,
88
+ 'type' : 'totp'
89
+ }
90
+ }
91
+ } ,
92
+ {
93
+ name : 'Steam migrate' ,
94
+ data : {
95
+ '95c869de1221960c7f7e6892f78d7062' : {
96
+ 'account' : 'test' ,
97
+ 'counter' : 0 ,
98
+ 'encrypted' : false ,
99
+ 'hash' : '95c869de1221960c7f7e6892f78d7062' ,
100
+ 'index' : 0 ,
101
+ 'issuer' : '' ,
102
+ 'secret' : 'stm-abcd2345' ,
103
+ 'type' : 'totp'
104
+ }
105
+ }
106
+ } ,
107
+ {
108
+ name : 'Missing field with HEX secret' ,
109
+ data : { 'e19d5cd5af0378da05f63f891c7467af' : { 'secret' : 'abcd1234' } }
110
+ } ,
111
+ {
112
+ name : 'Mess index' ,
113
+ data : {
114
+ '7733be61632fa6af88d31218e6c4afb2' : {
115
+ 'account' : 'test' ,
116
+ 'counter' : 0 ,
117
+ 'encrypted' : false ,
118
+ 'hash' : '7733be61632fa6af88d31218e6c4afb2' ,
119
+ 'index' : 6 ,
120
+ 'issuer' : '' ,
121
+ 'secret' : 'abcd2345' ,
122
+ 'type' : 'totp'
123
+ } ,
124
+ '770f51f23603ddae810e446630c2f673' : {
125
+ 'account' : 'test' ,
126
+ 'counter' : 0 ,
127
+ 'encrypted' : false ,
128
+ 'hash' : '770f51f23603ddae810e446630c2f673' ,
129
+ 'index' : 6 ,
130
+ 'issuer' : '' ,
131
+ 'secret' : 'abcd2346' ,
132
+ 'type' : 'totp'
133
+ }
134
+ }
135
+ }
136
+ ] ;
137
+
138
+ let testCaseIndex = 0 ;
139
+ let testRes : Array < { pass : boolean , error : string } > = [ ] ;
140
+
141
+ function testStart ( ) {
142
+ if ( document . getElementById ( 'lock' ) ) {
143
+ const checkbox = document . getElementById ( 'lock' ) as HTMLInputElement ;
144
+ if ( ! checkbox . checked ) {
145
+ return ;
146
+ }
147
+ }
148
+ const startBtn = document . getElementById ( 'start' ) ;
149
+ if ( startBtn ) {
150
+ startBtn . setAttribute ( 'disabled' , 'true' ) ;
151
+ }
152
+ testCaseIndex = 0 ;
153
+ testRes = [ ] ;
154
+ test ( ) ;
155
+ }
156
+
157
+ function testFinished ( ) {
158
+ clear ( ) ;
159
+ console . log ( 'Test finished.' ) ;
160
+ for ( const res of testRes ) {
161
+ if ( ! res . pass ) {
162
+ alert ( 'Test failed!' ) ;
163
+ return ;
164
+ }
165
+ }
166
+ alert ( 'Test passed!' ) ;
167
+ return ;
168
+ }
169
+
170
+ async function clear ( ) {
171
+ return new Promise ( ( resolve : ( ) => void , reject : ( reason : Error ) => void ) => {
172
+ try {
173
+ chrome . storage . sync . clear ( resolve ) ;
174
+ } catch ( error ) {
175
+ reject ( error ) ;
176
+ }
177
+ } ) ;
178
+ }
179
+
180
+ async function get < T > ( ) {
181
+ return new Promise (
182
+ ( resolve : ( items : { [ key : string ] : T } ) => void ,
183
+ reject : ( reason : Error ) => void ) => {
184
+ try {
185
+ chrome . storage . sync . get ( resolve ) ;
186
+ } catch ( error ) {
187
+ reject ( error ) ;
188
+ }
189
+ } ) ;
190
+ }
191
+
192
+ async function set ( items : { [ key : string ] : { } } ) {
193
+ /* tslint:disable-next-line:no-any */
194
+ return new Promise ( ( resolve : ( ) => void , reject : ( reason : Error ) => void ) => {
195
+ try {
196
+ chrome . storage . sync . set ( items , resolve ) ;
197
+ } catch ( error ) {
198
+ reject ( error ) ;
199
+ }
200
+ } ) ;
201
+ }
202
+
203
+ async function test ( ) {
204
+ if ( testCaseIndex === cases . length * 2 ) {
205
+ testFinished ( ) ;
206
+ return ;
207
+ }
208
+
209
+ console . log (
210
+ cases [ Math . floor ( testCaseIndex / 2 ) ] . name ,
211
+ testCaseIndex % 2 ? 'Reopen' : '' ) ;
212
+
213
+ await clear ( ) ;
214
+ if ( testCaseIndex % 2 === 0 ) {
215
+ await set ( cases [ Math . floor ( testCaseIndex / 2 ) ] . data ) ;
216
+ }
217
+
218
+ if ( document . getElementsByTagName ( 'iframe' ) &&
219
+ document . getElementsByTagName ( 'iframe' ) [ 0 ] ) {
220
+ testRes [ testCaseIndex ] = { pass : true , error : '' } ;
221
+
222
+ document . getElementsByTagName ( 'iframe' ) [ 0 ] . src = 'popup.html' ;
223
+ document . getElementsByTagName ( 'iframe' ) [ 0 ] . onload = ( ) => {
224
+ document . getElementsByTagName ( 'iframe' ) [ 0 ] . contentWindow . addEventListener (
225
+ 'unhandledrejection' , event => {
226
+ const rejectionEvent = event as PromiseRejectionEvent ;
227
+ testRes [ testCaseIndex ] = {
228
+ pass : false ,
229
+ error : rejectionEvent . reason
230
+ } ;
231
+ } ) ;
232
+
233
+ document . getElementsByTagName ( 'iframe' ) [ 0 ] . contentWindow . onerror =
234
+ error => {
235
+ testRes [ testCaseIndex ] = { pass : false , error} ;
236
+ } ;
237
+ } ;
238
+ }
239
+
240
+ setTimeout ( async ( ) => {
241
+ if ( testRes [ testCaseIndex ] . pass ) {
242
+ const data = await get < {
243
+ /* tslint:disable-next-line:no-any */
244
+ [ key : string ] : any
245
+ } > ( ) ;
246
+ for ( const hash of Object . keys ( data ) ) {
247
+ const item = data [ hash ] ;
248
+ const keys = [
249
+ 'issuer' , 'account' , 'secret' , 'hash' , 'index' , 'type' , 'counter' ,
250
+ 'encrypted'
251
+ ] ;
252
+ for ( const key of keys ) {
253
+ if ( item [ key ] === undefined ) {
254
+ testRes [ testCaseIndex ] = {
255
+ pass : false ,
256
+ error : `Missing key<${ key } >: ${ JSON . stringify ( item ) } `
257
+ } ;
258
+ break ;
259
+ }
260
+ }
261
+ }
262
+ }
263
+
264
+ showTestResult ( ) ;
265
+ testCaseIndex ++ ;
266
+
267
+ if ( document . getElementsByTagName ( 'iframe' ) &&
268
+ document . getElementsByTagName ( 'iframe' ) [ 0 ] ) {
269
+ document . getElementsByTagName ( 'iframe' ) [ 0 ] . src = 'about:blank' ;
270
+ }
271
+
272
+ test ( ) ;
273
+ } , 1000 ) ;
274
+ }
275
+
276
+ function showTestResult ( ) {
277
+ const testResultContainer = document . getElementById ( 'test' ) ;
278
+ if ( ! testResultContainer ) {
279
+ return ;
280
+ }
281
+
282
+ testResultContainer . innerHTML = '' ;
283
+ for ( let i = 0 ; i < testRes . length ; i ++ ) {
284
+ const el = document . createElement ( 'tr' ) ;
285
+ el . innerHTML = `<td style="vertical-align: text-top; width: 50px; color: ${
286
+ testRes [ i ] . pass ? 'green' :
287
+ 'red' } ">[${ testRes [ i ] . pass ? 'Pass' : 'Fail' } ]</td>`;
288
+ el . innerHTML +=
289
+ `<td><h3 style="margin: 0">${ cases [ Math . floor ( i / 2 ) ] . name } ${
290
+ i % 2 === 1 ? ' (Reopen)' : '' } </h3>${ testRes [ i ] . error } <br></td>`;
291
+
292
+ testResultContainer . appendChild ( el ) ;
293
+ }
294
+ }
295
+
296
+ const startBtn = document . getElementById ( 'start' ) ;
297
+ if ( startBtn ) {
298
+ startBtn . onclick = testStart ;
299
+ }
300
+
301
+ window . addEventListener ( 'message' , ( message ) => {
302
+ console . log ( message ) ;
303
+ } , false ) ;
0 commit comments