fix: prevent write:groups from self-promoting
This commit is contained in:
		| @@ -1,39 +1,68 @@ | ||||
| const graphHelper = require('../../helpers/graph') | ||||
| const safeRegex = require('safe-regex') | ||||
| const _ = require('lodash') | ||||
| const gql = require('graphql') | ||||
|  | ||||
| /* global WIKI */ | ||||
|  | ||||
| const gql = require('graphql') | ||||
|  | ||||
| module.exports = { | ||||
|   Query: { | ||||
|     async groups() { return {} } | ||||
|     async groups () { return {} } | ||||
|   }, | ||||
|   Mutation: { | ||||
|     async groups() { return {} } | ||||
|     async groups () { return {} } | ||||
|   }, | ||||
|   GroupQuery: { | ||||
|     async list(obj, args, context, info) { | ||||
|     /** | ||||
|      * FETCH ALL GROUPS | ||||
|      */ | ||||
|     async list () { | ||||
|       return WIKI.models.groups.query().select( | ||||
|         'groups.*', | ||||
|         WIKI.models.groups.relatedQuery('users').count().as('userCount') | ||||
|       ) | ||||
|     }, | ||||
|     async single(obj, args, context, info) { | ||||
|     /** | ||||
|      * FETCH A SINGLE GROUP | ||||
|      */ | ||||
|     async single(obj, args) { | ||||
|       return WIKI.models.groups.query().findById(args.id) | ||||
|     } | ||||
|   }, | ||||
|   GroupMutation: { | ||||
|     async assignUser(obj, args) { | ||||
|     /** | ||||
|      * ASSIGN USER TO GROUP | ||||
|      */ | ||||
|     async assignUser (obj, args, { req }) { | ||||
|       // Check for guest user | ||||
|       if (args.userId === 2) { | ||||
|         throw new gql.GraphQLError('Cannot assign the Guest user to a group.') | ||||
|       } | ||||
|  | ||||
|       // Check for valid group | ||||
|       const grp = await WIKI.models.groups.query().findById(args.groupId) | ||||
|       if (!grp) { | ||||
|         throw new gql.GraphQLError('Invalid Group ID') | ||||
|       } | ||||
|  | ||||
|       // Check assigned permissions for write:groups | ||||
|       if ( | ||||
|         WIKI.auth.checkExclusiveAccess(req.user, ['write:groups'], ['manage:groups', 'manage:system']) && | ||||
|         grp.permissions.some(p => { | ||||
|           const resType = _.last(p.split(':')) | ||||
|           return ['users', 'groups', 'navigation', 'theme', 'api', 'system'].includes(resType) | ||||
|         }) | ||||
|       ) { | ||||
|         throw new gql.GraphQLError('You are not authorized to assign a user to this elevated group.') | ||||
|       } | ||||
|  | ||||
|       // Check for valid user | ||||
|       const usr = await WIKI.models.users.query().findById(args.userId) | ||||
|       if (!usr) { | ||||
|         throw new gql.GraphQLError('Invalid User ID') | ||||
|       } | ||||
|  | ||||
|       // Check for existing relation | ||||
|       const relExist = await WIKI.models.knex('userGroups').where({ | ||||
|         userId: args.userId, | ||||
|         groupId: args.groupId | ||||
| @@ -41,8 +70,11 @@ module.exports = { | ||||
|       if (relExist) { | ||||
|         throw new gql.GraphQLError('User is already assigned to group.') | ||||
|       } | ||||
|  | ||||
|       // Assign user to group | ||||
|       await grp.$relatedQuery('users').relate(usr.id) | ||||
|  | ||||
|       // Revoke tokens for this user | ||||
|       WIKI.auth.revokeUserTokens({ id: usr.id, kind: 'u' }) | ||||
|       WIKI.events.outbound.emit('addAuthRevoke', { id: usr.id, kind: 'u' }) | ||||
|  | ||||
| @@ -50,7 +82,10 @@ module.exports = { | ||||
|         responseResult: graphHelper.generateSuccess('User has been assigned to group.') | ||||
|       } | ||||
|     }, | ||||
|     async create(obj, args) { | ||||
|     /** | ||||
|      * CREATE NEW GROUP | ||||
|      */ | ||||
|     async create (obj, args, { req }) { | ||||
|       const group = await WIKI.models.groups.query().insertAndFetch({ | ||||
|         name: args.name, | ||||
|         permissions: JSON.stringify(WIKI.data.groups.defaultPermissions), | ||||
| @@ -64,7 +99,14 @@ module.exports = { | ||||
|         group | ||||
|       } | ||||
|     }, | ||||
|     async delete(obj, args) { | ||||
|     /** | ||||
|      * DELETE GROUP | ||||
|      */ | ||||
|     async delete (obj, args) { | ||||
|       if (args.id === 1 || args.id === 2) { | ||||
|         throw new gql.GraphQLError('Cannot delete this group.') | ||||
|       } | ||||
|  | ||||
|       await WIKI.models.groups.query().deleteById(args.id) | ||||
|  | ||||
|       WIKI.auth.revokeUserTokens({ id: args.id, kind: 'g' }) | ||||
| @@ -77,7 +119,16 @@ module.exports = { | ||||
|         responseResult: graphHelper.generateSuccess('Group has been deleted.') | ||||
|       } | ||||
|     }, | ||||
|     async unassignUser(obj, args) { | ||||
|     /** | ||||
|      * UNASSIGN USER FROM GROUP | ||||
|      */ | ||||
|     async unassignUser (obj, args) { | ||||
|       if (args.userId === 2) { | ||||
|         throw new gql.GraphQLError('Cannot unassign Guest user') | ||||
|       } | ||||
|       if (args.userId === 1 && args.groupId === 1) { | ||||
|         throw new gql.GraphQLError('Cannot unassign Administrator user from Administrators group.') | ||||
|       } | ||||
|       const grp = await WIKI.models.groups.query().findById(args.groupId) | ||||
|       if (!grp) { | ||||
|         throw new gql.GraphQLError('Invalid Group ID') | ||||
| @@ -95,17 +146,34 @@ module.exports = { | ||||
|         responseResult: graphHelper.generateSuccess('User has been unassigned from group.') | ||||
|       } | ||||
|     }, | ||||
|     async update(obj, args) { | ||||
|     /** | ||||
|      * UPDATE GROUP | ||||
|      */ | ||||
|     async update (obj, args, { req }) { | ||||
|       // Check for unsafe regex page rules | ||||
|       if (_.some(args.pageRules, pr => { | ||||
|         return pr.match === 'REGEX' && !safeRegex(pr.path) | ||||
|       })) { | ||||
|         throw new gql.GraphQLError('Some Page Rules contains unsafe or exponential time regex.') | ||||
|       } | ||||
|  | ||||
|       // Set default redirect on login value | ||||
|       if (_.isEmpty(args.redirectOnLogin)) { | ||||
|         args.redirectOnLogin = '/' | ||||
|       } | ||||
|  | ||||
|       // Check assigned permissions for write:groups | ||||
|       if ( | ||||
|         WIKI.auth.checkExclusiveAccess(req.user, ['write:groups'], ['manage:groups', 'manage:system']) && | ||||
|         args.permissions.some(p => { | ||||
|           const resType = _.last(p.split(':')) | ||||
|           return ['users', 'groups', 'navigation', 'theme', 'api', 'system'].includes(resType) | ||||
|         }) | ||||
|       ) { | ||||
|         throw new gql.GraphQLError('You are not authorized to manage this group or assign these permissions.') | ||||
|       } | ||||
|  | ||||
|       // Update group | ||||
|       await WIKI.models.groups.query().patch({ | ||||
|         name: args.name, | ||||
|         redirectOnLogin: args.redirectOnLogin, | ||||
| @@ -113,9 +181,11 @@ module.exports = { | ||||
|         pageRules: JSON.stringify(args.pageRules) | ||||
|       }).where('id', args.id) | ||||
|  | ||||
|       // Revoke tokens for this group | ||||
|       WIKI.auth.revokeUserTokens({ id: args.id, kind: 'g' }) | ||||
|       WIKI.events.outbound.emit('addAuthRevoke', { id: args.id, kind: 'g' }) | ||||
|  | ||||
|       // Reload group permissions | ||||
|       await WIKI.auth.reloadGroups() | ||||
|       WIKI.events.outbound.emit('reloadGroups') | ||||
|  | ||||
| @@ -125,7 +195,7 @@ module.exports = { | ||||
|     } | ||||
|   }, | ||||
|   Group: { | ||||
|     users(grp) { | ||||
|     users (grp) { | ||||
|       return grp.$relatedQuery('users') | ||||
|     } | ||||
|   } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user