diff --git a/hosting/docker-compose.yaml b/hosting/docker-compose.yaml
index ada377f1f6..bab7f61df1 100644
--- a/hosting/docker-compose.yaml
+++ b/hosting/docker-compose.yaml
@@ -5,6 +5,7 @@ version: "3"
services:
app-service:
restart: always
+ #build: ./build/server
image: budibase/budibase-apps
ports:
- "${APP_PORT}:4002"
@@ -22,6 +23,7 @@ services:
worker-service:
restart: always
+ #build: ./build/worker
image: budibase/budibase-worker
ports:
- "${WORKER_PORT}:4003"
diff --git a/hosting/envoy.yaml b/hosting/envoy.yaml
index 3c816cb1ca..11f5c81b99 100644
--- a/hosting/envoy.yaml
+++ b/hosting/envoy.yaml
@@ -20,6 +20,11 @@ static_resources:
route:
cluster: app-service
prefix_rewrite: "/"
+
+ # special case for presenting our static self hosting page
+ - match: { path: "/" }
+ route:
+ cluster: app-service
# special case for when API requests are made, can just forward, not to minio
- match: { prefix: "/api/" }
diff --git a/packages/server/src/api/controllers/auth.js b/packages/server/src/api/controllers/auth.js
index f9c3ef945f..4020e0c492 100644
--- a/packages/server/src/api/controllers/auth.js
+++ b/packages/server/src/api/controllers/auth.js
@@ -45,7 +45,7 @@ exports.authenticate = async ctx => {
expiresIn: "1 day",
})
- setCookie(ctx, appId, token)
+ setCookie(ctx, token, appId)
delete dbUser.password
ctx.body = {
diff --git a/packages/server/src/api/controllers/static/index.js b/packages/server/src/api/controllers/static/index.js
index 4f3d8d1611..9686a4c390 100644
--- a/packages/server/src/api/controllers/static/index.js
+++ b/packages/server/src/api/controllers/static/index.js
@@ -49,6 +49,18 @@ exports.serveBuilder = async function(ctx) {
await send(ctx, ctx.file, { root: ctx.devPath || builderPath })
}
+exports.serveSelfHostPage = async function(ctx) {
+ const logo = fs.readFileSync(resolve(__dirname, "selfhost/logo.svg"), "utf8")
+ const hostingHbs = fs.readFileSync(
+ resolve(__dirname, "selfhost/index.hbs"),
+ "utf8"
+ )
+ ctx.body = await processString(hostingHbs, {
+ logo,
+ key: env.HOSTING_KEY,
+ })
+}
+
exports.uploadFile = async function(ctx) {
let files
files =
@@ -177,7 +189,6 @@ exports.serveApp = async function(ctx) {
})
const appHbs = fs.readFileSync(`${__dirname}/templates/app.hbs`, "utf8")
- console.log(appHbs)
ctx.body = await processString(appHbs, {
head,
body: html,
diff --git a/packages/server/src/api/controllers/static/selfhost/index.hbs b/packages/server/src/api/controllers/static/selfhost/index.hbs
new file mode 100644
index 0000000000..9e47389efa
--- /dev/null
+++ b/packages/server/src/api/controllers/static/selfhost/index.hbs
@@ -0,0 +1,161 @@
+
+
+
+
+ Budibase self hosting️
+
+
+
+
+
+ {{logo}}
+
+
Get started with Budibase Self Hosting
+
Use the Hosting Key and the address Hosting URL in your Builder
+
+
+
📚Documentation
+
+ Find out more about your self hosted platform.
+
+
+ Documentation
+
+
+
+
💻Next steps
+
+ Find out how to make use of your self hosted Budibase platform.
+
+
+ Next steps
+
+
+
+
+
Your Hosting Key: {{key}}
+
Your Hosting URL:
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/server/src/api/controllers/static/selfhost/logo.svg b/packages/server/src/api/controllers/static/selfhost/logo.svg
new file mode 100644
index 0000000000..37bfb4ff83
--- /dev/null
+++ b/packages/server/src/api/controllers/static/selfhost/logo.svg
@@ -0,0 +1,17 @@
+
diff --git a/packages/server/src/api/index.js b/packages/server/src/api/index.js
index c76eb82643..48afb1eb90 100644
--- a/packages/server/src/api/index.js
+++ b/packages/server/src/api/index.js
@@ -63,6 +63,8 @@ for (let route of mainRoutes) {
router.use(staticRoutes.routes())
router.use(staticRoutes.allowedMethods())
-router.redirect("/", "/_builder")
+if (!env.SELF_HOSTED && !env.CLOUD) {
+ router.redirect("/", "/_builder")
+}
module.exports = router
diff --git a/packages/server/src/api/routes/static.js b/packages/server/src/api/routes/static.js
index a519a63781..2b0c9b36fc 100644
--- a/packages/server/src/api/routes/static.js
+++ b/packages/server/src/api/routes/static.js
@@ -23,6 +23,10 @@ if (env.NODE_ENV !== "production") {
router.get("/_builder/:file*", controller.serveBuilder)
}
+if (env.SELF_HOSTED) {
+ router.get("/", controller.serveSelfHostPage)
+}
+
router
.post(
"/api/attachments/process",
diff --git a/packages/server/src/middleware/authenticated.js b/packages/server/src/middleware/authenticated.js
index 27b3f52725..e2061c8eb5 100644
--- a/packages/server/src/middleware/authenticated.js
+++ b/packages/server/src/middleware/authenticated.js
@@ -2,7 +2,13 @@ const jwt = require("jsonwebtoken")
const STATUS_CODES = require("../utilities/statusCodes")
const { getRole, BUILTIN_ROLES } = require("../utilities/security/roles")
const { AuthTypes } = require("../constants")
-const { getAppId, getCookieName, setCookie, isClient } = require("../utilities")
+const {
+ getAppId,
+ getCookieName,
+ clearCookie,
+ setCookie,
+ isClient,
+} = require("../utilities")
module.exports = async (ctx, next) => {
if (ctx.path === "/_builder") {
@@ -15,16 +21,17 @@ module.exports = async (ctx, next) => {
let appId = getAppId(ctx)
const cookieAppId = ctx.cookies.get(getCookieName("currentapp"))
if (appId && cookieAppId !== appId) {
- setCookie(ctx, "currentapp", appId)
+ setCookie(ctx, appId, "currentapp")
} else if (cookieAppId) {
appId = cookieAppId
}
-
- let token = ctx.cookies.get(getCookieName(appId))
- let authType = AuthTypes.APP
- if (!token && !isClient(ctx)) {
- authType = AuthTypes.BUILDER
+ let token, authType
+ if (!isClient(ctx)) {
token = ctx.cookies.get(getCookieName())
+ authType = AuthTypes.BUILDER
+ } else if (appId) {
+ token = ctx.cookies.get(getCookieName(appId))
+ authType = AuthTypes.APP
}
if (!token) {
@@ -49,9 +56,13 @@ module.exports = async (ctx, next) => {
role: await getRole(appId, jwtPayload.roleId),
}
} catch (err) {
- // TODO - this can happen if the JWT secret is changed and can never login
- // TODO: wipe cookies if they exist
- ctx.throw(err.status || STATUS_CODES.FORBIDDEN, err.text)
+ if (authType === AuthTypes.BUILDER) {
+ clearCookie(ctx)
+ ctx.status = 200
+ return
+ } else {
+ ctx.throw(err.status || STATUS_CODES.FORBIDDEN, err.text)
+ }
}
await next()
diff --git a/packages/server/src/utilities/builder/setBuilderToken.js b/packages/server/src/utilities/builder/setBuilderToken.js
index 93863cee63..42730fd2ea 100644
--- a/packages/server/src/utilities/builder/setBuilderToken.js
+++ b/packages/server/src/utilities/builder/setBuilderToken.js
@@ -3,7 +3,7 @@ const env = require("../../environment")
const CouchDB = require("../../db")
const jwt = require("jsonwebtoken")
const { DocumentTypes, SEPARATOR } = require("../../db/utils")
-const { setCookie } = require("../index")
+const { setCookie, clearCookie } = require("../index")
const APP_PREFIX = DocumentTypes.APP + SEPARATOR
module.exports = async (ctx, appId, version) => {
@@ -20,13 +20,13 @@ module.exports = async (ctx, appId, version) => {
})
// set the builder token
- setCookie(ctx, "builder", token)
- setCookie(ctx, "currentapp", appId)
+ setCookie(ctx, token, "builder")
+ setCookie(ctx, appId, "currentapp")
// need to clear all app tokens or else unable to use the app in the builder
let allDbNames = await CouchDB.allDbs()
allDbNames.map(dbName => {
if (dbName.startsWith(APP_PREFIX)) {
- setCookie(ctx, dbName, "")
+ clearCookie(ctx, dbName)
}
})
}
diff --git a/packages/server/src/utilities/index.js b/packages/server/src/utilities/index.js
index fd51bcdaf0..9da2937a4d 100644
--- a/packages/server/src/utilities/index.js
+++ b/packages/server/src/utilities/index.js
@@ -111,16 +111,28 @@ exports.getCookieName = (name = "builder") => {
* @param {string} name The name of the cookie to set.
* @param {string|object} value The value of cookie which will be set.
*/
-exports.setCookie = (ctx, name, value) => {
+exports.setCookie = (ctx, value, name = "builder") => {
const expires = new Date()
expires.setDate(expires.getDate() + 1)
- ctx.cookies.set(exports.getCookieName(name), value, {
- expires,
- path: "/",
- httpOnly: false,
- overwrite: true,
- })
+ const cookieName = exports.getCookieName(name)
+ if (!value) {
+ ctx.cookies.set(cookieName)
+ } else {
+ ctx.cookies.set(cookieName, value, {
+ expires,
+ path: "/",
+ httpOnly: false,
+ overwrite: true,
+ })
+ }
+}
+
+/**
+ * Utility function, simply calls setCookie with an empty string for value
+ */
+exports.clearCookie = (ctx, name) => {
+ exports.setCookie(ctx, "", name)
}
exports.isClient = ctx => {
diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock
index 55450d3e0c..36efad1747 100644
--- a/packages/server/yarn.lock
+++ b/packages/server/yarn.lock
@@ -947,6 +947,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.11.8.tgz#fe2012f2355e4ce08bca44aeb3abbb21cf88d33f"
integrity sha512-KPcKqKm5UKDkaYPTuXSx8wEP7vE9GnuaXIZKijwRYcePpZFDVuy2a57LarFKiORbHOuTOOwYzxVxcUzsh2P2Pw==
+"@types/node@>=13.13.4":
+ version "14.14.22"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.22.tgz#0d29f382472c4ccf3bd96ff0ce47daf5b7b84b18"
+ integrity sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw==
+
"@types/node@>=8.0.0 <15":
version "14.14.20"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.20.tgz#f7974863edd21d1f8a494a73e8e2b3658615c340"
@@ -1278,6 +1283,17 @@ app-builder-lib@22.9.1:
semver "^7.3.2"
temp-file "^3.3.7"
+arangojs@^7.2.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/arangojs/-/arangojs-7.2.0.tgz#e576926b4b3469c5a130cceba45fada8b5f015d1"
+ integrity sha512-9mQRCcttaG0lckapNF9TA71ZU7H2ATXK2a1w+0fj+Y4TlTP1bNDMIz3ZN+EnaSgEtwVu0rb6N6Ac97Yd56GmkQ==
+ dependencies:
+ "@types/node" ">=13.13.4"
+ es6-error "^4.0.1"
+ multi-part "^3.0.0"
+ x3-linkedlist "1.2.0"
+ xhr "^2.4.1"
+
archive-type@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/archive-type/-/archive-type-4.0.0.tgz#f92e72233056dfc6969472749c267bdb046b1d70"
@@ -2759,7 +2775,7 @@ es3ify@^0.2.2:
jstransform "~11.0.0"
through "~2.3.4"
-es6-error@^4.1.1:
+es6-error@^4.0.1, es6-error@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
@@ -3173,6 +3189,11 @@ file-type@^11.1.0:
resolved "https://registry.yarnpkg.com/file-type/-/file-type-11.1.0.tgz#93780f3fed98b599755d846b99a1617a2ad063b8"
integrity sha512-rM0UO7Qm9K7TWTtA6AShI/t7H5BPjDeGVDaNyg9BjHAj3PysKy7+8C8D137R88jnR3rFJZQB/tFgydl5sN5m7g==
+file-type@^12.1.0:
+ version "12.4.2"
+ resolved "https://registry.yarnpkg.com/file-type/-/file-type-12.4.2.tgz#a344ea5664a1d01447ee7fb1b635f72feb6169d9"
+ integrity sha512-UssQP5ZgIOKelfsaB5CuGAL+Y+q7EmONuiwF3N5HAH0t27rvrttgi6Ra9k/+DVaY9UF6+ybxu5pOXLUdA8N7Vg==
+
file-type@^3.8.0:
version "3.9.0"
resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9"
@@ -3524,6 +3545,14 @@ global@~4.3.0:
min-document "^2.19.0"
process "~0.5.1"
+global@~4.4.0:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406"
+ integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==
+ dependencies:
+ min-document "^2.19.0"
+ process "^0.11.10"
+
globals@^11.1.0:
version "11.12.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
@@ -5441,11 +5470,19 @@ mime-db@1.44.0:
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==
-"mime-db@>= 1.43.0 < 2", mime-db@^1.28.0:
+mime-db@1.45.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0:
version "1.45.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea"
integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==
+mime-kind@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/mime-kind/-/mime-kind-3.0.0.tgz#23bb3aba03ed6a1ea8c4f6093a9c7ab7121a9cb2"
+ integrity sha512-sx9lClVP7GXY2mO3aVDWTQLhfvAdDvNhGi3o3g7+ae3aKaoybeGbEIlnreoRKjrbDpvlPltlkIryxOtatojeXQ==
+ dependencies:
+ file-type "^12.1.0"
+ mime-types "^2.1.24"
+
mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.19, mime-types@~2.1.24:
version "2.1.27"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
@@ -5453,6 +5490,13 @@ mime-types@^2.1.12, mime-types@^2.1.18, mime-types@~2.1.19, mime-types@~2.1.24:
dependencies:
mime-db "1.44.0"
+mime-types@^2.1.24:
+ version "2.1.28"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.28.tgz#1160c4757eab2c5363888e005273ecf79d2a0ecd"
+ integrity sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==
+ dependencies:
+ mime-db "1.45.0"
+
mime@^1.3.4, mime@^1.4.1:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
@@ -5549,6 +5593,19 @@ mssql@^6.2.3:
tarn "^1.1.5"
tedious "^6.6.2"
+multi-part-lite@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/multi-part-lite/-/multi-part-lite-1.0.0.tgz#7b86baf8ff83ef20ca13f1269a0f35aec42b9000"
+ integrity sha512-KxIRbBZZ45hoKX1ROD/19wJr0ql1bef1rE8Y1PCwD3PuNXV42pp7Wo8lEHYuAajoT4vfAFcd3rPjlkyEEyt1nw==
+
+multi-part@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/multi-part/-/multi-part-3.0.0.tgz#2bde386e8c1dcc9f15a2277267a7f5ed13aa0cc0"
+ integrity sha512-pDbdYQ6DLDxAsD83w9R7r7rlW56cETL7hIB5bCWX7FJYw0K+kL5JwHr0I8tRk9lGeFcAzf+2OEzXWlG/4wCnFw==
+ dependencies:
+ mime-kind "^3.0.0"
+ multi-part-lite "^1.0.0"
+
mute-stream@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
@@ -6452,6 +6509,11 @@ process-nextick-args@~2.0.0:
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
+process@^0.11.10:
+ version "0.11.10"
+ resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
+ integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
+
process@~0.5.1:
version "0.5.2"
resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf"
@@ -8264,6 +8326,11 @@ ws@^5.2.0:
dependencies:
async-limiter "~1.0.0"
+x3-linkedlist@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/x3-linkedlist/-/x3-linkedlist-1.2.0.tgz#c70467559b7c748595f0f79222af1d709402699e"
+ integrity sha512-mH/YwxpYSKNa8bDNF1yOuZCMuV+K80LtDN8vcLDUAwNazCxptDNsYt+zA/EJeYiGbdtKposhKLZjErGVOR8mag==
+
xdg-basedir@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
@@ -8279,6 +8346,16 @@ xhr@^2.0.1:
parse-headers "^2.0.0"
xtend "^4.0.0"
+xhr@^2.4.1:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d"
+ integrity sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==
+ dependencies:
+ global "~4.4.0"
+ is-function "^1.0.1"
+ parse-headers "^2.0.0"
+ xtend "^4.0.0"
+
xml-name-validator@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"