[
MAINHACK
]
Mail Test
BC
Config Scan
HOME
Create...
New File
New Folder
Viewing / Editing File: Factory.php
<?php declare(strict_types=1); namespace Kreait\Firebase; use Beste\Cache\InMemoryCache; use Beste\Clock\SystemClock; use Beste\Clock\WrappingClock; use Beste\Json; use Firebase\JWT\CachedKeySet; use Google\Auth\ApplicationDefaultCredentials; use Google\Auth\Credentials\ServiceAccountCredentials; use Google\Auth\FetchAuthTokenCache; use Google\Auth\FetchAuthTokenInterface; use Google\Auth\HttpHandler\HttpHandlerFactory; use Google\Auth\Middleware\AuthTokenMiddleware; use Google\Auth\ProjectIdProviderInterface; use Google\Auth\SignBlobInterface; use Google\Cloud\Firestore\FirestoreClient; use Google\Cloud\Storage\StorageClient; use GuzzleHttp\Client; use GuzzleHttp\HandlerStack; use GuzzleHttp\MessageFormatter; use GuzzleHttp\Psr7\HttpFactory; use GuzzleHttp\Psr7\Utils as GuzzleUtils; use Kreait\Firebase\AppCheck\AppCheckTokenGenerator; use Kreait\Firebase\AppCheck\AppCheckTokenVerifier; use Kreait\Firebase\Auth\ApiClient; use Kreait\Firebase\Auth\CustomTokenViaGoogleCredentials; use Kreait\Firebase\Auth\SignIn\GuzzleHandler; use Kreait\Firebase\Database\UrlBuilder; use Kreait\Firebase\Exception\InvalidArgumentException; use Kreait\Firebase\Exception\MessagingApiExceptionConverter; use Kreait\Firebase\Exception\RuntimeException; use Kreait\Firebase\Http\HttpClientOptions; use Kreait\Firebase\Http\Middleware; use Kreait\Firebase\JWT\IdTokenVerifier; use Kreait\Firebase\JWT\SessionCookieVerifier; use Kreait\Firebase\Messaging\AppInstanceApiClient; use Kreait\Firebase\Messaging\RequestFactory; use Psr\Cache\CacheItemPoolInterface; use Psr\Clock\ClockInterface; use Psr\Http\Message\UriInterface; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; use Stringable; use Throwable; use UnexpectedValueException; use function array_filter; use function is_string; use function sprintf; use function trim; /** * @phpstan-type ServiceAccountShape array{ * project_id: non-empty-string, * client_email: non-empty-string, * private_key: non-empty-string, * type: 'service_account' * } */ final class Factory { public const API_CLIENT_SCOPES = [ 'https://www.googleapis.com/auth/iam', 'https://www.googleapis.com/auth/cloud-platform', 'https://www.googleapis.com/auth/firebase', 'https://www.googleapis.com/auth/firebase.database', 'https://www.googleapis.com/auth/firebase.messaging', 'https://www.googleapis.com/auth/firebase.remoteconfig', 'https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/securetoken', ]; /** * @var non-empty-string|null */ private ?string $databaseUrl = null; /** * @var non-empty-string|null */ private ?string $defaultStorageBucket = null; /** * @var ServiceAccountShape|null */ private ?array $serviceAccount = null; private ?FetchAuthTokenInterface $googleAuthTokenCredentials = null; /** * @var non-empty-string|null */ private ?string $projectId = null; private CacheItemPoolInterface $verifierCache; private CacheItemPoolInterface $authTokenCache; private CacheItemPoolInterface $keySetCache; private ClockInterface $clock; /** * @var callable|null */ private $httpLogMiddleware; /** * @var callable|null */ private $httpDebugLogMiddleware; /** * @var callable|null */ private $databaseAuthVariableOverrideMiddleware; /** * @var non-empty-string|null */ private ?string $tenantId = null; private HttpFactory $httpFactory; private HttpClientOptions $httpClientOptions; /** * @var array<non-empty-string, mixed> */ private array $firestoreClientConfig = []; public function __construct() { $this->clock = SystemClock::create(); $this->httpFactory = new HttpFactory(); $this->verifierCache = new InMemoryCache($this->clock); $this->authTokenCache = new InMemoryCache($this->clock); $this->keySetCache = new InMemoryCache($this->clock); $this->httpClientOptions = HttpClientOptions::default(); } /** * @param non-empty-string|ServiceAccountShape $value */ public function withServiceAccount(string|array $value): self { $serviceAccount = $value; if (is_string($value) && str_starts_with($value, '{')) { try { $serviceAccount = Json::decode($value, true); } catch (UnexpectedValueException $e) { throw new InvalidArgumentException('Invalid service account: '.$e->getMessage(), $e->getCode(), $e); } } elseif (is_string($value)) { try { $serviceAccount = Json::decodeFile($value, true); } catch (UnexpectedValueException $e) { throw new InvalidArgumentException('Invalid service account: '.$e->getMessage(), $e->getCode(), $e); } } $factory = clone $this; $factory->serviceAccount = $serviceAccount; return $factory; } /** * @param non-empty-string $projectId */ public function withProjectId(string $projectId): self { $factory = clone $this; $factory->projectId = $projectId; return $factory; } /** * @param non-empty-string $tenantId */ public function withTenantId(string $tenantId): self { $factory = clone $this; $factory->tenantId = $tenantId; return $factory; } /** * @param UriInterface|non-empty-string $uri */ public function withDatabaseUri(UriInterface|string $uri): self { $url = trim($uri instanceof UriInterface ? $uri->__toString() : $uri); if ($url === '') { throw new InvalidArgumentException('The database URI cannot be empty'); } $factory = clone $this; $factory->databaseUrl = $url; return $factory; } /** * The object to use as the `auth` variable in your Realtime Database Rules * when the Admin SDK reads from or writes to the Realtime Database. * * This allows you to downscope the Admin SDK from its default full read and * write privileges. You can pass `null` to act as an unauthenticated client. * * @see https://firebase.google.com/docs/database/admin/start#authenticate-with-limited-privileges * * @param array<non-empty-string, mixed>|null $override */ public function withDatabaseAuthVariableOverride(?array $override): self { $factory = clone $this; $factory->databaseAuthVariableOverrideMiddleware = Middleware::addDatabaseAuthVariableOverride($override); return $factory; } /** * @param non-empty-string $database */ public function withFirestoreDatabase(string $database): self { return $this->withFirestoreClientConfig(['database' => $database]); } /** * @param array<non-empty-string, mixed> $config */ public function withFirestoreClientConfig(array $config): self { $factory = clone $this; $factory->firestoreClientConfig = array_merge($this->firestoreClientConfig, $config); return $factory; } /** * @param non-empty-string $name */ public function withDefaultStorageBucket(string $name): self { $factory = clone $this; $factory->defaultStorageBucket = $name; return $factory; } public function withVerifierCache(CacheItemPoolInterface $cache): self { $factory = clone $this; $factory->verifierCache = $cache; return $factory; } public function withAuthTokenCache(CacheItemPoolInterface $cache): self { $factory = clone $this; $factory->authTokenCache = $cache; return $factory; } public function withKeySetCache(CacheItemPoolInterface $cache): self { $factory = clone $this; $factory->keySetCache = $cache; return $factory; } public function withHttpClientOptions(HttpClientOptions $options): self { $factory = clone $this; $factory->httpClientOptions = $options; return $factory; } /** * @param non-empty-string|null $logLevel * @param non-empty-string|null $errorLogLevel */ public function withHttpLogger(LoggerInterface $logger, ?MessageFormatter $formatter = null, ?string $logLevel = null, ?string $errorLogLevel = null): self { $formatter = $formatter ?: new MessageFormatter(); $logLevel = $logLevel ?: LogLevel::INFO; $errorLogLevel = $errorLogLevel ?: LogLevel::NOTICE; $factory = clone $this; $factory->httpLogMiddleware = Middleware::log($logger, $formatter, $logLevel, $errorLogLevel); return $factory; } /** * @param non-empty-string|null $logLevel * @param non-empty-string|null $errorLogLevel */ public function withHttpDebugLogger(LoggerInterface $logger, ?MessageFormatter $formatter = null, ?string $logLevel = null, ?string $errorLogLevel = null): self { $formatter = $formatter ?: new MessageFormatter(MessageFormatter::DEBUG); $logLevel = $logLevel ?: LogLevel::INFO; $errorLogLevel = $errorLogLevel ?: LogLevel::NOTICE; $factory = clone $this; $factory->httpDebugLogMiddleware = Middleware::log($logger, $formatter, $logLevel, $errorLogLevel); return $factory; } public function withClock(object $clock): self { if (!$clock instanceof ClockInterface) { $clock = WrappingClock::wrapping($clock); } $factory = clone $this; $factory->clock = $clock; return $factory; } public function createAppCheck(): Contract\AppCheck { $projectId = $this->getProjectId(); $serviceAccount = $this->getServiceAccount(); if ($serviceAccount === null) { throw new RuntimeException('Unable to use AppCheck without credentials'); } $http = $this->createApiClient([ 'base_uri' => 'https://firebaseappcheck.googleapis.com/v1/projects/'.$projectId.'/', ]); $keySet = new CachedKeySet( 'https://firebaseappcheck.googleapis.com/v1/jwks', new Client($this->httpClientOptions->guzzleConfig()), $this->httpFactory, $this->keySetCache, 21600, true, ); return new AppCheck( new AppCheck\ApiClient($http), new AppCheckTokenGenerator( $serviceAccount['client_email'], $serviceAccount['private_key'], $this->clock, ), new AppCheckTokenVerifier($projectId, $keySet), ); } public function createAuth(): Contract\Auth { $projectId = $this->getProjectId(); $httpClient = $this->createApiClient(); $signInHandler = new GuzzleHandler($projectId, $httpClient); $authApiClient = new ApiClient($projectId, $this->tenantId, $httpClient, $signInHandler, $this->clock); $customTokenGenerator = $this->createCustomTokenGenerator(); $idTokenVerifier = $this->createIdTokenVerifier(); $sessionCookieVerifier = $this->createSessionCookieVerifier(); return new Auth($authApiClient, $customTokenGenerator, $idTokenVerifier, $sessionCookieVerifier, $this->clock); } public function createDatabase(): Contract\Database { $middlewares = array_filter([ Middleware::ensureJsonSuffix(), $this->databaseAuthVariableOverrideMiddleware, ]); $http = $this->createApiClient(null, $middlewares); $databaseUrl = $this->getDatabaseUrl(); $resourceUrlBuilder = UrlBuilder::create($databaseUrl); return new Database( GuzzleUtils::uriFor($databaseUrl), new Database\ApiClient($http, $resourceUrlBuilder), $resourceUrlBuilder, ); } public function createRemoteConfig(): Contract\RemoteConfig { $http = $this->createApiClient([ 'base_uri' => "https://firebaseremoteconfig.googleapis.com/v1/projects/{$this->getProjectId()}/remoteConfig", ]); return new RemoteConfig(new RemoteConfig\ApiClient($this->getProjectId(), $http)); } public function createMessaging(): Contract\Messaging { $projectId = $this->getProjectId(); $errorHandler = new MessagingApiExceptionConverter($this->clock); $requestFactory = new RequestFactory( requestFactory: $this->httpFactory, streamFactory: $this->httpFactory, ); $messagingApiClient = new Messaging\ApiClient( $this->createApiClient(), $projectId, $requestFactory, ); $appInstanceApiClient = new AppInstanceApiClient( $this->createApiClient([ 'base_uri' => 'https://iid.googleapis.com', 'headers' => [ 'access_token_auth' => 'true', ], ]), $errorHandler, ); return new Messaging($messagingApiClient, $appInstanceApiClient, $errorHandler); } /** * @deprecated 7.14.0 Firebase Dynamic Links is deprecated and should not be used in new projects. The service will * shut down on August 25, 2025. The component will remain in the SDK until then, but as the * Firebase service is deprecated, this component is also deprecated * * @see https://firebase.google.com/support/dynamic-links-faq Dynamic Links Deprecation FAQ * * @param Stringable|non-empty-string|null $defaultDynamicLinksDomain */ public function createDynamicLinksService($defaultDynamicLinksDomain = null): Contract\DynamicLinks { $apiClient = new DynamicLink\ApiClient( $this->createApiClient(), $this->httpFactory, $this->httpFactory, ); $defaultDynamicLinksDomain = trim((string) $defaultDynamicLinksDomain); if ($defaultDynamicLinksDomain !== '') { return DynamicLinks::withApiClientAndDefaultDomain($apiClient, $defaultDynamicLinksDomain); } return DynamicLinks::withApiClient($apiClient); } public function createFirestore(): Contract\Firestore { $config = $this->googleCloudClientConfig() + $this->firestoreClientConfig; try { $firestoreClient = new FirestoreClient($config); } catch (Throwable $e) { throw new RuntimeException('Unable to create a FirestoreClient: '.$e->getMessage(), $e->getCode(), $e); } return Firestore::withFirestoreClient($firestoreClient); } public function createStorage(): Contract\Storage { try { $storageClient = new StorageClient($this->googleCloudClientConfig()); } catch (Throwable $e) { throw new RuntimeException('Unable to create a StorageClient: '.$e->getMessage(), $e->getCode(), $e); } return new Storage($storageClient, $this->getStorageBucketName()); } /** * @return array{ * credentialsType: string|null, * databaseUrl: string, * defaultStorageBucket: string|null, * serviceAccount: string|array<string, string>|null, * projectId: string, * tenantId: non-empty-string|null, * tokenCacheType: class-string, * verifierCacheType: class-string, * } */ public function getDebugInfo(): array { try { $projectId = $this->getProjectId(); } catch (Throwable $e) { $projectId = $e->getMessage(); } try { $credentials = $this->getGoogleAuthTokenCredentials(); if ($credentials !== null) { $credentials = $credentials::class; } } catch (Throwable $e) { $credentials = $e->getMessage(); } try { $databaseUrl = $this->getDatabaseUrl(); } catch (Throwable $e) { $databaseUrl = $e->getMessage(); } return [ 'credentialsType' => $credentials, 'databaseUrl' => $databaseUrl, 'defaultStorageBucket' => $this->defaultStorageBucket, 'projectId' => $projectId, 'serviceAccount' => $this->getServiceAccount(), 'tenantId' => $this->tenantId, 'tokenCacheType' => $this->authTokenCache::class, 'verifierCacheType' => $this->verifierCache::class, ]; } /** * @param array<non-empty-string, mixed>|null $config * @param array<callable(callable): callable>|null $middlewares */ public function createApiClient(?array $config = null, ?array $middlewares = null): Client { $config ??= []; $middlewares ??= []; $config = [...$this->httpClientOptions->guzzleConfig(), ...$config]; $handler = HandlerStack::create(); if ($this->httpLogMiddleware) { $handler->push($this->httpLogMiddleware, 'http_logs'); } if ($this->httpDebugLogMiddleware) { $handler->push($this->httpDebugLogMiddleware, 'http_debug_logs'); } foreach ($this->httpClientOptions->guzzleMiddlewares() as $middleware) { $handler->push($middleware['middleware'], $middleware['name']); } foreach ($middlewares as $middleware) { $handler->push($middleware); } $credentials = $this->getGoogleAuthTokenCredentials(); if (!$credentials instanceof FetchAuthTokenInterface) { throw new RuntimeException('Unable to create an API client without credentials'); } $projectId = $this->getProjectId(); $cachePrefix = 'kreait_firebase_'.$projectId; $credentials = new FetchAuthTokenCache($credentials, ['prefix' => $cachePrefix], $this->authTokenCache); $authTokenHandler = HttpHandlerFactory::build(new Client($config)); $handler->push(new AuthTokenMiddleware($credentials, $authTokenHandler)); $config['handler'] = $handler; $config['auth'] = 'google_auth'; return new Client($config); } /** * @return array{ * projectId: non-empty-string, * authCache: CacheItemPoolInterface, * credentialsFetcher?: FetchAuthTokenInterface, * keyFile?: ServiceAccountShape, * keyFilePath?: non-empty-string * } */ private function googleCloudClientConfig(): array { $config = [ 'projectId' => $this->getProjectId(), 'authCache' => $this->authTokenCache, ]; if ($credentials = $this->getGoogleAuthTokenCredentials()) { $config['credentialsFetcher'] = $credentials; } $serviceAccount = $this->getServiceAccount(); if ($serviceAccount !== null) { $config['keyFile'] = $serviceAccount; } return $config; } /** * @return non-empty-string */ private function getProjectId(): string { if ($this->projectId !== null) { return $this->projectId; } if ( ($credentials = $this->getGoogleAuthTokenCredentials()) && ($credentials instanceof ProjectIdProviderInterface) && ($projectId = $credentials->getProjectId()) ) { return $this->projectId = $projectId; } if ($projectId = Util::getenv('GOOGLE_CLOUD_PROJECT')) { return $this->projectId = $projectId; } throw new RuntimeException('Unable to determine the Firebase Project ID'); } /** * @return non-empty-string */ private function getDatabaseUrl(): string { if ($this->databaseUrl === null) { $this->databaseUrl = sprintf('https://%s.firebaseio.com', $this->getProjectId()); } return $this->databaseUrl; } /** * @return non-empty-string */ private function getStorageBucketName(): string { if ($this->defaultStorageBucket === null) { $this->defaultStorageBucket = sprintf('%s.appspot.com', $this->getProjectId()); } return $this->defaultStorageBucket; } private function createCustomTokenGenerator(): ?CustomTokenViaGoogleCredentials { $credentials = $this->getGoogleAuthTokenCredentials(); if ($credentials instanceof SignBlobInterface) { return new CustomTokenViaGoogleCredentials($credentials, $this->tenantId); } return null; } private function createIdTokenVerifier(): IdTokenVerifier { $verifier = IdTokenVerifier::createWithProjectIdAndCache($this->getProjectId(), $this->verifierCache); if ($this->tenantId === null) { return $verifier; } return $verifier->withExpectedTenantId($this->tenantId); } private function createSessionCookieVerifier(): SessionCookieVerifier { return SessionCookieVerifier::createWithProjectIdAndCache($this->getProjectId(), $this->verifierCache); } /** * @return ServiceAccountShape|null */ private function getServiceAccount(): ?array { if ($this->serviceAccount === null) { $googleApplicationCredentials = Util::getenv('GOOGLE_APPLICATION_CREDENTIALS'); if ($googleApplicationCredentials === null) { return null; } if (!str_starts_with($googleApplicationCredentials, '{')) { return null; } $this->serviceAccount = Json::decode($googleApplicationCredentials, true); } return $this->serviceAccount; } private function getGoogleAuthTokenCredentials(): ?FetchAuthTokenInterface { if ($this->googleAuthTokenCredentials !== null) { return $this->googleAuthTokenCredentials; } $serviceAccount = $this->getServiceAccount(); if ($serviceAccount !== null) { return $this->googleAuthTokenCredentials = new ServiceAccountCredentials(self::API_CLIENT_SCOPES, $serviceAccount); } try { return $this->googleAuthTokenCredentials = ApplicationDefaultCredentials::getCredentials(self::API_CLIENT_SCOPES); } catch (Throwable) { return null; } } }
Save Changes
Cancel / Back
Close ×
Server Info
Hostname: server1.winmanyltd.com
Server IP: 203.161.60.52
PHP Version: 8.3.27
Server Software: Apache
System: Linux server1.winmanyltd.com 4.18.0-553.22.1.el8_10.x86_64 #1 SMP Tue Sep 24 05:16:59 EDT 2024 x86_64
HDD Total: 117.98 GB
HDD Free: 59.46 GB
Domains on IP: N/A (Requires external lookup)
System Features
Safe Mode:
Off
disable_functions:
None
allow_url_fopen:
On
allow_url_include:
Off
magic_quotes_gpc:
Off
register_globals:
Off
open_basedir:
None
cURL:
Enabled
ZipArchive:
Enabled
MySQLi:
Enabled
PDO:
Enabled
wget:
Yes
curl (cmd):
Yes
perl:
Yes
python:
Yes (py3)
gcc:
Yes
pkexec:
Yes
git:
Yes
User Info
Username: eliosofonline
User ID (UID): 1002
Group ID (GID): 1003
Script Owner UID: 1002
Current Dir Owner: 1002