From d1bf7179d1a11e89218d17ed8d42b9ecd9f6ab8d Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 5 Nov 2024 11:08:08 +0000 Subject: [PATCH 01/17] Increase min width of grid create/edit column popovers --- .../src/components/grid/layout/NewColumnButton.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend-core/src/components/grid/layout/NewColumnButton.svelte b/packages/frontend-core/src/components/grid/layout/NewColumnButton.svelte index 261954379b..215fdabd8d 100644 --- a/packages/frontend-core/src/components/grid/layout/NewColumnButton.svelte +++ b/packages/frontend-core/src/components/grid/layout/NewColumnButton.svelte @@ -53,6 +53,7 @@ on:close={close} maxHeight={null} resizable + minWidth={360} >
@@ -80,7 +81,6 @@ } .content { - width: 300px; padding: 20px; display: flex; flex-direction: column; From 00f145e8cecb29c2e028aa0b79365b0825cadf51 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 6 Nov 2024 12:42:25 +0000 Subject: [PATCH 02/17] Add loading spinner while uploading files --- packages/bbui/src/Form/Core/Dropzone.svelte | 37 +++++++++++++++++---- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/packages/bbui/src/Form/Core/Dropzone.svelte b/packages/bbui/src/Form/Core/Dropzone.svelte index 2922d88e7a..b1af2c5c63 100644 --- a/packages/bbui/src/Form/Core/Dropzone.svelte +++ b/packages/bbui/src/Form/Core/Dropzone.svelte @@ -8,6 +8,7 @@ import Link from "../../Link/Link.svelte" import Tag from "../../Tags/Tag.svelte" import Tags from "../../Tags/Tags.svelte" + import ProgressCircle from "../../ProgressCircle/ProgressCircle.svelte" const BYTES_IN_KB = 1000 const BYTES_IN_MB = 1000000 @@ -39,12 +40,14 @@ "jfif", "webp", ] - const fieldId = id || uuid() + let selectedImageIdx = 0 let fileDragged = false let selectedUrl let fileInput + let loading = false + $: selectedImage = value?.[selectedImageIdx] ?? null $: fileCount = value?.length ?? 0 $: isImage = @@ -86,10 +89,15 @@ } if (processFiles) { - const processedFiles = await processFiles(fileList) - const newValue = [...value, ...processedFiles] - dispatch("change", newValue) - selectedImageIdx = newValue.length - 1 + loading = true + try { + const processedFiles = await processFiles(fileList) + const newValue = [...value, ...processedFiles] + dispatch("change", newValue) + selectedImageIdx = newValue.length - 1 + } finally { + loading = false + } } else { dispatch("change", fileList) } @@ -227,7 +235,7 @@ {#if showDropzone}
+ + {#if loading} +
+ +
+ {/if}
{/if}
@@ -464,6 +478,7 @@ .spectrum-Dropzone { height: 220px; + position: relative; } .compact .spectrum-Dropzone { height: 40px; @@ -488,4 +503,14 @@ .tag { margin-top: 8px; } + + .loading { + position: absolute; + display: grid; + place-items: center; + height: 100%; + width: 100%; + top: 0; + left: 0; + } From 52d3126d602c7ba51c043881cbc5227a2e56509a Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 6 Nov 2024 12:56:08 +0000 Subject: [PATCH 03/17] Prevent adding multiple files to single attacment cells and fields --- packages/bbui/src/Form/Core/Dropzone.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bbui/src/Form/Core/Dropzone.svelte b/packages/bbui/src/Form/Core/Dropzone.svelte index b1af2c5c63..26f1dc86c6 100644 --- a/packages/bbui/src/Form/Core/Dropzone.svelte +++ b/packages/bbui/src/Form/Core/Dropzone.svelte @@ -249,7 +249,7 @@ id={fieldId} {disabled} type="file" - multiple + multiple={maximum !== 1} accept={extensions} bind:this={fileInput} on:change={handleFile} From 9996fc7f1255da1550fde0e534234f440f5f0cdf Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Fri, 8 Nov 2024 17:40:29 +0000 Subject: [PATCH 04/17] CSP nonce E2E --- .../src/middleware/contentSecurityPolicy.ts | 104 ++++++++++++++++++ packages/backend-core/src/middleware/index.ts | 1 + .../src/api/controllers/static/index.ts | 3 + .../static/templates/BudibaseApp.svelte | 8 +- .../api/controllers/static/templates/app.hbs | 4 +- .../controllers/static/templates/preview.hbs | 2 +- packages/server/src/koa.ts | 1 + 7 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 packages/backend-core/src/middleware/contentSecurityPolicy.ts diff --git a/packages/backend-core/src/middleware/contentSecurityPolicy.ts b/packages/backend-core/src/middleware/contentSecurityPolicy.ts new file mode 100644 index 0000000000..5d465cbc3c --- /dev/null +++ b/packages/backend-core/src/middleware/contentSecurityPolicy.ts @@ -0,0 +1,104 @@ +import crypto from "crypto" + +const CSP_DIRECTIVES = { + "default-src": ["'self'"], + "script-src": [ + "'self'", + // "'unsafe-inline'", + "'unsafe-eval'", + "https://*.budibase.net", + "https://cdn.budi.live", + "https://js.intercomcdn.com", + "https://widget.intercom.io", + "https://d2l5prqdbvm3op.cloudfront.net", + "https://us-assets.i.posthog.com" + ], + "style-src": [ + "'self'", + "'unsafe-inline'", + "https://cdn.jsdelivr.net", + "https://fonts.googleapis.com", + "https://rsms.me", + "https://maxcdn.bootstrapcdn.com" + ], + "object-src": ["'none'"], + "base-uri": ["'self'"], + "connect-src": [ + "'self'", + "https://*.budibase.app", + "https://*.budibaseqa.app", + "https://*.budibase.net", + "https://api-iam.intercom.io", + "https://api-ping.intercom.io", + "https://app.posthog.com", + "https://us.i.posthog.com", + "wss://nexus-websocket-a.intercom.io", + "wss://nexus-websocket-b.intercom.io", + "https://nexus-websocket-a.intercom.io", + "https://nexus-websocket-b.intercom.io", + "https://uploads.intercomcdn.com", + "https://uploads.intercomusercontent.com", + "https://*.amazonaws.com", + "https://*.s3.amazonaws.com", + "https://*.s3.us-east-2.amazonaws.com", + "https://*.s3.us-east-1.amazonaws.com", + "https://*.s3.us-west-1.amazonaws.com", + "https://*.s3.us-west-2.amazonaws.com", + "https://*.s3.af-south-1.amazonaws.com", + "https://*.s3.ap-east-1.amazonaws.com", + "https://*.s3.ap-south-1.amazonaws.com", + "https://*.s3.ap-northeast-2.amazonaws.com", + "https://*.s3.ap-southeast-1.amazonaws.com", + "https://*.s3.ap-southeast-2.amazonaws.com", + "https://*.s3.ap-northeast-1.amazonaws.com", + "https://*.s3.ca-central-1.amazonaws.com", + "https://*.s3.cn-north-1.amazonaws.com", + "https://*.s3.cn-northwest-1.amazonaws.com", + "https://*.s3.eu-central-1.amazonaws.com", + "https://*.s3.eu-west-1.amazonaws.com", + "https://*.s3.eu-west-2.amazonaws.com", + "https://*.s3.eu-south-1.amazonaws.com", + "https://*.s3.eu-west-3.amazonaws.com", + "https://*.s3.eu-north-1.amazonaws.com", + "https://*.s3.sa-east-1.amazonaws.com", + "https://*.s3.me-south-1.amazonaws.com", + "https://*.s3.us-gov-east-1.amazonaws.com", + "https://*.s3.us-gov-west-1.amazonaws.com", + "https://api.github.com" + ], + "font-src": [ + "'self'", + "data:", + "https://cdn.jsdelivr.net", + "https://fonts.gstatic.com", + "https://rsms.me", + "https://maxcdn.bootstrapcdn.com", + "https://js.intercomcdn.com", + "https://fonts.intercomcdn.com" + ], + "frame-src": ["'self'", "https:"], + "img-src": ["http:", "https:", "data:", "blob:"], + "manifest-src": ["'self'"], + "media-src": ["'self'", "https://js.intercomcdn.com", "https://cdn.budi.live"], + "worker-src": ["blob:"] +} + +export async function contentSecurityPolicy(ctx: any, next: any) { + try { + const nonce = crypto.randomBytes(16).toString("base64") + + CSP_DIRECTIVES['script-src'].push(`'nonce-${nonce}'`) + + ctx.state.nonce = nonce + + const cspHeader = Object.entries(CSP_DIRECTIVES) + .map(([key, sources]) => `${key} ${sources.join(' ')}`) + .join('; ') + ctx.set("Content-Security-Policy", cspHeader); + await next() + } catch (err: any) { + console.error(`Some error: ${err}`) + } +} + +export default contentSecurityPolicy diff --git a/packages/backend-core/src/middleware/index.ts b/packages/backend-core/src/middleware/index.ts index 20c2125b13..9ee51db45b 100644 --- a/packages/backend-core/src/middleware/index.ts +++ b/packages/backend-core/src/middleware/index.ts @@ -19,5 +19,6 @@ export { default as pino } from "../logging/pino/middleware" export { default as correlation } from "../logging/correlation/middleware" export { default as errorHandling } from "./errorHandling" export { default as querystringToBody } from "./querystringToBody" +export { default as csp } from "./contentSecurityPolicy" export * as joiValidator from "./joi-validator" export { default as ip } from "./ip" diff --git a/packages/server/src/api/controllers/static/index.ts b/packages/server/src/api/controllers/static/index.ts index daf7b9b25c..139d07c86d 100644 --- a/packages/server/src/api/controllers/static/index.ts +++ b/packages/server/src/api/controllers/static/index.ts @@ -209,6 +209,7 @@ export const serveApp = async function (ctx: UserCtx) { ? objectStore.getGlobalFileUrl("settings", "logoUrl") : "", appMigrating: needMigrations, + nonce: ctx.state.nonce, }) const appHbs = loadHandlebarsFile(appHbsPath) ctx.body = await processString(appHbs, { @@ -217,6 +218,7 @@ export const serveApp = async function (ctx: UserCtx) { css: `:root{${themeVariables}} ${css.code}`, appId, embedded: bbHeaderEmbed, + nonce: ctx.state.nonce, }) } else { // just return the app info for jest to assert on @@ -258,6 +260,7 @@ export const serveBuilderPreview = async function (ctx: Ctx) { const previewHbs = loadHandlebarsFile(join(previewLoc, "preview.hbs")) ctx.body = await processString(previewHbs, { clientLibPath: objectStore.clientLibraryUrl(appId!, appInfo.version), + nonce: ctx.state.nonce }) } else { // just return the app info for jest to assert on diff --git a/packages/server/src/api/controllers/static/templates/BudibaseApp.svelte b/packages/server/src/api/controllers/static/templates/BudibaseApp.svelte index b4bfbe6660..b88b738f90 100644 --- a/packages/server/src/api/controllers/static/templates/BudibaseApp.svelte +++ b/packages/server/src/api/controllers/static/templates/BudibaseApp.svelte @@ -16,6 +16,8 @@ export let hideDevTools export let sideNav export let hideFooter + + export let nonce @@ -118,11 +120,11 @@

{/if} - {#if appMigrating} - {/if} @@ -135,7 +137,7 @@ {/each} {/if} - diff --git a/packages/server/src/api/controllers/static/templates/preview.hbs b/packages/server/src/api/controllers/static/templates/preview.hbs index 54b5b1a4e4..87b9ad6ea3 100644 --- a/packages/server/src/api/controllers/static/templates/preview.hbs +++ b/packages/server/src/api/controllers/static/templates/preview.hbs @@ -31,7 +31,7 @@ } -