forked from discourse/discourse
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
FEATURE: Add support for two factor authentication.
- Loading branch information
Showing
26 changed files
with
563 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
app/assets/javascripts/discourse/controllers/preferences/two-factor-authentication.js.es6
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
export default Ember.ObjectController.extend({ | ||
qr: Em.computed.alias('twoFactorAuthenticationData.modules'), | ||
enabledTwoFactorAuthentication: Em.computed.alias('enabled_two_factor_authentication'), | ||
|
||
appName: function() { | ||
const data = this.get('twoFactorAuthenticationData.data'); | ||
return data ? data.match(/otpauth:\/\/totp\/(\S+)\?secret=(\S+)/)[1] : null; | ||
}.property('twoFactorAuthenticationData'), | ||
|
||
secret: function() { | ||
const data = this.get('twoFactorAuthenticationData.data'); | ||
return data ? data.match(/otpauth:\/\/totp\/(\S+)\?secret=(\S+)/)[2] : null; | ||
}.property('twoFactorAuthenticationData'), | ||
|
||
savingStatus: function() { | ||
if (this.get('saving')) { | ||
return I18n.t('saving'); | ||
} else { | ||
return I18n.t('save'); | ||
} | ||
}.property('saving'), | ||
|
||
actions: { | ||
save() { | ||
this.setProperties({ saved: false, saving: true }); | ||
|
||
const self = this; | ||
Discourse.ajax(this.get('model.path') + '/preferences/two-factor-authentication', { | ||
type: 'PUT', | ||
data: { | ||
secret: self.get('secret'), | ||
code: self.get('code') | ||
} | ||
}).then(function() { | ||
self.setProperties({ | ||
saved: true, | ||
saving: false, | ||
enabledTwoFactorAuthentication: true | ||
}); | ||
}).catch(function() { | ||
self.set('saving', false); | ||
bootbox.alert(I18n.t('user.two_factor_authentication.configuration.incorret_code')); | ||
}); | ||
}, | ||
|
||
revoke() { | ||
const self = this; | ||
Discourse.ajax(this.get('model.path') + '/preferences/revoke-two-factor-authentication', { | ||
type: 'PUT', | ||
data: { revoke: true } | ||
}).then(function() { | ||
self.setProperties({ | ||
enabledTwoFactorAuthentication: false | ||
}); | ||
}).catch(function() { | ||
bootbox.alert(I18n.t('generic_error')); | ||
}); | ||
} | ||
|
||
} | ||
}); |
65 changes: 65 additions & 0 deletions
65
app/assets/javascripts/discourse/controllers/two-factor-authentication-code-verifier.es6
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import ModalFunctionality from 'discourse/mixins/modal-functionality'; | ||
import DiscourseController from 'discourse/controllers/controller'; | ||
|
||
export default DiscourseController.extend(ModalFunctionality, { | ||
needs: ['modal', 'application'], | ||
authenticate: null, | ||
loggingIn: false, | ||
loggedIn: false, | ||
|
||
loginRequired: Em.computed.alias('controllers.application.loginRequired'), | ||
|
||
resetForm() { | ||
this.set('authenticate', null); | ||
this.set('loggingIn', false); | ||
this.set('loggedIn', false); | ||
}, | ||
|
||
loginButtonText: function() { | ||
return this.get('loggingIn') ? I18n.t('login.logging_in') : I18n.t('login.title'); | ||
}.property('loggingIn'), | ||
|
||
actions: { | ||
verify() { | ||
var self = this; | ||
|
||
if (this.blank('twoFactorAuthenticationCode')) { | ||
self.flash(I18n.t('login.blank_code'), 'error'); | ||
return; | ||
} | ||
|
||
this.set('loggingIn', true); | ||
|
||
Discourse.ajax("/session/verify_two_factor_authentication_code", { | ||
data: { code: this.get('twoFactorAuthenticationCode') }, | ||
type: 'POST' | ||
}).then(function(result) { | ||
// Successful login | ||
if (result.error) { | ||
self.set('loggingIn', false); | ||
self.flash(result.error, 'error'); | ||
} else { | ||
self.set('loggedIn', true); | ||
var $hidden_login_form = $('#hidden-login-form'); | ||
var destinationUrl = $.cookie('destination_url'); | ||
if (self.get('loginRequired') && destinationUrl) { | ||
// redirect client to the original URL | ||
$.cookie('destination_url', null); | ||
$hidden_login_form.find('input[name=redirect]').val(destinationUrl); | ||
} else { | ||
$hidden_login_form.find('input[name=redirect]').val(window.location.href); | ||
} | ||
$hidden_login_form.submit(); | ||
} | ||
|
||
}, function() { | ||
// Failed to login | ||
self.flash(I18n.t('login.error'), 'error'); | ||
self.set('loggingIn', false); | ||
}); | ||
|
||
return false; | ||
} | ||
} | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
app/assets/javascripts/discourse/routes/preferences-two-factor-authentication.js.es6
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import RestrictedUserRoute from "discourse/routes/restricted-user"; | ||
|
||
export default RestrictedUserRoute.extend({ | ||
renderTemplate() { | ||
return this.render({ into: 'user' }); | ||
}, | ||
|
||
// A bit odd, but if we leave to /preferences we need to re-render that outlet | ||
deactivate() { | ||
this._super(); | ||
this.render('preferences', { into: 'user', controller: 'preferences' }); | ||
}, | ||
|
||
setupController(controller, model) { | ||
controller.set('model', model); | ||
|
||
if (!model.get('enabledTwoFactorAuthentication')) { | ||
Discourse.ajax(model.get('path') + '/preferences/two_factor_authentication/provisioning_url.json').then(function(result) { | ||
controller.set('twoFactorAuthenticationData', result.otp); | ||
}); | ||
} | ||
} | ||
|
||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
app/assets/javascripts/discourse/templates/modal/two_factor_authentication_code_verifier.hbs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<div class="modal-body"> | ||
<form id='two-factor-authentication-form' method='post'> | ||
<div> | ||
<table> | ||
<tr> | ||
<td> | ||
<label for='two-factor-authentication-code'>{{i18n 'login.code'}} </label> | ||
</td> | ||
<td> | ||
{{text-field value=twoFactorAuthenticationCode placeholderKey="login.code_placeholder" id="two-factor-authentication-code" autocorrect="off" autocapitalize="off" autofocus="autofocus"}} | ||
</td> | ||
</tr> | ||
</table> | ||
</div> | ||
</form> | ||
</div> | ||
<div class="modal-footer"> | ||
<button class="btn btn-large btn-primary" | ||
{{action "verify"}}> | ||
<i class="fa fa-unlock"></i> {{loginButtonText}} | ||
</button> | ||
|
||
{{#if authenticate}} | ||
{{i18n 'login.authenticating'}} | ||
{{/if}} | ||
|
||
{{loading-spinner condition=showSpinner size="small"}} | ||
</div> |
76 changes: 76 additions & 0 deletions
76
app/assets/javascripts/discourse/templates/preferences/two-factor-authentication.hbs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
<section class='user-content'> | ||
<form class="form-horizontal"> | ||
|
||
<div class="control-group"> | ||
<div class="controls"> | ||
<h3>{{i18n 'user.two_factor_authentication.configuration.title'}}</h3> | ||
</div> | ||
</div> | ||
|
||
{{#if enabledTwoFactorAuthentication}} | ||
<div class="control-group"> | ||
<div class="controls"> | ||
<p>{{i18n 'user.two_factor_authentication.configuration.setup'}}</p> | ||
</div> | ||
</div> | ||
<div class="control-group"> | ||
<label class="control-label">{{i18n 'user.two_factor_authentication.configuration.revoke_label'}}</label> | ||
<div class="controls"> | ||
{{d-button action="revoke" icon="minus-circle" label="user.two_factor_authentication.configuration.revoke" class="btn-primary"}} | ||
</div> | ||
</div> | ||
{{else}} | ||
<div class="control-group"> | ||
<label class="control-label">{{i18n 'user.two_factor_authentication.configuration.scan'}}</label> | ||
<div class="controls"> | ||
<table class="otp-qr"> | ||
{{#each row in qr}} | ||
<tr> | ||
{{#each data in row}} | ||
<td {{bind-attr class="data:black:white"}}></td> | ||
{{/each}} | ||
</tr> | ||
{{/each}} | ||
</table> | ||
</div> | ||
</div> | ||
|
||
<div class="control-group"> | ||
<div class="controls"> | ||
<p>{{i18n 'user.two_factor_authentication.configuration.enter_secret'}}</p> | ||
</div> | ||
</div> | ||
|
||
<div class="control-group"> | ||
<label class="control-label">{{i18n 'user.two_factor_authentication.configuration.app_name'}}</label> | ||
<div class="controls"> | ||
<label>{{appName}}</label> | ||
</div> | ||
</div> | ||
|
||
<div class="control-group"> | ||
<label class="control-label">{{i18n 'user.two_factor_authentication.configuration.secret'}}</label> | ||
<div class="controls"> | ||
<label>{{secret}}</label> | ||
</div> | ||
</div> | ||
|
||
<div class="control-group"> | ||
<label class="control-label">{{i18n 'user.two_factor_authentication.configuration.verify'}}</label> | ||
<div class="controls"> | ||
{{input type="text" value=code class="input-xxlarge"}} | ||
</div> | ||
</div> | ||
|
||
<div class="control-group"> | ||
<div class="controls"> | ||
<button class="btn btn-primary" {{bind-attr disabled=disableSave}} {{action "save"}}>{{savingStatus}}</button> | ||
{{#if saved}}{{i18n 'saved'}}{{/if}} | ||
</div> | ||
</div> | ||
|
||
{{/if}} | ||
|
||
|
||
</form> | ||
</section> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.