scoped configuration management
This commit is contained in:
parent
caa4f0dfb7
commit
9a12239e62
|
@ -98,7 +98,7 @@ exports.getTemplateParams = (ownerId, templateId, otherProps = {}) => {
|
|||
* Generates a new configuration ID.
|
||||
* @returns {string} The new configuration ID which the config doc can be stored under.
|
||||
*/
|
||||
exports.generateConfigID = ({ type, group, user }) => {
|
||||
const generateConfigID = ({ type, group, user }) => {
|
||||
const scope = [type, group, user].filter(Boolean).join(SEPARATOR)
|
||||
|
||||
return `${DocumentTypes.CONFIG}${SEPARATOR}${scope}`
|
||||
|
@ -107,7 +107,7 @@ exports.generateConfigID = ({ type, group, user }) => {
|
|||
/**
|
||||
* Gets parameters for retrieving configurations.
|
||||
*/
|
||||
exports.getConfigParams = ({ type, group, user }, otherProps = {}) => {
|
||||
const getConfigParams = ({ type, group, user }, otherProps = {}) => {
|
||||
const scope = [type, group, user].filter(Boolean).join(SEPARATOR)
|
||||
|
||||
return {
|
||||
|
@ -116,3 +116,48 @@ exports.getConfigParams = ({ type, group, user }, otherProps = {}) => {
|
|||
endkey: `${DocumentTypes.CONFIG}${SEPARATOR}${scope}${UNICODE_MAX}`,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most granular configuration document from the DB based on the type, group and userID passed.
|
||||
* @param {*} db - db instance to quer
|
||||
* @param {Object} scopes - the type, group and userID scopes of the configuration.
|
||||
* @returns The most granular configuration document based on the scope.
|
||||
*/
|
||||
const determineScopedConfig = async function(db, { type, user, group }) {
|
||||
const response = await db.allDocs(
|
||||
getConfigParams(
|
||||
{ type, user, group },
|
||||
{
|
||||
include_docs: true,
|
||||
}
|
||||
)
|
||||
)
|
||||
const configs = response.rows.map(row => row.doc)
|
||||
|
||||
// Find the config with the most granular scope based on context
|
||||
const scopedConfig = configs.find(config => {
|
||||
// Config is specific to a user and a group
|
||||
if (config._id.includes(generateConfigID({ type, user, group }))) {
|
||||
return config
|
||||
}
|
||||
|
||||
// Config is specific to a user
|
||||
if (config._id.includes(generateConfigID({ type, user }))) {
|
||||
return config
|
||||
}
|
||||
|
||||
// Config is specific to a group only
|
||||
if (config._id.includes(generateConfigID({ type, group }))) {
|
||||
return config
|
||||
}
|
||||
|
||||
// Config specific to a config type only
|
||||
return config
|
||||
})
|
||||
|
||||
return scopedConfig
|
||||
}
|
||||
|
||||
exports.generateConfigID = generateConfigID
|
||||
exports.getConfigParams = getConfigParams
|
||||
exports.determineScopedConfig = determineScopedConfig
|
||||
|
|
|
@ -22,6 +22,7 @@ const {
|
|||
getEmailFromUserID,
|
||||
generateConfigID,
|
||||
getConfigParams,
|
||||
determineScopedConfig,
|
||||
} = require("./db/utils")
|
||||
|
||||
// Strategies
|
||||
|
@ -71,6 +72,7 @@ module.exports = {
|
|||
getEmailFromUserID,
|
||||
generateConfigID,
|
||||
getConfigParams,
|
||||
determineScopedConfig,
|
||||
hash,
|
||||
compare,
|
||||
getAppId,
|
||||
|
|
|
@ -51,12 +51,8 @@ async function authenticate(token, tokenSecret, profile, done) {
|
|||
* from couchDB rather than environment variables, using this factory is necessary for dynamically configuring passport.
|
||||
* @returns Dynamically configured Passport Google Strategy
|
||||
*/
|
||||
exports.strategyFactory = async function(scope) {
|
||||
exports.strategyFactory = async function(config) {
|
||||
try {
|
||||
const db = database.getDB(StaticDatabases.GLOBAL.name)
|
||||
|
||||
const config = await db.get(scope)
|
||||
|
||||
const { clientID, clientSecret, callbackURL } = config
|
||||
|
||||
if (!clientID || !clientSecret || !callbackURL) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const CouchDB = require("../../../db")
|
||||
const { StaticDatabases } = require("@budibase/auth")
|
||||
const { StaticDatabases, determineScopedConfig } = require("@budibase/auth")
|
||||
const { generateConfigID, getConfigParams } = require("@budibase/auth")
|
||||
|
||||
const GLOBAL_DB = StaticDatabases.GLOBAL.name
|
||||
|
@ -59,49 +59,11 @@ exports.find = async function(ctx) {
|
|||
}
|
||||
|
||||
try {
|
||||
const response = await db.allDocs(
|
||||
getConfigParams(
|
||||
{
|
||||
// Find the config with the most granular scope based on context
|
||||
const scopedConfig = await determineScopedConfig(db, {
|
||||
type: ctx.params.type,
|
||||
user: userId,
|
||||
group,
|
||||
},
|
||||
{
|
||||
include_docs: true,
|
||||
}
|
||||
)
|
||||
)
|
||||
const configs = response.rows.map(row => row.doc)
|
||||
|
||||
// Find the config with the most granular scope based on context
|
||||
const scopedConfig = configs.find(config => {
|
||||
// Config is specific to a user and a group
|
||||
if (
|
||||
config._id.includes(
|
||||
generateConfigID({ type: ctx.params.type, user: userId, group })
|
||||
)
|
||||
) {
|
||||
return config
|
||||
}
|
||||
|
||||
// Config is specific to a user
|
||||
if (
|
||||
config._id.includes(
|
||||
generateConfigID({ type: ctx.params.type, user: userId })
|
||||
)
|
||||
) {
|
||||
return config
|
||||
}
|
||||
|
||||
// Config is specific to a group only
|
||||
if (
|
||||
config._id.includes(generateConfigID({ type: ctx.params.type, group }))
|
||||
) {
|
||||
return config
|
||||
}
|
||||
|
||||
// Config specific to a config type only
|
||||
return config
|
||||
})
|
||||
|
||||
if (scopedConfig) {
|
||||
|
|
|
@ -74,6 +74,6 @@ exports.find = async ctx => {
|
|||
|
||||
exports.destroy = async ctx => {
|
||||
// TODO
|
||||
const db = new CouchDB(GLOBAL_DB)
|
||||
// const db = new CouchDB(GLOBAL_DB)
|
||||
ctx.body = {}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
const { determineScopedConfig } = require("@budibase/auth")
|
||||
const authPkg = require("@budibase/auth")
|
||||
const { google } = require("@budibase/auth/src/middleware")
|
||||
const { Configs } = require("../../constants")
|
||||
const CouchDB = require("../../db")
|
||||
const { clearCookie } = authPkg.utils
|
||||
const { Cookies } = authPkg
|
||||
const { passport } = authPkg.auth
|
||||
|
||||
const GLOBAL_DB = authPkg.StaticDatabases.GLOBAL.name
|
||||
|
||||
exports.authenticate = async (ctx, next) => {
|
||||
return passport.authenticate("local", async (err, user) => {
|
||||
if (err) {
|
||||
|
@ -41,11 +45,12 @@ exports.logout = async ctx => {
|
|||
* On a successful login, you will be redirected to the googleAuth callback route.
|
||||
*/
|
||||
exports.googlePreAuth = async (ctx, next) => {
|
||||
const strategy = await google.strategyFactory({
|
||||
const db = new CouchDB(GLOBAL_DB)
|
||||
const config = await determineScopedConfig(db, {
|
||||
type: Configs.GOOGLE,
|
||||
user: ctx.user._id,
|
||||
group: ctx.query.group,
|
||||
})
|
||||
const strategy = await google.strategyFactory(config)
|
||||
|
||||
return passport.authenticate(strategy, {
|
||||
scope: ["profile", "email"],
|
||||
|
@ -53,11 +58,13 @@ exports.googlePreAuth = async (ctx, next) => {
|
|||
}
|
||||
|
||||
exports.googleAuth = async (ctx, next) => {
|
||||
const strategy = await google.strategyFactory({
|
||||
const db = new CouchDB(GLOBAL_DB)
|
||||
|
||||
const config = await determineScopedConfig(db, {
|
||||
type: Configs.GOOGLE,
|
||||
user: ctx.user._id,
|
||||
group: ctx.query.group,
|
||||
})
|
||||
const strategy = await google.strategyFactory(config)
|
||||
|
||||
return passport.authenticate(
|
||||
strategy,
|
||||
|
|
Loading…
Reference in New Issue