From ed7b8733eef5c88c29b48ca8bab62d805bc80158 Mon Sep 17 00:00:00 2001 From: Evert Prants Date: Sun, 20 Mar 2022 20:21:15 +0200 Subject: [PATCH] logout button --- src/fe/scss/_settings.scss | 51 +++++++++++++++++++ .../features/settings/settings.controller.ts | 14 +++++ src/modules/utility/services/token.service.ts | 4 +- views/settings/layout.pug | 19 ++++--- views/settings/security.pug | 50 ++++++++++++++++++ 5 files changed, 129 insertions(+), 9 deletions(-) create mode 100644 views/settings/security.pug diff --git a/src/fe/scss/_settings.scss b/src/fe/scss/_settings.scss index dd26179..a102245 100644 --- a/src/fe/scss/_settings.scss +++ b/src/fe/scss/_settings.scss @@ -6,6 +6,16 @@ flex-direction: row; padding: 0; + .form-container { + .form-label:first-of-type { + margin-top: 0; + } + } + + .d-flex p:first-of-type { + margin-top: 0; + } + &__nav { padding: 2rem 0rem; background-color: var(--main-darker); @@ -139,4 +149,45 @@ } } } + + &__nav { + &-content { + @include break-on(xs, down) { + display: none; + } + } + + &-mobile { + @include break-on(xs, up) { + display: none; + } + } + + @include break-on(xs, down) { + position: absolute; + background-color: transparent; + padding: 1rem; + + &:hover, + &:focus, + &:focus-within { + left: 0; + top: 0; + right: 0; + padding: 0; + background-color: var(--main-darker); + box-shadow: 0px 6px 62px -14px rgba(0, 0, 0, 0.45); + + & > .settings__nav-content { + display: block; + margin-top: 1rem; + } + + & > .settings__nav-mobile { + display: flex; + justify-content: center; + } + } + } + } } diff --git a/src/modules/features/settings/settings.controller.ts b/src/modules/features/settings/settings.controller.ts index 729dc74..74efa10 100644 --- a/src/modules/features/settings/settings.controller.ts +++ b/src/modules/features/settings/settings.controller.ts @@ -5,6 +5,7 @@ import { Get, Param, Post, + Query, Redirect, Render, Req, @@ -277,4 +278,17 @@ export class SettingsController { }); res.redirect('/account/security'); } + + @Get('logout') + public logOut( + @Req() req: Request, + @Res() res: Response, + @Query('csrf') csrf: string, + ) { + if (!this._token.verifyCSRF(req, csrf)) { + throw new BadRequestException('Invalid csrf token'); + } + + req.session.destroy(() => res.redirect('/login')); + } } diff --git a/src/modules/utility/services/token.service.ts b/src/modules/utility/services/token.service.ts index aae5793..7f59f2c 100644 --- a/src/modules/utility/services/token.service.ts +++ b/src/modules/utility/services/token.service.ts @@ -17,8 +17,8 @@ export class TokenService { constructor(private config: ConfigurationService) {} - public verifyCSRF(req: Request): boolean { - return this.csrf.verify(req.session.csrf, req.body._csrf); + public verifyCSRF(req: Request, token?: string): boolean { + return this.csrf.verify(req.session.csrf, token || req.body._csrf); } public generateString(length: number): string { diff --git a/views/settings/layout.pug b/views/settings/layout.pug index 570a29b..7a053ba 100644 --- a/views/settings/layout.pug +++ b/views/settings/layout.pug @@ -5,12 +5,17 @@ block body div.container div.center-box.settings nav.sidebar.settings__nav - ul - li - a(href="/account/general", class=path === '/account/general' ? 'active' : '') General - li - a(href="/account/oauth2", class=path === '/account/oauth2' ? 'active' : '') Authorizations - li - a(href="/account/security", class=path === '/account/security' ? 'active' : '') Security + .settings__nav-mobile + a.btn.btn-link(href="#") Menu + .settings__nav-content + ul + li + a(href="/account/general", class=path === '/account/general' ? 'active' : '') General + li + a(href="/account/oauth2", class=path === '/account/oauth2' ? 'active' : '') Authorizations + li + a(href="/account/security", class=path === '/account/security' ? 'active' : '') Security + li + a(href="/account/logout?csrf=" + csrf) Log out section.content.settings__content block settings diff --git a/views/settings/security.pug b/views/settings/security.pug new file mode 100644 index 0000000..f0506c9 --- /dev/null +++ b/views/settings/security.pug @@ -0,0 +1,50 @@ +extends ./layout.pug + +block title + |Security - Account settings | Icy Network + +block settings + h1 Security + if message.text + if message.error + .alert.alert-danger + span #{message.text} + else + .alert.alert-success + span #{message.text} + .row + .col + h2 Change Password + form(method="post", action="/account/security/password", autocomplete="off") + div.form-container + input#csrf(type="hidden", name="_csrf", value=csrf) + label.form-label(for="password") Current Password + input.form-control#password(type="password", name="password") + label.form-label(for="new_password") New Password + input.form-control#new_password(type="password", name="new_password", autocomplete="new-password") + label.form-label(for="password_repeat") Repeat new password + input.form-control#password_repeat(type="password", name="password_repeat") + button.btn.btn-primary(type="submit") Change + .col + h2 Change Email Address + form(method="post", action="/account/security/email", autocomplete="off") + div.form-container + input#csrf(type="hidden", name="_csrf", value=csrf) + label.form-label(for="current_email") Current Email Address + input.form-control#current_email(type="email", name="current_email") + small.form-hint Hint: #{emailHint} + label.form-label(for="email") New Email Address + input.form-control#email(type="email", name="email") + button.btn.btn-primary(type="submit") Change + h2 Two-factor authentication + .d-flex.flex-column.align-items-start + if twofactor + p Two-factor authentication is enabled. + a.btn.btn-primary(href="/account/two-factor/disable") Disable + else + p You can enable two-factor authentication using an authenticator app of your choice, such as + b Google Authenticator + | or + b andOTP + |. + a.btn.btn-primary(href="/account/two-factor/activate") Activate