Skip to content

Commit 8267a13

Browse files
committed
Download public keys if possible.
1 parent ab170ee commit 8267a13

File tree

3 files changed

+83
-11
lines changed

3 files changed

+83
-11
lines changed

src/public-key-download.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { httpGet } from './utils.js';
2+
3+
function getKeyFromX5c(x5c) {
4+
if(!x5c) {
5+
throw new Error('x5c claim not present?');
6+
}
7+
8+
if(!(x5c instanceof Array)) {
9+
x5c = [ x5c ];
10+
}
11+
12+
let certChain = '';
13+
x5c.forEach(cert => {
14+
certChain += '-----BEGIN CERTIFICATE-----\n';
15+
certChain += cert + '\n';
16+
certChain += '-----END CERTIFICATE-----\n';
17+
});
18+
19+
return certChain;
20+
}
21+
22+
function getKeyFromX5Claims(claims) {
23+
return new Promise((resolve, reject) => {
24+
if(claims.x5c) {
25+
resolve(getKeyFromX5c(claims.x5c));
26+
} else if(claims.x5u) {
27+
resolve(httpGet(claims.x5u).then(getKeyFromX5c));
28+
} else {
29+
reject('x5c or x5u claims not available');
30+
}
31+
});
32+
}
33+
34+
function getKeyFromJwkKeySetUrl(kid, url) {
35+
return httpGet(url).then(data => {
36+
data = JSON.parse(data);
37+
38+
if(!data || !data.keys || !(data.keys instanceof Array)) {
39+
throw new Error(`Could not get JWK key set from URL: ${url}`);
40+
}
41+
42+
for(let i = 0; i < data.keys.length; ++i) {
43+
const jwk = data.keys[i];
44+
if(jwk.kid === kid) {
45+
return getKeyFromX5Claims(jwk);
46+
}
47+
}
48+
49+
throw new Error(`Could not find key with kid ${kid} in URL: ${url}`);
50+
});
51+
}
52+
53+
export function downloadPublicKeyIfPossible(decodedToken) {
54+
return new Promise((resolve, reject) => {
55+
const header = decodedToken.header;
56+
const payload = decodedToken.payload;
57+
58+
if(!header.alg || header.alg.indexOf('HS') === 0) {
59+
reject(`Unsupported alg: ${header.alg}`);
60+
return;
61+
}
62+
63+
if(header.x5c || header.x5u) {
64+
resolve(getKeyFromX5Claims(header));
65+
} else if(header.jku) {
66+
resolve(getKeyFromJwkKeySetUrl(header.kid, header.jku));
67+
} else if(header.jwk) {
68+
resolve(getKeyFromX5Claims(header.jwk));
69+
} else if(header.kid && payload.iss) {
70+
//Auth0-specific scheme
71+
const url = payload.iss + '.well-known/jwks.json';
72+
resolve(getKeyFromJwkKeySetUrl(header.kid, url));
73+
} else {
74+
reject('No details about key');
75+
}
76+
});
77+
}

src/utils.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,3 @@ export function isValidKey(key) {
100100
key: key
101101
};
102102
}
103-
104-
export function downloadPublicKeyIfPossible(decodedToken) {
105-
return Promise.reject();
106-
}
107-

src/website/editor/index.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { copyTextToClipboard } from '../utils.js';
2-
import { downloadPublicKeyIfPossible } from '../../utils.js';
2+
import { downloadPublicKeyIfPossible } from '../../public-key-download.js';
33
import { tooltipHandler } from './tooltip.js';
44
import { tokenEditor, headerEditor, payloadEditor } from './instances.js';
55
import {
@@ -114,8 +114,8 @@ export function useDefaultToken(algorithm) {
114114
if(algorithm.indexOf('HS') === 0) {
115115
secretInput.value = defaults.secret;
116116
} else {
117-
publicKeyTextArea.firstChild.textContent = defaults.publicKey;
118-
privateKeyTextArea.firstChild.textContent = defaults.privateKey;
117+
publicKeyTextArea.value = defaults.publicKey;
118+
privateKeyTextArea.value = defaults.privateKey;
119119
}
120120

121121
markAsValid();
@@ -203,7 +203,7 @@ function encodeToken() {
203203
const encoded = sign(header, payload,
204204
header.alg.indexOf('HS') === 0 ?
205205
secretInput.value :
206-
privateKeyTextArea.firstChild.textContent,
206+
privateKeyTextArea.value,
207207
secretBase64Checkbox.checked);
208208

209209
tokenEditor.setValue(encoded);
@@ -224,7 +224,7 @@ function decodeToken() {
224224
selectAlgorithm(decoded.header.alg);
225225
downloadPublicKeyIfPossible(decoded).then(publicKey => {
226226
eventManager.withDisabledEvents(() => {
227-
publicKeyTextArea.firstChild.textContent = publicKey;
227+
publicKeyTextArea.value = publicKey;
228228
verifyToken();
229229
});
230230
});
@@ -251,7 +251,7 @@ function verifyToken() {
251251
const publicKeyOrSecret =
252252
decoded.header.alg.indexOf('HS') === 0 ?
253253
secretInput.value :
254-
publicKeyTextArea.firstChild.textContent;
254+
publicKeyTextArea.value;
255255

256256
if(verify(jwt, publicKeyOrSecret, secretBase64Checkbox.checked)) {
257257
markAsValid();

0 commit comments

Comments
 (0)