group.mjs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import { generateSuccess } from '../../helpers/graph.mjs'
  2. import safeRegex from 'safe-regex'
  3. import _ from 'lodash-es'
  4. import { v4 as uuid } from 'uuid'
  5. export default {
  6. Query: {
  7. /**
  8. * FETCH ALL GROUPS
  9. */
  10. async groups (obj, args, context) {
  11. if (!WIKI.auth.checkAccess(context.req.user, ['manage:groups', 'manage:users', 'manage:system'])) {
  12. throw new Error('ERR_FORBIDDEN')
  13. }
  14. return WIKI.db.groups.query().select(
  15. 'groups.*',
  16. WIKI.db.groups.relatedQuery('users').count().as('userCount')
  17. )
  18. },
  19. /**
  20. * FETCH A SINGLE GROUP
  21. */
  22. async groupById(obj, args, context) {
  23. if (!WIKI.auth.checkAccess(context.req.user, ['manage:groups', 'manage:users', 'manage:system'])) {
  24. throw new Error('ERR_FORBIDDEN')
  25. }
  26. return WIKI.db.groups.query().findById(args.id)
  27. }
  28. },
  29. Mutation: {
  30. /**
  31. * ASSIGN USER TO GROUP
  32. */
  33. async assignUserToGroup (obj, args, { req }) {
  34. if (!WIKI.auth.checkAccess(req.user, ['manage:groups', 'manage:users', 'manage:system'])) {
  35. throw new Error('ERR_FORBIDDEN')
  36. }
  37. // Check for guest user
  38. if (args.userId === WIKI.config.auth.guestUserId) {
  39. throw new Error('Cannot assign the Guest user to a group.')
  40. }
  41. // Check for valid group
  42. const grp = await WIKI.db.groups.query().findById(args.groupId)
  43. if (!grp) {
  44. throw new Error('Invalid Group ID')
  45. }
  46. // Check assigned permissions for write:groups
  47. if (
  48. WIKI.auth.checkExclusiveAccess(req.user, ['write:groups'], ['manage:groups', 'manage:system']) &&
  49. grp.permissions.some(p => {
  50. const resType = _.last(p.split(':'))
  51. return ['users', 'groups', 'navigation', 'theme', 'api', 'system'].includes(resType)
  52. })
  53. ) {
  54. throw new Error('You are not authorized to assign a user to this elevated group.')
  55. }
  56. // Check for valid user
  57. const usr = await WIKI.db.users.query().findById(args.userId)
  58. if (!usr) {
  59. throw new Error('Invalid User ID')
  60. }
  61. // Check for existing relation
  62. const relExist = await WIKI.db.knex('userGroups').where({
  63. userId: args.userId,
  64. groupId: args.groupId
  65. }).first()
  66. if (relExist) {
  67. throw new Error('User is already assigned to group.')
  68. }
  69. // Assign user to group
  70. await grp.$relatedQuery('users').relate(usr.id)
  71. // Revoke tokens for this user
  72. WIKI.auth.revokeUserTokens({ id: usr.id, kind: 'u' })
  73. WIKI.events.outbound.emit('addAuthRevoke', { id: usr.id, kind: 'u' })
  74. return {
  75. operation: generateSuccess('User has been assigned to group.')
  76. }
  77. },
  78. /**
  79. * CREATE NEW GROUP
  80. */
  81. async createGroup (obj, args, { req }) {
  82. if (!WIKI.auth.checkAccess(req.user, ['manage:groups', 'manage:system'])) {
  83. throw new Error('ERR_FORBIDDEN')
  84. }
  85. const group = await WIKI.db.groups.query().insertAndFetch({
  86. name: args.name,
  87. permissions: JSON.stringify(WIKI.data.groups.defaultPermissions),
  88. rules: JSON.stringify(WIKI.data.groups.defaultRules.map(r => ({
  89. id: uuid(),
  90. ...r
  91. }))),
  92. isSystem: false
  93. })
  94. await WIKI.auth.reloadGroups()
  95. WIKI.events.outbound.emit('reloadGroups')
  96. return {
  97. operation: generateSuccess('Group created successfully.'),
  98. group
  99. }
  100. },
  101. /**
  102. * DELETE GROUP
  103. */
  104. async deleteGroup (obj, args, { req }) {
  105. if (!WIKI.auth.checkAccess(req.user, ['manage:groups', 'manage:system'])) {
  106. throw new Error('ERR_FORBIDDEN')
  107. }
  108. if (args.id === WIKI.data.systemIds.guestsGroupId || args.id === WIKI.data.systemIds.usersGroupId || args.id === WIKI.config.auth.rootAdminGroupId) {
  109. throw new Error('Cannot delete this group.')
  110. }
  111. await WIKI.db.groups.query().deleteById(args.id)
  112. WIKI.auth.revokeUserTokens({ id: args.id, kind: 'g' })
  113. WIKI.events.outbound.emit('addAuthRevoke', { id: args.id, kind: 'g' })
  114. await WIKI.auth.reloadGroups()
  115. WIKI.events.outbound.emit('reloadGroups')
  116. return {
  117. operation: generateSuccess('Group has been deleted.')
  118. }
  119. },
  120. /**
  121. * UNASSIGN USER FROM GROUP
  122. */
  123. async unassignUserFromGroup (obj, args, { req }) {
  124. if (!WIKI.auth.checkAccess(req.user, ['manage:groups', 'manage:users', 'manage:system'])) {
  125. throw new Error('ERR_FORBIDDEN')
  126. }
  127. if (args.userId === 2) {
  128. throw new Error('Cannot unassign Guest user')
  129. }
  130. if (args.userId === WIKI.config.auth.guestUserId && args.groupId === WIKI.data.systemIds.guestsGroupId) {
  131. throw new Error('Cannot unassign Administrator user from Administrators group.')
  132. }
  133. const grp = await WIKI.db.groups.query().findById(args.groupId)
  134. if (!grp) {
  135. throw new Error('Invalid Group ID')
  136. }
  137. const usr = await WIKI.db.users.query().findById(args.userId)
  138. if (!usr) {
  139. throw new Error('Invalid User ID')
  140. }
  141. await grp.$relatedQuery('users').unrelate().where('userId', usr.id)
  142. WIKI.auth.revokeUserTokens({ id: usr.id, kind: 'u' })
  143. WIKI.events.outbound.emit('addAuthRevoke', { id: usr.id, kind: 'u' })
  144. return {
  145. operation: generateSuccess('User has been unassigned from group.')
  146. }
  147. },
  148. /**
  149. * UPDATE GROUP
  150. */
  151. async updateGroup (obj, args, { req }) {
  152. if (!WIKI.auth.checkAccess(req.user, ['manage:groups', 'manage:system'])) {
  153. throw new Error('ERR_FORBIDDEN')
  154. }
  155. // Check for unsafe regex page rules
  156. if (_.some(args.pageRules, pr => {
  157. return pr.match === 'REGEX' && !safeRegex(pr.path)
  158. })) {
  159. throw new Error('Some Page Rules contains unsafe or exponential time regex.')
  160. }
  161. // Set default redirect on login value
  162. if (_.isEmpty(args.redirectOnLogin)) {
  163. args.redirectOnLogin = '/'
  164. }
  165. // Check assigned permissions for write:groups
  166. if (
  167. WIKI.auth.checkExclusiveAccess(req.user, ['write:groups'], ['manage:groups', 'manage:system']) &&
  168. args.permissions.some(p => {
  169. const resType = _.last(p.split(':'))
  170. return ['users', 'groups', 'navigation', 'theme', 'api', 'system'].includes(resType)
  171. })
  172. ) {
  173. throw new Error('You are not authorized to manage this group or assign these permissions.')
  174. }
  175. // Check assigned permissions for manage:groups
  176. if (
  177. WIKI.auth.checkExclusiveAccess(req.user, ['manage:groups'], ['manage:system']) &&
  178. args.permissions.some(p => _.last(p.split(':')) === 'system')
  179. ) {
  180. throw new Error('You are not authorized to manage this group or assign the manage:system permissions.')
  181. }
  182. // Update group
  183. await WIKI.db.groups.query().patch({
  184. name: args.name,
  185. redirectOnLogin: args.redirectOnLogin,
  186. permissions: JSON.stringify(args.permissions),
  187. pageRules: JSON.stringify(args.pageRules)
  188. }).where('id', args.id)
  189. // Revoke tokens for this group
  190. WIKI.auth.revokeUserTokens({ id: args.id, kind: 'g' })
  191. WIKI.events.outbound.emit('addAuthRevoke', { id: args.id, kind: 'g' })
  192. // Reload group permissions
  193. await WIKI.auth.reloadGroups()
  194. WIKI.events.outbound.emit('reloadGroups')
  195. return {
  196. operation: generateSuccess('Group has been updated.')
  197. }
  198. }
  199. },
  200. Group: {
  201. users (grp) {
  202. return grp.$relatedQuery('users')
  203. }
  204. }
  205. }