BigW Consortium Gitlab
Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
gitlab-ce
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Forest Godfrey
gitlab-ce
Commits
41b430b2
Unverified
Commit
41b430b2
authored
Oct 09, 2017
by
Filipa Lacerda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove u2f from globalnamespace
parent
d6170ce4
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
321 additions
and
374 deletions
+321
-374
dispatcher.js
app/assets/javascripts/dispatcher.js
+5
-2
main.js
app/assets/javascripts/main.js
+0
-6
two_factor_auth.js
app/assets/javascripts/two_factor_auth.js
+2
-1
authenticate.js
app/assets/javascripts/u2f/authenticate.js
+89
-99
error.js
app/assets/javascripts/u2f/error.js
+20
-23
register.js
app/assets/javascripts/u2f/register.js
+71
-80
util.js
app/assets/javascripts/u2f/util.js
+3
-12
authenticate_spec.js
spec/javascripts/u2f/authenticate_spec.js
+50
-59
mock_u2f_device.js
spec/javascripts/u2f/mock_u2f_device.js
+25
-28
register_spec.js
spec/javascripts/u2f/register_spec.js
+56
-64
No files found.
app/assets/javascripts/dispatcher.js
View file @
41b430b2
...
@@ -78,6 +78,7 @@ import initChangesDropdown from './init_changes_dropdown';
...
@@ -78,6 +78,7 @@ import initChangesDropdown from './init_changes_dropdown';
import
AbuseReports
from
'./abuse_reports'
;
import
AbuseReports
from
'./abuse_reports'
;
import
{
ajaxGet
,
convertPermissionToBoolean
}
from
'./lib/utils/common_utils'
;
import
{
ajaxGet
,
convertPermissionToBoolean
}
from
'./lib/utils/common_utils'
;
import
AjaxLoadingSpinner
from
'./ajax_loading_spinner'
;
import
AjaxLoadingSpinner
from
'./ajax_loading_spinner'
;
import
U2FAuthenticate
from
'./u2f/authenticate'
;
(
function
()
{
(
function
()
{
var
Dispatcher
;
var
Dispatcher
;
...
@@ -535,14 +536,16 @@ import AjaxLoadingSpinner from './ajax_loading_spinner';
...
@@ -535,14 +536,16 @@ import AjaxLoadingSpinner from './ajax_loading_spinner';
case
'sessions'
:
case
'sessions'
:
case
'omniauth_callbacks'
:
case
'omniauth_callbacks'
:
if
(
!
gon
.
u2f
)
break
;
if
(
!
gon
.
u2f
)
break
;
gl
.
u2fAuthenticate
=
new
gl
.
U2FAuthenticate
(
const
u2fAuthenticate
=
new
U2FAuthenticate
(
$
(
'#js-authenticate-u2f'
),
$
(
'#js-authenticate-u2f'
),
'#js-login-u2f-form'
,
'#js-login-u2f-form'
,
gon
.
u2f
,
gon
.
u2f
,
document
.
querySelector
(
'#js-login-2fa-device'
),
document
.
querySelector
(
'#js-login-2fa-device'
),
document
.
querySelector
(
'.js-2fa-form'
),
document
.
querySelector
(
'.js-2fa-form'
),
);
);
gl
.
u2fAuthenticate
.
start
();
u2fAuthenticate
.
start
();
// needed in rspec
gl
.
u2fAuthenticate
=
u2fAuthenticate
;
case
'admin'
:
case
'admin'
:
new
Admin
();
new
Admin
();
switch
(
path
[
1
])
{
switch
(
path
[
1
])
{
...
...
app/assets/javascripts/main.js
View file @
41b430b2
...
@@ -47,12 +47,6 @@ import './lib/utils/url_utility';
...
@@ -47,12 +47,6 @@ import './lib/utils/url_utility';
// behaviors
// behaviors
import
'./behaviors/'
;
import
'./behaviors/'
;
// u2f
import
'./u2f/authenticate'
;
import
'./u2f/error'
;
import
'./u2f/register'
;
import
'./u2f/util'
;
// everything else
// everything else
import
'./activities'
;
import
'./activities'
;
import
'./admin'
;
import
'./admin'
;
...
...
app/assets/javascripts/two_factor_auth.js
View file @
41b430b2
/* global U2FRegister */
import
U2FRegister
from
'./u2f/register'
;
document
.
addEventListener
(
'DOMContentLoaded'
,
()
=>
{
document
.
addEventListener
(
'DOMContentLoaded'
,
()
=>
{
const
twoFactorNode
=
document
.
querySelector
(
'.js-two-factor-auth'
);
const
twoFactorNode
=
document
.
querySelector
(
'.js-two-factor-auth'
);
const
skippable
=
twoFactorNode
.
dataset
.
twoFactorSkippable
===
'true'
;
const
skippable
=
twoFactorNode
.
dataset
.
twoFactorSkippable
===
'true'
;
...
...
app/assets/javascripts/u2f/authenticate.js
View file @
41b430b2
/* eslint-disable func-names,
space-before-function-paren, no-var, prefer-rest-params, wrap-iife, prefer-arrow-callback, no-else-return, quotes, quote-props, comma-dangle, one-var, one-var-declaration-per-line, max-len
*/
/* eslint-disable func-names,
wrap-iife
*/
/* global u2f */
/* global u2f */
/* global U2FError */
/* global U2FUtil */
import
_
from
'underscore'
;
import
_
from
'underscore'
;
import
isU2FSupported
from
'./util'
;
import
U2FError
from
'./error'
;
// Authenticate U2F (universal 2nd factor) devices for users to authenticate with.
// Authenticate U2F (universal 2nd factor) devices for users to authenticate with.
//
//
// State Flow #1: setup -> in_progress -> authenticated -> POST to server
// State Flow #1: setup -> in_progress -> authenticated -> POST to server
// State Flow #2: setup -> in_progress -> error -> setup
// State Flow #2: setup -> in_progress -> error -> setup
(
function
()
{
export
default
class
U2FAuthenticate
{
const
global
=
window
.
gl
||
(
window
.
gl
=
{});
constructor
(
container
,
form
,
u2fParams
,
fallbackButton
,
fallbackUI
)
{
this
.
container
=
container
;
global
.
U2FAuthenticate
=
(
function
()
{
this
.
renderNotSupported
=
this
.
renderNotSupported
.
bind
(
this
);
function
U2FAuthenticate
(
container
,
form
,
u2fParams
,
fallbackButton
,
fallbackUI
)
{
this
.
renderAuthenticated
=
this
.
renderAuthenticated
.
bind
(
this
);
this
.
container
=
container
;
this
.
renderError
=
this
.
renderError
.
bind
(
this
);
this
.
renderNotSupported
=
this
.
renderNotSupported
.
bind
(
this
);
this
.
renderInProgress
=
this
.
renderInProgress
.
bind
(
this
);
this
.
renderAuthenticated
=
this
.
renderAuthenticated
.
bind
(
this
);
this
.
renderTemplate
=
this
.
renderTemplate
.
bind
(
this
);
this
.
renderError
=
this
.
renderError
.
bind
(
this
);
this
.
authenticate
=
this
.
authenticate
.
bind
(
this
);
this
.
renderInProgress
=
this
.
renderInProgress
.
bind
(
this
);
this
.
start
=
this
.
start
.
bind
(
this
);
this
.
renderTemplate
=
this
.
renderTemplate
.
bind
(
this
);
this
.
appId
=
u2fParams
.
app_id
;
this
.
authenticate
=
this
.
authenticate
.
bind
(
this
);
this
.
challenge
=
u2fParams
.
challenge
;
this
.
start
=
this
.
start
.
bind
(
this
);
this
.
form
=
form
;
this
.
appId
=
u2fParams
.
app_id
;
this
.
fallbackButton
=
fallbackButton
;
this
.
challenge
=
u2fParams
.
challenge
;
this
.
fallbackUI
=
fallbackUI
;
this
.
form
=
form
;
if
(
this
.
fallbackButton
)
{
this
.
fallbackButton
=
fallbackButton
;
this
.
fallbackButton
.
addEventListener
(
'click'
,
this
.
switchToFallbackUI
.
bind
(
this
));
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
// 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
return
_
(
request
).
omit
(
'challenge'
);
});
}
}
U2FAuthenticate
.
prototype
.
start
=
function
()
{
// The U2F Javascript API v1.1 requires a single challenge, with
if
(
U2FUtil
.
isU2FSupported
())
{
// _no challenges per-request_. The U2F Javascript API v1.0 requires a
return
this
.
renderInProgress
();
// challenge per-request, which is done by copying the single challenge
}
else
{
// into every request.
return
this
.
renderNotSupported
();
//
}
// 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
=>
_
(
request
).
omit
(
'challenge'
));
U2FAuthenticate
.
prototype
.
authenticate
=
function
()
{
this
.
templates
=
{
return
u2f
.
sign
(
this
.
appId
,
this
.
challenge
,
this
.
signRequests
,
(
function
(
_this
)
{
notSupported
:
'#js-authenticate-u2f-not-supported'
,
return
function
(
response
)
{
setup
:
'#js-authenticate-u2f-setup'
,
var
error
;
inProgress
:
'#js-authenticate-u2f-in-progress'
,
if
(
response
.
errorCode
)
{
error
:
'#js-authenticate-u2f-error'
,
error
=
new
U2FError
(
response
.
errorCode
,
'authenticate'
);
authenticated
:
'#js-authenticate-u2f-authenticated'
,
return
_this
.
renderError
(
error
);
}
else
{
return
_this
.
renderAuthenticated
(
JSON
.
stringify
(
response
));
}
};
})(
this
),
10
);
};
};
}
// Rendering #
start
()
{
U2FAuthenticate
.
prototype
.
templates
=
{
if
(
isU2FSupported
())
{
"notSupported"
:
"#js-authenticate-u2f-not-supported"
,
return
this
.
renderInProgress
();
"setup"
:
'#js-authenticate-u2f-setup'
,
}
"inProgress"
:
'#js-authenticate-u2f-in-progress'
,
return
this
.
renderNotSupported
();
"error"
:
'#js-authenticate-u2f-error'
,
}
"authenticated"
:
'#js-authenticate-u2f-authenticated'
};
U2FAuthenticate
.
prototype
.
renderTemplate
=
function
(
name
,
params
)
{
authenticate
()
{
var
template
,
templateString
;
return
u2f
.
sign
(
this
.
appId
,
this
.
challenge
,
this
.
signRequests
,
(
function
(
_this
)
{
templateString
=
$
(
this
.
templates
[
name
]).
html
();
return
function
(
response
)
{
template
=
_
.
template
(
templateString
);
if
(
response
.
errorCode
)
{
return
this
.
container
.
html
(
template
(
params
));
const
error
=
new
U2FError
(
response
.
errorCode
,
'authenticate'
);
};
return
_this
.
renderError
(
error
);
}
return
_this
.
renderAuthenticated
(
JSON
.
stringify
(
response
));
};
})(
this
),
10
);
}
U2FAuthenticate
.
prototype
.
renderInProgress
=
function
()
{
renderTemplate
(
name
,
params
)
{
this
.
renderTemplate
(
'inProgress'
);
const
templateString
=
$
(
this
.
templates
[
name
]).
html
();
return
this
.
authenticate
();
const
template
=
_
.
template
(
templateString
);
};
return
this
.
container
.
html
(
template
(
params
));
}
U2FAuthenticate
.
prototype
.
renderError
=
function
(
error
)
{
renderInProgress
()
{
this
.
renderTemplate
(
'error'
,
{
this
.
renderTemplate
(
'inProgress'
);
error_message
:
error
.
message
(),
return
this
.
authenticate
();
error_code
:
error
.
errorCode
}
});
return
this
.
container
.
find
(
'#js-u2f-try-again'
).
on
(
'click'
,
this
.
renderInProgress
);
};
U2FAuthenticate
.
prototype
.
renderAuthenticated
=
function
(
deviceResponse
)
{
renderError
(
error
)
{
this
.
renderTemplate
(
'authenticated'
);
this
.
renderTemplate
(
'error'
,
{
const
container
=
this
.
container
[
0
];
error_message
:
error
.
message
(),
container
.
querySelector
(
'#js-device-response'
).
value
=
deviceResponse
;
error_code
:
error
.
errorCode
,
container
.
querySelector
(
this
.
form
).
submit
(
);
}
);
this
.
fallbackButton
.
classList
.
add
(
'hidden'
);
return
this
.
container
.
find
(
'#js-u2f-try-again'
).
on
(
'click'
,
this
.
renderInProgress
);
};
}
U2FAuthenticate
.
prototype
.
renderNotSupported
=
function
()
{
renderAuthenticated
(
deviceResponse
)
{
return
this
.
renderTemplate
(
'notSupported'
);
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'
);
}
U2FAuthenticate
.
prototype
.
switchToFallbackUI
=
function
()
{
renderNotSupported
()
{
this
.
fallbackButton
.
classList
.
add
(
'hidden'
);
return
this
.
renderTemplate
(
'notSupported'
);
this
.
container
[
0
].
classList
.
add
(
'hidden'
);
}
this
.
fallbackUI
.
classList
.
remove
(
'hidden'
);
};
switchToFallbackUI
()
{
this
.
fallbackButton
.
classList
.
add
(
'hidden'
);
this
.
container
[
0
].
classList
.
add
(
'hidden'
);
this
.
fallbackUI
.
classList
.
remove
(
'hidden'
);
}
return
U2FAuthenticate
;
}
})();
})();
app/assets/javascripts/u2f/error.js
View file @
41b430b2
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-console, quotes, prefer-template, max-len */
export
default
class
U2FError
{
/* global u2f */
constructor
(
errorCode
,
u2fFlowType
)
{
this
.
errorCode
=
errorCode
;
this
.
message
=
this
.
message
.
bind
(
this
);
this
.
httpsDisabled
=
window
.
location
.
protocol
!==
'https:'
;
this
.
u2fFlowType
=
u2fFlowType
;
}
(
function
()
{
message
()
{
this
.
U2FError
=
(
function
()
{
if
(
this
.
errorCode
===
window
.
u2f
.
ErrorCodes
.
BAD_REQUEST
&&
this
.
httpsDisabled
)
{
function
U2FError
(
errorCode
,
u2fFlowType
)
{
return
'U2F only works with HTTPS-enabled websites. Contact your administrator for more details.'
;
this
.
errorCode
=
errorCode
;
}
else
if
(
this
.
errorCode
===
window
.
u2f
.
ErrorCodes
.
DEVICE_INELIGIBLE
)
{
this
.
message
=
this
.
message
.
bind
(
this
);
if
(
this
.
u2fFlowType
===
'authenticate'
)
{
this
.
httpsDisabled
=
window
.
location
.
protocol
!==
'https:'
;
return
'This device has not been registered with us.'
;
this
.
u2fFlowType
=
u2fFlowType
;
}
U2FError
.
prototype
.
message
=
function
()
{
if
(
this
.
errorCode
===
u2f
.
ErrorCodes
.
BAD_REQUEST
&&
this
.
httpsDisabled
)
{
return
'U2F only works with HTTPS-enabled websites. Contact your administrator for more details.'
;
}
else
if
(
this
.
errorCode
===
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."
;
if
(
this
.
u2fFlowType
===
'register'
)
{
};
return
'This device has already been registered with us.'
;
}
return
U2FError
;
}
})();
return
'There was a problem communicating with your device.'
;
}).
call
(
window
);
}
}
app/assets/javascripts/u2f/register.js
View file @
41b430b2
/* eslint-disable func-names,
space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-else-return, quotes, quote-props, comma-dangle, one-var, one-var-declaration-per-line, max-len
*/
/* eslint-disable func-names,
wrap-iife
*/
/* global u2f */
/* global u2f */
/* global U2FError */
/* global U2FUtil */
import
_
from
'underscore'
;
import
_
from
'underscore'
;
import
isU2FSupported
from
'./util'
;
import
U2FError
from
'./error'
;
// Register U2F (universal 2nd factor) devices for users to authenticate with.
// Register U2F (universal 2nd factor) devices for users to authenticate with.
//
//
// State Flow #1: setup -> in_progress -> registered -> POST to server
// State Flow #1: setup -> in_progress -> registered -> POST to server
// State Flow #2: setup -> in_progress -> error -> setup
// State Flow #2: setup -> in_progress -> error -> setup
(
function
()
{
export
default
class
U2FRegister
{
this
.
U2FRegister
=
(
function
()
{
constructor
(
container
,
u2fParams
)
{
function
U2FRegister
(
container
,
u2fParams
)
{
this
.
container
=
container
;
this
.
container
=
container
;
this
.
renderNotSupported
=
this
.
renderNotSupported
.
bind
(
this
);
this
.
renderNotSupported
=
this
.
renderNotSupported
.
bind
(
this
);
this
.
renderRegistered
=
this
.
renderRegistered
.
bind
(
this
);
this
.
renderRegistered
=
this
.
renderRegistered
.
bind
(
this
);
this
.
renderError
=
this
.
renderError
.
bind
(
this
);
this
.
renderError
=
this
.
renderError
.
bind
(
this
);
this
.
renderInProgress
=
this
.
renderInProgress
.
bind
(
this
);
this
.
renderInProgress
=
this
.
renderInProgress
.
bind
(
this
);
this
.
renderSetup
=
this
.
renderSetup
.
bind
(
this
);
this
.
renderSetup
=
this
.
renderSetup
.
bind
(
this
);
this
.
renderTemplate
=
this
.
renderTemplate
.
bind
(
this
);
this
.
renderTemplate
=
this
.
renderTemplate
.
bind
(
this
);
this
.
register
=
this
.
register
.
bind
(
this
);
this
.
register
=
this
.
register
.
bind
(
this
);
this
.
start
=
this
.
start
.
bind
(
this
);
this
.
start
=
this
.
start
.
bind
(
this
);
this
.
appId
=
u2fParams
.
app_id
;
this
.
appId
=
u2fParams
.
app_id
;
this
.
registerRequests
=
u2fParams
.
register_requests
;
this
.
registerRequests
=
u2fParams
.
register_requests
;
this
.
signRequests
=
u2fParams
.
sign_requests
;
this
.
signRequests
=
u2fParams
.
sign_requests
;
}
U2FRegister
.
prototype
.
start
=
function
()
{
this
.
templates
=
{
if
(
U2FUtil
.
isU2FSupported
())
{
notSupported
:
'#js-register-u2f-not-supported'
,
return
this
.
renderSetup
();
setup
:
'#js-register-u2f-setup'
,
}
else
{
inProgress
:
'#js-register-u2f-in-progress'
,
return
this
.
renderNotSupported
();
error
:
'#js-register-u2f-error'
,
}
registered
:
'#js-register-u2f-registered'
,
};
};
}
U2FRegister
.
prototype
.
register
=
function
()
{
start
()
{
return
u2f
.
register
(
this
.
appId
,
this
.
registerRequests
,
this
.
signRequests
,
(
function
(
_this
)
{
if
(
isU2FSupported
())
{
return
function
(
response
)
{
return
this
.
renderSetup
();
var
error
;
}
if
(
response
.
errorCode
)
{
return
this
.
renderNotSupported
();
error
=
new
U2FError
(
response
.
errorCode
,
'register'
);
}
return
_this
.
renderError
(
error
);
}
else
{
return
_this
.
renderRegistered
(
JSON
.
stringify
(
response
));
}
};
})(
this
),
10
);
};
// Rendering #
register
()
{
U2FRegister
.
prototype
.
templates
=
{
return
u2f
.
register
(
this
.
appId
,
this
.
registerRequests
,
this
.
signRequests
,
(
function
(
_this
)
{
"notSupported"
:
"#js-register-u2f-not-supported"
,
return
function
(
response
)
{
"setup"
:
'#js-register-u2f-setup'
,
if
(
response
.
errorCode
)
{
"inProgress"
:
'#js-register-u2f-in-progress'
,
const
error
=
new
U2FError
(
response
.
errorCode
,
'register'
);
"error"
:
'#js-register-u2f-error'
,
return
_this
.
renderError
(
error
);
"registered"
:
'#js-register-u2f-registered'
}
};
return
_this
.
renderRegistered
(
JSON
.
stringify
(
response
));
};
})(
this
),
10
);
}
U2FRegister
.
prototype
.
renderTemplate
=
function
(
name
,
params
)
{
renderTemplate
(
name
,
params
)
{
var
template
,
templateString
;
const
templateString
=
$
(
this
.
templates
[
name
]).
html
();
templateString
=
$
(
this
.
templates
[
name
]).
html
();
const
template
=
_
.
template
(
templateString
);
template
=
_
.
template
(
templateString
);
return
this
.
container
.
html
(
template
(
params
));
return
this
.
container
.
html
(
template
(
params
));
}
};
U2FRegister
.
prototype
.
renderSetup
=
function
()
{
renderSetup
()
{
this
.
renderTemplate
(
'setup'
);
this
.
renderTemplate
(
'setup'
);
return
this
.
container
.
find
(
'#js-setup-u2f-device'
).
on
(
'click'
,
this
.
renderInProgress
);
return
this
.
container
.
find
(
'#js-setup-u2f-device'
).
on
(
'click'
,
this
.
renderInProgress
);
};
}
U2FRegister
.
prototype
.
renderInProgress
=
function
()
{
renderInProgress
()
{
this
.
renderTemplate
(
'inProgress'
);
this
.
renderTemplate
(
'inProgress'
);
return
this
.
register
();
return
this
.
register
();
};
}
U2FRegister
.
prototype
.
renderError
=
function
(
error
)
{
renderError
(
error
)
{
this
.
renderTemplate
(
'error'
,
{
this
.
renderTemplate
(
'error'
,
{
error_message
:
error
.
message
(),
error_message
:
error
.
message
(),
error_code
:
error
.
errorCode
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
.
renderSetup
);
};
}
U2FRegister
.
prototype
.
renderRegistered
=
function
(
deviceResponse
)
{
renderRegistered
(
deviceResponse
)
{
this
.
renderTemplate
(
'registered'
);
this
.
renderTemplate
(
'registered'
);
// Prefer to do this instead of interpolating using Underscore templates
// Prefer to do this instead of interpolating using Underscore templates
// because of JSON escaping issues.
// because of JSON escaping issues.
return
this
.
container
.
find
(
"#js-device-response"
).
val
(
deviceResponse
);
return
this
.
container
.
find
(
'#js-device-response'
).
val
(
deviceResponse
);
};
}
U2FRegister
.
prototype
.
renderNotSupported
=
function
()
{
return
this
.
renderTemplate
(
'notSupported'
);
};
return
U2FRegister
;
renderNotSupported
()
{
})();
return
this
.
renderTemplate
(
'notSupported'
);
}).
call
(
window
);
}
}
app/assets/javascripts/u2f/util.js
View file @
41b430b2
/* eslint-disable func-names, space-before-function-paren, wrap-iife */
export
default
function
isU2FSupported
()
{
(
function
()
{
return
window
.
u2f
;
this
.
U2FUtil
=
(
function
()
{
}
function
U2FUtil
()
{}
U2FUtil
.
isU2FSupported
=
function
()
{
return
window
.
u2f
;
};
return
U2FUtil
;
})();
}).
call
(
window
);
spec/javascripts/u2f/authenticate_spec.js
View file @
41b430b2
/* eslint-disable space-before-function-paren, new-parens, quotes, comma-dangle, no-var, one-var, one-var-declaration-per-line, max-len */
import
U2FAuthenticate
from
'~/u2f/authenticate'
;
/* global MockU2FDevice */
/* global U2FAuthenticate */
import
'~/u2f/authenticate'
;
import
'~/u2f/util'
;
import
'~/u2f/error'
;
import
'vendor/u2f'
;
import
'vendor/u2f'
;
import
'./mock_u2f_device'
;
import
MockU2FDevice
from
'./mock_u2f_device'
;
describe
(
'U2FAuthenticate'
,
()
=>
{
preloadFixtures
(
'u2f/authenticate.html.raw'
);
(
function
()
{
beforeEach
(()
=>
{
describe
(
'U2FAuthenticate'
,
function
()
{
loadFixtures
(
'u2f/authenticate.html.raw'
);
preloadFixtures
(
'u2f/authenticate.html.raw'
);
this
.
u2fDevice
=
new
MockU2FDevice
();
this
.
container
=
$
(
'#js-authenticate-u2f'
);
this
.
component
=
new
U2FAuthenticate
(
this
.
container
,
'#js-login-u2f-form'
,
{
sign_requests
:
[],
},
document
.
querySelector
(
'#js-login-2fa-device'
),
document
.
querySelector
(
'.js-2fa-form'
),
);
beforeEach
(
function
()
{
// bypass automatic form submission within renderAuthenticated
loadFixtures
(
'u2f/authenticate.html.raw'
);
spyOn
(
this
.
component
,
'renderAuthenticated'
).
and
.
returnValue
(
true
);
this
.
u2fDevice
=
new
MockU2FDevice
;
this
.
container
=
$
(
"#js-authenticate-u2f"
);
this
.
component
=
new
window
.
gl
.
U2FAuthenticate
(
this
.
container
,
'#js-login-u2f-form'
,
{
sign_requests
:
[]
},
document
.
querySelector
(
'#js-login-2fa-device'
),
document
.
querySelector
(
'.js-2fa-form'
)
);
// bypass automatic form submission within renderAuthenticated
return
this
.
component
.
start
();
spyOn
(
this
.
component
,
'renderAuthenticated'
).
and
.
returnValue
(
true
);
}
);
return
this
.
component
.
start
();
it
(
'allows authenticating via a U2F device'
,
()
=>
{
const
inProgressMessage
=
this
.
container
.
find
(
'p'
);
expect
(
inProgressMessage
.
text
()).
toContain
(
'Trying to communicate with your device'
);
this
.
u2fDevice
.
respondToAuthenticateRequest
({
deviceData
:
'this is data from the device'
,
});
});
it
(
'allows authenticating via a U2F device'
,
function
()
{
expect
(
this
.
component
.
renderAuthenticated
).
toHaveBeenCalledWith
(
'{"deviceData":"this is data from the device"}'
);
var
inProgressMessage
;
});
inProgressMessage
=
this
.
container
.
find
(
"p"
);
expect
(
inProgressMessage
.
text
()).
toContain
(
"Trying to communicate with your device"
);
return
describe
(
'errors'
,
()
=>
{
it
(
'displays an error message'
,
()
=>
{
const
setupButton
=
this
.
container
.
find
(
'#js-login-u2f-device'
);
setupButton
.
trigger
(
'click'
);
this
.
u2fDevice
.
respondToAuthenticateRequest
({
this
.
u2fDevice
.
respondToAuthenticateRequest
({
deviceData
:
"this is data from the device"
errorCode
:
'error!'
,
});
});
expect
(
this
.
component
.
renderAuthenticated
).
toHaveBeenCalledWith
(
'{"deviceData":"this is data from the device"}'
);
const
errorMessage
=
this
.
container
.
find
(
'p'
);
return
expect
(
errorMessage
.
text
()).
toContain
(
'There was a problem communicating with your device'
);
});
});
return
describe
(
"errors"
,
function
()
{
return
it
(
'allows retrying authentication after an error'
,
()
=>
{
it
(
"displays an error message"
,
function
()
{
let
setupButton
=
this
.
container
.
find
(
'#js-login-u2f-device'
);
var
errorMessage
,
setupButton
;
setupButton
.
trigger
(
'click'
);
setupButton
=
this
.
container
.
find
(
"#js-login-u2f-device"
);
this
.
u2fDevice
.
respondToAuthenticateRequest
({
setupButton
.
trigger
(
'click'
);
errorCode
:
'error!'
,
this
.
u2fDevice
.
respondToAuthenticateRequest
({
errorCode
:
"error!"
});
errorMessage
=
this
.
container
.
find
(
"p"
);
return
expect
(
errorMessage
.
text
()).
toContain
(
"There was a problem communicating with your device"
);
});
});
return
it
(
"allows retrying authentication after an error"
,
function
()
{
const
retryButton
=
this
.
container
.
find
(
'#js-u2f-try-again'
);
var
retryButton
,
setupButton
;
retryButton
.
trigger
(
'click'
);
setupButton
=
this
.
container
.
find
(
"#js-login-u2f-device"
);
setupButton
=
this
.
container
.
find
(
'#js-login-u2f-device'
);
setupButton
.
trigger
(
'click'
);
setupButton
.
trigger
(
'click'
);
this
.
u2fDevice
.
respondToAuthenticateRequest
({
this
.
u2fDevice
.
respondToAuthenticateRequest
({
errorCode
:
"error!"
deviceData
:
'this is data from the device'
,
});
retryButton
=
this
.
container
.
find
(
"#js-u2f-try-again"
);
retryButton
.
trigger
(
'click'
);
setupButton
=
this
.
container
.
find
(
"#js-login-u2f-device"
);
setupButton
.
trigger
(
'click'
);
this
.
u2fDevice
.
respondToAuthenticateRequest
({
deviceData
:
"this is data from the device"
});
expect
(
this
.
component
.
renderAuthenticated
).
toHaveBeenCalledWith
(
'{"deviceData":"this is data from the device"}'
);
});
});
expect
(
this
.
component
.
renderAuthenticated
).
toHaveBeenCalledWith
(
'{"deviceData":"this is data from the device"}'
);
});
});
});
});
})
.
call
(
window
)
;
});
spec/javascripts/u2f/mock_u2f_device.js
View file @
41b430b2
/* eslint-disable space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-unused-expressions, no-return-assign, no-param-reassign, max-len */
/* eslint-disable prefer-rest-params, wrap-iife,
no-unused-expressions, no-return-assign, no-param-reassign*/
(
function
()
{
export
default
class
MockU2FDevice
{
this
.
MockU2FDevice
=
(
function
()
{
constructor
()
{
function
MockU2FDevice
()
{
this
.
respondToAuthenticateRequest
=
this
.
respondToAuthenticateRequest
.
bind
(
this
);
this
.
respondToAuthenticateRequest
=
this
.
respondToAuthenticateRequest
.
bind
(
this
);
this
.
respondToRegisterRequest
=
this
.
respondToRegisterRequest
.
bind
(
this
);
this
.
respondToRegisterRequest
=
this
.
respondToRegisterRequest
.
bind
(
this
);
window
.
u2f
||
(
window
.
u2f
=
{});
window
.
u2f
||
(
window
.
u2f
=
{});
window
.
u2f
.
register
=
(
function
(
_this
)
{
window
.
u2f
.
register
=
(
function
(
_this
)
{
return
function
(
appId
,
registerRequests
,
signRequests
,
callback
)
{
return
function
(
appId
,
registerRequests
,
signRequests
,
callback
)
{
return
_this
.
registerCallback
=
callback
;
return
_this
.
registerCallback
=
callback
;
};
};
})(
this
);
})(
this
);
window
.
u2f
.
sign
=
(
function
(
_this
)
{
window
.
u2f
.
sign
=
(
function
(
_this
)
{
return
function
(
appId
,
challenges
,
signRequests
,
callback
)
{
return
function
(
appId
,
challenges
,
signRequests
,
callback
)
{
return
_this
.
authenticateCallback
=
callback
;
return
_this
.
authenticateCallback
=
callback
;
};
};
})(
this
);
})(
this
);
}
}
MockU2FDevice
.
prototype
.
respondToRegisterRequest
=
function
(
params
)
{
respondToRegisterRequest
(
params
)
{
return
this
.
registerCallback
(
params
);
return
this
.
registerCallback
(
params
);
};
}
MockU2FDevice
.
prototype
.
respondToAuthenticateRequest
=
function
(
params
)
{
respondToAuthenticateRequest
(
params
)
{
return
this
.
authenticateCallback
(
params
);
return
this
.
authenticateCallback
(
params
);
};
}
}
return
MockU2FDevice
;
})();
}).
call
(
window
);
spec/javascripts/u2f/register_spec.js
View file @
41b430b2
/* eslint-disable space-before-function-paren, new-parens, quotes, no-var, one-var, one-var-declaration-per-line, comma-dangle, max-len */
import
U2FRegister
from
'~/u2f/register'
;
/* global MockU2FDevice */
/* global U2FRegister */
import
'~/u2f/register'
;
import
'~/u2f/util'
;
import
'~/u2f/error'
;
import
'vendor/u2f'
;
import
'vendor/u2f'
;
import
'./mock_u2f_device'
;
import
MockU2FDevice
from
'./mock_u2f_device'
;
describe
(
'U2FRegister'
,
()
=>
{
preloadFixtures
(
'u2f/register.html.raw'
);
(
function
()
{
beforeEach
(()
=>
{
describe
(
'U2FRegister'
,
function
()
{
loadFixtures
(
'u2f/register.html.raw'
);
preloadFixtures
(
'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
();
});
beforeEach
(
function
()
{
it
(
'allows registering a U2F device'
,
()
=>
{
loadFixtures
(
'u2f/register.html.raw'
);
const
setupButton
=
this
.
container
.
find
(
'#js-setup-u2f-device'
);
this
.
u2fDevice
=
new
MockU2FDevice
;
expect
(
setupButton
.
text
()).
toBe
(
'Setup new U2F device'
);
this
.
container
=
$
(
"#js-register-u2f"
);
setupButton
.
trigger
(
'click'
);
this
.
component
=
new
U2FRegister
(
this
.
container
,
$
(
"#js-register-u2f-templates"
),
{},
"token"
);
const
inProgressMessage
=
this
.
container
.
children
(
'p'
);
return
this
.
component
.
start
();
expect
(
inProgressMessage
.
text
()).
toContain
(
'Trying to communicate with your device'
);
this
.
u2fDevice
.
respondToRegisterRequest
({
deviceData
:
'this is data from the device'
,
});
});
it
(
'allows registering a U2F device'
,
function
()
{
const
registeredMessage
=
this
.
container
.
find
(
'p'
);
var
deviceResponse
,
inProgressMessage
,
registeredMessage
,
setupButton
;
const
deviceResponse
=
this
.
container
.
find
(
'#js-device-response'
);
setupButton
=
this
.
container
.
find
(
"#js-setup-u2f-device"
);
expect
(
registeredMessage
.
text
()).
toContain
(
'Your device was successfully set up!'
);
expect
(
setupButton
.
text
()).
toBe
(
'Setup new U2F device'
);
return
expect
(
deviceResponse
.
val
()).
toBe
(
'{"deviceData":"this is data from the device"}'
);
});
return
describe
(
'errors'
,
()
=>
{
it
(
'doesn
\'
t allow the same device to be registered twice (for the same user'
,
()
=>
{
const
setupButton
=
this
.
container
.
find
(
'#js-setup-u2f-device'
);
setupButton
.
trigger
(
'click'
);
setupButton
.
trigger
(
'click'
);
inProgressMessage
=
this
.
container
.
children
(
"p"
);
expect
(
inProgressMessage
.
text
()).
toContain
(
"Trying to communicate with your device"
);
this
.
u2fDevice
.
respondToRegisterRequest
({
this
.
u2fDevice
.
respondToRegisterRequest
({
deviceData
:
"this is data from the device"
errorCode
:
4
,
});
});
registeredMessage
=
this
.
container
.
find
(
'p'
);
const
errorMessage
=
this
.
container
.
find
(
'p'
);
deviceResponse
=
this
.
container
.
find
(
'#js-device-response'
);
return
expect
(
errorMessage
.
text
()).
toContain
(
'already been registered with us'
);
expect
(
registeredMessage
.
text
()).
toContain
(
"Your device was successfully set up!"
);
return
expect
(
deviceResponse
.
val
()).
toBe
(
'{"deviceData":"this is data from the device"}'
);
});
});
return
describe
(
"errors"
,
function
()
{
it
(
"doesn't allow the same device to be registered twice (for the same user"
,
function
()
{
it
(
'displays an error message for other errors'
,
()
=>
{
var
errorMessage
,
setupButton
;
const
setupButton
=
this
.
container
.
find
(
'#js-setup-u2f-device'
);
setupButton
=
this
.
container
.
find
(
"#js-setup-u2f-device"
);
setupButton
.
trigger
(
'click'
);
setupButton
.
trigger
(
'click'
);
this
.
u2fDevice
.
respondToRegisterRequest
({
this
.
u2fDevice
.
respondToRegisterRequest
({
errorCode
:
'error!'
,
errorCode
:
4
});
errorMessage
=
this
.
container
.
find
(
"p"
);
return
expect
(
errorMessage
.
text
()).
toContain
(
"already been registered with us"
);
});
});
it
(
"displays an error message for other errors"
,
function
()
{
const
errorMessage
=
this
.
container
.
find
(
'p'
);
var
errorMessage
,
setupButton
;
return
expect
(
errorMessage
.
text
()).
toContain
(
'There was a problem communicating with your device'
)
;
setupButton
=
this
.
container
.
find
(
"#js-setup-u2f-device"
);
}
);
setupButton
.
trigger
(
'click'
);
this
.
u2fDevice
.
respondToRegisterRequest
(
{
return
it
(
'allows retrying registration after an error'
,
()
=>
{
errorCode
:
"error!"
let
setupButton
=
this
.
container
.
find
(
'#js-setup-u2f-device'
);
}
);
setupButton
.
trigger
(
'click'
);
errorMessage
=
this
.
container
.
find
(
"p"
);
this
.
u2fDevice
.
respondToRegisterRequest
({
return
expect
(
errorMessage
.
text
()).
toContain
(
"There was a problem communicating with your device"
);
errorCode
:
'error!'
,
});
});
return
it
(
"allows retrying registration after an error"
,
function
()
{
const
retryButton
=
this
.
container
.
find
(
'#U2FTryAgain'
);
var
registeredMessage
,
retryButton
,
setupButton
;
retryButton
.
trigger
(
'click'
);
setupButton
=
this
.
container
.
find
(
"#js-setup-u2f-device"
);
setupButton
=
this
.
container
.
find
(
'#js-setup-u2f-device'
);
setupButton
.
trigger
(
'click'
);
setupButton
.
trigger
(
'click'
);
this
.
u2fDevice
.
respondToRegisterRequest
({
this
.
u2fDevice
.
respondToRegisterRequest
({
errorCode
:
"error!"
deviceData
:
'this is data from the device'
,
});
retryButton
=
this
.
container
.
find
(
"#U2FTryAgain"
);
retryButton
.
trigger
(
'click'
);
setupButton
=
this
.
container
.
find
(
"#js-setup-u2f-device"
);
setupButton
.
trigger
(
'click'
);
this
.
u2fDevice
.
respondToRegisterRequest
({
deviceData
:
"this is data from the device"
});
registeredMessage
=
this
.
container
.
find
(
"p"
);
return
expect
(
registeredMessage
.
text
()).
toContain
(
"Your device was successfully set up!"
);
});
});
const
registeredMessage
=
this
.
container
.
find
(
'p'
);
return
expect
(
registeredMessage
.
text
()).
toContain
(
'Your device was successfully set up!'
);
});
});
});
});
})
.
call
(
window
)
;
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment