Adding sessions API.

This commit is contained in:
mike12345567 2021-07-07 23:29:19 +01:00
parent 278d984006
commit cc67e2caa6
8 changed files with 80 additions and 19 deletions

View File

@ -68,7 +68,7 @@ module.exports = (noAuthPatterns = [], opts) => {
clearCookie(ctx, Cookies.Auth)
} else {
// make sure we denote that the session is still in use
await updateSessionTTL(userId, sessionId)
await updateSessionTTL(session)
}
}
const apiKey = ctx.request.headers["x-budibase-api-key"]

View File

@ -62,14 +62,12 @@ async function authenticate(token, tokenSecret, profile, done) {
// authenticate
const sessionId = newid()
const payload = {
await createASession(dbUser._id, sessionId)
dbUser.token = jwt.sign({
userId: dbUser._id,
sessionId,
}
await createASession(dbUser._id, sessionId, payload)
dbUser.sessionId = sessionId
dbUser.token = jwt.sign(payload, env.JWT_SECRET)
}, env.JWT_SECRET)
return done(null, dbUser)
}

View File

@ -34,14 +34,12 @@ exports.authenticate = async function (email, password, done) {
// authenticate
if (await compare(password, dbUser.password)) {
const sessionId = newid()
const payload = {
await createASession(dbUser._id, sessionId)
dbUser.token = jwt.sign({
userId: dbUser._id,
sessionId,
}
await createASession(dbUser._id, sessionId, payload)
dbUser.sessionId = sessionId
dbUser.token = jwt.sign(payload, env.JWT_SECRET)
}, env.JWT_SECRET)
// Remove users password in payload
delete dbUser.password

View File

@ -4,16 +4,23 @@ const EXPIRY_SECONDS = 86400
async function getSessionsForUser(userId) {
const client = await redis.getSessionClient()
return client.scan(userId)
const sessions = await client.scan(userId)
return sessions.map(session => session.value)
}
function makeSessionID(userId, sessionId) {
return `${userId}/${sessionId}`
}
exports.createASession = async (userId, sessionId, token) => {
exports.createASession = async (userId, sessionId) => {
const client = await redis.getSessionClient()
await client.store(makeSessionID(userId, sessionId), token, EXPIRY_SECONDS)
const session = {
createdAt: (new Date()).toISOString(),
lastAccessedAt: (new Date()).toISOString(),
sessionId,
userId,
}
await client.store(makeSessionID(userId, sessionId), session, EXPIRY_SECONDS)
}
exports.invalidateSessions = async (userId, sessionId = null) => {
@ -31,9 +38,11 @@ exports.invalidateSessions = async (userId, sessionId = null) => {
await Promise.all(promises)
}
exports.updateSessionTTL = async (userId, sessionId) => {
exports.updateSessionTTL = async session => {
const client = await redis.getSessionClient()
await client.setExpiry(makeSessionID(userId, sessionId), EXPIRY_SECONDS)
const key = makeSessionID(session.userId, session.sessionId)
session.lastAccessedAt = (new Date()).toISOString()
await client.store(key, session, EXPIRY_SECONDS)
}
exports.endSession = async (userId, sessionId) => {
@ -41,6 +50,8 @@ exports.endSession = async (userId, sessionId) => {
await client.delete(makeSessionID(userId, sessionId))
}
exports.getUserSessions = getSessionsForUser
exports.getSession = async (userId, sessionId) => {
try {
const client = await redis.getSessionClient()
@ -53,5 +64,6 @@ exports.getSession = async (userId, sessionId) => {
exports.getAllSessions = async () => {
const client = await redis.getSessionClient()
return client.scan()
const sessions = await client.scan()
return sessions.map(session => session.value)
}

View File

@ -0,0 +1,33 @@
const { getAllSessions, getUserSessions, invalidateSessions } = require("@budibase/auth/sessions")
exports.fetch = async ctx => {
ctx.body = await getAllSessions()
}
exports.find = async ctx => {
const { userId } = ctx.params
const sessions = await getUserSessions(userId)
ctx.body = sessions.map(session => session.value)
}
exports.invalidateUser = async ctx => {
const { userId } = ctx.params
await invalidateSessions(userId)
ctx.body = {
message: "User sessions invalidated"
}
}
exports.selfSessions = async ctx => {
const userId = ctx.user._id
ctx.body = await getUserSessions(userId)
}
exports.invalidateSession = async ctx => {
const userId = ctx.user._id
const { sessionId } = ctx.params
await invalidateSessions(userId, sessionId)
ctx.body = {
message: "Session invalidated successfully."
}
}

View File

@ -122,13 +122,16 @@ exports.removeAppRole = async ctx => {
const db = new CouchDB(GLOBAL_DB)
const users = await allUsers()
const bulk = []
const cacheInvalidations = []
for (let user of users) {
if (user.roles[appId]) {
cacheInvalidations.push(userCache.invalidateUser(user._id))
delete user.roles[appId]
bulk.push(user)
}
}
await db.bulkDocs(bulk)
await Promise.all(cacheInvalidations)
ctx.body = {
message: "App role removed from all users",
}
@ -158,6 +161,7 @@ exports.updateSelf = async ctx => {
...user,
...ctx.request.body,
})
await userCache.invalidateUser(user._id)
ctx.body = {
_id: response.id,
_rev: response.rev,

View File

@ -0,0 +1,14 @@
const Router = require("@koa/router")
const controller = require("../../controllers/admin/sessions")
const adminOnly = require("../../../middleware/adminOnly")
const router = Router()
router
.get("/api/admin/sessions", adminOnly, controller.fetch)
.get("/api/admin/sessions/self", controller.selfSessions)
.get("/api/admin/sessions/:userId", adminOnly, controller.find)
.delete("/api/admin/sessions/:userId", adminOnly, controller.invalidateUser)
.delete("/api/admin/sessions/self/:sessionId", controller.invalidateSession)
module.exports = router

View File

@ -5,6 +5,7 @@ const templateRoutes = require("./admin/templates")
const emailRoutes = require("./admin/email")
const authRoutes = require("./admin/auth")
const roleRoutes = require("./admin/roles")
const sessionRoutes = require("./admin/sessions")
const appRoutes = require("./app")
exports.routes = [
@ -15,5 +16,6 @@ exports.routes = [
appRoutes,
templateRoutes,
emailRoutes,
sessionRoutes,
roleRoutes,
]