Skip to content

Commit 9a4d68c

Browse files
committed
add test case, fix issuer error
1 parent 6fb284f commit 9a4d68c

File tree

4 files changed

+328
-3
lines changed

4 files changed

+328
-3
lines changed

src/test/test.ts

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
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);

src/ui/entry.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ function hasMatchedEntry(siteName: Array<string|null>, entries: OTPEntry[]) {
137137
}
138138

139139
function isMatchedEntry(siteName: Array<string|null>, entry: OTPEntry) {
140+
if (!entry.issuer) {
141+
return false;
142+
}
143+
140144
const issuerHostMatches = entry.issuer.split('::');
141145
const issuer = issuerHostMatches[0].replace(/[^0-9a-z]/ig, '').toLowerCase();
142146

test.html

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<style>
5+
iframe {
6+
display: none;
7+
}
8+
</style>
9+
</head>
10+
<body>
11+
<iframe src="about:black" frameborder="0"></iframe>
12+
<button id="start">Test</button>
13+
Test will destroy all data! <input type="checkbox" id="lock">
14+
<hr>
15+
<div>
16+
<table id="test"></table>
17+
</div>
18+
<script src="build/test/test.js"></script>
19+
</body>
20+
</html>

tsconfig.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@
99
},
1010
"include": [
1111
"src/*.ts",
12-
"src/**/*.ts",
13-
"test/*.ts",
14-
"test/**/*.ts"
12+
"src/**/*.ts"
1513
],
1614
"exclude": [
1715
"node_modules"

0 commit comments

Comments
 (0)