remove some anys

This commit is contained in:
Evert Prants 2022-09-18 10:22:57 +03:00
parent 9c7820dc94
commit 33080558bc
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
24 changed files with 110 additions and 90 deletions

View File

@ -35,7 +35,7 @@ export class OAuth2Guard implements CanActivate {
})
.catch(reject);
});
} catch (e: any) {
} catch (e: unknown) {
reject(e);
}
});

View File

@ -22,7 +22,7 @@ export class FlashMiddleware implements NestMiddleware {
return msgs;
} 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);

View File

@ -204,7 +204,7 @@ export class UserAdminController {
try {
await this._user.sendActivationEmail(user);
} catch (e: any) {
} catch (e: unknown) {
error = e as Error;
}
@ -229,7 +229,7 @@ export class UserAdminController {
try {
await this._user.sendPasswordEmail(user);
} catch (e: any) {
} catch (e: unknown) {
error = e as Error;
}

View File

@ -55,7 +55,7 @@ export class ApiController {
// Management scope allows access to basically everything anyway
const scopelessAccess = scope.includes('management');
const userData: Record<string, any> = {
const userData: Record<string, unknown> = {
id: user.id,
uuid: user.uuid,
username: user.username,

View File

@ -23,8 +23,13 @@ export interface EmailConfiguration {
export interface AppConfiguration {
base_url: string;
host: string;
port: number;
session_name: string;
session_secret: string;
challenge_secret: string;
registrations: boolean;
redis_url?: string;
}
export interface Configuration {

View File

@ -2,16 +2,16 @@ import * as toml from 'toml';
import { resolve } from 'path';
import { readFile } from 'fs/promises';
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_FILENAME = process.env.CONFIG || `config.${CONFIG_ENV}.toml`;
export const configProviders: Provider<any>[] = [
export const configProviders = [
{
provide: 'CONFIG_PATH',
useValue: resolve(__dirname, '..', '..', '..', CONFIG_FILENAME),
},
} as ValueProvider<string>,
{
provide: 'DEFAULT_CONFIG',
useValue: {
@ -57,7 +57,7 @@ export const configProviders: Provider<any>[] = [
},
},
} as Configuration,
},
} as ValueProvider<Configuration>,
{
provide: 'CONFIGURATION',
useFactory: async (
@ -70,11 +70,11 @@ export const configProviders: Provider<any>[] = [
...defaultConfig,
...JSON.parse(JSON.stringify(toml.parse(file))),
};
} catch (e: any) {
console.error('Failed to load configuration:', e.message);
} catch (e: unknown) {
console.error('Failed to load configuration:', (e as Error).message);
return defaultConfig;
}
},
inject: ['CONFIG_PATH', 'DEFAULT_CONFIG'],
},
} as FactoryProvider<Configuration>,
];

View File

@ -1,20 +1,20 @@
import { join } from 'path';
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',
useValue: join(__dirname, '..', '..', '..', 'private'),
},
} as ValueProvider<string>,
{
provide: 'JWT_PRIVATE_KEY',
useFactory: async (path: string) => readFile(join(path, 'jwt.private.pem')),
inject: ['PRIVATE_PATH'],
},
} as FactoryProvider<Buffer>,
{
provide: 'JWT_PUBLIC_KEY',
useFactory: async (path: string) => readFile(join(path, 'jwt.public.pem')),
inject: ['PRIVATE_PATH'],
},
} as FactoryProvider<Buffer>,
];

View File

@ -10,13 +10,13 @@ import * as jwt from 'jsonwebtoken';
@Injectable()
export class JWTService {
constructor(
@Inject('JWT_PRIVATE_KEY') private _privateKey: string,
@Inject('JWT_PUBLIC_KEY') private _publicKey: string,
@Inject('JWT_PRIVATE_KEY') private _privateKey: Buffer,
@Inject('JWT_PUBLIC_KEY') private _publicKey: Buffer,
private _config: ConfigurationService,
) {}
public issue(
claims: Record<string, any>,
claims: Record<string, unknown>,
subject: string,
audience?: string,
): string {

View File

@ -1,17 +1,17 @@
import { Provider } from '@nestjs/common';
import { FactoryProvider, ValueProvider } from '@nestjs/common';
import { join } from 'path';
import { DataSource } from 'typeorm';
import { DataSource, Repository } from 'typeorm';
import { Document } from './document.entity';
export const documentProviders: Provider<any>[] = [
export const documentProviders = [
{
provide: 'DOCUMENT_CACHE',
useValue: join(process.cwd(), '.cache'),
},
} as ValueProvider<string>,
{
provide: 'DOCUMENT_REPOSITORY',
useFactory: (dataSource: DataSource) => dataSource.getRepository(Document),
inject: ['DATA_SOURCE'],
},
} as FactoryProvider<Repository<Document>>,
];

View File

@ -17,7 +17,7 @@ export class EmailService {
text: string,
html?: string,
from = this.config.get<string>('email.from'),
): Promise<any> {
): Promise<unknown> {
return this.transport.sendMail({
to,
subject,
@ -31,7 +31,7 @@ export class EmailService {
to: string,
subject: string,
message: EmailTemplate,
): Promise<any> {
): Promise<unknown> {
return this.sendEmail(to, subject, message.text, message.html);
}
}

View File

@ -1,10 +1,12 @@
import { Provider } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { FactoryProvider } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { OAuth2ClientAuthorization } from './oauth2-client-authorization.entity';
import { OAuth2ClientURL } from './oauth2-client-url.entity';
import { OAuth2Client } from './oauth2-client.entity';
export const clientProviders: Provider<any>[] = [
export const clientProviders: FactoryProvider<
Repository<OAuth2Client | OAuth2ClientURL | OAuth2ClientAuthorization>
>[] = [
{
provide: 'CLIENT_REPOSITORY',
useFactory: (dataSource: DataSource) =>

View File

@ -1,12 +1,12 @@
import { Provider } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { FactoryProvider } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { OAuth2Token } from './oauth2-token.entity';
export const tokenProviders: Provider<any>[] = [
export const tokenProviders = [
{
provide: 'TOKEN_REPOSITORY',
useFactory: (dataSource: DataSource) =>
dataSource.getRepository(OAuth2Token),
inject: ['DATA_SOURCE'],
},
} as FactoryProvider<Repository<OAuth2Token>>,
];

View File

@ -1,11 +1,11 @@
import { Provider } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { FactoryProvider } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { Privilege } from './privilege.entity';
export const privilegeProviders: Provider<any>[] = [
export const privilegeProviders = [
{
provide: 'PRIVILEGE_REPOSITORY',
useFactory: (dataSource: DataSource) => dataSource.getRepository(Privilege),
inject: ['DATA_SOURCE'],
},
} as FactoryProvider<Repository<Privilege>>,
];

View File

@ -1,11 +1,11 @@
import { Provider } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { FactoryProvider } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { Upload } from './upload.entity';
export const uploadProviders: Provider<any>[] = [
export const uploadProviders = [
{
provide: 'UPLOAD_REPOSITORY',
useFactory: (dataSource: DataSource) => dataSource.getRepository(Upload),
inject: ['DATA_SOURCE'],
},
} as FactoryProvider<Repository<Upload>>,
];

View File

@ -56,8 +56,8 @@ export class UploadService {
try {
await unlink(path);
} catch (e: any) {
console.error('Failed to unlink avatar file:', e.stack);
} catch (e: unknown) {
console.error('Failed to unlink avatar file:', (e as Error).stack);
}
await this.uploadRepository.remove(upload);

View File

@ -1,11 +1,11 @@
import { Provider } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { FactoryProvider } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { UserToken } from './user-token.entity';
export const userTokenProviders: Provider<any>[] = [
export const userTokenProviders = [
{
provide: 'USER_TOKEN_REPOSITORY',
useFactory: (dataSource: DataSource) => dataSource.getRepository(UserToken),
inject: ['DATA_SOURCE'],
},
} as FactoryProvider<Repository<UserToken>>,
];

View File

@ -1,11 +1,11 @@
import { Provider } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { FactoryProvider } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { User } from './user.entity';
export const userProviders: Provider<any>[] = [
export const userProviders = [
{
provide: 'USER_REPOSITORY',
useFactory: (dataSource: DataSource) => dataSource.getRepository(User),
inject: ['DATA_SOURCE'],
},
} as FactoryProvider<Repository<User>>,
];

View File

@ -41,7 +41,7 @@ export class LoginController {
public loginView(
@Req() req: Request,
@Query('redirectTo') redirectTo?: string,
): Record<string, any> {
): Record<string, unknown> {
return this.formUtil.populateTemplate(req, {
query: redirectTo
? new URLSearchParams({ redirectTo }).toString()
@ -141,7 +141,11 @@ export class LoginController {
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) {
throw new Error('Bad challenge');
}
@ -152,7 +156,7 @@ export class LoginController {
}
remember = decrypted.remember;
} catch (e: any) {
} catch (e: unknown) {
req.flash('message', {
error: true,
text: 'An unexpected error occured, please log in again.',
@ -173,10 +177,10 @@ export class LoginController {
if (!this.totpService.validateTOTP(totp.token, body.totp)) {
throw new Error('Invalid code!');
}
} catch (e: any) {
} catch (e: unknown) {
req.flash('message', {
error: true,
text: e.message,
text: (e as Error).message,
});
res.redirect(req.originalUrl);
return;
@ -220,7 +224,7 @@ export class LoginController {
}
user = token.user;
} catch (e: any) {
} catch (e: unknown) {
req.flash('message', {
error: true,
text: 'Invalid or expired activation link.',
@ -355,8 +359,8 @@ export class LoginController {
});
res.redirect('/login');
} catch (e: any) {
req.flash('message', { error: true, text: e.message });
} catch (e: unknown) {
req.flash('message', { error: true, text: (e as Error).message });
res.redirect(req.originalUrl);
}
}

View File

@ -8,7 +8,7 @@ import {
Res,
UseGuards,
} from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { ApiBearerAuth, ApiExcludeEndpoint, ApiTags } from '@nestjs/swagger';
import { NextFunction, Request, Response } from 'express';
import { Scope } from 'src/decorators/scope.decorator';
import { CurrentUser } from 'src/decorators/user.decorator';
@ -36,6 +36,7 @@ export class OAuth2Controller {
return this._service.oauth.controller.authorization(req, res, next);
}
@ApiExcludeEndpoint()
@Post('authorize')
public authorizePostWrapper(
@Req() req: Request,
@ -66,18 +67,18 @@ export class OAuth2Controller {
// User information endpoint
@ApiBearerAuth()
@ApiExcludeEndpoint()
@Get('user')
@UseGuards(OAuth2Guard)
public async userInfo(
@CurrentUser() user: User,
@Scope() scope: string,
): Promise<Record<string, any>> {
): Promise<Record<string, unknown>> {
if (!user) {
throw new NotFoundException('No such user');
}
const userData: Record<string, any> = {
const userData: Record<string, unknown> = {
id: user.id,
uuid: user.uuid,
username: user.username,

View File

@ -29,7 +29,7 @@ export class RegisterController {
@Get()
@Render('register')
public registerView(@Req() req: Request): Record<string, any> {
public registerView(@Req() req: Request): Record<string, unknown> {
return this.formUtil.populateTemplate(req, {
registrationAuthorized: this.config.get<boolean>('app.registrations'),
});
@ -99,8 +99,8 @@ export class RegisterController {
});
res.redirect('/login' + (redirectTo ? '?redirectTo=' + redirectTo : ''));
} catch (e: any) {
req.flash('message', { error: true, text: e.message });
} catch (e: unknown) {
req.flash('message', { error: true, text: (e as Error).message });
req.flash('form', { ...body, password_repeat: undefined });
res.redirect(req.originalUrl);
}

View File

@ -80,10 +80,10 @@ export class SettingsController {
error: false,
text: 'Display name has been changed!',
});
} catch (e: any) {
} catch (e: unknown) {
req.flash('message', {
error: true,
text: e.message,
text: (e as Error).message,
});
}
res.redirect('/account/general');
@ -222,10 +222,10 @@ export class SettingsController {
if (new_password !== password_repeat) {
throw new Error('The passwords do not match.');
}
} catch (e: any) {
} catch (e: unknown) {
req.flash('message', {
error: true,
text: e.message,
text: (e as Error).message,
});
res.redirect('/account/security');
return;
@ -288,10 +288,10 @@ export class SettingsController {
'There is already an existing user with this email address.',
);
}
} catch (e: any) {
} catch (e: unknown) {
req.flash('message', {
error: true,
text: e.message,
text: (e as Error).message,
});
res.redirect('/account/security');
return;

View File

@ -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 { TokenService } from 'src/modules/utility/services/token.service';
interface ChallengeType {
secret: string;
type: 'totp';
user: string;
}
@Controller('/account/two-factor')
export class TwoFactorController {
constructor(
@ -27,7 +33,9 @@ export class TwoFactorController {
if (!twoFA) {
const challengeString = req.query.challenge as string;
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) {
secret = challenge.secret;
}
@ -69,7 +77,9 @@ export class TwoFactorController {
throw new Error('Invalid request');
}
const challenge = await this.token.decryptChallenge(challengeString);
const challenge = await this.token.decryptChallenge<ChallengeType>(
challengeString,
);
secret = challenge.secret;
if (
@ -84,10 +94,10 @@ export class TwoFactorController {
if (!verify) {
throw new Error('Invalid code! Try again.');
}
} catch (e: any) {
} catch (e: unknown) {
req.flash('message', {
error: true,
text: e.message,
text: (e as Error).message,
});
res.redirect('/two-factor');
return;
@ -137,10 +147,10 @@ export class TwoFactorController {
await this.totp.deactivateTOTP(twoFA);
await this.audit.auditRequest(req, AuditAction.TOTP_DEACTIVATE);
} catch (e: any) {
} catch (e: unknown) {
req.flash('message', {
error: true,
text: e.message,
text: (e as Error).message,
});
res.redirect('/account/two-factor/disable');
return;

View File

@ -13,8 +13,10 @@ export class FormUtilityService {
* @param flash Array of objects
* @returns Merged object
*/
public mergeObjectArray(flash: Record<string, any>[]): Record<string, any> {
return flash.reduce<Record<string, any>>(
public mergeObjectArray(
flash: Record<string, unknown>[],
): Record<string, unknown> {
return flash.reduce<Record<string, unknown>>(
(obj, item) => ({ ...obj, ...item }),
{},
);
@ -93,11 +95,11 @@ export class FormUtilityService {
*/
public populateTemplate(
req: Request,
additional: Record<string, any> = {},
): Record<string, any> {
additional: Record<string, unknown> = {},
): Record<string, unknown> {
const message = req.flash('message')[0] || {};
const form = this.mergeObjectArray(
(req.flash('form') as Record<string, any>[]) || [],
(req.flash('form') as Record<string, unknown>[]) || [],
);
return {

View File

@ -78,18 +78,14 @@ export class TokenService {
return decrypted.toString();
}
public async encryptChallenge(
challenge: Record<string, any>,
): Promise<string> {
public async encryptChallenge<T>(challenge: T): Promise<string> {
return this.encrypt(
JSON.stringify(challenge),
this.config.get<string>('app.challenge_secret'),
);
}
public async decryptChallenge(
challenge: string,
): Promise<Record<string, any>> {
public async decryptChallenge<T>(challenge: string): Promise<T> {
return JSON.parse(
this.decrypt(challenge, this.config.get<string>('app.challenge_secret')),
);