authentication.mjs 23 KB

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