From d9025d1aa1b4cd82e8bd46ae7e0c89a35540c224 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 30 Oct 2020 17:12:06 +0000 Subject: [PATCH 01/10] Getting rid of userInstanceMap, preparing for meat of auth update. --- packages/server/src/api/controllers/application.js | 1 - packages/server/src/api/controllers/user.js | 7 ------- 2 files changed, 8 deletions(-) diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index 66cde54fd6..1214ad43cb 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -70,7 +70,6 @@ exports.create = async function(ctx) { const newApplication = { _id: appId, type: "app", - userInstanceMap: {}, version: packageJson.version, componentLibraries: ["@budibase/standard-components"], name: ctx.request.body.name, diff --git a/packages/server/src/api/controllers/user.js b/packages/server/src/api/controllers/user.js index da0adff895..ba6adeb060 100644 --- a/packages/server/src/api/controllers/user.js +++ b/packages/server/src/api/controllers/user.js @@ -39,13 +39,6 @@ exports.create = async function(ctx) { const response = await db.post(user) - const app = await db.get(ctx.user.appId) - app.userInstanceMap = { - ...app.userInstanceMap, - [username]: ctx.user.appId, - } - await db.put(app) - ctx.status = 200 ctx.message = "User created successfully." ctx.userId = response._id From c89f73efc0a40537115be538cfe7687152e19819 Mon Sep 17 00:00:00 2001 From: Michael Drury Date: Mon, 2 Nov 2020 15:46:08 +0000 Subject: [PATCH 02/10] Some updates, still WIP. --- packages/server/src/api/controllers/application.js | 2 +- packages/server/src/api/controllers/auth.js | 2 +- packages/server/src/api/controllers/static.js | 2 +- .../server/src/api/routes/tests/couchTestUtils.js | 2 +- .../server/src/utilities/builder/setBuilderToken.js | 13 ++++++++----- packages/server/src/utilities/index.js | 4 ++++ 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index 1214ad43cb..a8596e38ac 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -61,7 +61,7 @@ exports.fetchAppPackage = async function(ctx) { const db = new CouchDB(ctx.params.appId) const application = await db.get(ctx.params.appId) ctx.body = await getPackageForBuilder(ctx.config, application) - setBuilderToken(ctx, ctx.params.appId, application.version) + await setBuilderToken(ctx, ctx.params.appId, application.version) } exports.create = async function(ctx) { diff --git a/packages/server/src/api/controllers/auth.js b/packages/server/src/api/controllers/auth.js index 9576d22da1..0cdaa25a85 100644 --- a/packages/server/src/api/controllers/auth.js +++ b/packages/server/src/api/controllers/auth.js @@ -48,7 +48,7 @@ exports.authenticate = async ctx => { const expires = new Date() expires.setDate(expires.getDate() + 1) - ctx.cookies.set("budibase:token", token, { + ctx.cookies.set(`budibase:token`, token, { expires, path: "/", httpOnly: false, diff --git a/packages/server/src/api/controllers/static.js b/packages/server/src/api/controllers/static.js index 1ebe169417..40728813b8 100644 --- a/packages/server/src/api/controllers/static.js +++ b/packages/server/src/api/controllers/static.js @@ -21,7 +21,7 @@ const COMP_LIB_BASE_APP_VERSION = "0.2.5" exports.serveBuilder = async function(ctx) { let builderPath = resolve(__dirname, "../../../builder") if (ctx.file === "index.html") { - setBuilderToken(ctx) + await setBuilderToken(ctx) } await send(ctx, ctx.file, { root: ctx.devPath || builderPath }) } diff --git a/packages/server/src/api/routes/tests/couchTestUtils.js b/packages/server/src/api/routes/tests/couchTestUtils.js index 83c968323d..6a4e67bfc7 100644 --- a/packages/server/src/api/routes/tests/couchTestUtils.js +++ b/packages/server/src/api/routes/tests/couchTestUtils.js @@ -209,7 +209,7 @@ const createUserWithPermissions = async ( const loginResult = await request .post(`/api/authenticate`) - .set({ Cookie: `budibase:token=${anonToken}` }) + .set({ Cookie: `budibase:${appId}=${anonToken}` }) .send({ username, password }) // returning necessary request headers diff --git a/packages/server/src/utilities/builder/setBuilderToken.js b/packages/server/src/utilities/builder/setBuilderToken.js index fca3e0724f..811f273d40 100644 --- a/packages/server/src/utilities/builder/setBuilderToken.js +++ b/packages/server/src/utilities/builder/setBuilderToken.js @@ -1,8 +1,9 @@ const { BUILDER_LEVEL_ID } = require("../accessLevels") const env = require("../../environment") +const CouchDB = require("../../db") const jwt = require("jsonwebtoken") -module.exports = (ctx, appId, version) => { +module.exports = async (ctx, appId, version) => { const builderUser = { userId: "BUILDER", accessLevelId: BUILDER_LEVEL_ID, @@ -18,14 +19,16 @@ module.exports = (ctx, appId, version) => { const expiry = new Date() expiry.setDate(expiry.getDate() + 30) - // remove the app token - ctx.cookies.set("budibase:token", "", { - overwrite: true, - }) // set the builder token ctx.cookies.set("builder:token", token, { expires: expiry, httpOnly: false, overwrite: true, }) + // need to clear all app tokens or else unable to use the app in the builder + let allDbNames = await CouchDB.allDbs() + allDbNames.map(dbName => {}) + ctx.cookies.set(`budibase:${appId}`, "", { + overwrite: true, + }) } diff --git a/packages/server/src/utilities/index.js b/packages/server/src/utilities/index.js index 9275659b3c..4fdc9f8b49 100644 --- a/packages/server/src/utilities/index.js +++ b/packages/server/src/utilities/index.js @@ -10,3 +10,7 @@ exports.isDev = () => { env.NODE_ENV !== "cypress" ) } + +exports.getAppId = ctx => { + +} From a1fd261af626d32b74885c647ad3d8e9591570d2 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 2 Nov 2020 20:14:10 +0000 Subject: [PATCH 03/10] Some more re-work, more testing needed to auth stuff. --- packages/client/src/createApp.js | 4 +-- packages/client/src/index.js | 4 +-- packages/client/src/render/getAppId.js | 15 ++-------- packages/client/src/render/screenRouter.js | 4 +-- packages/client/tests/testAppDef.js | 2 +- packages/server/src/api/controllers/auth.js | 5 +++- .../server/src/middleware/authenticated.js | 17 ++++------- .../src/utilities/builder/setBuilderToken.js | 14 +++++++--- packages/server/src/utilities/index.js | 28 ++++++++++++++++++- 9 files changed, 55 insertions(+), 38 deletions(-) diff --git a/packages/client/src/createApp.js b/packages/client/src/createApp.js index 233abc0f58..f9d4f2bea5 100644 --- a/packages/client/src/createApp.js +++ b/packages/client/src/createApp.js @@ -2,7 +2,7 @@ import { attachChildren } from "./render/attachChildren" import { createTreeNode } from "./render/prepareRenderComponent" import { screenRouter } from "./render/screenRouter" import { createStateManager } from "./state/stateManager" -import { parseAppIdFromCookie } from "./render/getAppId" +import { getAppIdFromPath } from "./render/getAppId" export const createApp = ({ componentLibraries, @@ -38,7 +38,7 @@ export const createApp = ({ window, }) const fallbackPath = window.location.pathname.replace( - parseAppIdFromCookie(window.document.cookie), + getAppIdFromPath(), "" ) routeTo(currentUrl || fallbackPath) diff --git a/packages/client/src/index.js b/packages/client/src/index.js index 6bbe2aee2b..54dbb7af9e 100644 --- a/packages/client/src/index.js +++ b/packages/client/src/index.js @@ -1,6 +1,6 @@ import { createApp } from "./createApp" import { builtins, builtinLibName } from "./render/builtinComponents" -import { parseAppIdFromCookie } from "./render/getAppId" +import { getAppIdFromPath } from "./render/getAppId" /** * create a web application from static budibase definition files. @@ -9,7 +9,7 @@ import { parseAppIdFromCookie } from "./render/getAppId" export const loadBudibase = async opts => { const _window = (opts && opts.window) || window // const _localStorage = (opts && opts.localStorage) || localStorage - const appId = parseAppIdFromCookie(_window.document.cookie) + const appId = getAppIdFromPath() const frontendDefinition = _window["##BUDIBASE_FRONTEND_DEFINITION##"] const user = {} diff --git a/packages/client/src/render/getAppId.js b/packages/client/src/render/getAppId.js index 4cbb6692b5..d476eda44c 100644 --- a/packages/client/src/render/getAppId.js +++ b/packages/client/src/render/getAppId.js @@ -1,14 +1,3 @@ -export const parseAppIdFromCookie = docCookie => { - const cookie = - docCookie.split(";").find(c => c.trim().startsWith("budibase:token")) || - docCookie.split(";").find(c => c.trim().startsWith("builder:token")) - - if (!cookie) return location.pathname.replace(/\//g, "") - - const base64Token = cookie.substring(lengthOfKey) - - const user = JSON.parse(atob(base64Token.split(".")[1])) - return user.appId +export const getAppIdFromPath = () => { + return location.pathname.split("/")[1] } - -const lengthOfKey = "budibase:token=".length diff --git a/packages/client/src/render/screenRouter.js b/packages/client/src/render/screenRouter.js index 0c045097ed..32a12c167a 100644 --- a/packages/client/src/render/screenRouter.js +++ b/packages/client/src/render/screenRouter.js @@ -1,6 +1,6 @@ import regexparam from "regexparam" import appStore from "../state/store" -import { parseAppIdFromCookie } from "./getAppId" +import { getAppIdFromPath } from "./getAppId" export const screenRouter = ({ screens, onScreenSelected, window }) => { function sanitize(url) { @@ -27,7 +27,7 @@ export const screenRouter = ({ screens, onScreenSelected, window }) => { const makeRootedPath = url => { if (isRunningLocally()) { - const appId = parseAppIdFromCookie(window.document.cookie) + const appId = getAppIdFromPath() if (url) { url = sanitize(url) if (!url.startsWith("/")) { diff --git a/packages/client/tests/testAppDef.js b/packages/client/tests/testAppDef.js index c583d91545..90dbd2717d 100644 --- a/packages/client/tests/testAppDef.js +++ b/packages/client/tests/testAppDef.js @@ -9,7 +9,7 @@ export const load = async (page, screens, url, host = "test.com") => { const cookieJar = new jsdom.CookieJar() const cookie = `${btoa("{}")}.${btoa('{"appId":"TEST_APP_ID"}')}.signature` cookieJar.setCookie( - `budibase:token=${cookie};domain=${host};path=/`, + `budibase:local:TEST_APP_ID=${cookie};domain=${host};path=/`, fullUrl, { looseMode: false, diff --git a/packages/server/src/api/controllers/auth.js b/packages/server/src/api/controllers/auth.js index 0cdaa25a85..2c7e43d2cc 100644 --- a/packages/server/src/api/controllers/auth.js +++ b/packages/server/src/api/controllers/auth.js @@ -4,6 +4,7 @@ const bcrypt = require("../../utilities/bcrypt") const env = require("../../environment") const { getAPIKey } = require("../../utilities/usageQuota") const { generateUserID } = require("../../db/utils") +const { getCookieName } = require("../../utilities") exports.authenticate = async ctx => { const appId = ctx.user.appId @@ -48,16 +49,18 @@ exports.authenticate = async ctx => { const expires = new Date() expires.setDate(expires.getDate() + 1) - ctx.cookies.set(`budibase:token`, token, { + ctx.cookies.set(getCookieName(appId), token, { expires, path: "/", httpOnly: false, overwrite: true, }) + delete dbUser.password ctx.body = { token, ...dbUser, + appId, } } else { ctx.throw(401, "Invalid credentials.") diff --git a/packages/server/src/middleware/authenticated.js b/packages/server/src/middleware/authenticated.js index 74f133cbde..a4bd347b75 100644 --- a/packages/server/src/middleware/authenticated.js +++ b/packages/server/src/middleware/authenticated.js @@ -9,6 +9,7 @@ const { } = require("../utilities/accessLevels") const env = require("../environment") const { AuthTypes } = require("../constants") +const { getAppId, getCookieName } = require("../utilities") module.exports = async (ctx, next) => { if (ctx.path === "/_builder") { @@ -16,8 +17,10 @@ module.exports = async (ctx, next) => { return } - const appToken = ctx.cookies.get("budibase:token") - const builderToken = ctx.cookies.get("builder:token") + const appId = getAppId(ctx) + + const appToken = ctx.cookies.get(getCookieName(appId)) + const builderToken = ctx.cookies.get(getCookieName()) let token // if running locally in the builder itself @@ -31,16 +34,6 @@ module.exports = async (ctx, next) => { if (!token) { ctx.auth.authenticated = false - - let appId = env.CLOUD ? ctx.subdomains[1] : ctx.params.appId - - // if appId can't be determined from path param or subdomain - if (!appId && ctx.request.headers.referer) { - const url = new URL(ctx.request.headers.referer) - // remove leading and trailing slashes from appId - appId = url.pathname.replace(/\//g, "") - } - ctx.user = { appId, } diff --git a/packages/server/src/utilities/builder/setBuilderToken.js b/packages/server/src/utilities/builder/setBuilderToken.js index 811f273d40..f77bfe49a4 100644 --- a/packages/server/src/utilities/builder/setBuilderToken.js +++ b/packages/server/src/utilities/builder/setBuilderToken.js @@ -2,6 +2,9 @@ const { BUILDER_LEVEL_ID } = require("../accessLevels") const env = require("../../environment") const CouchDB = require("../../db") const jwt = require("jsonwebtoken") +const { DocumentTypes, SEPARATOR } = require("../../db/utils") +const { getCookieName } = require("../index") +const APP_PREFIX = DocumentTypes.APP + SEPARATOR module.exports = async (ctx, appId, version) => { const builderUser = { @@ -20,15 +23,18 @@ module.exports = async (ctx, appId, version) => { const expiry = new Date() expiry.setDate(expiry.getDate() + 30) // set the builder token - ctx.cookies.set("builder:token", token, { + ctx.cookies.set(getCookieName(), token, { expires: expiry, httpOnly: false, overwrite: true, }) // need to clear all app tokens or else unable to use the app in the builder let allDbNames = await CouchDB.allDbs() - allDbNames.map(dbName => {}) - ctx.cookies.set(`budibase:${appId}`, "", { - overwrite: true, + allDbNames.map(dbName => { + if (dbName.startsWith(APP_PREFIX)) { + ctx.cookies.set(getCookieName(dbName), "", { + overwrite: true, + }) + } }) } diff --git a/packages/server/src/utilities/index.js b/packages/server/src/utilities/index.js index 4fdc9f8b49..4c324cbfdf 100644 --- a/packages/server/src/utilities/index.js +++ b/packages/server/src/utilities/index.js @@ -11,6 +11,32 @@ exports.isDev = () => { ) } +/** + * Given a request tries to find the appId, which can be located in various places + * @param {object} ctx The main request body to look through. + * @returns {string|undefined} If an appId was found it will be returned. + */ exports.getAppId = ctx => { - + let appId = env.CLOUD ? ctx.subdomains[1] : ctx.params.appId + // look in body if can't find it in subdomain + if (!appId && ctx.request.body && ctx.request.body.appId) { + appId = ctx.request.body.appId + } + // if appId can't be determined from path param or subdomain + if (!appId && ctx.request.headers.referer) { + const url = new URL(ctx.request.headers.referer) + // remove leading and trailing slashes from appId + appId = url.pathname.replace(/\//g, "") + } + return appId +} + +/** + * Get the name of the cookie which is to be updated/retrieved + * @param {string|undefined|null} appId OPTIONAL can specify the specific app if previewing etc + * @returns {string} The name of the token trying to find + */ +exports.getCookieName = (appId = null) => { + let mid = env.CLOUD ? "cloud" : "local" + return `budibase:${mid}:${appId ? appId : "builder"}` } From 871e9b123edfd60628949a1ae93336a9bf38bf99 Mon Sep 17 00:00:00 2001 From: Michael Drury Date: Mon, 2 Nov 2020 22:46:31 +0000 Subject: [PATCH 04/10] Some further work, logout and preview appear to be working much better now. --- packages/builder/cypress/support/cookies.js | 2 +- .../builder/src/pages/[application]/_reset.svelte | 3 ++- packages/client/tests/testAppDef.js | 2 +- .../server/src/api/routes/tests/couchTestUtils.js | 4 ++-- packages/server/src/utilities/index.js | 4 ++-- packages/standard-components/src/Navigation.svelte | 11 ++++++++--- 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/builder/cypress/support/cookies.js b/packages/builder/cypress/support/cookies.js index 1c172f4d4c..1245f84960 100644 --- a/packages/builder/cypress/support/cookies.js +++ b/packages/builder/cypress/support/cookies.js @@ -1,3 +1,3 @@ Cypress.Cookies.defaults({ - preserve: "builder:token", + preserve: "budibase:builder:local", }) diff --git a/packages/builder/src/pages/[application]/_reset.svelte b/packages/builder/src/pages/[application]/_reset.svelte index d1d682d0b9..06942e03c8 100644 --- a/packages/builder/src/pages/[application]/_reset.svelte +++ b/packages/builder/src/pages/[application]/_reset.svelte @@ -84,7 +84,8 @@