-
Notifications
You must be signed in to change notification settings - Fork 3
/
main.js
166 lines (138 loc) · 5.84 KB
/
main.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
162
163
164
165
166
//Require everything we need.
//Node STDLib requires.
var https = require("https");
var http = require("http");
var fs = require("fs"); //Needed to load the certificates and see if a page exists.
var path = require("path");
//Express requires.
var express = require("express"); //Web server.
var helmet = require("helmet"); //Security layer.
var compression = require("compression"); //Compresses pages to save bandwith.
var device = require("express-device"); //Gets the device type.
var session = require("express-session"); //Stores data for each user.
//CSS.
var sass = require("node-sass");
var cssMin = new (require("clean-css"))({
level: 2,
compatibility: "ie8"
});
//GeoIP.
var geoip = require("geoip-lite"); //Library to get the user's location.
//Custom requires.
//var accountRouter = require("./routers/account.js").router; //Not needed for now.
var info = require("./routers/info.js");
//Load the settings.
var settings = JSON.parse(fs.readFileSync("./settings.json"));
//Compile the SCSS.
function compileSCSS() {
//Get all the SCSS files.
fs.readdir(path.join(__dirname, "public", "scss"), async (err, files) => {
//Go through each.
files.forEach(async (scssFile) => {
//Compile the SCSS.
sass.render({
file: path.join(__dirname, "public", "scss", scssFile),
}, async (err, sassRes) => {
//Save the CSS.
fs.writeFile(
path.join(__dirname, "public", "css", (scssFile.split(".")[0] + ".css")),
cssMin.minify(sassRes.css.toString()).styles,
async ()=>{}
);
});
});
});
//Compile every hour.
setTimeout(compileSCSS, 60*60*1000);
}
compileSCSS();
//Create the server and configure it.
var siteServer = express();
siteServer.set("etag", false); //Disable etag as it leaks system info.
siteServer.set("view engine", "pug"); //Set the view engine to Pug.
siteServer.set("views", path.join(__dirname, "public")); // Set Pug to work off the public files.
siteServer.use(sass);
//Add middleware.
siteServer.use(helmet({ //Add in helmet for security.
hsts: false, //Disable HSTS. We can try to make sure no data is sent over a bad certificate but we can't let the site go down.
expectCt: true
}));
siteServer.use(compression()); //Enable page compression.
siteServer.use(device.capture()); //Add in device recognition.
siteServer.use(express.json()); //Add in the JSON body parser so we can handle POST data.
siteServer.use(session({ //Enable session for tracking user's language and who they're logged in as.
secret: settings.session.secret,
resave: false,
saveUninitialized: true,
cookie: {secure: true}
}));
//Save the language of the user and their device type to req.language/req.deviceType.
siteServer.use((req, res, next) => {
if (req.session.language) { //If the language is already is set...
req.language = req.session.language; //Set it.
} else { //Else, get the country the user is in and go through each language to see what language that country is assigned to.
var countryCode = geoip.lookup(req.ip).country.toLowerCase();
for (var lang in settings.languages) {
if (settings.languages[lang].indexOf(country) > -1) {
req.session.language = lang;
req.language = lang;
}
}
if (!(req.language)) { //If req.language is still not set, default to "en".
req.session.language = "en";
req.language = "en";
}
}
switch (req.device.type) {
case "desktop": //Most popular option. Putting this first will save CPU cycles.
req.deviceType = "desktop";
break;
case "tablet":
req.deviceType = "tablet";
break;
case "phone":
req.deviceType = "phone";
break;
default: //If it's unrecognized (car/bot), just give data like it's for the most popular platform (desktop).
req.deviceType = "desktop";
break;
}
next();
});
//Add in CSS, JS, and images. These should be language agnostic.
siteServer.use("/css", express.static(path.join(__dirname, "public", "css")));
siteServer.use("/js", express.static(path.join(__dirname, "public", "js")));
siteServer.use("/images", express.static(path.join(__dirname, "public", "images")));
//Setup and add in the various routers.
//siteServer.use("/account", account.router);
siteServer.use("/", info.genRouter(settings.info.pages));
siteServer.get("*", (req, res) => { //Capture every GET route not already handled.
res.status(404).render(req.language + "/404.pug"); //Send a 404 page.
});
siteServer.use(errorFix); //Use errorFix (defined below). errorFix is hopefully never called but the server must NOT crash.
https.createServer({ //Create an HTTPS server.
key: fs.readFileSync(settings.ssl.key), //Set the SSL key.
cert: fs.readFileSync(settings.ssl.cert) //Set the SSL cert.
}, siteServer).listen(443); //Listen on the HTTPS port.
function errorFix(err, req, res, next) { //Try/catch safety wrapper.
try {
if (res.headersSent) {
return next(err);
}
} catch(e) {
console.log(e);
}
}
//----------------------------------------
var httpRedirect = express(); //Create a new web server for redirecting port 80 requests to 443.
httpRedirect.set("etag", false);
httpRedirect.use(helmet({
hsts: false,
expectCt: true
}));
//No compression as it would be minimally helpful yet take up CPU cycles.
httpRedirect.get("*", (req, res) => { //Catch all page requests.
res.redirect("https://" + req.headers.host + req.originalUrl); //Redirect to the HTTPS version of the page.
});
httpRedirect.use(errorFix); //Also use errorFix.
http.createServer(httpRedirect).listen(80); //Listen on the HTTP port.