Skip to content
Snippets Groups Projects
Commit d79df7ba authored by Mike Greiling's avatar Mike Greiling Committed by Jacob Schatz
Browse files

Remove u2f webpack bundle

parent 868c27de
No related branches found
No related tags found
No related merge requests found
Showing with 118 additions and 99 deletions
/* eslint-disable func-names, wrap-iife */
/* global u2f */
import _ from 'underscore';
import isU2FSupported from './util';
import importU2FLibrary from './util';
import U2FError from './error';
 
// Authenticate U2F (universal 2nd factor) devices for users to authenticate with.
Loading
Loading
@@ -10,6 +8,7 @@ import U2FError from './error';
// 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.renderNotSupported = this.renderNotSupported.bind(this);
this.renderAuthenticated = this.renderAuthenticated.bind(this);
Loading
Loading
@@ -50,22 +49,23 @@ export default class U2FAuthenticate {
}
 
start() {
if (isU2FSupported()) {
return this.renderInProgress();
}
return this.renderNotSupported();
return importU2FLibrary()
.then((utils) => {
this.u2fUtils = utils;
this.renderInProgress();
})
.catch(() => this.renderNotSupported());
}
 
authenticate() {
return u2f.sign(this.appId, this.challenge, this.signRequests, (function (_this) {
return function (response) {
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.renderError(error);
}
return _this.renderAuthenticated(JSON.stringify(response));
};
})(this), 10);
return this.renderAuthenticated(JSON.stringify(response));
}, 10);
}
 
renderTemplate(name, params) {
Loading
Loading
/* eslint-disable func-names, wrap-iife */
/* global u2f */
import _ from 'underscore';
import isU2FSupported from './util';
import importU2FLibrary from './util';
import U2FError from './error';
 
// Register U2F (universal 2nd factor) devices for users to authenticate with.
Loading
Loading
@@ -11,6 +8,7 @@ import U2FError from './error';
// 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);
Loading
Loading
@@ -34,22 +32,23 @@ export default class U2FRegister {
}
 
start() {
if (isU2FSupported()) {
return this.renderSetup();
}
return this.renderNotSupported();
return importU2FLibrary()
.then((utils) => {
this.u2fUtils = utils;
this.renderSetup();
})
.catch(() => this.renderNotSupported());
}
 
register() {
return u2f.register(this.appId, this.registerRequests, this.signRequests, (function (_this) {
return function (response) {
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.renderError(error);
}
return _this.renderRegistered(JSON.stringify(response));
};
})(this), 10);
return this.renderRegistered(JSON.stringify(response));
}, 10);
}
 
renderTemplate(name, params) {
Loading
Loading
export default function isU2FSupported() {
return window.u2f;
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();
}
module U2fHelper
def inject_u2f_api?
((browser.chrome? && browser.version.to_i >= 41) || (browser.opera? && browser.version.to_i >= 40)) && !browser.device.mobile?
end
end
- if inject_u2f_api?
- content_for :page_specific_javascripts do
= webpack_bundle_tag('u2f')
%div
= render 'devise/shared/tab_single', tab_title: 'Two-Factor Authentication'
.login-box
Loading
Loading
Loading
Loading
@@ -4,8 +4,6 @@
 
 
- content_for :page_specific_javascripts do
- if inject_u2f_api?
= webpack_bundle_tag('u2f')
= webpack_bundle_tag('two_factor_auth')
 
.js-two-factor-auth{ 'data-two-factor-skippable' => "#{two_factor_skippable?}", 'data-two_factor_skip_url' => skip_profile_two_factor_auth_path }
Loading
Loading
Loading
Loading
@@ -57,7 +57,6 @@ function generateEntries() {
ide: './ide/index.js',
raven: './raven/index.js',
test: './test.js',
u2f: ['vendor/u2f'],
webpack_runtime: './webpack.js',
};
 
Loading
Loading
Loading
Loading
@@ -19,6 +19,7 @@ module Gitlab
gon.gitlab_logo = ActionController::Base.helpers.asset_path('gitlab_logo.png')
gon.sprite_icons = IconsHelper.sprite_icon_path
gon.sprite_file_icons = IconsHelper.sprite_file_icons_path
gon.test_env = Rails.env.test?
 
if current_user
gon.current_user_id = current_user.id
Loading
Loading
require 'spec_helper'
 
feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do
before do
allow_any_instance_of(U2fHelper).to receive(:inject_u2f_api?).and_return(true)
end
def manage_two_factor_authentication
click_on 'Manage two-factor authentication'
expect(page).to have_content("Setup new U2F device")
Loading
Loading
require 'spec_helper'
describe U2fHelper do
describe 'when not on mobile' do
it 'does not inject u2f on chrome 40' do
device = double(mobile?: false)
browser = double(chrome?: true, opera?: false, version: 40, device: device)
allow(helper).to receive(:browser).and_return(browser)
expect(helper.inject_u2f_api?).to eq false
end
it 'injects u2f on chrome 41' do
device = double(mobile?: false)
browser = double(chrome?: true, opera?: false, version: 41, device: device)
allow(helper).to receive(:browser).and_return(browser)
expect(helper.inject_u2f_api?).to eq true
end
it 'does not inject u2f on opera 39' do
device = double(mobile?: false)
browser = double(chrome?: false, opera?: true, version: 39, device: device)
allow(helper).to receive(:browser).and_return(browser)
expect(helper.inject_u2f_api?).to eq false
end
it 'injects u2f on opera 40' do
device = double(mobile?: false)
browser = double(chrome?: false, opera?: true, version: 40, device: device)
allow(helper).to receive(:browser).and_return(browser)
expect(helper.inject_u2f_api?).to eq true
end
end
describe 'when on mobile' do
it 'does not inject u2f on chrome 41' do
device = double(mobile?: true)
browser = double(chrome?: true, opera?: false, version: 41, device: device)
allow(helper).to receive(:browser).and_return(browser)
expect(helper.inject_u2f_api?).to eq false
end
it 'does not inject u2f on opera 40' do
device = double(mobile?: true)
browser = double(chrome?: false, opera?: true, version: 40, device: device)
allow(helper).to receive(:browser).and_return(browser)
expect(helper.inject_u2f_api?).to eq false
end
end
end
Loading
Loading
@@ -37,6 +37,7 @@ window.$ = window.jQuery = $;
window.gl = window.gl || {};
window.gl.TEST_HOST = 'http://test.host';
window.gon = window.gon || {};
window.gon.test_env = true;
 
let hasUnhandledPromiseRejections = false;
 
Loading
Loading
Loading
Loading
@@ -5,7 +5,7 @@ import MockU2FDevice from './mock_u2f_device';
describe('U2FAuthenticate', () => {
preloadFixtures('u2f/authenticate.html.raw');
 
beforeEach(() => {
beforeEach((done) => {
loadFixtures('u2f/authenticate.html.raw');
this.u2fDevice = new MockU2FDevice();
this.container = $('#js-authenticate-u2f');
Loading
Loading
@@ -22,7 +22,7 @@ describe('U2FAuthenticate', () => {
// bypass automatic form submission within renderAuthenticated
spyOn(this.component, 'renderAuthenticated').and.returnValue(true);
 
return this.component.start();
this.component.start().then(done).catch(done.fail);
});
 
it('allows authenticating via a U2F device', () => {
Loading
Loading
@@ -34,7 +34,7 @@ describe('U2FAuthenticate', () => {
expect(this.component.renderAuthenticated).toHaveBeenCalledWith('{"deviceData":"this is data from the device"}');
});
 
return describe('errors', () => {
describe('errors', () => {
it('displays an error message', () => {
const setupButton = this.container.find('#js-login-u2f-device');
setupButton.trigger('click');
Loading
Loading
Loading
Loading
@@ -5,12 +5,12 @@ import MockU2FDevice from './mock_u2f_device';
describe('U2FRegister', () => {
preloadFixtures('u2f/register.html.raw');
 
beforeEach(() => {
beforeEach((done) => {
loadFixtures('u2f/register.html.raw');
this.u2fDevice = new MockU2FDevice();
this.container = $('#js-register-u2f');
this.component = new U2FRegister(this.container, $('#js-register-u2f-templates'), {}, 'token');
return this.component.start();
this.component.start().then(done).catch(done.fail);
});
 
it('allows registering a U2F device', () => {
Loading
Loading
import { canInjectU2fApi } from '~/u2f/util';
describe('U2F Utils', () => {
describe('canInjectU2fApi', () => {
it('returns false for Chrome < 41', () => {
const userAgent = 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.28 Safari/537.36';
expect(canInjectU2fApi(userAgent)).toBe(false);
});
it('returns true for Chrome >= 41', () => {
const userAgent = 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36';
expect(canInjectU2fApi(userAgent)).toBe(true);
});
it('returns false for Opera < 40', () => {
const userAgent = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36 OPR/32.0.1948.25';
expect(canInjectU2fApi(userAgent)).toBe(false);
});
it('returns true for Opera >= 40', () => {
const userAgent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.991';
expect(canInjectU2fApi(userAgent)).toBe(true);
});
it('returns false for Safari', () => {
const userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/603.2.4 (KHTML, like Gecko) Version/10.1.1 Safari/603.2.4';
expect(canInjectU2fApi(userAgent)).toBe(false);
});
it('returns false for Chrome on Android', () => {
const userAgent = 'Mozilla/5.0 (Linux; Android 7.0; VS988 Build/NRD90U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3145.0 Mobile Safari/537.36';
expect(canInjectU2fApi(userAgent)).toBe(false);
});
it('returns false for Chrome on iOS', () => {
const userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e Safari/602.1';
expect(canInjectU2fApi(userAgent)).toBe(false);
});
it('returns false for Safari on iOS', () => {
const userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A356 Safari/604.1';
expect(canInjectU2fApi(userAgent)).toBe(false);
});
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment