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

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

13
import {
14
  findUserByEmail
15
} from '@app/services/user.service'
16

17
import {
18
  LoginSchema,
19
  PasswordResetSchema,
20
  PasswordResetRequestSchema
21
} from '@app/schemas';
22

23
export const AuthController = {
24
  login: async (req: Request, res: Response, next: NextFunction) => {
25
    try {
26
      const parsed = LoginSchema.safeParse(req.body);
27

28
      if (!parsed.success) {
29
        return res.status(400).json({
30
          errors: parsed.error!.issues
31
        });
32
      }
33

34
      const { user, token } = await login(parsed.data);
35

36
      return res.json({
37
        token,
38
        user
39
      });
40
    } catch (err: any) {
41
      if (err.message === 'Invalid credentials') {
42
        return res.status(401).json({ error: 'Invalid credentials' });
43
      }
44
      next(err);
45
    }
46
  },
47

48
  forgotPassword: async (req: Request, res: Response, next: NextFunction) => {
49
    try {
50

51
      const parsed = PasswordResetRequestSchema.safeParse(req.body);
52

53
      if (!parsed.success) {
54
        return res.status(400).json({
55
          errors: parsed.error!.issues
56
        });
57
      }
58

59
      const result = await requestPasswordReset(parsed.data);
60
      return res.status(200).json(result)
61
    } catch (err) {
62
      next(err);
63
    }
64
  },
65

66
  resetPassword: async (req: Request, res: Response, next: NextFunction) => {
67
    try {
68
      const parsed = PasswordResetSchema.safeParse(req.body);
69

70
      if (!parsed.success) {
71
        return res.status(400).json({
72
          errors: parsed.error!.issues
73
        });
74
      }
75

76
      const result = await resetPassword(parsed.data);
77
      return res.status(200).json(result);
78
    } catch (err: any) {
79
      if (err.message.includes('token')) {
80
        return res.status(400).json({ error: err.message });
81
      }
82
      next(err);
83
    }
84
  },
85

86
  verify: async (req: Request, res: Response, next: NextFunction) => {
87
    try {
88
      const authHeader = req.headers.authorization;
89

90
      if (!authHeader || !authHeader.startsWith('Bearer ')) {
91
        return res.status(401).json({ error: 'No token provided' });
92
      }
93

94
      const token = authHeader.substring(7);
95
      const payload = verifyToken(token);
96
      const user = await findUserByEmail(payload.email);
97

98
      if (!user) {
99
        // XXX: Investigate which actual cases this would happen
100
        // But the possible reason is that a token is living inside
101
        // the user's phone, but somehow he was banned/deleted
102
        return res.status(404).json({
103
          errors: "User does not exist anymore"
104
        });
105
      }
106

107
      res.json({
108
        valid: true,
109
        userId: payload.userId,
110
        email: payload.email,
111
        user: {
112
          firstName: user.firstName,
113
          email: user.email,
114
          lastName: user.lastName,
115
          updatedAt: user.updatedAt
116
        }
117
      });
118
    } catch (err: any) {
119
      if (err.name === 'JsonWebTokenError' || err.name === 'TokenExpiredError') {
120
        return res.status(401).json({ error: 'Invalid or expired token' });
121
      }
122
      next(err);
123
    }
124
  }
125
};