From 221c4121d7be018b01077a806cef69ceb264df7c Mon Sep 17 00:00:00 2001 From: Stephen Daly Date: Wed, 13 Jan 2021 16:29:36 +0000 Subject: [PATCH] PP-7583 Move 3ds routes to use account URL structure Use the account router for these routes so that the URL contains the account external ID and we use our new middleware for resolving the service/account and checking the user is authorised. Also move paths for existing URLs that are now using the account router to be under `account` in the Object exported by `paths.js`. --- .secrets.baseline | 4 +- .../payment-types/post-index.controller.js | 4 +- .../toggle-3ds/3ds.post.controller.js | 3 +- app/paths.js | 12 ++-- app/routes.js | 62 ++++++++++--------- app/utils/nav-builder.js | 12 ++-- app/views/settings/index.njk | 2 +- app/views/toggle-3ds/index.njk | 2 +- .../integration/settings/3ds.cy.test.js | 7 ++- test/cypress/stubs/user-stubs.js | 2 +- .../payment-types/payment-types.it.test.js | 4 +- 11 files changed, 63 insertions(+), 51 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index 5f002033cb..daa00ef91e 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "package-lock.json", "lines": null }, - "generated_at": "2021-01-12T17:03:50Z", + "generated_at": "2021-01-13T17:09:45Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -72,7 +72,7 @@ "hashed_secret": "ece65afda87c1c6120602c9a3b66890308d7e53c", "is_secret": false, "is_verified": false, - "line_number": 52, + "line_number": 58, "type": "Secret Keyword" } ], diff --git a/app/controllers/payment-types/post-index.controller.js b/app/controllers/payment-types/post-index.controller.js index dcb2d6b6e0..97fa1754b8 100644 --- a/app/controllers/payment-types/post-index.controller.js +++ b/app/controllers/payment-types/post-index.controller.js @@ -19,7 +19,7 @@ module.exports = async (req, res) => { if (typeof acceptedDebitCards === 'undefined' && typeof acceptedCreditCards === 'undefined') { req.flash('genericError', 'You must choose at least one card') return res.redirect( - formatAccountPathsFor(paths.paymentTypes.index, req.account && req.account.external_id) + formatAccountPathsFor(paths.account.paymentTypes.index, req.account && req.account.external_id) ) } @@ -31,7 +31,7 @@ module.exports = async (req, res) => { await connector.postAcceptedCardsForAccount(accountId, payload, correlationId) req.flash('generic', 'Accepted card types have been updated') return res.redirect( - formatAccountPathsFor(paths.paymentTypes.index, req.account && req.account.external_id) + formatAccountPathsFor(paths.account.paymentTypes.index, req.account && req.account.external_id) ) } catch (error) { return renderErrorView(req, res, 'Unable to update payment types. Please try again or contact support team.', error.errorCode) diff --git a/app/controllers/toggle-3ds/3ds.post.controller.js b/app/controllers/toggle-3ds/3ds.post.controller.js index c790d94675..d7a6a6c78a 100644 --- a/app/controllers/toggle-3ds/3ds.post.controller.js +++ b/app/controllers/toggle-3ds/3ds.post.controller.js @@ -1,6 +1,7 @@ 'use strict' const paths = require('../../paths') +const formatAccountPathsFor = require('../../utils/format-account-paths-for') const { renderErrorView } = require('../../utils/response') const { ConnectorClient } = require('../../services/clients/connector.client') const { correlationHeader } = require('../../utils/correlation-header') @@ -23,7 +24,7 @@ module.exports = async (req, res) => { await connector.update3dsEnabled(params) req.flash('generic', '3D secure settings have been updated') - return res.redirect(paths.toggle3ds.index) + return res.redirect(formatAccountPathsFor(paths.account.toggle3ds.index, req.account && req.account.external_id)) } catch (error) { return renderErrorView(req, res, false, error.errorCode) } diff --git a/app/paths.js b/app/paths.js index 9c4d5dec12..e365f9b4b0 100644 --- a/app/paths.js +++ b/app/paths.js @@ -12,6 +12,12 @@ module.exports = { keys, account: { root: `/account/:${keys.GATEWAY_ACCOUNT_EXTERNAL_ID}`, + paymentTypes: { + index: '/payment-types' + }, + toggle3ds: { + index: '/3ds' + }, toggleBillingAddress: { index: '/billing-address' } @@ -72,9 +78,6 @@ module.exports = { revoke: '/api-keys/revoke', update: '/api-keys/update' }, - paymentTypes: { - index: '/payment-types' - }, digitalWallet: { applePay: '/digital-wallet/apple-pay', googlePay: '/digital-wallet/google-pay' @@ -129,9 +132,6 @@ module.exports = { logUserIn: '/create-service/proceed-to-login', serviceNaming: '/service/set-name' }, - toggle3ds: { - index: '/3ds' - }, toggleMotoMaskCardNumberAndSecurityCode: { cardNumber: '/moto-hide-card-number', securityCode: '/moto-hide-security-code' diff --git a/app/routes.js b/app/routes.js index 69d4ae4e46..ecc2ea9eb2 100644 --- a/app/routes.js +++ b/app/routes.js @@ -88,11 +88,15 @@ const stripeSetupDashboardRedirectController = require('./controllers/stripe-set const { healthcheck, registerUser, user, dashboard, selfCreateService, transactions, credentials, apiKeys, serviceSwitcher, teamMembers, staticPaths, inviteValidation, editServiceName, merchantDetails, - notificationCredentials: nc, paymentTypes: pt, emailNotifications: en, toggle3ds: t3ds, toggleMotoMaskCardNumberAndSecurityCode, prototyping, paymentLinks, + notificationCredentials, emailNotifications: emailNotifications, toggleMotoMaskCardNumberAndSecurityCode, prototyping, paymentLinks, requestToGoLive, policyPages, stripeSetup, stripe, digitalWallet, settings, yourPsp, allServiceTransactions, payouts } = paths -const { toggleBillingAddress: billingAddress } = paths.account +const { + paymentTypes, + toggle3ds, + toggleBillingAddress + } = paths.account // Exports module.exports.generateRoute = generateRoute @@ -170,20 +174,20 @@ module.exports.bind = function (app) { ...lodash.values(transactions), ...lodash.values(allServiceTransactions), ...lodash.values(credentials), - ...lodash.values(nc), + ...lodash.values(notificationCredentials), ...lodash.values(apiKeys), - ...lodash.values(pt), - ...lodash.values(en), + ...lodash.values(paymentTypes), + ...lodash.values(emailNotifications), ...lodash.values(editServiceName), ...lodash.values(serviceSwitcher), ...lodash.values(teamMembers), - ...lodash.values(t3ds), + ...lodash.values(toggle3ds), ...lodash.values(merchantDetails), ...lodash.values(prototyping.demoPayment), ...lodash.values(prototyping.demoService), ...lodash.values(paymentLinks), ...lodash.values(user.profile), - ...lodash.values(billingAddress), + ...lodash.values(toggleBillingAddress), ...lodash.values(requestToGoLive), ...lodash.values(policyPages), ...lodash.values(stripeSetup), @@ -225,9 +229,9 @@ module.exports.bind = function (app) { app.get(credentials.edit, permission('gateway-credentials:update'), getAccount, paymentMethodIsCard, credentialsController.editCredentials) app.post(credentials.index, permission('gateway-credentials:update'), getAccount, paymentMethodIsCard, credentialsController.update) - app.get(nc.index, permission('gateway-credentials:read'), getAccount, paymentMethodIsCard, credentialsController.index) - app.get(nc.edit, permission('gateway-credentials:update'), getAccount, paymentMethodIsCard, credentialsController.editNotificationCredentials) - app.post(nc.update, permission('gateway-credentials:update'), getAccount, paymentMethodIsCard, credentialsController.updateNotificationCredentials) + app.get(notificationCredentials.index, permission('gateway-credentials:read'), getAccount, paymentMethodIsCard, credentialsController.index) + app.get(notificationCredentials.edit, permission('gateway-credentials:update'), getAccount, paymentMethodIsCard, credentialsController.editNotificationCredentials) + app.post(notificationCredentials.update, permission('gateway-credentials:update'), getAccount, paymentMethodIsCard, credentialsController.updateNotificationCredentials) // MERCHANT DETAILS app.get(merchantDetails.index, permission('merchant-details:read'), merchantDetailsController.getIndex) @@ -242,8 +246,8 @@ module.exports.bind = function (app) { app.post(apiKeys.revoke, permission('tokens:delete'), getAccount, apiKeysController.postRevoke) app.post(apiKeys.update, permission('tokens:update'), getAccount, apiKeysController.postUpdate) - account.get(pt.index, permission('payment-types:read'), paymentTypesController.getIndex) - account.post(pt.index, permission('payment-types:update'), paymentTypesController.postIndex) + account.get(paymentTypes.index, permission('payment-types:read'), paymentTypesController.getIndex) + account.post(paymentTypes.index, permission('payment-types:update'), paymentTypesController.postIndex) // DIGITAL WALLET app.get(digitalWallet.applePay, permission('payment-types:update'), getAccount, paymentMethodIsCard, digitalWalletController.getApplePay) @@ -252,19 +256,19 @@ module.exports.bind = function (app) { app.post(digitalWallet.googlePay, permission('payment-types:update'), getAccount, paymentMethodIsCard, digitalWalletController.postGooglePay) // EMAIL - app.get(en.index, permission('email-notification-template:read'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.index) - app.get(en.indexRefundTabEnabled, permission('email-notification-template:read'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.indexRefundTabEnabled) - app.get(en.edit, permission('email-notification-paragraph:update'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.edit) - app.post(en.confirm, permission('email-notification-paragraph:update'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.confirm) - app.post(en.update, permission('email-notification-paragraph:update'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.update) - app.get(en.collection, permission('email-notification-template:read'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.collectionEmailIndex) - app.post(en.collection, permission('email-notification-toggle:update'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.collectionEmailUpdate) - app.get(en.confirmation, permission('email-notification-template:read'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.confirmationEmailIndex) - app.post(en.confirmation, permission('email-notification-toggle:update'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.confirmationEmailUpdate) - app.post(en.off, permission('email-notification-toggle:update'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.confirmationEmailOff) - app.post(en.on, permission('email-notification-toggle:update'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.confirmationEmailOn) - app.get(en.refund, permission('email-notification-template:read'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.refundEmailIndex) - app.post(en.refund, permission('email-notification-toggle:update'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.refundEmailUpdate) + app.get(emailNotifications.index, permission('email-notification-template:read'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.index) + app.get(emailNotifications.indexRefundTabEnabled, permission('email-notification-template:read'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.indexRefundTabEnabled) + app.get(emailNotifications.edit, permission('email-notification-paragraph:update'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.edit) + app.post(emailNotifications.confirm, permission('email-notification-paragraph:update'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.confirm) + app.post(emailNotifications.update, permission('email-notification-paragraph:update'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.update) + app.get(emailNotifications.collection, permission('email-notification-template:read'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.collectionEmailIndex) + app.post(emailNotifications.collection, permission('email-notification-toggle:update'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.collectionEmailUpdate) + app.get(emailNotifications.confirmation, permission('email-notification-template:read'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.confirmationEmailIndex) + app.post(emailNotifications.confirmation, permission('email-notification-toggle:update'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.confirmationEmailUpdate) + app.post(emailNotifications.off, permission('email-notification-toggle:update'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.confirmationEmailOff) + app.post(emailNotifications.on, permission('email-notification-toggle:update'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.confirmationEmailOn) + app.get(emailNotifications.refund, permission('email-notification-template:read'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.refundEmailIndex) + app.post(emailNotifications.refund, permission('email-notification-toggle:update'), getAccount, getEmailNotification, paymentMethodIsCard, emailNotificationsController.refundEmailUpdate) // SERVICE SWITCHER app.get(serviceSwitcher.index, myServicesController.getIndex) @@ -289,8 +293,8 @@ module.exports.bind = function (app) { app.post(teamMembers.invite, permission('users-service:create'), inviteUserController.invite) // 3D SECURE TOGGLE - app.get(t3ds.index, permission('toggle-3ds:read'), getAccount, paymentMethodIsCard, toggle3dsController.get) - app.post(t3ds.index, permission('toggle-3ds:update'), getAccount, paymentMethodIsCard, toggle3dsController.post) + account.get(toggle3ds.index, permission('toggle-3ds:read'), paymentMethodIsCard, toggle3dsController.get) + account.post(toggle3ds.index, permission('toggle-3ds:update'), paymentMethodIsCard, toggle3dsController.post) // MOTO MASK CARD NUMBER & SECURITY CODE TOGGLE app.get(toggleMotoMaskCardNumberAndSecurityCode.cardNumber, permission('moto-mask-input:read'), getAccount, paymentMethodIsCard, toggleMotoMaskCardNumber.get) @@ -298,8 +302,8 @@ module.exports.bind = function (app) { app.get(toggleMotoMaskCardNumberAndSecurityCode.securityCode, permission('moto-mask-input:read'), getAccount, paymentMethodIsCard, toggleMotoMaskSecurityCode.get) app.post(toggleMotoMaskCardNumberAndSecurityCode.securityCode, permission('moto-mask-input:update'), getAccount, paymentMethodIsCard, toggleMotoMaskSecurityCode.post) - account.get(billingAddress.index, permission('toggle-billing-address:read'), toggleBillingAddressController.getIndex) - account.post(billingAddress.index, permission('toggle-billing-address:update'), toggleBillingAddressController.postIndex) + account.get(toggleBillingAddress.index, permission('toggle-billing-address:read'), toggleBillingAddressController.getIndex) + account.post(toggleBillingAddress.index, permission('toggle-billing-address:update'), toggleBillingAddressController.postIndex) // Prototyping app.get(prototyping.demoService.index, permission('transactions:read'), resolveService, getAccount, restrictToSandbox, testWithYourUsersController.index) diff --git a/app/utils/nav-builder.js b/app/utils/nav-builder.js index b402910b61..3d4bd0e042 100644 --- a/app/utils/nav-builder.js +++ b/app/utils/nav-builder.js @@ -9,7 +9,7 @@ const formatPSPname = require('./format-PSP-name') const mainSettingsPaths = [ paths.settings, paths.digitalWallet, - paths.toggle3ds, + paths.account.toggle3ds, paths.account.toggleBillingAddress, paths.emailNotifications, paths.toggleMotoMaskCardNumberAndSecurityCode @@ -54,7 +54,7 @@ const serviceNavigationItems = (currentPath, permissions, type) => { ...mainSettingsPaths, ...yourPspPaths, paths.apiKeys, - paths.paymentTypes + paths.account.paymentTypes ]) : false, permissions: _.some([ permissions.tokens_read, @@ -94,13 +94,17 @@ const adminNavigationItems = (currentPath, permissions, type, paymentProvider, a { id: 'navigation-menu-payment-types', name: 'Card types', - url: formatAccountPathsFor(paths.paymentTypes.index, account.external_id), - current: pathLookup(currentPath, paths.paymentTypes.index), + url: formatAccountPathsFor(paths.account.paymentTypes.index, account.external_id), + current: pathLookup(currentPath, paths.account.paymentTypes.index), permissions: permissions.payment_types_read && type === 'card' } ] } +// const pathMatches(url, paths) { + +// } + module.exports = { serviceNavigationItems: serviceNavigationItems, adminNavigationItems: adminNavigationItems diff --git a/app/views/settings/index.njk b/app/views/settings/index.njk index aebc9c78d9..6ccdd3a9c7 100644 --- a/app/views/settings/index.njk +++ b/app/views/settings/index.njk @@ -88,7 +88,7 @@ classes: 'govuk-!-width-one-quarter', items: [ { - href: routes.toggle3ds.index, + href: formatAccountPathsFor(routes.account.toggle3ds.index, currentGatewayAccount.external_id), classes: 'govuk-link--no-visited-state', text: 'Change' if permissions.toggle_3ds_update else 'View', visuallyHiddenText: '3D Secure settings' diff --git a/app/views/toggle-3ds/index.njk b/app/views/toggle-3ds/index.njk index 6c20b97555..8859ca5021 100644 --- a/app/views/toggle-3ds/index.njk +++ b/app/views/toggle-3ds/index.njk @@ -92,7 +92,7 @@ }) }} -

or cancel

+

or cancel

{% else %}

3D Secure

3D Secure is not currently supported for this payment service provider (PSP).

diff --git a/test/cypress/integration/settings/3ds.cy.test.js b/test/cypress/integration/settings/3ds.cy.test.js index 867dc54229..033fa724b2 100644 --- a/test/cypress/integration/settings/3ds.cy.test.js +++ b/test/cypress/integration/settings/3ds.cy.test.js @@ -7,6 +7,7 @@ const stripeAccountSetupStubs = require('../../stubs/stripe-account-setup-stub') describe('3DS settings page', () => { const userExternalId = 'cd0fa54cf3b7408a80ae2f1b93e7c16e' const gatewayAccountId = 42 + const gatewayAccountExternalId = 'a-valid-external-id' const serviceName = 'Purchase a positron projection permit' function setup3dsStubs (opts = {}) { @@ -31,10 +32,11 @@ describe('3DS settings page', () => { user = userStubs.getUserSuccess({ userExternalId, gatewayAccountId, serviceName }) } const gatewayAccount = gatewayAccountStubs.getGatewayAccountSuccess({ gatewayAccountId, paymentProvider: opts.gateway, requires3ds: opts.requires3ds }) + const gatewayAccountByExternalId = gatewayAccountStubs.getGatewayAccountByExternalIdSuccess({ gatewayAccountId, gatewayAccountExternalId, paymentProvider: opts.gateway, requires3ds: opts.requires3ds }) const card = gatewayAccountStubs.getAcceptedCardTypesSuccess({ gatewayAccountId, updated: false, maestro: opts.maestro }) - stubs.push(user, gatewayAccount, card) + stubs.push(user, gatewayAccount, gatewayAccountByExternalId, card) cy.task('setupStubs', stubs) } @@ -52,7 +54,7 @@ describe('3DS settings page', () => { cy.setEncryptedCookies(userExternalId, gatewayAccountId) cy.visit('/settings') cy.get('.govuk-summary-list__key').first().should('not.contain', '3D Secure') - cy.visit('/3ds') + cy.visit(`/account/${gatewayAccountExternalId}/3ds`) cy.title().should('eq', `3D Secure - ${serviceName} - GOV.UK Pay`) cy.get('#threeds-not-supported').should('be.visible') cy.get('#threeds-not-supported').should('contain', '3D Secure is not currently supported for this payment service provider (PSP).') @@ -182,6 +184,7 @@ describe('3DS settings page', () => { cy.task('setupStubs', [ userStubs.getUserSuccess({ userExternalId, gatewayAccountId, serviceName }), gatewayAccountStubs.getGatewayAccountSuccess({ gatewayAccountId, type: 'live', paymentProvider: 'stripe', requires3ds: true }), + gatewayAccountStubs.getGatewayAccountByExternalIdSuccess({ gatewayAccountId, gatewayAccountExternalId, type: 'live', paymentProvider: 'stripe', requires3ds: true }), gatewayAccountStubs.getAcceptedCardTypesSuccess({ gatewayAccountId, updated: false }), stripeAccountSetupStubs.getGatewayAccountStripeSetupSuccess({ gatewayAccountId, vatNumber: true, bankAccount: true, companyNumber: true, responsiblePerson: true }) ]) diff --git a/test/cypress/stubs/user-stubs.js b/test/cypress/stubs/user-stubs.js index 93662a2499..788cecf024 100644 --- a/test/cypress/stubs/user-stubs.js +++ b/test/cypress/stubs/user-stubs.js @@ -173,7 +173,7 @@ function getUserSuccessRespondDifferentlySecondTime (userExternalId, firstRespon function buildServiceRoleOpts (opts) { const serviceRole = { service: { - gateway_account_ids: [opts.gatewayAccountId] + gateway_account_ids: [String(opts.gatewayAccountId)] } } diff --git a/test/integration/payment-types/payment-types.it.test.js b/test/integration/payment-types/payment-types.it.test.js index d23e7e09c0..ee410be260 100644 --- a/test/integration/payment-types/payment-types.it.test.js +++ b/test/integration/payment-types/payment-types.it.test.js @@ -25,7 +25,7 @@ let app function whenGetPaymentTypes (baseApp) { return request(baseApp) - .get(formatAccountPathsFor(paths.paymentTypes.index, gatewayAccountExternalId)) + .get(formatAccountPathsFor(paths.account.paymentTypes.index, gatewayAccountExternalId)) } function whenPaymentTypesUpdated (baseApp, payload) { @@ -34,7 +34,7 @@ function whenPaymentTypesUpdated (baseApp, payload) { csrfToken: csrf().create('123') } return request(baseApp) - .post(formatAccountPathsFor(paths.paymentTypes.index, gatewayAccountExternalId)) + .post(formatAccountPathsFor(paths.account.paymentTypes.index, gatewayAccountExternalId)) .send(payload) }