diff --git a/hosting/docker-compose.yaml b/hosting/docker-compose.yaml
index 4d338cb221..bab7f61df1 100644
--- a/hosting/docker-compose.yaml
+++ b/hosting/docker-compose.yaml
@@ -1,8 +1,11 @@
version: "3"
+# optional ports are specified throughout for more advanced use cases.
+
services:
app-service:
restart: always
+ #build: ./build/server
image: budibase/budibase-apps
ports:
- "${APP_PORT}:4002"
@@ -20,6 +23,7 @@ services:
worker-service:
restart: always
+ #build: ./build/worker
image: budibase/budibase-worker
ports:
- "${WORKER_PORT}:4003"
@@ -62,7 +66,7 @@ services:
- ./envoy.yaml:/etc/envoy/envoy.yaml
ports:
- "${MAIN_PORT}:10000"
- - "9901:9901"
+ #- "9901:9901"
depends_on:
- minio-service
- worker-service
@@ -77,8 +81,8 @@ services:
- COUCHDB_USER=${COUCH_DB_USER}
ports:
- "${COUCH_DB_PORT}:5984"
- - "4369:4369"
- - "9100:9100"
+ #- "4369:4369"
+ #- "9100:9100"
volumes:
- couchdb_data:/couchdb
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 af6e0b2ee2..5c3674d1b9 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 2096b3039e..770cbaf088 100644
--- a/packages/server/src/api/controllers/static/index.js
+++ b/packages/server/src/api/controllers/static/index.js
@@ -49,6 +49,17 @@ 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,
+ })
+}
+
exports.uploadFile = async function(ctx) {
let files
files =
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..cbf1b8f3e5
--- /dev/null
+++ b/packages/server/src/api/controllers/static/selfhost/index.hbs
@@ -0,0 +1,173 @@
+
+
+
+
+ Budibase self hosting️
+
+
+
+
+
+ {{logo}}
+
+
Get started with Budibase Self Hosting
+
Use the address 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
+
+
+
+
+
+
A Hosting Key will also be required, this can be found in your hosting properties, info found here.
+
+
+
+
+
\ 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 ea0ed4b875..5b9b51363b 100644
--- a/packages/server/src/api/index.js
+++ b/packages/server/src/api/index.js
@@ -65,6 +65,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..e4e678abad 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,18 @@ 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
+ }
+ if (!token && appId) {
+ token = ctx.cookies.get(getCookieName(appId))
+ authType = AuthTypes.APP
}
if (!token) {
@@ -49,9 +57,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 => {