99use Pterodactyl \Models \ApiKey ;
1010use Illuminate \Auth \AuthManager ;
1111use Illuminate \Contracts \Encryption \Encrypter ;
12+ use Pterodactyl \Traits \Helpers \ProvidesJWTServices ;
1213use Symfony \Component \HttpKernel \Exception \HttpException ;
1314use Pterodactyl \Exceptions \Repository \RecordNotFoundException ;
1415use Pterodactyl \Contracts \Repository \ApiKeyRepositoryInterface ;
1516use Symfony \Component \HttpKernel \Exception \AccessDeniedHttpException ;
1617
1718class AuthenticateKey
1819{
20+ use ProvidesJWTServices;
21+
1922 /**
2023 * @var \Illuminate\Auth\AuthManager
2124 */
@@ -65,24 +68,55 @@ public function handle(Request $request, Closure $next, int $keyType)
6568
6669 $ raw = $ request ->bearerToken ();
6770
68- // This is an internal JWT, treat it differently to get the correct user
69- // before passing it along.
71+ // This is an internal JWT, treat it differently to get the correct user before passing it along.
7072 if (strlen ($ raw ) > ApiKey::IDENTIFIER_LENGTH + ApiKey::KEY_LENGTH ) {
71- $ token = (new Parser )->parse ($ raw );
73+ $ model = $ this ->authenticateJWT ($ raw );
74+ } else {
75+ $ model = $ this ->authenticateApiKey ($ raw , $ keyType );
76+ }
7277
73- $ model = (new ApiKey )->fill ([
74- 'user_id ' => $ token ->getClaim ('uid ' ),
75- 'key_type ' => ApiKey::TYPE_ACCOUNT ,
76- ]);
78+ $ this ->auth ->guard ()->loginUsingId ($ model ->user_id );
79+ $ request ->attributes ->set ('api_key ' , $ model );
7780
78- $ this -> auth -> guard ()-> loginUsingId ( $ token -> getClaim ( ' uid ' ) );
79- $ request -> attributes -> set ( ' api_key ' , $ model );
81+ return $ next ( $ request );
82+ }
8083
81- return $ next ($ request );
84+ /**
85+ * Authenticate an API request using a JWT rather than an API key.
86+ *
87+ * @param string $token
88+ * @return \Pterodactyl\Models\ApiKey
89+ */
90+ protected function authenticateJWT (string $ token ): ApiKey
91+ {
92+ $ token = (new Parser )->parse ($ token );
93+
94+ // If the key cannot be verified throw an exception to indicate that a bad
95+ // authorization header was provided.
96+ if (! $ token ->verify ($ this ->getJWTSigner (), $ this ->getJWTSigningKey ())) {
97+ throw new HttpException (401 , null , null , ['WWW-Authenticate ' => 'Bearer ' ]);
8298 }
8399
84- $ identifier = substr ($ raw , 0 , ApiKey::IDENTIFIER_LENGTH );
85- $ token = substr ($ raw , ApiKey::IDENTIFIER_LENGTH );
100+ return (new ApiKey )->forceFill ([
101+ 'user_id ' => object_get ($ token ->getClaim ('user ' ), 'id ' , 0 ),
102+ 'key_type ' => ApiKey::TYPE_ACCOUNT ,
103+ ]);
104+ }
105+
106+ /**
107+ * Authenticate an API key.
108+ *
109+ * @param string $key
110+ * @param int $keyType
111+ * @return \Pterodactyl\Models\ApiKey
112+ *
113+ * @throws \Pterodactyl\Exceptions\Model\DataValidationException
114+ * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
115+ */
116+ protected function authenticateApiKey (string $ key , int $ keyType ): ApiKey
117+ {
118+ $ identifier = substr ($ key , 0 , ApiKey::IDENTIFIER_LENGTH );
119+ $ token = substr ($ key , ApiKey::IDENTIFIER_LENGTH );
86120
87121 try {
88122 $ model = $ this ->repository ->findFirstWhere ([
@@ -97,10 +131,8 @@ public function handle(Request $request, Closure $next, int $keyType)
97131 throw new AccessDeniedHttpException ;
98132 }
99133
100- $ this ->auth ->guard ()->loginUsingId ($ model ->user_id );
101- $ request ->attributes ->set ('api_key ' , $ model );
102134 $ this ->repository ->withoutFreshModel ()->update ($ model ->id , ['last_used_at ' => Chronos::now ()]);
103135
104- return $ next ( $ request ) ;
136+ return $ model ;
105137 }
106138}
0 commit comments