diff --git a/README.md b/README.md index 31facb7..25a2524 100755 --- a/README.md +++ b/README.md @@ -20,4 +20,8 @@ Crie um endpoint REST '/restricted' que receba o token JWT e retorne o JSON "{me Quinta tarefa: -Altere o serviço '/restricted' e adicione ao cabeçalho HTTP de retorno 'HOSTNAME=[container-hostname]' para identificarmos a instância do container que atendeu à requisição. Mande o print da chamada cURL mostrando esse cabeçalho HTTP na resposta. \ No newline at end of file +Altere o serviço '/restricted' e adicione ao cabeçalho HTTP de retorno 'HOSTNAME=[container-hostname]' para identificarmos a instância do container que atendeu à requisição. Mande o print da chamada cURL mostrando esse cabeçalho HTTP na resposta. + +Sexta tarefa: + +Levante a página e o serviço REST em Swarm Mode. Escale o container do NodeJS para 6 instâncias e do NGINX para 3 instâncias. Altere a página HTML para mostrar o nome do hostname retornado no cabeçalho de /restricted pra vc saber qual instância te respondeu. Mande o print da página HTML funcionando, demonstrando que a cada requisição uma instância diferente de NodeJS responde à requisição. \ No newline at end of file diff --git a/node/app.js b/node/app.js index 67acb30..2e2b847 100755 --- a/node/app.js +++ b/node/app.js @@ -1,45 +1,48 @@ 'use strict' -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 successUrl = 'http://localhost:3002/yay.html'; -const failureUrl = 'http://localhost:3002/nay.html'; -const cookieParser = require('cookie-parser'); - -app.use(cookieParser()); - -// const morgan = require('morgan'); +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 successUrl = 'yay.html' +const failureUrl = 'nay.html' +const cookieParser = require('cookie-parser') +const os = require('os') + +app.use(cookieParser()) + +app.use(express.static('html')) + +// const morgan = require('morgan') // // use morgan to log requests to the console -// app.use(morgan('dev')); +// 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 -// }); +// 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 +// 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(); -// }); +// next() +// }) // setting CORS headers app.all('/', function(req, res, next) { - res.header("Access-Control-Allow-Origin", "*"); - res.header("Access-Control-Allow-Headers", "X-Requested-With"); + res.header("Access-Control-Allow-Origin", "*") + res.header("Access-Control-Allow-Headers", "X-Requested-With") next() -}); +}) // database connection (with retries) const options = { @@ -65,20 +68,20 @@ const connectWithRetry = () => { 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); +console.log('mongousr: ', process.env.mongousr) +console.log('mongopwd: ', process.env.mongopwd) // Prometheus Default Metrics collector -const collectDefaultMetrics = Prometheus.collectDefaultMetrics; +const collectDefaultMetrics = Prometheus.collectDefaultMetrics // Probe every 5th second. -collectDefaultMetrics({ timeout: 5000 }); +collectDefaultMetrics({ timeout: 5000 }) // new schema model object based on the structure of what I want to put on MongoDB collection var testSchema = new Schema({ @@ -87,79 +90,81 @@ var testSchema = new Schema({ } },{ collection: 'test' -}); +}) // new object that will hold the data using model structure made above -var thingies = mongoose.model('thingieName', testSchema); +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' + '\n'); - 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(); -}); + res.json([{message:'yes, your nodejs app is really running'}]) + // res.send('Oh hay' + '\n') + 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) + console.log('\x1b[35m', 'HOSTNAME below:') + console.log(os.hostname()) + next() +}) // cookie experiments endpoint app.get('/cookie', function(req, res, next) { - // res.cookie('cookiename', 'cookievalue'); - // res.setHeader('Set-Cookie', 'cookiename=cookievalue; HttpOnly'); - // res.cookie('foo3', 'bar3', { maxAge: 900000, httpOnly: true }); - res.json({message: 'I am inside endpoint /cookie'}); - res.json(JSON.stringify(req.headers)); - res.end(); - console.log('\x1b[35m', 'Cookies: ', req.cookies); - console.log('\x1b[35m', 'req.cookies.token below:'); - console.log(req.cookies.token); -}); + // res.cookie('cookiename', 'cookievalue') + // res.setHeader('Set-Cookie', 'cookiename=cookievalue HttpOnly') + // res.cookie('foo3', 'bar3', { maxAge: 900000, httpOnly: true }) + res.json({message: 'I am inside endpoint /cookie'}) + res.json(JSON.stringify(req.headers)) + res.end() + console.log('\x1b[35m', 'Cookies: ', req.cookies) + console.log('\x1b[35m', 'req.cookies.token below:') + console.log(req.cookies.token) +}) // Clear cookies app.get('/clear', function(req, res) { - res.clearCookie('token'); - res.clearCookie('cookiename'); - res.clearCookie('Authorization'); - res.clearCookie('foo3'); - console.log(req.cookies); - res.status(200).send('Cookies cleared'); + res.clearCookie('token') + res.clearCookie('cookiename') + res.clearCookie('Authorization') + res.clearCookie('foo3') + console.log(req.cookies) + res.status(200).send('Cookies cleared') }) // 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())); -}); + 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())); + libUptime.inc(Math.floor(process.uptime())) res.set('Content-Type', Prometheus.register.contentType) res.end(Prometheus.register.metrics()) - libUptime.reset(); -}); + 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(); + 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.use(bodyParser.urlencoded({ extended: false })) app.post('/token', function(req, res) { @@ -169,7 +174,7 @@ app.post('/token', function(req, res) { subject: 'power#1234', issuer: 'http://youcantrustme.io', scope: 'admin' - }; + } const claims_user = { username: req.body.username, @@ -177,158 +182,158 @@ app.post('/token', function(req, res) { subject: 'normal_user', issuer: 'http://youcantrustme.io', scope: 'user' - }; + } switch(req.body.username) { case 'user1': if (req.body.password === 'pass1') { - let 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(successUrl); + let 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(successUrl) } else { - res.redirect(failureUrl); + res.redirect(failureUrl) } - break; + break case 'power': if (req.body.password === 'weak') { - let 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(successUrl); + let 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(successUrl) } else { - res.redirect(failureUrl); + res.redirect(failureUrl) } - break; + break default: - res.status(500).send('User not found'); + res.status(500).send('User not found') } - console.log('http headers below:'); - console.log(req.headers); -}); + console.log('http headers below:') + console.log(req.headers) +}) // Restricted route root -const restrictedRoutes = express.Router(); -app.use('/restricted', restrictedRoutes); +const restrictedRoutes = express.Router() +app.use('/restricted', restrictedRoutes) // setting CORS headers restrictedRoutes.all('/', function(req, res, next) { - res.header("Access-Control-Allow-Origin", "*"); - res.header("Access-Control-Allow-Headers", "X-Requested-With"); + res.header("Access-Control-Allow-Origin", "*") + res.header("Access-Control-Allow-Headers", "X-Requested-With") next() -}); +}) restrictedRoutes.use(function (req, res, next) { - // let sentToken = req.headers['token']; - // let sentToken = req.cookies.token; + // let hostname = os.hostname() + res.setHeader('HOSTNAME', os.hostname()) if (req.cookies.token) { jwt.verify(req.cookies.token, secret, function (err, decoded) { if (err) { - return res.json({ message: 'invalid token' }); + res.json({ message: 'invalid token' }) } else { - req.decoded = decoded; - console.log(decoded); - console.log(req.decoded['scope']); + req.decoded = decoded + console.log(decoded) + console.log(req.decoded['scope']) switch(req.decoded['scope']) { case 'user': - res.status(200).json([{message: 'Need ADMIN scope to access this'}]); - break; + res.status(200).json([{message: 'Need ADMIN scope to access the good stuff'}]) + break case 'admin': - next(); - break; + next() + break default: - res.status(401).json([{message: 'Not authorized'}]); + res.status(401).json([{message: 'Not authorized'}]) } } - }); + }) } else { - res.status(500).send({ message: 'no token found' }); - }; -}); + res.status(500).json({ message: 'no token found' }) + } +}) + +// Restricted endpoint +restrictedRoutes.get('/', (req, res) => { + // let 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(JSON.stringify({secret:'You have access to restricted contents!'})) +}) // // Restricted route root stupid -// const restrictedRoutes = express.Router(); -// app.use('/restricted', restrictedRoutes); +// 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); +// 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(); +// console.log('success! secret message will be shown.') +// next() // } else { -// res.status(401).json({message: 'nope, you are not authorized'}); +// res.status(401).json({message: 'nope, you are not authorized'}) // } -// }); - -// Restricted endpoint -restrictedRoutes.get('/', (req, res) => { - // let 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(JSON.stringify({secret:'You have access to restricted contents!'})); -}); +// }) // Restricted route root test (KISS) -const router = express.Router(); -app.use('/api', router); +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(); -}); + 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'}); + 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']; + let sentToken = req.headers['token'] if (sentToken) { - var decode = jwt.verify(sentToken, secret); - console.log(decode); - res.status(200).send('success'); + 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); - }); -}); + 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'); -}); + var item = {thingies: req.params.name} + var data = new thingies(item) + data.save() + res.send('thingie ' + req.params.name + ' added to database' + '\n') +}) -connectWithRetry(); +connectWithRetry() app.listen(3001, () => { - console.log('Server running on port 3001'); - console.log('process.env.PORT: ' + process.env.PORT); -}); \ No newline at end of file + console.log('Server running on port 3001') + console.log('process.env.PORT: ' + process.env.PORT) +}) \ No newline at end of file diff --git a/nginx/html/nay.html b/node/html/nay.html similarity index 100% rename from nginx/html/nay.html rename to node/html/nay.html diff --git a/nginx/html/yay.html b/node/html/yay.html similarity index 95% rename from nginx/html/yay.html rename to node/html/yay.html index 9deafdf..8aca960 100644 --- a/nginx/html/yay.html +++ b/node/html/yay.html @@ -16,11 +16,8 @@ } - -
-