mirror of
https://github.com/CaramelFur/Picsur.git
synced 2025-11-12 23:05:39 +01:00
change validation to be stricter
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import { Permissions } from 'picsur-shared/dist/dto/permissions';
|
||||
import {
|
||||
ImmuteableRolesList,
|
||||
@@ -14,6 +13,7 @@ import {
|
||||
HasFailed,
|
||||
HasSuccess
|
||||
} from 'picsur-shared/dist/types';
|
||||
import { strictValidate } from 'picsur-shared/dist/util/validate';
|
||||
import { In, Repository } from 'typeorm';
|
||||
import { ERoleBackend } from '../../models/entities/role.entity';
|
||||
|
||||
@@ -172,7 +172,7 @@ export class RolesService {
|
||||
return await this.findOne(user);
|
||||
} else {
|
||||
user = plainToClass(ERoleBackend, user);
|
||||
const errors = await validate(user, { forbidUnknownValues: true });
|
||||
const errors = await strictValidate(user);
|
||||
if (errors.length > 0) {
|
||||
this.logger.warn(errors);
|
||||
return Fail('Invalid role');
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import {
|
||||
InternalSysprefRepresentation,
|
||||
SysPreferences,
|
||||
@@ -14,6 +13,7 @@ import {
|
||||
Failable,
|
||||
HasFailed
|
||||
} from 'picsur-shared/dist/types';
|
||||
import { strictValidate } from 'picsur-shared/dist/util/validate';
|
||||
import { Repository } from 'typeorm';
|
||||
import { ESysPreferenceBackend } from '../../models/entities/syspreference.entity';
|
||||
import { SysPreferenceDefaultsService } from './syspreferencedefaults.service';
|
||||
@@ -81,9 +81,7 @@ export class SysPreferenceService {
|
||||
ESysPreferenceBackend,
|
||||
foundSysPreference,
|
||||
);
|
||||
const errors = await validate(foundSysPreference, {
|
||||
forbidUnknownValues: true,
|
||||
});
|
||||
const errors = await strictValidate(foundSysPreference);
|
||||
if (errors.length > 0) {
|
||||
this.logger.warn(errors);
|
||||
return Fail('Invalid preference');
|
||||
@@ -183,9 +181,7 @@ export class SysPreferenceService {
|
||||
verifySysPreference.value = validatedValue;
|
||||
|
||||
// Just to be sure
|
||||
const errors = await validate(verifySysPreference, {
|
||||
forbidUnknownValues: true,
|
||||
});
|
||||
const errors = await strictValidate(verifySysPreference);
|
||||
if (errors.length > 0) {
|
||||
this.logger.warn(errors);
|
||||
return Fail('Invalid preference');
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import { Permissions } from 'picsur-shared/dist/dto/permissions';
|
||||
import { PermanentRolesList, Roles } from 'picsur-shared/dist/dto/roles.dto';
|
||||
import {
|
||||
@@ -11,6 +10,7 @@ import {
|
||||
HasFailed,
|
||||
HasSuccess
|
||||
} from 'picsur-shared/dist/types';
|
||||
import { strictValidate } from 'picsur-shared/dist/util/validate';
|
||||
import { Repository } from 'typeorm';
|
||||
import { EUserBackend } from '../../models/entities/user.entity';
|
||||
import { GetCols } from '../collectionutils';
|
||||
@@ -170,7 +170,7 @@ export class UsersService {
|
||||
return await this.findOne(user);
|
||||
} else {
|
||||
user = plainToClass(EUserBackend, user);
|
||||
const errors = await validate(user, { forbidUnknownValues: true });
|
||||
const errors = await strictValidate(user);
|
||||
if (errors.length > 0) {
|
||||
this.logger.warn(errors);
|
||||
return Fail('Invalid user');
|
||||
|
||||
@@ -5,10 +5,10 @@ import {
|
||||
PipeTransform,
|
||||
Scope
|
||||
} from '@nestjs/common';
|
||||
import { validate } from 'class-validator';
|
||||
import { FastifyRequest } from 'fastify';
|
||||
import { MultipartFields, MultipartFile } from 'fastify-multipart';
|
||||
import { Newable } from 'picsur-shared/dist/types';
|
||||
import { strictValidate } from 'picsur-shared/dist/util/validate';
|
||||
import { MultipartConfigService } from '../config/multipart.config.service';
|
||||
import {
|
||||
MultiPartFieldDto,
|
||||
@@ -61,7 +61,7 @@ export class MultiPartPipe implements PipeTransform {
|
||||
}
|
||||
}
|
||||
|
||||
const errors = await validate(dtoClass, { forbidUnknownValues: true });
|
||||
const errors = await strictValidate(dtoClass);
|
||||
if (errors.length > 0) {
|
||||
this.logger.warn(errors);
|
||||
throw new BadRequestException('Invalid file');
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
NestFastifyApplication
|
||||
} from '@nestjs/platform-fastify';
|
||||
import * as multipart from 'fastify-multipart';
|
||||
import { ValidateOptions } from 'picsur-shared/dist/util/validate';
|
||||
import { AppModule } from './app.module';
|
||||
import { UsersService } from './collections/userdb/userdb.service';
|
||||
import { HostConfigService } from './config/host.config.service';
|
||||
@@ -28,12 +29,7 @@ async function bootstrap() {
|
||||
);
|
||||
app.useGlobalFilters(new MainExceptionFilter());
|
||||
app.useGlobalInterceptors(new SuccessInterceptor());
|
||||
app.useGlobalPipes(
|
||||
new ValidationPipe({
|
||||
disableErrorMessages: true,
|
||||
forbidUnknownValues: true,
|
||||
}),
|
||||
);
|
||||
app.useGlobalPipes(new ValidationPipe(ValidateOptions));
|
||||
app.useGlobalGuards(
|
||||
new MainAuthGuard(app.get(Reflector), app.get(UsersService)),
|
||||
);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { instanceToPlain, plainToClass } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import { JwtDataDto } from 'picsur-shared/dist/dto/jwt.dto';
|
||||
import { strictValidate } from 'picsur-shared/dist/util/validate';
|
||||
import { EUserBackend } from '../../models/entities/user.entity';
|
||||
|
||||
@Injectable()
|
||||
@@ -16,7 +16,7 @@ export class AuthManagerService {
|
||||
user,
|
||||
});
|
||||
|
||||
const errors = await validate(jwtData, { forbidUnknownValues: true });
|
||||
const errors = await strictValidate(jwtData);
|
||||
if (errors.length > 0) {
|
||||
this.logger.warn(errors);
|
||||
throw new Error('Invalid jwt token generated');
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
Logger
|
||||
} from '@nestjs/common';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import { strictValidate } from 'picsur-shared/dist/util/validate';
|
||||
import { EUserBackend } from '../../../models/entities/user.entity';
|
||||
|
||||
@Injectable()
|
||||
@@ -20,7 +20,7 @@ export class AdminGuard implements CanActivate {
|
||||
}
|
||||
|
||||
const user = plainToClass(EUserBackend, request.user);
|
||||
const errors = await validate(user, { forbidUnknownValues: true });
|
||||
const errors = await strictValidate(user);
|
||||
if (errors.length > 0) {
|
||||
this.logger.warn(errors);
|
||||
return false;
|
||||
|
||||
@@ -6,9 +6,9 @@ import {
|
||||
} from '@nestjs/common';
|
||||
import { PassportStrategy } from '@nestjs/passport';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import { ExtractJwt, Strategy } from 'passport-jwt';
|
||||
import { JwtDataDto } from 'picsur-shared/dist/dto/jwt.dto';
|
||||
import { strictValidate } from 'picsur-shared/dist/util/validate';
|
||||
import { EUserBackend } from '../../../models/entities/user.entity';
|
||||
|
||||
@Injectable()
|
||||
@@ -26,9 +26,7 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
|
||||
async validate(payload: any): Promise<EUserBackend> {
|
||||
const jwt = plainToClass(JwtDataDto, payload);
|
||||
|
||||
const errors = await validate(jwt, {
|
||||
forbidUnknownValues: true,
|
||||
});
|
||||
const errors = await strictValidate(jwt);
|
||||
|
||||
if (errors.length > 0) {
|
||||
this.logger.warn(errors);
|
||||
|
||||
@@ -8,12 +8,12 @@ import {
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import {
|
||||
Permissions
|
||||
} from 'picsur-shared/dist/dto/permissions';
|
||||
import { Fail, Failable, HasFailed } from 'picsur-shared/dist/types';
|
||||
import { isPermissionsArray } from 'picsur-shared/dist/util/permissions';
|
||||
import { strictValidate } from 'picsur-shared/dist/util/validate';
|
||||
import { UsersService } from '../../../collections/userdb/userdb.service';
|
||||
import { EUserBackend } from '../../../models/entities/user.entity';
|
||||
|
||||
@@ -77,9 +77,7 @@ export class MainAuthGuard extends AuthGuard(['jwt', 'guest']) {
|
||||
|
||||
private async validateUser(user: EUserBackend): Promise<EUserBackend> {
|
||||
const userClass = plainToClass(EUserBackend, user);
|
||||
const errors = await validate(userClass, {
|
||||
forbidUnknownValues: true,
|
||||
});
|
||||
const errors = await strictValidate(userClass);
|
||||
|
||||
if (errors.length > 0) {
|
||||
this.logger.error(
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { UserApiModule } from './auth/user.module';
|
||||
import { ExperimentModule } from './experiment/experiment.module';
|
||||
import { InfoModule } from './info/info.module';
|
||||
import { PrefModule } from './pref/pref.module';
|
||||
import { RolesApiModule } from './roles/roles.module';
|
||||
import { UserApiModule } from './user/user.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
||||
@@ -8,18 +8,11 @@ import {
|
||||
Request
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
UserDeleteRequest,
|
||||
UserDeleteResponse,
|
||||
UserInfoRequest,
|
||||
UserInfoResponse,
|
||||
UserListResponse,
|
||||
UserLoginResponse,
|
||||
UserMePermissionsResponse,
|
||||
UserMeResponse,
|
||||
UserRegisterRequest,
|
||||
UserRegisterResponse,
|
||||
UserUpdateRolesRequest,
|
||||
UserUpdateRolesResponse
|
||||
UserRegisterResponse
|
||||
} from 'picsur-shared/dist/dto/api/user.dto';
|
||||
import { Permission } from 'picsur-shared/dist/dto/permissions';
|
||||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
@@ -34,7 +27,7 @@ import AuthFasityRequest from '../../../models/dto/authrequest.dto';
|
||||
|
||||
@Controller('api/user')
|
||||
export class UserController {
|
||||
private readonly logger = new Logger('AuthController');
|
||||
private readonly logger = new Logger('UserController');
|
||||
|
||||
constructor(
|
||||
private usersService: UsersService,
|
||||
@@ -66,65 +59,6 @@ export class UserController {
|
||||
return user;
|
||||
}
|
||||
|
||||
@Post('delete')
|
||||
@RequiredPermissions(Permission.UserManage)
|
||||
async delete(
|
||||
@Body() deleteData: UserDeleteRequest,
|
||||
): Promise<UserDeleteResponse> {
|
||||
const user = await this.usersService.delete(deleteData.username);
|
||||
if (HasFailed(user)) {
|
||||
this.logger.warn(user.getReason());
|
||||
throw new InternalServerErrorException('Could not delete user');
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
@Post('roles')
|
||||
@RequiredPermissions(Permission.UserManage)
|
||||
async setPermissions(
|
||||
@Body() body: UserUpdateRolesRequest,
|
||||
): Promise<UserUpdateRolesResponse> {
|
||||
const updatedUser = await this.usersService.setRoles(
|
||||
body.username,
|
||||
body.roles,
|
||||
);
|
||||
|
||||
if (HasFailed(updatedUser)) {
|
||||
this.logger.warn(updatedUser.getReason());
|
||||
throw new InternalServerErrorException('Could not update user');
|
||||
}
|
||||
|
||||
return updatedUser;
|
||||
}
|
||||
|
||||
@Post('info')
|
||||
@RequiredPermissions(Permission.UserManage)
|
||||
async getUser(@Body() body: UserInfoRequest): Promise<UserInfoResponse> {
|
||||
const user = await this.usersService.findOne(body.username);
|
||||
if (HasFailed(user)) {
|
||||
this.logger.warn(user.getReason());
|
||||
throw new InternalServerErrorException('Could not find user');
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
@Get('list')
|
||||
@RequiredPermissions(Permission.UserManage)
|
||||
async listUsers(): Promise<UserListResponse> {
|
||||
const users = await this.usersService.findAll();
|
||||
if (HasFailed(users)) {
|
||||
this.logger.warn(users.getReason());
|
||||
throw new InternalServerErrorException('Could not list users');
|
||||
}
|
||||
|
||||
return {
|
||||
users,
|
||||
total: users.length,
|
||||
};
|
||||
}
|
||||
|
||||
@Get('me')
|
||||
@RequiredPermissions(Permission.UserMe)
|
||||
async me(@Request() req: AuthFasityRequest): Promise<UserMeResponse> {
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AuthManagerModule } from '../../../managers/auth/auth.module';
|
||||
import { UserController } from './user.controller';
|
||||
import { UserManageController } from './usermanage.controller';
|
||||
|
||||
@Module({
|
||||
imports: [AuthManagerModule],
|
||||
controllers: [UserController],
|
||||
controllers: [UserController, UserManageController],
|
||||
})
|
||||
export class UserApiModule {}
|
||||
85
backend/src/routes/api/user/usermanage.controller.ts
Normal file
85
backend/src/routes/api/user/usermanage.controller.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
InternalServerErrorException,
|
||||
Logger,
|
||||
Post
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
UserDeleteRequest,
|
||||
UserDeleteResponse,
|
||||
UserInfoRequest,
|
||||
UserInfoResponse,
|
||||
UserListResponse,
|
||||
UserUpdateRolesRequest,
|
||||
UserUpdateRolesResponse
|
||||
} from 'picsur-shared/dist/dto/api/usermanage.dto';
|
||||
import { Permission } from 'picsur-shared/dist/dto/permissions';
|
||||
import { HasFailed } from 'picsur-shared/dist/types';
|
||||
import { UsersService } from '../../../collections/userdb/userdb.service';
|
||||
import { RequiredPermissions } from '../../../decorators/permissions.decorator';
|
||||
|
||||
@Controller('api/user')
|
||||
@RequiredPermissions(Permission.UserManage)
|
||||
export class UserManageController {
|
||||
private readonly logger = new Logger('UserManageController');
|
||||
|
||||
constructor(private usersService: UsersService) {}
|
||||
|
||||
@Get('list')
|
||||
async listUsers(): Promise<UserListResponse> {
|
||||
const users = await this.usersService.findAll();
|
||||
if (HasFailed(users)) {
|
||||
this.logger.warn(users.getReason());
|
||||
throw new InternalServerErrorException('Could not list users');
|
||||
}
|
||||
|
||||
return {
|
||||
users,
|
||||
total: users.length,
|
||||
};
|
||||
}
|
||||
|
||||
@Post('delete')
|
||||
async delete(
|
||||
@Body() deleteData: UserDeleteRequest,
|
||||
): Promise<UserDeleteResponse> {
|
||||
const user = await this.usersService.delete(deleteData.username);
|
||||
if (HasFailed(user)) {
|
||||
this.logger.warn(user.getReason());
|
||||
throw new InternalServerErrorException('Could not delete user');
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
@Post('roles')
|
||||
async setPermissions(
|
||||
@Body() body: UserUpdateRolesRequest,
|
||||
): Promise<UserUpdateRolesResponse> {
|
||||
const updatedUser = await this.usersService.setRoles(
|
||||
body.username,
|
||||
body.roles,
|
||||
);
|
||||
|
||||
if (HasFailed(updatedUser)) {
|
||||
this.logger.warn(updatedUser.getReason());
|
||||
throw new InternalServerErrorException('Could not update user');
|
||||
}
|
||||
|
||||
return updatedUser;
|
||||
}
|
||||
|
||||
@Post('info')
|
||||
async getUser(@Body() body: UserInfoRequest): Promise<UserInfoResponse> {
|
||||
console.log(body);
|
||||
const user = await this.usersService.findOne(body.username);
|
||||
if (HasFailed(user)) {
|
||||
this.logger.warn(user.getReason());
|
||||
throw new InternalServerErrorException('Could not find user');
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
<h1>Users</h1>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
templateUrl: './settings-users.component.html',
|
||||
})
|
||||
export class SettingsUsersComponent implements OnInit {
|
||||
constructor() {}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { SettingsUsersComponent } from './settings-users.component';
|
||||
import { SettingsUsersRoutingModule } from './settings-users.routing.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [SettingsUsersComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SettingsUsersRoutingModule,
|
||||
],
|
||||
})
|
||||
export class SettingsUsersRouteModule {}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { PRoutes } from 'src/app/models/picsur-routes';
|
||||
import { SettingsUsersComponent } from './settings-users.component';
|
||||
|
||||
const routes: PRoutes = [
|
||||
{
|
||||
path: '',
|
||||
component: SettingsUsersComponent,
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class SettingsUsersRoutingModule {}
|
||||
@@ -7,6 +7,7 @@ import { SidebarResolverService } from 'src/app/services/sidebar-resolver/sideba
|
||||
import { SettingsGeneralRouteModule } from './settings-general/settings-general.module';
|
||||
import { SettingsSidebarComponent } from './settings-sidebar/settings-sidebar.component';
|
||||
import { SettingsSysprefRouteModule } from './settings-syspref/settings-syspref.module';
|
||||
import { SettingsUsersRouteModule } from './settings-users/settings-users.module';
|
||||
|
||||
const SettingsRoutes: PRoutes = [
|
||||
{
|
||||
@@ -40,6 +41,18 @@ const SettingsRoutes: PRoutes = [
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'users',
|
||||
loadChildren: () => SettingsUsersRouteModule,
|
||||
data: {
|
||||
permissions: [Permission.UserManage],
|
||||
page: {
|
||||
title: 'Users',
|
||||
icon: 'people',
|
||||
category: 'system',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
canActivate: [PermissionGuard],
|
||||
canActivateChild: [PermissionGuard],
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ClassConstructor, plainToClass } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import {
|
||||
ApiResponse,
|
||||
ApiSuccessResponse
|
||||
} from 'picsur-shared/dist/dto/api';
|
||||
import { ApiResponse, ApiSuccessResponse } from 'picsur-shared/dist/dto/api';
|
||||
import { AsyncFailable, Fail, HasFailed } from 'picsur-shared/dist/types';
|
||||
import { strictValidate } from 'picsur-shared/dist/util/validate';
|
||||
import { MultiPartRequest } from '../../models/multi-part-request';
|
||||
import { KeyService } from './key.service';
|
||||
|
||||
@@ -31,7 +28,7 @@ export class ApiService {
|
||||
data: object
|
||||
): AsyncFailable<W> {
|
||||
const sendClass = plainToClass(sendType, data);
|
||||
const errors = await validate(sendClass);
|
||||
const errors = await strictValidate(sendClass);
|
||||
if (errors.length > 0) {
|
||||
this.logger.warn(errors);
|
||||
return Fail('Something went wrong');
|
||||
@@ -68,14 +65,15 @@ export class ApiService {
|
||||
ApiSuccessResponse<T>,
|
||||
ApiSuccessResponse<T>
|
||||
>(ApiSuccessResponse, result);
|
||||
const resultErrors = await validate(resultClass);
|
||||
|
||||
const resultErrors = await strictValidate(resultClass);
|
||||
if (resultErrors.length > 0) {
|
||||
this.logger.warn('result', resultErrors);
|
||||
return Fail('Something went wrong');
|
||||
}
|
||||
|
||||
const dataClass = plainToClass(type, result.data);
|
||||
const dataErrors = await validate(dataClass);
|
||||
const dataErrors = await strictValidate(dataClass);
|
||||
if (dataErrors.length > 0) {
|
||||
this.logger.warn('data', dataErrors);
|
||||
return Fail('Something went wrong');
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { plainToClass } from 'class-transformer';
|
||||
import { validate } from 'class-validator';
|
||||
import jwt_decode from 'jwt-decode';
|
||||
import {
|
||||
UserLoginRequest,
|
||||
UserLoginResponse, UserMeResponse, UserRegisterRequest, UserRegisterResponse
|
||||
UserLoginResponse,
|
||||
UserMeResponse,
|
||||
UserRegisterRequest,
|
||||
UserRegisterResponse
|
||||
} from 'picsur-shared/dist/dto/api/user.dto';
|
||||
import { JwtDataDto } from 'picsur-shared/dist/dto/jwt.dto';
|
||||
import { EUser } from 'picsur-shared/dist/entities/user.entity';
|
||||
import { AsyncFailable, Fail, HasFailed } from 'picsur-shared/dist/types';
|
||||
import { strictValidate } from 'picsur-shared/dist/util/validate';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { ApiService } from './api.service';
|
||||
import { KeyService } from './key.service';
|
||||
@@ -60,7 +63,10 @@ export class UserService {
|
||||
return user;
|
||||
}
|
||||
|
||||
public async register(username: string, password: string): AsyncFailable<EUser> {
|
||||
public async register(
|
||||
username: string,
|
||||
password: string
|
||||
): AsyncFailable<EUser> {
|
||||
const request: UserRegisterRequest = {
|
||||
username,
|
||||
password,
|
||||
@@ -119,7 +125,7 @@ export class UserService {
|
||||
}
|
||||
|
||||
const jwtData = plainToClass(JwtDataDto, decoded);
|
||||
const errors = await validate(jwtData);
|
||||
const errors = await strictValidate(jwtData);
|
||||
if (errors.length > 0) {
|
||||
this.logger.warn(errors);
|
||||
return Fail('Invalid token data');
|
||||
|
||||
@@ -5,8 +5,7 @@ import {
|
||||
IsNotEmpty,
|
||||
IsString,
|
||||
Max,
|
||||
Min,
|
||||
ValidateNested,
|
||||
Min
|
||||
} from 'class-validator';
|
||||
|
||||
class BaseApiResponse<T extends Object, W extends boolean> {
|
||||
@@ -24,7 +23,7 @@ class BaseApiResponse<T extends Object, W extends boolean> {
|
||||
@IsNotEmpty()
|
||||
timestamp: string;
|
||||
|
||||
@ValidateNested()
|
||||
//@ValidateNested()
|
||||
@IsDefined()
|
||||
data: T;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsArray, IsDefined,
|
||||
IsEnum,
|
||||
IsInt,
|
||||
IsNotEmpty, IsPositive,
|
||||
IsString,
|
||||
IsEnum, IsNotEmpty, IsString,
|
||||
ValidateNested
|
||||
} from 'class-validator';
|
||||
import { EUser } from '../../entities/user.entity';
|
||||
import { Permissions, PermissionsList } from '../permissions';
|
||||
import { Roles } from '../roles.dto';
|
||||
|
||||
// Api
|
||||
|
||||
@@ -43,38 +39,6 @@ export class UserRegisterRequest {
|
||||
|
||||
export class UserRegisterResponse extends EUser {}
|
||||
|
||||
// UserDelete
|
||||
export class UserDeleteRequest {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
username: string;
|
||||
}
|
||||
|
||||
export class UserDeleteResponse extends EUser {}
|
||||
|
||||
// UserInfo
|
||||
export class UserInfoRequest {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
username: string;
|
||||
}
|
||||
|
||||
export class UserInfoResponse extends EUser {}
|
||||
|
||||
// UserList
|
||||
export class UserListResponse {
|
||||
@IsArray()
|
||||
@IsDefined()
|
||||
@ValidateNested()
|
||||
@Type(() => EUser)
|
||||
users: EUser[];
|
||||
|
||||
@IsInt()
|
||||
@IsPositive()
|
||||
@IsDefined()
|
||||
total: number;
|
||||
}
|
||||
|
||||
// UserMe
|
||||
export class UserMeResponse {
|
||||
@IsDefined()
|
||||
@@ -94,17 +58,3 @@ export class UserMePermissionsResponse {
|
||||
@IsEnum(PermissionsList, { each: true })
|
||||
permissions: Permissions;
|
||||
}
|
||||
|
||||
// UserUpdateRoles
|
||||
export class UserUpdateRolesRequest {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
username: string;
|
||||
|
||||
@IsArray()
|
||||
@IsDefined()
|
||||
@IsString({ each: true })
|
||||
roles: Roles;
|
||||
}
|
||||
|
||||
export class UserUpdateRolesResponse extends EUser {}
|
||||
|
||||
50
shared/src/dto/api/usermanage.dto.ts
Normal file
50
shared/src/dto/api/usermanage.dto.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Type } from 'class-transformer';
|
||||
import { IsArray, IsDefined, IsInt, IsNotEmpty, IsPositive, IsString, ValidateNested } from 'class-validator';
|
||||
import { EUser } from '../../entities/user.entity';
|
||||
import { Roles } from '../roles.dto';
|
||||
|
||||
// UserDelete
|
||||
export class UserDeleteRequest {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
username: string;
|
||||
}
|
||||
|
||||
export class UserDeleteResponse extends EUser {}
|
||||
|
||||
// UserInfo
|
||||
export class UserInfoRequest {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
username: string;
|
||||
}
|
||||
|
||||
export class UserInfoResponse extends EUser {}
|
||||
|
||||
// UserList
|
||||
export class UserListResponse {
|
||||
@IsArray()
|
||||
@IsDefined()
|
||||
@ValidateNested()
|
||||
@Type(() => EUser)
|
||||
users: EUser[];
|
||||
|
||||
@IsInt()
|
||||
@IsPositive()
|
||||
@IsDefined()
|
||||
total: number;
|
||||
}
|
||||
|
||||
// UserUpdateRoles
|
||||
export class UserUpdateRolesRequest {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
username: string;
|
||||
|
||||
@IsArray()
|
||||
@IsDefined()
|
||||
@IsString({ each: true })
|
||||
roles: Roles;
|
||||
}
|
||||
|
||||
export class UserUpdateRolesResponse extends EUser {}
|
||||
12
shared/src/util/validate.ts
Normal file
12
shared/src/util/validate.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { validate } from 'class-validator';
|
||||
|
||||
export const ValidateOptions = {
|
||||
disableErrorMessages: true,
|
||||
forbidNonWhitelisted: true,
|
||||
forbidUnknownValues: true,
|
||||
stopAtFirstError: true,
|
||||
whitelist: true,
|
||||
};
|
||||
|
||||
export const strictValidate = (object: object) =>
|
||||
validate(object, ValidateOptions);
|
||||
Reference in New Issue
Block a user