From 821334fd68931e47a37ae697f936f5ee812b6a28 Mon Sep 17 00:00:00 2001 From: rchristian Date: Fri, 13 Jul 2018 18:26:51 -0700 Subject: [PATCH 01/25] Fix code-smells like redudant comments, lack of spacing, missing var/const/let, replace vars with consts, etc. Add useBasicAuth to make it actually work. --- .env-example | 2 + .gitignore | 3 +- include/auth.js | 36 ------------- include/config.js | 5 -- index.js | 41 +++++++++++++++ lib/auth.js | 48 +++++++++++++++++ lib/config.js | 5 ++ lib/index.js | 129 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 5 +- routes/users.js | 88 ------------------------------- server.js | 45 ---------------- 11 files changed, 230 insertions(+), 177 deletions(-) create mode 100644 .env-example delete mode 100644 include/auth.js delete mode 100644 include/config.js create mode 100644 index.js create mode 100644 lib/auth.js create mode 100644 lib/config.js create mode 100644 lib/index.js delete mode 100644 routes/users.js delete mode 100644 server.js diff --git a/.env-example b/.env-example new file mode 100644 index 0000000..d4b2142 --- /dev/null +++ b/.env-example @@ -0,0 +1,2 @@ +DB_USERPASS=mysecuredbpassword +DB_USERNAME=dbuser \ No newline at end of file diff --git a/.gitignore b/.gitignore index 40b878d..3ec544c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -node_modules/ \ No newline at end of file +node_modules/ +.env \ No newline at end of file diff --git a/include/auth.js b/include/auth.js deleted file mode 100644 index 2afbe09..0000000 --- a/include/auth.js +++ /dev/null @@ -1,36 +0,0 @@ -var JwtStrategy = require('passport-jwt').Strategy, - ExtractJwt = require('passport-jwt').ExtractJwt; -var config = require('./../include/config'); - -module.exports = function(passport) { - var opts = {}; - opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme('jwt'); - opts.secretOrKey = config.jwt_secret; - passport.use(new JwtStrategy(opts, function(jwt_payload, done) { - if (jwt_payload.expiration <= Date.now()){ - return done(null, false, {msg: 'Token expired.'}); - }else{ - return done(null, jwt_payload); - } - })); - return { - initialize: function() { - return passport.initialize(); - }, - authenticate: function() { - return passport.authenticate('jwt', { session: false}); - }, - getToken: function (headers) { - if (headers && headers.authorization) { - var parted = headers.authorization.split(' '); - if (parted.length === 2) { - return parted[1]; - } else { - return null; - } - } else { - return null; - } - } - }; -}; \ No newline at end of file diff --git a/include/config.js b/include/config.js deleted file mode 100644 index 05fcc09..0000000 --- a/include/config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - 'jwt_secret': 'devdacticIsAwesome', - 'db_location': 'http://localhost:8529/', //your ArangoDB location - 'db_name':'database', //your ArangoDB database -}; \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..1dee167 --- /dev/null +++ b/index.js @@ -0,0 +1,41 @@ +'use strict' + +require('dotenv').config() + +const express = require('express') +const app = express() +const helmet = require('helmet') +const bodyParser = require('body-parser') +const morgan = require('morgan') +const authRoutes = require('./lib') +const port = process.env.PORT || 4000 + +app.use(bodyParser.urlencoded({ extended: false })) +app.use(bodyParser.json()) + +app.use(morgan('dev')) + +// use security middleware +app.use(helmet()) + +app.get('/', (req, res)=> { + res.send(`Hello! The API is at http://localhost:${port}/api`) +}) + +app.all('/api/*', (req, res, next)=> { + res.set('Access-Control-Allow-Origin', '*') + res.set('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT') + res.set('Access-Control-Allow-Headers', 'Content-Type, Authorization') + if (req.method=='OPTIONS') return res.sendStatus(200) + next() +}) + +app.get('/api/', (req, res)=> { + res.send(`Hello! This is the API at http://localhost:${port}/api`) +}) + +app.use('/api/users', authRoutes) + +app.listen(port, ()=> { + console.log(`API is now running on http://localhost:${port}`) +}) diff --git a/lib/auth.js b/lib/auth.js new file mode 100644 index 0000000..8639937 --- /dev/null +++ b/lib/auth.js @@ -0,0 +1,48 @@ +'use strict' + +const { Strategy: StrategyJwt, ExtractJwt } = require('passport-jwt') +const config = require('./config') +const passport = require('passport') + + +const opts = { + jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme('jwt'), + secretOrKey: config.jwt_secret, +} + +passport.use(new StrategyJwt(opts, (jwt_payload, done)=> { + + return (jwt_payload.expiration <= Date.now()) ? ( + done(null, false, {msg: 'Token expired.'}) + ) : ( + done(null, jwt_payload) + ) + +})) + +module.exports = { + + initialize: function() { + return passport.initialize() + }, + + authenticate: function() { + return passport.authenticate('jwt', { session: false}) + }, + + getToken: function (headers) { + + if (headers && headers.authorization) { + + const parted = headers.authorization.split(' ') + + return (parted.length === 2) ? parted[1] : null + + } + + else { + return null + } + + } +} diff --git a/lib/config.js b/lib/config.js new file mode 100644 index 0000000..45bf2c1 --- /dev/null +++ b/lib/config.js @@ -0,0 +1,5 @@ +module.exports = { + jwt_secret: 'devdacticIsAwesome', + db_location: 'http://localhost:8529', // 192.168.99.100:30981 + db_name: 'jwt-demo', +} \ No newline at end of file diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..3276907 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,129 @@ +'use strict' + +const { DB_USERNAME, DB_USERPASS } = process.env + +const express = require('express') +const apiRoutes = express.Router() +const bcrypt = require('bcryptjs') +const config = require('./config') +const jwt = require('jwt-simple') +const auth = require('./auth') + +const second = 1000 +const minute = 60 * second +const hour = 60 * minute +const day = 24 * hour + +const { Database } = require('arangojs') +const db = new Database(config.db_location) +db.useDatabase(config.db_name) +db.useBasicAuth(DB_USERNAME, DB_USERPASS) + +apiRoutes.use(auth.initialize()) + +apiRoutes.post('/register', (req, res)=> { + + if (!req.body.username || !req.body.password) { + return res.json({ + success: false, + msg: 'Please pass username and password.', + }) + } + + const doc = { + username: req.body.username, + password: bcrypt.hashSync(req.body.password, 10), + } + + ;(async ()=> { + + try { + const cursor = await db.query(`FOR x IN users FILTER x.username=="${doc.username}" RETURN "true"`) + const result = await cursor.next() + + if (!result) { + await db.collection('users').save(doc) + res.json({ success: true, msg: 'Successful created new user' }) + } + + else { + res.json({ success: false, msg: 'Username already exists.' }) + } + + } catch (err) { + console.log(err) + res.send({ success: false, msg: err.message}) + } + + })() +}) + +apiRoutes.post('/authenticate', (req, res)=> { + + if (req.body.username && req.body.password) { + + ;(async ()=> { + + try { + const cursor = await db.query(`FOR x IN users FILTER x.username=="${req.body.username}" RETURN { username: x.username, password:x.password }`) + const result = await cursor.next() + + // if user is found and password is correct return a token with payload + if (result && bcrypt.compareSync(req.body.password, result.password)) { + + const payload = { + username: result.username, + expiration: Date.now() + 2 * day, + } + + const token = jwt.encode(payload, config.jwt_secret) + res.json({ + success: true, + token: `JWT ${token}`, + payload: payload + }) + } + + else { + res.send({ success: false, msg: 'Authentication failed.' }) + } + + } catch (err) { + res.send({ success: false, msg: 'Authentication failed.' }) + } + + })() + } + + else { + res.send({ success: false, msg: 'Authentication failed.' }) + } +}) + +// route to a restricted info (GET /api/users/memberinfo) +apiRoutes.get('/memberinfo', auth.authenticate(), (req, res)=> { + + const decoded = jwt.decode(auth.getToken(req.headers), config.jwt_secret) + + if (decoded) { + + db.query(`FOR x IN users FILTER x.username=="${decoded.username}" RETURN x`, (err, user, fields)=> { + + if (err) throw err + + else if (user._result[0]) { + res.json({ success: true, msg: 'Welcome in the member area, this is your data:', data: user._result[0] }) + } + + else { + return res.send({ success: false, msg: 'Authentication failed. User not found.' }) + } + }) + } + + else { + return res.send({ success: false, msg: 'No token provided.' }) + } +}) + +module.exports = apiRoutes diff --git a/package.json b/package.json index f7c003c..9a6647e 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,12 @@ { "name": "node-rest-auth-arangodb", - "main": "server.js", + "main": "index.js", "dependencies": { "arango": "*", "arangojs": "^5.4.2", "bcryptjs": "*", "body-parser": "*", + "dotenv": "^6.0.0", "express": "*", "helmet": "^3.12.0", "jwt-simple": "*", @@ -14,7 +15,7 @@ "passport-jwt": "*" }, "scripts": { - "start": "node server.js" + "start": "node index.js" }, "version": "1.0.0", "description": "Creating API with JWT user authentication using Express, Passport JWT and ArangoDB", diff --git a/routes/users.js b/routes/users.js deleted file mode 100644 index c5d6cbb..0000000 --- a/routes/users.js +++ /dev/null @@ -1,88 +0,0 @@ -var express = require('express'); -var apiRoutes = express.Router(); -var bcrypt = require('bcryptjs'); -var config = require('./../include/config.js'); -var jwt = require('jwt-simple'); - -// connect to database -var Database = require('arangojs').Database; -var db = new Database(config.db_location); -db.useDatabase(config.db_name); - -// include passport -var passport = require('passport'); -var auth = require('./../include/auth.js')(passport); -apiRoutes.use(auth.initialize()); - -// create a new user account (POST /api/users/register) -apiRoutes.post('/register', function(req, res) { - if (!req.body.username || !req.body.password) { - res.json({success: false, msg: 'Please pass username and password.'}); - } else { - doc = { - "username": req.body.username, - "password": bcrypt.hashSync(req.body.password, 10) - }; - (async ()=>{ - try { - const cursor = await db.query('FOR x IN users FILTER x.username=="'+doc.username+'" RETURN "true"'); - const result = await cursor.next(); - // if username is available create new user - if(!result){ - await db.collection('users').save(doc); - res.json({success: true, msg: 'Successful created new user'}); - }else{ - res.json({success: false, msg: 'Username already exists.'}) - } - } catch (err) { - res.send({success: false, msg: 'Registration failed.'}); - } - })(); - } -}); - -// route to authenticate a user (POST /api/users/authenticate) -apiRoutes.post('/authenticate', function(req, res) { - if (req.body.username && req.body.password) { - (async ()=>{ - try { - const cursor = await db.query('FOR x IN users FILTER x.username=="'+req.body.username+'" RETURN {username: x.username, password:x.password}'); - const result = await cursor.next(); - // if user is found and password is correct return a token with payload - if(result && bcrypt.compareSync(req.body.password, result['password'])){ - var payload = { - username: result['username'], - expiration: Date.now() + 1000 * 60 * 60 * 48 //48 hours - } - var token = jwt.encode(payload, config.jwt_secret); - res.json({success: true, token: 'JWT ' + token, payload: payload}); - }else{ - res.send({success: false, msg: 'Authentication failed.'}); - } - } catch (err) { - res.send({success: false, msg: 'Authentication failed.'}); - } - })(); - }else{ - res.send({success: false, msg: 'Authentication failed.'}); - } -}); - -// route to a restricted info (GET /api/users/memberinfo) -apiRoutes.get('/memberinfo', auth.authenticate(), function(req, res) { - var decoded = jwt.decode(auth.getToken(req.headers), config.jwt_secret); - if (decoded) { - db.query('FOR x IN users FILTER x.username=="'+decoded.username+'" RETURN x', function (err, user, fields) { - if(err) throw err; - else if(user['_result'][0]){ - res.json({success: true, msg: 'Welcome in the member area, this is your data:', data: user['_result'][0]}); - }else{ - return res.send({success: false, msg: 'Authentication failed. User not found.'}); - } - }); - } else { - return res.send({success: false, msg: 'No token provided.'}); - } -}); - -module.exports = apiRoutes; \ No newline at end of file diff --git a/server.js b/server.js deleted file mode 100644 index e6a0944..0000000 --- a/server.js +++ /dev/null @@ -1,45 +0,0 @@ -var express = require('express'); -var app = express(); -var helmet = require("helmet"); -var bodyParser = require('body-parser'); -var morgan = require('morgan'); -var config = require('./include/config'); -var port = process.env.PORT || 4000; -var users = require('./routes/users'); - -// get our request parameters -app.use(bodyParser.urlencoded({ extended: false })); -app.use(bodyParser.json()); - -// log to console -app.use(morgan('dev')); - -// use security middleware -app.use(helmet()); - -// initial view (GET /) -app.get('/', function(req, res) { - res.send('Hello! The API is at http://localhost:' + port + '/api'); -}); - - // all api views (ALL /api/*) -app.all('/api/*', function(req, res, next) { - res.set('Access-Control-Allow-Origin', '*'); //set allowed origin or wildcard '*' - res.set('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT'); - res.set('Access-Control-Allow-Headers', 'Content-Type, Authorization'); - if (req.method=='OPTIONS') return res.sendStatus(200); - next(); -}); - -// initial api view (GET /api/) -app.get('/api/', function(req, res) { - res.send('Hello! This is the API at http://localhost:' + port + '/api'); -}); - -// connect the api routes under /api/* -app.use('/api/users', users); - -// start the server -app.listen(port, function() { - console.log('My API is running on http://localhost:' + port); -}); \ No newline at end of file From e3cb1fccdd4cf2cf082db263ef1b26a0d6062511 Mon Sep 17 00:00:00 2001 From: rchristian Date: Fri, 13 Jul 2018 19:17:25 -0700 Subject: [PATCH 02/25] Prevent parameter injection --- .gitignore | 3 ++- lib/index.js | 21 +++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 3ec544c..8636d04 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ -.env \ No newline at end of file +.env +yarn.lock \ No newline at end of file diff --git a/lib/index.js b/lib/index.js index 3276907..24037c2 100644 --- a/lib/index.js +++ b/lib/index.js @@ -14,7 +14,7 @@ const minute = 60 * second const hour = 60 * minute const day = 24 * hour -const { Database } = require('arangojs') +const { Database, aql } = require('arangojs') const db = new Database(config.db_location) db.useDatabase(config.db_name) db.useBasicAuth(DB_USERNAME, DB_USERPASS) @@ -38,7 +38,8 @@ apiRoutes.post('/register', (req, res)=> { ;(async ()=> { try { - const cursor = await db.query(`FOR x IN users FILTER x.username=="${doc.username}" RETURN "true"`) + const { username } = doc + const cursor = await db.query(aql`FOR x IN users FILTER x.username==${String(username)} RETURN "true"`) const result = await cursor.next() if (!result) { @@ -65,7 +66,8 @@ apiRoutes.post('/authenticate', (req, res)=> { ;(async ()=> { try { - const cursor = await db.query(`FOR x IN users FILTER x.username=="${req.body.username}" RETURN { username: x.username, password:x.password }`) + const { username } = req.body + const cursor = await db.query(aql`FOR x IN users FILTER x.username==${String(username)} RETURN { username: x.username, password:x.password }`) const result = await cursor.next() // if user is found and password is correct return a token with payload @@ -107,16 +109,23 @@ apiRoutes.get('/memberinfo', auth.authenticate(), (req, res)=> { if (decoded) { - db.query(`FOR x IN users FILTER x.username=="${decoded.username}" RETURN x`, (err, user, fields)=> { + db.query(aql`FOR x IN users FILTER x.username==${String(decoded.username)} RETURN x`, (err, user, fields)=> { if (err) throw err else if (user._result[0]) { - res.json({ success: true, msg: 'Welcome in the member area, this is your data:', data: user._result[0] }) + res.json({ + success: true, + msg: 'Welcome in the member area, this is your data:', + data: user._result[0], + }) } else { - return res.send({ success: false, msg: 'Authentication failed. User not found.' }) + return res.send({ + success: false, + msg: 'Authentication failed. User not found.', + }) } }) } From 3d943bec562cd8c72a49bee6018bf1131d1d86c5 Mon Sep 17 00:00:00 2001 From: Rob Christian Date: Sat, 14 Jul 2018 07:35:27 -0700 Subject: [PATCH 03/25] - --- lib/index.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/index.js b/lib/index.js index 24037c2..f1a5f2d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -39,7 +39,9 @@ apiRoutes.post('/register', (req, res)=> { try { const { username } = doc - const cursor = await db.query(aql`FOR x IN users FILTER x.username==${String(username)} RETURN "true"`) + const cursor = await db.query(aql`FOR x IN users + FILTER x.username==${String(username)} + RETURN "true"`) const result = await cursor.next() if (!result) { @@ -67,7 +69,9 @@ apiRoutes.post('/authenticate', (req, res)=> { try { const { username } = req.body - const cursor = await db.query(aql`FOR x IN users FILTER x.username==${String(username)} RETURN { username: x.username, password:x.password }`) + const cursor = await db.query(aql`FOR x IN users + FILTER x.username==${String(username)} + RETURN { username: x.username, password: x.password }`) const result = await cursor.next() // if user is found and password is correct return a token with payload @@ -109,7 +113,9 @@ apiRoutes.get('/memberinfo', auth.authenticate(), (req, res)=> { if (decoded) { - db.query(aql`FOR x IN users FILTER x.username==${String(decoded.username)} RETURN x`, (err, user, fields)=> { + db.query(aql`FOR x IN users + FILTER x.username==${String(decoded.username)} + RETURN x`, (err, user, fields)=> { if (err) throw err From a3b7ffb55b67631b16c5293b9bd689c1c6b65747 Mon Sep 17 00:00:00 2001 From: Rob Christian Date: Sat, 14 Jul 2018 08:03:18 -0700 Subject: [PATCH 04/25] Remove unnecessary IIFE, use more destructuring --- index.js | 2 +- lib/index.js | 54 ++++++++++++++++++++++++---------------------------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/index.js b/index.js index 1dee167..f59afe6 100644 --- a/index.js +++ b/index.js @@ -8,7 +8,7 @@ const helmet = require('helmet') const bodyParser = require('body-parser') const morgan = require('morgan') const authRoutes = require('./lib') -const port = process.env.PORT || 4000 +const port = process.env.PORT || 8080 app.use(bodyParser.urlencoded({ extended: false })) app.use(bodyParser.json()) diff --git a/lib/index.js b/lib/index.js index f1a5f2d..0f25b9a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -21,61 +21,57 @@ db.useBasicAuth(DB_USERNAME, DB_USERPASS) apiRoutes.use(auth.initialize()) -apiRoutes.post('/register', (req, res)=> { +apiRoutes.post('/register', async (req, res)=> { - if (!req.body.username || !req.body.password) { + const { username, password: _password } = req.body + + if (!username || !_password) { return res.json({ success: false, msg: 'Please pass username and password.', }) } - const doc = { - username: req.body.username, - password: bcrypt.hashSync(req.body.password, 10), - } - - ;(async ()=> { + const password = bcrypt.hashSync(_password, 10) - try { - const { username } = doc - const cursor = await db.query(aql`FOR x IN users - FILTER x.username==${String(username)} - RETURN "true"`) - const result = await cursor.next() + try { + const cursor = await db.query(aql`FOR x IN users + FILTER x.username==${String(username)} + RETURN "true"`) + const result = await cursor.next() - if (!result) { - await db.collection('users').save(doc) - res.json({ success: true, msg: 'Successful created new user' }) - } - - else { - res.json({ success: false, msg: 'Username already exists.' }) - } + if (!result) { + await db.collection('users').save({ username, password }) + res.json({ success: true, msg: 'Successful created new user' }) + } - } catch (err) { - console.log(err) - res.send({ success: false, msg: err.message}) + else { + res.json({ success: false, msg: 'Username already exists.' }) } - })() + } catch (err) { + console.log(err) + res.send({ success: false, msg: err.message}) + } + }) apiRoutes.post('/authenticate', (req, res)=> { - if (req.body.username && req.body.password) { + const { username, password } = req.body + + if (username && password) { ;(async ()=> { try { - const { username } = req.body const cursor = await db.query(aql`FOR x IN users FILTER x.username==${String(username)} RETURN { username: x.username, password: x.password }`) const result = await cursor.next() // if user is found and password is correct return a token with payload - if (result && bcrypt.compareSync(req.body.password, result.password)) { + if (result && bcrypt.compareSync(password, result.password)) { const payload = { username: result.username, From 5c04672b479801d9ba33d9c853f45e5999187c09 Mon Sep 17 00:00:00 2001 From: rchristian Date: Mon, 16 Jul 2018 14:45:15 -0700 Subject: [PATCH 05/25] add docker launch script --- scripts/launch.sh | 1 + 1 file changed, 1 insertion(+) create mode 100755 scripts/launch.sh diff --git a/scripts/launch.sh b/scripts/launch.sh new file mode 100755 index 0000000..8ab683d --- /dev/null +++ b/scripts/launch.sh @@ -0,0 +1 @@ +docker run -e ARANGO_ROOT_PASSWORD="" -v $PWD:/source -p 8529:8529 arangodb \ No newline at end of file From c32e13dc31aaeaecaf1a4866caaf4f5c31d714e2 Mon Sep 17 00:00:00 2001 From: rchristian Date: Tue, 17 Jul 2018 07:42:25 -0700 Subject: [PATCH 06/25] wip --- .env-example | 6 ++++- .gitignore | 7 ++++- README.md | 21 ++++++++++++++- certs/new-certs.sh | 66 ++++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 9 +++++++ index.js | 30 ++++++++++++++++----- kube/nginx.yml | 23 ++++++++++++++++ kube/proxy.yml | 25 ++++++++++++++++++ lib/auth.js | 4 +-- lib/config.js | 5 ---- lib/index.js | 17 +++++++----- scripts/launch.sh | 1 - 12 files changed, 191 insertions(+), 23 deletions(-) create mode 100755 certs/new-certs.sh create mode 100644 docker-compose.yml create mode 100644 kube/nginx.yml create mode 100644 kube/proxy.yml delete mode 100644 lib/config.js delete mode 100755 scripts/launch.sh diff --git a/.env-example b/.env-example index d4b2142..5bb4efd 100644 --- a/.env-example +++ b/.env-example @@ -1,2 +1,6 @@ +JWT_SECRET=devdacticIsAwesome +ENABLE_HTTPS=true DB_USERPASS=mysecuredbpassword -DB_USERNAME=dbuser \ No newline at end of file +DB_USERNAME=dbuser +DB_LOCATION=https://minikube:30981 +DB_NAME=jwt-demo \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8636d04..b4b6461 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ node_modules/ .env -yarn.lock \ No newline at end of file +yarn.lock +certs/intermediate/ +certs/root-ca/ +certs/out/ +certs/*.key +certs/*.crt \ No newline at end of file diff --git a/README.md b/README.md index b1917df..2927949 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Creating API with JWT user authentication using the following: ## Configure `/include/config.js` 0. Set JWT secret key -1. Set location to ArangoDB +1. Set location to ArangoDB 2. Set database in ArangoDB ## Install @@ -48,6 +48,25 @@ Get user data by providing `token`. Based on https://github.com/clemudensi/nodeJS_backend +## HTTPS + +* [The LetsEncrypt guide for HTTPS on localhost](https://letsencrypt.org/docs/certificates-for-localhost/) +* [Longer explanation here...](https://stackoverflow.com/questions/20433287/node-js-request-cert-has-expired#answer-29397100) +* [Explanation for `certs/new-certs.sh`](https://stackoverflow.com/questions/26759550/how-to-create-own-self-signed-root-certificate-and-intermediate-ca-to-be-importe) + +### For macOS... + +[steps originally found here](https://www.bounca.org/tutorials/install_root_certificate.html) + +To add: +``` +sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ./certs/localhost.crt +``` +To remove: +``` +sudo security delete-certificate -c "localhost" +``` + ## License MIT \ No newline at end of file diff --git a/certs/new-certs.sh b/certs/new-certs.sh new file mode 100755 index 0000000..f02fbc3 --- /dev/null +++ b/certs/new-certs.sh @@ -0,0 +1,66 @@ +#!/bin/bash -x + +set -e + +for C in `echo root-ca intermediate`; do + + mkdir $C + cd $C + mkdir certs crl newcerts private + cd .. + + echo 1000 > $C/serial + touch $C/index.txt $C/index.txt.attr + + echo ' +[ ca ] +default_ca = CA_default +[ CA_default ] +dir = '$C' # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +new_certs_dir = $dir/newcerts # default place for new certs. +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/ca.key.pem # The private key +RANDFILE = $dir/.rnd # private random number file +nameopt = default_ca +certopt = default_ca +policy = policy_match +default_days = 365 +default_md = sha256 + +[ policy_match ] +countryName = optional +stateOrProvinceName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[req] +req_extensions = v3_req +distinguished_name = req_distinguished_name + +[req_distinguished_name] + +[v3_req] +basicConstraints = CA:TRUE +' > $C/openssl.conf +done + +openssl genrsa -out root-ca/private/ca.key 2048 +openssl req -config root-ca/openssl.conf -new -x509 -days 3650 -key root-ca/private/ca.key -sha256 -extensions v3_req -out root-ca/certs/ca.crt -subj '/CN=Root-ca' + +openssl genrsa -out intermediate/private/intermediate.key 2048 +openssl req -config intermediate/openssl.conf -sha256 -new -key intermediate/private/intermediate.key -out intermediate/certs/intermediate.csr -subj '/CN=Interm.' +openssl ca -batch -config root-ca/openssl.conf -keyfile root-ca/private/ca.key -cert root-ca/certs/ca.crt -extensions v3_req -notext -md sha256 -in intermediate/certs/intermediate.csr -out intermediate/certs/intermediate.crt + +mkdir out + +for I in `seq 1 3` ; do + openssl req -new -keyout out/$I.key -out out/$I.request -days 365 -nodes -subj "/CN=$I.example.com" -newkey rsa:2048 + openssl ca -batch -config root-ca/openssl.conf -keyfile intermediate/private/intermediate.key -cert intermediate/certs/intermediate.crt -out out/$I.crt -infiles out/$I.request +done \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f0d1bc8 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +version: '3' + +services: + platform-db: + image: arangodb + environment: + - ARANGO_ROOT_PASSWORD='' + ports: + - 8529:8529 \ No newline at end of file diff --git a/index.js b/index.js index f59afe6..cb623c1 100644 --- a/index.js +++ b/index.js @@ -1,13 +1,17 @@ 'use strict' require('dotenv').config() +const { ENABLE_HTTPS } = process.env -const express = require('express') -const app = express() +const fs = require('fs') +const https = require('https') +const http = require('http') const helmet = require('helmet') const bodyParser = require('body-parser') const morgan = require('morgan') const authRoutes = require('./lib') +const express = require('express') +const app = express() const port = process.env.PORT || 8080 app.use(bodyParser.urlencoded({ extended: false })) @@ -26,7 +30,7 @@ app.all('/api/*', (req, res, next)=> { res.set('Access-Control-Allow-Origin', '*') res.set('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT') res.set('Access-Control-Allow-Headers', 'Content-Type, Authorization') - if (req.method=='OPTIONS') return res.sendStatus(200) + if (req.method == 'OPTIONS') return res.sendStatus(200) next() }) @@ -36,6 +40,20 @@ app.get('/api/', (req, res)=> { app.use('/api/users', authRoutes) -app.listen(port, ()=> { - console.log(`API is now running on http://localhost:${port}`) -}) + +if (JSON.parse(ENABLE_HTTPS)) { + const ssl = { + key: fs.readFileSync('./certs/1.key'), + cert: fs.readFileSync('./certs/root-ca.crt'), + ca: fs.readFileSync('./certs/intermediate.crt'), + } + https.createServer(ssl, app).listen(port, ()=> { + console.log(`API is now running on https://localhost:${port}`) + }) +} +else { + app.listen(port, ()=> { + console.log(`API is now running on http://localhost:${port}`) + }) +} + diff --git a/kube/nginx.yml b/kube/nginx.yml new file mode 100644 index 0000000..e0d7e40 --- /dev/null +++ b/kube/nginx.yml @@ -0,0 +1,23 @@ +kind: "Service" +apiVersion: "v1" +metadata: + name: "nginx-ssl-proxy" + labels: + name: "nginx" + role: "ssl-proxy" +spec: + ports: + - + name: "https" + port: 443 + targetPort: "nginx-ssl-proxy-https" + protocol: "TCP" + - + name: "http" + port: 80 + targetPort: "nginx-ssl-proxy-http" + protocol: "TCP" + selector: + name: "nginx" + role: "ssl-proxy" + type: "LoadBalancer" \ No newline at end of file diff --git a/kube/proxy.yml b/kube/proxy.yml new file mode 100644 index 0000000..9614804 --- /dev/null +++ b/kube/proxy.yml @@ -0,0 +1,25 @@ +spec: + containers: + - + name: "nginx-ssl-proxy" + image: "gcr.io/cloud-solutions-images/nginx-ssl-proxy:latest" + env: + - + name: "SERVICE\_HOST\_ENV\_NAME" + value: "JENKINS\_SERVICE\_HOST" + - + name: "SERVICE\_PORT\_ENV\_NAME" + value: "JENKINS\_SERVICE\_PORT\_UI" + - + name: "ENABLE\_SSL" + value: "true" + - + name: "ENABLE\_BASIC\_AUTH" + value: "true" + ports: + - + name: "nginx-ssl-proxy-http" + containerPort: 80 + - + name: "nginx-ssl-proxy-https" + containerPort: 443 \ No newline at end of file diff --git a/lib/auth.js b/lib/auth.js index 8639937..c0a7f86 100644 --- a/lib/auth.js +++ b/lib/auth.js @@ -1,13 +1,13 @@ 'use strict' +const { JWT_SECRET } = process.env const { Strategy: StrategyJwt, ExtractJwt } = require('passport-jwt') -const config = require('./config') const passport = require('passport') const opts = { jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme('jwt'), - secretOrKey: config.jwt_secret, + secretOrKey: JWT_SECRET, } passport.use(new StrategyJwt(opts, (jwt_payload, done)=> { diff --git a/lib/config.js b/lib/config.js deleted file mode 100644 index 45bf2c1..0000000 --- a/lib/config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - jwt_secret: 'devdacticIsAwesome', - db_location: 'http://localhost:8529', // 192.168.99.100:30981 - db_name: 'jwt-demo', -} \ No newline at end of file diff --git a/lib/index.js b/lib/index.js index 0f25b9a..5d0b98a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,22 +1,27 @@ 'use strict' -const { DB_USERNAME, DB_USERPASS } = process.env +const { + DB_USERNAME, + DB_USERPASS, + DB_LOCATION, + DB_NAME, +} = process.env const express = require('express') const apiRoutes = express.Router() const bcrypt = require('bcryptjs') -const config = require('./config') const jwt = require('jwt-simple') const auth = require('./auth') + const second = 1000 const minute = 60 * second const hour = 60 * minute const day = 24 * hour const { Database, aql } = require('arangojs') -const db = new Database(config.db_location) -db.useDatabase(config.db_name) +const db = new Database(DB_LOCATION) +db.useDatabase(DB_NAME) db.useBasicAuth(DB_USERNAME, DB_USERPASS) apiRoutes.use(auth.initialize()) @@ -78,7 +83,7 @@ apiRoutes.post('/authenticate', (req, res)=> { expiration: Date.now() + 2 * day, } - const token = jwt.encode(payload, config.jwt_secret) + const token = jwt.encode(payload, JWT_SECRET) res.json({ success: true, token: `JWT ${token}`, @@ -105,7 +110,7 @@ apiRoutes.post('/authenticate', (req, res)=> { // route to a restricted info (GET /api/users/memberinfo) apiRoutes.get('/memberinfo', auth.authenticate(), (req, res)=> { - const decoded = jwt.decode(auth.getToken(req.headers), config.jwt_secret) + const decoded = jwt.decode(auth.getToken(req.headers), JWT_SECRET) if (decoded) { diff --git a/scripts/launch.sh b/scripts/launch.sh deleted file mode 100755 index 8ab683d..0000000 --- a/scripts/launch.sh +++ /dev/null @@ -1 +0,0 @@ -docker run -e ARANGO_ROOT_PASSWORD="" -v $PWD:/source -p 8529:8529 arangodb \ No newline at end of file From 300e8d43e6501b6361452a2f01acdd8c29a335d6 Mon Sep 17 00:00:00 2001 From: rchristian Date: Tue, 17 Jul 2018 09:19:11 -0700 Subject: [PATCH 07/25] Restructure for dockerizing --- api/docker-compose.yml | 14 ++++ .env-example => api/src/.example-env | 0 index.js => api/src/index.js | 0 {lib => api/src/lib}/auth.js | 0 {lib => api/src/lib}/index.js | 0 package.json => api/src/package.json | 0 .../docker-compose.yml | 0 certs/new-certs.sh | 66 ------------------- 8 files changed, 14 insertions(+), 66 deletions(-) create mode 100644 api/docker-compose.yml rename .env-example => api/src/.example-env (100%) rename index.js => api/src/index.js (100%) rename {lib => api/src/lib}/auth.js (100%) rename {lib => api/src/lib}/index.js (100%) rename package.json => api/src/package.json (100%) rename docker-compose.yml => arangodb/docker-compose.yml (100%) delete mode 100755 certs/new-certs.sh diff --git a/api/docker-compose.yml b/api/docker-compose.yml new file mode 100644 index 0000000..1c13fd9 --- /dev/null +++ b/api/docker-compose.yml @@ -0,0 +1,14 @@ +version: '3' + +services: + api-server: + image: node:9 + user: "node" + working_dir: /home/node/app + environment: + - NODE_ENV=develop + volumes: + - ./src:/home/node/app + ports: + - 8080:8080 + command: "npm start" \ No newline at end of file diff --git a/.env-example b/api/src/.example-env similarity index 100% rename from .env-example rename to api/src/.example-env diff --git a/index.js b/api/src/index.js similarity index 100% rename from index.js rename to api/src/index.js diff --git a/lib/auth.js b/api/src/lib/auth.js similarity index 100% rename from lib/auth.js rename to api/src/lib/auth.js diff --git a/lib/index.js b/api/src/lib/index.js similarity index 100% rename from lib/index.js rename to api/src/lib/index.js diff --git a/package.json b/api/src/package.json similarity index 100% rename from package.json rename to api/src/package.json diff --git a/docker-compose.yml b/arangodb/docker-compose.yml similarity index 100% rename from docker-compose.yml rename to arangodb/docker-compose.yml diff --git a/certs/new-certs.sh b/certs/new-certs.sh deleted file mode 100755 index f02fbc3..0000000 --- a/certs/new-certs.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash -x - -set -e - -for C in `echo root-ca intermediate`; do - - mkdir $C - cd $C - mkdir certs crl newcerts private - cd .. - - echo 1000 > $C/serial - touch $C/index.txt $C/index.txt.attr - - echo ' -[ ca ] -default_ca = CA_default -[ CA_default ] -dir = '$C' # Where everything is kept -certs = $dir/certs # Where the issued certs are kept -crl_dir = $dir/crl # Where the issued crl are kept -database = $dir/index.txt # database index file. -new_certs_dir = $dir/newcerts # default place for new certs. -certificate = $dir/cacert.pem # The CA certificate -serial = $dir/serial # The current serial number -crl = $dir/crl.pem # The current CRL -private_key = $dir/private/ca.key.pem # The private key -RANDFILE = $dir/.rnd # private random number file -nameopt = default_ca -certopt = default_ca -policy = policy_match -default_days = 365 -default_md = sha256 - -[ policy_match ] -countryName = optional -stateOrProvinceName = optional -organizationName = optional -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -[req] -req_extensions = v3_req -distinguished_name = req_distinguished_name - -[req_distinguished_name] - -[v3_req] -basicConstraints = CA:TRUE -' > $C/openssl.conf -done - -openssl genrsa -out root-ca/private/ca.key 2048 -openssl req -config root-ca/openssl.conf -new -x509 -days 3650 -key root-ca/private/ca.key -sha256 -extensions v3_req -out root-ca/certs/ca.crt -subj '/CN=Root-ca' - -openssl genrsa -out intermediate/private/intermediate.key 2048 -openssl req -config intermediate/openssl.conf -sha256 -new -key intermediate/private/intermediate.key -out intermediate/certs/intermediate.csr -subj '/CN=Interm.' -openssl ca -batch -config root-ca/openssl.conf -keyfile root-ca/private/ca.key -cert root-ca/certs/ca.crt -extensions v3_req -notext -md sha256 -in intermediate/certs/intermediate.csr -out intermediate/certs/intermediate.crt - -mkdir out - -for I in `seq 1 3` ; do - openssl req -new -keyout out/$I.key -out out/$I.request -days 365 -nodes -subj "/CN=$I.example.com" -newkey rsa:2048 - openssl ca -batch -config root-ca/openssl.conf -keyfile intermediate/private/intermediate.key -cert intermediate/certs/intermediate.crt -out out/$I.crt -infiles out/$I.request -done \ No newline at end of file From 9d9bd30b35827718a56ff4b9b8723bf4cf29445c Mon Sep 17 00:00:00 2001 From: rchristian Date: Wed, 18 Jul 2018 03:03:13 -0700 Subject: [PATCH 08/25] Make API & DB launch together with `docker-compose up`. --- api/src/.example-env => .example-env | 0 api/docker-compose.yml | 14 ------------- {api/src => app}/index.js | 17 ++++++++------- {api/src => app}/lib/auth.js | 0 {api/src => app}/lib/index.js | 3 ++- {api/src => app}/package.json | 0 arangodb/docker-compose.yml | 9 -------- docker-compose.yml | 31 ++++++++++++++++++++++++++++ kube/nginx.yml | 23 --------------------- kube/proxy.yml | 25 ---------------------- scripts/bootstrap.js | 24 +++++++++++++++++++++ test/.keep | 0 12 files changed, 66 insertions(+), 80 deletions(-) rename api/src/.example-env => .example-env (100%) delete mode 100644 api/docker-compose.yml rename {api/src => app}/index.js (70%) rename {api/src => app}/lib/auth.js (100%) rename {api/src => app}/lib/index.js (98%) rename {api/src => app}/package.json (100%) delete mode 100644 arangodb/docker-compose.yml create mode 100644 docker-compose.yml delete mode 100644 kube/nginx.yml delete mode 100644 kube/proxy.yml create mode 100755 scripts/bootstrap.js create mode 100644 test/.keep diff --git a/api/src/.example-env b/.example-env similarity index 100% rename from api/src/.example-env rename to .example-env diff --git a/api/docker-compose.yml b/api/docker-compose.yml deleted file mode 100644 index 1c13fd9..0000000 --- a/api/docker-compose.yml +++ /dev/null @@ -1,14 +0,0 @@ -version: '3' - -services: - api-server: - image: node:9 - user: "node" - working_dir: /home/node/app - environment: - - NODE_ENV=develop - volumes: - - ./src:/home/node/app - ports: - - 8080:8080 - command: "npm start" \ No newline at end of file diff --git a/api/src/index.js b/app/index.js similarity index 70% rename from api/src/index.js rename to app/index.js index cb623c1..47b5973 100644 --- a/api/src/index.js +++ b/app/index.js @@ -1,7 +1,7 @@ 'use strict' require('dotenv').config() -const { ENABLE_HTTPS } = process.env +const { ENABLE_HTTPS, API_DOMAIN, API_PORT } = process.env const fs = require('fs') const https = require('https') @@ -12,7 +12,6 @@ const morgan = require('morgan') const authRoutes = require('./lib') const express = require('express') const app = express() -const port = process.env.PORT || 8080 app.use(bodyParser.urlencoded({ extended: false })) app.use(bodyParser.json()) @@ -23,7 +22,7 @@ app.use(morgan('dev')) app.use(helmet()) app.get('/', (req, res)=> { - res.send(`Hello! The API is at http://localhost:${port}/api`) + res.send(`Hello! The API is at ${API_DOMAIN}:${API_PORT}/api`) }) app.all('/api/*', (req, res, next)=> { @@ -35,7 +34,7 @@ app.all('/api/*', (req, res, next)=> { }) app.get('/api/', (req, res)=> { - res.send(`Hello! This is the API at http://localhost:${port}/api`) + res.send(`Hello! This is the API at ${API_DOMAIN}:${API_PORT}/api`) }) app.use('/api/users', authRoutes) @@ -47,13 +46,15 @@ if (JSON.parse(ENABLE_HTTPS)) { cert: fs.readFileSync('./certs/root-ca.crt'), ca: fs.readFileSync('./certs/intermediate.crt'), } - https.createServer(ssl, app).listen(port, ()=> { - console.log(`API is now running on https://localhost:${port}`) + https.createServer(ssl, app).listen(API_PORT, ()=> { + console.log('Using HTTPS') + console.log(`API is now running on ${API_DOMAIN}:${API_PORT}/api`) }) } else { - app.listen(port, ()=> { - console.log(`API is now running on http://localhost:${port}`) + app.listen(API_PORT, ()=> { + console.log('Using HTTP') + console.log(`API is now running on ${API_DOMAIN}:${API_PORT}/api`) }) } diff --git a/api/src/lib/auth.js b/app/lib/auth.js similarity index 100% rename from api/src/lib/auth.js rename to app/lib/auth.js diff --git a/api/src/lib/index.js b/app/lib/index.js similarity index 98% rename from api/src/lib/index.js rename to app/lib/index.js index 5d0b98a..d993fd4 100644 --- a/api/src/lib/index.js +++ b/app/lib/index.js @@ -4,6 +4,7 @@ const { DB_USERNAME, DB_USERPASS, DB_LOCATION, + DB_PORT, DB_NAME, } = process.env @@ -20,7 +21,7 @@ const hour = 60 * minute const day = 24 * hour const { Database, aql } = require('arangojs') -const db = new Database(DB_LOCATION) +const db = new Database(`${DB_LOCATION}:${DB_PORT}`) db.useDatabase(DB_NAME) db.useBasicAuth(DB_USERNAME, DB_USERPASS) diff --git a/api/src/package.json b/app/package.json similarity index 100% rename from api/src/package.json rename to app/package.json diff --git a/arangodb/docker-compose.yml b/arangodb/docker-compose.yml deleted file mode 100644 index f0d1bc8..0000000 --- a/arangodb/docker-compose.yml +++ /dev/null @@ -1,9 +0,0 @@ -version: '3' - -services: - platform-db: - image: arangodb - environment: - - ARANGO_ROOT_PASSWORD='' - ports: - - 8529:8529 \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..77c413c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,31 @@ + +# ENV variables below are found in .env +version: '3' + +services: + + platform-db: + image: arangodb + environment: + - ARANGO_ROOT_PASSWORD=${ARANGO_ROOT_PASSWORD} + ports: + - ${DB_PORT}:${DB_PORT} + expose: + - "${DB_PORT}" + volumes: + - ./scripts:/docker-entrypoint-initdb.d + + platform-api: + build: + context: ./app + ports: + - ${API_PORT}:${API_PORT} + image: node:9 + user: node + working_dir: /home/node/app + environment: + - NODE_ENV=${NODE_ENV} + volumes: + - ./app:/home/node/app + - ./.env:/home/node/app/.env + command: "npm start" \ No newline at end of file diff --git a/kube/nginx.yml b/kube/nginx.yml deleted file mode 100644 index e0d7e40..0000000 --- a/kube/nginx.yml +++ /dev/null @@ -1,23 +0,0 @@ -kind: "Service" -apiVersion: "v1" -metadata: - name: "nginx-ssl-proxy" - labels: - name: "nginx" - role: "ssl-proxy" -spec: - ports: - - - name: "https" - port: 443 - targetPort: "nginx-ssl-proxy-https" - protocol: "TCP" - - - name: "http" - port: 80 - targetPort: "nginx-ssl-proxy-http" - protocol: "TCP" - selector: - name: "nginx" - role: "ssl-proxy" - type: "LoadBalancer" \ No newline at end of file diff --git a/kube/proxy.yml b/kube/proxy.yml deleted file mode 100644 index 9614804..0000000 --- a/kube/proxy.yml +++ /dev/null @@ -1,25 +0,0 @@ -spec: - containers: - - - name: "nginx-ssl-proxy" - image: "gcr.io/cloud-solutions-images/nginx-ssl-proxy:latest" - env: - - - name: "SERVICE\_HOST\_ENV\_NAME" - value: "JENKINS\_SERVICE\_HOST" - - - name: "SERVICE\_PORT\_ENV\_NAME" - value: "JENKINS\_SERVICE\_PORT\_UI" - - - name: "ENABLE\_SSL" - value: "true" - - - name: "ENABLE\_BASIC\_AUTH" - value: "true" - ports: - - - name: "nginx-ssl-proxy-http" - containerPort: 80 - - - name: "nginx-ssl-proxy-https" - containerPort: 443 \ No newline at end of file diff --git a/scripts/bootstrap.js b/scripts/bootstrap.js new file mode 100755 index 0000000..1b7e375 --- /dev/null +++ b/scripts/bootstrap.js @@ -0,0 +1,24 @@ +#!/usr/bin/arangosh --javascript.execute + +const _user = require('@arangodb/users') + +try { + db._useDatabase('platform') +} catch (err) { + db._createDatabase('platform') + db._useDatabase('platform') +} + +try { + _user.save('api-user', 'chickenbrainlanguage') + _user.grantDatabase('api-user', 'platform') +} catch (err) { + // if error, assume the user already exists + _user.grantDatabase('api-user', 'platform') +} + +try { + db._create('users') +} catch (err) { + // if error, the users collection must already exist +} diff --git a/test/.keep b/test/.keep new file mode 100644 index 0000000..e69de29 From 8de739aadbfe3b8163e9cd69b182a8cee697b2ab Mon Sep 17 00:00:00 2001 From: rchristian Date: Wed, 18 Jul 2018 03:45:16 -0700 Subject: [PATCH 09/25] Fix structure and stuff. --- app/{lib => }/auth.js | 0 app/index.js | 3 +-- app/{lib/index.js => routes.js} | 1 - docker-compose.yml | 8 +++++--- app/package.json => package.json | 2 +- scripts/bootstrap.js | 8 +++++--- 6 files changed, 12 insertions(+), 10 deletions(-) rename app/{lib => }/auth.js (100%) rename app/{lib/index.js => routes.js} (99%) rename app/package.json => package.json (92%) diff --git a/app/lib/auth.js b/app/auth.js similarity index 100% rename from app/lib/auth.js rename to app/auth.js diff --git a/app/index.js b/app/index.js index 47b5973..eeb615b 100644 --- a/app/index.js +++ b/app/index.js @@ -1,6 +1,5 @@ 'use strict' -require('dotenv').config() const { ENABLE_HTTPS, API_DOMAIN, API_PORT } = process.env const fs = require('fs') @@ -9,7 +8,7 @@ const http = require('http') const helmet = require('helmet') const bodyParser = require('body-parser') const morgan = require('morgan') -const authRoutes = require('./lib') +const authRoutes = require('./routes') const express = require('express') const app = express() diff --git a/app/lib/index.js b/app/routes.js similarity index 99% rename from app/lib/index.js rename to app/routes.js index d993fd4..9f97aba 100644 --- a/app/lib/index.js +++ b/app/routes.js @@ -56,7 +56,6 @@ apiRoutes.post('/register', async (req, res)=> { } } catch (err) { - console.log(err) res.send({ success: false, msg: err.message}) } diff --git a/docker-compose.yml b/docker-compose.yml index 77c413c..39dfaa3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,10 +22,12 @@ services: - ${API_PORT}:${API_PORT} image: node:9 user: node - working_dir: /home/node/app + working_dir: /home/node environment: - NODE_ENV=${NODE_ENV} volumes: + - ./.env:/home/node/.env + - ./package.json:/home/node/package.json - ./app:/home/node/app - - ./.env:/home/node/app/.env - command: "npm start" \ No newline at end of file + - ./node_modules:/home/node/node_modules + command: "npm start" diff --git a/app/package.json b/package.json similarity index 92% rename from app/package.json rename to package.json index 9a6647e..231654a 100644 --- a/app/package.json +++ b/package.json @@ -15,7 +15,7 @@ "passport-jwt": "*" }, "scripts": { - "start": "node index.js" + "start": "node -r dotenv/config app/index.js" }, "version": "1.0.0", "description": "Creating API with JWT user authentication using Express, Passport JWT and ArangoDB", diff --git a/scripts/bootstrap.js b/scripts/bootstrap.js index 1b7e375..fd45cd2 100755 --- a/scripts/bootstrap.js +++ b/scripts/bootstrap.js @@ -1,5 +1,7 @@ #!/usr/bin/arangosh --javascript.execute +// the values here must match with .env + const _user = require('@arangodb/users') try { @@ -10,11 +12,11 @@ try { } try { - _user.save('api-user', 'chickenbrainlanguage') - _user.grantDatabase('api-user', 'platform') + _user.save('api_user', 'localhost') + _user.grantDatabase('api_user', 'platform') } catch (err) { // if error, assume the user already exists - _user.grantDatabase('api-user', 'platform') + _user.grantDatabase('api_user', 'platform') } try { From 065235a49acc20cd45d625a7535d33fab0bd1fa7 Mon Sep 17 00:00:00 2001 From: rchristian Date: Wed, 18 Jul 2018 03:48:03 -0700 Subject: [PATCH 10/25] Fix example-env contents --- .example-env | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/.example-env b/.example-env index 5bb4efd..5202fea 100644 --- a/.example-env +++ b/.example-env @@ -1,6 +1,14 @@ -JWT_SECRET=devdacticIsAwesome -ENABLE_HTTPS=true -DB_USERPASS=mysecuredbpassword -DB_USERNAME=dbuser -DB_LOCATION=https://minikube:30981 -DB_NAME=jwt-demo \ No newline at end of file +JWT_SECRET=keep_it_secret_keep_it_safe +ENABLE_HTTPS=false + +ARANGO_ROOT_PASSWORD=localhost +DB_USERPASS=localhost +DB_USERNAME=api_user +DB_NAME=platform +DB_LOCATION=http://platform-db +DB_PORT=8529 + +API_DOMAIN=http://localhost +API_PORT=8080 + +NODE_ENV=develop \ No newline at end of file From 337e6db5ae95842ec08ffb1944c46299957a6d61 Mon Sep 17 00:00:00 2001 From: Rob Date: Wed, 18 Jul 2018 04:18:45 -0700 Subject: [PATCH 11/25] Update README.md --- README.md | 68 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 2927949..72f175e 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,49 @@ # node-rest-auth-arangodb -Creating API with JWT user authentication using the following: +Creating API with JWT user authentication using: -* nodejs +* Nodejs * Express -* jwt -* passport +* JWT +* [Passport](http://www.passportjs.org) * ArangoDB +FYI: I've only run this project on macOS. ## Requirements -0. Install [ArangoDB](https://www.arangodb.com/) -1. Install [Node.js](https://nodejs.org/en/) +[Node.js](https://nodejs.org/en/). -## Configure `/include/config.js` +If you have [Docker](https://www.docker.com/), you can simply run `docker-compose up` +and both the Nodejs app and ArangoDB will be launched in separate containers and ready to use. -0. Set JWT secret key -1. Set location to ArangoDB -2. Set database in ArangoDB +Or, if you prefer, you can install ArangoDB on localhost. See the next section for setup steps. -## Install +## Setup -`npm install` +* `npm install` or `yarn install` (yarn is faster) +* Rename `.example-env` to `.env`, this file sets ENV vars for both the API and docker-compose. + +If you're running ArangoDB on localhost, you can manually run the bootstrap script to setup +the database, user, and users collection. Simply run `./scripts/bootstrap.js`, assuming +arangodb is running and arangosh is accessible. If needed, set exec permissions on the file +like `chmod +x scripts/bootstrap.js` (or whatever it is you do on Windows). ## Run -0. Make sure ArangoDB is running -1. `node server` +`docker-compose up` or `npm start` if you have ArangoDB running on localhost. + +If you pass `-d` to docker-compose (`docker-compose up -d`) it will run in detached mode, +meaning it gives you the terminal back once things have started. After that, you can use either +`docker-compose stop` or `docker-compose down`. The latter will do more cleanup work for you. ## RESTful API endpoints +[Postman](https://www.getpostman.com/) is a great tool for using the API. Otherwise, see the +sample cURL command below. + + ### POST `/api/users/register` Register by providing `username` and `password`. @@ -44,29 +56,19 @@ Authenticate by providing `username` and `password`. Get user data by providing `token`. +### Using cURL to register a new user +``` +curl -X POST \ + http://localhost:8080/api/users/register \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -d 'username=jwoods&password=password' +``` + ## Credits Based on https://github.com/clemudensi/nodeJS_backend -## HTTPS - -* [The LetsEncrypt guide for HTTPS on localhost](https://letsencrypt.org/docs/certificates-for-localhost/) -* [Longer explanation here...](https://stackoverflow.com/questions/20433287/node-js-request-cert-has-expired#answer-29397100) -* [Explanation for `certs/new-certs.sh`](https://stackoverflow.com/questions/26759550/how-to-create-own-self-signed-root-certificate-and-intermediate-ca-to-be-importe) - -### For macOS... - -[steps originally found here](https://www.bounca.org/tutorials/install_root_certificate.html) - -To add: -``` -sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ./certs/localhost.crt -``` -To remove: -``` -sudo security delete-certificate -c "localhost" -``` ## License -MIT \ No newline at end of file +MIT From a9383b14cba524f1ede61f1ca05f6d48df6546f7 Mon Sep 17 00:00:00 2001 From: Rob Date: Wed, 18 Jul 2018 04:21:19 -0700 Subject: [PATCH 12/25] Update README.md --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 72f175e..7eef3fc 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # node-rest-auth-arangodb -Creating API with JWT user authentication using: +An API with JWT user authentication. +Built with: * Nodejs * Express * JWT @@ -10,6 +11,7 @@ Creating API with JWT user authentication using: FYI: I've only run this project on macOS. + ## Requirements [Node.js](https://nodejs.org/en/). @@ -17,7 +19,9 @@ FYI: I've only run this project on macOS. If you have [Docker](https://www.docker.com/), you can simply run `docker-compose up` and both the Nodejs app and ArangoDB will be launched in separate containers and ready to use. -Or, if you prefer, you can install ArangoDB on localhost. See the next section for setup steps. +You can install ArangoDB on localhost if you prefer, but using docker is really the faster/easier +and more correct way to run it. + ## Setup @@ -29,6 +33,7 @@ the database, user, and users collection. Simply run `./scripts/bootstrap.js`, a arangodb is running and arangosh is accessible. If needed, set exec permissions on the file like `chmod +x scripts/bootstrap.js` (or whatever it is you do on Windows). + ## Run `docker-compose up` or `npm start` if you have ArangoDB running on localhost. From 7a58cd706196ae8138d80a007e2c894e30e8e8e3 Mon Sep 17 00:00:00 2001 From: Rob Date: Wed, 18 Jul 2018 04:23:23 -0700 Subject: [PATCH 13/25] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7eef3fc..7f69f5b 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ An API with JWT user authentication. Built with: -* Nodejs -* Express -* JWT +* [Nodejs](https://nodejs.org) +* [Express](https://expressjs.com) +* [jwt-simple](https://www.npmjs.com/package/jwt-simple) * [Passport](http://www.passportjs.org) -* ArangoDB +* [ArangoDB](https://www.arangodb.com) FYI: I've only run this project on macOS. From 481a3e49eb6e8ab36bffca58a9c4f3f3540ac1fe Mon Sep 17 00:00:00 2001 From: rchristian Date: Wed, 18 Jul 2018 21:12:12 -0700 Subject: [PATCH 14/25] wip 1 --- Dockerfile | 2 ++ app/index.js | 10 +++++----- docker-compose.yml | 5 ++--- 3 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f4df0ee --- /dev/null +++ b/Dockerfile @@ -0,0 +1,2 @@ +FROM node:9 +CMD npm start \ No newline at end of file diff --git a/app/index.js b/app/index.js index eeb615b..f7641ff 100644 --- a/app/index.js +++ b/app/index.js @@ -1,6 +1,6 @@ 'use strict' -const { ENABLE_HTTPS, API_DOMAIN, API_PORT } = process.env +const { ENABLE_HTTPS, API_PORT } = process.env const fs = require('fs') const https = require('https') @@ -21,7 +21,7 @@ app.use(morgan('dev')) app.use(helmet()) app.get('/', (req, res)=> { - res.send(`Hello! The API is at ${API_DOMAIN}:${API_PORT}/api`) + res.send(`Hello from API`) }) app.all('/api/*', (req, res, next)=> { @@ -33,7 +33,7 @@ app.all('/api/*', (req, res, next)=> { }) app.get('/api/', (req, res)=> { - res.send(`Hello! This is the API at ${API_DOMAIN}:${API_PORT}/api`) + res.send(`Hello from API`) }) app.use('/api/users', authRoutes) @@ -47,13 +47,13 @@ if (JSON.parse(ENABLE_HTTPS)) { } https.createServer(ssl, app).listen(API_PORT, ()=> { console.log('Using HTTPS') - console.log(`API is now running on ${API_DOMAIN}:${API_PORT}/api`) + console.log(`API is now running on port ${API_PORT}`) }) } else { app.listen(API_PORT, ()=> { console.log('Using HTTP') - console.log(`API is now running on ${API_DOMAIN}:${API_PORT}/api`) + console.log(`API is now running on port ${API_PORT}`) }) } diff --git a/docker-compose.yml b/docker-compose.yml index 39dfaa3..42ff8ba 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,11 +16,10 @@ services: - ./scripts:/docker-entrypoint-initdb.d platform-api: - build: - context: ./app + build: ./ + # context: ./app ports: - ${API_PORT}:${API_PORT} - image: node:9 user: node working_dir: /home/node environment: From c67210f1475b313c39528365db4565ae240a1e69 Mon Sep 17 00:00:00 2001 From: rchristian Date: Thu, 19 Jul 2018 02:46:23 -0700 Subject: [PATCH 15/25] Make env vars work on local, in docker build, and docker-compose. --- .example-env => .env-example | 7 +- .gitignore | 10 +- Dockerfile | 8 +- docker-compose.yml | 12 +- localhost-env-vars/.keep | 0 package.json | 10 +- scripts/bootstrap.js | 6 +- yarn.lock | 694 +++++++++++++++++++++++++++++++++++ 8 files changed, 718 insertions(+), 29 deletions(-) rename .example-env => .env-example (62%) create mode 100644 localhost-env-vars/.keep create mode 100644 yarn.lock diff --git a/.example-env b/.env-example similarity index 62% rename from .example-env rename to .env-example index 5202fea..d64f982 100644 --- a/.example-env +++ b/.env-example @@ -1,14 +1,13 @@ JWT_SECRET=keep_it_secret_keep_it_safe ENABLE_HTTPS=false -ARANGO_ROOT_PASSWORD=localhost DB_USERPASS=localhost -DB_USERNAME=api_user +DB_USERNAME=apiuser DB_NAME=platform DB_LOCATION=http://platform-db DB_PORT=8529 -API_DOMAIN=http://localhost API_PORT=8080 +NODE_ENV=develop -NODE_ENV=develop \ No newline at end of file +ARANGO_ROOT_PASSWORD=localhost \ No newline at end of file diff --git a/.gitignore b/.gitignore index b4b6461..b706e9d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,4 @@ node_modules/ -.env -yarn.lock -certs/intermediate/ -certs/root-ca/ -certs/out/ -certs/*.key -certs/*.crt \ No newline at end of file +localhost-env-vars/* +!localhost-env-vars/.keep +.env \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index f4df0ee..503df0d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,2 +1,8 @@ FROM node:9 -CMD npm start \ No newline at end of file +WORKDIR /home/node +COPY package.json /home/node +COPY yarn.lock /home/node +COPY app /home/node/app +RUN yarn install --pure-lockfile +CMD npm start:containerized +EXPOSE 8080 \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 42ff8ba..30a53d7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,9 +5,8 @@ version: '3' services: platform-db: + env_file: .env image: arangodb - environment: - - ARANGO_ROOT_PASSWORD=${ARANGO_ROOT_PASSWORD} ports: - ${DB_PORT}:${DB_PORT} expose: @@ -16,17 +15,10 @@ services: - ./scripts:/docker-entrypoint-initdb.d platform-api: + env_file: .env build: ./ - # context: ./app ports: - ${API_PORT}:${API_PORT} user: node working_dir: /home/node - environment: - - NODE_ENV=${NODE_ENV} - volumes: - - ./.env:/home/node/.env - - ./package.json:/home/node/package.json - - ./app:/home/node/app - - ./node_modules:/home/node/node_modules command: "npm start" diff --git a/localhost-env-vars/.keep b/localhost-env-vars/.keep new file mode 100644 index 0000000..e69de29 diff --git a/package.json b/package.json index 231654a..1095b28 100644 --- a/package.json +++ b/package.json @@ -6,20 +6,22 @@ "arangojs": "^5.4.2", "bcryptjs": "*", "body-parser": "*", - "dotenv": "^6.0.0", "express": "*", - "helmet": "^3.12.0", + "helmet": "^3.12.1", "jwt-simple": "*", "morgan": "*", "passport": "*", "passport-jwt": "*" }, "scripts": { - "start": "node -r dotenv/config app/index.js" + "start": "node -r dotenv/config app/index.js dotenv_config_path=localhost-env-vars/$(hostname)", + "start:containerized": "node app/index.js" }, "version": "1.0.0", "description": "Creating API with JWT user authentication using Express, Passport JWT and ArangoDB", - "devDependencies": {}, + "devDependencies": { + "dotenv": "^6.0.0" + }, "repository": { "type": "git", "url": "https://github.com/mikicoding/node-rest-auth-arangodb.git" diff --git a/scripts/bootstrap.js b/scripts/bootstrap.js index fd45cd2..0f17133 100755 --- a/scripts/bootstrap.js +++ b/scripts/bootstrap.js @@ -12,11 +12,11 @@ try { } try { - _user.save('api_user', 'localhost') - _user.grantDatabase('api_user', 'platform') + _user.save('apiuser', 'localhost') + _user.grantDatabase('apiuser', 'platform') } catch (err) { // if error, assume the user already exists - _user.grantDatabase('api_user', 'platform') + _user.grantDatabase('apiuser', 'platform') } try { diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..ae88f7e --- /dev/null +++ b/yarn.lock @@ -0,0 +1,694 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +accepts@~1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + +arango@*: + version "1.3.4" + resolved "https://registry.yarnpkg.com/arango/-/arango-1.3.4.tgz#5a3ccc24bc152c7fafc61658c1dedce331085970" + dependencies: + base64 "git://github.com/kaerus-component/base64.git#0.1.0" + micropromise "0.4.6" + urlparser "git://github.com/kaerus-component/urlparser.git#0.3.9" + +arangojs@^5.4.2: + version "5.8.0" + resolved "https://registry.yarnpkg.com/arangojs/-/arangojs-5.8.0.tgz#5a84214209ea2cb9d2d25415213c2add28335ba8" + dependencies: + es6-error "^4.0.1" + http-errors "^1.6.1" + linkedlist "^1.0.1" + multi-part "^2.0.0" + retry "^0.10.0" + utf8-length "^0.0.1" + xhr "^2.3.1" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +"base64@git://github.com/kaerus-component/base64.git#0.1.0": + version "0.1.0" + resolved "git://github.com/kaerus-component/base64.git#b2b0d864a0da58616d56f83ac7e06866bf90ab93" + +basic-auth@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.0.tgz#015db3f353e02e56377755f962742e8981e7bbba" + dependencies: + safe-buffer "5.1.1" + +bcryptjs@*: + version "2.4.3" + resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" + +body-parser@*: + version "1.18.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "~1.6.3" + iconv-lite "0.4.23" + on-finished "~2.3.0" + qs "6.5.2" + raw-body "2.3.3" + type-is "~1.6.16" + +body-parser@1.18.2: + version "1.18.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.1" + http-errors "~1.6.2" + iconv-lite "0.4.19" + on-finished "~2.3.0" + qs "6.5.1" + raw-body "2.3.2" + type-is "~1.6.15" + +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + +camelize@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + +content-security-policy-builder@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/content-security-policy-builder/-/content-security-policy-builder-2.0.0.tgz#8749a1d542fcbe82237281ea9f716ce68b394dd2" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + +dasherize@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dasherize/-/dasherize-2.0.0.tgz#6d809c9cd0cf7bb8952d80fc84fa13d47ddb1308" + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +depd@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" + +depd@~1.1.1, depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +dns-prefetch-control@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz#60ddb457774e178f1f9415f0cabb0e85b0b300b2" + +dom-walk@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" + +dont-sniff-mimetype@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz#5932890dc9f4e2f19e5eb02a20026e5e5efc8f58" + +dotenv@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.0.0.tgz#24e37c041741c5f4b25324958ebbc34bca965935" + +ecdsa-sig-formatter@1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz#1c595000f04a8897dfb85000892a0f4c33af86c3" + dependencies: + safe-buffer "^5.0.1" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + +es6-error@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + +expect-ct@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/expect-ct/-/expect-ct-0.1.1.tgz#de84476a2dbcb85000d5903737e9bc8a5ba7b897" + +express@*: + version "4.16.3" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53" + dependencies: + accepts "~1.3.5" + array-flatten "1.1.1" + body-parser "1.18.2" + content-disposition "0.5.2" + content-type "~1.0.4" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.1.1" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.2" + path-to-regexp "0.1.7" + proxy-addr "~2.0.3" + qs "6.5.1" + range-parser "~1.2.0" + safe-buffer "5.1.1" + send "0.16.2" + serve-static "1.13.2" + setprototypeof "1.1.0" + statuses "~1.4.0" + type-is "~1.6.16" + utils-merge "1.0.1" + vary "~1.1.2" + +file-type@^4.3.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-4.4.0.tgz#1b600e5fca1fbdc6e80c0a70c71c8dba5f7906c5" + +finalhandler@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.4.0" + unpipe "~1.0.0" + +for-each@^0.3.2: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + dependencies: + is-callable "^1.1.3" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + +frameguard@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/frameguard/-/frameguard-3.0.0.tgz#7bcad469ee7b96e91d12ceb3959c78235a9272e9" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + +global@~4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" + dependencies: + min-document "^2.19.0" + process "~0.5.1" + +helmet-csp@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/helmet-csp/-/helmet-csp-2.7.0.tgz#7934094617d1feb7bb2dc43bb7d9e8830f774716" + dependencies: + camelize "1.0.0" + content-security-policy-builder "2.0.0" + dasherize "2.0.0" + lodash.reduce "4.6.0" + platform "1.3.5" + +helmet@^3.12.1: + version "3.12.1" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.12.1.tgz#8b05bbd60f3966d70f13dad0de2c1d6c1a8303f1" + dependencies: + dns-prefetch-control "0.1.0" + dont-sniff-mimetype "1.0.0" + expect-ct "0.1.1" + frameguard "3.0.0" + helmet-csp "2.7.0" + hide-powered-by "1.0.0" + hpkp "2.0.0" + hsts "2.1.0" + ienoopen "1.0.0" + nocache "2.0.0" + referrer-policy "1.1.0" + x-xss-protection "1.1.0" + +hide-powered-by@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.0.0.tgz#4a85ad65881f62857fc70af7174a1184dccce32b" + +hpkp@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hpkp/-/hpkp-2.0.0.tgz#10e142264e76215a5d30c44ec43de64dee6d1672" + +hsts@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/hsts/-/hsts-2.1.0.tgz#cbd6c918a2385fee1dd5680bfb2b3a194c0121cc" + +http-errors@1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" + dependencies: + depd "1.1.1" + inherits "2.0.3" + setprototypeof "1.0.3" + statuses ">= 1.3.1 < 2" + +http-errors@1.6.3, http-errors@^1.6.1, http-errors@~1.6.2, http-errors@~1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +iconv-lite@0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + +iconv-lite@0.4.23: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ienoopen@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.0.0.tgz#346a428f474aac8f50cf3784ea2d0f16f62bda6b" + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +ipaddr.js@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" + +is-callable@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + +is-function@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" + +jsonwebtoken@^8.2.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz#056c90eee9a65ed6e6c72ddb0a1d325109aaf643" + dependencies: + jws "^3.1.5" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + +jwa@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.1.6.tgz#87240e76c9808dbde18783cf2264ef4929ee50e6" + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.10" + safe-buffer "^5.0.1" + +jws@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.5.tgz#80d12d05b293d1e841e7cb8b4e69e561adcf834f" + dependencies: + jwa "^1.1.5" + safe-buffer "^5.0.1" + +jwt-simple@*: + version "0.5.1" + resolved "https://registry.yarnpkg.com/jwt-simple/-/jwt-simple-0.5.1.tgz#79ea01891b61de6b68e13e67c0b4b5bda937b294" + +linkedlist@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/linkedlist/-/linkedlist-1.0.1.tgz#7b74189bfad6e76367fb5a10f3c36913128b782b" + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + +lodash.reduce@4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micropromise@0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/micropromise/-/micropromise-0.4.6.tgz#91628d56a21d365060b0a4493100234f3131fa0a" + dependencies: + microtask "0.1.6" + +microtask@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/microtask/-/microtask-0.1.6.tgz#e1eb96cd54871229d171542580ea21051200a37e" + +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + +mime-kind@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/mime-kind/-/mime-kind-2.0.2.tgz#5a43d5bebdeb082182224d9d263206329e57cdf8" + dependencies: + file-type "^4.3.0" + mime-types "^2.1.15" + +mime-types@^2.1.15, mime-types@~2.1.18: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + dependencies: + mime-db "~1.33.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + dependencies: + dom-walk "^0.1.0" + +morgan@*: + version "1.9.0" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.0.tgz#d01fa6c65859b76fcf31b3cb53a3821a311d8051" + dependencies: + basic-auth "~2.0.0" + debug "2.6.9" + depd "~1.1.1" + on-finished "~2.3.0" + on-headers "~1.0.1" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + +multi-part@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/multi-part/-/multi-part-2.0.0.tgz#674f53b432f850cf8cc02d30d21f2064e309563c" + dependencies: + mime-kind "^2.0.1" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +nocache@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.0.0.tgz#202b48021a0c4cbde2df80de15a17443c8b43980" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + +parse-headers@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.1.tgz#6ae83a7aa25a9d9b700acc28698cd1f1ed7e9536" + dependencies: + for-each "^0.3.2" + trim "0.0.1" + +parseurl@~1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + +passport-jwt@*: + version "4.0.0" + resolved "https://registry.yarnpkg.com/passport-jwt/-/passport-jwt-4.0.0.tgz#7f0be7ba942e28b9f5d22c2ebbb8ce96ef7cf065" + dependencies: + jsonwebtoken "^8.2.0" + passport-strategy "^1.0.0" + +passport-strategy@1.x.x, passport-strategy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" + +passport@*: + version "0.4.0" + resolved "https://registry.yarnpkg.com/passport/-/passport-0.4.0.tgz#c5095691347bd5ad3b5e180238c3914d16f05811" + dependencies: + passport-strategy "1.x.x" + pause "0.0.1" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +pause@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" + +platform@1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.5.tgz#fb6958c696e07e2918d2eeda0f0bc9448d733444" + +process@~0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" + +proxy-addr@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341" + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.6.0" + +qs@6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + +qs@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + +range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +raw-body@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" + dependencies: + bytes "3.0.0" + http-errors "1.6.2" + iconv-lite "0.4.19" + unpipe "1.0.0" + +raw-body@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" + dependencies: + bytes "3.0.0" + http-errors "1.6.3" + iconv-lite "0.4.23" + unpipe "1.0.0" + +referrer-policy@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.1.0.tgz#35774eb735bf50fb6c078e83334b472350207d79" + +retry@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" + +safe-buffer@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + +safe-buffer@^5.0.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + +send@0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + +setprototypeof@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + +"statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + +trim@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" + +type-is@~1.6.15, type-is@~1.6.16: + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +"urlparser@git://github.com/kaerus-component/urlparser.git#0.3.9": + version "0.3.9" + resolved "git://github.com/kaerus-component/urlparser.git#07e88f200dba112749f731a19d4d548d2f0a575a" + +utf8-length@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/utf8-length/-/utf8-length-0.0.1.tgz#d315c4bed529c977f18dd35c73d72628327d9ada" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + +x-xss-protection@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/x-xss-protection/-/x-xss-protection-1.1.0.tgz#4f1898c332deb1e7f2be1280efb3e2c53d69c1a7" + +xhr@^2.3.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.5.0.tgz#bed8d1676d5ca36108667692b74b316c496e49dd" + dependencies: + global "~4.3.0" + is-function "^1.0.1" + parse-headers "^2.0.0" + xtend "^4.0.0" + +xtend@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" From edd9a2e7a5cb30ed0189c0bb170bb0116edb0ae5 Mon Sep 17 00:00:00 2001 From: rchristian Date: Thu, 19 Jul 2018 04:28:56 -0700 Subject: [PATCH 16/25] Fix start commands, update readme, other misc too. --- .env-example | 2 +- Dockerfile | 2 +- README.md | 52 +++++++++++++++++++++++++++++----------------- docker-compose.yml | 9 ++++---- 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/.env-example b/.env-example index d64f982..ba16f88 100644 --- a/.env-example +++ b/.env-example @@ -4,7 +4,7 @@ ENABLE_HTTPS=false DB_USERPASS=localhost DB_USERNAME=apiuser DB_NAME=platform -DB_LOCATION=http://platform-db +DB_LOCATION=http://localhost DB_PORT=8529 API_PORT=8080 diff --git a/Dockerfile b/Dockerfile index 503df0d..aef9149 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,5 +4,5 @@ COPY package.json /home/node COPY yarn.lock /home/node COPY app /home/node/app RUN yarn install --pure-lockfile -CMD npm start:containerized +CMD npm run start:containerized EXPOSE 8080 \ No newline at end of file diff --git a/README.md b/README.md index 7f69f5b..1861339 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,60 @@ # node-rest-auth-arangodb -An API with JWT user authentication. +An API with JWT user authentication. Project works out of the box with Docker, or just localhost. +Be sure to follow the setup instructions so that env vars are passed in. -Built with: +Made using: * [Nodejs](https://nodejs.org) * [Express](https://expressjs.com) * [jwt-simple](https://www.npmjs.com/package/jwt-simple) * [Passport](http://www.passportjs.org) * [ArangoDB](https://www.arangodb.com) -FYI: I've only run this project on macOS. +_Only tested with macOS_ ## Requirements -[Node.js](https://nodejs.org/en/). +* [Docker](https://www.docker.com/get-docker) -If you have [Docker](https://www.docker.com/), you can simply run `docker-compose up` -and both the Nodejs app and ArangoDB will be launched in separate containers and ready to use. +### Optional Requirements -You can install ArangoDB on localhost if you prefer, but using docker is really the faster/easier -and more correct way to run it. +* [Node.js](https://nodejs.org/en/) ## Setup -* `npm install` or `yarn install` (yarn is faster) -* Rename `.example-env` to `.env`, this file sets ENV vars for both the API and docker-compose. +* Rename `.env-example` to `.env` -If you're running ArangoDB on localhost, you can manually run the bootstrap script to setup -the database, user, and users collection. Simply run `./scripts/bootstrap.js`, assuming -arangodb is running and arangosh is accessible. If needed, set exec permissions on the file -like `chmod +x scripts/bootstrap.js` (or whatever it is you do on Windows). +## To Run -## Run +* `docker-compose up -d` (or just `docker-compose up`) -`docker-compose up` or `npm start` if you have ArangoDB running on localhost. +When done, `docker-compose stop` or `docker-compose down`. -If you pass `-d` to docker-compose (`docker-compose up -d`) it will run in detached mode, -meaning it gives you the terminal back once things have started. After that, you can use either -`docker-compose stop` or `docker-compose down`. The latter will do more cleanup work for you. + +## To Run On `localhost` + +If you'd rather run node on localhost, then... + +* `yarn install` + * (Yarn is better than npm, do `npm install -g yarn`) +* Copy `.env` to `localhost-env-vars/` + * (If you don't know your hostname, run `hostname` in the terminal) +* `docker-compose up -d database` to run ArangoDB +* `npm start` + +If you're going to run ArangoDB on localhost, see `scripts/boostrap.js`, this runs +automatically when using `docker-compose`. + + +## When Done + +`docker-compose down` will clean up for you. + +`docker-compose build api` (or just `docker-compose build`) will build the API image +(so you can deploy to Kubernetes or whatnot). ## RESTful API endpoints diff --git a/docker-compose.yml b/docker-compose.yml index 30a53d7..35c226e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ version: '3' services: - platform-db: + database: env_file: .env image: arangodb ports: @@ -14,11 +14,10 @@ services: volumes: - ./scripts:/docker-entrypoint-initdb.d - platform-api: + api: env_file: .env build: ./ + image: auth-api ports: - ${API_PORT}:${API_PORT} - user: node - working_dir: /home/node - command: "npm start" + command: "npm run start:containerized" From f7035d56df74dc95d6ab348b5f1945885c50f684 Mon Sep 17 00:00:00 2001 From: Rob Date: Thu, 19 Jul 2018 04:50:29 -0700 Subject: [PATCH 17/25] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1861339..0138e72 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ _Only tested with macOS_ When done, `docker-compose stop` or `docker-compose down`. -## To Run On `localhost` +## To Run On localhost If you'd rather run node on localhost, then... From 6a80439b3da883bcc91289ef44adeb0d3b2a4bba Mon Sep 17 00:00:00 2001 From: rchristian Date: Thu, 19 Jul 2018 20:50:15 -0700 Subject: [PATCH 18/25] Separate .env vars from hostname vars, improve bootstrap.js dependability. --- .env-example | 17 +++------ .gitignore | 4 +-- app/index.js | 12 ++++--- app/routes.js | 9 ++--- docker-compose.yml | 24 ++++++------- env/your hostname here | 12 +++++++ localhost-env-vars/.keep | 0 scripts/bootstrap.js | 74 +++++++++++++++++++++++++++++++--------- 8 files changed, 100 insertions(+), 52 deletions(-) create mode 100644 env/your hostname here delete mode 100644 localhost-env-vars/.keep diff --git a/.env-example b/.env-example index ba16f88..617176f 100644 --- a/.env-example +++ b/.env-example @@ -1,13 +1,4 @@ -JWT_SECRET=keep_it_secret_keep_it_safe -ENABLE_HTTPS=false - -DB_USERPASS=localhost -DB_USERNAME=apiuser -DB_NAME=platform -DB_LOCATION=http://localhost -DB_PORT=8529 - -API_PORT=8080 -NODE_ENV=develop - -ARANGO_ROOT_PASSWORD=localhost \ No newline at end of file +DB_PORT_EXTERNAL=8181 +API_PORT_EXTERNAL=8686 +HOSTNAME=your hostname goes here +COMPOSE_PROJECT_NAME=platform \ No newline at end of file diff --git a/.gitignore b/.gitignore index b706e9d..2ba874b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ node_modules/ -localhost-env-vars/* -!localhost-env-vars/.keep +env/* +!env/your hostname here .env \ No newline at end of file diff --git a/app/index.js b/app/index.js index f7641ff..8cf00a9 100644 --- a/app/index.js +++ b/app/index.js @@ -1,6 +1,8 @@ 'use strict' -const { ENABLE_HTTPS, API_PORT } = process.env +// API_PORT_INTERNAL = 9191 + +const { ENABLE_HTTPS } = process.env const fs = require('fs') const https = require('https') @@ -45,15 +47,15 @@ if (JSON.parse(ENABLE_HTTPS)) { cert: fs.readFileSync('./certs/root-ca.crt'), ca: fs.readFileSync('./certs/intermediate.crt'), } - https.createServer(ssl, app).listen(API_PORT, ()=> { + https.createServer(ssl, app).listen(9191, ()=> { console.log('Using HTTPS') - console.log(`API is now running on port ${API_PORT}`) + console.log(`API is now running on port ${9191}`) }) } else { - app.listen(API_PORT, ()=> { + app.listen(9191, ()=> { console.log('Using HTTP') - console.log(`API is now running on port ${API_PORT}`) + console.log(`API is now running on port ${9191}`) }) } diff --git a/app/routes.js b/app/routes.js index 9f97aba..593ef4b 100644 --- a/app/routes.js +++ b/app/routes.js @@ -1,10 +1,11 @@ 'use strict' +// DB_PORT_INTERNAL = 8529 + const { + ARANGODB_DOCKER_NAME, DB_USERNAME, DB_USERPASS, - DB_LOCATION, - DB_PORT, DB_NAME, } = process.env @@ -21,7 +22,7 @@ const hour = 60 * minute const day = 24 * hour const { Database, aql } = require('arangojs') -const db = new Database(`${DB_LOCATION}:${DB_PORT}`) +const db = new Database(`http://${ARANGODB_DOCKER_NAME}:8529`) db.useDatabase(DB_NAME) db.useBasicAuth(DB_USERNAME, DB_USERPASS) @@ -56,7 +57,7 @@ apiRoutes.post('/register', async (req, res)=> { } } catch (err) { - res.send({ success: false, msg: err.message}) + res.send({ success: false, msg: err.message }) } }) diff --git a/docker-compose.yml b/docker-compose.yml index 35c226e..6a042bb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,20 +4,20 @@ version: '3' services: - database: - env_file: .env - image: arangodb - ports: - - ${DB_PORT}:${DB_PORT} - expose: - - "${DB_PORT}" - volumes: - - ./scripts:/docker-entrypoint-initdb.d - api: - env_file: .env + env_file: env/${HOSTNAME} build: ./ image: auth-api ports: - - ${API_PORT}:${API_PORT} + - ${API_PORT_EXTERNAL}:9191 command: "npm run start:containerized" + + database: + env_file: env/${HOSTNAME} + image: arangodb + ports: + - ${DB_PORT_EXTERNAL}:8529 + # expose: + # - "8529" + volumes: + - ./scripts:/docker-entrypoint-initdb.d diff --git a/env/your hostname here b/env/your hostname here new file mode 100644 index 0000000..0372951 --- /dev/null +++ b/env/your hostname here @@ -0,0 +1,12 @@ +JWT_SECRET=keep_it_secret_keep_it_safe +ENABLE_HTTPS=false + +DB_USERPASS=localhost +DB_USERNAME=apiuser +DB_NAME=platform +ARANGODB_DOCKER_NAME=database +DB_PORT_EXTERNAL=8181 + +NODE_ENV=develop + +ARANGO_ROOT_PASSWORD=localhost \ No newline at end of file diff --git a/localhost-env-vars/.keep b/localhost-env-vars/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/scripts/bootstrap.js b/scripts/bootstrap.js index 0f17133..15dc438 100755 --- a/scripts/bootstrap.js +++ b/scripts/bootstrap.js @@ -1,26 +1,68 @@ #!/usr/bin/arangosh --javascript.execute -// the values here must match with .env const _user = require('@arangodb/users') -try { - db._useDatabase('platform') -} catch (err) { - db._createDatabase('platform') - db._useDatabase('platform') +// v must match with your env vars! +const dbname = 'platform' +const dbuser = 'apiuser' +const passwd = 'localhost' +const collectionName = 'users' +// ^ must match with your env vars! + +const attempts = 5 +let status = null + +for (let i=1; i <= attempts && status !== 'success'; i++) { + + bootstrap() + status = verify() + + console.log(`Attempt ${i} of ${attempts}: Bootstrap status: ${status}`) } -try { - _user.save('apiuser', 'localhost') - _user.grantDatabase('apiuser', 'platform') -} catch (err) { - // if error, assume the user already exists - _user.grantDatabase('apiuser', 'platform') +function bootstrap() { + + try { + db._createDatabase(dbname) + } catch (err) {} + + try { + db._useDatabase(dbname) + } catch (err) {} + + try { + _user.save(dbuser, passwd) + } catch (err) {} + + try { + _user.grantDatabase(dbuser, dbname) + } catch (err) {} + + try { + db._create(collectionName) + } catch (err) {} + + return 'all done' } -try { - db._create('users') -} catch (err) { - // if error, the users collection must already exist +function verify() { + + if (db._name() !== dbname) { + return 'failure' + } + + if (db._collection(collectionName) === null) { + return 'failure' + } + + if (!_user.isValid(dbuser, passwd)) { + return 'failure' + } + + if (_user.permission(dbuser, dbname) !== 'rw') { + return 'failure' + } + + return 'success' } From 6c2d9c101ba1e01d3cc80718cd2abf1979025096 Mon Sep 17 00:00:00 2001 From: rchristian Date: Fri, 20 Jul 2018 00:32:07 -0700 Subject: [PATCH 19/25] Update readme, remove unused env var. --- README.md | 9 +++++---- docker-compose.yml | 2 -- env/your hostname here | 4 +--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 0138e72..a57a352 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,11 @@ _Only tested with macOS_ ## Setup +* Update `HOSTNAME=your hostname goes here` in file `.env-example` * Rename `.env-example` to `.env` +* Rename `env/your hostname here` to match your hostname exactly + +You can get the hostname of your machine by running `hostname` in the command terminal. ## To Run @@ -77,10 +81,7 @@ Get user data by providing `token`. ### Using cURL to register a new user ``` -curl -X POST \ - http://localhost:8080/api/users/register \ - -H 'Content-Type: application/x-www-form-urlencoded' \ - -d 'username=jwoods&password=password' +curl -X POST http://localhost:8686/api/users/register -d 'username=jwoods&password=password' ``` ## Credits diff --git a/docker-compose.yml b/docker-compose.yml index 6a042bb..569268b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,7 +17,5 @@ services: image: arangodb ports: - ${DB_PORT_EXTERNAL}:8529 - # expose: - # - "8529" volumes: - ./scripts:/docker-entrypoint-initdb.d diff --git a/env/your hostname here b/env/your hostname here index 0372951..62c01cd 100644 --- a/env/your hostname here +++ b/env/your hostname here @@ -5,8 +5,6 @@ DB_USERPASS=localhost DB_USERNAME=apiuser DB_NAME=platform ARANGODB_DOCKER_NAME=database -DB_PORT_EXTERNAL=8181 +ARANGO_ROOT_PASSWORD=localhost NODE_ENV=develop - -ARANGO_ROOT_PASSWORD=localhost \ No newline at end of file From bee03507cd09db21822a2bedd1b79d70374a411e Mon Sep 17 00:00:00 2001 From: rchristian Date: Fri, 20 Jul 2018 08:28:37 -0700 Subject: [PATCH 20/25] Rewrite & make auth controllers "thin", make JWT work, try to improve bootstrap.js. --- README.md | 13 +- app/auth.js | 48 -- app/helpers.js | 90 +++ app/index.js | 4 +- app/jwt.js | 23 + app/routes.js | 194 +++--- package.json | 6 +- scripts/bootstrap.js | 14 +- yarn.lock | 1481 +++++++++++++++++++++++++++++++++++++++++- 9 files changed, 1691 insertions(+), 182 deletions(-) delete mode 100644 app/auth.js create mode 100644 app/helpers.js create mode 100644 app/jwt.js diff --git a/README.md b/README.md index a57a352..7c55538 100644 --- a/README.md +++ b/README.md @@ -70,20 +70,27 @@ sample cURL command below. ### POST `/api/users/register` Register by providing `username` and `password`. +``` +curl -X POST http://localhost:8686/api/users/register -d 'username=jim&password=password' +``` + ### POST `/api/users/authenticate` Authenticate by providing `username` and `password`. +``` +curl -X POST http://localhost:8686/api/users/authenticate -d 'username=jim&password=password' +``` + ### GET `/api/users/memberinfo` Get user data by providing `token`. - -### Using cURL to register a new user ``` -curl -X POST http://localhost:8686/api/users/register -d 'username=jwoods&password=password' +curl -X GET http://localhost:8686/api/users/memberinfo -H 'Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImppbSIsImV4cGlyYXRpb24iOjE1MzIyNzMxMjQwODV9.uKTvxRwZbRMF_WYA5EmVKGvGUJc3Wx9TTjWR7I7MLy4' ``` + ## Credits Based on https://github.com/clemudensi/nodeJS_backend diff --git a/app/auth.js b/app/auth.js deleted file mode 100644 index c0a7f86..0000000 --- a/app/auth.js +++ /dev/null @@ -1,48 +0,0 @@ -'use strict' - -const { JWT_SECRET } = process.env -const { Strategy: StrategyJwt, ExtractJwt } = require('passport-jwt') -const passport = require('passport') - - -const opts = { - jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme('jwt'), - secretOrKey: JWT_SECRET, -} - -passport.use(new StrategyJwt(opts, (jwt_payload, done)=> { - - return (jwt_payload.expiration <= Date.now()) ? ( - done(null, false, {msg: 'Token expired.'}) - ) : ( - done(null, jwt_payload) - ) - -})) - -module.exports = { - - initialize: function() { - return passport.initialize() - }, - - authenticate: function() { - return passport.authenticate('jwt', { session: false}) - }, - - getToken: function (headers) { - - if (headers && headers.authorization) { - - const parted = headers.authorization.split(' ') - - return (parted.length === 2) ? parted[1] : null - - } - - else { - return null - } - - } -} diff --git a/app/helpers.js b/app/helpers.js new file mode 100644 index 0000000..eccad7d --- /dev/null +++ b/app/helpers.js @@ -0,0 +1,90 @@ +'use strict' + +// DB_PORT_INTERNAL = 8529 + +const { + JWT_SECRET, + ARANGODB_DOCKER_NAME, + DB_USERNAME, + DB_USERPASS, + DB_NAME, +} = process.env + +const jwtSimple = require('jwt-simple') // <-- I suspect this is a hack +const bcrypt = require('bcryptjs') + +const { Database, aql } = require('arangojs') +const db = new Database(`http://${ARANGODB_DOCKER_NAME}:8529`) +db.useDatabase(DB_NAME) +db.useBasicAuth(DB_USERNAME, DB_USERPASS) + +const salt = bcrypt.genSaltSync(10) +const second = 1000 +const minute = 60 * second +const hour = 60 * minute +const day = 24 * hour + + +async function userRegister(username, password) { + + const hash = bcrypt.hashSync(password, salt) + + return await db.collection('users').save({ username, password: hash }) +} + +async function findUser(username) { + + const cursor = await db.query(aql`FOR user IN users + FILTER user.username==${String(username)} + RETURN user`) + + return await cursor.next() +} + +const passwordMatch = (user, plaintext)=> bcrypt.compareSync(plaintext, user.password) + +const okay = (res, message)=> jsonMessage(res, true, message) + +const fail = (res, message)=> jsonMessage(res, false, message) + +const jsonOkay = (res, json)=> res.json({ success: true, ...json }) + +const jsonMessage = (res, status, message)=> res.json({ success: status, msg: message }) + +const jwtDecode = headers=> + headers && headers.authorization + ? jwtSimple.decode(headers.authorization.replace(/^JWT\s/,''), JWT_SECRET) + : null + +const jwtEncode = (req, username)=> { + + // using data from req is not yet implemented + const payload = { + username, + expiration: Date.now() + 2 * day, + } + + return { payload, token: `JWT ${jwtSimple.encode(payload, JWT_SECRET)}` } +} + +function exitIfMissing(res, username, password) { + + if (!username || !password) { + + fail(res, `Missing ${ + andify([[!username, 'username'], [!password, 'password']]) + }`) + + return true + } + return false +} + +function andify(words) { + const missing = [] + words.forEach(word=> word[0] ? missing.push(word[1]) : 0) + + return missing.join(' and ') +} + +module.exports = { andify, exitIfMissing, jwtEncode, jwtDecode, jsonOkay, fail, okay, findUser, userRegister, passwordMatch } diff --git a/app/index.js b/app/index.js index 8cf00a9..0d7fed7 100644 --- a/app/index.js +++ b/app/index.js @@ -49,13 +49,13 @@ if (JSON.parse(ENABLE_HTTPS)) { } https.createServer(ssl, app).listen(9191, ()=> { console.log('Using HTTPS') - console.log(`API is now running on port ${9191}`) + console.log(`API is now running on port 9191`) }) } else { app.listen(9191, ()=> { console.log('Using HTTP') - console.log(`API is now running on port ${9191}`) + console.log(`API is now running on port 9191`) }) } diff --git a/app/jwt.js b/app/jwt.js new file mode 100644 index 0000000..124956c --- /dev/null +++ b/app/jwt.js @@ -0,0 +1,23 @@ +'use strict' + +const { JWT_SECRET } = process.env +const { Strategy, ExtractJwt } = require('passport-jwt') +const passport = require('passport') + + +const opts = { + jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme('jwt'), + secretOrKey: JWT_SECRET, +} +const strategy = new Strategy(opts, (jwtPayload, done)=> { + return jwtPayload.expiration <= Date.now() + ? done(null, false, { msg:'Token expired' }) + : done(null, jwtPayload) +}) +passport.use(strategy) + + +module.exports = { + authenticate: passport.authenticate('jwt', { session:false, assignProperty:'jwt' }), + initialize: ()=> passport.initialize(), +} diff --git a/app/routes.js b/app/routes.js index 593ef4b..2e4ca30 100644 --- a/app/routes.js +++ b/app/routes.js @@ -1,146 +1,98 @@ 'use strict' -// DB_PORT_INTERNAL = 8529 +const JWT = require('./jwt') +const passport = require('passport') +const express = require('express') +const apiRoutes = express.Router() const { - ARANGODB_DOCKER_NAME, - DB_USERNAME, - DB_USERPASS, - DB_NAME, -} = process.env - -const express = require('express') -const apiRoutes = express.Router() -const bcrypt = require('bcryptjs') -const jwt = require('jwt-simple') -const auth = require('./auth') - - -const second = 1000 -const minute = 60 * second -const hour = 60 * minute -const day = 24 * hour - -const { Database, aql } = require('arangojs') -const db = new Database(`http://${ARANGODB_DOCKER_NAME}:8529`) -db.useDatabase(DB_NAME) -db.useBasicAuth(DB_USERNAME, DB_USERPASS) - -apiRoutes.use(auth.initialize()) - -apiRoutes.post('/register', async (req, res)=> { - - const { username, password: _password } = req.body - - if (!username || !_password) { - return res.json({ - success: false, - msg: 'Please pass username and password.', - }) - } + andify, + exitIfMissing, + jwtEncode, + jwtDecode, + jsonOkay, + findUser, + userRegister, + okay, + fail, + passwordMatch, +} = require('./helpers') + +apiRoutes.use(JWT.initialize()) +apiRoutes.post('/register', register) +apiRoutes.post('/authenticate', authenticate) +apiRoutes.get('/memberinfo', JWT.authenticate, memberInfo) + + +async function register(req, res) { + try { + + const { username, password } = req.body + if (exitIfMissing(res, username, password)) { + return + } - const password = bcrypt.hashSync(_password, 10) + if (await findUser(username)) { + return fail(res, 'That username is already taken') + } - try { - const cursor = await db.query(aql`FOR x IN users - FILTER x.username==${String(username)} - RETURN "true"`) - const result = await cursor.next() + const regResult = await userRegister(username, password) + console.log('regResult', regResult) + return okay(res, 'Registration successful') - if (!result) { - await db.collection('users').save({ username, password }) - res.json({ success: true, msg: 'Successful created new user' }) + } catch (err) { + fail(res, err.message) + console.log(err) } +} - else { - res.json({ success: false, msg: 'Username already exists.' }) - } - - } catch (err) { - res.send({ success: false, msg: err.message }) - } - -}) - -apiRoutes.post('/authenticate', (req, res)=> { - const { username, password } = req.body +async function authenticate(req, res) { + try { - if (username && password) { - - ;(async ()=> { - - try { - const cursor = await db.query(aql`FOR x IN users - FILTER x.username==${String(username)} - RETURN { username: x.username, password: x.password }`) - const result = await cursor.next() - - // if user is found and password is correct return a token with payload - if (result && bcrypt.compareSync(password, result.password)) { - - const payload = { - username: result.username, - expiration: Date.now() + 2 * day, - } + const { username, password } = req.body + if (exitIfMissing(res, username, password)) { + return + } - const token = jwt.encode(payload, JWT_SECRET) - res.json({ - success: true, - token: `JWT ${token}`, - payload: payload - }) + const user = await findUser(username) + if (!user) { + return fail(res, 'Authentication failed, no match') } + if (passwordMatch(user, password)) { + const { payload, token } = jwtEncode(req, username) + return jsonOkay(res, { token, payload }) + } else { - res.send({ success: false, msg: 'Authentication failed.' }) + return fail(res, 'Invalid credentials') } - } catch (err) { - res.send({ success: false, msg: 'Authentication failed.' }) - } - - })() - } - - else { - res.send({ success: false, msg: 'Authentication failed.' }) - } -}) - -// route to a restricted info (GET /api/users/memberinfo) -apiRoutes.get('/memberinfo', auth.authenticate(), (req, res)=> { - - const decoded = jwt.decode(auth.getToken(req.headers), JWT_SECRET) + } catch (err) { + fail(res, err.message) + console.log(err) + } +} - if (decoded) { - db.query(aql`FOR x IN users - FILTER x.username==${String(decoded.username)} - RETURN x`, (err, user, fields)=> { +async function memberInfo(req, res, done) { + try { - if (err) throw err + const { jwt } = req + if (!jwt || !jwt.username) { + return fail(res, 'Unknown auth error') + } - else if (user._result[0]) { - res.json({ - success: true, - msg: 'Welcome in the member area, this is your data:', - data: user._result[0], - }) - } + const user = await findUser(jwt.username) + return user + ? jsonOkay(res, { msg:'Welcome', data:user }) + : fail(res, 'Authentication failed. User not found') - else { - return res.send({ - success: false, - msg: 'Authentication failed. User not found.', - }) - } - }) - } + } catch (err) { + fail(res, err.message) + console.log(err) + } +} - else { - return res.send({ success: false, msg: 'No token provided.' }) - } -}) module.exports = apiRoutes diff --git a/package.json b/package.json index 1095b28..8661cbb 100644 --- a/package.json +++ b/package.json @@ -14,13 +14,15 @@ "passport-jwt": "*" }, "scripts": { - "start": "node -r dotenv/config app/index.js dotenv_config_path=localhost-env-vars/$(hostname)", + "start": "node -r dotenv/config app/index.js dotenv_config_path=env/$(hostname)", + "start:watch": "nodemon -r dotenv/config app/index.js dotenv_config_path=env/$(hostname)", "start:containerized": "node app/index.js" }, "version": "1.0.0", "description": "Creating API with JWT user authentication using Express, Passport JWT and ArangoDB", "devDependencies": { - "dotenv": "^6.0.0" + "dotenv": "^6.0.0", + "nodemon": "^1.18.3" }, "repository": { "type": "git", diff --git a/scripts/bootstrap.js b/scripts/bootstrap.js index 15dc438..3dbf736 100755 --- a/scripts/bootstrap.js +++ b/scripts/bootstrap.js @@ -15,12 +15,22 @@ let status = null for (let i=1; i <= attempts && status !== 'success'; i++) { - bootstrap() - status = verify() + try { + bootstrap() + } catch (err) { + // + } + try { + status = verify() + } catch (err) { + // + } console.log(`Attempt ${i} of ${attempts}: Bootstrap status: ${status}`) } +console.log('Bootstrapping complete') + function bootstrap() { try { diff --git a/yarn.lock b/yarn.lock index ae88f7e..d2ff488 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,10 @@ # yarn lockfile v1 +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + accepts@~1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" @@ -9,6 +13,37 @@ accepts@~1.3.5: mime-types "~2.1.18" negotiator "0.6.1" +ansi-align@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" + dependencies: + string-width "^2.0.0" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + arango@*: version "1.3.4" resolved "https://registry.yarnpkg.com/arango/-/arango-1.3.4.tgz#5a3ccc24bc152c7fafc61658c1dedce331085970" @@ -29,14 +64,65 @@ arangojs@^5.4.2: utf8-length "^0.0.1" xhr "^2.3.1" +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +atob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + "base64@git://github.com/kaerus-component/base64.git#0.1.0": version "0.1.0" resolved "git://github.com/kaerus-component/base64.git#b2b0d864a0da58616d56f83ac7e06866bf90ab93" +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + basic-auth@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.0.tgz#015db3f353e02e56377755f962742e8981e7bbba" @@ -47,6 +133,10 @@ bcryptjs@*: version "2.4.3" resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" +binary-extensions@^1.0.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + body-parser@*: version "1.18.3" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" @@ -77,6 +167,40 @@ body-parser@1.18.2: raw-body "2.3.2" type-is "~1.6.15" +boxen@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" + dependencies: + ansi-align "^2.0.0" + camelcase "^4.0.0" + chalk "^2.0.1" + cli-boxes "^1.0.0" + string-width "^2.0.0" + term-size "^1.2.0" + widest-line "^2.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.0, braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" @@ -85,10 +209,124 @@ bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +camelcase@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + camelize@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" +capture-stack-trace@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" + +chalk@^2.0.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chokidar@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + lodash.debounce "^4.0.8" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.5" + optionalDependencies: + fsevents "^1.2.2" + +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + +ci-info@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +cli-boxes@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.2" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" + dependencies: + color-name "1.1.1" + +color-name@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" + +component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +configstore@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f" + dependencies: + dot-prop "^4.1.0" + graceful-fs "^4.1.2" + make-dir "^1.0.0" + unique-string "^1.0.0" + write-file-atomic "^2.0.0" + xdg-basedir "^3.0.0" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" @@ -109,16 +347,79 @@ cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +create-error-class@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" + dependencies: + capture-stack-trace "^1.0.0" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +crypto-random-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" + dasherize@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/dasherize/-/dasherize-2.0.0.tgz#6d809c9cd0cf7bb8952d80fc84fa13d47ddb1308" -debug@2.6.9: +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: ms "2.0.0" +debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + depd@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" @@ -131,6 +432,10 @@ destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + dns-prefetch-control@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz#60ddb457774e178f1f9415f0cabb0e85b0b300b2" @@ -143,10 +448,24 @@ dont-sniff-mimetype@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz#5932890dc9f4e2f19e5eb02a20026e5e5efc8f58" +dot-prop@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" + dependencies: + is-obj "^1.0.0" + dotenv@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.0.0.tgz#24e37c041741c5f4b25324958ebbc34bca965935" +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + +duplexer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + ecdsa-sig-formatter@1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz#1c595000f04a8897dfb85000892a0f4c33af86c3" @@ -169,10 +488,50 @@ escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" +event-stream@~3.3.0: + version "3.3.4" + resolved "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" + dependencies: + duplexer "~0.1.1" + from "~0" + map-stream "~0.1.0" + pause-stream "0.0.11" + split "0.3" + stream-combiner "~0.0.4" + through "~2.3.1" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + expect-ct@0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/expect-ct/-/expect-ct-0.1.1.tgz#de84476a2dbcb85000d5903737e9bc8a5ba7b897" @@ -212,10 +571,45 @@ express@*: utils-merge "1.0.1" vary "~1.1.2" +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + file-type@^4.3.0: version "4.4.0" resolved "https://registry.yarnpkg.com/file-type/-/file-type-4.4.0.tgz#1b600e5fca1fbdc6e80c0a70c71c8dba5f7906c5" +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + finalhandler@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" @@ -234,10 +628,20 @@ for-each@^0.3.2: dependencies: is-callable "^1.1.3" +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + frameguard@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/frameguard/-/frameguard-3.0.0.tgz#7bcad469ee7b96e91d12ceb3959c78235a9272e9" @@ -246,6 +650,72 @@ fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" +from@~0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + dependencies: + minipass "^2.2.1" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.2.2: + version "1.2.4" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426" + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.10.0" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob@^7.0.5: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-dirs@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" + dependencies: + ini "^1.3.4" + global@~4.3.0: version "4.3.2" resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" @@ -253,6 +723,61 @@ global@~4.3.0: min-document "^2.19.0" process "~0.5.1" +got@^6.7.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" + dependencies: + create-error-class "^3.0.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-redirect "^1.0.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + lowercase-keys "^1.0.0" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + unzip-response "^2.0.1" + url-parse-lax "^1.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + helmet-csp@2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/helmet-csp/-/helmet-csp-2.7.0.tgz#7934094617d1feb7bb2dc43bb7d9e8830f774716" @@ -314,7 +839,7 @@ iconv-lite@0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" -iconv-lite@0.4.23: +iconv-lite@0.4.23, iconv-lite@^0.4.4: version "0.4.23" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" dependencies: @@ -324,22 +849,210 @@ ienoopen@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.0.0.tgz#346a428f474aac8f50cf3784ea2d0f16f62bda6b" -inherits@2.0.3: +ignore-by-default@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + dependencies: + minimatch "^3.0.4" + +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" +ini@^1.3.4, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + ipaddr.js@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b" +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + is-callable@^1.1.3: version "1.1.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" +is-ci@^1.0.10: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5" + dependencies: + ci-info "^1.0.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + is-function@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + dependencies: + is-extglob "^2.1.1" + +is-installed-globally@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" + dependencies: + global-dirs "^0.1.0" + is-path-inside "^1.0.0" + +is-npm@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + dependencies: + path-is-inside "^1.0.1" + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + +is-redirect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + +is-retry-allowed@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34" + +is-stream@^1.0.0, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + jsonwebtoken@^8.2.0: version "8.3.0" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz#056c90eee9a65ed6e6c72ddb0a1d325109aaf643" @@ -373,10 +1086,40 @@ jwt-simple@*: version "0.5.1" resolved "https://registry.yarnpkg.com/jwt-simple/-/jwt-simple-0.5.1.tgz#79ea01891b61de6b68e13e67c0b4b5bda937b294" +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + +latest-version@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" + dependencies: + package-json "^4.0.0" + linkedlist@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/linkedlist/-/linkedlist-1.0.1.tgz#7b74189bfad6e76367fb5a10f3c36913128b782b" +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + lodash.includes@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" @@ -409,6 +1152,37 @@ lodash.reduce@4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" +lowercase-keys@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + +lru-cache@^4.0.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + dependencies: + pify "^3.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -421,6 +1195,24 @@ methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" +micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + micropromise@0.4.6: version "0.4.6" resolved "https://registry.yarnpkg.com/micropromise/-/micropromise-0.4.6.tgz#91628d56a21d365060b0a4493100234f3131fa0a" @@ -458,6 +1250,46 @@ min-document@^2.19.0: dependencies: dom-walk "^0.1.0" +minimatch@^3.0.2, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +minipass@^2.2.1, minipass@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" + dependencies: + minipass "^2.2.1" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + morgan@*: version "1.9.0" resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.0.tgz#d01fa6c65859b76fcf31b3cb53a3821a311d8051" @@ -482,6 +1314,34 @@ multi-part@^2.0.0: dependencies: mime-kind "^2.0.1" +nan@^2.9.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +needle@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" @@ -490,6 +1350,109 @@ nocache@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.0.0.tgz#202b48021a0c4cbde2df80de15a17443c8b43980" +node-pre-gyp@^0.10.0: + version "0.10.3" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +nodemon@^1.18.3: + version "1.18.3" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.18.3.tgz#46e681ee0dd1b590562e03019b4c5df234f906f9" + dependencies: + chokidar "^2.0.2" + debug "^3.1.0" + ignore-by-default "^1.0.1" + minimatch "^3.0.4" + pstree.remy "^1.1.0" + semver "^5.5.0" + supports-color "^5.2.0" + touch "^3.1.0" + undefsafe "^2.0.2" + update-notifier "^2.3.0" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +nopt@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" + dependencies: + abbrev "1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +npm-bundled@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" + +npm-packlist@^1.1.6: + version "1.1.10" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.10.tgz#1039db9e985727e464df066f4cf0ab6ef85c398a" + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + dependencies: + path-key "^2.0.0" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -500,6 +1463,40 @@ on-headers@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-tmpdir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + +package-json@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" + dependencies: + got "^6.7.1" + registry-auth-token "^3.0.1" + registry-url "^3.0.3" + semver "^5.1.0" + parse-headers@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.1.tgz#6ae83a7aa25a9d9b700acc28698cd1f1ed7e9536" @@ -511,6 +1508,10 @@ parseurl@~1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + passport-jwt@*: version "4.0.0" resolved "https://registry.yarnpkg.com/passport-jwt/-/passport-jwt-4.0.0.tgz#7f0be7ba942e28b9f5d22c2ebbb8ce96ef7cf065" @@ -529,18 +1530,56 @@ passport@*: passport-strategy "1.x.x" pause "0.0.1" +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-key@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" +pause-stream@0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" + dependencies: + through "~2.3" + pause@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + platform@1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.5.tgz#fb6958c696e07e2918d2eeda0f0bc9448d733444" +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + process@~0.5.1: version "0.5.2" resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" @@ -552,6 +1591,22 @@ proxy-addr@~2.0.3: forwarded "~0.1.2" ipaddr.js "1.6.0" +ps-tree@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.1.0.tgz#b421b24140d6203f1ed3c76996b4427b08e8c014" + dependencies: + event-stream "~3.3.0" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +pstree.remy@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.0.tgz#f2af27265bd3e5b32bbfcc10e80bac55ba78688b" + dependencies: + ps-tree "^1.1.0" + qs@6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" @@ -582,26 +1637,122 @@ raw-body@2.3.3: iconv-lite "0.4.23" unpipe "1.0.0" +rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +readable-stream@^2.0.2, readable-stream@^2.0.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + referrer-policy@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.1.0.tgz#35774eb735bf50fb6c078e83334b472350207d79" +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +registry-auth-token@^3.0.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" + dependencies: + rc "^1.1.6" + safe-buffer "^5.0.1" + +registry-url@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + dependencies: + rc "^1.0.1" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + retry@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" +rimraf@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + safe-buffer@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -safe-buffer@^5.0.1: +safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + "safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + +semver-diff@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" + dependencies: + semver "^5.0.3" + +semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + send@0.16.2: version "0.16.2" resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" @@ -629,6 +1780,32 @@ serve-static@1.13.2: parseurl "~1.3.2" send "0.16.2" +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + setprototypeof@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" @@ -637,6 +1814,84 @@ setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + +split@0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" + dependencies: + through "2" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + "statuses@>= 1.3.1 < 2", "statuses@>= 1.4.0 < 2": version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -645,6 +1900,113 @@ statuses@~1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" +stream-combiner@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" + dependencies: + duplexer "~0.1.1" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +supports-color@^5.2.0, supports-color@^5.3.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + dependencies: + has-flag "^3.0.0" + +tar@^4: + version "4.4.4" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" + dependencies: + chownr "^1.0.1" + fs-minipass "^1.2.5" + minipass "^2.3.3" + minizlib "^1.1.0" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +term-size@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" + dependencies: + execa "^0.7.0" + +through@2, through@~2.3, through@~2.3.1: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +timed-out@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +touch@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" + dependencies: + nopt "~1.0.10" + trim@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" @@ -656,18 +2018,87 @@ type-is@~1.6.15, type-is@~1.6.16: media-typer "0.3.0" mime-types "~2.1.18" +undefsafe@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.2.tgz#225f6b9e0337663e0d8e7cfd686fc2836ccace76" + dependencies: + debug "^2.2.0" + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +unique-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" + dependencies: + crypto-random-string "^1.0.0" + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +unzip-response@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" + +upath@^1.0.5: + version "1.1.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" + +update-notifier@^2.3.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6" + dependencies: + boxen "^1.2.1" + chalk "^2.0.1" + configstore "^3.0.0" + import-lazy "^2.1.0" + is-ci "^1.0.10" + is-installed-globally "^0.1.0" + is-npm "^1.0.0" + latest-version "^3.0.0" + semver-diff "^2.0.0" + xdg-basedir "^3.0.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + dependencies: + prepend-http "^1.0.1" + "urlparser@git://github.com/kaerus-component/urlparser.git#0.3.9": version "0.3.9" resolved "git://github.com/kaerus-component/urlparser.git#07e88f200dba112749f731a19d4d548d2f0a575a" +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + utf8-length@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/utf8-length/-/utf8-length-0.0.1.tgz#d315c4bed529c977f18dd35c73d72628327d9ada" +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -676,10 +2107,44 @@ vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + dependencies: + string-width "^1.0.2 || 2" + +widest-line@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.0.tgz#0142a4e8a243f8882c0233aa0e0281aa76152273" + dependencies: + string-width "^2.1.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-atomic@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + x-xss-protection@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/x-xss-protection/-/x-xss-protection-1.1.0.tgz#4f1898c332deb1e7f2be1280efb3e2c53d69c1a7" +xdg-basedir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" + xhr@^2.3.1: version "2.5.0" resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.5.0.tgz#bed8d1676d5ca36108667692b74b316c496e49dd" @@ -692,3 +2157,11 @@ xhr@^2.3.1: xtend@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" From 06a82b8339f84f1155d4ec8cc54d6cc3678cd6d4 Mon Sep 17 00:00:00 2001 From: rchristian Date: Fri, 20 Jul 2018 08:57:30 -0700 Subject: [PATCH 21/25] Fix needed updates to ENV vars and readme. --- .env-example | 4 ++-- README.md | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/.env-example b/.env-example index 617176f..4390a93 100644 --- a/.env-example +++ b/.env-example @@ -1,4 +1,4 @@ -DB_PORT_EXTERNAL=8181 -API_PORT_EXTERNAL=8686 +DB_PORT_EXTERNAL=8529 +API_PORT_EXTERNAL=9191 HOSTNAME=your hostname goes here COMPOSE_PROJECT_NAME=platform \ No newline at end of file diff --git a/README.md b/README.md index 7c55538..3f37e41 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,8 @@ You can get the hostname of your machine by running `hostname` in the command te * `docker-compose up -d` (or just `docker-compose up`) -When done, `docker-compose stop` or `docker-compose down`. +When done, `docker-compose stop` or `docker-compose down`. I notice the API image has to be +erased manually to get the code to update, use `docker image remove `. ## To Run On localhost @@ -43,11 +44,12 @@ When done, `docker-compose stop` or `docker-compose down`. If you'd rather run node on localhost, then... * `yarn install` - * (Yarn is better than npm, do `npm install -g yarn`) -* Copy `.env` to `localhost-env-vars/` + * (Yarn is faster than npm, if you don't have it, do `npm install -g yarn`) +* Rename `env/your hostname here` to match your hostname exactly * (If you don't know your hostname, run `hostname` in the terminal) -* `docker-compose up -d database` to run ArangoDB -* `npm start` +* Change the `ARANGODB_DOCKER_NAME` ENV var to `localhost` instead of `database` +* `docker-compose up -d database` to run ArangoDB (or just `docker-compose up database`) +* `npm start` to run the API on localhost, or `npm run start:watch` for auto-reload If you're going to run ArangoDB on localhost, see `scripts/boostrap.js`, this runs automatically when using `docker-compose`. @@ -71,7 +73,7 @@ sample cURL command below. Register by providing `username` and `password`. ``` -curl -X POST http://localhost:8686/api/users/register -d 'username=jim&password=password' +curl -X POST http://localhost:9191/api/users/register -d 'username=jim&password=password' ``` @@ -79,7 +81,7 @@ curl -X POST http://localhost:8686/api/users/register -d 'username=jim&password= Authenticate by providing `username` and `password`. ``` -curl -X POST http://localhost:8686/api/users/authenticate -d 'username=jim&password=password' +curl -X POST http://localhost:9191/api/users/authenticate -d 'username=jim&password=password' ``` @@ -87,7 +89,7 @@ curl -X POST http://localhost:8686/api/users/authenticate -d 'username=jim&passw Get user data by providing `token`. ``` -curl -X GET http://localhost:8686/api/users/memberinfo -H 'Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImppbSIsImV4cGlyYXRpb24iOjE1MzIyNzMxMjQwODV9.uKTvxRwZbRMF_WYA5EmVKGvGUJc3Wx9TTjWR7I7MLy4' +curl -X GET http://localhost:9191/api/users/memberinfo -H 'Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImppbSIsImV4cGlyYXRpb24iOjE1MzIyNzMxMjQwODV9.uKTvxRwZbRMF_WYA5EmVKGvGUJc3Wx9TTjWR7I7MLy4' ``` From 3d96cfbf7de951382c61834e27cf3a3c43b5999a Mon Sep 17 00:00:00 2001 From: rchristian Date: Fri, 20 Jul 2018 09:11:02 -0700 Subject: [PATCH 22/25] Move controllers to individual files. --- app/controllers/authenticate.js | 37 +++++++++++++ app/{ => controllers}/helpers.js | 0 app/controllers/memberinfo.js | 26 +++++++++ app/controllers/register.js | 31 +++++++++++ app/routes.js | 90 ++------------------------------ 5 files changed, 97 insertions(+), 87 deletions(-) create mode 100644 app/controllers/authenticate.js rename app/{ => controllers}/helpers.js (100%) create mode 100644 app/controllers/memberinfo.js create mode 100644 app/controllers/register.js diff --git a/app/controllers/authenticate.js b/app/controllers/authenticate.js new file mode 100644 index 0000000..0f4c2cf --- /dev/null +++ b/app/controllers/authenticate.js @@ -0,0 +1,37 @@ + +const { + exitIfMissing, + findUser, + passwordMatch, + jwtEncode, + jsonOkay, + fail, +} = require('./helpers') + + +module.exports = async (req, res)=> { + try { + + const { username, password } = req.body + if (exitIfMissing(res, username, password)) { + return + } + + const user = await findUser(username) + if (!user) { + return fail(res, 'Authentication failed, no match') + } + + if (passwordMatch(user, password)) { + const { payload, token } = jwtEncode(req, username) + return jsonOkay(res, { token, payload }) + } + else { + return fail(res, 'Invalid credentials') + } + + } catch (err) { + fail(res, err.message) + console.log(err) + } +} diff --git a/app/helpers.js b/app/controllers/helpers.js similarity index 100% rename from app/helpers.js rename to app/controllers/helpers.js diff --git a/app/controllers/memberinfo.js b/app/controllers/memberinfo.js new file mode 100644 index 0000000..230373a --- /dev/null +++ b/app/controllers/memberinfo.js @@ -0,0 +1,26 @@ + +const { + fail, + findUser, + jsonOkay, +} = require('./helpers') + + +module.exports = async (req, res, done)=> { + try { + + const { jwt } = req + if (!jwt || !jwt.username) { + return fail(res, 'Unknown auth error') + } + + const user = await findUser(jwt.username) + return user + ? jsonOkay(res, { msg:'Welcome', data:user }) + : fail(res, 'Authentication failed. User not found') + + } catch (err) { + fail(res, err.message) + console.log(err) + } +} diff --git a/app/controllers/register.js b/app/controllers/register.js new file mode 100644 index 0000000..ea631af --- /dev/null +++ b/app/controllers/register.js @@ -0,0 +1,31 @@ + +const { + exitIfMissing, + findUser, + userRegister, + okay, + fail, +} = require('./helpers') + + +module.exports = async (req, res)=> { + try { + + const { username, password } = req.body + if (exitIfMissing(res, username, password)) { + return + } + + if (await findUser(username)) { + return fail(res, 'That username is already taken') + } + + const regResult = await userRegister(username, password) + console.log('regResult', regResult) + return okay(res, 'Registration successful') + + } catch (err) { + fail(res, err.message) + console.log(err) + } +} diff --git a/app/routes.js b/app/routes.js index 2e4ca30..a7aed51 100644 --- a/app/routes.js +++ b/app/routes.js @@ -1,98 +1,14 @@ 'use strict' const JWT = require('./jwt') -const passport = require('passport') const express = require('express') const apiRoutes = express.Router() -const { - andify, - exitIfMissing, - jwtEncode, - jwtDecode, - jsonOkay, - findUser, - userRegister, - okay, - fail, - passwordMatch, -} = require('./helpers') apiRoutes.use(JWT.initialize()) -apiRoutes.post('/register', register) -apiRoutes.post('/authenticate', authenticate) -apiRoutes.get('/memberinfo', JWT.authenticate, memberInfo) - - -async function register(req, res) { - try { - - const { username, password } = req.body - if (exitIfMissing(res, username, password)) { - return - } - - if (await findUser(username)) { - return fail(res, 'That username is already taken') - } - - const regResult = await userRegister(username, password) - console.log('regResult', regResult) - return okay(res, 'Registration successful') - - } catch (err) { - fail(res, err.message) - console.log(err) - } -} - - -async function authenticate(req, res) { - try { - - const { username, password } = req.body - if (exitIfMissing(res, username, password)) { - return - } - - const user = await findUser(username) - if (!user) { - return fail(res, 'Authentication failed, no match') - } - - if (passwordMatch(user, password)) { - const { payload, token } = jwtEncode(req, username) - return jsonOkay(res, { token, payload }) - } - else { - return fail(res, 'Invalid credentials') - } - - } catch (err) { - fail(res, err.message) - console.log(err) - } -} - - -async function memberInfo(req, res, done) { - try { - - const { jwt } = req - if (!jwt || !jwt.username) { - return fail(res, 'Unknown auth error') - } - - const user = await findUser(jwt.username) - return user - ? jsonOkay(res, { msg:'Welcome', data:user }) - : fail(res, 'Authentication failed. User not found') - - } catch (err) { - fail(res, err.message) - console.log(err) - } -} +apiRoutes.post('/register', require('./controllers/register')) +apiRoutes.post('/authenticate', require('./controllers/authenticate')) +apiRoutes.get('/memberinfo', JWT.authenticate, require('./controllers/memberInfo')) module.exports = apiRoutes From 7f4eeb44066c69d2ff9dbba563b6c27f46f2d3e1 Mon Sep 17 00:00:00 2001 From: Rob Christian Date: Sat, 21 Jul 2018 13:25:26 -0700 Subject: [PATCH 23/25] Add node version to readme --- README.md | 2 +- app/routes.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3f37e41..9cb24f7 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ _Only tested with macOS_ ### Optional Requirements -* [Node.js](https://nodejs.org/en/) +* [Node.js](https://nodejs.org/en/) version 9+ ## Setup diff --git a/app/routes.js b/app/routes.js index a7aed51..e70f9c7 100644 --- a/app/routes.js +++ b/app/routes.js @@ -8,7 +8,7 @@ const apiRoutes = express.Router() apiRoutes.use(JWT.initialize()) apiRoutes.post('/register', require('./controllers/register')) apiRoutes.post('/authenticate', require('./controllers/authenticate')) -apiRoutes.get('/memberinfo', JWT.authenticate, require('./controllers/memberInfo')) +apiRoutes.get('/memberinfo', JWT.authenticate, require('./controllers/memberinfo')) module.exports = apiRoutes From 6bfee0115a20714a3c5990a9feb4c90cf702138a Mon Sep 17 00:00:00 2001 From: Rob Christian Date: Sat, 21 Jul 2018 13:28:54 -0700 Subject: [PATCH 24/25] Remove expose in dockerfile --- Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index aef9149..c0fd388 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,4 +5,3 @@ COPY yarn.lock /home/node COPY app /home/node/app RUN yarn install --pure-lockfile CMD npm run start:containerized -EXPOSE 8080 \ No newline at end of file From 66c7cd4678486131c27fd790ea5b0888b12f16c7 Mon Sep 17 00:00:00 2001 From: Rob Christian Date: Mon, 23 Jul 2018 02:05:16 -0700 Subject: [PATCH 25/25] Update dockerfile to expose port --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index c0fd388..d502269 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ FROM node:9 +EXPOSE 9191 WORKDIR /home/node COPY package.json /home/node COPY yarn.lock /home/node