diff --git a/backend/windmill-api/src/apps.rs b/backend/windmill-api/src/apps.rs index 1b986f0d59..24d3d816c6 100644 --- a/backend/windmill-api/src/apps.rs +++ b/backend/windmill-api/src/apps.rs @@ -425,6 +425,8 @@ async fn get_app_by_id( } async fn get_public_app_by_secret( + OptAuthed(opt_authed): OptAuthed, + Extension(user_db): Extension, Extension(db): Extension, Path((w_id, secret)): Path<(String, String)>, ) -> JsonResult { @@ -454,10 +456,32 @@ async fn get_public_app_by_secret( let policy = serde_json::from_str::(app.policy.0.get()).map_err(to_anyhow)?; - if !matches!(policy.execution_mode, ExecutionMode::Anonymous) { - return Err(Error::NotAuthorized( - "App visibility does not allow public access".to_string(), - )); + if matches!(policy.execution_mode, ExecutionMode::Anonymous) { + return Ok(Json(app)); + } + + if opt_authed.is_none() { + { + return Err(Error::NotAuthorized( + "App visibility does not allow public access and you are not logged in".to_string(), + )); + } + } else { + let authed = opt_authed.unwrap(); + let mut tx = user_db.begin(&authed).await?; + let is_visible = sqlx::query_scalar!( + "SELECT EXISTS(SELECT 1 FROM app WHERE id = $1 AND workspace_id = $2)", + id, + &w_id + ) + .fetch_one(&mut *tx) + .await?; + tx.commit().await?; + if !is_visible.unwrap_or(false) { + return Err(Error::NotAuthorized( + "App visibility does not allow public access and you are logged in but you have no read-access to that app".to_string(), + )); + } } Ok(Json(app)) diff --git a/frontend/src/lib/components/LightweightResourcePicker.svelte b/frontend/src/lib/components/LightweightResourcePicker.svelte index 4a3ace7e6d..88131cacb4 100644 --- a/frontend/src/lib/components/LightweightResourcePicker.svelte +++ b/frontend/src/lib/components/LightweightResourcePicker.svelte @@ -1,13 +1,14 @@ + +
+
+ {#if !logins} + {#each Array(4) as _} + + {/each} + {:else} + {#each providers as { type, icon, name }} + {#if logins?.includes(type)} + + {/if} + {/each} + {#each logins.filter((x) => !providersType?.includes(x)) as login} + + {/each} + {/if} + {#if saml} + + {/if} +
+ {#if saml || (logins && logins.length > 0)} +
0 ? 'mt-6' : '')}> + +
+ {/if} + + {#if showPassword} +
+
+ {#if isCloudHosted()} +

+ To get credentials without the OAuth providers above, send an email at + contact@windmill.dev +

+ {/if} +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+
+ + {#if isCloudHosted()} +

+ By logging in, you agree to our + + Terms of Service + + and + + Privacy Policy + +

+ {/if} +
+ {/if} +
diff --git a/frontend/src/lib/components/apps/components/display/AppAlert.svelte b/frontend/src/lib/components/apps/components/display/AppAlert.svelte index 53bd288671..20fc60ba03 100644 --- a/frontend/src/lib/components/apps/components/display/AppAlert.svelte +++ b/frontend/src/lib/components/apps/components/display/AppAlert.svelte @@ -9,7 +9,7 @@ import { twMerge } from 'tailwind-merge' import InitializeComponent from '../helpers/InitializeComponent.svelte' import { Alert } from '$lib/components/common' - import { AlignWrapper } from '../helpers' + import AlignWrapper from '../helpers/AlignWrapper.svelte' export let id: string export let configuration: RichConfigurations diff --git a/frontend/src/lib/components/apps/components/display/AppCustomComponent.svelte b/frontend/src/lib/components/apps/components/display/AppCustomComponent.svelte index c3d38fe3da..d481de1a1b 100644 --- a/frontend/src/lib/components/apps/components/display/AppCustomComponent.svelte +++ b/frontend/src/lib/components/apps/components/display/AppCustomComponent.svelte @@ -18,9 +18,9 @@ import InitializeComponent from '../helpers/InitializeComponent.svelte' import { sendUserToast } from '$lib/toast' import type { AppInput } from '../../inputType' - import { RunnableWrapper } from '../helpers' import type { CustomComponentConfig } from '../../editor/component' import { Loader2 } from 'lucide-svelte' + import RunnableWrapper from '../helpers/RunnableWrapper.svelte' export let id: string export let render: boolean diff --git a/frontend/src/lib/components/apps/components/display/AppDownload.svelte b/frontend/src/lib/components/apps/components/display/AppDownload.svelte index 8b06d11130..ef2822f32f 100644 --- a/frontend/src/lib/components/apps/components/display/AppDownload.svelte +++ b/frontend/src/lib/components/apps/components/display/AppDownload.svelte @@ -7,11 +7,11 @@ import { initCss, transformBareBase64IfNecessary } from '../../utils' import ResolveConfig from '../helpers/ResolveConfig.svelte' import InitializeComponent from '../helpers/InitializeComponent.svelte' - import { AlignWrapper } from '../helpers' import { Button } from '$lib/components/common' import { loadIcon } from '../icon' import ComponentErrorHandler from '../helpers/ComponentErrorHandler.svelte' import ResolveStyle from '../helpers/ResolveStyle.svelte' + import AlignWrapper from '../helpers/AlignWrapper.svelte' export let id: string export let configuration: RichConfigurations diff --git a/frontend/src/lib/components/apps/components/display/AppIcon.svelte b/frontend/src/lib/components/apps/components/display/AppIcon.svelte index 7f56e4642a..00085af7a1 100644 --- a/frontend/src/lib/components/apps/components/display/AppIcon.svelte +++ b/frontend/src/lib/components/apps/components/display/AppIcon.svelte @@ -3,13 +3,13 @@ import { initConfig, initOutput } from '../../editor/appUtils' import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types' import { initCss } from '../../utils' - import { AlignWrapper } from '../helpers' import { loadIcon } from '../icon' import InitializeComponent from '../helpers/InitializeComponent.svelte' import { components } from '../../editor/component' import ResolveConfig from '../helpers/ResolveConfig.svelte' import { twMerge } from 'tailwind-merge' import ResolveStyle from '../helpers/ResolveStyle.svelte' + import AlignWrapper from '../helpers/AlignWrapper.svelte' export let id: string export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = 'left' diff --git a/frontend/src/lib/components/apps/components/display/AppMenu.svelte b/frontend/src/lib/components/apps/components/display/AppMenu.svelte index 16105afcc8..686319b7bd 100644 --- a/frontend/src/lib/components/apps/components/display/AppMenu.svelte +++ b/frontend/src/lib/components/apps/components/display/AppMenu.svelte @@ -12,12 +12,12 @@ import { initCss } from '../../utils' import ResolveConfig from '../helpers/ResolveConfig.svelte' import InitializeComponent from '../helpers/InitializeComponent.svelte' - import { AlignWrapper } from '../helpers' import { Button } from '$lib/components/common' import { loadIcon } from '../icon' import ResolveStyle from '../helpers/ResolveStyle.svelte' import Menu from '$lib/components/common/menu/MenuV2.svelte' import { AppButton } from '../buttons' + import AlignWrapper from '../helpers/AlignWrapper.svelte' export let id: string export let configuration: RichConfigurations diff --git a/frontend/src/lib/components/apps/components/display/dbtable/AppDbExplorer.svelte b/frontend/src/lib/components/apps/components/display/dbtable/AppDbExplorer.svelte index 7c05cc76d2..43db70a0fd 100644 --- a/frontend/src/lib/components/apps/components/display/dbtable/AppDbExplorer.svelte +++ b/frontend/src/lib/components/apps/components/display/dbtable/AppDbExplorer.svelte @@ -31,7 +31,6 @@ import DbExplorerCount from './DbExplorerCount.svelte' import AppAggridExplorerTable from '../table/AppAggridExplorerTable.svelte' import type { IDatasource } from 'ag-grid-community' - import { RunnableWrapper } from '../../helpers' import type RunnableComponent from '../../helpers/RunnableComponent.svelte' import InsertRowRunnable from './InsertRowRunnable.svelte' import DeleteRow from './DeleteRow.svelte' @@ -40,6 +39,7 @@ import DebouncedInput from '../../helpers/DebouncedInput.svelte' import { CancelablePromise } from '$lib/gen' import RefreshButton from '$lib/components/apps/components/helpers/RefreshButton.svelte' + import RunnableWrapper from '../../helpers/RunnableWrapper.svelte' export let id: string export let configuration: RichConfigurations diff --git a/frontend/src/lib/components/apps/components/display/index.ts b/frontend/src/lib/components/apps/components/display/index.ts deleted file mode 100644 index 033fed135d..0000000000 --- a/frontend/src/lib/components/apps/components/display/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -export { default as AppTable } from './table/AppTable.svelte' -export { default as AppAggridTable } from './table/AppAggridTable.svelte' -export { default as AppBarChart } from './AppBarChart.svelte' -export { default as AppDisplayComponent } from './AppDisplayComponent.svelte' -export { default as AppHtml } from './AppHtml.svelte' -export { default as AppIcon } from './AppIcon.svelte' -export { default as AppImage } from './AppImage.svelte' -export { default as AppMap } from './AppMap.svelte' -export { default as AppPdf } from './AppPdf.svelte' -export { default as AppPieChart } from './AppPieChart.svelte' -export { default as AppScatterChart } from './AppScatterChart.svelte' -export { default as AppText } from './AppText.svelte' -export { default as AppTimeseries } from './AppTimeseries.svelte' -export { default as PlotlyHtml } from './PlotlyHtml.svelte' -export { default as VegaLiteHtml } from './VegaLiteHtml.svelte' -export { default as AppMarkdown } from './AppMarkdown.svelte' -export { default as PlotlyHtmlV2 } from './PlotlyHtmlV2.svelte' diff --git a/frontend/src/lib/components/apps/components/display/table/AppAggridInfiniteTable.svelte b/frontend/src/lib/components/apps/components/display/table/AppAggridInfiniteTable.svelte index 86c3267a0d..c4470ed230 100644 --- a/frontend/src/lib/components/apps/components/display/table/AppAggridInfiniteTable.svelte +++ b/frontend/src/lib/components/apps/components/display/table/AppAggridInfiniteTable.svelte @@ -16,9 +16,10 @@ import { initCss } from '$lib/components/apps/utils' import ResolveStyle from '../../helpers/ResolveStyle.svelte' import AppAggridExplorerTable from './AppAggridExplorerTable.svelte' - import { DebouncedInput, type RunnableComponent } from '../..' import { getPrimaryKeys } from '../dbtable/utils' import InitializeComponent from '../../helpers/InitializeComponent.svelte' + import DebouncedInput from '../../helpers/DebouncedInput.svelte' + import RunnableComponent from '../../helpers/RunnableComponent.svelte' export let id: string export let componentInput: AppInput | undefined diff --git a/frontend/src/lib/components/apps/components/display/table/AppAggridTableActions.svelte b/frontend/src/lib/components/apps/components/display/table/AppAggridTableActions.svelte index 8174632a75..4e70d49145 100644 --- a/frontend/src/lib/components/apps/components/display/table/AppAggridTableActions.svelte +++ b/frontend/src/lib/components/apps/components/display/table/AppAggridTableActions.svelte @@ -7,7 +7,9 @@ import 'ag-grid-community/styles/ag-theme-alpine.css' import AppButton from '../../buttons/AppButton.svelte' - import { AppCheckbox, AppSelect } from '../..' + import AppCheckbox from '../../inputs/AppCheckbox.svelte' + import AppSelect from '../../inputs/AppSelect.svelte' + import { twMerge } from 'tailwind-merge' import { Popup } from '$lib/components/common' import { Plug2 } from 'lucide-svelte' diff --git a/frontend/src/lib/components/apps/components/helpers/ResolveConfig.svelte b/frontend/src/lib/components/apps/components/helpers/ResolveConfig.svelte index af8412662f..eb6234fad7 100644 --- a/frontend/src/lib/components/apps/components/helpers/ResolveConfig.svelte +++ b/frontend/src/lib/components/apps/components/helpers/ResolveConfig.svelte @@ -1,5 +1,5 @@
-
-
- {#if !logins} - {#each Array(4) as _} - - {/each} - {:else} - {#each providers as { type, icon, name }} - {#if logins?.includes(type)} - - {/if} - {/each} - {#each logins.filter((x) => !providersType?.includes(x)) as login} - - {/each} - {/if} - {#if saml} - - {/if} -
- {#if saml || (logins && logins.length > 0)} -
0 ? 'mt-6' : '')}> - -
- {/if} - - {#if showPassword} -
-
- {#if isCloudHosted()} -

- To get credentials without the OAuth providers above, send an email at - contact@windmill.dev -

- {/if} -
- -
- -
-
- -
- -
- -
-
- -
- -
-
- - {#if isCloudHosted()} -

- By logging in, you agree to our - - Terms of Service - - and - - Privacy Policy - -

- {/if} -
- {/if} -
+ diff --git a/frontend/src/routes/(root)/embed_connect/+page.svelte b/frontend/src/routes/(root)/embed_connect/+page.svelte index 2131cee355..edc4cf3a4d 100644 --- a/frontend/src/routes/(root)/embed_connect/+page.svelte +++ b/frontend/src/routes/(root)/embed_connect/+page.svelte @@ -4,6 +4,7 @@ import AppConnectInner from '$lib/components/AppConnectInner.svelte' import DarkModeObserver from '$lib/components/DarkModeObserver.svelte' import { Button } from '$lib/components/common' + import { workspaceStore } from '$lib/stores' import { onMount } from 'svelte' let resourceType = $page.url.searchParams.get('resource_type') ?? undefined @@ -15,6 +16,11 @@ let appConnect: AppConnectInner | undefined = undefined let darkMode: boolean = false + const workspace = $page.url.searchParams.get('workspace') + + if (workspace) { + $workspaceStore = workspace + } onMount(async () => { if (resourceType) { diff --git a/frontend/src/routes/public/[workspace]/[...secret]/+page.svelte b/frontend/src/routes/public/[workspace]/[...secret]/+page.svelte index b6f9628884..c12d4f6c45 100644 --- a/frontend/src/routes/public/[workspace]/[...secret]/+page.svelte +++ b/frontend/src/routes/public/[workspace]/[...secret]/+page.svelte @@ -15,10 +15,14 @@ import { writable } from 'svelte/store' import { setLicense } from '$lib/enterpriseUtils' import { isCloudHosted } from '$lib/cloud' + import Login from '$lib/components/Login.svelte' + import { getUserExt } from '$lib/user' + import { User, UserRoundX } from 'lucide-svelte' + import ChartHighlightTheme from '$lib/components/ChartHighlightTheme.svelte' let app: (AppWithLastVersion & { value: any }) | undefined = undefined let notExists = false - + let noPermission = false setContext(IS_APP_PUBLIC_CONTEXT_KEY, true) async function loadApp() { @@ -28,22 +32,47 @@ path: $page.params.secret }) } catch (e) { - notExists = true + if (e.status == 401) { + noPermission = true + } else { + notExists = true + } } } if (BROWSER) { setLicense() loadApp() + loadUser() + } + + async function loadUser() { + try { + userStore.set(await getUserExt($page.params.workspace)) + } catch (e) { + console.warn('Anonymous user') + } } const breakpoint = writable('lg') + + const darkMode = + window.localStorage.getItem('dark-mode') ?? + (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') + + if (darkMode === 'dark') { + document.documentElement.classList.add('dark') + } else { + document.documentElement.classList.remove('dark') + } {@html github} + +
{#if $userStore} +
{$userStore.username}
+ {:else}{/if} +
+ {#if notExists}
There was an error loading the app. Either it does not exist at this url or its visibility - has changed to not be public anymore. Go to app + >There was an error loading the app, is the url correct? Go to Windmill
+{:else if noPermission} +
{#if $userStore}You are logged in but have no read access for this app{:else}You must be logged + in and have read access for this app{/if}
+
+ +
{:else if app} {#key app}