login page
This commit is contained in:
parent
0c34f1a108
commit
98576f586e
|
@ -1,125 +0,0 @@
|
|||
static_resources:
|
||||
listeners:
|
||||
- name: main_listener
|
||||
address:
|
||||
socket_address: { address: 0.0.0.0, port_value: 10000 }
|
||||
filter_chains:
|
||||
- filters:
|
||||
- name: envoy.filters.network.http_connection_manager
|
||||
typed_config:
|
||||
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
|
||||
stat_prefix: ingress
|
||||
codec_type: auto
|
||||
route_config:
|
||||
name: local_route
|
||||
virtual_hosts:
|
||||
- name: local_services
|
||||
domains: ["*"]
|
||||
routes:
|
||||
- match: { prefix: "/db/" }
|
||||
route:
|
||||
cluster: couchdb-service
|
||||
prefix_rewrite: "/"
|
||||
|
||||
- match: { prefix: "/cache/" }
|
||||
route:
|
||||
cluster: redis-service
|
||||
prefix_rewrite: "/"
|
||||
|
||||
- match: { prefix: "/api/" }
|
||||
route:
|
||||
cluster: server-dev
|
||||
|
||||
- match: { prefix: "/app_" }
|
||||
route:
|
||||
cluster: server-dev
|
||||
|
||||
- match: { prefix: "/builder/" }
|
||||
route:
|
||||
cluster: builder-dev
|
||||
|
||||
- match: { prefix: "/builder" }
|
||||
route:
|
||||
cluster: builder-dev
|
||||
prefix_rewrite: "/builder/"
|
||||
|
||||
# minio is on the default route because this works
|
||||
# best, minio + AWS SDK doesn't handle path proxy
|
||||
- match: { prefix: "/" }
|
||||
route:
|
||||
cluster: minio-service
|
||||
|
||||
http_filters:
|
||||
- name: envoy.filters.http.router
|
||||
|
||||
clusters:
|
||||
- name: minio-service
|
||||
connect_timeout: 0.25s
|
||||
type: strict_dns
|
||||
lb_policy: round_robin
|
||||
load_assignment:
|
||||
cluster_name: minio-service
|
||||
endpoints:
|
||||
- lb_endpoints:
|
||||
- endpoint:
|
||||
address:
|
||||
socket_address:
|
||||
address: minio-service
|
||||
port_value: 9000
|
||||
|
||||
- name: couchdb-service
|
||||
connect_timeout: 0.25s
|
||||
type: strict_dns
|
||||
lb_policy: round_robin
|
||||
load_assignment:
|
||||
cluster_name: couchdb-service
|
||||
endpoints:
|
||||
- lb_endpoints:
|
||||
- endpoint:
|
||||
address:
|
||||
socket_address:
|
||||
address: couchdb-service
|
||||
port_value: 5984
|
||||
|
||||
- name: redis-service
|
||||
connect_timeout: 0.25s
|
||||
type: strict_dns
|
||||
lb_policy: round_robin
|
||||
load_assignment:
|
||||
cluster_name: redis-service
|
||||
endpoints:
|
||||
- lb_endpoints:
|
||||
- endpoint:
|
||||
address:
|
||||
socket_address:
|
||||
address: redis-service
|
||||
port_value: 6379
|
||||
|
||||
- name: server-dev
|
||||
connect_timeout: 0.25s
|
||||
type: strict_dns
|
||||
lb_policy: round_robin
|
||||
load_assignment:
|
||||
cluster_name: server-dev
|
||||
endpoints:
|
||||
- lb_endpoints:
|
||||
- endpoint:
|
||||
address:
|
||||
socket_address:
|
||||
address: host.docker.internal
|
||||
port_value: 4001
|
||||
|
||||
- name: builder-dev
|
||||
connect_timeout: 15s
|
||||
type: strict_dns
|
||||
lb_policy: round_robin
|
||||
load_assignment:
|
||||
cluster_name: builder-dev
|
||||
endpoints:
|
||||
- lb_endpoints:
|
||||
- endpoint:
|
||||
address:
|
||||
socket_address:
|
||||
address: host.docker.internal
|
||||
port_value: 3000
|
||||
|
|
@ -4,11 +4,15 @@ const JwtStrategy = require("passport-jwt").Strategy
|
|||
// const GoogleStrategy = require("passport-google-oauth").Strategy
|
||||
const CouchDB = require("./db")
|
||||
const { StaticDatabases } = require("./db/utils")
|
||||
const { jwt, local, google } = require("./middleware")
|
||||
const { jwt, local, google, authenticated } = require("./middleware")
|
||||
const { Cookies, UserStatus } = require("./constants")
|
||||
const { hash, compare } = require("./hashing")
|
||||
const { getAppId, setCookie } = require("./utils")
|
||||
const { generateUserID, getUserParams, getEmailFromUserID } = require("./db/utils")
|
||||
const {
|
||||
generateUserID,
|
||||
getUserParams,
|
||||
getEmailFromUserID,
|
||||
} = require("./db/utils")
|
||||
|
||||
// Strategies
|
||||
passport.use(new LocalStrategy(local.options, local.authenticate))
|
||||
|
@ -41,4 +45,5 @@ module.exports = {
|
|||
compare,
|
||||
getAppId,
|
||||
setCookie,
|
||||
authenticated,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
const CouchDB = require("../db")
|
||||
const { Cookies } = require("../constants")
|
||||
const { getAppId, setCookie, getCookie } = require("../utils")
|
||||
const { StaticDatabases } = require("../db/utils")
|
||||
|
||||
async function setCurrentAppContext(ctx) {
|
||||
let role = "PUBLIC"
|
||||
|
||||
// Current app cookie
|
||||
let appId = getAppId(ctx)
|
||||
if (!appId) {
|
||||
ctx.user = {
|
||||
role,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const currentAppCookie = getCookie(ctx, Cookies.CurrentApp, { decrypt: true })
|
||||
const appIdChanged = appId && currentAppCookie.appId !== appId
|
||||
if (appIdChanged) {
|
||||
try {
|
||||
// get roles for user from global DB
|
||||
const db = new CouchDB(StaticDatabases.USER)
|
||||
const user = await db.get(ctx.user)
|
||||
role = user.roles[appId]
|
||||
} catch (err) {
|
||||
// no user exists
|
||||
}
|
||||
} else if (currentAppCookie.appId) {
|
||||
appId = currentAppCookie.appId
|
||||
}
|
||||
setCookie(ctx, { appId, role }, Cookies.CurrentApp, { encrypt: true })
|
||||
return appId
|
||||
}
|
||||
|
||||
module.exports = async (ctx, next) => {
|
||||
try {
|
||||
// check the actual user is authenticated first
|
||||
const authCookie = getCookie(ctx, Cookies.Auth, { decrypt: true })
|
||||
|
||||
if (authCookie) {
|
||||
ctx.isAuthenticated = true
|
||||
ctx.user = authCookie._id
|
||||
}
|
||||
|
||||
ctx.appId = await setCurrentAppContext(ctx)
|
||||
|
||||
await next()
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
ctx.throw(err.status || 403, err.text)
|
||||
}
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
const jwt = require("./passport/jwt")
|
||||
const local = require("./passport/local")
|
||||
const google = require("./passport/google")
|
||||
const authenticated = require("./authenticated")
|
||||
|
||||
module.exports = {
|
||||
google,
|
||||
jwt,
|
||||
local,
|
||||
authenticated,
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
const { DocumentTypes, SEPARATOR } = require("./db/utils")
|
||||
const jwt = require("jsonwebtoken")
|
||||
const { options } = require("./middleware/passport/jwt")
|
||||
|
||||
const APP_PREFIX = DocumentTypes.APP + SEPARATOR
|
||||
|
||||
|
@ -39,6 +41,23 @@ exports.getAppId = ctx => {
|
|||
return appId
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a cookie from context, and decrypt if necessary.
|
||||
* @param {object} ctx The request which is to be manipulated.
|
||||
* @param {string} name The name of the cookie to get.
|
||||
* @param {object} options options .
|
||||
*/
|
||||
exports.getCookie = (ctx, value, options = {}) => {
|
||||
const cookie = ctx.cookies.get(value)
|
||||
|
||||
if (!cookie) return
|
||||
|
||||
if (!options.decrypt) return cookie
|
||||
|
||||
const payload = jwt.verify(cookie, process.env.JWT_SECRET)
|
||||
return payload
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a cookie for the request, has a hardcoded expiry.
|
||||
* @param {object} ctx The request which is to be manipulated.
|
||||
|
@ -52,6 +71,11 @@ exports.setCookie = (ctx, value, name = "builder") => {
|
|||
if (!value) {
|
||||
ctx.cookies.set(name)
|
||||
} else {
|
||||
if (options.encrypt) {
|
||||
value = jwt.sign(value, process.env.JWT_SECRET, {
|
||||
expiresIn: "1 day",
|
||||
})
|
||||
}
|
||||
ctx.cookies.set(name, value, {
|
||||
expires,
|
||||
path: "/",
|
||||
|
|
|
@ -20,9 +20,9 @@ export const get = apiCall("GET")
|
|||
export const patch = apiCall("PATCH")
|
||||
export const del = apiCall("DELETE")
|
||||
export const put = apiCall("PUT")
|
||||
export const getBuilderCookie = async () => {
|
||||
await post("/api/builder/login", {})
|
||||
}
|
||||
// export const getBuilderCookie = async () => {
|
||||
// await post("/api/builder/login", {})
|
||||
// }
|
||||
|
||||
export default {
|
||||
post: apiCall("POST"),
|
||||
|
@ -30,5 +30,5 @@ export default {
|
|||
patch: apiCall("PATCH"),
|
||||
delete: apiCall("DELETE"),
|
||||
put: apiCall("PUT"),
|
||||
getBuilderCookie,
|
||||
// getBuilderCookie,
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import { derived, writable } from "svelte/store"
|
|||
import analytics from "analytics"
|
||||
import { FrontendTypes, LAYOUT_NAMES } from "../constants"
|
||||
import { findComponent } from "./storeUtils"
|
||||
import { getBuilderCookie } from "./api"
|
||||
// import { getBuilderCookie } from "./api"
|
||||
|
||||
export const store = getFrontendStore()
|
||||
export const automationStore = getAutomationStore()
|
||||
|
@ -59,7 +59,7 @@ export const selectedAccessRole = writable("BASIC")
|
|||
export const initialise = async () => {
|
||||
try {
|
||||
// TODO this needs to be replaced by a real login
|
||||
await getBuilderCookie()
|
||||
// await getBuilderCookie()
|
||||
await analytics.activate()
|
||||
analytics.captureEvent("Builder Started")
|
||||
} catch (err) {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<script>
|
||||
import { Button, Label, Input, TextArea, Spacer } from "@budibase/bbui"
|
||||
import { auth } from "stores/backend"
|
||||
|
||||
let username = ""
|
||||
let password = ""
|
||||
|
||||
async function login() {
|
||||
const json = await auth.login({
|
||||
username,
|
||||
password,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<form on:submit|preventDefault>
|
||||
<Spacer large />
|
||||
<Label small>Email</Label>
|
||||
<Input outline bind:value={username} />
|
||||
<Spacer large />
|
||||
<Label small>Password</Label>
|
||||
<Input outline type="password" on:change bind:value={password} />
|
||||
<Spacer large />
|
||||
<Button primary on:click={login}>Login</Button>
|
||||
</form>
|
||||
|
||||
<style>
|
||||
form {
|
||||
width: 60%;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1 @@
|
|||
export { LoginForm } from "./LoginForm.svelte"
|
|
@ -7,15 +7,20 @@
|
|||
CommunityIcon,
|
||||
BugIcon,
|
||||
} from "components/common/Icons"
|
||||
import LoginForm from "components/login/LoginForm.svelte"
|
||||
import BuilderSettingsButton from "components/start/BuilderSettingsButton.svelte"
|
||||
import Logo from "/assets/budibase-logo.svg"
|
||||
import { auth } from "stores/backend"
|
||||
|
||||
let modal
|
||||
</script>
|
||||
|
||||
<div class="root">
|
||||
{#if $auth.user}
|
||||
<div class="root">
|
||||
<div class="ui-nav">
|
||||
<div class="home-logo"><img src={Logo} alt="Budibase icon" /></div>
|
||||
<div class="home-logo">
|
||||
<img src={Logo} alt="Budibase icon" />
|
||||
</div>
|
||||
<div class="nav-section">
|
||||
<div class="nav-top">
|
||||
<Link icon={AppsIcon} title="Apps" href="/" active />
|
||||
|
@ -44,7 +49,13 @@
|
|||
<div class="main">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{:else}
|
||||
<section class="login">
|
||||
<LoginForm />
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.root {
|
||||
|
@ -55,6 +66,14 @@
|
|||
background: var(--grey-1);
|
||||
}
|
||||
|
||||
.login {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.main {
|
||||
grid-column: 2;
|
||||
overflow: auto;
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import { writable, get } from "svelte/store"
|
||||
import api from "../../builderStore/api"
|
||||
|
||||
export function createAuthStore() {
|
||||
const { subscribe } = writable({})
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
login: async () => {
|
||||
const response = await api.post(`/api/admin/auth/authenticate`)
|
||||
const json = await response.json()
|
||||
set({ user: json })
|
||||
},
|
||||
logout: async () => {
|
||||
const response = await api.post(`/api/auth/logout`)
|
||||
const json = await response.json()
|
||||
set({ user: null })
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const auth = createAuthStore()
|
|
@ -7,3 +7,4 @@ export { roles } from "./roles"
|
|||
export { datasources } from "./datasources"
|
||||
export { integrations } from "./integrations"
|
||||
export { queries } from "./queries"
|
||||
export { auth } from "./auth"
|
||||
|
|
|
@ -70,10 +70,10 @@ exports.authenticate = async ctx => {
|
|||
}
|
||||
}
|
||||
|
||||
exports.builderLogin = async ctx => {
|
||||
await setBuilderToken(ctx)
|
||||
ctx.status = 200
|
||||
}
|
||||
// exports.builderLogin = async ctx => {
|
||||
// await setBuilderToken(ctx)
|
||||
// ctx.status = 200
|
||||
// }
|
||||
|
||||
exports.fetchSelf = async ctx => {
|
||||
const { userId, appId } = ctx.user
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const Router = require("@koa/router")
|
||||
const authenticated = require("../middleware/authenticated")
|
||||
const { authenticated } = require("@budibase/auth")
|
||||
const compress = require("koa-compress")
|
||||
const zlib = require("zlib")
|
||||
const { mainRoutes, authRoutes, staticRoutes } = require("./routes")
|
||||
|
|
|
@ -7,7 +7,7 @@ const router = Router()
|
|||
|
||||
router.post("/api/authenticate", controller.authenticate)
|
||||
// TODO: this is a hack simply to make sure builder has a cookie until auth reworked
|
||||
router.post("/api/builder/login", authorized(BUILDER), controller.builderLogin)
|
||||
// router.post("/api/builder/login", authorized(BUILDER), controller.builderLogin)
|
||||
// doesn't need authorization as can only fetch info about self
|
||||
router.get("/api/self", controller.fetchSelf)
|
||||
|
||||
|
|
|
@ -40,7 +40,8 @@ module.exports = (permType, permLevel = null) => async (ctx, next) => {
|
|||
|
||||
const role = ctx.user.role
|
||||
const isAdmin = ADMIN_ROLES.includes(role._id)
|
||||
const isAuthed = ctx.auth.authenticated
|
||||
// const isAuthed = ctx.auth.authenticated
|
||||
const isAuthed = ctx.isAuthenticated
|
||||
|
||||
const { basePermissions, permissions } = await getUserPermissions(
|
||||
ctx.appId,
|
||||
|
@ -50,11 +51,11 @@ module.exports = (permType, permLevel = null) => async (ctx, next) => {
|
|||
// this may need to change in the future, right now only admins
|
||||
// can have access to builder features, this is hard coded into
|
||||
// our rules
|
||||
if (isAdmin && isAuthed) {
|
||||
return next()
|
||||
} else if (permType === PermissionTypes.BUILDER) {
|
||||
return ctx.throw(403, "Not Authorized")
|
||||
}
|
||||
// if (isAdmin && isAuthed) {
|
||||
// return next()
|
||||
// } else if (permType === PermissionTypes.BUILDER) {
|
||||
// return ctx.throw(403, "Not Authorized")
|
||||
// }
|
||||
|
||||
if (
|
||||
hasResource(ctx) &&
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const { passport } = require("@budibase/auth")
|
||||
const { passport, Cookies } = require("@budibase/auth")
|
||||
|
||||
exports.authenticate = async (ctx, next) => {
|
||||
return passport.authenticate("local", async (err, user) => {
|
||||
|
@ -9,7 +9,7 @@ exports.authenticate = async (ctx, next) => {
|
|||
const expires = new Date()
|
||||
expires.setDate(expires.getDate() + 1)
|
||||
|
||||
ctx.cookies.set("budibase:auth", user.token, {
|
||||
ctx.cookies.set(Cookies.Auth, user.token, {
|
||||
expires,
|
||||
path: "/",
|
||||
httpOnly: false,
|
||||
|
@ -19,3 +19,7 @@ exports.authenticate = async (ctx, next) => {
|
|||
ctx.body = { success: true }
|
||||
})(ctx, next)
|
||||
}
|
||||
|
||||
exports.googleAuth = async (ctx, next) => {
|
||||
// return passport.authenticate("google")
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const Router = require("@koa/router")
|
||||
const controller = require("../../controllers/admin")
|
||||
const authenticated = require("../../../middleware/authenticated")
|
||||
const joiValidator = require("../../../middleware/joi-validator")
|
||||
const { authenticated } = require("@budibase/auth")
|
||||
const Joi = require("joi")
|
||||
|
||||
const router = Router()
|
||||
|
@ -22,7 +22,12 @@ function buildUserSaveValidation() {
|
|||
}
|
||||
|
||||
router
|
||||
.post("/api/admin/users", buildUserSaveValidation(), authenticated, controller.userSave)
|
||||
.post(
|
||||
"/api/admin/users",
|
||||
buildUserSaveValidation(),
|
||||
authenticated,
|
||||
controller.userSave
|
||||
)
|
||||
.delete("/api/admin/users/:email", authenticated, controller.userDelete)
|
||||
.get("/api/admin/users", authenticated, controller.userFetch)
|
||||
.get("/api/admin/users/:email", authenticated, controller.userFind)
|
||||
|
|
|
@ -1,8 +1,18 @@
|
|||
const Router = require("@koa/router")
|
||||
const { passport } = require("@budibase/auth")
|
||||
const authController = require("../controllers/auth")
|
||||
|
||||
const router = Router()
|
||||
|
||||
router.post("/api/auth/authenticate", authController.authenticate)
|
||||
router
|
||||
.post("/api/admin/auth", authController.authenticate)
|
||||
.get("/api/auth/google", passport.authenticate("google"))
|
||||
.get(
|
||||
"/api/auth/google/callback",
|
||||
passport.authenticate("google", {
|
||||
successRedirect: "/app",
|
||||
failureRedirect: "/",
|
||||
})
|
||||
)
|
||||
|
||||
module.exports = router
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
const { passport, getAppId, setCookie, Cookies } = require("@budibase/auth")
|
||||
|
||||
module.exports = async (ctx, next) => {
|
||||
// do everything we can to make sure the appId is held correctly
|
||||
let appId = getAppId(ctx)
|
||||
const cookieAppId = ctx.cookies.get(Cookies.CurrentApp)
|
||||
// const builtinRoles = getBuiltinRoles()
|
||||
if (appId && cookieAppId !== appId) {
|
||||
setCookie(ctx, appId, Cookies.CurrentApp)
|
||||
} else if (cookieAppId) {
|
||||
appId = cookieAppId
|
||||
}
|
||||
|
||||
return passport.authenticate("jwt", async (err, user) => {
|
||||
if (err) {
|
||||
return ctx.throw(err.status || 403, err)
|
||||
}
|
||||
|
||||
try {
|
||||
ctx.appId = appId
|
||||
ctx.isAuthenticated = true
|
||||
// TODO: introduce roles again
|
||||
ctx.user = user
|
||||
await next()
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
ctx.throw(err.status || 403, err.text)
|
||||
}
|
||||
})(ctx, next)
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
/**
|
||||
* Check the user token, used when creating admin resources, like for example
|
||||
* a global user record.
|
||||
*/
|
||||
module.exports = async (ctx, next) => {
|
||||
return next()
|
||||
}
|
Loading…
Reference in New Issue