diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-03 15:10:00 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-03 15:10:00 +0300 |
commit | 14a32c2d551a646525b1fabd93cb70a0e6924478 (patch) | |
tree | 782ba91ba786aee2cda379704e7f2ebcb5b46748 /app/assets/javascripts/authentication | |
parent | 11c2f3b08c3bab4718a97360d1502f90793d028b (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/authentication')
8 files changed, 23 insertions, 320 deletions
diff --git a/app/assets/javascripts/authentication/mount_2fa.js b/app/assets/javascripts/authentication/mount_2fa.js index ebdcd1e074d..29dcab9ed4d 100644 --- a/app/assets/javascripts/authentication/mount_2fa.js +++ b/app/assets/javascripts/authentication/mount_2fa.js @@ -1,29 +1,9 @@ -import $ from 'jquery'; -import initU2F from './u2f'; -import U2FRegister from './u2f/register'; -import initWebauthnAuthentication from './webauthn'; -import WebAuthnRegister from './webauthn/register'; +import { initWebauthnAuthenticate, initWebauthnRegister } from './webauthn'; export const mount2faAuthentication = () => { - if (gon.webauthn) { - initWebauthnAuthentication(); - } else { - initU2F(); - } + initWebauthnAuthenticate(); }; export const mount2faRegistration = () => { - const el = $('#js-register-token-2fa'); - - if (!el.length) { - return; - } - - if (gon.webauthn) { - const webauthnRegister = new WebAuthnRegister(el, gon.webauthn); - webauthnRegister.start(); - } else { - const u2fRegister = new U2FRegister(el, gon.u2f); - u2fRegister.start(); - } + initWebauthnRegister(); }; diff --git a/app/assets/javascripts/authentication/two_factor_auth/components/manage_two_factor_form.vue b/app/assets/javascripts/authentication/two_factor_auth/components/manage_two_factor_form.vue index 484c6524d0e..98ed2a31730 100644 --- a/app/assets/javascripts/authentication/two_factor_auth/components/manage_two_factor_form.vue +++ b/app/assets/javascripts/authentication/two_factor_auth/components/manage_two_factor_form.vue @@ -6,10 +6,8 @@ import { __ } from '~/locale'; export const i18n = { currentPassword: __('Current password'), confirmTitle: __('Are you sure?'), - confirmWebAuthn: __( - 'This will invalidate your registered applications and U2F / WebAuthn devices.', - ), - confirm: __('This will invalidate your registered applications and U2F devices.'), + confirmWebAuthn: __('This will invalidate your registered applications and WebAuthn devices.'), + confirm: __('This will invalidate your registered applications and WebAuthn devices.'), disableTwoFactor: __('Disable two-factor authentication'), disable: __('Disable'), cancel: __('Cancel'), diff --git a/app/assets/javascripts/authentication/u2f/authenticate.js b/app/assets/javascripts/authentication/u2f/authenticate.js deleted file mode 100644 index 22eca904f32..00000000000 --- a/app/assets/javascripts/authentication/u2f/authenticate.js +++ /dev/null @@ -1,106 +0,0 @@ -import $ from 'jquery'; -import { template as lodashTemplate, omit } from 'lodash'; -import U2FError from './error'; -import importU2FLibrary from './util'; - -// Authenticate U2F (universal 2nd factor) devices for users to authenticate with. -// -// State Flow #1: setup -> in_progress -> authenticated -> POST to server -// State Flow #2: setup -> in_progress -> error -> setup -export default class U2FAuthenticate { - constructor(container, form, u2fParams, fallbackButton, fallbackUI) { - this.u2fUtils = null; - this.container = container; - this.renderAuthenticated = this.renderAuthenticated.bind(this); - this.renderError = this.renderError.bind(this); - this.renderInProgress = this.renderInProgress.bind(this); - this.renderTemplate = this.renderTemplate.bind(this); - this.authenticate = this.authenticate.bind(this); - this.start = this.start.bind(this); - this.appId = u2fParams.app_id; - this.challenge = u2fParams.challenge; - this.form = form; - this.fallbackButton = fallbackButton; - this.fallbackUI = fallbackUI; - if (this.fallbackButton) { - this.fallbackButton.addEventListener('click', this.switchToFallbackUI.bind(this)); - } - - // The U2F Javascript API v1.1 requires a single challenge, with - // _no challenges per-request_. The U2F Javascript API v1.0 requires a - // challenge per-request, which is done by copying the single challenge - // into every request. - // - // In either case, we don't need the per-request challenges that the server - // has generated, so we can remove them. - // - // Note: The server library fixes this behaviour in (unreleased) version 1.0.0. - // This can be removed once we upgrade. - // https://github.com/castle/ruby-u2f/commit/103f428071a81cd3d5f80c2e77d522d5029946a4 - this.signRequests = u2fParams.sign_requests.map((request) => omit(request, 'challenge')); - - this.templates = { - inProgress: '#js-authenticate-token-2fa-in-progress', - error: '#js-authenticate-token-2fa-error', - authenticated: '#js-authenticate-token-2fa-authenticated', - }; - } - - start() { - return importU2FLibrary() - .then((utils) => { - this.u2fUtils = utils; - this.renderInProgress(); - }) - .catch(() => this.switchToFallbackUI()); - } - - authenticate() { - return this.u2fUtils.sign( - this.appId, - this.challenge, - this.signRequests, - (response) => { - if (response.errorCode) { - const error = new U2FError(response.errorCode, 'authenticate'); - return this.renderError(error); - } - return this.renderAuthenticated(JSON.stringify(response)); - }, - 10, - ); - } - - renderTemplate(name, params) { - const templateString = $(this.templates[name]).html(); - const template = lodashTemplate(templateString); - return this.container.html(template(params)); - } - - renderInProgress() { - this.renderTemplate('inProgress'); - return this.authenticate(); - } - - renderError(error) { - this.renderTemplate('error', { - error_message: error.message(), - error_name: error.errorCode, - }); - return this.container.find('#js-token-2fa-try-again').on('click', this.renderInProgress); - } - - renderAuthenticated(deviceResponse) { - this.renderTemplate('authenticated'); - const container = this.container[0]; - container.querySelector('#js-device-response').value = deviceResponse; - container.querySelector(this.form).submit(); - this.fallbackButton.classList.add('hidden'); - } - - switchToFallbackUI() { - this.fallbackButton.classList.add('hidden'); - this.container[0].classList.add('hidden'); - this.fallbackUI.classList.remove('hidden'); - } -} diff --git a/app/assets/javascripts/authentication/u2f/error.js b/app/assets/javascripts/authentication/u2f/error.js deleted file mode 100644 index ca0fc0700ad..00000000000 --- a/app/assets/javascripts/authentication/u2f/error.js +++ /dev/null @@ -1,26 +0,0 @@ -import { __ } from '~/locale'; - -export default class U2FError { - constructor(errorCode, u2fFlowType) { - this.errorCode = errorCode; - this.message = this.message.bind(this); - this.httpsDisabled = window.location.protocol !== 'https:'; - this.u2fFlowType = u2fFlowType; - } - - message() { - if (this.errorCode === window.u2f.ErrorCodes.BAD_REQUEST && this.httpsDisabled) { - return __( - 'U2F only works with HTTPS-enabled websites. Contact your administrator for more details.', - ); - } else if (this.errorCode === window.u2f.ErrorCodes.DEVICE_INELIGIBLE) { - if (this.u2fFlowType === 'authenticate') { - return __('This device has not been registered with us.'); - } - if (this.u2fFlowType === 'register') { - return __('This device has already been registered with us.'); - } - } - return __('There was a problem communicating with your device.'); - } -} diff --git a/app/assets/javascripts/authentication/u2f/index.js b/app/assets/javascripts/authentication/u2f/index.js deleted file mode 100644 index f129acca1c3..00000000000 --- a/app/assets/javascripts/authentication/u2f/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import $ from 'jquery'; -import U2FAuthenticate from './authenticate'; - -export default () => { - if (!gon.u2f) return; - - const u2fAuthenticate = new U2FAuthenticate( - $('#js-authenticate-token-2fa'), - '#js-login-token-2fa-form', - gon.u2f, - document.querySelector('#js-login-2fa-device'), - document.querySelector('.js-2fa-form'), - ); - u2fAuthenticate.start(); - // needed in rspec (FakeU2fDevice) - gl.u2fAuthenticate = u2fAuthenticate; -}; diff --git a/app/assets/javascripts/authentication/u2f/register.js b/app/assets/javascripts/authentication/u2f/register.js deleted file mode 100644 index 6c98f0978bc..00000000000 --- a/app/assets/javascripts/authentication/u2f/register.js +++ /dev/null @@ -1,102 +0,0 @@ -import $ from 'jquery'; -import { template as lodashTemplate } from 'lodash'; -import { __ } from '~/locale'; -import U2FError from './error'; -import importU2FLibrary from './util'; - -// Register U2F (universal 2nd factor) devices for users to authenticate with. -// -// State Flow #1: setup -> in_progress -> registered -> POST to server -// State Flow #2: setup -> in_progress -> error -> setup -export default class U2FRegister { - constructor(container, u2fParams) { - this.u2fUtils = null; - this.container = container; - this.renderNotSupported = this.renderNotSupported.bind(this); - this.renderRegistered = this.renderRegistered.bind(this); - this.renderError = this.renderError.bind(this); - this.renderInProgress = this.renderInProgress.bind(this); - this.renderSetup = this.renderSetup.bind(this); - this.renderTemplate = this.renderTemplate.bind(this); - this.register = this.register.bind(this); - this.start = this.start.bind(this); - this.appId = u2fParams.app_id; - this.registerRequests = u2fParams.register_requests; - this.signRequests = u2fParams.sign_requests; - - this.templates = { - message: '#js-register-2fa-message', - setup: '#js-register-token-2fa-setup', - error: '#js-register-token-2fa-error', - registered: '#js-register-token-2fa-registered', - }; - } - - start() { - return importU2FLibrary() - .then((utils) => { - this.u2fUtils = utils; - this.renderSetup(); - }) - .catch(() => this.renderNotSupported()); - } - - register() { - return this.u2fUtils.register( - this.appId, - this.registerRequests, - this.signRequests, - (response) => { - if (response.errorCode) { - const error = new U2FError(response.errorCode, 'register'); - return this.renderError(error); - } - return this.renderRegistered(JSON.stringify(response)); - }, - 10, - ); - } - - renderTemplate(name, params) { - const templateString = $(this.templates[name]).html(); - const template = lodashTemplate(templateString); - return this.container.html(template(params)); - } - - renderSetup() { - this.renderTemplate('setup'); - return this.container.find('#js-setup-token-2fa-device').on('click', this.renderInProgress); - } - - renderInProgress() { - this.renderTemplate('message', { - message: __( - 'Trying to communicate with your device. Plug it in (if needed) and press the button on the device now.', - ), - }); - return this.register(); - } - - renderError(error) { - this.renderTemplate('error', { - error_message: error.message(), - error_name: error.errorCode, - }); - return this.container.find('#js-token-2fa-try-again').on('click', this.renderSetup); - } - - renderRegistered(deviceResponse) { - this.renderTemplate('registered'); - // Prefer to do this instead of interpolating using Underscore templates - // because of JSON escaping issues. - return this.container.find('#js-device-response').val(deviceResponse); - } - - renderNotSupported() { - return this.renderTemplate('message', { - message: __( - "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer).", - ), - }); - } -} diff --git a/app/assets/javascripts/authentication/u2f/util.js b/app/assets/javascripts/authentication/u2f/util.js deleted file mode 100644 index b706481c02f..00000000000 --- a/app/assets/javascripts/authentication/u2f/util.js +++ /dev/null @@ -1,40 +0,0 @@ -function isOpera(userAgent) { - return userAgent.indexOf('Opera') >= 0 || userAgent.indexOf('OPR') >= 0; -} - -function getOperaVersion(userAgent) { - const match = userAgent.match(/OPR[^0-9]*([0-9]+)[^0-9]+/); - return match ? parseInt(match[1], 10) : false; -} - -function isChrome(userAgent) { - return userAgent.indexOf('Chrom') >= 0 && !isOpera(userAgent); -} - -function getChromeVersion(userAgent) { - const match = userAgent.match(/Chrom(?:e|ium)\/([0-9]+)\./); - return match ? parseInt(match[1], 10) : false; -} - -export function canInjectU2fApi(userAgent) { - const isSupportedChrome = isChrome(userAgent) && getChromeVersion(userAgent) >= 41; - const isSupportedOpera = isOpera(userAgent) && getOperaVersion(userAgent) >= 40; - const isMobile = - userAgent.indexOf('droid') >= 0 || - userAgent.indexOf('CriOS') >= 0 || - /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent); - return (isSupportedChrome || isSupportedOpera) && !isMobile; -} - -export default function importU2FLibrary() { - if (window.u2f) { - return Promise.resolve(window.u2f); - } - - const userAgent = typeof navigator !== 'undefined' ? navigator.userAgent : ''; - if (canInjectU2fApi(userAgent) || (gon && gon.test_env)) { - return import(/* webpackMode: "eager" */ 'vendor/u2f').then(() => window.u2f); - } - - return Promise.reject(); -} diff --git a/app/assets/javascripts/authentication/webauthn/index.js b/app/assets/javascripts/authentication/webauthn/index.js index e9c20ce7795..1fbe89d1097 100644 --- a/app/assets/javascripts/authentication/webauthn/index.js +++ b/app/assets/javascripts/authentication/webauthn/index.js @@ -1,7 +1,12 @@ import $ from 'jquery'; -import WebAuthnAuthenticate from '~/authentication/webauthn/authenticate'; +import WebAuthnAuthenticate from './authenticate'; +import WebAuthnRegister from './register'; + +export const initWebauthnAuthenticate = () => { + if (!gon.webauthn) { + return; + } -export default () => { const webauthnAuthenticate = new WebAuthnAuthenticate( $('#js-authenticate-token-2fa'), '#js-login-token-2fa-form', @@ -11,3 +16,14 @@ export default () => { ); webauthnAuthenticate.start(); }; + +export const initWebauthnRegister = () => { + const el = $('#js-register-token-2fa'); + + if (!el.length) { + return; + } + + const webauthnRegister = new WebAuthnRegister(el, gon.webauthn); + webauthnRegister.start(); +}; |