From cf31fc5caf3d57510057a22fbf46ca7015d273af Mon Sep 17 00:00:00 2001 From: Jedd Fenner Date: Mon, 20 Jan 2020 09:40:16 +0000 Subject: [PATCH 1/2] error logging on local dev (currently too noisy to turn on in prod) --- web/config/options.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/config/options.js b/web/config/options.js index 487dbf7a4..97ac0c28b 100644 --- a/web/config/options.js +++ b/web/config/options.js @@ -27,6 +27,10 @@ module.exports = { }, hapi: { + debug: + process.env.NODE_ENV === 'development' + ? { log: ['error'], request: ['error'] } + : false, connections: { routes: { security: { From b08c942bae2aa6987cec834fbe0ebdf062bdf41f Mon Sep 17 00:00:00 2001 From: Jedd Fenner Date: Mon, 20 Jan 2020 09:44:57 +0000 Subject: [PATCH 2/2] Error logging and client user display redirects - Use new error display query param in zen frontend - Temporarily verbose client side messages while oauth flow is private --- web/controllers/rpi/index.js | 64 ++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/web/controllers/rpi/index.js b/web/controllers/rpi/index.js index 2ba9897fa..9248b147a 100644 --- a/web/controllers/rpi/index.js +++ b/web/controllers/rpi/index.js @@ -2,6 +2,7 @@ const _ = require('lodash'); // eslint-disable-next-line import/no-extraneous-dependencies const Boom = require('boom'); +const { URLSearchParams } = require('url'); const { getRedirectUri, getRegisterRedirectUri, @@ -11,6 +12,13 @@ const { rpiZenAccountPassword, } = require('../../lib/rpi-auth'); +const oauthErrorMessage = 'Raspberry Pi Authentication Failed'; + +function getErrorRedirectUrl(message = oauthErrorMessage) { + const errorUrlQueryParams = new URLSearchParams({ error: message }); + return `/?${errorUrlQueryParams}`; +} + function handleRPILogin(request, reply) { const session = request.state['seneca-login']; if (session && session.token) { @@ -70,8 +78,11 @@ function getZenRegisterPayload(decodedIdToken) { function handleCb(request, reply) { if (request.query.error) { - request.log(['error', 'rpi', 'callback'], request.query); - return reply(Boom.badImplementation('callback error')); + request.log(['error', '40x'], request.query); + return reply.redirect( + // TODO: use generic user friendly error + getErrorRedirectUrl(`rpi callback error: ${request.query.error}`) + ); } const login = (email, idToken) => { @@ -84,8 +95,18 @@ function handleCb(request, reply) { }, (err, res) => { if (err) { - // TODO: Graceful error display - return reply(Boom.badImplementation(err)); + request.log(['error', '50x'], err); + // TODO: use generic user friendly error + return reply.redirect( + getErrorRedirectUrl('Zen Login Failed - Seneca error.') + ); + } + if (!res.login || !res.login.token) { + request.log(['error', '50x'], 'Zen Login Failed - No token.'); + // TODO: use generic user friendly error + return reply.redirect( + getErrorRedirectUrl('Zen Login Failed - No token.') + ); } request.cookieAuth.set({ token: res.login.token, @@ -107,8 +128,14 @@ function handleCb(request, reply) { profileId: rpiProfile.uuid, }, (err, resp) => { + if (err) { + request.log(['error', '50x'], err); + // TODO: use generic user friendly error + return reply.redirect( + getErrorRedirectUrl('Get Profile User Failed - Seneca error.') + ); + } if (resp.email) { - // TODO: update email if not matching return login(resp.email, idToken); } else { const zenRegisterPayload = getZenRegisterPayload(rpiProfile); @@ -119,14 +146,20 @@ function handleCb(request, reply) { ); return request.seneca.act(msg, (err, resp) => { if (err) { - // TODO: Graceful error display - return reply(Boom.badImplementation(err)); + request.log(['error', '50x'], err); + // TODO: use generic user friendly error + return reply.redirect( + getErrorRedirectUrl('Zen Registration Failed - Seneca error.') + ); } if (!resp.user) { - // TODO: Graceful error display - // Observed error reason: nick is already used - return reply( - Boom.badImplementation('No user on registerResponse') + request.log( + ['error', '50x'], + 'Zen Registration Failed - No user.' + ); + return reply.redirect( + // TODO: use generic user friendly error + getErrorRedirectUrl('Zen Registration Failed - No user.') ); } return login(resp.user.email, idToken); @@ -136,8 +169,13 @@ function handleCb(request, reply) { ); }) .catch(error => { - // TODO: Graceful error display - return reply(Boom.badImplementation(error)); + request.log(['error', '40x'], error.data.payload); + return reply.redirect( + // TODO: use generic user friendly error + getErrorRedirectUrl( + `rpi id token error: ${error.data.payload.error_description}` + ) + ); }); }