create-prisma-php-app 3.1.11 → 4.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/bootstrap.php +10 -10
  2. package/dist/index.js +12 -8
  3. package/dist/settings/restart-websocket.bat +1 -1
  4. package/dist/settings/restart-websocket.ts +2 -9
  5. package/dist/src/{Lib/Websocket → Websocket}/ConnectionManager.php +1 -1
  6. package/dist/src/app/error.php +1 -1
  7. package/dist/src/app/index.php +1 -1
  8. package/dist/src/app/js/index.js +1 -1
  9. package/dist/src/app/layout.php +2 -2
  10. package/dist/{src/Lib/Websocket/websocket-server.php → websocket-server.php} +2 -7
  11. package/package.json +1 -1
  12. package/dist/src/Lib/AI/ChatGPTClient.php +0 -147
  13. package/dist/src/Lib/Auth/Auth.php +0 -544
  14. package/dist/src/Lib/Auth/AuthConfig.php +0 -89
  15. package/dist/src/Lib/CacheHandler.php +0 -121
  16. package/dist/src/Lib/ErrorHandler.php +0 -322
  17. package/dist/src/Lib/FileManager/UploadFile.php +0 -383
  18. package/dist/src/Lib/Headers/Boom.php +0 -208
  19. package/dist/src/Lib/IncludeTracker.php +0 -59
  20. package/dist/src/Lib/MainLayout.php +0 -215
  21. package/dist/src/Lib/Middleware/AuthMiddleware.php +0 -154
  22. package/dist/src/Lib/PHPMailer/Mailer.php +0 -169
  23. package/dist/src/Lib/PHPX/Exceptions/ComponentValidationException.php +0 -49
  24. package/dist/src/Lib/PHPX/IPHPX.php +0 -22
  25. package/dist/src/Lib/PHPX/PHPX.php +0 -173
  26. package/dist/src/Lib/PHPX/TemplateCompiler.php +0 -571
  27. package/dist/src/Lib/PHPX/TwMerge.php +0 -195
  28. package/dist/src/Lib/PHPX/TypeCoercer.php +0 -490
  29. package/dist/src/Lib/PartialRenderer.php +0 -40
  30. package/dist/src/Lib/PrismaPHPSettings.php +0 -181
  31. package/dist/src/Lib/Request.php +0 -476
  32. package/dist/src/Lib/Set.php +0 -102
  33. package/dist/src/Lib/StateManager.php +0 -127
  34. package/dist/src/Lib/Validator.php +0 -738
@@ -1,147 +0,0 @@
1
- <?php
2
-
3
- declare(strict_types=1);
4
-
5
- namespace Lib\AI;
6
-
7
- use GuzzleHttp\Client;
8
- use GuzzleHttp\Exception\RequestException;
9
- use Lib\Validator;
10
- use RuntimeException;
11
-
12
- class ChatGPTClient
13
- {
14
- private Client $client;
15
- private string $apiUrl = '';
16
- private string $apiKey = '';
17
- private array $cache = [];
18
-
19
- public function __construct(?Client $client = null)
20
- {
21
- // Initialize the Guzzle HTTP client, allowing for dependency injection
22
- $this->client = $client ?: new Client();
23
-
24
- // API URL for chat completions
25
- $this->apiUrl = 'https://api.openai.com/v1/chat/completions';
26
-
27
- // Get the API key from environment variables (keep this private and secure)
28
- $this->apiKey = $_ENV['CHATGPT_API_KEY'];
29
- }
30
-
31
- /**
32
- * Determines the appropriate model based on internal logic.
33
- *
34
- * @param array $conversationHistory The conversation history array.
35
- * @return string The model name to be used.
36
- */
37
- protected function determineModel(array $conversationHistory): string
38
- {
39
- $messageCount = count($conversationHistory);
40
- $totalTokens = array_reduce(
41
- $conversationHistory,
42
- fn($carry, $item) => $carry + str_word_count($item['content'] ?? ''),
43
- 0
44
- );
45
-
46
- // If the conversation is long or complex, use a model with more tokens
47
- if ($totalTokens > 4000 || $messageCount > 10) {
48
- return 'gpt-3.5-turbo-16k'; // Use the model with a larger token limit
49
- }
50
-
51
- // Default to the standard model for shorter conversations
52
- return 'gpt-3.5-turbo';
53
- }
54
-
55
- /**
56
- * Formats the conversation history to ensure it is valid.
57
- *
58
- * @param array $conversationHistory The conversation history array.
59
- * @return array The formatted conversation history.
60
- */
61
- protected function formatConversationHistory(array $conversationHistory): array
62
- {
63
- $formattedHistory = [];
64
- foreach ($conversationHistory as $message) {
65
- if (is_array($message) && isset($message['role'], $message['content']) && Validator::string($message['content'])) {
66
- $formattedHistory[] = $message;
67
- } else {
68
- $formattedHistory[] = ['role' => 'user', 'content' => (string) $message];
69
- }
70
- }
71
- return $formattedHistory;
72
- }
73
-
74
- /**
75
- * Sends a message to the OpenAI API and returns the AI's response as HTML.
76
- *
77
- * @param array $conversationHistory The conversation history array containing previous messages.
78
- * @param string $userMessage The new user message to add to the conversation.
79
- * @return string The AI-generated HTML response.
80
- *
81
- * @throws \InvalidArgumentException If a message in the conversation history is not valid.
82
- * @throws RuntimeException If the API request fails or returns an unexpected format.
83
- */
84
- public function sendMessage(array $conversationHistory, string $userMessage): string
85
- {
86
- if (!Validator::string($userMessage)) {
87
- throw new \InvalidArgumentException("Invalid user message: must be a string.");
88
- }
89
-
90
- // Optional: Convert emojis or special patterns in the message
91
- $userMessage = Validator::emojis($userMessage);
92
-
93
- // Prepare the conversation, including a system-level instruction to return valid HTML
94
- $systemInstruction = [
95
- 'role' => 'system',
96
- 'content' => 'You are ChatGPT. Please provide your response in valid HTML format.'
97
- ];
98
-
99
- // Format existing history, then prepend the system message
100
- $formattedHistory = $this->formatConversationHistory($conversationHistory);
101
- array_unshift($formattedHistory, $systemInstruction);
102
-
103
- // Append the new user message
104
- $formattedHistory[] = ['role' => 'user', 'content' => $userMessage];
105
-
106
- // Check cache
107
- $cacheKey = md5(serialize($formattedHistory));
108
- if (isset($this->cache[$cacheKey])) {
109
- return $this->cache[$cacheKey];
110
- }
111
-
112
- // Determine the appropriate model to use
113
- $model = $this->determineModel($formattedHistory);
114
-
115
- try {
116
- // Sending a POST request to the AI API
117
- $response = $this->client->request('POST', $this->apiUrl, [
118
- 'headers' => [
119
- 'Authorization' => 'Bearer ' . $this->apiKey,
120
- 'Content-Type' => 'application/json',
121
- ],
122
- 'json' => [
123
- 'model' => $model,
124
- 'messages' => $formattedHistory,
125
- 'max_tokens' => 500,
126
- ],
127
- ]);
128
-
129
- $responseBody = $response->getBody();
130
- $responseContent = json_decode((string) $responseBody, true);
131
-
132
- // Check if response is in expected format
133
- if (isset($responseContent['choices'][0]['message']['content'])) {
134
- $aiMessage = $responseContent['choices'][0]['message']['content'];
135
-
136
- // Cache the result
137
- $this->cache[$cacheKey] = $aiMessage;
138
-
139
- return $aiMessage;
140
- }
141
-
142
- throw new RuntimeException('Unexpected API response format.');
143
- } catch (RequestException $e) {
144
- throw new RuntimeException("API request failed: " . $e->getMessage(), 0, $e);
145
- }
146
- }
147
- }
@@ -1,544 +0,0 @@
1
- <?php
2
-
3
- declare(strict_types=1);
4
-
5
- namespace Lib\Auth;
6
-
7
- use Firebase\JWT\JWT;
8
- use Firebase\JWT\Key;
9
- use DateInterval;
10
- use DateTime;
11
- use Lib\Validator;
12
- use GuzzleHttp\Client;
13
- use GuzzleHttp\Exception\RequestException;
14
- use Lib\Request;
15
- use Exception;
16
- use InvalidArgumentException;
17
- use ArrayObject;
18
-
19
- class Auth
20
- {
21
- public const PAYLOAD_NAME = 'payload_name_8639D';
22
- public const ROLE_NAME = '';
23
- public const PAYLOAD_SESSION_KEY = 'payload_session_key_2183A';
24
-
25
- public static string $cookieName = '';
26
-
27
- private static ?Auth $instance = null;
28
- private const PPHPAUTH = 'pphpauth';
29
- private string $secretKey;
30
- private string $defaultTokenValidity = '1h'; // Default to 1 hour
31
-
32
- /**
33
- * Private constructor to prevent direct instantiation.
34
- * Use Auth::getInstance() to get the singleton instance.
35
- */
36
- private function __construct()
37
- {
38
- $this->secretKey = $_ENV['AUTH_SECRET'] ?? 'CD24eEv4qbsC5LOzqeaWbcr58mBMSvA4Mkii8GjRiHkt';
39
- self::$cookieName = self::getCookieName();
40
- }
41
-
42
- /**
43
- * Returns the singleton instance of the Auth class.
44
- *
45
- * @return Auth The singleton instance.
46
- */
47
- public static function getInstance(): Auth
48
- {
49
- if (self::$instance === null) {
50
- self::$instance = new self();
51
- }
52
- return self::$instance;
53
- }
54
-
55
- /**
56
- * Authenticates a user and generates a JWT (JSON Web Token) based on the specified user data
57
- * and token validity duration. The method first checks if the secret key is set, calculates
58
- * the token's expiration time, sets the necessary payload, and encodes it into a JWT.
59
- * If possible (HTTP headers not yet sent), it also sets cookies with the JWT for client-side storage.
60
- *
61
- * @param mixed $data User data which can be a simple string or an instance of AuthRole.
62
- * If an instance of AuthRole is provided, its `value` property will be used as the role in the token.
63
- * @param string|null $tokenValidity Optional parameter specifying the duration the token is valid for (e.g., '10m', '1h').
64
- * If null, the default validity period set in the class property is used, which is 1 hour.
65
- * The format should be a number followed by a time unit ('s' for seconds, 'm' for minutes,
66
- * 'h' for hours, 'd' for days), and this is parsed to calculate the exact expiration time.
67
- *
68
- * @return string Returns the encoded JWT as a string.
69
- *
70
- * @throws InvalidArgumentException Thrown if the secret key is not set or if the duration format is invalid.
71
- *
72
- * Example:
73
- * $auth = Auth::getInstance();
74
- * $auth->setSecretKey('your_secret_key');
75
- * try {
76
- * $jwt = $auth->signIn('Admin', '1h');
77
- * echo "JWT: " . $jwt;
78
- * } catch (InvalidArgumentException $e) {
79
- * echo "Error: " . $e->getMessage();
80
- * }
81
- */
82
- public function signIn($data, ?string $tokenValidity = null): string
83
- {
84
- if (!$this->secretKey) {
85
- throw new InvalidArgumentException("Secret key is required for authentication.");
86
- }
87
-
88
- $expirationTime = $this->calculateExpirationTime($tokenValidity ?? $this->defaultTokenValidity);
89
-
90
- if ($data instanceof AuthRole) {
91
- $data = $data->value;
92
- }
93
-
94
- $payload = [
95
- self::PAYLOAD_NAME => $data,
96
- 'exp' => $expirationTime,
97
- ];
98
-
99
- // Set the payload in the session
100
- $_SESSION[self::PAYLOAD_SESSION_KEY] = $payload;
101
-
102
- // Encode the JWT
103
- $jwt = JWT::encode($payload, $this->secretKey, 'HS256');
104
-
105
- if (!headers_sent()) {
106
- $this->setCookies($jwt, $expirationTime);
107
- }
108
-
109
- return $jwt;
110
- }
111
-
112
- /**
113
- * Checks if the user is authenticated based on the presence of the payload in the session.
114
- * Returns true if the user is authenticated, false otherwise.
115
- *
116
- * @return bool Returns true if the user is authenticated, false otherwise.
117
- */
118
- public function isAuthenticated(): bool
119
- {
120
- if (!isset($_COOKIE[self::$cookieName])) {
121
- unset($_SESSION[self::PAYLOAD_SESSION_KEY]);
122
- return false;
123
- }
124
-
125
- if (Request::$fileToInclude === 'route.php') {
126
- $bearerToken = Request::getBearerToken();
127
- $verifyBearerToken = $this->verifyToken($bearerToken);
128
- if (!$verifyBearerToken) {
129
- return false;
130
- }
131
- }
132
-
133
- $jwt = $_COOKIE[self::$cookieName];
134
- $verifyToken = $this->verifyToken($jwt);
135
- if ($verifyToken === false) {
136
- return false;
137
- }
138
-
139
- if (!isset($_SESSION[self::PAYLOAD_SESSION_KEY])) {
140
- return false;
141
- }
142
-
143
- return true;
144
- }
145
-
146
- private function calculateExpirationTime(string $duration): int
147
- {
148
- $now = new DateTime();
149
- $interval = $this->convertDurationToInterval($duration);
150
- $futureDate = $now->add($interval);
151
- return $futureDate->getTimestamp();
152
- }
153
-
154
- private function convertDurationToInterval(string $duration): DateInterval
155
- {
156
- if (preg_match('/^(\d+)(s|m|h|d)$/', $duration, $matches)) {
157
- $value = (int)$matches[1];
158
- $unit = $matches[2];
159
-
160
- switch ($unit) {
161
- case 's':
162
- return new DateInterval("PT{$value}S");
163
- case 'm':
164
- return new DateInterval("PT{$value}M");
165
- case 'h':
166
- return new DateInterval("PT{$value}H");
167
- case 'd':
168
- return new DateInterval("P{$value}D");
169
- default:
170
- throw new InvalidArgumentException("Invalid duration format: {$duration}");
171
- }
172
- }
173
-
174
- throw new InvalidArgumentException("Invalid duration format: {$duration}");
175
- }
176
-
177
- /**
178
- * Verifies the JWT token and returns the decoded payload if the token is valid.
179
- * If the token is invalid or expired, null is returned.
180
- *
181
- * @param string $jwt The JWT token to verify.
182
- * @return object|null Returns the decoded payload if the token is valid, or null if invalid or expired.
183
- */
184
- public function verifyToken(?string $jwt): ?object
185
- {
186
- try {
187
- if (!$jwt) {
188
- return null;
189
- }
190
-
191
- $token = JWT::decode($jwt, new Key($this->secretKey, 'HS256'));
192
-
193
- if (empty($token->{Auth::PAYLOAD_NAME})) {
194
- return null;
195
- }
196
-
197
- if (isset($token->exp) && time() >= $token->exp) {
198
- return null;
199
- }
200
-
201
- return $token;
202
- } catch (Exception) {
203
- return null;
204
- }
205
- }
206
-
207
- /**
208
- * Refreshes the JWT token by updating the expiration time and encoding the new payload into a JWT.
209
- * If the token validity duration is not specified, the default token validity period is used.
210
- * If possible (HTTP headers not yet sent), it also sets cookies with the new JWT for client-side storage.
211
- *
212
- * @param string $jwt The JWT token to refresh.
213
- * @param string|null $tokenValidity Optional parameter specifying the duration the token is valid for (e.g., '10m', '1h').
214
- * If null, the default validity period set in the class property is used.
215
- * The format should be a number followed by a time unit ('s' for seconds, 'm' for minutes,
216
- * 'h' for hours, 'd' for days), and this is parsed to calculate the exact expiration time.
217
- *
218
- * @return string Returns the refreshed JWT as a string.
219
- *
220
- * @throws InvalidArgumentException Thrown if the token is invalid.
221
- */
222
- public function refreshToken(string $jwt, ?string $tokenValidity = null): string
223
- {
224
- $decodedToken = $this->verifyToken($jwt);
225
-
226
- if (!$decodedToken) {
227
- throw new InvalidArgumentException("Invalid token.");
228
- }
229
-
230
- $expirationTime = $this->calculateExpirationTime($tokenValidity ?? $this->defaultTokenValidity);
231
-
232
- $decodedToken->exp = $expirationTime;
233
- $newJwt = JWT::encode((array)$decodedToken, $this->secretKey, 'HS256');
234
-
235
- if (!headers_sent()) {
236
- $this->setCookies($newJwt, $expirationTime);
237
- }
238
-
239
- return $newJwt;
240
- }
241
-
242
- protected function setCookies(string $jwt, int $expirationTime)
243
- {
244
- if (!headers_sent()) {
245
- setcookie(self::$cookieName, $jwt, [
246
- 'expires' => $expirationTime,
247
- 'path' => '/', // Set the path to '/' to make the cookie available site-wide
248
- 'domain' => '', // Specify your domain
249
- 'secure' => true, // Set to true if using HTTPS
250
- 'httponly' => true, // Prevent JavaScript access to the cookie
251
- 'samesite' => 'Lax', // or 'Strict' depending on your requirements
252
- ]);
253
- }
254
- }
255
-
256
- /**
257
- * Logs out the user by unsetting the session payload and deleting the authentication cookie.
258
- * If a redirect URL is provided, the user is redirected to that URL after logging out.
259
- *
260
- * @param string|null $redirect Optional parameter specifying the URL to redirect to after logging out.
261
- *
262
- * Example:
263
- * $auth = Auth::getInstance();
264
- * $auth->signOut('/login');
265
- *
266
- * @return void
267
- */
268
- public function signOut(?string $redirect = null)
269
- {
270
- if (isset($_COOKIE[self::$cookieName])) {
271
- unset($_COOKIE[self::$cookieName]);
272
- setcookie(self::$cookieName, '', time() - 3600, '/');
273
- }
274
-
275
- if (isset($_SESSION[self::PAYLOAD_SESSION_KEY])) {
276
- unset($_SESSION[self::PAYLOAD_SESSION_KEY]);
277
- }
278
-
279
- if ($redirect) {
280
- Request::redirect($redirect);
281
- }
282
- }
283
-
284
- /**
285
- * Returns the role of the authenticated user based on the payload stored in the session.
286
- * If the user is not authenticated, null is returned.
287
- *
288
- * @return mixed|null Returns the role of the authenticated user or null if the user is not authenticated.
289
- */
290
- public function getPayload()
291
- {
292
- if (isset($_SESSION[self::PAYLOAD_SESSION_KEY])) {
293
- $value = $_SESSION[self::PAYLOAD_SESSION_KEY][self::PAYLOAD_NAME];
294
- return is_array($value) ? new ArrayObject($value, ArrayObject::ARRAY_AS_PROPS) : $value;
295
- }
296
-
297
- return null;
298
- }
299
-
300
- private function exchangeCode($data, $apiUrl)
301
- {
302
- try {
303
- $client = new Client();
304
- $response = $client->post($apiUrl, [
305
- 'headers' => [
306
- 'Accept' => 'application/json',
307
- ],
308
- 'form_params' => $data,
309
- ]);
310
-
311
- if ($response->getStatusCode() === 200) {
312
- return json_decode($response->getBody()->getContents());
313
- }
314
-
315
- return false;
316
- } catch (RequestException) {
317
- return false;
318
- }
319
- }
320
-
321
- private function saveAuthInfo($responseInfo, $accountData)
322
- {
323
- // Save user data to the database
324
- }
325
-
326
- private function findProvider(array $providers, string $type): ?object
327
- {
328
- foreach ($providers as $provider) {
329
- if (is_object($provider) && get_class($provider) === $type) {
330
- return $provider;
331
- }
332
- }
333
- return null;
334
- }
335
-
336
- /**
337
- * Authenticates a user using OAuth providers such as Google or GitHub.
338
- * The method first checks if the request is a GET request and if the route is a sign-in route.
339
- * It then processes the authentication code received from the provider and retrieves the user's data.
340
- * The user data is saved to the database, and the user is authenticated using the authenticate method.
341
- *
342
- * @param mixed ...$providers An array of provider objects such as GoogleProvider or GithubProvider.
343
- *
344
- * Example:
345
- * $auth = Auth::getInstance();
346
- * $auth->authProviders(new GoogleProvider('client_id', 'client_secret', 'redirect_uri'));
347
- */
348
- public function authProviders(...$providers)
349
- {
350
- $dynamicRouteParams = Request::$dynamicParams[self::PPHPAUTH] ?? [];
351
-
352
- if (Request::$isGet && in_array('signin', $dynamicRouteParams)) {
353
- foreach ($providers as $provider) {
354
- if ($provider instanceof GithubProvider && in_array('github', $dynamicRouteParams)) {
355
- $githubAuthUrl = "https://github.com/login/oauth/authorize?scope=user:email%20read:user&client_id={$provider->clientId}";
356
- Request::redirect($githubAuthUrl);
357
- } elseif ($provider instanceof GoogleProvider && in_array('google', $dynamicRouteParams)) {
358
- $googleAuthUrl = "https://accounts.google.com/o/oauth2/v2/auth?"
359
- . "scope=" . urlencode('email profile') . "&"
360
- . "response_type=code&"
361
- . "client_id=" . urlencode($provider->clientId) . "&"
362
- . "redirect_uri=" . urlencode($provider->redirectUri);
363
- Request::redirect($googleAuthUrl);
364
- }
365
- }
366
- }
367
-
368
- $authCode = Validator::string($_GET['code'] ?? '');
369
-
370
- if (Request::$isGet && in_array('callback', $dynamicRouteParams) && isset($authCode)) {
371
- if (in_array('github', $dynamicRouteParams)) {
372
- $provider = $this->findProvider($providers, GithubProvider::class);
373
-
374
- if (!$provider) {
375
- exit("Error occurred. Please try again.");
376
- }
377
-
378
- return $this->githubProvider($provider, $authCode);
379
- } elseif (in_array('google', $dynamicRouteParams)) {
380
- $provider = $this->findProvider($providers, GoogleProvider::class);
381
-
382
- if (!$provider) {
383
- exit("Error occurred. Please try again.");
384
- }
385
-
386
- return $this->googleProvider($provider, $authCode);
387
- }
388
- }
389
-
390
- exit("Error occurred. Please try again.");
391
- }
392
-
393
- private function githubProvider(GithubProvider $githubProvider, string $authCode)
394
- {
395
- $gitToken = [
396
- 'client_id' => $githubProvider->clientId,
397
- 'client_secret' => $githubProvider->clientSecret,
398
- 'code' => $authCode,
399
- ];
400
-
401
- $apiUrl = 'https://github.com/login/oauth/access_token';
402
- $tokenData = (object)$this->exchangeCode($gitToken, $apiUrl);
403
-
404
- if (!$tokenData) {
405
- exit("Error occurred. Please try again.");
406
- }
407
-
408
- if (isset($tokenData->error)) {
409
- exit("Error occurred. Please try again.");
410
- }
411
-
412
- if (isset($tokenData->access_token)) {
413
- $client = new Client();
414
- $emailResponse = $client->get('https://api.github.com/user/emails', [
415
- 'headers' => [
416
- 'Authorization' => 'Bearer ' . $tokenData->access_token,
417
- 'Accept' => 'application/json',
418
- ],
419
- ]);
420
-
421
- $emails = json_decode($emailResponse->getBody()->getContents(), true);
422
-
423
- $primaryEmail = array_reduce($emails, function ($carry, $item) {
424
- return ($item['primary'] && $item['verified']) ? $item['email'] : $carry;
425
- }, null);
426
-
427
- $response = $client->get('https://api.github.com/user', [
428
- 'headers' => [
429
- 'Accept' => 'application/json',
430
- 'Authorization' => 'Bearer ' . $tokenData->access_token,
431
- ],
432
- ]);
433
-
434
- if ($response->getStatusCode() == 200) {
435
- $responseInfo = json_decode($response->getBody()->getContents());
436
-
437
- $accountData = [
438
- 'provider' => 'github',
439
- 'type' => 'oauth',
440
- 'providerAccountId' => "$responseInfo->id",
441
- 'access_token' => $tokenData->access_token,
442
- 'expires_at' => $tokenData->expires_at ?? null,
443
- 'token_type' => $tokenData->token_type,
444
- 'scope' => $tokenData->scope,
445
- ];
446
-
447
- $this->saveAuthInfo($responseInfo, $accountData);
448
-
449
- $userToAuthenticate = [
450
- 'name' => $responseInfo->login,
451
- 'email' => $primaryEmail,
452
- 'image' => $responseInfo->avatar_url,
453
- 'Account' => (object)$accountData
454
- ];
455
- $userToAuthenticate = (object)$userToAuthenticate;
456
-
457
- $this->signIn($userToAuthenticate, $githubProvider->maxAge);
458
- }
459
- }
460
- }
461
-
462
- private function googleProvider(GoogleProvider $googleProvider, string $authCode)
463
- {
464
- $googleToken = [
465
- 'client_id' => $googleProvider->clientId,
466
- 'client_secret' => $googleProvider->clientSecret,
467
- 'code' => $authCode,
468
- 'grant_type' => 'authorization_code',
469
- 'redirect_uri' => $googleProvider->redirectUri
470
- ];
471
-
472
- $apiUrl = 'https://oauth2.googleapis.com/token';
473
- $tokenData = (object)$this->exchangeCode($googleToken, $apiUrl);
474
-
475
- if (!$tokenData) {
476
- exit("Error occurred. Please try again.");
477
- }
478
-
479
- if (isset($tokenData->error)) {
480
- exit("Error occurred. Please try again.");
481
- }
482
-
483
- if (isset($tokenData->access_token)) {
484
- $client = new Client();
485
- $response = $client->get('https://www.googleapis.com/oauth2/v1/userinfo', [
486
- 'headers' => [
487
- 'Authorization' => 'Bearer ' . $tokenData->access_token,
488
- 'Accept' => 'application/json',
489
- ],
490
- ]);
491
-
492
- if ($response->getStatusCode() == 200) {
493
- $responseInfo = json_decode($response->getBody()->getContents());
494
-
495
- $accountData = [
496
- 'provider' => 'google',
497
- 'type' => 'oauth',
498
- 'providerAccountId' => "$responseInfo->id",
499
- 'access_token' => $tokenData->access_token,
500
- 'expires_at' => $tokenData->expires_at ?? null,
501
- 'token_type' => $tokenData->token_type,
502
- 'scope' => $tokenData->scope,
503
- ];
504
-
505
- $this->saveAuthInfo($responseInfo, $accountData);
506
-
507
- $userToAuthenticate = [
508
- 'name' => $responseInfo->name,
509
- 'email' => $responseInfo->email,
510
- 'image' => $responseInfo->picture,
511
- 'Account' => (object)$accountData
512
- ];
513
- $userToAuthenticate = (object)$userToAuthenticate;
514
-
515
- $this->signIn($userToAuthenticate, $googleProvider->maxAge);
516
- }
517
- }
518
- }
519
-
520
- private static function getCookieName(): string
521
- {
522
- $authCookieName = $_ENV['AUTH_COOKIE_NAME'] ?? 'auth_cookie_name_d36e5';
523
- return strtolower(preg_replace('/\s+/', '_', trim($authCookieName)));
524
- }
525
- }
526
-
527
- class GoogleProvider
528
- {
529
- public function __construct(
530
- public string $clientId,
531
- public string $clientSecret,
532
- public string $redirectUri,
533
- public string $maxAge = '30d'
534
- ) {}
535
- }
536
-
537
- class GithubProvider
538
- {
539
- public function __construct(
540
- public string $clientId,
541
- public string $clientSecret,
542
- public string $maxAge = '30d'
543
- ) {}
544
- }