2828use Auth ;
2929use Alert ;
3030use Cache ;
31+ use Crypt ;
3132use Illuminate \Http \Request ;
3233use Pterodactyl \Models \User ;
3334use PragmaRX \Google2FA \Google2FA ;
35+ use Pterodactyl \Events \Auth \FailedLogin ;
3436use Pterodactyl \Http \Controllers \Controller ;
3537use Illuminate \Foundation \Auth \AuthenticatesUsers ;
3638
@@ -79,6 +81,27 @@ public function __construct()
7981 $ this ->middleware ('guest ' , ['except ' => 'logout ' ]);
8082 }
8183
84+ /**
85+ * Get the failed login response instance.
86+ *
87+ * @param \Illuminate\Http\Request $request
88+ * @return \Illuminate\Http\RedirectResponse
89+ */
90+ protected function sendFailedLoginResponse (Request $ request )
91+ {
92+ $ this ->incrementLoginAttempts ($ request );
93+
94+ $ errors = [$ this ->username () => trans ('auth.failed ' )];
95+
96+ if ($ request ->expectsJson ()) {
97+ return response ()->json ($ errors , 422 );
98+ }
99+
100+ return redirect ()->route ('auth.login ' )
101+ ->withInput ($ request ->only ($ this ->username (), 'remember ' ))
102+ ->withErrors ($ errors );
103+ }
104+
82105 /**
83106 * Handle a login request to the application.
84107 *
@@ -88,42 +111,46 @@ public function __construct()
88111 public function login (Request $ request )
89112 {
90113 // Check wether the user identifier is an email address or a username
91- $ isEmail = str_contains ($ request ->input ('user ' ), '@ ' );
92-
93- $ this ->validate ($ request , [
94- 'user ' => $ isEmail ? 'required|email ' : 'required|string ' ,
95- 'password ' => 'required ' ,
96- ]);
114+ $ checkField = str_contains ($ request ->input ('user ' ), '@ ' ) ? 'email ' : 'username ' ;
97115
98- if ($ lockedOut = $ this ->hasTooManyLoginAttempts ($ request )) {
116+ if ($ this ->hasTooManyLoginAttempts ($ request )) {
99117 $ this ->fireLockoutEvent ($ request );
100118
101119 return $ this ->sendLockoutResponse ($ request );
102120 }
103121
104- // Is the user (email or username) & password valid?
105- if (! Auth::once ([
106- $ isEmail ? 'email ' : 'username ' => $ request ->input ('user ' ),
107- 'password ' => $ request ->input ('password ' ),
108- ], $ request ->has ('remember ' ))) {
109- if (! $ lockedOut ) {
110- $ this ->incrementLoginAttempts ($ request );
111- }
112-
122+ // Determine if the user even exists.
123+ $ user = User::where ($ checkField , $ request ->input ($ this ->username ()))->first ();
124+ if (! $ user ) {
113125 return $ this ->sendFailedLoginResponse ($ request );
114126 }
115127
116- // Verify TOTP Token was Valid
117- if (Auth::user ()->use_totp ) {
118- $ verifyKey = str_random (64 );
119- Cache::put ($ verifyKey , Auth::user ()->id , 5 );
128+ // If user uses 2FA, redirect to that page.
129+ if ($ user ->use_totp ) {
130+ $ token = str_random (64 );
131+ Cache::put ($ token , [
132+ 'user_id ' => $ user ->id ,
133+ 'credentials ' => Crypt::encrypt (serialize ([
134+ $ checkField => $ request ->input ($ this ->username ()),
135+ 'password ' => $ request ->input ('password ' ),
136+ ])),
137+ ], 5 );
138+
139+ return redirect ()->route ('auth.totp ' )->with ('authentication_token ' , $ token );
140+ }
120141
121- return redirect ()->route ('auth.totp ' )->with ('authentication_token ' , $ verifyKey );
122- } else {
123- Auth::login (Auth::user (), $ request ->has ('remember ' ));
142+ $ attempt = Auth::attempt ([
143+ $ checkField => $ request ->input ($ this ->username ()),
144+ 'password ' => $ request ->input ('password ' ),
145+ 'use_totp ' => 0 ,
146+ ], $ request ->has ('remember ' ));
124147
148+ if ($ attempt ) {
125149 return $ this ->sendLoginResponse ($ request );
126150 }
151+
152+ // Login failed, send response.
153+ return $ this ->sendFailedLoginResponse ($ request );
127154 }
128155
129156 /**
@@ -134,14 +161,14 @@ public function login(Request $request)
134161 */
135162 public function totp (Request $ request )
136163 {
137- $ verifyKey = $ request ->session ()->get ('authentication_token ' );
164+ $ token = $ request ->session ()->get ('authentication_token ' );
138165
139- if (is_null ($ verifyKey ) || Auth::user ()) {
166+ if (is_null ($ token ) || Auth::user ()) {
140167 return redirect ()->route ('auth.login ' );
141168 }
142169
143170 return view ('auth.totp ' , [
144- 'verify_key ' => $ verifyKey ,
171+ 'verify_key ' => $ token ,
145172 'remember ' => $ request ->has ('remember ' ),
146173 ]);
147174 }
@@ -157,30 +184,40 @@ public function totpCheckpoint(Request $request)
157184 $ G2FA = new Google2FA ();
158185
159186 if (is_null ($ request ->input ('verify_token ' ))) {
160- $ this ->incrementLoginAttempts ($ request );
161- Alert:: danger ( trans ( ' auth.totp_failed ' ))-> flash ();
187+ return $ this ->sendFailedLoginResponse ($ request );
188+ }
162189
163- return redirect ()->route ('auth.login ' );
190+ $ cache = Cache::pull ($ request ->input ('verify_token ' ));
191+ $ user = User::where ('id ' , $ cache ['user_id ' ])->first ();
192+
193+ if (! $ user || ! $ cache ) {
194+ $ this ->sendFailedLoginResponse ($ request );
164195 }
165196
166- $ user = User::where ('id ' , Cache::pull ($ request ->input ('verify_token ' )))->first ();
167- if (! $ user ) {
168- $ this ->incrementLoginAttempts ($ request );
169- Alert::danger (trans ('auth.totp_failed ' ))->flash ();
197+ if (is_null ($ request ->input ('2fa_token ' ))) {
198+ return $ this ->sendFailedLoginResponse ($ request );
199+ }
170200
171- return redirect ()->route ('auth.login ' );
201+ try {
202+ $ credentials = unserialize (Crypt::decrypt ($ cache ['credentials ' ]));
203+ } catch (\Illuminate \Contracts \Encryption \DecryptException $ ex ) {
204+ return $ this ->sendFailedLoginResponse ($ request );
172205 }
173206
174- if (! is_null ($ request ->input ('2fa_token ' )) && $ G2FA ->verifyKey ($ user ->totp_secret , $ request ->input ('2fa_token ' ), 1 )) {
175- Auth::login ($ user , $ request ->has ('remember ' ));
207+ if (! $ G2FA ->verifyKey ($ user ->totp_secret , $ request ->input ('2fa_token ' ), 2 )) {
208+ event (new \Illuminate \Auth \Events \Failed ($ user , $ credentials ));
209+
210+ return $ this ->sendFailedLoginResponse ($ request );
211+ }
176212
177- return redirect ()->intended ($ this ->redirectPath ());
178- } else {
179- $ this ->incrementLoginAttempts ($ request );
180- Alert::danger (trans ('auth.2fa_failed ' ))->flash ();
213+ $ attempt = Auth::attempt ($ credentials , $ request ->has ('remember ' ));
181214
182- return redirect ()->route ('auth.login ' );
215+ if ($ attempt ) {
216+ return $ this ->sendLoginResponse ($ request );
183217 }
218+
219+ // Login failed, send response.
220+ return $ this ->sendFailedLoginResponse ($ request );
184221 }
185222
186223 /**
0 commit comments