security settings
This commit is contained in:
parent
abb0e24d99
commit
bcc3b86b4d
@ -1,23 +1,10 @@
|
|||||||
import { Controller, Get, Req, Res, Session } from '@nestjs/common';
|
import { Controller, Get, Redirect } from '@nestjs/common';
|
||||||
import { Request, Response } from 'express';
|
|
||||||
import { SessionData } from 'express-session';
|
|
||||||
import { AppService } from './app.service';
|
|
||||||
|
|
||||||
@Controller()
|
@Controller()
|
||||||
export class AppController {
|
export class AppController {
|
||||||
constructor(private readonly appService: AppService) {}
|
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
getHello(
|
@Redirect('/account/general')
|
||||||
@Session() session: SessionData,
|
getHello() {
|
||||||
@Res() res: Response,
|
return;
|
||||||
@Req() req: Request,
|
|
||||||
): Record<string, any> {
|
|
||||||
if (!session.user) {
|
|
||||||
res.redirect('/login');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.render('index', { user: req.user });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
outline: 0px solid var(--focus-outline);
|
outline: 0px solid var(--focus-outline);
|
||||||
background-color: var(--btn-background);
|
background-color: var(--btn-background);
|
||||||
color: var(--btn-color);
|
color: var(--btn-color);
|
||||||
|
text-shadow: none;
|
||||||
|
text-decoration: none;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
min-width: 120px;
|
min-width: 120px;
|
||||||
transition: background-color 0.35s linear, outline 0.15s linear;
|
transition: background-color 0.35s linear, outline 0.15s linear;
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
.align-self-center {
|
.align-self-center {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
.align-items-start {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
.d-flex {
|
.d-flex {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import { Request, Response } from 'express';
|
|||||||
import { unlink } from 'fs/promises';
|
import { unlink } from 'fs/promises';
|
||||||
import { OAuth2ClientService } from 'src/modules/objects/oauth2-client/oauth2-client.service';
|
import { OAuth2ClientService } from 'src/modules/objects/oauth2-client/oauth2-client.service';
|
||||||
import { UploadService } from 'src/modules/objects/upload/upload.service';
|
import { UploadService } from 'src/modules/objects/upload/upload.service';
|
||||||
|
import { UserTOTPService } from 'src/modules/objects/user-token/user-totp-token.service';
|
||||||
import { UserService } from 'src/modules/objects/user/user.service';
|
import { UserService } from 'src/modules/objects/user/user.service';
|
||||||
import { FormUtilityService } from 'src/modules/utility/services/form-utility.service';
|
import { FormUtilityService } from 'src/modules/utility/services/form-utility.service';
|
||||||
import { TokenService } from 'src/modules/utility/services/token.service';
|
import { TokenService } from 'src/modules/utility/services/token.service';
|
||||||
@ -31,6 +32,7 @@ export class SettingsController {
|
|||||||
private readonly _upload: UploadService,
|
private readonly _upload: UploadService,
|
||||||
private readonly _token: TokenService,
|
private readonly _token: TokenService,
|
||||||
private readonly _user: UserService,
|
private readonly _user: UserService,
|
||||||
|
private readonly _totp: UserTOTPService,
|
||||||
private readonly _client: OAuth2ClientService,
|
private readonly _client: OAuth2ClientService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@ -163,4 +165,116 @@ export class SettingsController {
|
|||||||
}
|
}
|
||||||
res.redirect('/account/oauth2');
|
res.redirect('/account/oauth2');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Get('security')
|
||||||
|
@Render('settings/security')
|
||||||
|
public async security(@Req() req: Request) {
|
||||||
|
const mailSplit = req.user.email.split('@');
|
||||||
|
const emailHint = `${mailSplit[0].substring(0, 1)}***@${mailSplit[1]}`;
|
||||||
|
const twofactor = await this._totp.userHasTOTP(req.user);
|
||||||
|
return this._form.populateTemplate(req, {
|
||||||
|
user: req.user,
|
||||||
|
emailHint,
|
||||||
|
twofactor,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('security/password')
|
||||||
|
public async setPassword(
|
||||||
|
@Req() req: Request,
|
||||||
|
@Res() res: Response,
|
||||||
|
@Body()
|
||||||
|
body: {
|
||||||
|
password: string;
|
||||||
|
new_password: string;
|
||||||
|
password_repeat: string;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
const { password, new_password, password_repeat } = body;
|
||||||
|
try {
|
||||||
|
if (!password || !new_password || !password_repeat) {
|
||||||
|
throw new Error('Please fill out all of the fields.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await this._user.comparePasswords(req.user.password, password))) {
|
||||||
|
throw new Error('Current password is invalid.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!new_password.match(this._form.passwordRegex)) {
|
||||||
|
throw new Error(
|
||||||
|
'Password must be at least 8 characters long, contain a capital and lowercase letter and a number',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_password !== password_repeat) {
|
||||||
|
throw new Error('The passwords do not match.');
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
req.flash('message', {
|
||||||
|
error: true,
|
||||||
|
text: e.message,
|
||||||
|
});
|
||||||
|
res.redirect('/account/security');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newPassword = await this._user.hashPassword(new_password);
|
||||||
|
req.user.password = newPassword;
|
||||||
|
await this._user.updateUser(req.user);
|
||||||
|
|
||||||
|
req.flash('message', {
|
||||||
|
error: false,
|
||||||
|
text: 'Password changed successfully.',
|
||||||
|
});
|
||||||
|
res.redirect('/account/security');
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('security/email')
|
||||||
|
public async setEmail(
|
||||||
|
@Req() req: Request,
|
||||||
|
@Res() res: Response,
|
||||||
|
@Body()
|
||||||
|
body: {
|
||||||
|
current_email: string;
|
||||||
|
email: string;
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
const { current_email, email } = body;
|
||||||
|
try {
|
||||||
|
if (!current_email || !email) {
|
||||||
|
throw new Error('Please fill out all of the fields.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_email !== req.user.email) {
|
||||||
|
throw new Error('The current email address is invalid.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!email.match(this._form.emailRegex)) {
|
||||||
|
throw new Error('The new email address is invalid.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const existing = await this._user.getByEmail(email);
|
||||||
|
if (existing) {
|
||||||
|
throw new Error(
|
||||||
|
'There is already an existing user with this email address.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
req.flash('message', {
|
||||||
|
error: true,
|
||||||
|
text: e.message,
|
||||||
|
});
|
||||||
|
res.redirect('/account/security');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
req.user.email = email;
|
||||||
|
await this._user.updateUser(req.user);
|
||||||
|
|
||||||
|
req.flash('message', {
|
||||||
|
error: false,
|
||||||
|
text: 'Email address changed successfully.',
|
||||||
|
});
|
||||||
|
res.redirect('/account/security');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import { OAuth2Module } from '../oauth2/oauth2.module';
|
|||||||
import { SettingsController } from './settings.controller';
|
import { SettingsController } from './settings.controller';
|
||||||
import { SettingsService } from './settings.service';
|
import { SettingsService } from './settings.service';
|
||||||
import { OAuth2ClientModule } from 'src/modules/objects/oauth2-client/oauth2-client.module';
|
import { OAuth2ClientModule } from 'src/modules/objects/oauth2-client/oauth2-client.module';
|
||||||
|
import { UserTokenModule } from 'src/modules/objects/user-token/user-token.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [SettingsController],
|
controllers: [SettingsController],
|
||||||
@ -26,6 +27,7 @@ import { OAuth2ClientModule } from 'src/modules/objects/oauth2-client/oauth2-cli
|
|||||||
ConfigurationModule,
|
ConfigurationModule,
|
||||||
UploadModule,
|
UploadModule,
|
||||||
UserModule,
|
UserModule,
|
||||||
|
UserTokenModule,
|
||||||
OAuth2Module,
|
OAuth2Module,
|
||||||
OAuth2ClientModule,
|
OAuth2ClientModule,
|
||||||
MulterModule.registerAsync({
|
MulterModule.registerAsync({
|
||||||
|
Reference in New Issue
Block a user