mirror of
https://github.com/CaramelFur/Picsur.git
synced 2025-11-12 14:55:39 +01:00
Partly refactor errors
This commit is contained in:
@@ -113,7 +113,8 @@ export class SysPreferenceService {
|
|||||||
): AsyncFailable<PrefValueType> {
|
): AsyncFailable<PrefValueType> {
|
||||||
let pref = await this.getPreference(key);
|
let pref = await this.getPreference(key);
|
||||||
if (HasFailed(pref)) return pref;
|
if (HasFailed(pref)) return pref;
|
||||||
if (pref.type !== type) return Fail(FT.UsrValidation, 'Invalid preference type');
|
if (pref.type !== type)
|
||||||
|
return Fail(FT.UsrValidation, 'Invalid preference type');
|
||||||
|
|
||||||
return pref.value;
|
return pref.value;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
ArgumentMetadata,
|
ArgumentMetadata, Injectable,
|
||||||
BadRequestException,
|
PipeTransform
|
||||||
Injectable,
|
|
||||||
PipeTransform,
|
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { Ext2Mime } from 'picsur-shared/dist/dto/mimes.dto';
|
import { Ext2Mime } from 'picsur-shared/dist/dto/mimes.dto';
|
||||||
|
import { Fail, FT } from 'picsur-shared/dist/types';
|
||||||
import { UUIDRegex } from 'picsur-shared/dist/util/common-regex';
|
import { UUIDRegex } from 'picsur-shared/dist/util/common-regex';
|
||||||
import { ImageFullId } from '../../models/constants/image-full-id.const';
|
import { ImageFullId } from '../../models/constants/image-full-id.const';
|
||||||
|
|
||||||
@@ -15,23 +14,23 @@ export class ImageFullIdPipe implements PipeTransform<string, ImageFullId> {
|
|||||||
if (split.length === 2) {
|
if (split.length === 2) {
|
||||||
const [id, ext] = split;
|
const [id, ext] = split;
|
||||||
if (!UUIDRegex.test(id))
|
if (!UUIDRegex.test(id))
|
||||||
throw new BadRequestException('Invalid image identifier');
|
throw Fail(FT.UsrValidation, 'Invalid image identifier');
|
||||||
|
|
||||||
const mime = Ext2Mime(ext);
|
const mime = Ext2Mime(ext);
|
||||||
|
|
||||||
if (mime === undefined)
|
if (mime === undefined)
|
||||||
throw new BadRequestException('Invalid image identifier');
|
throw Fail(FT.UsrValidation, 'Invalid image identifier');
|
||||||
|
|
||||||
return { type: 'normal', id, ext, mime };
|
return { type: 'normal', id, ext, mime };
|
||||||
} else if (split.length === 1) {
|
} else if (split.length === 1) {
|
||||||
const [id] = split;
|
const [id] = split;
|
||||||
|
|
||||||
if (!UUIDRegex.test(id))
|
if (!UUIDRegex.test(id))
|
||||||
throw new BadRequestException('Invalid image identifier');
|
throw Fail(FT.UsrValidation, 'Invalid image identifier');
|
||||||
|
|
||||||
return { type: 'original', id, ext: null, mime: null };
|
return { type: 'original', id, ext: null, mime: null };
|
||||||
} else {
|
} else {
|
||||||
throw new BadRequestException('Invalid image identifier');
|
throw Fail(FT.UsrValidation, 'Invalid image identifier');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import {
|
import {
|
||||||
ArgumentMetadata,
|
ArgumentMetadata, Injectable,
|
||||||
BadRequestException,
|
PipeTransform
|
||||||
Injectable,
|
|
||||||
PipeTransform,
|
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
|
import { Fail, FT } from 'picsur-shared/dist/types';
|
||||||
import { UUIDRegex } from 'picsur-shared/dist/util/common-regex';
|
import { UUIDRegex } from 'picsur-shared/dist/util/common-regex';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ImageIdPipe implements PipeTransform<string, string> {
|
export class ImageIdPipe implements PipeTransform<string, string> {
|
||||||
transform(value: string, metadata: ArgumentMetadata): string {
|
transform(value: string, metadata: ArgumentMetadata): string {
|
||||||
if (UUIDRegex.test(value)) return value;
|
if (UUIDRegex.test(value)) return value;
|
||||||
throw new BadRequestException('Invalid image id');
|
throw Fail(FT.UsrValidation, 'Invalid image id');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
import { MultipartFields, MultipartFile } from '@fastify/multipart';
|
import { MultipartFields, MultipartFile } from '@fastify/multipart';
|
||||||
import {
|
import {
|
||||||
ArgumentMetadata,
|
ArgumentMetadata, Injectable,
|
||||||
BadRequestException,
|
|
||||||
Injectable,
|
|
||||||
InternalServerErrorException,
|
|
||||||
Logger,
|
Logger,
|
||||||
PipeTransform,
|
PipeTransform,
|
||||||
Scope
|
Scope
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { FastifyRequest } from 'fastify';
|
import { FastifyRequest } from 'fastify';
|
||||||
import { HasFailed } from 'picsur-shared/dist/types';
|
import { Fail, FT, HasFailed } from 'picsur-shared/dist/types';
|
||||||
import { ZodDtoStatic } from 'picsur-shared/dist/util/create-zod-dto';
|
import { ZodDtoStatic } from 'picsur-shared/dist/util/create-zod-dto';
|
||||||
import { MultipartConfigService } from '../../config/early/multipart.config.service';
|
import { MultipartConfigService } from '../../config/early/multipart.config.service';
|
||||||
import {
|
import {
|
||||||
@@ -32,11 +29,11 @@ export class MultiPartPipe implements PipeTransform {
|
|||||||
let zodSchema = (metadata?.metatype as ZodDtoStatic)?.zodSchema;
|
let zodSchema = (metadata?.metatype as ZodDtoStatic)?.zodSchema;
|
||||||
if (!zodSchema) {
|
if (!zodSchema) {
|
||||||
this.logger.error('Invalid scheme on multipart body');
|
this.logger.error('Invalid scheme on multipart body');
|
||||||
throw new InternalServerErrorException('Invalid scheme on backend');
|
throw Fail(FT.Internal, 'Invalid scheme on backend');
|
||||||
}
|
}
|
||||||
|
|
||||||
let multipartData = {};
|
let multipartData = {};
|
||||||
if (!req.isMultipart()) throw new BadRequestException('Invalid file');
|
if (!req.isMultipart()) throw Fail(FT.UsrValidation, 'Invalid file');
|
||||||
|
|
||||||
// Fetch all fields from the request
|
// Fetch all fields from the request
|
||||||
let fields: MultipartFields | null = null;
|
let fields: MultipartFields | null = null;
|
||||||
@@ -49,7 +46,7 @@ export class MultiPartPipe implements PipeTransform {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.warn(e);
|
this.logger.warn(e);
|
||||||
}
|
}
|
||||||
if (!fields) throw new BadRequestException('Invalid file');
|
if (!fields) throw Fail(FT.UsrValidation, 'Invalid file');
|
||||||
|
|
||||||
// Loop over every formfield that was sent
|
// Loop over every formfield that was sent
|
||||||
for (const key of Object.keys(fields)) {
|
for (const key of Object.keys(fields)) {
|
||||||
@@ -66,10 +63,7 @@ export class MultiPartPipe implements PipeTransform {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const file = await CreateMultiPartFileDto(fields[key] as MultipartFile);
|
const file = await CreateMultiPartFileDto(fields[key] as MultipartFile);
|
||||||
if (HasFailed(file)) {
|
if (HasFailed(file)) throw file;
|
||||||
this.logger.error(file.getReason());
|
|
||||||
throw new InternalServerErrorException('Invalid file');
|
|
||||||
}
|
|
||||||
(multipartData as any)[key] = file;
|
(multipartData as any)[key] = file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,7 +72,7 @@ export class MultiPartPipe implements PipeTransform {
|
|||||||
const result = zodSchema.safeParse(multipartData);
|
const result = zodSchema.safeParse(multipartData);
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
this.logger.warn(result.error);
|
this.logger.warn(result.error);
|
||||||
throw new BadRequestException('Invalid file');
|
throw Fail(FT.UsrValidation, 'Invalid file');
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.data;
|
return result.data;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { Multipart } from '@fastify/multipart';
|
import { Multipart } from '@fastify/multipart';
|
||||||
import {
|
import {
|
||||||
BadRequestException,
|
|
||||||
Injectable,
|
Injectable,
|
||||||
Logger,
|
Logger,
|
||||||
PipeTransform,
|
PipeTransform,
|
||||||
Scope
|
Scope
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { FastifyRequest } from 'fastify';
|
import { FastifyRequest } from 'fastify';
|
||||||
|
import { Fail, FT } from 'picsur-shared/dist/types';
|
||||||
import { MultipartConfigService } from '../../config/early/multipart.config.service';
|
import { MultipartConfigService } from '../../config/early/multipart.config.service';
|
||||||
|
|
||||||
@Injectable({ scope: Scope.REQUEST })
|
@Injectable({ scope: Scope.REQUEST })
|
||||||
@@ -18,7 +18,7 @@ export class PostFilePipe implements PipeTransform {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async transform({ req }: { req: FastifyRequest }) {
|
async transform({ req }: { req: FastifyRequest }) {
|
||||||
if (!req.isMultipart()) throw new BadRequestException('Invalid file');
|
if (!req.isMultipart()) throw Fail(FT.UsrValidation, 'Invalid file');
|
||||||
|
|
||||||
// Only one file is allowed
|
// Only one file is allowed
|
||||||
const file = await req.file({
|
const file = await req.file({
|
||||||
@@ -27,7 +27,7 @@ export class PostFilePipe implements PipeTransform {
|
|||||||
files: 1,
|
files: 1,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (file === undefined) throw new BadRequestException('Invalid file');
|
if (file === undefined) throw Fail(FT.UsrValidation, 'Invalid file');
|
||||||
|
|
||||||
// Remove empty fields
|
// Remove empty fields
|
||||||
const allFields: Multipart[] = Object.values(file.fields).filter(
|
const allFields: Multipart[] = Object.values(file.fields).filter(
|
||||||
@@ -37,14 +37,14 @@ export class PostFilePipe implements PipeTransform {
|
|||||||
// Remove non-file fields
|
// Remove non-file fields
|
||||||
const files = allFields.filter((entry) => entry.file !== undefined);
|
const files = allFields.filter((entry) => entry.file !== undefined);
|
||||||
|
|
||||||
if (files.length !== 1) throw new BadRequestException('Invalid file');
|
if (files.length !== 1) throw Fail(FT.UsrValidation, 'Invalid file');
|
||||||
|
|
||||||
// Return a buffer of the file
|
// Return a buffer of the file
|
||||||
try {
|
try {
|
||||||
return await files[0].toBuffer();
|
return await files[0].toBuffer();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.warn(e);
|
this.logger.warn(e);
|
||||||
throw new BadRequestException('Invalid file');
|
throw Fail(FT.Internal, 'Invalid file');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,23 +25,27 @@ export class MainExceptionFilter implements ExceptionFilter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const status = exception.getCode();
|
||||||
|
const type = exception.getType();
|
||||||
|
|
||||||
|
const message = exception.getReason();
|
||||||
|
const logmessage =
|
||||||
|
message +
|
||||||
|
(exception.getDebugMessage() ? ' - ' + exception.getDebugMessage() : '');
|
||||||
|
|
||||||
if (exception.isImportant()) {
|
if (exception.isImportant()) {
|
||||||
MainExceptionFilter.logger.error(
|
MainExceptionFilter.logger.error(
|
||||||
`${traceString} ${exception.getName()}: ${exception.getReason()}`,
|
`${traceString} ${exception.getName()}: ${logmessage}`,
|
||||||
);
|
);
|
||||||
if (exception.getStack()) {
|
if (exception.getStack()) {
|
||||||
MainExceptionFilter.logger.debug(exception.getStack());
|
MainExceptionFilter.logger.debug(exception.getStack());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
MainExceptionFilter.logger.warn(
|
MainExceptionFilter.logger.warn(
|
||||||
`${traceString} ${exception.getName()}: ${exception.getReason()}`,
|
`${traceString} ${exception.getName()}: ${logmessage}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const status = exception.getCode();
|
|
||||||
const type = exception.getType();
|
|
||||||
const message = exception.getReason();
|
|
||||||
|
|
||||||
const toSend: ApiErrorResponse = {
|
const toSend: ApiErrorResponse = {
|
||||||
success: false,
|
success: false,
|
||||||
statusCode: status,
|
statusCode: status,
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import {
|
import {
|
||||||
CallHandler,
|
CallHandler,
|
||||||
ExecutionContext,
|
ExecutionContext,
|
||||||
Injectable,
|
Injectable, Logger,
|
||||||
InternalServerErrorException,
|
|
||||||
Logger,
|
|
||||||
NestInterceptor,
|
NestInterceptor,
|
||||||
Optional
|
Optional
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { Reflector } from '@nestjs/core';
|
import { Reflector } from '@nestjs/core';
|
||||||
import { ApiAnySuccessResponse } from 'picsur-shared/dist/dto/api/api.dto';
|
import { ApiAnySuccessResponse } from 'picsur-shared/dist/dto/api/api.dto';
|
||||||
|
import { Fail, FT } from 'picsur-shared/dist/types';
|
||||||
import { ZodDtoStatic } from 'picsur-shared/dist/util/create-zod-dto';
|
import { ZodDtoStatic } from 'picsur-shared/dist/util/create-zod-dto';
|
||||||
import { map, Observable } from 'rxjs';
|
import { map, Observable } from 'rxjs';
|
||||||
|
|
||||||
@@ -55,24 +54,24 @@ export class SuccessInterceptor<T> implements NestInterceptor {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!schemaStatic) {
|
if (!schemaStatic) {
|
||||||
this.logger.warn(
|
throw Fail(
|
||||||
|
FT.Internal,
|
||||||
|
"Couldn't find schema",
|
||||||
`No zodSchema found on handler ${context.getHandler().name}`,
|
`No zodSchema found on handler ${context.getHandler().name}`,
|
||||||
);
|
);
|
||||||
throw new InternalServerErrorException("Couldn't find schema");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let schema = schemaStatic.zodSchema;
|
let schema = schemaStatic.zodSchema;
|
||||||
|
|
||||||
const parseResult = schema.safeParse(data);
|
const parseResult = schema.safeParse(data);
|
||||||
if (!parseResult.success) {
|
if (!parseResult.success) {
|
||||||
this.logger.warn(
|
throw Fail(
|
||||||
|
FT.Internal,
|
||||||
|
'Server produced invalid response',
|
||||||
`Function ${context.getHandler().name} failed validation: ${
|
`Function ${context.getHandler().name} failed validation: ${
|
||||||
parseResult.error
|
parseResult.error
|
||||||
}`,
|
}`,
|
||||||
);
|
);
|
||||||
throw new InternalServerErrorException(
|
|
||||||
'Server produced invalid response',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return parseResult.data;
|
return parseResult.data;
|
||||||
|
|||||||
@@ -5,11 +5,11 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
ArgumentMetadata,
|
ArgumentMetadata,
|
||||||
BadRequestException,
|
|
||||||
Injectable,
|
Injectable,
|
||||||
Optional,
|
Optional,
|
||||||
PipeTransform,
|
PipeTransform
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
|
import { Fail, FT } from 'picsur-shared/dist/types';
|
||||||
import { ZodDtoStatic } from 'picsur-shared/dist/util/create-zod-dto';
|
import { ZodDtoStatic } from 'picsur-shared/dist/util/create-zod-dto';
|
||||||
|
|
||||||
export interface ZodValidationPipeOptions {
|
export interface ZodValidationPipeOptions {
|
||||||
@@ -36,7 +36,11 @@ export class ZodValidationPipe implements PipeTransform {
|
|||||||
const parseResult = zodSchema.safeParse(value);
|
const parseResult = zodSchema.safeParse(value);
|
||||||
|
|
||||||
if (!parseResult.success) {
|
if (!parseResult.success) {
|
||||||
throw new BadRequestException();
|
throw Fail(
|
||||||
|
FT.UsrValidation,
|
||||||
|
'Invalid data',
|
||||||
|
parseResult.error
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parseResult.data;
|
return parseResult.data;
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ export class AuthManagerService {
|
|||||||
// in case of any failures
|
// in case of any failures
|
||||||
const result = JwtDataSchema.safeParse(jwtData);
|
const result = JwtDataSchema.safeParse(jwtData);
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
return Fail(FT.SysValidation, 'Invalid JWT: ' + result.error);
|
return Fail(FT.SysValidation, undefined, 'Invalid JWT: ' + result.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await this.jwtService.signAsync(result.data);
|
return await this.jwtService.signAsync(result.data);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Fail(FT.Internal, "Couldn't create JWT: " + e);
|
return Fail(FT.Internal, undefined, "Couldn't create JWT: " + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { PassportStrategy } from '@nestjs/passport';
|
import { PassportStrategy } from '@nestjs/passport';
|
||||||
import { Strategy } from 'passport-local';
|
import { Strategy } from 'passport-local';
|
||||||
import { EUser } from 'picsur-shared/dist/entities/user.entity';
|
import { EUser } from 'picsur-shared/dist/entities/user.entity';
|
||||||
@@ -15,9 +15,7 @@ export class LocalAuthStrategy extends PassportStrategy(Strategy, 'local') {
|
|||||||
async validate(username: string, password: string): AsyncFailable<EUser> {
|
async validate(username: string, password: string): AsyncFailable<EUser> {
|
||||||
// All this does is call the usersservice authenticate for authentication
|
// All this does is call the usersservice authenticate for authentication
|
||||||
const user = await this.usersService.authenticate(username, password);
|
const user = await this.usersService.authenticate(username, password);
|
||||||
if (HasFailed(user)) {
|
if (HasFailed(user)) throw user;
|
||||||
throw new UnauthorizedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return EUserBackend2EUser(user);
|
return EUserBackend2EUser(user);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
import {
|
import { ExecutionContext, Injectable, Logger } from '@nestjs/common';
|
||||||
ExecutionContext, Injectable,
|
|
||||||
InternalServerErrorException,
|
|
||||||
Logger
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { Reflector } from '@nestjs/core';
|
import { Reflector } from '@nestjs/core';
|
||||||
import { AuthGuard } from '@nestjs/passport';
|
import { AuthGuard } from '@nestjs/passport';
|
||||||
import { EUser, EUserSchema } from 'picsur-shared/dist/entities/user.entity';
|
import { EUser, EUserSchema } from 'picsur-shared/dist/entities/user.entity';
|
||||||
@@ -30,34 +26,42 @@ export class MainAuthGuard extends AuthGuard(['jwt', 'guest']) {
|
|||||||
// Sanity check
|
// Sanity check
|
||||||
const result = await super.canActivate(context);
|
const result = await super.canActivate(context);
|
||||||
if (result !== true) {
|
if (result !== true) {
|
||||||
this.logger.error('Main Auth has denied access, this should not happen');
|
throw Fail(
|
||||||
throw new InternalServerErrorException();
|
FT.Internal,
|
||||||
|
undefined,
|
||||||
|
'Main Auth has denied access, this should not happen',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = await this.validateUser(
|
const user = await this.validateUser(
|
||||||
context.switchToHttp().getRequest().user,
|
context.switchToHttp().getRequest().user,
|
||||||
);
|
);
|
||||||
if (!user.id) {
|
if (!user.id) {
|
||||||
this.logger.error('User has no id, this should not happen');
|
throw Fail(
|
||||||
throw new InternalServerErrorException();
|
FT.Internal,
|
||||||
|
undefined,
|
||||||
|
'User has no id, this should not happen',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are the permissions required to access the route
|
// These are the permissions required to access the route
|
||||||
const permissions = this.extractPermissions(context);
|
const permissions = this.extractPermissions(context);
|
||||||
if (HasFailed(permissions)) {
|
if (HasFailed(permissions)) {
|
||||||
this.logger.error(
|
throw Fail(
|
||||||
|
FT.Internal,
|
||||||
|
undefined,
|
||||||
'Fetching route permission failed: ' + permissions.getReason(),
|
'Fetching route permission failed: ' + permissions.getReason(),
|
||||||
);
|
);
|
||||||
throw new InternalServerErrorException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are the permissions the user has
|
// These are the permissions the user has
|
||||||
const userPermissions = await this.usersService.getPermissions(user.id);
|
const userPermissions = await this.usersService.getPermissions(user.id);
|
||||||
if (HasFailed(userPermissions)) {
|
if (HasFailed(userPermissions)) {
|
||||||
this.logger.warn(
|
throw Fail(
|
||||||
|
FT.Internal,
|
||||||
|
undefined,
|
||||||
'Fetching user permissions failed: ' + userPermissions.getReason(),
|
'Fetching user permissions failed: ' + userPermissions.getReason(),
|
||||||
);
|
);
|
||||||
throw new InternalServerErrorException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.switchToHttp().getRequest().userPermissions = userPermissions;
|
context.switchToHttp().getRequest().userPermissions = userPermissions;
|
||||||
@@ -78,12 +82,14 @@ export class MainAuthGuard extends AuthGuard(['jwt', 'guest']) {
|
|||||||
if (permissions === undefined)
|
if (permissions === undefined)
|
||||||
return Fail(
|
return Fail(
|
||||||
FT.Internal,
|
FT.Internal,
|
||||||
|
undefined,
|
||||||
`${handlerName} does not have any permissions defined, denying access`,
|
`${handlerName} does not have any permissions defined, denying access`,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isPermissionsArray(permissions))
|
if (!isPermissionsArray(permissions))
|
||||||
return Fail(
|
return Fail(
|
||||||
FT.Internal,
|
FT.Internal,
|
||||||
|
undefined,
|
||||||
`Permissions for ${handlerName} is not a string array`,
|
`Permissions for ${handlerName} is not a string array`,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -93,10 +99,11 @@ export class MainAuthGuard extends AuthGuard(['jwt', 'guest']) {
|
|||||||
private async validateUser(user: EUser): Promise<EUser> {
|
private async validateUser(user: EUser): Promise<EUser> {
|
||||||
const result = EUserSchema.safeParse(user);
|
const result = EUserSchema.safeParse(user);
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
this.logger.warn(
|
throw Fail(
|
||||||
|
FT.Internal,
|
||||||
|
undefined,
|
||||||
`Invalid user object, where it should always be valid: ${result.error}`,
|
`Invalid user object, where it should always be valid: ${result.error}`,
|
||||||
);
|
);
|
||||||
throw new InternalServerErrorException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.data;
|
return result.data;
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import { Controller, Get, Request } from '@nestjs/common';
|
import { Controller, Get, Request } from '@nestjs/common';
|
||||||
import { UserInfoResponse } from 'picsur-shared/dist/dto/api/user-manage.dto';
|
import { UserInfoResponse } from 'picsur-shared/dist/dto/api/user-manage.dto';
|
||||||
import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
|
import { Permission } from 'picsur-shared/dist/dto/permissions.enum';
|
||||||
import { RequiredPermissions } from '../../../decorators/permissions.decorator';
|
import { Fail, FT } from 'picsur-shared/dist/types';
|
||||||
|
import { NoPermissions, RequiredPermissions } from '../../../decorators/permissions.decorator';
|
||||||
import { ReqUserID } from '../../../decorators/request-user.decorator';
|
import { ReqUserID } from '../../../decorators/request-user.decorator';
|
||||||
import { Returns } from '../../../decorators/returns.decorator';
|
import { Returns } from '../../../decorators/returns.decorator';
|
||||||
import type AuthFasityRequest from '../../../models/interfaces/authrequest.dto';
|
import type AuthFasityRequest from '../../../models/interfaces/authrequest.dto';
|
||||||
|
|
||||||
@Controller('api/experiment')
|
@Controller('api/experiment')
|
||||||
//@NoPermissions()
|
@NoPermissions()
|
||||||
@RequiredPermissions(Permission.Settings)
|
@RequiredPermissions(Permission.Settings)
|
||||||
export class ExperimentController {
|
export class ExperimentController {
|
||||||
@Get()
|
@Get()
|
||||||
@@ -16,6 +17,7 @@ export class ExperimentController {
|
|||||||
@Request() req: AuthFasityRequest,
|
@Request() req: AuthFasityRequest,
|
||||||
@ReqUserID() thing: string,
|
@ReqUserID() thing: string,
|
||||||
): Promise<UserInfoResponse> {
|
): Promise<UserInfoResponse> {
|
||||||
|
throw Fail(FT.NotFound, new Error("hello"));
|
||||||
return req.user;
|
return req.user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,8 +58,11 @@ export class ApiService {
|
|||||||
|
|
||||||
const validateResult = sendSchema.safeParse(data);
|
const validateResult = sendSchema.safeParse(data);
|
||||||
if (!validateResult.success) {
|
if (!validateResult.success) {
|
||||||
this.logger.error(validateResult.error);
|
return Fail(
|
||||||
return Fail(FT.SysValidation, 'Something went wrong');
|
FT.SysValidation,
|
||||||
|
'Something went wrong',
|
||||||
|
validateResult.error,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.fetchSafeJson(receiveType, url, {
|
return this.fetchSafeJson(receiveType, url, {
|
||||||
@@ -92,8 +95,11 @@ export class ApiService {
|
|||||||
|
|
||||||
const validateResult = resultSchema.safeParse(result);
|
const validateResult = resultSchema.safeParse(result);
|
||||||
if (!validateResult.success) {
|
if (!validateResult.success) {
|
||||||
this.logger.error(validateResult.error);
|
return Fail(
|
||||||
return Fail(FT.SysValidation, 'Something went wrong');
|
FT.SysValidation,
|
||||||
|
'Something went wrong',
|
||||||
|
validateResult.error,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (validateResult.data.success === false)
|
if (validateResult.data.success === false)
|
||||||
@@ -113,8 +119,7 @@ export class ApiService {
|
|||||||
try {
|
try {
|
||||||
return await response.json();
|
return await response.json();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.error(e);
|
return Fail(FT.Internal, e);
|
||||||
return Fail(FT.Internal, 'Something went wrong');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,8 +155,7 @@ export class ApiService {
|
|||||||
name,
|
name,
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.error(e);
|
return Fail(FT.Internal, e);
|
||||||
return Fail(FT.Internal, 'Something went wrong');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +191,7 @@ export class ApiService {
|
|||||||
error: e,
|
error: e,
|
||||||
url,
|
url,
|
||||||
});
|
});
|
||||||
return Fail(FT.Network, 'Network Error');
|
return Fail(FT.Network, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export enum FT {
|
|||||||
SysValidation = 'sysvalidation',
|
SysValidation = 'sysvalidation',
|
||||||
UsrValidation = 'usrvalidation',
|
UsrValidation = 'usrvalidation',
|
||||||
Permission = 'permission',
|
Permission = 'permission',
|
||||||
NotFound = 'notFound',
|
NotFound = 'notfound',
|
||||||
Conflict = 'conflict',
|
Conflict = 'conflict',
|
||||||
Internal = 'internal',
|
Internal = 'internal',
|
||||||
Authentication = 'authentication',
|
Authentication = 'authentication',
|
||||||
@@ -21,6 +21,7 @@ export enum FT {
|
|||||||
interface FTProp {
|
interface FTProp {
|
||||||
important: boolean;
|
important: boolean;
|
||||||
code: number;
|
code: number;
|
||||||
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FTProps: {
|
const FTProps: {
|
||||||
@@ -29,56 +30,68 @@ const FTProps: {
|
|||||||
[FT.Unknown]: {
|
[FT.Unknown]: {
|
||||||
important: false,
|
important: false,
|
||||||
code: 500,
|
code: 500,
|
||||||
|
message: 'An unkown error occurred',
|
||||||
},
|
},
|
||||||
[FT.Internal]: {
|
[FT.Internal]: {
|
||||||
important: true,
|
important: true,
|
||||||
code: 500,
|
code: 500,
|
||||||
|
message: 'An internal error occurred',
|
||||||
},
|
},
|
||||||
[FT.Database]: {
|
[FT.Database]: {
|
||||||
important: true,
|
important: true,
|
||||||
code: 500,
|
code: 500,
|
||||||
|
message: 'A database error occurred',
|
||||||
},
|
},
|
||||||
[FT.Network]: {
|
[FT.Network]: {
|
||||||
important: true,
|
important: true,
|
||||||
code: 500,
|
code: 500,
|
||||||
|
message: 'A network error occurred',
|
||||||
},
|
},
|
||||||
[FT.SysValidation]: {
|
[FT.SysValidation]: {
|
||||||
important: true,
|
important: true,
|
||||||
code: 500,
|
code: 500,
|
||||||
|
message: 'Validation of internal items failed',
|
||||||
},
|
},
|
||||||
[FT.UsrValidation]: {
|
[FT.UsrValidation]: {
|
||||||
important: false,
|
important: false,
|
||||||
code: 400,
|
code: 400,
|
||||||
|
message: 'Validation of user input failed',
|
||||||
},
|
},
|
||||||
[FT.Permission]: {
|
[FT.Permission]: {
|
||||||
important: false,
|
important: false,
|
||||||
code: 403,
|
code: 403,
|
||||||
|
message: 'Permission denied',
|
||||||
},
|
},
|
||||||
[FT.NotFound]: {
|
[FT.NotFound]: {
|
||||||
important: false,
|
important: false,
|
||||||
code: 404,
|
code: 404,
|
||||||
|
message: 'Item(s) could not be found',
|
||||||
},
|
},
|
||||||
[FT.Conflict]: {
|
[FT.Conflict]: {
|
||||||
important: false,
|
important: false,
|
||||||
code: 409,
|
code: 409,
|
||||||
|
message: 'There was a conflict',
|
||||||
},
|
},
|
||||||
[FT.Authentication]: {
|
[FT.Authentication]: {
|
||||||
important: false,
|
important: false,
|
||||||
code: 200,
|
code: 200,
|
||||||
} ,
|
message: 'Authentication failed',
|
||||||
|
},
|
||||||
[FT.Impossible]: {
|
[FT.Impossible]: {
|
||||||
important: true,
|
important: true,
|
||||||
code: 422,
|
code: 422,
|
||||||
} ,
|
message: 'What you are doing is impossible',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Failure {
|
export class Failure {
|
||||||
private __68351953531423479708__id_failure = 1148363914;
|
private __68351953531423479708__id_failure = 1148363914;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private readonly type: FT = FT.Unknown,
|
||||||
private readonly reason?: string,
|
private readonly reason?: string,
|
||||||
private readonly stack?: string,
|
private readonly stack?: string,
|
||||||
private readonly type: FT = FT.Unknown,
|
private readonly debugMessage?: string,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
getReason(): string {
|
getReason(): string {
|
||||||
@@ -89,6 +102,10 @@ export class Failure {
|
|||||||
return this.stack;
|
return this.stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDebugMessage(): string | undefined {
|
||||||
|
return this.debugMessage;
|
||||||
|
}
|
||||||
|
|
||||||
getType(): FT {
|
getType(): FT {
|
||||||
return this.type;
|
return this.type;
|
||||||
}
|
}
|
||||||
@@ -112,19 +129,34 @@ export class Failure {
|
|||||||
throw new Error('Invalid failure data');
|
throw new Error('Invalid failure data');
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Failure(data.reason, data.stack, data.type);
|
return new Failure(data.type, data.reason, data.stack, data.debugMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Fail(type: FT, reason: any): Failure {
|
export function Fail(type: FT, reason?: any, dbgReason?: any): Failure {
|
||||||
if (typeof reason === 'string') {
|
const strReason = reason.toString();
|
||||||
return new Failure(reason, undefined, type);
|
|
||||||
} else if (reason instanceof Error) {
|
if (typeof dbgReason === 'string') {
|
||||||
return new Failure(reason.message, reason.stack, type);
|
return new Failure(type, strReason, undefined, dbgReason);
|
||||||
} else if (reason instanceof Failure) {
|
} else if (dbgReason instanceof Error) {
|
||||||
|
return new Failure(type, strReason, dbgReason.stack, dbgReason.message);
|
||||||
|
} else if (dbgReason instanceof Failure) {
|
||||||
throw new Error('Cannot fail with a failure, just return it');
|
throw new Error('Cannot fail with a failure, just return it');
|
||||||
} else {
|
} else {
|
||||||
return new Failure('Unkown reason', undefined, type);
|
if (typeof reason === 'string') {
|
||||||
|
return new Failure(type, strReason, undefined, undefined);
|
||||||
|
} else if (reason instanceof Error) {
|
||||||
|
return new Failure(
|
||||||
|
type,
|
||||||
|
FTProps[type].message,
|
||||||
|
reason.stack,
|
||||||
|
reason.message,
|
||||||
|
);
|
||||||
|
} else if (dbgReason instanceof Failure) {
|
||||||
|
throw new Error('Cannot fail with a failure, just return it');
|
||||||
|
} else {
|
||||||
|
return new Failure(type, FTProps[type].message, undefined, undefined);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,5 +13,5 @@ export function ParseMime(mime: string): Failable<FullMime> {
|
|||||||
if (SupportedAnimMimes.includes(mime))
|
if (SupportedAnimMimes.includes(mime))
|
||||||
return { mime, type: SupportedMimeCategory.Animation };
|
return { mime, type: SupportedMimeCategory.Animation };
|
||||||
|
|
||||||
return Fail(FT.Validation, 'Unsupported mime type');
|
return Fail(FT.UsrValidation, 'Unsupported mime type');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user