mirror of
https://github.com/flarum/core.git
synced 2025-08-05 16:07:34 +02:00
Overhaul sessions, tokens, and authentication
- Use cookies + CSRF token for API authentication in the default client. This mitigates potential XSS attacks by making the token unavailable to JavaScript. The Authorization header is still supported, but not used by default. - Make sensitive/destructive actions (editing a user, permanently deleting anything, visiting the admin CP) require the user to re-enter their password if they haven't entered it in the last 30 minutes. - Refactor and clean up the authentication middleware. - Add an `onhide` hook to the Modal component. (+1 squashed commit)
This commit is contained in:
@@ -81,10 +81,17 @@ export default class ChangeEmailModal extends Modal {
|
||||
return;
|
||||
}
|
||||
|
||||
const oldEmail = app.session.user.email();
|
||||
|
||||
this.loading = true;
|
||||
|
||||
app.session.user.save({email: this.email()}, {errorHandler: this.onerror.bind(this)})
|
||||
.then(() => this.success = true)
|
||||
.finally(this.loaded.bind(this));
|
||||
|
||||
// The save method will update the cached email address on the user model...
|
||||
// But in the case of a "sudo" password prompt, we'll still want to have
|
||||
// the old email address on file for the purposes of logging in.
|
||||
app.session.user.pushAttributes({email: oldEmail});
|
||||
}
|
||||
}
|
||||
|
@@ -124,8 +124,10 @@ export default class LogInModal extends Modal {
|
||||
const email = this.email();
|
||||
const password = this.password();
|
||||
|
||||
app.session.login(email, password, {errorHandler: this.onerror.bind(this)})
|
||||
.catch(this.loaded.bind(this));
|
||||
app.session.login(email, password, {errorHandler: this.onerror.bind(this)}).then(
|
||||
() => window.location.reload(),
|
||||
this.loaded.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
onerror(error) {
|
||||
|
@@ -18,6 +18,8 @@ import ItemList from 'flarum/utils/ItemList';
|
||||
*/
|
||||
export default class Post extends Component {
|
||||
init() {
|
||||
this.loading = false;
|
||||
|
||||
/**
|
||||
* Set up a subtree retainer so that the post will not be redrawn
|
||||
* unless new data comes in.
|
||||
@@ -37,7 +39,7 @@ export default class Post extends Component {
|
||||
view() {
|
||||
const attrs = this.attrs();
|
||||
|
||||
attrs.className = 'Post ' + (attrs.className || '');
|
||||
attrs.className = 'Post ' + (this.loading ? 'Post--loading ' : '') + (attrs.className || '');
|
||||
|
||||
return (
|
||||
<article {...attrs}>
|
||||
|
@@ -217,18 +217,19 @@ export default {
|
||||
*/
|
||||
deleteAction() {
|
||||
if (confirm(extractText(app.translator.trans('core.forum.discussion_controls.delete_confirmation')))) {
|
||||
// If there is a discussion list in the cache, remove this discussion.
|
||||
if (app.cache.discussionList) {
|
||||
app.cache.discussionList.removeDiscussion(this);
|
||||
}
|
||||
|
||||
// If we're currently viewing the discussion that was deleted, go back
|
||||
// to the previous page.
|
||||
if (app.viewingDiscussion(this)) {
|
||||
app.history.back();
|
||||
}
|
||||
|
||||
return this.delete();
|
||||
return this.delete().then(() => {
|
||||
// If there is a discussion list in the cache, remove this discussion.
|
||||
if (app.cache.discussionList) {
|
||||
app.cache.discussionList.removeDiscussion(this);
|
||||
m.redraw();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
@@ -78,7 +78,7 @@ export default {
|
||||
* @return {ItemList}
|
||||
* @protected
|
||||
*/
|
||||
destructiveControls(post) {
|
||||
destructiveControls(post, context) {
|
||||
const items = new ItemList();
|
||||
|
||||
if (post.contentType() === 'comment' && !post.isHidden()) {
|
||||
@@ -101,7 +101,7 @@ export default {
|
||||
items.add('delete', Button.component({
|
||||
icon: 'times',
|
||||
children: app.translator.trans('core.forum.post_controls.delete_forever_button'),
|
||||
onclick: this.deleteAction.bind(post)
|
||||
onclick: this.deleteAction.bind(post, context)
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -144,9 +144,14 @@ export default {
|
||||
*
|
||||
* @return {Promise}
|
||||
*/
|
||||
deleteAction() {
|
||||
this.discussion().removePost(this.id());
|
||||
deleteAction(context) {
|
||||
if (context) context.loading = true;
|
||||
|
||||
return this.delete();
|
||||
return this.delete().then(() => {
|
||||
this.discussion().removePost(this.id());
|
||||
}).finally(() => {
|
||||
if (context) context.loading = false;
|
||||
m.redraw();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user