change password -> postpassword so browsers stop suggesting login password, add it to modal and make it random generate and save based on user input for JS users

merge-requests/208/head
fatchan 4 years ago
parent a120aa03c4
commit 198c76ea8a
  1. 2
      controllers/forms/actions.js
  2. 2
      controllers/forms/globalactions.js
  3. 2
      controllers/forms/makepost.js
  4. 2
      gulp/res/js/modal.js
  5. 42
      gulp/res/js/password.js
  6. 2
      helpers/paramconverter.js
  7. 4
      models/forms/actionhandler.js
  8. 4
      models/forms/makepost.js
  9. 2
      views/includes/actionfooter.pug
  10. 2
      views/includes/postform.pug
  11. 3
      views/mixins/modal.pug

@ -47,7 +47,7 @@ module.exports = async (req, res, next) => {
}
//check that actions are valid
if (req.body.password && req.body.password.length > 50) {
if (req.body.postpassword && req.body.postpassword.length > 50) {
errors.push('Password must be 50 characters or less');
}
if (req.body.report_reason && req.body.report_reason.length > 50) {

@ -32,7 +32,7 @@ module.exports = async (req, res, next) => {
}
//check that actions are valid
if (req.body.password && req.body.password.length > 50) {
if (req.body.postpassword && req.body.postpassword.length > 50) {
errors.push('Password must be 50 characters or less');
}
if (req.body.ban_reason && req.body.ban_reason.length > 50) {

@ -65,7 +65,7 @@ module.exports = async (req, res, next) => {
if (req.body.email && req.body.email.length > 50) {
errors.push('Email must be 50 characters or less');
}
if (req.body.password && req.body.password.length > 50) {
if (req.body.postpassword && req.body.postpassword.length > 50) {
errors.push('Password must be 50 characters or less');
}

@ -95,7 +95,7 @@ pug_html = pug_html + "\u003Coption" + (pug_attr("value", theme, true, false)) +
}
}).call(this);
pug_html = pug_html + "\u003C\u002Fselect\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003ELive posts\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"live-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003ENotifications\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"notification-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003EScroll to new posts\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"scroll-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003ELocal time\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"localtime-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003E24h time\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"24hour-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003EShow relative time\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"relative-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003EHide Thumbnails\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"hideimages-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003ERecursive Post Hide\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"hiderecursive-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003EVideo\u002FAudio Volume\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"volume-setting\" type=\"range\" min=\"0\" max=\"100\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003ELoop audio\u002Fvideo\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"loop-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003EUnlimit expand height\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"heightlimit-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003ECrisp image rendering\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"crispimages-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003ECustom CSS\u003C\u002Fdiv\u003E\u003Ctextarea id=\"customcss-setting\"\u003E\u003C\u002Ftextarea\u003E\u003C\u002Fdiv\u003E\u003C\u002Fdiv\u003E";
pug_html = pug_html + "\u003C\u002Fselect\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003ELive posts\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"live-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003ENotifications\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"notification-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003EScroll to new posts\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"scroll-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003ELocal time\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"localtime-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003E24h time\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"24hour-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003EShow relative time\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"relative-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003EHide Thumbnails\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"hideimages-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003ERecursive Post Hide\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"hiderecursive-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003EVideo\u002FAudio Volume\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"volume-setting\" type=\"range\" min=\"0\" max=\"100\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003ELoop audio\u002Fvideo\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"loop-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003EUnlimit expand height\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"heightlimit-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003ECrisp image rendering\u003C\u002Fdiv\u003E\u003Clabel class=\"postform-style ph-5\"\u003E\u003Cinput id=\"crispimages-setting\" type=\"checkbox\"\u002F\u003E\u003C\u002Flabel\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003EPost Password\u003C\u002Fdiv\u003E\u003Cinput id=\"postpassword-setting\" type=\"password\" name=\"postpassword\"\u002F\u003E\u003C\u002Fdiv\u003E\u003Cdiv class=\"row\"\u003E\u003Cdiv class=\"label\"\u003ECustom CSS\u003C\u002Fdiv\u003E\u003Ctextarea id=\"customcss-setting\"\u003E\u003C\u002Ftextarea\u003E\u003C\u002Fdiv\u003E\u003C\u002Fdiv\u003E";
}
pug_html = pug_html + "\u003C\u002Fdiv\u003E\u003C\u002Fdiv\u003E";
};

@ -0,0 +1,42 @@
const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/';
const generatePassword = () => {
if (window.crypto) {
const buf = new Uint8Array(20); //8 keeps charcodes within range
window.crypto.getRandomValues(buf);
return btoa(String.fromCharCode.apply(null, buf));
} else {
return new Array(20)
.fill(null)
.map(x => charset[Math.floor(Math.random()*charset.length)])
.join('');
}
}
setDefaultLocalStorage('postpassword', generatePassword());
class syncedField {
constructor(selector, key, persistent) {
this.fields = document.querySelectorAll(selector);
this.key = key;
this.persistent = persistent;
for (let field of this.fields) {
field.value = localStorage.getItem(this.key);
field.addEventListener('input', (e) => { this.update(e) }, false);
}
}
update(e) {
if (this.persistent) {
setLocalStorage(this.key, e.target.value);
}
for (let field of this.fields) {
field.value = e.target.value;
}
}
}
window.addEventListener('settingsReady', () => {
new syncedField('input[name="postpassword"]', 'postpassword', true);
});

@ -4,7 +4,7 @@ const { ObjectId } = require(__dirname+'/../db/db.js')
, allowedArrays = new Set(['checkednews', 'checkedposts', 'globalcheckedposts',
'checkedreports', 'checkedbans', 'checkedbanners', 'checkedaccounts']) //only these should be arrays, since express bodyparser can output arrays
, trimFields = ['tags', 'uri', 'moderators', 'filters', 'announcement', 'description', 'message',
'name', 'subject', 'email', 'password', 'default_name', 'report_reason', 'ban_reason', 'log_message', 'custom_css'] //trim if we dont want filed with whitespace
'name', 'subject', 'email', 'postpassword', 'password', 'default_name', 'report_reason', 'ban_reason', 'log_message', 'custom_css'] //trim if we dont want filed with whitespace
, numberFields = ['filter_mode', 'captcha_mode', 'tph_trigger', 'pph_trigger', 'trigger_action', 'reply_limit', 'move_to_thread',
'max_files', 'thread_limit', 'thread', 'max_thread_message_length', 'max_reply_message_length', 'min_thread_message_length', 'min_reply_message_length', 'auth_level'] //convert these to numbers before they hit our routes
, banDurationRegex = /^(?<YEAR>[\d]+y)?(?<MONTH>[\d]+m)?(?<WEEK>[\d]+w)?(?<DAY>[\d]+d)?(?<HOUR>[\d]+h)?$/

@ -27,9 +27,9 @@ module.exports = async (req, res, next) => {
//if user isnt staff, and they put an action that requires password, e.g. delete/spoiler, then filter posts to only matching password
if (res.locals.permLevel >= 4 && res.locals.actions.numPasswords > 0) {
let passwordPosts = [];
if (req.body.password && req.body.password.length > 0) {
if (req.body.postpassword && req.body.postpassword.length > 0) {
//hash their input and make it a buffer
const inputPasswordHash = createHash('sha256').update(postPasswordSecret + req.body.password).digest('base64');
const inputPasswordHash = createHash('sha256').update(postPasswordSecret + req.body.postpassword).digest('base64');
const inputPasswordBuffer = Buffer.from(inputPasswordHash);
passwordPosts = res.locals.posts.filter(post => {
if (post.password != null) { //null password doesnt matter for timing attack, it cant be deleted by non-staff

@ -302,8 +302,8 @@ module.exports = async (req, res, next) => {
}
}
let password = null;
if (req.body.password) {
password = createHash('sha256').update(postPasswordSecret + req.body.password).digest('base64');
if (req.body.postpassword) {
password = createHash('sha256').update(postPasswordSecret + req.body.postpassword).digest('base64');
}
//forceanon hide reply subjects so cant be used as name for replies

@ -12,7 +12,7 @@ details.toggle-label
input.post-check(type='checkbox', name='spoiler' value='1')
| Spoiler Files
label
input#password(type='text', name='password', placeholder='post password' autocomplete='off')
input#password(type='password', name='postpassword', placeholder='post password' autocomplete='off')
label
input.post-check(type='checkbox', name='report' value='1')
| Report

@ -52,7 +52,7 @@ section.form-wrapper.flex-center
if board.settings.userPostSpoiler || board.settings.userPostDelete || board.settings.userPostUnlink
section.row
.label Password
input(type='password', name='password', autocomplete='off' placeholder='password to delete/spoiler/unlink later' maxlength='50')
input(type='password', name='postpassword', autocomplete='off' placeholder='password to delete/spoiler/unlink later' maxlength='50')
if (board.settings.captchaMode === 1 && !isThread) || board.settings.captchaMode === 2
section.row
.label

@ -79,6 +79,9 @@ mixin modal(data)
.label Crisp image rendering
label.postform-style.ph-5
input#crispimages-setting(type='checkbox')
.row
.label Post Password
input#postpassword-setting(type='password' name='postpassword')
.row
.label Custom CSS
textarea#customcss-setting

Loading…
Cancel
Save