mirror of
https://github.com/Lissy93/dashy.git
synced 2025-09-24 10:18:50 +02:00
🛂 Adds support for HTTP authorization
This commit is contained in:
parent
9d683dcbf0
commit
99643acddf
@ -26,6 +26,7 @@
|
|||||||
"connect-history-api-fallback": "^1.6.0",
|
"connect-history-api-fallback": "^1.6.0",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"express": "^4.17.2",
|
"express": "^4.17.2",
|
||||||
|
"express-basic-auth": "^1.2.1",
|
||||||
"frappe-charts": "^1.6.2",
|
"frappe-charts": "^1.6.2",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"keycloak-js": "^20.0.3",
|
"keycloak-js": "^20.0.3",
|
||||||
|
59
server.js
59
server.js
@ -11,9 +11,13 @@ const path = require('path');
|
|||||||
const util = require('util');
|
const util = require('util');
|
||||||
const dns = require('dns');
|
const dns = require('dns');
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
|
const fs = require('fs');
|
||||||
|
const crypto = require('crypto');
|
||||||
|
const yaml = require('js-yaml');
|
||||||
|
|
||||||
/* Import Express + middleware functions */
|
/* Import Express + middleware functions */
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
const basicAuth = require('express-basic-auth');
|
||||||
const history = require('connect-history-api-fallback');
|
const history = require('connect-history-api-fallback');
|
||||||
|
|
||||||
/* Kick of some basic checks */
|
/* Kick of some basic checks */
|
||||||
@ -71,6 +75,56 @@ const printWarning = (msg, error) => {
|
|||||||
console.warn(`\x1b[103m\x1b[34m${msg}\x1b[0m\n`, error || ''); // eslint-disable-line no-console
|
console.warn(`\x1b[103m\x1b[34m${msg}\x1b[0m\n`, error || ''); // eslint-disable-line no-console
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function loadUserConfig() {
|
||||||
|
try {
|
||||||
|
const filePath = path.join(__dirname, process.env.USER_DATA_DIR || 'user-data', 'conf.yml');
|
||||||
|
const fileContents = fs.readFileSync(filePath, 'utf8');
|
||||||
|
const data = yaml.load(fileContents);
|
||||||
|
return data?.appConfig?.auth?.users || null;
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function customAuthorizer(username, password) {
|
||||||
|
const sha256 = (input) => crypto.createHash('sha256').update(input).digest('hex').toUpperCase();
|
||||||
|
if (password.startsWith('Bearer ')) {
|
||||||
|
const token = password.slice('Bearer '.length);
|
||||||
|
const tokenHash = sha256(token);
|
||||||
|
const users = loadUserConfig();
|
||||||
|
return users.some(user => user.hash.toUpperCase() === tokenHash);
|
||||||
|
} else {
|
||||||
|
const users = loadUserConfig();
|
||||||
|
const userHash = sha256(password);
|
||||||
|
return users.some(user => (
|
||||||
|
user.user.toLowerCase() === username.toLowerCase() && user.hash.toUpperCase() === userHash
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If a username and password are set, setup auth for config access, otherwise skip */
|
||||||
|
function getBasicAuthMiddleware() {
|
||||||
|
const configUsers = process.env.ENABLE_HTTP_AUTH ? loadUserConfig() : null;
|
||||||
|
const { BASIC_AUTH_USERNAME, BASIC_AUTH_PASSWORD } = process.env;
|
||||||
|
if (BASIC_AUTH_USERNAME && BASIC_AUTH_PASSWORD) {
|
||||||
|
return basicAuth({
|
||||||
|
users: { [BASIC_AUTH_USERNAME]: BASIC_AUTH_PASSWORD },
|
||||||
|
challenge: true,
|
||||||
|
unauthorizedResponse: () => 'Unauthorized - Incorrect username or password',
|
||||||
|
});
|
||||||
|
} else if ((configUsers && configUsers.length > 0)) {
|
||||||
|
return basicAuth({
|
||||||
|
authorizer: customAuthorizer,
|
||||||
|
challenge: true,
|
||||||
|
unauthorizedResponse: () => 'Unauthorized - Incorrect token',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return (req, res, next) => next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const protectConfig = getBasicAuthMiddleware();
|
||||||
|
|
||||||
/* A middleware function for Connect, that filters requests based on method type */
|
/* A middleware function for Connect, that filters requests based on method type */
|
||||||
const method = (m, mw) => (req, res, next) => (req.method === m ? mw(req, res, next) : next());
|
const method = (m, mw) => (req, res, next) => (req.method === m ? mw(req, res, next) : next());
|
||||||
|
|
||||||
@ -134,6 +188,11 @@ const app = express()
|
|||||||
res.end(JSON.stringify({ success: false, message: e }));
|
res.end(JSON.stringify({ success: false, message: e }));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
// Middleware to serve any .yml files in USER_DATA_DIR with optional protection
|
||||||
|
.get('/*.yml', protectConfig, (req, res) => {
|
||||||
|
const ymlFile = req.path.split('/').pop();
|
||||||
|
res.sendFile(path.join(__dirname, process.env.USER_DATA_DIR || 'user-data', ymlFile));
|
||||||
|
})
|
||||||
// Serves up static files
|
// Serves up static files
|
||||||
.use(express.static(path.join(__dirname, process.env.USER_DATA_DIR || 'user-data')))
|
.use(express.static(path.join(__dirname, process.env.USER_DATA_DIR || 'user-data')))
|
||||||
.use(express.static(path.join(__dirname, 'dist')))
|
.use(express.static(path.join(__dirname, 'dist')))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user