1
+ const bcrypt = require ( 'bcrypt' ) ;
2
+ const speakeasy = require ( 'speakeasy' ) ;
3
+ const emailSender = require ( '../utils/emailSender' ) ;
4
+ const jwtHelper = require ( '../utils/jwtHelper' ) ;
5
+ const User = require ( '../models/User' ) ;
6
+
7
+ // Temporary storage for OTPs during registration
8
+ const otpStore = { } ;
9
+
10
+ // Step 1: Register and send OTP
11
+ exports . register = async ( req , res ) => {
12
+ try {
13
+ const { name, email, password, role, club } = req . body ;
14
+
15
+ // Check if user already exists
16
+ const existingUser = await User . findOne ( { email } ) ;
17
+ if ( existingUser ) {
18
+ return res . status ( 400 ) . json ( { error : 'Email already registered' } ) ;
19
+ }
20
+
21
+ // Generate OTP
22
+ const otp = speakeasy . totp ( {
23
+ secret : process . env . OTP_SECRET , // Use a strong secret
24
+ encoding : 'base32' ,
25
+ } ) ;
26
+
27
+ // Store OTP temporarily
28
+ otpStore [ email ] = {
29
+ name,
30
+ password,
31
+ role,
32
+ club,
33
+ otp,
34
+ expiresAt : Date . now ( ) + 5 * 60 * 1000 , // OTP valid for 5 minutes
35
+ } ;
36
+
37
+ // Send OTP via email
38
+ await emailSender . sendEmail (
39
+ email ,
40
+ 'Verify Your Email' ,
41
+ `Your OTP for registration is: ${ otp } . It is valid for 5 minutes.`
42
+ ) ;
43
+
44
+ res . status ( 200 ) . json ( { message : 'OTP sent to your email for verification' } ) ;
45
+ } catch ( error ) {
46
+ res . status ( 500 ) . json ( { error : error . message } ) ;
47
+ }
48
+ } ;
49
+
50
+ // Step 2: Verify OTP and create user
51
+ exports . verifyOtp = async ( req , res ) => {
52
+ try {
53
+ const { email, otp } = req . body ;
54
+
55
+ const storedOtp = otpStore [ email ] ;
56
+ if ( ! storedOtp ) {
57
+ return res . status ( 400 ) . json ( { error : 'OTP not found or expired' } ) ;
58
+ }
59
+
60
+ // Check if OTP matches and has not expired
61
+ if ( storedOtp . otp !== otp || storedOtp . expiresAt < Date . now ( ) ) {
62
+ return res . status ( 400 ) . json ( { error : 'Invalid or expired OTP' } ) ;
63
+ }
64
+
65
+ // Hash the password and save the user
66
+ const hashedPassword = await bcrypt . hash ( storedOtp . password , 10 ) ;
67
+ const newUser = new User ( {
68
+ name : storedOtp . name ,
69
+ email,
70
+ password : hashedPassword ,
71
+ role : storedOtp . role ,
72
+ club : storedOtp . club ,
73
+ } ) ;
74
+ await newUser . save ( ) ;
75
+
76
+ // Clear OTP after successful verification
77
+ delete otpStore [ email ] ;
78
+
79
+ res . status ( 201 ) . json ( { message : 'User registered and verified successfully' , user : newUser } ) ;
80
+ } catch ( error ) {
81
+ res . status ( 500 ) . json ( { error : error . message } ) ;
82
+ }
83
+ } ;
84
+
85
+ // Login with 2FA
86
+ exports . login = async ( req , res ) => {
87
+ try {
88
+ const { email, password } = req . body ;
89
+ const user = await User . findOne ( { email } ) ;
90
+
91
+ if ( ! user || ! ( await bcrypt . compare ( password , user . password ) ) ) {
92
+ return res . status ( 400 ) . json ( { error : 'Invalid email or password' } ) ;
93
+ }
94
+
95
+ const token = jwtHelper . signToken ( { id : user . _id , role : user . role , club : user . club } ) ;
96
+ res . status ( 200 ) . json ( { message : 'Login successful' , token } ) ;
97
+ } catch ( error ) {
98
+ res . status ( 500 ) . json ( { error : error . message } ) ;
99
+ }
100
+ } ;
101
+
102
+ exports . logout = ( req , res ) => {
103
+ res . status ( 200 ) . json ( { message : 'Logout successful' } ) ;
104
+ } ;
105
+
106
+ exports . validateToken = ( req , res ) => {
107
+ try {
108
+ const token = req . header ( 'Authorization' ) ?. replace ( 'Bearer ' , '' ) ;
109
+ const decoded = jwtHelper . verifyToken ( token ) ;
110
+ res . status ( 200 ) . json ( { valid : true , user : decoded } ) ;
111
+ } catch ( error ) {
112
+ res . status ( 401 ) . json ( { valid : false , error : 'Invalid or expired token' } ) ;
113
+ }
114
+ } ;
0 commit comments