Move UI configs to DB

This commit is contained in:
Shweelan Samson authored and Zaid Abdulla committed 2019-01-16 05:22:14 -08:00
1 parent 192ed6b034
commit 1cceba3f8b
22 files changed
+337 -448

No files matched your search

+1
View File
@@ -59,6 +59,7 @@ const options = {
UI_SSL: { type: "bool", default: false },
UI_LOG_FILE: { type: "path", default: "" },
UI_ACCESS_LOG_FILE: { type: "path", default: "" },
UI_JWT_SECRET: { type: "string", default: "" },
UDP_CONNECTION_REQUEST_PORT: { type: "int", default: 0 },
+63 -4
View File
@@ -307,8 +307,30 @@ function refresh(callback) {
db.getConfig((err, conf) => {
if (err) return void reject(err);
conf.sort((a, b) => (a.id > b.id ? 1 : a.id < b.id ? -1 : 0));
const _config = {};
for (const c of conf) _config[c.id] = c.value;
for (const c of conf) {
if (
c.id.startsWith("auth.") ||
c.id.startsWith("permissions.") ||
c.id.startsWith("ui.")
) {
const keys = c.id.split(".");
let ref = _config;
while (keys.length > 1) {
const k = keys.shift();
if (typeof ref[k] !== "object") ref[k] = {};
ref = ref[k];
}
// Evaluate expressions to simplify them
ref[keys[0]] = expression.evaluate(c.value);
} else {
// Evaluate expressions to simplify them
_config[c.id] = expression.evaluate(c.value);
}
}
resolve(_config);
});
@@ -348,9 +370,22 @@ function refresh(callback) {
}
function getCurrentSnapshot(callback) {
if (Date.now() < nextRefresh) return void callback(null, currentSnapshot);
refresh(err => {
callback(err, currentSnapshot);
if (Date.now() < nextRefresh) {
if (callback) return callback(null, currentSnapshot);
return Promise.resolve(currentSnapshot);
}
if (callback) {
return refresh(err => {
callback(err, currentSnapshot);
});
}
return new Promise((resolve, reject) => {
refresh(err => {
if (err) return void reject(err);
resolve(currentSnapshot);
});
});
}
@@ -410,6 +445,27 @@ function getConfig(snapshotKey, key, context, now) {
return expression.evaluate(snapshot.config[key], context, now || Date.now());
}
function getAuthConfig(snapshotKey) {
const snapshot = snapshots.get(snapshotKey);
if (!snapshot) throw new Error("Cache snapshot does not exist");
return snapshot.config.auth;
}
function getPermissionsConfig(snapshotKey) {
const snapshot = snapshots.get(snapshotKey);
if (!snapshot) throw new Error("Cache snapshot does not exist");
return snapshot.config.permissions;
}
function getUiConfig(snapshotKey) {
const snapshot = snapshots.get(snapshotKey);
if (!snapshot) throw new Error("Cache snapshot does not exist");
return snapshot.config.ui;
}
exports.getCurrentSnapshot = getCurrentSnapshot;
exports.hasSnapshot = hasSnapshot;
exports.getPresets = getPresets;
@@ -417,3 +473,6 @@ exports.getProvisions = getProvisions;
exports.getVirtualParameters = getVirtualParameters;
exports.getFiles = getFiles;
exports.getConfig = getConfig;
exports.getAuthConfig = getAuthConfig;
exports.getPermissionsConfig = getPermissionsConfig;
exports.getUiConfig = getUiConfig;
+32 -17
View File
@@ -8,21 +8,24 @@ const koaBodyParser = require("koa-bodyparser");
const koaJwt = require("koa-jwt");
const jwt = require("jsonwebtoken");
const config = require("./ui/config");
const config = require("./config");
const api = require("./ui/api");
const Authorizer = require("./common/authorizer");
const expression = require("./common/expression");
const logger = require("./logger");
const localCache = require("./local-cache");
const koa = new Koa();
const router = new Router();
const JWT_SECRET = config.server.jwtSecret;
const JWT_SECRET = config.get("UI_JWT_SECRET");
const JWT_COOKIE = "genieacs-ui-jwt";
function getPermissionSets(roles) {
const allPermissions = config.permissions;
const permissionSets = roles.map(role => {
function getPermissionSets(ctx) {
const allPermissions = localCache.getPermissionsConfig(
ctx.state.configSnapshot
);
const permissionSets = ctx.state.user.roles.map(role => {
return Object.values(allPermissions[role] || {}).map(p => {
p = Object.assign({}, p);
for (let [k, v] of Object.entries(p)) {
@@ -47,8 +50,9 @@ function getPermissionSets(roles) {
return permissionSets;
}
function authSimple(username, password) {
const user = config.auth.simple.users[username];
function authSimple(ctx, username, password) {
const authConfig = localCache.getAuthConfig(ctx.state.configSnapshot);
const user = authConfig.simple.users[username];
if (user && user.password === password) {
const roles = user.roles.split(",").map(s => s.trim());
return Promise.resolve(roles);
@@ -60,6 +64,12 @@ koa.on("error", async err => {
throw err;
});
koa.use(async (ctx, next) => {
const configSnapshot = await localCache.getCurrentSnapshot();
ctx.state.configSnapshot = configSnapshot;
return next();
});
koa.use(
koaJwt({
secret: JWT_SECRET,
@@ -69,18 +79,21 @@ koa.use(
);
koa.use(async (ctx, next) => {
if (ctx.state.user && ctx.state.user.roles) {
ctx.state.authorizer = new Authorizer(
getPermissionSets(ctx.state.user.roles)
);
} else {
ctx.state.authorizer = new Authorizer([]);
}
if (ctx.state.user && ctx.state.user.roles)
ctx.state.authorizer = new Authorizer(getPermissionSets(ctx));
else ctx.state.authorizer = new Authorizer([]);
return next();
});
router.post("/login", async ctx => {
if (!JWT_SECRET) {
ctx.status = 500;
ctx.body = "UI_JWT_SECRET is not set";
logger.error({ message: "UI_JWT_SECRET is not set" });
return;
}
const username = ctx.request.body.username;
const password = ctx.request.body.password;
@@ -105,7 +118,7 @@ router.post("/login", async ctx => {
logger.accessWarn(log);
}
const roles = await authSimple(username, password);
const roles = await authSimple(ctx, username, password);
if (roles) return void success(roles, "simple");
@@ -135,7 +148,7 @@ router.use("/api", api.routes(), api.allowedMethods());
router.get("/", async ctx => {
let permissionSets = [];
if (ctx.state.user && ctx.state.user.roles)
permissionSets = getPermissionSets(ctx.state.user.roles);
permissionSets = getPermissionSets(ctx);
ctx.body = `
<html>
@@ -146,7 +159,9 @@ router.get("/", async ctx => {
</head>
<body>
<script>
window.clientConfig = ${JSON.stringify(config.getClientConfig())};
window.clientConfig = ${JSON.stringify({
ui: localCache.getUiConfig(ctx.state.configSnapshot)
})};
window.username = ${JSON.stringify(
ctx.state.user ? ctx.state.user.username : ""
)};
+19 -9
View File
@@ -4,7 +4,7 @@ const http = require("http");
const https = require("https");
const url = require("url");
const config = require("./config");
const config = require("../config");
const db = require("./db");
const mongodbFunctions = require("./mongodb-functions");
@@ -71,7 +71,9 @@ function deleteResource(resource, id) {
const resourceUrl =
resource === "virtualParameters" ? "virtual_parameters" : resource;
const options = url.parse(
`${config.server.nbi}${resourceUrl}/${encodeURIComponent(id)}`
`http://127.0.0.1:${config.get(
"NBI_PORT"
)}/${resourceUrl}/${encodeURIComponent(id)}`
);
options.method = "DELETE";
@@ -91,9 +93,9 @@ function deleteResource(resource, id) {
function postTask(task, connectionRequest, callback) {
const options = url.parse(
`${config.server.nbi}devices/${encodeURIComponent(task.device)}/tasks${
connectionRequest ? "?connection_request" : ""
}`
`http://127.0.0.1:${config.get("NBI_PORT")}/devices/${encodeURIComponent(
task.device
)}/tasks${connectionRequest ? "?connection_request" : ""}`
);
options.method = "POST";
const _http = options.protocol === "https:" ? https : http;
@@ -210,7 +212,9 @@ function updateTags(deviceId, tags) {
([tag, onOff]) =>
new Promise((resolve, reject) => {
const options = url.parse(
`${config.server.nbi}devices/${encodeURIComponent(
`http://127.0.0.1:${config.get(
"NBI_PORT"
)}/devices/${encodeURIComponent(
deviceId
)}/tags/${encodeURIComponent(tag)}`
);
@@ -234,7 +238,9 @@ function updateTags(deviceId, tags) {
function ping(host) {
return new Promise((resolve, reject) => {
const options = url.parse(
`${config.server.nbi}ping/${encodeURIComponent(host)}`
`http://127.0.0.1:${config.get("NBI_PORT")}/ping/${encodeURIComponent(
host
)}`
);
const _http = options.protocol === "https:" ? https : http;
@@ -294,7 +300,9 @@ function putResource(resource, id, data) {
const resourceUrl =
resource === "virtualParameters" ? "virtual_parameters" : resource;
const options = url.parse(
`${config.server.nbi}${resourceUrl}/${encodeURIComponent(id)}`
`http://127.0.0.1:${config.get(
"NBI_PORT"
)}/${resourceUrl}/${encodeURIComponent(id)}`
);
options.method = "PUT";
@@ -343,7 +351,9 @@ function putResource(resource, id, data) {
function putFile(id, metadata, fileStream) {
return new Promise((resolve, reject) => {
const options = url.parse(
`${config.server.nbi}files/${encodeURIComponent(id)}`
`http://127.0.0.1:${config.get("NBI_PORT")}/files/${encodeURIComponent(
id
)}`
);
options.method = "PUT";
-36
View File
@@ -1,36 +0,0 @@
"use strict";
const fs = require("fs");
const configFile = JSON.parse(fs.readFileSync("./config/config-ui.json"));
const config = loadConfig(configFile);
function getClientConfig() {
return Object.assign({}, config, {
server: null,
auth: null,
permissions: null
});
}
function loadConfig(conf, root = {}) {
for (const [key, value] of Object.entries(conf)) {
const keys = key.split(".");
let ref = root;
while (keys.length > 1) {
const k = keys.shift();
if (typeof ref[k] !== "object") ref[k] = {};
ref = ref[k];
}
if (typeof value === "object") {
if (typeof ref[keys[0]] !== "object") ref[keys[0]] = {};
loadConfig(value, ref[keys[0]]);
} else {
ref[keys[0]] = value;
}
}
return root;
}
module.exports = Object.assign({}, config, { getClientConfig });
+6 -17
View File
@@ -1,7 +1,7 @@
"use strict";
const mongodb = require("mongodb");
const config = require("./config");
const config = require("../config");
const mongodbFunctions = require("./mongodb-functions");
const expression = require("../common/expression");
@@ -9,24 +9,13 @@ const CACHE_TTL = 300000;
let _clientPromise = null;
const RESOURCE_DB = {
devices: "genieacs",
faults: "genieacs",
tasks: "genieacs",
presets: "genieacs",
provisions: "genieacs",
virtualParameters: "genieacs",
files: "genieacs",
cache: "genieacs-ui"
};
const RESOURCE_COLLECTION = {
files: "fs.files"
};
function ensureIndexes(client) {
client
.db(RESOURCE_DB["cache"])
.db()
.collection("cache")
.createIndex({ expire: 1 }, { expireAfterSeconds: 0 });
}
@@ -34,7 +23,7 @@ function ensureIndexes(client) {
function getClient() {
if (!_clientPromise) {
_clientPromise = new Promise((resolve, reject) => {
const CONNECTION_URL = config.server.mongodbConnectionUrl;
const CONNECTION_URL = config.get("MONGODB_CONNECTION_URL");
mongodb.MongoClient.connect(
CONNECTION_URL,
{ useNewUrlParser: true },
@@ -54,7 +43,7 @@ function cache(key, valueGetter, ttl) {
return new Promise((resolve, reject) => {
getClient()
.then(client => {
const collection = client.db(RESOURCE_DB["cache"]).collection("cache");
const collection = client.db().collection("cache");
collection.findOne({ _id: key }, (err, doc) => {
if (err) return void reject(err);
if (doc != null) return void resolve(JSON.parse(doc.value));
@@ -103,7 +92,7 @@ function query(resource, filter, options, callback) {
return new Promise((resolve, reject) => {
getClient().then(client => {
const collection = client
.db(RESOURCE_DB[resource])
.db()
.collection(RESOURCE_COLLECTION[resource] || resource);
const cursor = collection.find(q);
if (options.projection) {
@@ -188,7 +177,7 @@ function count(resource, filter) {
return new Promise((resolve, reject) => {
getClient().then(client => {
const collection = client
.db(RESOURCE_DB[resource])
.db()
.collection(RESOURCE_COLLECTION[resource] || resource);
collection.find(q).count((err, c) => {
if (err) reject(err);