diff --git a/frontend/server/routes/api/databases.js b/frontend/server/routes/api/databases.js index ed77e3f4..058c5b13 100644 --- a/frontend/server/routes/api/databases.js +++ b/frontend/server/routes/api/databases.js @@ -4,56 +4,79 @@ module.exports = function (databasesLocation) { const fs = require("fs"); const path = require("path"); + function securePath(base, ...parts) { + const fullPath = path.resolve(base, ...parts); + const resolvedBase = path.resolve(base); + + if (!fullPath.startsWith(resolvedBase)) { + throw new Error("Invalid path"); + } + + return fullPath; + } + router.get('/:type/:name', function (req, res) { - var contents = fs.readFileSync(path.join(databasesLocation, req.params.type, req.params.name + ".json")); - res.status(200).send(contents); + try { + const filePath = securePath(databasesLocation, req.params.type, req.params.name + ".json"); + const contents = fs.readFileSync(filePath); + res.status(200).send(contents); + } catch (error) { + res.status(404).send('Not found'); + } }); router.put('/save/:type/:name', function (req, res) { - var dir = path.join(databasesLocation, req.params.type, "old"); - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir); - } - - var filepath = path.join(databasesLocation, req.params.type, req.params.name + ".json"); - if (fs.existsSync(filepath)) { - var newFilepath = path.join(databasesLocation, req.params.type, "old", req.params.name + ".json"); - fs.copyFileSync(filepath, newFilepath); - if (fs.existsSync(newFilepath)) { - try { - var json = JSON.stringify(req.body.blueprints, null, "\t"); - fs.writeFileSync(filepath, json, 'utf8'); - res.send("OK"); - } catch { - res.status(422).send("Error"); - } - } else { - res.status(422).send("Error"); + try { + const dir = securePath(databasesLocation, req.params.type, "old"); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); } - } else { - res.status(404).send('Not found'); + + const filePath = securePath(databasesLocation, req.params.type, req.params.name + ".json"); + const backupPath = securePath(databasesLocation, req.params.type, "old", req.params.name + ".json"); + + if (fs.existsSync(filePath)) { + fs.copyFileSync(filePath, backupPath); + const json = JSON.stringify(req.body.blueprints, null, "\t"); + fs.writeFileSync(filePath, json, 'utf8'); + res.send("OK"); + } else { + res.status(404).send('Not found'); + } + } catch (error) { + res.status(422).send("Error"); } }); router.put('/reset/:type/:name', function (req, res) { - var filepath = path.join(databasesLocation, req.params.type, "default", req.params.name + ".json"); - if (fs.existsSync(filepath)) { - var newFilepath = path.join(databasesLocation, req.params.type, req.params.name + ".json"); - fs.copyFileSync(filepath, newFilepath); - res.send("OK"); - } else { - res.status(404).send('Not found'); + try { + const defaultPath = securePath(databasesLocation, req.params.type, "default", req.params.name + ".json"); + const targetPath = securePath(databasesLocation, req.params.type, req.params.name + ".json"); + + if (fs.existsSync(defaultPath)) { + fs.copyFileSync(defaultPath, targetPath); + res.send("OK"); + } else { + res.status(404).send('Not found'); + } + } catch (error) { + res.status(422).send("Error"); } }); router.put('/restore/:type/:name', function (req, res) { - var filepath = path.join(databasesLocation, req.params.type, "old", req.params.name + ".json"); - if (fs.existsSync(filepath)) { - var newFilepath = path.join(databasesLocation, req.params.type, req.params.name + ".json"); - fs.copyFileSync(filepath, newFilepath); - res.send("OK"); - } else { - res.status(404).send('Not found'); + try { + const backupPath = securePath(databasesLocation, req.params.type, "old", req.params.name + ".json"); + const targetPath = securePath(databasesLocation, req.params.type, req.params.name + ".json"); + + if (fs.existsSync(backupPath)) { + fs.copyFileSync(backupPath, targetPath); + res.send("OK"); + } else { + res.status(404).send('Not found'); + } + } catch (error) { + res.status(422).send("Error"); } });