From 5a7368a0a45d705a403f96686babd7badc7af422 Mon Sep 17 00:00:00 2001 From: Thomas Lynch Date: Tue, 3 Jan 2023 17:49:59 +1100 Subject: [PATCH] Add a new property to permissions metadata and reflect on frontend inability for users without that "parent" permission to edit roles/accounts to have some permissions e.g. root, edit roles, edit accs Put the metadata into permissions.js (also TODO: key the metadata by bits instead? i.e [Permisions.whatever]: {}) --- controllers/forms.js | 2 +- controllers/forms/actions.js | 2 +- controllers/forms/boardsettings.js | 2 +- controllers/forms/create.js | 2 +- controllers/forms/deletestaff.js | 2 +- controllers/forms/editpost.js | 2 +- controllers/forms/register.js | 2 +- controllers/pages.js | 2 +- db/accounts.js | 2 +- db/posts.js | 2 +- gulp/res/css/style.css | 4 ++ gulpfile.js | 2 +- lib/build/render.js | 2 +- lib/input/actionchecker.js | 2 +- lib/input/decodequeryip.js | 2 +- lib/middleware/captcha/blockbypass.js | 2 +- lib/middleware/captcha/verify.js | 2 +- lib/middleware/misc/spamcheck.js | 2 +- lib/middleware/permission/bancheck.js | 2 +- lib/misc/socketio.js | 2 +- lib/permission/calcperms.js | 2 +- lib/permission/permission.js | 6 +-- lib/permission/permission.test.js | 2 +- lib/permission/permissions.js | 68 +++++++++++++++++++++++- lib/permission/permissiontext.js | 43 --------------- lib/post/markdown/handler/linkmatch.js | 2 +- lib/post/markdown/markdown.js | 2 +- lib/post/name.js | 2 +- migrations/0.4.0.js | 2 +- models/forms/actionhandler.js | 2 +- models/forms/editaccount.js | 3 +- models/forms/editpost.js | 2 +- models/forms/editrole.js | 3 +- models/forms/editstaff.js | 2 +- models/forms/makepost.js | 2 +- models/pages/account.js | 2 +- models/pages/globalmanage/bans.js | 2 +- models/pages/globalmanage/editaccount.js | 1 + models/pages/globalmanage/editrole.js | 1 + models/pages/globalmanage/logs.js | 2 +- models/pages/globalmanage/recent.js | 2 +- models/pages/globalmanage/reports.js | 2 +- models/pages/manage/bans.js | 2 +- models/pages/manage/logs.js | 2 +- models/pages/manage/recent.js | 2 +- models/pages/manage/reports.js | 2 +- server.js | 2 +- views/includes/globalpermissionsform.pug | 5 +- 48 files changed, 121 insertions(+), 91 deletions(-) delete mode 100644 lib/permission/permissiontext.js diff --git a/controllers/forms.js b/controllers/forms.js index 219b981f..1aed0819 100644 --- a/controllers/forms.js +++ b/controllers/forms.js @@ -7,7 +7,7 @@ const express = require('express') , geoIp = require(__dirname+'/../lib/middleware/ip/geoip.js') , processIp = require(__dirname+'/../lib/middleware/ip/processip.js') , calcPerms = require(__dirname+'/../lib/middleware/permission/calcpermsmiddleware.js') - , Permissions = require(__dirname+'/../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../lib/permission/permissions.js') , hasPerms = require(__dirname+'/../lib/middleware/permission/haspermsmiddleware.js') , numFiles = require(__dirname+'/../lib/middleware/file/numfiles.js') , imageHashes = require(__dirname+'/../lib/middleware/file/imagehash.js') diff --git a/controllers/forms/actions.js b/controllers/forms/actions.js index a2bdd283..3eedd7fd 100644 --- a/controllers/forms/actions.js +++ b/controllers/forms/actions.js @@ -1,7 +1,7 @@ 'use strict'; const { Posts, Boards } = require(__dirname+'/../../db/') - , Permissions = require(__dirname+'/../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../lib/permission/permissions.js') , config = require(__dirname+'/../../lib/misc/config.js') , actionHandler = require(__dirname+'/../../models/forms/actionhandler.js') , dynamicResponse = require(__dirname+'/../../lib/misc/dynamic.js') diff --git a/controllers/forms/boardsettings.js b/controllers/forms/boardsettings.js index 0dcebec1..4283ac74 100644 --- a/controllers/forms/boardsettings.js +++ b/controllers/forms/boardsettings.js @@ -1,7 +1,7 @@ 'use strict'; const changeBoardSettings = require(__dirname+'/../../models/forms/changeboardsettings.js') - , Permissions = require(__dirname+'/../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../lib/permission/permissions.js') , { themes, codeThemes } = require(__dirname+'/../../lib/misc/themes.js') , { Ratelimits } = require(__dirname+'/../../db/') , dynamicResponse = require(__dirname+'/../../lib/misc/dynamic.js') diff --git a/controllers/forms/create.js b/controllers/forms/create.js index 6c2f4be1..8bfa5691 100644 --- a/controllers/forms/create.js +++ b/controllers/forms/create.js @@ -1,7 +1,7 @@ 'use strict'; const createBoard = require(__dirname+'/../../models/forms/create.js') - , Permissions = require(__dirname+'/../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../lib/permission/permissions.js') , dynamicResponse = require(__dirname+'/../../lib/misc/dynamic.js') , config = require(__dirname+'/../../lib/misc/config.js') , paramConverter = require(__dirname+'/../../lib/middleware/input/paramconverter.js') diff --git a/controllers/forms/deletestaff.js b/controllers/forms/deletestaff.js index c107b620..160c8948 100644 --- a/controllers/forms/deletestaff.js +++ b/controllers/forms/deletestaff.js @@ -3,7 +3,7 @@ const deleteStaff = require(__dirname+'/../../models/forms/deletestaff.js') , dynamicResponse = require(__dirname+'/../../lib/misc/dynamic.js') , paramConverter = require(__dirname+'/../../lib/middleware/input/paramconverter.js') - , Permissions = require(__dirname+'/../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../lib/permission/permissions.js') , { checkSchema, lengthBody, existsBody } = require(__dirname+'/../../lib/input/schema.js'); module.exports = { diff --git a/controllers/forms/editpost.js b/controllers/forms/editpost.js index 23035d3f..ec84a389 100644 --- a/controllers/forms/editpost.js +++ b/controllers/forms/editpost.js @@ -1,7 +1,7 @@ 'use strict'; const editPost = require(__dirname+'/../../models/forms/editpost.js') - , Permissions = require(__dirname+'/../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../lib/permission/permissions.js') , dynamicResponse = require(__dirname+'/../../lib/misc/dynamic.js') , config = require(__dirname+'/../../lib/misc/config.js') , { Ratelimits, Posts } = require(__dirname+'/../../db/') diff --git a/controllers/forms/register.js b/controllers/forms/register.js index febb5fdb..5541152c 100644 --- a/controllers/forms/register.js +++ b/controllers/forms/register.js @@ -1,6 +1,6 @@ 'use strict'; -const Permissions = require(__dirname+'/../../lib/permission/permissions.js') +const { Permissions } = require(__dirname+'/../../lib/permission/permissions.js') , dynamicResponse = require(__dirname+'/../../lib/misc/dynamic.js') , registerAccount = require(__dirname+'/../../models/forms/register.js') , paramConverter = require(__dirname+'/../../lib/middleware/input/paramconverter.js') diff --git a/controllers/pages.js b/controllers/pages.js index 3ca0ad9a..a6679e6c 100644 --- a/controllers/pages.js +++ b/controllers/pages.js @@ -8,7 +8,7 @@ const express = require('express') , processIp = require(__dirname+'/../lib/middleware/ip/processip.js') , geoIp = require(__dirname+'/../lib/middleware/ip/geoip.js') , calcPerms = require(__dirname+'/../lib/middleware/permission/calcpermsmiddleware.js') - , Permissions = require(__dirname+'/../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../lib/permission/permissions.js') , hasPerms = require(__dirname+'/../lib/middleware/permission/haspermsmiddleware.js') , isLoggedIn = require(__dirname+'/../lib/middleware/permission/isloggedin.js') , paramConverter = require(__dirname+'/../lib/middleware/input/paramconverter.js') diff --git a/db/accounts.js b/db/accounts.js index 2254c53b..edb3aab3 100644 --- a/db/accounts.js +++ b/db/accounts.js @@ -5,7 +5,7 @@ const Mongo = require(__dirname+'/db.js') , bcrypt = require('bcrypt') , cache = require(__dirname+'/../lib/redis/redis.js') , { MONTH } = require(__dirname+'/../lib/converter/timeutils.js') - , Permissions = require(__dirname+'/../lib/permission/permissions.js'); + , { Permissions } = require(__dirname+'/../lib/permission/permissions.js'); module.exports = { diff --git a/db/posts.js b/db/posts.js index 8ce35476..45c7613c 100644 --- a/db/posts.js +++ b/db/posts.js @@ -5,7 +5,7 @@ const Mongo = require(__dirname+'/db.js') , { DAY } = require(__dirname+'/../lib/converter/timeutils.js') , Boards = require(__dirname+'/boards.js') , Stats = require(__dirname+'/stats.js') - , Permissions = require(__dirname+'/../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../lib/permission/permissions.js') , { randomBytes } = require('crypto') , randomBytesAsync = require('util').promisify(randomBytes) , db = Mongo.db.collection('posts') diff --git a/gulp/res/css/style.css b/gulp/res/css/style.css index 72c77559..149255b5 100644 --- a/gulp/res/css/style.css +++ b/gulp/res/css/style.css @@ -772,6 +772,10 @@ span.captchacheckbox { cursor: help; } +.notallowed { + cursor: not-allowed; +} + #float { box-shadow: 0 0 3px 1px var(--darken); max-width: calc(100% - 10px); diff --git a/gulpfile.js b/gulpfile.js index a35771cf..98145cc1 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -3,7 +3,7 @@ const config = require(__dirname+'/lib/misc/config.js') , { Binary } = require('mongodb') , Permission = require(__dirname+'/lib/permission/permission.js') - , Permissions = require(__dirname+'/lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/lib/permission/permissions.js') , { hcaptcha, google } = require(__dirname+'/configs/secrets.js') , gulp = require('gulp') // , pugRuntime = require('pug-runtime/build') diff --git a/lib/build/render.js b/lib/build/render.js index 26cc74b9..8a2eaa7a 100644 --- a/lib/build/render.js +++ b/lib/build/render.js @@ -11,7 +11,7 @@ const { outputFile } = require('fs-extra') , { addCallback } = require(__dirname+'/../redis/redis.js') , { version } = require(__dirname+'/../../package.json') , templateDirectory = path.join(__dirname+'/../../views/pages/') - , Permissions = require(__dirname+'/../permission/permissions.js') + , { Permissions } = require(__dirname+'/../permission/permissions.js') , config = require(__dirname+'/../../lib/misc/config.js'); let { archiveLinksURL, lockWait, globalLimits, boardDefaults, cacheTemplates, diff --git a/lib/input/actionchecker.js b/lib/input/actionchecker.js index ae28a3ef..5f1282b8 100644 --- a/lib/input/actionchecker.js +++ b/lib/input/actionchecker.js @@ -1,6 +1,6 @@ 'use strict'; -const Permissions = require(__dirname+'/../permission/permissions.js') +const { Permissions } = require(__dirname+'/../permission/permissions.js') , actions = [ {name:'unlink_file', global:true, passwords:true, build:true}, {name:'delete_file', global:true, auth:Permissions.MANAGE_GLOBAL_GENERAL, passwords:false, build:true}, diff --git a/lib/input/decodequeryip.js b/lib/input/decodequeryip.js index 884208f9..a597455f 100644 --- a/lib/input/decodequeryip.js +++ b/lib/input/decodequeryip.js @@ -1,7 +1,7 @@ 'use strict'; const { isIP } = require('net') - , Permissions = require(__dirname+'/../permission/permissions.js'); + , { Permissions } = require(__dirname+'/../permission/permissions.js'); module.exports = (query, permissions) => { if (query && query.ip && typeof query.ip === 'string') { diff --git a/lib/middleware/captcha/blockbypass.js b/lib/middleware/captcha/blockbypass.js index 2cd1c8bd..87c14973 100644 --- a/lib/middleware/captcha/blockbypass.js +++ b/lib/middleware/captcha/blockbypass.js @@ -6,7 +6,7 @@ const { Bypass } = require(__dirname+'/../../../db/') , deleteTempFiles = require(__dirname+'/../../file/deletetempfiles.js') , dynamicResponse = require(__dirname+'/../../misc/dynamic.js') , production = process.env.NODE_ENV === 'production' - , Permissions = require(__dirname+'/../../permission/permissions.js'); + , { Permissions } = require(__dirname+'/../../permission/permissions.js'); module.exports = { diff --git a/lib/middleware/captcha/verify.js b/lib/middleware/captcha/verify.js index 3ab47129..cc007da8 100644 --- a/lib/middleware/captcha/verify.js +++ b/lib/middleware/captcha/verify.js @@ -7,7 +7,7 @@ const { Ratelimits } = require(__dirname+'/../../../db/') , dynamicResponse = require(__dirname+'/../../misc/dynamic.js') , deleteTempFiles = require(__dirname+'/../../file/deletetempfiles.js') , uploadDirectory = require(__dirname+'/../../file/uploaddirectory.js') - , Permissions = require(__dirname+'/../../permission/permissions.js'); + , { Permissions } = require(__dirname+'/../../permission/permissions.js'); module.exports = async (req, res, next) => { diff --git a/lib/middleware/misc/spamcheck.js b/lib/middleware/misc/spamcheck.js index 40e940f2..17d3045a 100644 --- a/lib/middleware/misc/spamcheck.js +++ b/lib/middleware/misc/spamcheck.js @@ -2,7 +2,7 @@ const Mongo = require(__dirname+'/../../../db/db.js') , { Posts } = require(__dirname+'/../../../db/') - , Permissions = require(__dirname+'/../../permission/permissions.js') + , { Permissions } = require(__dirname+'/../../permission/permissions.js') , config = require(__dirname+'/../../misc/config.js'); module.exports = async (req, res) => { diff --git a/lib/middleware/permission/bancheck.js b/lib/middleware/permission/bancheck.js index 94e2f5af..b0b1def4 100644 --- a/lib/middleware/permission/bancheck.js +++ b/lib/middleware/permission/bancheck.js @@ -2,7 +2,7 @@ const { Bans } = require(__dirname+'/../../../db/') , dynamicResponse = require(__dirname+'/../../misc/dynamic.js') - , Permissions = require(__dirname+'/../../permission/permissions.js'); + , { Permissions } = require(__dirname+'/../../permission/permissions.js'); module.exports = async (req, res, next) => { diff --git a/lib/misc/socketio.js b/lib/misc/socketio.js index dc9930f1..6bea7d96 100644 --- a/lib/misc/socketio.js +++ b/lib/misc/socketio.js @@ -4,7 +4,7 @@ const { redis: redisConfig } = require(__dirname+'/../../configs/secrets.js') , { Boards } = require(__dirname+'/../../db/') , roomRegex = /^(?[a-z0-9]+)-(?[a-z0-9-]+)$/i , calcPerms = require(__dirname+'/../permission/calcperms.js') - , Permissions = require(__dirname+'/../permission/permissions.js') + , { Permissions } = require(__dirname+'/../permission/permissions.js') , socketIO = require('socket.io') , createAdapter = require('@socket.io/redis-adapter') , Redis = require('ioredis'); diff --git a/lib/permission/calcperms.js b/lib/permission/calcperms.js index 9f206b06..6f1a3a3e 100644 --- a/lib/permission/calcperms.js +++ b/lib/permission/calcperms.js @@ -1,6 +1,6 @@ 'use strict'; -const Permissions = require(__dirname+'/permissions.js') +const { Permissions } = require(__dirname+'/permissions.js') , Permission = require(__dirname+'/permission.js') , roleManager = require(__dirname+'/rolemanager.js'); diff --git a/lib/permission/permission.js b/lib/permission/permission.js index 9873b2f1..da3fb54e 100644 --- a/lib/permission/permission.js +++ b/lib/permission/permission.js @@ -1,7 +1,6 @@ 'use strict'; -const Permissions = require(__dirname+'/permissions.js') - , PermissionText = require(__dirname+'/permissiontext.js') //todo:combine^ +const { Permissions, Metadata } = require(__dirname+'/permissions.js') , BigBitfield = require('big-bitfield'); class Permission extends BigBitfield { @@ -19,10 +18,11 @@ class Permission extends BigBitfield { toJSON() { return this.constructor.permissionEntries .reduce((acc, entry) => { - const { label, desc, title, subtitle } = PermissionText[entry[0]]; + const { label, desc, title, subtitle, parent } = Metadata[entry[0]]; acc[entry[0]] = { bit: entry[1], state: this.get(entry[1]), + parent, label, desc, title, diff --git a/lib/permission/permission.test.js b/lib/permission/permission.test.js index 42cf2d7d..3d782d16 100644 --- a/lib/permission/permission.test.js +++ b/lib/permission/permission.test.js @@ -1,5 +1,5 @@ const Permission = require('./permission.js'); -const Permissions = require('./permissions.js'); +const { Permissions } = require('./permissions.js'); describe('testing permissions', () => { diff --git a/lib/permission/permissions.js b/lib/permission/permissions.js index c5887519..5a67a853 100644 --- a/lib/permission/permissions.js +++ b/lib/permission/permissions.js @@ -1,15 +1,20 @@ 'use strict'; -const Permissions = { +const Permissions = Object.seal(Object.freeze(Object.preventExtensions({ + ROOT: 0, + VIEW_RAW_IP: 1, + CREATE_BOARD: 2, CREATE_ACCOUNT: 3, + BYPASS_BANS: 4, BYPASS_SPAMCHECK: 5, BYPASS_RATELIMITS: 6, BYPASS_FILTERS: 7, BYPASS_CAPTCHA: 8, + MANAGE_GLOBAL_GENERAL: 10, MANAGE_GLOBAL_BANS: 11, MANAGE_GLOBAL_LOGS: 12, @@ -18,6 +23,7 @@ const Permissions = { MANAGE_GLOBAL_SETTINGS: 15, MANAGE_GLOBAL_ACCOUNTS: 16, MANAGE_GLOBAL_ROLES: 17, + MANAGE_BOARD_OWNER: 20, MANAGE_BOARD_GENERAL: 21, MANAGE_BOARD_BANS: 22, @@ -26,6 +32,7 @@ const Permissions = { MANAGE_BOARD_CUSTOMISATION: 25, MANAGE_BOARD_STAFF: 26, _MANAGE_BOARD_BITS: [20,21,22,23,24,25,26], + USE_MARKDOWN_PINKTEXT: 35, USE_MARKDOWN_GREENTEXT: 36, USE_MARKDOWN_BOLD: 37, @@ -40,6 +47,63 @@ const Permissions = { USE_MARKDOWN_LINK: 46, USE_MARKDOWN_DICE: 47, USE_MARKDOWN_FORTUNE: 48, + +}))); + +//todo: make these keyed by the bits? but then how to get the name param for form fields? might change that +const Metadata = { + + ROOT: { title: 'Root', label: 'Root', desc: 'Full control. Use with caution!', parent: Permissions.ROOT }, + + VIEW_RAW_IP: { title: 'Raw IPs', label: 'View Raw IPs', desc: 'Ability to see raw IPs in moderation interfaces.' }, + + CREATE_BOARD: { title: 'Create', label: 'Create Board', desc: 'Ability to create new boards.' }, + CREATE_ACCOUNT: { label: 'Create Account', desc: 'Ability to register an account.' }, + + BYPASS_BANS: { title: 'Bypasses', label: 'Bypass Bans', desc: 'Bypass all bans.' }, + BYPASS_SPAMCHECK: { label: 'Bypass Spamcheck', desc: 'Bypass the basic anti-flood spamcheck for too frequent similar posting.' }, + BYPASS_RATELIMITS: { label: 'Bypass Ratelimits', desc: 'Bypass ratelimits for getting new captchas, editing posts, editing board settings, etc.' }, + BYPASS_FILTERS: { label: 'Bypass Filters', desc: 'Bypass all post filters.' }, + BYPASS_CAPTCHA: { label: 'Bypass Captcha', desc: 'Bypass captcha.' }, + + MANAGE_GLOBAL_GENERAL: { title: 'Global Management',label: 'Global Staff', desc: 'General global staff permission. Access to recent posts and reports. Ability to submit global actions.' }, + MANAGE_GLOBAL_BANS: { label: 'Global Bans', desc: 'Access global bans. Ability to unban, edit, or deny appeals.' }, + MANAGE_GLOBAL_LOGS: { label: 'Global Logs', desc: 'Access global logs. Ability to search/filter' }, + MANAGE_GLOBAL_NEWS: { label: 'News', desc: 'Access news posting. Ability to add, edit, or delete newsposts.' }, + 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.', parent: Permissions.ROOT }, + MANAGE_GLOBAL_ROLES: { label: 'Roles', desc: 'Access roles list. Ability to edit roles', parent: Permissions.ROOT }, + + MANAGE_BOARD_OWNER: { title: 'Board Management', subtitle: 'Note: Setting board management permissions on an account/role level will grant them globally i.e for all boards.\nTo make somebody a normal board owner/staff, transfer them the board or give them the appropriate permissions in the board staff permission editing interface.', 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.' }, + MANAGE_BOARD_LOGS: { label: 'Logs', desc: 'Access board logs. Ability to search/filter.' }, + MANAGE_BOARD_SETTINGS: { label: 'Settings', desc: 'Access board settings. Ability to change any settings. Settings page will show transfer/delete forms for those with "Board Owner" permission.' }, + MANAGE_BOARD_CUSTOMISATION: { label: 'Customisation', desc: 'Access to board assets and custompages. Ability to upload, create, edit, delete.' }, + MANAGE_BOARD_STAFF: { label: 'Staff', desc: 'Access to staff management, and ability to add or remove permissions from others. Can only be given by somebody else with "Board Owner" permission. Use with caution!' }, + + USE_MARKDOWN_PINKTEXT: { title: 'Post styling', label: 'Pinktext', desc: 'Use pinktext' }, + USE_MARKDOWN_GREENTEXT: { label: 'Greentext', desc: 'Use greentext' }, + USE_MARKDOWN_BOLD: { label: 'Bold', desc: 'Use bold' }, + USE_MARKDOWN_UNDERLINE: { label: 'Underline', desc: 'Use underline' }, + USE_MARKDOWN_STRIKETHROUGH: { label: 'Strikethrough', desc: 'Use strikethrough' }, + USE_MARKDOWN_TITLE: { label: 'Title', desc: 'Use titles' }, + USE_MARKDOWN_ITALIC: { label: 'Italic', desc: 'Use italics' }, + USE_MARKDOWN_SPOILER: { label: 'Spoiler', desc: 'Use spoilers' }, + USE_MARKDOWN_MONO: { label: 'Inline Monospace', desc: 'Use inline monospace' }, + USE_MARKDOWN_CODE: { label: 'Code Block', desc: 'Use code blocks' }, + USE_MARKDOWN_DETECTED: { label: 'Detected', desc: 'Use detected' }, + USE_MARKDOWN_LINK: { label: 'Links', desc: 'Make links clickable' }, + USE_MARKDOWN_DICE: { label: 'Dice Roll', desc: 'Use dice rolls' }, + USE_MARKDOWN_FORTUNE: { label: 'Fortune', desc: 'Use fortunes' }, + }; -module.exports = Object.seal(Object.freeze(Object.preventExtensions(Permissions))); +module.exports = { + + Permissions, + + Metadata, + +}; diff --git a/lib/permission/permissiontext.js b/lib/permission/permissiontext.js deleted file mode 100644 index 244fe6e1..00000000 --- a/lib/permission/permissiontext.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict'; - -//todo: merge in permissions.js -module.exports = { - ROOT: { title: 'Root', label: 'Root', desc: 'Full control. Use with caution!' }, - VIEW_RAW_IP: { title: 'Raw IPs', label: 'View Raw IPs', desc: 'Ability to see raw IPs in moderation interfaces.' }, - CREATE_BOARD: { title: 'Create', label: 'Create Board', desc: 'Ability to create new boards.' }, - CREATE_ACCOUNT: { label: 'Create Account', desc: 'Ability to register an account.' }, - BYPASS_BANS: { title: 'Bypasses', label: 'Bypass Bans', desc: 'Bypass all bans.' }, - BYPASS_SPAMCHECK: { label: 'Bypass Spamcheck', desc: 'Bypass the basic anti-flood spamcheck for too frequent similar posting.' }, - BYPASS_RATELIMITS: { label: 'Bypass Ratelimits', desc: 'Bypass ratelimits for getting new captchas, editing posts, editing board settings, etc.' }, - BYPASS_FILTERS: { label: 'Bypass Filters', desc: 'Bypass all post filters.' }, - BYPASS_CAPTCHA: { label: 'Bypass Captcha', desc: 'Bypass captcha.' }, - MANAGE_GLOBAL_GENERAL: { title: 'Global Management',label: 'Global Staff', desc: 'General global staff permission. Access to recent posts and reports. Ability to submit global actions.' }, - MANAGE_GLOBAL_BANS: { label: 'Global Bans', desc: 'Access global bans. Ability to unban, edit, or deny appeals.' }, - MANAGE_GLOBAL_LOGS: { label: 'Global Logs', desc: 'Access global logs. Ability to search/filter' }, - MANAGE_GLOBAL_NEWS: { label: 'News', desc: 'Access news posting. Ability to add, edit, or delete newsposts.' }, - 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', subtitle: 'Note: Setting board management permissions on an account/role level will grant them globally i.e for all boards.\nTo make somebody a normal board owner/staff, transfer them the board or give them the appropriate permissions in the board staff permission editing interface.', 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.' }, - MANAGE_BOARD_LOGS: { label: 'Logs', desc: 'Access board logs. Ability to search/filter.' }, - MANAGE_BOARD_SETTINGS: { label: 'Settings', desc: 'Access board settings. Ability to change any settings. Settings page will show transfer/delete forms for those with "Board Owner" permission.' }, - MANAGE_BOARD_CUSTOMISATION: { label: 'Customisation', desc: 'Access to board assets and custompages. Ability to upload, create, edit, delete.' }, - MANAGE_BOARD_STAFF: { label: 'Staff', desc: 'Access to staff management, and ability to add or remove permissions from others. Can only be given by somebody else with "Board Owner" permission. Use with caution!' }, - USE_MARKDOWN_PINKTEXT: { title: 'Post styling', label: 'Pinktext', desc: 'Use pinktext' }, - USE_MARKDOWN_GREENTEXT: { label: 'Greentext', desc: 'Use greentext' }, - USE_MARKDOWN_BOLD: { label: 'Bold', desc: 'Use bold' }, - USE_MARKDOWN_UNDERLINE: { label: 'Underline', desc: 'Use underline' }, - USE_MARKDOWN_STRIKETHROUGH: { label: 'Strikethrough', desc: 'Use strikethrough' }, - USE_MARKDOWN_TITLE: { label: 'Title', desc: 'Use titles' }, - USE_MARKDOWN_ITALIC: { label: 'Italic', desc: 'Use italics' }, - USE_MARKDOWN_SPOILER: { label: 'Spoiler', desc: 'Use spoilers' }, - USE_MARKDOWN_MONO: { label: 'Inline Monospace', desc: 'Use inline monospace' }, - USE_MARKDOWN_CODE: { label: 'Code Block', desc: 'Use code blocks' }, - USE_MARKDOWN_DETECTED: { label: 'Detected', desc: 'Use detected' }, - USE_MARKDOWN_LINK: { label: 'Links', desc: 'Make links clickable' }, - USE_MARKDOWN_DICE: { label: 'Dice Roll', desc: 'Use dice rolls' }, - USE_MARKDOWN_FORTUNE: { label: 'Fortune', desc: 'Use fortunes' }, -}; diff --git a/lib/post/markdown/handler/linkmatch.js b/lib/post/markdown/handler/linkmatch.js index 1715b280..d8f29355 100644 --- a/lib/post/markdown/handler/linkmatch.js +++ b/lib/post/markdown/handler/linkmatch.js @@ -1,6 +1,6 @@ 'use strict'; -const Permissions = require(__dirname+'/../../../permission/permissions.js'); +const { Permissions } = require(__dirname+'/../../../permission/permissions.js'); module.exports = (permissions, match, p1, p2, p3, offset, string, groups) => { diff --git a/lib/post/markdown/markdown.js b/lib/post/markdown/markdown.js index be629c73..2e58c1c8 100644 --- a/lib/post/markdown/markdown.js +++ b/lib/post/markdown/markdown.js @@ -24,7 +24,7 @@ const greentextRegex = /^>((?!>\d+|>>/\w+(/\d*)?|>># , diceroll = require(__dirname+'/handler/diceroll.js') , fortune = require(__dirname+'/handler/fortune.js') , linkmatch = require(__dirname+'/handler/linkmatch.js') - , Permissions = require(__dirname+'/../../permission/permissions.js'); + , { Permissions } = require(__dirname+'/../../permission/permissions.js'); let replacements = []; diff --git a/lib/post/name.js b/lib/post/name.js index 6ac541f8..8d12a277 100644 --- a/lib/post/name.js +++ b/lib/post/name.js @@ -1,7 +1,7 @@ 'use strict'; const { getInsecureTrip, getSecureTrip } = require(__dirname+'/tripcode.js') - , Permissions = require(__dirname+'/../permission/permissions.js') + , { Permissions } = require(__dirname+'/../permission/permissions.js') , nameRegex = /^(?[^#].*?)?(?:(?##(?[^ ].*?)|#(?[^#].*?)))?(?##(? .*?)?)?$/ , staffLevels = ['Admin', 'Global Staff', 'Board Owner', 'Board Mod'] , staffLevelsRegex = new RegExp(`(${staffLevels.join('|')})+`, 'igm'); diff --git a/migrations/0.4.0.js b/migrations/0.4.0.js index 035d6e9b..4b620315 100644 --- a/migrations/0.4.0.js +++ b/migrations/0.4.0.js @@ -3,7 +3,7 @@ const hashIp = require(__dirname+'/../lib/misc/haship.js') , { createCIDR, parse } = require('ip6addr') , Permission = require(__dirname+'/../lib/permission/permission.js') - , Permissions = require(__dirname+'/../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../lib/permission/permissions.js') , { Binary } = require('mongodb'); module.exports = async(db, redis) => { diff --git a/models/forms/actionhandler.js b/models/forms/actionhandler.js index eb881943..2a7d2262 100644 --- a/models/forms/actionhandler.js +++ b/models/forms/actionhandler.js @@ -17,7 +17,7 @@ const { Posts, Boards, Modlogs } = require(__dirname+'/../../db/') , uploadDirectory = require(__dirname+'/../../lib/file/uploaddirectory.js') , getAffectedBoards = require(__dirname+'/../../lib/misc/affectedboards.js') , dynamicResponse = require(__dirname+'/../../lib/misc/dynamic.js') - , Permissions = require(__dirname+'/../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../lib/permission/permissions.js') , buildQueue = require(__dirname+'/../../lib/build/queue.js') , { postPasswordSecret } = require(__dirname+'/../../configs/secrets.js') , threadRegex = /\/[a-z0-9]+\/(?:manage\/)?thread\/(\d+)\.html/i diff --git a/models/forms/editaccount.js b/models/forms/editaccount.js index 24da011b..26ba61a6 100644 --- a/models/forms/editaccount.js +++ b/models/forms/editaccount.js @@ -2,7 +2,7 @@ const { Accounts } = require(__dirname+'/../../db/') , dynamicResponse = require(__dirname+'/../../lib/misc/dynamic.js') - , Permissions = require(__dirname+'/../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../lib/permission/permissions.js') , Permission = require(__dirname+'/../../lib/permission/permission.js'); module.exports = async (req, res) => { @@ -13,6 +13,7 @@ module.exports = async (req, res) => { updatingPermissions = new Permission(req.body.template); } else { updatingPermissions = new Permission(res.locals.editingAccount.permissions); + //TODO: change to just be a loop now, and use Metadata[].bit to handle the check on l49 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)); diff --git a/models/forms/editpost.js b/models/forms/editpost.js index e97ccebb..c447e650 100644 --- a/models/forms/editpost.js +++ b/models/forms/editpost.js @@ -1,7 +1,7 @@ 'use strict'; const { Posts, Modlogs } = require(__dirname+'/../../db/') - , Permissions = require(__dirname+'/../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../lib/permission/permissions.js') , { createHash } = require('crypto') , Mongo = require(__dirname+'/../../db/db.js') , { prepareMarkdown } = require(__dirname+'/../../lib/post/markdown/markdown.js') diff --git a/models/forms/editrole.js b/models/forms/editrole.js index 8caf478a..e42e6121 100644 --- a/models/forms/editrole.js +++ b/models/forms/editrole.js @@ -4,12 +4,13 @@ const { Roles, Accounts } = require(__dirname+'/../../db/') , redis = require(__dirname+'/../../lib/redis/redis.js') , dynamicResponse = require(__dirname+'/../../lib/misc/dynamic.js') , roleManager = require(__dirname+'/../../lib/permission/rolemanager.js') - , Permissions = require(__dirname+'/../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../lib/permission/permissions.js') , Permission = require(__dirname+'/../../lib/permission/permission.js'); module.exports = async (req, res) => { let rolePermissions = new Permission(res.locals.editingRole.permissions); + //TODO: change to just be a loop now, and use Metadata[].bit to handle the check on l49 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)); diff --git a/models/forms/editstaff.js b/models/forms/editstaff.js index efba9164..1ed43045 100644 --- a/models/forms/editstaff.js +++ b/models/forms/editstaff.js @@ -2,7 +2,7 @@ const { Boards } = require(__dirname+'/../../db/') , dynamicResponse = require(__dirname+'/../../lib/misc/dynamic.js') - , Permissions = require(__dirname+'/../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../lib/permission/permissions.js') , Permission = require(__dirname+'/../../lib/permission/permission.js'); module.exports = async (req, res) => { diff --git a/models/forms/makepost.js b/models/forms/makepost.js index a46dddd3..4ffeec2c 100644 --- a/models/forms/makepost.js +++ b/models/forms/makepost.js @@ -24,7 +24,7 @@ const { createHash, randomBytes } = require('crypto') , deleteTempFiles = require(__dirname+'/../../lib/file/deletetempfiles.js') , fixGifs = require(__dirname+'/../../lib/file/image/fixgifs.js') , timeUtils = require(__dirname+'/../../lib/converter/timeutils.js') - , Permissions = require(__dirname+'/../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../lib/permission/permissions.js') , deletePosts = require(__dirname+'/deletepost.js') , spamCheck = require(__dirname+'/../../lib/middleware/misc/spamcheck.js') , config = require(__dirname+'/../../lib/misc/config.js') diff --git a/models/pages/account.js b/models/pages/account.js index e4f42d8c..1dbbf721 100644 --- a/models/pages/account.js +++ b/models/pages/account.js @@ -1,7 +1,7 @@ 'use strict'; const { Posts, Boards } = require(__dirname+'/../../db/') - , Permissions = require(__dirname+'/../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../lib/permission/permissions.js') , Permission = require(__dirname+'/../../lib/permission/permission.js'); module.exports = async (req, res, next) => { diff --git a/models/pages/globalmanage/bans.js b/models/pages/globalmanage/bans.js index 7a95016d..9a409471 100644 --- a/models/pages/globalmanage/bans.js +++ b/models/pages/globalmanage/bans.js @@ -1,7 +1,7 @@ 'use strict'; const { Bans } = require(__dirname+'/../../../db/') - , Permissions = require(__dirname+'/../../../lib/permission/permissions.js'); + , { Permissions } = require(__dirname+'/../../../lib/permission/permissions.js'); module.exports = async (req, res, next) => { diff --git a/models/pages/globalmanage/editaccount.js b/models/pages/globalmanage/editaccount.js index e5516eac..9996fa9c 100644 --- a/models/pages/globalmanage/editaccount.js +++ b/models/pages/globalmanage/editaccount.js @@ -24,6 +24,7 @@ module.exports = async (req, res, next) => { accountUsername: req.params.accountusername, accountPermissions, roles: roleManager.roles, + permissions: res.locals.permissions, }); }; diff --git a/models/pages/globalmanage/editrole.js b/models/pages/globalmanage/editrole.js index 1cd24acc..203d33ee 100644 --- a/models/pages/globalmanage/editrole.js +++ b/models/pages/globalmanage/editrole.js @@ -20,6 +20,7 @@ module.exports = async (req, res, next) => { role, rolePermissions: new Permission(role.permissions), roleNameMap: roleManager.roleNameMap, + permissions: res.locals.permissions, }); }; diff --git a/models/pages/globalmanage/logs.js b/models/pages/globalmanage/logs.js index 393ff9f7..b9d8d718 100644 --- a/models/pages/globalmanage/logs.js +++ b/models/pages/globalmanage/logs.js @@ -2,7 +2,7 @@ const { Modlogs } = require(__dirname+'/../../../db/') , pageQueryConverter = require(__dirname+'/../../../lib/input/pagequeryconverter.js') - , Permissions = require(__dirname+'/../../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../../lib/permission/permissions.js') , decodeQueryIP = require(__dirname+'/../../../lib/input/decodequeryip.js') , { isIP } = require('net') , limit = 50; diff --git a/models/pages/globalmanage/recent.js b/models/pages/globalmanage/recent.js index 262cc22a..00bf5a95 100644 --- a/models/pages/globalmanage/recent.js +++ b/models/pages/globalmanage/recent.js @@ -3,7 +3,7 @@ const { Posts } = require(__dirname+'/../../../db/') , config = require(__dirname+'/../../../lib/misc/config.js') , pageQueryConverter = require(__dirname+'/../../../lib/input/pagequeryconverter.js') - , Permissions = require(__dirname+'/../../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../../lib/permission/permissions.js') , decodeQueryIP = require(__dirname+'/../../../lib/input/decodequeryip.js') , limit = 20; diff --git a/models/pages/globalmanage/reports.js b/models/pages/globalmanage/reports.js index b1c8b127..ef9b988b 100644 --- a/models/pages/globalmanage/reports.js +++ b/models/pages/globalmanage/reports.js @@ -2,7 +2,7 @@ const { Posts } = require(__dirname+'/../../../db/') , pageQueryConverter = require(__dirname+'/../../../lib/input/pagequeryconverter.js') - , Permissions = require(__dirname+'/../../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../../lib/permission/permissions.js') , decodeQueryIP = require(__dirname+'/../../../lib/input/decodequeryip.js') , limit = 20; diff --git a/models/pages/manage/bans.js b/models/pages/manage/bans.js index 7c747f8f..adfcca25 100644 --- a/models/pages/manage/bans.js +++ b/models/pages/manage/bans.js @@ -1,7 +1,7 @@ 'use strict'; const Bans = require(__dirname+'/../../../db/bans.js') - , Permissions = require(__dirname+'/../../../lib/permission/permissions.js'); + , { Permissions } = require(__dirname+'/../../../lib/permission/permissions.js'); module.exports = async (req, res, next) => { diff --git a/models/pages/manage/logs.js b/models/pages/manage/logs.js index 4c1b59f9..6a3ad0a6 100644 --- a/models/pages/manage/logs.js +++ b/models/pages/manage/logs.js @@ -2,7 +2,7 @@ const { Modlogs } = require(__dirname+'/../../../db/') , pageQueryConverter = require(__dirname+'/../../../lib/input/pagequeryconverter.js') - , Permissions = require(__dirname+'/../../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../../lib/permission/permissions.js') // , decodeQueryIP = require(__dirname+'/../../../lib/input/decodequeryip.js') , limit = 50; diff --git a/models/pages/manage/recent.js b/models/pages/manage/recent.js index c8c5d5eb..86931a1e 100644 --- a/models/pages/manage/recent.js +++ b/models/pages/manage/recent.js @@ -3,7 +3,7 @@ const { Posts } = require(__dirname+'/../../../db/') , config = require(__dirname+'/../../../lib/misc/config.js') , decodeQueryIP = require(__dirname+'/../../../lib/input/decodequeryip.js') - , Permissions = require(__dirname+'/../../../lib/permission/permissions.js') + , { Permissions } = require(__dirname+'/../../../lib/permission/permissions.js') , pageQueryConverter = require(__dirname+'/../../../lib/input/pagequeryconverter.js') , limit = 20; diff --git a/models/pages/manage/reports.js b/models/pages/manage/reports.js index 5fd53a69..f51bf40d 100644 --- a/models/pages/manage/reports.js +++ b/models/pages/manage/reports.js @@ -1,7 +1,7 @@ 'use strict'; const Posts = require(__dirname+'/../../../db/posts.js') - , Permissions = require(__dirname+'/../../../lib/permission/permissions.js'); + , { Permissions } = require(__dirname+'/../../../lib/permission/permissions.js'); module.exports = async (req, res, next) => { diff --git a/server.js b/server.js index 4aa97a81..3630ca38 100644 --- a/server.js +++ b/server.js @@ -17,7 +17,7 @@ const config = require(__dirname+'/lib/misc/config.js') , { version } = require(__dirname+'/package.json') , formatSize = require(__dirname+'/lib/converter/formatsize.js') , CachePugTemplates = require('cache-pug-templates') - , Permissions = require(__dirname+'/lib/permission/permissions.js'); + , { Permissions } = require(__dirname+'/lib/permission/permissions.js'); (async () => { diff --git a/views/includes/globalpermissionsform.pug b/views/includes/globalpermissionsform.pug index ed8ef492..a7c2f87f 100644 --- a/views/includes/globalpermissionsform.pug +++ b/views/includes/globalpermissionsform.pug @@ -5,8 +5,9 @@ for perm, index in Object.keys(jsonPermissions) if jsonPermissions[perm].subtitle p #{jsonPermissions[perm].subtitle} .row - label.postform-style.ph-5 - input(type='checkbox' name=perm value=jsonPermissions[perm].bit checked=jsonPermissions[perm].state) + - const hasParent = jsonPermissions[perm].parent == null || permissions.get(jsonPermissions[perm].parent); + label.postform-style.ph-5(class=(!hasParent ? 'notallowed' : null)) + input(type='checkbox' name=perm value=jsonPermissions[perm].bit checked=jsonPermissions[perm].state disabled=!hasParent) .rlabel #{jsonPermissions[perm].label} p #{jsonPermissions[perm].desc} input(type='submit', value='Save')