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 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) }