Start making roles editable ref #377

permtemplates are now roles.
They are in the db and can be edited.
Still have to do a few things like the migration, gulpfile and some small details.
merge-requests/341/head
Thomas Lynch 2 years ago
parent 78f56b4be0
commit 993924a5f2
  1. 6
      controllers/forms.js
  2. 6
      controllers/forms/editaccount.js
  3. 42
      controllers/forms/editrole.js
  4. 1
      controllers/forms/index.js
  5. 11
      controllers/pages.js
  6. 1
      db/index.js
  7. 46
      db/roles.js
  8. 12
      gulpfile.js
  9. 4
      helpers/checks/calcperms.js
  10. 6
      helpers/permission.js
  11. 1
      helpers/permissions.js
  12. 1
      helpers/permissiontext.js
  13. 62
      helpers/permtemplates.js
  14. 4
      helpers/posting/message.js
  15. 4
      helpers/render.js
  16. 103
      helpers/roles.js
  17. 12
      migrations/0.4.0.js
  18. 4
      models/forms/addstaff.js
  19. 4
      models/forms/create.js
  20. 4
      models/forms/editaccount.js
  21. 72
      models/forms/editrole.js
  22. 4
      models/forms/register.js
  23. 6
      models/forms/transferboard.js
  24. 9
      models/pages/globalmanage/editaccount.js
  25. 23
      models/pages/globalmanage/editrole.js
  26. 2
      models/pages/globalmanage/index.js
  27. 17
      models/pages/globalmanage/roles.js
  28. 5
      redis.js
  29. 9
      server.js
  30. 3
      views/mixins/globalmanagenav.pug
  31. 3
      views/pages/account.pug
  32. 10
      views/pages/editaccount.pug
  33. 27
      views/pages/editrole.pug
  34. 2
      views/pages/globalmanageaccounts.pug
  35. 22
      views/pages/globalmanageroles.pug

@ -30,7 +30,7 @@ const express = require('express')
resignController, deleteAccountController, loginController, registerController, changePasswordController,
deleteAccountsController, editAccountController, globalSettingsController, createBoardController, makePostController,
addStaffController, deleteStaffController, editStaffController, editCustomPageController, editPostController,
newCaptcha, blockBypass, logout } = require(__dirname+'/forms/index.js');
editRoleController, newCaptcha, blockBypass, logout } = require(__dirname+'/forms/index.js');
//make new post
@ -103,7 +103,9 @@ hasPerms.one(Permissions.MANAGE_GLOBAL_NEWS), deleteNewsController.paramConverte
router.post('/global/deleteaccounts', useSession, sessionRefresh, csrf, calcPerms, isLoggedIn,
hasPerms.one(Permissions.MANAGE_GLOBAL_ACCOUNTS), deleteAccountsController.paramConverter, deleteAccountsController.controller); //account deleting
router.post('/global/editaccount', useSession, sessionRefresh, csrf, calcPerms, isLoggedIn,
hasPerms.one(Permissions.MANAGE_GLOBAL_ACCOUNTS), editAccountController.paramConverter, editAccountController.controller); //account deleting
hasPerms.one(Permissions.MANAGE_GLOBAL_ACCOUNTS), editAccountController.paramConverter, editAccountController.controller); //account editing
router.post('/global/editrole', useSession, sessionRefresh, csrf, calcPerms, isLoggedIn,
hasPerms.one(Permissions.MANAGE_GLOBAL_ROLES), editRoleController.paramConverter, editRoleController.controller); //role editing
router.post('/global/settings', useSession, sessionRefresh, csrf, calcPerms, isLoggedIn,
hasPerms.one(Permissions.MANAGE_GLOBAL_SETTINGS), globalSettingsController.paramConverter, globalSettingsController.controller); //global settings

@ -6,7 +6,7 @@ const editAccount = require(__dirname+'/../../models/forms/editaccount.js')
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js')
, paramConverter = require(__dirname+'/../../helpers/paramconverter.js')
, Permissions = require(__dirname+'/../../helpers/permissions.js')
, { permTemplates } = require(__dirname+'/../../helpers/permtemplates.js')
, { roles } = require(__dirname+'/../../helpers/roles.js')
, { checkSchema, lengthBody, numberBody, minmaxBody, numberBodyVariable,
inArrayBody, arrayInBody, existsBody } = require(__dirname+'/../../helpers/schema.js');
@ -28,8 +28,8 @@ module.exports = {
}, expected: true, error: 'Invalid account username' },
{ result: (res.locals.user.username === req.body.username), expected: false, error: "You can't edit your own permissions" },
{ result: !existsBody(req.body.template) //no template, OR the template is a valid one
|| inArrayBody(req.body.template, [permTemplates.ANON.base64, permTemplates.GLOBAL_STAFF.base64, permTemplates.ADMIN.base64,
permTemplates.BOARD_STAFF.base64, permTemplates.BOARD_OWNER.base64]),
|| inArrayBody(req.body.template, [roles.ANON.base64, roles.GLOBAL_STAFF.base64, roles.ADMIN.base64,
roles.BOARD_STAFF.base64, roles.BOARD_OWNER.base64]),
expected: true, error: "Invalid template selection" },
]);

@ -0,0 +1,42 @@
'use strict';
const editRole = require(__dirname+'/../../models/forms/editrole.js')
, { Roles } = require(__dirname+'/../../db/')
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js')
, paramConverter = require(__dirname+'/../../helpers/paramconverter.js')
, { checkSchema, lengthBody, numberBody, minmaxBody, numberBodyVariable,
inArrayBody, arrayInBody, existsBody } = require(__dirname+'/../../helpers/schema.js');
module.exports = {
paramConverter: paramConverter({
objectIdFields: ['roleid'],
}),
controller: async (req, res, next) => {
const errors = await checkSchema([
{ result: existsBody(req.body.roleid), expected: true, error: 'Missing role id' },
{ result: async () => {
res.locals.editingRole = await Roles.findOne(req.body.roleid);
return res.locals.editingRole != null && res.locals.editingRole.name !== 'ROOT';
}, blocking: true, expected: true, error: "You can't edit this role" },
]);
if (errors.length > 0) {
return dynamicResponse(req, res, 400, 'message', {
'title': 'Bad request',
'errors': errors,
'redirect': req.headers.referer || `/${req.params.board}/manage/roles.html`,
});
}
try {
await editRole(req, res, next);
} catch (err) {
return next(err);
}
}
}

@ -35,6 +35,7 @@ module.exports = {
addStaffController: require(__dirname+'/addstaff.js'),
deleteStaffController: require(__dirname+'/deletestaff.js'),
editStaffController: require(__dirname+'/editstaff.js'),
editRoleController: require(__dirname+'/editrole.js'),
//these dont have a "real" controller
newCaptcha: require(__dirname+'/../../models/forms/newcaptcha.js'),

@ -19,14 +19,15 @@ const express = require('express')
//page models
, { manageRecent, manageReports, manageAssets, manageSettings, manageBans, editCustomPage, manageMyPermissions,
manageBoard, manageThread, manageLogs, manageCatalog, manageCustomPages, manageStaff, editStaff } = require(__dirname+'/../models/pages/manage/')
, { globalManageSettings, globalManageReports, globalManageBans, globalManageBoards, editNews, editAccount,
globalManageRecent, globalManageAccounts, globalManageNews, globalManageLogs } = require(__dirname+'/../models/pages/globalmanage/')
, { globalManageSettings, globalManageReports, globalManageBans, globalManageBoards, editNews, editAccount, editRole,
globalManageRecent, globalManageAccounts, globalManageNews, globalManageLogs, globalManageRoles } = require(__dirname+'/../models/pages/globalmanage/')
, { changePassword, blockBypass, home, register, login, create, myPermissions,
board, catalog, banners, randombanner, news, captchaPage, overboard, overboardCatalog,
captcha, thread, modlog, modloglist, account, boardlist, customPage, csrfPage } = require(__dirname+'/../models/pages/')
, threadParamConverter = paramConverter({ processThreadIdParam: true })
, logParamConverter = paramConverter({ processDateParam: true })
, newsParamConverter = paramConverter({ objectIdParams: ['newsid'] })
, roleParamConverter = paramConverter({ objectIdParams: ['roleid'] })
, custompageParamConverter = paramConverter({ objectIdParams: ['custompageid'] });
//homepage
@ -97,13 +98,17 @@ router.get('/globalmanage/news.html', useSession, sessionRefresh, isLoggedIn, ca
hasPerms.one(Permissions.MANAGE_GLOBAL_NEWS), csrf, globalManageNews);
router.get('/globalmanage/accounts.html', useSession, sessionRefresh, isLoggedIn, calcPerms,
hasPerms.one(Permissions.MANAGE_GLOBAL_ACCOUNTS), csrf, globalManageAccounts);
router.get('/globalmanage/roles.html', useSession, sessionRefresh, isLoggedIn, calcPerms,
hasPerms.one(Permissions.MANAGE_GLOBAL_ROLES), csrf, globalManageRoles);
router.get('/globalmanage/settings.html', useSession, sessionRefresh, isLoggedIn, calcPerms,
hasPerms.one(Permissions.MANAGE_GLOBAL_SETTINGS), csrf, globalManageSettings);
router.get('/globalmanage/editnews/:newsid([a-f0-9]{24}).html', useSession, sessionRefresh, isLoggedIn, calcPerms,
hasPerms.one(Permissions.MANAGE_GLOBAL_NEWS), csrf, newsParamConverter, editNews);
router.get('/globalmanage/editaccount/:accountusername([a-zA-Z0-9]{1,50}).html', useSession, sessionRefresh, isLoggedIn, calcPerms,
hasPerms.one(Permissions.MANAGE_GLOBAL_ACCOUNTS), csrf, editAccount);
//TODO: edit post edit page form, like editnews/editaccount endpoint
router.get('/globalmanage/editrole/:roleid([a-f0-9]{24}).html', useSession, sessionRefresh, isLoggedIn, calcPerms,
hasPerms.one(Permissions.MANAGE_GLOBAL_ROLES), csrf, roleParamConverter, editRole);
//TODO: edit post edit page form, like editnews/editaccount/editrole endpoint
//captcha
router.get('/captcha', geoAndTor, processIp, captcha); //get captcha image and cookie

@ -6,6 +6,7 @@ module.exports = {
Boards: require(__dirname+'/boards.js'),
Stats: require(__dirname+'/stats.js'),
Accounts: require(__dirname+'/accounts.js'),
Roles: require(__dirname+'/roles.js'),
Bans: require(__dirname+'/bans.js'),
Captchas: require(__dirname+'/captchas.js'),
Files: require(__dirname+'/files.js'),

@ -0,0 +1,46 @@
'use strict';
const Mongo = require(__dirname+'/db.js')
, db = Mongo.db.collection('roles')
, cache = require(__dirname+'/../redis.js');
module.exports = {
db,
findOne: async (id) => {
//is there any point even caching
let role = await cache.get(`role:${id}`);
if (role) {
return role;
} else {
role = await db.findOne({ '_id': id });
if (role) {
role.permissions = role.permissions.toString('base64');
cache.set(`role:${id}`, role);
}
}
return role;
},
find: () => {
return db.find({}).toArray();
},
updateOne: async (id, permissions) => {
const res = await db.updateOne({
'_id': id
}, {
'$set': {
'permissions': Mongo.Binary(permissions.array),
},
});
cache.del(`role:${id}`);
return res;
},
deleteAll: () => {
return db.deleteMany({});
},
};

@ -1,13 +1,13 @@
'use strict';
const config = require(__dirname+'/config.js')
, Permissions = require(__dirname+'/helpers/permissions.js')
, { hcaptcha, google } = require(__dirname+'/configs/secrets.js')
, gulp = require('gulp')
, fs = require('fs-extra')
, semver = require('semver')
, uploadDirectory = require(__dirname+'/helpers/files/uploadDirectory.js')
, commit = require(__dirname+'/helpers/commit.js')
, { permTemplates } = require(__dirname+'/helpers/permtemplates.js')
, replace = require('gulp-replace')
, less = require('gulp-less')
, concat = require('gulp-concat')
@ -160,7 +160,7 @@ async function wipe() {
}
const { Boards, Posts, Captchas, Ratelimits, News, CustomPages,
Accounts, Files, Stats, Modlogs, Bans, Bypass } = require(__dirname+'/db/');
Accounts, Files, Stats, Modlogs, Bans, Bypass, Roles } = require(__dirname+'/db/');
//wipe db shit
await Promise.all([
@ -168,6 +168,7 @@ async function wipe() {
Captchas.deleteAll(),
Ratelimits.deleteAll(),
Accounts.deleteAll(),
Roles.deleteAll(),
Posts.deleteAll(),
Boards.deleteAll(),
Bans.deleteAll(),
@ -203,8 +204,12 @@ async function wipe() {
await Posts.db.createIndex({ 'board': 1, 'reports.0': 1 }, { 'partialFilterExpression': { 'reports.0': { '$exists': true } } })
await Posts.db.createIndex({ 'globalreports.0': 1 }, { 'partialFilterExpression': { 'globalreports.0': { '$exists': true } } })
//todo: insert roles to roles db
const randomPassword = randomBytes(20).toString('base64')
await Accounts.insertOne('admin', 'admin', randomPassword, permTemplates.ROOT);
const rootPermission = new Permission();
rootPermissions.set(Permissions.ROOT);
await Accounts.insertOne('admin', 'admin', randomPassword, rootPermission);
console.log('=====LOGIN DETAILS=====\nusername: admin\npassword:', randomPassword, '\n=======================');
await db.collection('version').replaceOne({
@ -345,7 +350,6 @@ function deletehtml() {
async function custompages() {
const formatSize = require(__dirname+'/helpers/files/formatsize.js');
const Permissions = require(__dirname+'/helpers/permissions.js');
return gulp.src([
`${paths.pug.src}/custompages/*.pug`,
`${paths.pug.src}/pages/404.pug`,

@ -2,7 +2,7 @@
const Permissions = require(__dirname+'/../permissions.js') //needs rename
, Permission = require(__dirname+'/../permission.js')
, { permTemplates } = require(__dirname+'/../permtemplates.js');
, { roles } = require(__dirname+'/../roles.js');
module.exports = (req, res) => {
@ -40,7 +40,7 @@ module.exports = (req, res) => {
} else {
//not logged in, gets default anon permission
calculatedPermissions = new Permission(permTemplates.ANON.base64);
calculatedPermissions = new Permission(roles.ANON.base64);
}
return calculatedPermissions;

@ -34,11 +34,7 @@ class Permission extends BigBitfield {
if (this.get(Permissions.ROOT)){ //root gets all perms
this.setAll(this.constructor.allPermissions);
} else if (this.get(Permissions.MANAGE_BOARD_OWNER)) { //BOs and "global staff"
this.setAll([
Permissions.MANAGE_BOARD_GENERAL, Permissions.MANAGE_BOARD_BANS,
Permissions.MANAGE_BOARD_LOGS, Permissions.MANAGE_BOARD_SETTINGS,
Permissions.MANAGE_BOARD_CUSTOMISATION, Permissions.MANAGE_BOARD_STAFF,
]);
this.setAll(Permissions._MANAGE_BOARD_BITS);
}
}

@ -16,6 +16,7 @@ const Permissions = {
MANAGE_GLOBAL_BOARDS: 14,
MANAGE_GLOBAL_SETTINGS: 15,
MANAGE_GLOBAL_ACCOUNTS: 16,
MANAGE_GLOBAL_ROLES: 17,
MANAGE_BOARD_OWNER: 20,
MANAGE_BOARD_GENERAL: 21,
MANAGE_BOARD_BANS: 22,

@ -17,6 +17,7 @@ module.exports = {
MANAGE_GLOBAL_BOARDS: { label: 'Boards', desc: 'Access the global board list. Ability to search/filter. Also grants the ability to transfer or delete any board.' },
MANAGE_GLOBAL_SETTINGS: { label: 'Global Settings', desc: 'Access global settings. Ability to change any settings.' },
MANAGE_GLOBAL_ACCOUNTS: { label: 'Accounts', desc: 'Access the accounts list. Ability to search/sort. Ability to edit permissions of any user. Can only be given by somebody else with "Root" permission.' }, //view, delete, change account permissions
MANAGE_GLOBAL_ROLES: { label: 'Roles', desc: 'Access roles list. Ability to edit roles. Can only be given by somebody else with "Root" permission.' }, //view and edit roles
MANAGE_BOARD_OWNER: { title: 'Board Management', label: 'Board Owner', desc: 'Full control of the board, equivalent to the BO. Can delete and/or transfer the board. Can only be given by somebody else with "Board Owner" permission. Use with caution!' },
MANAGE_BOARD_GENERAL: { label: 'Board Staff', desc: 'General board staff permission. Access mod index, catalog, recent posts and reports. Ability to submit mod actions. Bypass board-specific bans and post filters.' },
MANAGE_BOARD_BANS: { label: 'Bans', desc: 'Access board bans. Ability to unban, edit, or deny appeals.' },

@ -1,62 +0,0 @@
'use strict';
const Permissions = require(__dirname+'/permissions.js')
, Permission = require(__dirname+'/permission.js');
const ANON = new Permission()
ANON.setAll([
Permissions.USE_MARKDOWN_PINKTEXT, Permissions.USE_MARKDOWN_GREENTEXT, Permissions.USE_MARKDOWN_BOLD,
Permissions.USE_MARKDOWN_UNDERLINE, Permissions.USE_MARKDOWN_STRIKETHROUGH, Permissions.USE_MARKDOWN_TITLE,
Permissions.USE_MARKDOWN_ITALIC, Permissions.USE_MARKDOWN_SPOILER, Permissions.USE_MARKDOWN_MONO,
Permissions.USE_MARKDOWN_CODE, Permissions.USE_MARKDOWN_DETECTED, Permissions.USE_MARKDOWN_LINK,
Permissions.USE_MARKDOWN_DICE, Permissions.USE_MARKDOWN_FORTUNE, Permissions.CREATE_BOARD,
Permissions.CREATE_ACCOUNT
]);
const BOARD_STAFF = new Permission(ANON.base64)
BOARD_STAFF.setAll([
Permissions.MANAGE_BOARD_GENERAL, Permissions.MANAGE_BOARD_BANS, Permissions.MANAGE_BOARD_LOGS,
]);
const BOARD_OWNER = new Permission(BOARD_STAFF.base64)
BOARD_OWNER.setAll([
Permissions.MANAGE_BOARD_OWNER, Permissions.MANAGE_BOARD_STAFF, Permissions.MANAGE_BOARD_CUSTOMISATION,
Permissions.MANAGE_BOARD_SETTINGS,
]);
const GLOBAL_STAFF = new Permission(BOARD_OWNER.base64);
GLOBAL_STAFF.setAll([
Permissions.MANAGE_GLOBAL_GENERAL, Permissions.MANAGE_GLOBAL_BANS, Permissions.MANAGE_GLOBAL_LOGS, Permissions.MANAGE_GLOBAL_NEWS,
Permissions.MANAGE_GLOBAL_BOARDS, Permissions.MANAGE_GLOBAL_SETTINGS, Permissions.MANAGE_BOARD_OWNER, Permissions.BYPASS_FILTERS,
Permissions.BYPASS_BANS, Permissions.BYPASS_SPAMCHECK, Permissions.BYPASS_RATELIMITS,
]);
const ADMIN = new Permission(GLOBAL_STAFF.base64);
ADMIN.setAll([
Permissions.MANAGE_GLOBAL_ACCOUNTS, Permissions.VIEW_RAW_IP,
]);
const ROOT = new Permission();
ROOT.setAll(Permission.allPermissions);
module.exports = {
permTemplates: {
ANON,
BOARD_STAFF,
BOARD_OWNER,
GLOBAL_STAFF,
ADMIN,
ROOT,
},
permTemplateMap: {
[ANON.base64]: 'Regular User',
[BOARD_STAFF.base64]: 'Board Staff',
[BOARD_OWNER.base64]: 'Board Owner',
[GLOBAL_STAFF.base64]: 'Global Staff',
[ADMIN.base64]: 'Admin',
[ROOT.base64]: 'Root',
},
};

@ -5,7 +5,7 @@ const quoteHandler = require(__dirname+'/quotes.js')
, { markdown } = require(__dirname+'/markdown.js')
, sanitizeOptions = require(__dirname+'/sanitizeoptions.js')
, Permission = require(__dirname+'/../permissions.js')
, { permTemplates } = require(__dirname+'/../permtemplates.js')
, { roles } = require(__dirname+'/../roles.js')
, sanitize = require('sanitize-html');
module.exports = async (inputMessage, boardName, threadId=null, permissions=null) => {
@ -16,7 +16,7 @@ module.exports = async (inputMessage, boardName, threadId=null, permissions=null
if (permissions === null) {
//technically there has for a long time been a bug here, but it can be fixed later. permissions unknown for old msgs
permissions = new Permission(permTemplates.ANON.base64);
permissions = new Permission(roles.ANON.base64);
}
//markdown a post, link the quotes, sanitize and return message and quote arrays

@ -12,7 +12,7 @@ const { outputFile } = require('fs-extra')
, { version } = require(__dirname+'/../package.json')
, templateDirectory = path.join(__dirname+'/../views/pages/')
, Permissions = require(__dirname+'/permissions.js')
, { permTemplateMap } = require(__dirname+'/permtemplates.js')
, { roleNameMap } = require(__dirname+'/roles.js')
, config = require(__dirname+'/../config.js');
let { archiveLinksURL, lockWait, globalLimits, boardDefaults, cacheTemplates,
@ -23,7 +23,7 @@ const updateLocals = () => {
({ archiveLinksURL, lockWait, globalLimits, boardDefaults, cacheTemplates,
reverseImageLinksURL, meta, enableWebring, captchaOptions, globalAnnouncement } = config.get);
renderLocals = {
permTemplateMap,
roleNameMap,
Permissions,
cache: cacheTemplates,
archiveLinksURL,

@ -0,0 +1,103 @@
'use strict';
const { Roles } = require(__dirname+'/../db/')
, { Binary } = require(__dirname+'/../db/db.js')
, redis = require(__dirname+'/../redis.js')
, Permissions = require(__dirname+'/permissions.js')
, Permission = require(__dirname+'/permission.js');
const load = async () => {
//todo: take a message argument from callback,
//maybe need separate func just for reloading single role
let roles = await Roles.find();
roles = roles.reduce((acc, r) => {
acc[r.name] = new Permission(r.permissions.toString('base64'));
return acc;
}, {});
const { ANON, BOARD_STAFF, BOARD_OWNER, GLOBAL_STAFF, ADMIN, ROOT } = roles;
module.exports.roles = {
ANON,
BOARD_STAFF,
BOARD_OWNER,
GLOBAL_STAFF,
ADMIN,
ROOT,
};
module.exports.roleNameMap = {
[ANON.base64]: 'Regular User',
[BOARD_STAFF.base64]: 'Board Staff',
[BOARD_OWNER.base64]: 'Board Owner',
[GLOBAL_STAFF.base64]: 'Global Staff',
[ADMIN.base64]: 'Admin',
[ROOT.base64]: 'Root',
};
// put in role edit model on successful edit
// redis.redisPublisher.publish('roles', JSON.stringify({/*ROLES OBJECT, make */}));
};
//possibly, will call a different function like "updaterole", with mesage for single
//role name, for when a role is edited
//redis.addCallback('roles', load);
module.exports = {
roles: {},
roleNameMap: {},
load,
};
//put in gulpfile/migration!!
//const ANON = new Permission()
//ANON.setAll([
// Permissions.USE_MARKDOWN_PINKTEXT, Permissions.USE_MARKDOWN_GREENTEXT, Permissions.USE_MARKDOWN_BOLD,
// Permissions.USE_MARKDOWN_UNDERLINE, Permissions.USE_MARKDOWN_STRIKETHROUGH, Permissions.USE_MARKDOWN_TITLE,
// Permissions.USE_MARKDOWN_ITALIC, Permissions.USE_MARKDOWN_SPOILER, Permissions.USE_MARKDOWN_MONO,
// Permissions.USE_MARKDOWN_CODE, Permissions.USE_MARKDOWN_DETECTED, Permissions.USE_MARKDOWN_LINK,
// Permissions.USE_MARKDOWN_DICE, Permissions.USE_MARKDOWN_FORTUNE, Permissions.CREATE_BOARD,
// Permissions.CREATE_ACCOUNT
//]);
//
//const BOARD_STAFF = new Permission(ANON.base64)
//BOARD_STAFF.setAll([
// Permissions.MANAGE_BOARD_GENERAL, Permissions.MANAGE_BOARD_BANS, Permissions.MANAGE_BOARD_LOGS,
//]);
//
//const BOARD_OWNER = new Permission(BOARD_STAFF.base64)
//BOARD_OWNER.setAll([
// Permissions.MANAGE_BOARD_OWNER, Permissions.MANAGE_BOARD_STAFF, Permissions.MANAGE_BOARD_CUSTOMISATION,
// Permissions.MANAGE_BOARD_SETTINGS,
//]);
//
//const GLOBAL_STAFF = new Permission(BOARD_OWNER.base64);
//GLOBAL_STAFF.setAll([
// Permissions.MANAGE_GLOBAL_GENERAL, Permissions.MANAGE_GLOBAL_BANS, Permissions.MANAGE_GLOBAL_LOGS, Permissions.MANAGE_GLOBAL_NEWS,
// Permissions.MANAGE_GLOBAL_BOARDS, Permissions.MANAGE_GLOBAL_SETTINGS, Permissions.MANAGE_BOARD_OWNER, Permissions.BYPASS_FILTERS,
// Permissions.BYPASS_BANS, Permissions.BYPASS_SPAMCHECK, Permissions.BYPASS_RATELIMITS,
//]);
//
//const ADMIN = new Permission(GLOBAL_STAFF.base64);
//ADMIN.setAll([
// Permissions.MANAGE_GLOBAL_ACCOUNTS, Permissions.MANAGE_GLOBAL_ROLES, Permissions.VIEW_RAW_IP,
//]);
//
//const ROOT = new Permission();
//ROOT.setAll(Permission.allPermissions);
//
// if (roles.length === 0) {
// await Roles.db.insertMany([
// { name: 'ANON', permission: Binary(ANON.array) },
// { name: 'BOARD_STAFF', permission: Binary(BOARD_STAFF.array) },
// { name: 'BOARD_OWNER', permission: Binary(BOARD_OWNER.array) },
// { name: 'GLOBAL_STAFF', permission: Binary(GLOBAL_STAFF.array) },
// { name: 'ADMIN', permission: Binary(ADMIN.array) },
// { name: 'ROOT', permission: Binary(ROOT.array) },
// ]);
// console.log((await Roles.find()))
// }

@ -1,6 +1,6 @@
'use strict';
const { permTemplates } = require(__dirname+'/../helpers/permtemplates.js')
const { roles } = require(__dirname+'/../helpers/roles.js')
, Permission = require(__dirname+'/../helpers/permission.js')
, { Binary } = require('mongodb');
@ -9,19 +9,19 @@ module.exports = async(db, redis) => {
console.log('setting new permission templates to replace old permission "levels"');
await db.collection('accounts').updateMany({ authLevel: 0 }, {
'$set': {
'permissions': Binary(permTemplates.ROOT.array),
'permissions': Binary(roles.ROOT.array),
},
});
await db.collection('accounts').updateMany({ authLevel: 1 }, {
'$set': {
'permissions': Binary(permTemplates.GLOBAL_STAFF.array),
'permissions': Binary(roles.GLOBAL_STAFF.array),
},
});
//not doing 2 and 3 anymore, since they were a weird, ugly part of the old "levels" system.
//they can be added back manually by editing global perms if desired
await db.collection('accounts').updateMany({ authLevel: { $gte: 2 } }, { //gte2, to get 2, 3, and 4.
'$set': {
'permissions': Binary(permTemplates.ANON.array),
'permissions': Binary(roles.ANON.array),
},
});
console.log('renaming account modBoards->staffBoards');
@ -51,14 +51,14 @@ module.exports = async(db, redis) => {
const bulkWrites = allBoards.map(board => {
const staffObject = board.settings.moderators.reduce((acc, mod) => {
acc[mod] = {
permissions: Binary(permTemplates.BOARD_STAFF.array),
permissions: Binary(roles.BOARD_STAFF.array),
addedDate: new Date(),
};
return acc;
}, {});
//add add the BO to staff
staffObject[board.owner] = {
permissions: Binary(permTemplates.BOARD_OWNER.array),
permissions: Binary(roles.BOARD_OWNER.array),
addedDate: new Date(),
}
return {

@ -2,13 +2,13 @@
const { Boards, Accounts } = require(__dirname+'/../../db/')
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js')
, { permTemplates } = require(__dirname+'/../../helpers/permtemplates.js');
, { roles } = require(__dirname+'/../../helpers/roles.js');
module.exports = async (req, res, next) => {
await Promise.all([
Accounts.addStaffBoard([req.body.username], res.locals.board._id),
Boards.addStaff(res.locals.board._id, req.body.username, permTemplates.BOARD_STAFF)
Boards.addStaff(res.locals.board._id, req.body.username, roles.BOARD_STAFF)
]);
return dynamicResponse(req, res, 200, 'message', {

@ -3,7 +3,7 @@
const { Boards, Accounts } = require(__dirname+'/../../db/')
, { Binary } = require(__dirname+'/../../db/db.js')
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js')
, { permTemplates } = require(__dirname+'/../../helpers/permtemplates.js')
, { roles } = require(__dirname+'/../../helpers/roles.js')
, uploadDirectory = require(__dirname+'/../../helpers/files/uploadDirectory.js')
, restrictedURIs = new Set(['captcha', 'forms', 'randombanner', 'all'])
, { ensureDir } = require('fs-extra')
@ -52,7 +52,7 @@ module.exports = async (req, res, next) => {
'webring': false,
'staff': {
[owner]: {
'permissions': Binary(permTemplates.BOARD_OWNER.array),
'permissions': Binary(roles.BOARD_OWNER.array),
'addedDate': new Date(),
},
},

@ -13,7 +13,6 @@ module.exports = async (req, res, next) => {
updatingPermissions = new Permission(req.body.template);
} else {
updatingPermissions = new Permission(res.locals.editingAccount.permissions);
//this can probably be made more general
updatingPermissions.set(Permissions.VIEW_RAW_IP, (req.body.VIEW_RAW_IP != null));
updatingPermissions.set(Permissions.CREATE_BOARD, (req.body.CREATE_BOARD != null));
updatingPermissions.set(Permissions.CREATE_ACCOUNT, (req.body.CREATE_ACCOUNT != null));
@ -49,11 +48,12 @@ module.exports = async (req, res, next) => {
updatingPermissions.set(Permissions.USE_MARKDOWN_DICE, (req.body.USE_MARKDOWN_DICE != null));
updatingPermissions.set(Permissions.USE_MARKDOWN_FORTUNE, (req.body.USE_MARKDOWN_FORTUNE != null));
if (res.locals.permissions.get(Permissions.ROOT)) {
//be careful giving others manage_global_accounts!
updatingPermissions.set(Permissions.MANAGE_GLOBAL_ACCOUNTS, (req.body.MANAGE_GLOBAL_ACCOUNTS != null))
updatingPermissions.set(Permissions.MANAGE_GLOBAL_ROLES, (req.body.MANAGE_GLOBAL_ROLES != null))
updatingPermissions.set(Permissions.ROOT, (req.body.ROOT != null));
}
}
updatingPermissions.applyInheritance();
const updated = await Accounts.setAccountPermissions(req.body.username, updatingPermissions).then(r => r.matchedCount);

@ -0,0 +1,72 @@
'use strict';
const { Roles } = require(__dirname+'/../../db/')
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js')
, Permissions = require(__dirname+'/../../helpers/permissions.js')
, Permission = require(__dirname+'/../../helpers/permission.js');
module.exports = async (req, res, next) => {
let rolePermissions;
rolePermissions = new Permission(res.locals.editingRole.permissions);
rolePermissions.set(Permissions.VIEW_RAW_IP, (req.body.VIEW_RAW_IP != null));
rolePermissions.set(Permissions.CREATE_BOARD, (req.body.CREATE_BOARD != null));
rolePermissions.set(Permissions.CREATE_ACCOUNT, (req.body.CREATE_ACCOUNT != null));
rolePermissions.set(Permissions.BYPASS_BANS, (req.body.BYPASS_BANS != null));
rolePermissions.set(Permissions.BYPASS_SPAMCHECK, (req.body.BYPASS_SPAMCHECK != null));
rolePermissions.set(Permissions.BYPASS_RATELIMITS, (req.body.BYPASS_RATELIMITS != null));
rolePermissions.set(Permissions.BYPASS_FILTERS, (req.body.BYPASS_FILTERS != null));
rolePermissions.set(Permissions.MANAGE_GLOBAL_GENERAL, (req.body.MANAGE_GLOBAL_GENERAL != null));
rolePermissions.set(Permissions.MANAGE_GLOBAL_BANS, (req.body.MANAGE_GLOBAL_BANS != null));
rolePermissions.set(Permissions.MANAGE_GLOBAL_LOGS, (req.body.MANAGE_GLOBAL_LOGS != null));
rolePermissions.set(Permissions.MANAGE_GLOBAL_NEWS, (req.body.MANAGE_GLOBAL_NEWS != null));
rolePermissions.set(Permissions.MANAGE_GLOBAL_BOARDS, (req.body.MANAGE_GLOBAL_BOARDS != null));
rolePermissions.set(Permissions.MANAGE_GLOBAL_SETTINGS, (req.body.MANAGE_GLOBAL_SETTINGS != null));
rolePermissions.set(Permissions.MANAGE_BOARD_GENERAL, (req.body.MANAGE_BOARD_GENERAL != null));
rolePermissions.set(Permissions.MANAGE_BOARD_OWNER, (req.body.MANAGE_BOARD_OWNER != null));
rolePermissions.set(Permissions.MANAGE_BOARD_BANS, (req.body.MANAGE_BOARD_BANS != null));
rolePermissions.set(Permissions.MANAGE_BOARD_LOGS, (req.body.MANAGE_BOARD_LOGS != null));
rolePermissions.set(Permissions.MANAGE_BOARD_SETTINGS, (req.body.MANAGE_BOARD_SETTINGS != null));
rolePermissions.set(Permissions.MANAGE_BOARD_CUSTOMISATION, (req.body.MANAGE_BOARD_CUSTOMISATION != null));
rolePermissions.set(Permissions.MANAGE_BOARD_STAFF, (req.body.MANAGE_BOARD_STAFF != null));
rolePermissions.set(Permissions.USE_MARKDOWN_PINKTEXT, (req.body.USE_MARKDOWN_PINKTEXT != null));
rolePermissions.set(Permissions.USE_MARKDOWN_GREENTEXT, (req.body.USE_MARKDOWN_GREENTEXT != null));
rolePermissions.set(Permissions.USE_MARKDOWN_BOLD, (req.body.USE_MARKDOWN_BOLD != null));
rolePermissions.set(Permissions.USE_MARKDOWN_UNDERLINE, (req.body.USE_MARKDOWN_UNDERLINE != null));
rolePermissions.set(Permissions.USE_MARKDOWN_STRIKETHROUGH, (req.body.USE_MARKDOWN_STRIKETHROUGH != null));
rolePermissions.set(Permissions.USE_MARKDOWN_TITLE, (req.body.USE_MARKDOWN_TITLE != null));
rolePermissions.set(Permissions.USE_MARKDOWN_ITALIC, (req.body.USE_MARKDOWN_ITALIC != null));
rolePermissions.set(Permissions.USE_MARKDOWN_SPOILER, (req.body.USE_MARKDOWN_SPOILER != null));
rolePermissions.set(Permissions.USE_MARKDOWN_MONO, (req.body.USE_MARKDOWN_MONO != null));
rolePermissions.set(Permissions.USE_MARKDOWN_CODE, (req.body.USE_MARKDOWN_CODE != null));
rolePermissions.set(Permissions.USE_MARKDOWN_DETECTED, (req.body.USE_MARKDOWN_DETECTED != null));
rolePermissions.set(Permissions.USE_MARKDOWN_LINK, (req.body.USE_MARKDOWN_LINK != null));
rolePermissions.set(Permissions.USE_MARKDOWN_DICE, (req.body.USE_MARKDOWN_DICE != null));
rolePermissions.set(Permissions.USE_MARKDOWN_FORTUNE, (req.body.USE_MARKDOWN_FORTUNE != null));
if (res.locals.permissions.get(Permissions.ROOT)) {
rolePermissions.set(Permissions.MANAGE_GLOBAL_ACCOUNTS, (req.body.MANAGE_GLOBAL_ACCOUNTS != null))
rolePermissions.set(Permissions.MANAGE_GLOBAL_ROLES, (req.body.MANAGE_GLOBAL_ROLES != null))
rolePermissions.set(Permissions.ROOT, (req.body.ROOT != null));
}
rolePermissions.applyInheritance();
//todo: error for making role with same permissions as another role.
const updated = await Roles.updateOne(req.body.roleid, rolePermissions).then(r => r.matchedCount);
if (updated === 0) {
return dynamicResponse(req, res, 400, 'message', {
'title': 'Bad request',
'errors': 'Role does not exist',
'redirect': req.headers.referer || `/globalmanage/roles.html`,
});
}
return dynamicResponse(req, res, 200, 'message', {
'title': 'Success',
'message': 'Edited role',
'redirect': `/globalmanage/editrole/${req.body.roleid}.html`,
});
}

@ -2,7 +2,7 @@
const { Accounts } = require(__dirname+'/../../db/')
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js')
, { permTemplates } = require(__dirname+'/../../helpers/permtemplates.js');
, { roles } = require(__dirname+'/../../helpers/roles.js');
module.exports = async (req, res, next) => {
@ -22,7 +22,7 @@ module.exports = async (req, res, next) => {
}
// add account to db. password is hashed in db model func for easier tests
await Accounts.insertOne(original, username, password, permTemplates.ANON);
await Accounts.insertOne(original, username, password, roles.ANON);
return res.redirect('/login.html');

@ -2,7 +2,7 @@
const { Boards, Accounts } = require(__dirname+'/../../db/')
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js')
, { permTemplates } = require(__dirname+'/../../helpers/permtemplates.js');
, { roles } = require(__dirname+'/../../helpers/roles.js');
module.exports = async (req, res, next) => {
@ -20,14 +20,14 @@ module.exports = async (req, res, next) => {
if (res.locals.board.staff[newOwner._id] != null) {
//if already a staff, just change their permission instead of removing+adding back
await Promise.all([
Boards.setStaffPermissions(req.params.board, newOwner._id, permTemplates.BOARD_OWNER, true),
Boards.setStaffPermissions(req.params.board, newOwner._id, roles.BOARD_OWNER, true),
Accounts.removeStaffBoard([newOwner._id], req.params.board),
Accounts.addOwnedBoard(newOwner._id, req.params.board),
]);
} else {
//otherwise add them as a new staff+owner
await Promise.all([
Boards.addStaff(req.params.board, newOwner._id, permTemplates.BOARD_OWNER, true),
Boards.addStaff(req.params.board, newOwner._id, roles.BOARD_OWNER, true),
Accounts.addOwnedBoard(newOwner._id, req.params.board),
]);
}

@ -1,7 +1,7 @@
'use strict';
const { Accounts } = require(__dirname+'/../../../db/')
, { permTemplates } = require(__dirname+'/../../../helpers/permtemplates.js')
, { roles } = require(__dirname+'/../../../helpers/roles.js')
, Permission = require(__dirname+'/../../../helpers/permission.js');
module.exports = async (req, res, next) => {
@ -13,14 +13,17 @@ module.exports = async (req, res, next) => {
return next();
}
const accountPermissions = new Permission(editingAccount.permissions);
//accountPermissions.applyInheritance();
res
.set('Cache-Control', 'private, max-age=5')
.render('editaccount', {
csrf: req.csrfToken(),
board: res.locals.board,
accountUsername: req.params.accountusername,
accountPermissions: new Permission(editingAccount.permissions),
permTemplates,
accountPermissions,
roles,
});
}

@ -0,0 +1,23 @@
'use strict';
const { Roles } = require(__dirname+'/../../../db/')
, Permission = require(__dirname+'/../../../helpers/permission.js');
module.exports = async (req, res, next) => {
const role = await Roles.findOne(req.params.roleid);
if (role == null) {
//role does not exist
return next();
}
res
.set('Cache-Control', 'private, max-age=5')
.render('editrole', {
csrf: req.csrfToken(),
role,
rolePermissions: new Permission(role.permissions),
});
}

@ -9,6 +9,8 @@ module.exports = {
globalManageNews: require(__dirname+'/news.js'),
globalManageAccounts: require(__dirname+'/accounts.js'),
globalManageSettings: require(__dirname+'/settings.js'),
globalManageRoles: require(__dirname+'/roles.js'),
editNews: require(__dirname+'/editnews.js'),
editAccount: require(__dirname+'/editaccount.js'),
editRole: require(__dirname+'/editrole.js'),
}

@ -0,0 +1,17 @@
'use strict';
const { Roles } = require(__dirname+'/../../../db/')
module.exports = async (req, res, next) => {
const roles = await Roles.find();
res
.set('Cache-Control', 'private, max-age=5')
.render('globalmanageroles', {
csrf: req.csrfToken(),
permissions: res.locals.permissions,
roles,
});
}

@ -6,8 +6,9 @@ const Redis = require('ioredis')
, subscriber = new Redis(secrets.redis)
, publisher = new Redis(secrets.redis)
, messageCallbacks = {
'config': [], //others in future?
}
'config': [],
'roles': [],
};
module.exports = {

@ -17,8 +17,7 @@ const config = require(__dirname+'/config.js')
, { version } = require(__dirname+'/package.json')
, formatSize = require(__dirname+'/helpers/files/formatsize.js')
, CachePugTemplates = require('cache-pug-templates')
, Permissions = require(__dirname+'/helpers/permissions.js')
, { permTemplateMap } = require(__dirname+'/helpers/permtemplates.js');
, Permissions = require(__dirname+'/helpers/permissions.js');
(async () => {
@ -36,6 +35,11 @@ const config = require(__dirname+'/config.js')
debugLogs && console.log('CONNECTING TO REDIS');
const redis = require(__dirname+'/redis.js');
// load roles early
const roles = require(__dirname+'/helpers/roles.js');
await roles.load();
app.locals.roleNameMap = roles.roleNameMap;
// disable useless express header
app.disable('x-powered-by');
//query strings
@ -72,7 +76,6 @@ const config = require(__dirname+'/config.js')
app.cache = {};
app[cacheTemplates === true ? 'enable' : 'disable']('view cache');
//default settings
app.locals.permTemplateMap = permTemplateMap;
app.locals.Permissions = Permissions;
app.locals.defaultTheme = boardDefaults.theme;
app.locals.defaultCodeTheme = boardDefaults.codeTheme;

@ -16,6 +16,9 @@ mixin globalmanagenav(selected, upLevel)
if permissions.get(Permissions.MANAGE_GLOBAL_ACCOUNTS)
|
a(href=`${upLevel ? '../' : ''}accounts.html` class=(selected === 'accounts' ? 'bold' : '')) [Accounts]
if permissions.get(Permissions.MANAGE_GLOBAL_ROLES)
|
a(href=`${upLevel ? '../' : ''}roles.html` class=(selected === 'roles' ? 'bold' : '')) [Roles]
if permissions.get(Permissions.MANAGE_GLOBAL_NEWS)
|
a(href=`${upLevel ? '../' : ''}news.html` class=(selected === 'news' ? 'bold' : '')) [News]

@ -42,6 +42,9 @@ block content
if permissions.get(Permissions.MANAGE_GLOBAL_ACCOUNTS)
|
a(href=`/globalmanage/accounts.html`) Accounts
if permissions.get(Permissions.MANAGE_GLOBAL_ROLES)
|
a(href=`/globalmanage/roles.html`) Roles
if permissions.get(Permissions.MANAGE_GLOBAL_NEWS)
|
a(href=`/globalmanage/news.html`) News

@ -32,9 +32,9 @@ block content
select(name='template')
option(disabled selected) None
//-limiting which ones atm
option(value=permTemplates.ANON.base64) Regular User
option(value=permTemplates.BOARD_STAFF.base64) Global Board Staff
option(value=permTemplates.GLOBAL_STAFF.base64) Global Board Owner
option(value=permTemplates.GLOBAL_STAFF.base64) Global Staff
option(value=permTemplates.ADMIN.base64) Admin
option(value=roles.ANON.base64) Regular User
option(value=roles.BOARD_STAFF.base64) Global Board Staff
option(value=roles.BOARD_OWNER.base64) Global Board Owner
option(value=roles.GLOBAL_STAFF.base64) Global Staff
option(value=roles.ADMIN.base64) Admin
input(type='submit', value='Apply')

@ -0,0 +1,27 @@
extends ../layout.pug
include ../mixins/globalmanagenav.pug
block head
title Edit role
block content
h1.board-title Global Management
br
+globalmanagenav('roles', true)
hr(size=1)
h4.mv-5 Edit role "#{roleNameMap[rolePermissions.base64]}"
- const jsonPermissions = rolePermissions.toJSON();
.form-wrapper.flexleft
form(action=`/forms/global/editrole` method='POST')
input(type='hidden' name='_csrf' value=csrf)
input(type='hidden' name='roleid' value=role._id)
for perm, index in Object.keys(jsonPermissions)
if jsonPermissions[perm].title && index > 0
hr(size=1)
h4.mv-5 #{jsonPermissions[perm].title}
.row
label.postform-style.ph-5
input(type='checkbox' name=perm value=jsonPermissions[perm].bit checked=jsonPermissions[perm].state)
.rlabel #{jsonPermissions[perm].label}
p #{jsonPermissions[perm].desc}
input(type='submit', value='Save')

@ -57,7 +57,7 @@ block content
time.reltime(datetime=account.lastActiveDate.toISOString()) #{account.lastActiveDate.toLocaleString(undefined, {hourCycle:'h23'})}
else
| -
td #{permTemplateMap[account.permissions.toString('base64')] || 'Custom'}
td #{roleNameMap[account.permissions.toString('base64')] || 'Custom'}
td
if account._id !== user.username
a(href=`/globalmanage/editaccount/${account._id}.html`) [Edit]

@ -0,0 +1,22 @@
extends ../layout.pug
include ../mixins/globalmanagenav.pug
block head
title Roles
block content
h1.board-title Global Management
br
+globalmanagenav('roles')
hr(size=1)
h4.mv-5 Roles:
.table-container.flex-left.text-center
table
tr
th Role
th Permissions
for role in roles
tr
td #{roleNameMap[role.permissions.toString('base64')]}
td: a(href=`/globalmanage/editrole/${role._id}.html`) [Edit]
Loading…
Cancel
Save