|
|
@@ -1,12 +1,41 @@
|
|
|
+import { AConfigChecker } from './src/AConfigChecker';
|
|
|
import * as express from 'express';
|
|
|
import { AddressInfo } from "net";
|
|
|
import * as path from 'path';
|
|
|
import * as bodyParser from 'body-parser';
|
|
|
import route_index from './routes/index';
|
|
|
+import route_login from './routes/login';
|
|
|
+import Security from './src/Security';
|
|
|
+import { Session, SessionManager } from './src/Session';
|
|
|
+import UserConnectorFactory from './src/UserConnector/UserConnectorFactory';
|
|
|
|
|
|
const debug = require('debug')('my express app');
|
|
|
const app = express();
|
|
|
|
|
|
+declare global {
|
|
|
+ namespace Express {
|
|
|
+ interface Request {
|
|
|
+ mSession: Session
|
|
|
+ mCookies: Map<string, string>
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Check config
|
|
|
+(_ => {
|
|
|
+ let cc: AConfigChecker[] = [
|
|
|
+ UserConnectorFactory
|
|
|
+ ];
|
|
|
+ for (let i of cc) {
|
|
|
+ let err = i.CheckConfig();
|
|
|
+ if (err) {
|
|
|
+ err = i.constructor.name + ": " + err;
|
|
|
+ console.error("Configuration error: " + err);
|
|
|
+ throw "Configuration error";
|
|
|
+ }
|
|
|
+ }
|
|
|
+})();
|
|
|
+
|
|
|
// view engine setup
|
|
|
app.set('views', [path.join(__dirname, 'views'), path.join(__dirname, 'views/template')]);
|
|
|
app.set('view engine', 'pug');
|
|
|
@@ -15,10 +44,46 @@ app.use(express.static(path.join(__dirname, 'public')));
|
|
|
app.use(bodyParser.json());
|
|
|
app.use(bodyParser.urlencoded({ extended: true }));
|
|
|
|
|
|
+// Security and session setup
|
|
|
+app.use((req, _, next) => {
|
|
|
+ req.mCookies = new Map();
|
|
|
+ (req.headers?.cookie || "").split(";").forEach(i => {
|
|
|
+ let keyValue = i.split("=", 2);
|
|
|
+ req.mCookies.set(keyValue[0].trim(), keyValue[1].trim());
|
|
|
+ });
|
|
|
+ req.mSession = SessionManager.GetSession(req);
|
|
|
+ if (req.mSession.IsValid())
|
|
|
+ req.mSession.Ping();
|
|
|
+ if (req.query["API_KEY"])
|
|
|
+ if (!Security.TryLoginApiKey(req.query["API_KEY"].toString())) {
|
|
|
+ let err: any = new Error("Access denied");
|
|
|
+ err['status'] = 403;
|
|
|
+ next(err);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ next();
|
|
|
+});
|
|
|
+
|
|
|
+// Annonymous pages
|
|
|
app.use('/', route_index);
|
|
|
+app.use('/login', route_login);
|
|
|
|
|
|
-// catch 404 and forward to error handler
|
|
|
+// Login check
|
|
|
app.use((req, res, next) => {
|
|
|
+ if (!req.mSession.IsValid()) {
|
|
|
+ const URL = '/login?redirect=' + encodeURIComponent(req.url);
|
|
|
+ res.status(302);
|
|
|
+ res.setHeader("Location", URL);
|
|
|
+ res.send("<!DOCTYPE html><html><body><a href='" + URL + "'>" + URL + "</a><script>document.location.href='" + URL + "';</script></html>");
|
|
|
+ } else {
|
|
|
+ next();
|
|
|
+ }
|
|
|
+});
|
|
|
+// Any following routes need login
|
|
|
+app.use('/logged', route_index);
|
|
|
+
|
|
|
+// catch 404 and forward to error handler
|
|
|
+app.use((_, __, next) => {
|
|
|
const err: any = new Error('Not Found');
|
|
|
err['status'] = 404;
|
|
|
next(err);
|
|
|
@@ -39,7 +104,7 @@ if (app.get('env') === 'development') {
|
|
|
|
|
|
// production error handler
|
|
|
// no stacktraces leaked to user
|
|
|
-app.use((err: any, req: any, res: any, next: any) => { // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
|
+app.use((err: any, _: any, res: any, __: any) => { // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
|
res.status(err.status || 500);
|
|
|
res.render('error', {
|
|
|
message: err.message,
|