pis #12
@ -8,4 +8,6 @@ db-manager
|
||||
run.sh
|
||||
LICENSE
|
||||
*.md
|
||||
static
|
||||
.eslintrc.js
|
||||
.vscode
|
||||
.test-tools
|
31
.eslintrc.js
Normal file
31
.eslintrc.js
Normal 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'
|
||||
]
|
||||
}
|
||||
};
|
19
.vscode/settings.json
vendored
19
.vscode/settings.json
vendored
@ -1,7 +1,14 @@
|
||||
{
|
||||
"git.autofetch": "all",
|
||||
"git.alwaysSignOff": true,
|
||||
"git.enableCommitSigning": false,
|
||||
"git.fetchOnPull": true,
|
||||
"git.pullBeforeCheckout": true
|
||||
}
|
||||
"git.autofetch": "all",
|
||||
"git.alwaysSignOff": true,
|
||||
"git.enableCommitSigning": false,
|
||||
"git.fetchOnPull": 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
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
# 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
85
app.js
@ -4,38 +4,55 @@
|
||||
// licensed separately, each folder contains a license file where a
|
||||
// different license applies.
|
||||
|
||||
console.log(`Initialising OwlBoard`)
|
||||
/* global process */
|
||||
|
||||
console.log('Initialising OwlBoard');
|
||||
const mode = process.env.NODE_ENV || 'development';
|
||||
|
||||
// External Requires
|
||||
const express = require('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
|
||||
const log = require('./src/utils/log.utils'); // Log Helper
|
||||
const version = require('./src/configs/version.configs'); // Version Strings
|
||||
const listRtr = require('./src/routes/list.routes'); // /list endpoints
|
||||
const ldbRtr = require('./src/routes/ldb.routes'); // /ldb endpoints
|
||||
const kubeRtr = require('./src/routes/kube.routes'); // /kube endpoints
|
||||
const findRtr = require('./src/routes/find.routes'); // /find endpoints
|
||||
const issueRtr = require('./src/routes/issue.routes') // /issue endpoints
|
||||
const statRtr = require('./src/routes/stats.routes'); // /stat endpoints
|
||||
const log = require('./src/utils/log.utils'); // Log Helper
|
||||
const version = require('./src/configs/version.configs'); // Version Strings
|
||||
const listRtr = require('./src/routes/list.routes'); // /list endpoints
|
||||
const ldbRtr = require('./src/routes/ldb.routes'); // /ldb endpoints
|
||||
const kubeRtr = require('./src/routes/kube.routes'); // /kube endpoints
|
||||
const findRtr = require('./src/routes/find.routes'); // /find endpoints
|
||||
const issueRtr = require('./src/routes/issue.routes'); // /issue 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
|
||||
const srvListen = process.env.OWL_SRV_LISTEN || "0.0.0.0"
|
||||
const srvPort = process.env.OWL_SRV_PORT || 8460
|
||||
const srvListen = process.env.OWL_SRV_LISTEN || '0.0.0.0';
|
||||
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:
|
||||
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:
|
||||
// const varTest = require('./src/utils/varTest.utils');
|
||||
// var startTest = await varTest.varTest();
|
||||
//console.log("Required Vars Missing:", startTest.missing_required);
|
||||
//console.log("Desired Vars Missing:", startTest.missing_desired);
|
||||
// if startTest.pass == false
|
||||
// console.log("Unable to start, missing required vars")
|
||||
// exit app
|
||||
// const varTest = require('./src/utils/varTest.utils');
|
||||
// var startTest = await varTest.varTest();
|
||||
//console.log("Required Vars Missing:", startTest.missing_required);
|
||||
//console.log("Desired Vars Missing:", startTest.missing_desired);
|
||||
// if startTest.pass == false
|
||||
// console.log("Unable to start, missing required vars")
|
||||
// exit app
|
||||
|
||||
// Express Error Handling:
|
||||
app.use((err, req, res, next) => {
|
||||
@ -45,25 +62,37 @@ app.use((err, req, res, next) => {
|
||||
return;
|
||||
});
|
||||
|
||||
// Express Submodules:
|
||||
// Global Middleware:
|
||||
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/ldb', ldbRtr);
|
||||
app.use('/api/v1/kube', kubeRtr);
|
||||
app.use('/api/v1/find', findRtr);
|
||||
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
|
||||
app.listen(srvPort, srvListen, (error) =>{
|
||||
if(!error) {
|
||||
log.out(`app.listen: Listening on http://${srvListen}:${srvPort}`, "init");
|
||||
log.out("app.listen: State - alive", "init")
|
||||
log.out(`app.listen: Listening on http://${srvListen}:${srvPort}`, 'init');
|
||||
log.out('app.listen: State - alive', 'init');
|
||||
} 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');
|
||||
}
|
||||
});
|
70
mail-templates/register.html
Normal file
70
mail-templates/register.html
Normal 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>
|
10
mail-templates/register.txt
Normal file
10
mail-templates/register.txt
Normal 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
4334
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
@ -3,22 +3,30 @@
|
||||
"axios": "^1.2.1",
|
||||
"compression": "^1.7.4",
|
||||
"express": "^4.18.2",
|
||||
"express-rate-limit": "^6.7.0",
|
||||
"html-minifier": "^4.0.0",
|
||||
"juice": "^9.0.0",
|
||||
"ldbs-json": "^1.2.1",
|
||||
"mongodb": "^4.13.0",
|
||||
"string-sanitizer-fix": "^2.0.1"
|
||||
"nodemailer": "^6.9.1"
|
||||
},
|
||||
"name": "owlboard",
|
||||
"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",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node app.js"
|
||||
"start": "node app.js",
|
||||
"run": "node app.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.fjla.uk/fred.boniface/owlboard.git"
|
||||
"url": "https://git.fjla.uk/owlboard/backend.git"
|
||||
},
|
||||
"author": "Fred Boniface",
|
||||
"license": "GPL-3.0-or-later"
|
||||
"license": "GPL-3.0-or-later",
|
||||
"devDependencies": {
|
||||
"eslint": "^8.39.0",
|
||||
"prettier": "^2.8.8"
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,36 @@
|
||||
module.exports = valid
|
||||
|
||||
const valid = [
|
||||
"owlboard.info",
|
||||
"fjla.uk",
|
||||
"gwr.com",
|
||||
"swrailway.com",
|
||||
"firstrail.com",
|
||||
"networkrail.co.uk"
|
||||
]
|
||||
'owlboard.info',
|
||||
'avantiwestcoast.co.uk',
|
||||
'btp.police.uk',
|
||||
'c2crail.net',
|
||||
'chilternrailways.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;
|
12
src/configs/errorCodes.configs.js
Normal file
12
src/configs/errorCodes.configs.js
Normal 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;
|
@ -1,6 +1,6 @@
|
||||
const version = {
|
||||
api: ["/api/v1/",],
|
||||
app: "1.1.5"
|
||||
api: ['/api/v1/',],
|
||||
app: '2.0.0'
|
||||
};
|
||||
|
||||
module.exports = version;
|
@ -1,58 +1,58 @@
|
||||
const find = require('../services/find.services');
|
||||
|
||||
async function findName(req, res, next){
|
||||
try {
|
||||
var id = req.params.id
|
||||
res.json(await find.name(id))
|
||||
} catch (err) {
|
||||
console.error(`Unknown Error`, err.message);
|
||||
next(err);
|
||||
}
|
||||
try {
|
||||
var id = req.params.id;
|
||||
res.json(await find.name(id));
|
||||
} catch (err) {
|
||||
console.error('Unknown Error', err.message);
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
async function findCrs(req, res, next){
|
||||
try {
|
||||
var id = req.params.id
|
||||
res.json(await find.crs(id))
|
||||
} catch (err) {
|
||||
console.error(`Unknown Error`, err.message);
|
||||
next(err);
|
||||
}
|
||||
try {
|
||||
var id = req.params.id;
|
||||
res.json(await find.crs(id));
|
||||
} catch (err) {
|
||||
console.error('Unknown Error', err.message);
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
async function findNlc(req, res, next){
|
||||
try {
|
||||
var id = req.params.id
|
||||
res.json(await find.nlc(id))
|
||||
} catch (err) {
|
||||
console.error(`Unknown Error`, err.message);
|
||||
next(err);
|
||||
}
|
||||
try {
|
||||
var id = req.params.id;
|
||||
res.json(await find.nlc(id));
|
||||
} catch (err) {
|
||||
console.error('Unknown Error', err.message);
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
async function findTiploc(req, res, next){
|
||||
try {
|
||||
var id = req.params.id
|
||||
res.json(await find.tiploc(id))
|
||||
} catch (err) {
|
||||
console.error(`Unknown Error`, err.message);
|
||||
next(err);
|
||||
}
|
||||
try {
|
||||
var id = req.params.id;
|
||||
res.json(await find.tiploc(id));
|
||||
} catch (err) {
|
||||
console.error('Unknown Error', err.message);
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
async function findStanox(req, res, next){
|
||||
try {
|
||||
var id = req.params.id
|
||||
res.json(await find.stanox(id))
|
||||
} catch (err) {
|
||||
console.error(`Unknown Error`, err.message);
|
||||
next(err);
|
||||
}
|
||||
try {
|
||||
var id = req.params.id;
|
||||
res.json(await find.stanox(id));
|
||||
} catch (err) {
|
||||
console.error('Unknown Error', err.message);
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
module.exports = {
|
||||
findName,
|
||||
findCrs,
|
||||
findNlc,
|
||||
findTiploc,
|
||||
findStanox
|
||||
}
|
||||
findName,
|
||||
findCrs,
|
||||
findNlc,
|
||||
findTiploc,
|
||||
findStanox
|
||||
};
|
@ -1,14 +1,14 @@
|
||||
const issue = require('../services/issue.services');
|
||||
|
||||
async function post(req, res, next){
|
||||
try {
|
||||
res.json(await issue.processor(req.body))
|
||||
} catch (err) {
|
||||
console.error(`Controller Error`, err.message);
|
||||
next(err);
|
||||
}
|
||||
try {
|
||||
res.json(await issue.processor(req.body));
|
||||
} catch (err) {
|
||||
console.error('Controller Error', err.message);
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
post
|
||||
}
|
||||
post
|
||||
};
|
@ -1,34 +1,35 @@
|
||||
const kube = require('../services/kube.services');
|
||||
|
||||
async function getAlive(req, res, next){
|
||||
try {
|
||||
var state = kube.getAlive()
|
||||
res.status((await state).code).send((await state).state)
|
||||
} catch (err) {
|
||||
res.status("503").send({state: "error"})
|
||||
}
|
||||
try {
|
||||
var state = kube.getAlive();
|
||||
res.status((await state).code).send((await state).state);
|
||||
} catch (err) {
|
||||
res.status('503').send({state: 'error'});
|
||||
}
|
||||
}
|
||||
|
||||
async function getReady(req, res, next){
|
||||
try {
|
||||
res.json(await kube.getReady(req.body))
|
||||
} catch (err) {
|
||||
console.error(`Unknown Error`, err.message);
|
||||
next(err);
|
||||
}
|
||||
try {
|
||||
res.json(await kube.getReady(req.body));
|
||||
} catch (err) {
|
||||
console.error('Unknown Error', err.message);
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
async function getTime(req, res, next){
|
||||
try {
|
||||
res.json(await kube.getTime(req.body))
|
||||
} catch (err) {
|
||||
console.error(`Unknown Error`, err.message);
|
||||
next(err);
|
||||
}
|
||||
try {
|
||||
res.json(await kube.getTime(req.body));
|
||||
} catch (err) {
|
||||
console.error('Unknown Error', err.message);
|
||||
err.status = 503;
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getAlive,
|
||||
getReady,
|
||||
getTime
|
||||
}
|
||||
getAlive,
|
||||
getReady,
|
||||
getTime
|
||||
};
|
@ -1,15 +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(req.body, id))
|
||||
} catch (err) {
|
||||
console.error(`Unknown Error`, err.message);
|
||||
next(err);
|
||||
}
|
||||
try {
|
||||
var id = req.params.id;
|
||||
res.json(await ldb.get(id));
|
||||
} catch (err) {
|
||||
console.error('Unknown Error', err.message);
|
||||
err.status = 500;
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
get
|
||||
}
|
||||
get
|
||||
};
|
16
src/controllers/ldbs.controllers copy.js
Normal file
16
src/controllers/ldbs.controllers copy.js
Normal 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
|
||||
};
|
@ -1,34 +1,37 @@
|
||||
const list = require('../services/list.services');
|
||||
|
||||
async function getStations(req, res, next){
|
||||
try {
|
||||
res.json(await list.getStations(req.body))
|
||||
} catch (err) {
|
||||
console.error(`Controller Error`, err.message);
|
||||
next(err);
|
||||
}
|
||||
try {
|
||||
res.json(await list.getStations(req.body));
|
||||
} catch (err) {
|
||||
console.error('Controller Error', err.message);
|
||||
err.status = 500;
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
async function getCorpus(req, res, next){
|
||||
try {
|
||||
res.json(await list.getCorpus(req.body))
|
||||
} catch (err) {
|
||||
console.error(`Controller Error`, err.message);
|
||||
next(err);
|
||||
}
|
||||
try {
|
||||
res.json(await list.getCorpus(req.body));
|
||||
} catch (err) {
|
||||
console.error('Controller Error', err.message);
|
||||
err.status = 500;
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
async function hits(req, res, next) {
|
||||
try {
|
||||
res.json(await list.hits())
|
||||
} catch (err) {
|
||||
console.error(`Controller Error`, err);
|
||||
next(err);
|
||||
}
|
||||
try {
|
||||
res.json(await list.hits());
|
||||
} catch (err) {
|
||||
console.error('Controller Error', err);
|
||||
err.status = 500;
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getStations,
|
||||
getCorpus,
|
||||
hits
|
||||
}
|
||||
getStations,
|
||||
getCorpus,
|
||||
hits
|
||||
};
|
17
src/controllers/pis.controllers.js
Normal file
17
src/controllers/pis.controllers.js
Normal 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
|
||||
};
|
26
src/controllers/registration.controllers.js
Normal file
26
src/controllers/registration.controllers.js
Normal 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
|
||||
};
|
@ -1,13 +1,15 @@
|
||||
const stat = require('../services/stats.services');
|
||||
|
||||
async function get(req, res, next) {
|
||||
try {
|
||||
res.json(await stat.hits())
|
||||
} catch (err) {
|
||||
console.error(`Controller Error`, err);
|
||||
next(err);
|
||||
}
|
||||
try {
|
||||
res.json(await stat.hits());
|
||||
} catch (err) {
|
||||
console.error('Controller Error', err);
|
||||
err.status = 500;
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
get}
|
||||
get
|
||||
};
|
@ -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>
|
27
src/middlewares/auth.middlewares.js
Normal file
27
src/middlewares/auth.middlewares.js
Normal 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);
|
||||
}
|
||||
};
|
12
src/middlewares/requireJson.middlewares.js
Normal file
12
src/middlewares/requireJson.middlewares.js
Normal 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?
|
@ -6,4 +6,4 @@ router.get('/alive', kubeController.getAlive);
|
||||
router.get('/ready', kubeController.getReady);
|
||||
router.get('/time', kubeController.getTime);
|
||||
|
||||
module.exports = router
|
||||
module.exports = router;
|
19
src/routes/ldbs.routes.js
Normal file
19
src/routes/ldbs.routes.js
Normal 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
7
src/routes/pis.routes.js
Normal 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;
|
8
src/routes/registration.routes.js
Normal file
8
src/routes/registration.routes.js
Normal 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;
|
@ -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 dbPass = process.env.OWL_DB_PASS || "twittwoo"
|
||||
const dbName = process.env.OWL_DB_NAME || "owlboard"
|
||||
const dbPort = process.env.OWL_DB_PORT || 27017
|
||||
const dbHost = process.env.OWL_DB_HOST || "localhost"
|
||||
const dbUser = process.env.OWL_DB_USER || 'owl';
|
||||
const dbPass = process.env.OWL_DB_PASS || 'twittwoo';
|
||||
const dbName = process.env.OWL_DB_NAME || 'owlboard';
|
||||
const dbPort = process.env.OWL_DB_PORT || 27017;
|
||||
const dbHost = process.env.OWL_DB_HOST || 'localhost';
|
||||
const uri = `mongodb://${dbUser}:${dbPass}@${dbHost}:${dbPort}`;
|
||||
|
||||
const { MongoClient } = require('mongodb');
|
||||
@ -13,27 +14,70 @@ const client = new MongoClient(uri);
|
||||
const db = client.db(dbName);
|
||||
|
||||
async function query(collection, query){
|
||||
await client.connect();
|
||||
log.out(`dbAccess.query: Connecting to collection: '${collection}'`, "info")
|
||||
var qcoll = db.collection(collection);
|
||||
var qcursor = qcoll.find(query)
|
||||
qcursor.project({_id: 0})
|
||||
log.out(`dbAccess.query: Running Query: ${JSON.stringify(query)}`, "info")
|
||||
increment(collection)
|
||||
return (await qcursor.toArray());
|
||||
await client.connect();
|
||||
log.out(`dbAccess.query: Connecting to collection: '${collection}'`, 'info');
|
||||
var qcoll = db.collection(collection);
|
||||
var qcursor = qcoll.find(query);
|
||||
qcursor.project({_id: 0});
|
||||
log.out(`dbAccess.query: Running Query: ${JSON.stringify(query)}`, 'info');
|
||||
increment(collection);
|
||||
return (await qcursor.toArray());
|
||||
}
|
||||
|
||||
async function increment(target) {
|
||||
log.out(`dbAccess.increment: Incrementing counter for: ${target}`, "info")
|
||||
await client.connect();
|
||||
let col = db.collection("meta");
|
||||
let update = {}
|
||||
update[target] = 1
|
||||
col.updateOne({target: "counters"}, {$inc:update})
|
||||
return;
|
||||
log.out(`dbAccess.increment: Incrementing counter for: ${target}`, 'info');
|
||||
await client.connect();
|
||||
let col = db.collection('meta');
|
||||
let update = {};
|
||||
update[target] = 1;
|
||||
col.updateOne({target: 'counters'}, {$inc:update});
|
||||
}
|
||||
|
||||
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 = {
|
||||
query,
|
||||
increment
|
||||
}
|
||||
query,
|
||||
increment, // Probqbly doesn't need exporting? - It does, ldbServices needs to increment when the API is hit!
|
||||
addUser,
|
||||
userAtime,
|
||||
addRegReq,
|
||||
delRegReq
|
||||
};
|
@ -2,58 +2,58 @@
|
||||
|
||||
const log = require('../utils/log.utils'); // Log Helper
|
||||
const db = require('../services/dbAccess.services');
|
||||
const san = require('../utils/sanitizer.utils')
|
||||
const san = require('../utils/sanitizer.utils');
|
||||
|
||||
// DB Query: query(collection, query)
|
||||
|
||||
// Define collection as all queries are for the "corpus" collection.
|
||||
const col = "corpus"
|
||||
const col = 'corpus';
|
||||
|
||||
async function name(id){
|
||||
log.out(`findServices.name: Finding station name: ${id}`, "info")
|
||||
var name = san.cleanApiEndpointTxt(id.toUpperCase())
|
||||
query = {NLCDESC: name}
|
||||
//var data = await db.query(col,query)
|
||||
return await db.query(col,query)
|
||||
log.out(`findServices.name: Finding station name: ${id}`, 'info');
|
||||
var name = san.cleanApiEndpointTxt(id.toUpperCase());
|
||||
let query = {NLCDESC: name};
|
||||
//var data = await db.query(col,query)
|
||||
return await db.query(col,query);
|
||||
}
|
||||
|
||||
async function crs(id){
|
||||
log.out(`findServices.crs: Finding crs: ${id}`, "info")
|
||||
var crs = san.cleanApiEndpointTxt(id.toUpperCase())
|
||||
query = {'3ALPHA': crs}
|
||||
//var data = await db.query(col,query)
|
||||
return await db.query(col,query)
|
||||
log.out(`findServices.crs: Finding crs: ${id}`, 'info');
|
||||
var crs = san.cleanApiEndpointTxt(id.toUpperCase());
|
||||
let query = {'3ALPHA': crs};
|
||||
//var data = await db.query(col,query)
|
||||
return await db.query(col,query);
|
||||
}
|
||||
|
||||
async function nlc(id){
|
||||
log.out(`findServices.nlc: Finding nlc: ${id}`, "info")
|
||||
var nlc = san.cleanApiEndpointNum(id)
|
||||
query = {NLC: parseInt(nlc)}
|
||||
log.out(`findServices.nlc: NLC Converted to int: ${query}`, "info")
|
||||
//var data = await db.query(col,query)
|
||||
return await db.query(col,query)
|
||||
log.out(`findServices.nlc: Finding nlc: ${id}`, 'info');
|
||||
var nlc = san.cleanApiEndpointNum(id);
|
||||
let query = {NLC: parseInt(nlc)};
|
||||
log.out(`findServices.nlc: NLC Converted to int: ${query}`, 'info');
|
||||
//var data = await db.query(col,query)
|
||||
return await db.query(col,query);
|
||||
}
|
||||
|
||||
async function tiploc(id){
|
||||
log.out(`findServices.tiploc: Finding tiploc: ${id}`, "info")
|
||||
var tiploc = san.cleanApiEndpointTxt(id.toUpperCase())
|
||||
query = {TIPLOC: tiploc}
|
||||
//var data = await db.query(col,query)
|
||||
return await db.query(col,query)
|
||||
log.out(`findServices.tiploc: Finding tiploc: ${id}`, 'info');
|
||||
var tiploc = san.cleanApiEndpointTxt(id.toUpperCase());
|
||||
let query = {TIPLOC: tiploc};
|
||||
//var data = await db.query(col,query)
|
||||
return await db.query(col,query);
|
||||
}
|
||||
|
||||
async function stanox(id){
|
||||
log.out(`findServices.stanox: Finding stanox: ${id}`, "info")
|
||||
var stanox = san.cleanApiEndpointNum(id)
|
||||
query = {STANOX: String(stanox)}
|
||||
//var data = await db.query(col,query)
|
||||
return await db.query(col,query)
|
||||
log.out(`findServices.stanox: Finding stanox: ${id}`, 'info');
|
||||
var stanox = san.cleanApiEndpointNum(id);
|
||||
let query = {STANOX: String(stanox)};
|
||||
//var data = await db.query(col,query)
|
||||
return await db.query(col,query);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
name,
|
||||
crs,
|
||||
nlc,
|
||||
tiploc,
|
||||
stanox
|
||||
}
|
||||
name,
|
||||
crs,
|
||||
nlc,
|
||||
tiploc,
|
||||
stanox
|
||||
};
|
@ -1,33 +1,35 @@
|
||||
const axios = require('axios')
|
||||
const log = require('../utils/log.utils')
|
||||
/* eslint-disable no-useless-escape */
|
||||
/* global process */
|
||||
const axios = require('axios');
|
||||
const log = require('../utils/log.utils');
|
||||
|
||||
async function processor(data) {
|
||||
log.out(`issueService.processor: Issue received`, "info")
|
||||
let out = {}
|
||||
out.title = data.subject.replace(/<[^>]+>|[\*\$]/g, '');
|
||||
out.body = data.msg.replace(/<[^>]+>|[\*\$]/g, '')
|
||||
return await sendToGitea(out);
|
||||
log.out('issueService.processor: Issue received', 'info');
|
||||
let out = {};
|
||||
out.title = data.subject.replace(/<[^>]+>|[\*\$]/g, '');
|
||||
out.body = data.msg.replace(/<[^>]+>|[\*\$]/g, '');
|
||||
return await sendToGitea(out);
|
||||
}
|
||||
|
||||
async function sendToGitea(body) {
|
||||
let key = process.env.OWL_GIT_ISSUEBOT
|
||||
let url = process.env.OWL_GIT_APIENDPOINT
|
||||
let opts = {
|
||||
headers: {
|
||||
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"}
|
||||
let key = process.env.OWL_GIT_ISSUEBOT;
|
||||
let url = process.env.OWL_GIT_APIENDPOINT;
|
||||
let opts = {
|
||||
headers: {
|
||||
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'};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
processor
|
||||
}
|
||||
processor
|
||||
};
|
@ -1,20 +1,28 @@
|
||||
const testing = require('../services/mail.services');
|
||||
const log = require('../utils/log.utils');
|
||||
|
||||
async function getAlive(){
|
||||
log.out(`kubeServices.getAlive: alive hook checked`, "info")
|
||||
return {code: 200, state: {state: "alive",noise: "twit-twoo"}}
|
||||
log.out('kubeServices.getAlive: alive hook checked', 'info');
|
||||
return {code: 200, state: {state: 'alive',noise: 'twit-twoo'}};
|
||||
}
|
||||
|
||||
async function getReady(){
|
||||
log.out(`kubeServices.getReady: ready hook checked`, "info")
|
||||
return "not_implemented";
|
||||
};
|
||||
log.out('kubeServices.getReady: ready hook checked', 'info');
|
||||
testing.send({
|
||||
to: 'fred@fjla.uk',
|
||||
subject: 'OwlBoard Test',
|
||||
txt: 'This is a test message from OwlBoard (testing)'
|
||||
});
|
||||
return 'not_implemented';
|
||||
}
|
||||
|
||||
async function getTime(){
|
||||
var now = new Date()
|
||||
return {responseGenerated: now}
|
||||
var now = new Date();
|
||||
return {responseGenerated: now};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getAlive,
|
||||
getReady,
|
||||
getTime
|
||||
}
|
||||
getAlive,
|
||||
getReady,
|
||||
getTime
|
||||
};
|
@ -1,46 +1,67 @@
|
||||
/* global process */
|
||||
// Parse and return an LDB Request
|
||||
|
||||
const log = require('../utils/log.utils'); // Log Helper
|
||||
const ldb = require('ldbs-json')
|
||||
const util = require('../utils/ldb.utils')
|
||||
const san = require('../utils/sanitizer.utils')
|
||||
const db = require('../services/dbAccess.services')
|
||||
const ldb = require('ldbs-json');
|
||||
const util = require('../utils/ldb.utils');
|
||||
const san = require('../utils/sanitizer.utils');
|
||||
const db = require('../services/dbAccess.services');
|
||||
|
||||
const ldbKey = process.env.OWL_LDB_KEY
|
||||
const ldbsvKey = process.env.OWL_LDB_SVKEY
|
||||
const ldbKey = process.env.OWL_LDB_KEY;
|
||||
const ldbsvKey = process.env.OWL_LDB_SVKEY;
|
||||
|
||||
async function get(body, id){
|
||||
var cleanId = san.cleanApiEndpointTxt(id);
|
||||
var obj = await util.checkCrs(cleanId);
|
||||
try {
|
||||
var crs = obj[0]['3ALPHA'];
|
||||
log.out(`ldbService.get: Determined CRS for lookup to be: ${crs}`, "info");
|
||||
var data = arrDepBoard(crs);
|
||||
db.increment("ldbws");
|
||||
await data;
|
||||
} catch (err) {
|
||||
log.out(`ldbService.get: Error, Unable to find CRS: ${err}`, "info")
|
||||
var data = {ERROR:'NOT_FOUND',description:'The entered station was not found. Please check and try again.'};
|
||||
async function get(id, staff=false){
|
||||
const cleanId = san.cleanApiEndpointTxt(id);
|
||||
const obj = await util.checkCrs(cleanId);
|
||||
try {
|
||||
const crs = obj[0]['3ALPHA'];
|
||||
log.out(`ldbService.get: Determined CRS for lookup to be: ${crs}`, 'info');
|
||||
if (staff) {
|
||||
const data = arrDepBoardStaff(crs);
|
||||
db.increment('ldbsvws');
|
||||
return await data;
|
||||
} else {
|
||||
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){
|
||||
log.out(`ldbService.arrDepBoard: Trying to fetch ArrDep Board for ${CRS}`, "info")
|
||||
try {
|
||||
var options = {
|
||||
numRows: 10,
|
||||
crs: CRS.toUpperCase()
|
||||
}
|
||||
var api = new ldb(ldbKey,false)
|
||||
var reply = api.call("GetArrDepBoardWithDetails", options, false, false)
|
||||
return await reply
|
||||
} catch (err) {
|
||||
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.`};
|
||||
}
|
||||
};
|
||||
log.out(`ldbService.arrDepBoard: Trying to fetch ArrDep Board for ${CRS}`, 'info');
|
||||
try {
|
||||
const options = {
|
||||
numRows: 10,
|
||||
crs: CRS.toUpperCase()
|
||||
};
|
||||
const api = new ldb(ldbKey,false);
|
||||
return await api.call('GetArrDepBoardWithDetails', options, false, false);
|
||||
} catch (err) {
|
||||
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.'};
|
||||
}
|
||||
}
|
||||
|
||||
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 = {
|
||||
get
|
||||
}
|
||||
get
|
||||
};
|
@ -1,20 +1,19 @@
|
||||
const log = require('../utils/log.utils'); // Log Helper
|
||||
const db = require('../services/dbAccess.services')
|
||||
const os = require('os')
|
||||
const db = require('../services/dbAccess.services');
|
||||
|
||||
async function getStations(){
|
||||
var out = db.query("stations")
|
||||
log.out(`listServices.getStations: Fetching stations list`, "info")
|
||||
return await out;
|
||||
var out = db.query('stations');
|
||||
log.out('listServices.getStations: Fetching stations list', 'info');
|
||||
return await out;
|
||||
}
|
||||
|
||||
async function getCorpus(){
|
||||
var out = db.query("corpus")
|
||||
log.out(`listServices.getCorpus: Fetching CORPUS list`, "info")
|
||||
return await out;
|
||||
var out = db.query('corpus');
|
||||
log.out('listServices.getCorpus: Fetching CORPUS list', 'info');
|
||||
return await out;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getStations,
|
||||
getCorpus
|
||||
}
|
||||
getStations,
|
||||
getCorpus
|
||||
};
|
@ -1,7 +1,36 @@
|
||||
const log = require('../utils/log.utils')
|
||||
const mail = require('some-mail-module')
|
||||
/* global process */
|
||||
const log = require('../utils/log.utils');
|
||||
const mail = require('nodemailer'); //>> Probs wrong
|
||||
|
||||
async function sendTest() {
|
||||
// Send test mail message
|
||||
return;
|
||||
}
|
||||
const fromAddr = process.env.OWL_EML_FROM;
|
||||
const smtpUser = process.env.OWL_EML_USER;
|
||||
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
|
||||
};
|
34
src/services/pis.services.js
Normal file
34
src/services/pis.services.js
Normal 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
|
||||
};
|
51
src/services/registration.services.js
Normal file
51
src/services/registration.services.js
Normal 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
|
||||
};
|
@ -1,24 +1,25 @@
|
||||
const log = require('../utils/log.utils'); // Log Helper
|
||||
const db = require('../services/dbAccess.services')
|
||||
const os = require('os')
|
||||
const vers = require('../configs/version.configs')
|
||||
const db = require('../services/dbAccess.services');
|
||||
const os = require('os');
|
||||
const vers = require('../configs/version.configs');
|
||||
|
||||
async function hits(){
|
||||
log.out("statsServices.hits: Statistics Requested", "info")
|
||||
var dat = db.query("meta", {target: "counters"});
|
||||
var ver = db.query("meta", {target: "versions"});
|
||||
log.out(`statsServices.hits: fetched server meta`, "info")
|
||||
let out = {};
|
||||
out.host = os.hostname();
|
||||
out.mode = process.env.NODE_ENV;
|
||||
out.verBkend = vers.app;
|
||||
out.verApi = vers.api;
|
||||
out.dat = await dat;
|
||||
out.ver = await ver;
|
||||
log.out(`statsServices.hits: Sending Data: ${JSON.stringify(out)}`, "info")
|
||||
return out;
|
||||
log.out('statsServices.hits: Statistics Requested', 'info');
|
||||
var dat = db.query('meta', {target: 'counters'});
|
||||
var ver = db.query('meta', {target: 'versions'});
|
||||
log.out('statsServices.hits: fetched server meta', 'info');
|
||||
let out = {};
|
||||
out.host = os.hostname();
|
||||
// eslint-disable-next-line no-undef
|
||||
out.mode = process.env.NODE_ENV;
|
||||
out.verBkend = vers.app;
|
||||
out.verApi = vers.api;
|
||||
out.dat = await dat;
|
||||
out.ver = await ver;
|
||||
log.out(`statsServices.hits: Sending Data: ${JSON.stringify(out)}`, 'info');
|
||||
return out;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hits
|
||||
}
|
||||
hits
|
||||
};
|
57
src/utils/auth.utils.js
Normal file
57
src/utils/auth.utils.js
Normal 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
|
||||
};
|
@ -1,43 +1,49 @@
|
||||
const log = require('../utils/log.utils'); // Log Helper
|
||||
const db = require('../services/dbAccess.services') // DB Access
|
||||
const san = require('../utils/sanitizer.utils') // Sanitiser
|
||||
const db = require('../services/dbAccess.services'); // DB Access
|
||||
const san = require('../utils/sanitizer.utils'); // Sanitiser
|
||||
|
||||
async function checkCrs(input){
|
||||
var INPUT = input.toUpperCase()
|
||||
log.out(`ldbUtils.checkCrs: Building database query to find: '${INPUT}'`, "info")
|
||||
var query = {'$or':[{'3ALPHA':INPUT},{'TIPLOC':INPUT},{'STANOX':INPUT}]};
|
||||
var result = await db.query("stations", query)
|
||||
log.out(`ldbUtils.checkCrs: Query results: ${JSON.stringify(result)}`, "info")
|
||||
return result
|
||||
var INPUT = input.toUpperCase();
|
||||
log.out(`ldbUtils.checkCrs: Building database query to find: '${INPUT}'`, 'info');
|
||||
var query = {
|
||||
'$or':[
|
||||
{'3ALPHA':INPUT},
|
||||
{'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`
|
||||
var out = []
|
||||
if (typeof input.message == "string") {
|
||||
out.push(await san.cleanNrcc(input.message))
|
||||
} else if (typeof input.message == "object") {
|
||||
for(var i = 0; i < input.message.length; i++) {
|
||||
out.push(await san.cleanNrcc(input.message[i]))
|
||||
}
|
||||
var out = [];
|
||||
if (typeof input.message == 'string') {
|
||||
out.push(await san.cleanNrcc(input.message));
|
||||
} else if (typeof input.message == 'object') {
|
||||
for(var i = 0; i < input.message.length; 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.
|
||||
async function cleanServices(input){ // Need to triple check but I don't think this is used anymore.
|
||||
var out = []
|
||||
if (!Array.isArray(input)) {
|
||||
log.out(`ldbUtils.cleanServices: Transforming input: ${input}`, "depr")
|
||||
out.push(input)
|
||||
log.out(`ldbUtils.cleanServices: Returning output: ${out}`, "depr")
|
||||
return out;
|
||||
} else {
|
||||
return input;
|
||||
}
|
||||
var out = [];
|
||||
if (!Array.isArray(input)) {
|
||||
log.out(`ldbUtils.cleanServices: Transforming input: ${input}`, 'depr');
|
||||
out.push(input);
|
||||
log.out(`ldbUtils.cleanServices: Returning output: ${out}`, 'depr');
|
||||
return out;
|
||||
} else {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
checkCrs,
|
||||
cleanMessages,
|
||||
cleanServices
|
||||
}
|
||||
checkCrs,
|
||||
cleanMessages,
|
||||
cleanServices
|
||||
};
|
@ -1,14 +1,17 @@
|
||||
/* global process */
|
||||
const environment = process.env.NODE_ENV;
|
||||
|
||||
const hideInProduction = ['info', 'dbug'];
|
||||
|
||||
async function out(msg, level = 'othr') {
|
||||
if (environment === "production" && level === "info") {
|
||||
return;
|
||||
} else {
|
||||
const time = new Date().toISOString();
|
||||
console.log(`${time} - ${level.toUpperCase()} - ${msg}`);
|
||||
}
|
||||
if (environment === 'production' && hideInProduction.includes(level.toLowerCase())) {
|
||||
return;
|
||||
} else {
|
||||
const time = new Date().toISOString();
|
||||
console.log(`${time} - ${level.toUpperCase()} - ${msg}`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
out
|
||||
}
|
||||
out
|
||||
};
|
10
src/utils/minify.utils.js
Normal file
10
src/utils/minify.utils.js
Normal 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
|
||||
});
|
||||
};
|
@ -1,45 +1,31 @@
|
||||
const clean = require('string-sanitizer-fix');
|
||||
const log = require('../utils/log.utils');
|
||||
//const log = require('../utils/log.utils');
|
||||
|
||||
/*
|
||||
string.sanitize("a.bc@d efg#h"); // abcdefgh
|
||||
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 removeNonAlphanumeric(inputString) { // Should be able to replace sanitizer module
|
||||
return inputString.replace(/[^a-zA-Z0-9]/g, '');
|
||||
}
|
||||
|
||||
function cleanApiEndpointNum(input) {
|
||||
var output = clean.sanitize.keepNumber(input)
|
||||
if (output != input){
|
||||
log.out(`sanitizerUtils.cleanApiEndpointNum: WARN: Sanitizing changed string. Input = ${input}`, "warn");
|
||||
}
|
||||
return output
|
||||
function removeNonAlpha(inputString) { // Should be able to replace sanitizer module
|
||||
return inputString.replace(/[^a-zA-Z]/g, '');
|
||||
}
|
||||
|
||||
function cleanNrcc(input) {
|
||||
var rmNewline = input.replace(/[\n\r]/g, ""); // Remove newlines
|
||||
var rmPara = rmNewline.replace(/<\/?p[^>]*>/g, ""); // Remove <p> & </p>
|
||||
return rmPara;
|
||||
const cleanApiEndpointTxt = removeNonAlpha;
|
||||
const cleanApiEndpointNum = removeNonAlphanumeric;
|
||||
|
||||
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 = {
|
||||
cleanApiEndpointTxt,
|
||||
cleanApiEndpointNum,
|
||||
cleanNrcc
|
||||
}
|
||||
cleanApiEndpointTxt,
|
||||
cleanApiEndpointNum,
|
||||
removeNonAlpha,
|
||||
removeNonAlphanumeric,
|
||||
cleanNrcc,
|
||||
getDomainFromEmail,
|
||||
};
|
@ -1,15 +1,15 @@
|
||||
function unixLocal(unix) {
|
||||
var jsTime = unix*1000
|
||||
var dt = new Date(jsTime)
|
||||
return dt.toLocaleString()
|
||||
var jsTime = unix*1000;
|
||||
var dt = new Date(jsTime);
|
||||
return dt.toLocaleString();
|
||||
}
|
||||
|
||||
function jsUnix(js) {
|
||||
var preRound = js / 1000
|
||||
return Math.round(preRound)
|
||||
var preRound = js / 1000;
|
||||
return Math.round(preRound);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
unixLocal,
|
||||
jsUnix,
|
||||
}
|
||||
unixLocal,
|
||||
jsUnix,
|
||||
};
|
@ -1,27 +1,28 @@
|
||||
/* global process */
|
||||
// Checks that all required environment variables are present.
|
||||
// Returns True or False and offers an object detailing what is missing.
|
||||
|
||||
async function varTest(){
|
||||
var required = {
|
||||
OWL_LDB_KEY: process.env.OWL_LDB_KEY,
|
||||
OWL_LDB_CORPUSUSER: process.env.OWL_LDB_CORPUSUSER,
|
||||
OWL_LDB_CORPUSPASS: process.env.OWL_LDB_CORPUSPASS,
|
||||
OWL_NOT_USED: process.env.OWL_NOT_USED
|
||||
}
|
||||
var desired = {
|
||||
OWL_DB_PASS: process.env.OWL_DB_PASS
|
||||
}
|
||||
// DO NOT LOG CREDENTIALS!!!
|
||||
var required = {
|
||||
OWL_LDB_KEY: process.env.OWL_LDB_KEY,
|
||||
OWL_LDB_CORPUSUSER: process.env.OWL_LDB_CORPUSUSER,
|
||||
OWL_LDB_CORPUSPASS: process.env.OWL_LDB_CORPUSPASS,
|
||||
OWL_NOT_USED: process.env.OWL_NOT_USED
|
||||
};
|
||||
var desired = {
|
||||
OWL_DB_PASS: process.env.OWL_DB_PASS
|
||||
};
|
||||
// DO NOT LOG CREDENTIALS!!!
|
||||
|
||||
// Test that each of required is NOT undefined.
|
||||
// var pass = true if all okay, false if not.
|
||||
// Append any missing values to missing_required = []
|
||||
// Test that each of desired is NOT undefined.
|
||||
// Append any missing values to missing_desired = []
|
||||
// Test that each of required is NOT undefined.
|
||||
// var pass = true if all okay, false if not.
|
||||
// Append any missing values to missing_required = []
|
||||
// Test that each of desired is NOT undefined.
|
||||
// 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 = {
|
||||
varTest
|
||||
}
|
||||
varTest
|
||||
};
|
Loading…
Reference in New Issue
Block a user