diff --git a/public/image/avatar.png b/public/image/avatar.png new file mode 100644 index 0000000..25ce30e Binary files /dev/null and b/public/image/avatar.png differ diff --git a/public/image/icynet-icon-analytics.svg b/public/image/icynet-icon-analytics.svg new file mode 100644 index 0000000..2eacb6b --- /dev/null +++ b/public/image/icynet-icon-analytics.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/public/image/icynet-icon-git.svg b/public/image/icynet-icon-git.svg new file mode 100644 index 0000000..86b8a2c --- /dev/null +++ b/public/image/icynet-icon-git.svg @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/public/image/icynet-icon-large.png b/public/image/icynet-icon-large.png new file mode 100644 index 0000000..69c4eb0 Binary files /dev/null and b/public/image/icynet-icon-large.png differ diff --git a/public/image/icynet-icon-pleroma.svg b/public/image/icynet-icon-pleroma.svg new file mode 100644 index 0000000..94843f1 --- /dev/null +++ b/public/image/icynet-icon-pleroma.svg @@ -0,0 +1,103 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/public/image/icynet-icon.png b/public/image/icynet-icon.png new file mode 100644 index 0000000..0fa1c85 Binary files /dev/null and b/public/image/icynet-icon.png differ diff --git a/public/image/icynet-icon.svg b/public/image/icynet-icon.svg new file mode 100644 index 0000000..7c21d99 --- /dev/null +++ b/public/image/icynet-icon.svg @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + ICYnet + ICYnet + + diff --git a/public/image/icynet-large.png b/public/image/icynet-large.png new file mode 100644 index 0000000..bda0598 Binary files /dev/null and b/public/image/icynet-large.png differ diff --git a/public/image/icynet-small.png b/public/image/icynet-small.png new file mode 100644 index 0000000..73abf84 Binary files /dev/null and b/public/image/icynet-small.png differ diff --git a/public/image/icynet.ico b/public/image/icynet.ico new file mode 100644 index 0000000..6e135cf Binary files /dev/null and b/public/image/icynet.ico differ diff --git a/public/image/icynet.svg b/public/image/icynet.svg new file mode 100644 index 0000000..a4ae9c8 --- /dev/null +++ b/public/image/icynet.svg @@ -0,0 +1,152 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + NETWORK + + + + ICY + + diff --git a/public/image/squeebot.svg b/public/image/squeebot.svg new file mode 100644 index 0000000..2beb9e1 --- /dev/null +++ b/public/image/squeebot.svg @@ -0,0 +1,703 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/app.module.ts b/src/app.module.ts index e736cc2..a1675a4 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -2,7 +2,6 @@ import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { CSRFMiddleware } from './middleware/csrf.middleware'; -import { FlashMiddleware } from './middleware/flash.middleware'; import { LoginModule } from './modules/features/login/login.module'; import { OAuth2Module } from './modules/features/oauth2/oauth2.module'; import { RegisterModule } from './modules/features/register/register.module'; @@ -33,8 +32,5 @@ import { UtilityModule } from './modules/utility/utility.module'; export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer.apply(CSRFMiddleware).forRoutes('*'); - consumer - .apply(FlashMiddleware) - .forRoutes('login', 'register', 'login/verify', 'two-factor'); } } diff --git a/src/modules/features/login/login.controller.ts b/src/modules/features/login/login.controller.ts index 6aa942e..706adc6 100644 --- a/src/modules/features/login/login.controller.ts +++ b/src/modules/features/login/login.controller.ts @@ -25,7 +25,7 @@ export class LoginController { ) {} @Get() - @Render('login') + @Render('login/login') public loginView( @Session() session: SessionData, @Req() req: Request, @@ -92,7 +92,10 @@ export class LoginController { return; } - res.render('totp-verify', this.formUtil.populateTemplate(req, session)); + res.render( + 'login/totp-verify', + this.formUtil.populateTemplate(req, session), + ); } @Post('verify') diff --git a/src/modules/features/login/login.module.ts b/src/modules/features/login/login.module.ts index 7435150..d51f393 100644 --- a/src/modules/features/login/login.module.ts +++ b/src/modules/features/login/login.module.ts @@ -4,6 +4,7 @@ import { NestModule, RequestMethod, } from '@nestjs/common'; +import { FlashMiddleware } from 'src/middleware/flash.middleware'; import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware'; import { UserModule } from 'src/modules/objects/user/user.module'; import { LoginController } from './login.controller'; @@ -17,5 +18,7 @@ export class LoginModule implements NestModule { consumer .apply(ValidateCSRFMiddleware) .forRoutes({ path: '*', method: RequestMethod.POST }); + + consumer.apply(FlashMiddleware).forRoutes('*'); } } diff --git a/src/modules/features/register/register.module.ts b/src/modules/features/register/register.module.ts index ad14c66..b04d152 100644 --- a/src/modules/features/register/register.module.ts +++ b/src/modules/features/register/register.module.ts @@ -4,6 +4,7 @@ import { NestModule, RequestMethod, } from '@nestjs/common'; +import { FlashMiddleware } from 'src/middleware/flash.middleware'; import { ValidateCSRFMiddleware } from 'src/middleware/validate-csrf.middleware'; import { UserModule } from 'src/modules/objects/user/user.module'; import { RegisterController } from './register.controller'; @@ -17,5 +18,7 @@ export class RegisterModule implements NestModule { consumer .apply(ValidateCSRFMiddleware) .forRoutes({ path: '*', method: RequestMethod.POST }); + + consumer.apply(FlashMiddleware).forRoutes('*'); } } diff --git a/src/modules/features/twofactor/twofactor.module.ts b/src/modules/features/twofactor/twofactor.module.ts index 3e6ed4b..b0e6a18 100644 --- a/src/modules/features/twofactor/twofactor.module.ts +++ b/src/modules/features/twofactor/twofactor.module.ts @@ -1,5 +1,6 @@ import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common'; import { AuthMiddleware } from 'src/middleware/auth.middleware'; +import { FlashMiddleware } from 'src/middleware/flash.middleware'; import { UserModule } from 'src/modules/objects/user/user.module'; import { TwoFactorController } from './twofactor.controller'; @@ -10,5 +11,6 @@ import { TwoFactorController } from './twofactor.controller'; export class TwoFactorModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer.apply(AuthMiddleware).forRoutes('two-factor'); + consumer.apply(FlashMiddleware).forRoutes('*'); } } diff --git a/src/scss/_alert.scss b/src/scss/_alert.scss new file mode 100644 index 0000000..48409d4 --- /dev/null +++ b/src/scss/_alert.scss @@ -0,0 +1,12 @@ +.alert { + padding: 16px; + border-radius: 4px; + + &-danger { + background-color: #ff292999; + } + + &-success { + background-color: #12930099; + } +} diff --git a/src/scss/_block.scss b/src/scss/_block.scss new file mode 100644 index 0000000..45c1d3d --- /dev/null +++ b/src/scss/_block.scss @@ -0,0 +1,29 @@ +.wrapper { +} + +.container { + max-width: 1200px; + margin: auto; +} + +.center-box { + max-width: 800px; + background-color: #2e6b81; + color: #fff; + margin: 2rem auto; + padding: 4rem; + + box-shadow: 0px 6px 62px -14px rgba(0, 0, 0, 0.45); + -webkit-box-shadow: 0px 6px 62px -14px rgba(0, 0, 0, 0.45); + -moz-box-shadow: 0px 6px 62px -14px rgba(0, 0, 0, 0.45); + + h1:first-of-type { + margin-top: 0; + text-align: center; + } +} + +.logo-container { + text-align: center; + margin-top: 2rem; +} diff --git a/src/scss/_button.scss b/src/scss/_button.scss new file mode 100644 index 0000000..536e2b6 --- /dev/null +++ b/src/scss/_button.scss @@ -0,0 +1,37 @@ +.btn { + padding: 12px 24px; + font-size: 1rem; + appearance: none; + border: none; + border-radius: 4px; + cursor: pointer; + outline: 0px solid #00c0ff8a; + + min-width: 120px; + transition: background-color 0.35s linear, outline 0.15s linear; + + &-link { + font-size: 1rem; + color: #fff; + padding: 12px; + } + + background-color: var(--btn-background); + color: var(--btn-color); + + &:hover { + background-color: var(--btn-background-hover); + } + + &:focus { + outline: 4px solid #00c0ff8a; + } + + &-primary { + --btn-background: #00c4ff; + --btn-background-hover: #3ed2ff; + --btn-color: #002d34; + text-transform: uppercase; + font-weight: 500; + } +} diff --git a/src/scss/_flex.scss b/src/scss/_flex.scss new file mode 100644 index 0000000..793fb7d --- /dev/null +++ b/src/scss/_flex.scss @@ -0,0 +1,18 @@ +.align-self-end { + align-self: end; +} +.align-self-start { + align-self: start; +} +.align-self-center { + align-self: center; +} +.d-flex { + display: flex; +} +.flex-column { + flex-direction: column; +} +.flex-row { + flex-direction: row; +} diff --git a/src/scss/_form.scss b/src/scss/_form.scss new file mode 100644 index 0000000..32b18c1 --- /dev/null +++ b/src/scss/_form.scss @@ -0,0 +1,33 @@ +.form-container { + display: flex; + flex-direction: column; + + .btn { + margin-top: 1rem; + } +} + +.form-label { + margin-top: 1rem; + text-transform: uppercase; + font-weight: 600; + margin-bottom: 0.25rem; +} + +input.form-control { + padding: 8px; + font-size: 1rem; + border-radius: 4px; + border: 1px solid #707070; + + transition: outline 0.15s linear; + + &:focus { + outline: 4px solid #00c0ff8a; + } + + &:hover, + &:focus { + border: 1px solid #5c5c5c; + } +} diff --git a/src/scss/_index.scss b/src/scss/_index.scss index f928e46..86bdf0c 100644 --- a/src/scss/_index.scss +++ b/src/scss/_index.scss @@ -1,3 +1,9 @@ +@import 'block'; +@import 'form'; +@import 'button'; +@import 'flex'; +@import 'alert'; + *, *::before, *::after { @@ -6,8 +12,6 @@ html, body { - width: 100%; - height: 100%; margin: 0; padding: 0; } @@ -15,4 +19,5 @@ body { body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; + background-color: #314550; } diff --git a/views/index.pug b/views/index.pug index daa6c5b..4118704 100644 --- a/views/index.pug +++ b/views/index.pug @@ -4,6 +4,9 @@ block title |Icy Network block body - h1 Hello world! - if user - h2 Logged in as #{ user.display_name } + include partials/logo.pug + div.container + div.center-box + h1 Hello, #{ user.display_name }! + p No pending authorization requests found. + p Have a good day! diff --git a/views/login.pug b/views/login.pug deleted file mode 100644 index fa386b4..0000000 --- a/views/login.pug +++ /dev/null @@ -1,20 +0,0 @@ -extends partials/layout.pug - -block title - |Icy Network | Log in - -block body - h1 Log in - if message.text - if message.error - .alert.alert-danger - span #{message.text} - else - .alert.alert-success - span #{message.text} - - form(method="post") - input#csrf(type="hidden", name="csrf", value=csrf) - input#username(type="text", name="username", placeholder="Username", value=form.username) - input#password(type="password", name="password", placeholder="Password") - button(type="submit") Log in diff --git a/views/login/login.pug b/views/login/login.pug new file mode 100644 index 0000000..9b1f8c6 --- /dev/null +++ b/views/login/login.pug @@ -0,0 +1,27 @@ +extends ../partials/layout.pug + +block title + |Icy Network | Log in + +block body + include ../partials/logo.pug + div.container + div.center-box + h1 Log in + if message.text + if message.error + .alert.alert-danger + span #{message.text} + else + .alert.alert-success + span #{message.text} + + form(method="post") + div.form-container + input#csrf(type="hidden", name="csrf", value=csrf) + label.form-label(for="username") Username + input.form-control#username(type="text", name="username", placeholder="Username", value=form.username) + label.form-label(for="password") Password + input.form-control#password(type="password", name="password", placeholder="Password") + button.btn.btn-primary(type="submit") Log in + a.btn.btn-link.align-self-end(type="button" href="/register") Create a new account diff --git a/views/login/totp-verify.pug b/views/login/totp-verify.pug new file mode 100644 index 0000000..d461e6e --- /dev/null +++ b/views/login/totp-verify.pug @@ -0,0 +1,24 @@ +extends ../partials/layout.pug + +block title + |Icy Network | Veify two-factor + +block body + include ../partials/logo.pug + div.container + div.center-box + h1 Verify two-factor authentication + if message.text + if message.error + .alert.alert-danger + span #{message.text} + else + .alert.alert-success + span #{message.text} + + form(method="post") + div.form-container + input#csrf(type="hidden", name="csrf", value=csrf) + label.form-label(for="totp") Code + input.form-control#totp(type="text", name="totp", placeholder="xxxxxx") + button.btn.btn-primary(type="submit") Log in diff --git a/views/partials/layout.pug b/views/partials/layout.pug index 0e6a64f..bd612e0 100644 --- a/views/partials/layout.pug +++ b/views/partials/layout.pug @@ -16,5 +16,6 @@ html(lang="en") link(rel="stylesheet", type="text/css", href="/public/css/index.css") title block title - body - block body + body + main.wrapper + block body diff --git a/views/partials/logo.pug b/views/partials/logo.pug new file mode 100644 index 0000000..57e7478 --- /dev/null +++ b/views/partials/logo.pug @@ -0,0 +1,2 @@ +div.logo-container + img(src="/public/image/icynet-icon.svg", alt="Icy Network") diff --git a/views/register.pug b/views/register.pug index 14ed1f5..066fa4a 100644 --- a/views/register.pug +++ b/views/register.pug @@ -4,21 +4,30 @@ block title |Icy Network | Register block body - h1 Register - if message.text - if message.error - .alert.alert-danger - span #{message.text} - else - .alert.alert-success - span #{message.text} + include partials/logo.pug + div.container + div.center-box + h1 Register + if message.text + if message.error + .alert.alert-danger + span #{message.text} + else + .alert.alert-success + span #{message.text} - form(method="post") - input#csrf(type="hidden", name="csrf", value=csrf) - input#username(type="text", name="username", placeholder="Username", value=form.username) - input#display_name(type="text", name="display_name", placeholder="Display name", value=form.display_name) - input#email(type="email", name="email", placeholder="Email address", value=form.email) - input#password(type="password", name="password", placeholder="Password", value=form.password) - input#password_repeat(type="password", name="password_repeat", placeholder="Confirm password") - button(type="submit") Create a new account - a(type="button" href="/login") Log in + form(method="post") + div.form-container + input#csrf(type="hidden", name="csrf", value=csrf) + label.form-label(for="username") Username + input.form-control#username(type="text", name="username", placeholder="Username", value=form.username) + label.form-label(for="display_name") Display name + input.form-control#display_name(type="text", name="display_name", placeholder="Display name", value=form.display_name) + label.form-label(for="email") Email address + input.form-control#email(type="email", name="email", placeholder="Email address", value=form.email) + label.form-label(for="password") Password + input.form-control#password(type="password", name="password", placeholder="Password", value=form.password) + label.form-label(for="password_repeat") Confirm password + input.form-control#password_repeat(type="password", name="password_repeat", placeholder="Confirm password") + button.btn.btn-primary(type="submit") Create a new account + a.btn.btn-link.align-self-end(type="button" href="/login") Log in instead diff --git a/views/totp-verify.pug b/views/totp-verify.pug deleted file mode 100644 index 09d2e9f..0000000 --- a/views/totp-verify.pug +++ /dev/null @@ -1,19 +0,0 @@ -extends partials/layout.pug - -block title - |Icy Network | Veify two-factor - -block body - h1 Verify two-factor authentication - if message.text - if message.error - .alert.alert-danger - span #{message.text} - else - .alert.alert-success - span #{message.text} - - form(method="post") - input#csrf(type="hidden", name="csrf", value=csrf) - input#totp(type="text", name="totp", placeholder="Code") - button(type="submit") Log in diff --git a/views/two-factor/activate.pug b/views/two-factor/activate.pug index eb74f25..3000ad3 100644 --- a/views/two-factor/activate.pug +++ b/views/two-factor/activate.pug @@ -4,18 +4,24 @@ block title |Icy Network | Two-factor authentication block body - h1 Activate two-factor authentication - if message.text - if message.error - .alert.alert-danger - span #{message.text} - else - .alert.alert-success - span #{message.text} - - img(src=qrcode) + include ../partials/logo.pug + div.container + div.center-box + h1 Activate two-factor authentication + if message.text + if message.error + .alert.alert-danger + span #{message.text} + else + .alert.alert-success + span #{message.text} + + div.qr-preview + img(src=qrcode) - form(method="post") - input#csrf(type="hidden", name="csrf", value=csrf) - input#code(type="text", name="code", placeholder="Code from app") - button(type="submit") Activate + form(method="post") + div.form-container + input#csrf(type="hidden", name="csrf", value=csrf) + label.form-label(for="code") Code from authenticator app + input.form-control#code(type="text", name="code", placeholder="xxxxxx") + button.btn.btn-primary(type="submit") Activate