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';
import
AbuseReports
from
'./abuse_reports'
;
import
{
ajaxGet
,
convertPermissionToBoolean
}
from
'./lib/utils/common_utils'
;
import
AjaxLoadingSpinner
from
'./ajax_loading_spinner'
;
import
U2FAuthenticate
from
'./u2f/authenticate'
;
(
function
()
{
var
Dispatcher
;
...
...
@@ -535,14 +536,16 @@ import AjaxLoadingSpinner from './ajax_loading_spinner';
case
'sessions'
:
case
'omniauth_callbacks'
:
if
(
!
gon
.
u2f
)
break
;
gl
.
u2fAuthenticate
=
new
gl
.
U2FAuthenticate
(
const
u2fAuthenticate
=
new
U2FAuthenticate
(
$
(
'#js-authenticate-u2f'
),
'#js-login-u2f-form'
,
gon
.
u2f
,
document
.
querySelector
(
'#js-login-2fa-device'
),
document
.
querySelector
(
'.js-2fa-form'
),
);
gl
.
u2fAuthenticate
.
start
();
u2fAuthenticate
.
start
();
// needed in rspec
gl
.
u2fAuthenticate
=
u2fAuthenticate
;
case
'admin'
:
new
Admin
();
switch
(
path
[
1
])
{
...
...
app/assets/javascripts/main.js
View file @
41b430b2
...
...
@@ -47,12 +47,6 @@ import './lib/utils/url_utility';
// behaviors
import
'./behaviors/'
;
// u2f
import
'./u2f/authenticate'
;
import
'./u2f/error'
;
import
'./u2f/register'
;
import
'./u2f/util'
;
// everything else
import
'./activities'
;
import
'./admin'
;
...
...
app/assets/javascripts/two_factor_auth.js
View file @
41b430b2
/* global U2FRegister */
import
U2FRegister
from
'./u2f/register'
;
document
.
addEventListener
(
'DOMContentLoaded'
,
()
=>
{
const
twoFactorNode
=
document
.
querySelector
(
'.js-two-factor-auth'
);
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 U2FError */
/* global U2FUtil */
import
_
from
'underscore'
;
import
isU2FSupported
from
'./util'
;
import
U2FError
from
'./error'
;
// 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
(
function
()
{
const
global
=
window
.
gl
||
(
window
.
gl
=
{});
global
.
U2FAuthenticate
=
(
function
()
{
function
U2FAuthenticate
(
container
,
form
,
u2fParams
,
fallbackButton
,
fallbackUI
)
{
this
.
container
=
container
;
this
.
renderNotSupported
=
this
.
renderNotSupported
.
bind
(
this
);
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
));
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'
);
});
export
default
class
U2FAuthenticate
{
constructor
(
container
,
form
,
u2fParams
,
fallbackButton
,
fallbackUI
)
{
this
.
container
=
container
;
this
.
renderNotSupported
=
this
.
renderNotSupported
.
bind
(
this
);
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
));
}
U2FAuthenticate
.
prototype
.
start
=
function
()
{
if
(
U2FUtil
.
isU2FSupported
())
{
return
this
.
renderInProgress
();
}
else
{
return
this
.
renderNotSupported
();
}
};
// 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
=>
_
(
request
).
omit
(
'challenge'
));
U2FAuthenticate
.
prototype
.
authenticate
=
function
()
{
return
u2f
.
sign
(
this
.
appId
,
this
.
challenge
,
this
.
signRequests
,
(
function
(
_this
)
{
return
function
(
response
)
{
var
error
;
if
(
response
.
errorCode
)
{
error
=
new
U2FError
(
response
.
errorCode
,
'authenticate'
);
return
_this
.
renderError
(
error
);
}
else
{
return
_this
.
renderAuthenticated
(
JSON
.
stringify
(
response
));
}
};
})(
this
),
10
);
this
.
templates
=
{
notSupported
:
'#js-authenticate-u2f-not-supported'
,
setup
:
'#js-authenticate-u2f-setup'
,
inProgress
:
'#js-authenticate-u2f-in-progress'
,
error
:
'#js-authenticate-u2f-error'
,
authenticated
:
'#js-authenticate-u2f-authenticated'
,
};
}
// Rendering #
U2FAuthenticate
.
prototype
.
templates
=
{
"notSupported"
:
"#js-authenticate-u2f-not-supported"
,
"setup"
:
'#js-authenticate-u2f-setup'
,
"inProgress"
:
'#js-authenticate-u2f-in-progress'
,
"error"
:
'#js-authenticate-u2f-error'
,
"authenticated"
:
'#js-authenticate-u2f-authenticated'
};
start
()
{
if
(
isU2FSupported
())
{
return
this
.
renderInProgress
();
}
return
this
.
renderNotSupported
();
}
U2FAuthenticate
.
prototype
.
renderTemplate
=
function
(
name
,
params
)
{
var
template
,
templateString
;
templateString
=
$
(
this
.
templates
[
name
]).
html
();
template
=
_
.
template
(
templateString
);
return
this
.
container
.
html
(
template
(
params
));
};
authenticate
()
{
return
u2f
.
sign
(
this
.
appId
,
this
.
challenge
,
this
.
signRequests
,
(
function
(
_this
)
{
return
function
(
response
)
{
if
(
response
.
errorCode
)
{
const
error
=
new
U2FError
(
response
.
errorCode
,
'authenticate'
);
return
_this
.
renderError
(
error
);
}
return
_this
.
renderAuthenticated
(
JSON
.
stringify
(
response
));
};
})(
this
),
10
);
}
U2FAuthenticate
.
prototype
.
renderInProgress
=
function
()
{
this
.
renderTemplate
(
'inProgress'
);
return
this
.
authenticate
();
};
renderTemplate
(
name
,
params
)
{
const
templateString
=
$
(
this
.
templates
[
name
]).
html
();
const
template
=
_
.
template
(
templateString
);
return
this
.
container
.
html
(
template
(
params
));
}
U2FAuthenticate
.
prototype
.
renderError
=
function
(
error
)
{
this
.
renderTemplate
(
'error'
,
{
error_message
:
error
.
message
(),
error_code
:
error
.
errorCode
});
return
this
.
container
.
find
(
'#js-u2f-try-again'
).
on
(
'click'
,
this
.
renderInProgress
);
};
renderInProgress
()
{
this
.
renderTemplate
(
'inProgress'
);
return
this
.
authenticate
();
}
U2FAuthenticate
.
prototype
.
renderAuthenticated
=
function
(
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'
);
};
renderError
(
error
)
{
this
.
renderTemplate
(
'error'
,
{
error_message
:
error
.
message
(),
error_code
:
error
.
errorCode
,
}
);
return
this
.
container
.
find
(
'#js-u2f-try-again'
).
on
(
'click'
,
this
.
renderInProgress
);
}
U2FAuthenticate
.
prototype
.
renderNotSupported
=
function
()
{
return
this
.
renderTemplate
(
'notSupported'
);
};
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'
);
}
U2FAuthenticate
.
prototype
.
switchToFallbackUI
=
function
()
{
this
.
fallbackButton
.
classList
.
add
(
'hidden'
);
this
.
container
[
0
].
classList
.
add
(
'hidden'
);
this
.
fallbackUI
.
classList
.
remove
(
'hidden'
);
};
renderNotSupported
()
{
return
this
.
renderTemplate
(
'notSupported'
);
}
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 */
/* global u2f */
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
;
}
(
function
()
{
this
.
U2FError
=
(
function
()
{
function
U2FError
(
errorCode
,
u2fFlowType
)
{
this
.
errorCode
=
errorCode
;
this
.
message
=
this
.
message
.
bind
(
this
);
this
.
httpsDisabled
=
window
.
location
.
protocol
!==
'https:'
;
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.'
;
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.'
;
}
return
"There was a problem communicating with your device."
;
};
return
U2FError
;
})();
}).
call
(
window
);
if
(
this
.
u2fFlowType
===
'register'
)
{
return
'This device has already been registered with us.'
;
}
}
return
'There was a problem communicating with your device.'
;
}
}
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 U2FError */
/* global U2FUtil */
import
_
from
'underscore'
;
import
isU2FSupported
from
'./util'
;
import
U2FError
from
'./error'
;
// 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
(
function
()
{
this
.
U2FRegister
=
(
function
()
{
function
U2FRegister
(
container
,
u2fParams
)
{
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
;
}
export
default
class
U2FRegister
{
constructor
(
container
,
u2fParams
)
{
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
;
U2FRegister
.
prototype
.
start
=
function
()
{
if
(
U2FUtil
.
isU2FSupported
())
{
return
this
.
renderSetup
();
}
else
{
return
this
.
renderNotSupported
();
}
this
.
templates
=
{
notSupported
:
'#js-register-u2f-not-supported'
,
setup
:
'#js-register-u2f-setup'
,
inProgress
:
'#js-register-u2f-in-progress'
,
error
:
'#js-register-u2f-error'
,
registered
:
'#js-register-u2f-registered'
,
};
}
U2FRegister
.
prototype
.
register
=
function
()
{
return
u2f
.
register
(
this
.
appId
,
this
.
registerRequests
,
this
.
signRequests
,
(
function
(
_this
)
{
return
function
(
response
)
{
var
error
;
if
(
response
.
errorCode
)
{
error
=
new
U2FError
(
response
.
errorCode
,
'register'
);
return
_this
.
renderError
(
error
);
}
else
{
return
_this
.
renderRegistered
(
JSON
.
stringify
(
response
));
}
};
})(
this
),
10
);
};
start
()
{
if
(
isU2FSupported
())
{
return
this
.
renderSetup
();
}
return
this
.
renderNotSupported
();
}
// Rendering #
U2FRegister
.
prototype
.
templates
=
{
"notSupported"
:
"#js-register-u2f-not-supported"
,
"setup"
:
'#js-register-u2f-setup'
,
"inProgress"
:
'#js-register-u2f-in-progress'
,
"error"
:
'#js-register-u2f-error'
,
"registered"
:
'#js-register-u2f-registered'
};
register
()
{
return
u2f
.
register
(
this
.
appId
,
this
.
registerRequests
,
this
.
signRequests
,
(
function
(
_this
)
{
return
function
(
response
)
{
if
(
response
.
errorCode
)
{
const
error
=
new
U2FError
(
response
.
errorCode
,
'register'
);
return
_this
.
renderError
(
error
);
}
return
_this
.
renderRegistered
(
JSON
.
stringify
(
response
));
};
})(
this
),
10
);
}
U2FRegister
.
prototype
.
renderTemplate
=
function
(
name
,
params
)
{
var
template
,
templateString
;
templateString
=
$
(
this
.
templates
[
name
]).
html
();
template
=
_
.
template
(
templateString
);
return
this
.
container
.
html
(
template
(
params
));
};
renderTemplate
(
name
,
params
)
{
const
templateString
=
$
(
this
.
templates
[
name
]).
html
();
const
template
=
_
.
template
(
templateString
);
return
this
.
container
.
html
(
template
(
params
));
}
U2FRegister
.
prototype
.
renderSetup
=
function
()
{
this
.
renderTemplate
(
'setup'
);
return
this
.
container
.
find
(
'#js-setup-u2f-device'
).
on
(
'click'
,
this
.
renderInProgress
);
};
renderSetup
()
{
this
.
renderTemplate
(
'setup'
);
return
this
.
container
.
find
(
'#js-setup-u2f-device'
).
on
(
'click'
,
this
.
renderInProgress
);
}
U2FRegister
.
prototype
.
renderInProgress
=
function
()
{
this
.
renderTemplate
(
'inProgress'
);
return
this
.
register
();
};
renderInProgress
()
{
this
.
renderTemplate
(
'inProgress'
);
return
this
.
register
();
}
U2FRegister
.
prototype
.
renderError
=
function
(
error
)
{
this
.
renderTemplate
(
'error'
,
{
error_message
:
error
.
message
(),
error_code
:
error
.
errorCode
});
return
this
.
container
.
find
(
'#js-u2f-try-again'
).
on
(
'click'
,
this
.
renderSetup
);
};
renderError
(
error
)
{
this
.
renderTemplate
(
'error'
,
{
error_message
:
error
.
message
(),
error_code
:
error
.
errorCode
,
});
return
this
.
container
.
find
(
'#js-u2f-try-again'
).
on
(
'click'
,
this
.
renderSetup
);
}
U2FRegister
.
prototype
.
renderRegistered
=
function
(
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
);
};
U2FRegister
.
prototype
.
renderNotSupported
=
function
()
{
return
this
.
renderTemplate
(
'notSupported'
);
};
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
);
}
return
U2FRegister
;
})();
}).
call
(
window
);
renderNotSupported
()
{
return
this
.
renderTemplate
(
'notSupported'
);
}
}
app/assets/javascripts/u2f/util.js
View file @
41b430b2
/* eslint-disable func-names, space-before-function-paren, wrap-iife */
(
function
()
{
this
.
U2FUtil
=
(
function
()
{
function
U2FUtil
()
{}
U2FUtil
.
isU2FSupported
=
function
()
{
return
window
.
u2f
;
};
return
U2FUtil
;
})();
}).
call
(
window
);
export
default
function
isU2FSupported
()
{
return
window
.
u2f
;
}
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 */
/* global MockU2FDevice */
/* global U2FAuthenticate */
import
'~/u2f/authenticate'
;
import
'~/u2f/util'
;
import
'~/u2f/error'
;
import
U2FAuthenticate
from
'~/u2f/authenticate'
;
import
'vendor/u2f'
;
import
'./mock_u2f_device'
;
import
MockU2FDevice
from
'./mock_u2f_device'
;
describe
(
'U2FAuthenticate'
,
()
=>
{
preloadFixtures
(
'u2f/authenticate.html.raw'
);
(
function
()
{
describe
(
'U2FAuthenticate'
,
function
()
{
preloadFixtures
(
'u2f/authenticate.html.raw'
);
beforeEach
(()
=>
{
loadFixtures
(
'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
()
{
loadFixtures
(
'u2f/authenticate.html.raw'
);
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
spyOn
(
this
.
component
,
'renderAuthenticated'
).
and
.
returnValue
(
true
);
// bypass automatic form submission within renderAuthenticated
spyOn
(
this
.
component
,
'renderAuthenticated'
).
and
.
returnValue
(
true
);
return
this
.
component
.
start
();
}
);
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
()
{
var
inProgressMessage
;
inProgressMessage
=
this
.
container
.
find
(
"p"
);
expect
(
inProgressMessage
.
text
()).
toContain
(
"Trying to communicate with your device"
);
expect
(
this
.
component
.
renderAuthenticated
).
toHaveBeenCalledWith
(
'{"deviceData":"this is data from the device"}'
);
});
return
describe
(
'errors'
,
()
=>
{
it
(
'displays an error message'
,
()
=>
{
const
setupButton
=
this
.
container
.
find
(
'#js-login-u2f-device'
);
setupButton
.
trigger
(
'click'
);
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
()
{
it
(
"displays an error message"
,
function
()
{
var
errorMessage
,
setupButton
;
setupButton
=
this
.
container
.
find
(
"#js-login-u2f-device"
);
setupButton
.
trigger
(
'click'
);
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'
,
()
=>
{
let
setupButton
=
this
.
container
.
find
(
'#js-login-u2f-device'
);
setupButton
.
trigger
(
'click'
);
this
.
u2fDevice
.
respondToAuthenticateRequest
({
errorCode
:
'error!'
,
});
return
it
(
"allows retrying authentication after an error"
,
function
()
{
var
retryButton
,
setupButton
;
setupButton
=
this
.
container
.
find
(
"#js-login-u2f-device"
);
setupButton
.
trigger
(
'click'
);
this
.
u2fDevice
.
respondToAuthenticateRequest
({
errorCode
:
"error!"
});
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"}'
);
const
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"}'
);
});
});
})
.
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
()
{
this
.
MockU2FDevice
=
(
function
()
{
function
MockU2FDevice
()
{
this
.
respondToAuthenticateRequest
=
this
.
respondToAuthenticateRequest
.
bind
(
this
);
this
.
respondToRegisterRequest
=
this
.
respondToRegisterRequest
.
bind
(
this
);
window
.
u2f
||
(
window
.
u2f
=
{});
window
.
u2f
.
register
=
(
function
(
_this
)
{
return
function
(
appId
,
registerRequests
,
signRequests
,
callback
)
{
return
_this
.
registerCallback
=
callback
;
};
})(
this
);
window
.
u2f
.
sign
=
(
function
(
_this
)
{
return
function
(
appId
,
challenges
,
signRequests
,
callback
)
{
return
_this
.
authenticateCallback
=
callback
;
};
})(
this
);
}
export
default
class
MockU2FDevice
{
constructor
()
{
this
.
respondToAuthenticateRequest
=
this
.
respondToAuthenticateRequest
.
bind
(
this
);
this
.
respondToRegisterRequest
=
this
.
respondToRegisterRequest
.
bind
(
this
);
window
.
u2f
||
(
window
.
u2f
=
{});
window
.
u2f
.
register
=
(
function
(
_this
)
{
return
function
(
appId
,
registerRequests
,
signRequests
,
callback
)
{
return
_this
.
registerCallback
=
callback
;
};
})(
this
);
window
.
u2f
.
sign
=
(
function
(
_this
)
{
return
function
(
appId
,
challenges
,
signRequests
,
callback
)
{
return
_this
.
authenticateCallback
=
callback
;
};
})(
this
);
}
MockU2FDevice
.
prototype
.
respondToRegisterRequest
=
function
(
params
)
{
return
this
.
registerCallback
(
params
);
};
respondToRegisterRequest
(
params
)
{
return
this
.
registerCallback
(
params
);
}
MockU2FDevice
.
prototype
.
respondToAuthenticateRequest
=
function
(
params
)
{
return
this
.
authenticateCallback
(
params
);
};
return
MockU2FDevice
;
})();
}).
call
(
window
);
respondToAuthenticateRequest
(
params
)
{
return
this
.
authenticateCallback
(
params
);
}
}
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 */
/* global MockU2FDevice */
/* global U2FRegister */
import
'~/u2f/register'
;
import
'~/u2f/util'
;
import
'~/u2f/error'
;
import
U2FRegister
from
'~/u2f/register'
;
import
'vendor/u2f'
;
import
'./mock_u2f_device'
;
import
MockU2FDevice
from
'./mock_u2f_device'
;
describe
(
'U2FRegister'
,
()
=>
{
preloadFixtures
(
'u2f/register.html.raw'
);
(
function
()
{
describe
(
'U2FRegister'
,
function
()
{
preloadFixtures
(
'u2f/register.html.raw'
);
beforeEach
(()
=>
{
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
();
});
beforeEach
(
function
()
{
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
();
it
(
'allows registering a U2F device'
,
()
=>
{
const
setupButton
=
this
.
container
.
find
(
'#js-setup-u2f-device'
);
expect
(
setupButton
.
text
()).
toBe
(
'Setup new U2F device'
);
setupButton
.
trigger
(
'click'
);
const
inProgressMessage
=
this
.
container
.
children
(
'p'
);
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
()
{
var
deviceResponse
,
inProgressMessage
,
registeredMessage
,
setupButton
;
setupButton
=
this
.
container
.
find
(
"#js-setup-u2f-device"
);
expect
(
setupButton
.
text
()).
toBe
(
'Setup new U2F device'
);
const
registeredMessage
=
this
.
container
.
find
(
'p'
);
const
deviceResponse
=
this
.
container
.
find
(
'#js-device-response'
);
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'
,
()
=>
{
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'
);
inProgressMessage
=
this
.
container
.
children
(
"p"
);
expect
(
inProgressMessage
.
text
()).
toContain
(
"Trying to communicate with your device"
);
this
.
u2fDevice
.
respondToRegisterRequest
({
deviceData
:
"this is data from the device"
errorCode
:
4
,
});
registeredMessage
=
this
.
container
.
find
(
'p'
);
deviceResponse
=
this
.
container
.
find
(
'#js-device-response'
);
expect
(
registeredMessage
.
text
()).
toContain
(
"Your device was successfully set up!"
);
return
expect
(
deviceResponse
.
val
()).
toBe
(
'{"deviceData":"this is data from the device"}'
);
const
errorMessage
=
this
.
container
.
find
(
'p'
);
return
expect
(
errorMessage
.
text
()).
toContain
(
'already been registered with us'
);
});
return
describe
(
"errors"
,
function
()
{
it
(
"doesn't allow the same device to be registered twice (for the same user"
,
function
()
{
var
errorMessage
,
setupButton
;
setupButton
=
this
.
container
.
find
(
"#js-setup-u2f-device"
);
setupButton
.
trigger
(
'click'
);
this
.
u2fDevice
.
respondToRegisterRequest
({
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'
,
()
=>
{
const
setupButton
=
this
.
container
.
find
(
'#js-setup-u2f-device'
);
setupButton
.
trigger
(
'click'
);
this
.
u2fDevice
.
respondToRegisterRequest
({
errorCode
:
'error!'
,
});
it
(
"displays an error message for other errors"
,
function
()
{
var
errorMessage
,
setupButton
;
setupButton
=
this
.
container
.
find
(
"#js-setup-u2f-device"
);
setupButton
.
trigger
(
'click'
);
this
.
u2fDevice
.
respondToRegisterRequest
(
{
errorCode
:
"error!"
}
);
errorMessage
=
this
.
container
.
find
(
"p"
);
return
expect
(
errorMessage
.
text
()).
toContain
(
"There was a problem communicating with your device"
);
const
errorMessage
=
this
.
container
.
find
(
'p'
);
return
expect
(
errorMessage
.
text
()).
toContain
(
'There was a problem communicating with your device'
)
;
}
);
return
it
(
'allows retrying registration after an error'
,
()
=>
{
let
setupButton
=
this
.
container
.
find
(
'#js-setup-u2f-device'
);
setupButton
.
trigger
(
'click'
);
this
.
u2fDevice
.
respondToRegisterRequest
({
errorCode
:
'error!'
,
});
return
it
(
"allows retrying registration after an error"
,
function
()
{
var
registeredMessage
,
retryButton
,
setupButton
;
setupButton
=
this
.
container
.
find
(
"#js-setup-u2f-device"
);
setupButton
.
trigger
(
'click'
);
this
.
u2fDevice
.
respondToRegisterRequest
({
errorCode
:
"error!"
});
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
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'
,
});
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