Updating auth package to remove use of email address (bar logging in).

This commit is contained in:
mike12345567 2021-04-19 17:31:47 +01:00
parent ade007482c
commit e787f22daa
8 changed files with 69 additions and 27 deletions

View File

@ -12,6 +12,7 @@
"passport-google-auth": "^1.0.2", "passport-google-auth": "^1.0.2",
"passport-google-oauth": "^2.0.0", "passport-google-oauth": "^2.0.0",
"passport-jwt": "^4.0.0", "passport-jwt": "^4.0.0",
"passport-local": "^1.0.0" "passport-local": "^1.0.0",
"uuid": "^8.3.2"
} }
} }

View File

@ -1,3 +1,9 @@
const uuid = require("uuid/v4")
exports.ViewNames = {
USER_BY_EMAIL: "by_email",
}
exports.StaticDatabases = { exports.StaticDatabases = {
GLOBAL: { GLOBAL: {
name: "global-db", name: "global-db",
@ -17,28 +23,23 @@ const SEPARATOR = "_"
exports.SEPARATOR = SEPARATOR exports.SEPARATOR = SEPARATOR
/** /**
* Generates a new user ID based on the passed in email. * Generates a new global user ID.
* @param {string} email The email which the ID is going to be built up of.
* @returns {string} The new user ID which the user doc can be stored under. * @returns {string} The new user ID which the user doc can be stored under.
*/ */
exports.generateUserID = email => { exports.generateUserID = () => {
return `${DocumentTypes.USER}${SEPARATOR}${email}` return `${DocumentTypes.USER}${SEPARATOR}${uuid()}`
}
exports.getEmailFromUserID = userId => {
return userId.split(`${DocumentTypes.USER}${SEPARATOR}`)[1]
} }
/** /**
* Gets parameters for retrieving users, this is a utility function for the getDocParams function. * Gets parameters for retrieving users, this is a utility function for the getDocParams function.
*/ */
exports.getUserParams = (email = "", otherProps = {}) => { exports.getUserParams = (globalId = "", otherProps = {}) => {
if (!email) { if (!globalId) {
email = "" globalId = ""
} }
return { return {
...otherProps, ...otherProps,
startkey: `${DocumentTypes.USER}${SEPARATOR}${email}`, startkey: `${DocumentTypes.USER}${SEPARATOR}${globalId}`,
endkey: `${DocumentTypes.USER}${SEPARATOR}${email}${UNICODE_MAX}`, endkey: `${DocumentTypes.USER}${SEPARATOR}${globalId}${UNICODE_MAX}`,
} }
} }

View File

@ -0,0 +1,20 @@
const { DocumentTypes, ViewNames, StaticDatabases } = require("./utils")
const { CouchDB } = require("./index")
exports.createUserEmailView = async () => {
const db = new CouchDB(StaticDatabases.GLOBAL.name)
const designDoc = await db.get("_design/database")
const view = {
// if using variables in a map function need to inject them before use
map: `function(doc) {
if (doc._id.startsWith("${DocumentTypes.USER}")) {
emit(doc.email, doc._id)
}
}`,
}
designDoc.views = {
...designDoc.views,
[ViewNames.USER_BY_EMAIL]: view,
}
await db.put(designDoc)
}

View File

@ -17,8 +17,8 @@ const {
const { const {
generateUserID, generateUserID,
getUserParams, getUserParams,
getEmailFromUserID,
} = require("./db/utils") } = require("./db/utils")
const { getGlobalUserByEmail } = require("./utils")
// Strategies // Strategies
passport.use(new LocalStrategy(local.options, local.authenticate)) passport.use(new LocalStrategy(local.options, local.authenticate))
@ -49,7 +49,6 @@ module.exports = {
StaticDatabases, StaticDatabases,
generateUserID, generateUserID,
getUserParams, getUserParams,
getEmailFromUserID,
hash, hash,
compare, compare,
getAppId, getAppId,
@ -58,4 +57,5 @@ module.exports = {
clearCookie, clearCookie,
authenticated, authenticated,
isClient, isClient,
getGlobalUserByEmail,
} }

View File

@ -1,6 +1,5 @@
const { Cookies } = require("../constants") const { Cookies } = require("../constants")
const { getCookie } = require("../utils") const { getCookie } = require("../utils")
const { getEmailFromUserID } = require("../db/utils")
module.exports = async (ctx, next) => { module.exports = async (ctx, next) => {
try { try {
@ -10,8 +9,6 @@ module.exports = async (ctx, next) => {
if (authCookie) { if (authCookie) {
ctx.isAuthenticated = true ctx.isAuthenticated = true
ctx.user = authCookie ctx.user = authCookie
// make sure email is correct from ID
ctx.user.email = getEmailFromUserID(authCookie.userId)
} }
await next() await next()

View File

@ -4,6 +4,7 @@ const database = require("../../db")
const { StaticDatabases, generateUserID } = require("../../db/utils") const { StaticDatabases, generateUserID } = require("../../db/utils")
const { compare } = require("../../hashing") const { compare } = require("../../hashing")
const env = require("../../environment") const env = require("../../environment")
const { getGlobalUserByEmail } = require("../../utils")
const INVALID_ERR = "Invalid Credentials" const INVALID_ERR = "Invalid Credentials"
@ -11,21 +12,18 @@ exports.options = {}
/** /**
* Passport Local Authentication Middleware. * Passport Local Authentication Middleware.
* @param {*} username - username to login with * @param {*} email - username to login with
* @param {*} password - plain text password to log in with * @param {*} password - plain text password to log in with
* @param {*} done - callback from passport to return user information and errors * @param {*} done - callback from passport to return user information and errors
* @returns The authenticated user, or errors if they occur * @returns The authenticated user, or errors if they occur
*/ */
exports.authenticate = async function(username, password, done) { exports.authenticate = async function(email, password, done) {
if (!username) return done(null, false, "Email Required.") if (!email) return done(null, false, "Email Required.")
if (!password) return done(null, false, "Password Required.") if (!password) return done(null, false, "Password Required.")
// Check the user exists in the instance DB by email
const db = new database.CouchDB(StaticDatabases.GLOBAL.name)
let dbUser let dbUser
try { try {
dbUser = await db.get(generateUserID(username)) dbUser = await getGlobalUserByEmail(email)
} catch (err) { } catch (err) {
console.error("User not found", err) console.error("User not found", err)
return done(null, false, { message: "User not found" }) return done(null, false, { message: "User not found" })

View File

@ -1,6 +1,8 @@
const { DocumentTypes, SEPARATOR } = require("./db/utils") const { DocumentTypes, SEPARATOR, ViewNames, StaticDatabases } = require("./db/utils")
const jwt = require("jsonwebtoken") const jwt = require("jsonwebtoken")
const { options } = require("./middleware/passport/jwt") const { options } = require("./middleware/passport/jwt")
const { createUserEmailView } = require("./db/views")
const { CouchDB } = require("./db")
const APP_PREFIX = DocumentTypes.APP + SEPARATOR const APP_PREFIX = DocumentTypes.APP + SEPARATOR
@ -97,3 +99,21 @@ exports.clearCookie = (ctx, name) => {
exports.isClient = ctx => { exports.isClient = ctx => {
return ctx.headers["x-budibase-type"] === "client" return ctx.headers["x-budibase-type"] === "client"
} }
exports.getGlobalUserByEmail = async email => {
const db = new CouchDB(StaticDatabases.GLOBAL.name)
try {
let users = (await db.query(
`database/${ViewNames.USER_BY_EMAIL}`,
{
key: email
})
).rows
return users.length <= 1 ? users[0] : users
} catch (err) {
if (err != null && err.name === "not_found") {
await createUserEmailView()
return exports.getGlobalUserByEmail(email)
}
}
}

View File

@ -584,6 +584,11 @@ uuid@^3.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
uuid@^8.3.2:
version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
verror@1.10.0: verror@1.10.0:
version "1.10.0" version "1.10.0"
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"