Fix cross tenant apps with session

This commit is contained in:
Rory Powell 2022-03-23 16:45:06 +00:00
parent 4ee5256ad3
commit a68abf2730
11 changed files with 725 additions and 2555 deletions

View File

@ -52,9 +52,8 @@ http {
proxy_pass http://{{ address }}:4001;
}
location /app/ {
location /app {
proxy_pass http://{{ address }}:4001;
rewrite ^/app/(.*)$ /$1 break;
}
location /builder {

View File

@ -62,7 +62,6 @@ http {
location /app {
proxy_pass http://$apps:4002;
rewrite ^/app/(.*)$ /$1 break;
}
location = / {

View File

@ -3,6 +3,7 @@ const {
SEPARATOR,
ViewNames,
generateGlobalUserID,
getAllApps,
} = require("./db/utils")
const jwt = require("jsonwebtoken")
const { options } = require("./middleware/passport/jwt")
@ -20,8 +21,10 @@ const { hash } = require("./hashing")
const userCache = require("./cache/user")
const env = require("./environment")
const { getUserSessions, invalidateSessions } = require("./security/sessions")
const tenancy = require("./tenancy")
const APP_PREFIX = DocumentTypes.APP + SEPARATOR
const PROD_APP_PREFIX = "/app/"
function confirmAppId(possibleAppId) {
return possibleAppId && possibleAppId.startsWith(APP_PREFIX)
@ -29,16 +32,35 @@ function confirmAppId(possibleAppId) {
: undefined
}
async function resolveAppUrl(ctx) {
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]
}
// search prod apps for a url that matches
const apps = await tenancy.doInTenant(tenantId, () =>
getAllApps({ dev: false })
)
const app = apps.filter(
a => a.url && a.url.toLowerCase() === possibleAppUrl
)[0]
return app && app.appId ? app.appId : undefined
}
/**
* Given a request tries to find the appId, which can be located in various places
* @param {object} ctx The main request body to look through.
* @returns {string|undefined} If an appId was found it will be returned.
*/
exports.getAppId = ctx => {
const options = [ctx.headers[Headers.APP_ID], ctx.params.appId]
if (ctx.subdomains) {
options.push(ctx.subdomains[1])
}
exports.getAppIdFromCtx = async ctx => {
// look in headers
const options = [ctx.headers[Headers.APP_ID]]
let appId
for (let option of options) {
appId = confirmAppId(option)
@ -47,16 +69,24 @@ exports.getAppId = ctx => {
}
}
// look in body if can't find it in subdomain
// look in body
if (!appId && ctx.request.body && ctx.request.body.appId) {
appId = confirmAppId(ctx.request.body.appId)
}
// look in the url - dev app
let appPath =
ctx.request.headers.referrer ||
ctx.path.split("/").filter(subPath => subPath.startsWith(APP_PREFIX))
if (!appId && appPath.length !== 0) {
if (!appId && appPath.length) {
appId = confirmAppId(appPath[0])
}
// look in the url - prod app
if (!appId && ctx.path.startsWith(PROD_APP_PREFIX)) {
appId = confirmAppId(await resolveAppUrl(ctx))
}
return appId
}

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,6 @@ const { resolve, join } = require("../../../utilities/centralPath")
const uuid = require("uuid")
const { ObjectStoreBuckets } = require("../../../constants")
const { processString } = require("@budibase/string-templates")
const { getAllApps } = require("@budibase/backend-core/db")
const {
loadHandlebarsFile,
NODE_MODULES_PATH,
@ -16,7 +15,7 @@ const { clientLibraryPath } = require("../../../utilities")
const { upload } = require("../../../utilities/fileSystem")
const { attachmentsRelativeURL } = require("../../../utilities")
const { DocumentTypes } = require("../../../db/utils")
const { getAppDB, updateAppId } = require("@budibase/backend-core/context")
const { getAppDB, getAppId } = require("@budibase/backend-core/context")
const AWS = require("aws-sdk")
const AWS_REGION = env.AWS_REGION ? env.AWS_REGION : "eu-west-1"
@ -39,21 +38,6 @@ async function prepareUpload({ s3Key, bucket, metadata, file }) {
}
}
async function getAppIdFromUrl(ctx) {
// the "appId" component of the URL can be the id or the custom url
let possibleAppUrl = `/${encodeURI(ctx.params.appId).toLowerCase()}`
// search prod apps for a url that matches, exclude dev where id is always used
const apps = await getAllApps({ dev: false })
const app = apps.filter(
a => a.url && a.url.toLowerCase() === possibleAppUrl
)[0]
const appId = app && app.appId ? app.appId : ctx.params.appId
updateAppId(appId)
return appId
}
exports.serveBuilder = async function (ctx) {
let builderPath = resolve(TOP_LEVEL_PATH, "builder")
await send(ctx, ctx.file, { root: builderPath })
@ -81,10 +65,10 @@ exports.uploadFile = async function (ctx) {
}
exports.serveApp = async function (ctx) {
let appId = await getAppIdFromUrl(ctx)
const App = require("./templates/BudibaseApp.svelte").default
const db = getAppDB({ skip_setup: true })
const appInfo = await db.get(DocumentTypes.APP_METADATA)
let appId = getAppId()
const { head, html, css } = App.render({
title: appInfo.name,

View File

@ -44,8 +44,7 @@ router
authorized(PermissionTypes.TABLE, PermissionLevels.WRITE),
controller.uploadFile
)
// TODO: this likely needs to be secured in some way
.get("/:appId/:path*", controller.serveApp)
.get("/app/:appUrl/:path*", controller.serveApp)
.post(
"/api/attachments/:datasourceId/url",
authorized(PermissionTypes.TABLE, PermissionLevels.READ),

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
const {
getAppId,
getAppIdFromCtx,
setCookie,
getCookie,
clearCookie,
@ -17,7 +17,7 @@ const { doInAppContext } = require("@budibase/backend-core/context")
module.exports = async (ctx, next) => {
// try to get the appID from the request
let requestAppId = getAppId(ctx)
let requestAppId = await getAppIdFromCtx(ctx)
// get app cookie if it exists
let appCookie = null
try {

View File

@ -1,9 +1,9 @@
const { Headers } = require("@budibase/backend-core/constants")
const { getAppId } = require("@budibase/backend-core/utils")
const { getAppIdFromCtx } = require("@budibase/backend-core/utils")
module.exports = function ({ requiresAppId } = {}) {
return async (ctx, next) => {
const appId = getAppId(ctx)
const appId = await getAppIdFromCtx(ctx)
if (requiresAppId && !appId) {
ctx.throw(
400,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff