"
}
diff --git a/server/index.js b/server/index.js
index fb116fd5..f002758f 100755
--- a/server/index.js
+++ b/server/index.js
@@ -14,7 +14,6 @@ process.on('uncaughtException', err => require('./config/errorHandler')(err));
// Register middlewares
app.use(express.json());
-app.use("/api/*", require('./middlewares/password'));
// Register routes
app.use("/api/config", require('./routes/config'));
diff --git a/server/middlewares/password.js b/server/middlewares/password.js
index e79bad82..ba23b615 100644
--- a/server/middlewares/password.js
+++ b/server/middlewares/password.js
@@ -1,17 +1,24 @@
const config = require('../controller/config');
const bcrypt = require('bcrypt');
-module.exports = async (req, res, next) => {
+module.exports = (allowViewAccess) => async (req, res, next) => {
let passwordHash = (await config.get("password")).value;
+ let passwordLevel = (await config.get("passwordLevel")).value;
- if (passwordHash === "none")
+ if (passwordHash === "none") {
+ req.viewMode = false;
return next();
+ }
- if (!req.headers.password)
- return res.status(401).json({message: "Please provide the correct password in the header"});
+ if (req.headers.password && bcrypt.compareSync(req.headers.password, passwordHash)) {
+ req.viewMode = false;
+ return next();
+ }
- if (!bcrypt.compareSync(req.headers.password, passwordHash))
- return res.status(401).json({message: "Please provide the correct password in the header"});
+ if (passwordLevel === "read" && allowViewAccess) {
+ req.viewMode = true;
+ return next();
+ }
- next();
+ return res.status(401).json({message: "Please provide the correct password in the header"});
}
\ No newline at end of file
diff --git a/server/routes/config.js b/server/routes/config.js
index 9f9fde0f..1aa15caa 100644
--- a/server/routes/config.js
+++ b/server/routes/config.js
@@ -2,32 +2,31 @@ const app = require('express').Router();
const config = require('../controller/config');
const timer = require('../tasks/timer');
const cron = require('cron-validator');
+const password = require('../middlewares/password');
// Gets all config entries
-app.get("/", async (req, res) => {
+app.get("/", password(true), async (req, res) => {
let configValues = {};
(await config.list()).forEach(row => {
- if (row.key !== "password") configValues[row.key] = row.value;
+ if (row.key !== "password" && !(req.viewMode && ["healthChecksUrl", "serverId", "cron", "passwordLevel"].includes(row.key)))
+ configValues[row.key] = row.value;
});
+ configValues['viewMode'] = req.viewMode;
+
if (Object.keys(configValues).length === 0) return res.status(404).json({message: "Hmm. There are no config values. Weird..."});
res.json(configValues);
});
-// Gets a specific config entry
-app.get("/:key", async (req, res) => {
- let row = await config.get(req.params.key);
- if (row === null) return res.status(404).json({message: "Config value not found"});
- if (row.key === "password") return res.status(403).json({message: "Really?"});
- res.json({key: row.key, value: row.value});
-});
-
// Updates a specific config entry
-app.patch("/:key", async (req, res) => {
+app.patch("/:key", password(false), async (req, res) => {
if (!req.body.value.toString()) return res.status(400).json({message: "You need to provide the new value"});
if ((req.params.key === "ping" || req.params.key === "download" || req.params.key === "upload") && isNaN(req.body.value))
return res.status(400).json({message: "You need to provide a number in order to change this"});
+ if (req.params.key === "passwordLevel" && !["none", "read"].includes(req.body.value))
+ return res.status(400).json({message: "You need to provide either none or read-access"});
+
if (req.params.key === "acceptOoklaLicense" && typeof req.body.value !== "boolean")
return res.status(400).json({message: "You need to provide a boolean value"});
diff --git a/server/routes/export.js b/server/routes/export.js
index c81d8e0b..beacbea3 100644
--- a/server/routes/export.js
+++ b/server/routes/export.js
@@ -1,21 +1,21 @@
const app = require('express').Router();
const tests = require('../controller/speedtests');
+const password = require('../middlewares/password');
-
-app.get("/json", async (req, res) => {
+app.get("/json", password(false), async (req, res) => {
res.set({"Content-Disposition": "attachment; filename=\"speedtests.json\""});
res.send(JSON.stringify(await tests.list(), null, 4));
});
-app.get("/csv", async (req, res) => {
+app.get("/csv", password(false), async (req, res) => {
res.set({"Content-Disposition": "attachment; filename=\"speedtests.csv\""});
let list = await tests.list();
let fields = Object.keys(list[0]);
- let replacer = (key, value) => value === null ? '' : value
+ let replacer = (key, value) => value === null ? '' : value;
let csv = list.map(row => fields.map(fieldName => JSON.stringify(row[fieldName], replacer)).join(','));
- csv.unshift(fields.join(','))
+ csv.unshift('"' + fields.join('","') + '"');
csv = csv.join('\r\n');
res.send(csv);
diff --git a/server/routes/recommendations.js b/server/routes/recommendations.js
index 26741ff7..33d57f52 100644
--- a/server/routes/recommendations.js
+++ b/server/routes/recommendations.js
@@ -1,8 +1,9 @@
const app = require('express').Router();
const recommendations = require('../controller/recommendations');
+const password = require('../middlewares/password');
// Gets all config entries
-app.get("/", async (req, res) => {
+app.get("/", password(false), async (req, res) => {
let currentRecommendations = await recommendations.get();
if (currentRecommendations === null) return res.status(501).json({message: "There are no recommendations yet"});
diff --git a/server/routes/speedtests.js b/server/routes/speedtests.js
index 248da419..dd3c497c 100644
--- a/server/routes/speedtests.js
+++ b/server/routes/speedtests.js
@@ -3,19 +3,20 @@ const tests = require('../controller/speedtests');
const pauseController = require('../controller/pause');
const config = require('../controller/config');
const testTask = require("../tasks/speedtest");
+const password = require('../middlewares/password');
// List all speedtests
-app.get("/", async (req, res) => {
+app.get("/", password(true), async (req, res) => {
res.json(await tests.list(req.query.hours || 24));
});
// List all speedtests by average
-app.get("/averages", async (req, res) => {
+app.get("/averages", password(true), async (req, res) => {
res.json(await tests.listAverage(req.query.days || 7));
});
// Runs a speedtest
-app.post("/run", async (req, res) => {
+app.post("/run", password(false), async (req, res) => {
if (pauseController.currentState) return res.status(410).json({message: "The speedtests are currently paused"});
if ((await config.get("acceptOoklaLicense")).value === 'false') return res.status(410).json({message: "You need to accept the ookla license first"});
let speedtest = await testTask.create("custom");
@@ -24,12 +25,12 @@ app.post("/run", async (req, res) => {
});
// Get the current test status
-app.get("/status", (req, res) => {
+app.get("/status", password(true), (req, res) => {
res.json({paused: pauseController.currentState, running: testTask.isRunning()});
});
// Pauses all speedtests
-app.post("/pause", (req, res) => {
+app.post("/pause", password(false), (req, res) => {
if (!req.body.resumeIn) return res.status(400).json({message: "You need to provide when to resume"});
if (req.body.resumeIn === -1) {
@@ -42,20 +43,20 @@ app.post("/pause", (req, res) => {
});
// Ends the pause-state
-app.post("/continue", (req, res) => {
+app.post("/continue", password(false), (req, res) => {
pauseController.updateState(false);
res.json({message: "Successfully resumed the speedtests"});
});
// Get a specific speedtest
-app.get("/:id", async (req, res) => {
+app.get("/:id", password(true), async (req, res) => {
let test = await tests.get(req.params.id);
if (test === null) return res.status(404).json({message: "Speedtest not found"});
res.json(test);
});
// Delete a specific speedtest
-app.delete("/:id", async (req, res) => {
+app.delete("/:id", password(false), async (req, res) => {
let test = await tests.delete(req.params.id);
if (!test) return res.status(404).json({message: "Speedtest not found"});
res.json({message: "Successfully deleted the provided speedtest"});
diff --git a/server/routes/system.js b/server/routes/system.js
index b9b9cff3..b2d0bac5 100644
--- a/server/routes/system.js
+++ b/server/routes/system.js
@@ -3,9 +3,10 @@ const version = require('../../package.json').version;
const remote_url = "https://api.github.com/repos/gnmyt/myspeed/releases/latest";
const axios = require('axios');
const fs = require("fs");
+const password = require('../middlewares/password');
-app.get("/version", async (req, res) => {
+app.get("/version", password(false), async (req, res) => {
try {
res.json({local: version, remote: ((await axios.get(remote_url)).data.tag_name).replace("v", "")});
} catch (e) {
@@ -13,7 +14,7 @@ app.get("/version", async (req, res) => {
}
});
-app.get("/server", (req, res) => {
+app.get("/server", password(false), (req, res) => {
fs.readFile("./data/servers.json", "utf8", (err, data) => {
if (err) return res.status(500).json({message: "Could not read servers"});
res.json(JSON.parse(data.toString()));