consolidate user config paths,

move global config values to global key in localdb
This commit is contained in:
2023-07-05 23:14:45 +00:00
parent 8e476ea352
commit 4fbb64745b
6 changed files with 233 additions and 242 deletions

View File

@@ -22,27 +22,18 @@ class LocalDB {
writeFileSync(path, JSON.stringify(this.#data));
}
getApplicationConfig () {
return this.#data.application;
}
getResourceConfig () {
return this.#data.resources;
getGlobalConfig () {
return this.#data.global;
}
getUserConfig (username) {
if (this.#data.users[username]) {
return this.#data.users[username];
}
else {
return null;
}
return this.#data.users[username];
}
}
export const db = new LocalDB();
export const pveAPI = db.getApplicationConfig().pveAPI;
export const pveAPIToken = db.getApplicationConfig().pveAPIToken;
export const listenPort = db.getApplicationConfig().listenPort;
export const hostname = db.getApplicationConfig().hostname;
export const domain = db.getApplicationConfig().domain;
export const pveAPI = db.getGlobalConfig().application.pveAPI;
export const pveAPIToken = db.getGlobalConfig().application.pveAPIToken;
export const listenPort = db.getGlobalConfig().application.listenPort;
export const hostname = db.getGlobalConfig().application.hostname;
export const domain = db.getGlobalConfig().application.domain;

View File

@@ -37,18 +37,6 @@ app.get("/api/echo", (req, res) => {
res.status(200).send({ body: req.body, cookies: req.cookies });
});
/**
* GET - check authentication
* responses:
* - 200: {auth: true, path: String}
* - 401: {auth: false, path: String}
*/
app.get("/api/auth", async (req, res) => {
let auth = await checkAuth(req.cookies, res);
if (!auth) { return; }
res.status(200).send({ auth: true });
});
/**
* GET - proxy proxmox api without privilege elevation
* request and responses passed through to/from proxmox
@@ -69,6 +57,18 @@ app.post("/api/proxmox/*", async (req, res) => { // proxy endpoint for POST prox
res.status(result.status).send(result.data);
});
/**
* GET - check authentication
* responses:
* - 200: {auth: true, path: String}
* - 401: {auth: false, path: String}
*/
app.get("/api/auth", async (req, res) => {
let auth = await checkAuth(req.cookies, res);
if (!auth) { return; }
res.status(200).send({ auth: true });
});
/**
* POST - safer ticket generation using proxmox authentication but adding HttpOnly
* request:
@@ -78,7 +78,7 @@ app.post("/api/proxmox/*", async (req, res) => { // proxy endpoint for POST prox
* - 200: {auth: true, path: String}
* - 401: {auth: false, path: String}
*/
app.post("/api/ticket", async (req, res) => {
app.post("/api/auth/ticket", async (req, res) => {
let response = await requestPVE("/access/ticket", "POST", null, JSON.stringify(req.body));
if (!(response.status === 200)) {
res.status(response.status).send({ auth: false });
@@ -101,7 +101,7 @@ app.post("/api/ticket", async (req, res) => {
* responses:
* - 200: {auth: false, path: String}
*/
app.delete("/api/ticket", async (req, res) => {
app.delete("/api/auth/ticket", async (req, res) => {
let expire = new Date(0);
res.cookie("PVEAuthCookie", "", { domain: domain, path: "/", httpOnly: true, secure: true, expires: expire });
res.cookie("CSRFPreventionToken", "", { domain: domain, path: "/", httpOnly: true, secure: true, expires: expire });
@@ -110,13 +110,35 @@ app.delete("/api/ticket", async (req, res) => {
res.status(200).send({ auth: false });
});
/**
* GET - get db global resource configuration
* responses:
* - 200: Object
*/
app.get("/api/global/config/:key", async (req, res) => {
let params = {
key: req.params.key
}
// check auth
let auth = await checkAuth(req.cookies, res);
if (!auth) { return; }
let allowKeys = ["resources"];
if (allowKeys.includes(params.key)){
let config = db.getGlobalConfig();
res.status(200).send(config[params.key]);
}
else {
res.status(401).send({auth: false, error: `User is not authorized to access /global/config/${params.key}.`});
}
});
/**
* GET - get db user resource information including allocated, free, and maximum resource values along with resource metadata
* responses:
* - 200: {avail: Object, max: Object, used: Object, resources: Object}
* - 401: {auth: false, path: String}
*/
app.get("/api/user/resources", async (req, res) => {
app.get("/api/user/dynamic/resources", async (req, res) => {
// check auth
let auth = await checkAuth(req.cookies, res);
if (!auth) { return; }
@@ -125,60 +147,31 @@ app.get("/api/user/resources", async (req, res) => {
});
/**
* GET - get db global resource configuration
* responses:
* - 200: Object
*/
app.get("/api/global/config/resources", async (req, res) => {
// check auth
let auth = await checkAuth(req.cookies, res);
if (!auth) { return; }
let config = db.getResourceConfig();
res.status(200).send(config);
});
/**
* GET - get db user resource configuration
* GET - get db user configuration by key
* request:
* - key: User config key
* responses:
* - 200: Object
* - 401: {auth: false, path: String}
* - 401: {auth: false, error: String}
*/
app.get("/api/user/config/resources", async (req, res) => {
app.get(`/api/user/config/:key`, async (req, res) => {
let params = {
key: req.params.key
}
// check auth
let auth = await checkAuth(req.cookies, res);
if (!auth) { return; }
let config = db.getUserConfig(req.cookies.username);
res.status(200).send(config.resources);
let allowKeys = ["resources", "cluster", "nodes"];
if (allowKeys.includes(params.key)){
let config = db.getUserConfig(req.cookies.username);
res.status(200).send(config[params.key]);
}
else {
res.status(401).send({auth: false, error: `User is not authorized to access /user/config/${params.key}.`});
}
});
/**
* GET - get db user cluster configuration
* responses:
* - 200: {pool: String, templates: {lxc: Object, qemu: Object}, vmid: {min: Number, max: Number}}
* - 401: {auth: false, path: String}
*/
app.get("/api/user/config/cluster", async (req, res) => {
// check auth
let auth = await checkAuth(req.cookies, res);
if (!auth) { return; }
let config = db.getUserConfig(req.cookies.username);
res.status(200).send(config.cluster)
});
/**
* GET - get db user node configuration
* responses:
* - 200: {nodes: String[]}
* - 401: {auth: false, path: String}
*/
app.get("/api/user/config/nodes", async (req, res) => {
// check auth
let auth = await checkAuth(req.cookies, res);
if (!auth) { return; }
let config = db.getUserConfig(req.cookies.username);
res.status(200).send(config.nodes)
})
/**
* POST - detach mounted disk from instance
* request:
@@ -259,7 +252,7 @@ app.post(`/api/:node(${nodeRegexP})/:type(${typeRegexP})/:vmid(${vmidRegexP})/di
}
// target disk must be allowed according to source disk's storage options
let diskConfig = await getDiskInfo(params.node, params.type, params.vmid, `unused${params.source}`); // get target disk
let resourceConfig = db.getResourceConfig();
let resourceConfig = db.getGlobalConfig().resources;
if (!resourceConfig[diskConfig.storage].disks.some(diskPrefix => params.disk.startsWith(diskPrefix))) {
res.status(500).send({ error: `Requested target ${params.disk} is not in allowed list [${resourceConfig[diskConfig.storage].disks}].` });
res.end();
@@ -486,7 +479,7 @@ app.post(`/api/:node(${nodeRegexP})/:type(${typeRegexP})/:vmid(${vmidRegexP})/di
return;
}
// target disk must be allowed according to storage options
let resourceConfig = db.getResourceConfig();
let resourceConfig = db.getGlobalConfig().resources;
if (!resourceConfig[params.storage].disks.some(diskPrefix => params.disk.startsWith(diskPrefix))) {
res.status(500).send({ error: `Requested target ${params.disk} is not in allowed list [${resourceConfig[params.storage].disks}].` });
res.end();
@@ -811,7 +804,7 @@ app.post(`/api/:node(${nodeRegexP})/:type(${typeRegexP})/:vmid(${vmidRegexP})/pc
action[`hostpci${params.hostpci}`] = `${params.device},pcie=${params.pcie}`;
action = JSON.stringify(action);
// commit action
let rootauth = await requestPVE("/access/ticket", "POST", null, JSON.stringify(db.getApplicationConfig().pveroot), null);
let rootauth = await requestPVE("/access/ticket", "POST", null, JSON.stringify(db.getGlobalConfig().application.pveroot), null);
if (!(rootauth.status === 200)) {
res.status(rootauth.status).send({ auth: false, error: "API could not authenticate as root user." });
res.end();
@@ -888,7 +881,7 @@ app.post(`/api/:node(${nodeRegexP})/:type(${typeRegexP})/:vmid(${vmidRegexP})/pc
action[`hostpci${hostpci}`] = `${params.device},pcie=${params.pcie}`;
action = JSON.stringify(action);
// commit action
let rootauth = await requestPVE("/access/ticket", "POST", null, JSON.stringify(db.getApplicationConfig().pveroot), null);
let rootauth = await requestPVE("/access/ticket", "POST", null, JSON.stringify(db.getGlobalConfig().application.pveroot), null);
if (!(rootauth.status === 200)) {
res.status(rootauth.status).send({ auth: false, error: "API could not authenticate as root user." });
res.end();
@@ -942,7 +935,7 @@ app.delete(`/api/:node(${nodeRegexP})/:type(${typeRegexP})/:vmid(${vmidRegexP})/
// setup action
let action = JSON.stringify({ delete: `hostpci${params.hostpci}` });
// commit action, need to use root user here because proxmox api only allows root to modify hostpci for whatever reason
let rootauth = await requestPVE("/access/ticket", "POST", null, JSON.stringify(db.getApplicationConfig().pveroot), null);
let rootauth = await requestPVE("/access/ticket", "POST", null, JSON.stringify(db.getGlobalConfig().application.pveroot), null);
if (!(rootauth.status === 200)) {
res.status(response.status).send({ auth: false, error: "API could not authenticate as root user." });
res.end();

View File

@@ -28,7 +28,7 @@ export async function checkAuth (cookies, res, vmpath = null) {
}
export async function getUserResources (req, username) {
const dbResources = db.getResourceConfig();
const dbResources = db.getGlobalConfig().resources;
const used = await getUsedResources(req, dbResources);
const max = db.getUserConfig(username).resources.max;
const avail = {};