Skip to content

Commit e9f41d7

Browse files
committed
Extension: attempt to load token from clipboard.
1 parent 6afc4bf commit e9f41d7

File tree

5 files changed

+150
-4
lines changed

5 files changed

+150
-4
lines changed

src/editor/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {
2-
copyTextToClipboard,
32
deferToNextLoop,
43
safeLocalStorageSetItem,
54
copyTokenLink
@@ -204,6 +203,7 @@ function saveAsLastToken() {
204203

205204
function loadToken() {
206205
const lastToken = localStorage.getItem('lastToken');
206+
207207
if(lastToken) {
208208
setTokenEditorValue(lastToken);
209209

src/editor/jwt.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,26 @@ export function verify(jwt, secretOrPublicKeyString, base64Secret = false) {
4848
}
4949

5050
export function decode(jwt) {
51-
const split = jwt.split('.');
52-
5351
const result = {
52+
header: {},
53+
payload: {},
5454
errors: false
5555
};
56+
57+
if(!jwt) {
58+
result.errors = true;
59+
return result;
60+
}
61+
62+
const split = jwt.split('.');
63+
5664
try {
5765
result.header = JSON.parse(b64utoutf8(split[0]));
5866
} catch(e) {
5967
result.header = {};
6068
result.errors = true;
6169
}
70+
6271
try {
6372
result.payload = JSON.parse(b64utoutf8(split[1]));
6473
} catch(e) {
@@ -68,3 +77,8 @@ export function decode(jwt) {
6877

6978
return result;
7079
}
80+
81+
export function isToken(jwt) {
82+
const decoded = decode(jwt);
83+
return !decoded.errors && decoded.header.typ === 'JWT';
84+
}

src/extension/index.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1-
import { setupTokenEditor, getTokenEditorValue } from '../editor';
1+
import {
2+
setupTokenEditor,
3+
setTokenEditorValue,
4+
getTokenEditorValue
5+
} from '../editor';
6+
import { setupTokenPageInspector } from './page-inspector.js';
27
import { shareJwtLink, shareJwtTextElement } from './dom-elements.js';
38
import { copyTokenLink } from '../utils.js';
9+
import { getTokenFromClipboardIfPossible } from './utils.js';
410
import strings from '../strings.js';
511

612
function setupShareJwtButton() {
@@ -22,6 +28,15 @@ function setupShareJwtButton() {
2228
});
2329
}
2430

31+
function loadFromClipboardIfPossible() {
32+
const token = getTokenFromClipboardIfPossible();
33+
if(token) {
34+
setTokenEditorValue(token);
35+
}
36+
}
37+
2538
// Initialization
2639
setupTokenEditor();
40+
loadFromClipboardIfPossible();
41+
setupTokenPageInspector();
2742
setupShareJwtButton();

src/extension/page-inspector.js

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
function loadFromStorageAndCookies() {
2+
// Populate cookies/LocalStorage combobox
3+
function checkLoadJwtFromLength() {
4+
var optGroups = [
5+
$('optgroup[label="Cookies"]'),
6+
$('optgroup[label="Web Storage"]')
7+
];
8+
9+
optGroups.forEach(function(optGroup) {
10+
var hasJWTs =
11+
optGroup.children(':not(.load-from-no-jwts)').length > 0;
12+
if(hasJWTs) {
13+
optGroup.children('.load-from-no-jwts').remove();
14+
} else {
15+
optGroup.empty();
16+
optGroup.append($('<option/>', {
17+
'class': 'load-from-no-jwts',
18+
'text': 'No JWTs found',
19+
'disabled': true
20+
}));
21+
}
22+
});
23+
}
24+
25+
function jwtMessage(message) {
26+
if(message.type !== 'cookies' && message.type !== 'storage') {
27+
return;
28+
}
29+
30+
var elements = [];
31+
32+
message.tokens.forEach(function(token) {
33+
if(!isToken(token.value)) {
34+
if(message.type === 'storage') {
35+
try {
36+
// Try again after parsing it first, some people do
37+
//localStorage.setItem('jwt', JSON.stringify(token))
38+
token.value = JSON.parse(token.value);
39+
if(!isToken(token.value)) {
40+
return;
41+
}
42+
} catch(e) {
43+
return;
44+
}
45+
} else {
46+
return;
47+
}
48+
}
49+
50+
var e = $('<option/>').text(token.name)
51+
.val(token.value)
52+
.data('type', token.type)
53+
if(token.cookie) {
54+
e.data('cookie', token.cookie);
55+
}
56+
elements.push(e);
57+
});
58+
59+
if(message.type === 'cookies') {
60+
$('optgroup[label="Cookies"]').append(elements);
61+
} else {
62+
$('optgroup[label="Web Storage"]').append(elements);
63+
}
64+
65+
checkLoadJwtFromLength();
66+
}
67+
68+
chrome.runtime.onMessage.addListener(jwtMessage);
69+
70+
chrome.tabs.executeScript({
71+
file: 'js/webstorage.js',
72+
runAt: "document_idle"
73+
});
74+
75+
chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
76+
chrome.cookies.getAll({
77+
url: tabs[0].url,
78+
}, function(cookies) {
79+
var result = cookies.map(function(cookie) {
80+
return {
81+
name: cookie.name,
82+
value: cookie.value,
83+
type: 'cookie',
84+
cookie: cookie
85+
}
86+
});
87+
88+
jwtMessage({
89+
type: 'cookies',
90+
tokens: result
91+
});
92+
});
93+
});
94+
95+
checkLoadJwtFromLength();
96+
}
97+
98+
export function setupTokenPageInspector() {
99+
100+
}

src/extension/utils.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { isToken } from '../editor/jwt.js';
2+
3+
// This only works on extensions
4+
export function getTokenFromClipboardIfPossible() {
5+
const input = document.createElement('textarea');
6+
7+
document.body.appendChild(input);
8+
input.focus();
9+
input.select();
10+
document.execCommand('Paste');
11+
12+
const token = input.value;
13+
14+
input.remove();
15+
16+
return isToken(token) ? token : null;
17+
}

0 commit comments

Comments
 (0)