Skip to content

Commit 18cad35

Browse files
committed
Extension: load/save from cookies/local storage.
1 parent ff99206 commit 18cad35

File tree

6 files changed

+213
-83
lines changed

6 files changed

+213
-83
lines changed

src/extension/dom-elements.js

+10
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,13 @@ export * from '../dom-elements.js';
33
export const shareJwtLink = document.querySelector('.jwt-clipboard-btn');
44
export const shareJwtTextElement =
55
document.getElementById('share-this-jwt-text');
6+
7+
export const cookiesOptGroup =
8+
document.querySelector('optgroup[label="Cookies"]');
9+
export const webStorageOptGroup =
10+
document.querySelector('optgroup[label="Web Storage"]');
11+
12+
export const storageSelect = cookiesOptGroup.parentElement;
13+
14+
export const saveBackElement = document.querySelector('.save-back');
15+
export const saveBackLink = document.getElementById('save-back-link');

src/extension/injected/webstorage.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
function readFrom(storage, result) {
2+
for (let i = 0; i < storage.length; ++i) {
3+
const key = storage.key(i);
4+
result.push({
5+
name: key,
6+
value: storage.getItem(key),
7+
type: storage === window.sessionStorage ? 'session' : 'local'
8+
});
9+
}
10+
}
11+
12+
const result = [];
13+
14+
readFrom(window.localStorage, result);
15+
readFrom(window.sessionStorage, result);
16+
17+
chrome.runtime.sendMessage({
18+
type: 'storage',
19+
tokens: result
20+
}, function response(ignored) {
21+
22+
});
23+
24+
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
25+
if (message.type !== 'sessionSave' && message.type !== 'localSave') {
26+
return;
27+
}
28+
29+
const storage = message.type === 'sessionSave' ?
30+
window.sessionStorage :
31+
window.localStorage;
32+
storage.setItem(message.name, message.value);
33+
});

src/extension/page-inspector.js

+165-81
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,184 @@
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-
});
1+
import { isToken } from '../editor/jwt.js'
2+
import { getTokenEditorValue, setTokenEditorValue } from '../editor';
3+
import {
4+
cookiesOptGroup,
5+
webStorageOptGroup,
6+
saveBackElement,
7+
saveBackLink,
8+
storageSelect
9+
} from './dom-elements.js';
10+
import strings from '../strings.js';
11+
12+
function updateOptGroups() {
13+
var optGroups = [cookiesOptGroup, webStorageOptGroup];
14+
15+
optGroups.forEach(optGroup => {
16+
const hasJWTs = optGroup.querySelectorAll(':not(.load-from-no-jwts)')
17+
.length > 0;
18+
if (hasJWTs) {
19+
const toRemove = optGroup.querySelectorAll('.load-from-no-jwts');
20+
Array.prototype.forEach.call(toRemove, e => e.remove());
21+
} else {
22+
const noJwtOption = document.createElement('option');
23+
noJwtOption.classList.add('load-from-no-jwts');
24+
noJwtOption.text = strings.extension.noJwtsFound;
25+
noJwtOption.disabled = true;
26+
27+
optGroup.innerHTML = ''; // Remove all elements
28+
optGroup.appendChild(noJwtOption);
29+
}
30+
});
31+
}
32+
33+
function messageHandler(message) {
34+
if (message.type !== 'cookies' && message.type !== 'storage') {
35+
return;
2336
}
2437

25-
function jwtMessage(message) {
26-
if(message.type !== 'cookies' && message.type !== 'storage') {
38+
const elements = [];
39+
40+
message.tokens.forEach(token => {
41+
if (!isToken(token.value)) {
42+
if(message.type === 'cookies') {
43+
return;
44+
}
45+
46+
try {
47+
// Try again after parsing it first, some people do
48+
//localStorage.setItem('jwt', JSON.stringify(token))
49+
token.value = JSON.parse(token.value);
50+
if (!isToken(token.value)) {
51+
// Not a valid token, ignore it.
2752
return;
53+
}
54+
} catch (e) {
55+
// Not a valid token, ignore it.
56+
return;
2857
}
58+
}
2959

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-
});
60+
const e = document.createElement('option');
61+
e.text = token.name;
62+
e.value = token.value;
63+
e.setAttribute('data-type', token.type);
5864

59-
if(message.type === 'cookies') {
60-
$('optgroup[label="Cookies"]').append(elements);
61-
} else {
62-
$('optgroup[label="Web Storage"]').append(elements);
63-
}
65+
if(token.cookie) {
66+
e.setAttribute('data-cookie', JSON.stringify(token.cookie));
67+
}
68+
69+
elements.push(e);
70+
});
6471

65-
checkLoadJwtFromLength();
72+
if (message.type === 'cookies') {
73+
elements.forEach(e => cookiesOptGroup.appendChild(e));
74+
} else {
75+
elements.forEach(e => webStorageOptGroup.appendChild(e));
6676
}
6777

68-
chrome.runtime.onMessage.addListener(jwtMessage);
78+
updateOptGroups();
79+
}
6980

70-
chrome.tabs.executeScript({
71-
file: 'js/webstorage.js',
72-
runAt: "document_idle"
81+
function saveCookie(url, cookie, oldCookie) {
82+
// Some cookies get duplicated otherwise (chrome.cookies.set bug?)
83+
chrome.cookies.remove({
84+
url: url,
85+
name: oldCookie.name,
86+
storeId: oldCookie.storeId
87+
});
88+
chrome.cookies.set({
89+
url: url,
90+
name: oldCookie.name,
91+
value: cookie.value,
92+
domain: oldCookie.domain,
93+
path: oldCookie.path,
94+
secure: oldCookie.secure,
95+
httpOnly: oldCookie.httpOnly,
96+
expirationDate: oldCookie.expirationDate,
97+
storeId: oldCookie.storeId
98+
});
99+
}
100+
101+
function saveBackClick() {
102+
const selected = storageSelect.options[storageSelect.selectedIndex];
103+
const type = selected.getAttribute('data-type');
104+
const name = selected.text;
105+
const value = getTokenEditorValue().token;
106+
107+
selected.value = value;
108+
109+
chrome.tabs.query({ active: true, currentWindow: true }, tabs => {
110+
const data = {
111+
type: type + 'Save',
112+
name: name,
113+
value: value
114+
};
115+
if(type === 'cookie') {
116+
saveCookie(tabs[0].url, data,
117+
JSON.parse(selected.getAttribute('data-cookie')));
118+
} else {
119+
chrome.tabs.sendMessage(tabs[0].id, data);
120+
}
73121
});
122+
}
123+
124+
function storedJwtSelect() {
125+
const selected = storageSelect.options[storageSelect.selectedIndex];
74126

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-
});
127+
if(selected.getAttribute('name') === '0') { // "None" selected
128+
saveBackElement.classList.add('hide');
129+
return;
130+
}
131+
saveBackElement.classList.remove('hide');
132+
133+
const type = selected.parentElement.getAttribute('label').toLowerCase();
134+
135+
const name = selected.text;
136+
const value = selected.value;
137+
138+
setTokenEditorValue(value);
139+
140+
saveBackLink.firstChild.textContent = strings.extension.saveBackTo + type;
141+
}
142+
143+
function setupListeners() {
144+
saveBackElement.addEventListener('click', saveBackClick);
145+
storageSelect.addEventListener('change', storedJwtSelect);
146+
}
147+
148+
function getCookies() {
149+
chrome.tabs.query({ active: true, currentWindow: true }, tabs => {
150+
chrome.cookies.getAll({
151+
url: tabs[0].url,
152+
}, cookies => {
153+
const result = cookies.map(cookie => {
154+
return {
155+
name: cookie.name,
156+
value: cookie.value,
157+
type: 'cookie',
158+
cookie: cookie
159+
}
160+
});
161+
162+
messageHandler({
163+
type: 'cookies',
164+
tokens: result
92165
});
166+
});
93167
});
168+
}
169+
170+
function setupInjectedCode() {
171+
chrome.runtime.onMessage.addListener(messageHandler);
94172

95-
checkLoadJwtFromLength();
173+
chrome.tabs.executeScript({
174+
file: 'js/webstorage.js',
175+
runAt: "document_idle"
176+
});
96177
}
97178

98179
export function setupTokenPageInspector() {
99-
180+
setupInjectedCode();
181+
getCookies();
182+
updateOptGroups();
183+
setupListeners();
100184
}

src/strings.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ export default {
33
alreadyInstalled: 'Already installed',
44
addToChrome: 'Add to Chrome',
55
shareThisJwt: 'Share this JWT',
6-
jwtIoUrlCopied: 'JWT.io URL copied'
6+
jwtIoUrlCopied: 'JWT.io URL copied',
7+
noJwtsFound: 'No JWTs found',
8+
saveBackTo: 'Save back to '
79
},
810
editor: {
911
signatureVerified: 'signature verified',

views/extension/index.pug

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ block content
4040
img(src="/img/ico_logo.svg")
4141

4242
.pull-right.save-back.hide
43-
a(href="#") Save back to localStorage
43+
a#save-back-link(href="#") Save back to localStorage
4444

4545
.pull-right.keyboard-info
4646
span Press Ctrl + Shift + K to open the JWT debugger

webpack.extension-dev.js

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const common = require('./webpack.common.js');
55
module.exports = merge(common, {
66
entry: {
77
index: './src/extension/index.js',
8+
webstorage: './src/extension/injected/webstorage.js'
89
},
910
output: {
1011
filename: '[name].js',

0 commit comments

Comments
 (0)