Updating test cases and some re-work of the email system.

This commit is contained in:
mike12345567 2021-04-23 18:07:39 +01:00
parent 6564c85a30
commit d985d338ec
18 changed files with 139 additions and 58 deletions

View File

@ -36,7 +36,7 @@ module.exports = {
buildAuthMiddleware: authenticated, buildAuthMiddleware: authenticated,
passport, passport,
google, google,
jwt, jwt: require("jsonwebtoken"),
}, },
StaticDatabases, StaticDatabases,
constants: require("./constants"), constants: require("./constants"),

View File

@ -1,6 +1,6 @@
const { Cookies } = require("../constants") const { Cookies } = require("../constants")
const database = require("../db") const database = require("../db")
const { getCookie } = require("../utils") const { getCookie, clearCookie } = require("../utils")
const { StaticDatabases } = require("../db/utils") const { StaticDatabases } = require("../db/utils")
module.exports = (noAuthPatterns = []) => { module.exports = (noAuthPatterns = []) => {
@ -15,11 +15,20 @@ module.exports = (noAuthPatterns = []) => {
const authCookie = getCookie(ctx, Cookies.Auth) const authCookie = getCookie(ctx, Cookies.Auth)
if (authCookie) { if (authCookie) {
const db = database.getDB(StaticDatabases.GLOBAL.name) try {
const user = await db.get(authCookie.userId) const db = database.getDB(StaticDatabases.GLOBAL.name)
delete user.password const user = await db.get(authCookie.userId)
ctx.isAuthenticated = true delete user.password
ctx.user = user ctx.isAuthenticated = true
ctx.user = user
} catch (err) {
// remove the cookie as the use does not exist anymore
clearCookie(ctx, Cookies.Auth)
}
}
// be explicit
if (ctx.isAuthenticated !== true) {
ctx.isAuthenticated = false
} }
return next() return next()

View File

@ -92,7 +92,7 @@ exports.setCookie = (ctx, value, name = "builder") => {
* Utility function, simply calls setCookie with an empty string for value * Utility function, simply calls setCookie with an empty string for value
*/ */
exports.clearCookie = (ctx, name) => { exports.clearCookie = (ctx, name) => {
exports.setCookie(ctx, "", name) exports.setCookie(ctx, null, name)
} }
/** /**

View File

@ -93,7 +93,7 @@ describe("/queries", () => {
const query = await config.createQuery() const query = await config.createQuery()
const res = await request const res = await request
.get(`/api/queries/${query._id}`) .get(`/api/queries/${query._id}`)
.set(await config.roleHeaders()) .set(await config.roleHeaders({}))
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200)
expect(res.body.fields).toBeUndefined() expect(res.body.fields).toBeUndefined()

View File

@ -35,7 +35,11 @@ describe("/routing", () => {
}) })
const res = await request const res = await request
.get(`/api/routing/client`) .get(`/api/routing/client`)
.set(await config.roleHeaders("basic@test.com", BUILTIN_ROLE_IDS.BASIC)) .set(await config.roleHeaders({
email: "basic@test.com",
roleId: BUILTIN_ROLE_IDS.BASIC,
builder: false
}))
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200)
expect(res.body.routes).toBeDefined() expect(res.body.routes).toBeDefined()
@ -59,7 +63,11 @@ describe("/routing", () => {
}) })
const res = await request const res = await request
.get(`/api/routing/client`) .get(`/api/routing/client`)
.set(await config.roleHeaders("basic@test.com", BUILTIN_ROLE_IDS.POWER)) .set(await config.roleHeaders({
email: "basic@test.com",
roleId: BUILTIN_ROLE_IDS.POWER,
builder: false,
}))
.expect("Content-Type", /json/) .expect("Content-Type", /json/)
.expect(200) .expect(200)
expect(res.body.routes).toBeDefined() expect(res.body.routes).toBeDefined()

View File

@ -5,7 +5,9 @@ const { basicUser } = setup.structures
const workerRequests = require("../../../utilities/workerRequests") const workerRequests = require("../../../utilities/workerRequests")
jest.mock("../../../utilities/workerRequests", () => ({ jest.mock("../../../utilities/workerRequests", () => ({
getGlobalUsers: jest.fn(), getGlobalUsers: jest.fn(() => {
return {}
}),
saveGlobalUser: jest.fn(() => { saveGlobalUser: jest.fn(() => {
const uuid = require("uuid/v4") const uuid = require("uuid/v4")
return { return {

View File

@ -46,7 +46,10 @@ exports.createRequest = (request, method, url, body) => {
} }
exports.checkBuilderEndpoint = async ({ config, method, url, body }) => { exports.checkBuilderEndpoint = async ({ config, method, url, body }) => {
const headers = await config.login() const headers = await config.login("test@test.com", "test", {
userId: "us_fail",
builder: false,
})
await exports await exports
.createRequest(config.request, method, url, body) .createRequest(config.request, method, url, body)
.set(headers) .set(headers)
@ -62,9 +65,10 @@ exports.checkPermissionsEndpoint = async ({
failRole, failRole,
}) => { }) => {
const password = "PASSWORD" const password = "PASSWORD"
await config.createUser("passUser@budibase.com", password, passRole) let user = await config.createUser("pass@budibase.com", password, passRole)
const passHeader = await config.login("passUser@budibase.com", password, { const passHeader = await config.login("pass@budibase.com", password, {
roleId: passRole, roleId: passRole,
userId: user.globalId,
}) })
await exports await exports
@ -72,9 +76,10 @@ exports.checkPermissionsEndpoint = async ({
.set(passHeader) .set(passHeader)
.expect(200) .expect(200)
await config.createUser("failUser@budibase.com", password, failRole) user = await config.createUser("fail@budibase.com", password, failRole)
const failHeader = await config.login("failUser@budibase.com", password, { const failHeader = await config.login("fail@budibase.com", password, {
roleId: failRole, roleId: failRole,
userId: user.globalId,
}) })
await exports await exports

View File

@ -3,10 +3,7 @@ const { Cookies } = require("@budibase/auth").constants
const { getRole } = require("../utilities/security/roles") const { getRole } = require("../utilities/security/roles")
const { getGlobalUsers } = require("../utilities/workerRequests") const { getGlobalUsers } = require("../utilities/workerRequests")
const { BUILTIN_ROLE_IDS } = require("../utilities/security/roles") const { BUILTIN_ROLE_IDS } = require("../utilities/security/roles")
const { const { generateUserMetadataID } = require("../db/utils")
getGlobalIDFromUserMetadataID,
generateUserMetadataID,
} = require("../db/utils")
module.exports = async (ctx, next) => { module.exports = async (ctx, next) => {
// try to get the appID from the request // try to get the appID from the request
@ -31,8 +28,7 @@ module.exports = async (ctx, next) => {
appCookie.roleId === BUILTIN_ROLE_IDS.PUBLIC) appCookie.roleId === BUILTIN_ROLE_IDS.PUBLIC)
) { ) {
// Different App ID means cookie needs reset, or if the same public user has logged in // Different App ID means cookie needs reset, or if the same public user has logged in
const globalId = getGlobalIDFromUserMetadataID(ctx.user._id) const globalUser = await getGlobalUsers(ctx, requestAppId, ctx.user._id)
const globalUser = await getGlobalUsers(ctx, requestAppId, globalId)
updateCookie = true updateCookie = true
appId = requestAppId appId = requestAppId
if (globalUser.roles && globalUser.roles[requestAppId]) { if (globalUser.roles && globalUser.roles[requestAppId]) {

View File

@ -5,7 +5,7 @@ function mockWorker() {
jest.mock("../../utilities/workerRequests", () => ({ jest.mock("../../utilities/workerRequests", () => ({
getGlobalUsers: () => { getGlobalUsers: () => {
return { return {
email: "us_uuid1", _id: "us_uuid1",
roles: { roles: {
"app_test": "BASIC", "app_test": "BASIC",
} }
@ -67,7 +67,8 @@ class TestConfiguration {
setUser() { setUser() {
this.ctx.user = { this.ctx.user = {
userId: "ro_ta_user_us_uuid1", userId: "us_uuid1",
_id: "us_uuid1",
} }
} }
@ -159,5 +160,4 @@ describe("Current app middleware", () => {
await checkExpected(false) await checkExpected(false)
}) })
}) })
})
})

View File

@ -16,7 +16,10 @@ const supertest = require("supertest")
const { cleanup } = require("../../utilities/fileSystem") const { cleanup } = require("../../utilities/fileSystem")
const { Cookies } = require("@budibase/auth").constants const { Cookies } = require("@budibase/auth").constants
const { jwt } = require("@budibase/auth").auth const { jwt } = require("@budibase/auth").auth
const { StaticDatabases } = require("@budibase/auth").db
const CouchDB = require("../../db")
const GLOBAL_USER_ID = "us_uuid1"
const EMAIL = "babs@babs.com" const EMAIL = "babs@babs.com"
const PASSWORD = "babs_password" const PASSWORD = "babs_password"
@ -57,7 +60,27 @@ class TestConfiguration {
return request.body return request.body
} }
async globalUser(id = GLOBAL_USER_ID, builder = true) {
const db = new CouchDB(StaticDatabases.GLOBAL.name)
let existing
try {
existing = await db.get(id)
} catch (err) {
existing = {}
}
const user = {
_id: id,
...existing,
roles: {},
}
if (builder) {
user.builder = { global: true }
}
await db.put(user)
}
async init(appName = "test_application") { async init(appName = "test_application") {
await this.globalUser()
return this.createApp(appName) return this.createApp(appName)
} }
@ -69,17 +92,14 @@ class TestConfiguration {
} }
defaultHeaders() { defaultHeaders() {
const user = { const auth = {
userId: "ro_ta_user_us_uuid1", userId: GLOBAL_USER_ID,
builder: {
global: true,
},
} }
const app = { const app = {
roleId: BUILTIN_ROLE_IDS.BUILDER, roleId: BUILTIN_ROLE_IDS.BUILDER,
appId: this.appId, appId: this.appId,
} }
const authToken = jwt.sign(user, env.JWT_SECRET) const authToken = jwt.sign(auth, env.JWT_SECRET)
const appToken = jwt.sign(app, env.JWT_SECRET) const appToken = jwt.sign(app, env.JWT_SECRET)
const headers = { const headers = {
Accept: "application/json", Accept: "application/json",
@ -104,14 +124,18 @@ class TestConfiguration {
return headers return headers
} }
async roleHeaders(email = EMAIL, roleId = BUILTIN_ROLE_IDS.ADMIN) { async roleHeaders({
email = EMAIL,
roleId = BUILTIN_ROLE_IDS.ADMIN,
builder = false,
}) {
let user let user
try { try {
user = await this.createUser(email, PASSWORD, roleId) user = await this.createUser(email, PASSWORD, roleId)
} catch (err) { } catch (err) {
// allow errors here // allow errors here
} }
return this.login(email, PASSWORD, { roleId, userId: user._id }) return this.login(email, PASSWORD, { roleId, userId: user._id, builder })
} }
async createApp(appName) { async createApp(appName) {
@ -282,7 +306,9 @@ class TestConfiguration {
password = PASSWORD, password = PASSWORD,
roleId = BUILTIN_ROLE_IDS.POWER roleId = BUILTIN_ROLE_IDS.POWER
) { ) {
return this._req( const globalId = `us_${Math.random()}`
await this.globalUser(globalId, roleId === BUILTIN_ROLE_IDS.BUILDER)
const user = await this._req(
{ {
email, email,
password, password,
@ -291,28 +317,34 @@ class TestConfiguration {
null, null,
controllers.user.createMetadata controllers.user.createMetadata
) )
return {
...user,
globalId,
}
} }
async login(email, password, { roleId, userId } = {}) { async login(email, password, { roleId, userId, builder } = {}) {
if (!roleId) { roleId = !roleId ? BUILTIN_ROLE_IDS.BUILDER : roleId
roleId = BUILTIN_ROLE_IDS.BUILDER userId = !userId ? `us_uuid1` : userId
}
if (!this.request) { if (!this.request) {
throw "Server has not been opened, cannot login." throw "Server has not been opened, cannot login."
} }
// make sure the user exists in the global DB
if (roleId !== BUILTIN_ROLE_IDS.PUBLIC) {
await this.globalUser(userId, builder)
}
if (!email || !password) { if (!email || !password) {
await this.createUser() await this.createUser()
} }
// have to fake this // have to fake this
const user = { const auth = {
userId: userId || `us_uuid1`, userId,
email: email || EMAIL,
} }
const app = { const app = {
roleId: roleId, roleId: roleId,
appId: this.appId, appId: this.appId,
} }
const authToken = jwt.sign(user, env.JWT_SECRET) const authToken = jwt.sign(auth, env.JWT_SECRET)
const appToken = jwt.sign(app, env.JWT_SECRET) const appToken = jwt.sign(app, env.JWT_SECRET)
// returning necessary request headers // returning necessary request headers

View File

@ -66,5 +66,9 @@ exports.sendEmail = async ctx => {
to: email, to: email,
html: await buildEmail(purpose, email, user), html: await buildEmail(purpose, email, user),
} }
await transport.sendMail(message) const response = await transport.sendMail(message)
ctx.body = {
...response,
message: `Email sent to ${email}.`,
}
} }

View File

@ -23,6 +23,13 @@ router
) )
.use("/health", ctx => (ctx.status = 200)) .use("/health", ctx => (ctx.status = 200))
.use(buildAuthMiddleware(NO_AUTH_ENDPOINTS)) .use(buildAuthMiddleware(NO_AUTH_ENDPOINTS))
// for now no public access is allowed to worker (bar health check)
.use((ctx, next) => {
if (!ctx.isAuthenticated) {
ctx.throw(403, "Unauthorized - no public worker access")
}
return next()
})
// error handling middleware // error handling middleware
router.use(async (ctx, next) => { router.use(async (ctx, next) => {

View File

@ -27,3 +27,5 @@ router
.get("/api/admin/template/:ownerId", controller.fetchByOwner) .get("/api/admin/template/:ownerId", controller.fetchByOwner)
.get("/api/admin/template/:id", controller.find) .get("/api/admin/template/:id", controller.find)
.delete("/api/admin/template/:id/:rev", controller.destroy) .delete("/api/admin/template/:id/:rev", controller.destroy)
module.exports = router

View File

@ -1,7 +1,17 @@
const userRoutes = require("./admin/users") const userRoutes = require("./admin/users")
const configRoutes = require("./admin/configs") const configRoutes = require("./admin/configs")
const groupRoutes = require("./admin/groups") const groupRoutes = require("./admin/groups")
const templateRoutes = require("./admin/templates")
const emailRoutes = require("./admin/email")
const authRoutes = require("./auth") const authRoutes = require("./auth")
const appRoutes = require("./app") const appRoutes = require("./app")
exports.routes = [configRoutes, userRoutes, groupRoutes, authRoutes, appRoutes] exports.routes = [
configRoutes,
userRoutes,
groupRoutes,
authRoutes,
appRoutes,
templateRoutes,
emailRoutes
]

View File

@ -36,12 +36,20 @@ class TestConfiguration {
return request.body return request.body
} }
defaultHeaders() { async init() {
const user = { // create a test user
userId: "us_uuid1", await this._req({
_id: "us_uuid1",
builder: { builder: {
global: true, global: true,
}, }
}, null, controllers.users.save)
}
defaultHeaders() {
const user = {
_id: "us_uuid1",
userId: "us_uuid1",
} }
const authToken = jwt.sign(user, env.JWT_SECRET) const authToken = jwt.sign(user, env.JWT_SECRET)
return { return {

View File

@ -8,18 +8,16 @@ const { join } = require("path")
const CouchDB = require("../../db") const CouchDB = require("../../db")
const { getTemplateParams, StaticDatabases } = require("@budibase/auth").db const { getTemplateParams, StaticDatabases } = require("@budibase/auth").db
const TEMPLATE_PATH = join(__dirname, "..", "constants", "templates")
exports.EmailTemplates = { exports.EmailTemplates = {
[EmailTemplatePurpose.PASSWORD_RECOVERY]: readStaticFile( [EmailTemplatePurpose.PASSWORD_RECOVERY]: readStaticFile(
join(TEMPLATE_PATH, "passwordRecovery.html") join(__dirname, "passwordRecovery.html")
), ),
[EmailTemplatePurpose.INVITATION]: readStaticFile( [EmailTemplatePurpose.INVITATION]: readStaticFile(
join(TEMPLATE_PATH, "invitation.html") join(__dirname, "invitation.html")
), ),
[EmailTemplatePurpose.BASE]: readStaticFile(join(TEMPLATE_PATH, "base.html")), [EmailTemplatePurpose.BASE]: readStaticFile(join(__dirname, "base.html")),
[EmailTemplatePurpose.STYLES]: readStaticFile( [EmailTemplatePurpose.STYLES]: readStaticFile(
join(TEMPLATE_PATH, "style.css") join(__dirname, "style.css")
), ),
} }

View File

@ -1,6 +1,6 @@
const nodemailer = require("nodemailer") const nodemailer = require("nodemailer")
exports.createSMTPTransport = (config) => { exports.createSMTPTransport = config => {
const options = { const options = {
port: config.port, port: config.port,
host: config.host, host: config.host,

View File

@ -1,4 +1,4 @@
const CouchDB = require("../../../db") const CouchDB = require("../db")
const { getConfigParams, StaticDatabases } = require("@budibase/auth").db const { getConfigParams, StaticDatabases } = require("@budibase/auth").db
const { Configs, TemplateBindings, LOGO_URL } = require("../constants") const { Configs, TemplateBindings, LOGO_URL } = require("../constants")
const { checkSlashesInUrl } = require("./index") const { checkSlashesInUrl } = require("./index")