Shifting over all of self API, deprecating old endpoints.

This commit is contained in:
mike12345567 2022-02-14 18:11:35 +00:00
parent c83e25fb59
commit edd4a3233e
9 changed files with 124 additions and 98 deletions

View File

@ -15,7 +15,7 @@ export const buildUserEndpoints = API => ({
*/
fetchBuilderSelf: async () => {
return await API.get({
url: "/api/global/users/self",
url: "/api/global/self",
})
},
@ -67,7 +67,7 @@ export const buildUserEndpoints = API => ({
*/
updateSelf: async user => {
return await API.post({
url: "/api/global/users/self",
url: "/api/global/self",
body: user,
})
},

View File

@ -59,7 +59,7 @@ exports.sendSmtpEmail = async (to, from, subject, contents, automation) => {
}
exports.getGlobalSelf = async (ctx, appId = null) => {
const endpoint = `/api/global/users/self`
const endpoint = `/api/global/self`
const response = await fetch(
checkSlashesInUrl(env.WORKER_URL + endpoint),
// we don't want to use API key when getting self

View File

@ -1,9 +1,12 @@
const { getGlobalDB, getTenantId } = require("@budibase/backend-core/tenancy")
const { generateDevInfoID, SEPARATOR } = require("@budibase/backend-core/db")
const { user: userCache } = require("@budibase/backend-core/cache")
const { hash, platformLogout } = require("@budibase/backend-core/utils")
const { newid } = require("@budibase/backend-core/utils")
const { getUser } = require("../../utilities")
function newApiKey() {
return `${getTenantId()}${SEPARATOR}${newid()}`
return hash(`${getTenantId()}${SEPARATOR}${newid()}`)
}
function cleanupDevInfo(info) {
@ -43,3 +46,49 @@ exports.fetchAPIKey = async ctx => {
}
ctx.body = cleanupDevInfo(devInfo)
}
exports.getSelf = async ctx => {
if (!ctx.user) {
ctx.throw(403, "User not logged in")
}
const userId = ctx.user._id
ctx.params = {
id: userId,
}
// get the main body of the user
ctx.body = await getUser(userId)
// forward session information not found in db
ctx.body.account = ctx.user.account
ctx.body.budibaseAccess = ctx.user.budibaseAccess
ctx.body.accountPortalAccess = ctx.user.accountPortalAccess
ctx.body.csrfToken = ctx.user.csrfToken
}
exports.updateSelf = async ctx => {
const db = getGlobalDB()
const user = await db.get(ctx.user._id)
if (ctx.request.body.password) {
// changing password
ctx.request.body.password = await hash(ctx.request.body.password)
// Log all other sessions out apart from the current one
await platformLogout({
ctx,
userId: ctx.user._id,
keepActiveSession: true,
})
}
// don't allow sending up an ID/Rev, always use the existing one
delete ctx.request.body._id
delete ctx.request.body._rev
// don't allow setting the csrf token
delete ctx.request.body.csrfToken
const response = await db.put({
...user,
...ctx.request.body,
})
await userCache.invalidateUser(user._id)
ctx.body = {
_id: response.id,
_rev: response.rev,
}
}

View File

@ -4,10 +4,8 @@ const {
generateNewUsageQuotaDoc,
} = require("@budibase/backend-core/db")
const {
hash,
getGlobalUserByEmail,
saveUser,
platformLogout,
} = require("@budibase/backend-core/utils")
const { EmailTemplatePurpose } = require("../../../constants")
const { checkInviteCode } = require("../../../utilities/redis")
@ -24,7 +22,7 @@ const {
const { removeUserFromInfoDB } = require("@budibase/backend-core/deprovision")
const env = require("../../../environment")
const { syncUserInApps } = require("../../../utilities/appService")
const { allUsers } = require("../../utilities")
const { allUsers, getUser } = require("../../utilities")
exports.save = async ctx => {
try {
@ -129,52 +127,6 @@ exports.destroy = async ctx => {
}
}
exports.getSelf = async ctx => {
if (!ctx.user) {
ctx.throw(403, "User not logged in")
}
ctx.params = {
id: ctx.user._id,
}
// this will set the body
await exports.find(ctx)
// forward session information not found in db
ctx.body.account = ctx.user.account
ctx.body.budibaseAccess = ctx.user.budibaseAccess
ctx.body.accountPortalAccess = ctx.user.accountPortalAccess
ctx.body.csrfToken = ctx.user.csrfToken
}
exports.updateSelf = async ctx => {
const db = getGlobalDB()
const user = await db.get(ctx.user._id)
if (ctx.request.body.password) {
// changing password
ctx.request.body.password = await hash(ctx.request.body.password)
// Log all other sessions out apart from the current one
await platformLogout({
ctx,
userId: ctx.user._id,
keepActiveSession: true,
})
}
// don't allow sending up an ID/Rev, always use the existing one
delete ctx.request.body._id
delete ctx.request.body._rev
// don't allow setting the csrf token
delete ctx.request.body.csrfToken
const response = await db.put({
...user,
...ctx.request.body,
})
await userCache.invalidateUser(user._id)
ctx.body = {
_id: response.id,
_rev: response.rev,
}
}
// called internally by app server user fetch
exports.fetch = async ctx => {
const users = await allUsers(ctx)
@ -189,18 +141,7 @@ exports.fetch = async ctx => {
// called internally by app server user find
exports.find = async ctx => {
const db = getGlobalDB()
let user
try {
user = await db.get(ctx.params.id)
} catch (err) {
// no user found, just return nothing
user = {}
}
if (user) {
delete user.password
}
ctx.body = user
ctx.body = await getUser(ctx.params.id)
}
exports.tenantUserLookup = async ctx => {

View File

@ -67,6 +67,10 @@ const NO_TENANCY_ENDPOINTS = [
route: "/api/global/users/self",
method: "GET",
},
{
route: "/api/global/self",
method: "GET",
},
]
// most public endpoints are gets, but some are posts

View File

@ -1,11 +1,18 @@
const Router = require("@koa/router")
const controller = require("../../controllers/global/self")
const builderOnly = require("../../../middleware/builderOnly")
const { buildUserSaveValidation } = require("../../utilities/validation")
const router = Router()
router
.post("/api/global/self/api_key", builderOnly, controller.generateAPIKey)
.get("/api/global/self/api_key", builderOnly, controller.fetchAPIKey)
.get("/api/global/self", controller.getSelf)
.post(
"/api/global/self",
buildUserSaveValidation(true),
controller.updateSelf
)
module.exports = router

View File

@ -4,6 +4,8 @@ const joiValidator = require("../../../middleware/joi-validator")
const adminOnly = require("../../../middleware/adminOnly")
const Joi = require("joi")
const cloudRestricted = require("../../../middleware/cloudRestricted")
const { buildUserSaveValidation } = require("../../utilities/validation")
const selfController = require("../../controllers/global/self")
const router = Router()
@ -19,32 +21,6 @@ function buildAdminInitValidation() {
)
}
function buildUserSaveValidation(isSelf = false) {
let schema = {
email: Joi.string().allow(null, ""),
password: Joi.string().allow(null, ""),
forceResetPassword: Joi.boolean().optional(),
firstName: Joi.string().allow(null, ""),
lastName: Joi.string().allow(null, ""),
builder: Joi.object({
global: Joi.boolean().optional(),
apps: Joi.array().optional(),
})
.unknown(true)
.optional(),
// maps appId -> roleId for the user
roles: Joi.object().pattern(/.*/, Joi.string()).required().unknown(true),
}
if (!isSelf) {
schema = {
...schema,
_id: Joi.string(),
_rev: Joi.string(),
}
}
return joiValidator.body(Joi.object(schema).required().unknown(true))
}
function buildInviteValidation() {
// prettier-ignore
return joiValidator.body(Joi.object({
@ -78,11 +54,6 @@ router
controller.invite
)
// non-global endpoints
.post(
"/api/global/users/self",
buildUserSaveValidation(true),
controller.updateSelf
)
.post(
"/api/global/users/invite/accept",
buildInviteAcceptValidation(),
@ -94,10 +65,15 @@ router
buildAdminInitValidation(),
controller.adminUser
)
.get("/api/global/users/self", controller.getSelf)
.get("/api/global/users/tenant/:id", controller.tenantUserLookup)
// global endpoint but needs to come at end (blocks other endpoints otherwise)
.get("/api/global/users/:id", adminOnly, controller.find)
// DEPRECATED - use new versions with self API
.get("/api/global/users/self", selfController.getSelf)
.post(
"/api/global/users/self",
buildUserSaveValidation(true),
selfController.updateSelf
)
module.exports = router

View File

@ -1,6 +1,9 @@
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
const { getGlobalUserParams } = require("@budibase/backend-core/db")
/**
* Retrieves all users from the current tenancy.
*/
exports.allUsers = async () => {
const db = getGlobalDB()
const response = await db.allDocs(
@ -10,3 +13,21 @@ exports.allUsers = async () => {
)
return response.rows.map(row => row.doc)
}
/**
* Gets a user by ID from the global database, based on the current tenancy.
*/
exports.getUser = async userId => {
const db = getGlobalDB()
let user
try {
user = await db.get(userId)
} catch (err) {
// no user found, just return nothing
user = {}
}
if (user) {
delete user.password
}
return user
}

View File

@ -0,0 +1,28 @@
const joiValidator = require("../../middleware/joi-validator")
const Joi = require("joi")
exports.buildUserSaveValidation = (isSelf = false) => {
let schema = {
email: Joi.string().allow(null, ""),
password: Joi.string().allow(null, ""),
forceResetPassword: Joi.boolean().optional(),
firstName: Joi.string().allow(null, ""),
lastName: Joi.string().allow(null, ""),
builder: Joi.object({
global: Joi.boolean().optional(),
apps: Joi.array().optional(),
})
.unknown(true)
.optional(),
// maps appId -> roleId for the user
roles: Joi.object().pattern(/.*/, Joi.string()).required().unknown(true),
}
if (!isSelf) {
schema = {
...schema,
_id: Joi.string(),
_rev: Joi.string(),
}
}
return joiValidator.body(Joi.object(schema).required().unknown(true))
}