group.js 6.51 KB
Newer Older
1
const graphHelper = require('../../helpers/graph')
2
const safeRegex = require('safe-regex')
3
const _ = require('lodash')
4
const gql = require('graphql')
NGPixel's avatar
NGPixel committed
5

6
/* global WIKI */
NGPixel's avatar
NGPixel committed
7 8

module.exports = {
9
  Query: {
10
    async groups () { return {} }
11 12
  },
  Mutation: {
13
    async groups () { return {} }
14 15
  },
  GroupQuery: {
16 17 18 19
    /**
     * FETCH ALL GROUPS
     */
    async list () {
20
      return WIKI.models.groups.query().select(
21
        'groups.*',
22
        WIKI.models.groups.relatedQuery('users').count().as('userCount')
23
      )
24
    },
25 26 27 28
    /**
     * FETCH A SINGLE GROUP
     */
    async single(obj, args) {
29
      return WIKI.models.groups.query().findById(args.id)
30 31
    }
  },
32
  GroupMutation: {
33 34 35 36 37 38 39 40 41 42
    /**
     * 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
43
      const grp = await WIKI.models.groups.query().findById(args.groupId)
44 45 46
      if (!grp) {
        throw new gql.GraphQLError('Invalid Group ID')
      }
47 48 49 50 51 52 53 54 55 56 57 58 59

      // 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
60
      const usr = await WIKI.models.users.query().findById(args.userId)
61 62 63
      if (!usr) {
        throw new gql.GraphQLError('Invalid User ID')
      }
64 65

      // Check for existing relation
66 67 68 69 70 71 72
      const relExist = await WIKI.models.knex('userGroups').where({
        userId: args.userId,
        groupId: args.groupId
      }).first()
      if (relExist) {
        throw new gql.GraphQLError('User is already assigned to group.')
      }
73 74

      // Assign user to group
75
      await grp.$relatedQuery('users').relate(usr.id)
76

77
      // Revoke tokens for this user
78 79 80
      WIKI.auth.revokeUserTokens({ id: usr.id, kind: 'u' })
      WIKI.events.outbound.emit('addAuthRevoke', { id: usr.id, kind: 'u' })

81 82 83
      return {
        responseResult: graphHelper.generateSuccess('User has been assigned to group.')
      }
84
    },
85 86 87 88
    /**
     * CREATE NEW GROUP
     */
    async create (obj, args, { req }) {
89
      const group = await WIKI.models.groups.query().insertAndFetch({
90 91
        name: args.name,
        permissions: JSON.stringify(WIKI.data.groups.defaultPermissions),
92
        pageRules: JSON.stringify(WIKI.data.groups.defaultPageRules),
93
        isSystem: false
94
      })
95
      await WIKI.auth.reloadGroups()
96
      WIKI.events.outbound.emit('reloadGroups')
97 98 99 100
      return {
        responseResult: graphHelper.generateSuccess('Group created successfully.'),
        group
      }
101
    },
102 103 104 105 106 107 108 109
    /**
     * DELETE GROUP
     */
    async delete (obj, args) {
      if (args.id === 1 || args.id === 2) {
        throw new gql.GraphQLError('Cannot delete this group.')
      }

110
      await WIKI.models.groups.query().deleteById(args.id)
111 112 113 114

      WIKI.auth.revokeUserTokens({ id: args.id, kind: 'g' })
      WIKI.events.outbound.emit('addAuthRevoke', { id: args.id, kind: 'g' })

115
      await WIKI.auth.reloadGroups()
116
      WIKI.events.outbound.emit('reloadGroups')
117

NGPixel's avatar
NGPixel committed
118 119 120
      return {
        responseResult: graphHelper.generateSuccess('Group has been deleted.')
      }
121
    },
122 123 124 125 126 127 128 129 130 131
    /**
     * 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.')
      }
132
      const grp = await WIKI.models.groups.query().findById(args.groupId)
133 134 135
      if (!grp) {
        throw new gql.GraphQLError('Invalid Group ID')
      }
136
      const usr = await WIKI.models.users.query().findById(args.userId)
137 138 139
      if (!usr) {
        throw new gql.GraphQLError('Invalid User ID')
      }
140
      await grp.$relatedQuery('users').unrelate().where('userId', usr.id)
141 142 143 144

      WIKI.auth.revokeUserTokens({ id: usr.id, kind: 'u' })
      WIKI.events.outbound.emit('addAuthRevoke', { id: usr.id, kind: 'u' })

145 146 147
      return {
        responseResult: graphHelper.generateSuccess('User has been unassigned from group.')
      }
148
    },
149 150 151 152 153
    /**
     * UPDATE GROUP
     */
    async update (obj, args, { req }) {
      // Check for unsafe regex page rules
154
      if (_.some(args.pageRules, pr => {
155
        return pr.match === 'REGEX' && !safeRegex(pr.path)
156 157 158 159
      })) {
        throw new gql.GraphQLError('Some Page Rules contains unsafe or exponential time regex.')
      }

160
      // Set default redirect on login value
161 162 163 164
      if (_.isEmpty(args.redirectOnLogin)) {
        args.redirectOnLogin = '/'
      }

165 166 167 168 169 170 171 172 173 174 175
      // 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.')
      }

176 177 178 179 180 181 182 183
      // Check assigned permissions for manage:groups
      if (
        WIKI.auth.checkExclusiveAccess(req.user, ['manage:groups'], ['manage:system']) &&
        args.permissions.some(p => _.last(p.split(':')) === 'system')
      ) {
        throw new gql.GraphQLError('You are not authorized to manage this group or assign the manage:system permissions.')
      }

184
      // Update group
185 186
      await WIKI.models.groups.query().patch({
        name: args.name,
187
        redirectOnLogin: args.redirectOnLogin,
188 189 190
        permissions: JSON.stringify(args.permissions),
        pageRules: JSON.stringify(args.pageRules)
      }).where('id', args.id)
191

192
      // Revoke tokens for this group
193 194 195
      WIKI.auth.revokeUserTokens({ id: args.id, kind: 'g' })
      WIKI.events.outbound.emit('addAuthRevoke', { id: args.id, kind: 'g' })

196
      // Reload group permissions
197
      await WIKI.auth.reloadGroups()
198
      WIKI.events.outbound.emit('reloadGroups')
199

200 201 202
      return {
        responseResult: graphHelper.generateSuccess('Group has been updated.')
      }
203
    }
NGPixel's avatar
NGPixel committed
204
  },
205
  Group: {
206
    users (grp) {
207
      return grp.$relatedQuery('users')
NGPixel's avatar
NGPixel committed
208 209 210
    }
  }
}