mirror of
https://github.com/flarum/core.git
synced 2025-07-31 13:40:20 +02:00
feat: global logout to clear all sessions, access tokens, email tokens and password tokens (#3605)
* chore: re-organize security locale keys alphabetically * test: can globally logout * feat: add global logout controller * feat: add global logout UI to user security page * test: re-adapt tests to changes * feat: add boolean to indicate if logout even is global * chore(review): split loading property * chore: follow-up branch update Signed-off-by: Sami Mazouz <sychocouldy@gmail.com>
This commit is contained in:
@@ -57,12 +57,30 @@ export default class UserSecurityPage<CustomAttrs extends IUserPageAttrs = IUser
|
||||
|
||||
items.add(
|
||||
section,
|
||||
<FieldSet className={`Security-${section}`} label={app.translator.trans(`core.forum.security.${sectionLocale}_heading`)}>
|
||||
<FieldSet className={`UserSecurityPage-${section}`} label={app.translator.trans(`core.forum.security.${sectionLocale}_heading`)}>
|
||||
{this[sectionName]().toArray()}
|
||||
</FieldSet>
|
||||
);
|
||||
});
|
||||
|
||||
if (this.user!.id() === app.session.user!.id()) {
|
||||
items.add(
|
||||
'globalLogout',
|
||||
<FieldSet className="UserSecurityPage-globalLogout" label={app.translator.trans('core.forum.security.global_logout.heading')}>
|
||||
<span className="helpText">{app.translator.trans('core.forum.security.global_logout.help_text')}</span>
|
||||
<Button
|
||||
className="Button"
|
||||
icon="fas fa-sign-out-alt"
|
||||
onclick={this.globalLogout.bind(this)}
|
||||
loading={this.state.loadingGlobalLogout}
|
||||
disabled={this.state.loadingTerminateSessions}
|
||||
>
|
||||
{app.translator.trans('core.forum.security.global_logout.log_out_button')}
|
||||
</Button>
|
||||
</FieldSet>
|
||||
);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -141,7 +159,12 @@ export default class UserSecurityPage<CustomAttrs extends IUserPageAttrs = IUser
|
||||
const isDisabled = !this.state.hasOtherActiveSessions();
|
||||
|
||||
let terminateAllOthersButton = (
|
||||
<Button className="Button" onclick={this.terminateAllOtherSessions.bind(this)} loading={this.state.isLoading()} disabled={isDisabled}>
|
||||
<Button
|
||||
className="Button"
|
||||
onclick={this.terminateAllOtherSessions.bind(this)}
|
||||
loading={this.state.loadingTerminateSessions}
|
||||
disabled={this.state.loadingGlobalLogout || isDisabled}
|
||||
>
|
||||
{app.translator.trans('core.forum.security.terminate_all_other_sessions')}
|
||||
</Button>
|
||||
);
|
||||
@@ -174,7 +197,7 @@ export default class UserSecurityPage<CustomAttrs extends IUserPageAttrs = IUser
|
||||
terminateAllOtherSessions() {
|
||||
if (!confirm(extractText(app.translator.trans('core.forum.security.terminate_all_other_sessions_confirmation')))) return;
|
||||
|
||||
this.state.setLoading(true);
|
||||
this.state.loadingTerminateSessions = true;
|
||||
|
||||
return app
|
||||
.request({
|
||||
@@ -188,12 +211,28 @@ export default class UserSecurityPage<CustomAttrs extends IUserPageAttrs = IUser
|
||||
this.state.removeOtherSessionTokens();
|
||||
|
||||
app.alerts.show({ type: 'success' }, app.translator.trans('core.forum.security.session_terminated', { count }));
|
||||
|
||||
m.redraw();
|
||||
})
|
||||
.catch(() => {
|
||||
app.alerts.show({ type: 'error' }, app.translator.trans('core.forum.security.session_termination_failed'));
|
||||
})
|
||||
.finally(() => this.state.setLoading(false));
|
||||
.finally(() => {
|
||||
this.state.loadingTerminateSessions = false;
|
||||
m.redraw();
|
||||
});
|
||||
}
|
||||
|
||||
globalLogout() {
|
||||
this.state.loadingGlobalLogout = true;
|
||||
|
||||
return app
|
||||
.request({
|
||||
method: 'POST',
|
||||
url: app.forum.attribute<string>('baseUrl') + '/global-logout',
|
||||
})
|
||||
.then(() => window.location.reload())
|
||||
.finally(() => {
|
||||
this.state.loadingGlobalLogout = false;
|
||||
m.redraw();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -2,20 +2,13 @@ import AccessToken from '../../common/models/AccessToken';
|
||||
|
||||
export default class UserSecurityPageState {
|
||||
protected tokens: AccessToken[] | null = null;
|
||||
protected loading: boolean = false;
|
||||
|
||||
public isLoading(): boolean {
|
||||
return this.loading;
|
||||
}
|
||||
public loadingTerminateSessions: boolean = false;
|
||||
public loadingGlobalLogout: boolean = false;
|
||||
|
||||
public hasLoadedTokens(): boolean {
|
||||
return this.tokens !== null;
|
||||
}
|
||||
|
||||
public setLoading(loading: boolean): void {
|
||||
this.loading = loading;
|
||||
}
|
||||
|
||||
public getTokens(): AccessToken[] | null {
|
||||
return this.tokens;
|
||||
}
|
||||
|
Reference in New Issue
Block a user