Update tenancy detection to honour any subdomain pattern according to platform url
This commit is contained in:
parent
e63afd560a
commit
ada0eb79bc
|
@ -58,12 +58,15 @@ http {
|
|||
}
|
||||
|
||||
location ~ ^/api/(system|admin|global)/ {
|
||||
proxy_pass http://worker-service;
|
||||
proxy_read_timeout 120s;
|
||||
proxy_connect_timeout 120s;
|
||||
proxy_send_timeout 120s;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Connection "";
|
||||
|
||||
proxy_pass http://worker-service;
|
||||
}
|
||||
|
||||
location /api/backups/ {
|
||||
|
@ -78,60 +81,78 @@ http {
|
|||
location /api/ {
|
||||
proxy_read_timeout 120s;
|
||||
proxy_connect_timeout 120s;
|
||||
proxy_send_timeout 120s;
|
||||
proxy_pass http://app-service;
|
||||
proxy_send_timeout 120s;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Connection "";
|
||||
|
||||
proxy_pass http://app-service;
|
||||
}
|
||||
|
||||
location = / {
|
||||
proxy_pass http://app-service;
|
||||
proxy_read_timeout 120s;
|
||||
proxy_connect_timeout 120s;
|
||||
proxy_send_timeout 120s;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Connection "";
|
||||
|
||||
proxy_pass http://app-service;
|
||||
}
|
||||
|
||||
location /app_ {
|
||||
proxy_pass http://app-service;
|
||||
proxy_read_timeout 120s;
|
||||
proxy_connect_timeout 120s;
|
||||
proxy_send_timeout 120s;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Connection "";
|
||||
|
||||
proxy_pass http://app-service;
|
||||
}
|
||||
|
||||
location /app {
|
||||
proxy_pass http://app-service;
|
||||
proxy_read_timeout 120s;
|
||||
proxy_connect_timeout 120s;
|
||||
proxy_send_timeout 120s;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Connection "";
|
||||
|
||||
proxy_pass http://app-service;
|
||||
}
|
||||
|
||||
location /builder {
|
||||
proxy_pass http://builder;
|
||||
proxy_read_timeout 120s;
|
||||
proxy_connect_timeout 120s;
|
||||
proxy_send_timeout 120s;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Connection "";
|
||||
|
||||
proxy_pass http://builder;
|
||||
rewrite ^/builder(.*)$ /builder/$1 break;
|
||||
}
|
||||
|
||||
location /builder/ {
|
||||
proxy_pass http://builder;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
proxy_read_timeout 120s;
|
||||
proxy_connect_timeout 120s;
|
||||
proxy_send_timeout 120s;
|
||||
|
||||
proxy_pass http://builder;
|
||||
}
|
||||
|
||||
location /vite/ {
|
||||
|
|
|
@ -100,18 +100,25 @@ http {
|
|||
|
||||
location ~ ^/(builder|app_) {
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
proxy_pass http://$apps:4002;
|
||||
}
|
||||
|
||||
location ~ ^/api/(system|admin|global)/ {
|
||||
proxy_set_header Host $host;
|
||||
|
||||
proxy_pass http://$worker:4003;
|
||||
}
|
||||
|
||||
location /worker/ {
|
||||
proxy_set_header Host $host;
|
||||
|
||||
proxy_pass http://$worker:4003;
|
||||
rewrite ^/worker/(.*)$ /$1 break;
|
||||
}
|
||||
|
@ -139,6 +146,7 @@ http {
|
|||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
proxy_pass http://$apps:4002;
|
||||
}
|
||||
|
@ -158,6 +166,7 @@ http {
|
|||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
proxy_pass http://$apps:4002;
|
||||
}
|
||||
|
|
|
@ -75,8 +75,8 @@
|
|||
"env:multi:disable": "lerna run env:multi:disable",
|
||||
"env:selfhost:enable": "lerna run env:selfhost:enable",
|
||||
"env:selfhost:disable": "lerna run env:selfhost:disable",
|
||||
"env:localdomain:enable": "lerna run env:localdomain:enable",
|
||||
"env:localdomain:disable": "lerna run env:localdomain:disable",
|
||||
"env:localdomain:enable": "./scripts/localdomain.sh enable",
|
||||
"env:localdomain:disable": "./scripts/localdomain.sh disable",
|
||||
"env:account:enable": "lerna run env:account:enable",
|
||||
"env:account:disable": "lerna run env:account:disable",
|
||||
"mode:self": "yarn env:selfhost:enable && yarn env:multi:disable && yarn env:account:disable",
|
||||
|
|
|
@ -15,6 +15,7 @@ import { getAppMetadata } from "../cache/appMetadata"
|
|||
import { isDevApp, isDevAppID, getProdAppID } from "./conversions"
|
||||
import { APP_PREFIX } from "./constants"
|
||||
import * as events from "../events"
|
||||
import { App } from "@budibase/types"
|
||||
|
||||
export * from "./constants"
|
||||
export * from "./conversions"
|
||||
|
@ -301,7 +302,12 @@ export async function getAllDbs(opts = { efficient: false }) {
|
|||
*
|
||||
* @return {Promise<object[]>} returns the app information document stored in each app database.
|
||||
*/
|
||||
export async function getAllApps({ dev, all, idsOnly, efficient }: any = {}) {
|
||||
export async function getAllApps({
|
||||
dev,
|
||||
all,
|
||||
idsOnly,
|
||||
efficient,
|
||||
}: any = {}): Promise<App[] | string[]> {
|
||||
let tenantId = getTenantId()
|
||||
if (!env.MULTI_TENANCY && !tenantId) {
|
||||
tenantId = DEFAULT_TENANT_ID
|
||||
|
@ -373,18 +379,16 @@ export async function getAllApps({ dev, all, idsOnly, efficient }: any = {}) {
|
|||
* Utility function for getAllApps but filters to production apps only.
|
||||
*/
|
||||
export async function getProdAppIDs() {
|
||||
return (await getAllApps({ idsOnly: true })).filter(
|
||||
(id: any) => !isDevAppID(id)
|
||||
)
|
||||
const apps = (await getAllApps({ idsOnly: true })) as string[]
|
||||
return apps.filter((id: any) => !isDevAppID(id))
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for the inverse of above.
|
||||
*/
|
||||
export async function getDevAppIDs() {
|
||||
return (await getAllApps({ idsOnly: true })).filter((id: any) =>
|
||||
isDevAppID(id)
|
||||
)
|
||||
const apps = (await getAllApps({ idsOnly: true })) as string[]
|
||||
return apps.filter((id: any) => isDevAppID(id))
|
||||
}
|
||||
|
||||
export async function dbExists(dbName: any) {
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
const { doInTenant, isMultiTenant, DEFAULT_TENANT_ID } = require("../tenancy")
|
||||
const { buildMatcherRegex, matches } = require("./matchers")
|
||||
const { Headers } = require("../constants")
|
||||
|
||||
const getTenantID = (ctx, opts = { allowQs: false, allowNoTenant: false }) => {
|
||||
// exit early if not multi-tenant
|
||||
if (!isMultiTenant()) {
|
||||
return DEFAULT_TENANT_ID
|
||||
}
|
||||
|
||||
let tenantId
|
||||
const allowQs = opts && opts.allowQs
|
||||
const allowNoTenant = opts && opts.allowNoTenant
|
||||
const header = ctx.request.headers[Headers.TENANT_ID]
|
||||
const user = ctx.user || {}
|
||||
if (allowQs) {
|
||||
const query = ctx.request.query || {}
|
||||
tenantId = query.tenantId
|
||||
}
|
||||
// override query string (if allowed) by user, or header
|
||||
// URL params cannot be used in a middleware, as they are
|
||||
// processed later in the chain
|
||||
tenantId = user.tenantId || header || tenantId
|
||||
|
||||
// Set the tenantId from the subdomain
|
||||
if (!tenantId) {
|
||||
tenantId = ctx.subdomains && ctx.subdomains[0]
|
||||
}
|
||||
|
||||
if (!tenantId && !allowNoTenant) {
|
||||
ctx.throw(403, "Tenant id not set")
|
||||
}
|
||||
|
||||
return tenantId
|
||||
}
|
||||
|
||||
module.exports = (
|
||||
allowQueryStringPatterns,
|
||||
noTenancyPatterns,
|
||||
opts = { noTenancyRequired: false }
|
||||
) => {
|
||||
const allowQsOptions = buildMatcherRegex(allowQueryStringPatterns)
|
||||
const noTenancyOptions = buildMatcherRegex(noTenancyPatterns)
|
||||
|
||||
return async function (ctx, next) {
|
||||
const allowNoTenant =
|
||||
opts.noTenancyRequired || !!matches(ctx, noTenancyOptions)
|
||||
const allowQs = !!matches(ctx, allowQsOptions)
|
||||
const tenantId = getTenantID(ctx, { allowQs, allowNoTenant })
|
||||
return doInTenant(tenantId, next)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
import { doInTenant, getTenantIDFromCtx } from "../tenancy"
|
||||
import { buildMatcherRegex, matches } from "./matchers"
|
||||
import {
|
||||
BBContext,
|
||||
EndpointMatcher,
|
||||
GetTenantIdOptions,
|
||||
TenantResolutionStrategy,
|
||||
} from "@budibase/types"
|
||||
|
||||
const tenancy = (
|
||||
allowQueryStringPatterns: EndpointMatcher[],
|
||||
noTenancyPatterns: EndpointMatcher,
|
||||
opts = { noTenancyRequired: false }
|
||||
) => {
|
||||
const allowQsOptions = buildMatcherRegex(allowQueryStringPatterns)
|
||||
const noTenancyOptions = buildMatcherRegex(noTenancyPatterns)
|
||||
|
||||
return async function (ctx: BBContext, next: any) {
|
||||
const allowNoTenant =
|
||||
opts.noTenancyRequired || !!matches(ctx, noTenancyOptions)
|
||||
const tenantOpts: GetTenantIdOptions = {
|
||||
allowNoTenant,
|
||||
}
|
||||
|
||||
const allowQs = !!matches(ctx, allowQsOptions)
|
||||
if (!allowQs) {
|
||||
tenantOpts.excludeStrategies = [TenantResolutionStrategy.QUERY]
|
||||
}
|
||||
|
||||
const tenantId = getTenantIDFromCtx(ctx, tenantOpts)
|
||||
return doInTenant(tenantId, next)
|
||||
}
|
||||
}
|
||||
|
||||
export = tenancy
|
|
@ -12,6 +12,7 @@ import {
|
|||
MigrationOptions,
|
||||
MigrationType,
|
||||
MigrationNoOpOptions,
|
||||
App,
|
||||
} from "@budibase/types"
|
||||
|
||||
export const getMigrationsDoc = async (db: any) => {
|
||||
|
@ -55,14 +56,17 @@ export const runMigration = async (
|
|||
}
|
||||
|
||||
// get the db to store the migration in
|
||||
let dbNames
|
||||
let dbNames: string[]
|
||||
if (migrationType === MigrationType.GLOBAL) {
|
||||
dbNames = [getGlobalDBName()]
|
||||
} else if (migrationType === MigrationType.APP) {
|
||||
if (options.noOp) {
|
||||
if (!options.noOp.appId) {
|
||||
throw new Error("appId is required for noOp app migration")
|
||||
}
|
||||
dbNames = [options.noOp.appId]
|
||||
} else {
|
||||
const apps = await getAllApps(migration.appOpts)
|
||||
const apps = (await getAllApps(migration.appOpts)) as App[]
|
||||
dbNames = apps.map(app => app.appId)
|
||||
}
|
||||
} else if (migrationType === MigrationType.INSTALLATION) {
|
||||
|
|
|
@ -9,7 +9,13 @@ import {
|
|||
getTenantIDFromAppID,
|
||||
} from "../context"
|
||||
import env from "../environment"
|
||||
import { PlatformUser } from "@budibase/types"
|
||||
import {
|
||||
BBContext,
|
||||
PlatformUser,
|
||||
TenantResolutionStrategy,
|
||||
GetTenantIdOptions,
|
||||
} from "@budibase/types"
|
||||
import { Headers } from "../constants"
|
||||
|
||||
const TENANT_DOC = StaticDatabases.PLATFORM_INFO.docs.tenants
|
||||
const PLATFORM_INFO_DB = StaticDatabases.PLATFORM_INFO.name
|
||||
|
@ -144,3 +150,82 @@ export const getTenantIds = async () => {
|
|||
return (tenants && tenants.tenantIds) || []
|
||||
})
|
||||
}
|
||||
|
||||
const ALL_STRATEGIES = Object.values(TenantResolutionStrategy)
|
||||
|
||||
export const getTenantIDFromCtx = (
|
||||
ctx: BBContext,
|
||||
opts: GetTenantIdOptions
|
||||
): string | null => {
|
||||
// exit early if not multi-tenant
|
||||
if (!isMultiTenant()) {
|
||||
return DEFAULT_TENANT_ID
|
||||
}
|
||||
|
||||
// opt defaults
|
||||
if (opts.allowNoTenant === undefined) {
|
||||
opts.allowNoTenant = false
|
||||
}
|
||||
if (!opts.includeStrategies) {
|
||||
opts.includeStrategies = ALL_STRATEGIES
|
||||
}
|
||||
if (!opts.excludeStrategies) {
|
||||
opts.excludeStrategies = []
|
||||
}
|
||||
|
||||
const isAllowed = (strategy: TenantResolutionStrategy) => {
|
||||
// excluded takes precedence
|
||||
if (opts.excludeStrategies?.includes(strategy)) {
|
||||
return false
|
||||
}
|
||||
if (opts.includeStrategies?.includes(strategy)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// always use user first
|
||||
if (isAllowed(TenantResolutionStrategy.USER)) {
|
||||
const userTenantId = ctx.user?.tenantId
|
||||
if (userTenantId) {
|
||||
return userTenantId
|
||||
}
|
||||
}
|
||||
|
||||
// header
|
||||
if (isAllowed(TenantResolutionStrategy.HEADER)) {
|
||||
const headerTenantId = ctx.request.headers[Headers.TENANT_ID]
|
||||
if (headerTenantId) {
|
||||
return headerTenantId as string
|
||||
}
|
||||
}
|
||||
|
||||
// query param
|
||||
if (isAllowed(TenantResolutionStrategy.QUERY)) {
|
||||
const queryTenantId = ctx.request.query.tenantId
|
||||
if (queryTenantId) {
|
||||
return queryTenantId as string
|
||||
}
|
||||
}
|
||||
|
||||
// subdomain
|
||||
if (isAllowed(TenantResolutionStrategy.SUBDOMAIN)) {
|
||||
// e.g. budibase.app or local.com:10000
|
||||
const platformHost = new URL(env.PLATFORM_URL).host.split(":")[0]
|
||||
// e.g. tenant.budibase.app or tenant.local.com
|
||||
const requestHost = ctx.host
|
||||
// parse the tenant id from the difference
|
||||
const tenantId = requestHost.substring(
|
||||
0,
|
||||
requestHost.indexOf(`.${platformHost}`)
|
||||
)
|
||||
if (tenantId) {
|
||||
return tenantId
|
||||
}
|
||||
}
|
||||
|
||||
if (!opts.allowNoTenant) {
|
||||
ctx.throw(403, "Tenant id not set")
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -1,38 +1,41 @@
|
|||
const { DocumentType, SEPARATOR, ViewName, getAllApps } = require("./db/utils")
|
||||
import { DocumentType, SEPARATOR, ViewName, getAllApps } from "./db/utils"
|
||||
const jwt = require("jsonwebtoken")
|
||||
const { options } = require("./middleware/passport/jwt")
|
||||
const { queryGlobalView } = require("./db/views")
|
||||
const { Headers, Cookies, MAX_VALID_DATE } = require("./constants")
|
||||
const env = require("./environment")
|
||||
const userCache = require("./cache/user")
|
||||
const {
|
||||
getSessionsForUser,
|
||||
invalidateSessions,
|
||||
} = require("./security/sessions")
|
||||
const events = require("./events")
|
||||
const tenancy = require("./tenancy")
|
||||
import { options } from "./middleware/passport/jwt"
|
||||
import { queryGlobalView } from "./db/views"
|
||||
import { Headers, Cookies, MAX_VALID_DATE } from "./constants"
|
||||
import env from "./environment"
|
||||
import userCache from "./cache/user"
|
||||
import { getSessionsForUser, invalidateSessions } from "./security/sessions"
|
||||
import * as events from "./events"
|
||||
import tenancy from "./tenancy"
|
||||
import { App, BBContext, TenantResolutionStrategy } from "@budibase/types"
|
||||
import { SetOption } from "cookies"
|
||||
|
||||
const APP_PREFIX = DocumentType.APP + SEPARATOR
|
||||
const PROD_APP_PREFIX = "/app/"
|
||||
|
||||
function confirmAppId(possibleAppId) {
|
||||
function confirmAppId(possibleAppId: string | undefined) {
|
||||
return possibleAppId && possibleAppId.startsWith(APP_PREFIX)
|
||||
? possibleAppId
|
||||
: undefined
|
||||
}
|
||||
|
||||
async function resolveAppUrl(ctx) {
|
||||
async function resolveAppUrl(ctx: BBContext) {
|
||||
const appUrl = ctx.path.split("/")[2]
|
||||
let possibleAppUrl = `/${appUrl.toLowerCase()}`
|
||||
|
||||
let tenantId = tenancy.getTenantId()
|
||||
if (!env.SELF_HOSTED && ctx.subdomains.length) {
|
||||
// always use the tenant id from the url in cloud
|
||||
tenantId = ctx.subdomains[0]
|
||||
if (!env.SELF_HOSTED) {
|
||||
// always use the tenant id from the subdomain in cloud
|
||||
// this ensures the logged-in user tenant id doesn't overwrite
|
||||
// e.g. in the case of viewing a public app while already logged-in to another tenant
|
||||
tenantId = tenancy.getTenantIDFromCtx(ctx, {
|
||||
includeStrategies: [TenantResolutionStrategy.SUBDOMAIN],
|
||||
})
|
||||
}
|
||||
|
||||
// search prod apps for a url that matches
|
||||
const apps = await tenancy.doInTenant(tenantId, () =>
|
||||
const apps: App[] = await tenancy.doInTenant(tenantId, () =>
|
||||
getAllApps({ dev: false })
|
||||
)
|
||||
const app = apps.filter(
|
||||
|
@ -42,7 +45,7 @@ async function resolveAppUrl(ctx) {
|
|||
return app && app.appId ? app.appId : undefined
|
||||
}
|
||||
|
||||
exports.isServingApp = ctx => {
|
||||
export const isServingApp = (ctx: BBContext) => {
|
||||
// dev app
|
||||
if (ctx.path.startsWith(`/${APP_PREFIX}`)) {
|
||||
return true
|
||||
|
@ -59,12 +62,12 @@ exports.isServingApp = ctx => {
|
|||
* @param {object} ctx The main request body to look through.
|
||||
* @returns {string|undefined} If an appId was found it will be returned.
|
||||
*/
|
||||
exports.getAppIdFromCtx = async ctx => {
|
||||
export const getAppIdFromCtx = async (ctx: BBContext) => {
|
||||
// look in headers
|
||||
const options = [ctx.headers[Headers.APP_ID]]
|
||||
let appId
|
||||
for (let option of options) {
|
||||
appId = confirmAppId(option)
|
||||
appId = confirmAppId(option as string)
|
||||
if (appId) {
|
||||
break
|
||||
}
|
||||
|
@ -95,7 +98,7 @@ exports.getAppIdFromCtx = async ctx => {
|
|||
* opens the contents of the specified encrypted JWT.
|
||||
* @return {object} the contents of the token.
|
||||
*/
|
||||
exports.openJwt = token => {
|
||||
export const openJwt = (token: string) => {
|
||||
if (!token) {
|
||||
return token
|
||||
}
|
||||
|
@ -107,14 +110,14 @@ exports.openJwt = token => {
|
|||
* @param {object} ctx The request which is to be manipulated.
|
||||
* @param {string} name The name of the cookie to get.
|
||||
*/
|
||||
exports.getCookie = (ctx, name) => {
|
||||
export const getCookie = (ctx: BBContext, name: string) => {
|
||||
const cookie = ctx.cookies.get(name)
|
||||
|
||||
if (!cookie) {
|
||||
return cookie
|
||||
}
|
||||
|
||||
return exports.openJwt(cookie)
|
||||
return openJwt(cookie)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,12 +127,17 @@ exports.getCookie = (ctx, name) => {
|
|||
* @param {string|object} value The value of cookie which will be set.
|
||||
* @param {object} opts options like whether to sign.
|
||||
*/
|
||||
exports.setCookie = (ctx, value, name = "builder", opts = { sign: true }) => {
|
||||
export const setCookie = (
|
||||
ctx: BBContext,
|
||||
value: any,
|
||||
name = "builder",
|
||||
opts = { sign: true }
|
||||
) => {
|
||||
if (value && opts && opts.sign) {
|
||||
value = jwt.sign(value, options.secretOrKey)
|
||||
}
|
||||
|
||||
const config = {
|
||||
const config: SetOption = {
|
||||
expires: MAX_VALID_DATE,
|
||||
path: "/",
|
||||
httpOnly: false,
|
||||
|
@ -146,8 +154,8 @@ exports.setCookie = (ctx, value, name = "builder", opts = { sign: true }) => {
|
|||
/**
|
||||
* Utility function, simply calls setCookie with an empty string for value
|
||||
*/
|
||||
exports.clearCookie = (ctx, name) => {
|
||||
exports.setCookie(ctx, null, name)
|
||||
export const clearCookie = (ctx: BBContext, name: string) => {
|
||||
setCookie(ctx, null, name)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -156,7 +164,7 @@ exports.clearCookie = (ctx, name) => {
|
|||
* @param {object} ctx The koa context object to be tested.
|
||||
* @return {boolean} returns true if the call is from the client lib (a built app rather than the builder).
|
||||
*/
|
||||
exports.isClient = ctx => {
|
||||
export const isClient = (ctx: BBContext) => {
|
||||
return ctx.headers[Headers.TYPE] === "client"
|
||||
}
|
||||
|
||||
|
@ -176,18 +184,28 @@ const getBuilders = async () => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.getBuildersCount = async () => {
|
||||
export const getBuildersCount = async () => {
|
||||
const builders = await getBuilders()
|
||||
return builders.length
|
||||
}
|
||||
|
||||
interface PlatformLogoutOpts {
|
||||
ctx: BBContext
|
||||
userId: string
|
||||
keepActiveSession: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a user out from budibase. Re-used across account portal and builder.
|
||||
*/
|
||||
exports.platformLogout = async ({ ctx, userId, keepActiveSession }) => {
|
||||
export const platformLogout = async (opts: PlatformLogoutOpts) => {
|
||||
const ctx = opts.ctx
|
||||
const userId = opts.userId
|
||||
const keepActiveSession = opts.keepActiveSession
|
||||
|
||||
if (!ctx) throw new Error("Koa context must be supplied to logout.")
|
||||
|
||||
const currentSession = exports.getCookie(ctx, Cookies.Auth)
|
||||
const currentSession = getCookie(ctx, Cookies.Auth)
|
||||
let sessions = await getSessionsForUser(userId)
|
||||
|
||||
if (keepActiveSession) {
|
||||
|
@ -196,8 +214,8 @@ exports.platformLogout = async ({ ctx, userId, keepActiveSession }) => {
|
|||
)
|
||||
} else {
|
||||
// clear cookies
|
||||
exports.clearCookie(ctx, Cookies.Auth)
|
||||
exports.clearCookie(ctx, Cookies.CurrentApp)
|
||||
clearCookie(ctx, Cookies.Auth)
|
||||
clearCookie(ctx, Cookies.CurrentApp)
|
||||
}
|
||||
|
||||
const sessionIds = sessions.map(({ sessionId }) => sessionId)
|
||||
|
@ -206,6 +224,6 @@ exports.platformLogout = async ({ ctx, userId, keepActiveSession }) => {
|
|||
await userCache.invalidateUser(userId)
|
||||
}
|
||||
|
||||
exports.timeout = timeMs => {
|
||||
export const timeout = (timeMs: number) => {
|
||||
return new Promise(resolve => setTimeout(resolve, timeMs))
|
||||
}
|
|
@ -2,6 +2,36 @@
|
|||
const updateDotEnv = require("update-dotenv")
|
||||
|
||||
const arg = process.argv.slice(2)[0]
|
||||
const isEnable = arg === "enable"
|
||||
|
||||
let domain = process.argv.slice(2)[1]
|
||||
if (!domain) {
|
||||
domain = "local.com"
|
||||
}
|
||||
|
||||
const getAccountPortalUrl = () => {
|
||||
if (isEnable) {
|
||||
return `http://account.${domain}:10001`
|
||||
} else {
|
||||
return `http://localhost:10001`
|
||||
}
|
||||
}
|
||||
|
||||
const getBudibaseUrl = () => {
|
||||
if (isEnable) {
|
||||
return `http://${domain}:10000`
|
||||
} else {
|
||||
return `http://localhost:10000`
|
||||
}
|
||||
}
|
||||
|
||||
const getCookieDomain = () => {
|
||||
if (isEnable) {
|
||||
return `.${domain}`
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For testing multi tenancy sub domains locally.
|
||||
|
@ -16,9 +46,7 @@ const arg = process.argv.slice(2)[0]
|
|||
* 127.0.0.1 t2.local.com
|
||||
*/
|
||||
updateDotEnv({
|
||||
ACCOUNT_PORTAL_URL:
|
||||
arg === "enable"
|
||||
? "http://account.local.com:10001"
|
||||
: "http://localhost:10001",
|
||||
COOKIE_DOMAIN: arg === "enable" ? ".local.com" : "",
|
||||
}).then(() => console.log("Updated worker!"))
|
||||
ACCOUNT_PORTAL_URL: getAccountPortalUrl(),
|
||||
COOKIE_DOMAIN: getCookieDomain(),
|
||||
PLATFORM_URL: getBudibaseUrl(),
|
||||
}).then(() => console.log("Updated server!"))
|
||||
|
|
|
@ -149,7 +149,7 @@ export const run = async (db: any) => {
|
|||
}
|
||||
|
||||
try {
|
||||
const allApps: App[] = await dbUtils.getAllApps({ dev: true })
|
||||
const allApps = (await dbUtils.getAllApps({ dev: true })) as App[]
|
||||
totals.apps = allApps.length
|
||||
|
||||
totals.usage = await quotas.backfill(allApps)
|
||||
|
|
|
@ -2,11 +2,11 @@ import { getTenantId } from "@budibase/backend-core/tenancy"
|
|||
import { getAllApps } from "@budibase/backend-core/db"
|
||||
import { getUniqueRows } from "../../../utilities/usageQuota/rows"
|
||||
import { quotas } from "@budibase/pro"
|
||||
import { StaticQuotaName, QuotaUsageType } from "@budibase/types"
|
||||
import { StaticQuotaName, QuotaUsageType, App } from "@budibase/types"
|
||||
|
||||
export const run = async () => {
|
||||
// get all rows in all apps
|
||||
const allApps = await getAllApps({ all: true })
|
||||
const allApps = (await getAllApps({ all: true })) as App[]
|
||||
const appIds = allApps ? allApps.map((app: { appId: any }) => app.appId) : []
|
||||
const { appRows } = await getUniqueRows(appIds)
|
||||
|
||||
|
|
|
@ -9,3 +9,4 @@ export * from "./koa"
|
|||
export * from "./auth"
|
||||
export * from "./locks"
|
||||
export * from "./db"
|
||||
export * from "./middleware"
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./matchers"
|
||||
export * from "./tenancy"
|
|
@ -0,0 +1,4 @@
|
|||
export interface EndpointMatcher {
|
||||
route: string
|
||||
method: string
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
export interface GetTenantIdOptions {
|
||||
allowNoTenant?: boolean
|
||||
excludeStrategies?: TenantResolutionStrategy[]
|
||||
includeStrategies?: TenantResolutionStrategy[]
|
||||
}
|
||||
|
||||
export enum TenantResolutionStrategy {
|
||||
USER = "user",
|
||||
HEADER = "header",
|
||||
QUERY = "query",
|
||||
SUBDOMAIN = "subdomain",
|
||||
}
|
|
@ -2,6 +2,36 @@
|
|||
const updateDotEnv = require("update-dotenv")
|
||||
|
||||
const arg = process.argv.slice(2)[0]
|
||||
const isEnable = arg === "enable"
|
||||
|
||||
let domain = process.argv.slice(2)[1]
|
||||
if (!domain) {
|
||||
domain = "local.com"
|
||||
}
|
||||
|
||||
const getAccountPortalUrl = () => {
|
||||
if (isEnable) {
|
||||
return `http://account.${domain}:10001`
|
||||
} else {
|
||||
return `http://localhost:10001`
|
||||
}
|
||||
}
|
||||
|
||||
const getBudibaseUrl = () => {
|
||||
if (isEnable) {
|
||||
return `http://${domain}:10000`
|
||||
} else {
|
||||
return `http://localhost:10000`
|
||||
}
|
||||
}
|
||||
|
||||
const getCookieDomain = () => {
|
||||
if (isEnable) {
|
||||
return `.${domain}`
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For testing multi tenancy sub domains locally.
|
||||
|
@ -16,11 +46,7 @@ const arg = process.argv.slice(2)[0]
|
|||
* 127.0.0.1 t2.local.com
|
||||
*/
|
||||
updateDotEnv({
|
||||
ACCOUNT_PORTAL_URL:
|
||||
arg === "enable"
|
||||
? "http://account.local.com:10001"
|
||||
: "http://localhost:10001",
|
||||
COOKIE_DOMAIN: arg === "enable" ? ".local.com" : "",
|
||||
PLATFORM_URL:
|
||||
arg === "enable" ? "http://local.com:10000" : "http://localhost:10000",
|
||||
ACCOUNT_PORTAL_URL: getAccountPortalUrl(),
|
||||
COOKIE_DOMAIN: getCookieDomain(),
|
||||
PLATFORM_URL: getBudibaseUrl(),
|
||||
}).then(() => console.log("Updated worker!"))
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#!/bin/bash
|
||||
|
||||
enable=$1
|
||||
domain=$2
|
||||
|
||||
if [ "$enable" = "enable" ]; then
|
||||
lerna run env:localdomain:enable -- "$domain"
|
||||
cd ../account-portal
|
||||
yarn env:localdomain:enable "$domain"
|
||||
cd -
|
||||
else
|
||||
lerna run env:localdomain:disable
|
||||
cd ../account-portal
|
||||
yarn env:localdomain:disable
|
||||
cd -
|
||||
fi
|
Loading…
Reference in New Issue