- breadcrumb_title _('Two-Factor Authentication') - page_title _('Two-Factor Authentication'), _('Account') - add_to_breadcrumbs _('Account'), profile_account_path - @content_class = "limit-container-width" unless fluid_layout - webauthn_enabled = Feature.enabled?(:webauthn) .js-two-factor-auth{ 'data-two-factor-skippable' => "#{two_factor_skippable?}", 'data-two_factor_skip_url' => skip_profile_two_factor_auth_path } .row.gl-mt-3 .col-lg-4 %h4.gl-mt-0 = _('Register Two-Factor Authenticator') %p = _('Use a one-time password authenticator on your mobile device or computer to enable two-factor authentication (2FA).') .col-lg-8 - if current_user.two_factor_otp_enabled? %p = _("You've already enabled two-factor authentication using one time password authenticators. In order to register a different device, you must first disable two-factor authentication.") %p = _('If you lose your recovery codes you can generate new ones, invalidating all previous codes.') - if @error = render Pajamas::AlertComponent.new(title: @error[:message], variant: :danger, alert_options: { class: 'gl-mb-3' }, dismissible: false) do |c| = c.body do = link_to _('Try the troubleshooting steps here.'), help_page_path('user/profile/account/two_factor_authentication.md', anchor: 'troubleshooting'), target: '_blank', rel: 'noopener noreferrer' .js-manage-two-factor-form{ data: { webauthn_enabled: webauthn_enabled, current_password_required: current_password_required?.to_s, profile_two_factor_auth_path: profile_two_factor_auth_path, profile_two_factor_auth_method: 'delete', codes_profile_two_factor_auth_path: codes_profile_two_factor_auth_path, codes_profile_two_factor_auth_method: 'post' } } - else %p - register_2fa_token = _('We recommend using cloud-based authenticator applications that can restore access if you lose your hardware device.') = register_2fa_token.html_safe = link_to _('What are some examples?'), help_page_path('user/profile/account/two_factor_authentication', anchor: 'enable-one-time-password'), target: '_blank', rel: 'noopener noreferrer' .row.gl-mb-3 .col-md-4.gl-min-w-fit-content .gl-p-2.gl-mb-3{ style: 'background: #fff' } = raw @qr_code .col-md-8 .gl-card .gl-card-body %p.gl-mt-0.gl-mb-3.gl-font-weight-bold = _("Can't scan the code?") %p.gl-mt-0.gl-mb-3 = _('To add the entry manually, provide the following details to the application on your phone.') %p.gl-mt-0.gl-mb-0 = _('Account: %{account}') % { account: @account_string } %p.gl-mt-0.gl-mb-0{ data: { qa_selector: 'otp_secret_content' } } = _('Key:') %code.two-factor-secret= current_user.otp_secret.scan(/.{4}/).join(' ') %p.gl-mb-0.two-factor-new-manual-content = _('Time based: Yes') = form_tag profile_two_factor_auth_path, method: :post do |f| - if @error = render Pajamas::AlertComponent.new(title: @error[:message], variant: :danger, alert_options: { class: 'gl-mb-3' }, dismissible: false) do |c| = c.body do = link_to _('Try the troubleshooting steps here.'), help_page_path('user/profile/account/two_factor_authentication.md', anchor: 'troubleshooting'), target: '_blank', rel: 'noopener noreferrer' .form-group = label_tag :pin_code, _('Pin code'), class: "label-bold" = text_field_tag :pin_code, nil, class: "form-control gl-form-input", required: true, data: { qa_selector: 'pin_code_field' } - if current_password_required? .form-group = label_tag :current_password, _('Current password'), class: 'label-bold' = password_field_tag :current_password, nil, autocomplete: 'current-password', required: true, class: 'form-control gl-form-input', data: { qa_selector: 'current_password_field' } %p.form-text.text-muted = _('Your current password is required to register a two-factor authenticator app.') .gl-mt-3 = submit_tag _('Register with two-factor app'), class: 'gl-button btn btn-confirm', data: { qa_selector: 'register_2fa_app_button' } %hr .row.gl-mt-3 .col-lg-4 %h4.gl-mt-0 - if webauthn_enabled = _('Register WebAuthn Device') - else = _('Register Universal Two-Factor (U2F) Device') %p = _('Set up a hardware device as a second factor to sign in.') %p - if webauthn_enabled = _("Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser.") - else = _("Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser.") .col-lg-8 - registration = webauthn_enabled ? @webauthn_registration : @u2f_registration - if registration.errors.present? = form_errors(registration) - if webauthn_enabled = render "authentication/register", target_path: create_webauthn_profile_two_factor_auth_path - else = render "authentication/register", target_path: create_u2f_profile_two_factor_auth_path %hr %h5 - if webauthn_enabled = _('WebAuthn Devices (%{length})') % { length: @registrations.length } - else = _('U2F Devices (%{length})') % { length: @registrations.length } - if @registrations.present? .table-responsive %table.table.table-bordered.u2f-registrations %colgroup %col{ width: "50%" } %col{ width: "30%" } %col{ width: "20%" } %thead %tr %th= _('Name') %th= s_('2FADevice|Registered On') %th %tbody - @registrations.each do |registration| %tr %td - if registration[:name].present? = registration[:name] - else %span.gl-text-gray-500 = _("no name set") %td= registration[:created_at].to_date.to_s(:medium) %td = render Pajamas::ButtonComponent.new(variant: :danger, href: registration[:delete_path], method: :delete, button_options: { class: 'float-right', data: { confirm: _('Are you sure you want to delete this device? This action cannot be undone.'), confirm_btn_variant: "danger" }, aria: { label: _('Delete') }}) do = _('Delete') - else .settings-message.text-center - if webauthn_enabled = _("You don't have any WebAuthn devices registered yet.") - else = _("You don't have any U2F devices registered yet.")