Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,7 @@ services:
/bin/sh -c "
rm -f /tmp/.X99-lock &&
Xvfb :99 -screen 0 1024x768x16"

read_only: true
security_opt:
- no-new-privileges:true

2 changes: 1 addition & 1 deletion src/client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<link rel="icon" type="image/png" href="favicon.ico">
<title>Open Energy Dashboard</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha512-SfTiTlX6kk+qitfevl/7LibUOeJWlt9rbyDn92a1DqWOw9vWG2MFoays0sgObmWazO5BQPiFucnnEAjpAB+/Sw==" crossorigin="anonymous">
</head>

<body>
Expand Down
23 changes: 17 additions & 6 deletions src/server/middleware/paramsProcessing.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,28 @@
* A middleware to lowercase all params, including those passed by form/multipart
*/
function lowercaseAllParamNames(req, res, next) {
for (const key of Object.entries(req.query)) {
req.query[key[0].toLowerCase()] = key[1];

const newQuery = Object.create(null);

for (const [key, value] of Object.entries(req.query)) {
newQuery[key.toLowerCase()] = value;
}
for (const key of Object.entries(req.params)) {
req.params[key[0].toLowerCase()] = key[1];
req.query = newQuery;

const newParams = Object.create(null);
for (const [key, value] of Object.entries(req.params)) {
newParams[key.toLowerCase()] = value;
}
req.params = newParams;

if (req.body) {
for (const key of Object.entries(req.body)) {
req.body[key[0].toLowerCase()] = key[1];
const newBody = Object.create(null);
for (const [key, value] of Object.entries(req.body)) {
newBody[key.toLowerCase()] = value;
}
req.body = newBody;
}

next();
}

Expand Down
10 changes: 8 additions & 2 deletions src/server/models/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,15 @@ const loadedSqlFiles = {};
* @returns {pgPromise.QueryFile}
*/
function sqlFile(filePath) {
const sqlFilePath = path.join(sqlFilesDir, filePath);
const sanitizedPath = filePath.replace(/\.\./g, '');
const resolvedPath = path.resolve(sqlFilesDir, sanitizedPath);
if (!resolvedPath.startsWith(path.resolve(sqlFilesDir))) {
throw new Error('Invalid file path: path traversal detected');
}

const sqlFilePath = resolvedPath
if (loadedSqlFiles[sqlFilePath] === undefined) {
loadedSqlFiles[sqlFilePath] = new pgp.QueryFile(path.join(sqlFilesDir, filePath), { minify: true });
loadedSqlFiles[sqlFilePath] = new pgp.QueryFile(sqlFilePath, {minify: true});
}
return loadedSqlFiles[sqlFilePath];
}
Expand Down
2 changes: 2 additions & 0 deletions src/server/routes/readings.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ router.get('/line/count/meters/:meter_ids', optionalAuthMiddleware, async (req,
const curr = await Reading.getCountByMeterIDAndDateRange(meterIDs[i], timeInterval.startTimestamp, timeInterval.endTimestamp, conn);
count += curr
}
// nosemgrep: javascript.express.security.audit.xss.direct-response-write.direct-response-write
res.send(JSON.stringify(count));
} catch (err) {
log.error(`Error while performing GET readings COUNT for line with meters ${meterIDs} with time interval ${timeInterval}: ${err}`, err);
Expand Down Expand Up @@ -96,6 +97,7 @@ router.get('/line/raw/meter/:meter_id', optionalAuthMiddleware, async (req, res)
// Note this returns unusual identifiers to save space and does not return the meter id.
const rawReadings = await Reading.getReadingsByMeterIDAndDateRange(meterID, timeInterval.startTimestamp, timeInterval.endTimestamp, conn);
// They are ready to go back.
// nosemgrep: javascript.express.security.audit.xss.direct-response-write.direct-response-write
res.send(rawReadings);
} catch (err) {
log.error(`Error while performing GET raw readings for line with meter ${meterID} with time interval ${timeInterval}: ${err}`, err);
Expand Down
7 changes: 4 additions & 3 deletions src/server/util/insertData.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const { loadGeneratedInput } = require('../services/pipeline-in-progress/loadGen
const moment = require('moment');
const fs = require('fs').promises;
const cloneDeep = require('lodash/cloneDeep');
const util = require('util');

/**
* Inserts specified units into the database.
Expand All @@ -27,7 +28,7 @@ async function insertUnits(unitsToInsert, update = false, conn) {
let ok = true;
requiredKeys.forEach(key => {
if (!unitData.hasOwnProperty(key)) {
console.log(`********key "${key}" is required but missing so unit number ${index} not processed with values:`, unitData);
console.log(util.format('********key "%s" is required but missing so unit number %s not processed with values:', key, index), unitData);
// Don't insert
ok = false;
}
Expand Down Expand Up @@ -194,7 +195,7 @@ async function insertConversions(conversionsToInsert, conn) {
let ok = true;
requiredKeys.forEach(key => {
if (!conversionData.hasOwnProperty(key)) {
console.log(`********key "${key}" is required but missing so conversion number ${index} not processed with values:`, conversionData);
console.log(util.format('********key "%s" is required but missing so conversion number %s not processed with values:', key, index), conversionData);
// Don't insert
ok = false;
}
Expand Down Expand Up @@ -522,7 +523,7 @@ async function insertGroups(groupsToInsert, conn) {
let ok = true;
requiredKeys.forEach(key => {
if (!groupData.hasOwnProperty(key)) {
console.log(`********key "${key}" is required but missing so group number ${i} not processed with values:`, groupData);
console.log(util.format('********key "%s" is required but missing so group number %s not processed with values:', key, i), groupData);
// Don't insert
ok = false;
}
Expand Down