authentication.mjs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  1. import _ from 'lodash-es'
  2. import { generateError, generateSuccess } from '../../helpers/graph.mjs'
  3. import jwt from 'jsonwebtoken'
  4. import ms from 'ms'
  5. import { DateTime } from 'luxon'
  6. import base64 from '@hexagon/base64'
  7. import {
  8. generateRegistrationOptions,
  9. verifyRegistrationResponse,
  10. generateAuthenticationOptions,
  11. verifyAuthenticationResponse
  12. } from '@simplewebauthn/server'
  13. export default {
  14. Query: {
  15. /**
  16. * List of API Keys
  17. */
  18. async apiKeys (obj, args, context) {
  19. if (!WIKI.auth.checkAccess(context.req.user, ['read:api', 'manage:api'])) {
  20. throw new Error('ERR_FORBIDDEN')
  21. }
  22. const keys = await WIKI.db.apiKeys.query().orderBy(['isRevoked', 'name'])
  23. return keys.map(k => ({
  24. id: k.id,
  25. name: k.name,
  26. keyShort: '...' + k.key.substring(k.key.length - 20),
  27. isRevoked: k.isRevoked,
  28. expiration: k.expiration,
  29. createdAt: k.createdAt,
  30. updatedAt: k.updatedAt
  31. }))
  32. },
  33. /**
  34. * Current API State
  35. */
  36. apiState (obj, args, context) {
  37. if (!WIKI.auth.checkAccess(context.req.user, ['read:api', 'manage:api', 'read:dashboard'])) {
  38. throw new Error('ERR_FORBIDDEN')
  39. }
  40. return WIKI.config.api.isEnabled
  41. },
  42. /**
  43. * Fetch authentication strategies
  44. */
  45. async authStrategies () {
  46. return WIKI.data.authentication.map(stg => ({
  47. ...stg,
  48. isAvailable: stg.isAvailable === true
  49. }))
  50. },
  51. /**
  52. * Fetch active authentication strategies
  53. */
  54. async authActiveStrategies (obj, args, context) {
  55. const strategies = await WIKI.db.authentication.getStrategies({ enabledOnly: args.enabledOnly })
  56. return strategies.map(a => {
  57. const str = _.find(WIKI.data.authentication, ['key', a.module]) || {}
  58. return {
  59. ...a,
  60. config: _.transform(str.props, (r, v, k) => {
  61. r[k] = v.sensitive ? '********' : a.config[k]
  62. }, {})
  63. }
  64. })
  65. },
  66. /**
  67. * Fetch site authentication strategies
  68. */
  69. async authSiteStrategies (obj, args, context, info) {
  70. const site = await WIKI.db.sites.query().findById(args.siteId)
  71. const activeStrategies = await WIKI.db.authentication.getStrategies({ enabledOnly: true })
  72. const siteStrategies = _.sortBy(activeStrategies.map(str => {
  73. const siteAuth = _.find(site.config.authStrategies, ['id', str.id]) || {}
  74. return {
  75. id: str.id,
  76. activeStrategy: str,
  77. order: siteAuth.order ?? 0,
  78. isVisible: siteAuth.isVisible ?? false
  79. }
  80. }), ['order'])
  81. return args.visibleOnly ? siteStrategies.filter(s => s.isVisible) : siteStrategies
  82. }
  83. },
  84. Mutation: {
  85. /**
  86. * Create New API Key
  87. */
  88. async createApiKey (obj, args, context) {
  89. try {
  90. if (!WIKI.auth.checkAccess(context.req.user, ['manage:api'])) {
  91. throw new Error('ERR_FORBIDDEN')
  92. }
  93. const key = await WIKI.db.apiKeys.createNewKey(args)
  94. await WIKI.auth.reloadApiKeys()
  95. WIKI.events.outbound.emit('reloadApiKeys')
  96. return {
  97. key,
  98. operation: generateSuccess('API Key created successfully')
  99. }
  100. } catch (err) {
  101. WIKI.logger.warn(err)
  102. return generateError(err)
  103. }
  104. },
  105. /**
  106. * Perform Login
  107. */
  108. async login (obj, args, context) {
  109. try {
  110. const authResult = await WIKI.db.users.login(args, context)
  111. return {
  112. ...authResult,
  113. operation: generateSuccess('Login success')
  114. }
  115. } catch (err) {
  116. // LDAP Debug Flag
  117. if (args.strategy === 'ldap' && WIKI.config.flags.ldapdebug) {
  118. WIKI.logger.warn('LDAP LOGIN ERROR (c1): ', err)
  119. }
  120. WIKI.logger.debug(err)
  121. return generateError(err)
  122. }
  123. },
  124. /**
  125. * Perform 2FA Login
  126. */
  127. async loginTFA (obj, args, context) {
  128. try {
  129. const authResult = await WIKI.db.users.loginTFA(args, context)
  130. return {
  131. ...authResult,
  132. operation: generateSuccess('TFA success')
  133. }
  134. } catch (err) {
  135. WIKI.logger.debug(err)
  136. return generateError(err)
  137. }
  138. },
  139. /**
  140. * Setup TFA
  141. */
  142. async setupTFA (obj, args, context) {
  143. try {
  144. const userId = context.req.user?.id
  145. if (!userId) {
  146. throw new Error('ERR_NOT_AUTHENTICATED')
  147. }
  148. const usr = await WIKI.db.users.query().findById(userId)
  149. if (!usr) {
  150. throw new Error('ERR_INVALID_USER')
  151. }
  152. const str = WIKI.auth.strategies[args.strategyId]
  153. if (!str) {
  154. throw new Error('ERR_INVALID_STRATEGY')
  155. }
  156. if (!usr.auth[args.strategyId]) {
  157. throw new Error('ERR_INVALID_STRATEGY')
  158. }
  159. if (usr.auth[args.strategyId].tfaIsActive) {
  160. throw new Error('ERR_TFA_ALREADY_ACTIVE')
  161. }
  162. const tfaQRImage = await usr.generateTFA(args.strategyId, args.siteId)
  163. const tfaToken = await WIKI.db.userKeys.generateToken({
  164. kind: 'tfaSetup',
  165. userId: usr.id,
  166. meta: {
  167. strategyId: args.strategyId
  168. }
  169. })
  170. return {
  171. operation: generateSuccess('TFA setup started'),
  172. continuationToken: tfaToken,
  173. tfaQRImage
  174. }
  175. } catch (err) {
  176. return generateError(err)
  177. }
  178. },
  179. /**
  180. * Deactivate 2FA
  181. */
  182. async deactivateTFA (obj, args, context) {
  183. try {
  184. const userId = context.req.user?.id
  185. if (!userId) {
  186. throw new Error('ERR_NOT_AUTHENTICATED')
  187. }
  188. const usr = await WIKI.db.users.query().findById(userId)
  189. if (!usr) {
  190. throw new Error('ERR_INVALID_USER')
  191. }
  192. const str = WIKI.auth.strategies[args.strategyId]
  193. if (!str) {
  194. throw new Error('ERR_INVALID_STRATEGY')
  195. }
  196. if (!usr.auth[args.strategyId]) {
  197. throw new Error('ERR_INVALID_STRATEGY')
  198. }
  199. if (!usr.auth[args.strategyId].tfaIsActive) {
  200. throw new Error('ERR_TFA_NOT_ACTIVE')
  201. }
  202. usr.auth[args.strategyId].tfaIsActive = false
  203. usr.auth[args.strategyId].tfaSecret = null
  204. await usr.$query().patch({
  205. auth: usr.auth
  206. })
  207. return {
  208. operation: generateSuccess('TFA deactivated successfully.')
  209. }
  210. } catch (err) {
  211. return generateError(err)
  212. }
  213. },
  214. /**
  215. * Setup Passkey
  216. */
  217. async setupPasskey (obj, args, context) {
  218. try {
  219. const userId = context.req.user?.id
  220. if (!userId) {
  221. throw new Error('ERR_NOT_AUTHENTICATED')
  222. }
  223. const usr = await WIKI.db.users.query().findById(userId)
  224. if (!usr) {
  225. throw new Error('ERR_INVALID_USER')
  226. }
  227. const site = WIKI.sites[args.siteId]
  228. if (!site) {
  229. throw new Error('ERR_INVALID_SITE')
  230. } else if (site.hostname === '*') {
  231. WIKI.logger.warn('Cannot use passkeys with a wildcard site hostname. Enter a valid hostname under the Administration Area > General.')
  232. throw new Error('ERR_PK_HOSTNAME_MISSING')
  233. }
  234. const options = await generateRegistrationOptions({
  235. rpName: site.config.title,
  236. rpId: site.hostname,
  237. userID: usr.id,
  238. userName: usr.email,
  239. userDisplayName: usr.name,
  240. attestationType: 'none',
  241. authenticatorSelection: {
  242. residentKey: 'required',
  243. userVerification: 'preferred'
  244. },
  245. excludeCredentials: usr.passkeys.authenticators?.map(authenticator => ({
  246. id: new Uint8Array(authenticator.credentialID),
  247. type: 'public-key',
  248. transports: authenticator.transports
  249. })) ?? []
  250. })
  251. usr.passkeys.reg = {
  252. challenge: options.challenge,
  253. rpId: site.hostname,
  254. siteId: site.id
  255. }
  256. await usr.$query().patch({
  257. passkeys: usr.passkeys
  258. })
  259. return {
  260. operation: generateSuccess('Passkey registration options generated successfully.'),
  261. registrationOptions: options
  262. }
  263. } catch (err) {
  264. return generateError(err)
  265. }
  266. },
  267. /**
  268. * Finalize Passkey Registration
  269. */
  270. async finalizePasskey (obj, args, context) {
  271. try {
  272. const userId = context.req.user?.id
  273. if (!userId) {
  274. throw new Error('ERR_NOT_AUTHENTICATED')
  275. }
  276. const usr = await WIKI.db.users.query().findById(userId)
  277. if (!usr) {
  278. throw new Error('ERR_INVALID_USER')
  279. } else if (!usr.passkeys?.reg) {
  280. throw new Error('ERR_PASSKEY_NOT_SETUP')
  281. }
  282. if (!args.name || args.name.trim().length < 1 || args.name.length > 255) {
  283. throw new Error('ERR_PK_NAME_MISSING_OR_INVALID')
  284. }
  285. const verification = await verifyRegistrationResponse({
  286. response: args.registrationResponse,
  287. expectedChallenge: usr.passkeys.reg.challenge,
  288. expectedOrigin: `https://${usr.passkeys.reg.rpId}`,
  289. expectedRPID: usr.passkeys.reg.rpId,
  290. requireUserVerification: true
  291. })
  292. if (!verification.verified) {
  293. throw new Error('ERR_PK_VERIFICATION_FAILED')
  294. }
  295. if (!usr.passkeys.authenticators) {
  296. usr.passkeys.authenticators = []
  297. }
  298. usr.passkeys.authenticators.push({
  299. ...verification.registrationInfo,
  300. id: base64.fromArrayBuffer(verification.registrationInfo.credentialID, true),
  301. createdAt: new Date(),
  302. name: args.name,
  303. siteId: usr.passkeys.reg.siteId,
  304. transports: args.registrationResponse.response.transports
  305. })
  306. delete usr.passkeys.reg
  307. await usr.$query().patch({
  308. passkeys: JSON.stringify(usr.passkeys, (k, v) => {
  309. if (v instanceof Uint8Array) {
  310. return Array.apply([], v)
  311. }
  312. return v
  313. })
  314. })
  315. return {
  316. operation: generateSuccess('Passkey registered successfully.')
  317. }
  318. } catch (err) {
  319. return generateError(err)
  320. }
  321. },
  322. /**
  323. * Deactivate a passkey
  324. */
  325. async deactivatePasskey (obj, args, context) {
  326. try {
  327. const userId = context.req.user?.id
  328. if (!userId) {
  329. throw new Error('ERR_NOT_AUTHENTICATED')
  330. }
  331. const usr = await WIKI.db.users.query().findById(userId)
  332. if (!usr) {
  333. throw new Error('ERR_INVALID_USER')
  334. } else if (!usr.passkeys?.authenticators) {
  335. throw new Error('ERR_PASSKEY_NOT_SETUP')
  336. }
  337. usr.passkeys.authenticators = usr.passkeys.authenticators.filter(a => a.id !== args.id)
  338. await usr.$query().patch({
  339. passkeys: usr.passkeys
  340. })
  341. return {
  342. operation: generateSuccess('Passkey deactivated successfully.')
  343. }
  344. } catch (err) {
  345. return generateError(err)
  346. }
  347. },
  348. /**
  349. * Login via passkey - Generate challenge
  350. */
  351. async authenticatePasskeyGenerate (obj, args, context) {
  352. try {
  353. const site = WIKI.sites[args.siteId]
  354. if (!site) {
  355. throw new Error('ERR_INVALID_SITE')
  356. } else if (site.hostname === '*') {
  357. WIKI.logger.warn('Cannot use passkeys with a wildcard site hostname. Enter a valid hostname under the Administration Area > General.')
  358. throw new Error('ERR_PK_HOSTNAME_MISSING')
  359. }
  360. const usr = await WIKI.db.users.query().findOne({ email: args.email })
  361. if (!usr || !usr.passkeys?.authenticators) {
  362. // Fake success response to prevent email leaking
  363. WIKI.logger.debug(`Cannot generate passkey challenge for ${args.email}... (non-existing or missing passkeys setup)`)
  364. return {
  365. operation: generateSuccess('Passkey challenge generated.'),
  366. authOptions: await generateAuthenticationOptions({
  367. allowCredentials: [{
  368. id: new Uint8Array(Array(30).map(v => _.random(0, 254))),
  369. type: 'public-key',
  370. transports: ['internal']
  371. }],
  372. userVerification: 'preferred',
  373. rpId: site.hostname
  374. })
  375. }
  376. }
  377. const options = await generateAuthenticationOptions({
  378. allowCredentials: usr.passkeys.authenticators.map(authenticator => ({
  379. id: new Uint8Array(authenticator.credentialID),
  380. type: 'public-key',
  381. transports: authenticator.transports
  382. })),
  383. userVerification: 'preferred',
  384. rpId: site.hostname
  385. })
  386. usr.passkeys.login = {
  387. challenge: options.challenge,
  388. rpId: site.hostname,
  389. siteId: site.id
  390. }
  391. await usr.$query().patch({
  392. passkeys: usr.passkeys
  393. })
  394. return {
  395. operation: generateSuccess('Passkey challenge generated.'),
  396. authOptions: options
  397. }
  398. } catch (err) {
  399. return generateError(err)
  400. }
  401. },
  402. /**
  403. * Login via passkey - Verify challenge
  404. */
  405. async authenticatePasskeyVerify (obj, args, context) {
  406. try {
  407. if (!args.authResponse?.response?.userHandle) {
  408. throw new Error('ERR_INVALID_PASSKEY_RESPONSE')
  409. }
  410. const usr = await WIKI.db.users.query().findById(args.authResponse.response.userHandle)
  411. if (!usr) {
  412. WIKI.logger.debug(`Passkey Login Failure: Cannot find user ${args.authResponse.response.userHandle}`)
  413. throw new Error('ERR_LOGIN_FAILED')
  414. } else if (!usr.passkeys?.login) {
  415. WIKI.logger.debug(`Passkey Login Failure: Missing login auth generation step for user ${args.authResponse.response.userHandle}`)
  416. throw new Error('ERR_LOGIN_FAILED')
  417. } else if (!usr.passkeys.authenticators?.some(a => a.id === args.authResponse.id)) {
  418. WIKI.logger.debug(`Passkey Login Failure: Authenticator provided is not registered for user ${args.authResponse.response.userHandle}`)
  419. throw new Error('ERR_LOGIN_FAILED')
  420. }
  421. const verification = await verifyAuthenticationResponse({
  422. response: args.authResponse,
  423. expectedChallenge: usr.passkeys.login.challenge,
  424. expectedOrigin: `https://${usr.passkeys.login.rpId}`,
  425. expectedRPID: usr.passkeys.login.rpId,
  426. requireUserVerification: true,
  427. authenticator: _.find(usr.passkeys.authenticators, ['id', args.authResponse.id])
  428. })
  429. if (!verification.verified) {
  430. WIKI.logger.debug(`Passkey Login Failure: Challenge verification failed for user ${args.authResponse.response.userHandle}`)
  431. throw new Error('ERR_LOGIN_FAILED')
  432. }
  433. delete usr.passkeys.login
  434. await usr.$query().patch({
  435. passkeys: usr.passkeys
  436. })
  437. const jwtToken = await WIKI.db.users.refreshToken(usr)
  438. return {
  439. operation: generateSuccess('Passkey challenge accepted.'),
  440. nextAction: 'redirect',
  441. jwt: jwtToken.token,
  442. redirect: '/'
  443. }
  444. } catch (err) {
  445. return generateError(err)
  446. }
  447. },
  448. /**
  449. * Perform Password Change
  450. */
  451. async changePassword (obj, args, context) {
  452. try {
  453. if (args.continuationToken) {
  454. const authResult = await WIKI.db.users.loginChangePassword(args, context)
  455. return {
  456. ...authResult,
  457. operation: generateSuccess('Password set successfully')
  458. }
  459. } else {
  460. await WIKI.db.users.changePassword(args, context)
  461. return {
  462. operation: generateSuccess('Password changed successfully')
  463. }
  464. }
  465. } catch (err) {
  466. WIKI.logger.debug(err)
  467. return generateError(err)
  468. }
  469. },
  470. /**
  471. * Perform Forget Password
  472. */
  473. async forgotPassword (obj, args, context) {
  474. try {
  475. await WIKI.db.users.loginForgotPassword(args, context)
  476. return {
  477. operation: generateSuccess('Password reset request processed.')
  478. }
  479. } catch (err) {
  480. return generateError(err)
  481. }
  482. },
  483. /**
  484. * Register a new account
  485. */
  486. async register (obj, args, context) {
  487. try {
  488. const usr = await WIKI.db.users.createNewUser({ ...args, userInitiated: true })
  489. const authResult = await WIKI.db.users.afterLoginChecks(usr, WIKI.data.systemIds.localAuthId, context)
  490. return {
  491. ...authResult,
  492. operation: generateSuccess('Registration success')
  493. }
  494. } catch (err) {
  495. return generateError(err)
  496. }
  497. },
  498. /**
  499. * Refresh Token
  500. */
  501. async refreshToken (obj, args, context) {
  502. try {
  503. let decoded = {}
  504. if (!args.token) {
  505. throw new Error('ERR_MISSING_TOKEN')
  506. }
  507. try {
  508. decoded = jwt.verify(args.token, WIKI.config.auth.certs.public, {
  509. audience: WIKI.config.auth.audience,
  510. issuer: 'urn:wiki.js',
  511. algorithms: ['RS256'],
  512. ignoreExpiration: true
  513. })
  514. } catch (err) {
  515. throw new Error('ERR_INVALID_TOKEN')
  516. }
  517. if (DateTime.utc().minus(ms(WIKI.config.auth.tokenRenewal)) > DateTime.fromSeconds(decoded.exp)) {
  518. throw new Error('ERR_EXPIRED_TOKEN')
  519. }
  520. const newToken = await WIKI.db.users.refreshToken(decoded.id)
  521. return {
  522. jwt: newToken.token,
  523. operation: generateSuccess('Token refreshed successfully')
  524. }
  525. } catch (err) {
  526. return generateError(err)
  527. }
  528. },
  529. /**
  530. * Set API state
  531. */
  532. async setApiState (obj, args, context) {
  533. try {
  534. if (!WIKI.auth.checkAccess(context.req.user, ['manage:system'])) {
  535. throw new Error('ERR_FORBIDDEN')
  536. }
  537. WIKI.config.api.isEnabled = args.enabled
  538. await WIKI.configSvc.saveToDb(['api'])
  539. return {
  540. operation: generateSuccess('API State changed successfully')
  541. }
  542. } catch (err) {
  543. return generateError(err)
  544. }
  545. },
  546. /**
  547. * Revoke an API key
  548. */
  549. async revokeApiKey (obj, args, context) {
  550. try {
  551. if (!WIKI.auth.checkAccess(context.req.user, ['manage:api'])) {
  552. throw new Error('ERR_FORBIDDEN')
  553. }
  554. await WIKI.db.apiKeys.query().findById(args.id).patch({
  555. isRevoked: true
  556. })
  557. await WIKI.auth.reloadApiKeys()
  558. WIKI.events.outbound.emit('reloadApiKeys')
  559. return {
  560. operation: generateSuccess('API Key revoked successfully')
  561. }
  562. } catch (err) {
  563. return generateError(err)
  564. }
  565. },
  566. /**
  567. * Update Authentication Strategies
  568. */
  569. async updateAuthStrategies (obj, args, context) {
  570. try {
  571. if (!WIKI.auth.checkAccess(context.req.user, ['manage:system'])) {
  572. throw new Error('ERR_FORBIDDEN')
  573. }
  574. const previousStrategies = await WIKI.db.authentication.getStrategies()
  575. for (const str of args.strategies) {
  576. const newStr = {
  577. displayName: str.displayName,
  578. isEnabled: str.isEnabled,
  579. config: _.reduce(str.config, (result, value, key) => {
  580. _.set(result, `${value.key}`, _.get(JSON.parse(value.value), 'v', null))
  581. return result
  582. }, {}),
  583. selfRegistration: str.selfRegistration,
  584. domainWhitelist: { v: str.domainWhitelist },
  585. autoEnrollGroups: { v: str.autoEnrollGroups }
  586. }
  587. if (_.some(previousStrategies, ['key', str.key])) {
  588. await WIKI.db.authentication.query().patch({
  589. key: str.key,
  590. strategyKey: str.strategyKey,
  591. ...newStr
  592. }).where('key', str.key)
  593. } else {
  594. await WIKI.db.authentication.query().insert({
  595. key: str.key,
  596. strategyKey: str.strategyKey,
  597. ...newStr
  598. })
  599. }
  600. }
  601. for (const str of _.differenceBy(previousStrategies, args.strategies, 'key')) {
  602. const hasUsers = await WIKI.db.users.query().count('* as total').where({ providerKey: str.key }).first()
  603. if (_.toSafeInteger(hasUsers.total) > 0) {
  604. throw new Error(`Cannot delete ${str.displayName} as 1 or more users are still using it.`)
  605. } else {
  606. await WIKI.db.authentication.query().delete().where('key', str.key)
  607. }
  608. }
  609. await WIKI.auth.activateStrategies()
  610. WIKI.events.outbound.emit('reloadAuthStrategies')
  611. return {
  612. responseResult: generateSuccess('Strategies updated successfully')
  613. }
  614. } catch (err) {
  615. return generateError(err)
  616. }
  617. },
  618. /**
  619. * Generate New Authentication Public / Private Key Certificates
  620. */
  621. async regenerateCertificates (obj, args, context) {
  622. try {
  623. if (!WIKI.auth.checkAccess(context.req.user, ['manage:system'])) {
  624. throw new Error('ERR_FORBIDDEN')
  625. }
  626. await WIKI.auth.regenerateCertificates()
  627. return {
  628. responseResult: generateSuccess('Certificates have been regenerated successfully.')
  629. }
  630. } catch (err) {
  631. return generateError(err)
  632. }
  633. },
  634. /**
  635. * Reset Guest User
  636. */
  637. async resetGuestUser (obj, args, context) {
  638. try {
  639. if (!WIKI.auth.checkAccess(context.req.user, ['manage:system'])) {
  640. throw new Error('ERR_FORBIDDEN')
  641. }
  642. await WIKI.auth.resetGuestUser()
  643. return {
  644. responseResult: generateSuccess('Guest user has been reset successfully.')
  645. }
  646. } catch (err) {
  647. return generateError(err)
  648. }
  649. }
  650. },
  651. // ------------------------------------------------------------------
  652. // TYPE: AuthenticationActiveStrategy
  653. // ------------------------------------------------------------------
  654. AuthenticationActiveStrategy: {
  655. config (obj, args, context) {
  656. if (!WIKI.auth.checkAccess(context.req.user, ['manage:system'])) {
  657. throw new Error('ERR_FORBIDDEN')
  658. }
  659. return obj.config ?? {}
  660. },
  661. allowedEmailRegex (obj, args, context) {
  662. if (!WIKI.auth.checkAccess(context.req.user, ['manage:system'])) {
  663. throw new Error('ERR_FORBIDDEN')
  664. }
  665. return obj.allowedEmailRegex ?? ''
  666. },
  667. autoEnrollGroups (obj, args, context) {
  668. if (!WIKI.auth.checkAccess(context.req.user, ['manage:system'])) {
  669. throw new Error('ERR_FORBIDDEN')
  670. }
  671. return obj.autoEnrollGroups ?? []
  672. },
  673. strategy (obj, args, context) {
  674. return _.find(WIKI.data.authentication, ['key', obj.module])
  675. }
  676. }
  677. }