eletrotupi / tcc/ api/src/models/user.tsd5dbfbd54d2fb3166d9d8ccdd14000bdcfb0dfdb
3.6 KB | 175 lines Raw
1
import bcrypt from "bcryptjs";
2
import { prisma } from '../lib/prisma'
3
import {
4
  generateToken as createJWT,
5
  generatePasswordResetToken,
6
  getPasswordResetExpiration,
7
  isTokenExpired
8
} from '@app/lib/jwt';
9

10
import {
11
  isValidEmail,
12
  isValidPassword,
13
  sanitizeString,
14
  validateRequiredFields
15
} from "@app/utils/validators";
16

17
import { InvalidEmailError, ShortPasswordError } from '@app/lib/errors/UserErrors'
18

19
type UserOptions = {
20
  email: string;
21
  firstName: string;
22
  lastName: string;
23
  password?: string;
24
  encryptedPassword?: string;
25
};
26

27
const createUser = async (email: string, firstName: string, lastName: string, password: string) => {
28
  // Validate email format
29
  if (!isValidEmail(email)) {
30
    throw new InvalidEmailError()
31
  }
32

33
  // Validate password strength
34
  if (!isValidPassword(password)) {
35
    throw new ShortPasswordError()
36
  }
37

38
  const encryptedPassword = bcrypt.hashSync(password, 10);
39

40
  try {
41
    const user = await prisma.user.create({
42
      data: {
43
        email,
44
        firstName,
45
        lastName,
46
        encryptedPassword
47
      }
48
    });
49

50
    return user;
51
  } catch (err: any) {
52
    throw err;
53
  }
54
}
55

56
const generateToken = (userId: number, email: string) => {
57
  return createJWT(userId, email);
58
}
59

60
const findUserById = async (id: number) => {
61
  return await prisma.user.findUnique({
62
    where: { id }
63
  });
64
};
65

66
const findUserByEmail = async (email: string) => {
67
  return await prisma.user.findUnique({
68
    where: { email }
69
  });
70
};
71

72
const authenticateUser = async (email: string, password: string) => {
73
  const user = await findUserByEmail(email);
74

75
  if (!user) {
76
    throw new Error('Invalid credentials');
77
  }
78

79
  const isPasswordValid = bcrypt.compareSync(password, user.encryptedPassword);
80

81
  if (!isPasswordValid) {
82
    throw new Error('Invalid credentials');
83
  }
84

85
  return user;
86
};
87

88
const initiatePasswordReset = async (email: string) => {
89
  const user = await findUserByEmail(email);
90

91
  if (!user) {
92
    // Don't reveal whether email exists
93
    return { success: true };
94
  }
95

96
  const resetToken = generatePasswordResetToken();
97
  const resetExpires = getPasswordResetExpiration();
98

99
  await prisma.user.update({
100
    where: { id: user.id },
101
    data: {
102
      passwordResetToken: resetToken,
103
      passwordResetExpires: resetExpires
104
    }
105
  });
106

107
  // In production, send email with reset link
108
  // For now, return token for testing
109
  return {
110
    success: true,
111
    token: resetToken,
112
    email: user.email
113
  };
114
};
115

116
const resetPassword = async (token: string, newPassword: string) => {
117
  const user = await prisma.user.findFirst({
118
    where: {
119
      passwordResetToken: token,
120
      passwordResetExpires: { not: null }
121
    }
122
  });
123

124
  if (!user || !user.passwordResetExpires) {
125
    throw new Error('Invalid or expired reset token');
126
  }
127

128
  if (isTokenExpired(user.passwordResetExpires)) {
129
    throw new Error('Reset token has expired');
130
  }
131

132
  if (!isValidPassword(newPassword)) {
133
    throw new ShortPasswordError();
134
  }
135

136
  const encryptedPassword = bcrypt.hashSync(newPassword, 10);
137

138
  await prisma.user.update({
139
    where: { id: user.id },
140
    data: {
141
      encryptedPassword,
142
      passwordResetToken: null,
143
      passwordResetExpires: null
144
    }
145
  });
146

147
  return { success: true };
148
};
149

150
const updateUser = async (user: any, data: UserOptions) => {
151
  const { password } = data;
152

153
  if (password) {
154
    const encryptedPassword = bcrypt.hashSync(password, 10);
155

156
    delete data.password;
157
    data = { ...data, encryptedPassword }
158
  }
159

160
  return await prisma.user.update({
161
    where: { id: user.id },
162
    data
163
  });
164
}
165

166
export {
167
  createUser,
168
  findUserById,
169
  generateToken,
170
  findUserByEmail,
171
  authenticateUser,
172
  initiatePasswordReset,
173
  resetPassword,
174
  updateUser
175
}