reset forgoten password tweak
This commit is contained in:
parent
239cd14521
commit
b38261e387
@ -34,3 +34,4 @@ DEFAULT_ADMIN_NAME=admin
|
||||
|
||||
# CORS_ORIGIN=http://localhost:5173
|
||||
# NODE_ENV=development
|
||||
FRONTEND_URL=https://placebo.mk
|
||||
|
||||
@ -1,11 +1,17 @@
|
||||
import { Injectable, ConflictException, Logger, UnauthorizedException, NotFoundException } from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import { CreateUserDto } from '../dto/create-user.dto';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { EmailService } from '../email/email.service';
|
||||
import { randomBytes } from 'crypto';
|
||||
import {
|
||||
Injectable,
|
||||
ConflictException,
|
||||
Logger,
|
||||
UnauthorizedException,
|
||||
NotFoundException,
|
||||
} from "@nestjs/common";
|
||||
import { JwtService } from "@nestjs/jwt";
|
||||
import { PrismaService } from "../prisma/prisma.service";
|
||||
import * as bcrypt from "bcrypt";
|
||||
import { CreateUserDto } from "../dto/create-user.dto";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { EmailService } from "../email/email.service";
|
||||
import { randomBytes } from "crypto";
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
@ -17,11 +23,11 @@ export class AuthService {
|
||||
private configService: ConfigService,
|
||||
private emailService: EmailService,
|
||||
) {
|
||||
this.logger.log('AuthService initialized with EmailService');
|
||||
this.logger.log("AuthService initialized with EmailService");
|
||||
}
|
||||
|
||||
async validateUser(email: string, password: string): Promise<any> {
|
||||
this.logger.debug('Validating user:', { email });
|
||||
this.logger.debug("Validating user:", { email });
|
||||
|
||||
try {
|
||||
const user = await this.prisma.user.findUnique({
|
||||
@ -35,32 +41,34 @@ export class AuthService {
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.debug('Database query result:', {
|
||||
this.logger.debug("Database query result:", {
|
||||
userFound: !!user,
|
||||
userData: user ? {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
isAdmin: user.isAdmin,
|
||||
} : null,
|
||||
userData: user
|
||||
? {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
isAdmin: user.isAdmin,
|
||||
}
|
||||
: null,
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
this.logger.debug('User not found:', { email });
|
||||
this.logger.debug("User not found:", { email });
|
||||
return null;
|
||||
}
|
||||
|
||||
const isPasswordValid = await bcrypt.compare(password, user.password);
|
||||
this.logger.debug('Password validation result:', { isPasswordValid });
|
||||
this.logger.debug("Password validation result:", { isPasswordValid });
|
||||
|
||||
if (!isPasswordValid) {
|
||||
this.logger.debug('Invalid password for user:', { email });
|
||||
this.logger.debug("Invalid password for user:", { email });
|
||||
return null;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { password: _, ...result } = user;
|
||||
this.logger.debug('User validated successfully:', {
|
||||
this.logger.debug("User validated successfully:", {
|
||||
id: result.id,
|
||||
email: result.email,
|
||||
name: result.name,
|
||||
@ -69,7 +77,7 @@ export class AuthService {
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
this.logger.error('Error validating user:', {
|
||||
this.logger.error("Error validating user:", {
|
||||
error: error.message,
|
||||
stack: error.stack,
|
||||
});
|
||||
@ -78,7 +86,7 @@ export class AuthService {
|
||||
}
|
||||
|
||||
async login(user: any) {
|
||||
this.logger.debug('Login called with user:', {
|
||||
this.logger.debug("Login called with user:", {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
@ -91,13 +99,13 @@ export class AuthService {
|
||||
sub: user.id,
|
||||
};
|
||||
|
||||
this.logger.debug('Generated JWT payload:', payload);
|
||||
this.logger.debug("Generated JWT payload:", payload);
|
||||
|
||||
const token = this.jwtService.sign(payload, {
|
||||
secret: this.configService.get<string>('JWT_SECRET'),
|
||||
secret: this.configService.get<string>("JWT_SECRET"),
|
||||
});
|
||||
|
||||
this.logger.debug('JWT token generated successfully');
|
||||
this.logger.debug("JWT token generated successfully");
|
||||
|
||||
return {
|
||||
access_token: token,
|
||||
@ -109,7 +117,7 @@ export class AuthService {
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
this.logger.error('Error generating JWT token:', {
|
||||
this.logger.error("Error generating JWT token:", {
|
||||
error: error.message,
|
||||
stack: error.stack,
|
||||
});
|
||||
@ -121,33 +129,41 @@ export class AuthService {
|
||||
createUserDto: CreateUserDto,
|
||||
isAdmin: boolean = false,
|
||||
): Promise<any> {
|
||||
console.log('=== Starting user creation process ===');
|
||||
this.logger.log('=== Starting user creation process ===');
|
||||
console.log('Creating user:', { ...createUserDto, isAdmin, password: '[REDACTED]' });
|
||||
this.logger.log('Creating user:', { ...createUserDto, isAdmin, password: '[REDACTED]' });
|
||||
console.log("=== Starting user creation process ===");
|
||||
this.logger.log("=== Starting user creation process ===");
|
||||
console.log("Creating user:", {
|
||||
...createUserDto,
|
||||
isAdmin,
|
||||
password: "[REDACTED]",
|
||||
});
|
||||
this.logger.log("Creating user:", {
|
||||
...createUserDto,
|
||||
isAdmin,
|
||||
password: "[REDACTED]",
|
||||
});
|
||||
|
||||
try {
|
||||
// Check for existing user
|
||||
console.log('Checking for existing user...');
|
||||
this.logger.log('Checking for existing user...');
|
||||
console.log("Checking for existing user...");
|
||||
this.logger.log("Checking for existing user...");
|
||||
const existingUser = await this.prisma.user.findUnique({
|
||||
where: { email: createUserDto.email },
|
||||
});
|
||||
|
||||
if (existingUser) {
|
||||
console.log('User already exists:', createUserDto.email);
|
||||
this.logger.warn('User already exists:', createUserDto.email);
|
||||
throw new ConflictException('Email already exists');
|
||||
console.log("User already exists:", createUserDto.email);
|
||||
this.logger.warn("User already exists:", createUserDto.email);
|
||||
throw new ConflictException("Email already exists");
|
||||
}
|
||||
|
||||
// Hash password
|
||||
console.log('Hashing password...');
|
||||
this.logger.log('Hashing password...');
|
||||
console.log("Hashing password...");
|
||||
this.logger.log("Hashing password...");
|
||||
const hashedPassword = await bcrypt.hash(createUserDto.password, 10);
|
||||
|
||||
// Create user
|
||||
console.log('Creating user in database...');
|
||||
this.logger.log('Creating user in database...');
|
||||
console.log("Creating user in database...");
|
||||
this.logger.log("Creating user in database...");
|
||||
const newUser = await this.prisma.user.create({
|
||||
data: {
|
||||
email: createUserDto.email,
|
||||
@ -157,22 +173,28 @@ export class AuthService {
|
||||
},
|
||||
});
|
||||
|
||||
console.log('User created successfully:', { id: newUser.id, email: newUser.email });
|
||||
this.logger.log('User created successfully:', { id: newUser.id, email: newUser.email });
|
||||
console.log("User created successfully:", {
|
||||
id: newUser.id,
|
||||
email: newUser.email,
|
||||
});
|
||||
this.logger.log("User created successfully:", {
|
||||
id: newUser.id,
|
||||
email: newUser.email,
|
||||
});
|
||||
|
||||
// Send welcome email
|
||||
console.log('Attempting to send welcome email...');
|
||||
this.logger.log('Attempting to send welcome email...');
|
||||
console.log("Attempting to send welcome email...");
|
||||
this.logger.log("Attempting to send welcome email...");
|
||||
|
||||
try {
|
||||
console.log('Calling EmailService.sendWelcomeEmail...');
|
||||
this.logger.log('Calling EmailService.sendWelcomeEmail...');
|
||||
console.log("Calling EmailService.sendWelcomeEmail...");
|
||||
this.logger.log("Calling EmailService.sendWelcomeEmail...");
|
||||
await this.emailService.sendWelcomeEmail(newUser.email, newUser.name);
|
||||
console.log('Welcome email sent successfully');
|
||||
this.logger.log('Welcome email sent successfully');
|
||||
console.log("Welcome email sent successfully");
|
||||
this.logger.log("Welcome email sent successfully");
|
||||
} catch (emailError) {
|
||||
console.error('Failed to send welcome email:', emailError);
|
||||
this.logger.error('Failed to send welcome email:', {
|
||||
console.error("Failed to send welcome email:", emailError);
|
||||
this.logger.error("Failed to send welcome email:", {
|
||||
error: emailError.message,
|
||||
code: emailError.code,
|
||||
command: emailError.command,
|
||||
@ -184,12 +206,12 @@ export class AuthService {
|
||||
|
||||
// Return user data
|
||||
const { password, ...result } = newUser;
|
||||
console.log('=== User creation completed ===');
|
||||
this.logger.log('=== User creation completed ===');
|
||||
console.log("=== User creation completed ===");
|
||||
this.logger.log("=== User creation completed ===");
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('Error in createUser:', error);
|
||||
this.logger.error('Error in createUser:', {
|
||||
console.error("Error in createUser:", error);
|
||||
this.logger.error("Error in createUser:", {
|
||||
error: error.message,
|
||||
code: error.code,
|
||||
command: error.command,
|
||||
@ -212,25 +234,25 @@ export class AuthService {
|
||||
// }
|
||||
async getUserInfo(userId: number) {
|
||||
if (!userId) {
|
||||
throw new Error('User ID is required');
|
||||
throw new Error("User ID is required");
|
||||
}
|
||||
|
||||
return this.prisma.user.findUnique({
|
||||
where: {
|
||||
id: userId, // Make sure userId is properly passed and converted to number if needed
|
||||
id: userId, // Make sure userId is properly passed and converted to number if needed
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
isAdmin: true
|
||||
}
|
||||
isAdmin: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async sendPasswordResetToken(email: string) {
|
||||
this.logger.log('=== Starting password reset token process ===');
|
||||
this.logger.debug('Reset token requested for:', email);
|
||||
this.logger.log("=== Starting password reset token process ===");
|
||||
this.logger.debug("Reset token requested for:", email);
|
||||
|
||||
try {
|
||||
// Find the user
|
||||
@ -244,13 +266,15 @@ export class AuthService {
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
this.logger.warn('User not found for password reset:', email);
|
||||
this.logger.warn("User not found for password reset:", email);
|
||||
// Return success anyway to prevent email enumeration
|
||||
return { message: 'If an account exists, a password reset link has been sent' };
|
||||
return {
|
||||
message: "If an account exists, a password reset link has been sent",
|
||||
};
|
||||
}
|
||||
|
||||
// Generate reset token
|
||||
const token = randomBytes(32).toString('hex');
|
||||
const token = randomBytes(32).toString("hex");
|
||||
const expiresAt = new Date();
|
||||
expiresAt.setHours(expiresAt.getHours() + 1); // Token expires in 1 hour
|
||||
|
||||
@ -268,11 +292,11 @@ export class AuthService {
|
||||
await this.emailService.sendPasswordResetEmail(
|
||||
user.email,
|
||||
user.name,
|
||||
token
|
||||
token,
|
||||
);
|
||||
this.logger.debug('Password reset email sent successfully');
|
||||
this.logger.debug("Password reset email sent successfully");
|
||||
} catch (emailError) {
|
||||
this.logger.error('Failed to send password reset email:', {
|
||||
this.logger.error("Failed to send password reset email:", {
|
||||
error: emailError.message,
|
||||
code: emailError.code,
|
||||
stack: emailError.stack,
|
||||
@ -280,9 +304,11 @@ export class AuthService {
|
||||
throw emailError;
|
||||
}
|
||||
|
||||
return { message: 'If an account exists, a password reset link has been sent' };
|
||||
return {
|
||||
message: "If an account exists, a password reset link has been sent",
|
||||
};
|
||||
} catch (error) {
|
||||
this.logger.error('Error in sendPasswordResetToken:', {
|
||||
this.logger.error("Error in sendPasswordResetToken:", {
|
||||
error: error.message,
|
||||
code: error.code,
|
||||
stack: error.stack,
|
||||
@ -292,8 +318,8 @@ export class AuthService {
|
||||
}
|
||||
|
||||
async resetPasswordWithToken(token: string, newPassword: string) {
|
||||
this.logger.log('=== Starting password reset with token process ===');
|
||||
this.logger.debug('Password reset attempted with token');
|
||||
this.logger.log("=== Starting password reset with token process ===");
|
||||
this.logger.debug("Password reset attempted with token");
|
||||
|
||||
try {
|
||||
// Find valid reset token
|
||||
@ -311,8 +337,8 @@ export class AuthService {
|
||||
});
|
||||
|
||||
if (!resetRecord) {
|
||||
this.logger.warn('Invalid or expired reset token used');
|
||||
throw new UnauthorizedException('Invalid or expired reset token');
|
||||
this.logger.warn("Invalid or expired reset token used");
|
||||
throw new UnauthorizedException("Invalid or expired reset token");
|
||||
}
|
||||
|
||||
// Hash new password
|
||||
@ -330,27 +356,29 @@ export class AuthService {
|
||||
}),
|
||||
]);
|
||||
|
||||
this.logger.log('Password reset successful for user:', resetRecord.userId);
|
||||
this.logger.log(
|
||||
"Password reset successful for user:",
|
||||
resetRecord.userId,
|
||||
);
|
||||
|
||||
// Send confirmation email
|
||||
try {
|
||||
await this.emailService.sendPasswordChangeConfirmation(
|
||||
resetRecord.user.email,
|
||||
resetRecord.user.name
|
||||
resetRecord.user.name,
|
||||
);
|
||||
this.logger.debug('Password change confirmation email sent');
|
||||
this.logger.debug("Password change confirmation email sent");
|
||||
} catch (emailError) {
|
||||
this.logger.error('Failed to send password change confirmation:', {
|
||||
this.logger.error("Failed to send password change confirmation:", {
|
||||
error: emailError.message,
|
||||
code: emailError.code,
|
||||
stack: emailError.stack,
|
||||
});
|
||||
// Don't throw error here as password is already changed
|
||||
}
|
||||
|
||||
return { message: 'Password reset successful' };
|
||||
return { message: "Password reset successful" };
|
||||
} catch (error) {
|
||||
this.logger.error('Error in resetPasswordWithToken:', {
|
||||
this.logger.error("Error in resetPasswordWithToken:", {
|
||||
error: error.message,
|
||||
code: error.code,
|
||||
stack: error.stack,
|
||||
|
||||
@ -1,17 +1,10 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { PrismaService } from "../prisma/prisma.service";
|
||||
|
||||
@Injectable()
|
||||
export class ClientService {
|
||||
constructor(private prisma: PrismaService) {}
|
||||
|
||||
// async getClientDocuments(userId: string) {
|
||||
// return this.prisma.document.findMany({
|
||||
// where: {
|
||||
// authorId: Number(userId),
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
async getDocuments(userId: string) {
|
||||
return this.prisma.document.findMany({
|
||||
where: {
|
||||
|
||||
@ -19,7 +19,7 @@ export class EmailService {
|
||||
const pass = this.configService.get<string>("SMTP_PASS");
|
||||
this.from = this.configService.get<string>("EMAIL_FROM");
|
||||
|
||||
console.log("Email Config:", { host, port, user, from: this.from }); // Direct console log
|
||||
console.log("Email Config:", { host, port, user, from: this.from });
|
||||
this.logger.log("Email Config:", { host, port, user, from: this.from });
|
||||
|
||||
this.transporter = nodemailer.createTransport({
|
||||
@ -27,8 +27,8 @@ export class EmailService {
|
||||
host: host,
|
||||
port: port,
|
||||
auth: { user, pass },
|
||||
debug: true, // Enable debug logs
|
||||
logger: true, // Enable transport level logging
|
||||
debug: true,
|
||||
logger: true,
|
||||
});
|
||||
|
||||
// Verify connection
|
||||
@ -37,15 +37,15 @@ export class EmailService {
|
||||
|
||||
private async verifyConnection() {
|
||||
try {
|
||||
console.log("Verifying SMTP connection..."); // Direct console log
|
||||
console.log("Verifying SMTP connection...");
|
||||
this.logger.log("Verifying SMTP connection...");
|
||||
|
||||
const verification = await this.transporter.verify();
|
||||
|
||||
console.log("SMTP connection verified successfully!", verification); // Direct console log
|
||||
console.log("SMTP connection verified successfully!", verification);
|
||||
this.logger.log("SMTP connection verified successfully!", verification);
|
||||
} catch (error) {
|
||||
console.error("SMTP connection failed:", error); // Direct console log
|
||||
console.error("SMTP connection failed:", error);
|
||||
this.logger.error("SMTP connection failed:", {
|
||||
error: error.message,
|
||||
code: error.code,
|
||||
@ -59,7 +59,7 @@ export class EmailService {
|
||||
}
|
||||
|
||||
async sendWelcomeEmail(userEmail: string, username: string): Promise<void> {
|
||||
console.log(`Sending welcome email to ${userEmail}...`); // Direct console log
|
||||
console.log(`Sending welcome email to ${userEmail}...`);
|
||||
this.logger.log(`Sending welcome email to ${userEmail}...`);
|
||||
|
||||
const mailOptions = {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user