Reviewed-on: #12
This commit is contained in:
Fred Boniface 2023-05-06 21:54:49 +01:00
parent fe9eeae7db
commit 7da713526f
46 changed files with 3166 additions and 2622 deletions

View File

@ -8,4 +8,6 @@ db-manager
run.sh run.sh
LICENSE LICENSE
*.md *.md
static .eslintrc.js
.vscode
.test-tools

31
.eslintrc.js Normal file
View File

@ -0,0 +1,31 @@
module.exports = {
'env': {
'browser': true,
'commonjs': true,
'es2021': true
},
'extends': 'eslint:recommended',
'overrides': [
],
'parserOptions': {
'ecmaVersion': 'latest'
},
'rules': {
'indent': [
'error',
2
],
'linebreak-style': [
'error',
'unix'
],
'quotes': [
'error',
'single'
],
'semi': [
'error',
'always'
]
}
};

17
.vscode/settings.json vendored
View File

@ -1,7 +1,14 @@
{ {
"git.autofetch": "all", "git.autofetch": "all",
"git.alwaysSignOff": true, "git.alwaysSignOff": true,
"git.enableCommitSigning": false, "git.enableCommitSigning": false,
"git.fetchOnPull": true, "git.fetchOnPull": true,
"git.pullBeforeCheckout": true "git.pullBeforeCheckout": true,
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint",
"editor.formatOnPaste": false, // required
"editor.formatOnType": false, // required
"editor.formatOnSave": true, // optional
"editor.formatOnSaveMode": "file", // required to format on save
"files.autoSave": "onFocusChange", // optional but recommended
"vs-code-prettier-eslint.prettierLast": "false" // set as "true" to run 'prettier' last not first
} }

View File

@ -1,3 +1,4 @@
# What to do next: # What to do next:
* Rewrite sanitizing functions to remove external dependancy. * Rewrite sanitizing functions to remove external dependancy.
* Change /api/v1/auth endpoints to /api/v1/register endpoints - auth is done in middleware

85
app.js
View File

@ -4,38 +4,55 @@
// licensed separately, each folder contains a license file where a // licensed separately, each folder contains a license file where a
// different license applies. // different license applies.
console.log(`Initialising OwlBoard`) /* global process */
console.log('Initialising OwlBoard');
const mode = process.env.NODE_ENV || 'development';
// External Requires // External Requires
const express = require('express'); const express = require('express');
const app = express(); const app = express();
const compression = require('compression')
// Middleware
const compression = require('compression');
const rateLimit = require('express-rate-limit');
const authenticate= require('./src/middlewares/auth.middlewares');
// Internal Requires // Internal Requires
const log = require('./src/utils/log.utils'); // Log Helper const log = require('./src/utils/log.utils'); // Log Helper
const version = require('./src/configs/version.configs'); // Version Strings const version = require('./src/configs/version.configs'); // Version Strings
const listRtr = require('./src/routes/list.routes'); // /list endpoints const listRtr = require('./src/routes/list.routes'); // /list endpoints
const ldbRtr = require('./src/routes/ldb.routes'); // /ldb endpoints const ldbRtr = require('./src/routes/ldb.routes'); // /ldb endpoints
const kubeRtr = require('./src/routes/kube.routes'); // /kube endpoints const kubeRtr = require('./src/routes/kube.routes'); // /kube endpoints
const findRtr = require('./src/routes/find.routes'); // /find endpoints const findRtr = require('./src/routes/find.routes'); // /find endpoints
const issueRtr = require('./src/routes/issue.routes') // /issue endpoints const issueRtr = require('./src/routes/issue.routes'); // /issue endpoints
const statRtr = require('./src/routes/stats.routes'); // /stat endpoints const statRtr = require('./src/routes/stats.routes'); // /stat endpoints
const regRtr = require('./src/routes/registration.routes'); // /registration endpoints
const pisRtr = require('./src/routes/pis.routes'); // /pis endpoints
// Set Server Configurations // Set Server Configurations
const srvListen = process.env.OWL_SRV_LISTEN || "0.0.0.0" const srvListen = process.env.OWL_SRV_LISTEN || '0.0.0.0';
const srvPort = process.env.OWL_SRV_PORT || 8460 const srvPort = process.env.OWL_SRV_PORT || 8460;
const limiter = rateLimit({
windowMs: 15 * (60 * 1000), // 15 minutes
max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes)
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: true, // Disable the `X-RateLimit-*` headers
});
// Print version number: // Print version number:
log.out(`app: Starting OwlBoard - Backend Version: ${version.app} - API versions: ${version.api}`, "init"); log.out(`app: Starting OwlBoard in ${mode} mode`, 'init');
log.out(`app: Starting OwlBoard - Backend Version: ${version.app} - API versions: ${version.api}`, 'init');
// Test for required vars: // Test for required vars:
// const varTest = require('./src/utils/varTest.utils'); // const varTest = require('./src/utils/varTest.utils');
// var startTest = await varTest.varTest(); // var startTest = await varTest.varTest();
//console.log("Required Vars Missing:", startTest.missing_required); //console.log("Required Vars Missing:", startTest.missing_required);
//console.log("Desired Vars Missing:", startTest.missing_desired); //console.log("Desired Vars Missing:", startTest.missing_desired);
// if startTest.pass == false // if startTest.pass == false
// console.log("Unable to start, missing required vars") // console.log("Unable to start, missing required vars")
// exit app // exit app
// Express Error Handling: // Express Error Handling:
app.use((err, req, res, next) => { app.use((err, req, res, next) => {
@ -45,25 +62,37 @@ app.use((err, req, res, next) => {
return; return;
}); });
// Express Submodules: // Global Middleware:
app.use(express.json()); //JSON Parsing for POST Requests app.use(express.json()); //JSON Parsing for POST Requests
//STATIC CONTENT NO LONGER SERVED FROM NODE app.use(compression()); // Compress API Data if supported by client
app.use(compression()) // Compress API Data if supported by client app.use(limiter);
// Express Routes // Unauthenticated Routes
app.use('/api/v1/list', listRtr); app.use('/api/v1/list', listRtr);
app.use('/api/v1/ldb', ldbRtr); app.use('/api/v1/ldb', ldbRtr);
app.use('/api/v1/kube', kubeRtr); app.use('/api/v1/kube', kubeRtr);
app.use('/api/v1/find', findRtr); app.use('/api/v1/find', findRtr);
app.use('/api/v1/issue', issueRtr); app.use('/api/v1/issue', issueRtr);
app.use('/api/v1/stats', statRtr) app.use('/api/v1/stats', statRtr);
app.use('/api/v1/register', regRtr);
// Authented Routes
app.use('/api/v1/ldbs', authenticate, (req, res) => res.status(501).json({status: 'Not Implemented', message: 'This feature is not yet implemented due to upstream issues'}));
app.use('/api/v1/pis', authenticate, pisRtr);
app.use('/api/v1/auth/test', authenticate, (req, res) => res.status(200).json({status: 'ok', message: 'Authentication successful'})); // Returns 401 if auth failed, 200 if successful.
// Number of proxies:
app.set('trust proxy', 4);
mode === 'development'
? app.get('/api/v1/ip', (req, res) => res.send(req.ip))
: null;
// Start Express // Start Express
app.listen(srvPort, srvListen, (error) =>{ app.listen(srvPort, srvListen, (error) =>{
if(!error) { if(!error) {
log.out(`app.listen: Listening on http://${srvListen}:${srvPort}`, "init"); log.out(`app.listen: Listening on http://${srvListen}:${srvPort}`, 'init');
log.out("app.listen: State - alive", "init") log.out('app.listen: State - alive', 'init');
} else { } else {
log.out(`app.listen: Error occurred, server can't start ${error}`, "err"); log.out(`app.listen: Error occurred, server can't start ${error}`, 'err');
} }
}); });

View File

@ -0,0 +1,70 @@
<html lang="en">
<head>
<title>OwlBoard - Register</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html {
background-color:#404c55;
background-image:radial-gradient(#2b343c,#404c55);
text-align: center;
width: 100%;
}
a {
color:azure;
}
table {
width: 100%;
color: azure;
font-family: sans-serif;
text-align: center;
}
#title {
height: 100px;
padding-top: 0px;
margin-top: 0px;
}
h1 {
color: #00b7b7;
}
#button {
color: azure;
font-size: larger;
background-color: #007979;
padding: 8px;
padding-left: 12px;
padding-right: 12px;
text-decoration: none;
border-radius: 14px;
}
</style>
</head>
<body>
<br><br>
<table>
<tr>
<td>
<img src="https://owlboard.info/images/logo/wide_logo.svg" id="title">
</td>
</tr>
<tr>
<td>
<h1>Register for OwlBoard</h1>
<br>
<p>Use the link below to register for OwlBoard (Staff Version)</p>
<br>
<a href="https://owlboard.info/auth.html?key=>>ACCESSCODE<<" id="button">Register</a>
<br><br><br>
<p>Alternatively copy and paste the link:<br>https://owlboard.info/auth.html?key=>>ACCESSCODE<<</p>
<p>This registration is for one device only, you can register again using the
same email address for other devices and access OwlBoard from elsewhere.
</p>
<p>If you did not request to sign up to OwlBoard (Staff Version), you can
safely ignore this email. Your email address has not been stored by us.
</p>
<p>The registration link will expire after 30 minutes.</p>
</td>
</tr>
</table>
<br>
</body>
</html>

View File

@ -0,0 +1,10 @@
Complete your OwlBoard (Staff) Registration using the link below.
https://owlboard.info/auth.html?key=>>ACCESSCODE<<
Alternatively you can copy and paste the above link.
If you did not request to register to OwlBoard then you can safely ignore this email.
Your email address has not been stored by us and will not be required unless you wish to register again.
The link will expire after 30 minutes.

4334
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,22 +3,30 @@
"axios": "^1.2.1", "axios": "^1.2.1",
"compression": "^1.7.4", "compression": "^1.7.4",
"express": "^4.18.2", "express": "^4.18.2",
"express-rate-limit": "^6.7.0",
"html-minifier": "^4.0.0",
"juice": "^9.0.0",
"ldbs-json": "^1.2.1", "ldbs-json": "^1.2.1",
"mongodb": "^4.13.0", "mongodb": "^4.13.0",
"string-sanitizer-fix": "^2.0.1" "nodemailer": "^6.9.1"
}, },
"name": "owlboard", "name": "owlboard",
"description": "OwlBoard is an API and PWA for live rail departure board in the UK.", "description": "OwlBoard is an API and PWA for live rail departure board in the UK.",
"version": "0.0.1", "version": "1.2.0-dev",
"main": "express.js", "main": "express.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"start": "node app.js" "start": "node app.js",
"run": "node app.js"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://git.fjla.uk/fred.boniface/owlboard.git" "url": "https://git.fjla.uk/owlboard/backend.git"
}, },
"author": "Fred Boniface", "author": "Fred Boniface",
"license": "GPL-3.0-or-later" "license": "GPL-3.0-or-later",
"devDependencies": {
"eslint": "^8.39.0",
"prettier": "^2.8.8"
}
} }

View File

@ -1,10 +1,36 @@
module.exports = valid
const valid = [ const valid = [
"owlboard.info", 'owlboard.info',
"fjla.uk", 'avantiwestcoast.co.uk',
"gwr.com", 'btp.police.uk',
"swrailway.com", 'c2crail.net',
"firstrail.com", 'chilternrailways.co.uk',
"networkrail.co.uk" 'crosscountrytrains.co.uk',
] 'eastmidlandsrailway.co.uk',
'abellio.co.uk',
'tfl.gov.uk',
'mtrel.co.uk',
'eurostar.com',
'eurotunnel.com',
'ffwhr.com',
'gwr.com',
'hitachirail-eu.com',
'greateranglia.co.uk',
'heathrow.com',
'swrailway.com',
'lsltoc.co.uk',
'lner.co.uk',
'arrivarl.co.uk',
'tube.tfl.gov.uk',
'lumo.co.uk',
'merseyrail.org',
'nrcommcentre.com',
'networkrail.co.uk',
'northernrailway.co.uk',
'scotrail.co.uk',
'southeasternrailway.co.uk',
'tpeexpress.co.uk',
'tfwrail.wales',
'wmtrains.co.uk',
];
module.exports = valid;

View File

@ -0,0 +1,12 @@
const statusCodes = {
700: 'no authentication attempt',
701: 'invalid credentials',
702: 'domain not whitelisted',
703: 'registration request not found, maybe expired',
800: 'location code not found',
801: 'unable to fetch location data',
900: 'invalid request format',
950: 'upstream server error',
};
module.exports = statusCodes;

View File

@ -1,6 +1,6 @@
const version = { const version = {
api: ["/api/v1/",], api: ['/api/v1/',],
app: "1.1.5" app: '2.0.0'
}; };
module.exports = version; module.exports = version;

View File

@ -1,58 +1,58 @@
const find = require('../services/find.services'); const find = require('../services/find.services');
async function findName(req, res, next){ async function findName(req, res, next){
try { try {
var id = req.params.id var id = req.params.id;
res.json(await find.name(id)) res.json(await find.name(id));
} catch (err) { } catch (err) {
console.error(`Unknown Error`, err.message); console.error('Unknown Error', err.message);
next(err); next(err);
} }
} }
async function findCrs(req, res, next){ async function findCrs(req, res, next){
try { try {
var id = req.params.id var id = req.params.id;
res.json(await find.crs(id)) res.json(await find.crs(id));
} catch (err) { } catch (err) {
console.error(`Unknown Error`, err.message); console.error('Unknown Error', err.message);
next(err); next(err);
} }
} }
async function findNlc(req, res, next){ async function findNlc(req, res, next){
try { try {
var id = req.params.id var id = req.params.id;
res.json(await find.nlc(id)) res.json(await find.nlc(id));
} catch (err) { } catch (err) {
console.error(`Unknown Error`, err.message); console.error('Unknown Error', err.message);
next(err); next(err);
} }
} }
async function findTiploc(req, res, next){ async function findTiploc(req, res, next){
try { try {
var id = req.params.id var id = req.params.id;
res.json(await find.tiploc(id)) res.json(await find.tiploc(id));
} catch (err) { } catch (err) {
console.error(`Unknown Error`, err.message); console.error('Unknown Error', err.message);
next(err); next(err);
} }
} }
async function findStanox(req, res, next){ async function findStanox(req, res, next){
try { try {
var id = req.params.id var id = req.params.id;
res.json(await find.stanox(id)) res.json(await find.stanox(id));
} catch (err) { } catch (err) {
console.error(`Unknown Error`, err.message); console.error('Unknown Error', err.message);
next(err); next(err);
} }
} }
module.exports = { module.exports = {
findName, findName,
findCrs, findCrs,
findNlc, findNlc,
findTiploc, findTiploc,
findStanox findStanox
} };

View File

@ -1,14 +1,14 @@
const issue = require('../services/issue.services'); const issue = require('../services/issue.services');
async function post(req, res, next){ async function post(req, res, next){
try { try {
res.json(await issue.processor(req.body)) res.json(await issue.processor(req.body));
} catch (err) { } catch (err) {
console.error(`Controller Error`, err.message); console.error('Controller Error', err.message);
next(err); next(err);
} }
} }
module.exports = { module.exports = {
post post
} };

View File

@ -1,34 +1,35 @@
const kube = require('../services/kube.services'); const kube = require('../services/kube.services');
async function getAlive(req, res, next){ async function getAlive(req, res, next){
try { try {
var state = kube.getAlive() var state = kube.getAlive();
res.status((await state).code).send((await state).state) res.status((await state).code).send((await state).state);
} catch (err) { } catch (err) {
res.status("503").send({state: "error"}) res.status('503').send({state: 'error'});
} }
} }
async function getReady(req, res, next){ async function getReady(req, res, next){
try { try {
res.json(await kube.getReady(req.body)) res.json(await kube.getReady(req.body));
} catch (err) { } catch (err) {
console.error(`Unknown Error`, err.message); console.error('Unknown Error', err.message);
next(err); next(err);
} }
} }
async function getTime(req, res, next){ async function getTime(req, res, next){
try { try {
res.json(await kube.getTime(req.body)) res.json(await kube.getTime(req.body));
} catch (err) { } catch (err) {
console.error(`Unknown Error`, err.message); console.error('Unknown Error', err.message);
next(err); err.status = 503;
} next(err);
}
} }
module.exports = { module.exports = {
getAlive, getAlive,
getReady, getReady,
getTime getTime
} };

View File

@ -1,15 +1,16 @@
const ldb = require('../services/ldb.services'); const ldb = require('../services/ldb.services');
async function get(req, res, next){ async function get(req, res, next){
try { try {
var id = req.params.id var id = req.params.id;
res.json(await ldb.get(req.body, id)) res.json(await ldb.get(id));
} catch (err) { } catch (err) {
console.error(`Unknown Error`, err.message); console.error('Unknown Error', err.message);
next(err); err.status = 500;
} next(err);
}
} }
module.exports = { module.exports = {
get get
} };

View File

@ -0,0 +1,16 @@
const ldb = require('../services/ldb.services');
async function get(req, res, next){
try {
var id = req.params.id;
res.json(await ldb.get(id, true));
} catch (err) {
console.error('Unknown Error', err.message);
err.status = 500;
next(err);
}
}
module.exports = {
get
};

View File

@ -1,34 +1,37 @@
const list = require('../services/list.services'); const list = require('../services/list.services');
async function getStations(req, res, next){ async function getStations(req, res, next){
try { try {
res.json(await list.getStations(req.body)) res.json(await list.getStations(req.body));
} catch (err) { } catch (err) {
console.error(`Controller Error`, err.message); console.error('Controller Error', err.message);
next(err); err.status = 500;
} next(err);
}
} }
async function getCorpus(req, res, next){ async function getCorpus(req, res, next){
try { try {
res.json(await list.getCorpus(req.body)) res.json(await list.getCorpus(req.body));
} catch (err) { } catch (err) {
console.error(`Controller Error`, err.message); console.error('Controller Error', err.message);
next(err); err.status = 500;
} next(err);
}
} }
async function hits(req, res, next) { async function hits(req, res, next) {
try { try {
res.json(await list.hits()) res.json(await list.hits());
} catch (err) { } catch (err) {
console.error(`Controller Error`, err); console.error('Controller Error', err);
next(err); err.status = 500;
} next(err);
}
} }
module.exports = { module.exports = {
getStations, getStations,
getCorpus, getCorpus,
hits hits
} };

View File

@ -0,0 +1,17 @@
const pis = require('../services/pis.services');
async function byOrigDest(req, res, next){
try {
let start = req.params.start;
let end = req.params.end;
res.json(await pis.findPisByOrigDest(start,end));
} catch (err) {
console.error('Unknown Error', err.message);
next(err);
}
}
module.exports = {
byOrigDest
};

View File

@ -0,0 +1,26 @@
const reg = require('../services/registration.services');
async function register(req, res, next) {
try {
let response = await reg.regUser(req.body);
res.status(response.status).json(response);
} catch (err) {
console.error('Controller Error', err.message);
next(err);
}
}
async function request(req, res, next) {
try {
let response = await reg.createRegKey(req.body);
res.status(response.status).json(response);
} catch (err) {
console.error(err);
next(err);
}
}
module.exports = {
register,
request
};

View File

@ -1,13 +1,15 @@
const stat = require('../services/stats.services'); const stat = require('../services/stats.services');
async function get(req, res, next) { async function get(req, res, next) {
try { try {
res.json(await stat.hits()) res.json(await stat.hits());
} catch (err) { } catch (err) {
console.error(`Controller Error`, err); console.error('Controller Error', err);
next(err); err.status = 500;
} next(err);
}
} }
module.exports = { module.exports = {
get} get
};

View File

@ -1,17 +0,0 @@
<html lang="en" style="background-color: grey; width: 100%;">
<head>
<title>OwlBoard - Register</title>
</head>
<body>
<table width="100%">
<tr>
<td>
<img src="https://owlboard.info/images/logo/wide_logo.svg" style="height: 100px">
</td>
<td>
<h1>Register for OwlBoard</h1>
</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1,27 @@
const utils = require('../utils/auth.utils');
const log = require('../utils/log.utils');
module.exports = async function authCheck(req, res, next) {
log.out('authMiddlewares: Checking authentication', 'dbug');
try {
var uuid = req.headers.uuid;
} catch(err) {
log.out('authMiddlewares: No authentication attempted', 'dbug');
err.status = 401;
return next(err);
}
try {
var result = await utils.isAuthed(uuid) || false;
if (!result) {
const err = new Error('Unauthorised');
err.status = 401;
log.out('authMiddlewares: Authentication attempted with incorrect key', 'warn');
return next(err);
} else {
log.out('authMiddlewares: User authenticated', 'dbug');
return next();
}
} catch(err) {
return next(err);
}
};

View File

@ -0,0 +1,12 @@
const log = require('../utils/log.utils');
module.exports = async function requireJson(req, res, next) {
if (req.headers['content-type'] !== 'application/json') {
log.out('requireJson.middlewares: Bad Request: Not in JSON format');
res.status(400).send({status: 400, message: 'Server requires JSON'});
} else {
next();
}
};
// Possibly want to check the req type?

View File

@ -6,4 +6,4 @@ router.get('/alive', kubeController.getAlive);
router.get('/ready', kubeController.getReady); router.get('/ready', kubeController.getReady);
router.get('/time', kubeController.getTime); router.get('/time', kubeController.getTime);
module.exports = router module.exports = router;

19
src/routes/ldbs.routes.js Normal file
View File

@ -0,0 +1,19 @@
const express = require('express');
const router = express.Router();
const ldbsController = require('../controllers/ldbs.controllers');
/* GET programming languages. */
//router.get('/', programmingLanguagesController.get);
/* POST programming language */
//router.post('/', programmingLanguagesController.create);
/* PUT programming language */
//router.put('/:id', programmingLanguagesController.update);
/* DELETE programming language */
//router.delete('/:id', programmingLanguagesController.remove);
router.get('/:id', ldbsController.get);
module.exports = router;

7
src/routes/pis.routes.js Normal file
View File

@ -0,0 +1,7 @@
const express = require('express');
const router = express.Router();
const pisController = require('../controllers/pis.controllers');
router.get('/origdest/:start/:end', pisController.byOrigDest);
module.exports = router;

View File

@ -0,0 +1,8 @@
const express = require('express');
const router = express.Router();
const regController = require('../controllers/registration.controllers');
router.post('/request', regController.request);
router.post('/register', regController.register);
module.exports = router;

View File

@ -1,10 +1,11 @@
const log = require('../utils/log.utils'); // Log Helper /* global process */
const log = require('../utils/log.utils'); // Log Helper
const dbUser = process.env.OWL_DB_USER || "owl" const dbUser = process.env.OWL_DB_USER || 'owl';
const dbPass = process.env.OWL_DB_PASS || "twittwoo" const dbPass = process.env.OWL_DB_PASS || 'twittwoo';
const dbName = process.env.OWL_DB_NAME || "owlboard" const dbName = process.env.OWL_DB_NAME || 'owlboard';
const dbPort = process.env.OWL_DB_PORT || 27017 const dbPort = process.env.OWL_DB_PORT || 27017;
const dbHost = process.env.OWL_DB_HOST || "localhost" const dbHost = process.env.OWL_DB_HOST || 'localhost';
const uri = `mongodb://${dbUser}:${dbPass}@${dbHost}:${dbPort}`; const uri = `mongodb://${dbUser}:${dbPass}@${dbHost}:${dbPort}`;
const { MongoClient } = require('mongodb'); const { MongoClient } = require('mongodb');
@ -13,27 +14,70 @@ const client = new MongoClient(uri);
const db = client.db(dbName); const db = client.db(dbName);
async function query(collection, query){ async function query(collection, query){
await client.connect(); await client.connect();
log.out(`dbAccess.query: Connecting to collection: '${collection}'`, "info") log.out(`dbAccess.query: Connecting to collection: '${collection}'`, 'info');
var qcoll = db.collection(collection); var qcoll = db.collection(collection);
var qcursor = qcoll.find(query) var qcursor = qcoll.find(query);
qcursor.project({_id: 0}) qcursor.project({_id: 0});
log.out(`dbAccess.query: Running Query: ${JSON.stringify(query)}`, "info") log.out(`dbAccess.query: Running Query: ${JSON.stringify(query)}`, 'info');
increment(collection) increment(collection);
return (await qcursor.toArray()); return (await qcursor.toArray());
} }
async function increment(target) { async function increment(target) {
log.out(`dbAccess.increment: Incrementing counter for: ${target}`, "info") log.out(`dbAccess.increment: Incrementing counter for: ${target}`, 'info');
await client.connect(); await client.connect();
let col = db.collection("meta"); let col = db.collection('meta');
let update = {} let update = {};
update[target] = 1 update[target] = 1;
col.updateOne({target: "counters"}, {$inc:update}) col.updateOne({target: 'counters'}, {$inc:update});
return; }
async function addUser(uuid, domain) { // Needs testing
log.out('dbAccess.addUser: Adding user to database');
let doc = {uuid: uuid, domain: domain, atime: new Date};
await client.connect();
let col = db.collection('users');
let res = await col.insertOne(doc);
if (res.insertedId) {
return true;
}
return false;
}
async function addRegReq(uuid, domain) { // Needs testing
log.out('dbAccess.addRegReq: Adding registration request');
let doc = {uuid: uuid, time: new Date, domain: domain};
await client.connect();
let col = db.collection('registrations');
let res = col.insertOne(doc);
return res;
}
async function userAtime(uuid) { // Needs testing
log.out('dbAccess.userAtime: Updating access time for user');
let q = {uuid: uuid};
let n = {$set: {uuid: uuid, atime: new Date}};
await client.connect();
let col = db.collection('users');
let res = col.updateOne(q, n, {upsert: true});
return res;
}
// Deletes one single registration request entry from the DB
async function delRegReq(uuid) {
log.out('dbAccess.delRegReq: Deleting a Registration Request');
let collection = 'registrations';
await client.connect();
let col = db.collection(collection);
col.deleteOne({uuid: uuid});
} }
module.exports = { module.exports = {
query, query,
increment increment, // Probqbly doesn't need exporting? - It does, ldbServices needs to increment when the API is hit!
} addUser,
userAtime,
addRegReq,
delRegReq
};

View File

@ -2,58 +2,58 @@
const log = require('../utils/log.utils'); // Log Helper const log = require('../utils/log.utils'); // Log Helper
const db = require('../services/dbAccess.services'); const db = require('../services/dbAccess.services');
const san = require('../utils/sanitizer.utils') const san = require('../utils/sanitizer.utils');
// DB Query: query(collection, query) // DB Query: query(collection, query)
// Define collection as all queries are for the "corpus" collection. // Define collection as all queries are for the "corpus" collection.
const col = "corpus" const col = 'corpus';
async function name(id){ async function name(id){
log.out(`findServices.name: Finding station name: ${id}`, "info") log.out(`findServices.name: Finding station name: ${id}`, 'info');
var name = san.cleanApiEndpointTxt(id.toUpperCase()) var name = san.cleanApiEndpointTxt(id.toUpperCase());
query = {NLCDESC: name} let query = {NLCDESC: name};
//var data = await db.query(col,query) //var data = await db.query(col,query)
return await db.query(col,query) return await db.query(col,query);
} }
async function crs(id){ async function crs(id){
log.out(`findServices.crs: Finding crs: ${id}`, "info") log.out(`findServices.crs: Finding crs: ${id}`, 'info');
var crs = san.cleanApiEndpointTxt(id.toUpperCase()) var crs = san.cleanApiEndpointTxt(id.toUpperCase());
query = {'3ALPHA': crs} let query = {'3ALPHA': crs};
//var data = await db.query(col,query) //var data = await db.query(col,query)
return await db.query(col,query) return await db.query(col,query);
} }
async function nlc(id){ async function nlc(id){
log.out(`findServices.nlc: Finding nlc: ${id}`, "info") log.out(`findServices.nlc: Finding nlc: ${id}`, 'info');
var nlc = san.cleanApiEndpointNum(id) var nlc = san.cleanApiEndpointNum(id);
query = {NLC: parseInt(nlc)} let query = {NLC: parseInt(nlc)};
log.out(`findServices.nlc: NLC Converted to int: ${query}`, "info") log.out(`findServices.nlc: NLC Converted to int: ${query}`, 'info');
//var data = await db.query(col,query) //var data = await db.query(col,query)
return await db.query(col,query) return await db.query(col,query);
} }
async function tiploc(id){ async function tiploc(id){
log.out(`findServices.tiploc: Finding tiploc: ${id}`, "info") log.out(`findServices.tiploc: Finding tiploc: ${id}`, 'info');
var tiploc = san.cleanApiEndpointTxt(id.toUpperCase()) var tiploc = san.cleanApiEndpointTxt(id.toUpperCase());
query = {TIPLOC: tiploc} let query = {TIPLOC: tiploc};
//var data = await db.query(col,query) //var data = await db.query(col,query)
return await db.query(col,query) return await db.query(col,query);
} }
async function stanox(id){ async function stanox(id){
log.out(`findServices.stanox: Finding stanox: ${id}`, "info") log.out(`findServices.stanox: Finding stanox: ${id}`, 'info');
var stanox = san.cleanApiEndpointNum(id) var stanox = san.cleanApiEndpointNum(id);
query = {STANOX: String(stanox)} let query = {STANOX: String(stanox)};
//var data = await db.query(col,query) //var data = await db.query(col,query)
return await db.query(col,query) return await db.query(col,query);
} }
module.exports = { module.exports = {
name, name,
crs, crs,
nlc, nlc,
tiploc, tiploc,
stanox stanox
} };

View File

@ -1,33 +1,35 @@
const axios = require('axios') /* eslint-disable no-useless-escape */
const log = require('../utils/log.utils') /* global process */
const axios = require('axios');
const log = require('../utils/log.utils');
async function processor(data) { async function processor(data) {
log.out(`issueService.processor: Issue received`, "info") log.out('issueService.processor: Issue received', 'info');
let out = {} let out = {};
out.title = data.subject.replace(/<[^>]+>|[\*\$]/g, ''); out.title = data.subject.replace(/<[^>]+>|[\*\$]/g, '');
out.body = data.msg.replace(/<[^>]+>|[\*\$]/g, '') out.body = data.msg.replace(/<[^>]+>|[\*\$]/g, '');
return await sendToGitea(out); return await sendToGitea(out);
} }
async function sendToGitea(body) { async function sendToGitea(body) {
let key = process.env.OWL_GIT_ISSUEBOT let key = process.env.OWL_GIT_ISSUEBOT;
let url = process.env.OWL_GIT_APIENDPOINT let url = process.env.OWL_GIT_APIENDPOINT;
let opts = { let opts = {
headers: { headers: {
Authorization: key Authorization: key
}
}
var res = await axios.post(url, body, opts)
// Need to read the output from the POST and pass the result upwards to the client.
if (res.status == 201) {
log.out("issueService.sendToGitea: Issue sent to Gitea", "info")
return {status: res.status,message:"issue created"}
} else {
log.out(`issueService.sendToGitea: Failed to send issue to Gitea: ${res.body}`, "err")
return {status: res.status,message:"issue not created"}
} }
};
var res = await axios.post(url, body, opts);
// Need to read the output from the POST and pass the result upwards to the client.
if (res.status == 201) {
log.out('issueService.sendToGitea: Issue sent to Gitea', 'info');
return {status: res.status,message:'issue created'};
} else {
log.out(`issueService.sendToGitea: Failed to send issue to Gitea: ${res.body}`, 'err');
return {status: res.status,message:'issue not created'};
}
} }
module.exports = { module.exports = {
processor processor
} };

View File

@ -1,20 +1,28 @@
const testing = require('../services/mail.services');
const log = require('../utils/log.utils');
async function getAlive(){ async function getAlive(){
log.out(`kubeServices.getAlive: alive hook checked`, "info") log.out('kubeServices.getAlive: alive hook checked', 'info');
return {code: 200, state: {state: "alive",noise: "twit-twoo"}} return {code: 200, state: {state: 'alive',noise: 'twit-twoo'}};
} }
async function getReady(){ async function getReady(){
log.out(`kubeServices.getReady: ready hook checked`, "info") log.out('kubeServices.getReady: ready hook checked', 'info');
return "not_implemented"; testing.send({
}; to: 'fred@fjla.uk',
subject: 'OwlBoard Test',
txt: 'This is a test message from OwlBoard (testing)'
});
return 'not_implemented';
}
async function getTime(){ async function getTime(){
var now = new Date() var now = new Date();
return {responseGenerated: now} return {responseGenerated: now};
} }
module.exports = { module.exports = {
getAlive, getAlive,
getReady, getReady,
getTime getTime
} };

View File

@ -1,46 +1,67 @@
/* global process */
// Parse and return an LDB Request // Parse and return an LDB Request
const log = require('../utils/log.utils'); // Log Helper const log = require('../utils/log.utils'); // Log Helper
const ldb = require('ldbs-json') const ldb = require('ldbs-json');
const util = require('../utils/ldb.utils') const util = require('../utils/ldb.utils');
const san = require('../utils/sanitizer.utils') const san = require('../utils/sanitizer.utils');
const db = require('../services/dbAccess.services') const db = require('../services/dbAccess.services');
const ldbKey = process.env.OWL_LDB_KEY const ldbKey = process.env.OWL_LDB_KEY;
const ldbsvKey = process.env.OWL_LDB_SVKEY const ldbsvKey = process.env.OWL_LDB_SVKEY;
async function get(body, id){ async function get(id, staff=false){
var cleanId = san.cleanApiEndpointTxt(id); const cleanId = san.cleanApiEndpointTxt(id);
var obj = await util.checkCrs(cleanId); const obj = await util.checkCrs(cleanId);
try { try {
var crs = obj[0]['3ALPHA']; const crs = obj[0]['3ALPHA'];
log.out(`ldbService.get: Determined CRS for lookup to be: ${crs}`, "info"); log.out(`ldbService.get: Determined CRS for lookup to be: ${crs}`, 'info');
var data = arrDepBoard(crs); if (staff) {
db.increment("ldbws"); const data = arrDepBoardStaff(crs);
await data; db.increment('ldbsvws');
} catch (err) { return await data;
log.out(`ldbService.get: Error, Unable to find CRS: ${err}`, "info") } else {
var data = {ERROR:'NOT_FOUND',description:'The entered station was not found. Please check and try again.'}; const data = arrDepBoard(crs);
db.increment('ldbws');
return await data;
} }
return data; } catch (err) {
log.out(`ldbService.get: Error, Unable to find CRS: ${err}`, 'info');
return {ERROR:'NOT_FOUND',description:'The entered station was not found. Please check and try again.'};
}
} }
async function arrDepBoard(CRS){ async function arrDepBoard(CRS){
log.out(`ldbService.arrDepBoard: Trying to fetch ArrDep Board for ${CRS}`, "info") log.out(`ldbService.arrDepBoard: Trying to fetch ArrDep Board for ${CRS}`, 'info');
try { try {
var options = { const options = {
numRows: 10, numRows: 10,
crs: CRS.toUpperCase() crs: CRS.toUpperCase()
} };
var api = new ldb(ldbKey,false) const api = new ldb(ldbKey,false);
var reply = api.call("GetArrDepBoardWithDetails", options, false, false) return await api.call('GetArrDepBoardWithDetails', options, false, false);
return await reply } catch (err) {
} catch (err) { log.out(`ldbService.arrDepBoard: Lookup Failed for: ${CRS}`, 'warn');
log.out(`ldbService.arrDepBoard: Lookup Failed for: ${CRS}`, "warn") return {GetStationBoardResult: 'not available', Reason: `The CRS code ${CRS} is not valid`, Why: 'Sometimes a station will have more than one CRS - for example Filton Abbey Wood has FIT and FAW however schedules are only available when looking up with FIT - this is how the National Rail Enquiries systems work.'};
return {GetStationBoardResult: "not available", Reason: `The CRS code ${CRS} is not valid`, Why: `Sometimes a station will have more than one CRS - for example Filton Abbey Wood has FIT and FAW however schedules are only available when looking up with FIT - this is how the National Rail Enquiries systems work.`}; }
} }
};
async function arrDepBoardStaff(CRS) {
log.out(`ldbService.arrDepBoardStaff: Trying to fetch ArrDep Board for ${CRS}`, 'dbug');
try {
const options = {
numRows: 25,
crs: CRS.toUpperCase(),
getNonPassengerServices: true
};
const api = new ldb(ldbsvKey,true);
return await api.call('GetArrDepBoardWithDetails', options, false, false);
} catch (err) {
log.out(`ldbService.arrDepBoardStaff: Lookup Failed for: ${CRS}, "warn`);
return {GetStationBoardResult: 'not available', Reason: `The CRS code ${CRS} is not valid`, Why: 'Sometimes a station will have more than one CRS - for example Filton Abbey Wood has FIT and FAW however schedules are only available when looking up with FIT - this is how the National Rail Enquiries systems work.'};
}
}
module.exports = { module.exports = {
get get
} };

View File

@ -1,20 +1,19 @@
const log = require('../utils/log.utils'); // Log Helper const log = require('../utils/log.utils'); // Log Helper
const db = require('../services/dbAccess.services') const db = require('../services/dbAccess.services');
const os = require('os')
async function getStations(){ async function getStations(){
var out = db.query("stations") var out = db.query('stations');
log.out(`listServices.getStations: Fetching stations list`, "info") log.out('listServices.getStations: Fetching stations list', 'info');
return await out; return await out;
} }
async function getCorpus(){ async function getCorpus(){
var out = db.query("corpus") var out = db.query('corpus');
log.out(`listServices.getCorpus: Fetching CORPUS list`, "info") log.out('listServices.getCorpus: Fetching CORPUS list', 'info');
return await out; return await out;
} }
module.exports = { module.exports = {
getStations, getStations,
getCorpus getCorpus
} };

View File

@ -1,7 +1,36 @@
const log = require('../utils/log.utils') /* global process */
const mail = require('some-mail-module') const log = require('../utils/log.utils');
const mail = require('nodemailer'); //>> Probs wrong
async function sendTest() { const fromAddr = process.env.OWL_EML_FROM;
// Send test mail message const smtpUser = process.env.OWL_EML_USER;
return; const smtpPass = process.env.OWL_EML_PASS;
const smtpHost = process.env.OWL_EML_HOST;
const smtpPort = process.env.OWL_EML_PORT;
let transporter = mail.createTransport({
host: smtpHost,
port: smtpPort,
secure: false, // Must be false for STARTTLS on port 587
auth: {
user: smtpUser,
pass: smtpPass
}
});
async function send(message){ // message is an object containing strings for: *to, cc, bcc, *subject, *txt, html (* denotes required)
log.out('mailServices.send: Message send request received', 'info');
message.from = fromAddr;
try {
var res = await transporter.sendMail(message);
} catch(err) {
log.out(`mailServices.send: Message send failed: ${err}`, 'err');
return false;
}
log.out(`mailServices.send: SMTP Response: ${res.response}`);
return true;
} }
module.exports = {
send
};

View File

@ -0,0 +1,34 @@
// Finds PIS Codes using DB Lookups
const db = require('../services/dbAccess.services');
const log = require('../utils/log.utils');
const clean = require('../utils/sanitizer.utils');
async function findPisByOrigDest(start,end) {
log.out(`pisServices.findPisByOrigDest: Searching for PIS for Orig: ${start}, Dest: ${end}`, 'dbug');
const firstCrs = clean.cleanApiEndpointTxt(start.toLowerCase());
const lastCrs = clean.cleanApiEndpointTxt(end.toLowerCase());
const query = {
stops: {
$all: [
{ $elemMatch: { $eq: firstCrs } },
{ $elemMatch: { $eq: lastCrs } }
]
},
$expr: {
$and: [
{ $eq: [{ $arrayElemAt: [ '$stops', -1 ] }, lastCrs] },
{ $eq: [{ $arrayElemAt: [ '$stops', 0 ] }, firstCrs] }
]
}
};
//const oldQuery = {$and:[{$expr:{$eq:[{$first:"$stops"},firstCrs]}},{$expr:{$eq:[{$last:"$stops"},lastCrs]}}]}
const search = db.query('pis', query);
return search;
}
// Hopefully at some point, I will also be able to implement a find PIS code by headcode option.
module.exports = {
findPisByOrigDest
};

View File

@ -0,0 +1,51 @@
const log = require('../utils/log.utils');
const auth = require('../utils/auth.utils');
const db = require('./dbAccess.services');
const mail = require('./mail.services');
const clean = require('../utils/sanitizer.utils');
const domains = require('../configs/domains.configs');
const errors = require('../configs/errorCodes.configs');
async function createRegKey(body) {
log.out('registerServices.createRegKey: Incoming request', 'INFO');
const domain = await clean.getDomainFromEmail(body.email); // The function should validate the email
log.out(`registerServices: New registration request from domain: ${domain}`, 'info');
if (domains.includes(domain)) {
log.out(`registerServices.createRegKey: Key from valid domain: ${domain}`);
const uuid = await auth.generateKey();
db.addRegReq(uuid, domain);
const message = await auth.generateConfirmationEmail(body.email, uuid);
if (!message) {
const err = new Error('Message generation error');
log.out('registerServices.createRegKey: Error generating registration email', 'err');
log.out(err, 'err');
return 500;
}
if (await mail.send(message) == true) {
return {status: 201, message: 'email sent'};
}
return {status: 500, errorCode: 950, errorMsg: errors[950]};
}
return {status: 403, errorCode: 702, errorMsg: errors[702]};
}
async function regUser(req) { // Add input validation
log.out(`Read UUID: ${req.uuid}`, 'dbug');
log.out(`registrationServices.regUser: Checking validity of : ${req.uuid}`, 'info');
const res = await auth.checkRequest(req.uuid);
log.out(`registrationServices.regUser: checkRequest returned: ${JSON.stringify(res)}`, 'info');
if (res.result) {
const uuid = await auth.generateKey();
const apiKey = await db.addUser(uuid, res.domain);
if (apiKey) {
db.delRegReq(req.uuid);
return {status: 201, message: 'User added', api_key: uuid};
}
}
return {status: 401, errorCode: 703, errorMsg: errors[703]};
}
module.exports = {
regUser,
createRegKey
};

View File

@ -1,24 +1,25 @@
const log = require('../utils/log.utils'); // Log Helper const log = require('../utils/log.utils'); // Log Helper
const db = require('../services/dbAccess.services') const db = require('../services/dbAccess.services');
const os = require('os') const os = require('os');
const vers = require('../configs/version.configs') const vers = require('../configs/version.configs');
async function hits(){ async function hits(){
log.out("statsServices.hits: Statistics Requested", "info") log.out('statsServices.hits: Statistics Requested', 'info');
var dat = db.query("meta", {target: "counters"}); var dat = db.query('meta', {target: 'counters'});
var ver = db.query("meta", {target: "versions"}); var ver = db.query('meta', {target: 'versions'});
log.out(`statsServices.hits: fetched server meta`, "info") log.out('statsServices.hits: fetched server meta', 'info');
let out = {}; let out = {};
out.host = os.hostname(); out.host = os.hostname();
out.mode = process.env.NODE_ENV; // eslint-disable-next-line no-undef
out.verBkend = vers.app; out.mode = process.env.NODE_ENV;
out.verApi = vers.api; out.verBkend = vers.app;
out.dat = await dat; out.verApi = vers.api;
out.ver = await ver; out.dat = await dat;
log.out(`statsServices.hits: Sending Data: ${JSON.stringify(out)}`, "info") out.ver = await ver;
return out; log.out(`statsServices.hits: Sending Data: ${JSON.stringify(out)}`, 'info');
return out;
} }
module.exports = { module.exports = {
hits hits
} };

57
src/utils/auth.utils.js Normal file
View File

@ -0,0 +1,57 @@
const log = require('../utils/log.utils');
const crypto = require('crypto');
const db = require('../services/dbAccess.services');
const fs = require('fs/promises');
const minify = require('../utils/minify.utils');
// Checks users registration key against issued keys
async function isAuthed(uuid) { // Needs testing
const q = {uuid: uuid};
const res = await db.query('users', q);
log.out(`authUtils.checkUser: DB Query answer: ${JSON.stringify(res[0])}`, 'dbug');
const authorized = res && res[0] && res[0].domain;
if (authorized) db.userAtime(uuid);
return authorized;
}
// Checks whether a registration request key is valid
async function checkRequest(key) {
const collection = 'registrations';
const query = {uuid: key};
const res = await db.query(collection, query);
log.out(`authUtils.checkRequest: DB Query result: ${JSON.stringify(res)}`, 'dbug');
const result = res.length > 0 && res[0].time
? { result: true, domain: res[0].domain }
: { result: false };
return result;
}
// Creates an API key for a user
async function generateKey() { // Needs testing & moving to 'register.utils'
return crypto.randomUUID();
}
async function generateConfirmationEmail(eml, uuid) {
try {
const htmlTpl = await fs.readFile('mail-templates/register.html', 'utf-8');
const htmlStr = htmlTpl.replace(/>>ACCESSCODE<</g, uuid);
const htmlMin = await minify(htmlStr);
const txtTpl = fs.readFile('mail-templates/register.txt', 'utf-8');
return {
to: eml,
subject: 'OwlBoard Registration',
text: (await txtTpl).replace(/>>ACCESSCODE<</g, uuid),
html: htmlMin
};
} catch(err) {
log.out('mailServices.generateConfirmationEmail: Error reading templates, $(err)', 'err');
return false;
}
}
module.exports = {
isAuthed,
generateKey,
generateConfirmationEmail,
checkRequest
};

View File

@ -1,43 +1,49 @@
const log = require('../utils/log.utils'); // Log Helper const log = require('../utils/log.utils'); // Log Helper
const db = require('../services/dbAccess.services') // DB Access const db = require('../services/dbAccess.services'); // DB Access
const san = require('../utils/sanitizer.utils') // Sanitiser const san = require('../utils/sanitizer.utils'); // Sanitiser
async function checkCrs(input){ async function checkCrs(input){
var INPUT = input.toUpperCase() var INPUT = input.toUpperCase();
log.out(`ldbUtils.checkCrs: Building database query to find: '${INPUT}'`, "info") log.out(`ldbUtils.checkCrs: Building database query to find: '${INPUT}'`, 'info');
var query = {'$or':[{'3ALPHA':INPUT},{'TIPLOC':INPUT},{'STANOX':INPUT}]}; var query = {
var result = await db.query("stations", query) '$or':[
log.out(`ldbUtils.checkCrs: Query results: ${JSON.stringify(result)}`, "info") {'3ALPHA':INPUT},
return result {'TIPLOC':INPUT},
{'STANOX':INPUT}
]
};
var result = await db.query('stations', query);
log.out(`ldbUtils.checkCrs: Query results: ${JSON.stringify(result)}`, 'dbug');
return result;
} }
async function cleanMessages(input){ // Needs to be moved to the frontend `ensureArray() func` async function cleanMessages(input){ // Needs to be moved to the frontend `ensureArray() func`
var out = [] var out = [];
if (typeof input.message == "string") { if (typeof input.message == 'string') {
out.push(await san.cleanNrcc(input.message)) out.push(await san.cleanNrcc(input.message));
} else if (typeof input.message == "object") { } else if (typeof input.message == 'object') {
for(var i = 0; i < input.message.length; i++) { for(var i = 0; i < input.message.length; i++) {
out.push(await san.cleanNrcc(input.message[i])) out.push(await san.cleanNrcc(input.message[i]));
}
} }
return out; }
return out;
} }
// Accepts an object but not an Array and returns it wrapped in an array. // Accepts an object but not an Array and returns it wrapped in an array.
async function cleanServices(input){ // Need to triple check but I don't think this is used anymore. async function cleanServices(input){ // Need to triple check but I don't think this is used anymore.
var out = [] var out = [];
if (!Array.isArray(input)) { if (!Array.isArray(input)) {
log.out(`ldbUtils.cleanServices: Transforming input: ${input}`, "depr") log.out(`ldbUtils.cleanServices: Transforming input: ${input}`, 'depr');
out.push(input) out.push(input);
log.out(`ldbUtils.cleanServices: Returning output: ${out}`, "depr") log.out(`ldbUtils.cleanServices: Returning output: ${out}`, 'depr');
return out; return out;
} else { } else {
return input; return input;
} }
} }
module.exports = { module.exports = {
checkCrs, checkCrs,
cleanMessages, cleanMessages,
cleanServices cleanServices
} };

View File

@ -1,14 +1,17 @@
/* global process */
const environment = process.env.NODE_ENV; const environment = process.env.NODE_ENV;
const hideInProduction = ['info', 'dbug'];
async function out(msg, level = 'othr') { async function out(msg, level = 'othr') {
if (environment === "production" && level === "info") { if (environment === 'production' && hideInProduction.includes(level.toLowerCase())) {
return; return;
} else { } else {
const time = new Date().toISOString(); const time = new Date().toISOString();
console.log(`${time} - ${level.toUpperCase()} - ${msg}`); console.log(`${time} - ${level.toUpperCase()} - ${msg}`);
} }
} }
module.exports = { module.exports = {
out out
} };

10
src/utils/minify.utils.js Normal file
View File

@ -0,0 +1,10 @@
const htmlShrink = require('html-minifier').minify;
const juice = require('juice');
module.exports = async function minifyMail(input) {
const inlined = juice(input);
return htmlShrink(inlined, {
removeComments: true,
collapseWhitespace: true
});
};

View File

@ -1,45 +1,31 @@
const clean = require('string-sanitizer-fix'); //const log = require('../utils/log.utils');
const log = require('../utils/log.utils');
/* function removeNonAlphanumeric(inputString) { // Should be able to replace sanitizer module
string.sanitize("a.bc@d efg#h"); // abcdefgh return inputString.replace(/[^a-zA-Z0-9]/g, '');
string.sanitize.keepSpace("a.bc@d efg#h"); // abcd efgh
string.sanitize.keepUnicode("a.bc@d efg#hক"); // abcd efghক
string.sanitize.addFullstop("a.bc@d efg#h"); // abcd.efgh
string.sanitize.addUnderscore("a.bc@d efg#h"); // abcd_efgh
string.sanitize.addDash("a.bc@d efg#h"); // abcd-efgh
string.sanitize.removeNumber("@abcd efgh123"); // abcdefgh
string.sanitize.keepNumber("@abcd efgh123"); // abcdefgh123
string.addFullstop("abcd efgh"); // abcd.efgh
string.addUnderscore("@abcd efgh"); // @abcd_efgh
string.addDash("@abcd efgh"); // @abcd-efgh
string.removeSpace("@abcd efgh"); // @abcdefgh
*/
function cleanApiEndpointTxt(input) {
var output = clean.sanitize.keepSpace(input)
if (output != input){
log.out(`sanitizerUtils.cleanApiEndpoint: WARN: Sanitizing changed string. Input = ${input}`, "warn");
}
return output
} }
function cleanApiEndpointNum(input) { function removeNonAlpha(inputString) { // Should be able to replace sanitizer module
var output = clean.sanitize.keepNumber(input) return inputString.replace(/[^a-zA-Z]/g, '');
if (output != input){
log.out(`sanitizerUtils.cleanApiEndpointNum: WARN: Sanitizing changed string. Input = ${input}`, "warn");
}
return output
} }
function cleanNrcc(input) { const cleanApiEndpointTxt = removeNonAlpha;
var rmNewline = input.replace(/[\n\r]/g, ""); // Remove newlines const cleanApiEndpointNum = removeNonAlphanumeric;
var rmPara = rmNewline.replace(/<\/?p[^>]*>/g, ""); // Remove <p> & </p>
return rmPara; function cleanNrcc(input) { // Remove newlines and then <p> tags from input
const cleanInput = input.replace(/[\n\r]/g, '').replace(/<\/?p[^>]*>/g, '');
return cleanInput;
}
async function getDomainFromEmail(mail) { // Needs testing
let split = mail.split('@');
return split[1];
} }
module.exports = { module.exports = {
cleanApiEndpointTxt, cleanApiEndpointTxt,
cleanApiEndpointNum, cleanApiEndpointNum,
cleanNrcc removeNonAlpha,
} removeNonAlphanumeric,
cleanNrcc,
getDomainFromEmail,
};

View File

@ -1,15 +1,15 @@
function unixLocal(unix) { function unixLocal(unix) {
var jsTime = unix*1000 var jsTime = unix*1000;
var dt = new Date(jsTime) var dt = new Date(jsTime);
return dt.toLocaleString() return dt.toLocaleString();
} }
function jsUnix(js) { function jsUnix(js) {
var preRound = js / 1000 var preRound = js / 1000;
return Math.round(preRound) return Math.round(preRound);
} }
module.exports = { module.exports = {
unixLocal, unixLocal,
jsUnix, jsUnix,
} };

View File

@ -1,27 +1,28 @@
/* global process */
// Checks that all required environment variables are present. // Checks that all required environment variables are present.
// Returns True or False and offers an object detailing what is missing. // Returns True or False and offers an object detailing what is missing.
async function varTest(){ async function varTest(){
var required = { var required = {
OWL_LDB_KEY: process.env.OWL_LDB_KEY, OWL_LDB_KEY: process.env.OWL_LDB_KEY,
OWL_LDB_CORPUSUSER: process.env.OWL_LDB_CORPUSUSER, OWL_LDB_CORPUSUSER: process.env.OWL_LDB_CORPUSUSER,
OWL_LDB_CORPUSPASS: process.env.OWL_LDB_CORPUSPASS, OWL_LDB_CORPUSPASS: process.env.OWL_LDB_CORPUSPASS,
OWL_NOT_USED: process.env.OWL_NOT_USED OWL_NOT_USED: process.env.OWL_NOT_USED
} };
var desired = { var desired = {
OWL_DB_PASS: process.env.OWL_DB_PASS OWL_DB_PASS: process.env.OWL_DB_PASS
} };
// DO NOT LOG CREDENTIALS!!! // DO NOT LOG CREDENTIALS!!!
// Test that each of required is NOT undefined. // Test that each of required is NOT undefined.
// var pass = true if all okay, false if not. // var pass = true if all okay, false if not.
// Append any missing values to missing_required = [] // Append any missing values to missing_required = []
// Test that each of desired is NOT undefined. // Test that each of desired is NOT undefined.
// Append any missing values to missing_desired = [] // Append any missing values to missing_desired = []
// Return : {pass: $pass, missong_required = $missing_required, missing_desired = $missing_desired} // Return : {pass: $pass, missong_required = $missing_required, missing_desired = $missing_desired}
} }
module.exports = { module.exports = {
varTest varTest
} };