From 8dfa27612ec425bc3bbc1e0b45ca35b11437f733 Mon Sep 17 00:00:00 2001 From: eugielimpin Date: Wed, 17 Aug 2022 14:26:42 +0800 Subject: [PATCH] Display Arkose Labs challenge in the registration form Display Arkose Labs challenge in the registration form and pass the session token returned by Arkose Labs to the backend when the challenge is solved. --- app/views/devise/sessions/_new_base.html.haml | 2 +- app/views/devise/shared/_signup_box.html.haml | 8 +- .../arkose_labs_signup_challenge.yml | 8 + .../components/sign_up_arkose_app.vue | 100 ++++++++++++ .../javascripts/arkose_labs/constants.js | 7 + .../assets/javascripts/arkose_labs/index.js | 28 +++- .../pages/registrations/new/index.js | 5 + .../controllers/concerns/arkose_labs_csp.rb | 5 +- .../ee/registrations_controller.rb | 27 ++++ ee/app/helpers/ee/registrations_helper.rb | 9 ++ .../registrations/_arkose_labs.html.haml | 1 + .../devise/sessions/_arkose_labs.html.haml | 2 +- .../ee/registrations_controller_spec.rb | 4 + .../trial_registrations_controller_spec.rb | 1 + ee/spec/features/invites_spec.rb | 1 + .../saas_user_registration_spec.rb | 4 +- ee/spec/features/signup_spec.rb | 1 + .../trial_registrations/signup_spec.rb | 1 + .../features/users/arkose_labs_csp_spec.rb | 48 +++++- .../components/sign_up_arkose_app_spec.js | 149 ++++++++++++++++++ .../helpers/ee/registrations_helper_spec.rb | 19 +++ .../requests/registrations_controller_spec.rb | 34 ++++ .../trial_registrations_controller_spec.rb | 1 + .../registrations/new.html.haml_spec.rb | 45 ++++++ .../devise/sessions/new.html.haml_spec.rb | 8 +- locale/gitlab.pot | 6 + .../registrations_controller_spec.rb | 1 + spec/features/invites_spec.rb | 1 + spec/features/users/signup_spec.rb | 1 + 29 files changed, 509 insertions(+), 18 deletions(-) create mode 100644 config/feature_flags/development/arkose_labs_signup_challenge.yml create mode 100644 ee/app/assets/javascripts/arkose_labs/components/sign_up_arkose_app.vue create mode 100644 ee/app/assets/javascripts/arkose_labs/constants.js create mode 100644 ee/app/views/devise/registrations/_arkose_labs.html.haml create mode 100644 ee/spec/frontend/arkose_labs/components/sign_up_arkose_app_spec.js create mode 100644 ee/spec/requests/registrations_controller_spec.rb create mode 100644 ee/spec/views/devise/registrations/new.html.haml_spec.rb diff --git a/app/views/devise/sessions/_new_base.html.haml b/app/views/devise/sessions/_new_base.html.haml index e0de8824625e65..3aeb89979bb666 100644 --- a/app/views/devise/sessions/_new_base.html.haml +++ b/app/views/devise/sessions/_new_base.html.haml @@ -1,4 +1,4 @@ -= gitlab_ui_form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: 'new_user gl-show-field-errors js-sign-in-form', aria: { live: 'assertive' }, data: { testid: 'sign-in-form' }}) do |f| += gitlab_ui_form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: 'new_user gl-show-field-errors js-arkose-labs-form', aria: { live: 'assertive' }, data: { testid: 'sign-in-form' }}) do |f| .form-group.gl-px-5.gl-pt-5 = render_if_exists 'devise/sessions/new_base_user_login_label', form: f = f.text_field :login, value: @invite_email, class: 'form-control gl-form-input top js-username-field', autofocus: 'autofocus', autocapitalize: 'off', autocorrect: 'off', required: true, title: _('This field is required.'), data: { qa_selector: 'login_field', testid: 'username-field' } diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml index 991af1eea0ccb4..b9c9c99bf1a238 100644 --- a/app/views/devise/shared/_signup_box.html.haml +++ b/app/views/devise/shared/_signup_box.html.haml @@ -6,7 +6,7 @@ - if show_omniauth_providers && omniauth_providers_placement == :top = render 'devise/shared/signup_omniauth_providers_top' - = form_for(resource, as: "new_#{resource_name}", url: url, html: { class: 'new_user gl-show-field-errors', 'aria-live' => 'assertive' }) do |f| + = form_for(resource, as: "new_#{resource_name}", url: url, html: { class: 'new_user gl-show-field-errors js-arkose-labs-form', 'aria-live' => 'assertive' }, data: { testid: 'signup-form' }) do |f| .devise-errors = render 'devise/shared/error_messages', resource: resource - if Gitlab::CurrentSettings.invisible_captcha_enabled @@ -66,8 +66,12 @@ = render_if_exists 'shared/password_requirements_list' = render_if_exists 'devise/shared/phone_verification', form: f %div - - if show_recaptcha_sign_up? + + - if Feature.enabled?(:arkose_labs_signup_challenge) + = render_if_exists 'devise/registrations/arkose_labs' + - elsif show_recaptcha_sign_up? = recaptcha_tags nonce: content_security_policy_nonce + .submit-container.gl-mt-5 = f.submit button_text, class: 'btn gl-button btn-confirm gl-display-block gl-w-full', data: { qa_selector: 'new_user_register_button' } - if Gitlab::CurrentSettings.sign_in_text.present? && Feature.enabled?(:restyle_login_page, @project) diff --git a/config/feature_flags/development/arkose_labs_signup_challenge.yml b/config/feature_flags/development/arkose_labs_signup_challenge.yml new file mode 100644 index 00000000000000..8b40ce5d0294c0 --- /dev/null +++ b/config/feature_flags/development/arkose_labs_signup_challenge.yml @@ -0,0 +1,8 @@ +--- +name: arkose_labs_signup_challenge +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95560 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/370932 +milestone: '15.4' +type: development +group: group::anti-abuse +default_enabled: false diff --git a/ee/app/assets/javascripts/arkose_labs/components/sign_up_arkose_app.vue b/ee/app/assets/javascripts/arkose_labs/components/sign_up_arkose_app.vue new file mode 100644 index 00000000000000..658067856b7245 --- /dev/null +++ b/ee/app/assets/javascripts/arkose_labs/components/sign_up_arkose_app.vue @@ -0,0 +1,100 @@ + + + diff --git a/ee/app/assets/javascripts/arkose_labs/constants.js b/ee/app/assets/javascripts/arkose_labs/constants.js new file mode 100644 index 00000000000000..91c5c6614ead11 --- /dev/null +++ b/ee/app/assets/javascripts/arkose_labs/constants.js @@ -0,0 +1,7 @@ +import { __ } from '~/locale'; + +export const VERIFICATION_REQUIRED_MESSAGE = __('Complete verification to sign up.'); +export const VERIFICATION_LOADING_MESSAGE = __('Please wait while we prepare for verification.'); + +export const CHALLENGE_CONTAINER_CLASS = 'js-arkose-labs-container-'; +export const VERIFICATION_TOKEN_INPUT_NAME = 'arkose_labs_token'; diff --git a/ee/app/assets/javascripts/arkose_labs/index.js b/ee/app/assets/javascripts/arkose_labs/index.js index 43d3ab95b11f2f..1ecf784bb92657 100644 --- a/ee/app/assets/javascripts/arkose_labs/index.js +++ b/ee/app/assets/javascripts/arkose_labs/index.js @@ -1,13 +1,14 @@ import Vue from 'vue'; import SignInArkoseApp from './components/sign_in_arkose_app.vue'; +import SignUpArkoseApp from './components/sign_up_arkose_app.vue'; -const FORM_SELECTOR = '.js-sign-in-form'; +const FORM_SELECTOR = '.js-arkose-labs-form'; const USERNAME_SELECTOR = `${FORM_SELECTOR} .js-username-field`; const SUBMIT_SELECTOR = `${FORM_SELECTOR} .js-sign-in-button`; export const setupArkoseLabs = () => { const signInForm = document.querySelector(FORM_SELECTOR); - const el = signInForm?.querySelector('.js-arkose-labs-challenge'); + const el = signInForm?.querySelector('#js-arkose-labs-challenge'); if (!el) { return null; @@ -30,3 +31,26 @@ export const setupArkoseLabs = () => { }, }); }; + +export const setupArkoseLabsForSignup = () => { + const el = document.querySelector('#js-arkose-labs-challenge'); + + if (!el) { + return null; + } + + const { apiKey, domain } = el.dataset; + + return new Vue({ + el, + render(h) { + return h(SignUpArkoseApp, { + props: { + formSelector: FORM_SELECTOR, + publicKey: apiKey, + domain, + }, + }); + }, + }); +}; diff --git a/ee/app/assets/javascripts/pages/registrations/new/index.js b/ee/app/assets/javascripts/pages/registrations/new/index.js index 3bb5c2c782958c..d4aa724a36f967 100644 --- a/ee/app/assets/javascripts/pages/registrations/new/index.js +++ b/ee/app/assets/javascripts/pages/registrations/new/index.js @@ -1,4 +1,9 @@ import '~/pages/registrations/new/index'; import PasswordValidator from 'ee/password/password_validator'; +import { setupArkoseLabsForSignup } from 'ee/arkose_labs'; new PasswordValidator(); // eslint-disable-line no-new + +if (gon.features.arkoseLabsSignupChallenge) { + setupArkoseLabsForSignup(); +} diff --git a/ee/app/controllers/concerns/arkose_labs_csp.rb b/ee/app/controllers/concerns/arkose_labs_csp.rb index 8d770378cd01d2..c78ccbf604d2f4 100644 --- a/ee/app/controllers/concerns/arkose_labs_csp.rb +++ b/ee/app/controllers/concerns/arkose_labs_csp.rb @@ -5,7 +5,10 @@ module ArkoseLabsCSP included do content_security_policy do |policy| - next unless Feature.enabled?(:arkose_labs_login_challenge) + allow_for_login = self == SessionsController && Feature.enabled?(:arkose_labs_login_challenge) + allow_for_signup = self == RegistrationsController && Feature.enabled?(:arkose_labs_signup_challenge) + + next unless allow_for_login || allow_for_signup default_script_src = policy.directives['script-src'] || policy.directives['default-src'] script_src_values = Array.wrap(default_script_src) | ["https://*.arkoselabs.com"] diff --git a/ee/app/controllers/ee/registrations_controller.rb b/ee/app/controllers/ee/registrations_controller.rb index b41e603727799f..56ec85196235a3 100644 --- a/ee/app/controllers/ee/registrations_controller.rb +++ b/ee/app/controllers/ee/registrations_controller.rb @@ -6,9 +6,28 @@ module RegistrationsController extend ::Gitlab::Utils::Override prepended do + include ArkoseLabsCSP + + skip_before_action :check_captcha, if: -> { ::Feature.enabled?(:arkose_labs_signup_challenge) } + before_action only: [:new, :create] do + push_frontend_feature_flag(:arkose_labs_signup_challenge) + end before_action :ensure_can_remove_self, only: [:destroy] end + override :create + def create + ensure_correct_params! + + unless verify_arkose_labs_token + flash[:alert] = _('Complete verification to sign up.') + render action: 'new' + return + end + + super + end + private override :after_request_hook @@ -41,5 +60,13 @@ def log_audit_event(user) custom_message: _('Instance access request') ).for_user.security_event end + + def verify_arkose_labs_token + return true unless ::Feature.enabled?(:arkose_labs_signup_challenge) + + # TODO: verify the token with Arkose Labs Verify API + # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96243 + params[:arkose_labs_token].present? + end end end diff --git a/ee/app/helpers/ee/registrations_helper.rb b/ee/app/helpers/ee/registrations_helper.rb index a8ea7c2c18e6c1..3db528ef113e44 100644 --- a/ee/app/helpers/ee/registrations_helper.rb +++ b/ee/app/helpers/ee/registrations_helper.rb @@ -46,6 +46,15 @@ def credit_card_verification_data } end + def arkose_labs_data + return {} unless ::Feature.enabled?(:arkose_labs_signup_challenge) + + { + api_key: Arkose::Settings.arkose_public_api_key, + domain: Arkose::Settings.arkose_labs_domain + } + end + private def redirect_path diff --git a/ee/app/views/devise/registrations/_arkose_labs.html.haml b/ee/app/views/devise/registrations/_arkose_labs.html.haml new file mode 100644 index 00000000000000..b35e2941da9ca9 --- /dev/null +++ b/ee/app/views/devise/registrations/_arkose_labs.html.haml @@ -0,0 +1 @@ +#js-arkose-labs-challenge{ data: arkose_labs_data } diff --git a/ee/app/views/devise/sessions/_arkose_labs.html.haml b/ee/app/views/devise/sessions/_arkose_labs.html.haml index 1390680b461134..6f8d9d0e5e1c65 100644 --- a/ee/app/views/devise/sessions/_arkose_labs.html.haml +++ b/ee/app/views/devise/sessions/_arkose_labs.html.haml @@ -1 +1 @@ -.js-arkose-labs-challenge{ data: { api_key: @arkose_labs_public_key, domain: @arkose_labs_domain } } +#js-arkose-labs-challenge{ data: { api_key: @arkose_labs_public_key, domain: @arkose_labs_domain } } diff --git a/ee/spec/controllers/ee/registrations_controller_spec.rb b/ee/spec/controllers/ee/registrations_controller_spec.rb index 215ecf7f4bfd4d..9a88148e93421b 100644 --- a/ee/spec/controllers/ee/registrations_controller_spec.rb +++ b/ee/spec/controllers/ee/registrations_controller_spec.rb @@ -8,6 +8,10 @@ let_it_be(:new_user_email) { 'new@user.com' } let_it_be(:user_params) { { user: base_user_params.merge(email: new_user_email) } } + before do + stub_feature_flags(arkose_labs_signup_challenge: false) + end + subject { post :create, params: user_params } shared_examples 'blocked user by default' do diff --git a/ee/spec/controllers/trial_registrations_controller_spec.rb b/ee/spec/controllers/trial_registrations_controller_spec.rb index e55d1c9df0ec7a..744805b7aa4b10 100644 --- a/ee/spec/controllers/trial_registrations_controller_spec.rb +++ b/ee/spec/controllers/trial_registrations_controller_spec.rb @@ -7,6 +7,7 @@ before do allow(Gitlab).to receive(:com?).and_return(com) + stub_feature_flags(arkose_labs_signup_challenge: false) end shared_examples 'a dot-com only feature' do diff --git a/ee/spec/features/invites_spec.rb b/ee/spec/features/invites_spec.rb index 1fd7677bc76bea..81868b3cde2935 100644 --- a/ee/spec/features/invites_spec.rb +++ b/ee/spec/features/invites_spec.rb @@ -10,6 +10,7 @@ let(:com) { true } before do + stub_feature_flags(arkose_labs_signup_challenge: false) stub_application_setting(require_admin_approval_after_user_signup: false) allow(::Gitlab).to receive(:com?).and_return(com) diff --git a/ee/spec/features/registrations/saas_user_registration_spec.rb b/ee/spec/features/registrations/saas_user_registration_spec.rb index ff9029cd6d78ea..543cc081640e88 100644 --- a/ee/spec/features/registrations/saas_user_registration_spec.rb +++ b/ee/spec/features/registrations/saas_user_registration_spec.rb @@ -21,7 +21,9 @@ # This is a feature flag to update the single-sign on registration flow # to match the standard registration flow - update_oauth_registration_flow: true + update_oauth_registration_flow: true, + + arkose_labs_signup_challenge: false ) stub_application_setting( diff --git a/ee/spec/features/signup_spec.rb b/ee/spec/features/signup_spec.rb index 329a1004d63cc1..34a8c80fa47c12 100644 --- a/ee/spec/features/signup_spec.rb +++ b/ee/spec/features/signup_spec.rb @@ -7,6 +7,7 @@ before do stub_application_setting(require_admin_approval_after_user_signup: false) + stub_feature_flags(arkose_labs_signup_challenge: false) end def fill_in_signup_form diff --git a/ee/spec/features/trial_registrations/signup_spec.rb b/ee/spec/features/trial_registrations/signup_spec.rb index f63eaf06ddda95..b54e99649f1237 100644 --- a/ee/spec/features/trial_registrations/signup_spec.rb +++ b/ee/spec/features/trial_registrations/signup_spec.rb @@ -7,6 +7,7 @@ before do stub_application_setting(require_admin_approval_after_user_signup: false) + stub_feature_flags(arkose_labs_signup_challenge: false) end describe 'on GitLab.com', :saas do diff --git a/ee/spec/features/users/arkose_labs_csp_spec.rb b/ee/spec/features/users/arkose_labs_csp_spec.rb index 76e87d15cbd725..be00ae9ff600fb 100644 --- a/ee/spec/features/users/arkose_labs_csp_spec.rb +++ b/ee/spec/features/users/arkose_labs_csp_spec.rb @@ -3,15 +3,51 @@ require 'spec_helper' RSpec.describe 'ArkoseLabs content security policy' do - let(:user) { create(:user) } + shared_examples 'configures Content Security Policy headers correctly' do + context 'when feature flag is enabled' do + let(:feature_flag_state) { true } - before do - stub_feature_flags(arkose_labs_login_challenge: true) + it 'adds ArkoseLabs URL to Content Security Policy headers' do + visit page_path + + expect(response_headers['Content-Security-Policy']).to include('https://*.arkoselabs.com') + end + end + + context 'when feature flag is disabled' do + let(:feature_flag_state) { false } + + it 'does not add ArkoseLabs URL to Content Security Policy headers' do + visit page_path + + expect(response_headers['Content-Security-Policy']).not_to include('https://*.arkoselabs.com') + end + end end - it 'has proper Content Security Policy headers' do - visit root_path + context 'when in login page' do + let(:page_path) { root_path } + + before do + stub_feature_flags( + arkose_labs_signup_challenge: false, + arkose_labs_login_challenge: feature_flag_state + ) + end + + it_behaves_like 'configures Content Security Policy headers correctly' + end + + context 'when in registration page' do + let(:page_path) { new_user_registration_path } + + before do + stub_feature_flags( + arkose_labs_login_challenge: false, + arkose_labs_signup_challenge: feature_flag_state + ) + end - expect(response_headers['Content-Security-Policy']).to include('https://*.arkoselabs.com') + it_behaves_like 'configures Content Security Policy headers correctly' end end diff --git a/ee/spec/frontend/arkose_labs/components/sign_up_arkose_app_spec.js b/ee/spec/frontend/arkose_labs/components/sign_up_arkose_app_spec.js new file mode 100644 index 00000000000000..cd9b1a747b1219 --- /dev/null +++ b/ee/spec/frontend/arkose_labs/components/sign_up_arkose_app_spec.js @@ -0,0 +1,149 @@ +import { nextTick } from 'vue'; +import { createAlert } from '~/flash'; +import DomElementListener from '~/vue_shared/components/dom_element_listener.vue'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import SignUpArkoseApp from 'ee/arkose_labs/components/sign_up_arkose_app.vue'; +import { initArkoseLabsScript } from 'ee/arkose_labs/init_arkose_labs_script'; +import { + VERIFICATION_LOADING_MESSAGE, + VERIFICATION_REQUIRED_MESSAGE, + VERIFICATION_TOKEN_INPUT_NAME, +} from 'ee/arkose_labs/constants'; + +jest.mock('~/flash'); +jest.mock('ee/arkose_labs/init_arkose_labs_script'); +let onShown; +let onCompleted; +initArkoseLabsScript.mockImplementation(() => ({ + setConfig: ({ onShown: shownHandler, onCompleted: completedHandler }) => { + onShown = shownHandler; + onCompleted = completedHandler; + }, +})); + +const MOCK_ARKOSE_RESPONSE = { token: 'verification-token' }; +const MOCK_PUBLIC_KEY = 'arkose-labs-public-api-key'; +const MOCK_DOMAIN = 'client-api.arkoselabs.com'; + +describe('SignUpArkoseApp', () => { + let wrapper; + + const findChallengeContainer = () => wrapper.findByTestId('arkose-labs-challenge'); + const findArkoseLabsVerificationTokenInput = () => + wrapper.find(`input[name="${VERIFICATION_TOKEN_INPUT_NAME}"]`); + + const submitForm = async (event) => { + wrapper.findComponent(DomElementListener).vm.$emit('submit', event); + await nextTick(); + }; + + const createComponent = () => { + wrapper = mountExtended(SignUpArkoseApp, { + propsData: { + publicKey: MOCK_PUBLIC_KEY, + domain: MOCK_DOMAIN, + formSelector: 'dummy', + }, + }); + }; + + afterEach(() => { + wrapper?.destroy(); + }); + + beforeEach(() => { + createComponent(); + }); + + it("includes Arkose Labs' script", () => { + expect(initArkoseLabsScript).toHaveBeenCalledWith({ + publicKey: MOCK_PUBLIC_KEY, + domain: MOCK_DOMAIN, + }); + }); + + it('creates a hidden input for the verification token', () => { + const input = findArkoseLabsVerificationTokenInput(); + + expect(input.exists()).toBe(true); + expect(input.element.value).toBe(''); + }); + + it('shows the challenge container when Arkose Labs calls `onShown`', async () => { + expect(findChallengeContainer().isVisible()).toBe(false); + + onShown(); + await nextTick(); + + expect(findChallengeContainer().isVisible()).toBe(true); + }); + + describe('when Arkose Labs calls `onCompleted`', () => { + beforeEach(() => { + onCompleted(MOCK_ARKOSE_RESPONSE); + }); + + it("sets the verification token input's value", () => { + expect(findArkoseLabsVerificationTokenInput().element.value).toBe(MOCK_ARKOSE_RESPONSE.token); + }); + }); + + describe('when form is submitted', () => { + let mockSubmitEvent; + + beforeEach(() => { + mockSubmitEvent = { preventDefault: jest.fn(), stopPropagation: jest.fn() }; + }); + + describe('when challenge was not completed', () => { + beforeEach(async () => { + onShown(); + + await submitForm(mockSubmitEvent); + }); + + it('shows verification required error message', async () => { + expect(createAlert).toHaveBeenCalledWith({ + message: VERIFICATION_REQUIRED_MESSAGE, + }); + }); + + it('stops the submit event', async () => { + expect(mockSubmitEvent.preventDefault).toHaveBeenCalledTimes(1); + expect(mockSubmitEvent.stopPropagation).toHaveBeenCalledTimes(1); + }); + }); + + describe('when challenge was completed', () => { + beforeEach(async () => { + onShown(); + onCompleted(MOCK_ARKOSE_RESPONSE); + + submitForm(mockSubmitEvent); + + await nextTick(); + }); + + it('does not show verification required error message', async () => { + expect(createAlert).not.toHaveBeenCalled(); + }); + + it('does not stop the submit event', async () => { + expect(mockSubmitEvent.preventDefault).not.toHaveBeenCalled(); + expect(mockSubmitEvent.stopPropagation).not.toHaveBeenCalled(); + }); + }); + + describe('when challenge has not been shown yet (loading)', () => { + beforeEach(async () => { + await submitForm(mockSubmitEvent); + }); + + it('shows verification loading message', async () => { + expect(createAlert).toHaveBeenCalledWith({ + message: VERIFICATION_LOADING_MESSAGE, + }); + }); + }); + }); +}); diff --git a/ee/spec/helpers/ee/registrations_helper_spec.rb b/ee/spec/helpers/ee/registrations_helper_spec.rb index 335b3c7a8dff36..98fb1d956fdb89 100644 --- a/ee/spec/helpers/ee/registrations_helper_spec.rb +++ b/ee/spec/helpers/ee/registrations_helper_spec.rb @@ -107,4 +107,23 @@ ) end end + + describe '#arkose_labs_data' do + before do + allow(::Arkose::Settings).to receive(:arkose_public_api_key).and_return('api-key') + allow(::Arkose::Settings).to receive(:arkose_labs_domain).and_return('domain') + end + + subject(:data) { helper.arkose_labs_data } + + it { is_expected.to eq({ api_key: 'api-key', domain: 'domain' }) } + + context 'when :arkose_labs_signup_challenge is disabled' do + before do + stub_feature_flags(arkose_labs_signup_challenge: false) + end + + it { is_expected.to eq({}) } + end + end end diff --git a/ee/spec/requests/registrations_controller_spec.rb b/ee/spec/requests/registrations_controller_spec.rb new file mode 100644 index 00000000000000..498ef566cb8f06 --- /dev/null +++ b/ee/spec/requests/registrations_controller_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe RegistrationsController, type: :request do + describe 'POST #create' do + let_it_be(:base_user_params) { build_stubbed(:user).slice(:first_name, :last_name, :username, :email, :password) } + + let(:arkose_labs_params) { { arkose_labs_token: 'arkose-labs-token' } } + let(:user_params) { { user: base_user_params }.merge(arkose_labs_params) } + + subject(:request) { post user_registration_path, params: user_params } + + context 'when arkose_labs_token verification succeeds' do + it 'does not render new action', :aggregate_failures do + request + + expect(flash[:alert]).to be_nil + expect(response).not_to render_template(:new) + end + end + + context 'when arkose_labs_token verification fails' do + let(:arkose_labs_params) { {} } + + it 'renders new action with an alert flash', :aggregate_failures do + request + + expect(flash[:alert]).to include(_('Complete verification to sign up.')) + expect(response).to render_template(:new) + end + end + end +end diff --git a/ee/spec/requests/trial_registrations_controller_spec.rb b/ee/spec/requests/trial_registrations_controller_spec.rb index e054b0a1a75dd8..c20a4e47005987 100644 --- a/ee/spec/requests/trial_registrations_controller_spec.rb +++ b/ee/spec/requests/trial_registrations_controller_spec.rb @@ -7,6 +7,7 @@ before do allow(Gitlab).to receive(:com?).and_return(com) + stub_feature_flags(arkose_labs_signup_challenge: false) end describe 'POST new' do diff --git a/ee/spec/views/devise/registrations/new.html.haml_spec.rb b/ee/spec/views/devise/registrations/new.html.haml_spec.rb new file mode 100644 index 00000000000000..2c881b1bbb5eea --- /dev/null +++ b/ee/spec/views/devise/registrations/new.html.haml_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'devise/registrations/new' do + let(:arkose_labs_api_key) { "api-key" } + let(:arkose_labs_domain) { "domain" } + + subject { render(template: 'devise/registrations/new') } + + before do + stub_devise + + allow(::Arkose::Settings).to receive(:arkose_public_api_key).and_return(arkose_labs_api_key) + allow(::Arkose::Settings).to receive(:arkose_labs_domain).and_return(arkose_labs_domain) + end + + it 'renders challenge container with the correct data attributes', :aggregate_failures do + subject + + expect(rendered).to have_selector('#js-arkose-labs-challenge') + expect(rendered).to have_selector("[data-api-key='#{arkose_labs_api_key}']") + expect(rendered).to have_selector("[data-domain='#{arkose_labs_domain}']") + end + + context 'when the :arkose_labs_signup_challenge feature flag is disabled' do + before do + stub_feature_flags(arkose_labs_signup_challenge: false) + end + + it 'does not render challenge container', :aggregate_failures do + subject + + expect(rendered).not_to have_selector('#js-arkose-labs-challenge') + expect(rendered).not_to have_selector("[data-api-key='#{arkose_labs_api_key}']") + expect(rendered).not_to have_selector("[data-domain='#{arkose_labs_domain}']") + end + end + + def stub_devise + allow(view).to receive(:devise_mapping).and_return(Devise.mappings[:user]) + allow(view).to receive(:resource).and_return(build(:user)) + allow(view).to receive(:resource_name).and_return(:user) + end +end diff --git a/ee/spec/views/devise/sessions/new.html.haml_spec.rb b/ee/spec/views/devise/sessions/new.html.haml_spec.rb index 6356b53a5d4af2..53d56ee0553d7e 100644 --- a/ee/spec/views/devise/sessions/new.html.haml_spec.rb +++ b/ee/spec/views/devise/sessions/new.html.haml_spec.rb @@ -25,15 +25,15 @@ end it 'renders the challenge container' do - expect(rendered).to have_css('.js-arkose-labs-challenge') + expect(rendered).to have_css('#js-arkose-labs-challenge') end it 'passes the API key to the challenge container' do - expect(rendered).to have_selector('.js-arkose-labs-challenge[data-api-key="arkose-api-key"]') + expect(rendered).to have_selector('#js-arkose-labs-challenge[data-api-key="arkose-api-key"]') end it 'passes the ArkoseLabs domain to the challenge container' do - expect(rendered).to have_selector('.js-arkose-labs-challenge[data-domain="gitlab-api.arkoselab.com"]') + expect(rendered).to have_selector('#js-arkose-labs-challenge[data-domain="gitlab-api.arkoselab.com"]') end end @@ -45,7 +45,7 @@ end it 'does not render challenge container' do - expect(rendered).not_to have_css('.js-arkose-labs-challenge') + expect(rendered).not_to have_css('#js-arkose-labs-challenge') end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 65281a6bc15773..ec6a1c98e12d19 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -9704,6 +9704,9 @@ msgstr "" msgid "Complete verification to sign in." msgstr "" +msgid "Complete verification to sign up." +msgstr "" + msgid "Completed" msgstr "" @@ -29845,6 +29848,9 @@ msgstr "" msgid "Please wait while we import the repository for you. Refresh at will." msgstr "" +msgid "Please wait while we prepare for verification." +msgstr "" + msgid "Pods in use" msgstr "" diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index 70d4559edc10c4..fcf7331423cdfa 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -7,6 +7,7 @@ before do stub_application_setting(require_admin_approval_after_user_signup: false) + stub_feature_flags(arkose_labs_signup_challenge: false) end describe '#new' do diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb index 1baa97096d9b34..a86e4cead48c46 100644 --- a/spec/features/invites_spec.rb +++ b/spec/features/invites_spec.rb @@ -10,6 +10,7 @@ let(:group_invite) { group.group_members.invite.last } before do + stub_feature_flags(arkose_labs_signup_challenge: false) stub_application_setting(require_admin_approval_after_user_signup: false) project.add_maintainer(owner) group.add_owner(owner) diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb index fa6a917a0597bd..998570da8b29c9 100644 --- a/spec/features/users/signup_spec.rb +++ b/spec/features/users/signup_spec.rb @@ -66,6 +66,7 @@ def confirm_email flag_values = [true, false] flag_values.each do |val| before do + stub_feature_flags(arkose_labs_signup_challenge: false) stub_feature_flags(restyle_login_page: val) stub_application_setting(require_admin_approval_after_user_signup: false) end -- GitLab