merge
This commit is contained in:
commit
d8db863faa
|
@ -1,5 +1,9 @@
|
|||
let Pouch
|
||||
|
||||
module.exports.setDB = pouch => {
|
||||
module.exports.CouchDB = pouch
|
||||
Pouch = pouch
|
||||
}
|
||||
|
||||
module.exports.CouchDB = null
|
||||
module.exports.getDB = dbName => {
|
||||
return new Pouch(dbName)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
const { newid } = require("../hashing")
|
||||
|
||||
exports.ViewNames = {
|
||||
USER_BY_EMAIL: "by_email",
|
||||
}
|
||||
|
||||
exports.StaticDatabases = {
|
||||
GLOBAL: {
|
||||
name: "global-db",
|
||||
|
@ -11,6 +15,7 @@ const DocumentTypes = {
|
|||
APP: "app",
|
||||
GROUP: "group",
|
||||
CONFIG: "config",
|
||||
TEMPLATE: "template",
|
||||
}
|
||||
|
||||
exports.DocumentTypes = DocumentTypes
|
||||
|
@ -20,19 +25,6 @@ const SEPARATOR = "_"
|
|||
|
||||
exports.SEPARATOR = SEPARATOR
|
||||
|
||||
/**
|
||||
* Generates a new user ID based on the passed in email.
|
||||
* @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.
|
||||
*/
|
||||
exports.generateUserID = email => {
|
||||
return `${DocumentTypes.USER}${SEPARATOR}${email}`
|
||||
}
|
||||
|
||||
exports.getEmailFromUserID = userId => {
|
||||
return userId.split(`${DocumentTypes.USER}${SEPARATOR}`)[1]
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new group ID.
|
||||
* @returns {string} The new group ID which the group doc can be stored under.
|
||||
|
@ -53,16 +45,52 @@ exports.getGroupParams = (id = "", otherProps = {}) => {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets parameters for retrieving users, this is a utility function for the getDocParams function.
|
||||
* Generates a new global user ID.
|
||||
* @returns {string} The new user ID which the user doc can be stored under.
|
||||
*/
|
||||
exports.getUserParams = (email = "", otherProps = {}) => {
|
||||
if (!email) {
|
||||
email = ""
|
||||
exports.generateGlobalUserID = () => {
|
||||
return `${DocumentTypes.USER}${SEPARATOR}${newid()}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets parameters for retrieving users.
|
||||
*/
|
||||
exports.getGlobalUserParams = (globalId, otherProps = {}) => {
|
||||
if (!globalId) {
|
||||
globalId = ""
|
||||
}
|
||||
return {
|
||||
...otherProps,
|
||||
startkey: `${DocumentTypes.USER}${SEPARATOR}${email}`,
|
||||
endkey: `${DocumentTypes.USER}${SEPARATOR}${email}${UNICODE_MAX}`,
|
||||
startkey: `${DocumentTypes.USER}${SEPARATOR}${globalId}`,
|
||||
endkey: `${DocumentTypes.USER}${SEPARATOR}${globalId}${UNICODE_MAX}`,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a template ID.
|
||||
* @param ownerId The owner/user of the template, this could be global or a group level.
|
||||
*/
|
||||
exports.generateTemplateID = ownerId => {
|
||||
return `${DocumentTypes.TEMPLATE}${SEPARATOR}${ownerId}${newid()}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets parameters for retrieving templates. Owner ID must be specified, either global or a group level.
|
||||
*/
|
||||
exports.getTemplateParams = (ownerId, templateId, otherProps = {}) => {
|
||||
if (!templateId) {
|
||||
templateId = ""
|
||||
}
|
||||
let final
|
||||
if (templateId) {
|
||||
final = templateId
|
||||
} else {
|
||||
final = `${DocumentTypes.TEMPLATE}${SEPARATOR}${ownerId}${SEPARATOR}`
|
||||
}
|
||||
return {
|
||||
...otherProps,
|
||||
startkey: final,
|
||||
endkey: `${final}${UNICODE_MAX}`,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
const { DocumentTypes, ViewNames, StaticDatabases } = require("./utils")
|
||||
const { getDB } = require("./index")
|
||||
|
||||
function DesignDoc() {
|
||||
return {
|
||||
_id: "_design/database",
|
||||
// view collation information, read before writing any complex views:
|
||||
// https://docs.couchdb.org/en/master/ddocs/views/collation.html#collation-specification
|
||||
views: {},
|
||||
}
|
||||
}
|
||||
|
||||
exports.createUserEmailView = async () => {
|
||||
const db = getDB(StaticDatabases.GLOBAL.name)
|
||||
let designDoc
|
||||
try {
|
||||
designDoc = await db.get("_design/database")
|
||||
} catch (err) {
|
||||
// no design doc, make one
|
||||
designDoc = DesignDoc()
|
||||
}
|
||||
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)
|
||||
}
|
|
@ -13,6 +13,7 @@ const {
|
|||
clearCookie,
|
||||
isClient,
|
||||
} = require("./utils")
|
||||
const { setDB, getDB } = require("./db")
|
||||
const {
|
||||
generateUserID,
|
||||
getUserParams,
|
||||
|
@ -31,7 +32,7 @@ passport.use(new JwtStrategy(jwt.options, jwt.authenticate))
|
|||
passport.serializeUser((user, done) => done(null, user))
|
||||
|
||||
passport.deserializeUser(async (user, done) => {
|
||||
const db = new database.CouchDB(StaticDatabases.GLOBAL.name)
|
||||
const db = getDB(StaticDatabases.GLOBAL.name)
|
||||
|
||||
try {
|
||||
const user = await db.get(user._id)
|
||||
|
@ -44,7 +45,16 @@ passport.deserializeUser(async (user, done) => {
|
|||
|
||||
module.exports = {
|
||||
init(pouch) {
|
||||
database.setDB(pouch)
|
||||
setDB(pouch)
|
||||
},
|
||||
db: require("./db/utils"),
|
||||
utils: {
|
||||
...require("./utils"),
|
||||
...require("./hashing"),
|
||||
},
|
||||
auth: {
|
||||
buildAuthMiddleware: authenticated,
|
||||
passport,
|
||||
},
|
||||
passport,
|
||||
Cookies,
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
const { Cookies } = require("../constants")
|
||||
const { getCookie } = require("../utils")
|
||||
const { getEmailFromUserID } = require("../db/utils")
|
||||
|
||||
module.exports = async (ctx, next) => {
|
||||
module.exports = (noAuthPatterns = []) => {
|
||||
const regex = new RegExp(noAuthPatterns.join("|"))
|
||||
return async (ctx, next) => {
|
||||
// the path is not authenticated
|
||||
if (regex.test(ctx.request.url)) {
|
||||
return next()
|
||||
}
|
||||
try {
|
||||
// check the actual user is authenticated first
|
||||
const authCookie = getCookie(ctx, Cookies.Auth)
|
||||
|
@ -10,12 +15,11 @@ module.exports = async (ctx, next) => {
|
|||
if (authCookie) {
|
||||
ctx.isAuthenticated = true
|
||||
ctx.user = authCookie
|
||||
// make sure email is correct from ID
|
||||
ctx.user.email = getEmailFromUserID(authCookie.userId)
|
||||
}
|
||||
|
||||
await next()
|
||||
return next()
|
||||
} catch (err) {
|
||||
ctx.throw(err.status || 403, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
const jwt = require("jsonwebtoken")
|
||||
const { UserStatus } = require("../../constants")
|
||||
const database = require("../../db")
|
||||
const { StaticDatabases, generateUserID } = require("../../db/utils")
|
||||
const { compare } = require("../../hashing")
|
||||
const env = require("../../environment")
|
||||
const { getGlobalUserByEmail } = require("../../utils")
|
||||
|
||||
const INVALID_ERR = "Invalid Credentials"
|
||||
|
||||
|
@ -11,23 +10,17 @@ exports.options = {}
|
|||
|
||||
/**
|
||||
* 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 {*} done - callback from passport to return user information and errors
|
||||
* @returns The authenticated user, or errors if they occur
|
||||
*/
|
||||
exports.authenticate = async function(username, password, done) {
|
||||
if (!username) return done(null, false, "Email Required.")
|
||||
exports.authenticate = async function(email, password, done) {
|
||||
if (!email) return done(null, false, "Email 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
|
||||
try {
|
||||
dbUser = await db.get(generateUserID(username))
|
||||
} catch (err) {
|
||||
console.error("User not found", err)
|
||||
const dbUser = await getGlobalUserByEmail(email)
|
||||
if (dbUser == null) {
|
||||
return done(null, false, { message: "User not found" })
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
const { DocumentTypes, SEPARATOR } = require("./db/utils")
|
||||
const {
|
||||
DocumentTypes,
|
||||
SEPARATOR,
|
||||
ViewNames,
|
||||
StaticDatabases,
|
||||
} = require("./db/utils")
|
||||
const jwt = require("jsonwebtoken")
|
||||
const { options } = require("./middleware/passport/jwt")
|
||||
const { createUserEmailView } = require("./db/views")
|
||||
const { getDB } = require("./db")
|
||||
|
||||
const APP_PREFIX = DocumentTypes.APP + SEPARATOR
|
||||
|
||||
|
@ -97,3 +104,24 @@ exports.clearCookie = (ctx, name) => {
|
|||
exports.isClient = ctx => {
|
||||
return ctx.headers["x-budibase-type"] === "client"
|
||||
}
|
||||
|
||||
exports.getGlobalUserByEmail = async email => {
|
||||
const db = getDB(StaticDatabases.GLOBAL.name)
|
||||
try {
|
||||
let users = (
|
||||
await db.query(`database/${ViewNames.USER_BY_EMAIL}`, {
|
||||
key: email,
|
||||
include_docs: true,
|
||||
})
|
||||
).rows
|
||||
users = users.map(user => user.doc)
|
||||
return users.length <= 1 ? users[0] : users
|
||||
} catch (err) {
|
||||
if (err != null && err.name === "not_found") {
|
||||
await createUserEmailView()
|
||||
return exports.getGlobalUserByEmail(email)
|
||||
} else {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,12 +6,8 @@ context("Create Bindings", () => {
|
|||
})
|
||||
|
||||
it("should add a current user binding", () => {
|
||||
cy.addComponent("Elements", "Paragraph").then(componentId => {
|
||||
cy.addComponent("Elements", "Paragraph").then(() => {
|
||||
addSettingBinding("text", "Current User._id")
|
||||
cy.getComponent(componentId).should(
|
||||
"have.text",
|
||||
`ro_ta_users_test@test.com`
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -1,28 +1,9 @@
|
|||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add("login", (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||
|
||||
Cypress.Commands.add("login", () => {
|
||||
cy.getCookie("budibase:auth").then(cookie => {
|
||||
|
|
|
@ -14,9 +14,10 @@
|
|||
"cy:setup": "node ./cypress/setup.js",
|
||||
"cy:run": "cypress run",
|
||||
"cy:open": "cypress open",
|
||||
"cy:run:ci": "cypress run --browser electron --record --key f308590b-6070-41af-b970-794a3823d451",
|
||||
"cy:run:ci": "cypress run --record --key f308590b-6070-41af-b970-794a3823d451",
|
||||
"cy:test": "start-server-and-test cy:setup http://localhost:10000/builder cy:run",
|
||||
"cy:ci": "start-server-and-test cy:setup http://localhost:10000/builder cy:run:ci"
|
||||
"cy:ci": "start-server-and-test cy:setup http://localhost:10000/builder cy:run:ci",
|
||||
"cy:debug": "start-server-and-test cy:setup http://localhost:10000/builder cy:open"
|
||||
},
|
||||
"jest": {
|
||||
"globals": {
|
||||
|
|
|
@ -21,14 +21,7 @@
|
|||
|
||||
async function createTestUser() {
|
||||
try {
|
||||
await auth.createUser({
|
||||
email: "test@test.com",
|
||||
password: "test",
|
||||
roles: {},
|
||||
builder: {
|
||||
global: true,
|
||||
},
|
||||
})
|
||||
await auth.firstUser()
|
||||
notifier.success("Test user created")
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
|
|
|
@ -151,8 +151,8 @@
|
|||
const user = {
|
||||
roleId: $createAppStore.values.roleId,
|
||||
}
|
||||
const userResp = await api.post(`/api/users/metadata`, user)
|
||||
const json = await userResp.json()
|
||||
const userResp = await api.post(`/api/users/metadata/self`, user)
|
||||
await userResp.json()
|
||||
$goto(`./${appJson._id}`)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
|
|
|
@ -30,11 +30,24 @@ export function createAuthStore() {
|
|||
},
|
||||
logout: async () => {
|
||||
const response = await api.post(`/api/admin/auth/logout`)
|
||||
if (response.status !== 200) {
|
||||
throw "Unable to create logout"
|
||||
}
|
||||
await response.json()
|
||||
set({ user: null })
|
||||
},
|
||||
createUser: async user => {
|
||||
const response = await api.post(`/api/admin/users`, user)
|
||||
if (response.status !== 200) {
|
||||
throw "Unable to create user"
|
||||
}
|
||||
await response.json()
|
||||
},
|
||||
firstUser: async () => {
|
||||
const response = await api.post(`/api/admin/users/first`)
|
||||
if (response.status !== 200) {
|
||||
throw "Unable to create test user"
|
||||
}
|
||||
await response.json()
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,75 +1,8 @@
|
|||
const jwt = require("jsonwebtoken")
|
||||
const CouchDB = require("../../db")
|
||||
const bcrypt = require("../../utilities/bcrypt")
|
||||
const env = require("../../environment")
|
||||
const { getAPIKey } = require("../../utilities/usageQuota")
|
||||
const { generateUserMetadataID } = require("../../db/utils")
|
||||
const { setCookie } = require("../../utilities")
|
||||
const { outputProcessing } = require("../../utilities/rowProcessor")
|
||||
const { InternalTables } = require("../../db/utils")
|
||||
const { UserStatus } = require("@budibase/auth")
|
||||
const { getFullUser } = require("../../utilities/users")
|
||||
|
||||
const INVALID_ERR = "Invalid Credentials"
|
||||
|
||||
exports.authenticate = async ctx => {
|
||||
const appId = ctx.appId
|
||||
if (!appId) ctx.throw(400, "No appId")
|
||||
|
||||
const { email, password } = ctx.request.body
|
||||
|
||||
if (!email) ctx.throw(400, "Email Required.")
|
||||
if (!password) ctx.throw(400, "Password Required.")
|
||||
|
||||
// Check the user exists in the instance DB by email
|
||||
const db = new CouchDB(appId)
|
||||
const app = await db.get(appId)
|
||||
|
||||
let dbUser
|
||||
try {
|
||||
dbUser = await db.get(generateUserMetadataID(email))
|
||||
} catch (_) {
|
||||
// do not want to throw a 404 - as this could be
|
||||
// used to determine valid emails
|
||||
ctx.throw(401, INVALID_ERR)
|
||||
}
|
||||
|
||||
// check that the user is currently inactive, if this is the case throw invalid
|
||||
if (dbUser.status === UserStatus.INACTIVE) {
|
||||
ctx.throw(401, INVALID_ERR)
|
||||
}
|
||||
|
||||
// authenticate
|
||||
if (await bcrypt.compare(password, dbUser.password)) {
|
||||
const payload = {
|
||||
userId: dbUser._id,
|
||||
roleId: dbUser.roleId,
|
||||
version: app.version,
|
||||
}
|
||||
// if in prod add the user api key, unless self hosted
|
||||
/* istanbul ignore next */
|
||||
if (env.isProd() && !env.SELF_HOSTED) {
|
||||
const { apiKey } = await getAPIKey(ctx.appId)
|
||||
payload.apiKey = apiKey
|
||||
}
|
||||
|
||||
const token = jwt.sign(payload, ctx.config.jwtSecret, {
|
||||
expiresIn: "1 day",
|
||||
})
|
||||
|
||||
setCookie(ctx, token, appId)
|
||||
|
||||
delete dbUser.password
|
||||
ctx.body = {
|
||||
token,
|
||||
...dbUser,
|
||||
appId,
|
||||
}
|
||||
} else {
|
||||
ctx.throw(401, INVALID_ERR)
|
||||
}
|
||||
}
|
||||
|
||||
exports.fetchSelf = async ctx => {
|
||||
if (!ctx.user) {
|
||||
ctx.throw(403, "No user logged in")
|
||||
|
@ -82,7 +15,7 @@ exports.fetchSelf = async ctx => {
|
|||
return
|
||||
}
|
||||
|
||||
const user = await getFullUser({ ctx, userId: userId })
|
||||
const user = await getFullUser(ctx, userId)
|
||||
|
||||
if (appId) {
|
||||
const db = new CouchDB(appId)
|
||||
|
|
|
@ -4,9 +4,9 @@ const { checkSlashesInUrl } = require("../../utilities")
|
|||
const { request } = require("../../utilities/workerRequests")
|
||||
|
||||
async function redirect(ctx, method) {
|
||||
const { path } = ctx.params
|
||||
const { devPath } = ctx.params
|
||||
const response = await fetch(
|
||||
checkSlashesInUrl(`${env.WORKER_URL}/api/admin/${path}`),
|
||||
checkSlashesInUrl(`${env.WORKER_URL}/api/admin/${devPath}`),
|
||||
request(ctx, {
|
||||
method,
|
||||
body: ctx.request.body,
|
||||
|
|
|
@ -7,7 +7,6 @@ const {
|
|||
DocumentTypes,
|
||||
SEPARATOR,
|
||||
InternalTables,
|
||||
generateUserMetadataID,
|
||||
} = require("../../db/utils")
|
||||
const userController = require("./user")
|
||||
const {
|
||||
|
@ -42,7 +41,7 @@ async function findRow(ctx, db, tableId, rowId) {
|
|||
// TODO remove special user case in future
|
||||
if (tableId === InternalTables.USER_METADATA) {
|
||||
ctx.params = {
|
||||
userId: rowId,
|
||||
id: rowId,
|
||||
}
|
||||
await userController.findMetadata(ctx)
|
||||
row = ctx.body
|
||||
|
@ -140,13 +139,8 @@ exports.save = async function(ctx) {
|
|||
}
|
||||
|
||||
if (!inputs._rev && !inputs._id) {
|
||||
// TODO remove special user case in future
|
||||
if (inputs.tableId === InternalTables.USER_METADATA) {
|
||||
inputs._id = generateUserMetadataID(inputs.email)
|
||||
} else {
|
||||
inputs._id = generateRowID(inputs.tableId)
|
||||
}
|
||||
}
|
||||
|
||||
// this returns the table and row incase they have been updated
|
||||
const dbTable = await db.get(inputs.tableId)
|
||||
|
@ -342,7 +336,7 @@ exports.destroy = async function(ctx) {
|
|||
// TODO remove special user case in future
|
||||
if (ctx.params.tableId === InternalTables.USER_METADATA) {
|
||||
ctx.params = {
|
||||
userId: ctx.params.rowId,
|
||||
id: ctx.params.rowId,
|
||||
}
|
||||
await userController.destroyMetadata(ctx)
|
||||
} else {
|
||||
|
@ -449,7 +443,7 @@ async function bulkDelete(ctx) {
|
|||
updates = updates.concat(
|
||||
rows.map(row => {
|
||||
ctx.params = {
|
||||
userId: row._id,
|
||||
id: row._id,
|
||||
}
|
||||
return userController.destroyMetadata(ctx)
|
||||
})
|
||||
|
|
|
@ -2,7 +2,7 @@ const CouchDB = require("../../db")
|
|||
const {
|
||||
generateUserMetadataID,
|
||||
getUserMetadataParams,
|
||||
getEmailFromUserMetadataID,
|
||||
getGlobalIDFromUserMetadataID,
|
||||
} = require("../../db/utils")
|
||||
const { InternalTables } = require("../../db/utils")
|
||||
const { getRole } = require("../../utilities/security/roles")
|
||||
|
@ -25,15 +25,14 @@ exports.fetchMetadata = async function(ctx) {
|
|||
).rows.map(row => row.doc)
|
||||
const users = []
|
||||
for (let user of global) {
|
||||
const info = metadata.find(meta => meta._id.includes(user.email))
|
||||
// find the metadata that matches up to the global ID
|
||||
const info = metadata.find(meta => meta._id.includes(user._id))
|
||||
// remove these props, not for the correct DB
|
||||
delete user._id
|
||||
delete user._rev
|
||||
users.push({
|
||||
...user,
|
||||
...info,
|
||||
// make sure the ID is always a local ID, not a global one
|
||||
_id: generateUserMetadataID(user.email),
|
||||
_id: generateUserMetadataID(user._id),
|
||||
})
|
||||
}
|
||||
ctx.body = users
|
||||
|
@ -43,17 +42,20 @@ exports.createMetadata = async function(ctx) {
|
|||
const appId = ctx.appId
|
||||
const db = new CouchDB(appId)
|
||||
const { roleId } = ctx.request.body
|
||||
const email = ctx.request.body.email || ctx.user.email
|
||||
|
||||
if (ctx.request.body._id) {
|
||||
return exports.updateMetadata(ctx)
|
||||
}
|
||||
|
||||
// check role valid
|
||||
const role = await getRole(appId, roleId)
|
||||
if (!role) ctx.throw(400, "Invalid Role")
|
||||
|
||||
const metadata = await saveGlobalUser(ctx, appId, email, ctx.request.body)
|
||||
const globalUser = await saveGlobalUser(ctx, appId, ctx.request.body)
|
||||
|
||||
const user = {
|
||||
...metadata,
|
||||
_id: generateUserMetadataID(email),
|
||||
...globalUser,
|
||||
_id: generateUserMetadataID(globalUser._id),
|
||||
type: "user",
|
||||
tableId: InternalTables.USER_METADATA,
|
||||
}
|
||||
|
@ -64,47 +66,48 @@ exports.createMetadata = async function(ctx) {
|
|||
ctx.body = {
|
||||
_id: response.id,
|
||||
_rev: response.rev,
|
||||
email,
|
||||
email: ctx.request.body.email,
|
||||
}
|
||||
}
|
||||
|
||||
exports.updateSelfMetadata = async function(ctx) {
|
||||
// overwrite the ID with current users
|
||||
ctx.request.body._id = ctx.user.userId
|
||||
// make sure no stale rev
|
||||
delete ctx.request.body._rev
|
||||
await exports.updateMetadata(ctx)
|
||||
}
|
||||
|
||||
exports.updateMetadata = async function(ctx) {
|
||||
const appId = ctx.appId
|
||||
const db = new CouchDB(appId)
|
||||
const user = ctx.request.body
|
||||
let email = user.email || getEmailFromUserMetadataID(user._id)
|
||||
const metadata = await saveGlobalUser(ctx, appId, email, ctx.request.body)
|
||||
if (!metadata._id) {
|
||||
metadata._id = generateUserMetadataID(email)
|
||||
}
|
||||
if (!metadata._rev) {
|
||||
metadata._rev = ctx.request.body._rev
|
||||
}
|
||||
ctx.body = await db.put({
|
||||
...metadata,
|
||||
const globalUser = await saveGlobalUser(ctx, appId, {
|
||||
...user,
|
||||
_id: getGlobalIDFromUserMetadataID(user._id),
|
||||
})
|
||||
const metadata = {
|
||||
...globalUser,
|
||||
_id: user._id || generateUserMetadataID(globalUser._id),
|
||||
_rev: user._rev,
|
||||
}
|
||||
ctx.body = await db.put(metadata)
|
||||
}
|
||||
|
||||
exports.destroyMetadata = async function(ctx) {
|
||||
const db = new CouchDB(ctx.appId)
|
||||
const email =
|
||||
ctx.params.email || getEmailFromUserMetadataID(ctx.params.userId)
|
||||
await deleteGlobalUser(ctx, email)
|
||||
await deleteGlobalUser(ctx, getGlobalIDFromUserMetadataID(ctx.params.id))
|
||||
try {
|
||||
const dbUser = await db.get(generateUserMetadataID(email))
|
||||
const dbUser = await db.get(ctx.params.id)
|
||||
await db.remove(dbUser._id, dbUser._rev)
|
||||
} catch (err) {
|
||||
// error just means the global user has no config in this app
|
||||
}
|
||||
ctx.body = {
|
||||
message: `User ${ctx.params.email} deleted.`,
|
||||
message: `User ${ctx.params.id} deleted.`,
|
||||
}
|
||||
}
|
||||
|
||||
exports.findMetadata = async function(ctx) {
|
||||
ctx.body = await getFullUser({
|
||||
ctx,
|
||||
email: ctx.params.email,
|
||||
userId: ctx.params.userId,
|
||||
})
|
||||
ctx.body = await getFullUser(ctx, ctx.params.id)
|
||||
}
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
const Router = require("@koa/router")
|
||||
const { authenticated } = require("@budibase/auth")
|
||||
const { buildAuthMiddleware } = require("@budibase/auth").auth
|
||||
const currentApp = require("../middleware/currentapp")
|
||||
const compress = require("koa-compress")
|
||||
const zlib = require("zlib")
|
||||
const { mainRoutes, authRoutes, staticRoutes } = require("./routes")
|
||||
const { mainRoutes, staticRoutes } = require("./routes")
|
||||
const pkg = require("../../package.json")
|
||||
|
||||
const router = new Router()
|
||||
const env = require("../environment")
|
||||
|
||||
const NO_AUTH_ENDPOINTS = [
|
||||
"/health",
|
||||
"/version",
|
||||
"webhooks/trigger",
|
||||
"webhooks/schema",
|
||||
]
|
||||
|
||||
router
|
||||
.use(
|
||||
compress({
|
||||
|
@ -31,7 +38,7 @@ router
|
|||
})
|
||||
.use("/health", ctx => (ctx.status = 200))
|
||||
.use("/version", ctx => (ctx.body = pkg.version))
|
||||
.use(authenticated)
|
||||
.use(buildAuthMiddleware(NO_AUTH_ENDPOINTS))
|
||||
.use(currentApp)
|
||||
|
||||
// error handling middleware
|
||||
|
@ -53,9 +60,6 @@ router.use(async (ctx, next) => {
|
|||
|
||||
router.get("/health", ctx => (ctx.status = 200))
|
||||
|
||||
router.use(authRoutes.routes())
|
||||
router.use(authRoutes.allowedMethods())
|
||||
|
||||
// authenticated routes
|
||||
for (let route of mainRoutes) {
|
||||
router.use(route.routes())
|
||||
|
|
|
@ -5,9 +5,10 @@ const env = require("../../environment")
|
|||
const router = Router()
|
||||
|
||||
if (env.isDev() || env.isTest()) {
|
||||
router.get("/api/admin/:path", controller.redirectGet)
|
||||
router.post("/api/admin/:path", controller.redirectPost)
|
||||
router.delete("/api/admin/:path", controller.redirectDelete)
|
||||
router
|
||||
.get("/api/admin/:devPath(.*)", controller.redirectGet)
|
||||
.post("/api/admin/:devPath(.*)", controller.redirectPost)
|
||||
.delete("/api/admin/:devPath(.*)", controller.redirectDelete)
|
||||
}
|
||||
|
||||
module.exports = router
|
||||
|
|
|
@ -25,6 +25,7 @@ const backupRoutes = require("./backup")
|
|||
const devRoutes = require("./dev")
|
||||
|
||||
exports.mainRoutes = [
|
||||
authRoutes,
|
||||
deployRoutes,
|
||||
layoutRoutes,
|
||||
screenRoutes,
|
||||
|
@ -52,5 +53,4 @@ exports.mainRoutes = [
|
|||
rowRoutes,
|
||||
]
|
||||
|
||||
exports.authRoutes = authRoutes
|
||||
exports.staticRoutes = staticRoutes
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
const setup = require("./utilities")
|
||||
const { generateUserMetadataID } = require("../../../db/utils")
|
||||
|
||||
require("../../../utilities/workerRequests")
|
||||
jest.mock("../../../utilities/workerRequests", () => ({
|
||||
getGlobalUsers: jest.fn(() => {
|
||||
return {
|
||||
email: "test@test.com",
|
||||
_id: "us_uuid1",
|
||||
}
|
||||
}),
|
||||
saveGlobalUser: jest.fn(() => {
|
||||
return {
|
||||
_id: "us_uuid1",
|
||||
}
|
||||
}),
|
||||
saveGlobalUser: jest.fn(),
|
||||
}))
|
||||
|
||||
describe("/authenticate", () => {
|
||||
|
@ -22,14 +27,14 @@ describe("/authenticate", () => {
|
|||
|
||||
describe("fetch self", () => {
|
||||
it("should be able to fetch self", async () => {
|
||||
await config.createUser("test@test.com", "p4ssw0rd")
|
||||
const headers = await config.login("test@test.com", "p4ssw0rd")
|
||||
const user = await config.createUser("test@test.com", "p4ssw0rd")
|
||||
const headers = await config.login("test@test.com", "p4ssw0rd", { userId: "us_uuid1" })
|
||||
const res = await request
|
||||
.get(`/api/self`)
|
||||
.set(headers)
|
||||
.expect("Content-Type", /json/)
|
||||
.expect(200)
|
||||
expect(res.body.email).toEqual("test@test.com")
|
||||
expect(res.body._id).toEqual(generateUserMetadataID("us_uuid1"))
|
||||
})
|
||||
})
|
||||
})
|
|
@ -4,11 +4,6 @@ const { checkBuilderEndpoint } = require("./utilities/TestFunctions")
|
|||
const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles")
|
||||
const workerRequests = require("../../../utilities/workerRequests")
|
||||
|
||||
jest.mock("../../../utilities/workerRequests", () => ({
|
||||
getGlobalUsers: jest.fn(),
|
||||
saveGlobalUser: jest.fn(),
|
||||
}))
|
||||
|
||||
const route = "/test"
|
||||
|
||||
describe("/routing", () => {
|
||||
|
|
|
@ -7,7 +7,10 @@ const workerRequests = require("../../../utilities/workerRequests")
|
|||
jest.mock("../../../utilities/workerRequests", () => ({
|
||||
getGlobalUsers: jest.fn(),
|
||||
saveGlobalUser: jest.fn(() => {
|
||||
return {}
|
||||
const uuid = require("uuid/v4")
|
||||
return {
|
||||
_id: `us_${uuid()}`
|
||||
}
|
||||
}),
|
||||
deleteGlobalUser: jest.fn(),
|
||||
}))
|
||||
|
@ -26,10 +29,10 @@ describe("/users", () => {
|
|||
beforeEach(() => {
|
||||
workerRequests.getGlobalUsers.mockImplementationOnce(() => ([
|
||||
{
|
||||
email: "brenda@brenda.com"
|
||||
_id: "us_uuid1",
|
||||
},
|
||||
{
|
||||
email: "pam@pam.com"
|
||||
_id: "us_uuid2",
|
||||
}
|
||||
]
|
||||
))
|
||||
|
@ -45,8 +48,8 @@ describe("/users", () => {
|
|||
.expect(200)
|
||||
|
||||
expect(res.body.length).toBe(2)
|
||||
expect(res.body.find(u => u.email === "brenda@brenda.com")).toBeDefined()
|
||||
expect(res.body.find(u => u.email === "pam@pam.com")).toBeDefined()
|
||||
expect(res.body.find(u => u._id === `ro_ta_users_us_uuid1`)).toBeDefined()
|
||||
expect(res.body.find(u => u._id === `ro_ta_users_us_uuid2`)).toBeDefined()
|
||||
})
|
||||
|
||||
it("should apply authorization to endpoint", async () => {
|
||||
|
@ -66,10 +69,10 @@ describe("/users", () => {
|
|||
beforeEach(() => {
|
||||
workerRequests.getGlobalUsers.mockImplementationOnce(() => ([
|
||||
{
|
||||
email: "bill@budibase.com"
|
||||
_id: "us_uuid1",
|
||||
},
|
||||
{
|
||||
email: "brandNewUser@user.com"
|
||||
_id: "us_uuid2",
|
||||
}
|
||||
]
|
||||
))
|
||||
|
@ -86,7 +89,6 @@ describe("/users", () => {
|
|||
|
||||
it("returns a success message when a user is successfully created", async () => {
|
||||
const body = basicUser(BUILTIN_ROLE_IDS.POWER)
|
||||
body.email = "bill@budibase.com"
|
||||
const res = await create(body)
|
||||
|
||||
expect(res.res.statusMessage).toEqual("OK")
|
||||
|
@ -95,7 +97,6 @@ describe("/users", () => {
|
|||
|
||||
it("should apply authorization to endpoint", async () => {
|
||||
const body = basicUser(BUILTIN_ROLE_IDS.POWER)
|
||||
body.email = "brandNewUser@user.com"
|
||||
await checkPermissionsEndpoint({
|
||||
config,
|
||||
method: "POST",
|
||||
|
@ -110,13 +111,6 @@ describe("/users", () => {
|
|||
const user = basicUser(null)
|
||||
await create(user, 400)
|
||||
})
|
||||
|
||||
it("should throw error if user exists already", async () => {
|
||||
await config.createUser("test@test.com")
|
||||
const user = basicUser(BUILTIN_ROLE_IDS.POWER)
|
||||
user.email = "test@test.com"
|
||||
await create(user, 409)
|
||||
})
|
||||
})
|
||||
|
||||
describe("update", () => {
|
||||
|
@ -141,10 +135,9 @@ describe("/users", () => {
|
|||
|
||||
describe("destroy", () => {
|
||||
it("should be able to delete the user", async () => {
|
||||
const email = "test@test.com"
|
||||
await config.createUser(email)
|
||||
const user = await config.createUser()
|
||||
const res = await request
|
||||
.delete(`/api/users/metadata/${email}`)
|
||||
.delete(`/api/users/metadata/${user._id}`)
|
||||
.set(config.defaultHeaders())
|
||||
.expect(200)
|
||||
.expect("Content-Type", /json/)
|
||||
|
@ -156,21 +149,23 @@ describe("/users", () => {
|
|||
describe("find", () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks()
|
||||
workerRequests.saveGlobalUser.mockImplementationOnce(() => ({
|
||||
_id: "us_uuid1",
|
||||
}))
|
||||
workerRequests.getGlobalUsers.mockImplementationOnce(() => ({
|
||||
email: "test@test.com",
|
||||
_id: "us_uuid1",
|
||||
roleId: BUILTIN_ROLE_IDS.POWER,
|
||||
}))
|
||||
})
|
||||
|
||||
it("should be able to find the user", async () => {
|
||||
const email = "test@test.com"
|
||||
await config.createUser(email)
|
||||
const user = await config.createUser()
|
||||
const res = await request
|
||||
.get(`/api/users/metadata/${email}`)
|
||||
.get(`/api/users/metadata/${user._id}`)
|
||||
.set(config.defaultHeaders())
|
||||
.expect(200)
|
||||
.expect("Content-Type", /json/)
|
||||
expect(res.body.email).toEqual(email)
|
||||
expect(res.body._id).toEqual(user._id)
|
||||
expect(res.body.roleId).toEqual(BUILTIN_ROLE_IDS.POWER)
|
||||
expect(res.body.tableId).toBeDefined()
|
||||
})
|
||||
|
|
|
@ -63,11 +63,9 @@ exports.checkPermissionsEndpoint = async ({
|
|||
}) => {
|
||||
const password = "PASSWORD"
|
||||
await config.createUser("passUser@budibase.com", password, passRole)
|
||||
const passHeader = await config.login(
|
||||
"passUser@budibase.com",
|
||||
password,
|
||||
passRole
|
||||
)
|
||||
const passHeader = await config.login("passUser@budibase.com", password, {
|
||||
roleId: passRole,
|
||||
})
|
||||
|
||||
await exports
|
||||
.createRequest(config.request, method, url, body)
|
||||
|
@ -75,11 +73,9 @@ exports.checkPermissionsEndpoint = async ({
|
|||
.expect(200)
|
||||
|
||||
await config.createUser("failUser@budibase.com", password, failRole)
|
||||
const failHeader = await config.login(
|
||||
"failUser@budibase.com",
|
||||
password,
|
||||
failRole
|
||||
)
|
||||
const failHeader = await config.login("failUser@budibase.com", password, {
|
||||
roleId: failRole,
|
||||
})
|
||||
|
||||
await exports
|
||||
.createRequest(config.request, method, url, body)
|
||||
|
|
|
@ -2,6 +2,15 @@ const TestConfig = require("../../../../tests/utilities/TestConfiguration")
|
|||
const structures = require("../../../../tests/utilities/structures")
|
||||
const env = require("../../../../environment")
|
||||
|
||||
jest.mock("../../../../utilities/workerRequests", () => ({
|
||||
getGlobalUsers: jest.fn(),
|
||||
saveGlobalUser: jest.fn(() => {
|
||||
return {
|
||||
_id: "us_uuid1",
|
||||
}
|
||||
}),
|
||||
}))
|
||||
|
||||
exports.delay = ms => new Promise(resolve => setTimeout(resolve, ms))
|
||||
|
||||
let request, config
|
||||
|
|
|
@ -16,7 +16,7 @@ router
|
|||
controller.fetchMetadata
|
||||
)
|
||||
.get(
|
||||
"/api/users/metadata/:email",
|
||||
"/api/users/metadata/:id",
|
||||
authorized(PermissionTypes.USER, PermissionLevels.READ),
|
||||
controller.findMetadata
|
||||
)
|
||||
|
@ -31,8 +31,14 @@ router
|
|||
usage,
|
||||
controller.createMetadata
|
||||
)
|
||||
.post(
|
||||
"/api/users/metadata/self",
|
||||
authorized(PermissionTypes.USER, PermissionLevels.WRITE),
|
||||
usage,
|
||||
controller.updateSelfMetadata
|
||||
)
|
||||
.delete(
|
||||
"/api/users/metadata/:email",
|
||||
"/api/users/metadata/:id",
|
||||
authorized(PermissionTypes.USER, PermissionLevels.WRITE),
|
||||
usage,
|
||||
controller.destroyMetadata
|
||||
|
|
|
@ -25,6 +25,7 @@ describe("test the create user action", () => {
|
|||
expect(res.id).toBeDefined()
|
||||
expect(res.revision).toBeDefined()
|
||||
const userDoc = await config.getRow(InternalTables.USER_METADATA, res.id)
|
||||
expect(userDoc).toBeDefined()
|
||||
})
|
||||
|
||||
it("should return an error if no inputs provided", async () => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const { BUILTIN_ROLE_IDS } = require("../utilities/security/roles")
|
||||
const { UserStatus } = require("@budibase/auth")
|
||||
const { UserStatus } = require("@budibase/auth").constants
|
||||
|
||||
exports.LOGO_URL =
|
||||
"https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg"
|
||||
|
@ -33,6 +33,7 @@ exports.USERS_TABLE_SCHEMA = {
|
|||
type: "table",
|
||||
views: {},
|
||||
name: "Users",
|
||||
// TODO: ADMIN PANEL - when implemented this doesn't need to be carried out
|
||||
schema: {
|
||||
email: {
|
||||
type: exports.FieldTypes.STRING,
|
||||
|
|
|
@ -107,8 +107,7 @@ exports.getRowParams = (tableId = null, rowId = null, otherProps = {}) => {
|
|||
return getDocParams(DocumentTypes.ROW, null, otherProps)
|
||||
}
|
||||
|
||||
const endOfKey =
|
||||
rowId == null ? `${tableId}${SEPARATOR}` : `${tableId}${SEPARATOR}${rowId}`
|
||||
const endOfKey = rowId == null ? `${tableId}${SEPARATOR}` : rowId
|
||||
|
||||
return getDocParams(DocumentTypes.ROW, endOfKey, otherProps)
|
||||
}
|
||||
|
@ -127,23 +126,23 @@ exports.generateRowID = (tableId, id = null) => {
|
|||
/**
|
||||
* Gets parameters for retrieving users, this is a utility function for the getDocParams function.
|
||||
*/
|
||||
exports.getUserMetadataParams = (email = "", otherProps = {}) => {
|
||||
return exports.getRowParams(InternalTables.USER_METADATA, email, otherProps)
|
||||
exports.getUserMetadataParams = (userId = null, otherProps = {}) => {
|
||||
return exports.getRowParams(InternalTables.USER_METADATA, userId, otherProps)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new user ID based on the passed in email.
|
||||
* @param {string} email The email which the ID is going to be built up of.
|
||||
* Generates a new user ID based on the passed in global ID.
|
||||
* @param {string} globalId The ID of the global user.
|
||||
* @returns {string} The new user ID which the user doc can be stored under.
|
||||
*/
|
||||
exports.generateUserMetadataID = email => {
|
||||
return exports.generateRowID(InternalTables.USER_METADATA, email)
|
||||
exports.generateUserMetadataID = globalId => {
|
||||
return exports.generateRowID(InternalTables.USER_METADATA, globalId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Breaks up the ID to get the email address back out of it.
|
||||
* Breaks up the ID to get the global ID.
|
||||
*/
|
||||
exports.getEmailFromUserMetadataID = id => {
|
||||
exports.getGlobalIDFromUserMetadataID = id => {
|
||||
return id.split(
|
||||
`${DocumentTypes.ROW}${SEPARATOR}${InternalTables.USER_METADATA}${SEPARATOR}`
|
||||
)[1]
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
const { getAppId, setCookie, getCookie, Cookies } = require("@budibase/auth")
|
||||
const { getAppId, setCookie, getCookie } = require("@budibase/auth").utils
|
||||
const { Cookies } = require("@budibase/auth").constants
|
||||
const { getRole } = require("../utilities/security/roles")
|
||||
const { generateUserMetadataID } = require("../db/utils")
|
||||
const { getGlobalUsers } = require("../utilities/workerRequests")
|
||||
const { BUILTIN_ROLE_IDS } = require("../utilities/security/roles")
|
||||
const {
|
||||
getGlobalIDFromUserMetadataID,
|
||||
generateUserMetadataID,
|
||||
} = require("../db/utils")
|
||||
|
||||
module.exports = async (ctx, next) => {
|
||||
// try to get the appID from the request
|
||||
|
@ -27,7 +31,8 @@ module.exports = async (ctx, next) => {
|
|||
appCookie.roleId === BUILTIN_ROLE_IDS.PUBLIC)
|
||||
) {
|
||||
// Different App ID means cookie needs reset, or if the same public user has logged in
|
||||
const globalUser = await getGlobalUsers(ctx, requestAppId, ctx.user.email)
|
||||
const globalId = getGlobalIDFromUserMetadataID(ctx.user.userId)
|
||||
const globalUser = await getGlobalUsers(ctx, requestAppId, globalId)
|
||||
updateCookie = true
|
||||
appId = requestAppId
|
||||
if (globalUser.roles && globalUser.roles[requestAppId]) {
|
||||
|
@ -37,22 +42,24 @@ module.exports = async (ctx, next) => {
|
|||
appId = appCookie.appId
|
||||
roleId = appCookie.roleId || BUILTIN_ROLE_IDS.PUBLIC
|
||||
}
|
||||
if (appId) {
|
||||
// nothing more to do
|
||||
if (!appId) {
|
||||
return next()
|
||||
}
|
||||
|
||||
ctx.appId = appId
|
||||
if (roleId) {
|
||||
const userId = ctx.user
|
||||
? generateUserMetadataID(ctx.user.email)
|
||||
: undefined
|
||||
ctx.roleId = roleId
|
||||
const userId = ctx.user ? generateUserMetadataID(ctx.user.userId) : null
|
||||
ctx.user = {
|
||||
...ctx.user,
|
||||
// override userID with metadata one
|
||||
_id: userId,
|
||||
userId,
|
||||
role: await getRole(appId, roleId),
|
||||
}
|
||||
}
|
||||
}
|
||||
if (updateCookie && appId) {
|
||||
if (updateCookie) {
|
||||
setCookie(ctx, { appId, roleId }, Cookies.CurrentApp)
|
||||
}
|
||||
return next()
|
||||
|
|
|
@ -5,7 +5,7 @@ function mockWorker() {
|
|||
jest.mock("../../utilities/workerRequests", () => ({
|
||||
getGlobalUsers: () => {
|
||||
return {
|
||||
email: "test@test.com",
|
||||
email: "us_uuid1",
|
||||
roles: {
|
||||
"app_test": "BASIC",
|
||||
}
|
||||
|
@ -23,10 +23,14 @@ function mockAuthWithNoCookie() {
|
|||
jest.resetModules()
|
||||
mockWorker()
|
||||
jest.mock("@budibase/auth", () => ({
|
||||
utils: {
|
||||
getAppId: jest.fn(),
|
||||
setCookie: jest.fn(),
|
||||
getCookie: jest.fn(),
|
||||
},
|
||||
constants: {
|
||||
Cookies: {},
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -34,15 +38,19 @@ function mockAuthWithCookie() {
|
|||
jest.resetModules()
|
||||
mockWorker()
|
||||
jest.mock("@budibase/auth", () => ({
|
||||
utils: {
|
||||
getAppId: () => {
|
||||
return "app_test"
|
||||
},
|
||||
setCookie: jest.fn(),
|
||||
getCookie: () => ({ appId: "app_different", roleId: "PUBLIC" }),
|
||||
getCookie: () => ({appId: "app_different", roleId: "PUBLIC"}),
|
||||
},
|
||||
constants: {
|
||||
Cookies: {
|
||||
Auth: "auth",
|
||||
CurrentApp: "currentapp",
|
||||
}
|
||||
},
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -59,7 +67,7 @@ class TestConfiguration {
|
|||
|
||||
setUser() {
|
||||
this.ctx.user = {
|
||||
email: "test@test.com",
|
||||
userId: "ro_ta_user_us_uuid1",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +110,7 @@ describe("Current app middleware", () => {
|
|||
async function checkExpected(setCookie) {
|
||||
config.setUser()
|
||||
await config.executeMiddleware()
|
||||
const cookieFn = require("@budibase/auth").setCookie
|
||||
const cookieFn = require("@budibase/auth").utils.setCookie
|
||||
if (setCookie) {
|
||||
expect(cookieFn).toHaveBeenCalled()
|
||||
} else {
|
||||
|
@ -122,12 +130,16 @@ describe("Current app middleware", () => {
|
|||
it("should perform correct when no cookie exists", async () => {
|
||||
mockReset()
|
||||
jest.mock("@budibase/auth", () => ({
|
||||
utils: {
|
||||
getAppId: () => {
|
||||
return "app_test"
|
||||
},
|
||||
setCookie: jest.fn(),
|
||||
getCookie: jest.fn(),
|
||||
},
|
||||
constants: {
|
||||
Cookies: {},
|
||||
},
|
||||
}))
|
||||
await checkExpected(true)
|
||||
})
|
||||
|
@ -135,12 +147,14 @@ describe("Current app middleware", () => {
|
|||
it("lastly check what occurs when cookie doesn't need updated", async () => {
|
||||
mockReset()
|
||||
jest.mock("@budibase/auth", () => ({
|
||||
utils: {
|
||||
getAppId: () => {
|
||||
return "app_test"
|
||||
},
|
||||
setCookie: jest.fn(),
|
||||
getCookie: () => ({ appId: "app_test", roleId: "BASIC" }),
|
||||
Cookies: {},
|
||||
getCookie: () => ({appId: "app_test", roleId: "BASIC"}),
|
||||
},
|
||||
constants: { Cookies: {} },
|
||||
}))
|
||||
await checkExpected(false)
|
||||
})
|
||||
|
|
|
@ -15,7 +15,7 @@ const {
|
|||
const controllers = require("./controllers")
|
||||
const supertest = require("supertest")
|
||||
const { cleanup } = require("../../utilities/fileSystem")
|
||||
const { Cookies } = require("@budibase/auth")
|
||||
const { Cookies } = require("@budibase/auth").constants
|
||||
|
||||
const EMAIL = "babs@babs.com"
|
||||
const PASSWORD = "babs_password"
|
||||
|
@ -70,8 +70,7 @@ class TestConfiguration {
|
|||
|
||||
defaultHeaders() {
|
||||
const user = {
|
||||
userId: "us_test@test.com",
|
||||
email: "test@test.com",
|
||||
userId: "ro_ta_user_us_uuid1",
|
||||
builder: {
|
||||
global: true,
|
||||
},
|
||||
|
@ -106,12 +105,13 @@ class TestConfiguration {
|
|||
}
|
||||
|
||||
async roleHeaders(email = EMAIL, roleId = BUILTIN_ROLE_IDS.ADMIN) {
|
||||
let user
|
||||
try {
|
||||
await this.createUser(email, PASSWORD, roleId)
|
||||
user = await this.createUser(email, PASSWORD, roleId)
|
||||
} catch (err) {
|
||||
// allow errors here
|
||||
}
|
||||
return this.login(email, PASSWORD, roleId)
|
||||
return this.login(email, PASSWORD, { roleId, userId: user._id })
|
||||
}
|
||||
|
||||
async createApp(appName) {
|
||||
|
@ -293,33 +293,19 @@ class TestConfiguration {
|
|||
)
|
||||
}
|
||||
|
||||
async makeUserInactive(email) {
|
||||
const user = await this._req(
|
||||
null,
|
||||
{
|
||||
email,
|
||||
},
|
||||
controllers.user.findMetadata
|
||||
)
|
||||
return this._req(
|
||||
{
|
||||
...user,
|
||||
status: "inactive",
|
||||
},
|
||||
null,
|
||||
controllers.user.updateMetadata
|
||||
)
|
||||
async login(email, password, { roleId, userId } = {}) {
|
||||
if (!roleId) {
|
||||
roleId = BUILTIN_ROLE_IDS.BUILDER
|
||||
}
|
||||
|
||||
async login(email, password, roleId = BUILTIN_ROLE_IDS.BUILDER) {
|
||||
if (!this.request) {
|
||||
throw "Server has not been opened, cannot login."
|
||||
}
|
||||
if (!email || !password) {
|
||||
await this.createUser()
|
||||
}
|
||||
// have to fake this
|
||||
const user = {
|
||||
userId: `us_${email || EMAIL}`,
|
||||
userId: userId || `us_uuid1`,
|
||||
email: email || EMAIL,
|
||||
}
|
||||
const app = {
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
const CouchDB = require("../db")
|
||||
const {
|
||||
generateUserMetadataID,
|
||||
getEmailFromUserMetadataID,
|
||||
} = require("../db/utils")
|
||||
const { getGlobalIDFromUserMetadataID } = require("../db/utils")
|
||||
const { getGlobalUsers } = require("../utilities/workerRequests")
|
||||
|
||||
exports.getFullUser = async ({ ctx, email, userId }) => {
|
||||
if (!email) {
|
||||
email = getEmailFromUserMetadataID(userId)
|
||||
}
|
||||
const global = await getGlobalUsers(ctx, ctx.appId, email)
|
||||
exports.getFullUser = async (ctx, userId) => {
|
||||
const global = await getGlobalUsers(
|
||||
ctx,
|
||||
ctx.appId,
|
||||
getGlobalIDFromUserMetadataID(userId)
|
||||
)
|
||||
let metadata
|
||||
try {
|
||||
// this will throw an error if the db doesn't exist, or there is no appId
|
||||
const db = new CouchDB(ctx.appId)
|
||||
metadata = await db.get(generateUserMetadataID(email))
|
||||
metadata = await db.get(userId)
|
||||
} catch (err) {
|
||||
// it is fine if there is no user metadata, just remove global db info
|
||||
delete global._id
|
||||
|
@ -24,6 +22,6 @@ exports.getFullUser = async ({ ctx, email, userId }) => {
|
|||
...global,
|
||||
...metadata,
|
||||
// make sure the ID is always a local ID, not a global one
|
||||
_id: generateUserMetadataID(email),
|
||||
_id: userId,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,8 +60,8 @@ exports.getDeployedApps = async ctx => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.deleteGlobalUser = async (ctx, email) => {
|
||||
const endpoint = `/api/admin/users/${email}`
|
||||
exports.deleteGlobalUser = async (ctx, globalId) => {
|
||||
const endpoint = `/api/admin/users/${globalId}`
|
||||
const reqCfg = { method: "DELETE" }
|
||||
const response = await fetch(
|
||||
checkSlashesInUrl(env.WORKER_URL + endpoint),
|
||||
|
@ -70,8 +70,10 @@ exports.deleteGlobalUser = async (ctx, email) => {
|
|||
return response.json()
|
||||
}
|
||||
|
||||
exports.getGlobalUsers = async (ctx, appId = null, email = null) => {
|
||||
const endpoint = email ? `/api/admin/users/${email}` : `/api/admin/users`
|
||||
exports.getGlobalUsers = async (ctx, appId = null, globalId = null) => {
|
||||
const endpoint = globalId
|
||||
? `/api/admin/users/${globalId}`
|
||||
: `/api/admin/users`
|
||||
const reqCfg = { method: "GET" }
|
||||
const response = await fetch(
|
||||
checkSlashesInUrl(env.WORKER_URL + endpoint),
|
||||
|
@ -89,8 +91,10 @@ exports.getGlobalUsers = async (ctx, appId = null, email = null) => {
|
|||
return users
|
||||
}
|
||||
|
||||
exports.saveGlobalUser = async (ctx, appId, email, body) => {
|
||||
const globalUser = await exports.getGlobalUsers(ctx, appId, email)
|
||||
exports.saveGlobalUser = async (ctx, appId, body) => {
|
||||
const globalUser = body._id
|
||||
? await exports.getGlobalUsers(ctx, appId, body._id)
|
||||
: {}
|
||||
const roles = globalUser.roles || {}
|
||||
if (body.roleId) {
|
||||
roles[appId] = body.roleId
|
||||
|
@ -100,9 +104,9 @@ exports.saveGlobalUser = async (ctx, appId, email, body) => {
|
|||
method: "POST",
|
||||
body: {
|
||||
...globalUser,
|
||||
email,
|
||||
password: body.password || undefined,
|
||||
status: body.status,
|
||||
email: body.email,
|
||||
roles,
|
||||
builder: {
|
||||
global: true,
|
||||
|
@ -124,5 +128,8 @@ exports.saveGlobalUser = async (ctx, appId, email, body) => {
|
|||
delete body.status
|
||||
delete body.roles
|
||||
delete body.builder
|
||||
return body
|
||||
return {
|
||||
...body,
|
||||
_id: json._id,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
const CouchDB = require("../../../db")
|
||||
const { getGroupParams, StaticDatabases } = require("@budibase/auth")
|
||||
const { generateGroupID } = require("@budibase/auth")
|
||||
const {
|
||||
getGroupParams,
|
||||
generateGroupID,
|
||||
StaticDatabases,
|
||||
} = require("@budibase/auth").db
|
||||
|
||||
const GLOBAL_DB = StaticDatabases.GLOBAL.name
|
||||
|
||||
|
@ -31,15 +34,13 @@ exports.fetch = async function(ctx) {
|
|||
include_docs: true,
|
||||
})
|
||||
)
|
||||
const groups = response.rows.map(row => row.doc)
|
||||
ctx.body = groups
|
||||
ctx.body = response.rows.map(row => row.doc)
|
||||
}
|
||||
|
||||
exports.find = async function(ctx) {
|
||||
const db = new CouchDB(GLOBAL_DB)
|
||||
try {
|
||||
const record = await db.get(ctx.params.id)
|
||||
ctx.body = record
|
||||
ctx.body = await db.get(ctx.params.id)
|
||||
} catch (err) {
|
||||
ctx.throw(err.status, err)
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
const users = require("./users")
|
||||
const groups = require("./groups")
|
||||
|
||||
module.exports = {
|
||||
users,
|
||||
groups,
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
const { generateTemplateID, getTemplateParams, StaticDatabases } = require("@budibase/auth").db
|
||||
const { CouchDB } = require("../../../db")
|
||||
const { TemplatePurposePretty } = require("../../../constants")
|
||||
|
||||
const GLOBAL_DB = StaticDatabases.GLOBAL.name
|
||||
const GLOBAL_OWNER = "global"
|
||||
|
||||
async function getTemplates({ ownerId, type, id } = {}) {
|
||||
const db = new CouchDB(GLOBAL_DB)
|
||||
const response = await db.allDocs(
|
||||
getTemplateParams(ownerId, id, {
|
||||
include_docs: true,
|
||||
})
|
||||
)
|
||||
let templates = response.rows.map(row => row.doc)
|
||||
if (type) {
|
||||
templates = templates.filter(template => template.type === type)
|
||||
}
|
||||
return templates
|
||||
}
|
||||
|
||||
exports.save = async ctx => {
|
||||
const db = new CouchDB(GLOBAL_DB)
|
||||
const type = ctx.params.type
|
||||
let template = ctx.request.body
|
||||
if (!template.ownerId) {
|
||||
template.ownerId = GLOBAL_OWNER
|
||||
}
|
||||
if (!template._id) {
|
||||
template._id = generateTemplateID(template.ownerId)
|
||||
}
|
||||
|
||||
const response = await db.put({
|
||||
...template,
|
||||
type,
|
||||
})
|
||||
ctx.body = {
|
||||
...template,
|
||||
_rev: response.rev,
|
||||
}
|
||||
}
|
||||
|
||||
exports.definitions = async ctx => {
|
||||
ctx.body = {
|
||||
purpose: TemplatePurposePretty
|
||||
}
|
||||
}
|
||||
|
||||
exports.fetch = async ctx => {
|
||||
ctx.body = await getTemplates()
|
||||
}
|
||||
|
||||
exports.fetchByType = async ctx => {
|
||||
ctx.body = await getTemplates({
|
||||
type: ctx.params.type,
|
||||
})
|
||||
}
|
||||
|
||||
exports.fetchByOwner = async ctx => {
|
||||
ctx.body = await getTemplates({
|
||||
ownerId: ctx.params.ownerId,
|
||||
})
|
||||
}
|
||||
|
||||
exports.find = async ctx => {
|
||||
ctx.body = await getTemplates({
|
||||
id: ctx.params.id,
|
||||
})
|
||||
}
|
||||
|
||||
exports.destroy = async ctx => {
|
||||
// TODO
|
||||
const db = new CouchDB(GLOBAL_DB)
|
||||
ctx.body = {}
|
||||
}
|
|
@ -1,27 +1,41 @@
|
|||
const CouchDB = require("../../../db")
|
||||
const {
|
||||
hash,
|
||||
generateUserID,
|
||||
getUserParams,
|
||||
generateGlobalUserID,
|
||||
getGlobalUserParams,
|
||||
StaticDatabases,
|
||||
} = require("@budibase/auth")
|
||||
} = require("@budibase/auth").db
|
||||
const { hash, getGlobalUserByEmail } = require("@budibase/auth").utils
|
||||
const { UserStatus } = require("../../../constants")
|
||||
|
||||
const FIRST_USER_EMAIL = "test@test.com"
|
||||
const FIRST_USER_PASSWORD = "test"
|
||||
const GLOBAL_DB = StaticDatabases.GLOBAL.name
|
||||
|
||||
exports.userSave = async ctx => {
|
||||
const db = new CouchDB(GLOBAL_DB)
|
||||
const { email, password, _id } = ctx.request.body
|
||||
const hashedPassword = password ? await hash(password) : null
|
||||
let user = {
|
||||
...ctx.request.body,
|
||||
_id: generateUserID(email),
|
||||
password: hashedPassword,
|
||||
|
||||
// make sure another user isn't using the same email
|
||||
const dbUser = await getGlobalUserByEmail(email)
|
||||
if (dbUser != null && (dbUser._id !== _id || Array.isArray(dbUser))) {
|
||||
ctx.throw(400, "Email address already in use.")
|
||||
}
|
||||
let dbUser
|
||||
// in-case user existed already
|
||||
if (_id) {
|
||||
dbUser = await db.get(_id)
|
||||
|
||||
// get the password, make sure one is defined
|
||||
let hashedPassword
|
||||
if (password) {
|
||||
hashedPassword = await hash(password)
|
||||
} else if (dbUser) {
|
||||
hashedPassword = dbUser.password
|
||||
} else {
|
||||
ctx.throw(400, "Password must be specified.")
|
||||
}
|
||||
|
||||
let user = {
|
||||
...dbUser,
|
||||
...ctx.request.body,
|
||||
_id: _id || generateGlobalUserID(),
|
||||
password: hashedPassword,
|
||||
}
|
||||
// add the active status to a user if its not provided
|
||||
if (user.status == null) {
|
||||
|
@ -29,7 +43,7 @@ exports.userSave = async ctx => {
|
|||
}
|
||||
try {
|
||||
const response = await db.post({
|
||||
password: hashedPassword || dbUser.password,
|
||||
password: hashedPassword,
|
||||
...user,
|
||||
})
|
||||
ctx.body = {
|
||||
|
@ -46,12 +60,24 @@ exports.userSave = async ctx => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.firstUser = async ctx => {
|
||||
ctx.request.body = {
|
||||
email: FIRST_USER_EMAIL,
|
||||
password: FIRST_USER_PASSWORD,
|
||||
roles: {},
|
||||
builder: {
|
||||
global: true,
|
||||
},
|
||||
}
|
||||
await exports.userSave(ctx)
|
||||
}
|
||||
|
||||
exports.userDelete = async ctx => {
|
||||
const db = new CouchDB(GLOBAL_DB)
|
||||
const dbUser = await db.get(generateUserID(ctx.params.email))
|
||||
const dbUser = await db.get(ctx.params.id)
|
||||
await db.remove(dbUser._id, dbUser._rev)
|
||||
ctx.body = {
|
||||
message: `User ${ctx.params.email} deleted.`,
|
||||
message: `User ${ctx.params.id} deleted.`,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,7 +85,7 @@ exports.userDelete = async ctx => {
|
|||
exports.userFetch = async ctx => {
|
||||
const db = new CouchDB(GLOBAL_DB)
|
||||
const response = await db.allDocs(
|
||||
getUserParams(null, {
|
||||
getGlobalUserParams(null, {
|
||||
include_docs: true,
|
||||
})
|
||||
)
|
||||
|
@ -78,7 +104,7 @@ exports.userFind = async ctx => {
|
|||
const db = new CouchDB(GLOBAL_DB)
|
||||
let user
|
||||
try {
|
||||
user = await db.get(generateUserID(ctx.params.email))
|
||||
user = await db.get(ctx.params.id)
|
||||
} catch (err) {
|
||||
// no user found, just return nothing
|
||||
user = {}
|
||||
|
|
|
@ -1,38 +1,7 @@
|
|||
const {
|
||||
passport,
|
||||
Cookies,
|
||||
StaticDatabases,
|
||||
clearCookie,
|
||||
} = require("@budibase/auth")
|
||||
const CouchDB = require("../../db")
|
||||
|
||||
const GLOBAL_DB = StaticDatabases.GLOBAL.name
|
||||
|
||||
async function setToken(ctx) {
|
||||
return async function(err, user) {
|
||||
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,
|
||||
})
|
||||
|
||||
delete user.token
|
||||
|
||||
ctx.body = { user }
|
||||
}
|
||||
}
|
||||
const authPkg = require("@budibase/auth")
|
||||
const { clearCookie } = authPkg.utils
|
||||
const { Cookies } = authPkg.constants
|
||||
const { passport } = authPkg.auth
|
||||
|
||||
exports.authenticate = async (ctx, next) => {
|
||||
return passport.authenticate("local", async (err, user) => {
|
||||
|
|
|
@ -2,6 +2,9 @@ const Router = require("@koa/router")
|
|||
const compress = require("koa-compress")
|
||||
const zlib = require("zlib")
|
||||
const { routes } = require("./routes")
|
||||
const { buildAuthMiddleware } = require("@budibase/auth").auth
|
||||
|
||||
const NO_AUTH_ENDPOINTS = ["/api/admin/users/first"]
|
||||
|
||||
const router = new Router()
|
||||
|
||||
|
@ -19,6 +22,7 @@ router
|
|||
})
|
||||
)
|
||||
.use("/health", ctx => (ctx.status = 200))
|
||||
.use(buildAuthMiddleware(NO_AUTH_ENDPOINTS))
|
||||
|
||||
// error handling middleware
|
||||
router.use(async (ctx, next) => {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../../controllers/admin/groups")
|
||||
const joiValidator = require("../../../middleware/joi-validator")
|
||||
const { authenticated } = require("@budibase/auth")
|
||||
const Joi = require("joi")
|
||||
|
||||
const router = Router()
|
||||
|
@ -25,14 +24,9 @@ function buildGroupSaveValidation() {
|
|||
}
|
||||
|
||||
router
|
||||
.post(
|
||||
"/api/admin/groups",
|
||||
buildGroupSaveValidation(),
|
||||
authenticated,
|
||||
controller.save
|
||||
)
|
||||
.delete("/api/admin/groups/:id", authenticated, controller.destroy)
|
||||
.get("/api/admin/groups", authenticated, controller.fetch)
|
||||
.get("/api/admin/groups/:id", authenticated, controller.find)
|
||||
.post("/api/admin/groups", buildGroupSaveValidation(), controller.save)
|
||||
.get("/api/admin/groups", controller.fetch)
|
||||
.delete("/api/admin/groups/:id", controller.destroy)
|
||||
.get("/api/admin/groups/:id", controller.find)
|
||||
|
||||
module.exports = router
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../../controllers/admin/templates")
|
||||
const joiValidator = require("../../../middleware/joi-validator")
|
||||
const Joi = require("joi")
|
||||
const { TemplatePurpose, TemplateTypes } = require("../../../constants")
|
||||
|
||||
const router = Router()
|
||||
|
||||
function buildTemplateSaveValidation() {
|
||||
// prettier-ignore
|
||||
return joiValidator.body(Joi.object({
|
||||
_id: Joi.string().allow(null, ""),
|
||||
_rev: Joi.string().allow(null, ""),
|
||||
ownerId: Joi.string().allow(null, ""),
|
||||
name: Joi.string().allow(null, ""),
|
||||
contents: Joi.string().required(),
|
||||
purpose: Joi.string().required().valid(...Object.values(TemplatePurpose)),
|
||||
type: Joi.string().required().valid(...Object.values(TemplateTypes)),
|
||||
}).required().unknown(true).optional())
|
||||
}
|
||||
|
||||
router
|
||||
.get("/api/admin/template/definitions", controller.definitions)
|
||||
.post(
|
||||
"/api/admin/template",
|
||||
buildTemplateSaveValidation(),
|
||||
controller.save
|
||||
)
|
||||
.get("/api/admin/template", controller.fetch)
|
||||
.get("/api/admin/template/:type", controller.fetchByType)
|
||||
.get("/api/admin/template/:ownerId", controller.fetchByOwner)
|
||||
.delete("/api/admin/template/:id", controller.destroy)
|
||||
.get("/api/admin/template/:id", controller.find)
|
|
@ -1,7 +1,6 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../../controllers/admin/users")
|
||||
const joiValidator = require("../../../middleware/joi-validator")
|
||||
const { authenticated } = require("@budibase/auth")
|
||||
const Joi = require("joi")
|
||||
|
||||
const router = Router()
|
||||
|
@ -26,14 +25,10 @@ function buildUserSaveValidation() {
|
|||
}
|
||||
|
||||
router
|
||||
.post(
|
||||
"/api/admin/users",
|
||||
buildUserSaveValidation(),
|
||||
authenticated,
|
||||
controller.userSave
|
||||
)
|
||||
.delete("/api/admin/users/:email", authenticated, controller.userDelete)
|
||||
.get("/api/admin/users", authenticated, controller.userFetch)
|
||||
.get("/api/admin/users/:email", authenticated, controller.userFind)
|
||||
.post("/api/admin/users", buildUserSaveValidation(), controller.userSave)
|
||||
.get("/api/admin/users", controller.userFetch)
|
||||
.post("/api/admin/users/first", controller.firstUser)
|
||||
.delete("/api/admin/users/:id", controller.userDelete)
|
||||
.get("/api/admin/users/:id", controller.userFind)
|
||||
|
||||
module.exports = router
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../controllers/app")
|
||||
const { authenticated } = require("@budibase/auth")
|
||||
|
||||
const router = Router()
|
||||
|
||||
router.get("/api/apps", authenticated, controller.getApps)
|
||||
router.get("/api/apps", controller.getApps)
|
||||
|
||||
module.exports = router
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const Router = require("@koa/router")
|
||||
const { passport } = require("@budibase/auth")
|
||||
const { passport } = require("@budibase/auth").auth
|
||||
const authController = require("../controllers/auth")
|
||||
const context = require("koa/lib/context")
|
||||
|
||||
|
|
|
@ -12,3 +12,28 @@ exports.Configs = {
|
|||
ACCOUNT: "account",
|
||||
SMTP: "smtp",
|
||||
}
|
||||
|
||||
exports.TemplateTypes = {
|
||||
EMAIL: "email",
|
||||
}
|
||||
|
||||
exports.TemplatePurpose = {
|
||||
PASSWORD_RECOVERY: "password_recovery",
|
||||
INVITATION: "invitation",
|
||||
CUSTOM: "custom",
|
||||
}
|
||||
|
||||
exports.TemplatePurposePretty = [
|
||||
{
|
||||
name: "Password Recovery",
|
||||
value: exports.TemplatePurpose.PASSWORD_RECOVERY,
|
||||
},
|
||||
{
|
||||
name: "New User Invitation",
|
||||
value: exports.TemplatePurpose.INVITATION,
|
||||
},
|
||||
{
|
||||
name: "Custom",
|
||||
value: exports.TemplatePurpose.CUSTOM,
|
||||
},
|
||||
]
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
exports.StaticDatabases = {
|
||||
USER: {
|
||||
name: "user-db",
|
||||
},
|
||||
}
|
||||
|
||||
const DocumentTypes = {
|
||||
USER: "us",
|
||||
APP: "app",
|
||||
}
|
||||
|
||||
exports.DocumentTypes = DocumentTypes
|
||||
|
||||
const UNICODE_MAX = "\ufff0"
|
||||
const SEPARATOR = "_"
|
||||
|
||||
/**
|
||||
* Generates a new user ID based on the passed in email.
|
||||
* @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.
|
||||
*/
|
||||
exports.generateUserID = email => {
|
||||
return `${DocumentTypes.USER}${SEPARATOR}${email}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets parameters for retrieving users, this is a utility function for the getDocParams function.
|
||||
*/
|
||||
exports.getUserParams = (email = "", otherProps = {}) => {
|
||||
return {
|
||||
...otherProps,
|
||||
startkey: `${DocumentTypes.USER}${SEPARATOR}${email}`,
|
||||
endkey: `${DocumentTypes.USER}${SEPARATOR}${email}${UNICODE_MAX}`,
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ require("@budibase/auth").init(CouchDB)
|
|||
const Koa = require("koa")
|
||||
const destroyable = require("server-destroy")
|
||||
const koaBody = require("koa-body")
|
||||
const { passport } = require("@budibase/auth")
|
||||
const { passport } = require("@budibase/auth").auth
|
||||
const logger = require("koa-pino-logger")
|
||||
const http = require("http")
|
||||
const api = require("./api")
|
||||
|
|
Loading…
Reference in New Issue