diff --git a/ee/app/assets/javascripts/arkose_labs/components/identity_verification_arkose_app.vue b/ee/app/assets/javascripts/arkose_labs/components/identity_verification_arkose_app.vue index a11932931d17ea1d9deb866913ce69cdcd0ce5cd..92a007b7f69c15b87101dff595b23e8ea8495492 100644 --- a/ee/app/assets/javascripts/arkose_labs/components/identity_verification_arkose_app.vue +++ b/ee/app/assets/javascripts/arkose_labs/components/identity_verification_arkose_app.vue @@ -27,6 +27,11 @@ export default { required: false, default: undefined, }, + dataExchangePayloadPath: { + type: String, + required: false, + default: undefined, + }, }, data() { return { @@ -40,6 +45,7 @@ export default { publicKey: this.publicKey, domain: this.domain, dataExchangePayload: this.dataExchangePayload, + dataExchangePayloadPath: this.dataExchangePayloadPath, config: { selector: `.${this.$options.CHALLENGE_CONTAINER_CLASS}`, onShown: this.onArkoseLabsIframeShown, diff --git a/ee/app/assets/javascripts/arkose_labs/components/phone_verification_arkose_app.vue b/ee/app/assets/javascripts/arkose_labs/components/phone_verification_arkose_app.vue index b28b38a5f88597497e7d0160f544d8563237aa52..252690f040d8871913b715204e42659ae12ce47f 100644 --- a/ee/app/assets/javascripts/arkose_labs/components/phone_verification_arkose_app.vue +++ b/ee/app/assets/javascripts/arkose_labs/components/phone_verification_arkose_app.vue @@ -1,30 +1,18 @@ <script> import { uniqueId } from 'lodash'; import { logError } from '~/lib/logger'; -import { initArkoseLabsChallenge } from '../init_arkose_labs'; +import { initArkoseLabsChallenge, resetArkoseLabsChallenge } from '../init_arkose_labs'; import { CHALLENGE_CONTAINER_CLASS } from '../constants'; export default { name: 'PhoneVerificationArkoseApp', + inject: ['arkoseConfiguration', 'arkoseDataExchangePayload'], props: { - publicKey: { - type: String, - required: true, - }, - domain: { - type: String, - required: true, - }, resetSession: { type: Boolean, required: false, default: false, }, - dataExchangePayload: { - type: String, - required: false, - default: undefined, - }, }, data() { return { @@ -50,9 +38,10 @@ export default { async mounted() { try { this.arkoseObject = await initArkoseLabsChallenge({ - publicKey: this.publicKey, - domain: this.domain, - dataExchangePayload: this.dataExchangePayload, + publicKey: this.arkoseConfiguration.apiKey, + domain: this.arkoseConfiguration.domain, + dataExchangePayload: this.arkoseDataExchangePayload, + dataExchangePayloadPath: this.arkoseConfiguration.dataExchangePayloadPath, config: { selector: `.${this.arkoseLabsContainerClass}`, onShown: this.onArkoseLabsIframeShown, @@ -71,7 +60,7 @@ export default { this.arkoseToken = response.token; }, resetArkoseSession() { - this.arkoseObject?.reset(); + resetArkoseLabsChallenge(this.arkoseObject); }, }, }; diff --git a/ee/app/assets/javascripts/arkose_labs/index.js b/ee/app/assets/javascripts/arkose_labs/index.js index bade514005e566a25a1e2f62ef89b6723b0397ba..8b0874d328f6b0b16cb0cbd2c9bf2771f1f6f6db 100644 --- a/ee/app/assets/javascripts/arkose_labs/index.js +++ b/ee/app/assets/javascripts/arkose_labs/index.js @@ -35,7 +35,8 @@ export const setupArkoseLabsForIdentityVerification = () => { return null; } - const { apiKey, domain, sessionVerificationPath, dataExchangePayload } = el.dataset; + const { apiKey, domain, sessionVerificationPath, dataExchangePayload, dataExchangePayloadPath } = + el.dataset; return new Vue({ el, @@ -46,6 +47,7 @@ export const setupArkoseLabsForIdentityVerification = () => { domain, sessionVerificationPath, dataExchangePayload, + dataExchangePayloadPath, }, }); }, diff --git a/ee/app/assets/javascripts/arkose_labs/init_arkose_labs.js b/ee/app/assets/javascripts/arkose_labs/init_arkose_labs.js index 028ce346adaa4b691977915b079623b794207afc..a0df4f5418271524df74a5c8e6c8f95413dcd8cc 100644 --- a/ee/app/assets/javascripts/arkose_labs/init_arkose_labs.js +++ b/ee/app/assets/javascripts/arkose_labs/init_arkose_labs.js @@ -1,4 +1,5 @@ import { uniqueId } from 'lodash'; +import axios from '~/lib/utils/axios_utils'; const CALLBACK_NAME = '_initArkoseLabsScript_callback_'; @@ -46,8 +47,46 @@ const configureArkoseLabs = (configObject, dataExchangePayload, options = {}) => }); }; -export const initArkoseLabsChallenge = ({ publicKey, domain, dataExchangePayload, config }) => - initArkoseLabsScript({ publicKey, domain }).then((arkoseObject) => { - configureArkoseLabs(arkoseObject, dataExchangePayload, config); - return arkoseObject; - }); +const fetchDataExchangePayload = async (path) => { + try { + const response = await axios.get(path); + return response.data?.payload; + } catch { + return undefined; + } +}; + +export const initArkoseLabsChallenge = async ({ + publicKey, + domain, + dataExchangePayloadPath, + config, + ...rest +}) => { + const dataExchangePayloadPromise = dataExchangePayloadPath + ? fetchDataExchangePayload(dataExchangePayloadPath) + : rest.dataExchangePayload; + + const initArkoseLabsScriptPromise = initArkoseLabsScript({ publicKey, domain }); + + const dataExchangePayload = await dataExchangePayloadPromise; + const arkoseObject = await initArkoseLabsScriptPromise; + + configureArkoseLabs(arkoseObject, dataExchangePayload, config); + + return arkoseObject; +}; + +export const resetArkoseLabsChallenge = async (arkoseObject, dataExchangePayloadPath) => { + const dataExchangePayloadPromise = dataExchangePayloadPath + ? fetchDataExchangePayload(dataExchangePayloadPath) + : undefined; + + const dataExchangePayload = await dataExchangePayloadPromise; + + arkoseObject.reset(); + + if (dataExchangePayload) { + arkoseObject.setConfig({ data: { blob: dataExchangePayload } }); + } +}; diff --git a/ee/app/assets/javascripts/users/identity_verification/components/identity_verification_captcha.vue b/ee/app/assets/javascripts/users/identity_verification/components/identity_verification_captcha.vue index 270e234cc97bc0066f7b23792bf69bf151f3daa4..6ee964d6754cdcfc53be0ff4d5c772cd97de5ac0 100644 --- a/ee/app/assets/javascripts/users/identity_verification/components/identity_verification_captcha.vue +++ b/ee/app/assets/javascripts/users/identity_verification/components/identity_verification_captcha.vue @@ -9,7 +9,6 @@ export default { PhoneVerificationArkoseApp, ReCaptcha, }, - inject: ['arkoseConfiguration', 'arkoseDataExchangePayload'], props: { showArkoseChallenge: { type: Boolean, @@ -87,9 +86,6 @@ export default { <phone-verification-arkose-app v-if="showArkoseChallenge" - :public-key="arkoseConfiguration.apiKey" - :domain="arkoseConfiguration.domain" - :data-exchange-payload="arkoseDataExchangePayload" :reset-session="arkose.reset" class="gl-mt-5" @challenge-solved="onArkoseChallengeSolved" diff --git a/ee/app/helpers/ee/registrations_helper.rb b/ee/app/helpers/ee/registrations_helper.rb index 2dfa723db4b0c4141929c192fcbac44e02dd26c9..d1228cc56b983d2818434546faf4b1d774e46948 100644 --- a/ee/app/helpers/ee/registrations_helper.rb +++ b/ee/app/helpers/ee/registrations_helper.rb @@ -12,10 +12,13 @@ def shuffled_registration_objective_options end def arkose_labs_data + path = data_exchange_payload_path if ::Feature.enabled?(:fetch_arkose_data_exchange_payload, :instance) + data = { api_key: ::AntiAbuse::IdentityVerification::Settings.arkose_public_api_key, domain: ::AntiAbuse::IdentityVerification::Settings.arkose_labs_domain, - data_exchange_payload: arkose_data_exchange_payload(Arkose::DataExchangePayload::USE_CASE_SIGN_UP) + data_exchange_payload: arkose_data_exchange_payload(Arkose::DataExchangePayload::USE_CASE_SIGN_UP), + data_exchange_payload_path: path } data.compact diff --git a/ee/spec/frontend/arkose_labs/components/identity_verification_arkose_app_spec.js b/ee/spec/frontend/arkose_labs/components/identity_verification_arkose_app_spec.js index 9fd3a6dc65e41ca3d03bb22f31bc1ad0d0475633..f1496c4f4a444b00f8bb6e1b598d619480abab36 100644 --- a/ee/spec/frontend/arkose_labs/components/identity_verification_arkose_app_spec.js +++ b/ee/spec/frontend/arkose_labs/components/identity_verification_arkose_app_spec.js @@ -14,6 +14,7 @@ let onShown; let onCompleted; const mockDataExchangePayload = 'fakeDataExchangePayload'; +const mockDataExchangePayloadPath = '/path/to/data_exchange_payload'; initArkoseLabsChallenge.mockImplementation(({ config }) => { onShown = config.onShown; onCompleted = config.onCompleted; @@ -38,6 +39,7 @@ describe('IdentityVerificationArkoseApp', () => { publicKey: MOCK_PUBLIC_KEY, domain: MOCK_DOMAIN, dataExchangePayload: mockDataExchangePayload, + dataExchangePayloadPath: mockDataExchangePayloadPath, sessionVerificationPath: MOCK_SESSION_VERIFICATION_PATH, ...props, }, @@ -53,6 +55,7 @@ describe('IdentityVerificationArkoseApp', () => { publicKey: MOCK_PUBLIC_KEY, domain: MOCK_DOMAIN, dataExchangePayload: mockDataExchangePayload, + dataExchangePayloadPath: mockDataExchangePayloadPath, config: expect.objectContaining({ selector: `.${CHALLENGE_CONTAINER_CLASS}`, onShown: expect.any(Function), diff --git a/ee/spec/frontend/arkose_labs/components/phone_verification_arkose_app_spec.js b/ee/spec/frontend/arkose_labs/components/phone_verification_arkose_app_spec.js index 9ff74b6535479a1b2100f05a2a1e0885f4747a8b..3f0a28221fe57befe59845be5232aea793d19ea2 100644 --- a/ee/spec/frontend/arkose_labs/components/phone_verification_arkose_app_spec.js +++ b/ee/spec/frontend/arkose_labs/components/phone_verification_arkose_app_spec.js @@ -1,27 +1,28 @@ import { nextTick } from 'vue'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import PhoneVerificationArkoseApp from 'ee/arkose_labs/components/phone_verification_arkose_app.vue'; -import { initArkoseLabsChallenge } from 'ee/arkose_labs/init_arkose_labs'; +import { initArkoseLabsChallenge, resetArkoseLabsChallenge } from 'ee/arkose_labs/init_arkose_labs'; import { logError } from '~/lib/logger'; jest.mock('~/lib/logger'); jest.mock('ee/arkose_labs/init_arkose_labs'); let onShown; let onCompleted; -const mockResetHandler = jest.fn(); -const mockDataExchangePayload = 'fakeDataExchangePayload'; +const MOCK_ARKOSE_RESPONSE = { token: 'verification-token' }; +const MOCK_PUBLIC_KEY = 'arkose-labs-public-api-key'; +const MOCK_DOMAIN = 'client-api.arkoselabs.com'; +const MOCK_DATA_EXCHANGE_PAYLOAD = 'fakeDataExchangePayload'; +const MOCK_DATA_EXCHANGE_PAYLOAD_PATH = '/path/to/data_exchange_payload'; +const MOCK_ARKOSE_OBJECT = 'mockArkoseObject'; + initArkoseLabsChallenge.mockImplementation(({ config }) => { onShown = config.onShown; onCompleted = config.onCompleted; - return { reset: mockResetHandler }; + return MOCK_ARKOSE_OBJECT; }); -const MOCK_ARKOSE_RESPONSE = { token: 'verification-token' }; -const MOCK_PUBLIC_KEY = 'arkose-labs-public-api-key'; -const MOCK_DOMAIN = 'client-api.arkoselabs.com'; - describe('PhoneVerificationArkoseApp', () => { let wrapper; @@ -29,12 +30,15 @@ describe('PhoneVerificationArkoseApp', () => { const createComponent = () => { wrapper = mountExtended(PhoneVerificationArkoseApp, { - propsData: { - publicKey: MOCK_PUBLIC_KEY, - domain: MOCK_DOMAIN, - dataExchangePayload: mockDataExchangePayload, - resetSession: false, + provide: { + arkoseConfiguration: { + apiKey: MOCK_PUBLIC_KEY, + domain: MOCK_DOMAIN, + dataExchangePayloadPath: MOCK_DATA_EXCHANGE_PAYLOAD_PATH, + }, + arkoseDataExchangePayload: MOCK_DATA_EXCHANGE_PAYLOAD, }, + propsData: { resetSession: false }, }); }; @@ -46,7 +50,8 @@ describe('PhoneVerificationArkoseApp', () => { expect(initArkoseLabsChallenge).toHaveBeenCalledWith({ publicKey: MOCK_PUBLIC_KEY, domain: MOCK_DOMAIN, - dataExchangePayload: mockDataExchangePayload, + dataExchangePayload: MOCK_DATA_EXCHANGE_PAYLOAD, + dataExchangePayloadPath: MOCK_DATA_EXCHANGE_PAYLOAD_PATH, config: expect.objectContaining({ onShown: expect.any(Function), onCompleted: expect.any(Function), @@ -81,7 +86,7 @@ describe('PhoneVerificationArkoseApp', () => { resetSession: true, }); - expect(mockResetHandler).toHaveBeenCalled(); + expect(resetArkoseLabsChallenge).toHaveBeenCalledWith(MOCK_ARKOSE_OBJECT); }); describe('when challenge initialization fails', () => { diff --git a/ee/spec/frontend/arkose_labs/init_arkose_labs_spec.js b/ee/spec/frontend/arkose_labs/init_arkose_labs_spec.js index b8b0f83b3bb87c22ecc6b0e81bdff08a20db6488..83938862bed3a9ab8fbf0215311e57a33cfe0406 100644 --- a/ee/spec/frontend/arkose_labs/init_arkose_labs_spec.js +++ b/ee/spec/frontend/arkose_labs/init_arkose_labs_spec.js @@ -1,22 +1,36 @@ -import { initArkoseLabsChallenge } from 'ee/arkose_labs/init_arkose_labs'; +import axios from 'axios'; +import MockAdapter from 'axios-mock-adapter'; +import { HTTP_STATUS_OK, HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status'; +import { initArkoseLabsChallenge, resetArkoseLabsChallenge } from 'ee/arkose_labs/init_arkose_labs'; jest.mock('lodash/uniqueId', () => (x) => `${x}7`); const EXPECTED_CALLBACK_NAME = '_initArkoseLabsScript_callback_7'; -const TEST_PUBLIC_KEY = 'arkose-labs-public-api-key'; -const TEST_DOMAIN = 'client-api.arkoselabs.com'; +const MOCK_PUBLIC_KEY = 'arkose-labs-public-api-key'; +const MOCK_DOMAIN = 'client-api.arkoselabs.com'; +const MOCK_DATA_EXCHANGE_PAYLOAD = 'fakeDataExchangePayload'; +const MOCK_DATA_EXCHANGE_PAYLOAD_PATH = '/path/to/data_exchange_payload'; -describe('initArkoseLabsScript', () => { +let axiosMock; + +beforeEach(() => { + axiosMock = new MockAdapter(axios); +}); + +afterEach(() => { + axiosMock.restore(); +}); + +describe('initArkoseLabsChallenge', () => { let subject; const initSubject = ( - { dataExchangePayload, config } = { dataExchangePayload: undefined, config: {} }, + args = { dataExchangePayload: undefined, dataExchangePayloadPath: undefined, config: {} }, ) => { subject = initArkoseLabsChallenge({ - publicKey: TEST_PUBLIC_KEY, - domain: TEST_DOMAIN, - dataExchangePayload, - config, + publicKey: MOCK_PUBLIC_KEY, + domain: MOCK_DOMAIN, + ...args, }); }; @@ -42,7 +56,7 @@ describe('initArkoseLabsScript', () => { expect(scriptTag.getAttribute('type')).toBe('text/javascript'); expect(scriptTag.getAttribute('src')).toBe( - `https://${TEST_DOMAIN}/v2/${TEST_PUBLIC_KEY}/api.js`, + `https://${MOCK_DOMAIN}/v2/${MOCK_PUBLIC_KEY}/api.js`, ); expect(scriptTag.dataset.callback).toBe(EXPECTED_CALLBACK_NAME); expect(scriptTag.getAttribute('id')).toBe('arkose-challenge-script'); @@ -50,6 +64,11 @@ describe('initArkoseLabsScript', () => { describe('when callback is called', () => { const enforcement = { setConfig: jest.fn() }; + const config = { a: 'a', b: 'b' }; + const expectedSetConfigArgs = (dataExchangePayload) => { + const baseArgs = { mode: 'inline', ...config }; + return dataExchangePayload ? { data: { blob: dataExchangePayload }, ...baseArgs } : baseArgs; + }; it('when callback is called, cleans up the global object and resolves the Promise', () => { initSubject(); @@ -59,8 +78,6 @@ describe('initArkoseLabsScript', () => { return expect(subject).resolves.toBe(enforcement); }); - const config = { a: 'a', b: 'b' }; - it('calls ArkoseLabs config object setDefault with defaults and passed in options', async () => { initSubject({ dataExchangePayload: undefined, config }); window[EXPECTED_CALLBACK_NAME](enforcement); @@ -76,10 +93,50 @@ describe('initArkoseLabsScript', () => { window[EXPECTED_CALLBACK_NAME](enforcement); await expect(subject).resolves.toBe(enforcement); - expect(enforcement.setConfig).toHaveBeenCalledWith({ - mode: 'inline', - data: { blob: dataExchangePayload }, - ...config, + expect(enforcement.setConfig).toHaveBeenCalledWith( + expectedSetConfigArgs(dataExchangePayload), + ); + }); + }); + + describe('when dataExchangePayloadPath is passed in', () => { + describe('when request to fetch data exchange payload succeeds', () => { + beforeEach(() => { + axiosMock + .onGet(MOCK_DATA_EXCHANGE_PAYLOAD_PATH) + .reply(HTTP_STATUS_OK, { payload: MOCK_DATA_EXCHANGE_PAYLOAD }); + }); + + it('calls ArkoseLabs config object setConfig with the data value', async () => { + initSubject({ + dataExchangePayloadPath: MOCK_DATA_EXCHANGE_PAYLOAD_PATH, + dataExchangePayload: 'not used', + config, + }); + window[EXPECTED_CALLBACK_NAME](enforcement); + + await expect(subject).resolves.toBe(enforcement); + expect(enforcement.setConfig).toHaveBeenCalledWith( + expectedSetConfigArgs(MOCK_DATA_EXCHANGE_PAYLOAD), + ); + }); + }); + + describe('when request to fetch data exchange fails', () => { + beforeEach(() => { + axiosMock.onGet(MOCK_DATA_EXCHANGE_PAYLOAD_PATH).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR); + }); + + it('calls ArkoseLabs config object setConfig without data value', async () => { + initSubject({ + dataExchangePayloadPath: MOCK_DATA_EXCHANGE_PAYLOAD_PATH, + dataExchangePayload: 'not used', + config, + }); + window[EXPECTED_CALLBACK_NAME](enforcement); + + await expect(subject).resolves.toBe(enforcement); + expect(enforcement.setConfig).toHaveBeenCalledWith(expectedSetConfigArgs(undefined)); }); }); }); @@ -102,3 +159,49 @@ describe('initArkoseLabsScript', () => { expect(findScriptTags()).toHaveLength(1); }); }); + +describe('resetArkoseLabsChallenge', () => { + const arkoseObject = { setConfig: jest.fn(), reset: jest.fn() }; + + it('calls reset on the Arkose object', async () => { + await expect(resetArkoseLabsChallenge(arkoseObject)).resolves.toBe(undefined); + expect(arkoseObject.reset).toHaveBeenCalled(); + }); + + describe('when dataExchangePayloadPath is passed in', () => { + describe('when request to fetch data exchange payload succeeds', () => { + beforeEach(() => { + axiosMock + .onGet(MOCK_DATA_EXCHANGE_PAYLOAD_PATH) + .reply(HTTP_STATUS_OK, { payload: MOCK_DATA_EXCHANGE_PAYLOAD }); + }); + + it('calls setConfig on the Arkose object with the fetched payload', async () => { + await expect( + resetArkoseLabsChallenge(arkoseObject, MOCK_DATA_EXCHANGE_PAYLOAD_PATH), + ).resolves.toBe(undefined); + expect(arkoseObject.setConfig).toHaveBeenCalledWith({ + data: { blob: MOCK_DATA_EXCHANGE_PAYLOAD }, + }); + }); + }); + + describe('when request to fetch data exchange fails', () => { + beforeEach(() => { + axiosMock.onGet(MOCK_DATA_EXCHANGE_PAYLOAD_PATH).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR); + }); + + it('calls reset on the Arkose object', async () => { + await expect(resetArkoseLabsChallenge(arkoseObject)).resolves.toBe(undefined); + expect(arkoseObject.reset).toHaveBeenCalled(); + }); + + it('does not call setConfig on the Arkose object', async () => { + await expect( + resetArkoseLabsChallenge(arkoseObject, MOCK_DATA_EXCHANGE_PAYLOAD_PATH), + ).resolves.toBe(undefined); + expect(arkoseObject.setConfig).not.toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/ee/spec/frontend/users/identity_verification/components/identity_verification_captcha_spec.js b/ee/spec/frontend/users/identity_verification/components/identity_verification_captcha_spec.js index 44c4126b2ede79806026c1cfbb6a49cd26090494..ae0c6cc4f3bb8bedab11e3a0630af27498e04d56 100644 --- a/ee/spec/frontend/users/identity_verification/components/identity_verification_captcha_spec.js +++ b/ee/spec/frontend/users/identity_verification/components/identity_verification_captcha_spec.js @@ -7,22 +7,11 @@ import IdentityVerificationCaptcha from 'ee/users/identity_verification/componen describe('Identity Verification Captcha component', () => { let wrapper; - const MOCK_ARKOSE_PUBLIC_KEY = 'arkose-labs-public-api-key'; - const MOCK_ARKOSE_DOMAIN = 'client-api.arkoselabs.com'; - const findRecaptcha = () => wrapper.findComponent(ReCaptcha); const findArkose = () => wrapper.findComponent(PhoneVerificationArkoseApp); - const createComponent = (provide = {}, props = {}) => { + const createComponent = (props = {}) => { wrapper = shallowMount(IdentityVerificationCaptcha, { - provide: { - arkoseDataExchangePayload: undefined, - arkoseConfiguration: { - apiKey: MOCK_ARKOSE_PUBLIC_KEY, - domain: MOCK_ARKOSE_DOMAIN, - }, - ...provide, - }, propsData: { showArkoseChallenge: false, showRecaptchaChallenge: false, @@ -44,18 +33,13 @@ describe('Identity Verification Captcha component', () => { describe('when showArkoseChallenge prop is true', () => { beforeEach(() => { - createComponent({ arkoseDataExchangePayload: 'payload' }, { showArkoseChallenge: true }); + createComponent({ showArkoseChallenge: true }); }); it('renders arkose', () => { expect(findArkose().exists()).toBe(true); - expect(findArkose().props()).toMatchObject({ - publicKey: MOCK_ARKOSE_PUBLIC_KEY, - domain: MOCK_ARKOSE_DOMAIN, - resetSession: false, - dataExchangePayload: 'payload', - }); + expect(findArkose().props()).toMatchObject({ resetSession: false }); }); it('emits `captcha-shown` event', () => { @@ -90,12 +74,7 @@ describe('Identity Verification Captcha component', () => { beforeEach(() => { window.gon.recaptcha_sitekey = 'site-key'; - createComponent( - {}, - { - showRecaptchaChallenge: true, - }, - ); + createComponent({ showRecaptchaChallenge: true }); }); it('renders recaptcha', () => { diff --git a/ee/spec/helpers/ee/registrations_helper_spec.rb b/ee/spec/helpers/ee/registrations_helper_spec.rb index 088f2b1ad50e1a8d5608feef9eaa8b5c5c8a32f8..4fd484d05932b680d8dcc15113df28467cbd1513 100644 --- a/ee/spec/helpers/ee/registrations_helper_spec.rb +++ b/ee/spec/helpers/ee/registrations_helper_spec.rb @@ -37,12 +37,27 @@ subject(:data) { helper.arkose_labs_data } - it { is_expected.to eq({ api_key: 'api-key', domain: 'domain', data_exchange_payload: data_exchange_payload }) } + it 'contains the correct values' do + expect(data).to eq({ + api_key: 'api-key', + domain: 'domain', + data_exchange_payload: data_exchange_payload, + data_exchange_payload_path: data_exchange_payload_path + }) + end + + context 'when fetch_arkose_data_exchange_payload feature flag is disabled' do + it 'does not include data_exchange_payload_path' do + stub_feature_flags(fetch_arkose_data_exchange_payload: false) + + expect(data.keys).not_to include(:data_exchange_payload_path) + end + end context 'when data exchange payload is nil' do let(:data_exchange_payload) { nil } - it 'does not include data exchange payload' do + it 'does not include data_exchange_payload' do expect(data.keys).not_to include(:data_exchange_payload) end end diff --git a/ee/spec/helpers/users/identity_verification_helper_spec.rb b/ee/spec/helpers/users/identity_verification_helper_spec.rb index 4d5add98c51b3fa36308fdf587d90863b4f373b1..3bc6e9f873d44f0a43d8031f274cd3df7a4c99cb 100644 --- a/ee/spec/helpers/users/identity_verification_helper_spec.rb +++ b/ee/spec/helpers/users/identity_verification_helper_spec.rb @@ -8,6 +8,10 @@ let_it_be_with_reload(:user) { create(:user) } describe '#*identity_verification_data' do + let(:request_double) { instance_double(ActionDispatch::Request) } + let(:sign_up_data_exchange_payload) { 'sign_up_data_exchange_payload' } + let(:iv_data_exchange_payload) { 'iv_data_exchange_payload' } + let(:signup_identity_verification_data) do { successful_verification_path: success_signup_identity_verification_path, @@ -48,9 +52,11 @@ }, arkose: { api_key: 'api-key', - domain: 'domain' + domain: 'domain', + data_exchange_payload: sign_up_data_exchange_payload, + data_exchange_payload_path: data_exchange_payload_path }, - arkose_data_exchange_payload: nil + arkose_data_exchange_payload: iv_data_exchange_payload } end @@ -83,6 +89,17 @@ allow(::AntiAbuse::IdentityVerification::Settings).to receive(:arkose_public_api_key).and_return('api-key') allow(::AntiAbuse::IdentityVerification::Settings).to receive(:arkose_labs_domain).and_return('domain') + + allow(helper).to receive(:request).and_return(request_double) + allow_next_instance_of(Arkose::DataExchangePayload, request_double, + a_hash_including({ use_case: Arkose::DataExchangePayload::USE_CASE_SIGN_UP })) do |builder| + allow(builder).to receive(:build).and_return(sign_up_data_exchange_payload) + end + + allow_next_instance_of(Arkose::DataExchangePayload, request_double, + a_hash_including({ use_case: Arkose::DataExchangePayload::USE_CASE_IDENTITY_VERIFICATION })) do |builder| + allow(builder).to receive(:build).and_return(iv_data_exchange_payload) + end end subject(:data) { helper.send(method, user) } @@ -109,28 +126,12 @@ end end - describe 'arkose_data_exchange_payload' do - let(:request_double) { instance_double(ActionDispatch::Request) } - let(:data_exchange_payload) { 'data_exchange_payload' } - - before do - allow(helper).to receive(:request).and_return(request_double) - - allow_next_instance_of(Arkose::DataExchangePayload, request_double, - a_hash_including({ use_case: 'SIGN_UP' })) do |builder| - allow(builder).to receive(:build).and_call_original - end - - allow_next_instance_of(Arkose::DataExchangePayload, request_double, - a_hash_including({ use_case: 'IDENTITY_VERIFICATION' })) do |builder| - allow(builder).to receive(:build).and_return(data_exchange_payload) - end - end + context 'when fetch_arkose_data_exchange_payload feature flag is disabled' do + it 'does not include arkose.data_exchange_payload_path' do + stub_feature_flags(fetch_arkose_data_exchange_payload: false) - it 'is included' do - expect(Gitlab::Json.parse(data[:data])).to include( - "arkose_data_exchange_payload" => data_exchange_payload - ) + arkose_data = Gitlab::Json.parse(data[:data])['arkose'] + expect(arkose_data.keys).not_to include('data_exchange_payload_path') end end end