From 9da1c7790311f5cf4b523a9f65abd2d00bc49a5c Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Thu, 13 Jan 2022 14:07:49 +0000 Subject: [PATCH 1/3] Fix return url using cookies --- packages/builder/src/builderStore/cookies.js | 18 +++++++-- .../builder/src/pages/builder/_layout.svelte | 37 ++++++++++++++++++- .../src/pages/builder/auth/login.svelte | 10 ++--- packages/builder/src/stores/portal/auth.js | 10 +++++ .../client/src/components/ClientApp.svelte | 5 ++- 5 files changed, 65 insertions(+), 15 deletions(-) diff --git a/packages/builder/src/builderStore/cookies.js b/packages/builder/src/builderStore/cookies.js index a84f1a4f20..cb4e46ec86 100644 --- a/packages/builder/src/builderStore/cookies.js +++ b/packages/builder/src/builderStore/cookies.js @@ -1,16 +1,26 @@ export const Cookies = { Auth: "budibase:auth", CurrentApp: "budibase:currentapp", + ReturnUrl: "budibase:returnurl", +} + +export function setCookie(name, value) { + if (getCookie(name)) { + removeCookie(name) + } + window.document.cookie = `${name}=${value}; Path=/;` } export function getCookie(cookieName) { - return document.cookie.split(";").some(cookie => { - return cookie.trim().startsWith(`${cookieName}=`) - }) + const value = `; ${document.cookie}` + const parts = value.split(`; ${cookieName}=`) + if (parts.length === 2) { + return parts[1].split(";").shift() + } } export function removeCookie(cookieName) { if (getCookie(cookieName)) { - document.cookie = `${cookieName}=; Max-Age=-99999999;` + document.cookie = `${cookieName}=; Max-Age=-99999999; Path=/;` } } diff --git a/packages/builder/src/pages/builder/_layout.svelte b/packages/builder/src/pages/builder/_layout.svelte index bf55be5534..eedab72ee4 100644 --- a/packages/builder/src/pages/builder/_layout.svelte +++ b/packages/builder/src/pages/builder/_layout.svelte @@ -2,6 +2,12 @@ import { isActive, redirect, params } from "@roxi/routify" import { admin, auth } from "stores/portal" import { onMount } from "svelte" + import { + Cookies, + getCookie, + removeCookie, + setCookie, + } from "builderStore/cookies" let loaded = false @@ -67,6 +73,25 @@ $: { const apiReady = $admin.loaded && $auth.loaded + + // firstly, set the return url + if ( + loaded && + apiReady && + !$auth.user && + !getCookie(Cookies.ReturnUrl) && + // logout triggers a page refresh, so we don't want to set the return url + !$auth.postLogout && + // don't set the return url on pre-login pages + !$isActive("./auth") && + !$isActive("./invite") && + !$isActive("./admin") + ) { + const url = window.location.pathname + console.log("setting return url:" + url) + setCookie(Cookies.ReturnUrl, url) + } + // if tenant is not set go to it if ( loaded && @@ -90,13 +115,21 @@ !$isActive("./invite") && !$isActive("./admin") ) { - const returnUrl = encodeURIComponent(window.location.pathname) - $redirect("./auth?", { returnUrl }) + $redirect("./auth") } // check if password reset required for user else if ($auth.user?.forceResetPassword) { $redirect("./auth/reset") } + // lastly, redirect to the return url if it has been set + else if (loaded && apiReady && $auth.user) { + const returnUrl = getCookie(Cookies.ReturnUrl) + if (returnUrl) { + removeCookie(Cookies.ReturnUrl) + console.log("redirecting to return url:" + returnUrl) + window.location.href = returnUrl + } + } } diff --git a/packages/builder/src/pages/builder/auth/login.svelte b/packages/builder/src/pages/builder/auth/login.svelte index 5a5a27eb6e..7a13164c51 100644 --- a/packages/builder/src/pages/builder/auth/login.svelte +++ b/packages/builder/src/pages/builder/auth/login.svelte @@ -10,7 +10,7 @@ notifications, Link, } from "@budibase/bbui" - import { goto, params } from "@roxi/routify" + import { goto } from "@roxi/routify" import { auth, organisation, oidc, admin } from "stores/portal" import GoogleButton from "./_components/GoogleButton.svelte" import OIDCButton from "./_components/OIDCButton.svelte" @@ -35,12 +35,8 @@ if ($auth?.user?.forceResetPassword) { $goto("./reset") } else { - if ($params["?returnUrl"]) { - window.location = decodeURIComponent($params["?returnUrl"]) - } else { - notifications.success("Logged in successfully") - $goto("../portal") - } + notifications.success("Logged in successfully") + $goto("../portal") } } catch (err) { console.error(err) diff --git a/packages/builder/src/stores/portal/auth.js b/packages/builder/src/stores/portal/auth.js index 6be2c7decf..bdd4d95915 100644 --- a/packages/builder/src/stores/portal/auth.js +++ b/packages/builder/src/stores/portal/auth.js @@ -9,6 +9,7 @@ export function createAuthStore() { tenantId: "default", tenantSet: false, loaded: false, + postLogout: false, }) const store = derived(auth, $store => { let initials = null @@ -34,6 +35,7 @@ export function createAuthStore() { tenantId: $store.tenantId, tenantSet: $store.tenantSet, loaded: $store.loaded, + postLogout: $store.postLogout, initials, isAdmin, isBuilder, @@ -89,6 +91,13 @@ export function createAuthStore() { return info } + async function setPostLogout() { + auth.update(store => { + store.postLogout = true + return store + }) + } + async function getInitInfo() { const response = await api.get(`/api/global/auth/init`) const json = response.json() @@ -145,6 +154,7 @@ export function createAuthStore() { await response.json() await setInitInfo({}) setUser(null) + setPostLogout() }, updateSelf: async fields => { const newUser = { ...get(auth).user, ...fields } diff --git a/packages/client/src/components/ClientApp.svelte b/packages/client/src/components/ClientApp.svelte index 98dec9667b..7f5bed210e 100644 --- a/packages/client/src/components/ClientApp.svelte +++ b/packages/client/src/components/ClientApp.svelte @@ -63,8 +63,9 @@ } else { // The user is not logged in, redirect them to login const returnUrl = `${window.location.pathname}${window.location.hash}` - const encodedUrl = encodeURIComponent(returnUrl) - window.location = `/builder/auth/login?returnUrl=${encodedUrl}` + // TODO: reuse `Cookies` from builder when frontend-core is added + window.document.cookie = `budibase:returnurl=${returnUrl}; Path=/` + window.location = `/builder/auth/login` } } } From e76ea10fc228a3da7c12da3bc9e54d3331d86440 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Thu, 13 Jan 2022 16:29:55 +0000 Subject: [PATCH 2/3] Fix dev app preview return url --- packages/backend-core/src/constants.js | 1 + packages/backend-core/src/utils.js | 9 +++-- packages/server/src/integrations/rest.ts | 37 +++++++++++++++----- packages/server/src/integrations/s3.ts | 2 +- packages/server/src/middleware/currentapp.js | 9 +++++ 5 files changed, 46 insertions(+), 12 deletions(-) diff --git a/packages/backend-core/src/constants.js b/packages/backend-core/src/constants.js index 28b9ced49b..8e6b01608e 100644 --- a/packages/backend-core/src/constants.js +++ b/packages/backend-core/src/constants.js @@ -8,6 +8,7 @@ exports.Cookies = { Auth: "budibase:auth", Init: "budibase:init", OIDC_CONFIG: "budibase:oidc:config", + RETURN_URL: "budibase:returnurl", } exports.Headers = { diff --git a/packages/backend-core/src/utils.js b/packages/backend-core/src/utils.js index 8c00f2a8b8..85dd32946f 100644 --- a/packages/backend-core/src/utils.js +++ b/packages/backend-core/src/utils.js @@ -96,7 +96,12 @@ exports.getCookie = (ctx, name) => { * @param {string|object} value The value of cookie which will be set. * @param {object} opts options like whether to sign. */ -exports.setCookie = (ctx, value, name = "builder", opts = { sign: true }) => { +exports.setCookie = ( + ctx, + value, + name = "builder", + opts = { sign: true, requestDomain: false } +) => { if (value && opts && opts.sign) { value = jwt.sign(value, options.secretOrKey) } @@ -108,7 +113,7 @@ exports.setCookie = (ctx, value, name = "builder", opts = { sign: true }) => { overwrite: true, } - if (environment.COOKIE_DOMAIN) { + if (environment.COOKIE_DOMAIN && !opts.requestDomain) { config.domain = environment.COOKIE_DOMAIN } diff --git a/packages/server/src/integrations/rest.ts b/packages/server/src/integrations/rest.ts index 3199ce3bde..ea40dfb609 100644 --- a/packages/server/src/integrations/rest.ts +++ b/packages/server/src/integrations/rest.ts @@ -43,8 +43,8 @@ const coreFields = { enum: Object.values(BodyTypes), }, pagination: { - type: DatasourceFieldTypes.OBJECT - } + type: DatasourceFieldTypes.OBJECT, + }, } module RestModule { @@ -178,12 +178,17 @@ module RestModule { headers, }, pagination: { - cursor: nextCursor - } + cursor: nextCursor, + }, } } - getUrl(path: string, queryString: string, pagination: PaginationConfig | null, paginationValues: PaginationValues | null): string { + getUrl( + path: string, + queryString: string, + pagination: PaginationConfig | null, + paginationValues: PaginationValues | null + ): string { // Add pagination params to query string if required if (pagination?.location === "query" && paginationValues) { const { pageParam, sizeParam } = pagination @@ -217,14 +222,22 @@ module RestModule { return complete } - addBody(bodyType: string, body: string | any, input: any, pagination: PaginationConfig | null, paginationValues: PaginationValues | null) { + addBody( + bodyType: string, + body: string | any, + input: any, + pagination: PaginationConfig | null, + paginationValues: PaginationValues | null + ) { if (!input.headers) { input.headers = {} } if (bodyType === BodyTypes.NONE) { return input } - let error, object: any = {}, string = "" + let error, + object: any = {}, + string = "" try { if (body) { string = typeof body !== "string" ? JSON.stringify(body) : body @@ -333,7 +346,7 @@ module RestModule { requestBody, authConfigId, pagination, - paginationValues + paginationValues, } = query const authHeaders = this.getAuthHeaders(authConfigId) @@ -352,7 +365,13 @@ module RestModule { } let input: any = { method, headers: this.headers } - input = this.addBody(bodyType, requestBody, input, pagination, paginationValues) + input = this.addBody( + bodyType, + requestBody, + input, + pagination, + paginationValues + ) this.startTimeMs = performance.now() const url = this.getUrl(path, queryString, pagination, paginationValues) diff --git a/packages/server/src/integrations/s3.ts b/packages/server/src/integrations/s3.ts index 25b439fd58..273f221575 100644 --- a/packages/server/src/integrations/s3.ts +++ b/packages/server/src/integrations/s3.ts @@ -38,7 +38,7 @@ module S3Module { signatureVersion: { type: "string", required: false, - default: "v4" + default: "v4", }, }, query: { diff --git a/packages/server/src/middleware/currentapp.js b/packages/server/src/middleware/currentapp.js index 69f80c895b..e11aefdf1c 100644 --- a/packages/server/src/middleware/currentapp.js +++ b/packages/server/src/middleware/currentapp.js @@ -47,6 +47,15 @@ module.exports = async (ctx, next) => { (!ctx.user || !ctx.user.builder || !ctx.user.builder.global) ) { clearCookie(ctx, Cookies.CurrentApp) + // have to set the return url on the server side as client side is not available + setCookie(ctx, ctx.url, Cookies.RETURN_URL, { + // don't sign so the browser can easily read + sign: false, + // use the request domain to match how ui handles the return url cookie. + // it's important we don't use the shared domain here as the builder + // can't delete from it without awareness of the domain. + requestDomain: true, + }) return ctx.redirect("/") } From 5f65c704014b36aabc6702ddc559058486937beb Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Mon, 17 Jan 2022 09:53:53 +0000 Subject: [PATCH 3/3] Remove console.log statements --- packages/builder/src/pages/builder/_layout.svelte | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/builder/src/pages/builder/_layout.svelte b/packages/builder/src/pages/builder/_layout.svelte index eedab72ee4..12a544096a 100644 --- a/packages/builder/src/pages/builder/_layout.svelte +++ b/packages/builder/src/pages/builder/_layout.svelte @@ -88,7 +88,6 @@ !$isActive("./admin") ) { const url = window.location.pathname - console.log("setting return url:" + url) setCookie(Cookies.ReturnUrl, url) } @@ -126,7 +125,6 @@ const returnUrl = getCookie(Cookies.ReturnUrl) if (returnUrl) { removeCookie(Cookies.ReturnUrl) - console.log("redirecting to return url:" + returnUrl) window.location.href = returnUrl } }