diff options
Diffstat (limited to 'app/assets/javascripts/authentication/webauthn/register.js')
-rw-r--r-- | app/assets/javascripts/authentication/webauthn/register.js | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/app/assets/javascripts/authentication/webauthn/register.js b/app/assets/javascripts/authentication/webauthn/register.js new file mode 100644 index 00000000000..06e4ffd6f3e --- /dev/null +++ b/app/assets/javascripts/authentication/webauthn/register.js @@ -0,0 +1,78 @@ +import { __ } from '~/locale'; +import WebAuthnError from './error'; +import WebAuthnFlow from './flow'; +import { supported, isHTTPS, convertCreateParams, convertCreateResponse } from './util'; + +// Register WebAuthn devices for users to authenticate with. +// +// State Flow #1: setup -> in_progress -> registered -> POST to server +// State Flow #2: setup -> in_progress -> error -> setup +export default class WebAuthnRegister { + constructor(container, webauthnParams) { + this.container = container; + this.renderInProgress = this.renderInProgress.bind(this); + this.webauthnOptions = convertCreateParams(webauthnParams.options); + + this.flow = new WebAuthnFlow(container, { + message: '#js-register-2fa-message', + setup: '#js-register-token-2fa-setup', + error: '#js-register-token-2fa-error', + registered: '#js-register-token-2fa-registered', + }); + + this.container.on('click', '#js-token-2fa-try-again', this.renderInProgress); + } + + start() { + if (!supported()) { + // we show a special error message when the user visits the site + // using a non-ssl connection as this makes WebAuthn unavailable in + // any case, regardless of the used browser + this.renderNotSupported(!isHTTPS()); + } else { + this.renderSetup(); + } + } + + register() { + navigator.credentials + .create({ + publicKey: this.webauthnOptions, + }) + .then(cred => this.renderRegistered(JSON.stringify(convertCreateResponse(cred)))) + .catch(err => this.flow.renderError(new WebAuthnError(err, 'register'))); + } + + renderSetup() { + this.flow.renderTemplate('setup'); + this.container.find('#js-setup-token-2fa-device').on('click', this.renderInProgress); + } + + renderInProgress() { + this.flow.renderTemplate('message', { + message: __( + 'Trying to communicate with your device. Plug it in (if needed) and press the button on the device now.', + ), + }); + return this.register(); + } + + renderRegistered(deviceResponse) { + this.flow.renderTemplate('registered'); + // Prefer to do this instead of interpolating using Underscore templates + // because of JSON escaping issues. + this.container.find('#js-device-response').val(deviceResponse); + } + + renderNotSupported(noHttps) { + const message = noHttps + ? __( + 'WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details.', + ) + : __( + "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+).", + ); + + this.flow.renderTemplate('message', { message }); + } +} |