Some major reworks towards higher levels of typescript.

This commit is contained in:
mike12345567 2022-11-16 17:23:12 +00:00
parent c6366c573a
commit 535fab7997
48 changed files with 236 additions and 239 deletions

View File

@ -3,7 +3,7 @@ const LocalStrategy = require("passport-local").Strategy
const JwtStrategy = require("passport-jwt").Strategy const JwtStrategy = require("passport-jwt").Strategy
import { getGlobalDB } from "./tenancy" import { getGlobalDB } from "./tenancy"
const refresh = require("passport-oauth2-refresh") const refresh = require("passport-oauth2-refresh")
import { Configs } from "./constants" import { Config } from "./constants"
import { getScopedConfig } from "./db/utils" import { getScopedConfig } from "./db/utils"
import { import {
jwt, jwt,
@ -76,7 +76,7 @@ async function refreshOIDCAccessToken(
return new Promise(resolve => { return new Promise(resolve => {
refresh.requestNewAccessToken( refresh.requestNewAccessToken(
Configs.OIDC, Config.OIDC,
refreshToken, refreshToken,
(err: any, accessToken: string, refreshToken: any, params: any) => { (err: any, accessToken: string, refreshToken: any, params: any) => {
resolve({ err, accessToken, refreshToken, params }) resolve({ err, accessToken, refreshToken, params })
@ -106,7 +106,7 @@ async function refreshGoogleAccessToken(
return new Promise(resolve => { return new Promise(resolve => {
refresh.requestNewAccessToken( refresh.requestNewAccessToken(
Configs.GOOGLE, Config.GOOGLE,
refreshToken, refreshToken,
(err: any, accessToken: string, refreshToken: string, params: any) => { (err: any, accessToken: string, refreshToken: string, params: any) => {
resolve({ err, accessToken, refreshToken, params }) resolve({ err, accessToken, refreshToken, params })
@ -129,7 +129,7 @@ async function refreshOAuthToken(
let chosenConfig = {} let chosenConfig = {}
let refreshResponse let refreshResponse
if (configType === Configs.OIDC) { if (configType === Config.OIDC) {
// configId - retrieved from cookie. // configId - retrieved from cookie.
chosenConfig = config.configs.filter((c: any) => c.uuid === configId)[0] chosenConfig = config.configs.filter((c: any) => c.uuid === configId)[0]
if (!chosenConfig) { if (!chosenConfig) {

View File

@ -1,6 +1,6 @@
import API from "./api" import API from "./api"
import env from "../environment" import env from "../environment"
import { Headers } from "../constants" import { Header } from "../constants"
import { CloudAccount } from "@budibase/types" import { CloudAccount } from "@budibase/types"
const api = new API(env.ACCOUNT_PORTAL_URL) const api = new API(env.ACCOUNT_PORTAL_URL)
@ -14,7 +14,7 @@ export const getAccount = async (
const response = await api.post(`/api/accounts/search`, { const response = await api.post(`/api/accounts/search`, {
body: payload, body: payload,
headers: { headers: {
[Headers.API_KEY]: env.ACCOUNT_PORTAL_API_KEY, [Header.API_KEY]: env.ACCOUNT_PORTAL_API_KEY,
}, },
}) })
@ -35,7 +35,7 @@ export const getAccountByTenantId = async (
const response = await api.post(`/api/accounts/search`, { const response = await api.post(`/api/accounts/search`, {
body: payload, body: payload,
headers: { headers: {
[Headers.API_KEY]: env.ACCOUNT_PORTAL_API_KEY, [Header.API_KEY]: env.ACCOUNT_PORTAL_API_KEY,
}, },
}) })
@ -50,7 +50,7 @@ export const getAccountByTenantId = async (
export const getStatus = async () => { export const getStatus = async () => {
const response = await api.get(`/api/status`, { const response = await api.get(`/api/status`, {
headers: { headers: {
[Headers.API_KEY]: env.ACCOUNT_PORTAL_API_KEY, [Header.API_KEY]: env.ACCOUNT_PORTAL_API_KEY,
}, },
}) })
const json = await response.json() const json = await response.json()

View File

@ -1,44 +0,0 @@
exports.UserStatus = {
ACTIVE: "active",
INACTIVE: "inactive",
}
exports.Cookies = {
CurrentApp: "budibase:currentapp",
Auth: "budibase:auth",
Init: "budibase:init",
ACCOUNT_RETURN_URL: "budibase:account:returnurl",
DatasourceAuth: "budibase:datasourceauth",
OIDC_CONFIG: "budibase:oidc:config",
}
exports.Headers = {
API_KEY: "x-budibase-api-key",
LICENSE_KEY: "x-budibase-license-key",
API_VER: "x-budibase-api-version",
APP_ID: "x-budibase-app-id",
TYPE: "x-budibase-type",
PREVIEW_ROLE: "x-budibase-role",
TENANT_ID: "x-budibase-tenant-id",
TOKEN: "x-budibase-token",
CSRF_TOKEN: "x-csrf-token",
}
exports.GlobalRoles = {
OWNER: "owner",
ADMIN: "admin",
BUILDER: "builder",
WORKSPACE_MANAGER: "workspace_manager",
}
exports.Configs = {
SETTINGS: "settings",
ACCOUNT: "account",
SMTP: "smtp",
GOOGLE: "google",
OIDC: "oidc",
OIDC_LOGOS: "logos_oidc",
}
exports.MAX_VALID_DATE = new Date(2147483647000)
exports.DEFAULT_TENANT_ID = "default"

View File

@ -0,0 +1,44 @@
export enum UserStatus {
ACTIVE = "active",
INACTIVE = "inactive",
}
export enum Cookie {
CurrentApp = "budibase:currentapp",
Auth = "budibase:auth",
Init = "budibase:init",
ACCOUNT_RETURN_URL = "budibase:account:returnurl",
DatasourceAuth = "budibase:datasourceauth",
OIDC_CONFIG = "budibase:oidc:config",
}
export enum Header {
API_KEY = "x-budibase-api-key",
LICENSE_KEY = "x-budibase-license-key",
API_VER = "x-budibase-api-version",
APP_ID = "x-budibase-app-id",
TYPE = "x-budibase-type",
PREVIEW_ROLE = "x-budibase-role",
TENANT_ID = "x-budibase-tenant-id",
TOKEN = "x-budibase-token",
CSRF_TOKEN = "x-csrf-token",
}
export enum GlobalRole {
OWNER = "owner",
ADMIN = "admin",
BUILDER = "builder",
WORKSPACE_MANAGER = "workspace_manager",
}
export enum Config {
SETTINGS = "settings",
ACCOUNT = "account",
SMTP = "smtp",
GOOGLE = "google",
OIDC = "oidc",
OIDC_LOGOS = "logos_oidc",
}
export const MAX_VALID_DATE = new Date(2147483647000)
export const DEFAULT_TENANT_ID = "default"

View File

@ -105,11 +105,12 @@ export async function doInAppContext(appId: string, task: any): Promise<any> {
} }
const tenantId = getTenantIDFromAppID(appId) const tenantId = getTenantIDFromAppID(appId)
const updates: ContextMap = { appId }
if (tenantId) {
updates.tenantId = tenantId
}
return newContext( return newContext(
{ updates,
tenantId,
appId,
},
task task
) )
} }

View File

@ -1,8 +1,7 @@
require("../../../tests/utilities/TestConfiguration") require("../../../tests")
const context = require("../") const context = require("../")
const { DEFAULT_TENANT_ID } = require("../../constants") const { DEFAULT_TENANT_ID } = require("../../constants")
const env = require("../../environment") const env = require("../../environment")
const dbCore = require("../../db")
describe("context", () => { describe("context", () => {
describe("doInTenant", () => { describe("doInTenant", () => {

View File

@ -9,7 +9,7 @@ const {
getScopedConfig getScopedConfig
} = require("../utils") } = require("../utils")
const tenancy = require("../../tenancy") const tenancy = require("../../tenancy")
const { Configs, DEFAULT_TENANT_ID } = require("../../constants") const { Config, DEFAULT_TENANT_ID } = require("../../constants")
const env = require("../../environment") const env = require("../../environment")
describe("utils", () => { describe("utils", () => {
@ -77,7 +77,7 @@ const setDbPlatformUrl = async () => {
const db = tenancy.getGlobalDB() const db = tenancy.getGlobalDB()
db.put({ db.put({
_id: "config_settings", _id: "config_settings",
type: Configs.SETTINGS, type: Config.SETTINGS,
config: { config: {
platformUrl: DB_URL platformUrl: DB_URL
} }
@ -178,7 +178,7 @@ describe("getScopedConfig", () => {
await tenancy.doInTenant(DEFAULT_TENANT_ID, async () => { await tenancy.doInTenant(DEFAULT_TENANT_ID, async () => {
await setDbPlatformUrl() await setDbPlatformUrl()
const db = tenancy.getGlobalDB() const db = tenancy.getGlobalDB()
const config = await getScopedConfig(db, { type: Configs.SETTINGS }) const config = await getScopedConfig(db, { type: Config.SETTINGS })
expect(config.platformUrl).toBe(DB_URL) expect(config.platformUrl).toBe(DB_URL)
}) })
}) })
@ -186,7 +186,7 @@ describe("getScopedConfig", () => {
it("returns the platform url without an existing config", async () => { it("returns the platform url without an existing config", async () => {
await tenancy.doInTenant(DEFAULT_TENANT_ID, async () => { await tenancy.doInTenant(DEFAULT_TENANT_ID, async () => {
const db = tenancy.getGlobalDB() const db = tenancy.getGlobalDB()
const config = await getScopedConfig(db, { type: Configs.SETTINGS }) const config = await getScopedConfig(db, { type: Config.SETTINGS })
expect(config.platformUrl).toBe(DEFAULT_URL) expect(config.platformUrl).toBe(DEFAULT_URL)
}) })
}) })

View File

@ -1,5 +1,5 @@
import { newid } from "../hashing" import { newid } from "../hashing"
import { DEFAULT_TENANT_ID, Configs } from "../constants" import { DEFAULT_TENANT_ID, Config } from "../constants"
import env from "../environment" import env from "../environment"
import { import {
SEPARATOR, SEPARATOR,
@ -491,7 +491,7 @@ export const getScopedFullConfig = async function (
)[0] )[0]
// custom logic for settings doc // custom logic for settings doc
if (type === Configs.SETTINGS) { if (type === Config.SETTINGS) {
if (scopedConfig && scopedConfig.doc) { if (scopedConfig && scopedConfig.doc) {
// overrides affected by environment variables // overrides affected by environment variables
scopedConfig.doc.config.platformUrl = await getPlatformUrl({ scopedConfig.doc.config.platformUrl = await getPlatformUrl({
@ -530,7 +530,7 @@ export const getPlatformUrl = async (opts = { tenantAware: true }) => {
// get the doc directly instead of with getScopedConfig to prevent loop // get the doc directly instead of with getScopedConfig to prevent loop
let settings let settings
try { try {
settings = await db.get(generateConfigID({ type: Configs.SETTINGS })) settings = await db.get(generateConfigID({ type: Config.SETTINGS }))
} catch (e: any) { } catch (e: any) {
if (e.status !== 404) { if (e.status !== 404) {
throw e throw e

View File

@ -1,7 +1,7 @@
import env from "../environment" import env from "../environment"
import tenancy from "../tenancy" import tenancy from "../tenancy"
import * as dbUtils from "../db/utils" import * as dbUtils from "../db/utils"
import { Configs } from "../constants" import { Config } from "../constants"
import { withCache, TTL, CacheKeys } from "../cache/generic" import { withCache, TTL, CacheKeys } from "../cache/generic"
export const enabled = async () => { export const enabled = async () => {
@ -46,7 +46,7 @@ const getSettingsDoc = async () => {
let settings let settings
try { try {
settings = await db.get( settings = await db.get(
dbUtils.generateConfigID({ type: Configs.SETTINGS }) dbUtils.generateConfigID({ type: Config.SETTINGS })
) )
} catch (e: any) { } catch (e: any) {
if (e.status !== 404) { if (e.status !== 404) {

View File

@ -19,7 +19,7 @@ import {
} from "@budibase/types" } from "@budibase/types"
import { processors } from "./processors" import { processors } from "./processors"
import * as dbUtils from "../db/utils" import * as dbUtils from "../db/utils"
import { Configs } from "../constants" import { Config } from "../constants"
import * as hashing from "../hashing" import * as hashing from "../hashing"
import * as installation from "../installation" import * as installation from "../installation"
import { withCache, TTL, CacheKeys } from "../cache/generic" import { withCache, TTL, CacheKeys } from "../cache/generic"
@ -273,7 +273,7 @@ const getUniqueTenantId = async (tenantId: string): Promise<string> => {
return withCache(CacheKeys.UNIQUE_TENANT_ID, TTL.ONE_DAY, async () => { return withCache(CacheKeys.UNIQUE_TENANT_ID, TTL.ONE_DAY, async () => {
const db = context.getGlobalDB() const db = context.getGlobalDB()
const config: SettingsConfig = await dbUtils.getScopedFullConfig(db, { const config: SettingsConfig = await dbUtils.getScopedFullConfig(db, {
type: Configs.SETTINGS, type: Config.SETTINGS,
}) })
let uniqueTenantId: string let uniqueTenantId: string

View File

@ -13,7 +13,7 @@ import featureFlags from "./featureFlags"
import * as sessions from "./security/sessions" import * as sessions from "./security/sessions"
import * as deprovisioning from "./context/deprovision" import * as deprovisioning from "./context/deprovision"
import auth from "./auth" import auth from "./auth"
import constants from "./constants" import * as constants from "./constants"
import * as dbConstants from "./db/constants" import * as dbConstants from "./db/constants"
import * as logging from "./logging" import * as logging from "./logging"
import pino from "./pino" import pino from "./pino"

View File

@ -1,11 +1,9 @@
import { Cookies, Headers } from "../constants" import { Cookie, Header } from "../constants"
import { getCookie, clearCookie, openJwt } from "../utils" import { getCookie, clearCookie, openJwt } from "../utils"
import { getUser } from "../cache/user" import { getUser } from "../cache/user"
import { getSession, updateSessionTTL } from "../security/sessions" import { getSession, updateSessionTTL } from "../security/sessions"
import { buildMatcherRegex, matches } from "./matchers" import { buildMatcherRegex, matches } from "./matchers"
import { SEPARATOR } from "../db/constants" import { SEPARATOR, queryGlobalView, ViewName } from "../db"
import { ViewName } from "../db/utils"
import { queryGlobalView } from "../db/views"
import { getGlobalDB, doInTenant } from "../tenancy" 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")
@ -74,7 +72,7 @@ export = (
const noAuthOptions = noAuthPatterns ? buildMatcherRegex(noAuthPatterns) : [] const noAuthOptions = noAuthPatterns ? buildMatcherRegex(noAuthPatterns) : []
return async (ctx: any, next: any) => { return async (ctx: any, next: any) => {
let publicEndpoint = false let publicEndpoint = false
const version = ctx.request.headers[Headers.API_VER] const version = ctx.request.headers[Header.API_VER]
// the path is not authenticated // the path is not authenticated
const found = matches(ctx, noAuthOptions) const found = matches(ctx, noAuthOptions)
if (found) { if (found) {
@ -82,10 +80,10 @@ export = (
} }
try { try {
// check the actual user is authenticated first, try header or cookie // check the actual user is authenticated first, try header or cookie
const headerToken = ctx.request.headers[Headers.TOKEN] const headerToken = ctx.request.headers[Header.TOKEN]
const authCookie = getCookie(ctx, Cookies.Auth) || openJwt(headerToken) const authCookie = getCookie(ctx, Cookie.Auth) || openJwt(headerToken)
const apiKey = ctx.request.headers[Headers.API_KEY] const apiKey = ctx.request.headers[Header.API_KEY]
const tenantId = ctx.request.headers[Headers.TENANT_ID] const tenantId = ctx.request.headers[Header.TENANT_ID]
let authenticated = false, let authenticated = false,
user = null, user = null,
internal = false internal = false
@ -116,7 +114,7 @@ export = (
authenticated = false authenticated = false
console.error("Auth Error", err?.message || err) console.error("Auth Error", err?.message || err)
// remove the cookie as the user does not exist anymore // remove the cookie as the user does not exist anymore
clearCookie(ctx, Cookies.Auth) clearCookie(ctx, Cookie.Auth)
} }
} }
// this is an internal request, no user made it // this is an internal request, no user made it
@ -140,7 +138,7 @@ export = (
delete user.password delete user.password
} }
// be explicit // be explicit
if (authenticated !== true) { if (!authenticated) {
authenticated = false authenticated = false
} }
// isAuthenticated is a function, so use a variable to be able to check authed state // isAuthenticated is a function, so use a variable to be able to check authed state
@ -155,7 +153,7 @@ export = (
console.error("Auth Error", err?.message || err) console.error("Auth Error", err?.message || err)
// invalid token, clear the cookie // invalid token, clear the cookie
if (err && err.name === "JsonWebTokenError") { if (err && err.name === "JsonWebTokenError") {
clearCookie(ctx, Cookies.Auth) clearCookie(ctx, Cookie.Auth)
} }
// allow configuring for public access // allow configuring for public access
if ((opts && opts.publicAllowed) || publicEndpoint) { if ((opts && opts.publicAllowed) || publicEndpoint) {

View File

@ -1,4 +1,4 @@
const { Headers } = require("../constants") const { Header } = require("../constants")
const { buildMatcherRegex, matches } = require("./matchers") const { buildMatcherRegex, matches } = require("./matchers")
/** /**
@ -68,7 +68,7 @@ module.exports = (opts = { noCsrfPatterns: [] }) => {
} }
// reject if no token in request or mismatch // reject if no token in request or mismatch
const requestToken = ctx.get(Headers.CSRF_TOKEN) const requestToken = ctx.get(Header.CSRF_TOKEN)
if (!requestToken || requestToken !== userToken) { if (!requestToken || requestToken !== userToken) {
ctx.throw(403, "Invalid CSRF token") ctx.throw(403, "Invalid CSRF token")
} }

View File

@ -1,11 +1,11 @@
const env = require("../environment") const env = require("../environment")
const { Headers } = require("../constants") const { Header } = require("../constants")
/** /**
* API Key only endpoint. * API Key only endpoint.
*/ */
module.exports = async (ctx, next) => { module.exports = async (ctx, next) => {
const apiKey = ctx.request.headers[Headers.API_KEY] const apiKey = ctx.request.headers[Header.API_KEY]
if (apiKey !== env.INTERNAL_API_KEY) { if (apiKey !== env.INTERNAL_API_KEY) {
ctx.throw(403, "Unauthorized") ctx.throw(403, "Unauthorized")
} }

View File

@ -1,6 +1,6 @@
const google = require("../google") const google = require("../google")
const GoogleStrategy = require("passport-google-oauth").OAuth2Strategy const GoogleStrategy = require("passport-google-oauth").OAuth2Strategy
const { Cookies, Configs } = require("../../../constants") const { Cookie, Config } = require("../../../constants")
const { clearCookie, getCookie } = require("../../../utils") const { clearCookie, getCookie } = require("../../../utils")
const { getScopedConfig, getPlatformUrl } = require("../../../db/utils") const { getScopedConfig, getPlatformUrl } = require("../../../db/utils")
const { doWithDB } = require("../../../db") const { doWithDB } = require("../../../db")
@ -11,7 +11,7 @@ async function fetchGoogleCreds() {
// try and get the config from the tenant // try and get the config from the tenant
const db = getGlobalDB() const db = getGlobalDB()
const googleConfig = await getScopedConfig(db, { const googleConfig = await getScopedConfig(db, {
type: Configs.GOOGLE, type: Config.GOOGLE,
}) })
// or fall back to env variables // or fall back to env variables
return ( return (
@ -47,7 +47,7 @@ async function postAuth(passport, ctx, next) {
const platformUrl = await getPlatformUrl({ tenantAware: false }) const platformUrl = await getPlatformUrl({ tenantAware: false })
let callbackUrl = `${platformUrl}/api/global/auth/datasource/google/callback` let callbackUrl = `${platformUrl}/api/global/auth/datasource/google/callback`
const authStateCookie = getCookie(ctx, Cookies.DatasourceAuth) const authStateCookie = getCookie(ctx, Cookie.DatasourceAuth)
return passport.authenticate( return passport.authenticate(
new GoogleStrategy( new GoogleStrategy(
@ -57,7 +57,7 @@ async function postAuth(passport, ctx, next) {
callbackURL: callbackUrl, callbackURL: callbackUrl,
}, },
(accessToken, refreshToken, profile, done) => { (accessToken, refreshToken, profile, done) => {
clearCookie(ctx, Cookies.DatasourceAuth) clearCookie(ctx, Cookie.DatasourceAuth)
done(null, { accessToken, refreshToken }) done(null, { accessToken, refreshToken })
} }
), ),

View File

@ -1,7 +1,7 @@
const GoogleStrategy = require("passport-google-oauth").OAuth2Strategy const GoogleStrategy = require("passport-google-oauth").OAuth2Strategy
const { ssoCallbackUrl } = require("./utils") const { ssoCallbackUrl } = require("./utils")
const { authenticateThirdParty } = require("./third-party-common") const { authenticateThirdParty } = require("./third-party-common")
const { Configs } = require("../../../constants") const { Config } = require("../../../constants")
const buildVerifyFn = saveUserFn => { const buildVerifyFn = saveUserFn => {
return (accessToken, refreshToken, profile, done) => { return (accessToken, refreshToken, profile, done) => {
@ -60,7 +60,7 @@ exports.strategyFactory = async function (config, callbackUrl, saveUserFn) {
} }
exports.getCallbackUrl = async function (db, config) { exports.getCallbackUrl = async function (db, config) {
return ssoCallbackUrl(db, config, Configs.GOOGLE) return ssoCallbackUrl(db, config, Config.GOOGLE)
} }
// expose for testing // expose for testing

View File

@ -1,11 +1,11 @@
const { Cookies } = require("../../constants") const { Cookie } = require("../../constants")
const env = require("../../environment") const env = require("../../environment")
const { authError } = require("./utils") const { authError } = require("./utils")
exports.options = { exports.options = {
secretOrKey: env.JWT_SECRET, secretOrKey: env.JWT_SECRET,
jwtFromRequest: function (ctx) { jwtFromRequest: function (ctx) {
return ctx.cookies.get(Cookies.Auth) return ctx.cookies.get(Cookie.Auth)
}, },
} }

View File

@ -2,7 +2,7 @@ const fetch = require("node-fetch")
const OIDCStrategy = require("@techpass/passport-openidconnect").Strategy const OIDCStrategy = require("@techpass/passport-openidconnect").Strategy
const { authenticateThirdParty } = require("./third-party-common") const { authenticateThirdParty } = require("./third-party-common")
const { ssoCallbackUrl } = require("./utils") const { ssoCallbackUrl } = require("./utils")
const { Configs } = require("../../../constants") const { Config } = require("../../../constants")
const buildVerifyFn = saveUserFn => { const buildVerifyFn = saveUserFn => {
/** /**
@ -140,7 +140,7 @@ exports.fetchStrategyConfig = async function (enrichedConfig, callbackUrl) {
} }
exports.getCallbackUrl = async function (db, config) { exports.getCallbackUrl = async function (db, config) {
return ssoCallbackUrl(db, config, Configs.OIDC) return ssoCallbackUrl(db, config, Config.OIDC)
} }
// expose for testing // expose for testing

View File

@ -1,6 +1,6 @@
const { isMultiTenant, getTenantId } = require("../../tenancy") const { isMultiTenant, getTenantId } = require("../../tenancy")
const { getScopedConfig } = require("../../db/utils") const { getScopedConfig } = require("../../db/utils")
const { Configs } = require("../../constants") const { Config } = require("../../constants")
/** /**
* Utility to handle authentication errors. * Utility to handle authentication errors.
@ -24,7 +24,7 @@ exports.ssoCallbackUrl = async (db, config, type) => {
return config.callbackURL return config.callbackURL
} }
const publicConfig = await getScopedConfig(db, { const publicConfig = await getScopedConfig(db, {
type: Configs.SETTINGS, type: Config.SETTINGS,
}) })
let callbackUrl = `/api/global/auth` let callbackUrl = `/api/global/auth`

View File

@ -1,6 +1,6 @@
const { doInTenant, isMultiTenant, DEFAULT_TENANT_ID } = require("../tenancy") const { doInTenant, isMultiTenant, DEFAULT_TENANT_ID } = require("../tenancy")
const { buildMatcherRegex, matches } = require("./matchers") const { buildMatcherRegex, matches } = require("./matchers")
const { Headers } = require("../constants") const { Header } = require("../constants")
const getTenantID = (ctx, opts = { allowQs: false, allowNoTenant: false }) => { const getTenantID = (ctx, opts = { allowQs: false, allowNoTenant: false }) => {
// exit early if not multi-tenant // exit early if not multi-tenant
@ -11,7 +11,7 @@ const getTenantID = (ctx, opts = { allowQs: false, allowNoTenant: false }) => {
let tenantId let tenantId
const allowQs = opts && opts.allowQs const allowQs = opts && opts.allowQs
const allowNoTenant = opts && opts.allowNoTenant const allowNoTenant = opts && opts.allowNoTenant
const header = ctx.request.headers[Headers.TENANT_ID] const header = ctx.request.headers[Header.TENANT_ID]
const user = ctx.user || {} const user = ctx.user || {}
if (allowQs) { if (allowQs) {
const query = ctx.request.query || {} const query = ctx.request.query || {}

View File

@ -3,9 +3,11 @@
import * as generic from "../cache/generic" import * as generic from "../cache/generic"
import * as user from "../cache/user" import * as user from "../cache/user"
import * as app from "../cache/appMetadata" import * as app from "../cache/appMetadata"
import * as writethrough from "../cache/writethrough"
export = { export = {
app, app,
user, user,
writethrough,
...generic, ...generic,
} }

View File

@ -2,7 +2,7 @@ const { DocumentType, SEPARATOR, ViewName, getAllApps } = require("./db/utils")
const jwt = require("jsonwebtoken") const jwt = require("jsonwebtoken")
const { options } = require("./middleware/passport/jwt") const { options } = require("./middleware/passport/jwt")
const { queryGlobalView } = require("./db/views") const { queryGlobalView } = require("./db/views")
const { Headers, Cookies, MAX_VALID_DATE } = require("./constants") const { Header, Cookie, MAX_VALID_DATE } = require("./constants")
const env = require("./environment") const env = require("./environment")
const userCache = require("./cache/user") const userCache = require("./cache/user")
const { const {
@ -61,7 +61,7 @@ exports.isServingApp = ctx => {
*/ */
exports.getAppIdFromCtx = async ctx => { exports.getAppIdFromCtx = async ctx => {
// look in headers // look in headers
const options = [ctx.headers[Headers.APP_ID]] const options = [ctx.headers[Header.APP_ID]]
let appId let appId
for (let option of options) { for (let option of options) {
appId = confirmAppId(option) appId = confirmAppId(option)
@ -157,7 +157,7 @@ exports.clearCookie = (ctx, name) => {
* @return {boolean} returns true if the call is from the client lib (a built app rather than the builder). * @return {boolean} returns true if the call is from the client lib (a built app rather than the builder).
*/ */
exports.isClient = ctx => { exports.isClient = ctx => {
return ctx.headers[Headers.TYPE] === "client" return ctx.headers[Header.TYPE] === "client"
} }
const getBuilders = async () => { const getBuilders = async () => {
@ -187,7 +187,7 @@ exports.getBuildersCount = async () => {
exports.platformLogout = async ({ ctx, userId, keepActiveSession }) => { exports.platformLogout = async ({ ctx, userId, keepActiveSession }) => {
if (!ctx) throw new Error("Koa context must be supplied to logout.") if (!ctx) throw new Error("Koa context must be supplied to logout.")
const currentSession = exports.getCookie(ctx, Cookies.Auth) const currentSession = exports.getCookie(ctx, Cookie.Auth)
let sessions = await getSessionsForUser(userId) let sessions = await getSessionsForUser(userId)
if (keepActiveSession) { if (keepActiveSession) {
@ -196,8 +196,8 @@ exports.platformLogout = async ({ ctx, userId, keepActiveSession }) => {
) )
} else { } else {
// clear cookies // clear cookies
exports.clearCookie(ctx, Cookies.Auth) exports.clearCookie(ctx, Cookie.Auth)
exports.clearCookie(ctx, Cookies.CurrentApp) exports.clearCookie(ctx, Cookie.CurrentApp)
} }
const sessionIds = sessions.map(({ sessionId }) => sessionId) const sessionIds = sessions.map(({ sessionId }) => sessionId)

View File

@ -112,13 +112,13 @@ export async function find(ctx: any) {
//Required to discern between OIDC OAuth config entries //Required to discern between OIDC OAuth config entries
function getOAuthConfigCookieId(ctx: any) { function getOAuthConfigCookieId(ctx: any) {
if (ctx.user.providerType === constants.Configs.OIDC) { if (ctx.user.providerType === constants.Config.OIDC) {
return utils.getCookie(ctx, constants.Cookies.OIDC_CONFIG) return utils.getCookie(ctx, constants.Cookie.OIDC_CONFIG)
} }
} }
function getAuthConfig(ctx: any) { function getAuthConfig(ctx: any) {
const authCookie = utils.getCookie(ctx, constants.Cookies.Auth) const authCookie = utils.getCookie(ctx, constants.Cookie.Auth)
let authConfigCtx: any = {} let authConfigCtx: any = {}
authConfigCtx["configId"] = getOAuthConfigCookieId(ctx) authConfigCtx["configId"] = getOAuthConfigCookieId(ctx)
authConfigCtx["sessionId"] = authCookie ? authCookie.sessionId : null authConfigCtx["sessionId"] = authCookie ? authCookie.sessionId : null

View File

@ -43,7 +43,7 @@ describe("/static", () => {
it("should ping from app", async () => { it("should ping from app", async () => {
const headers = config.defaultHeaders() const headers = config.defaultHeaders()
headers[constants.Headers.APP_ID] = config.prodAppId headers[constants.Header.APP_ID] = config.prodAppId
await request await request
.post("/api/bbtel/ping") .post("/api/bbtel/ping")

View File

@ -46,7 +46,7 @@ describe("/static", () => {
it("should serve the app by id", async () => { it("should serve the app by id", async () => {
const headers = config.defaultHeaders() const headers = config.defaultHeaders()
delete headers[constants.Headers.APP_ID] delete headers[constants.Header.APP_ID]
const res = await request const res = await request
.get(`/${config.prodAppId}`) .get(`/${config.prodAppId}`)
@ -58,7 +58,7 @@ describe("/static", () => {
it("should serve the app by url", async () => { it("should serve the app by url", async () => {
const headers = config.defaultHeaders() const headers = config.defaultHeaders()
delete headers[constants.Headers.APP_ID] delete headers[constants.Header.APP_ID]
const res = await request const res = await request
.get(`/app${config.prodApp.url}`) .get(`/app${config.prodApp.url}`)

View File

@ -12,10 +12,7 @@ import { buildExternalTableId } from "./utils"
import { DataSourceOperation, FieldTypes } from "../constants" import { DataSourceOperation, FieldTypes } from "../constants"
import { GoogleSpreadsheet } from "google-spreadsheet" import { GoogleSpreadsheet } from "google-spreadsheet"
import env from "../environment" import env from "../environment"
import { tenancy, db as dbCore, constants } from "@budibase/backend-core"
const { getGlobalDB } = require("@budibase/backend-core/tenancy")
const { getScopedConfig } = require("@budibase/backend-core/db")
const { Configs } = require("@budibase/backend-core/constants")
const fetch = require("node-fetch") const fetch = require("node-fetch")
interface GoogleSheetsConfig { interface GoogleSheetsConfig {
@ -176,9 +173,9 @@ class GoogleSheetsIntegration implements DatasourcePlus {
async connect() { async connect() {
try { try {
// Initialise oAuth client // Initialise oAuth client
const db = getGlobalDB() const db = tenancy.getGlobalDB()
let googleConfig = await getScopedConfig(db, { let googleConfig = await dbCore.getScopedConfig(db, {
type: Configs.GOOGLE, type: constants.Config.GOOGLE,
}) })
if (!googleConfig) { if (!googleConfig) {

View File

@ -18,9 +18,9 @@ export = async (ctx: BBContext, next: any) => {
// get app cookie if it exists // get app cookie if it exists
let appCookie: { appId?: string } | undefined let appCookie: { appId?: string } | undefined
try { try {
appCookie = utils.getCookie(ctx, constants.Cookies.CurrentApp) appCookie = utils.getCookie(ctx, constants.Cookie.CurrentApp)
} catch (err) { } catch (err) {
utils.clearCookie(ctx, constants.Cookies.CurrentApp) utils.clearCookie(ctx, constants.Cookie.CurrentApp)
} }
if (!appCookie && !requestAppId) { if (!appCookie && !requestAppId) {
return next() return next()
@ -30,7 +30,7 @@ export = async (ctx: BBContext, next: any) => {
const appId = appCookie.appId const appId = appCookie.appId
const exists = await dbCore.dbExists(appId) const exists = await dbCore.dbExists(appId)
if (!exists) { if (!exists) {
utils.clearCookie(ctx, constants.Cookies.CurrentApp) utils.clearCookie(ctx, constants.Cookie.CurrentApp)
return next() return next()
} }
// if the request app ID wasn't set, update it with the cookie // if the request app ID wasn't set, update it with the cookie
@ -44,7 +44,7 @@ export = async (ctx: BBContext, next: any) => {
!isWebhookEndpoint(ctx) && !isWebhookEndpoint(ctx) &&
(!ctx.user || !ctx.user.builder || !ctx.user.builder.global) (!ctx.user || !ctx.user.builder || !ctx.user.builder.global)
) { ) {
utils.clearCookie(ctx, constants.Cookies.CurrentApp) utils.clearCookie(ctx, constants.Cookie.CurrentApp)
return ctx.redirect("/") return ctx.redirect("/")
} }
} }
@ -67,7 +67,7 @@ export = async (ctx: BBContext, next: any) => {
const isDevApp = appId && isDevAppID(appId) const isDevApp = appId && isDevAppID(appId)
const roleHeader = const roleHeader =
ctx.request && ctx.request &&
(ctx.request.headers[constants.Headers.PREVIEW_ROLE] as string) (ctx.request.headers[constants.Header.PREVIEW_ROLE] as string)
if (isBuilder && isDevApp && roleHeader) { if (isBuilder && isDevApp && roleHeader) {
// Ensure the role is valid by ensuring a definition exists // Ensure the role is valid by ensuring a definition exists
try { try {
@ -132,7 +132,7 @@ export = async (ctx: BBContext, next: any) => {
appCookie.appId !== requestAppId) && appCookie.appId !== requestAppId) &&
!skipCookie !skipCookie
) { ) {
utils.setCookie(ctx, { appId }, constants.Cookies.CurrentApp) utils.setCookie(ctx, { appId }, constants.Cookie.CurrentApp)
} }
return next() return next()

View File

@ -1,4 +1,4 @@
const { Headers } = require("@budibase/backend-core/constants") const { Header } = require("@budibase/backend-core/constants")
const { getAppIdFromCtx } = require("@budibase/backend-core/utils") const { getAppIdFromCtx } = require("@budibase/backend-core/utils")
module.exports = function ({ requiresAppId } = {}) { module.exports = function ({ requiresAppId } = {}) {
@ -7,13 +7,13 @@ module.exports = function ({ requiresAppId } = {}) {
if (requiresAppId && !appId) { if (requiresAppId && !appId) {
ctx.throw( ctx.throw(
400, 400,
`Invalid app ID provided, please check the ${Headers.APP_ID} header.` `Invalid app ID provided, please check the ${Header.APP_ID} header.`
) )
} }
if (!ctx.headers[Headers.API_KEY]) { if (!ctx.headers[Header.API_KEY]) {
ctx.throw( ctx.throw(
400, 400,
`Invalid API key provided, please check the ${Headers.API_KEY} header.` `Invalid API key provided, please check the ${Header.API_KEY} header.`
) )
} }
return next() return next()

View File

@ -16,7 +16,7 @@ const {
const controllers = require("./controllers") const controllers = require("./controllers")
const supertest = require("supertest") const supertest = require("supertest")
const { cleanup } = require("../../utilities/fileSystem") const { cleanup } = require("../../utilities/fileSystem")
const { Cookies, Headers } = require("@budibase/backend-core/constants") const { Cookie, Headers } = require("@budibase/backend-core/constants")
const { jwt } = require("@budibase/backend-core/auth") const { jwt } = require("@budibase/backend-core/auth")
const { doInTenant, doWithGlobalDB } = require("@budibase/backend-core/tenancy") const { doInTenant, doWithGlobalDB } = require("@budibase/backend-core/tenancy")
const { createASession } = require("@budibase/backend-core/sessions") const { createASession } = require("@budibase/backend-core/sessions")
@ -256,10 +256,10 @@ class TestConfiguration {
return { return {
Accept: "application/json", Accept: "application/json",
Cookie: [ Cookie: [
`${Cookies.Auth}=${authToken}`, `${Cookie.Auth}=${authToken}`,
`${Cookies.CurrentApp}=${appToken}`, `${Cookie.CurrentApp}=${appToken}`,
], ],
[Headers.APP_ID]: appId, [Header.APP_ID]: appId,
} }
}) })
} }
@ -279,14 +279,14 @@ class TestConfiguration {
const headers = { const headers = {
Accept: "application/json", Accept: "application/json",
Cookie: [ Cookie: [
`${Cookies.Auth}=${authToken}`, `${Cookie.Auth}=${authToken}`,
`${Cookies.CurrentApp}=${appToken}`, `${Cookie.CurrentApp}=${appToken}`,
], ],
[Headers.CSRF_TOKEN]: CSRF_TOKEN, [Header.CSRF_TOKEN]: CSRF_TOKEN,
...extras, ...extras,
} }
if (this.appId) { if (this.appId) {
headers[Headers.APP_ID] = this.appId headers[Header.APP_ID] = this.appId
} }
return headers return headers
} }
@ -298,7 +298,7 @@ class TestConfiguration {
Accept: "application/json", Accept: "application/json",
} }
if (appId) { if (appId) {
headers[Headers.APP_ID] = appId headers[Header.APP_ID] = appId
} }
return headers return headers
} }

View File

@ -11,9 +11,9 @@ function request(ctx, request) {
request.headers = {} request.headers = {}
} }
if (!ctx) { if (!ctx) {
request.headers[Headers.API_KEY] = env.INTERNAL_API_KEY request.headers[Header.API_KEY] = env.INTERNAL_API_KEY
if (isTenantIdSet()) { if (isTenantIdSet()) {
request.headers[Headers.TENANT_ID] = getTenantId() request.headers[Header.TENANT_ID] = getTenantId()
} }
} }
if (request.body && Object.keys(request.body).length > 0) { if (request.body && Object.keys(request.body).length > 0) {

View File

@ -1,8 +1,8 @@
const core = require("@budibase/backend-core") const core = require("@budibase/backend-core")
const { Configs, EmailTemplatePurpose } = require("../../../constants") const { Config, EmailTemplatePurpose } = require("../../../constants")
const { sendEmail, isEmailConfigured } = require("../../../utilities/email") const { sendEmail, isEmailConfigured } = require("../../../utilities/email")
const { setCookie, getCookie, clearCookie, hash, platformLogout } = core.utils const { setCookie, getCookie, clearCookie, hash, platformLogout } = core.utils
const { Cookies, Headers } = core.constants const { Cookie, Headers } = core.constants
const { passport, ssoCallbackUrl, google, oidc } = core.auth const { passport, ssoCallbackUrl, google, oidc } = core.auth
const { checkResetPasswordCode } = require("../../../utilities/redis") const { checkResetPasswordCode } = require("../../../utilities/redis")
const { getGlobalDB } = require("@budibase/backend-core/tenancy") const { getGlobalDB } = require("@budibase/backend-core/tenancy")
@ -30,13 +30,13 @@ async function authInternal(ctx: any, user: any, err = null, info = null) {
} }
// set a cookie for browser access // set a cookie for browser access
setCookie(ctx, user.token, Cookies.Auth, { sign: false }) setCookie(ctx, user.token, Cookie.Auth, { sign: false })
// set the token in a header as well for APIs // set the token in a header as well for APIs
ctx.set(Headers.TOKEN, user.token) ctx.set(Header.TOKEN, user.token)
// get rid of any app cookies on login // get rid of any app cookies on login
// have to check test because this breaks cypress // have to check test because this breaks cypress
if (!env.isTest()) { if (!env.isTest()) {
clearCookie(ctx, Cookies.CurrentApp) clearCookie(ctx, Cookie.CurrentApp)
} }
} }
@ -55,15 +55,15 @@ export const authenticate = async (ctx: any, next: any) => {
export const setInitInfo = (ctx: any) => { export const setInitInfo = (ctx: any) => {
const initInfo = ctx.request.body const initInfo = ctx.request.body
setCookie(ctx, initInfo, Cookies.Init) setCookie(ctx, initInfo, Cookie.Init)
ctx.status = 200 ctx.status = 200
} }
export const getInitInfo = (ctx: any) => { export const getInitInfo = (ctx: any) => {
try { try {
ctx.body = getCookie(ctx, Cookies.Init) || {} ctx.body = getCookie(ctx, Cookie.Init) || {}
} catch (err) { } catch (err) {
clearCookie(ctx, Cookies.Init) clearCookie(ctx, Cookie.Init)
ctx.body = {} ctx.body = {}
} }
} }
@ -141,14 +141,14 @@ export const datasourcePreAuth = async (ctx: any, next: any) => {
appId: ctx.query.appId, appId: ctx.query.appId,
datasourceId: ctx.query.datasourceId, datasourceId: ctx.query.datasourceId,
}, },
Cookies.DatasourceAuth Cookie.DatasourceAuth
) )
return handler.preAuth(passport, ctx, next) return handler.preAuth(passport, ctx, next)
} }
export const datasourceAuth = async (ctx: any, next: any) => { export const datasourceAuth = async (ctx: any, next: any) => {
const authStateCookie = getCookie(ctx, Cookies.DatasourceAuth) const authStateCookie = getCookie(ctx, Cookie.DatasourceAuth)
const provider = authStateCookie.provider const provider = authStateCookie.provider
const middleware = require(`@budibase/backend-core/middleware`) const middleware = require(`@budibase/backend-core/middleware`)
const handler = middleware.datasource[provider] const handler = middleware.datasource[provider]
@ -163,7 +163,7 @@ export const googlePreAuth = async (ctx: any, next: any) => {
const db = getGlobalDB() const db = getGlobalDB()
const config = await core.db.getScopedConfig(db, { const config = await core.db.getScopedConfig(db, {
type: Configs.GOOGLE, type: Config.GOOGLE,
workspace: ctx.query.workspace, workspace: ctx.query.workspace,
}) })
let callbackUrl = await exports.googleCallbackUrl(config) let callbackUrl = await exports.googleCallbackUrl(config)
@ -184,7 +184,7 @@ export const googleAuth = async (ctx: any, next: any) => {
const db = getGlobalDB() const db = getGlobalDB()
const config = await core.db.getScopedConfig(db, { const config = await core.db.getScopedConfig(db, {
type: Configs.GOOGLE, type: Config.GOOGLE,
workspace: ctx.query.workspace, workspace: ctx.query.workspace,
}) })
const callbackUrl = await exports.googleCallbackUrl(config) const callbackUrl = await exports.googleCallbackUrl(config)
@ -210,7 +210,7 @@ export const googleAuth = async (ctx: any, next: any) => {
export const oidcStrategyFactory = async (ctx: any, configId: any) => { export const oidcStrategyFactory = async (ctx: any, configId: any) => {
const db = getGlobalDB() const db = getGlobalDB()
const config = await core.db.getScopedConfig(db, { const config = await core.db.getScopedConfig(db, {
type: Configs.OIDC, type: Config.OIDC,
group: ctx.query.group, group: ctx.query.group,
}) })
@ -233,11 +233,11 @@ export const oidcPreAuth = async (ctx: any, next: any) => {
const { configId } = ctx.params const { configId } = ctx.params
const strategy = await oidcStrategyFactory(ctx, configId) const strategy = await oidcStrategyFactory(ctx, configId)
setCookie(ctx, configId, Cookies.OIDC_CONFIG) setCookie(ctx, configId, Cookie.OIDC_CONFIG)
const db = getGlobalDB() const db = getGlobalDB()
const config = await core.db.getScopedConfig(db, { const config = await core.db.getScopedConfig(db, {
type: Configs.OIDC, type: Config.OIDC,
group: ctx.query.group, group: ctx.query.group,
}) })
@ -255,7 +255,7 @@ export const oidcPreAuth = async (ctx: any, next: any) => {
} }
export const oidcAuth = async (ctx: any, next: any) => { export const oidcAuth = async (ctx: any, next: any) => {
const configId = getCookie(ctx, Cookies.OIDC_CONFIG) const configId = getCookie(ctx, Cookie.OIDC_CONFIG)
const strategy = await oidcStrategyFactory(ctx, configId) const strategy = await oidcStrategyFactory(ctx, configId)
return passport.authenticate( return passport.authenticate(

View File

@ -4,7 +4,7 @@ const {
getScopedFullConfig, getScopedFullConfig,
getAllApps, getAllApps,
} = require("@budibase/backend-core/db") } = require("@budibase/backend-core/db")
const { Configs } = require("../../../constants") const { Config } = require("../../../constants")
const email = require("../../../utilities/email") const email = require("../../../utilities/email")
const { const {
upload, upload,
@ -33,25 +33,25 @@ const getEventFns = async (db, config) => {
if (!existing) { if (!existing) {
switch (config.type) { switch (config.type) {
case Configs.SMTP: { case Config.SMTP: {
fns.push(events.email.SMTPCreated) fns.push(events.email.SMTPCreated)
break break
} }
case Configs.GOOGLE: { case Config.GOOGLE: {
fns.push(() => events.auth.SSOCreated(type)) fns.push(() => events.auth.SSOCreated(type))
if (config.config.activated) { if (config.config.activated) {
fns.push(() => events.auth.SSOActivated(type)) fns.push(() => events.auth.SSOActivated(type))
} }
break break
} }
case Configs.OIDC: { case Config.OIDC: {
fns.push(() => events.auth.SSOCreated(type)) fns.push(() => events.auth.SSOCreated(type))
if (config.config.configs[0].activated) { if (config.config.configs[0].activated) {
fns.push(() => events.auth.SSOActivated(type)) fns.push(() => events.auth.SSOActivated(type))
} }
break break
} }
case Configs.SETTINGS: { case Config.SETTINGS: {
// company // company
const company = config.config.company const company = config.config.company
if (company && company !== "Budibase") { if (company && company !== "Budibase") {
@ -78,11 +78,11 @@ const getEventFns = async (db, config) => {
} }
} else { } else {
switch (config.type) { switch (config.type) {
case Configs.SMTP: { case Config.SMTP: {
fns.push(events.email.SMTPUpdated) fns.push(events.email.SMTPUpdated)
break break
} }
case Configs.GOOGLE: { case Config.GOOGLE: {
fns.push(() => events.auth.SSOUpdated(type)) fns.push(() => events.auth.SSOUpdated(type))
if (!existing.config.activated && config.config.activated) { if (!existing.config.activated && config.config.activated) {
fns.push(() => events.auth.SSOActivated(type)) fns.push(() => events.auth.SSOActivated(type))
@ -91,7 +91,7 @@ const getEventFns = async (db, config) => {
} }
break break
} }
case Configs.OIDC: { case Config.OIDC: {
fns.push(() => events.auth.SSOUpdated(type)) fns.push(() => events.auth.SSOUpdated(type))
if ( if (
!existing.config.configs[0].activated && !existing.config.configs[0].activated &&
@ -106,7 +106,7 @@ const getEventFns = async (db, config) => {
} }
break break
} }
case Configs.SETTINGS: { case Config.SETTINGS: {
// company // company
const existingCompany = existing.config.company const existingCompany = existing.config.company
const company = config.config.company const company = config.config.company
@ -155,7 +155,7 @@ exports.save = async function (ctx) {
try { try {
// verify the configuration // verify the configuration
switch (type) { switch (type) {
case Configs.SMTP: case Config.SMTP:
await email.verifyConfig(config) await email.verifyConfig(config)
break break
} }
@ -237,7 +237,7 @@ exports.publicOidc = async function (ctx) {
try { try {
// Find the config with the most granular scope based on context // Find the config with the most granular scope based on context
const oidcConfig = await getScopedFullConfig(db, { const oidcConfig = await getScopedFullConfig(db, {
type: Configs.OIDC, type: Config.OIDC,
}) })
if (!oidcConfig) { if (!oidcConfig) {
@ -260,15 +260,15 @@ exports.publicSettings = async function (ctx) {
try { try {
// Find the config with the most granular scope based on context // Find the config with the most granular scope based on context
const publicConfig = await getScopedFullConfig(db, { const publicConfig = await getScopedFullConfig(db, {
type: Configs.SETTINGS, type: Config.SETTINGS,
}) })
const googleConfig = await getScopedFullConfig(db, { const googleConfig = await getScopedFullConfig(db, {
type: Configs.GOOGLE, type: Config.GOOGLE,
}) })
const oidcConfig = await getScopedFullConfig(db, { const oidcConfig = await getScopedFullConfig(db, {
type: Configs.OIDC, type: Config.OIDC,
}) })
let config let config
@ -390,17 +390,17 @@ exports.configChecklist = async function (ctx) {
// They have set up SMTP // They have set up SMTP
const smtpConfig = await getScopedFullConfig(db, { const smtpConfig = await getScopedFullConfig(db, {
type: Configs.SMTP, type: Config.SMTP,
}) })
// They have set up Google Auth // They have set up Google Auth
const googleConfig = await getScopedFullConfig(db, { const googleConfig = await getScopedFullConfig(db, {
type: Configs.GOOGLE, type: Config.GOOGLE,
}) })
// They have set up OIDC // They have set up OIDC
const oidcConfig = await getScopedFullConfig(db, { const oidcConfig = await getScopedFullConfig(db, {
type: Configs.OIDC, type: Config.OIDC,
}) })
// They have set up an global user // They have set up an global user

View File

@ -73,12 +73,12 @@ export async function fetchAPIKey(ctx: any) {
} }
const checkCurrentApp = (ctx: any) => { const checkCurrentApp = (ctx: any) => {
const appCookie = getCookie(ctx, constants.Cookies.CurrentApp) const appCookie = getCookie(ctx, constants.Cookie.CurrentApp)
if (appCookie && !tenancy.isUserInAppTenant(appCookie.appId)) { if (appCookie && !tenancy.isUserInAppTenant(appCookie.appId)) {
// there is a currentapp cookie from another tenant // there is a currentapp cookie from another tenant
// remove the cookie as this is incompatible with the builder // remove the cookie as this is incompatible with the builder
// due to builder and admin permissions being removed // due to builder and admin permissions being removed
clearCookie(ctx, constants.Cookies.CurrentApp) clearCookie(ctx, constants.Cookie.CurrentApp)
} }
} }

View File

@ -3,7 +3,7 @@ const controller = require("../../controllers/global/configs")
const { joiValidator } = require("@budibase/backend-core/auth") const { joiValidator } = require("@budibase/backend-core/auth")
const { adminOnly } = require("@budibase/backend-core/auth") const { adminOnly } = require("@budibase/backend-core/auth")
const Joi = require("joi") const Joi = require("joi")
const { Configs } = require("../../../constants") const { Config } = require("../../../constants")
const router = new Router() const router = new Router()
@ -65,17 +65,17 @@ function buildConfigSaveValidation() {
_id: Joi.string().optional(), _id: Joi.string().optional(),
_rev: Joi.string().optional(), _rev: Joi.string().optional(),
workspace: Joi.string().optional(), workspace: Joi.string().optional(),
type: Joi.string().valid(...Object.values(Configs)).required(), type: Joi.string().valid(...Object.values(Config)).required(),
createdAt: Joi.string().optional(), createdAt: Joi.string().optional(),
updatedAt: Joi.string().optional(), updatedAt: Joi.string().optional(),
config: Joi.alternatives() config: Joi.alternatives()
.conditional("type", { .conditional("type", {
switch: [ switch: [
{ is: Configs.SMTP, then: smtpValidation() }, { is: Config.SMTP, then: smtpValidation() },
{ is: Configs.SETTINGS, then: settingValidation() }, { is: Config.SETTINGS, then: settingValidation() },
{ is: Configs.ACCOUNT, then: Joi.object().unknown(true) }, { is: Config.ACCOUNT, then: Joi.object().unknown(true) },
{ is: Configs.GOOGLE, then: googleValidation() }, { is: Config.GOOGLE, then: googleValidation() },
{ is: Configs.OIDC, then: oidcValidation() } { is: Config.OIDC, then: oidcValidation() }
], ],
}), }),
}).required().unknown(true), }).required().unknown(true),
@ -85,7 +85,7 @@ function buildConfigSaveValidation() {
function buildUploadValidation() { function buildUploadValidation() {
// prettier-ignore // prettier-ignore
return joiValidator.params(Joi.object({ return joiValidator.params(Joi.object({
type: Joi.string().valid(...Object.values(Configs)).required(), type: Joi.string().valid(...Object.values(Config)).required(),
name: Joi.string().required(), name: Joi.string().required(),
}).required().unknown(true)) }).required().unknown(true))
} }
@ -93,7 +93,7 @@ function buildUploadValidation() {
function buildConfigGetValidation() { function buildConfigGetValidation() {
// prettier-ignore // prettier-ignore
return joiValidator.params(Joi.object({ return joiValidator.params(Joi.object({
type: Joi.string().valid(...Object.values(Configs)).required() type: Joi.string().valid(...Object.values(Config)).required()
}).required().unknown(true)) }).required().unknown(true))
} }

View File

@ -2,7 +2,7 @@
jest.mock("nodemailer") jest.mock("nodemailer")
import { TestConfiguration, structures, mocks, API } from "../../../../tests" import { TestConfiguration, structures, mocks, API } from "../../../../tests"
mocks.email.mock() mocks.email.mock()
import { Configs, events } from "@budibase/backend-core" import { Config, events } from "@budibase/backend-core"
describe("configs", () => { describe("configs", () => {
const config = new TestConfiguration() const config = new TestConfiguration()
@ -50,20 +50,20 @@ describe("configs", () => {
it("should create activated google config", async () => { it("should create activated google config", async () => {
await saveGoogleConfig() await saveGoogleConfig()
expect(events.auth.SSOCreated).toBeCalledTimes(1) expect(events.auth.SSOCreated).toBeCalledTimes(1)
expect(events.auth.SSOCreated).toBeCalledWith(Configs.GOOGLE) expect(events.auth.SSOCreated).toBeCalledWith(Config.GOOGLE)
expect(events.auth.SSODeactivated).not.toBeCalled() expect(events.auth.SSODeactivated).not.toBeCalled()
expect(events.auth.SSOActivated).toBeCalledTimes(1) expect(events.auth.SSOActivated).toBeCalledTimes(1)
expect(events.auth.SSOActivated).toBeCalledWith(Configs.GOOGLE) expect(events.auth.SSOActivated).toBeCalledWith(Config.GOOGLE)
await config.deleteConfig(Configs.GOOGLE) await config.deleteConfig(Config.GOOGLE)
}) })
it("should create deactivated google config", async () => { it("should create deactivated google config", async () => {
await saveGoogleConfig({ activated: false }) await saveGoogleConfig({ activated: false })
expect(events.auth.SSOCreated).toBeCalledTimes(1) expect(events.auth.SSOCreated).toBeCalledTimes(1)
expect(events.auth.SSOCreated).toBeCalledWith(Configs.GOOGLE) expect(events.auth.SSOCreated).toBeCalledWith(Config.GOOGLE)
expect(events.auth.SSOActivated).not.toBeCalled() expect(events.auth.SSOActivated).not.toBeCalled()
expect(events.auth.SSODeactivated).not.toBeCalled() expect(events.auth.SSODeactivated).not.toBeCalled()
await config.deleteConfig(Configs.GOOGLE) await config.deleteConfig(Config.GOOGLE)
}) })
}) })
@ -77,11 +77,11 @@ describe("configs", () => {
googleConf._rev googleConf._rev
) )
expect(events.auth.SSOUpdated).toBeCalledTimes(1) expect(events.auth.SSOUpdated).toBeCalledTimes(1)
expect(events.auth.SSOUpdated).toBeCalledWith(Configs.GOOGLE) expect(events.auth.SSOUpdated).toBeCalledWith(Config.GOOGLE)
expect(events.auth.SSOActivated).not.toBeCalled() expect(events.auth.SSOActivated).not.toBeCalled()
expect(events.auth.SSODeactivated).toBeCalledTimes(1) expect(events.auth.SSODeactivated).toBeCalledTimes(1)
expect(events.auth.SSODeactivated).toBeCalledWith(Configs.GOOGLE) expect(events.auth.SSODeactivated).toBeCalledWith(Config.GOOGLE)
await config.deleteConfig(Configs.GOOGLE) await config.deleteConfig(Config.GOOGLE)
}) })
it("should update google config to activated", async () => { it("should update google config to activated", async () => {
@ -93,11 +93,11 @@ describe("configs", () => {
googleConf._rev googleConf._rev
) )
expect(events.auth.SSOUpdated).toBeCalledTimes(1) expect(events.auth.SSOUpdated).toBeCalledTimes(1)
expect(events.auth.SSOUpdated).toBeCalledWith(Configs.GOOGLE) expect(events.auth.SSOUpdated).toBeCalledWith(Config.GOOGLE)
expect(events.auth.SSODeactivated).not.toBeCalled() expect(events.auth.SSODeactivated).not.toBeCalled()
expect(events.auth.SSOActivated).toBeCalledTimes(1) expect(events.auth.SSOActivated).toBeCalledTimes(1)
expect(events.auth.SSOActivated).toBeCalledWith(Configs.GOOGLE) expect(events.auth.SSOActivated).toBeCalledWith(Config.GOOGLE)
await config.deleteConfig(Configs.GOOGLE) await config.deleteConfig(Config.GOOGLE)
}) })
}) })
}) })
@ -116,20 +116,20 @@ describe("configs", () => {
it("should create activated OIDC config", async () => { it("should create activated OIDC config", async () => {
await saveOIDCConfig() await saveOIDCConfig()
expect(events.auth.SSOCreated).toBeCalledTimes(1) expect(events.auth.SSOCreated).toBeCalledTimes(1)
expect(events.auth.SSOCreated).toBeCalledWith(Configs.OIDC) expect(events.auth.SSOCreated).toBeCalledWith(Config.OIDC)
expect(events.auth.SSODeactivated).not.toBeCalled() expect(events.auth.SSODeactivated).not.toBeCalled()
expect(events.auth.SSOActivated).toBeCalledTimes(1) expect(events.auth.SSOActivated).toBeCalledTimes(1)
expect(events.auth.SSOActivated).toBeCalledWith(Configs.OIDC) expect(events.auth.SSOActivated).toBeCalledWith(Config.OIDC)
await config.deleteConfig(Configs.OIDC) await config.deleteConfig(Config.OIDC)
}) })
it("should create deactivated OIDC config", async () => { it("should create deactivated OIDC config", async () => {
await saveOIDCConfig({ activated: false }) await saveOIDCConfig({ activated: false })
expect(events.auth.SSOCreated).toBeCalledTimes(1) expect(events.auth.SSOCreated).toBeCalledTimes(1)
expect(events.auth.SSOCreated).toBeCalledWith(Configs.OIDC) expect(events.auth.SSOCreated).toBeCalledWith(Config.OIDC)
expect(events.auth.SSOActivated).not.toBeCalled() expect(events.auth.SSOActivated).not.toBeCalled()
expect(events.auth.SSODeactivated).not.toBeCalled() expect(events.auth.SSODeactivated).not.toBeCalled()
await config.deleteConfig(Configs.OIDC) await config.deleteConfig(Config.OIDC)
}) })
}) })
@ -143,11 +143,11 @@ describe("configs", () => {
oidcConf._rev oidcConf._rev
) )
expect(events.auth.SSOUpdated).toBeCalledTimes(1) expect(events.auth.SSOUpdated).toBeCalledTimes(1)
expect(events.auth.SSOUpdated).toBeCalledWith(Configs.OIDC) expect(events.auth.SSOUpdated).toBeCalledWith(Config.OIDC)
expect(events.auth.SSOActivated).not.toBeCalled() expect(events.auth.SSOActivated).not.toBeCalled()
expect(events.auth.SSODeactivated).toBeCalledTimes(1) expect(events.auth.SSODeactivated).toBeCalledTimes(1)
expect(events.auth.SSODeactivated).toBeCalledWith(Configs.OIDC) expect(events.auth.SSODeactivated).toBeCalledWith(Config.OIDC)
await config.deleteConfig(Configs.OIDC) await config.deleteConfig(Config.OIDC)
}) })
it("should update OIDC config to activated", async () => { it("should update OIDC config to activated", async () => {
@ -159,11 +159,11 @@ describe("configs", () => {
oidcConf._rev oidcConf._rev
) )
expect(events.auth.SSOUpdated).toBeCalledTimes(1) expect(events.auth.SSOUpdated).toBeCalledTimes(1)
expect(events.auth.SSOUpdated).toBeCalledWith(Configs.OIDC) expect(events.auth.SSOUpdated).toBeCalledWith(Config.OIDC)
expect(events.auth.SSODeactivated).not.toBeCalled() expect(events.auth.SSODeactivated).not.toBeCalled()
expect(events.auth.SSOActivated).toBeCalledTimes(1) expect(events.auth.SSOActivated).toBeCalledTimes(1)
expect(events.auth.SSOActivated).toBeCalledWith(Configs.OIDC) expect(events.auth.SSOActivated).toBeCalledWith(Config.OIDC)
await config.deleteConfig(Configs.OIDC) await config.deleteConfig(Config.OIDC)
}) })
}) })
}) })
@ -180,11 +180,11 @@ describe("configs", () => {
describe("create", () => { describe("create", () => {
it("should create SMTP config", async () => { it("should create SMTP config", async () => {
await config.deleteConfig(Configs.SMTP) await config.deleteConfig(Config.SMTP)
await saveSMTPConfig() await saveSMTPConfig()
expect(events.email.SMTPUpdated).not.toBeCalled() expect(events.email.SMTPUpdated).not.toBeCalled()
expect(events.email.SMTPCreated).toBeCalledTimes(1) expect(events.email.SMTPCreated).toBeCalledTimes(1)
await config.deleteConfig(Configs.SMTP) await config.deleteConfig(Config.SMTP)
}) })
}) })
@ -195,7 +195,7 @@ describe("configs", () => {
await saveSMTPConfig(smtpConf.config, smtpConf._id, smtpConf._rev) await saveSMTPConfig(smtpConf.config, smtpConf._id, smtpConf._rev)
expect(events.email.SMTPCreated).not.toBeCalled() expect(events.email.SMTPCreated).not.toBeCalled()
expect(events.email.SMTPUpdated).toBeCalledTimes(1) expect(events.email.SMTPUpdated).toBeCalledTimes(1)
await config.deleteConfig(Configs.SMTP) await config.deleteConfig(Config.SMTP)
}) })
}) })
}) })
@ -212,7 +212,7 @@ describe("configs", () => {
describe("create", () => { describe("create", () => {
it("should create settings config with default settings", async () => { it("should create settings config with default settings", async () => {
await config.deleteConfig(Configs.SETTINGS) await config.deleteConfig(Config.SETTINGS)
await saveSettingsConfig() await saveSettingsConfig()
@ -223,7 +223,7 @@ describe("configs", () => {
it("should create settings config with non-default settings", async () => { it("should create settings config with non-default settings", async () => {
config.modeSelf() config.modeSelf()
await config.deleteConfig(Configs.SETTINGS) await config.deleteConfig(Config.SETTINGS)
const conf = { const conf = {
company: "acme", company: "acme",
logoUrl: "http://example.com", logoUrl: "http://example.com",
@ -242,7 +242,7 @@ describe("configs", () => {
describe("update", () => { describe("update", () => {
it("should update settings config", async () => { it("should update settings config", async () => {
config.modeSelf() config.modeSelf()
await config.deleteConfig(Configs.SETTINGS) await config.deleteConfig(Config.SETTINGS)
const settingsConfig = await saveSettingsConfig() const settingsConfig = await saveSettingsConfig()
settingsConfig.config.company = "acme" settingsConfig.config.company = "acme"
settingsConfig.config.logoUrl = "http://example.com" settingsConfig.config.logoUrl = "http://example.com"

View File

@ -1,4 +1,4 @@
const { Configs } = require("@budibase/backend-core/constants") const { Config } = require("@budibase/backend-core/constants")
exports.LOGO_URL = exports.LOGO_URL =
"https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg" "https://d33wubrfki0l68.cloudfront.net/aac32159d7207b5085e74a7ef67afbb7027786c5/2b1fd/img/logo/bb-emblem.svg"
@ -8,7 +8,7 @@ exports.UserStatus = {
INACTIVE: "inactive", INACTIVE: "inactive",
} }
exports.Configs = Configs exports.Config = Config
exports.ConfigUploads = { exports.ConfigUploads = {
LOGO: "logo", LOGO: "logo",

View File

@ -7,7 +7,7 @@ const { Headers } = require("@budibase/backend-core/constants")
*/ */
module.exports = async (ctx, next) => { module.exports = async (ctx, next) => {
if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) { if (!env.SELF_HOSTED && !env.DISABLE_ACCOUNT_PORTAL) {
const apiKey = ctx.request.headers[Headers.API_KEY] const apiKey = ctx.request.headers[Header.API_KEY]
if (apiKey !== env.INTERNAL_API_KEY) { if (apiKey !== env.INTERNAL_API_KEY) {
ctx.throw(403, "Unauthorized") ctx.throw(403, "Unauthorized")
} }

View File

@ -4,12 +4,12 @@ dbConfig.init()
import env from "../environment" import env from "../environment"
import controllers from "./controllers" import controllers from "./controllers"
const supertest = require("supertest") const supertest = require("supertest")
import { Configs } from "../constants" import { Config } from "../constants"
import { import {
users, users,
tenancy, tenancy,
Cookies, Cookie,
Headers, Header,
sessions, sessions,
auth, auth,
} from "@budibase/backend-core" } from "@budibase/backend-core"
@ -163,8 +163,8 @@ class TestConfiguration {
const authCookie = auth.jwt.sign(authToken, env.JWT_SECRET) const authCookie = auth.jwt.sign(authToken, env.JWT_SECRET)
return { return {
Accept: "application/json", Accept: "application/json",
...this.cookieHeader([`${Cookies.Auth}=${authCookie}`]), ...this.cookieHeader([`${Cookie.Auth}=${authCookie}`]),
[Headers.CSRF_TOKEN]: CSRF_TOKEN, [Header.CSRF_TOKEN]: CSRF_TOKEN,
} }
} }
@ -223,7 +223,7 @@ class TestConfiguration {
// CONFIGS - SETTINGS // CONFIGS - SETTINGS
async saveSettingsConfig() { async saveSettingsConfig() {
await this.deleteConfig(Configs.SETTINGS) await this.deleteConfig(Config.SETTINGS)
await this._req( await this._req(
structures.configs.settings(), structures.configs.settings(),
null, null,
@ -234,7 +234,7 @@ class TestConfiguration {
// CONFIGS - GOOGLE // CONFIGS - GOOGLE
async saveGoogleConfig() { async saveGoogleConfig() {
await this.deleteConfig(Configs.GOOGLE) await this.deleteConfig(Config.GOOGLE)
await this._req(structures.configs.google(), null, controllers.config.save) await this._req(structures.configs.google(), null, controllers.config.save)
} }
@ -242,11 +242,11 @@ class TestConfiguration {
getOIDConfigCookie(configId: string) { getOIDConfigCookie(configId: string) {
const token = auth.jwt.sign(configId, env.JWT_SECRET) const token = auth.jwt.sign(configId, env.JWT_SECRET)
return this.cookieHeader([[`${Cookies.OIDC_CONFIG}=${token}`]]) return this.cookieHeader([[`${Cookie.OIDC_CONFIG}=${token}`]])
} }
async saveOIDCConfig() { async saveOIDCConfig() {
await this.deleteConfig(Configs.OIDC) await this.deleteConfig(Config.OIDC)
const config = structures.configs.oidc() const config = structures.configs.oidc()
await this._req(config, null, controllers.config.save) await this._req(config, null, controllers.config.save)
@ -256,12 +256,12 @@ class TestConfiguration {
// CONFIGS - SMTP // CONFIGS - SMTP
async saveSmtpConfig() { async saveSmtpConfig() {
await this.deleteConfig(Configs.SMTP) await this.deleteConfig(Config.SMTP)
await this._req(structures.configs.smtp(), null, controllers.config.save) await this._req(structures.configs.smtp(), null, controllers.config.save)
} }
async saveEtherealSmtpConfig() { async saveEtherealSmtpConfig() {
await this.deleteConfig(Configs.SMTP) await this.deleteConfig(Config.SMTP)
await this._req( await this._req(
structures.configs.smtpEthereal(), structures.configs.smtpEthereal(),
null, null,

View File

@ -1,9 +1,9 @@
const { Configs } = require("../../constants") const { Config } = require("../../constants")
const { utils } = require("@budibase/backend-core") const { utils } = require("@budibase/backend-core")
exports.oidc = conf => { exports.oidc = conf => {
return { return {
type: Configs.OIDC, type: Config.OIDC,
config: { config: {
configs: [ configs: [
{ {
@ -23,7 +23,7 @@ exports.oidc = conf => {
exports.google = conf => { exports.google = conf => {
return { return {
type: Configs.GOOGLE, type: Config.GOOGLE,
config: { config: {
clientID: "clientId", clientID: "clientId",
clientSecret: "clientSecret", clientSecret: "clientSecret",
@ -35,7 +35,7 @@ exports.google = conf => {
exports.smtp = conf => { exports.smtp = conf => {
return { return {
type: Configs.SMTP, type: Config.SMTP,
config: { config: {
port: 12345, port: 12345,
host: "smtptesthost.com", host: "smtptesthost.com",
@ -49,7 +49,7 @@ exports.smtp = conf => {
exports.smtpEthereal = () => { exports.smtpEthereal = () => {
return { return {
type: Configs.SMTP, type: Config.SMTP,
config: { config: {
port: 587, port: 587,
host: "smtp.ethereal.email", host: "smtp.ethereal.email",
@ -65,7 +65,7 @@ exports.smtpEthereal = () => {
exports.settings = conf => { exports.settings = conf => {
return { return {
type: Configs.SETTINGS, type: Config.SETTINGS,
config: { config: {
platformUrl: "http://localhost:10000", platformUrl: "http://localhost:10000",
logoUrl: "", logoUrl: "",

View File

@ -9,9 +9,9 @@ async function makeAppRequest(url, method, body) {
return return
} }
const request = { headers: {} } const request = { headers: {} }
request.headers[Headers.API_KEY] = env.INTERNAL_API_KEY request.headers[Header.API_KEY] = env.INTERNAL_API_KEY
if (isTenantIdSet()) { if (isTenantIdSet()) {
request.headers[Headers.TENANT_ID] = getTenantId() request.headers[Header.TENANT_ID] = getTenantId()
} }
if (body) { if (body) {
request.headers["Content-Type"] = "application/json" request.headers["Content-Type"] = "application/json"

View File

@ -1,7 +1,7 @@
const nodemailer = require("nodemailer") const nodemailer = require("nodemailer")
const env = require("../environment") const env = require("../environment")
const { getScopedConfig } = require("@budibase/backend-core/db") const { getScopedConfig } = require("@budibase/backend-core/db")
const { EmailTemplatePurpose, TemplateTypes, Configs } = require("../constants") const { EmailTemplatePurpose, TemplateTypes, Config } = require("../constants")
const { getTemplateByPurpose } = require("../constants/templates") const { getTemplateByPurpose } = require("../constants/templates")
const { getSettingsTemplateContext } = require("./templates") const { getSettingsTemplateContext } = require("./templates")
const { processString } = require("@budibase/string-templates") const { processString } = require("@budibase/string-templates")
@ -115,7 +115,7 @@ async function buildEmail(purpose, email, context, { user, contents } = {}) {
*/ */
async function getSmtpConfiguration(db, workspaceId = null, automation) { async function getSmtpConfiguration(db, workspaceId = null, automation) {
const params = { const params = {
type: Configs.SMTP, type: Config.SMTP,
} }
if (workspaceId) { if (workspaceId) {
params.workspace = workspaceId params.workspace = workspaceId

View File

@ -1,6 +1,6 @@
const { getScopedConfig } = require("@budibase/backend-core/db") const { getScopedConfig } = require("@budibase/backend-core/db")
const { const {
Configs, Config,
InternalTemplateBindings, InternalTemplateBindings,
LOGO_URL, LOGO_URL,
EmailTemplatePurpose, EmailTemplatePurpose,
@ -15,7 +15,7 @@ const BASE_COMPANY = "Budibase"
exports.getSettingsTemplateContext = async (purpose, code = null) => { exports.getSettingsTemplateContext = async (purpose, code = null) => {
const db = getGlobalDB() const db = getGlobalDB()
// TODO: use more granular settings in the future if required // TODO: use more granular settings in the future if required
let settings = (await getScopedConfig(db, { type: Configs.SETTINGS })) || {} let settings = (await getScopedConfig(db, { type: Config.SETTINGS })) || {}
const URL = settings.platformUrl const URL = settings.platformUrl
const context = { const context = {
[InternalTemplateBindings.LOGO_URL]: [InternalTemplateBindings.LOGO_URL]: