-
Notifications
You must be signed in to change notification settings - Fork 1
/
backend.js
161 lines (140 loc) · 5.01 KB
/
backend.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
const express = require('express');
const ArgumentParser = require('argparse').ArgumentParser;
const bodyParser = require('body-parser');
const fs = require('fs');
const path = require('path');
const app = express();
// parse arguments
var parser = new ArgumentParser({
version: '0.0.1',
addHelp: true,
description: 'Windows Portfolio Backend'
});
parser.addArgument(
['-d', '--dist'],
{
help: 'path from app (as root) that points to dist. don\'t include / at start',
defaultValue: 'dist/'
}
);
var args = parser.parseArgs();
// turn the dist path into an absolute path (__dirname points to backend.js directory)
const distPath = path.join(__dirname, args.dist);
// the "faux" root directory
const assetsRoot = '/assets/portfolio-documents';
const assetsPath = path.join(distPath, assetsRoot);
// Serve only the static files form the npmdist directory
app.use(express.static(distPath));
// Parse the bodies from all requests
app.use(bodyParser.json());
// CORS
app.use(function (req, res, next) {
/* Enable CORS requests */
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.get('/', (req, res) => {
/* Route to the angular app */
res.sendFile(distPath + '/index.html'); //_dirname = path to app
});
/* POST Requests */
app.post("/files", (req, res) => {
/* Let the angular app know the files in a directory */
getFiles(req.body.currentDirectory).then((success) => {
res.json(success);
})
.catch((error) => {
console.error(error);
res.json({error: error});
});
});
app.post("/fileExists", async (req, res) => {
res.send(await fileExists(req.body.path));
});
/* Listen for the app on the Heroku port (if set as an env variable)
or default to 8080. */
app.listen(process.env.PORT || 8080);
async function fileExists(filePath) {
/* checks to see if the file exists
returns true/false if so
*/
// makes sure the path is valid and simplifies it
let simpPath = pathCheck(filePath);
// actually get the file information
let result = false;
try {
const fullPath = path.join(assetsPath, simpPath);
const containingDir = path.dirname(fullPath);
return dirContainsFile(containingDir, fullPath);
} catch (error) {
result = false;
console.error(error);
}
return result;
}
async function dirContainsFile(dirPath, fullFilePath) {
// because fs.readfilesync is case insensitive
try {
const realFilePath = fs.realpathSync(fullFilePath);
const matchingPaths = fs.readdirSync(dirPath)
.map((fileName) => path.join(dirPath, fileName))
.filter(fullPath => fullPath === realFilePath);
return matchingPaths.length !== 0 && fs.statSync(matchingPaths[0]).isFile();
} catch (error) {
return false;
}
}
async function getFiles(direcPath) {
/* Return a promise that returns the files and directories
within a directory */
return new Promise((resolve, reject) => {
let files;
let simpPath;
let fullPath;
try {
// get the simplified path and checks for restirctions
simpPath = pathCheck(direcPath);
// add assetsPath because it's the root
fullPath = path.join(assetsPath, simpPath);
files = fs.readdirSync(fullPath);
} catch (error) {
reject(error);
}
// set the simp path to the user's "relative root"
let output = {files: [], dirs: [], simpPath: simpPath};
files.forEach((file) => {
try {
let filePath = path.join(fullPath, file);
let result = fs.lstatSync(filePath);
/* not all files might be directories or files, so don't just
use if else. explicitly check for each one */
result.name = file;
result.path = path.join(simpPath, file);
result.extension = path.extname(result.name);
result.isDirectory() && output.dirs.push(result);
result.isFile() && output.files.push(result);
} catch (error) {
reject(error);
}
});
resolve(output);
});
}
function pathCheck(inspectionPath) {
/* Makes sure the path is within the limited range of directories.
if not, it sets the path to the root. Returns a simplified version of the
path rooted at the assetsPath. */
let simpPath = path.join(assetsPath, inspectionPath); // just combines the path
if (path.relative(assetsPath, simpPath).includes('..')) {
/* the user is trying to access something outside assets.
prevent them */
simpPath = assetsPath;
}
/*
path.relative negates the assets path from the simp path
because the root is the assets path. It also simplifies it.
*/
simpPath = '/' + path.relative(assetsPath, simpPath);
return simpPath;
}