diff --git a/src/core/exceptions/mail-server.exceptions.ts b/src/core/exceptions/mail-server.exceptions.ts index ec5ecdf..df1a79f 100644 --- a/src/core/exceptions/mail-server.exceptions.ts +++ b/src/core/exceptions/mail-server.exceptions.ts @@ -6,36 +6,341 @@ export class MailServerException extends HttpException { } } +// User-related exceptions export class UserNotFoundException extends MailServerException { constructor(userId: string) { super(`User with ID '${userId}' not found`, HttpStatus.NOT_FOUND); } } -export class MailboxNotFoundException extends MailServerException { - constructor(mailboxId: string) { - super(`Mailbox with ID '${mailboxId}' not found`, HttpStatus.NOT_FOUND); - } -} - -export class MessageNotFoundException extends MailServerException { - constructor(messageId: number) { - super(`Message with ID '${messageId}' not found`, HttpStatus.NOT_FOUND); - } -} - export class UserAlreadyExistsException extends MailServerException { constructor(username: string) { super(`User '${username}' already exists`, HttpStatus.CONFLICT); } } +export class UserQuotaExceededException extends MailServerException { + constructor(userId: string, quotaType?: string) { + super(`User '${userId}' has exceeded ${quotaType || "storage"} quota`, HttpStatus.INSUFFICIENT_STORAGE); + } +} + +export class UserDisabledException extends MailServerException { + constructor(userId: string) { + super(`User '${userId}' is disabled`, HttpStatus.FORBIDDEN); + } +} + +// Authentication exceptions +export class AuthenticationFailedException extends MailServerException { + constructor(details?: string) { + super(`Authentication failed${details ? `: ${details}` : ""}`, HttpStatus.UNAUTHORIZED); + } +} + +export class InvalidCredentialsException extends MailServerException { + constructor() { + super("Invalid username or password", HttpStatus.UNAUTHORIZED); + } +} + +export class PasswordExpiredException extends MailServerException { + constructor() { + super("Password has expired and must be changed", HttpStatus.UNAUTHORIZED); + } +} + +export class TooManyLoginAttemptsException extends MailServerException { + constructor() { + super("Too many login attempts, account temporarily locked", HttpStatus.TOO_MANY_REQUESTS); + } +} + +// 2FA exceptions +export class TwoFactorRequiredException extends MailServerException { + constructor(methods: string[]) { + super(`Two-factor authentication required. Available methods: ${methods.join(", ")}`, HttpStatus.UNAUTHORIZED); + } +} + +export class InvalidTwoFactorTokenException extends MailServerException { + constructor(method?: string) { + super(`Invalid ${method || "2FA"} token provided`, HttpStatus.UNAUTHORIZED); + } +} + +export class TwoFactorNotSetupException extends MailServerException { + constructor(method?: string) { + super(`${method || "Two-factor authentication"} is not setup for this user`, HttpStatus.PRECONDITION_FAILED); + } +} + +export class TwoFactorAlreadySetupException extends MailServerException { + constructor(method?: string) { + super(`${method || "Two-factor authentication"} is already setup for this user`, HttpStatus.CONFLICT); + } +} + +export class InvalidBackupCodeException extends MailServerException { + constructor() { + super("Invalid or already used backup code", HttpStatus.UNAUTHORIZED); + } +} + +export class NoBackupCodesException extends MailServerException { + constructor() { + super("No backup codes available for this user", HttpStatus.NOT_FOUND); + } +} + +// Mailbox exceptions +export class MailboxNotFoundException extends MailServerException { + constructor(mailboxId: string) { + super(`Mailbox with ID '${mailboxId}' not found`, HttpStatus.NOT_FOUND); + } +} + +export class MailboxAlreadyExistsException extends MailServerException { + constructor(mailboxPath: string) { + super(`Mailbox '${mailboxPath}' already exists`, HttpStatus.CONFLICT); + } +} + +export class SpecialMailboxException extends MailServerException { + constructor(operation: string) { + super(`Cannot ${operation} special mailbox`, HttpStatus.FORBIDDEN); + } +} + +// Message exceptions +export class MessageNotFoundException extends MailServerException { + constructor(messageId: number) { + super(`Message with ID '${messageId}' not found`, HttpStatus.NOT_FOUND); + } +} + +export class MessageTooLargeException extends MailServerException { + constructor(size?: number, limit?: number) { + const sizeInfo = size && limit ? ` (${size} bytes, limit: ${limit} bytes)` : ""; + super(`Message is too large${sizeInfo}`, HttpStatus.PAYLOAD_TOO_LARGE); + } +} + +export class InvalidMessageFormatException extends MailServerException { + constructor(details?: string) { + super(`Invalid message format${details ? `: ${details}` : ""}`, HttpStatus.BAD_REQUEST); + } +} + +export class MessageExpiredException extends MailServerException { + constructor(messageId: number) { + super(`Message with ID '${messageId}' has expired`, HttpStatus.GONE); + } +} + +// Address exceptions +export class AddressNotFoundException extends MailServerException { + constructor(address: string) { + super(`Address '${address}' not found`, HttpStatus.NOT_FOUND); + } +} + export class AddressAlreadyExistsException extends MailServerException { constructor(address: string) { super(`Address '${address}' already exists`, HttpStatus.CONFLICT); } } +export class InvalidAddressFormatException extends MailServerException { + constructor(address: string) { + super(`Invalid email address format: '${address}'`, HttpStatus.BAD_REQUEST); + } +} + +export class AddressQuotaExceededException extends MailServerException { + constructor(userId: string) { + super(`User '${userId}' has reached maximum number of addresses`, HttpStatus.FORBIDDEN); + } +} + +// Validation exceptions +export class ValidationException extends MailServerException { + constructor(field: string, value?: string) { + super(`Validation failed for field '${field}'${value ? ` with value '${value}'` : ""}`, HttpStatus.BAD_REQUEST); + } +} + +export class RequiredFieldException extends MailServerException { + constructor(field: string) { + super(`Required field '${field}' is missing`, HttpStatus.BAD_REQUEST); + } +} + +export class InvalidParameterException extends MailServerException { + constructor(parameter: string, expectedType?: string) { + super(`Invalid parameter '${parameter}'${expectedType ? `, expected ${expectedType}` : ""}`, HttpStatus.BAD_REQUEST); + } +} + +export class DuplicateValueException extends MailServerException { + constructor(field: string, value: string) { + super(`Duplicate value '${value}' for field '${field}'`, HttpStatus.CONFLICT); + } +} + +// Storage and quota exceptions +export class StorageQuotaExceededException extends MailServerException { + constructor(used?: number, limit?: number) { + const quotaInfo = used && limit ? ` (used: ${used}MB, limit: ${limit}MB)` : ""; + super(`Storage quota exceeded${quotaInfo}`, HttpStatus.INSUFFICIENT_STORAGE); + } +} + +export class RecipientQuotaExceededException extends MailServerException { + constructor(count?: number, limit?: number) { + const quotaInfo = count && limit ? ` (current: ${count}, limit: ${limit})` : ""; + super(`Recipient quota exceeded${quotaInfo}`, HttpStatus.TOO_MANY_REQUESTS); + } +} + +export class ConnectionQuotaExceededException extends MailServerException { + constructor(type: string, count?: number, limit?: number) { + const quotaInfo = count && limit ? ` (current: ${count}, limit: ${limit})` : ""; + super(`${type} connection quota exceeded${quotaInfo}`, HttpStatus.TOO_MANY_REQUESTS); + } +} + +// Filter exceptions +export class FilterNotFoundException extends MailServerException { + constructor(filterId: string) { + super(`Filter with ID '${filterId}' not found`, HttpStatus.NOT_FOUND); + } +} + +export class InvalidFilterRuleException extends MailServerException { + constructor(details?: string) { + super(`Invalid filter rule${details ? `: ${details}` : ""}`, HttpStatus.BAD_REQUEST); + } +} + +// DKIM exceptions +export class DKIMNotFoundException extends MailServerException { + constructor(domain: string) { + super(`DKIM key not found for domain '${domain}'`, HttpStatus.NOT_FOUND); + } +} + +export class InvalidDKIMKeyException extends MailServerException { + constructor(details?: string) { + super(`Invalid DKIM key${details ? `: ${details}` : ""}`, HttpStatus.BAD_REQUEST); + } +} + +// Submission exceptions +export class SubmissionFailedException extends MailServerException { + constructor(details?: string) { + super(`Message submission failed${details ? `: ${details}` : ""}`, HttpStatus.BAD_GATEWAY); + } +} + +export class RateLimitExceededException extends MailServerException { + constructor(type?: string) { + super(`Rate limit exceeded${type ? ` for ${type}` : ""}`, HttpStatus.TOO_MANY_REQUESTS); + } +} + +// Application Password exceptions +export class ApplicationPasswordNotFoundException extends MailServerException { + constructor(aspId: string) { + super(`Application password with ID '${aspId}' not found`, HttpStatus.NOT_FOUND); + } +} + +export class ApplicationPasswordExpiredException extends MailServerException { + constructor(aspId: string) { + super(`Application password with ID '${aspId}' has expired`, HttpStatus.UNAUTHORIZED); + } +} + +// Export/Import exceptions +export class ExportNotFoundException extends MailServerException { + constructor(exportId: string) { + super(`Export with ID '${exportId}' not found`, HttpStatus.NOT_FOUND); + } +} + +export class ExportInProgressException extends MailServerException { + constructor(exportId: string) { + super(`Export with ID '${exportId}' is still in progress`, HttpStatus.CONFLICT); + } +} + +export class ImportFailedException extends MailServerException { + constructor(details?: string) { + super(`Import failed${details ? `: ${details}` : ""}`, HttpStatus.BAD_REQUEST); + } +} + +// Audit exceptions +export class AuditLogNotFoundException extends MailServerException { + constructor(entryId: string) { + super(`Audit log entry with ID '${entryId}' not found`, HttpStatus.NOT_FOUND); + } +} + +// Webhook exceptions +export class WebhookNotFoundException extends MailServerException { + constructor(webhookId: string) { + super(`Webhook with ID '${webhookId}' not found`, HttpStatus.NOT_FOUND); + } +} + +export class WebhookDeliveryFailedException extends MailServerException { + constructor(url: string, details?: string) { + super(`Webhook delivery failed to '${url}'${details ? `: ${details}` : ""}`, HttpStatus.BAD_GATEWAY); + } +} + +// Autoreply exceptions +export class AutoreplyAlreadyActiveException extends MailServerException { + constructor(userId: string) { + super(`Autoreply is already active for user '${userId}'`, HttpStatus.CONFLICT); + } +} + +export class AutoreplyNotActiveException extends MailServerException { + constructor(userId: string) { + super(`Autoreply is not active for user '${userId}'`, HttpStatus.NOT_FOUND); + } +} + +// Archive exceptions +export class ArchiveNotFoundException extends MailServerException { + constructor(archiveId: string) { + super(`Archive with ID '${archiveId}' not found`, HttpStatus.NOT_FOUND); + } +} + +export class ArchiveCorruptedException extends MailServerException { + constructor(archiveId: string) { + super(`Archive with ID '${archiveId}' is corrupted`, HttpStatus.UNPROCESSABLE_ENTITY); + } +} + +// Domain Access exceptions +export class DomainAccessForbiddenException extends MailServerException { + constructor(domain: string) { + super(`Access to domain '${domain}' is forbidden`, HttpStatus.FORBIDDEN); + } +} + +export class DomainNotAllowedException extends MailServerException { + constructor(domain: string) { + super(`Domain '${domain}' is not allowed`, HttpStatus.FORBIDDEN); + } +} + +// Connection and server exceptions export class MailServerConnectionException extends MailServerException { constructor(details?: string) { super(`Mail server connection failed${details ? `: ${details}` : ""}`, HttpStatus.SERVICE_UNAVAILABLE); @@ -47,3 +352,15 @@ export class InvalidMailServerResponseException extends MailServerException { super("Invalid response from mail server", HttpStatus.BAD_GATEWAY); } } + +export class MailServerTimeoutException extends MailServerException { + constructor(operation?: string) { + super(`Mail server timeout${operation ? ` during ${operation}` : ""}`, HttpStatus.GATEWAY_TIMEOUT); + } +} + +export class MailServerMaintenanceException extends MailServerException { + constructor() { + super("Mail server is under maintenance", HttpStatus.SERVICE_UNAVAILABLE); + } +} diff --git a/src/main.ts b/src/main.ts index 8f2aaba..775a112 100644 --- a/src/main.ts +++ b/src/main.ts @@ -29,7 +29,7 @@ async function bootstrap() { app.useGlobalInterceptors(new ResponseInterceptor(), new PaginationInterceptor()); - app.useGlobalFilters(new MailServerExceptionFilter(), new HttpExceptionFilter()); + app.useGlobalFilters(new HttpExceptionFilter(), new MailServerExceptionFilter()); app.enableCors({ origin: true, diff --git a/src/modules/auth/DTO/create-two-factor.dto.ts b/src/modules/auth/DTO/create-two-factor.dto.ts index 44bfd9b..1b26e57 100644 --- a/src/modules/auth/DTO/create-two-factor.dto.ts +++ b/src/modules/auth/DTO/create-two-factor.dto.ts @@ -25,6 +25,12 @@ export class Verify2FADto { token: string; } +export class Disable2FADto { + @ApiProperty({ description: "TOTP token or backup code for verification", example: "123456" }) + @IsString() + token: string; +} + export class UseBackupCodeDto { @ApiProperty({ description: "Backup code", example: "abcd1234" }) @IsString() diff --git a/src/modules/auth/auth.controller.ts b/src/modules/auth/auth.controller.ts index ef6a0f5..0640826 100644 --- a/src/modules/auth/auth.controller.ts +++ b/src/modules/auth/auth.controller.ts @@ -1,8 +1,8 @@ -import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Patch, Post } from "@nestjs/common"; +import { Body, Controller, HttpCode, HttpStatus, Patch, Post } from "@nestjs/common"; import { ApiBadRequestResponse, ApiOperation, ApiResponse, ApiTags, ApiUnauthorizedResponse } from "@nestjs/swagger"; import { ChangePasswordDto } from "./DTO/change-password.dto"; -import { Enable2FADto, GenerateBackupCodesDto, UseBackupCodeDto, Verify2FADto } from "./DTO/create-two-factor.dto"; +import { Disable2FADto, Enable2FADto, GenerateBackupCodesDto, UseBackupCodeDto, Verify2FADto } from "./DTO/create-two-factor.dto"; import { LoginDto } from "./DTO/login.dto"; import { RefreshTokenDto } from "./DTO/refresh-token.dto"; import { AuthService } from "./services/auth.service"; @@ -81,21 +81,12 @@ export class AuthController { } @AuthGuards() - @Get("2fa/status") - @ApiOperation({ summary: "Get 2FA status for user" }) - @ApiResponse({ status: 200, description: "2FA status retrieved successfully" }) - @ApiResponse({ status: 400, description: "Failed to get 2FA status" }) - get2FAStatus(@UserDec("wildduckUserId") wildduckUserId: string) { - return this.twoFactorService.get2FAStatus(wildduckUserId); - } - - @AuthGuards() - @Delete("2fa/disable") + @Post("2fa/disable") @ApiOperation({ summary: "Disable 2FA for user" }) @ApiResponse({ status: 200, description: "2FA disabled successfully" }) @ApiResponse({ status: 400, description: "Failed to disable 2FA" }) - disable2FA(@UserDec("wildduckUserId") wildduckUserId: string) { - return this.twoFactorService.disable2FA(wildduckUserId); + disable2FA(@UserDec("wildduckUserId") wildduckUserId: string, @Body() disable2FADto: Disable2FADto) { + return this.twoFactorService.disable2FA(wildduckUserId, disable2FADto); } @AuthGuards() diff --git a/src/modules/auth/services/auth.service.ts b/src/modules/auth/services/auth.service.ts index 7d2e147..af0689b 100644 --- a/src/modules/auth/services/auth.service.ts +++ b/src/modules/auth/services/auth.service.ts @@ -29,7 +29,12 @@ export class AuthService { if (!user.isActive) throw new BadRequestException(AuthMessage.USER_ACCOUNT_INACTIVE); if (user.is2FAEnabled) { - if (!twoFactorToken) throw new BadRequestException(TwoFactorMessage.TWO_FACTOR_TOKEN_REQUIRED); + if (!twoFactorToken) { + return { + message: TwoFactorMessage.TWO_FACTOR_TOKEN_REQUIRED, + requires2FA: true, + }; + } const is2FAValid = await this.twoFactorService.validateTwoFactorToken(user, twoFactorToken); if (!is2FAValid) throw new BadRequestException(TwoFactorMessage.TWO_FACTOR_TOKEN_INVALID); diff --git a/src/modules/auth/services/two-factor.service.ts b/src/modules/auth/services/two-factor.service.ts index 2588a4d..c1679c8 100644 --- a/src/modules/auth/services/two-factor.service.ts +++ b/src/modules/auth/services/two-factor.service.ts @@ -6,7 +6,7 @@ import { TwoFactorMessage, UserMessage } from "../../../common/enums/message.enu import { MailServerService } from "../../mail-server/services/mail-server.service"; import { User } from "../../users/entities/user.entity"; import { UserRepository } from "../../users/repositories/user.repository"; -import { Enable2FADto, UseBackupCodeDto, Verify2FADto } from "../DTO/create-two-factor.dto"; +import { Disable2FADto, Enable2FADto, UseBackupCodeDto, Verify2FADto } from "../DTO/create-two-factor.dto"; @Injectable() export class TwoFactorService { @@ -72,27 +72,14 @@ export class TwoFactorService { } //============================================== - async get2FAStatus(wildduckUserId: string) { + async disable2FA(wildduckUserId: string, disable2FADto: Disable2FADto) { const user = await this.userRepository.findOne({ wildduckUserId }); if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND); - const response = await firstValueFrom(this.mailServerService.twoFactor.get2FAStatus(wildduckUserId)); + if (!user.is2FAEnabled) throw new BadRequestException(TwoFactorMessage.TWO_FACTOR_NOT_ENABLED); - return { - enabled: user.is2FAEnabled, - enabledMethods: response.enabled2fa, - totpEnabled: response.enabled2fa.includes("totp"), - backupCodesAvailable: response.enabled2fa.includes("backup"), - enabledAt: user.twoFactorEnabledAt, - }; - } - - //============================================== - async disable2FA(wildduckUserId: string) { - const user = await this.userRepository.findOne({ wildduckUserId }); - - if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND); + await this.validateTwoFactorToken(user, disable2FADto.token); await firstValueFrom(this.mailServerService.twoFactor.disableAll2FA(wildduckUserId)); diff --git a/src/modules/mail-server/interfaces/two-factor-response.interface.ts b/src/modules/mail-server/interfaces/two-factor-response.interface.ts index 598602a..d7a3045 100644 --- a/src/modules/mail-server/interfaces/two-factor-response.interface.ts +++ b/src/modules/mail-server/interfaces/two-factor-response.interface.ts @@ -1,17 +1,3 @@ -export interface TwoFactorStatusResponse { - success: true; - enabled2fa: string[]; - totp?: { - enabled: boolean; - url?: string; - label?: string; - }; - u2f?: { - enabled: boolean; - keyHandle?: string; - }; -} - export interface TOTPSetupResponse { success: true; qrcode: string; diff --git a/src/modules/mail-server/services/wildduck-base.service.ts b/src/modules/mail-server/services/wildduck-base.service.ts index 812401f..1c69d75 100644 --- a/src/modules/mail-server/services/wildduck-base.service.ts +++ b/src/modules/mail-server/services/wildduck-base.service.ts @@ -4,6 +4,7 @@ import { ConfigService } from "@nestjs/config"; import { AxiosResponse } from "axios"; import { Observable, catchError, map, throwError } from "rxjs"; +import * as MailServerExceptions from "../../../core/exceptions/mail-server.exceptions"; import { MailServerException } from "../../../core/exceptions/mail-server.exceptions"; import { WildDuckErrorResponse, WildDuckSuccessResponse } from "../interfaces/wildduck-response.interface"; @@ -19,17 +20,15 @@ export class WildDuckBaseService { this.baseURL = this.configService.getOrThrow("WILDDUCK_BASE_URL"); } - protected buildUrl(path: string, params?: Record): string { + protected buildUrl(path: string, params?: Record): string { const url = new URL(path, this.baseURL); - if (params) { - Object.entries(params).forEach(([key, value]) => { - if (value !== undefined && value !== null) { - url.searchParams.set(key, String(value)); + Object.keys(params).forEach((key) => { + if (params[key] !== undefined && params[key] !== null) { + url.searchParams.append(key, params[key].toString()); } }); } - return url.toString(); } @@ -41,7 +40,7 @@ export class WildDuckBaseService { const data = response.data; if ("success" in data && data.success === false) { - throw new MailServerException(data.error || "WildDuck API error"); + throw this.handleMailServerError(data.error || "WildDuck API error", response.status); } if ("success" in data && data.success === true) { @@ -54,14 +53,57 @@ export class WildDuckBaseService { this.logger.error(`WildDuck API error: ${error.message}`, error.stack); if (error.response?.data?.error) { - return throwError(() => new MailServerException(error.response.data.error)); + return throwError(() => this.handleMailServerError(error.response.data.error, error.response.status)); } - return throwError(() => error); + if (error.code === "ECONNREFUSED" || error.code === "ENOTFOUND") { + return throwError(() => new MailServerExceptions.MailServerConnectionException(error.message)); + } + + return throwError(() => new MailServerException(error.message || "Unknown mail server error")); }), ); } + /** + * Handle mail server errors and throw appropriate exceptions + */ + protected handleMailServerError(errorMessage: string, statusCode?: number): MailServerException { + // Map HTTP status codes to appropriate exceptions + if (statusCode) { + switch (statusCode) { + case 401: + return new MailServerExceptions.AuthenticationFailedException(errorMessage); + case 403: + return new MailServerExceptions.UserDisabledException("user"); + case 404: + return new MailServerExceptions.UserNotFoundException("unknown"); + case 409: + return new MailServerExceptions.UserAlreadyExistsException("user"); + case 413: + return new MailServerExceptions.MessageTooLargeException(); + case 429: + return new MailServerExceptions.TooManyLoginAttemptsException(); + case 502: + return new MailServerExceptions.InvalidMailServerResponseException(); + case 503: + return new MailServerExceptions.MailServerMaintenanceException(); + case 504: + return new MailServerExceptions.MailServerTimeoutException(); + case 507: + return new MailServerExceptions.StorageQuotaExceededException(); + default: + if (statusCode >= 500) { + return new MailServerExceptions.InvalidMailServerResponseException(); + } + break; + } + } + + // Default to generic mail server exception with the error message + return new MailServerException(errorMessage); + } + protected get(path: string, params?: Record): Observable { const url = this.buildUrl(path, params); this.logger.debug(`WildDuck GET: ${url}`); @@ -81,6 +123,6 @@ export class WildDuckBaseService { protected delete(path: string, params?: Record): Observable { const url = this.buildUrl(path, params); - return this.handleResponse(this.httpService.delete(url)); + return this.handleResponse(this.httpService.delete(url, { params })); } } diff --git a/src/modules/mail-server/services/wildduck-messages.service.ts b/src/modules/mail-server/services/wildduck-messages.service.ts index 976ef2e..fd8c4de 100644 --- a/src/modules/mail-server/services/wildduck-messages.service.ts +++ b/src/modules/mail-server/services/wildduck-messages.service.ts @@ -3,6 +3,7 @@ import { Observable } from "rxjs"; import { catchError, map, throwError } from "rxjs"; import { WildDuckBaseService } from "./wildduck-base.service"; +import * as MailServerExceptions from "../../../core/exceptions/mail-server.exceptions"; import { MailServerException } from "../../../core/exceptions/mail-server.exceptions"; import { ListMessagesQueryDto, SearchMessagesMailServerQueryDto, UpdateMessageDto, UploadMessageDto } from "../DTO/message.dto"; import { AttachmentResponse } from "../interfaces/attachment.interface"; @@ -101,10 +102,14 @@ export class WildDuckMessagesService extends WildDuckBaseService { this.logger.error(`WildDuck API error: ${error.message}`, error.stack); if (error.response?.data?.error) { - return throwError(() => new MailServerException(error.response.data.error)); + return throwError(() => this.handleMailServerError(error.response.data.error, error.response.status)); } - return throwError(() => error); + if (error.code === "ECONNREFUSED" || error.code === "ENOTFOUND") { + return throwError(() => new MailServerExceptions.MailServerConnectionException(error.message)); + } + + return throwError(() => new MailServerException(error.message || "Unknown mail server error")); }), ); } diff --git a/src/modules/mail-server/services/wildduck-two-factor.service.ts b/src/modules/mail-server/services/wildduck-two-factor.service.ts index 45f4a94..85fff50 100644 --- a/src/modules/mail-server/services/wildduck-two-factor.service.ts +++ b/src/modules/mail-server/services/wildduck-two-factor.service.ts @@ -2,12 +2,7 @@ import { Injectable } from "@nestjs/common"; import { Observable } from "rxjs"; import { WildDuckBaseService } from "./wildduck-base.service"; -import { - BackupCodesGenerateResponse, - BackupCodesListResponse, - TOTPSetupResponse, - TwoFactorStatusResponse, -} from "../interfaces/two-factor-response.interface"; +import { BackupCodesGenerateResponse, BackupCodesListResponse, TOTPSetupResponse } from "../interfaces/two-factor-response.interface"; import { BackupCodeData, BaseTwoFactorData, @@ -20,13 +15,6 @@ import { WildDuckSuccessResponse } from "../interfaces/wildduck-response.interfa @Injectable() export class WildDuckTwoFactorService extends WildDuckBaseService { - /** - * Get 2FA status for user - */ - get2FAStatus(userId: string): Observable { - return this.get(`/users/${userId}/2fa`); - } - // TOTP Methods /** * Setup TOTP 2FA