diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/dispatcher.js.es6 | 11 | ||||
-rw-r--r-- | app/assets/javascripts/u2f/authenticate.js.es6 (renamed from app/assets/javascripts/u2f/authenticate.js) | 35 | ||||
-rw-r--r-- | app/views/devise/sessions/two_factor.html.haml | 2 | ||||
-rw-r--r-- | app/views/u2f/_authenticate.html.haml | 17 |
4 files changed, 37 insertions, 28 deletions
diff --git a/app/assets/javascripts/dispatcher.js.es6 b/app/assets/javascripts/dispatcher.js.es6 index 78f68a247a2..1c1b6cd2dad 100644 --- a/app/assets/javascripts/dispatcher.js.es6 +++ b/app/assets/javascripts/dispatcher.js.es6 @@ -64,6 +64,17 @@ new UsernameValidator(); new ActiveTabMemoizer(); break; + case 'sessions:create': + if (!gon.u2f) break; + window.gl.u2fAuthenticate = new gl.U2FAuthenticate( + $("#js-authenticate-u2f"), + '#js-login-u2f-form', + gon.u2f, + document.querySelector('#js-login-2fa-device'), + document.querySelector('.js-2fa-form'), + ); + window.gl.u2fAuthenticate.start(); + break; case 'projects:boards:show': case 'projects:boards:index': shortcut_handler = new ShortcutsNavigation(); diff --git a/app/assets/javascripts/u2f/authenticate.js b/app/assets/javascripts/u2f/authenticate.js.es6 index e407b856e10..2b992109a8c 100644 --- a/app/assets/javascripts/u2f/authenticate.js +++ b/app/assets/javascripts/u2f/authenticate.js.es6 @@ -8,21 +8,26 @@ // State Flow #1: setup -> in_progress -> authenticated -> POST to server // State Flow #2: setup -> in_progress -> error -> setup (function() { + const global = window.gl || (window.gl = {}); + var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; - this.U2FAuthenticate = (function() { - function U2FAuthenticate(container, u2fParams) { + global.U2FAuthenticate = (function() { + function U2FAuthenticate(container, form, u2fParams, fallbackButton, fallbackUI) { this.container = container; this.renderNotSupported = bind(this.renderNotSupported, this); this.renderAuthenticated = bind(this.renderAuthenticated, this); this.renderError = bind(this.renderError, this); this.renderInProgress = bind(this.renderInProgress, this); - this.renderSetup = bind(this.renderSetup, this); this.renderTemplate = bind(this.renderTemplate, this); this.authenticate = bind(this.authenticate, this); this.start = bind(this.start, 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)); this.signRequests = u2fParams.sign_requests.map(function(request) { // The U2F Javascript API v1.1 requires a single challenge, with // _no challenges per-request_. The U2F Javascript API v1.0 requires a @@ -41,7 +46,7 @@ U2FAuthenticate.prototype.start = function() { if (U2FUtil.isU2FSupported()) { - return this.renderSetup(); + return this.renderInProgress(); } else { return this.renderNotSupported(); } @@ -77,11 +82,6 @@ return this.container.html(template(params)); }; - U2FAuthenticate.prototype.renderSetup = function() { - this.renderTemplate('setup'); - return this.container.find('#js-login-u2f-device').on('click', this.renderInProgress); - }; - U2FAuthenticate.prototype.renderInProgress = function() { this.renderTemplate('inProgress'); return this.authenticate(); @@ -92,22 +92,29 @@ error_message: error.message(), error_code: error.errorCode }); - return this.container.find('#js-u2f-try-again').on('click', this.renderSetup); + return this.container.find('#js-u2f-try-again').on('click', this.renderInProgress); }; U2FAuthenticate.prototype.renderAuthenticated = function(deviceResponse) { this.renderTemplate('authenticated'); - // Prefer to do this instead of interpolating using Underscore templates - // because of JSON escaping issues. - return this.container.find("#js-device-response").val(deviceResponse); + const container = this.container[0]; + container.querySelector('#js-device-response').value = deviceResponse; + container.querySelector(this.form).submit(); + this.fallbackButton.classList.add('hidden'); }; U2FAuthenticate.prototype.renderNotSupported = function() { return this.renderTemplate('notSupported'); }; + U2FAuthenticate.prototype.switchToFallbackUI = function() { + this.fallbackButton.classList.add('hidden'); + this.container[0].classList.add('hidden'); + this.fallbackUI.classList.remove('hidden'); + }; + return U2FAuthenticate; })(); -}).call(this); +})(); diff --git a/app/views/devise/sessions/two_factor.html.haml b/app/views/devise/sessions/two_factor.html.haml index 2cadc424668..951f03083bf 100644 --- a/app/views/devise/sessions/two_factor.html.haml +++ b/app/views/devise/sessions/two_factor.html.haml @@ -7,7 +7,7 @@ .login-box .login-body - if @user.two_factor_otp_enabled? - = form_for(resource, as: resource_name, url: session_path(resource_name), method: :post, html: { class: 'edit_user gl-show-field-errors' }) do |f| + = form_for(resource, as: resource_name, url: session_path(resource_name), method: :post, html: { class: "edit_user gl-show-field-errors js-2fa-form #{'hidden' if @user.two_factor_u2f_enabled?}" }) do |f| - resource_params = params[resource_name].presence || params = f.hidden_field :remember_me, value: resource_params.fetch(:remember_me, 0) %div diff --git a/app/views/u2f/_authenticate.html.haml b/app/views/u2f/_authenticate.html.haml index fa998c91f72..f878bece2fa 100644 --- a/app/views/u2f/_authenticate.html.haml +++ b/app/views/u2f/_authenticate.html.haml @@ -1,30 +1,21 @@ #js-authenticate-u2f +%a.btn.btn-block.btn-info#js-login-2fa-device{ href: '#' } Sign in via 2FA code %script#js-authenticate-u2f-not-supported{ type: "text/template" } %p Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer). -%script#js-authenticate-u2f-setup{ type: "text/template" } - %div - %p Insert your security key (if you haven't already), and press the button below. - %a.btn.btn-info#js-login-u2f-device{ href: 'javascript:void(0)' } Sign in via U2F device - %script#js-authenticate-u2f-in-progress{ type: "text/template" } %p Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now. %script#js-authenticate-u2f-error{ type: "text/template" } %div %p <%= error_message %> (error code: <%= error_code %>) - %a.btn.btn-warning#js-u2f-try-again Try again? + %a.btn.btn-block.btn-warning#js-u2f-try-again Try again? %script#js-authenticate-u2f-authenticated{ type: "text/template" } %div - %p We heard back from your U2F device. Click this button to authenticate with the GitLab server. - = form_tag(new_user_session_path, method: :post) do |f| + %p We heard back from your U2F device. You have been authenticated. + = form_tag(new_user_session_path, method: :post, id: 'js-login-u2f-form') do |f| - resource_params = params[resource_name].presence || params = hidden_field_tag 'user[remember_me]', resource_params.fetch(:remember_me, 0) = hidden_field_tag 'user[device_response]', nil, class: 'form-control', required: true, id: "js-device-response" - = submit_tag "Authenticate via U2F Device", class: "btn btn-success" - -:javascript - var u2fAuthenticate = new U2FAuthenticate($("#js-authenticate-u2f"), gon.u2f); - u2fAuthenticate.start(); |