feat: add permission check to resolvers (wip)

pull/6816/merge
NGPixel 4 months ago
parent 1aa58546fe
commit 1c65d23408
No known key found for this signature in database
GPG Key ID: B755FB6870B30F63

@ -1,5 +1,3 @@
/* global WIKI */
import express from 'express'
import ExpressBrute from 'express-brute'
import BruteKnex from '../helpers/brute-knex.mjs'

@ -475,6 +475,7 @@ export async function up (knex) {
private: certs.privateKey
},
secret,
rootAdminGroupId: groupAdminId,
rootAdminUserId: userAdminId,
guestUserId: userGuestId
}

@ -4,6 +4,10 @@ import { generateError, generateSuccess } from '../../helpers/graph.mjs'
export default {
Query: {
async analyticsProviders(obj, args, context, info) {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:system'])) {
throw new Error('ERR_FORBIDDEN')
}
let providers = await WIKI.db.analytics.getProviders(args.isEnabled)
providers = providers.map(stg => {
const providerInfo = find(WIKI.data.analytics, ['key', stg.key]) || {}
@ -28,6 +32,10 @@ export default {
Mutation: {
async updateAnalyticsProviders(obj, args, context) {
try {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:system'])) {
throw new Error('ERR_FORBIDDEN')
}
for (let str of args.providers) {
await WIKI.db.analytics.query().patch({
isEnabled: str.isEnabled,

@ -10,6 +10,7 @@ import { pipeline } from 'node:stream/promises'
export default {
Query: {
async assetById(obj, args, context) {
// FIXME: Perm
const asset = await WIKI.db.assets.query().findById(args.id)
if (asset) {
return asset
@ -145,6 +146,7 @@ export default {
*/
async uploadAssets(obj, args, context) {
try {
// FIXME: Perm
// -> Get Folder
let folder = {}
if (args.folderId || args.folderPath) {
@ -380,6 +382,10 @@ export default {
*/
async flushTempUploads(obj, args, context) {
try {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:system'])) {
throw new Error('ERR_FORBIDDEN')
}
await WIKI.db.assets.flushTempUploads()
return {
operation: generateSuccess('Temporary Uploads have been flushed successfully.')

@ -46,7 +46,11 @@ export default {
/**
* Fetch authentication strategies
*/
async authStrategies () {
async authStrategies (obj, args, context) {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:system'])) {
throw new Error('ERR_FORBIDDEN')
}
return WIKI.data.authentication.map(stg => ({
...stg,
isAvailable: stg.isAvailable === true
@ -56,6 +60,10 @@ export default {
* Fetch active authentication strategies
*/
async authActiveStrategies (obj, args, context) {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:system'])) {
throw new Error('ERR_FORBIDDEN')
}
const strategies = await WIKI.db.authentication.getStrategies({ enabledOnly: args.enabledOnly })
return strategies.map(a => {
const str = _.find(WIKI.data.authentication, ['key', a.module]) || {}

@ -7,6 +7,10 @@ export default {
* Fetch list of Comments Providers
*/
async commentsProviders(obj, args, context, info) {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:system'])) {
throw new Error('ERR_FORBIDDEN')
}
const providers = await WIKI.db.commentProviders.getProviders()
return providers.map(provider => {
const providerInfo = _.find(WIKI.data.commentProviders, ['key', provider.key]) || {}
@ -137,6 +141,10 @@ export default {
*/
async updateCommentsProviders(obj, args, context) {
try {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:system'])) {
throw new Error('ERR_FORBIDDEN')
}
for (let provider of args.providers) {
await WIKI.db.commentProviders.query().patch({
isEnabled: provider.isEnabled,

@ -1,4 +1,4 @@
import { generateError, generateSuccess } from '../../helpers/graph.mjs'
import { generateSuccess } from '../../helpers/graph.mjs'
import safeRegex from 'safe-regex'
import _ from 'lodash-es'
import { v4 as uuid } from 'uuid'
@ -8,7 +8,10 @@ export default {
/**
* FETCH ALL GROUPS
*/
async groups () {
async groups (obj, args, context) {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:groups', 'manage:users', 'manage:system'])) {
throw new Error('ERR_FORBIDDEN')
}
return WIKI.db.groups.query().select(
'groups.*',
WIKI.db.groups.relatedQuery('users').count().as('userCount')
@ -17,7 +20,10 @@ export default {
/**
* FETCH A SINGLE GROUP
*/
async groupById(obj, args) {
async groupById(obj, args, context) {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:groups', 'manage:users', 'manage:system'])) {
throw new Error('ERR_FORBIDDEN')
}
return WIKI.db.groups.query().findById(args.id)
}
},
@ -26,8 +32,12 @@ export default {
* ASSIGN USER TO GROUP
*/
async assignUserToGroup (obj, args, { req }) {
if (!WIKI.auth.checkAccess(req.user, ['manage:groups', 'manage:users', 'manage:system'])) {
throw new Error('ERR_FORBIDDEN')
}
// Check for guest user
if (args.userId === 2) {
if (args.userId === WIKI.config.auth.guestUserId) {
throw new Error('Cannot assign the Guest user to a group.')
}
@ -78,6 +88,10 @@ export default {
* CREATE NEW GROUP
*/
async createGroup (obj, args, { req }) {
if (!WIKI.auth.checkAccess(req.user, ['manage:groups', 'manage:system'])) {
throw new Error('ERR_FORBIDDEN')
}
const group = await WIKI.db.groups.query().insertAndFetch({
name: args.name,
permissions: JSON.stringify(WIKI.data.groups.defaultPermissions),
@ -97,8 +111,12 @@ export default {
/**
* DELETE GROUP
*/
async deleteGroup (obj, args) {
if (args.id === 1 || args.id === 2) {
async deleteGroup (obj, args, { req }) {
if (!WIKI.auth.checkAccess(req.user, ['manage:groups', 'manage:system'])) {
throw new Error('ERR_FORBIDDEN')
}
if (args.id === WIKI.data.systemIds.guestsGroupId || args.id === WIKI.data.systemIds.usersGroupId || args.id === WIKI.config.auth.rootAdminGroupId) {
throw new Error('Cannot delete this group.')
}
@ -117,11 +135,15 @@ export default {
/**
* UNASSIGN USER FROM GROUP
*/
async unassignUserFromGroup (obj, args) {
async unassignUserFromGroup (obj, args, { req }) {
if (!WIKI.auth.checkAccess(req.user, ['manage:groups', 'manage:users', 'manage:system'])) {
throw new Error('ERR_FORBIDDEN')
}
if (args.userId === 2) {
throw new Error('Cannot unassign Guest user')
}
if (args.userId === 1 && args.groupId === 1) {
if (args.userId === WIKI.config.auth.guestUserId && args.groupId === WIKI.data.systemIds.guestsGroupId) {
throw new Error('Cannot unassign Administrator user from Administrators group.')
}
const grp = await WIKI.db.groups.query().findById(args.groupId)
@ -145,6 +167,10 @@ export default {
* UPDATE GROUP
*/
async updateGroup (obj, args, { req }) {
if (!WIKI.auth.checkAccess(req.user, ['manage:groups', 'manage:system'])) {
throw new Error('ERR_FORBIDDEN')
}
// Check for unsafe regex page rules
if (_.some(args.pageRules, pr => {
return pr.match === 'REGEX' && !safeRegex(pr.path)

@ -11,7 +11,7 @@ export default {
* FETCH ALL USERS
*/
async users (obj, args, context, info) {
if (!WIKI.auth.checkAccess(context.req.user, ['read:users', 'write:users', 'manage:users'])) {
if (!WIKI.auth.checkAccess(context.req.user, ['read:users', 'write:users', 'manage:users', 'manage:groups'])) {
throw new Error('ERR_FORBIDDEN')
}
@ -51,7 +51,7 @@ export default {
*/
async userById (obj, args, context, info) {
if (!context.req.isAuthenticated || context.req.user.id !== args.id) {
if (!WIKI.auth.checkAccess(context.req.user, ['read:users', 'write:users', 'manage:users'])) {
if (!WIKI.auth.checkAccess(context.req.user, ['read:users', 'write:users', 'manage:users', 'manage:groups'])) {
throw new Error('ERR_FORBIDDEN')
}
}
@ -88,7 +88,7 @@ export default {
},
async userDefaults (obj, args, context) {
if (!WIKI.auth.checkAccess(context.req.user, ['read:users', 'write:users', 'manage:users'])) {
if (!WIKI.auth.checkAccess(context.req.user, ['read:users', 'write:users', 'manage:users', 'manage:groups'])) {
throw new Error('ERR_FORBIDDEN')
}
@ -134,7 +134,7 @@ export default {
Mutation: {
async createUser (obj, args, context) {
try {
if (!WIKI.auth.checkAccess(context.req.user, ['write:users', 'manage:users'])) {
if (!WIKI.auth.checkAccess(context.req.user, ['write:users', 'manage:users', 'manage:groups'])) {
throw new Error('ERR_FORBIDDEN')
}
@ -149,7 +149,7 @@ export default {
},
async deleteUser (obj, args, context) {
try {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users'])) {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users', 'manage:groups'])) {
throw new Error('ERR_FORBIDDEN')
}
@ -174,7 +174,7 @@ export default {
},
async updateUser (obj, args, context) {
try {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users'])) {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users', 'manage:groups'])) {
throw new Error('ERR_FORBIDDEN')
}
@ -189,7 +189,7 @@ export default {
},
async verifyUser (obj, args, context) {
try {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users'])) {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users', 'manage:groups'])) {
throw new Error('ERR_FORBIDDEN')
}
@ -204,7 +204,7 @@ export default {
},
async activateUser (obj, args, context) {
try {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users'])) {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users', 'manage:groups'])) {
throw new Error('ERR_FORBIDDEN')
}
@ -219,7 +219,7 @@ export default {
},
async deactivateUser (obj, args, context) {
try {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users'])) {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users', 'manage:groups'])) {
throw new Error('ERR_FORBIDDEN')
}
@ -240,7 +240,7 @@ export default {
},
async enableUserTFA (obj, args, context) {
try {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users'])) {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users', 'manage:groups'])) {
throw new Error('ERR_FORBIDDEN')
}
@ -255,7 +255,7 @@ export default {
},
async disableUserTFA (obj, args, context) {
try {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users'])) {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users', 'manage:groups'])) {
throw new Error('ERR_FORBIDDEN')
}
@ -270,7 +270,7 @@ export default {
},
async changeUserPassword (obj, args, context) {
try {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users'])) {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users', 'manage:groups'])) {
throw new Error('ERR_FORBIDDEN')
}
@ -430,7 +430,7 @@ export default {
*/
async updateUserDefaults (obj, args, context) {
try {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users'])) {
if (!WIKI.auth.checkAccess(context.req.user, ['manage:users', 'manage:groups'])) {
throw new Error('ERR_FORBIDDEN')
}

@ -188,7 +188,7 @@ q-layout.admin(view='hHh Lpr lff')
q-item-section {{ t('admin.metrics.title') }}
q-item-section(side)
status-light(:color='adminStore.info.isMetricsEnabled ? `positive` : `negative`')
q-item(to='/_admin/rendering', v-ripple, active-class='bg-primary text-white')
q-item(to='/_admin/rendering', v-ripple, active-class='bg-primary text-white', v-if='flagsStore.experimental')
q-item-section(avatar)
q-icon(name='img:/_assets/icons/fluent-rich-text-converter.svg')
q-item-section {{ t('admin.rendering.title') }}
@ -416,14 +416,15 @@ onMounted(async () => {
}
> .q-layout-container {
border-radius: 6px;
box-shadow: 0 0 0 1px rgba(0,0,0,.5);
@at-root .body--light & {
background-image: linear-gradient(to bottom, $dark-5 10px, $grey-3 11px, $grey-4);
}
@at-root .body--dark & {
background-image: linear-gradient(to bottom, $dark-4 10px, $dark-4 11px, $dark-3);
}
border-radius: 6px;
box-shadow: 0 0 0 1px rgba(0,0,0,.5);
}
}
}

@ -2,7 +2,7 @@
q-layout(view='hHh Lpr lff')
header-nav
q-drawer.bg-sidebar(
:modelValue='isSidebarShown'
:model-value='isSidebarShown'
:show-if-above='siteStore.theme.sidebarPosition !== `off`'
:width='isSidebarMini ? 56 : 255'
:side='siteStore.theme.sidebarPosition === `right` ? `right` : `left`'
@ -63,7 +63,7 @@ q-layout(view='hHh Lpr lff')
:aria-label='commonStore.locale'
size='sm'
)
locale-selector-menu(:offset="[-5, 5]")
locale-selector-menu(:offset='[-5, 5]')
q-separator(vertical)
q-btn.q-px-sm.col(
flat
@ -232,14 +232,15 @@ body.body--dark {
}
> .q-layout-container {
border-radius: 6px;
box-shadow: 0 0 30px 0 rgba(0,0,0,.3);
@at-root .body--light & {
background-image: linear-gradient(to bottom, $dark-5 10px, $grey-3 11px, $grey-4);
}
@at-root .body--dark & {
background-image: linear-gradient(to bottom, $dark-4 10px, $dark-4 11px, $dark-3);
}
border-radius: 6px;
box-shadow: 0 0 30px 0 rgba(0,0,0,.3);
}
}
}

Loading…
Cancel
Save