diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index f4c0774520..5418ec1f3e 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -4302ebbb8ded39e04ebcf7aaac71847c9bebe19c \ No newline at end of file +5c9a2780bdc82f243d2539007045c34049d762a6 \ No newline at end of file diff --git a/backend/windmill-api/src/public_app_layer.rs b/backend/windmill-api/src/public_app_layer.rs index 7d5e5a6e3b..c11c920475 100644 --- a/backend/windmill-api/src/public_app_layer.rs +++ b/backend/windmill-api/src/public_app_layer.rs @@ -75,6 +75,7 @@ fn is_public_route_whitelisted(path: &str) -> bool { "/api/oauth/list_logins", "/public/*", "/a/*", + "/api/oauth/get_connect/*", "/Inter-Variable.woff2", ]; diff --git a/frontend/src/lib/components/AppConnectInner.svelte b/frontend/src/lib/components/AppConnectInner.svelte index 817a6f4f16..6e4854e550 100644 --- a/frontend/src/lib/components/AppConnectInner.svelte +++ b/frontend/src/lib/components/AppConnectInner.svelte @@ -33,6 +33,7 @@ import TextInput from './text_input/TextInput.svelte' import { usePromise } from '$lib/svelte5Utils.svelte' import { pollJobResult } from './jobs/utils' + import { sameTopDomainOrigin } from '$lib/cookies' interface Props { step?: number @@ -239,7 +240,7 @@ function popupListener(event) { console.log('Received oauth popup message', event) let data = event.data - if (event.origin == null || event.origin !== window.location.origin) { + if (!sameTopDomainOrigin(event.origin, window.location.origin)) { console.log( 'Received oauth popup message from different origin', event.origin, @@ -397,6 +398,7 @@ } window.addEventListener('message', popupListener) window.addEventListener('storage', handleStorageEvent) + console.log('opening popup', url.toString()) window.open(url.toString(), '_blank', 'popup=true') step += 1 } diff --git a/frontend/src/lib/components/AppConnectLightweightResourcePicker.svelte b/frontend/src/lib/components/AppConnectLightweightResourcePicker.svelte index 9e3fe4b55a..81dd26c04b 100644 --- a/frontend/src/lib/components/AppConnectLightweightResourcePicker.svelte +++ b/frontend/src/lib/components/AppConnectLightweightResourcePicker.svelte @@ -42,7 +42,7 @@ {})}>Back {/if} - {})}> + {})}> {#if step == 2 && !manual} Connect {:else if step == 1} diff --git a/frontend/src/lib/components/Login.svelte b/frontend/src/lib/components/Login.svelte index 086ab367b6..617d494189 100644 --- a/frontend/src/lib/components/Login.svelte +++ b/frontend/src/lib/components/Login.svelte @@ -19,6 +19,7 @@ import { onDestroy, onMount } from 'svelte' import Skeleton from './common/skeleton/Skeleton.svelte' import Button from './common/button/Button.svelte' + import { sameTopDomainOrigin } from '$lib/cookies' interface Props { rd?: string | undefined @@ -212,8 +213,9 @@ function popupListener(event) { let data = event.data - console.log('popupListener', data, event.origin, window.location.origin) - if (event.origin !== window.location.origin) { + // console.log('popupListener', data, event.origin, window.location.origin) + if (!sameTopDomainOrigin(event.origin, window.location.origin)) { + console.log('popupListener from different origin', event.origin, window.location.origin) return } @@ -261,7 +263,9 @@ console.error('Could not persist redirection to local storage', e) } } - let url = base + '/api/oauth/login/' + provider + let url = base + '/api/oauth/login/' + provider + (popup ? '?close=true' : '') + console.log('storeRedirect', popup, url) + if (popup) { localStorage.setItem('closeUponLogin', 'true') window.addEventListener('message', popupListener) diff --git a/frontend/src/lib/components/apps/editor/PublicApp.svelte b/frontend/src/lib/components/apps/editor/PublicApp.svelte new file mode 100644 index 0000000000..9495030573 --- /dev/null +++ b/frontend/src/lib/components/apps/editor/PublicApp.svelte @@ -0,0 +1,145 @@ + + + + Powered by Windmill + + +{#snippet userInfo(child)} + {child} +{/snippet} + +{#if $userStore} + {@render userInfo($userStore.username)} + {:else if globalUser} + {@render userInfo(globalUser.email)} + {:else}{/if} + + +{#if notExists} + There was an error loading the app, is the url correct? Go to Windmill + +{:else if noPermission} + This app requires read access + + {#if $userStore}You are logged in but have no read access to this app{:else if globalUser && workspace} + You are logged in but are not a member of the workspace {workspace} this app is part of + {:else}You must be logged in and have read access to this app{/if} + + {#if !jwtError} + + {/if} + +{:else if app} + {#key app} + + goto(path)} + gotoFn={(path, opt) => goto(path, opt)} + /> + + {/key} +{:else} + +{/if} diff --git a/frontend/src/lib/cookies.ts b/frontend/src/lib/cookies.ts new file mode 100644 index 0000000000..22d162bf03 --- /dev/null +++ b/frontend/src/lib/cookies.ts @@ -0,0 +1,29 @@ +/** + * Reads the value of a cookie by name. + * @param {string} name - The name of the cookie to retrieve. + * @returns {string | undefined} The cookie value, or undefined if not found. + */ +export function getCookie(name: string): string | undefined { + const match = document.cookie.match( + new RegExp('(?:^|; )' + name.replace(/([.$?*|{}()\[\]\\\/\+^])/g, '\\$1') + '=([^;]*)') + ) + return match ? decodeURIComponent(match[1]) : undefined +} + + + +// this only check the last 2 segments to work for popup on shared top-domain +export function sameTopDomainOrigin(origin: string | null, desktopOrigin: string): boolean { + if (origin == null) { + return false + } + const getLastTwoSegments = (url: string) => { + const parts = url.split('.'); + return parts.length >= 2 ? parts.slice(-2).join('.') : url; + }; + if (origin.includes('.') && desktopOrigin.includes('.')) { + return getLastTwoSegments(origin) === getLastTwoSegments(desktopOrigin); + } else { + return origin === desktopOrigin; + } +} \ No newline at end of file diff --git a/frontend/src/routes/a/[...path]/+page.svelte b/frontend/src/routes/a/[...path]/+page.svelte index 6aa05e6110..062f7ae8de 100644 --- a/frontend/src/routes/a/[...path]/+page.svelte +++ b/frontend/src/routes/a/[...path]/+page.svelte @@ -1,33 +1,21 @@ - - Powered by Windmill - - -{#if $userStore} - {$userStore.username} - {:else}{/if} - - -{#if notExists} - 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 to this app{:else}You must be logged - in and have read access to this app{/if} - - {#if !jwtError} - { - - // window.location.reload() - loadApp() - app = app - }} - popup - rd={page.url.toString()} - /> - {/if} - -{:else if app} - {#key app} - - goto(path)} - gotoFn={(path, opt) => goto(path, opt)} - /> - - {/key} -{:else} - -{/if} + { + loadApp() + }} +> diff --git a/frontend/src/routes/(root)/(logged)/oauth/callback/[client_name]/+page.svelte b/frontend/src/routes/oauth/callback/[client_name]/+page.svelte similarity index 100% rename from frontend/src/routes/(root)/(logged)/oauth/callback/[client_name]/+page.svelte rename to frontend/src/routes/oauth/callback/[client_name]/+page.svelte diff --git a/frontend/src/routes/(root)/(logged)/oauth/callback_slack/+page.svelte b/frontend/src/routes/oauth/callback_slack/+page.svelte similarity index 100% rename from frontend/src/routes/(root)/(logged)/oauth/callback_slack/+page.svelte rename to frontend/src/routes/oauth/callback_slack/+page.svelte diff --git a/frontend/src/routes/(root)/(logged)/oauth/callback_slack/instance/+page.svelte b/frontend/src/routes/oauth/callback_slack/instance/+page.svelte similarity index 100% rename from frontend/src/routes/(root)/(logged)/oauth/callback_slack/instance/+page.svelte rename to frontend/src/routes/oauth/callback_slack/instance/+page.svelte diff --git a/frontend/src/routes/(root)/(logged)/oauth/callback_supabase/+page.svelte b/frontend/src/routes/oauth/callback_supabase/+page.svelte similarity index 100% rename from frontend/src/routes/(root)/(logged)/oauth/callback_supabase/+page.svelte rename to frontend/src/routes/oauth/callback_supabase/+page.svelte diff --git a/frontend/src/routes/public/[workspace]/[...secret]/+page.svelte b/frontend/src/routes/public/[workspace]/[...secret]/+page.svelte index fadae2baf9..c661aa48c6 100644 --- a/frontend/src/routes/public/[workspace]/[...secret]/+page.svelte +++ b/frontend/src/routes/public/[workspace]/[...secret]/+page.svelte @@ -1,34 +1,22 @@ - - Powered by Windmill - - -{#if $userStore} - {$userStore.username} - {:else}{/if} - - -{#if notExists} - 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 to this app{:else}You must be logged - in and have read access to this app{/if} - - {#if !jwtError} - { - console.log('login') - // window.location.reload() - loadUser().then(() => { - loadApp() - }) - app = app - }} - popup - rd={page.url.toString()} - /> - {/if} - -{:else if app} - {#key app} - - goto(path)} - gotoFn={(path, opt) => goto(path, opt)} - /> - - {/key} -{:else} - -{/if} + { + loadAll() + }} +> diff --git a/frontend/src/routes/user/login_callback/[client_name]/+page.svelte b/frontend/src/routes/user/login_callback/[client_name]/+page.svelte index 902a9e4a15..ac05ae04b5 100644 --- a/frontend/src/routes/user/login_callback/[client_name]/+page.svelte +++ b/frontend/src/routes/user/login_callback/[client_name]/+page.svelte @@ -12,6 +12,8 @@ import { parseQueryParams } from '$lib/utils' import { page } from '$app/state' import { isCloudHosted } from '$lib/cloud' + import { getCookie } from '$lib/cookies' + // import { getAndDeleteCookie } from '$lib/cookies' let error = page.url.searchParams.get('error') let clientName = page.params.client_name ?? '' @@ -19,11 +21,14 @@ let state = page.url.searchParams.get('state') ?? undefined onMount(async () => { + // const closeCookie = getAndDeleteCookie('close') + // console.log('closeCookie', closeCookie) const rd = localStorage.getItem('rd') if (rd) { localStorage.removeItem('rd') } - const closeUponLogin = localStorage.getItem('closeUponLogin') == 'true' + const cookieCloseUponLogin = getCookie('close') == 'true' + const closeUponLogin = cookieCloseUponLogin ?? localStorage.getItem('closeUponLogin') == 'true' if (error) { sendUserToast(`Error trying to login with ${clientName} ${error}`, true) if (closeUponLogin) { diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 9fc6660220..27397cadb9 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -11,7 +11,15 @@ const version = JSON.parse(json) const config = { server: { https: process.env.HTTPS === 'true', - allowedHosts: ['localhost', '127.0.0.1', '0.0.0.0', 'rubendev.wimill.xyz', 'windmill.xyz'], + allowedHosts: [ + 'localhost', + '127.0.0.1', + '0.0.0.0', + 'rubendev.wimill.xyz', + 'windmill.xyz', + 'app.windmill.xyz', + 'public.windmill.xyz' + ], port: 3000, proxy: { '^/api/w/[^/]+/s3_proxy/.*': { @@ -28,8 +36,8 @@ const config = { }, '^/api/.*': { target: process.env.REMOTE ?? 'https://app.windmill.dev/', - changeOrigin: true, - cookieDomainRewrite: 'localhost' + changeOrigin: true + // cookieDomainRewrite: 'localhost' }, '^/ws/.*': { target: process.env.REMOTE_LSP ?? 'https://app.windmill.dev', @@ -64,7 +72,7 @@ const config = { exclude: [ '@codingame/monaco-vscode-standalone-typescript-language-features', '@codingame/monaco-vscode-standalone-languages' - ], + ] }, worker: { format: 'es'