diff --git a/.github/workflows/deploy-preprod.yml b/.github/workflows/deploy-preprod.yml index cef47636ee..eec5546444 100644 --- a/.github/workflows/deploy-preprod.yml +++ b/.github/workflows/deploy-preprod.yml @@ -37,7 +37,7 @@ jobs: wc -l values.preprod.yaml - name: Deploy to Preprod Environment - uses: glopezep/helm@v1.7.1 + uses: budibase/helm@v1.8.0 with: release: budibase-preprod namespace: budibase diff --git a/.github/workflows/deploy-release.yml b/.github/workflows/deploy-release.yml index cff26fd7c8..1f7a5ebfd4 100644 --- a/.github/workflows/deploy-release.yml +++ b/.github/workflows/deploy-release.yml @@ -38,7 +38,7 @@ jobs: wc -l values.release.yaml - name: Deploy to Release Environment - uses: glopezep/helm@v1.7.1 + uses: budibase/helm@v1.8.0 with: release: budibase-release namespace: budibase diff --git a/.github/workflows/release-selfhost.yml b/.github/workflows/release-selfhost.yml index 12fb8f5a9d..f5a2f643c3 100644 --- a/.github/workflows/release-selfhost.yml +++ b/.github/workflows/release-selfhost.yml @@ -16,9 +16,13 @@ jobs: - uses: actions/checkout@v2 with: - node-version: 14.x fetch_depth: 0 + - name: Use Node.js 14.x + uses: actions/setup-node@v1 + with: + node-version: 14.x + - name: Get the latest budibase release version id: version run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2a28150891..a24537ccd4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -107,7 +107,7 @@ jobs: wc -l values.preprod.yaml - name: Deploy to Preprod Environment - uses: glopezep/helm@v1.7.1 + uses: budibase/helm@v1.8.0 with: release: budibase-preprod namespace: budibase diff --git a/charts/budibase/templates/proxy-service-deployment.yaml b/charts/budibase/templates/proxy-service-deployment.yaml index e422df8db3..0dea38fcbd 100644 --- a/charts/budibase/templates/proxy-service-deployment.yaml +++ b/charts/budibase/templates/proxy-service-deployment.yaml @@ -51,6 +51,14 @@ spec: value: {{ tpl .Values.services.proxy.upstreams.minio . | quote }} - name: COUCHDB_UPSTREAM_URL value: {{ .Values.services.couchdb.url | default (tpl .Values.services.proxy.upstreams.couchdb .) | quote }} + {{ if .Values.services.proxy.proxyRateLimitWebhooksPerSecond }} + - name: PROXY_RATE_LIMIT_WEBHOOKS_PER_SECOND + value: {{ .Values.services.proxy.proxyRateLimitWebhooksPerSecond | quote }} + {{ end }} + {{ if .Values.services.proxy.proxyRateLimitApiPerSecond }} + - name: PROXY_RATE_LIMIT_API_PER_SECOND + value: {{ .Values.services.proxy.proxyRateLimitApiPerSecond | quote }} + {{ end }} - name: RESOLVER {{ if .Values.services.proxy.resolver }} value: {{ .Values.services.proxy.resolver }} diff --git a/charts/budibase/values.yaml b/charts/budibase/values.yaml index dd75b2daa3..536af8560f 100644 --- a/charts/budibase/values.yaml +++ b/charts/budibase/values.yaml @@ -245,7 +245,7 @@ couchdb: ## The CouchDB image image: repository: couchdb - tag: 3.2.1 + tag: 3.1.1 pullPolicy: IfNotPresent ## Experimental integration with Lucene-powered fulltext search diff --git a/lerna.json b/lerna.json index 5f01f98b3a..67b7904a53 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.3.18-alpha.17", + "version": "2.3.21-alpha.1", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/package.json b/packages/backend-core/package.json index db49070128..421304809c 100644 --- a/packages/backend-core/package.json +++ b/packages/backend-core/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/backend-core", - "version": "2.3.18-alpha.17", + "version": "2.3.21-alpha.1", "description": "Budibase backend core libraries used in server and worker", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -22,9 +22,9 @@ "test:watch": "jest --watchAll" }, "dependencies": { - "@budibase/nano": "10.1.1", + "@budibase/nano": "10.1.2", "@budibase/pouchdb-replication-stream": "1.2.10", - "@budibase/types": "2.3.18-alpha.17", + "@budibase/types": "2.3.21-alpha.1", "@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 936d06ddff..7e6fe4bcee 100644 --- a/packages/backend-core/src/auth/auth.ts +++ b/packages/backend-core/src/auth/auth.ts @@ -28,6 +28,7 @@ import * as events from "../events" import * as configs from "../configs" import { clearCookie, getCookie } from "../utils" import { ssoSaveUserNoOp } from "../middleware/passport/sso/sso" +import env from "../environment" const refresh = require("passport-oauth2-refresh") export { @@ -52,7 +53,7 @@ export const jwt = require("jsonwebtoken") _passport.use(new LocalStrategy(local.options, local.authenticate)) if (jwtPassport.options.secretOrKey) { _passport.use(new JwtStrategy(jwtPassport.options, jwtPassport.authenticate)) -} else { +} else if (!env.DISABLE_JWT_WARNING) { logAlert("No JWT Secret supplied, cannot configure JWT strategy") } diff --git a/packages/backend-core/src/cache/appMetadata.ts b/packages/backend-core/src/cache/appMetadata.ts index d24c4a3140..5b66c356d3 100644 --- a/packages/backend-core/src/cache/appMetadata.ts +++ b/packages/backend-core/src/cache/appMetadata.ts @@ -1,6 +1,6 @@ import { getAppClient } from "../redis/init" import { doWithDB, DocumentType } from "../db" -import { Database } from "@budibase/types" +import { Database, App } from "@budibase/types" const AppState = { INVALID: "invalid", @@ -65,7 +65,7 @@ export async function getAppMetadata(appId: string) { if (isInvalid(metadata)) { throw { status: 404, message: "No app metadata found" } } - return metadata + return metadata as App } /** diff --git a/packages/backend-core/src/configs/configs.ts b/packages/backend-core/src/configs/configs.ts index 38e7bcbb29..b461497747 100644 --- a/packages/backend-core/src/configs/configs.ts +++ b/packages/backend-core/src/configs/configs.ts @@ -42,7 +42,9 @@ export async function getConfig( } } -export async function save(config: Config) { +export async function save( + config: Config +): Promise<{ id: string; rev: string }> { const db = context.getGlobalDB() return db.put(config) } @@ -54,7 +56,7 @@ export async function getSettingsConfigDoc(): Promise { if (!config) { config = { - _id: generateConfigID(ConfigType.GOOGLE), + _id: generateConfigID(ConfigType.SETTINGS), type: ConfigType.SETTINGS, config: {}, } diff --git a/packages/backend-core/src/environment.ts b/packages/backend-core/src/environment.ts index cd7bcca11d..8dc2cce487 100644 --- a/packages/backend-core/src/environment.ts +++ b/packages/backend-core/src/environment.ts @@ -94,6 +94,7 @@ const environment = { SMTP_HOST: process.env.SMTP_HOST, SMTP_PORT: parseInt(process.env.SMTP_PORT || ""), SMTP_FROM_ADDRESS: process.env.SMTP_FROM_ADDRESS, + DISABLE_JWT_WARNING: process.env.DISABLE_JWT_WARNING, /** * 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/events/processors/AuditLogsProcessor.ts b/packages/backend-core/src/events/processors/AuditLogsProcessor.ts index fd68b66871..94b4e1b09f 100644 --- a/packages/backend-core/src/events/processors/AuditLogsProcessor.ts +++ b/packages/backend-core/src/events/processors/AuditLogsProcessor.ts @@ -8,7 +8,7 @@ import { HostInfo, } from "@budibase/types" import { EventProcessor } from "./types" -import { getAppId } from "../../context" +import { getAppId, doInTenant, getTenantId } from "../../context" import BullQueue from "bull" import { createQueue, JobQueue } from "../../queue" import { isAudited } from "../../utils" @@ -26,28 +26,30 @@ export default class AuditLogsProcessor implements EventProcessor { JobQueue.AUDIT_LOG ) return AuditLogsProcessor.auditLogQueue.process(async job => { - let properties = job.data.properties - if (properties.audited) { - properties = { - ...properties, - ...properties.audited, + return doInTenant(job.data.tenantId, async () => { + let properties = job.data.properties + if (properties.audited) { + properties = { + ...properties, + ...properties.audited, + } + delete properties.audited } - delete properties.audited - } - // this feature is disabled by default due to privacy requirements - // in some countries - available as env var in-case it is desired - // in self host deployments - let hostInfo: HostInfo | undefined = {} - if (env.ENABLE_AUDIT_LOG_IP_ADDR) { - hostInfo = job.data.opts.hostInfo - } + // this feature is disabled by default due to privacy requirements + // in some countries - available as env var in-case it is desired + // in self host deployments + let hostInfo: HostInfo | undefined = {} + if (env.ENABLE_AUDIT_LOG_IP_ADDR) { + hostInfo = job.data.opts.hostInfo + } - await writeAuditLogs(job.data.event, properties, { - userId: job.data.opts.userId, - timestamp: job.data.opts.timestamp, - appId: job.data.opts.appId, - hostInfo, + await writeAuditLogs(job.data.event, properties, { + userId: job.data.opts.userId, + timestamp: job.data.opts.timestamp, + appId: job.data.opts.appId, + hostInfo, + }) }) }) } @@ -72,6 +74,7 @@ export default class AuditLogsProcessor implements EventProcessor { appId: getAppId(), hostInfo: identity.hostInfo, }, + tenantId: getTenantId(), }) } } diff --git a/packages/backend-core/src/middleware/authenticated.ts b/packages/backend-core/src/middleware/authenticated.ts index d7e6346b3f..0708581570 100644 --- a/packages/backend-core/src/middleware/authenticated.ts +++ b/packages/backend-core/src/middleware/authenticated.ts @@ -154,7 +154,8 @@ export default function ( return next() } } catch (err: any) { - console.error("Auth Error", err?.message || err) + console.error(`Auth Error: ${err.message}`) + console.error(err) // invalid token, clear the cookie if (err && err.name === "JsonWebTokenError") { clearCookie(ctx, Cookie.Auth) diff --git a/packages/backend-core/src/migrations/migrations.ts b/packages/backend-core/src/migrations/migrations.ts index 2e3524775f..ab72091d56 100644 --- a/packages/backend-core/src/migrations/migrations.ts +++ b/packages/backend-core/src/migrations/migrations.ts @@ -87,6 +87,7 @@ export const runMigration = async ( const lengthStatement = length > 1 ? `[${count}/${length}]` : "" const db = getDB(dbName) + try { const doc = await getMigrationsDoc(db) diff --git a/packages/backend-core/tests/utilities/structures/accounts.ts b/packages/backend-core/tests/utilities/structures/accounts.ts index 6bfeedf196..62a9ac19d1 100644 --- a/packages/backend-core/tests/utilities/structures/accounts.ts +++ b/packages/backend-core/tests/utilities/structures/accounts.ts @@ -8,6 +8,8 @@ import { CloudAccount, Hosting, SSOAccount, + CreateAccount, + CreatePassswordAccount, } from "@budibase/types" import _ from "lodash" @@ -29,6 +31,10 @@ export const account = (): Account => { } } +export function selfHostAccount() { + return account() +} + export const cloudAccount = (): CloudAccount => { return { ...account(), @@ -47,9 +53,9 @@ function provider(): AccountSSOProvider { return _.sample(Object.values(AccountSSOProvider)) as AccountSSOProvider } -export function ssoAccount(): SSOAccount { +export function ssoAccount(account: Account = cloudAccount()): SSOAccount { return { - ...cloudAccount(), + ...account, authType: AuthType.SSO, oauth2: { accessToken: generator.string(), @@ -61,3 +67,49 @@ export function ssoAccount(): SSOAccount { thirdPartyProfile: {}, } } + +export const cloudCreateAccount: CreatePassswordAccount = { + email: "cloud@budibase.com", + tenantId: "cloud", + hosting: Hosting.CLOUD, + authType: AuthType.PASSWORD, + password: "Password123!", + tenantName: "cloud", + name: "Budi Armstrong", + size: "10+", + profession: "Software Engineer", +} + +export const cloudSSOCreateAccount: CreateAccount = { + email: "cloud-sso@budibase.com", + tenantId: "cloud-sso", + hosting: Hosting.CLOUD, + authType: AuthType.SSO, + tenantName: "cloudsso", + name: "Budi Armstrong", + size: "10+", + profession: "Software Engineer", +} + +export const selfCreateAccount: CreatePassswordAccount = { + email: "self@budibase.com", + tenantId: "self", + hosting: Hosting.SELF, + authType: AuthType.PASSWORD, + password: "Password123!", + tenantName: "self", + name: "Budi Armstrong", + size: "10+", + profession: "Software Engineer", +} + +export const selfSSOCreateAccount: CreateAccount = { + email: "self-sso@budibase.com", + tenantId: "self-sso", + hosting: Hosting.SELF, + authType: AuthType.SSO, + tenantName: "selfsso", + name: "Budi Armstrong", + size: "10+", + profession: "Software Engineer", +} diff --git a/packages/backend-core/tests/utilities/structures/sso.ts b/packages/backend-core/tests/utilities/structures/sso.ts index a5957c9233..7413fa3c09 100644 --- a/packages/backend-core/tests/utilities/structures/sso.ts +++ b/packages/backend-core/tests/utilities/structures/sso.ts @@ -1,6 +1,7 @@ import { GoogleInnerConfig, JwtClaims, + OAuth2, OIDCInnerConfig, OIDCWellKnownConfig, SSOAuthDetails, @@ -14,6 +15,13 @@ import * as shared from "./shared" import _ from "lodash" import { user } from "./shared" +export function OAuth(): OAuth2 { + return { + refreshToken: generator.string(), + accessToken: generator.string(), + } +} + export function authDetails(userDoc?: User): SSOAuthDetails { if (!userDoc) { userDoc = user() @@ -28,10 +36,7 @@ export function authDetails(userDoc?: User): SSOAuthDetails { return { email: userDoc.email, - oauth2: { - refreshToken: generator.string(), - accessToken: generator.string(), - }, + oauth2: OAuth(), profile, provider, providerType: providerType(), diff --git a/packages/backend-core/yarn.lock b/packages/backend-core/yarn.lock index 5f8edb3df6..91c5c6c9f3 100644 --- a/packages/backend-core/yarn.lock +++ b/packages/backend-core/yarn.lock @@ -475,10 +475,10 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/nano@10.1.1": - version "10.1.1" - resolved "https://registry.yarnpkg.com/@budibase/nano/-/nano-10.1.1.tgz#36ccda4d9bb64b5ee14dd2b27a295b40739b1038" - integrity sha512-kbMIzMkjVtl+xI0UPwVU0/pn8/ccxTyfzwBz6Z+ZiN2oUSb0fJCe0qwA6o8dxwSa8nZu4MbGAeMJl3CJndmWtA== +"@budibase/nano@10.1.2": + version "10.1.2" + resolved "https://registry.yarnpkg.com/@budibase/nano/-/nano-10.1.2.tgz#10fae5a1ab39be6a81261f40e7b7ec6d21cbdd4a" + integrity sha512-1w+YN2n/M5aZ9hBKCP4NEjdQbT8BfCLRizkdvm0Je665eEHw3aE1hvo8mon9Ro9QuDdxj1DfDMMFnym6/QUwpQ== dependencies: "@types/tough-cookie" "^4.0.2" axios "^1.1.3" diff --git a/packages/bbui/package.json b/packages/bbui/package.json index c200860933..502d32c7b0 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.3.18-alpha.17", + "version": "2.3.21-alpha.1", "license": "MPL-2.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", @@ -38,7 +38,7 @@ ], "dependencies": { "@adobe/spectrum-css-workflow-icons": "1.2.1", - "@budibase/string-templates": "2.3.18-alpha.17", + "@budibase/string-templates": "2.3.21-alpha.1", "@spectrum-css/accordion": "3.0.24", "@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actiongroup": "1.0.1", diff --git a/packages/bbui/src/Form/Core/Multiselect.svelte b/packages/bbui/src/Form/Core/Multiselect.svelte index 8860fcbf0b..1d04c210f4 100644 --- a/packages/bbui/src/Form/Core/Multiselect.svelte +++ b/packages/bbui/src/Form/Core/Multiselect.svelte @@ -15,6 +15,7 @@ export let sort = false export let autoWidth = false export let fetchTerm = null + export let useFetch = false export let customPopoverHeight const dispatch = createEventDispatcher() @@ -86,6 +87,7 @@ isPlaceholder={!value?.length} {autocomplete} bind:fetchTerm + {useFetch} {isOptionSelected} {getOptionLabel} {getOptionValue} diff --git a/packages/bbui/src/Form/Core/Picker.svelte b/packages/bbui/src/Form/Core/Picker.svelte index 104596c8cb..bd575600b1 100644 --- a/packages/bbui/src/Form/Core/Picker.svelte +++ b/packages/bbui/src/Form/Core/Picker.svelte @@ -33,6 +33,7 @@ export let autocomplete = false export let sort = false export let fetchTerm = null + export let useFetch = false export let customPopoverHeight export let align = "left" export let footer = null @@ -150,9 +151,9 @@ > {#if autocomplete} - fetchTerm ? (fetchTerm = event.detail) : (searchTerm = event.detail)} + useFetch ? (fetchTerm = event.detail) : (searchTerm = event.detail)} {disabled} placeholder="Search" /> diff --git a/packages/bbui/src/Form/Multiselect.svelte b/packages/bbui/src/Form/Multiselect.svelte index 2237cd1dce..185eb7069b 100644 --- a/packages/bbui/src/Form/Multiselect.svelte +++ b/packages/bbui/src/Form/Multiselect.svelte @@ -17,6 +17,7 @@ export let autoWidth = false export let autocomplete = false export let fetchTerm = null + export let useFetch = false export let customPopoverHeight const dispatch = createEventDispatcher() @@ -41,6 +42,7 @@ {autocomplete} {customPopoverHeight} bind:fetchTerm + {useFetch} on:change={onChange} on:click /> diff --git a/packages/builder/package.json b/packages/builder/package.json index a06235cbb5..acc537e593 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "2.3.18-alpha.17", + "version": "2.3.21-alpha.1", "license": "GPL-3.0", "private": true, "scripts": { @@ -58,10 +58,10 @@ } }, "dependencies": { - "@budibase/bbui": "2.3.18-alpha.17", - "@budibase/client": "2.3.18-alpha.17", - "@budibase/frontend-core": "2.3.18-alpha.17", - "@budibase/string-templates": "2.3.18-alpha.17", + "@budibase/bbui": "2.3.21-alpha.1", + "@budibase/client": "2.3.21-alpha.1", + "@budibase/frontend-core": "2.3.21-alpha.1", + "@budibase/string-templates": "2.3.21-alpha.1", "@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/components/deploy/VersionModal.svelte b/packages/builder/src/components/deploy/VersionModal.svelte index 23d9fd83a0..f357cc7820 100644 --- a/packages/builder/src/components/deploy/VersionModal.svelte +++ b/packages/builder/src/components/deploy/VersionModal.svelte @@ -24,7 +24,10 @@ let updateModal $: appId = $store.appId - $: updateAvailable = clientPackage.version !== $store.version + $: updateAvailable = + clientPackage.version && + $store.version && + clientPackage.version !== $store.version $: revertAvailable = $store.revertableVersion != null const refreshAppPackage = async () => { diff --git a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExecuteQuery.svelte b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExecuteQuery.svelte index 840a639fb4..ba72fd2ed7 100644 --- a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExecuteQuery.svelte +++ b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/ExecuteQuery.svelte @@ -20,6 +20,12 @@ x => x._id !== BUDIBASE_INTERNAL_DB_ID && x.type !== BUDIBASE_DATASOURCE_TYPE ) + // Ensure query params exist so they can be bound + $: { + if (!parameters.queryParams) { + parameters.queryParams = {} + } + } function fetchQueryDefinition(query) { const source = $datasources.list.find( diff --git a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/NavigateTo.svelte b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/NavigateTo.svelte index d90b645315..dca2887fb4 100644 --- a/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/NavigateTo.svelte +++ b/packages/builder/src/components/design/settings/controls/ButtonActionEditor/actions/NavigateTo.svelte @@ -1,22 +1,66 @@
- - (parameters.url = value.detail)} - {bindings} + +