Skip to content

Commit

Permalink
doulble-check master password on change request (options page); fixes #…
Browse files Browse the repository at this point in the history
  • Loading branch information
ray-lothian committed Feb 9, 2021
1 parent 31f4a47 commit 5243234
Show file tree
Hide file tree
Showing 6 changed files with 388 additions and 132 deletions.
11 changes: 8 additions & 3 deletions firefox/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,10 @@ const onMessage = (request, sender, response) => {
focused: true
});
}
else if (request.method === 'ask-for-password') {
prompt(chrome.i18n.getMessage('bg_msg_17')).then(response);
return true;
}
};
chrome.runtime.onMessage.addListener(onMessage);

Expand Down Expand Up @@ -647,10 +651,11 @@ chrome.alarms.onAlarm.addListener(alarm => {
if (reason === 'install' || (prefs.faqs && reason === 'update')) {
const doUpdate = (Date.now() - prefs['last-update']) / 1000 / 60 / 60 / 24 > 45;
if (doUpdate && previousVersion !== version) {
tabs.create({
tabs.query({active: true, currentWindow: true}, tbs => tabs.create({
url: page + '?version=' + version + (previousVersion ? '&p=' + previousVersion : '') + '&type=' + reason,
active: reason === 'install'
});
active: reason === 'install',
...(tbs && tbs.length && {index: tbs[0].index + 1})
}));
storage.local.set({'last-update': Date.now()});
}
}
Expand Down
10 changes: 9 additions & 1 deletion firefox/data/options/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@
body {
background-color: #fff;
color: #4d5156;
font-size: 13px;
max-width: 80%;
margin: 10px auto;
}
@media screen and (max-width: 600px) {
body {
margin: 10px;
max-width: unset;
}
}
@supports (-moz-appearance:none) {
body {
font-size: 13px;
font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
margin: 15px;
}
h1 {
font-size: 18px;
Expand Down
6 changes: 3 additions & 3 deletions firefox/data/options/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,10 @@ <h1 data-i18n="options_tools_header"></h1>
<div id="tools">
<input type="button" data-i18n-value="value" data-i18n="options_support" id="support">
<input type="button" data-i18n-value="value" data-i18n="options_save" data-cmd="save" disabled="true">
<div id="save-container" data-i18n="options_master_password_comment" data-i18n-value="title">
<form id="save-container" data-i18n="options_master_password_comment" data-i18n-value="title">
<input type="password" id="password" data-i18n="options_master_password" data-i18n-value="placeholder">&nbsp;
<input type="button" data-i18n-value="value" data-i18n="options_unlock" data-cmd="unlock">
</div>
<input type="submit" data-i18n-value="value" data-i18n="options_unlock" data-cmd="unlock">
</form>
</div>
<span id="toast"></span>
</div>
Expand Down
275 changes: 152 additions & 123 deletions firefox/data/options/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,25 @@ const fs = schedule => {
}
};

// double-check password; based on https://github.com/ray-lothian/Block-Site/issues/51
const grant = callback => chrome.storage.local.get({
'sha256': ''
}, prefs => {
if (prefs.sha256) {
chrome.runtime.sendMessage({
method: 'ask-for-password'
}, password => {
chrome.runtime.sendMessage({
method: 'check-password',
password
}, resp => resp && callback());
});
}
else {
callback();
}
});

const init = (table = true) => chrome.storage.local.get(DEFAULTS, ps => {
Object.assign(prefs, ps);

Expand Down Expand Up @@ -173,100 +192,106 @@ document.querySelector('#schedule [name="hostname"]').addEventListener('input',
}
});

document.getElementById('save-container').onsubmit = e => {
e.preventDefault();
e.stopPropagation();

const password = document.getElementById('password').value;
chrome.runtime.sendMessage({
method: 'check-password',
password
}, resp => {
document.querySelector('[data-cmd="unlock"]').disabled = resp;
document.querySelector('[data-cmd="save"]').disabled = !resp;
document.querySelector('[data-cmd="export"]').disabled = !resp;
document.querySelector('[data-cmd="import-json"]').disabled = !resp;
if (!resp) {
document.getElementById('password').focus();
}
});
};

document.addEventListener('click', async e => {
const {target} = e;
const cmd = target.dataset.cmd;
if (cmd === 'remove') {
target.closest('div').remove();
}
else if (cmd === 'unlock') {
const password = document.getElementById('password').value;
chrome.runtime.sendMessage({
method: 'check-password',
password
}, resp => {
document.querySelector('[data-cmd="unlock"]').disabled = resp;
document.querySelector('[data-cmd="save"]').disabled = !resp;
document.querySelector('[data-cmd="export"]').disabled = !resp;
document.querySelector('[data-cmd="import-json"]').disabled = !resp;
if (!resp) {
document.getElementById('password').focus();
}
});
}
else if (cmd === 'save') {
let schedule = {
times: days.reduce((p, c) => {
const start = document.querySelector(`input[type=time][name=start][data-id=${c}]`).value;
const end = document.querySelector(`input[type=time][name=end][data-id=${c}]`).value;
grant(async () => {
let schedule = {
times: days.reduce((p, c) => {
const start = document.querySelector(`input[type=time][name=start][data-id=${c}]`).value;
const end = document.querySelector(`input[type=time][name=end][data-id=${c}]`).value;

if (start && end) {
p[c] = [{start, end}];
}
if (start && end) {
p[c] = [{start, end}];
}

return p;
}, {})
};
const rule = document.querySelector('#schedule [name="hostname"]');
if (rule.value) {
const e = validateRegex(rule.value);
if (e) {
return toast('Schedule Blocking; ' + e.message, 3000, 'error');
}
else {
if (Object.values(schedule.times).some(times => times.some(({start, end}) => start && end))) {
prefs.schedules[rule.value] = schedule;
return p;
}, {})
};
const rule = document.querySelector('#schedule [name="hostname"]');
if (rule.value) {
const e = validateRegex(rule.value);
if (e) {
return toast('Schedule Blocking; ' + e.message, 3000, 'error');
}
else {
delete prefs.schedules[rule.value];
console.log('deleting rule for', rule.value);
if (Object.values(schedule.times).some(times => times.some(({start, end}) => start && end))) {
prefs.schedules[rule.value] = schedule;
}
else {
delete prefs.schedules[rule.value];
console.log('deleting rule for', rule.value);
}
schedule = prefs.schedule;
}
schedule = prefs.schedule;
}
}
localStorage.setItem('mode-top', document.getElementById('mode-top').value);
localStorage.setItem('mode-frame', document.getElementById('mode-frame').value);
localStorage.setItem('mode-top', document.getElementById('mode-top').value);
localStorage.setItem('mode-frame', document.getElementById('mode-frame').value);

const password = document.getElementById('password').value;
const sha256 = password ? await new Promise(resolve => {
chrome.runtime.getBackgroundPage(bg => resolve(bg.sha256(password)));
}) : '';
const password = document.getElementById('password').value;
const sha256 = password ? await new Promise(resolve => {
chrome.runtime.getBackgroundPage(bg => resolve(bg.sha256(password)));
}) : '';

// clear deprecated password preference
chrome.storage.local.remove('password');
chrome.storage.local.set({
sha256,
'title': document.getElementById('title').checked,
'initialBlock': document.getElementById('initialBlock').checked,
'reverse': document.getElementById('reverse').checked,
'no-password-on-add': document.getElementById('no-password-on-add').checked,
'redirect': document.getElementById('redirect').value,
'message': document.getElementById('message').value,
'css': document.getElementById('css').value,
'timeout': Math.max(Number(document.getElementById('timeout').value), 1),
'close': Math.max(Number(document.getElementById('close').value), 0),
'wrong': Math.max(Number(document.getElementById('wrong').value), 1),
schedule,
'schedules': prefs.schedules,
'blocked': [...document.querySelectorAll('#rules-container > div')]
.map(tr => tr.dataset.hostname)
.filter((s, i, l) => s && l.indexOf(s) === i),
'map': [...document.querySelectorAll('#rules-container > div')].reduce((p, c) => {
const {hostname} = c.dataset;
const mapped = c.querySelector('input[type=text]').value;
if (mapped) {
p[hostname] = mapped;
}
return p;
}, {}),
'contextmenu-resume': document.getElementById('contextmenu-resume').checked,
'contextmenu-pause': document.getElementById('contextmenu-pause').checked,
'contextmenu-frame': document.getElementById('contextmenu-frame').checked,
'contextmenu-top': document.getElementById('contextmenu-top').checked
}, () => {
toast('Options saved');
window.removeEventListener('beforeunload', warning);
init(false);
// clear deprecated password preference
chrome.storage.local.remove('password');
chrome.storage.local.set({
sha256,
'title': document.getElementById('title').checked,
'initialBlock': document.getElementById('initialBlock').checked,
'reverse': document.getElementById('reverse').checked,
'no-password-on-add': document.getElementById('no-password-on-add').checked,
'redirect': document.getElementById('redirect').value,
'message': document.getElementById('message').value,
'css': document.getElementById('css').value,
'timeout': Math.max(Number(document.getElementById('timeout').value), 1),
'close': Math.max(Number(document.getElementById('close').value), 0),
'wrong': Math.max(Number(document.getElementById('wrong').value), 1),
schedule,
'schedules': prefs.schedules,
'blocked': [...document.querySelectorAll('#rules-container > div')]
.map(tr => tr.dataset.hostname)
.filter((s, i, l) => s && l.indexOf(s) === i),
'map': [...document.querySelectorAll('#rules-container > div')].reduce((p, c) => {
const {hostname} = c.dataset;
const mapped = c.querySelector('input[type=text]').value;
if (mapped) {
p[hostname] = mapped;
}
return p;
}, {}),
'contextmenu-resume': document.getElementById('contextmenu-resume').checked,
'contextmenu-pause': document.getElementById('contextmenu-pause').checked,
'contextmenu-frame': document.getElementById('contextmenu-frame').checked,
'contextmenu-top': document.getElementById('contextmenu-top').checked
}, () => {
toast('Options saved');
window.removeEventListener('beforeunload', warning);
init(false);
});
});
}
else if (cmd === 'import-txt') {
Expand Down Expand Up @@ -301,56 +326,60 @@ document.addEventListener('click', async e => {
input.click();
}
else if (cmd === 'export') {
chrome.storage.local.get(null, prefs => {
const guid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
const r = Math.random() * 16 | 0;
const v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
grant(() => {
chrome.storage.local.get(null, prefs => {
const guid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
const r = Math.random() * 16 | 0;
const v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});

const blob = new Blob([
JSON.stringify(Object.assign({}, prefs, {
'managed.storage.overwrite.on.start': false,
guid
}), null, e.shiftKey ? '' : ' ')
], {type: 'application/json'});
const href = URL.createObjectURL(blob);
Object.assign(document.createElement('a'), {
href,
type: 'application/json',
download: 'block-site-preferences.json'
}).dispatchEvent(new MouseEvent('click'));
setTimeout(() => URL.revokeObjectURL(href));
const blob = new Blob([
JSON.stringify(Object.assign({}, prefs, {
'managed.storage.overwrite.on.start': false,
guid
}), null, e.shiftKey ? '' : ' ')
], {type: 'application/json'});
const href = URL.createObjectURL(blob);
Object.assign(document.createElement('a'), {
href,
type: 'application/json',
download: 'block-site-preferences.json'
}).dispatchEvent(new MouseEvent('click'));
setTimeout(() => URL.revokeObjectURL(href));
});
});
}
else if (cmd == 'import-json') {
const input = document.createElement('input');
input.style.display = 'none';
input.type = 'file';
input.accept = '.json';
input.acceptCharset = 'utf-8';
grant(() => {
const input = document.createElement('input');
input.style.display = 'none';
input.type = 'file';
input.accept = '.json';
input.acceptCharset = 'utf-8';

document.body.appendChild(input);
input.initialValue = input.value;
input.onchange = () => {
if (input.value !== input.initialValue) {
const file = input.files[0];
if (file.size > 100e6) {
return toast('100MB backup? I don\'t believe you.', undefined, 'error');
document.body.appendChild(input);
input.initialValue = input.value;
input.onchange = () => {
if (input.value !== input.initialValue) {
const file = input.files[0];
if (file.size > 100e6) {
return toast('100MB backup? I don\'t believe you.', undefined, 'error');
}
const reader = new FileReader();
reader.onloadend = event => {
input.remove();
const json = JSON.parse(event.target.result);
chrome.storage.local.clear(() => chrome.storage.local.set(json, () => {
chrome.runtime.reload();
window.close();
}));
};
reader.readAsText(file, 'utf-8');
}
const reader = new FileReader();
reader.onloadend = event => {
input.remove();
const json = JSON.parse(event.target.result);
chrome.storage.local.clear(() => chrome.storage.local.set(json, () => {
chrome.runtime.reload();
window.close();
}));
};
reader.readAsText(file, 'utf-8');
}
};
input.click();
};
input.click();
});
}
else if (cmd === 'reset') {
if (e.detail === 1) {
Expand Down
1 change: 0 additions & 1 deletion firefox/data/options/matched.js

This file was deleted.

Loading

0 comments on commit 5243234

Please sign in to comment.