diff --git a/hosting/kubernetes/budibase/templates/worker-service-deployment.yaml b/hosting/kubernetes/budibase/templates/worker-service-deployment.yaml index 98a921a8a6..08b40d3b6b 100644 --- a/hosting/kubernetes/budibase/templates/worker-service-deployment.yaml +++ b/hosting/kubernetes/budibase/templates/worker-service-deployment.yaml @@ -89,6 +89,8 @@ spec: value: {{ .Values.globals.selfHosted | quote }} - name: ACCOUNT_PORTAL_URL value: {{ .Values.globals.accountPortalUrl | quote }} + - name: ACCOUNT_PORTAL_API_KEY + value: {{ .Values.globals.accountPortalApiKey | quote }} - name: COOKIE_DOMAIN value: {{ .Values.globals.cookieDomain | quote }} image: budibase/worker diff --git a/hosting/kubernetes/budibase/values.yaml b/hosting/kubernetes/budibase/values.yaml index c9b2549b30..5999f9c4bc 100644 --- a/hosting/kubernetes/budibase/values.yaml +++ b/hosting/kubernetes/budibase/values.yaml @@ -90,6 +90,7 @@ globals: logLevel: info selfHosted: 1 accountPortalUrL: "" + accountPortalApiKey: "" cookieDomain: "" createSecrets: true # creates an internal API key, JWT secrets and redis password for you diff --git a/hosting/kubernetes/envoy/envoy.yaml b/hosting/kubernetes/envoy/envoy.yaml index 4bf751b3a3..25a774dc7e 100644 --- a/hosting/kubernetes/envoy/envoy.yaml +++ b/hosting/kubernetes/envoy/envoy.yaml @@ -50,6 +50,11 @@ static_resources: route: cluster: app-service + - match: { path: "/api/deploy" } + route: + timeout: 60s + cluster: app-service + # special case for when API requests are made, can just forward, not to minio - match: { prefix: "/api/" } route: diff --git a/lerna.json b/lerna.json index 0a0da9c300..31acac22a6 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.9.148-alpha.7", + "version": "0.9.150-alpha.0", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/package.json b/package.json index 3df577ca58..3596ec7800 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,8 @@ "multi:disable": "lerna run multi:disable", "selfhost:enable": "lerna run selfhost:enable", "selfhost:disable": "lerna run selfhost:disable", + "localdomain:enable": "lerna run localdomain:enable", + "localdomain:disable": "lerna run localdomain:disable", "postinstall": "husky install" } } diff --git a/packages/auth/package.json b/packages/auth/package.json index b5acd8c467..e84b5a7029 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/auth", - "version": "0.9.148-alpha.7", + "version": "0.9.150-alpha.0", "description": "Authentication middlewares for budibase builder and apps", "main": "src/index.js", "author": "Budibase", diff --git a/packages/auth/src/cloud/accounts.js b/packages/auth/src/cloud/accounts.js index a102df8920..a02fe60926 100644 --- a/packages/auth/src/cloud/accounts.js +++ b/packages/auth/src/cloud/accounts.js @@ -1,16 +1,18 @@ const API = require("./api") const env = require("../environment") +const { Headers } = require("../constants") const api = new API(env.ACCOUNT_PORTAL_URL) -// TODO: Authorization - exports.getAccount = async email => { const payload = { email, } const response = await api.post(`/api/accounts/search`, { body: payload, + headers: { + [Headers.API_KEY]: env.ACCOUNT_PORTAL_API_KEY, + }, }) const json = await response.json() diff --git a/packages/auth/src/environment.js b/packages/auth/src/environment.js index 7f822090d7..c36b469c4e 100644 --- a/packages/auth/src/environment.js +++ b/packages/auth/src/environment.js @@ -21,6 +21,7 @@ module.exports = { INTERNAL_API_KEY: process.env.INTERNAL_API_KEY, MULTI_TENANCY: process.env.MULTI_TENANCY, ACCOUNT_PORTAL_URL: process.env.ACCOUNT_PORTAL_URL, + ACCOUNT_PORTAL_API_KEY: process.env.ACCOUNT_PORTAL_API_KEY, DISABLE_ACCOUNT_PORTAL: process.env.DISABLE_ACCOUNT_PORTAL, SELF_HOSTED: !!parseInt(process.env.SELF_HOSTED), COOKIE_DOMAIN: process.env.COOKIE_DOMAIN, diff --git a/packages/auth/src/middleware/matchers.js b/packages/auth/src/middleware/matchers.js index a555823136..3d5065c069 100644 --- a/packages/auth/src/middleware/matchers.js +++ b/packages/auth/src/middleware/matchers.js @@ -7,6 +7,7 @@ exports.buildMatcherRegex = patterns => { return patterns.map(pattern => { const isObj = typeof pattern === "object" && pattern.route const method = isObj ? pattern.method : "GET" + const strict = pattern.strict ? pattern.strict : false let route = isObj ? pattern.route : pattern const matches = route.match(PARAM_REGEX) @@ -16,13 +17,19 @@ exports.buildMatcherRegex = patterns => { route = route.replace(match, pattern) } } - return { regex: new RegExp(route), method } + return { regex: new RegExp(route), method, strict, route } }) } exports.matches = (ctx, options) => { - return options.find(({ regex, method }) => { - const urlMatch = regex.test(ctx.request.url) + return options.find(({ regex, method, strict, route }) => { + let urlMatch + if (strict) { + urlMatch = ctx.request.url === route + } else { + urlMatch = regex.test(ctx.request.url) + } + const methodMatch = method === "ALL" ? true diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 53220fe02a..62e1c68278 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "0.9.148-alpha.7", + "version": "0.9.150-alpha.0", "license": "AGPL-3.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", diff --git a/packages/builder/package.json b/packages/builder/package.json index deca819917..3cbf160cbf 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.9.148-alpha.7", + "version": "0.9.150-alpha.0", "license": "AGPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^0.9.148-alpha.7", - "@budibase/client": "^0.9.148-alpha.7", + "@budibase/bbui": "^0.9.150-alpha.0", + "@budibase/client": "^0.9.150-alpha.0", "@budibase/colorpicker": "1.1.2", - "@budibase/string-templates": "^0.9.148-alpha.7", + "@budibase/string-templates": "^0.9.150-alpha.0", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/builder/src/components/automation/Shared/WebhookDisplay.svelte b/packages/builder/src/components/automation/Shared/WebhookDisplay.svelte index fc5e20f241..857640896c 100644 --- a/packages/builder/src/components/automation/Shared/WebhookDisplay.svelte +++ b/packages/builder/src/components/automation/Shared/WebhookDisplay.svelte @@ -1,22 +1,14 @@ diff --git a/packages/builder/src/components/design/PropertiesPanel/ScreenSettingsSection.svelte b/packages/builder/src/components/design/PropertiesPanel/ScreenSettingsSection.svelte index d782d1cd44..efe51ebdac 100644 --- a/packages/builder/src/components/design/PropertiesPanel/ScreenSettingsSection.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/ScreenSettingsSection.svelte @@ -7,6 +7,7 @@ import RoleSelect from "./PropertyControls/RoleSelect.svelte" import { currentAsset, store } from "builderStore" import { FrontendTypes } from "constants" + import sanitizeUrl from "builderStore/store/screenTemplates/utils/sanitizeUrl" export let componentInstance export let bindings @@ -37,7 +38,12 @@ key: "routing.route", label: "Route", control: Input, - parser: val => val.replace(/ +/g, "-"), + parser: val => { + if (!val.startsWith("/")) { + val = "/" + val + } + return sanitizeUrl(val) + }, }, { key: "routing.roleId", label: "Access", control: RoleSelect }, { key: "layoutId", label: "Layout", control: LayoutSelect }, diff --git a/packages/builder/src/components/upgrade/UpgradeModal.svelte b/packages/builder/src/components/upgrade/UpgradeModal.svelte index 9ceef1ddf8..7571e6d773 100644 --- a/packages/builder/src/components/upgrade/UpgradeModal.svelte +++ b/packages/builder/src/components/upgrade/UpgradeModal.svelte @@ -1,10 +1,11 @@ @@ -25,8 +26,8 @@ confirmText="Self-host Budibase" > - Self-host Budibase for free, and get SSO, unlimited apps, and more - and - it only takes a few minutes! + Self-host budibase for free to get unlimited apps and more - and it only + takes a few minutes! diff --git a/packages/builder/src/pages/builder/_layout.svelte b/packages/builder/src/pages/builder/_layout.svelte index 6cb78aa9da..625071c07e 100644 --- a/packages/builder/src/pages/builder/_layout.svelte +++ b/packages/builder/src/pages/builder/_layout.svelte @@ -14,16 +14,30 @@ $: useAccountPortal = cloud && !$admin.disableAccountPortal const validateTenantId = async () => { - // set the tenant from the url in the cloud - const tenantId = window.location.host.split(".")[0] + const host = window.location.host + if (host.includes("localhost:")) { + // ignore local dev + return + } - if (!tenantId.includes("localhost:")) { - // user doesn't have permission to access this tenant - kick them out - if (user && user.tenantId !== tenantId) { - await auth.logout() - await auth.setOrganisation(null) + if (user && user.tenantId) { + let urlTenantId + const hostParts = host.split(".") + + // only run validation when we know we are in a tenant url + // not when we visit the root budibase.app domain + // e.g. ['tenant', 'budibase', 'app'] vs ['budibase', 'app'] + if (hostParts.length > 2) { + urlTenantId = hostParts[0] } else { - await auth.setOrganisation(tenantId) + // no tenant in the url - send to account portal to fix this + window.location.href = $admin.accountPortalUrl + return + } + + if (user.tenantId !== urlTenantId) { + // user should not be here - play it safe and log them out + await auth.logout() } } } @@ -32,7 +46,7 @@ await auth.checkAuth() await admin.init() - if (cloud && multiTenancyEnabled) { + if (useAccountPortal && multiTenancyEnabled) { await validateTenantId() } diff --git a/packages/builder/src/pages/builder/app/[application]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/_layout.svelte index ae21a9dbb9..aaf948883d 100644 --- a/packages/builder/src/pages/builder/app/[application]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_layout.svelte @@ -92,7 +92,7 @@
- {#if $admin.cloud} + {#if $admin.cloud && $auth.user.account} {/if} diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/CreateEditRelationship/CreateEditRelationship.svelte b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/CreateEditRelationship/CreateEditRelationship.svelte index fbc2b401ef..583ca5e887 100644 --- a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/CreateEditRelationship/CreateEditRelationship.svelte +++ b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/CreateEditRelationship/CreateEditRelationship.svelte @@ -156,6 +156,8 @@ ...relateTo, through: through._id, fieldName: fromTable.primary[0], + throughFrom: relateFrom.throughTo, + throughTo: relateFrom.throughFrom, } } else { // the relateFrom.fieldName should remain the same, as it is the foreignKey in the other @@ -251,6 +253,22 @@ bind:error={errors.through} bind:value={fromRelationship.through} /> + {#if fromTable && toTable && through} + ($touched.toForeign = true)} + bind:error={errors.toForeign} + bind:value={fromRelationship.throughFrom} + /> + {/if} {:else if fromRelationship?.relationshipType && toTable}