diff --git a/gulpfile.js b/gulpfile.js index 090cdd4f2a..f2ad7482d4 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -69,7 +69,8 @@ gulp.task('min:js', ['clean:js'], function () { [ paths.js, '!' + paths.minJs, - '!' + paths.webroot + 'js/fallback*.js' + '!' + paths.webroot + 'js/fallback*.js', + '!' + paths.webroot + 'js/u2f-connector.js' ], { base: '.' }) .pipe(concat(paths.concatJsDest)) .pipe(uglify()) @@ -323,6 +324,7 @@ gulp.task('dist:move', function () { paths.webroot + '**/app/**/*.html', paths.webroot + '**/images/**/*', paths.webroot + 'index.html', + paths.webroot + 'u2f-connector.html', paths.webroot + 'favicon.ico' ], dest: paths.dist @@ -378,6 +380,18 @@ gulp.task('dist:js:fallback', function () { .pipe(gulp.dest(paths.dist + 'js')); }); +gulp.task('dist:js:u2f', function () { + var mainStream = gulp + .src([ + paths.webroot + 'js/u2f*.js' + ]); + + merge(mainStream, config()) + .pipe(concat(paths.dist + '/js/u2f.min.js')) + .pipe(uglify()) + .pipe(gulp.dest('.')); +}); + gulp.task('dist:js:lib', function () { return gulp .src([ @@ -405,7 +419,7 @@ gulp.task('dist:preprocess', function () { gulp.task('dist', ['build'], function (cb) { return runSequence( 'dist:clean', - ['dist:move', 'dist:css', 'dist:js:app', 'dist:js:lib', 'dist:js:fallback'], + ['dist:move', 'dist:css', 'dist:js:app', 'dist:js:lib', 'dist:js:fallback', 'dist:js:u2f'], 'dist:preprocess', cb); }); diff --git a/src/js/u2f-api.js b/src/js/u2f-api.js index ff0f59e1ad..909aaf4518 100644 --- a/src/js/u2f-api.js +++ b/src/js/u2f-api.js @@ -18,6 +18,12 @@ */ var u2f = u2f || {}; +/** + * Modification: + * Check if browser supports U2F API before this wrapper was added. + */ +u2f.isSupported = ((typeof u2f !== 'undefined') && u2f.register) || (chrome && chrome.runtime); + /** * FIDO U2F Javascript API Version * @number diff --git a/src/js/u2f-connector.js b/src/js/u2f-connector.js new file mode 100644 index 0000000000..a8da989b9e --- /dev/null +++ b/src/js/u2f-connector.js @@ -0,0 +1,96 @@ +document.addEventListener('DOMContentLoaded', function (event) { + init(); +}); + +var parentUrl = null, + version = null; + +function init() { + info('initing'); + + if (!u2f.isSupported) { + error('U2F is not supported in this browser.'); + return; + } + + var data = getQsParam('data'); + if (!data) { + error('No data.'); + return; + } + + parentUrl = getQsParam('parent'); + if (!parentUrl) { + error('No parent.'); + return; + } + + var versionQs = getQsParam('v'); + if (!versionQs) { + error('No version.'); + return; + } + + try { + version = parseInt(versionQs); + var jsonString = b64Decode(data); + var json = JSON.parse(jsonString); + } + catch (e) { + error('Cannot parse data.'); + return; + } + + if (!json.appId || !json.challenge || !json.keys || !json.keys.length) { + error('Invalid data parameters.'); + return; + } + + initU2f(json); + info('ready'); +} + +function initU2f(obj) { + u2f.sign(obj.appId, obj.challenge, obj.keys, function (data) { + if (data.errorCode) { + if (data.errorCode === 5) { + initU2f(obj); + return; + } + + error('U2F Error: ' + data.errorCode); + return; + } + + success(data); + }, 5); +} + +function error(message) { + parent.postMessage('error|' + message, parentUrl); +} + +function success(data) { + var dataString = JSON.stringify(data); + parent.postMessage('success|' + dataString, parentUrl); +} + +function info(message) { + parent.postMessage('info|' + message, parentUrl); +} + +function getQsParam(name) { + var url = window.location.href; + name = name.replace(/[\[\]]/g, '\\$&'); + var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'), + results = regex.exec(url); + if (!results) return null; + if (!results[2]) return ''; + return decodeURIComponent(results[2].replace(/\+/g, ' ')); +} + +function b64Decode(str) { + return decodeURIComponent(Array.prototype.map.call(atob(str), function (c) { + return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); + }).join('')); +} diff --git a/src/u2f-connector.html b/src/u2f-connector.html new file mode 100644 index 0000000000..13ae06884a --- /dev/null +++ b/src/u2f-connector.html @@ -0,0 +1,16 @@ + + + + + U2F Connector + + + + + + + + +