| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- 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';
- const i18next = require('i18next'); // FIXME import from
- const i18nextMiddleware = require('i18next-http-middleware'); // FIXME import from
- const resourcesToBackend = require('i18next-resources-to-backend'); // FIXME import from
- import route_index from './routes/index';
- import route_login from './routes/login';
- import route_calendar from './routes/calendar';
- import route_trombinoscope from './routes/trombinoscope';
- import route_accounting from './routes/accounting';
- import Security from './src/Security';
- import { Session, SessionManager } from './src/Session';
- import UserConnectorFactory, { IUserConnector } from './src/UserConnector/UserConnectorFactory';
- import DBConnectorFactory from './src/DbConnector/DBConnectorFactory';
- const debug = require('debug')('my express app');
- const app = express();
- declare global {
- namespace Express {
- interface Request {
- mSession: Session
- mCookies: Map<string, string>
- t: (s: string, opts: any|undefined) => string // i18n translation function
- }
- interface Response {
- i18next: any
- renderWithTranslations: (translationNs: string, renderView: string, args: any) => Promise<void>
- }
- }
- }
- function translate(t: any, ns: string, str: string, args: any | undefined = undefined) {
- args = args || {};
- args.ns = args.ns || ns;
- return t(str, args);
- }
- // Check config
- (async _ => {
- await i18next.use(i18nextMiddleware.LanguageDetector)
- .use(resourcesToBackend((language: string, namespace: string, callback: Function) => {
- import(`./locales/${language}/${namespace}.json`)
- .then((resources) => {
- callback(null, resources)
- })
- .catch((error) => {
- callback(error, null)
- })
- }))
- .init({
- preload: ['fr', 'en'],
- nonExplicitSupportedLngs: true,
- lowerCaseLng: true
- });
- let cc: AConfigChecker[] = [
- UserConnectorFactory,
- await DBConnectorFactory.GetConnector()
- ];
- for (let i of cc) {
- let err: Promise<void> | Error | null = i.CheckConfig();
- let errResult: Error | null = null;
- try {
- if (err instanceof Promise)
- await err;
- else
- errResult = err;
- }
- catch (_err) {
- errResult = _err;
- }
- if (errResult !== null) {
- console.error("Configuration error: " + i.constructor.name +": "+ errResult.message);
- throw "Configuration error";
- }
- }
- // view engine setup
- app.set('views', [path.join(__dirname, 'views'), path.join(__dirname, 'views/template')]);
- app.set('view engine', 'pug');
- app.use(express.static(path.join(__dirname, 'public')));
- app.use(bodyParser.json());
- app.use(bodyParser.urlencoded({ extended: true }));
- app.use(i18nextMiddleware.handle(i18next, {
- ignoreRoutes: [] // or function(req, res, options, i18next) { /* return true to ignore */ }
- }));
- // Security and session setup
- app.use((req: express.Request, res: express.Response, next) => {
- res.i18next = i18next;
- res.renderWithTranslations = async (defaultNs: string, renderView: string, args: any) => {
- await i18next.loadNamespaces(defaultNs);
- args = args || {};
- args["t"] = (a1: string, a2: any | undefined, a3: any | undefined): string => {
- if (a3)
- return translate(req.t, a1, a2, a3);
- if (a2) {
- if (typeof a2 === 'string')
- return translate(req.t, a1, a2);
- else
- return translate(req.t, defaultNs, a1, a2);
- }
- return req.t(a1, { ns: defaultNs });
- };
- res.render(renderView, args);
- };
- req.mCookies = new Map();
- (req.headers?.cookie || "").split(";").filter(i => i.length).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"]) {
- Security.TryLoginApiKey(req.query["API_KEY"].toString()).then(user => {
- req.mSession.Login(user);
- })
- .catch(e => {
- let err: any = new Error("Access denied");
- err['status'] = 403;
- next(err);
- return;
- });
- }
- next();
- });
- let HasAccount = await UserConnectorFactory.GetConnector().HasUsers();
- // Anonymous pages
- !HasAccount && app.use(async (req, res, next) => {
- HasAccount = HasAccount || await UserConnectorFactory.GetConnector().HasUsers();
- if (HasAccount) {
- next();
- return;
- }
- let connector: IUserConnector = UserConnectorFactory.GetConnector();
- if (!connector.CanCreateAccount()) {
- res.end("No account defined, and cannot create account from Connector Backend");
- return;
- }
- if (req.method.toUpperCase() === "POST" && (req.body["username"] || "").trim().length && (req.body["password"] || "").trim().length) {
- let user = await connector.CreateAccount(req.body["username"].trim(), req.body["password"].trim());
- req.mSession.Login(user);
- HasAccount = true;
- SessionManager.Write(res, req.mSession);
- res.redirect(302, "/");
- return;
- }
- if (req.method.toUpperCase() === "GET") {
- res.render('setup_user');
- }
- });
- app.use('/', route_index);
- app.use('/login', route_login);
- // Login check
- app.use((req, res, next) => {
- if (!req.mSession.IsValid())
- res.redirect(302, '/login?redirect=' + encodeURIComponent(req.url));
- else
- next();
- });
- // Any following routes need login
- app.use('/calendar', route_calendar);
- app.use('/trombinoscope', route_trombinoscope);
- app.use('/accounting', route_accounting);
- // catch 404 and forward to error handler
- app.use((_, __, next) => {
- const err: any = new Error('Not Found');
- err['status'] = 404;
- next(err);
- });
- // error handlers
- // development error handler
- // will print stacktrace
- if (app.get('env') === 'development') {
- app.use((err: any, req: Express.Request, res: any, next: any) => { // eslint-disable-line @typescript-eslint/no-unused-vars
- err && console.error(err);
- res.status(err['status'] || 500);
- res.render('error', {
- message: err.message,
- error: err
- });
- });
- }
- // production error handler
- // no stacktraces leaked to user
- app.use((err: any, _: any, res: any, __: any) => { // eslint-disable-line @typescript-eslint/no-unused-vars
- err && console.error(err);
- res.status(err.status || 500);
- res.render('error', {
- message: err.message,
- error: {}
- });
- });
- app.set('port', process.env.port || 1337);
- const server = app.listen(app.get('port'), function () {
- debug(`Express server listening on port ${(server.address() as AddressInfo).port}`);
- });
- })();
|