Docker containers running sample nodejs app among others tools for learning purposes.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

319 lines
10 KiB

const express = require('express');
const app = express();
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const database = 'mongodb://' + process.env.mongousr + ':' + process.env.mongopwd + '@mongo:27017/test';
const today = new Date();
var counter = 0;
const Prometheus = require('prom-client');
const fs = require('file-system');
const marked = require('marked');
const jwt = require('jsonwebtoken');
const bodyParser= require('body-parser');
const secret = 'wowmuchsecretveryhiddenwow';
const cookieParser = require('cookie-parser');
app.use(cookieParser());
// const morgan = require('morgan');
// // use morgan to log requests to the console
// app.use(morgan('dev'));
// global controller
// app.get('/*',function(req,res,next){
// res.header.token = 'sample-token';
// next(); // http://expressjs.com/guide.html#passing-route control
// });
// a middleware with no mount path; gets executed for every request to the app
// app.use(function(req, res, next) {
// res.setHeader('charset', 'utf-8')
// next();
// });
// database connection (with retries)
const options = {
autoIndex: false, // Don't build indexes
reconnectTries:30, // Retry up to 30 times
reconnectInterval: 500, // Reconnect every 500ms
poolSize: 10, // Maintain up to 10 socket connections
// If not connected, return errors immediately rather than waiting for reconnect
bufferMaxEntries: 0,
useNewUrlParser: true
}
const connectWithRetry = () => {
console.log('MongoDB connection with retry')
mongoose.connect(database, options).then(()=>{
console.log('MongoDB is connected')
}).catch(err=>{
console.log('MongoDB connection unsuccessful, retry after 5 seconds.')
setTimeout(connectWithRetry, 5000)
})
}
const libCounter = new Prometheus.Counter({
name: 'lib_invocation_count',
help: 'A simple counter for app access during runtime created with prometheus nodejs library'
});
const libUptime = new Prometheus.Counter({
name: 'lib_upTime',
help: 'uptime A counter of the application\'s uptime in seconds created with prometheus nodejs library.'
})
console.log('mongousr: ', process.env.mongousr);
console.log('mongopwd: ', process.env.mongopwd);
// Prometheus Default Metrics collector
const collectDefaultMetrics = Prometheus.collectDefaultMetrics;
// Probe every 5th second.
collectDefaultMetrics({ timeout: 5000 });
// new schema model object based on the structure of what I want to put on MongoDB collection
var testSchema = new Schema({
thingies: {
type: String
}
},{
collection: 'test'
});
// new object that will hold the data using model structure made above
var thingies = mongoose.model('thingieName', testSchema);
// Default message for testing
app.get('/', (req, res, next)=>{
// res.json([{message:'yes, your nodejs app is really running'}]);
res.send('Oh hay');
counter++; // for prometheus invocation_count metric
libCounter.inc(); // for prometheus lib_invocation_count metric
console.log('Hello, I\'m inside endpoint \'/\'');
console.log('HTTP headers below:');
console.log(req.headers);
console.log('Cookies: ', req.cookies);
console.log('Cookies: ', res.cookies);
next();
});
// cookie experiments endpoint
app.get('/cookie', function(req, res, next) {
// res.cookie('cookiename', 'cookievalue');
res.setHeader('Set-Cookie', 'cookiename=cookievalue; HttpOnly');
// res.json({message: 'I am inside endpoint /cookie'});
res.json(JSON.stringify(req.headers));
res.end();
console.log('Learned that cookies when set will not appear immediatly but they will on the next request.');
console.log('\x1b[35m', 'Cookies: ', req.cookies);
console.log('\x1b[35m', 'Cookies: ', res.cookies);
console.log('\x1b[35m', 'Headers:');
console.log(req.headers);
console.log('\x1b[35m', 'req.headers[\'cookie\']:');
console.log(req.headers['cookie']);
let headerToken = req.headers['cookie'];
let cookieArray = headerToken.split(" ");
console.log('\x1b[35m', 'cookieArray variable below:');
console.log(cookieArray);
console.log('\x1b[35m', 'cookieArray[0] below:');
console.log(cookieArray[0]);
console.log('\x1b[35m', 'cookieArray[1] below:');
console.log(cookieArray[1]);
console.log('\x1b[35m', 'cookieArray[2] below:');
console.log(cookieArray[2]);
});
// Test endpoint for md files rendering
app.get('/test', function(req, res) {
var path = '/app/README.md';
var file = fs.readFileSync(path, 'utf8');
res.send(marked(file.toString()));
});
// Prometheus metrics endpoint - Library
app.get('/metrics', function(req, res){
libUptime.inc(Math.floor(process.uptime()));
res.set('Content-Type', Prometheus.register.contentType)
res.end(Prometheus.register.metrics())
libUptime.reset();
});
// Prometheus metrics endpoint - Handmade
app.get('/metrics2', function(req, res){
var now = new Date();
var passedTime = now - today;
res.writeHead(200, {'Content-Type':'text/plain'});
res.write('# HELP uptime A counter of the application\'s uptime in millisenconds.' + '\n');
res.write('# TYPE uptime counter' + '\n');
res.write('uptime ' + passedTime + '\n');
res.write('# HELP invocation_count A simple counter for app access during runtime' + '\n');
res.write('# TYPE invocation_count counter'+ '\n');
res.write('invocation_count ' + counter + '\n');
res.end();
})
// JWT generation
app.use(bodyParser.urlencoded({ extended: false }));
app.post('/token', function(req, res) {
const claims_power = {
username: req.body.username,
password: req.body.password,
subject: 'power#1234',
issuer: 'http://youcantrustme.io',
scope: 'admin'
};
const claims_user = {
username: req.body.username,
password: req.body.password,
subject: 'normal_user',
issuer: 'http://youcantrustme.io',
scope: 'user'
};
switch(req.body.username) {
case 'user1':
if (req.body.password === 'pass1') {
token = jwt.sign(claims_user, secret);
// res.cookie('token',token);
res.setHeader('Set-Cookie', 'token=' + token + '; HttpOnly');
res.setHeader('Set-Cookie', 'Authorization=Bearer ' + token + '; HttpOnly');
console.log('JWT Token: ' + token);
console.log(jwt.decode(token));
res.redirect('http://localhost/yay.html');
} else {
res.redirect('http://localhost/nay.html');
}
break;
case 'power':
if (req.body.password === 'weak') {
token = jwt.sign(claims_power, secret);
// res.cookie('token',token);
res.setHeader('Set-Cookie', 'token=' + token + '; HttpOnly');
console.log('JWT Token: ' + token);
console.log(jwt.decode(token));
res.redirect('http://localhost/yay.html');
} else {
res.redirect('http://localhost/nay.html');
}
break;
default:
res.status(500).send('User not found');
}
console.log('http headers below:');
console.log(req.headers);
});
// Restricted route root
const restrictedRoutes = express.Router();
app.use('/', restrictedRoutes);
restrictedRoutes.use(function (req, res, next) {
let sentToken = req.headers['token'];
if (sentToken) {
jwt.verify(sentToken, secret, function (err, decoded) {
if (err) {
return res.json({ message: 'invalid token' });
} else {
req.decoded = decoded;
console.log(decoded);
console.log(req.decoded['scope']);
switch(req.decoded['scope']) {
case 'user':
res.status(200).send('Need ADMIN scope to access this');
break;
case 'admin':
next();
break;
default:
res.status(401).send('Not authorized');
}
}
});
} else {
res.status(500).send({ message: 'no token found' });
};
});
// // Restricted route root stupid
// const restrictedRoutes = express.Router();
// app.use('/restricted', restrictedRoutes);
// restrictedRoutes.use( function(req, res, next){
// let sentToken = req.headers['token'];
// console.log('hello there, do not mind me.');
// console.log('next line will show the JWT token:');
// console.log(sentToken);
// console.log('okay, so, next line will show the decoded JWT token:');
// let decodedToken = jwt.decode(sentToken);
// console.log(decodedToken);
// console.log('yay, so now I am going to verify it and show again the decoded token if successful.');
// console.log('if NOT successful I will not let you see the secret message');
// console.log('here we go...');
// let verifiedToken = jwt.verify(sentToken, secret);
// console.log(verifiedToken);
// if (verifiedToken) {
// console.log('success! secret message will be shown.');
// next();
// } else {
// res.status(401).json({message: 'nope, you are not authorized'});
// }
// });
// Restricted endpoint
restrictedRoutes.get('/restricted', (req, res) => {
// successMsg = JSON.stringify({secret:'You have access to restricted contents!'});
res.status(200).json([{secret:'You have access to restricted contents!'}]);
// res.status(200).send(successMsg);
console.log(successMsg);
});
// Restricted route root test (KISS)
const router = express.Router();
app.use('/api', router);
router.use( function(req, res, next){
console.log('yo, this should always be called whenever /api or anything inside is called');
next();
});
// Restricted route endpoint test (KISS)
router.get('/inside', (req, res) => {
console.log('I am inside /api, hopefully');
res.status(200).json({message: 'it worked'});
})
// JWT decode test
app.get('/decode', function(req, res){
let sentToken = req.headers['token'];
if (sentToken) {
var decode = jwt.verify(sentToken, secret);
console.log(decode);
res.status(200).send('success');
}
})
// Mongo query
app.get('/info', function(req, res){
thingies.find({}).then(function (thingies) {
res.json(thingies);
});
});
// Mongo insert
app.post('/info/add/:name', function(req, res){
var item = {thingies: req.params.name};
var data = new thingies(item);
data.save();
res.send('thingie ' + req.params.name + ' added to database' + '\n');
});
connectWithRetry();
app.listen(3001, () => {
console.log('Server running on port 3001');
console.log('process.env.PORT: ' + process.env.PORT);
});