Fix bugs in data validation
This commit is contained in:
parent
0f1eec81a7
commit
85bd389a2b
|
@ -11,6 +11,7 @@ import {
|
|||
import { SupportedMime } from 'imagur-shared/dist/dto/mimes.dto';
|
||||
import { GetCols } from '../collectionutils';
|
||||
import { EImage } from 'imagur-shared/dist/entities/image.entity';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
|
||||
@Injectable()
|
||||
export class ImageDBService {
|
||||
|
@ -27,15 +28,19 @@ export class ImageDBService {
|
|||
const find = await this.findOne(hash);
|
||||
if (HasSuccess(find)) return find;
|
||||
|
||||
const imageEntity = new EImage();
|
||||
let imageEntity = new EImage();
|
||||
imageEntity.data = image;
|
||||
imageEntity.mime = type;
|
||||
imageEntity.hash = hash;
|
||||
|
||||
try {
|
||||
return await this.imageRepository.save(imageEntity);
|
||||
imageEntity = await this.imageRepository.save(imageEntity);
|
||||
} catch (e: any) {
|
||||
return Fail(e?.message);
|
||||
}
|
||||
|
||||
// Strips unwanted data
|
||||
return plainToClass(EImage, imageEntity);
|
||||
}
|
||||
|
||||
public async findOne<B extends true | undefined = undefined>(
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import { EUser } from 'imagur-shared/dist/entities/user.entity';
|
||||
import {
|
||||
|
@ -26,17 +27,20 @@ export class UsersService {
|
|||
): AsyncFailable<EUser> {
|
||||
if (await this.exists(username)) return Fail('User already exists');
|
||||
|
||||
const user = new EUser();
|
||||
let user = new EUser();
|
||||
user.username = username;
|
||||
user.password = hashedPassword;
|
||||
|
||||
try {
|
||||
return await this.usersRepository.save(user);
|
||||
user = await this.usersRepository.save(user, { reload: true });
|
||||
} catch (e: any) {
|
||||
return Fail(e?.message);
|
||||
}
|
||||
|
||||
return plainToClass(EUser, user); // Strips unwanted data
|
||||
}
|
||||
|
||||
// Returns user object without id
|
||||
public async delete(user: string | EUser): AsyncFailable<EUser> {
|
||||
const userToModify = await this.resolve(user);
|
||||
if (HasFailed(userToModify)) return userToModify;
|
||||
|
@ -94,7 +98,8 @@ export class UsersService {
|
|||
if (typeof user === 'string') {
|
||||
return await this.findOne(user);
|
||||
} else {
|
||||
const errors = await validate(user);
|
||||
user = plainToClass(EUser, user);
|
||||
const errors = await validate(user, { forbidUnknownValues: true });
|
||||
if (errors.length > 0) {
|
||||
this.logger.warn(errors);
|
||||
return Fail('Invalid user');
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import { JwtDataDto } from 'imagur-shared/dist/dto/auth.dto';
|
||||
import { EUser } from 'imagur-shared/dist/entities/user.entity';
|
||||
import { AsyncFailable, HasFailed, Fail } from 'imagur-shared/dist/types';
|
||||
|
@ -8,6 +10,8 @@ import { UsersService } from '../../../collections/userdb/userdb.service';
|
|||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
private readonly logger = new Logger('AuthService');
|
||||
|
||||
constructor(
|
||||
private usersService: UsersService,
|
||||
private jwtService: JwtService,
|
||||
|
@ -37,9 +41,15 @@ export class AuthService {
|
|||
}
|
||||
|
||||
async createToken(user: EUser): Promise<string> {
|
||||
const jwtData: JwtDataDto = {
|
||||
const jwtData: JwtDataDto = plainToClass(JwtDataDto, {
|
||||
user,
|
||||
};
|
||||
});
|
||||
|
||||
const errors = await validate(jwtData, { forbidUnknownValues: true });
|
||||
if (errors.length > 0) {
|
||||
this.logger.warn(errors);
|
||||
throw new Error('Invalid jwt token generated');
|
||||
}
|
||||
|
||||
return this.jwtService.signAsync(jwtData);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,10 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
|
|||
async validate(payload: any): Promise<EUser> {
|
||||
const jwt = plainToClass(JwtDataDto, payload);
|
||||
|
||||
const errors = await validate(jwt, { forbidUnknownValues: true });
|
||||
const errors = await validate(jwt, {
|
||||
forbidUnknownValues: true,
|
||||
});
|
||||
|
||||
if (errors.length > 0) {
|
||||
this.logger.warn(errors);
|
||||
throw new UnauthorizedException();
|
||||
|
|
|
@ -1,23 +1,28 @@
|
|||
import { IsDefined, IsEnum, IsHash, IsNumber, IsOptional, IsString } from 'class-validator';
|
||||
import { Exclude } from 'class-transformer';
|
||||
import {
|
||||
IsDefined,
|
||||
IsEnum,
|
||||
IsHash,
|
||||
IsOptional,
|
||||
} from 'class-validator';
|
||||
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
|
||||
import { SupportedMime, SupportedMimes } from '../dto/mimes.dto';
|
||||
|
||||
@Entity()
|
||||
export class EImage {
|
||||
@PrimaryGeneratedColumn()
|
||||
@IsNumber()
|
||||
@IsDefined()
|
||||
id: number;
|
||||
@IsOptional()
|
||||
id?: number;
|
||||
|
||||
@Index()
|
||||
@Column({ unique: true })
|
||||
@IsString()
|
||||
@IsHash('sha256')
|
||||
hash: string;
|
||||
|
||||
// Binary data
|
||||
@Column({ type: 'bytea', nullable: false, select: false })
|
||||
@IsOptional()
|
||||
@Exclude()
|
||||
data?: Buffer;
|
||||
|
||||
@Column({ enum: SupportedMimes })
|
||||
|
|
|
@ -1,33 +1,31 @@
|
|||
import { Exclude, Expose } from 'class-transformer';
|
||||
import {
|
||||
IsBoolean,
|
||||
IsDefined,
|
||||
IsEmpty,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString,
|
||||
} from 'class-validator';
|
||||
import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
|
||||
|
||||
// Different data for public and private
|
||||
|
||||
@Entity()
|
||||
export class EUser {
|
||||
@PrimaryGeneratedColumn()
|
||||
@IsNumber()
|
||||
@IsDefined()
|
||||
id: number;
|
||||
@IsOptional()
|
||||
id?: number;
|
||||
|
||||
@Index()
|
||||
@Column({ unique: true })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
username: string;
|
||||
|
||||
@Column({ default: false })
|
||||
@IsDefined()
|
||||
@IsBoolean()
|
||||
isAdmin: boolean;
|
||||
|
||||
@Column({ select: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@Exclude()
|
||||
password?: string;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue