Day pass middleware

This commit is contained in:
Rory Powell 2022-09-06 12:25:57 +01:00
parent a0e79bf9d5
commit ba211b8490
9 changed files with 68 additions and 29 deletions

View File

@ -10,6 +10,7 @@ import { getGlobalDB, doInTenant } from "../tenancy"
import { decrypt } from "../security/encryption" import { decrypt } from "../security/encryption"
const identity = require("../context/identity") const identity = require("../context/identity")
const env = require("../environment") const env = require("../environment")
import { User } from "@budibase/types"
const ONE_MINUTE = env.SESSION_UPDATE_PERIOD || 60 * 1000 const ONE_MINUTE = env.SESSION_UPDATE_PERIOD || 60 * 1000
@ -67,7 +68,11 @@ async function checkApiKey(apiKey: string, populateUser?: Function) {
*/ */
export = ( export = (
noAuthPatterns = [], noAuthPatterns = [],
opts: { publicAllowed: boolean; populateUser?: Function } = { opts: {
publicAllowed: boolean
populateUser?: Function
checkDayPass?: (ctx: any, user: User, tenantId: string) => Promise<void>
} = {
publicAllowed: false, publicAllowed: false,
} }
) => { ) => {
@ -106,7 +111,16 @@ export = (
user = await getUser(userId, session.tenantId) user = await getUser(userId, session.tenantId)
} }
user.csrfToken = session.csrfToken user.csrfToken = session.csrfToken
if (session?.lastAccessedAt < timeMinusOneMinute()) {
// check day passes for the current user
if (opts.checkDayPass) {
await opts.checkDayPass(ctx, user, session.tenantId)
}
if (
!session.lastAccessedAt ||
session.lastAccessedAt < timeMinusOneMinute()
) {
// make sure we denote that the session is still in use // make sure we denote that the session is still in use
await updateSessionTTL(session) await updateSessionTTL(session)
} }

View File

@ -2,28 +2,12 @@ const redis = require("../redis/init")
const { v4: uuidv4 } = require("uuid") const { v4: uuidv4 } = require("uuid")
const { logWarn } = require("../logging") const { logWarn } = require("../logging")
const env = require("../environment") const env = require("../environment")
import {
interface CreateSession { Session,
sessionId: string ScannedSession,
tenantId: string SessionKey,
csrfToken?: string CreateSession,
} } from "@budibase/types"
interface Session extends CreateSession {
userId: string
lastAccessedAt: string
createdAt: string
// make optional attributes required
csrfToken: string
}
interface SessionKey {
key: string
}
interface ScannedSession {
value: Session
}
// a week in seconds // a week in seconds
const EXPIRY_SECONDS = 86400 * 7 const EXPIRY_SECONDS = 86400 * 7

View File

@ -13,7 +13,9 @@ import { User } from "@budibase/types"
* all the users to find one with this email address. * all the users to find one with this email address.
* @param {string} email the email to lookup the user by. * @param {string} email the email to lookup the user by.
*/ */
export const getGlobalUserByEmail = async (email: String) => { export const getGlobalUserByEmail = async (
email: String
): Promise<User | undefined> => {
if (email == null) { if (email == null) {
throw "Must supply an email address to view" throw "Must supply an email address to view"
} }

View File

@ -42,6 +42,18 @@ async function resolveAppUrl(ctx) {
return app && app.appId ? app.appId : undefined return app && app.appId ? app.appId : undefined
} }
exports.isServingApp = ctx => {
// dev app
if (ctx.path.startsWith(`/${APP_PREFIX}`)) {
return true
}
// prod app
if (ctx.path.startsWith(PROD_APP_PREFIX)) {
return true
}
return false
}
/** /**
* Given a request tries to find the appId, which can be located in various places * Given a request tries to find the appId, which can be located in various places
* @param {object} ctx The main request body to look through. * @param {object} ctx The main request body to look through.

View File

@ -18,7 +18,6 @@ const { DocumentType } = require("../../../db/utils")
const { getAppDB, getAppId } = require("@budibase/backend-core/context") const { getAppDB, getAppId } = require("@budibase/backend-core/context")
const { setCookie, clearCookie } = require("@budibase/backend-core/utils") const { setCookie, clearCookie } = require("@budibase/backend-core/utils")
const AWS = require("aws-sdk") const AWS = require("aws-sdk")
const fs = require("fs") const fs = require("fs")
const { const {
downloadTarballDirect, downloadTarballDirect,

View File

@ -11,7 +11,7 @@ const zlib = require("zlib")
const { mainRoutes, staticRoutes, publicRoutes } = require("./routes") const { mainRoutes, staticRoutes, publicRoutes } = require("./routes")
const pkg = require("../../package.json") const pkg = require("../../package.json")
const env = require("../environment") const env = require("../environment")
const { middleware: pro } = require("@budibase/pro") const { middleware: pro, quotas } = require("@budibase/pro")
const { shutdown } = require("./routes/public") const { shutdown } = require("./routes/public")
const router = new Router() const router = new Router()
@ -44,6 +44,7 @@ router
.use( .use(
buildAuthMiddleware(null, { buildAuthMiddleware(null, {
publicAllowed: true, publicAllowed: true,
checkDayPass: quotas.checkDayPass,
}) })
) )
// nothing in the server should allow query string tenants // nothing in the server should allow query string tenants

View File

@ -16,6 +16,7 @@ export interface User extends Document {
createdAt?: number // override the default createdAt behaviour - users sdk historically set this to Date.now() createdAt?: number // override the default createdAt behaviour - users sdk historically set this to Date.now()
userGroups?: string[] userGroups?: string[]
forceResetPassword?: boolean forceResetPassword?: boolean
dayPassRecordedAt?: string
} }
export interface UserRoles { export interface UserRoles {

View File

@ -3,3 +3,25 @@ export interface AuthToken {
tenantId: string tenantId: string
sessionId: string sessionId: string
} }
export interface CreateSession {
sessionId: string
tenantId: string
csrfToken?: string
}
export interface Session extends CreateSession {
userId: string
lastAccessedAt: string
createdAt: string
// make optional attributes required
csrfToken: string
}
export interface SessionKey {
key: string
}
export interface ScannedSession {
value: Session
}

View File

@ -2,7 +2,7 @@ import Router from "@koa/router"
const compress = require("koa-compress") const compress = require("koa-compress")
const zlib = require("zlib") const zlib = require("zlib")
import { routes } from "./routes" import { routes } from "./routes"
import { middleware as pro } from "@budibase/pro" import { middleware as pro, quotas } from "@budibase/pro"
import { errors, auth, middleware } from "@budibase/backend-core" import { errors, auth, middleware } from "@budibase/backend-core"
import { APIError } from "@budibase/types" import { APIError } from "@budibase/types"
@ -92,7 +92,11 @@ router
}) })
) )
.use("/health", ctx => (ctx.status = 200)) .use("/health", ctx => (ctx.status = 200))
.use(auth.buildAuthMiddleware(PUBLIC_ENDPOINTS)) .use(
auth.buildAuthMiddleware(PUBLIC_ENDPOINTS, {
checkDayPass: quotas.checkDayPass,
})
)
.use(auth.buildTenancyMiddleware(PUBLIC_ENDPOINTS, NO_TENANCY_ENDPOINTS)) .use(auth.buildTenancyMiddleware(PUBLIC_ENDPOINTS, NO_TENANCY_ENDPOINTS))
.use(auth.buildCsrfMiddleware({ noCsrfPatterns: NO_CSRF_ENDPOINTS })) .use(auth.buildCsrfMiddleware({ noCsrfPatterns: NO_CSRF_ENDPOINTS }))
.use(pro.licensing()) .use(pro.licensing())