finish up password protection

closes #5073
- takes password protection out of labs and moves it to general settings
- adds random-words generator to randomly generate passwords
This commit is contained in:
Austin Burdine 2015-05-11 09:35:55 -06:00
parent c4cc5d5b8d
commit ed9fdbca7f
13 changed files with 44 additions and 134 deletions

View File

@ -60,5 +60,6 @@ app.import('bower_components/codemirror/mode/xml/xml.js');
app.import('bower_components/codemirror/mode/css/css.js');
app.import('bower_components/codemirror/mode/javascript/javascript.js');
app.import('bower_components/xregexp/xregexp-all.js');
app.import('bower_components/password-generator/lib/password-generator.js');
module.exports = app.toTree();

View File

@ -24,10 +24,6 @@ var FeatureController = Ember.Controller.extend(Ember.PromiseProxyMixin, {
}
return value;
}),
passProtectUI: Ember.computed('config.passProtectUI', 'labs.passProtectUI', function () {
return this.get('config.passProtectUI') || this.get('labs.passProtectUI');
})
});

View File

@ -1,4 +1,6 @@
import Ember from 'ember';
import randomPassword from 'ghost/utils/random-password';
var SettingsGeneralController = Ember.Controller.extend({
selectedTheme: null,
@ -37,6 +39,12 @@ var SettingsGeneralController = Ember.Controller.extend({
}, []);
}).readOnly(),
generatePassword: Ember.observer('model.isPrivate', function () {
if (this.get('model.isPrivate') && this.get('model.isDirty')) {
this.get('model').set('password', randomPassword());
}
}),
actions: {
save: function () {
var self = this;

View File

@ -23,16 +23,6 @@ var LabsController = Ember.Controller.extend(Ember.Evented, {
});
},
usePassProtectUI: Ember.computed('controllers.feature.passProtectUI', function (key, value) {
// setter
if (arguments.length > 1) {
this.saveLabs('passProtectUI', value);
}
// getter
return this.get('controllers.feature.passProtectUI');
}),
actions: {
onUpload: function (file) {
var self = this,

View File

@ -1,27 +0,0 @@
import Ember from 'ember';
var SettingsPassProtectController = Ember.Controller.extend({
actions: {
save: function () {
var self = this;
if (this.get('model.isPrivate') && this.get('model.password') === '') {
self.notifications.closePassive();
self.notifications.showError('Password must have a value.');
return;
}
return this.get('model').save().then(function (model) {
self.notifications.closePassive();
self.notifications.showSuccess('Settings successfully saved.');
return model;
}).catch(function (errors) {
self.notifications.closePassive();
self.notifications.showErrors(errors);
});
}
}
});
export default SettingsPassProtectController;

View File

@ -43,7 +43,6 @@ Router.map(function () {
this.route('labs');
this.route('code-injection');
this.route('navigation');
this.route('pass-protect');
});
// Redirect debug to settings labs

View File

@ -1,45 +0,0 @@
import AuthenticatedRoute from 'ghost/routes/authenticated';
import loadingIndicator from 'ghost/mixins/loading-indicator';
import CurrentUserSettings from 'ghost/mixins/current-user-settings';
import styleBody from 'ghost/mixins/style-body';
var SettingsPassProtectRoute = AuthenticatedRoute.extend(styleBody, loadingIndicator, CurrentUserSettings, {
classNames: ['settings-view-pass'],
beforeModel: function () {
var feature = this.controllerFor('feature'),
self = this;
if (!feature) {
this.generateController('feature');
feature = this.controllerFor('feature');
}
return this.get('session.user')
.then(this.transitionAuthor())
.then(this.transitionEditor())
.then(function () {
return feature.then(function () {
if (!feature.get('passProtectUI')) {
return self.transitionTo('settings.general');
}
});
});
},
model: function () {
return this.store.find('setting', {type: 'blog,theme'}).then(function (records) {
return records.get('firstObject');
});
},
actions: {
save: function () {
this.get('controller').send('save');
}
}
});
export default SettingsPassProtectRoute;

View File

@ -84,6 +84,23 @@
</span>
<p>Select a theme for your blog</p>
</div>
<div class="form-group for-checkbox">
<label for="isPrivate">Make this blog private</label>
<label class="checkbox" for="isPrivate">
{{input id="isPrivate" name="general[isPrivate]" type="checkbox"
checked=model.isPrivate}}
<span class="input-toggle-component"></span>
<p>Enable password protection</p>
</label>
</div>
{{#if model.isPrivate}}
<div class="form-group">
{{input name="general[password]" type="text" value=model.password}}
<p>This password will be needed to access your blog. All search engine optimization and social features are now disabled.</p>
</div>
{{/if}}
</fieldset>
</form>
</section>

View File

@ -44,21 +44,4 @@
</fieldset>
</form>
<hr>
<form>
<fieldset>
<div class="form-group for-checkbox">
<label for="labs-passProtectUI">Password Protection</label>
<label class="checkbox" for="labs-passProtectUI">
{{input id="labs-passProtectUI" name="labs[passProtectUI]" type="checkbox"
checked=usePassProtectUI}}
<span class="input-toggle-component"></span>
<p>Enable the password protection interface</p>
</label>
<p>A settings screen which enables you to add password protection to the front of your blog (work in progress)</p>
</div>
</fieldset>
</form>
</section>

View File

@ -1,29 +0,0 @@
<header class="settings-view-header">
{{#link-to "settings" class="btn btn-default btn-back"}}Back{{/link-to}}
<h2 class="page-title">Password protect your blog</h2>
<section class="page-actions">
<button type="button" class="btn btn-blue" {{action "save"}}>Save</button>
</section>
</header>
<section class="content settings-pass">
<form id="settings-pass" novalidate="novalidate">
<fieldset>
<div class="form-group for-checkbox">
<label for="blog-isPrivate">Make this blog private</label>
<label class="checkbox" for="blog-isPrivate">
{{input id="blog-isPrivate" name="labs[passProtectUI]" type="checkbox"
checked=model.isPrivate}}
<span class="input-toggle-component"></span>
<p>Enable password protection</p>
</label>
</div>
{{#if model.isPrivate}}
<div class="form-group">
{{input name="private[password]" type="text" value=model.password}}
<p>This password will be needed to access your blog. All search engine optimization and social features are now disabled.</p>
</div>
{{/if}}
</fieldset>
</form>
</section>

View File

@ -0,0 +1,10 @@
/* global generatePassword */
function randomPassword() {
var word = generatePassword(6),
randomN = Math.floor(Math.random() * 1000);
return word + randomN;
}
export default randomPassword;

View File

@ -5,7 +5,9 @@ var SettingValidator = Ember.Object.create({
title = model.get('title'),
description = model.get('description'),
email = model.get('email'),
postsPerPage = model.get('postsPerPage');
postsPerPage = model.get('postsPerPage'),
isPrivate = model.get('isPrivate'),
password = model.get('password');
if (!validator.isLength(title, 0, 150)) {
validationErrors.push({message: 'Title is too long'});
@ -19,6 +21,10 @@ var SettingValidator = Ember.Object.create({
validationErrors.push({message: 'Supply a valid email address'});
}
if (isPrivate && password === '') {
validationErrors.push({message: 'Password must be supplied'});
}
if (postsPerPage > 1000) {
validationErrors.push({message: 'The maximum number of posts per page is 1000'});
}

View File

@ -22,6 +22,7 @@
"nanoscroller": "0.8.4",
"normalize-scss": "3.0.2",
"nprogress": "0.1.6",
"password-generator": "git://github.com/bermi/password-generator#49accd7",
"rangyinputs": "1.2.0",
"showdown-ghost": "0.3.6",
"validator-js": "3.39.0",