Skip to content

Commit c920ad6

Browse files
committed
Remove duplicate code, move functions of little use to better places.
1 parent a058353 commit c920ad6

File tree

8 files changed

+102
-137
lines changed

8 files changed

+102
-137
lines changed

package-lock.json

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
},
88
"dependencies": {
99
"express": "^4.16.2",
10-
"express-sslify": "^1.2.0"
10+
"express-sslify": "^1.2.0",
11+
"querystring": "^0.2.0"
1112
},
1213
"devDependencies": {
1314
"@babel/core": "^7.0.0-beta.36",

src/editor/jwt.js

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { isValidBase64String } from '../utils.js';
2-
31
import {
42
jws,
53
KEYUTIL,
@@ -127,6 +125,36 @@ export function decode(jwt) {
127125
return result;
128126
}
129127

128+
export function isValidBase64String(s, urlOnly) {
129+
try {
130+
const validChars = urlOnly ?
131+
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=' :
132+
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_+/=';
133+
134+
let hasPadding = false;
135+
for(let i = 0; i < s.length; ++i) {
136+
hasPadding |= s.charAt(i) === '=';
137+
if(validChars.indexOf(s.charAt(i)) === -1) {
138+
return false;
139+
}
140+
}
141+
142+
if(hasPadding) {
143+
for(let i = s.indexOf('='); i < s.length; ++i) {
144+
if(s.charAt(i) !== '=') {
145+
return false;
146+
}
147+
}
148+
149+
return s.length % 4 === 0;
150+
}
151+
152+
return true;
153+
} catch (e) {
154+
return false;
155+
}
156+
}
157+
130158
export function isToken(jwt, checkTypClaim = false) {
131159
const decoded = decode(jwt);
132160

src/utils.js

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { KEYUTIL } from 'jsrsasign';
22
import log from 'loglevel';
33
import clipboard from 'clipboard-polyfill';
4-
import { isToken } from './editor/jwt.js';
54

65
export function httpGet(url, cache = true) {
76
return new Promise((resolve, reject) => {
@@ -31,36 +30,6 @@ export function httpGet(url, cache = true) {
3130
});
3231
}
3332

34-
export function isValidBase64String(s, urlOnly) {
35-
try {
36-
const validChars = urlOnly ?
37-
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=' :
38-
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_+/=';
39-
40-
let hasPadding = false;
41-
for(let i = 0; i < s.length; ++i) {
42-
hasPadding |= s.charAt(i) === '=';
43-
if(validChars.indexOf(s.charAt(i)) === -1) {
44-
return false;
45-
}
46-
}
47-
48-
if(hasPadding) {
49-
for(let i = s.indexOf('='); i < s.length; ++i) {
50-
if(s.charAt(i) !== '=') {
51-
return false;
52-
}
53-
}
54-
55-
return s.length % 4 === 0;
56-
}
57-
58-
return true;
59-
} catch (e) {
60-
return false;
61-
}
62-
};
63-
6433
export function isValidKey(key) {
6534
// Four tries: no header, header for cert, header for pub key,
6635
// header for priv key
@@ -118,45 +87,6 @@ export function copyTokenLink(token, publicKeyOptional) {
11887
return url;
11988
}
12089

121-
function regexp(body, flag) {
122-
return new RegExp("[?&#]" + body + "(?:=([^&#]*)|&|#|$)", flag);
123-
}
124-
125-
const tokenRegexp = regexp('((?:id_|access_)?token|value)', 'g');
126-
127-
export function getTokensFromLocation() {
128-
const { href } = window.location;
129-
let name, value;
130-
const val = {};
131-
132-
try {
133-
while ([, name, value] = tokenRegexp.exec(href)) {
134-
if(isToken(value)) val[name] = value;
135-
}
136-
} catch (err) {}
137-
return val;
138-
}
139-
140-
// https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
141-
export function getParameterByName(name, url) {
142-
if(!url) {
143-
url = window.location.href;
144-
}
145-
146-
name = name.replace(/[\[\]]/g, "\\$&");
147-
148-
const regex = regexp(name);
149-
const results = regex.exec(url);
150-
if(!results) {
151-
return null;
152-
}
153-
if(!results[1]) {
154-
return '';
155-
}
156-
157-
return decodeURIComponent(results[1].replace(/\+/g, " "));
158-
}
159-
16090
export function isWideScreen() {
16191
return window.matchMedia('(min-width: 768px)').matches;
16292
}

src/website/index.js

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { setupTokenEditor, setTokenEditorValue } from '../editor';
55
import { setupJwtCounter } from './counter.js';
66
import { setupSmoothScrolling } from './smooth-scrolling.js';
77
import { setupHighlighting } from './highlighting.js';
8-
import { getParameterByName, getTokensFromLocation } from '../utils.js';
98
import { isChrome, isFirefox } from './utils.js';
109
import { setupShareJwtButton } from '../share-button.js';
1110
import {
@@ -18,27 +17,29 @@ import {
1817
shareJwtTextElement
1918
} from './dom-elements.js';
2019

20+
import queryString from 'querystring';
21+
2122
/* For initialization, look at the end of this file */
2223

2324
function parseLocationQuery() {
24-
const publicKey = getParameterByName('publicKey');
25-
const { id_token, access_token, value, token } = getTokensFromLocation();
25+
const locSearch = queryString.parse(document.location.search.substr(1));
26+
const locHash = queryString.parse(document.location.hash.substr(1));
2627

27-
let scroll = false;
28-
if(publicKey) {
29-
publicKeyTextArea.value = publicKey;
30-
scroll = true;
31-
}
28+
const token = locSearch.id_token ||
29+
locSearch.access_token ||
30+
locSearch.value ||
31+
locSearch.token;
32+
if(token) {
33+
setTokenEditorValue(token);
3234

33-
const val = value || token || id_token || access_token;
34-
if(val) {
35-
setTokenEditorValue(val);
36-
scroll = true;
37-
}
35+
if(locSearch.publicKey) {
36+
publicKeyTextArea.value = locSearch.publicKey;
37+
}
3838

39-
if(scroll) {
4039
debuggerSection.scrollIntoView(true);
41-
}
40+
} else if(locHash.token) { // Legacy token passing method (as hash)
41+
setTokenEditorValue(locHash.token);
42+
}
4243
}
4344

4445
function pickEbookOrExtensionBanner() {

test/functional/editor.js

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ describe('Editor', function() {
726726
});
727727

728728
it('Clears the token when the header is edited and there ' +
729-
'is no private key', async function() {
729+
'is no private key', async function() {
730730
await this.page.select('#algorithm-select', 'RS256');
731731

732732
const secretInput = await this.page.$('textarea[name="private-key"]');
@@ -1152,22 +1152,29 @@ describe('Editor', function() {
11521152
);
11531153
});
11541154

1155-
describe('parsing tokens from window.location.href', () => {
1156-
const token = 'eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.';
1155+
describe('Parses tokens from window.location.href', () => {
1156+
const token = defaultTokens.hs384.token;
1157+
11571158
['token', 'value', 'id_token', 'access_token'].forEach((key) => {
1159+
11581160
[
11591161
`/?${key}=${token}`,
11601162
`/#${key}=${token}`,
11611163
`/?foo=bar&${key}=${token}`,
11621164
`/#foo=bar&${key}=${token}`,
1163-
].forEach((structure, i) => {
1164-
it(`Should parse ${key} from window.location.href [${i}]`, async function () {
1165-
await this.page.goto(`http://localhost:8000${structure}${key}${i}`);
1166-
expect(await this.page.evaluate(() => {
1167-
return window.test.tokenEditor.getValue();
1168-
})).to.equal(`${token}${key}${i}`);
1169-
});
1170-
})
1165+
].forEach((searchStr, i) => {
1166+
this.timeout(20000);
1167+
1168+
it(`Should parse ${key} from window.location.href [${i}]`,
1169+
async function () {
1170+
await this.page.goto(`http://localhost:8000${searchStr}`);
1171+
expect(await this.page.evaluate(() => {
1172+
return window.test.tokenEditor.getValue();
1173+
})).to.equal(`${token}`);
1174+
});
1175+
});
1176+
11711177
});
1178+
11721179
});
11731180
});

test/unit/editor/jwt.js

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import * as jwt from '../../../src/editor/jwt.js';
22
import tokens from '../../../src/editor/default-tokens.js';
33

4-
import { utf8tob64u, b64utob64 } from 'jsrsasign';
5-
4+
import { utf8tob64, utf8tob64u, b64utob64 } from 'jsrsasign';
65
import log from 'loglevel';
7-
86
import { should } from 'chai';
7+
import { randomFillSync } from 'crypto';
98

109
should();
1110

@@ -200,4 +199,36 @@ describe('JWT', function() {
200199

201200
jwt.verify(token, publicKeyPlainRSA).should.be.true;
202201
});
202+
203+
describe('isValidBase64String', function() {
204+
// Generate random data of different sizes.
205+
const data = [];
206+
for(let i = 0; i < 1000; ++i) {
207+
let bytes = new Uint8Array(i);
208+
randomFillSync(bytes);
209+
bytes = String.fromCharCode.apply(null, bytes);
210+
211+
data.push({
212+
b64: utf8tob64(bytes),
213+
b64u: utf8tob64u(bytes)
214+
});
215+
}
216+
217+
it('detects valid Base64 and Base64URL strings', function() {
218+
data.forEach(d => {
219+
jwt.isValidBase64String(d.b64, false).should.be.true;
220+
jwt.isValidBase64String(d.b64u, false).should.be.true;
221+
jwt.isValidBase64String(d.b64u).should.be.true;
222+
jwt.isValidBase64String(d.b64u, true).should.be.true;
223+
});
224+
});
225+
226+
it('fails on invalid Base64 and Base64 URL strings', function() {
227+
data.forEach(d => {
228+
if(d.b64.match(/[\+\/]/)) {
229+
jwt.isValidBase64String(d.b64, true).should.be.false;
230+
}
231+
});
232+
});
233+
});
203234
});

test/unit/utils.js

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import chai from 'chai';
22
import chaiAsPromised from 'chai-as-promised';
33
import xhrMock from 'xhr-mock';
44

5-
import { httpGet, isValidBase64String } from '../../src/utils.js';
5+
import { httpGet } from '../../src/utils.js';
66
import { utf8tob64, utf8tob64u } from 'jsrsasign';
77

88
import { randomFillSync } from 'crypto';
@@ -11,38 +11,6 @@ chai.use(chaiAsPromised);
1111
chai.should();
1212

1313
describe('Generic utils', function() {
14-
describe('isValidBase64String', function() {
15-
// Generate random data of different sizes.
16-
const data = [];
17-
for(let i = 0; i < 1000; ++i) {
18-
let bytes = new Uint8Array(i);
19-
randomFillSync(bytes);
20-
bytes = String.fromCharCode.apply(null, bytes);
21-
22-
data.push({
23-
b64: utf8tob64(bytes),
24-
b64u: utf8tob64u(bytes)
25-
});
26-
}
27-
28-
it('detects valid Base64 and Base64URL strings', function() {
29-
data.forEach(d => {
30-
isValidBase64String(d.b64, false).should.be.true;
31-
isValidBase64String(d.b64u, false).should.be.true;
32-
isValidBase64String(d.b64u).should.be.true;
33-
isValidBase64String(d.b64u, true).should.be.true;
34-
});
35-
});
36-
37-
it('fails on invalid Base64 and Base64 URL strings', function() {
38-
data.forEach(d => {
39-
if(d.b64.match(/[\+\/]/)) {
40-
isValidBase64String(d.b64, true).should.be.false;
41-
}
42-
});
43-
});
44-
});
45-
4614
describe('httpGet', function() {
4715
const url = '/';
4816
const reply = 'test';

0 commit comments

Comments
 (0)