ckn.systems.backend
Version:
CKN Systems Package for Backend
256 lines (238 loc) • 10.5 kB
JavaScript
const fs = require('fs');
const http = require('http');
const https = require('https');
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const ejs = require('ejs');
const ckn = require("ckn.systems");
var CryptoJS = require("crypto-js");
ckn.initialBackend(exports);
exports.getTheme = (themeName) => {
return require("./themes/" + themeName);
}
exports.server = express();
exports.configuration = require("./ckn.systems.backend.configuration");
exports.models = {};
exports.views = [path.join(exports.configuration.themeFolder + "/templates")];
exports.apps = [];
exports.themes = [];
const checkParameters = () => {
exports.CKN_ENVIRIONMENT_PRODUCTION = "CKN.ENVIRONMENT.PRODUCTION";
exports.CKN_ENVIRIONMENT_DEVELOPMENT = "CKN.ENVIRONMENT.DEVELOPMENT";
exports.mode = exports.CKN_ENVIRIONMENT_PRODUCTION;
process.argv.forEach(arg => {
if (arg.toLocaleLowerCase() == "dev") {
exports.mode = exports.CKN_ENVIRIONMENT_DEVELOPMENT;
}
});
if (exports.mode == exports.CKN_ENVIRIONMENT_PRODUCTION) {
exports.log.info("Mode is Production.");
}
else {
exports.log.info("Mode is Developement.");
}
}
const intialApps = () => {
exports.log.info("Start to intial applications.");
exports.server.use("/", express.static("public"));
exports.apps.forEach(app => {
var appName = app.name;
exports.models[appName] = {};
exports.log.info("Intial \"" + appName + "\" application.");
app.physicalPath = exports.configuration.appFolder + "/" + appName + "/";
app.startups = require(app.physicalPath + "startup.js");
app.startups.initial(app);
if (app.url == null) {
app.url = "";
app.rootURL = "";
}
if (app.url != "") {
app.url = app.url + "/";
app.rootURL = "../";
}
// Setup application properties
// Initial Static Public Folder
const publicFolder = app.physicalPath + "public";
exports.server.use("/" + appName, express.static(publicFolder));
// Initial Models
const modelFolder = path.join(app.physicalPath + "models");
fs.readdir(modelFolder, (err, files) => {
files.forEach(modelFile => {
exports.log.info("Loading models");
var model = require(modelFolder + "/" + modelFile);
exports.mergeObject(model, exports.models[appName]);
});
});
// Initial Views
const viewFolder = path.join(app.physicalPath + "views");
exports.views.push(viewFolder);
if (app.views != null) app.views.forEach(v => {
var _viewFolder = path.join(app.physicalPath + "views/" + v);
exports.views.push(_viewFolder);
});
// Initial Controllers
const controllers = ["controllers", "apis"];
controllers.forEach(controller => {
const controllerFolder = path.join(app.physicalPath + controller);
fs.readdir(controllerFolder, (err, files) => {
files.forEach(controllerFile => {
var controller = require(controllerFolder + "/" + controllerFile);
var controllerFileNameNoJS = controllerFile.slice(0, controllerFile.length - 3).toLocaleLowerCase(); // Remove .js
exports.log.info("Loading controllers from " + controllerFileNameNoJS);
// Set Default values for controller
if (controller.url == null) controller.url = (controllerFileNameNoJS == "default" ? "" : "" + controllerFileNameNoJS);
if (controller.method == null) controller.method = "GET";
// Setup controller properties
controller.physicalPath = controllerFolder + "/" + controllerFile;
controller.url = app.url + controller.url;
exports.log.info("Controller URL is " + controller.url)
function processSession(app, controller, req, res) {
var session = {};
session.url = controller.url;
session.request = req;
session.response = res;
session.ckn = exports;
session.application = app;
session.controller = controller;
session.configuration = exports.configuration;
session.scripts = [];
session.styles = [];
session = initialSession(session);
controller.process(session);
}
if (controller.method.toUpperCase() == "GET") {
exports.server.get("/" + controller.url, (req, res) => {
processSession(app, controller, req, res);
});
} else if (controller.method.toUpperCase() == "POST") {
exports.server.post("/" + controller.url, (req, res) => {
processSession(app, controller, req, res);
});
} else if (controller.method.toUpperCase() == "PUT") {
exports.server.put("/" + controller.url, (req, res) => {
processSession(app, controller, req, res);
});
}
});
});
});
});
}
const initialSession = (_session) => {
_session.send = (data) => {
_session.response.send(data);
};
_session.render = (theme) => {
theme.prepare(_session);
_session.rootPath = "";
var n = (_session.url.match(/\//g) || []).length;
exports.loop(n, i => {
_session.rootPath += "../";
});
_session.response.render(theme.template, _session);
};
_session.cookies = {
set: (key, value) => {
const oneDayToSeconds = 24 * 60 * 60;
_session.response.cookie(key, value,
{
maxAge: oneDayToSeconds,
// You can't access these tokens in the client's javascript
httpOnly: true,
// Forces to use https in production
secure: process.env.NODE_ENV === 'production' ? true : false
}
);
},
get: (key) => {
// We extract the raw cookies from the request headers
var rawCookies = _session.request.headers.cookie;
if (rawCookies != null) {
rawCookies = rawCookies.split('; ');
// rawCookies = ['myapp=secretcookie, 'analytics_cookie=beacon;']
const parsedCookies = {};
rawCookies.forEach(rawCookie => {
const parsedCookie = rawCookie.split('=');
// parsedCookie = ['myapp', 'secretcookie'], ['analytics_cookie', 'beacon']
parsedCookies[parsedCookie[0]] = parsedCookie[1];
});
return parsedCookies[key];
}
return null;
}
}
_session.authenticated = (authURL) => {
var auth = _session.cookies.get("CKN.AUTHENTICATION.TOKEN") != null;
if (!auth) {
if (authURL != null) {
_session.response.redirect(authURL);
}
}
if (auth) return _session.cookies.get("CKN.AUTHENTICATION.TOKEN");
else return null;
}
_session.authenticate = (info) => {
var key = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for (var i = 0; i < 125; i++) {
key += characters.charAt(Math.floor(Math.random() *
charactersLength));
}
var ciphertext = CryptoJS.AES.encrypt(JSON.stringify(info), key + "CKN").toString();
_session.cookies.set("CKN.AUTHENTICATION", ciphertext);
_session.cookies.set("CKN.AUTHENTICATION.TOKEN", key);
return key;
}
_session.authenticatedInfo = () => {
if (_session.cookies.get("CKN.AUTHENTICATION.TOKEN") == null) return null;
var key = _session.cookies.get("CKN.AUTHENTICATION.TOKEN").toString();
var ciphertext = _session.cookies.get("CKN.AUTHENTICATION").toString();
ciphertext = decodeURIComponent(ciphertext);
var originalText = CryptoJS.AES.decrypt(ciphertext, key + "CKN");
originalText = originalText.toString(CryptoJS.enc.Utf8);
return JSON.parse(originalText);
};
return _session;
}
const InitialBackendServer = () => {
// Configure server to support JSON
exports.server.use(bodyParser.json());
// Configure EJS View Engine
exports.server.set('view engine', 'ejs');
// Configure EJS View Folders
exports.server.set('views', exports.views);
// Start to listen
exports.server.listen(exports.configuration.server.port, () => {
exports.log.info('Listening at http://127.0.0.1:' + exports.configuration.server.port);
});
}
exports.start = () => {
// Load Themes
const themeFolder = path.join(exports.configuration.themeFolder);
fs.readdir(themeFolder, (err, files) => {
files.forEach(file => {
if (file.toLowerCase().endsWith(".js")) {
var theme = require(themeFolder + "/" + file);
theme.initial();
exports.themes[theme.name] = theme;
}
});
});
const appFolder = path.join(exports.configuration.appFolder);
fs.readdir(appFolder, (err, files) => {
files.forEach(file => {
if (!file.toLowerCase().includes(".")) {
exports.log.info("Load App " + file);
exports.apps.push({ name: file });
}
});
/* Check Evironment */
checkParameters();
/* Intial Applications */
intialApps();
/* Intial Backend Server */
InitialBackendServer();
});
}