remove some anys
This commit is contained in:
parent
9c7820dc94
commit
33080558bc
@ -35,7 +35,7 @@ export class OAuth2Guard implements CanActivate {
|
|||||||
})
|
})
|
||||||
.catch(reject);
|
.catch(reject);
|
||||||
});
|
});
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
reject(e);
|
reject(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -22,7 +22,7 @@ export class FlashMiddleware implements NestMiddleware {
|
|||||||
|
|
||||||
return msgs;
|
return msgs;
|
||||||
} else {
|
} else {
|
||||||
result = msg.length > 1 ? format(...msg) : msg[0];
|
result = (msg.length > 1 ? format(...msg) : msg[0]) as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (msgs[type] = msgs[type] || []).push(result);
|
return (msgs[type] = msgs[type] || []).push(result);
|
||||||
|
@ -204,7 +204,7 @@ export class UserAdminController {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await this._user.sendActivationEmail(user);
|
await this._user.sendActivationEmail(user);
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
error = e as Error;
|
error = e as Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +229,7 @@ export class UserAdminController {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await this._user.sendPasswordEmail(user);
|
await this._user.sendPasswordEmail(user);
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
error = e as Error;
|
error = e as Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ export class ApiController {
|
|||||||
// Management scope allows access to basically everything anyway
|
// Management scope allows access to basically everything anyway
|
||||||
const scopelessAccess = scope.includes('management');
|
const scopelessAccess = scope.includes('management');
|
||||||
|
|
||||||
const userData: Record<string, any> = {
|
const userData: Record<string, unknown> = {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
uuid: user.uuid,
|
uuid: user.uuid,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
|
@ -23,8 +23,13 @@ export interface EmailConfiguration {
|
|||||||
|
|
||||||
export interface AppConfiguration {
|
export interface AppConfiguration {
|
||||||
base_url: string;
|
base_url: string;
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
session_name: string;
|
||||||
session_secret: string;
|
session_secret: string;
|
||||||
challenge_secret: string;
|
challenge_secret: string;
|
||||||
|
registrations: boolean;
|
||||||
|
redis_url?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Configuration {
|
export interface Configuration {
|
||||||
|
@ -2,16 +2,16 @@ import * as toml from 'toml';
|
|||||||
import { resolve } from 'path';
|
import { resolve } from 'path';
|
||||||
import { readFile } from 'fs/promises';
|
import { readFile } from 'fs/promises';
|
||||||
import { Configuration } from './config.interfaces';
|
import { Configuration } from './config.interfaces';
|
||||||
import { Provider } from '@nestjs/common';
|
import { FactoryProvider, ValueProvider } from '@nestjs/common';
|
||||||
|
|
||||||
const CONFIG_ENV = process.env.NODE_ENV === 'production' ? 'prod' : 'dev';
|
const CONFIG_ENV = process.env.NODE_ENV === 'production' ? 'prod' : 'dev';
|
||||||
const CONFIG_FILENAME = process.env.CONFIG || `config.${CONFIG_ENV}.toml`;
|
const CONFIG_FILENAME = process.env.CONFIG || `config.${CONFIG_ENV}.toml`;
|
||||||
|
|
||||||
export const configProviders: Provider<any>[] = [
|
export const configProviders = [
|
||||||
{
|
{
|
||||||
provide: 'CONFIG_PATH',
|
provide: 'CONFIG_PATH',
|
||||||
useValue: resolve(__dirname, '..', '..', '..', CONFIG_FILENAME),
|
useValue: resolve(__dirname, '..', '..', '..', CONFIG_FILENAME),
|
||||||
},
|
} as ValueProvider<string>,
|
||||||
{
|
{
|
||||||
provide: 'DEFAULT_CONFIG',
|
provide: 'DEFAULT_CONFIG',
|
||||||
useValue: {
|
useValue: {
|
||||||
@ -57,7 +57,7 @@ export const configProviders: Provider<any>[] = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as Configuration,
|
} as Configuration,
|
||||||
},
|
} as ValueProvider<Configuration>,
|
||||||
{
|
{
|
||||||
provide: 'CONFIGURATION',
|
provide: 'CONFIGURATION',
|
||||||
useFactory: async (
|
useFactory: async (
|
||||||
@ -70,11 +70,11 @@ export const configProviders: Provider<any>[] = [
|
|||||||
...defaultConfig,
|
...defaultConfig,
|
||||||
...JSON.parse(JSON.stringify(toml.parse(file))),
|
...JSON.parse(JSON.stringify(toml.parse(file))),
|
||||||
};
|
};
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
console.error('Failed to load configuration:', e.message);
|
console.error('Failed to load configuration:', (e as Error).message);
|
||||||
return defaultConfig;
|
return defaultConfig;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
inject: ['CONFIG_PATH', 'DEFAULT_CONFIG'],
|
inject: ['CONFIG_PATH', 'DEFAULT_CONFIG'],
|
||||||
},
|
} as FactoryProvider<Configuration>,
|
||||||
];
|
];
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { readFile } from 'fs/promises';
|
import { readFile } from 'fs/promises';
|
||||||
import { Provider } from '@nestjs/common';
|
import { FactoryProvider, ValueProvider } from '@nestjs/common';
|
||||||
|
|
||||||
export const jwtProviders: Provider<any>[] = [
|
export const jwtProviders = [
|
||||||
{
|
{
|
||||||
provide: 'PRIVATE_PATH',
|
provide: 'PRIVATE_PATH',
|
||||||
useValue: join(__dirname, '..', '..', '..', 'private'),
|
useValue: join(__dirname, '..', '..', '..', 'private'),
|
||||||
},
|
} as ValueProvider<string>,
|
||||||
{
|
{
|
||||||
provide: 'JWT_PRIVATE_KEY',
|
provide: 'JWT_PRIVATE_KEY',
|
||||||
useFactory: async (path: string) => readFile(join(path, 'jwt.private.pem')),
|
useFactory: async (path: string) => readFile(join(path, 'jwt.private.pem')),
|
||||||
inject: ['PRIVATE_PATH'],
|
inject: ['PRIVATE_PATH'],
|
||||||
},
|
} as FactoryProvider<Buffer>,
|
||||||
{
|
{
|
||||||
provide: 'JWT_PUBLIC_KEY',
|
provide: 'JWT_PUBLIC_KEY',
|
||||||
useFactory: async (path: string) => readFile(join(path, 'jwt.public.pem')),
|
useFactory: async (path: string) => readFile(join(path, 'jwt.public.pem')),
|
||||||
inject: ['PRIVATE_PATH'],
|
inject: ['PRIVATE_PATH'],
|
||||||
},
|
} as FactoryProvider<Buffer>,
|
||||||
];
|
];
|
||||||
|
@ -10,13 +10,13 @@ import * as jwt from 'jsonwebtoken';
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class JWTService {
|
export class JWTService {
|
||||||
constructor(
|
constructor(
|
||||||
@Inject('JWT_PRIVATE_KEY') private _privateKey: string,
|
@Inject('JWT_PRIVATE_KEY') private _privateKey: Buffer,
|
||||||
@Inject('JWT_PUBLIC_KEY') private _publicKey: string,
|
@Inject('JWT_PUBLIC_KEY') private _publicKey: Buffer,
|
||||||
private _config: ConfigurationService,
|
private _config: ConfigurationService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public issue(
|
public issue(
|
||||||
claims: Record<string, any>,
|
claims: Record<string, unknown>,
|
||||||
subject: string,
|
subject: string,
|
||||||
audience?: string,
|
audience?: string,
|
||||||
): string {
|
): string {
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import { Provider } from '@nestjs/common';
|
import { FactoryProvider, ValueProvider } from '@nestjs/common';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource, Repository } from 'typeorm';
|
||||||
|
|
||||||
import { Document } from './document.entity';
|
import { Document } from './document.entity';
|
||||||
|
|
||||||
export const documentProviders: Provider<any>[] = [
|
export const documentProviders = [
|
||||||
{
|
{
|
||||||
provide: 'DOCUMENT_CACHE',
|
provide: 'DOCUMENT_CACHE',
|
||||||
useValue: join(process.cwd(), '.cache'),
|
useValue: join(process.cwd(), '.cache'),
|
||||||
},
|
} as ValueProvider<string>,
|
||||||
{
|
{
|
||||||
provide: 'DOCUMENT_REPOSITORY',
|
provide: 'DOCUMENT_REPOSITORY',
|
||||||
useFactory: (dataSource: DataSource) => dataSource.getRepository(Document),
|
useFactory: (dataSource: DataSource) => dataSource.getRepository(Document),
|
||||||
inject: ['DATA_SOURCE'],
|
inject: ['DATA_SOURCE'],
|
||||||
},
|
} as FactoryProvider<Repository<Document>>,
|
||||||
];
|
];
|
||||||
|
@ -17,7 +17,7 @@ export class EmailService {
|
|||||||
text: string,
|
text: string,
|
||||||
html?: string,
|
html?: string,
|
||||||
from = this.config.get<string>('email.from'),
|
from = this.config.get<string>('email.from'),
|
||||||
): Promise<any> {
|
): Promise<unknown> {
|
||||||
return this.transport.sendMail({
|
return this.transport.sendMail({
|
||||||
to,
|
to,
|
||||||
subject,
|
subject,
|
||||||
@ -31,7 +31,7 @@ export class EmailService {
|
|||||||
to: string,
|
to: string,
|
||||||
subject: string,
|
subject: string,
|
||||||
message: EmailTemplate,
|
message: EmailTemplate,
|
||||||
): Promise<any> {
|
): Promise<unknown> {
|
||||||
return this.sendEmail(to, subject, message.text, message.html);
|
return this.sendEmail(to, subject, message.text, message.html);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { Provider } from '@nestjs/common';
|
import { FactoryProvider } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource, Repository } from 'typeorm';
|
||||||
import { OAuth2ClientAuthorization } from './oauth2-client-authorization.entity';
|
import { OAuth2ClientAuthorization } from './oauth2-client-authorization.entity';
|
||||||
import { OAuth2ClientURL } from './oauth2-client-url.entity';
|
import { OAuth2ClientURL } from './oauth2-client-url.entity';
|
||||||
import { OAuth2Client } from './oauth2-client.entity';
|
import { OAuth2Client } from './oauth2-client.entity';
|
||||||
|
|
||||||
export const clientProviders: Provider<any>[] = [
|
export const clientProviders: FactoryProvider<
|
||||||
|
Repository<OAuth2Client | OAuth2ClientURL | OAuth2ClientAuthorization>
|
||||||
|
>[] = [
|
||||||
{
|
{
|
||||||
provide: 'CLIENT_REPOSITORY',
|
provide: 'CLIENT_REPOSITORY',
|
||||||
useFactory: (dataSource: DataSource) =>
|
useFactory: (dataSource: DataSource) =>
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { Provider } from '@nestjs/common';
|
import { FactoryProvider } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource, Repository } from 'typeorm';
|
||||||
import { OAuth2Token } from './oauth2-token.entity';
|
import { OAuth2Token } from './oauth2-token.entity';
|
||||||
|
|
||||||
export const tokenProviders: Provider<any>[] = [
|
export const tokenProviders = [
|
||||||
{
|
{
|
||||||
provide: 'TOKEN_REPOSITORY',
|
provide: 'TOKEN_REPOSITORY',
|
||||||
useFactory: (dataSource: DataSource) =>
|
useFactory: (dataSource: DataSource) =>
|
||||||
dataSource.getRepository(OAuth2Token),
|
dataSource.getRepository(OAuth2Token),
|
||||||
inject: ['DATA_SOURCE'],
|
inject: ['DATA_SOURCE'],
|
||||||
},
|
} as FactoryProvider<Repository<OAuth2Token>>,
|
||||||
];
|
];
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { Provider } from '@nestjs/common';
|
import { FactoryProvider } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource, Repository } from 'typeorm';
|
||||||
import { Privilege } from './privilege.entity';
|
import { Privilege } from './privilege.entity';
|
||||||
|
|
||||||
export const privilegeProviders: Provider<any>[] = [
|
export const privilegeProviders = [
|
||||||
{
|
{
|
||||||
provide: 'PRIVILEGE_REPOSITORY',
|
provide: 'PRIVILEGE_REPOSITORY',
|
||||||
useFactory: (dataSource: DataSource) => dataSource.getRepository(Privilege),
|
useFactory: (dataSource: DataSource) => dataSource.getRepository(Privilege),
|
||||||
inject: ['DATA_SOURCE'],
|
inject: ['DATA_SOURCE'],
|
||||||
},
|
} as FactoryProvider<Repository<Privilege>>,
|
||||||
];
|
];
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { Provider } from '@nestjs/common';
|
import { FactoryProvider } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource, Repository } from 'typeorm';
|
||||||
import { Upload } from './upload.entity';
|
import { Upload } from './upload.entity';
|
||||||
|
|
||||||
export const uploadProviders: Provider<any>[] = [
|
export const uploadProviders = [
|
||||||
{
|
{
|
||||||
provide: 'UPLOAD_REPOSITORY',
|
provide: 'UPLOAD_REPOSITORY',
|
||||||
useFactory: (dataSource: DataSource) => dataSource.getRepository(Upload),
|
useFactory: (dataSource: DataSource) => dataSource.getRepository(Upload),
|
||||||
inject: ['DATA_SOURCE'],
|
inject: ['DATA_SOURCE'],
|
||||||
},
|
} as FactoryProvider<Repository<Upload>>,
|
||||||
];
|
];
|
||||||
|
@ -56,8 +56,8 @@ export class UploadService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await unlink(path);
|
await unlink(path);
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
console.error('Failed to unlink avatar file:', e.stack);
|
console.error('Failed to unlink avatar file:', (e as Error).stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.uploadRepository.remove(upload);
|
await this.uploadRepository.remove(upload);
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { Provider } from '@nestjs/common';
|
import { FactoryProvider } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource, Repository } from 'typeorm';
|
||||||
import { UserToken } from './user-token.entity';
|
import { UserToken } from './user-token.entity';
|
||||||
|
|
||||||
export const userTokenProviders: Provider<any>[] = [
|
export const userTokenProviders = [
|
||||||
{
|
{
|
||||||
provide: 'USER_TOKEN_REPOSITORY',
|
provide: 'USER_TOKEN_REPOSITORY',
|
||||||
useFactory: (dataSource: DataSource) => dataSource.getRepository(UserToken),
|
useFactory: (dataSource: DataSource) => dataSource.getRepository(UserToken),
|
||||||
inject: ['DATA_SOURCE'],
|
inject: ['DATA_SOURCE'],
|
||||||
},
|
} as FactoryProvider<Repository<UserToken>>,
|
||||||
];
|
];
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { Provider } from '@nestjs/common';
|
import { FactoryProvider } from '@nestjs/common';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource, Repository } from 'typeorm';
|
||||||
import { User } from './user.entity';
|
import { User } from './user.entity';
|
||||||
|
|
||||||
export const userProviders: Provider<any>[] = [
|
export const userProviders = [
|
||||||
{
|
{
|
||||||
provide: 'USER_REPOSITORY',
|
provide: 'USER_REPOSITORY',
|
||||||
useFactory: (dataSource: DataSource) => dataSource.getRepository(User),
|
useFactory: (dataSource: DataSource) => dataSource.getRepository(User),
|
||||||
inject: ['DATA_SOURCE'],
|
inject: ['DATA_SOURCE'],
|
||||||
},
|
} as FactoryProvider<Repository<User>>,
|
||||||
];
|
];
|
||||||
|
@ -41,7 +41,7 @@ export class LoginController {
|
|||||||
public loginView(
|
public loginView(
|
||||||
@Req() req: Request,
|
@Req() req: Request,
|
||||||
@Query('redirectTo') redirectTo?: string,
|
@Query('redirectTo') redirectTo?: string,
|
||||||
): Record<string, any> {
|
): Record<string, unknown> {
|
||||||
return this.formUtil.populateTemplate(req, {
|
return this.formUtil.populateTemplate(req, {
|
||||||
query: redirectTo
|
query: redirectTo
|
||||||
? new URLSearchParams({ redirectTo }).toString()
|
? new URLSearchParams({ redirectTo }).toString()
|
||||||
@ -141,7 +141,11 @@ export class LoginController {
|
|||||||
throw new Error('No challenge');
|
throw new Error('No challenge');
|
||||||
}
|
}
|
||||||
|
|
||||||
const decrypted = await this.token.decryptChallenge(query.challenge);
|
const decrypted = await this.token.decryptChallenge<{
|
||||||
|
type: 'verify';
|
||||||
|
user: string;
|
||||||
|
remember: boolean;
|
||||||
|
}>(query.challenge);
|
||||||
if (!decrypted || decrypted.type !== 'verify' || !decrypted.user) {
|
if (!decrypted || decrypted.type !== 'verify' || !decrypted.user) {
|
||||||
throw new Error('Bad challenge');
|
throw new Error('Bad challenge');
|
||||||
}
|
}
|
||||||
@ -152,7 +156,7 @@ export class LoginController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
remember = decrypted.remember;
|
remember = decrypted.remember;
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
req.flash('message', {
|
req.flash('message', {
|
||||||
error: true,
|
error: true,
|
||||||
text: 'An unexpected error occured, please log in again.',
|
text: 'An unexpected error occured, please log in again.',
|
||||||
@ -173,10 +177,10 @@ export class LoginController {
|
|||||||
if (!this.totpService.validateTOTP(totp.token, body.totp)) {
|
if (!this.totpService.validateTOTP(totp.token, body.totp)) {
|
||||||
throw new Error('Invalid code!');
|
throw new Error('Invalid code!');
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
req.flash('message', {
|
req.flash('message', {
|
||||||
error: true,
|
error: true,
|
||||||
text: e.message,
|
text: (e as Error).message,
|
||||||
});
|
});
|
||||||
res.redirect(req.originalUrl);
|
res.redirect(req.originalUrl);
|
||||||
return;
|
return;
|
||||||
@ -220,7 +224,7 @@ export class LoginController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
user = token.user;
|
user = token.user;
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
req.flash('message', {
|
req.flash('message', {
|
||||||
error: true,
|
error: true,
|
||||||
text: 'Invalid or expired activation link.',
|
text: 'Invalid or expired activation link.',
|
||||||
@ -355,8 +359,8 @@ export class LoginController {
|
|||||||
});
|
});
|
||||||
|
|
||||||
res.redirect('/login');
|
res.redirect('/login');
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
req.flash('message', { error: true, text: e.message });
|
req.flash('message', { error: true, text: (e as Error).message });
|
||||||
res.redirect(req.originalUrl);
|
res.redirect(req.originalUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
Res,
|
Res,
|
||||||
UseGuards,
|
UseGuards,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
import { ApiBearerAuth, ApiExcludeEndpoint, ApiTags } from '@nestjs/swagger';
|
||||||
import { NextFunction, Request, Response } from 'express';
|
import { NextFunction, Request, Response } from 'express';
|
||||||
import { Scope } from 'src/decorators/scope.decorator';
|
import { Scope } from 'src/decorators/scope.decorator';
|
||||||
import { CurrentUser } from 'src/decorators/user.decorator';
|
import { CurrentUser } from 'src/decorators/user.decorator';
|
||||||
@ -36,6 +36,7 @@ export class OAuth2Controller {
|
|||||||
return this._service.oauth.controller.authorization(req, res, next);
|
return this._service.oauth.controller.authorization(req, res, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiExcludeEndpoint()
|
||||||
@Post('authorize')
|
@Post('authorize')
|
||||||
public authorizePostWrapper(
|
public authorizePostWrapper(
|
||||||
@Req() req: Request,
|
@Req() req: Request,
|
||||||
@ -66,18 +67,18 @@ export class OAuth2Controller {
|
|||||||
|
|
||||||
// User information endpoint
|
// User information endpoint
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiExcludeEndpoint()
|
||||||
@Get('user')
|
@Get('user')
|
||||||
@UseGuards(OAuth2Guard)
|
@UseGuards(OAuth2Guard)
|
||||||
public async userInfo(
|
public async userInfo(
|
||||||
@CurrentUser() user: User,
|
@CurrentUser() user: User,
|
||||||
@Scope() scope: string,
|
@Scope() scope: string,
|
||||||
): Promise<Record<string, any>> {
|
): Promise<Record<string, unknown>> {
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new NotFoundException('No such user');
|
throw new NotFoundException('No such user');
|
||||||
}
|
}
|
||||||
|
|
||||||
const userData: Record<string, any> = {
|
const userData: Record<string, unknown> = {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
uuid: user.uuid,
|
uuid: user.uuid,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
|
@ -29,7 +29,7 @@ export class RegisterController {
|
|||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@Render('register')
|
@Render('register')
|
||||||
public registerView(@Req() req: Request): Record<string, any> {
|
public registerView(@Req() req: Request): Record<string, unknown> {
|
||||||
return this.formUtil.populateTemplate(req, {
|
return this.formUtil.populateTemplate(req, {
|
||||||
registrationAuthorized: this.config.get<boolean>('app.registrations'),
|
registrationAuthorized: this.config.get<boolean>('app.registrations'),
|
||||||
});
|
});
|
||||||
@ -99,8 +99,8 @@ export class RegisterController {
|
|||||||
});
|
});
|
||||||
|
|
||||||
res.redirect('/login' + (redirectTo ? '?redirectTo=' + redirectTo : ''));
|
res.redirect('/login' + (redirectTo ? '?redirectTo=' + redirectTo : ''));
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
req.flash('message', { error: true, text: e.message });
|
req.flash('message', { error: true, text: (e as Error).message });
|
||||||
req.flash('form', { ...body, password_repeat: undefined });
|
req.flash('form', { ...body, password_repeat: undefined });
|
||||||
res.redirect(req.originalUrl);
|
res.redirect(req.originalUrl);
|
||||||
}
|
}
|
||||||
|
@ -80,10 +80,10 @@ export class SettingsController {
|
|||||||
error: false,
|
error: false,
|
||||||
text: 'Display name has been changed!',
|
text: 'Display name has been changed!',
|
||||||
});
|
});
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
req.flash('message', {
|
req.flash('message', {
|
||||||
error: true,
|
error: true,
|
||||||
text: e.message,
|
text: (e as Error).message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
res.redirect('/account/general');
|
res.redirect('/account/general');
|
||||||
@ -222,10 +222,10 @@ export class SettingsController {
|
|||||||
if (new_password !== password_repeat) {
|
if (new_password !== password_repeat) {
|
||||||
throw new Error('The passwords do not match.');
|
throw new Error('The passwords do not match.');
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
req.flash('message', {
|
req.flash('message', {
|
||||||
error: true,
|
error: true,
|
||||||
text: e.message,
|
text: (e as Error).message,
|
||||||
});
|
});
|
||||||
res.redirect('/account/security');
|
res.redirect('/account/security');
|
||||||
return;
|
return;
|
||||||
@ -288,10 +288,10 @@ export class SettingsController {
|
|||||||
'There is already an existing user with this email address.',
|
'There is already an existing user with this email address.',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
req.flash('message', {
|
req.flash('message', {
|
||||||
error: true,
|
error: true,
|
||||||
text: e.message,
|
text: (e as Error).message,
|
||||||
});
|
});
|
||||||
res.redirect('/account/security');
|
res.redirect('/account/security');
|
||||||
return;
|
return;
|
||||||
|
@ -8,6 +8,12 @@ import { FormUtilityService } from 'src/modules/utility/services/form-utility.se
|
|||||||
import { QRCodeService } from 'src/modules/utility/services/qr-code.service';
|
import { QRCodeService } from 'src/modules/utility/services/qr-code.service';
|
||||||
import { TokenService } from 'src/modules/utility/services/token.service';
|
import { TokenService } from 'src/modules/utility/services/token.service';
|
||||||
|
|
||||||
|
interface ChallengeType {
|
||||||
|
secret: string;
|
||||||
|
type: 'totp';
|
||||||
|
user: string;
|
||||||
|
}
|
||||||
|
|
||||||
@Controller('/account/two-factor')
|
@Controller('/account/two-factor')
|
||||||
export class TwoFactorController {
|
export class TwoFactorController {
|
||||||
constructor(
|
constructor(
|
||||||
@ -27,7 +33,9 @@ export class TwoFactorController {
|
|||||||
if (!twoFA) {
|
if (!twoFA) {
|
||||||
const challengeString = req.query.challenge as string;
|
const challengeString = req.query.challenge as string;
|
||||||
if (challengeString) {
|
if (challengeString) {
|
||||||
const challenge = await this.token.decryptChallenge(challengeString);
|
const challenge = await this.token.decryptChallenge<ChallengeType>(
|
||||||
|
challengeString,
|
||||||
|
);
|
||||||
if (challenge.type === 'totp' && challenge.user === req.user.uuid) {
|
if (challenge.type === 'totp' && challenge.user === req.user.uuid) {
|
||||||
secret = challenge.secret;
|
secret = challenge.secret;
|
||||||
}
|
}
|
||||||
@ -69,7 +77,9 @@ export class TwoFactorController {
|
|||||||
throw new Error('Invalid request');
|
throw new Error('Invalid request');
|
||||||
}
|
}
|
||||||
|
|
||||||
const challenge = await this.token.decryptChallenge(challengeString);
|
const challenge = await this.token.decryptChallenge<ChallengeType>(
|
||||||
|
challengeString,
|
||||||
|
);
|
||||||
secret = challenge.secret;
|
secret = challenge.secret;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -84,10 +94,10 @@ export class TwoFactorController {
|
|||||||
if (!verify) {
|
if (!verify) {
|
||||||
throw new Error('Invalid code! Try again.');
|
throw new Error('Invalid code! Try again.');
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
req.flash('message', {
|
req.flash('message', {
|
||||||
error: true,
|
error: true,
|
||||||
text: e.message,
|
text: (e as Error).message,
|
||||||
});
|
});
|
||||||
res.redirect('/two-factor');
|
res.redirect('/two-factor');
|
||||||
return;
|
return;
|
||||||
@ -137,10 +147,10 @@ export class TwoFactorController {
|
|||||||
|
|
||||||
await this.totp.deactivateTOTP(twoFA);
|
await this.totp.deactivateTOTP(twoFA);
|
||||||
await this.audit.auditRequest(req, AuditAction.TOTP_DEACTIVATE);
|
await this.audit.auditRequest(req, AuditAction.TOTP_DEACTIVATE);
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
req.flash('message', {
|
req.flash('message', {
|
||||||
error: true,
|
error: true,
|
||||||
text: e.message,
|
text: (e as Error).message,
|
||||||
});
|
});
|
||||||
res.redirect('/account/two-factor/disable');
|
res.redirect('/account/two-factor/disable');
|
||||||
return;
|
return;
|
||||||
|
@ -13,8 +13,10 @@ export class FormUtilityService {
|
|||||||
* @param flash Array of objects
|
* @param flash Array of objects
|
||||||
* @returns Merged object
|
* @returns Merged object
|
||||||
*/
|
*/
|
||||||
public mergeObjectArray(flash: Record<string, any>[]): Record<string, any> {
|
public mergeObjectArray(
|
||||||
return flash.reduce<Record<string, any>>(
|
flash: Record<string, unknown>[],
|
||||||
|
): Record<string, unknown> {
|
||||||
|
return flash.reduce<Record<string, unknown>>(
|
||||||
(obj, item) => ({ ...obj, ...item }),
|
(obj, item) => ({ ...obj, ...item }),
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
@ -93,11 +95,11 @@ export class FormUtilityService {
|
|||||||
*/
|
*/
|
||||||
public populateTemplate(
|
public populateTemplate(
|
||||||
req: Request,
|
req: Request,
|
||||||
additional: Record<string, any> = {},
|
additional: Record<string, unknown> = {},
|
||||||
): Record<string, any> {
|
): Record<string, unknown> {
|
||||||
const message = req.flash('message')[0] || {};
|
const message = req.flash('message')[0] || {};
|
||||||
const form = this.mergeObjectArray(
|
const form = this.mergeObjectArray(
|
||||||
(req.flash('form') as Record<string, any>[]) || [],
|
(req.flash('form') as Record<string, unknown>[]) || [],
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -78,18 +78,14 @@ export class TokenService {
|
|||||||
return decrypted.toString();
|
return decrypted.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async encryptChallenge(
|
public async encryptChallenge<T>(challenge: T): Promise<string> {
|
||||||
challenge: Record<string, any>,
|
|
||||||
): Promise<string> {
|
|
||||||
return this.encrypt(
|
return this.encrypt(
|
||||||
JSON.stringify(challenge),
|
JSON.stringify(challenge),
|
||||||
this.config.get<string>('app.challenge_secret'),
|
this.config.get<string>('app.challenge_secret'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async decryptChallenge(
|
public async decryptChallenge<T>(challenge: string): Promise<T> {
|
||||||
challenge: string,
|
|
||||||
): Promise<Record<string, any>> {
|
|
||||||
return JSON.parse(
|
return JSON.parse(
|
||||||
this.decrypt(challenge, this.config.get<string>('app.challenge_secret')),
|
this.decrypt(challenge, this.config.get<string>('app.challenge_secret')),
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user