const debug = require('debug')('ctrl:common') const util = require('util') const url = require('url') const sso = require('src/utils/sso/index.js') const { get: getCacheInstance } = require('src/utils/cache.js') const { resp, codeMessage, APIError } = require('src/utils/response/index.js') const config = require('src/config/index.js') const acl = require('src/utils/acl.js') const { copyObject } = require('src/utils/index.js') const controller = {} module.exports = controller controller.verifyCode = () => async (ctx) => { const { code, session_state: sessionState, state } = ctx.query // logout flow redirect tot frontend if (state === 'logout') { ctx.redirect(config.server.frontend_url) return } // get back url from redis const cacheKey = `login-${state}` const cache = getCacheInstance() const data = cache.get(cacheKey) if (!data) ctx.throw('get login cache fail') const stateObj = JSON.parse(data) const { back_url: backURL } = stateObj if (!backURL) ctx.throw('cache data missing') const u = new url.URL(backURL) try { const token = await sso.getToken(code, sessionState) if (!acl.checkAllow(token.groups)) { const copy = copyObject(resp.Forbidden) copy.object = codeMessage.CodeAccountNoPermission throw new APIError('account no permission', copy) } // set accessToken/refreshToken cache cache.set(token.access_token, token.refresh_token, false) u.searchParams.append( 'success', Buffer.from(JSON.stringify({ token: token.access_token })).toString('base64') ) try { cache.del(cacheKey) } catch (err) { debug(`delete cache fail: ${util.inspect(err, false, null)}`) } } catch (err) { debug(`openid verify fail: ${util.inspect(err, false, null)}`) /** @type {object} */ const errObj = { ...codeMessage.CodeInternalError } if (err instanceof APIError) { // @ts-ignore Object.assign(errObj, err.object.object) } errObj.errorStack = err.stack errObj.errorMessage = err.message u.searchParams.append( 'error', Buffer.from(JSON.stringify(errObj)).toString('base64') ) } ctx.redirect(u.toString()) }