diff --git a/.github/workflows/deploy-preprod.yml b/.github/workflows/deploy-preprod.yml index a1eee2c465..57e2504ded 100644 --- a/.github/workflows/deploy-preprod.yml +++ b/.github/workflows/deploy-preprod.yml @@ -17,6 +17,7 @@ jobs: id: version run: | if [ -z "${{ github.event.inputs.version }}" ]; then + git pull release_version=$(cat lerna.json | jq -r '.version') else release_version=${{ github.event.inputs.version }} diff --git a/.github/workflows/release-master.yml b/.github/workflows/release-master.yml index 20a48f5802..41af142bfc 100644 --- a/.github/workflows/release-master.yml +++ b/.github/workflows/release-master.yml @@ -134,6 +134,7 @@ jobs: - name: Get the latest budibase release version id: version run: | + git pull release_version=$(cat lerna.json | jq -r '.version') echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV diff --git a/charts/budibase/templates/app-service-deployment.yaml b/charts/budibase/templates/app-service-deployment.yaml index 9ff7dc1ddc..df4070806f 100644 --- a/charts/budibase/templates/app-service-deployment.yaml +++ b/charts/budibase/templates/app-service-deployment.yaml @@ -212,11 +212,24 @@ spec: image: budibase/apps:{{ .Values.globals.appVersion }} imagePullPolicy: Always livenessProbe: + httpGet: + path: /health + port: {{ .Values.services.apps.port }} + initialDelaySeconds: 10 + periodSeconds: 5 + successThreshold: 1 + failureThreshold: 3 + timeoutSeconds: 3 + readinessProbe: httpGet: path: /health port: {{ .Values.services.apps.port }} initialDelaySeconds: 5 periodSeconds: 5 + successThreshold: 1 + failureThreshold: 3 + timeoutSeconds: 3 + name: bbapps ports: - containerPort: {{ .Values.services.apps.port }} diff --git a/charts/budibase/templates/worker-service-deployment.yaml b/charts/budibase/templates/worker-service-deployment.yaml index f998e5dfb9..f48d19689b 100644 --- a/charts/budibase/templates/worker-service-deployment.yaml +++ b/charts/budibase/templates/worker-service-deployment.yaml @@ -202,11 +202,23 @@ spec: image: budibase/worker:{{ .Values.globals.appVersion }} imagePullPolicy: Always livenessProbe: + httpGet: + path: /health + port: {{ .Values.services.worker.port }} + initialDelaySeconds: 10 + periodSeconds: 5 + successThreshold: 1 + failureThreshold: 3 + timeoutSeconds: 3 + readinessProbe: httpGet: path: /health port: {{ .Values.services.worker.port }} initialDelaySeconds: 5 periodSeconds: 5 + successThreshold: 1 + failureThreshold: 3 + timeoutSeconds: 3 name: bbworker ports: - containerPort: {{ .Values.services.worker.port }} diff --git a/charts/budibase/values.yaml b/charts/budibase/values.yaml index ed4ff014a9..ccbbf9878e 100644 --- a/charts/budibase/values.yaml +++ b/charts/budibase/values.yaml @@ -343,6 +343,7 @@ couchdb: ## Configure liveness and readiness probe values ## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes + # FOR COUCHDB livenessProbe: enabled: true failureThreshold: 3 diff --git a/lerna.json b/lerna.json index 85a8ed3fcb..7926e03ecb 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.4.27-alpha.12", + "version": "2.4.42-alpha.5", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index 48b5694fa5..e7c6217cee 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.4.27-alpha.12", + "version": "2.4.42-alpha.5", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -24,7 +24,7 @@ "dependencies": { "@budibase/nano": "10.1.2", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "2.4.27-alpha.12", + "@budibase/types": "2.4.42-alpha.5", "@shopify/jest-koa-mocks": "5.0.1", "@techpass/passport-openidconnect": "0.3.2", "aws-cloudfront-sign": "2.2.0", diff --git a/packages/backend-core/src/auth/auth.ts b/packages/backend-core/src/auth/auth.ts index 26c7cd4e26..fb2fd2cf51 100644 --- a/packages/backend-core/src/auth/auth.ts +++ b/packages/backend-core/src/auth/auth.ts @@ -199,7 +199,6 @@ export async function platformLogout(opts: PlatformLogoutOpts) { } else { // clear cookies clearCookie(ctx, Cookie.Auth) - clearCookie(ctx, Cookie.CurrentApp) } const sessionIds = sessions.map(({ sessionId }) => sessionId) diff --git a/packages/backend-core/src/blacklist/blacklist.ts b/packages/backend-core/src/blacklist/blacklist.ts new file mode 100644 index 0000000000..1fbb4683f9 --- /dev/null +++ b/packages/backend-core/src/blacklist/blacklist.ts @@ -0,0 +1,54 @@ +import dns from "dns" +import net from "net" +import env from "../environment" +import { promisify } from "util" + +let blackListArray: string[] | undefined +const performLookup = promisify(dns.lookup) + +async function lookup(address: string): Promise { + if (!net.isIP(address)) { + // need this for URL parsing simply + if (!address.startsWith("http")) { + address = `https://${address}` + } + address = new URL(address).hostname + } + const addresses = await performLookup(address, { + all: true, + }) + return addresses.map(addr => addr.address) +} + +export async function refreshBlacklist() { + const blacklist = env.BLACKLIST_IPS + const list = blacklist?.split(",") || [] + let final: string[] = [] + for (let addr of list) { + const trimmed = addr.trim() + if (!net.isIP(trimmed)) { + const addresses = await lookup(trimmed) + final = final.concat(addresses) + } else { + final.push(trimmed) + } + } + blackListArray = final +} + +export async function isBlacklisted(address: string): Promise { + if (!blackListArray) { + await refreshBlacklist() + } + if (blackListArray?.length === 0) { + return false + } + // no need for DNS + let ips: string[] + if (!net.isIP(address)) { + ips = await lookup(address) + } else { + ips = [address] + } + return !!blackListArray?.find(addr => ips.includes(addr)) +} diff --git a/packages/backend-core/src/blacklist/index.ts b/packages/backend-core/src/blacklist/index.ts new file mode 100644 index 0000000000..b5123eed3e --- /dev/null +++ b/packages/backend-core/src/blacklist/index.ts @@ -0,0 +1 @@ +export * from "./blacklist" diff --git a/packages/backend-core/src/blacklist/tests/blacklist.spec.ts b/packages/backend-core/src/blacklist/tests/blacklist.spec.ts new file mode 100644 index 0000000000..23a8dd1454 --- /dev/null +++ b/packages/backend-core/src/blacklist/tests/blacklist.spec.ts @@ -0,0 +1,46 @@ +import { refreshBlacklist, isBlacklisted } from ".." +import env from "../../environment" + +describe("blacklist", () => { + beforeAll(async () => { + env._set( + "BLACKLIST_IPS", + "www.google.com,192.168.1.1, 1.1.1.1,2.2.2.2/something" + ) + await refreshBlacklist() + }) + + it("should blacklist 192.168.1.1", async () => { + expect(await isBlacklisted("192.168.1.1")).toBe(true) + }) + + it("should allow 192.168.1.2", async () => { + expect(await isBlacklisted("192.168.1.2")).toBe(false) + }) + + it("should blacklist www.google.com", async () => { + expect(await isBlacklisted("www.google.com")).toBe(true) + }) + + it("should handle a complex domain", async () => { + expect( + await isBlacklisted("https://www.google.com/derp/?something=1") + ).toBe(true) + }) + + it("should allow www.microsoft.com", async () => { + expect(await isBlacklisted("www.microsoft.com")).toBe(false) + }) + + it("should blacklist an IP that needed trimming", async () => { + expect(await isBlacklisted("1.1.1.1")).toBe(true) + }) + + it("should blacklist 1.1.1.1/something", async () => { + expect(await isBlacklisted("1.1.1.1/something")).toBe(true) + }) + + it("should blacklist 2.2.2.2", async () => { + expect(await isBlacklisted("2.2.2.2")).toBe(true) + }) +}) diff --git a/packages/backend-core/src/configs/tests/configs.spec.ts b/packages/backend-core/src/configs/tests/configs.spec.ts index 079f2ab681..45e56a2581 100644 --- a/packages/backend-core/src/configs/tests/configs.spec.ts +++ b/packages/backend-core/src/configs/tests/configs.spec.ts @@ -1,4 +1,9 @@ -import { DBTestConfiguration, generator, testEnv } from "../../../tests" +import { + DBTestConfiguration, + generator, + testEnv, + structures, +} from "../../../tests" import { ConfigType } from "@budibase/types" import env from "../../environment" import * as configs from "../configs" @@ -113,4 +118,71 @@ describe("configs", () => { }) }) }) + + describe("getGoogleDatasourceConfig", () => { + function setEnvVars() { + env.GOOGLE_CLIENT_SECRET = "test" + env.GOOGLE_CLIENT_ID = "test" + } + + function unsetEnvVars() { + env.GOOGLE_CLIENT_SECRET = undefined + env.GOOGLE_CLIENT_ID = undefined + } + + describe("cloud", () => { + beforeEach(() => { + testEnv.cloudHosted() + }) + + it("returns from env vars", async () => { + await config.doInTenant(async () => { + setEnvVars() + const config = await configs.getGoogleDatasourceConfig() + unsetEnvVars() + + expect(config).toEqual({ + activated: true, + clientID: "test", + clientSecret: "test", + }) + }) + }) + + it("returns undefined when no env vars are configured", async () => { + await config.doInTenant(async () => { + const config = await configs.getGoogleDatasourceConfig() + expect(config).toBeUndefined() + }) + }) + }) + + describe("self host", () => { + beforeEach(() => { + testEnv.selfHosted() + }) + + it("returns from config", async () => { + await config.doInTenant(async () => { + const googleDoc = structures.sso.googleConfigDoc() + await configs.save(googleDoc) + const config = await configs.getGoogleDatasourceConfig() + expect(config).toEqual(googleDoc.config) + }) + }) + + it("falls back to env vars when config is disabled", async () => { + await config.doInTenant(async () => { + setEnvVars() + const config = await configs.getGoogleDatasourceConfig() + unsetEnvVars() + expect(config).toEqual({ + activated: true, + clientID: "test", + clientSecret: "test", + }) + }) + }) + }) + }) }) diff --git a/packages/backend-core/src/constants/misc.ts b/packages/backend-core/src/constants/misc.ts index e25c90575f..15cec7a6b9 100644 --- a/packages/backend-core/src/constants/misc.ts +++ b/packages/backend-core/src/constants/misc.ts @@ -4,7 +4,6 @@ export enum UserStatus { } export enum Cookie { - CurrentApp = "budibase:currentapp", Auth = "budibase:auth", Init = "budibase:init", ACCOUNT_RETURN_URL = "budibase:account:returnurl", diff --git a/packages/backend-core/src/environment.ts b/packages/backend-core/src/environment.ts index f1c96c7fec..5718494fc4 100644 --- a/packages/backend-core/src/environment.ts +++ b/packages/backend-core/src/environment.ts @@ -104,6 +104,7 @@ const environment = { SMTP_PORT: parseInt(process.env.SMTP_PORT || ""), SMTP_FROM_ADDRESS: process.env.SMTP_FROM_ADDRESS, DISABLE_JWT_WARNING: process.env.DISABLE_JWT_WARNING, + BLACKLIST_IPS: process.env.BLACKLIST_IPS, /** * Enable to allow an admin user to login using a password. * This can be useful to prevent lockout when configuring SSO. diff --git a/packages/backend-core/src/index.ts b/packages/backend-core/src/index.ts index a6d5423756..30072196ba 100644 --- a/packages/backend-core/src/index.ts +++ b/packages/backend-core/src/index.ts @@ -26,6 +26,7 @@ export * as utils from "./utils" export * as errors from "./errors" export * as timers from "./timers" export { default as env } from "./environment" +export * as blacklist from "./blacklist" export { SearchParams } from "./db" // Add context to tenancy for backwards compatibility // only do this for external usages to prevent internal diff --git a/packages/backend-core/tests/utilities/structures/sso.ts b/packages/backend-core/tests/utilities/structures/sso.ts index 7413fa3c09..9da9c82223 100644 --- a/packages/backend-core/tests/utilities/structures/sso.ts +++ b/packages/backend-core/tests/utilities/structures/sso.ts @@ -1,4 +1,6 @@ import { + ConfigType, + GoogleConfig, GoogleInnerConfig, JwtClaims, OAuth2, @@ -10,10 +12,10 @@ import { User, } from "@budibase/types" import { generator } from "./generator" -import { uuid, email } from "./common" +import { email, uuid } from "./common" import * as shared from "./shared" -import _ from "lodash" import { user } from "./shared" +import _ from "lodash" export function OAuth(): OAuth2 { return { @@ -107,3 +109,11 @@ export function googleConfig(): GoogleInnerConfig { clientSecret: generator.string(), } } + +export function googleConfigDoc(): GoogleConfig { + return { + _id: "config_google", + type: ConfigType.GOOGLE, + config: googleConfig(), + } +} diff --git a/packages/bbui/package.json b/packages/bbui/package.json index cd0bafb66f..b4c0241a49 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": "2.4.27-alpha.12", + "version": "2.4.42-alpha.5", "license": "MPL-2.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", @@ -38,8 +38,8 @@ ], "dependencies": { "@adobe/spectrum-css-workflow-icons": "1.2.1", - "@budibase/shared-core": "2.4.27-alpha.12", - "@budibase/string-templates": "2.4.27-alpha.12", + "@budibase/shared-core": "2.4.42-alpha.5", + "@budibase/string-templates": "2.4.42-alpha.5", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/builder/package.json b/packages/builder/package.json index 781d0221df..1e175eb757 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.4.27-alpha.12", + "version": "2.4.42-alpha.5", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,11 +58,11 @@ } }, "dependencies": { - "@budibase/bbui": "2.4.27-alpha.12", - "@budibase/client": "2.4.27-alpha.12", - "@budibase/frontend-core": "2.4.27-alpha.12", - "@budibase/shared-core": "2.4.27-alpha.12", - "@budibase/string-templates": "2.4.27-alpha.12", + "@budibase/bbui": "2.4.42-alpha.5", + "@budibase/client": "2.4.42-alpha.5", + "@budibase/frontend-core": "2.4.42-alpha.5", + "@budibase/shared-core": "2.4.42-alpha.5", + "@budibase/string-templates": "2.4.42-alpha.5", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/free-brands-svg-icons": "^6.2.1", "@fortawesome/free-solid-svg-icons": "^6.2.1", diff --git a/packages/builder/src/builderStore/componentUtils.js b/packages/builder/src/builderStore/componentUtils.js index a9425da742..16b972058e 100644 --- a/packages/builder/src/builderStore/componentUtils.js +++ b/packages/builder/src/builderStore/componentUtils.js @@ -163,7 +163,12 @@ export const getComponentSettings = componentType => { def.settings ?.filter(setting => setting.section) .forEach(section => { - settings = settings.concat(section.settings || []) + settings = settings.concat( + (section.settings || []).map(setting => ({ + ...setting, + section: section.name, + })) + ) }) } componentSettingCache[componentType] = settings diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index f47fb8a086..eb9c618c24 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -32,8 +32,8 @@ import { getSchemaForTable } from "builderStore/dataBinding" import { Utils } from "@budibase/frontend-core" import { TriggerStepID, ActionStepID } from "constants/backend/automations" - import { cloneDeep } from "lodash/fp" import { onMount } from "svelte" + import { cloneDeep } from "lodash/fp" export let block export let testData @@ -214,8 +214,6 @@ function saveFilters(key) { const filters = LuceneUtils.buildLuceneQuery(tempFilters) const defKey = `${key}-def` - inputData[key] = filters - inputData[defKey] = tempFilters onChange({ detail: filters }, key) // need to store the builder definition in the automation onChange({ detail: tempFilters }, defKey) diff --git a/packages/builder/src/components/automation/SetupPanel/RowSelector.svelte b/packages/builder/src/components/automation/SetupPanel/RowSelector.svelte index c14455b7fc..1080fc7305 100644 --- a/packages/builder/src/components/automation/SetupPanel/RowSelector.svelte +++ b/packages/builder/src/components/automation/SetupPanel/RowSelector.svelte @@ -95,8 +95,11 @@ } const onChange = (e, field, type) => { - value[field] = coerce(e.detail, type) - dispatch("change", value) + let newValue = { + ...value, + [field]: coerce(e.detail, type), + } + dispatch("change", newValue) } const onChangeSetting = (e, field) => { diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte index c12ddab78d..de9ecce778 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte +++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte @@ -12,7 +12,7 @@ // kill the reference so the input isn't saved let datasource = cloneDeep(integration) - $: isGoogleConfigured = !!$organisation.google + $: isGoogleConfigured = !!$organisation.googleDatasourceConfigured onMount(async () => { await organisation.init() diff --git a/packages/builder/src/components/design/settings/controls/PropertyControl.svelte b/packages/builder/src/components/design/settings/controls/PropertyControl.svelte index e190805654..3fb3e13a94 100644 --- a/packages/builder/src/components/design/settings/controls/PropertyControl.svelte +++ b/packages/builder/src/components/design/settings/controls/PropertyControl.svelte @@ -8,6 +8,7 @@ import { onDestroy } from "svelte" export let label = "" + export let labelHidden = false export let componentInstance = {} export let control = null export let key = "" @@ -76,10 +77,10 @@
- {#if label} + {#if label && !labelHidden} {/if}
diff --git a/packages/builder/src/pages/builder/_layout.svelte b/packages/builder/src/pages/builder/_layout.svelte index 25b25e754c..b216958045 100644 --- a/packages/builder/src/pages/builder/_layout.svelte +++ b/packages/builder/src/pages/builder/_layout.svelte @@ -10,24 +10,27 @@ $: multiTenancyEnabled = $admin.multiTenancy $: hasAdminUser = $admin?.checklist?.adminUser?.checked + $: baseUrl = $admin?.baseUrl $: tenantSet = $auth.tenantSet - $: cloud = $admin.cloud + $: cloud = $admin?.cloud $: user = $auth.user $: useAccountPortal = cloud && !$admin.disableAccountPortal const validateTenantId = async () => { const host = window.location.host - if (host.includes("localhost:")) { + if (host.includes("localhost:") || !baseUrl) { // ignore local dev return } - // e.g. ['tenant', 'budibase', 'app'] vs ['budibase', 'app'] + const mainHost = new URL(baseUrl).host let urlTenantId - const hostParts = host.split(".") - if (hostParts.length > 2) { - urlTenantId = hostParts[0] + // remove the main host part + const hostParts = host.split(mainHost).filter(part => part !== "") + // if there is a part left, it has to be the tenant ID subdomain + if (hostParts.length === 1) { + urlTenantId = hostParts[0].replace(/\./g, "") } if (user && user.tenantId) { @@ -47,7 +50,9 @@ await auth.logout() await auth.setOrganisation(null) } catch (error) { - console.error("Tenant mis-match, logout.") + console.error( + `Tenant mis-match - "${urlTenantId}" and "${user.tenantId}" - logout` + ) } } } else { @@ -74,7 +79,7 @@ } // Validate tenant if in a multi-tenant env - if (useAccountPortal && multiTenancyEnabled) { + if (multiTenancyEnabled) { await validateTenantId() } } catch (error) { diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/settings/ComponentSettingsSection.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/settings/ComponentSettingsSection.svelte index c21094c7f2..8fa0af45ed 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/settings/ComponentSettingsSection.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/settings/ComponentSettingsSection.svelte @@ -133,6 +133,7 @@ type={setting.type} control={getComponentForSetting(setting)} label={setting.label} + labelHidden={setting.labelHidden} key={setting.key} value={componentInstance[setting.key]} defaultValue={setting.defaultValue} diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/settings/ConditionalUIDrawer.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/settings/ConditionalUIDrawer.svelte index 855c42173b..db6e66b87b 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/settings/ConditionalUIDrawer.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/settings/ConditionalUIDrawer.svelte @@ -62,7 +62,7 @@ type: "text", }) $: settingOptions = settings.map(setting => ({ - label: setting.label, + label: makeLabel(setting), value: setting.key, })) $: conditions.forEach(link => { @@ -71,6 +71,15 @@ } }) + const makeLabel = setting => { + const { section, label } = setting + if (section) { + return label ? `${section} - ${label}` : section + } else { + return label + } + } + const getSettingDefinition = key => { return settings.find(setting => setting.key === key) } diff --git a/packages/builder/src/stores/backend/tables.js b/packages/builder/src/stores/backend/tables.js index ee38504dd1..3b7ce35dde 100644 --- a/packages/builder/src/stores/backend/tables.js +++ b/packages/builder/src/stores/backend/tables.js @@ -22,6 +22,18 @@ export function createTablesStore() { })) } + const fetchTable = async tableId => { + const table = await API.fetchTableDefinition(tableId) + + store.update(state => { + const indexToUpdate = state.list.findIndex(t => t._id === table._id) + state.list[indexToUpdate] = table + return { + ...state, + } + }) + } + const select = tableId => { store.update(state => ({ ...state, @@ -126,6 +138,7 @@ export function createTablesStore() { return { subscribe: derivedStore.subscribe, fetch, + fetchTable, init: fetch, select, save, diff --git a/packages/builder/src/stores/portal/admin.js b/packages/builder/src/stores/portal/admin.js index ba95db64b7..273d92f463 100644 --- a/packages/builder/src/stores/portal/admin.js +++ b/packages/builder/src/stores/portal/admin.js @@ -53,6 +53,7 @@ export function createAdminStore() { store.disableAccountPortal = environment.disableAccountPortal store.accountPortalUrl = environment.accountPortalUrl store.isDev = environment.isDev + store.baseUrl = environment.baseUrl return store }) } diff --git a/packages/builder/src/stores/portal/organisation.js b/packages/builder/src/stores/portal/organisation.js index 486b45642d..ed7dd36636 100644 --- a/packages/builder/src/stores/portal/organisation.js +++ b/packages/builder/src/stores/portal/organisation.js @@ -19,6 +19,7 @@ const DEFAULT_CONFIG = { company: "Budibase", oidc: undefined, google: undefined, + googleDatasourceConfigured: undefined, oidcCallbackUrl: "", googleCallbackUrl: "", isSSOEnforced: false, @@ -39,6 +40,7 @@ export function createOrganisationStore() { const storeConfig = _.cloneDeep(get(store)) delete storeConfig.oidc delete storeConfig.google + delete storeConfig.googleDatasourceConfigured delete storeConfig.oidcCallbackUrl delete storeConfig.googleCallbackUrl await API.saveConfig({ diff --git a/packages/cli/package.json b/packages/cli/package.json index 27b522d69c..8dc178342f 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "2.4.27-alpha.12", + "version": "2.4.42-alpha.5", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "dist/index.js", "bin": { @@ -29,9 +29,9 @@ "outputPath": "build" }, "dependencies": { - "@budibase/backend-core": "2.4.27-alpha.12", - "@budibase/string-templates": "2.4.27-alpha.12", - "@budibase/types": "2.4.27-alpha.12", + "@budibase/backend-core": "2.4.42-alpha.5", + "@budibase/string-templates": "2.4.42-alpha.5", + "@budibase/types": "2.4.42-alpha.5", "axios": "0.21.2", "chalk": "4.1.0", "cli-progress": "3.11.2", diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 5d0c6a33a5..8977244a0d 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -4389,6 +4389,8 @@ "name": "On row click", "settings": [ { + "label": "Behaviour", + "labelHidden": true, "type": "radio", "key": "clickBehaviour", "sendEvents": true, @@ -4406,6 +4408,8 @@ ] }, { + "label": "Actions", + "labelHidden": true, "type": "event", "key": "onClick", "nested": true, @@ -4442,7 +4446,7 @@ { "type": "radio", "key": "titleButtonClickBehaviour", - "label": "Click behaviour", + "label": "Behaviour", "dependsOn": "showTitleButton", "defaultValue": "actions", "info": "New row side panel is only compatible with internal or SQL tables", @@ -4460,6 +4464,8 @@ { "label": "On click", "type": "event", + "label": "On click", + "labelHidden": true, "key": "onClickTitleButton", "nested": true, "dependsOn": { diff --git a/packages/client/package.json b/packages/client/package.json index 21ad1c8dfb..b491cad175 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "2.4.27-alpha.12", + "version": "2.4.42-alpha.5", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,11 +19,11 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "2.4.27-alpha.12", - "@budibase/frontend-core": "2.4.27-alpha.12", - "@budibase/shared-core": "2.4.27-alpha.12", - "@budibase/string-templates": "2.4.27-alpha.12", - "@budibase/types": "2.4.27-alpha.12", + "@budibase/bbui": "2.4.42-alpha.5", + "@budibase/frontend-core": "2.4.42-alpha.5", + "@budibase/shared-core": "2.4.42-alpha.5", + "@budibase/string-templates": "2.4.42-alpha.5", + "@budibase/types": "2.4.42-alpha.5", "@spectrum-css/button": "^3.0.3", "@spectrum-css/card": "^3.0.3", "@spectrum-css/divider": "^1.0.3", diff --git a/packages/frontend-core/package.json b/packages/frontend-core/package.json index 43a5784547..48678278cd 100644 --- a/packages/frontend-core/package.json +++ b/packages/frontend-core/package.json @@ -1,13 +1,13 @@ { "name": "@budibase/frontend-core", - "version": "2.4.27-alpha.12", + "version": "2.4.42-alpha.5", "description": "Budibase frontend core libraries used in builder and client", "author": "Budibase", "license": "MPL-2.0", "svelte": "src/index.js", "dependencies": { - "@budibase/bbui": "2.4.27-alpha.12", - "@budibase/shared-core": "2.4.27-alpha.12", + "@budibase/bbui": "2.4.42-alpha.5", + "@budibase/shared-core": "2.4.42-alpha.5", "dayjs": "^1.11.7", "lodash": "^4.17.21", "socket.io-client": "^4.6.1", diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 078a431367..57d0973471 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/sdk", - "version": "2.4.27-alpha.12", + "version": "2.4.42-alpha.5", "description": "Budibase Public API SDK", "author": "Budibase", "license": "MPL-2.0", diff --git a/packages/server/package.json b/packages/server/package.json index 44af324a80..ffbdecfb93 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "2.4.27-alpha.12", + "version": "2.4.42-alpha.5", "description": "Budibase Web Server", "main": "src/index.ts", "repository": { @@ -44,12 +44,12 @@ "license": "GPL-3.0", "dependencies": { "@apidevtools/swagger-parser": "10.0.3", - "@budibase/backend-core": "2.4.27-alpha.12", - "@budibase/client": "2.4.27-alpha.12", - "@budibase/pro": "2.4.27-alpha.12", - "@budibase/shared-core": "2.4.27-alpha.12", - "@budibase/string-templates": "2.4.27-alpha.12", - "@budibase/types": "2.4.27-alpha.12", + "@budibase/backend-core": "2.4.42-alpha.5", + "@budibase/client": "2.4.42-alpha.5", + "@budibase/pro": "2.4.42-alpha.5", + "@budibase/shared-core": "2.4.42-alpha.5", + "@budibase/string-templates": "2.4.42-alpha.5", + "@budibase/types": "2.4.42-alpha.5", "@bull-board/api": "3.7.0", "@bull-board/koa": "3.9.4", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/server/src/api/controllers/row/index.ts b/packages/server/src/api/controllers/row/index.ts index d55b1ce726..21737d975a 100644 --- a/packages/server/src/api/controllers/row/index.ts +++ b/packages/server/src/api/controllers/row/index.ts @@ -144,10 +144,15 @@ export async function search(ctx: any) { export async function validate(ctx: Ctx) { const tableId = getTableId(ctx) - ctx.body = await utils.validate({ - row: ctx.request.body, - tableId, - }) + // external tables are hard to validate currently + if (isExternalTable(tableId)) { + ctx.body = { valid: true } + } else { + ctx.body = await utils.validate({ + row: ctx.request.body, + tableId, + }) + } } export async function fetchEnrichedRow(ctx: any) { diff --git a/packages/server/src/api/controllers/static/templates/BudibaseApp.svelte b/packages/server/src/api/controllers/static/templates/BudibaseApp.svelte index 8a495aec93..5df821f453 100644 --- a/packages/server/src/api/controllers/static/templates/BudibaseApp.svelte +++ b/packages/server/src/api/controllers/static/templates/BudibaseApp.svelte @@ -23,7 +23,7 @@ - + @@ -32,8 +32,8 @@ - - + + {title} diff --git a/packages/server/src/automations/automationUtils.ts b/packages/server/src/automations/automationUtils.ts index 478acc8fab..44de2e7d6b 100644 --- a/packages/server/src/automations/automationUtils.ts +++ b/packages/server/src/automations/automationUtils.ts @@ -107,7 +107,7 @@ export function substituteLoopStep(hbsString: string, substitute: string) { let pointer = 0, openPointer = 0, closedPointer = 0 - while (pointer < hbsString.length) { + while (pointer < hbsString?.length) { openPointer = hbsString.indexOf(open, pointer) closedPointer = hbsString.indexOf(closed, pointer) + 2 if (openPointer < 0 || closedPointer < 0) { diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index a21c8e7d54..90107dfd4e 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -156,7 +156,7 @@ class InternalBuilder { const rawFnc = `${fnc}Raw` // @ts-ignore query = query[rawFnc](`LOWER(${likeKey(this.client, key)}) LIKE ?`, [ - `%${value}%`, + `%${value.toLowerCase()}%`, ]) } } @@ -202,7 +202,7 @@ class InternalBuilder { let statement = "" for (let i in value) { if (typeof value[i] === "string") { - value[i] = `%"${value[i]}"%` + value[i] = `%"${value[i].toLowerCase()}"%` } else { value[i] = `%${value[i]}%` } @@ -238,7 +238,7 @@ class InternalBuilder { const rawFnc = `${fnc}Raw` // @ts-ignore query = query[rawFnc](`LOWER(${likeKey(this.client, key)}) LIKE ?`, [ - `${value}%`, + `${value.toLowerCase()}%`, ]) } }) diff --git a/packages/server/src/integrations/rest.ts b/packages/server/src/integrations/rest.ts index c24636a5fd..dc63b961c4 100644 --- a/packages/server/src/integrations/rest.ts +++ b/packages/server/src/integrations/rest.ts @@ -19,6 +19,7 @@ import { formatBytes } from "../utilities" import { performance } from "perf_hooks" import FormData from "form-data" import { URLSearchParams } from "url" +import { blacklist } from "@budibase/backend-core" const BodyTypes = { NONE: "none", @@ -398,6 +399,9 @@ class RestIntegration implements IntegrationBase { this.startTimeMs = performance.now() const url = this.getUrl(path, queryString, pagination, paginationValues) + if (await blacklist.isBlacklisted(url)) { + throw new Error("Cannot connect to URL.") + } const response = await fetch(url, input) return await this.parseResponse(response, pagination) } diff --git a/packages/server/src/integrations/tests/sql.spec.ts b/packages/server/src/integrations/tests/sql.spec.ts index 2b9a0f1f10..bd1497bdc7 100644 --- a/packages/server/src/integrations/tests/sql.spec.ts +++ b/packages/server/src/integrations/tests/sql.spec.ts @@ -351,7 +351,7 @@ describe("SQL query builder", () => { }) ) expect(query).toEqual({ - bindings: [10, "%20%", "%25%", `%"John"%`, `%"Mary"%`], + bindings: [10, "%20%", "%25%", `%"john"%`, `%"mary"%`], sql: `select * from (select top (@p0) * from [${TABLE_NAME}] where (LOWER([${TABLE_NAME}].[age]) LIKE @p1 AND LOWER([${TABLE_NAME}].[age]) LIKE @p2) and (LOWER([${TABLE_NAME}].[name]) LIKE @p3 AND LOWER([${TABLE_NAME}].[name]) LIKE @p4)) as [${TABLE_NAME}]`, }) }) @@ -402,7 +402,7 @@ describe("SQL query builder", () => { }) ) expect(query).toEqual({ - bindings: [10, "%20%", `%"John"%`], + bindings: [10, "%20%", `%"john"%`], sql: `select * from (select top (@p0) * from [${TABLE_NAME}] where NOT (LOWER([${TABLE_NAME}].[age]) LIKE @p1) and NOT (LOWER([${TABLE_NAME}].[name]) LIKE @p2)) as [${TABLE_NAME}]`, }) }) @@ -453,7 +453,7 @@ describe("SQL query builder", () => { }) ) expect(query).toEqual({ - bindings: [10, "%20%", "%25%", `%"John"%`, `%"Mary"%`], + bindings: [10, "%20%", "%25%", `%"john"%`, `%"mary"%`], sql: `select * from (select top (@p0) * from [${TABLE_NAME}] where (LOWER([${TABLE_NAME}].[age]) LIKE @p1 OR LOWER([${TABLE_NAME}].[age]) LIKE @p2) and (LOWER([${TABLE_NAME}].[name]) LIKE @p3 OR LOWER([${TABLE_NAME}].[name]) LIKE @p4)) as [${TABLE_NAME}]`, }) }) @@ -531,7 +531,7 @@ describe("SQL query builder", () => { }) ) expect(query).toEqual({ - bindings: ["John%", limit], + bindings: ["john%", limit], sql: `select * from (select * from \`${tableName}\` where LOWER(\`${tableName}\`.\`name\`) LIKE ? limit ?) as \`${tableName}\``, }) }) @@ -549,7 +549,7 @@ describe("SQL query builder", () => { }) ) expect(query).toEqual({ - bindings: [limit, "John%"], + bindings: [limit, "john%"], sql: `select * from (select top (@p0) * from [${tableName}] where LOWER([${tableName}].[name]) LIKE @p1) as [${tableName}]`, }) }) @@ -591,4 +591,49 @@ describe("SQL query builder", () => { sql: `select * from (select * from \"${TABLE_NAME}\" where \"${TABLE_NAME}\".\"dob\" < $1 limit $2) as \"${TABLE_NAME}\"`, }) }) + + it("should lowercase the values for Oracle LIKE statements", () => { + let query = new Sql(SqlClient.ORACLE, limit)._query( + generateReadJson({ + filters: { + string: { + name: "John", + }, + }, + }) + ) + expect(query).toEqual({ + bindings: ["john%", limit], + sql: `select * from (select * from (select * from \"test\" where LOWER(\"test\".\"name\") LIKE :1) where rownum <= :2) \"test\"`, + }) + + query = new Sql(SqlClient.ORACLE, limit)._query( + generateReadJson({ + filters: { + contains: { + age: [20, 25], + name: ["John", "Mary"], + }, + }, + }) + ) + expect(query).toEqual({ + bindings: ["%20%", "%25%", `%"john"%`, `%"mary"%`, limit], + sql: `select * from (select * from (select * from \"test\" where (LOWER(\"test\".\"age\") LIKE :1 AND LOWER(\"test\".\"age\") LIKE :2) and (LOWER(\"test\".\"name\") LIKE :3 AND LOWER(\"test\".\"name\") LIKE :4)) where rownum <= :5) \"test\"`, + }) + + query = new Sql(SqlClient.ORACLE, limit)._query( + generateReadJson({ + filters: { + fuzzy: { + name: "Jo", + }, + }, + }) + ) + expect(query).toEqual({ + bindings: [`%jo%`, limit], + sql: `select * from (select * from (select * from \"test\" where LOWER(\"test\".\"name\") LIKE :1) where rownum <= :2) \"test\"`, + }) + }) }) diff --git a/packages/server/src/middleware/currentapp.ts b/packages/server/src/middleware/currentapp.ts index 7621bf61ee..efafc59e21 100644 --- a/packages/server/src/middleware/currentapp.ts +++ b/packages/server/src/middleware/currentapp.ts @@ -2,7 +2,6 @@ import { utils, constants, roles, - db as dbCore, tenancy, context, } from "@budibase/backend-core" @@ -15,29 +14,10 @@ import { UserCtx } from "@budibase/types" export default async (ctx: UserCtx, next: any) => { // try to get the appID from the request let requestAppId = await utils.getAppIdFromCtx(ctx) - // get app cookie if it exists - let appCookie: { appId?: string } | undefined - try { - appCookie = utils.getCookie(ctx, constants.Cookie.CurrentApp) - } catch (err) { - utils.clearCookie(ctx, constants.Cookie.CurrentApp) - } - if (!appCookie && !requestAppId) { + if (!requestAppId) { return next() } - // check the app exists referenced in cookie - if (appCookie) { - const appId = appCookie.appId - const exists = await dbCore.dbExists(appId) - if (!exists) { - utils.clearCookie(ctx, constants.Cookie.CurrentApp) - return next() - } - // if the request app ID wasn't set, update it with the cookie - requestAppId = requestAppId || appId - } - // deny access to application preview if (!env.isTest()) { if ( @@ -45,7 +25,6 @@ export default async (ctx: UserCtx, next: any) => { !isWebhookEndpoint(ctx) && (!ctx.user || !ctx.user.builder || !ctx.user.builder.global) ) { - utils.clearCookie(ctx, constants.Cookie.CurrentApp) return ctx.redirect("/") } } @@ -127,14 +106,6 @@ export default async (ctx: UserCtx, next: any) => { role: await roles.getRole(roleId), } } - if ( - (requestAppId !== appId || - appCookie == null || - appCookie.appId !== requestAppId) && - !skipCookie - ) { - utils.setCookie(ctx, { appId }, constants.Cookie.CurrentApp) - } return next() }) diff --git a/packages/server/src/middleware/tests/currentapp.spec.js b/packages/server/src/middleware/tests/currentapp.spec.js index 8770118da2..b80800fd96 100644 --- a/packages/server/src/middleware/tests/currentapp.spec.js +++ b/packages/server/src/middleware/tests/currentapp.spec.js @@ -158,27 +158,22 @@ describe("Current app middleware", () => { }) describe("check functionality when logged in", () => { - async function checkExpected(setCookie) { + async function checkExpected() { config.setUser() await config.executeMiddleware() - let { utils } = require("@budibase/backend-core") - if (setCookie) { - expect(utils.setCookie).toHaveBeenCalled() - } else { - expect(utils.setCookie).not.toHaveBeenCalled() - } + expect(config.ctx.roleId).toEqual("PUBLIC") expect(config.ctx.user.role._id).toEqual("PUBLIC") expect(config.ctx.appId).toEqual("app_test") expect(config.next).toHaveBeenCalled() } - it("should be able to setup an app token when cookie not setup", async () => { + it("should be able to setup an app token on a first call", async () => { mockAuthWithCookie() - await checkExpected(true) + await checkExpected() }) - it("should perform correct when no cookie exists", async () => { + it("should perform correct on a first call", async () => { mockReset() jest.mock("@budibase/backend-core", () => { const core = jest.requireActual("@budibase/backend-core") @@ -206,38 +201,7 @@ describe("Current app middleware", () => { }, } }) - await checkExpected(true) - }) - - it("lastly check what occurs when cookie doesn't need updated", async () => { - mockReset() - jest.mock("@budibase/backend-core", () => { - const core = jest.requireActual("@budibase/backend-core") - return { - ...core, - db: { - ...core.db, - dbExists: () => true, - }, - utils: { - getAppIdFromCtx: () => { - return "app_test" - }, - setCookie: jest.fn(), - getCookie: () => ({ appId: "app_test", roleId: "PUBLIC" }), - }, - cache: { - user: { - getUser: async id => { - return { - _id: "us_uuid1", - } - }, - }, - }, - } - }) - await checkExpected(false) + await checkExpected() }) }) }) diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index cf337c689f..f5009e95a8 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -330,21 +330,13 @@ class TestConfiguration { sessionId: "sessionid", tenantId: this.getTenantId(), } - const app = { - roleId: roleId, - appId, - } const authToken = auth.jwt.sign(authObj, coreEnv.JWT_SECRET) - const appToken = auth.jwt.sign(app, coreEnv.JWT_SECRET) // returning necessary request headers await cache.user.invalidateUser(userId) return { Accept: "application/json", - Cookie: [ - `${constants.Cookie.Auth}=${authToken}`, - `${constants.Cookie.CurrentApp}=${appToken}`, - ], + Cookie: [`${constants.Cookie.Auth}=${authToken}`], [constants.Header.APP_ID]: appId, } }) @@ -359,18 +351,11 @@ class TestConfiguration { sessionId: "sessionid", tenantId, } - const app = { - roleId: roles.BUILTIN_ROLE_IDS.ADMIN, - appId: this.appId, - } const authToken = auth.jwt.sign(authObj, coreEnv.JWT_SECRET) - const appToken = auth.jwt.sign(app, coreEnv.JWT_SECRET) + const headers: any = { Accept: "application/json", - Cookie: [ - `${constants.Cookie.Auth}=${authToken}`, - `${constants.Cookie.CurrentApp}=${appToken}`, - ], + Cookie: [`${constants.Cookie.Auth}=${authToken}`], [constants.Header.CSRF_TOKEN]: this.defaultUserValues.csrfToken, Host: this.tenantHost(), ...extras, diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 1a916dd694..9ee2faa23e 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -1290,14 +1290,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.4.27-alpha.12": - version "2.4.27-alpha.12" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.4.27-alpha.12.tgz#655367eaa16a8bf1a28ff38eb0ab2127decb5b23" - integrity sha512-qCszwPDuYvMYZLl54T82ZrpM5xHD6nTEzPAkPQFrZIDtkW1dfKd2z+E2OirIOYb1CRN4GwrnIDjR0+u231Qo5w== +"@budibase/backend-core@2.4.42-alpha.5": + version "2.4.42-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.4.42-alpha.5.tgz#3e4b44c6e1b7f9c0652527a48dfa46dbe022e93b" + integrity sha512-vclysH06NASv9XZ55W9yonPIodVTCWklo6alfKPQTbvjINGBopfTglV9new+OVJoqlaYPyt4AyBVp0si29vuKg== dependencies: "@budibase/nano" "10.1.2" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.4.27-alpha.12" + "@budibase/types" "2.4.42-alpha.5" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -1429,14 +1429,14 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.4.27-alpha.12": - version "2.4.27-alpha.12" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.4.27-alpha.12.tgz#c3f74e4ef04ea1355bdc1333dd033f4a47087ac2" - integrity sha512-Hl/zalqmtlINgylFqQz3zWG/4dTXm/Skck2Q/j69gyqy0DotWXfRko03CbDQCyHGWhM/oXXiYJK54HIkn+kOTw== +"@budibase/pro@2.4.42-alpha.5": + version "2.4.42-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.4.42-alpha.5.tgz#99774e2e06fc22892c545b7208d78144395859db" + integrity sha512-Axxx4zqsBsu2fl5UKetNXCJWoMi2pcA/kVY88Z9BYNPmGp7k3s2pKU/kShy751I2fDF0TGgxSCGzpVzWqM8ZEg== dependencies: - "@budibase/backend-core" "2.4.27-alpha.12" + "@budibase/backend-core" "2.4.42-alpha.5" "@budibase/string-templates" "2.3.20" - "@budibase/types" "2.4.27-alpha.12" + "@budibase/types" "2.4.42-alpha.5" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -1475,10 +1475,10 @@ lodash "^4.17.20" vm2 "^3.9.4" -"@budibase/types@2.4.27-alpha.12": - version "2.4.27-alpha.12" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.4.27-alpha.12.tgz#4c0dd66434f52c41080c17b810262ff8f195cb6c" - integrity sha512-mpzlQM49WWQyWnysFcMkJDD3jY6Wf5HG7R8/eb5PRbSWx92+17g0iCbhuaswfCJdz0GIi73hebmvaFeuQ/glMg== +"@budibase/types@2.4.42-alpha.5": + version "2.4.42-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.4.42-alpha.5.tgz#21408ab88b74833f176003f9e54dc109252d8080" + integrity sha512-3uZmKryzMcAxIrR0hnBwoNfuqR8yvCWjK880h4Mdi2ik/uYfndUAhdVi/Bh/oU3ZGu9KiJzqh/IE29IuRboiNg== "@bull-board/api@3.7.0": version "3.7.0" diff --git a/packages/shared-core/package.json b/packages/shared-core/package.json index 34d090ba0e..8a827b1969 100644 --- a/packages/shared-core/package.json +++ b/packages/shared-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/shared-core", - "version": "2.4.27-alpha.12", + "version": "2.4.42-alpha.5", "description": "Shared data utils", "main": "dist/cjs/src/index.js", "types": "dist/mjs/src/index.d.ts", @@ -20,7 +20,7 @@ "dev:builder": "yarn prebuild && concurrently \"tsc -p tsconfig.build.json --watch\" \"tsc -p tsconfig-cjs.build.json --watch\"" }, "dependencies": { - "@budibase/types": "2.4.27-alpha.12" + "@budibase/types": "2.4.42-alpha.5" }, "devDependencies": { "concurrently": "^7.6.0", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 7e78b7b2f6..d8609616b7 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "2.4.27-alpha.12", + "version": "2.4.42-alpha.5", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/types/package.json b/packages/types/package.json index a6a3757ae7..c48a4fe708 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/types", - "version": "2.4.27-alpha.12", + "version": "2.4.42-alpha.5", "description": "Budibase types", "main": "dist/cjs/index.js", "types": "dist/mjs/index.d.ts", diff --git a/packages/types/src/api/web/global/configs.ts b/packages/types/src/api/web/global/configs.ts index 1476d13cee..b36d974904 100644 --- a/packages/types/src/api/web/global/configs.ts +++ b/packages/types/src/api/web/global/configs.ts @@ -5,6 +5,7 @@ import { SettingsConfig, SettingsInnerConfig } from "../../../documents" */ export interface PublicSettingsInnerConfig extends SettingsInnerConfig { google: boolean + googleDatasourceConfigured: boolean oidc: boolean oidcCallbackUrl: string googleCallbackUrl: string diff --git a/packages/worker/package.json b/packages/worker/package.json index d905874c93..5dd8074b9f 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "2.4.27-alpha.12", + "version": "2.4.42-alpha.5", "description": "Budibase background service", "main": "src/index.ts", "repository": { @@ -36,10 +36,10 @@ "author": "Budibase", "license": "GPL-3.0", "dependencies": { - "@budibase/backend-core": "2.4.27-alpha.12", - "@budibase/pro": "2.4.27-alpha.12", - "@budibase/string-templates": "2.4.27-alpha.12", - "@budibase/types": "2.4.27-alpha.12", + "@budibase/backend-core": "2.4.42-alpha.5", + "@budibase/pro": "2.4.42-alpha.5", + "@budibase/string-templates": "2.4.42-alpha.5", + "@budibase/types": "2.4.42-alpha.5", "@koa/router": "8.0.8", "@sentry/node": "6.17.7", "@techpass/passport-openidconnect": "0.3.2", diff --git a/packages/worker/src/api/controllers/global/auth.ts b/packages/worker/src/api/controllers/global/auth.ts index 1286fd519d..c8f75b3610 100644 --- a/packages/worker/src/api/controllers/global/auth.ts +++ b/packages/worker/src/api/controllers/global/auth.ts @@ -50,11 +50,6 @@ async function passportCallback( setCookie(ctx, token, Cookie.Auth, { sign: false }) // set the token in a header as well for APIs ctx.set(Header.TOKEN, token) - // get rid of any app cookies on login - // have to check test because this breaks cypress - if (!env.isTest()) { - clearCookie(ctx, Cookie.CurrentApp) - } } export const login = async (ctx: Ctx, next: any) => { diff --git a/packages/worker/src/api/controllers/global/configs.ts b/packages/worker/src/api/controllers/global/configs.ts index ab63a06ab4..66804c3b9c 100644 --- a/packages/worker/src/api/controllers/global/configs.ts +++ b/packages/worker/src/api/controllers/global/configs.ts @@ -332,6 +332,8 @@ export async function publicSettings( // google const googleConfig = await configs.getGoogleConfig() + const googleDatasourceConfigured = + !!(await configs.getGoogleDatasourceConfig()) const preActivated = googleConfig && googleConfig.activated == null const google = preActivated || !!googleConfig?.activated const _googleCallbackUrl = await googleCallbackUrl(googleConfig) @@ -352,6 +354,7 @@ export async function publicSettings( ...config, ...branding, google, + googleDatasourceConfigured, oidc, isSSOEnforced, oidcCallbackUrl: _oidcCallbackUrl, diff --git a/packages/worker/src/api/controllers/global/self.ts b/packages/worker/src/api/controllers/global/self.ts index 78e5bf7164..d0232bee60 100644 --- a/packages/worker/src/api/controllers/global/self.ts +++ b/packages/worker/src/api/controllers/global/self.ts @@ -2,7 +2,6 @@ import * as userSdk from "../../../sdk/users" import { featureFlags, tenancy, - constants, db as dbCore, utils, encryption, @@ -11,7 +10,7 @@ import { import env from "../../../environment" import { groups } from "@budibase/pro" import { UpdateSelfRequest, UpdateSelfResponse, UserCtx } from "@budibase/types" -const { getCookie, clearCookie, newid } = utils +const { newid } = utils function newTestApiKey() { return env.ENCRYPTED_TEST_PUBLIC_API_KEY @@ -71,16 +70,6 @@ export async function fetchAPIKey(ctx: any) { ctx.body = cleanupDevInfo(devInfo) } -const checkCurrentApp = (ctx: any) => { - const appCookie = getCookie(ctx, constants.Cookie.CurrentApp) - if (appCookie && !tenancy.isUserInAppTenant(appCookie.appId)) { - // there is a currentapp cookie from another tenant - // remove the cookie as this is incompatible with the builder - // due to builder and admin permissions being removed - clearCookie(ctx, constants.Cookie.CurrentApp) - } -} - /** * Add the attributes that are session based to the current user. */ @@ -101,8 +90,6 @@ export async function getSelf(ctx: any) { id: userId, } - checkCurrentApp(ctx) - // get the main body of the user const user = await userSdk.getUser(userId) ctx.body = await groups.enrichUserRolesFromGroups(user) diff --git a/packages/worker/src/api/controllers/system/environment.ts b/packages/worker/src/api/controllers/system/environment.ts index 8ae0fcda3f..17cf73b5ed 100644 --- a/packages/worker/src/api/controllers/system/environment.ts +++ b/packages/worker/src/api/controllers/system/environment.ts @@ -7,6 +7,7 @@ export const fetch = async (ctx: BBContext) => { cloud: !env.SELF_HOSTED, accountPortalUrl: env.ACCOUNT_PORTAL_URL, disableAccountPortal: env.DISABLE_ACCOUNT_PORTAL, + baseUrl: env.PLATFORM_URL, // in test need to pretend its in production for the UI (Cypress) isDev: env.isDev() && !env.isTest(), } diff --git a/packages/worker/src/api/controllers/system/tenants.ts b/packages/worker/src/api/controllers/system/tenants.ts index 151507358f..476343a05e 100644 --- a/packages/worker/src/api/controllers/system/tenants.ts +++ b/packages/worker/src/api/controllers/system/tenants.ts @@ -5,7 +5,7 @@ export async function destroy(ctx: UserCtx) { const user = ctx.user! const tenantId = ctx.params.tenantId - if (tenantId !== user.tenantId) { + if (!ctx.internal && tenantId !== user.tenantId) { ctx.throw(403, "Tenant ID does not match current user") } @@ -17,3 +17,7 @@ export async function destroy(ctx: UserCtx) { throw err } } + +export async function info(ctx: UserCtx) { + ctx.body = await tenantSdk.tenantInfo(ctx.params.tenantId) +} diff --git a/packages/worker/src/api/routes/global/tests/configs.spec.ts b/packages/worker/src/api/routes/global/tests/configs.spec.ts index 8c31adff2b..193dbf4a59 100644 --- a/packages/worker/src/api/routes/global/tests/configs.spec.ts +++ b/packages/worker/src/api/routes/global/tests/configs.spec.ts @@ -290,6 +290,7 @@ describe("configs", () => { logoUrl: "", analyticsEnabled: false, google: false, + googleDatasourceConfigured: false, googleCallbackUrl: `http://localhost:10000/api/global/auth/${config.tenantId}/google/callback`, isSSOEnforced: false, oidc: false, diff --git a/packages/worker/src/api/routes/system/tests/environment.spec.ts b/packages/worker/src/api/routes/system/tests/environment.spec.ts index 0f7a690abc..4e6907a9d7 100644 --- a/packages/worker/src/api/routes/system/tests/environment.spec.ts +++ b/packages/worker/src/api/routes/system/tests/environment.spec.ts @@ -23,6 +23,7 @@ describe("/api/system/environment", () => { disableAccountPortal: 0, isDev: false, multiTenancy: true, + baseUrl: "http://localhost:10000", }) }) }) diff --git a/packages/worker/src/sdk/tenants/tenants.ts b/packages/worker/src/sdk/tenants/tenants.ts index 829b144c75..4f580402f7 100644 --- a/packages/worker/src/sdk/tenants/tenants.ts +++ b/packages/worker/src/sdk/tenants/tenants.ts @@ -74,3 +74,10 @@ async function removeTenantUsers(tenantId: string) { throw err } } + +export async function tenantInfo(tenantId: string) { + const globalDbName = tenancy.getGlobalDBName(tenantId) + return { + exists: await dbCore.dbExists(globalDbName), + } +} diff --git a/packages/worker/src/tests/api/tenants.ts b/packages/worker/src/tests/api/tenants.ts index b28b55697f..16f970915a 100644 --- a/packages/worker/src/tests/api/tenants.ts +++ b/packages/worker/src/tests/api/tenants.ts @@ -2,8 +2,10 @@ import TestConfiguration from "../TestConfiguration" import { TestAPI, TestAPIOpts } from "./base" export class TenantAPI extends TestAPI { + config: TestConfiguration constructor(config: TestConfiguration) { super(config) + this.config = config } delete = (tenantId: string, opts?: TestAPIOpts) => { diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 7b589ce2a7..e090e273aa 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -475,14 +475,14 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/backend-core@2.4.27-alpha.12": - version "2.4.27-alpha.12" - resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.4.27-alpha.12.tgz#655367eaa16a8bf1a28ff38eb0ab2127decb5b23" - integrity sha512-qCszwPDuYvMYZLl54T82ZrpM5xHD6nTEzPAkPQFrZIDtkW1dfKd2z+E2OirIOYb1CRN4GwrnIDjR0+u231Qo5w== +"@budibase/backend-core@2.4.42-alpha.5": + version "2.4.42-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/backend-core/-/backend-core-2.4.42-alpha.5.tgz#3e4b44c6e1b7f9c0652527a48dfa46dbe022e93b" + integrity sha512-vclysH06NASv9XZ55W9yonPIodVTCWklo6alfKPQTbvjINGBopfTglV9new+OVJoqlaYPyt4AyBVp0si29vuKg== dependencies: "@budibase/nano" "10.1.2" "@budibase/pouchdb-replication-stream" "1.2.10" - "@budibase/types" "2.4.27-alpha.12" + "@budibase/types" "2.4.42-alpha.5" "@shopify/jest-koa-mocks" "5.0.1" "@techpass/passport-openidconnect" "0.3.2" aws-cloudfront-sign "2.2.0" @@ -564,14 +564,14 @@ pouchdb-promise "^6.0.4" through2 "^2.0.0" -"@budibase/pro@2.4.27-alpha.12": - version "2.4.27-alpha.12" - resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.4.27-alpha.12.tgz#c3f74e4ef04ea1355bdc1333dd033f4a47087ac2" - integrity sha512-Hl/zalqmtlINgylFqQz3zWG/4dTXm/Skck2Q/j69gyqy0DotWXfRko03CbDQCyHGWhM/oXXiYJK54HIkn+kOTw== +"@budibase/pro@2.4.42-alpha.5": + version "2.4.42-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/pro/-/pro-2.4.42-alpha.5.tgz#99774e2e06fc22892c545b7208d78144395859db" + integrity sha512-Axxx4zqsBsu2fl5UKetNXCJWoMi2pcA/kVY88Z9BYNPmGp7k3s2pKU/kShy751I2fDF0TGgxSCGzpVzWqM8ZEg== dependencies: - "@budibase/backend-core" "2.4.27-alpha.12" + "@budibase/backend-core" "2.4.42-alpha.5" "@budibase/string-templates" "2.3.20" - "@budibase/types" "2.4.27-alpha.12" + "@budibase/types" "2.4.42-alpha.5" "@koa/router" "8.0.8" bull "4.10.1" joi "17.6.0" @@ -592,10 +592,10 @@ lodash "^4.17.20" vm2 "^3.9.4" -"@budibase/types@2.4.27-alpha.12": - version "2.4.27-alpha.12" - resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.4.27-alpha.12.tgz#4c0dd66434f52c41080c17b810262ff8f195cb6c" - integrity sha512-mpzlQM49WWQyWnysFcMkJDD3jY6Wf5HG7R8/eb5PRbSWx92+17g0iCbhuaswfCJdz0GIi73hebmvaFeuQ/glMg== +"@budibase/types@2.4.42-alpha.5": + version "2.4.42-alpha.5" + resolved "https://registry.yarnpkg.com/@budibase/types/-/types-2.4.42-alpha.5.tgz#21408ab88b74833f176003f9e54dc109252d8080" + integrity sha512-3uZmKryzMcAxIrR0hnBwoNfuqR8yvCWjK880h4Mdi2ik/uYfndUAhdVi/Bh/oU3ZGu9KiJzqh/IE29IuRboiNg== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" diff --git a/qa-core/package.json b/qa-core/package.json index 9a5cc8dc32..3f818b7aaa 100644 --- a/qa-core/package.json +++ b/qa-core/package.json @@ -21,7 +21,7 @@ "api:test:ci": "start-server-and-test api:server:setup:ci http://localhost:4100/builder test", "api:test": "start-server-and-test api:server:setup http://localhost:4100/builder test", "api:test:local": "env-cmd jest --runInBand --testPathIgnorePatterns=\\\"\\/dataSources\\/\\\"", - "api:test:nightly": "env-cmd jest --runInBand --outputFile=testResults.json" + "api:test:nightly": "env-cmd jest --runInBand --json --outputFile=testResults.json" }, "jest": { "preset": "ts-jest", diff --git a/qa-core/scripts/testResultsWebhook.js b/qa-core/scripts/testResultsWebhook.js index fc00bf34ad..b4725cae56 100644 --- a/qa-core/scripts/testResultsWebhook.js +++ b/qa-core/scripts/testResultsWebhook.js @@ -10,7 +10,7 @@ const GITHUB_ACTIONS_RUN_URL = process.env.GITHUB_ACTIONS_RUN_URL async function generateReport() { // read the report file - const REPORT_PATH = path.resolve(__dirname, "..", "testReport.json") + const REPORT_PATH = path.resolve(__dirname, "..", "testResults.json") const report = fs.readFileSync(REPORT_PATH, "utf-8") return JSON.parse(report) }