eletrotupi / tcc/ api/src/controllers/auth.tse6b6493185741dd24cf765760d87180cb7e1f6a1
3.9 KB | 160 lines Raw
1
import { Request, Response, NextFunction } from 'express';
2
import {
3
  login,
4
  generateToken,
5
  requestPasswordReset,
6
  resetPassword,
7
  activateUser
8
} from '@app/services/auth.service';
9

10
import {
11
  verifyToken
12
} from '@app/lib/jwt';
13

14
import {
15
  findUserByEmail,
16
  findUserById,
17
  findUserByActivationCode
18
} from '@app/services/user.service'
19

20
import {
21
  LoginSchema,
22
  PasswordResetSchema,
23
  PasswordResetRequestSchema,
24
  ActivateUserSchema
25
} from '@app/schemas';
26

27
export const AuthController = {
28
  login: async (req: Request, res: Response, next: NextFunction) => {
29
    try {
30
      const parsed = LoginSchema.safeParse(req.body);
31

32
      if (!parsed.success) {
33
        return res.status(400).json({
34
          errors: parsed.error!.issues
35
        });
36
      }
37

38
      const { user, token } = await login(parsed.data);
39

40
      if (!user.active) {
41
        // TODO: generate a new activation code and send an email
42
        // if the code has expired
43
      }
44

45
      return res.json({
46
        token,
47
        user
48
      });
49
    } catch (err: any) {
50
      if (err.message === 'Invalid credentials') {
51
        return res.status(401).json({ error: 'Invalid credentials' });
52
      }
53
      next(err);
54
    }
55
  },
56

57
  forgotPassword: async (req: Request, res: Response, next: NextFunction) => {
58
    try {
59

60
      const parsed = PasswordResetRequestSchema.safeParse(req.body);
61

62
      if (!parsed.success) {
63
        return res.status(400).json({
64
          errors: parsed.error!.issues
65
        });
66
      }
67

68
      const result = await requestPasswordReset(parsed.data);
69
      return res.status(200).json(result)
70
    } catch (err) {
71
      next(err);
72
    }
73
  },
74

75
  resetPassword: async (req: Request, res: Response, next: NextFunction) => {
76
    try {
77
      const parsed = PasswordResetSchema.safeParse(req.body);
78

79
      if (!parsed.success) {
80
        return res.status(400).json({
81
          errors: parsed.error!.issues
82
        });
83
      }
84

85
      const result = await resetPassword(parsed.data);
86
      return res.status(200).json(result);
87
    } catch (err: any) {
88
      if (err.message.includes('token')) {
89
        return res.status(400).json({ error: err.message });
90
      }
91
      next(err);
92
    }
93
  },
94

95
  verify: async (req: Request, res: Response, next: NextFunction) => {
96
    try {
97
      const authHeader = req.headers.authorization;
98

99
      if (!authHeader || !authHeader.startsWith('Bearer ')) {
100
        return res.status(401).json({ error: 'No token provided' });
101
      }
102

103
      const token = authHeader.substring(7);
104
      const payload = verifyToken(token);
105
      const user = await findUserByEmail(payload.email);
106

107
      if (!user) {
108
        // XXX: Investigate which actual cases this would happen
109
        // But the possible reason is that a token is living inside
110
        // the user's phone, but somehow he was banned/deleted
111
        return res.status(404).json({
112
          errors: "User does not exist anymore"
113
        });
114
      }
115

116
      res.json({
117
        valid: true,
118
        userId: payload.userId,
119
        email: payload.email,
120
        user: {
121
          firstName: user.firstName,
122
          email: user.email,
123
          lastName: user.lastName,
124
          updatedAt: user.updatedAt
125
        }
126
      });
127
    } catch (err: any) {
128
      if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
129
        return res.status(401).json({ error: 'Invalid or expired token' });
130
      }
131
      next(err);
132
    }
133
  },
134

135
  activate: async (req: Request, res: Response, next: NextFunction) => {
136
    try {
137
      const parsed = ActivateUserSchema.safeParse(req.body);
138

139
      if (!parsed.success) {
140
        return res.status(400).json({
141
          errors: parsed.error!.issues
142
        });
143
      }
144

145
      const user = await findUserByActivationCode(String(parsed.data.code));
146

147
      if (!user) {
148
        return res.status(403).json({ error: "Usuario não encontrado" })
149
      }
150

151
      const result = await activateUser(user);
152

153
      return res.status(200).json({
154
        user: result
155
      });
156
    } catch (err: any) {
157
      next(err);
158
    }
159
  }
160
};