From 8e34c88457e73792302853bb5ceb83e558fb9a44 Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Tue, 30 Jul 2019 15:55:08 -0400 Subject: [PATCH 01/14] working on updating cb url ref #65 --- config.js | 36 +++++++++++++++++++++--------------- index.js | 8 +++++--- sessionsManager.js | 15 +++++++-------- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/config.js b/config.js index 213e172..36e83c9 100644 --- a/config.js +++ b/config.js @@ -1,33 +1,39 @@ const host = process.env.HOST || 'http://localhost'; const port = process.env.PORT || '3001'; +const maprules = `${host}:${port}`; + module.exports = { 'development': { - injectDefaults: { simulate: { error: false }}, + maprules: maprules, + injectDefaults: { simulate: { error: false } }, consumerKey: process.env.CONSUMER_KEY || '', consumerSecret: process.env.CONSUMER_SECRET || '', - callbackUrl: `${host}:${port}/auth/callback`, + callbackUrl: `${maprules}/auth/callback`, osmSite: process.env.OSM_SITE || '', - yar: { - cookieOptions: { - password: process.env.YAR, // password must be greater than 32 characters - isSecure: false // make true when requests are made of HTTPS - } + session: { + isSecure: false, // make true when requests are made of HTTPS + clearInvalid: true, + strictHeader: false }, - jwt: process.env.JWT || '' + jwt: process.env.JWT || '', + sessionKey: process.env.SESSION_KEY || '', + cors: false }, 'testing': { + maprules: maprules, injectDefaults: { simulate: { error: false }}, consumerKey: process.env.CONSUMER_KEY || '', consumerSecret: process.env.CONSUMER_SECRET || '', - callbackUrl: `${host}:${port}/auth/callback`, + callbackUrl: `${maprules}/auth/callback`, osmSite: process.env.OSM_SITE || '', - yar: { - cookieOptions: { - password: process.env.YAR, - isSecure: false - } + session: { + isSecure: false, // make true when requests are made of HTTPS + clearInvalid: true, + strictHeader: true }, - jwt: process.env.JWT || '' + jwt: process.env.JWT || '', + sessionKey: process.env.SESSION_KEY || '', + cors: true } }; diff --git a/index.js b/index.js index 074519b..3422652 100644 --- a/index.js +++ b/index.js @@ -4,13 +4,15 @@ const Hapi = require('@hapi/hapi'); const routes = require('./routes'); const config = require('./config')[process.env.NODE_ENV || 'development']; const inert = require('@hapi/inert'); -const yar = { plugin: require('@hapi/yar'), options: config.yar }; const jwtScheme = require('./jwtScheme').scheme; const server = Hapi.server({ port: process.env.PORT || 3000, host: process.env.HOST || 'localhost', - routes: { cors: true } + debug: { request: ['*']}, + routes: { + cors: true + } }); server.auth.scheme('jwt', jwtScheme); @@ -18,8 +20,8 @@ server.auth.strategy('default', 'jwt'); // initialize server const initServer = async() => { + // server.state('session', config.session); await server.register(inert); - await server.register(yar); // add endpoints server.route(routes); diff --git a/sessionsManager.js b/sessionsManager.js index 4b8659b..aef749a 100644 --- a/sessionsManager.js +++ b/sessionsManager.js @@ -1,6 +1,6 @@ 'use strict'; -let sessions = []; +let sessions = {}; /** * Manages list of current OSM oAuth sessions. @@ -10,20 +10,19 @@ let sessions = []; * */ module.exports = { - add: function(session) { - sessions.push(session); + add: function(session, value) { + sessions[session] = value; }, get: function(idx) { return sessions[idx]; }, - all: function() { - return sessions; + sessions: function() { + return Object.keys(sessions); }, remove: function(session) { - const idx = sessions.indexOf(session); - if (idx !== -1) sessions.splice(idx, 1); + delete sessions[session]; }, clear: function() { - sessions = []; + sessions = {}; } }; From bc3f4379aa569441e5deb2b0788ccaeddcbe1a86 Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Wed, 31 Jul 2019 15:39:02 -0400 Subject: [PATCH 02/14] add verify route and use jwt as httpOnly cookie ref #65 --- index.js | 7 +--- jwtScheme.js | 16 ++------ requestPromise.js | 3 +- routes/auth/index.js | 93 ++++++++++++++++++++++++++++++++------------ routes/index.js | 4 +- sessionsManager.js | 6 +++ 6 files changed, 85 insertions(+), 44 deletions(-) diff --git a/index.js b/index.js index 3422652..ad34d15 100644 --- a/index.js +++ b/index.js @@ -9,10 +9,7 @@ const jwtScheme = require('./jwtScheme').scheme; const server = Hapi.server({ port: process.env.PORT || 3000, host: process.env.HOST || 'localhost', - debug: { request: ['*']}, - routes: { - cors: true - } + routes: { cors: true } }); server.auth.scheme('jwt', jwtScheme); @@ -20,7 +17,7 @@ server.auth.strategy('default', 'jwt'); // initialize server const initServer = async() => { - // server.state('session', config.session); + server.state('maprules_session', config.session); await server.register(inert); // add endpoints diff --git a/jwtScheme.js b/jwtScheme.js index 99b8336..8024587 100644 --- a/jwtScheme.js +++ b/jwtScheme.js @@ -70,23 +70,15 @@ function isAuthorized(token, userAgent) { } function jwtAuthentication(request, h) { - return Promise.resolve(request.headers.authorization) - .then(function(authHeader) { - if (!authHeader || !authHeader.length) { - throw new Error('no token provided'); - } - - if (!authHeader.startsWith('Bearer ')) { - throw new Error('authentication strategy is invalid'); - } - - if (!authHeader.replace('Bearer ', '').length) { + return Promise.resolve(request.state.maprules_session) + .then(function(cookie) { + if (!cookie || !cookie.length) { throw new Error('no token provided'); } let token; try { - token = jwt.verify(authHeader.replace('Bearer ', ''), config.jwt); + token = jwt.verify(cookie, config.jwt); } catch (error) { throw new Error('invalid token provided'); } diff --git a/requestPromise.js b/requestPromise.js index 46cf82e..d3d3c82 100644 --- a/requestPromise.js +++ b/requestPromise.js @@ -10,8 +10,9 @@ let requestPromise = function(options) { request(options, function(err, rs, body) { if (err) { reject(err); + } else { + resolve(body); } - resolve(body); }); }); }; diff --git a/routes/auth/index.js b/routes/auth/index.js index 79a5dbd..116742a 100644 --- a/routes/auth/index.js +++ b/routes/auth/index.js @@ -11,8 +11,44 @@ const parseXML = require('xml2js').parseString; const uuid = require('uuid/v4'); const jwt = require('jsonwebtoken'); const callbackUrl = config.callbackUrl; +// const maprules = config.maprules; module.exports = { + verify: authenticate({ + method: 'GET', + path: '/auth/verify', + config: { + handler: function(r, h) { + + const { oauth_token, oauth_verifier } = r.query; + + if (!oauth_token || !oauth_verifier) { + throw Error('missing required query parameters'); + } + + let match = false; + for (let id of sessionsManager.sessions()) { + let session = sessionsManager.get(id); + if ( + session.oauth_token === oauth_token && + session.oauth_verifier === oauth_verifier + ) { + match = true; + sessionsManager.remove(id); + break; + } + } + + if (!match) throw Error('query parameter values are invalid'); + + const user = jwt.verify(r.state.maprules_session, config.jwt); + return h + .response({ name: user.name, id: user.id }) + .header('Content-Type', 'application/json') + .code(200); + } + } + }), callback: { method: 'GET', path: '/auth/callback', @@ -41,15 +77,14 @@ module.exports = { throw err; } - let oauthTokenSecret, userAgent, sessionId; + let origin, oauthTokenSecret, userAgent, sessionId; + + for (id of sessionsManager.sessions()) { + let session = sessionsManager.get(id); - for (let i = 0; i < sessionsManager.all().length; i++) { - sessionId = sessionsManager.get(i); - let session = r.yar.get(sessionId); if (!session) { - sessionsManager.remove(sessionId); - throw new Error('unknown session!!!'); + continue; } @@ -59,6 +94,8 @@ module.exports = { oauthTokenSecret = session.oauth_token_secret; userAgent = session.user_agent; + origin = session.origin; + sessionId = id; break; } @@ -71,14 +108,24 @@ module.exports = { oauthVerifier: oauthVerifier, oauthTokenSecret: oauthTokenSecret, sessionId: sessionId, - userAgent: userAgent + userAgent: userAgent, + origin: origin }; } } ], handler: function(r, h) { - let { oauthToken, oauthVerifier, oauthTokenSecret, sessionId, userAgent } = r.pre.callbackValidation; + let { + oauthToken, + oauthVerifier, + oauthTokenSecret, + sessionId, + userAgent, + origin + } = r.pre.callbackValidation; + + sessionsManager.update(sessionId, { oauth_verifier: oauthVerifier }); const accessTokenConfig = { url: `${osm}/oauth/access_token`, @@ -147,8 +194,8 @@ module.exports = { }; decodedJWT.session = uuid(); - - if (!user.length) { // if new user, insert into db and make new session jwt + + if (!user.length) { // if new user, insert into db and make new session jwt await db('users').insert(details); await db('user_sessions').insert({ id: decodedJWT.session, @@ -180,23 +227,22 @@ module.exports = { } } - return decodedJWT; + return { + jwt: decodedJWT, + origin: origin + }; } catch (error) { throw error; } }); }) - .then(function(decodedJWT) { - sessionsManager.remove(sessionId); - r.yar.clear(sessionId); - - const signedToken = jwt.sign(decodedJWT, config.jwt); - return h.response(signedToken).code(200); + .then(function(resp) { + return h + .redirect(`${resp.origin}/login.html?oauth_token=${oauthToken}&oauth_verifier=${oauthVerifier}`) + .state('maprules_session', jwt.sign(resp.jwt, config.jwt)); }) .catch(function(err) { sessionsManager.remove(sessionId); - r.yar.clear(sessionId); - throw err; }); } @@ -230,14 +276,11 @@ module.exports = { // create record ofo new session in sessions list so we can track response when // logged in user comes back to callback_url - const sessionId = uuid(); - sessionsManager.add(sessionId); - - // save the session in our session manager... - r.yar.set(sessionId, { + sessionsManager.add(uuid(), { oauth_token: tokenResponse.oauth_token, oauth_token_secret: tokenResponse.oauth_token_secret, - user_agent: r.headers['user-agent'] + user_agent: r.headers['user-agent'], + origin: r.headers.origin }); return h diff --git a/routes/index.js b/routes/index.js index 7418bad..0ed89fd 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,11 +1,13 @@ 'use strict'; -const { login, logout, callback } = require('./auth'); +const { login, logout, callback, session, verify } = require('./auth'); module.exports = [ login, logout, callback, + session, + verify, require('./iDPresets').get, require('./iDRules').get, require('./josmPresets').get, diff --git a/sessionsManager.js b/sessionsManager.js index aef749a..24edc5b 100644 --- a/sessionsManager.js +++ b/sessionsManager.js @@ -16,6 +16,12 @@ module.exports = { get: function(idx) { return sessions[idx]; }, + update: function (session, value) { + let sessionConfig = sessions[session]; + if (sessionConfig) { + sessionConfig = Object.assign(sessionConfig, value); + } + }, sessions: function() { return Object.keys(sessions); }, From 1749f2ca7cc2710aa8573ae23b692b6b72ad8184 Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Wed, 31 Jul 2019 16:53:05 -0400 Subject: [PATCH 03/14] add needed cors headers for cross origin ref #65 --- routes/auth/index.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/routes/auth/index.js b/routes/auth/index.js index 116742a..359a1fb 100644 --- a/routes/auth/index.js +++ b/routes/auth/index.js @@ -18,7 +18,7 @@ module.exports = { method: 'GET', path: '/auth/verify', config: { - handler: function(r, h) { + handler: function (r, h) { const { oauth_token, oauth_verifier } = r.query; @@ -27,7 +27,7 @@ module.exports = { } let match = false; - for (let id of sessionsManager.sessions()) { + for (let id of sessionsManager.sessions()) { let session = sessionsManager.get(id); if ( session.oauth_token === oauth_token && @@ -46,6 +46,11 @@ module.exports = { .response({ name: user.name, id: user.id }) .header('Content-Type', 'application/json') .code(200); + }, + cors: { + origin: ['*'], + headers: ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'Access-Control-Allow-Origin'], + credentials: true } } }), From b06dc8ed8445f3ce46194f8168d715018e4dfe99 Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Thu, 1 Aug 2019 14:33:51 -0400 Subject: [PATCH 04/14] add get user route to handle when session is valid but localstorage lacks user ref #65 --- routes/auth/index.js | 42 +++++++++++++++++++++++++++++++----------- routes/index.js | 3 ++- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/routes/auth/index.js b/routes/auth/index.js index 359a1fb..a794492 100644 --- a/routes/auth/index.js +++ b/routes/auth/index.js @@ -13,6 +13,13 @@ const jwt = require('jsonwebtoken'); const callbackUrl = config.callbackUrl; // const maprules = config.maprules; +// https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request +const contentTypeCORS = { + origin: ['*'], + headers: ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'Access-Control-Allow-Origin'], + credentials: true +} + module.exports = { verify: authenticate({ method: 'GET', @@ -47,11 +54,7 @@ module.exports = { .header('Content-Type', 'application/json') .code(200); }, - cors: { - origin: ['*'], - headers: ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'Access-Control-Allow-Origin'], - credentials: true - } + cors: contentTypeCORS } }), callback: { @@ -338,12 +341,29 @@ module.exports = { session: authenticate({ method: 'GET', path: '/auth/session', - handler: function(r, h) { - return h - .response('authenticated') - .code(200) - .header('Content-Type', 'text') - .header('X-Content-Type-Options', 'nosniff'); + config: { + handler: function(r, h) { + return h + .response('authenticated') + .code(200) + .header('Content-Type', 'text') + .header('X-Content-Type-Options', 'nosniff'); + }, + cors: contentTypeCORS + } + }), + user: authenticate({ + method: 'GET', + path: '/auth/user', + config: { + handler: function (r, h) { + const user = jwt.verify(r.state.maprules_session, config.jwt); + return h + .response({ name: user.name, id: user.id }) + .header('Content-Type', 'application/json') + .code(200); + }, + cors: contentTypeCORS } }) }; diff --git a/routes/index.js b/routes/index.js index 0ed89fd..d6d046a 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,6 +1,6 @@ 'use strict'; -const { login, logout, callback, session, verify } = require('./auth'); +const { login, logout, callback, session, verify, user } = require('./auth'); module.exports = [ login, @@ -8,6 +8,7 @@ module.exports = [ callback, session, verify, + user, require('./iDPresets').get, require('./iDRules').get, require('./josmPresets').get, From 583b6b4cd2a76d9688b5c298ee66603db8c8a36f Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Thu, 1 Aug 2019 17:11:43 -0400 Subject: [PATCH 05/14] add cors to route ref #65 --- routes/auth/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/routes/auth/index.js b/routes/auth/index.js index a794492..e76170e 100644 --- a/routes/auth/index.js +++ b/routes/auth/index.js @@ -331,8 +331,9 @@ module.exports = { .catch(function(e) { throw e; }); - } - } + }, + cors: contentTypeCORS + }, }), /** * the jwt strategy will capture fail cases and return 401. From 0a45e41525934d936eeb3b4f97330579f8205a7f Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Fri, 2 Aug 2019 11:10:44 -0400 Subject: [PATCH 06/14] add more cors configurations, make cookie include access to everythign at / ref #65 --- index.js | 2 +- routes/auth/index.js | 19 +++++++------------ routes/config.js | 7 +++++++ routes/presetConfig/index.js | 12 ++++++------ 4 files changed, 21 insertions(+), 19 deletions(-) create mode 100644 routes/config.js diff --git a/index.js b/index.js index ad34d15..83b6166 100644 --- a/index.js +++ b/index.js @@ -9,7 +9,7 @@ const jwtScheme = require('./jwtScheme').scheme; const server = Hapi.server({ port: process.env.PORT || 3000, host: process.env.HOST || 'localhost', - routes: { cors: true } + routes: { cors: { origin: ['*'], credentials: true } } }); server.auth.scheme('jwt', jwtScheme); diff --git a/routes/auth/index.js b/routes/auth/index.js index e76170e..d643d0c 100644 --- a/routes/auth/index.js +++ b/routes/auth/index.js @@ -11,14 +11,11 @@ const parseXML = require('xml2js').parseString; const uuid = require('uuid/v4'); const jwt = require('jsonwebtoken'); const callbackUrl = config.callbackUrl; +const routesConfig = require('../config'); +const contentTypeCORS = routesConfig.contentTypeCORS; // const maprules = config.maprules; // https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request -const contentTypeCORS = { - origin: ['*'], - headers: ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'Access-Control-Allow-Origin'], - credentials: true -} module.exports = { verify: authenticate({ @@ -247,7 +244,7 @@ module.exports = { .then(function(resp) { return h .redirect(`${resp.origin}/login.html?oauth_token=${oauthToken}&oauth_verifier=${oauthVerifier}`) - .state('maprules_session', jwt.sign(resp.jwt, config.jwt)); + .state('maprules_session', jwt.sign(resp.jwt, config.jwt), { path: '/' }); // set path so cookie usable for requesting configs }) .catch(function(err) { sessionsManager.remove(sessionId); @@ -321,19 +318,17 @@ module.exports = { return db('user_sessions') .where(sessionWhere) .delete() - .then(function(r) { + .then(function() { return h - .response('logged out') - .code(200) - .header('Content-Type', 'text') - .header('X-Content-Type-Options', 'nosniff'); + .response(200) + .unstate('maprules_session'); }) .catch(function(e) { throw e; }); }, cors: contentTypeCORS - }, + } }), /** * the jwt strategy will capture fail cases and return 401. diff --git a/routes/config.js b/routes/config.js new file mode 100644 index 0000000..f7459d0 --- /dev/null +++ b/routes/config.js @@ -0,0 +1,7 @@ +module.exports = { + contentTypeCORS: { + origin: ['*'], + headers: ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'Access-Control-Allow-Origin', 'Access-Control-Allow-Credentials'], + credentials: true + } +} \ No newline at end of file diff --git a/routes/presetConfig/index.js b/routes/presetConfig/index.js index 579e82f..fb1923c 100644 --- a/routes/presetConfig/index.js +++ b/routes/presetConfig/index.js @@ -6,6 +6,9 @@ const db = require('../../connection'); const uuid4 = require('uuid/v4'); const authenticate = require('../../jwtScheme').authenticate; +const routesConfig = require('../config'); +const contentTypeCors = routesConfig.contentTypeCors; + const presetExists = require('../helpers').presetExists; const validateIdPathParam = require('../helpers').validateIdPathParam; @@ -72,14 +75,14 @@ module.exports = { return Boom.badImplementation(error); } }, + cors: Object.assign({ additionalHeaders: ['cache-control', 'x-request-with'] }, contentTypeCors), validate: { payload: presetConfigSchema, params: { id: validateIdPathParam }, failAction: function(request, h, error) { return Boom.badRequest(error.message); } - }, - cors: { origin: ['*'], additionalHeaders: ['cache-control', 'x-request-with'] } + } } }), post: authenticate({ @@ -109,10 +112,7 @@ module.exports = { return Boom.badImplementation(error); } }, - cors: { - origin: ['*'], - additionalHeaders: ['cache-control', 'x-request-with'] - }, + cors: Object.assign({ additionalHeaders: ['cache-control', 'x-request-with'] }, contentTypeCors), validate: { payload: presetConfigSchema, failAction: function(request, h, error) { From 9f8df9c2140892713accdd12934d23105a0c4fc0 Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Fri, 2 Aug 2019 13:11:26 -0400 Subject: [PATCH 07/14] update tests so they put jwt in cookie header and respond redirect in callback route ref #65 --- routes/auth/index.js | 13 +++++++++---- routes/helpers.js | 9 +++++++++ sessionsManager.js | 11 +++++++---- test/auth/authSpec.js | 31 ++++++++++++++++++++----------- test/helpers.js | 2 +- test/server.js | 4 ++-- testData/seeds.js | 1 - 7 files changed, 48 insertions(+), 23 deletions(-) diff --git a/routes/auth/index.js b/routes/auth/index.js index d643d0c..954668a 100644 --- a/routes/auth/index.js +++ b/routes/auth/index.js @@ -13,7 +13,7 @@ const jwt = require('jsonwebtoken'); const callbackUrl = config.callbackUrl; const routesConfig = require('../config'); const contentTypeCORS = routesConfig.contentTypeCORS; -// const maprules = config.maprules; +const toQueryString = require('../helpers').toQueryString; // https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request @@ -22,7 +22,7 @@ module.exports = { method: 'GET', path: '/auth/verify', config: { - handler: function (r, h) { + handler: function(r, h) { const { oauth_token, oauth_verifier } = r.query; @@ -242,8 +242,13 @@ module.exports = { }); }) .then(function(resp) { + const queryString = toQueryString({ + oauth_token: oauthToken, + oauth_verifier: oauthVerifier + }); + return h - .redirect(`${resp.origin}/login.html?oauth_token=${oauthToken}&oauth_verifier=${oauthVerifier}`) + .redirect(`${resp.origin}/login.html?${queryString}`) .state('maprules_session', jwt.sign(resp.jwt, config.jwt), { path: '/' }); // set path so cookie usable for requesting configs }) .catch(function(err) { @@ -352,7 +357,7 @@ module.exports = { method: 'GET', path: '/auth/user', config: { - handler: function (r, h) { + handler: function(r, h) { const user = jwt.verify(r.state.maprules_session, config.jwt); return h .response({ name: user.name, id: user.id }) diff --git a/routes/helpers.js b/routes/helpers.js index 5baa01d..92ab586 100644 --- a/routes/helpers.js +++ b/routes/helpers.js @@ -32,3 +32,12 @@ exports.adaptError = function(error) { exports.validateIdPathParam = uuidSchema.error(new Error('id path parameter is invalid')); +/** + * Little helper function to prevent manually adding query string params in response. + * Doing so is an easy way to 'miss a character and bring the system down!' + */ +exports.toQueryString = function(queryParams) { + return Object.keys(queryParams).map(function(param) { + return `${param}=${queryParams[param]}`; + }).join('&'); +} \ No newline at end of file diff --git a/sessionsManager.js b/sessionsManager.js index 24edc5b..0a47fe2 100644 --- a/sessionsManager.js +++ b/sessionsManager.js @@ -3,10 +3,13 @@ let sessions = {}; /** - * Manages list of current OSM oAuth sessions. + * Manages hashMap of current OSM oAuth sessions. * - * These are different from the json web token sessions used for being 'logged in' to maprules... - * These are the sessions where the service is communicating w/OpenStreetMap to get user details. + * values include information like origin of request, + * as well as the different tokens provided and needed + * while going through the OSM oAuth flow. + * Once a flow is complete (in literal terms, when we reply the redirect in the /auth/callback route) + * Or a flow has failed, we remove a session. * */ module.exports = { @@ -16,7 +19,7 @@ module.exports = { get: function(idx) { return sessions[idx]; }, - update: function (session, value) { + update: function(session, value) { let sessionConfig = sessions[session]; if (sessionConfig) { sessionConfig = Object.assign(sessionConfig, value); diff --git a/test/auth/authSpec.js b/test/auth/authSpec.js index 1b4dae5..02cf4c9 100644 --- a/test/auth/authSpec.js +++ b/test/auth/authSpec.js @@ -34,11 +34,11 @@ describe('auth', () => { done(); }); }); - it('replies with 401 code when provided non-jwt token in authorization header', function(done) { + it('replies with 401 code when provided non-jwt token in the session cookie', function(done) { const request = Object.assign({}, mergeDefaults({ method: 'GET', url: '/auth/session', - headers: { Authorization: 'Bearer blimblam' } + headers: { Cookie: 'maprules_session=womp' } })); server.inject(request).then(function(r) { @@ -85,7 +85,7 @@ describe('auth', () => { const request = mergeDefaults({ method: 'GET', url: '/auth/session', - headers: { Authorization: `Bearer ${unknownJWT}` } + headers: { Cookie: `maprules_session=${unknownJWT}` } }); server.inject(request).then(function(r) { @@ -143,7 +143,7 @@ describe('auth', () => { const request = mergeDefaults({ method: 'GET', url: '/auth/session', - headers: { Authorization: `Bearer ${dummyJWT}` } + headers: { Cookie: `maprules_session=${dummyJWT}` } }); server.inject(request).then(function(r) { @@ -236,8 +236,7 @@ describe('auth', () => { method: function(r, h) { sessionManager.clear(); sessionId = uuid(); - sessionManager.add(sessionId); - r.yar.set(sessionId, { + sessionManager.add(sessionId, { oauth_token: oauthToken, oauth_token_secret: oauthTokenSecret, user_agent: r.headers['user-agent'] @@ -250,14 +249,26 @@ describe('auth', () => { }); describe('callback', () => { - it('replies signed jwt when it receives authorized request from OSM site', function(done) { + it('replies a redirect response that includes a JWT in its \'Set-Cookie\' response header', function(done) { let request = mergeDefaults({ method: 'GET', url: `/auth/callback?oauth_token=${oauthToken}&oauth_verifier=${oauthVerifier}` }); server.inject(request).then(function(r) { - let decoded = jwt.verify(r.result, config.jwt); + expect(r.statusCode).to.eql(302); + expect(r.headers.location).to.eql( + `undefined/login.html?oauth_token=${oauthToken}&oauth_verifier=${oauthVerifier}` + ); + + + let cookieHeaders = r.headers['set-cookie'][0].split(';').reduce(function(map, header) { + var [name, value] = header.trim().split('='); + map[name] = value || ''; + return map; + }, {}); + let decoded = jwt.verify(cookieHeaders['maprules_session'], config.jwt); + expect(decoded.id).to.eql('1'); expect(decoded.name).to.eql('test_user'); expect(decoded.session).to.not.eql(seedData.fakeToken); @@ -391,14 +402,12 @@ describe('auth', () => { let request = mergeDefaults({ method: 'POST', url: '/auth/logout', - headers: { Authorization: `Bearer ${signedJWT}`, 'user-agent': 'james_bond' } + headers: { Cookie: `maprules_session=${signedJWT}`, 'user-agent': 'james_bond' } }); // logout with session we just made... server.inject(request).then(function(r) { expect(r.statusCode).to.eql(200); // we should have successfully logged out... - expect(r.result).to.eql('logged out'); - db('user_sessions') // the session record should be removed from user_sessions table... .where({ user_id: 1, user_agent: userAgent }) .then(function(sessions) { diff --git a/test/helpers.js b/test/helpers.js index 2352161..c29e2aa 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -4,7 +4,7 @@ const db = require('../connection'); const seedData = require('../testData/seeds'); const signedToken = seedData.fakeToken; const injectDefaults = require('../config')['development'].injectDefaults; -const authorizationHeader = { Authorization: `Bearer ${signedToken}` }; +const authorizationHeader = { Cookie: `maprules_session=${signedToken}` }; exports.fixtureSession = function() { return db('user_sessions') diff --git a/test/server.js b/test/server.js index c28d312..6da2904 100644 --- a/test/server.js +++ b/test/server.js @@ -4,11 +4,12 @@ const Hapi = require('@hapi/hapi'); const config = require('../config')['development']; const host = config.host; const jwtScheme = require('../jwtScheme').scheme; -const yar = { plugin: require('@hapi/yar'), options: config.yar }; const server = Hapi.server({ port: 3001, host: host }); + server.auth.scheme('jwt', jwtScheme); server.auth.strategy('default', 'jwt'); +server.state('maprules_session', config.session); server.liftOff = async(route) => { try { @@ -40,7 +41,6 @@ server.crashLanding = async() => { void async function() { try { - await server.register(yar); if (!module.parent) { await server.start(); diff --git a/testData/seeds.js b/testData/seeds.js index baab6da..e748263 100644 --- a/testData/seeds.js +++ b/testData/seeds.js @@ -26,7 +26,6 @@ module.exports = { user: user, session: unsignedToken.session, fakeToken: jwt.sign(unsignedToken, config.jwt), - // fakeUserAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246', fakeUserAgent: 'shot', // this is what hapi uses for test mocks... fakeUserDetail1: 'en-USen', fakeUserDetail2: 'en-USen' From cc418e866480ba2e136579976f4ab37a55963a0c Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Fri, 2 Aug 2019 15:05:29 -0400 Subject: [PATCH 08/14] reach 95% coverage and unveil good bug to fix (I think)! ref #65 --- requestPromise.js | 4 +- routes/auth/index.js | 6 +-- routes/presetConfig/index.js | 91 ++++++++++++++++-------------------- test/auth/authSpec.js | 38 +++++++++++++-- 4 files changed, 79 insertions(+), 60 deletions(-) diff --git a/requestPromise.js b/requestPromise.js index d3d3c82..051a1a1 100644 --- a/requestPromise.js +++ b/requestPromise.js @@ -8,8 +8,8 @@ const request = require('request'); let requestPromise = function(options) { return new Promise (function(resolve, reject) { request(options, function(err, rs, body) { - if (err) { - reject(err); + if (err || rs.statusCode !== 200) { + reject(err || { statusCode: rs.statusCode }); } else { resolve(body); } diff --git a/routes/auth/index.js b/routes/auth/index.js index 954668a..968462f 100644 --- a/routes/auth/index.js +++ b/routes/auth/index.js @@ -280,6 +280,9 @@ module.exports = { let tokenResponse; try { tokenResponse = qs.parse(body); + if (!Object.keys(tokenResponse).length) { + throw new Error('empty response from OSM!'); + } } catch (err) { throw err; } @@ -327,9 +330,6 @@ module.exports = { return h .response(200) .unstate('maprules_session'); - }) - .catch(function(e) { - throw e; }); }, cors: contentTypeCORS diff --git a/routes/presetConfig/index.js b/routes/presetConfig/index.js index fb1923c..a18bf4a 100644 --- a/routes/presetConfig/index.js +++ b/routes/presetConfig/index.js @@ -25,20 +25,16 @@ module.exports = { config: { auth: false, handler: function(r, h) { - try { - const { id } = r.params; + const { id } = r.params; - return presetExists(id) - .then(function(results) { - const config = JSON.parse(results[0].preset); - return h.response(config).code(200); - }) - .catch(function(error) { - return Boom.notFound(error.message); - }); - } catch (error) { - return Boom.badImplementation(error); - } + return presetExists(id) + .then(function(results) { + const config = JSON.parse(results[0].preset); + return h.response(config).code(200); + }) + .catch(function(error) { + return Boom.notFound(error.message); + }); }, validate: { params: { id: validateIdPathParam }, @@ -54,26 +50,22 @@ module.exports = { path: '/config/{id}', config: { handler: function(r, h) { - try { - const token = r.auth.credentials; - const id = r.params.id; - const preset = JSON.stringify(r.payload); + const token = r.auth.credentials; + const id = r.params.id; + const preset = JSON.stringify(r.payload); - return presetExists(id, token.id) - .then(function() { // check first that to update exists, then update, otherwise throw 404 to user. - return db('presets') - .where({ id: id, user_id: token.id }) - .update('preset', preset); - }) - .then(function(r) { - return h.response({ update: 'successful' }).code(200); - }) - .catch(function(error) { - return Boom.notFound(error.message); - }); - } catch (error) { - return Boom.badImplementation(error); - } + return presetExists(id, token.id) + .then(function() { // check first that to update exists, then update, otherwise throw 404 to user. + return db('presets') + .where({ id: id, user_id: token.id }) + .update('preset', preset); + }) + .then(function(r) { + return h.response({ update: 'successful' }).code(200); + }) + .catch(function(error) { + return Boom.notFound(error.message); + }); }, cors: Object.assign({ additionalHeaders: ['cache-control', 'x-request-with'] }, contentTypeCors), validate: { @@ -90,27 +82,22 @@ module.exports = { path: '/config', config: { handler: function(r, h) { - try { - const token = r.auth.credentials; - const presets = r.payload; - const uuid = uuid4(); + const token = r.auth.credentials; + const presets = r.payload; + const uuid = uuid4(); - return db('presets') - .insert({ - id: uuid, - preset: JSON.stringify(presets), - user_id: token.id - }) - .then(function(r) { // reply uuid used to generate the preset. - return h.response({ upload: 'successful', id: uuid }).code(200); - }) - .catch(function(error) { - throw Boom.badImplementation(error.message); - }); - - } catch (error) { - return Boom.badImplementation(error); - } + return db('presets') + .insert({ + id: uuid, + preset: JSON.stringify(presets), + user_id: token.id + }) + .then(function(r) { // reply uuid used to generate the preset. + return h.response({ upload: 'successful', id: uuid }).code(200); + }) + .catch(function(error) { + throw Boom.badImplementation(error.message); + }); }, cors: Object.assign({ additionalHeaders: ['cache-control', 'x-request-with'] }, contentTypeCors), validate: { diff --git a/test/auth/authSpec.js b/test/auth/authSpec.js index 02cf4c9..e2837b5 100644 --- a/test/auth/authSpec.js +++ b/test/auth/authSpec.js @@ -179,15 +179,16 @@ describe('auth', () => { userXML2 = seedData.fakeUserDetail2; // set up nock - scope = nock(osm).persist(true); + scope = nock(osm).persist(false); - scope.post('/oauth/request_token').reply('200', function(uri, reqBody) { + scope.post('/oauth/request_token').times(1).reply('200', function(uri, reqBody) { let authHeaders = this.req.headers.authorization; let hasHeaders = authHeaders.includes('OAuth') && authHeaders.includes('oauth_callback') && authHeaders.includes('oauth_consumer_key'); expect(hasHeaders).to.be.true; + scope.interceptors.shift(); return requestTokenResp; }); @@ -224,7 +225,38 @@ describe('auth', () => { server.inject(request).then(function(r) { expect(r.result).to.eql(oauthTokenUrl); - done(); + // done(); + + scope.post('/oauth/request_token').reply('400'); + + const request = mergeDefaults({ + method: 'GET', + url: '/auth/login' + }); + + server.inject(request).then(function(nextR) { + expect(nextR.statusCode).to.eql(500); + + scope.post('/oauth/request_token').times(1).reply('200', function(uri, reqBody) { + let authHeaders = this.req.headers.authorization; + let hasHeaders = authHeaders.includes('OAuth') + && authHeaders.includes('oauth_callback') + && authHeaders.includes('oauth_consumer_key'); + + expect(hasHeaders).to.be.true; + scope.interceptors.shift(); + return ''; + }); + const request = mergeDefaults({ + method: 'GET', + url: '/auth/login' + }); + + server.inject(request).then(function(lastR) { + expect(lastR.statusCode).to.eql(500); + done(); + }); + }); }); }); }); From 0093ea7551facd0871d75e83071d4fc30cc2bc45 Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Tue, 6 Aug 2019 16:33:48 -0400 Subject: [PATCH 09/14] simplify auth test and remove some lines of code to get coverage working ref #65 --- adapters/iDPresets/helpers.js | 21 ++++++++++---------- routes/auth/index.js | 36 +++++++---------------------------- test/auth/authSpec.js | 35 ++-------------------------------- test/helpers/index.js | 21 +++++++++++++++----- 4 files changed, 36 insertions(+), 77 deletions(-) diff --git a/adapters/iDPresets/helpers.js b/adapters/iDPresets/helpers.js index f2071b0..e73f484 100644 --- a/adapters/iDPresets/helpers.js +++ b/adapters/iDPresets/helpers.js @@ -61,15 +61,16 @@ exports.getiDDefaults = () => JSON.parse(JSON.stringify(ID_DEFAULTS)); * @return {string} make icon type.... */ exports.getIcon = (primaryTags) => { - const tagsString = primaryTags.sort((a, b) => { - if (a.key < b.key) return -1; - if (a.key > b.key) return 1; - return 0; - }).map(tag => { - return (tag.val && tag.val !== '*') - ? `${tag.key}=${tag.val}` - : tag.key; - }).join(':'); - + const tagsString = primaryTags + .reduce(function(uniqueStrings, tag) { + var tagString = (tag.val && tag.val !== '*') ? `${tag.key}=${tag.val}` : tag.key; + if (uniqueStrings.indexOf(tagString) === -1) { + uniqueStrings.push(tagString); + } + return uniqueStrings; + }, []) + .sort() + .join(':'); + console.log(ID_ICONS[tagsString] || 'maki-natural'); return ID_ICONS[tagsString] || 'maki-natural'; }; \ No newline at end of file diff --git a/routes/auth/index.js b/routes/auth/index.js index 968462f..da13224 100644 --- a/routes/auth/index.js +++ b/routes/auth/index.js @@ -70,15 +70,9 @@ module.exports = { * ... if the token/verifier query parameters are not preset or it cannot find the partner oauth_token_secret, it returns an error. */ method: function(r, h) { // gets called before handler... - let oauthToken = r.query.oauth_token; + let oauthToken = r.query.oauth_token, oauthVerifier = r.query.oauth_verifier; - if (!oauthToken || !oauthToken.length) { - throw err; - } - - let oauthVerifier = r.query.oauth_verifier; - - if (!oauthToken || !oauthToken.length) { + if (!oauthToken || !oauthToken.length || !oauthVerifier || !oauthVerifier.length) { throw err; } @@ -87,13 +81,7 @@ module.exports = { for (id of sessionsManager.sessions()) { let session = sessionsManager.get(id); - - if (!session) { - continue; - } - - - if (!session.oauth_token === oauthToken && session.user_agent !== r.headers['user-agent']) { + if (!session || (!session.oauth_token === oauthToken && session.user_agent !== r.headers['user-agent'])) { continue; } @@ -242,10 +230,7 @@ module.exports = { }); }) .then(function(resp) { - const queryString = toQueryString({ - oauth_token: oauthToken, - oauth_verifier: oauthVerifier - }); + const queryString = toQueryString({ oauth_token: oauthToken, oauth_verifier: oauthVerifier }); return h .redirect(`${resp.origin}/login.html?${queryString}`) @@ -277,16 +262,10 @@ module.exports = { return requestPromise(requestTokenConfig) .then(function(body) { - let tokenResponse; - try { - tokenResponse = qs.parse(body); - if (!Object.keys(tokenResponse).length) { - throw new Error('empty response from OSM!'); - } - } catch (err) { - throw err; + let tokenResponse = qs.parse(body); + if (!Object.keys(tokenResponse).length) { + throw new Error('empty response from OSM!'); } - // create record ofo new session in sessions list so we can track response when // logged in user comes back to callback_url sessionsManager.add(uuid(), { @@ -304,7 +283,6 @@ module.exports = { }) .catch(function(error) { - console.log(error); throw error; }); } diff --git a/test/auth/authSpec.js b/test/auth/authSpec.js index e2837b5..35c297d 100644 --- a/test/auth/authSpec.js +++ b/test/auth/authSpec.js @@ -179,7 +179,7 @@ describe('auth', () => { userXML2 = seedData.fakeUserDetail2; // set up nock - scope = nock(osm).persist(false); + scope = nock(osm).persist(true); scope.post('/oauth/request_token').times(1).reply('200', function(uri, reqBody) { let authHeaders = this.req.headers.authorization; @@ -225,38 +225,7 @@ describe('auth', () => { server.inject(request).then(function(r) { expect(r.result).to.eql(oauthTokenUrl); - // done(); - - scope.post('/oauth/request_token').reply('400'); - - const request = mergeDefaults({ - method: 'GET', - url: '/auth/login' - }); - - server.inject(request).then(function(nextR) { - expect(nextR.statusCode).to.eql(500); - - scope.post('/oauth/request_token').times(1).reply('200', function(uri, reqBody) { - let authHeaders = this.req.headers.authorization; - let hasHeaders = authHeaders.includes('OAuth') - && authHeaders.includes('oauth_callback') - && authHeaders.includes('oauth_consumer_key'); - - expect(hasHeaders).to.be.true; - scope.interceptors.shift(); - return ''; - }); - const request = mergeDefaults({ - method: 'GET', - url: '/auth/login' - }); - - server.inject(request).then(function(lastR) { - expect(lastR.statusCode).to.eql(500); - done(); - }); - }); + done(); }); }); }); diff --git a/test/helpers/index.js b/test/helpers/index.js index b2f50a2..8c53d74 100644 --- a/test/helpers/index.js +++ b/test/helpers/index.js @@ -205,11 +205,22 @@ describe('helpers', () => { }); describe('getIcon', () => { it('returns icon for given set of tags', () => { - const primary = [ - { key: 'amenity', val: 'fast_food' }, - { key: 'cuisine', val: 'sandwich' } - ]; - expect(getIcon(primary)).to.eql('maki-restaurant'); + var restaurant = new Set([ + [ + { key: 'amenity', val: 'fast_food' }, + { key: 'cuisine', val: 'sandwich' } + ], + [ + { key: 'cuisine', val: 'sandwich' }, + { key: 'amenity', val: 'fast_food' } + ], + [ + { key: 'amenity', val: 'restaurant' }, + { key: 'amenity', val: 'restaurant' } + ] + ].map(getIcon)); + expect(restaurant.size).to.eql(1); + expect(restaurant.values().next().value).to.eql('maki-restaurant'); }); it('returns maki-natural if nothing found', () => { const primary = [ From 0b2e6927d5b0ae33127ff19bc99ec27f3974da0b Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Tue, 6 Aug 2019 18:55:10 -0400 Subject: [PATCH 10/14] initial explore route ref #65 --- jwtScheme.js | 3 ++- routes/explore/index.js | 57 +++++++++++++++++++++++++++++++++++++++++ routes/index.js | 8 +++--- test/helpers/index.js | 1 + 4 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 routes/explore/index.js diff --git a/jwtScheme.js b/jwtScheme.js index 8024587..19c374c 100644 --- a/jwtScheme.js +++ b/jwtScheme.js @@ -114,5 +114,6 @@ function authenticate(route) { module.exports = { scheme: scheme, - authenticate: authenticate + authenticate: authenticate, + isAuthorized: isAuthorized }; diff --git a/routes/explore/index.js b/routes/explore/index.js new file mode 100644 index 0000000..cb731b6 --- /dev/null +++ b/routes/explore/index.js @@ -0,0 +1,57 @@ +'use strict'; + +const Boom = require('@hapi/boom'); +const db = require('../../connection'); +const config = require('../../config')[process.env.NODE_ENV || 'development']; +const jwt = require('jsonwebtoken'); +const isAuthorized = require('../../jwtScheme').isAuthorized; + +module.exports = { + get: { + method: 'GET', + path: '/explore', + config: { + auth: false, + pre: [ + { + assign: 'sessionValidation', + method: function(r, h) { + // if we... + // - fail to find token, we return an empty object. + // - find a session, but the request client is not authorized to use the token, reply an empty object. + // - find client to be who we think they are, return the user object + return Promise.resolve(r.state.maprules_session) + .then(function(session) { + let token = jwt.verify(r.state.maprules_session); + return isAuthorized(token, r.headers['user-agent']); + }) + .then(function(session) { + return { id: session.user_id }; + }) + .catch(function(error) { + return {}; + }); + } + } + ], + handler: function(r, h) { + const user = r.pre.sessionValidation; + + // get preset id, user id, and user name for each preset + return db('presets').select('presets.id', 'presets.user_id', 'users.name') + .innerJoin('users', 'users.id', '=', 'presets.user_id') + .then(function(results) { + let presets = results.map(function(config) { + config.edit = config.user_id === user.id; + return config; + }); + + return h.response(presets).code(200); + }) + .catch(function(error) { + return Boom.badImplementation(error); + }); + } + } + } +} \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index d6d046a..94e8aa2 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,6 +1,7 @@ 'use strict'; const { login, logout, callback, session, verify, user } = require('./auth'); +const presetConfig = require('./presetConfig'); module.exports = [ login, @@ -14,9 +15,10 @@ module.exports = [ require('./josmPresets').get, require('./josmRules').get, require('./mapcss').post, - require('./presetConfig').get, - require('./presetConfig').put, - require('./presetConfig').post, + presetConfig.get, + presetConfig.put, + presetConfig.post, + require('./explore').get, require('./docs'), require('./spec'), require('./rules') diff --git a/test/helpers/index.js b/test/helpers/index.js index 8c53d74..ed01e71 100644 --- a/test/helpers/index.js +++ b/test/helpers/index.js @@ -219,6 +219,7 @@ describe('helpers', () => { { key: 'amenity', val: 'restaurant' } ] ].map(getIcon)); + expect(restaurant.size).to.eql(1); expect(restaurant.values().next().value).to.eql('maki-restaurant'); }); From 57f244712166201938c57adc15465348a0532838 Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Tue, 13 Aug 2019 19:29:39 -0400 Subject: [PATCH 11/14] include preset name. ref #65 --- routes/explore/index.js | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/routes/explore/index.js b/routes/explore/index.js index cb731b6..73bc92a 100644 --- a/routes/explore/index.js +++ b/routes/explore/index.js @@ -22,11 +22,11 @@ module.exports = { // - find client to be who we think they are, return the user object return Promise.resolve(r.state.maprules_session) .then(function(session) { - let token = jwt.verify(r.state.maprules_session); + let token = jwt.verify(r.state.maprules_session, config.jwt); return isAuthorized(token, r.headers['user-agent']); }) .then(function(session) { - return { id: session.user_id }; + return { id: Number(session.id) }; }) .catch(function(error) { return {}; @@ -38,13 +38,25 @@ module.exports = { const user = r.pre.sessionValidation; // get preset id, user id, and user name for each preset - return db('presets').select('presets.id', 'presets.user_id', 'users.name') + return db('presets') + .select({ + id: 'presets.id', + preset: 'presets.preset', + user_id: 'users.id', + user_name: 'users.name' + }) .innerJoin('users', 'users.id', '=', 'presets.user_id') .then(function(results) { - let presets = results.map(function(config) { - config.edit = config.user_id === user.id; - return config; - }); + let presets = results.reduce(function(configs, config) { + configs.push({ + preset_name: JSON.parse(config.preset).name, + id: config.id, + user_id: config.user_id, + user_name: config.user_name, + edit: config.user_id === user.id + }); + return configs; + }, []); return h.response(presets).code(200); }) @@ -54,4 +66,4 @@ module.exports = { } } } -} \ No newline at end of file +} From d7629e1bdd3ca4d646e0f911e13135592c37db53 Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Fri, 30 Aug 2019 08:28:18 -0400 Subject: [PATCH 12/14] lint, update icon lookup test ref #65 --- .circleci/config.yml | 4 ++-- routes/config.js | 3 ++- routes/explore/index.js | 2 +- routes/helpers.js | 3 ++- routes/presetConfig/index.js | 4 ++-- test/helpers/index.js | 2 +- 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 74f61a3..362b40e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -25,7 +25,7 @@ jobs: npm run fixture environment: NODE_ENV: testing - YAR: thelongestyarstringofalltimeever + SESSION_KEY: thelongestyarstringofalltimeever JWT: reveemitllafognirtsraytsegnoleht - run: name: test @@ -33,7 +33,7 @@ jobs: npm test environment: NODE_ENV: testing - YAR: thelongestyarstringofalltimeever + SESSION_KEY: thelongestyarstringofalltimeever JWT: reveemitllafognirtsraytsegnoleht OSM_SITE: http://fake.osm.org CONSUMER_KEY: keythatconsumes diff --git a/routes/config.js b/routes/config.js index f7459d0..1488c81 100644 --- a/routes/config.js +++ b/routes/config.js @@ -4,4 +4,5 @@ module.exports = { headers: ['Accept', 'Authorization', 'Content-Type', 'If-None-Match', 'Access-Control-Allow-Origin', 'Access-Control-Allow-Credentials'], credentials: true } -} \ No newline at end of file +}; + diff --git a/routes/explore/index.js b/routes/explore/index.js index 73bc92a..43957bd 100644 --- a/routes/explore/index.js +++ b/routes/explore/index.js @@ -66,4 +66,4 @@ module.exports = { } } } -} +}; diff --git a/routes/helpers.js b/routes/helpers.js index 92ab586..49f1552 100644 --- a/routes/helpers.js +++ b/routes/helpers.js @@ -40,4 +40,5 @@ exports.toQueryString = function(queryParams) { return Object.keys(queryParams).map(function(param) { return `${param}=${queryParams[param]}`; }).join('&'); -} \ No newline at end of file +}; + diff --git a/routes/presetConfig/index.js b/routes/presetConfig/index.js index a18bf4a..0b34920 100644 --- a/routes/presetConfig/index.js +++ b/routes/presetConfig/index.js @@ -89,8 +89,8 @@ module.exports = { return db('presets') .insert({ id: uuid, - preset: JSON.stringify(presets), - user_id: token.id + user_id: token.id, + preset: JSON.stringify(presets) }) .then(function(r) { // reply uuid used to generate the preset. return h.response({ upload: 'successful', id: uuid }).code(200); diff --git a/test/helpers/index.js b/test/helpers/index.js index ed01e71..217f5fe 100644 --- a/test/helpers/index.js +++ b/test/helpers/index.js @@ -215,7 +215,7 @@ describe('helpers', () => { { key: 'amenity', val: 'fast_food' } ], [ - { key: 'amenity', val: 'restaurant' }, + { key: 'cuisine', val: 'american' }, { key: 'amenity', val: 'restaurant' } ] ].map(getIcon)); From 08b00c645326f820c0e78d081062d84b87314190 Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Fri, 30 Aug 2019 08:31:30 -0400 Subject: [PATCH 13/14] remove console log ref #65 --- adapters/iDPresets/helpers.js | 1 - 1 file changed, 1 deletion(-) diff --git a/adapters/iDPresets/helpers.js b/adapters/iDPresets/helpers.js index e73f484..078c040 100644 --- a/adapters/iDPresets/helpers.js +++ b/adapters/iDPresets/helpers.js @@ -71,6 +71,5 @@ exports.getIcon = (primaryTags) => { }, []) .sort() .join(':'); - console.log(ID_ICONS[tagsString] || 'maki-natural'); return ID_ICONS[tagsString] || 'maki-natural'; }; \ No newline at end of file From 5975924e47d2c98c979d455bcc8150b314ae1f9d Mon Sep 17 00:00:00 2001 From: Max Grossman Date: Fri, 30 Aug 2019 08:45:12 -0400 Subject: [PATCH 14/14] update test after re-building icon map ref #65 --- test/helpers/index.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/test/helpers/index.js b/test/helpers/index.js index 217f5fe..f959db6 100644 --- a/test/helpers/index.js +++ b/test/helpers/index.js @@ -205,23 +205,19 @@ describe('helpers', () => { }); describe('getIcon', () => { it('returns icon for given set of tags', () => { - var restaurant = new Set([ + [ [ { key: 'amenity', val: 'fast_food' }, - { key: 'cuisine', val: 'sandwich' } - ], - [ - { key: 'cuisine', val: 'sandwich' }, - { key: 'amenity', val: 'fast_food' } + { key: 'cuisine', val: 'kebab' } ], [ { key: 'cuisine', val: 'american' }, { key: 'amenity', val: 'restaurant' } ] - ].map(getIcon)); - - expect(restaurant.size).to.eql(1); - expect(restaurant.values().next().value).to.eql('maki-restaurant'); + ].map(function(tags) { + let icon = getIcon(tags); + expect(icon).to.eql('maki-restaurant'); + }); }); it('returns maki-natural if nothing found', () => { const primary = [