157 lines
4.0 KiB
JavaScript
157 lines
4.0 KiB
JavaScript
const authPkg = require("@budibase/auth")
|
|
const { google } = require("@budibase/auth/src/middleware")
|
|
const { oidc } = require("@budibase/auth/src/middleware")
|
|
const { Configs, EmailTemplatePurpose } = require("../../../constants")
|
|
const CouchDB = require("../../../db")
|
|
const { sendEmail, isEmailConfigured } = require("../../../utilities/email")
|
|
const { clearCookie, getGlobalUserByEmail, hash } = authPkg.utils
|
|
const { Cookies } = authPkg.constants
|
|
const { passport } = authPkg.auth
|
|
const { checkResetPasswordCode } = require("../../../utilities/redis")
|
|
|
|
const GLOBAL_DB = authPkg.StaticDatabases.GLOBAL.name
|
|
|
|
function authInternal(ctx, user, err = null) {
|
|
if (err) {
|
|
return ctx.throw(403, "Unauthorized")
|
|
}
|
|
|
|
const expires = new Date()
|
|
expires.setDate(expires.getDate() + 1)
|
|
|
|
if (!user) {
|
|
return ctx.throw(403, "Unauthorized")
|
|
}
|
|
|
|
ctx.cookies.set(Cookies.Auth, user.token, {
|
|
expires,
|
|
path: "/",
|
|
httpOnly: false,
|
|
overwrite: true,
|
|
})
|
|
}
|
|
|
|
exports.authenticate = async (ctx, next) => {
|
|
return passport.authenticate("local", async (err, user) => {
|
|
authInternal(ctx, user, err)
|
|
|
|
delete user.token
|
|
|
|
ctx.body = { user }
|
|
})(ctx, next)
|
|
}
|
|
|
|
/**
|
|
* Reset the user password, used as part of a forgotten password flow.
|
|
*/
|
|
exports.reset = async ctx => {
|
|
const { email } = ctx.request.body
|
|
const configured = await isEmailConfigured()
|
|
if (!configured) {
|
|
ctx.throw(
|
|
400,
|
|
"Please contact your platform administrator, SMTP is not configured."
|
|
)
|
|
}
|
|
try {
|
|
const user = await getGlobalUserByEmail(email)
|
|
// only if user exists, don't error though if they don't
|
|
if (user) {
|
|
await sendEmail(email, EmailTemplatePurpose.PASSWORD_RECOVERY, {
|
|
user,
|
|
subject: "{{ company }} platform password reset",
|
|
})
|
|
}
|
|
} catch (err) {
|
|
// don't throw any kind of error to the user, this might give away something
|
|
}
|
|
ctx.body = {
|
|
message: "Please check your email for a reset link.",
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Perform the user password update if the provided reset code is valid.
|
|
*/
|
|
exports.resetUpdate = async ctx => {
|
|
const { resetCode, password } = ctx.request.body
|
|
try {
|
|
const userId = await checkResetPasswordCode(resetCode)
|
|
const db = new CouchDB(GLOBAL_DB)
|
|
const user = await db.get(userId)
|
|
user.password = await hash(password)
|
|
await db.put(user)
|
|
ctx.body = {
|
|
message: "password reset successfully.",
|
|
}
|
|
} catch (err) {
|
|
ctx.throw(400, "Cannot reset password.")
|
|
}
|
|
}
|
|
|
|
exports.logout = async ctx => {
|
|
clearCookie(ctx, Cookies.Auth)
|
|
ctx.body = { message: "User logged out." }
|
|
}
|
|
|
|
/**
|
|
* The initial call that google authentication makes to take you to the google login screen.
|
|
* On a successful login, you will be redirected to the googleAuth callback route.
|
|
*/
|
|
exports.googlePreAuth = async (ctx, next) => {
|
|
const db = new CouchDB(GLOBAL_DB)
|
|
const config = await authPkg.db.getScopedConfig(db, {
|
|
type: Configs.GOOGLE,
|
|
group: ctx.query.group,
|
|
})
|
|
const strategy = await google.strategyFactory(config)
|
|
|
|
return passport.authenticate(strategy, {
|
|
scope: ["profile", "email"],
|
|
})(ctx, next)
|
|
}
|
|
|
|
exports.googleAuth = async (ctx, next) => {
|
|
const db = new CouchDB(GLOBAL_DB)
|
|
|
|
const config = await authPkg.db.getScopedConfig(db, {
|
|
type: Configs.GOOGLE,
|
|
group: ctx.query.group,
|
|
})
|
|
const strategy = await google.strategyFactory(config)
|
|
|
|
return passport.authenticate(
|
|
strategy,
|
|
{ successRedirect: "/", failureRedirect: "/error" },
|
|
async (err, user) => {
|
|
authInternal(ctx, user, err)
|
|
|
|
ctx.redirect("/")
|
|
}
|
|
)(ctx, next)
|
|
}
|
|
|
|
// Minimal OIDC attempt
|
|
|
|
exports.oidcPreAuth = async (ctx, next) => {
|
|
const strategy = await oidc.strategyFactory()
|
|
|
|
return passport.authenticate(strategy, {
|
|
scope: ["profile", "email"],
|
|
})(ctx, next)
|
|
}
|
|
|
|
exports.oidcAuth = async (ctx, next) => {
|
|
const strategy = await oidc.strategyFactory()
|
|
|
|
return passport.authenticate(
|
|
strategy,
|
|
{ successRedirect: "/", failureRedirect: "/error" },
|
|
async (err, user) => {
|
|
authInternal(ctx, user, err)
|
|
|
|
ctx.redirect("/")
|
|
}
|
|
)(ctx, next)
|
|
}
|