allow vendord
All checks were successful
Build, Push and Deploy / build-and-push (push) Successful in 3m3s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 16s
Build, Push and Deploy / deploy-staging (push) Successful in 32s
Build, Push and Deploy / deploy-production (push) Has been skipped
Build, Push and Deploy / cleanup (push) Successful in 1s
All checks were successful
Build, Push and Deploy / build-and-push (push) Successful in 3m3s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 16s
Build, Push and Deploy / deploy-staging (push) Successful in 32s
Build, Push and Deploy / deploy-production (push) Has been skipped
Build, Push and Deploy / cleanup (push) Successful in 1s
This commit is contained in:
46
vendor/kreait/firebase-php/src/Firebase/AppCheck.php
vendored
Normal file
46
vendor/kreait/firebase-php/src/Firebase/AppCheck.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase;
|
||||
|
||||
use Kreait\Firebase\AppCheck\ApiClient;
|
||||
use Kreait\Firebase\AppCheck\AppCheckToken;
|
||||
use Kreait\Firebase\AppCheck\AppCheckTokenGenerator;
|
||||
use Kreait\Firebase\AppCheck\AppCheckTokenOptions;
|
||||
use Kreait\Firebase\AppCheck\AppCheckTokenVerifier;
|
||||
use Kreait\Firebase\AppCheck\VerifyAppCheckTokenResponse;
|
||||
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class AppCheck implements Contract\AppCheck
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ApiClient $client,
|
||||
private readonly AppCheckTokenGenerator $tokenGenerator,
|
||||
private readonly AppCheckTokenVerifier $tokenVerifier,
|
||||
) {
|
||||
}
|
||||
|
||||
public function createToken(string $appId, $options = null): AppCheckToken
|
||||
{
|
||||
if (is_array($options)) {
|
||||
$options = AppCheckTokenOptions::fromArray($options);
|
||||
}
|
||||
|
||||
$customToken = $this->tokenGenerator->createCustomToken($appId, $options);
|
||||
$result = $this->client->exchangeCustomToken($appId, $customToken);
|
||||
|
||||
return AppCheckToken::fromArray($result);
|
||||
}
|
||||
|
||||
public function verifyToken(string $appCheckToken): VerifyAppCheckTokenResponse
|
||||
{
|
||||
$decodedToken = $this->tokenVerifier->verifyToken($appCheckToken);
|
||||
|
||||
return new VerifyAppCheckTokenResponse($decodedToken->app_id, $decodedToken);
|
||||
}
|
||||
}
|
||||
65
vendor/kreait/firebase-php/src/Firebase/AppCheck/ApiClient.php
vendored
Normal file
65
vendor/kreait/firebase-php/src/Firebase/AppCheck/ApiClient.php
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\AppCheck;
|
||||
|
||||
use Beste\Json;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Kreait\Firebase\Exception\AppCheckApiExceptionConverter;
|
||||
use Kreait\Firebase\Exception\AppCheckException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @phpstan-import-type AppCheckTokenShape from AppCheckToken
|
||||
*/
|
||||
final class ApiClient
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ClientInterface $client,
|
||||
private readonly AppCheckApiExceptionConverter $errorHandler,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AppCheckException
|
||||
*
|
||||
* @return AppCheckTokenShape
|
||||
*/
|
||||
public function exchangeCustomToken(string $appId, string $customToken): array
|
||||
{
|
||||
$response = $this->requestApi('POST', 'apps/'.$appId.':exchangeCustomToken', [
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json; UTF-8',
|
||||
],
|
||||
'body' => Json::encode([
|
||||
'customToken' => $customToken,
|
||||
]),
|
||||
]);
|
||||
|
||||
/** @var AppCheckTokenShape $decoded */
|
||||
$decoded = Json::decode((string) $response->getBody(), true);
|
||||
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $method
|
||||
* @param array<string, mixed>|null $options
|
||||
* @throws AppCheckException
|
||||
*/
|
||||
private function requestApi(string $method, string|UriInterface $uri, ?array $options = null): ResponseInterface
|
||||
{
|
||||
$options ??= [];
|
||||
|
||||
try {
|
||||
return $this->client->request($method, $uri, $options);
|
||||
} catch (Throwable $e) {
|
||||
throw $this->errorHandler->convertException($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
28
vendor/kreait/firebase-php/src/Firebase/AppCheck/AppCheckToken.php
vendored
Normal file
28
vendor/kreait/firebase-php/src/Firebase/AppCheck/AppCheckToken.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\AppCheck;
|
||||
|
||||
/**
|
||||
* @phpstan-type AppCheckTokenShape array{
|
||||
* token: string,
|
||||
* ttl: string
|
||||
* }
|
||||
*/
|
||||
final class AppCheckToken
|
||||
{
|
||||
private function __construct(
|
||||
public readonly string $token,
|
||||
public readonly string $ttl,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AppCheckTokenShape $data
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self($data['token'], $data['ttl']);
|
||||
}
|
||||
}
|
||||
60
vendor/kreait/firebase-php/src/Firebase/AppCheck/AppCheckTokenGenerator.php
vendored
Normal file
60
vendor/kreait/firebase-php/src/Firebase/AppCheck/AppCheckTokenGenerator.php
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\AppCheck;
|
||||
|
||||
use Beste\Clock\SystemClock;
|
||||
use Firebase\JWT\JWT;
|
||||
use Kreait\Firebase\Exception\AppCheck\InvalidAppCheckTokenOptions;
|
||||
use Psr\Clock\ClockInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @todo Add #[SensitiveParameter] attribute to the private key once the minimum required PHP version is >=8.2
|
||||
*/
|
||||
final class AppCheckTokenGenerator
|
||||
{
|
||||
private const APP_CHECK_AUDIENCE = 'https://firebaseappcheck.googleapis.com/google.firebase.appcheck.v1.TokenExchangeService';
|
||||
|
||||
private readonly ClockInterface $clock;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $clientEmail
|
||||
* @param non-empty-string $privateKey
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly string $clientEmail,
|
||||
private readonly string $privateKey,
|
||||
?ClockInterface $clock = null,
|
||||
) {
|
||||
$this->clock = $clock ?? SystemClock::create();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $appId the Application ID to use for the generated token
|
||||
*
|
||||
* @throws InvalidAppCheckTokenOptions
|
||||
*
|
||||
* @return string the generated token
|
||||
*/
|
||||
public function createCustomToken(string $appId, ?AppCheckTokenOptions $options = null): string
|
||||
{
|
||||
$now = $this->clock->now()->getTimestamp();
|
||||
$payload = [
|
||||
'iss' => $this->clientEmail,
|
||||
'sub' => $this->clientEmail,
|
||||
'app_id' => $appId,
|
||||
'aud' => self::APP_CHECK_AUDIENCE,
|
||||
'iat' => $now,
|
||||
'exp' => $now + 300,
|
||||
];
|
||||
|
||||
if ($options?->ttl !== null) {
|
||||
$payload['ttl'] = $options->ttl.'s';
|
||||
}
|
||||
|
||||
return JWT::encode($payload, $this->privateKey, 'RS256');
|
||||
}
|
||||
}
|
||||
40
vendor/kreait/firebase-php/src/Firebase/AppCheck/AppCheckTokenOptions.php
vendored
Normal file
40
vendor/kreait/firebase-php/src/Firebase/AppCheck/AppCheckTokenOptions.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\AppCheck;
|
||||
|
||||
use Kreait\Firebase\Exception\AppCheck\InvalidAppCheckTokenOptions;
|
||||
|
||||
/**
|
||||
* @phpstan-type AppCheckTokenOptionsShape array{
|
||||
* ttl?: int|null,
|
||||
* }
|
||||
*/
|
||||
final class AppCheckTokenOptions
|
||||
{
|
||||
private function __construct(
|
||||
public readonly ?int $ttl = null,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AppCheckTokenOptionsShape $data
|
||||
*
|
||||
* @throws InvalidAppCheckTokenOptions
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$ttl = $data['ttl'] ?? null;
|
||||
|
||||
if (null === $ttl) {
|
||||
return new self();
|
||||
}
|
||||
|
||||
if ($ttl < 1800 || $ttl > 604800) {
|
||||
throw new InvalidAppCheckTokenOptions('The ttl must be a duration between 30 minutes and 7 days.');
|
||||
}
|
||||
|
||||
return new self($ttl);
|
||||
}
|
||||
}
|
||||
89
vendor/kreait/firebase-php/src/Firebase/AppCheck/AppCheckTokenVerifier.php
vendored
Normal file
89
vendor/kreait/firebase-php/src/Firebase/AppCheck/AppCheckTokenVerifier.php
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\AppCheck;
|
||||
|
||||
use Firebase\JWT\CachedKeySet;
|
||||
use Firebase\JWT\JWT;
|
||||
use Kreait\Firebase\Exception\AppCheck\FailedToVerifyAppCheckToken;
|
||||
use Kreait\Firebase\Exception\AppCheck\InvalidAppCheckToken;
|
||||
use LogicException;
|
||||
use Throwable;
|
||||
|
||||
use function in_array;
|
||||
use function str_starts_with;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @phpstan-import-type DecodedAppCheckTokenShape from DecodedAppCheckToken
|
||||
*/
|
||||
final class AppCheckTokenVerifier
|
||||
{
|
||||
private const APP_CHECK_ISSUER_PREFIX = 'https://firebaseappcheck.googleapis.com/';
|
||||
|
||||
/**
|
||||
* @param non-empty-string $projectId
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly string $projectId,
|
||||
private readonly CachedKeySet $keySet,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the format and signature of a Firebase App Check token.
|
||||
*
|
||||
* @param string $token the Firebase Auth JWT token to verify
|
||||
*
|
||||
* @throws FailedToVerifyAppCheckToken if the token could not be verified
|
||||
* @throws InvalidAppCheckToken if the token is invalid
|
||||
*/
|
||||
public function verifyToken(string $token): DecodedAppCheckToken
|
||||
{
|
||||
$decodedToken = $this->decodeJwt($token);
|
||||
|
||||
$this->verifyContent($decodedToken);
|
||||
|
||||
return $decodedToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $token the Firebase App Check JWT token to decode
|
||||
*
|
||||
* @throws FailedToVerifyAppCheckToken if the token could not be verified
|
||||
* @throws InvalidAppCheckToken if the token is invalid
|
||||
*/
|
||||
private function decodeJwt(string $token): DecodedAppCheckToken
|
||||
{
|
||||
try {
|
||||
/** @var DecodedAppCheckTokenShape $payload */
|
||||
$payload = (array) JWT::decode($token, $this->keySet);
|
||||
} catch (LogicException $e) {
|
||||
throw new InvalidAppCheckToken($e->getMessage(), $e->getCode(), $e);
|
||||
} catch (Throwable $e) {
|
||||
throw new FailedToVerifyAppCheckToken($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return DecodedAppCheckToken::fromArray($payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the content of a Firebase App Check JWT.
|
||||
*
|
||||
* @param DecodedAppCheckToken $token the decoded Firebase App Check token to verify
|
||||
*
|
||||
* @throws FailedToVerifyAppCheckToken if the token could not be verified
|
||||
*/
|
||||
private function verifyContent(DecodedAppCheckToken $token): void
|
||||
{
|
||||
if (!in_array('projects/'.$this->projectId, $token->aud, true)) {
|
||||
throw new FailedToVerifyAppCheckToken('The "aud" claim must include the project ID.');
|
||||
}
|
||||
|
||||
if (!str_starts_with($token->iss, self::APP_CHECK_ISSUER_PREFIX)) {
|
||||
throw new FailedToVerifyAppCheckToken('The provided App Check token has incorrect "iss" (issuer) claim.');
|
||||
}
|
||||
}
|
||||
}
|
||||
48
vendor/kreait/firebase-php/src/Firebase/AppCheck/DecodedAppCheckToken.php
vendored
Normal file
48
vendor/kreait/firebase-php/src/Firebase/AppCheck/DecodedAppCheckToken.php
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\AppCheck;
|
||||
|
||||
/**
|
||||
* @phpstan-type DecodedAppCheckTokenShape array{
|
||||
* app_id?: non-empty-string,
|
||||
* aud: array<string>,
|
||||
* exp: int,
|
||||
* iat: int,
|
||||
* iss: non-empty-string,
|
||||
* sub: non-empty-string,
|
||||
* }
|
||||
*/
|
||||
final class DecodedAppCheckToken
|
||||
{
|
||||
/**
|
||||
* @param non-empty-string $app_id
|
||||
* @param array<string> $aud
|
||||
* @param non-empty-string $sub
|
||||
*/
|
||||
private function __construct(
|
||||
public readonly string $app_id,
|
||||
public readonly array $aud,
|
||||
public readonly int $exp,
|
||||
public readonly int $iat,
|
||||
public readonly string $iss,
|
||||
public readonly string $sub,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DecodedAppCheckTokenShape $data
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self(
|
||||
$data['app_id'] ?? $data['sub'],
|
||||
$data['aud'],
|
||||
$data['exp'],
|
||||
$data['iat'],
|
||||
$data['iss'],
|
||||
$data['sub'],
|
||||
);
|
||||
}
|
||||
}
|
||||
25
vendor/kreait/firebase-php/src/Firebase/AppCheck/VerifyAppCheckTokenResponse.php
vendored
Normal file
25
vendor/kreait/firebase-php/src/Firebase/AppCheck/VerifyAppCheckTokenResponse.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\AppCheck;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type DecodedAppCheckTokenShape from DecodedAppCheckToken
|
||||
*
|
||||
* @phpstan-type VerifyAppCheckTokenResponseShape array{
|
||||
* appId: non-empty-string,
|
||||
* token: DecodedAppCheckTokenShape,
|
||||
* }
|
||||
*/
|
||||
final class VerifyAppCheckTokenResponse
|
||||
{
|
||||
/**
|
||||
* @param non-empty-string $appId
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly string $appId,
|
||||
public readonly DecodedAppCheckToken $token,
|
||||
) {
|
||||
}
|
||||
}
|
||||
709
vendor/kreait/firebase-php/src/Firebase/Auth.php
vendored
Normal file
709
vendor/kreait/firebase-php/src/Firebase/Auth.php
vendored
Normal file
@@ -0,0 +1,709 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase;
|
||||
|
||||
use Beste\Json;
|
||||
use DateInterval;
|
||||
use DateTimeImmutable;
|
||||
use Kreait\Firebase\Auth\ActionCodeSettings;
|
||||
use Kreait\Firebase\Auth\ActionCodeSettings\ValidatedActionCodeSettings;
|
||||
use Kreait\Firebase\Auth\ApiClient;
|
||||
use Kreait\Firebase\Auth\CustomTokenViaGoogleCredentials;
|
||||
use Kreait\Firebase\Auth\DeleteUsersRequest;
|
||||
use Kreait\Firebase\Auth\DeleteUsersResult;
|
||||
use Kreait\Firebase\Auth\SendActionLink\FailedToSendActionLink;
|
||||
use Kreait\Firebase\Auth\SignIn\FailedToSignIn;
|
||||
use Kreait\Firebase\Auth\SignInAnonymously;
|
||||
use Kreait\Firebase\Auth\SignInResult;
|
||||
use Kreait\Firebase\Auth\SignInWithCustomToken;
|
||||
use Kreait\Firebase\Auth\SignInWithEmailAndOobCode;
|
||||
use Kreait\Firebase\Auth\SignInWithEmailAndPassword;
|
||||
use Kreait\Firebase\Auth\SignInWithIdpCredentials;
|
||||
use Kreait\Firebase\Auth\SignInWithRefreshToken;
|
||||
use Kreait\Firebase\Auth\UserQuery;
|
||||
use Kreait\Firebase\Auth\UserRecord;
|
||||
use Kreait\Firebase\Contract\Transitional\FederatedUserFetcher;
|
||||
use Kreait\Firebase\Exception\Auth\AuthError;
|
||||
use Kreait\Firebase\Exception\Auth\FailedToVerifySessionCookie;
|
||||
use Kreait\Firebase\Exception\Auth\FailedToVerifyToken;
|
||||
use Kreait\Firebase\Exception\Auth\RevokedIdToken;
|
||||
use Kreait\Firebase\Exception\Auth\RevokedSessionCookie;
|
||||
use Kreait\Firebase\Exception\Auth\UserNotFound;
|
||||
use Kreait\Firebase\Exception\InvalidArgumentException;
|
||||
use Kreait\Firebase\JWT\IdTokenVerifier;
|
||||
use Kreait\Firebase\JWT\SessionCookieVerifier;
|
||||
use Kreait\Firebase\JWT\Token\Parser;
|
||||
use Kreait\Firebase\Request\CreateUser;
|
||||
use Kreait\Firebase\Request\UpdateUser;
|
||||
use Kreait\Firebase\Util\DT;
|
||||
use Kreait\Firebase\Value\ClearTextPassword;
|
||||
use Kreait\Firebase\Value\Email;
|
||||
use Kreait\Firebase\Value\Uid;
|
||||
use Lcobucci\JWT\Encoding\JoseEncoder;
|
||||
use Lcobucci\JWT\Token;
|
||||
use Lcobucci\JWT\UnencryptedToken;
|
||||
use Psr\Clock\ClockInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Stringable;
|
||||
use Throwable;
|
||||
use Traversable;
|
||||
|
||||
use function array_fill_keys;
|
||||
use function array_map;
|
||||
use function assert;
|
||||
use function is_string;
|
||||
use function mb_strtolower;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @phpstan-import-type UserRecordResponseShape from UserRecord
|
||||
*/
|
||||
final class Auth implements Contract\Auth, FederatedUserFetcher
|
||||
{
|
||||
private readonly Parser $jwtParser;
|
||||
|
||||
public function __construct(
|
||||
private readonly ApiClient $client,
|
||||
private readonly ?CustomTokenViaGoogleCredentials $tokenGenerator,
|
||||
private readonly IdTokenVerifier $idTokenVerifier,
|
||||
private readonly SessionCookieVerifier $sessionCookieVerifier,
|
||||
private readonly ClockInterface $clock,
|
||||
) {
|
||||
$this->jwtParser = new Parser(new JoseEncoder());
|
||||
}
|
||||
|
||||
public function getUser(Stringable|string $uid): UserRecord
|
||||
{
|
||||
$uid = Uid::fromString($uid)->value;
|
||||
|
||||
$userRecord = $this->getUsers([$uid])[$uid] ?? null;
|
||||
|
||||
if ($userRecord !== null) {
|
||||
return $userRecord;
|
||||
}
|
||||
|
||||
throw new UserNotFound("No user with uid '{$uid}' found.");
|
||||
}
|
||||
|
||||
public function getUsers(array $uids): array
|
||||
{
|
||||
$uids = array_map(static fn($uid): string => Uid::fromString($uid)->value, $uids);
|
||||
|
||||
$users = array_fill_keys($uids, null);
|
||||
|
||||
$response = $this->client->getAccountInfo($uids);
|
||||
|
||||
$data = Json::decode((string) $response->getBody(), true);
|
||||
|
||||
foreach ($data['users'] ?? [] as $userData) {
|
||||
$userRecord = UserRecord::fromResponseData($userData);
|
||||
$users[$userRecord->uid] = $userRecord;
|
||||
}
|
||||
|
||||
return $users;
|
||||
}
|
||||
|
||||
public function queryUsers(UserQuery|array $query): array
|
||||
{
|
||||
$userQuery = $query instanceof UserQuery ? $query : UserQuery::fromArray($query);
|
||||
|
||||
$response = $this->client->queryUsers($userQuery);
|
||||
|
||||
$data = Json::decode((string) $response->getBody(), true);
|
||||
|
||||
$users = [];
|
||||
|
||||
foreach ($data['userInfo'] ?? [] as $userData) {
|
||||
$userRecord = UserRecord::fromResponseData($userData);
|
||||
$users[$userRecord->uid] = $userRecord;
|
||||
}
|
||||
|
||||
return $users;
|
||||
}
|
||||
|
||||
public function listUsers(int $maxResults = 1000, int $batchSize = 1000): Traversable
|
||||
{
|
||||
$pageToken = null;
|
||||
$count = 0;
|
||||
|
||||
if ($batchSize > $maxResults) {
|
||||
$batchSize = $maxResults;
|
||||
}
|
||||
|
||||
do {
|
||||
$response = $this->client->downloadAccount($batchSize, $pageToken);
|
||||
$result = Json::decode((string) $response->getBody(), true);
|
||||
|
||||
foreach ((array) ($result['users'] ?? []) as $userData) {
|
||||
yield UserRecord::fromResponseData($userData);
|
||||
|
||||
if (++$count === $maxResults) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$pageToken = $result['nextPageToken'] ?? null;
|
||||
} while ($pageToken !== null);
|
||||
}
|
||||
|
||||
public function createUser(array|CreateUser $properties): UserRecord
|
||||
{
|
||||
$request = $properties instanceof CreateUser
|
||||
? $properties
|
||||
: CreateUser::withProperties($properties);
|
||||
|
||||
$response = $this->client->createUser($request);
|
||||
|
||||
return $this->getUserRecordFromResponseAfterUserUpdate($response);
|
||||
}
|
||||
|
||||
public function updateUser(Stringable|string $uid, array|UpdateUser $properties): UserRecord
|
||||
{
|
||||
$request = $properties instanceof UpdateUser
|
||||
? $properties
|
||||
: UpdateUser::withProperties($properties);
|
||||
|
||||
$request = $request->withUid($uid);
|
||||
|
||||
$response = $this->client->updateUser($request);
|
||||
|
||||
return $this->getUserRecordFromResponseAfterUserUpdate($response);
|
||||
}
|
||||
|
||||
public function createUserWithEmailAndPassword(Stringable|string $email, Stringable|string $password): UserRecord
|
||||
{
|
||||
return $this->createUser(
|
||||
CreateUser::new()
|
||||
->withUnverifiedEmail($email)
|
||||
->withClearTextPassword($password),
|
||||
);
|
||||
}
|
||||
|
||||
public function getUserByEmail(Stringable|string $email): UserRecord
|
||||
{
|
||||
$email = Email::fromString((string) $email)->value;
|
||||
|
||||
$response = $this->client->getUserByEmail($email);
|
||||
|
||||
$userRecord = self::getFirstUserRecordFromUserListResponse($response);
|
||||
|
||||
if ($userRecord === null) {
|
||||
throw new UserNotFound("No user with email '{$email}' found.");
|
||||
}
|
||||
|
||||
return $userRecord;
|
||||
}
|
||||
|
||||
public function getUserByPhoneNumber(Stringable|string $phoneNumber): UserRecord
|
||||
{
|
||||
$phoneNumber = (string) $phoneNumber;
|
||||
|
||||
$response = $this->client->getUserByPhoneNumber($phoneNumber);
|
||||
|
||||
$userRecord = self::getFirstUserRecordFromUserListResponse($response);
|
||||
|
||||
if ($userRecord === null) {
|
||||
throw new UserNotFound("No user with phone number '{$phoneNumber}' found.");
|
||||
}
|
||||
|
||||
return $userRecord;
|
||||
}
|
||||
|
||||
public function getUserByProviderUid(Stringable|string $providerId, Stringable|string $providerUid): UserRecord
|
||||
{
|
||||
$providerId = (string) $providerId;
|
||||
$providerUid = (string) $providerUid;
|
||||
|
||||
$response = $this->client->getUserByProviderUid($providerId, $providerUid);
|
||||
|
||||
$userRecord = self::getFirstUserRecordFromUserListResponse($response);
|
||||
|
||||
if ($userRecord === null) {
|
||||
throw new UserNotFound("No user with federated account ID '{$providerId}:{$providerUid}' found.");
|
||||
}
|
||||
|
||||
return $userRecord;
|
||||
}
|
||||
|
||||
public function createAnonymousUser(): UserRecord
|
||||
{
|
||||
return $this->createUser(CreateUser::new());
|
||||
}
|
||||
|
||||
public function changeUserPassword(Stringable|string $uid, Stringable|string $newPassword): UserRecord
|
||||
{
|
||||
return $this->updateUser($uid, UpdateUser::new()->withClearTextPassword($newPassword));
|
||||
}
|
||||
|
||||
public function changeUserEmail(Stringable|string $uid, Stringable|string $newEmail): UserRecord
|
||||
{
|
||||
return $this->updateUser($uid, UpdateUser::new()->withEmail($newEmail));
|
||||
}
|
||||
|
||||
public function enableUser(Stringable|string $uid): UserRecord
|
||||
{
|
||||
return $this->updateUser($uid, UpdateUser::new()->markAsEnabled());
|
||||
}
|
||||
|
||||
public function disableUser(Stringable|string $uid): UserRecord
|
||||
{
|
||||
return $this->updateUser($uid, UpdateUser::new()->markAsDisabled());
|
||||
}
|
||||
|
||||
public function deleteUser(Stringable|string $uid): void
|
||||
{
|
||||
$uid = Uid::fromString($uid)->value;
|
||||
|
||||
try {
|
||||
$this->client->deleteUser($uid);
|
||||
} catch (UserNotFound) {
|
||||
throw new UserNotFound("No user with uid '{$uid}' found.");
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteUsers(iterable $uids, bool $forceDeleteEnabledUsers = false): DeleteUsersResult
|
||||
{
|
||||
$request = DeleteUsersRequest::withUids($uids, $forceDeleteEnabledUsers);
|
||||
|
||||
$response = $this->client->deleteUsers(
|
||||
$request->uids(),
|
||||
$request->enabledUsersShouldBeForceDeleted(),
|
||||
);
|
||||
|
||||
return DeleteUsersResult::fromRequestAndResponse($request, $response);
|
||||
}
|
||||
|
||||
public function getEmailActionLink(string $type, Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): string
|
||||
{
|
||||
$email = Email::fromString((string) $email)->value;
|
||||
|
||||
if ($actionCodeSettings === null) {
|
||||
$actionCodeSettings = ValidatedActionCodeSettings::empty();
|
||||
} else {
|
||||
$actionCodeSettings = $actionCodeSettings instanceof ActionCodeSettings
|
||||
? $actionCodeSettings
|
||||
: ValidatedActionCodeSettings::fromArray($actionCodeSettings);
|
||||
}
|
||||
|
||||
return $this->client->getEmailActionLink($type, $email, $actionCodeSettings, $locale);
|
||||
}
|
||||
|
||||
public function sendEmailActionLink(string $type, Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): void
|
||||
{
|
||||
$email = Email::fromString((string) $email)->value;
|
||||
|
||||
if ($actionCodeSettings === null) {
|
||||
$actionCodeSettings = ValidatedActionCodeSettings::empty();
|
||||
} else {
|
||||
$actionCodeSettings = $actionCodeSettings instanceof ActionCodeSettings
|
||||
? $actionCodeSettings
|
||||
: ValidatedActionCodeSettings::fromArray($actionCodeSettings);
|
||||
}
|
||||
|
||||
$idToken = null;
|
||||
|
||||
if (mb_strtolower($type) === 'verify_email') {
|
||||
// The Firebase API expects an ID token for the user belonging to this email address
|
||||
// see https://github.com/firebase/firebase-js-sdk/issues/1958
|
||||
try {
|
||||
$user = $this->getUserByEmail($email);
|
||||
} catch (Throwable $e) {
|
||||
throw new FailedToSendActionLink($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
try {
|
||||
$signInResult = $this->signInAsUser($user);
|
||||
} catch (Throwable $e) {
|
||||
throw new FailedToSendActionLink($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
$idToken = $signInResult->idToken();
|
||||
if ($idToken === null) {
|
||||
throw new FailedToSendActionLink("Failed to send action link: Unable to retrieve ID token for user assigned to email {$email}");
|
||||
}
|
||||
}
|
||||
|
||||
$this->client->sendEmailActionLink($type, $email, $actionCodeSettings, $locale, $idToken);
|
||||
}
|
||||
|
||||
public function getEmailVerificationLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): string
|
||||
{
|
||||
return $this->getEmailActionLink('VERIFY_EMAIL', $email, $actionCodeSettings, $locale);
|
||||
}
|
||||
|
||||
public function sendEmailVerificationLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): void
|
||||
{
|
||||
$this->sendEmailActionLink('VERIFY_EMAIL', $email, $actionCodeSettings, $locale);
|
||||
}
|
||||
|
||||
public function getPasswordResetLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): string
|
||||
{
|
||||
return $this->getEmailActionLink('PASSWORD_RESET', $email, $actionCodeSettings, $locale);
|
||||
}
|
||||
|
||||
public function sendPasswordResetLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): void
|
||||
{
|
||||
$this->sendEmailActionLink('PASSWORD_RESET', $email, $actionCodeSettings, $locale);
|
||||
}
|
||||
|
||||
public function getSignInWithEmailLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): string
|
||||
{
|
||||
return $this->getEmailActionLink('EMAIL_SIGNIN', $email, $actionCodeSettings, $locale);
|
||||
}
|
||||
|
||||
public function sendSignInWithEmailLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): void
|
||||
{
|
||||
$this->sendEmailActionLink('EMAIL_SIGNIN', $email, $actionCodeSettings, $locale);
|
||||
}
|
||||
|
||||
public function setCustomUserClaims(Stringable|string $uid, ?array $claims): void
|
||||
{
|
||||
$uid = Uid::fromString($uid)->value;
|
||||
$claims ??= [];
|
||||
|
||||
$this->client->setCustomUserClaims($uid, $claims);
|
||||
}
|
||||
|
||||
public function createCustomToken(Stringable|string $uid, array $claims = [], $ttl = 3600): UnencryptedToken
|
||||
{
|
||||
if ($this->tokenGenerator === null) {
|
||||
throw new AuthError('Custom Token Generation is disabled because the current credentials do not permit it');
|
||||
}
|
||||
|
||||
$uid = Uid::fromString($uid)->value;
|
||||
|
||||
if (!$ttl instanceof DateInterval) {
|
||||
$ttl = new DateInterval(sprintf('PT%sS', $ttl));
|
||||
}
|
||||
|
||||
$expiresAt = $this->clock->now()->add($ttl);
|
||||
|
||||
$token = $this->tokenGenerator->createCustomToken($uid, $claims, $expiresAt);
|
||||
|
||||
assert($token instanceof UnencryptedToken);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
public function parseToken(string $tokenString): UnencryptedToken
|
||||
{
|
||||
try {
|
||||
$parsedToken = $this->jwtParser->parse($tokenString);
|
||||
assert($parsedToken instanceof UnencryptedToken);
|
||||
} catch (Throwable $e) {
|
||||
throw new InvalidArgumentException('The given token could not be parsed: '.$e->getMessage());
|
||||
}
|
||||
|
||||
return $parsedToken;
|
||||
}
|
||||
|
||||
public function verifyIdToken($idToken, bool $checkIfRevoked = false, ?int $leewayInSeconds = null): UnencryptedToken
|
||||
{
|
||||
$verifier = $this->idTokenVerifier;
|
||||
|
||||
$idTokenString = is_string($idToken) ? $idToken : $idToken->toString();
|
||||
|
||||
try {
|
||||
if ($leewayInSeconds !== null) {
|
||||
$verifier->verifyIdTokenWithLeeway($idTokenString, $leewayInSeconds);
|
||||
} else {
|
||||
$verifier->verifyIdToken($idTokenString);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
throw new FailedToVerifyToken($e->getMessage());
|
||||
}
|
||||
|
||||
$verifiedToken = $this->parseToken($idTokenString);
|
||||
|
||||
if (!$checkIfRevoked) {
|
||||
return $verifiedToken;
|
||||
}
|
||||
|
||||
$userId = $verifiedToken->claims()->get('sub');
|
||||
assert(is_string($userId) && $userId !== ''); // It's safe to assume that the 'sub' claim is always a string
|
||||
|
||||
try {
|
||||
$user = $this->getUser($userId);
|
||||
} catch (Throwable $e) {
|
||||
throw new FailedToVerifyToken("Error while getting the token's user: {$e->getMessage()}", 0, $e);
|
||||
}
|
||||
|
||||
if ($this->userSessionHasBeenRevoked($verifiedToken, $user, $leewayInSeconds)) {
|
||||
throw new RevokedIdToken($verifiedToken);
|
||||
}
|
||||
|
||||
return $verifiedToken;
|
||||
}
|
||||
|
||||
public function verifySessionCookie(string $sessionCookie, bool $checkIfRevoked = false, ?int $leewayInSeconds = null): UnencryptedToken
|
||||
{
|
||||
$verifier = $this->sessionCookieVerifier;
|
||||
|
||||
try {
|
||||
if ($leewayInSeconds !== null) {
|
||||
$verifier->verifySessionCookieWithLeeway($sessionCookie, $leewayInSeconds);
|
||||
} else {
|
||||
$verifier->verifySessionCookie($sessionCookie);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
throw new FailedToVerifySessionCookie($e->getMessage());
|
||||
}
|
||||
|
||||
$verifiedSessionCookie = $this->parseToken($sessionCookie);
|
||||
|
||||
if (!$checkIfRevoked) {
|
||||
return $verifiedSessionCookie;
|
||||
}
|
||||
|
||||
$userId = $verifiedSessionCookie->claims()->get('sub');
|
||||
assert(is_string($userId) && $userId !== ''); // It's safe to assume that the 'sub' claim is always a string
|
||||
|
||||
try {
|
||||
$user = $this->getUser($userId);
|
||||
} catch (Throwable $e) {
|
||||
throw new FailedToVerifySessionCookie("Error while getting the session cookie's user: {$e->getMessage()}", 0, $e);
|
||||
}
|
||||
|
||||
if ($this->userSessionHasBeenRevoked($verifiedSessionCookie, $user, $leewayInSeconds)) {
|
||||
throw new RevokedSessionCookie($verifiedSessionCookie);
|
||||
}
|
||||
|
||||
return $verifiedSessionCookie;
|
||||
}
|
||||
|
||||
public function verifyPasswordResetCode(string $oobCode): string
|
||||
{
|
||||
$response = $this->client->verifyPasswordResetCode($oobCode);
|
||||
$responseData = Json::decode((string) $response->getBody(), true);
|
||||
|
||||
if (!array_key_exists('email', $responseData) || $responseData['email'] === '') {
|
||||
throw new AuthError('Expected API response to contain a field "email" being a non-empty string, got: '.gettype($responseData));
|
||||
}
|
||||
|
||||
return $responseData['email'];
|
||||
}
|
||||
|
||||
public function confirmPasswordReset(string $oobCode, $newPassword, bool $invalidatePreviousSessions = true): string
|
||||
{
|
||||
$newPassword = ClearTextPassword::fromString($newPassword)->value;
|
||||
|
||||
$response = $this->client->confirmPasswordReset($oobCode, $newPassword);
|
||||
$responseData = Json::decode((string) $response->getBody(), true);
|
||||
|
||||
if (!array_key_exists('email', $responseData) || $responseData['email'] === '') {
|
||||
throw new AuthError('Expected API response to contain a field "email" being a non-empty string, got: '.gettype($responseData));
|
||||
}
|
||||
|
||||
$email = $responseData['email'];
|
||||
|
||||
if ($invalidatePreviousSessions) {
|
||||
$this->revokeRefreshTokens($this->getUserByEmail($email)->uid);
|
||||
}
|
||||
|
||||
return $email;
|
||||
}
|
||||
|
||||
public function revokeRefreshTokens(Stringable|string $uid): void
|
||||
{
|
||||
$uid = Uid::fromString($uid)->value;
|
||||
|
||||
$this->client->revokeRefreshTokens($uid);
|
||||
}
|
||||
|
||||
public function unlinkProvider($uid, $provider): UserRecord
|
||||
{
|
||||
$uid = Uid::fromString($uid)->value;
|
||||
|
||||
$provider = array_values(
|
||||
array_filter(
|
||||
array_map('strval', (array) $provider),
|
||||
static fn(string $value): bool => $value !== '',
|
||||
),
|
||||
);
|
||||
|
||||
$response = $this->client->unlinkProvider($uid, $provider);
|
||||
|
||||
return $this->getUserRecordFromResponseAfterUserUpdate($response);
|
||||
}
|
||||
|
||||
public function signInAsUser($user, ?array $claims = null): SignInResult
|
||||
{
|
||||
$claims ??= [];
|
||||
$uid = $user instanceof UserRecord ? $user->uid : (string) $user;
|
||||
|
||||
try {
|
||||
$customToken = $this->createCustomToken($uid, $claims);
|
||||
} catch (Throwable $e) {
|
||||
throw FailedToSignIn::fromPrevious($e);
|
||||
}
|
||||
|
||||
return $this->client->handleSignIn(SignInWithCustomToken::fromValue($customToken->toString()));
|
||||
}
|
||||
|
||||
public function signInWithCustomToken($token): SignInResult
|
||||
{
|
||||
$token = $token instanceof Token ? $token->toString() : $token;
|
||||
|
||||
$action = SignInWithCustomToken::fromValue($token);
|
||||
|
||||
return $this->client->handleSignIn($action);
|
||||
}
|
||||
|
||||
public function signInWithRefreshToken(string $refreshToken): SignInResult
|
||||
{
|
||||
return $this->client->handleSignIn(SignInWithRefreshToken::fromValue($refreshToken));
|
||||
}
|
||||
|
||||
public function signInWithEmailAndPassword($email, $clearTextPassword): SignInResult
|
||||
{
|
||||
$email = Email::fromString((string) $email)->value;
|
||||
$clearTextPassword = ClearTextPassword::fromString($clearTextPassword)->value;
|
||||
|
||||
return $this->client->handleSignIn(SignInWithEmailAndPassword::fromValues($email, $clearTextPassword));
|
||||
}
|
||||
|
||||
public function signInWithEmailAndOobCode($email, string $oobCode): SignInResult
|
||||
{
|
||||
$email = Email::fromString((string) $email)->value;
|
||||
|
||||
return $this->client->handleSignIn(SignInWithEmailAndOobCode::fromValues($email, $oobCode));
|
||||
}
|
||||
|
||||
public function signInAnonymously(): SignInResult
|
||||
{
|
||||
$result = $this->client->handleSignIn(SignInAnonymously::new());
|
||||
|
||||
if ($result->idToken() !== null) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$uid = $result->firebaseUserId();
|
||||
if ($uid !== null) {
|
||||
return $this->signInAsUser($uid);
|
||||
}
|
||||
|
||||
throw new FailedToSignIn('Failed to sign in anonymously: No ID token or UID available');
|
||||
}
|
||||
|
||||
public function signInWithIdpAccessToken($provider, string $accessToken, $redirectUrl = null, ?string $oauthTokenSecret = null, ?string $linkingIdToken = null, ?string $rawNonce = null): SignInResult
|
||||
{
|
||||
$provider = (string) $provider;
|
||||
$redirectUrl = trim((string) ($redirectUrl ?? 'http://localhost'));
|
||||
$linkingIdToken = trim((string) $linkingIdToken);
|
||||
$oauthTokenSecret = trim((string) $oauthTokenSecret);
|
||||
$rawNonce = trim((string) $rawNonce);
|
||||
|
||||
if ($oauthTokenSecret !== '') {
|
||||
$action = SignInWithIdpCredentials::withAccessTokenAndOauthTokenSecret($provider, $accessToken, $oauthTokenSecret);
|
||||
} else {
|
||||
$action = SignInWithIdpCredentials::withAccessToken($provider, $accessToken);
|
||||
}
|
||||
|
||||
if ($linkingIdToken !== '') {
|
||||
$action = $action->withLinkingIdToken($linkingIdToken);
|
||||
}
|
||||
|
||||
if ($rawNonce !== '') {
|
||||
$action = $action->withRawNonce($rawNonce);
|
||||
}
|
||||
|
||||
if ($redirectUrl !== '') {
|
||||
$action = $action->withRequestUri($redirectUrl);
|
||||
}
|
||||
|
||||
return $this->client->handleSignIn($action);
|
||||
}
|
||||
|
||||
public function signInWithIdpIdToken($provider, $idToken, $redirectUrl = null, ?string $linkingIdToken = null, ?string $rawNonce = null): SignInResult
|
||||
{
|
||||
$provider = trim((string) $provider);
|
||||
$redirectUrl = trim((string) ($redirectUrl ?? 'http://localhost'));
|
||||
$linkingIdToken = trim((string) $linkingIdToken);
|
||||
$rawNonce = trim((string) $rawNonce);
|
||||
|
||||
if ($idToken instanceof Token) {
|
||||
$idToken = $idToken->toString();
|
||||
}
|
||||
|
||||
$action = SignInWithIdpCredentials::withIdToken($provider, $idToken);
|
||||
|
||||
if ($rawNonce !== '') {
|
||||
$action = $action->withRawNonce($rawNonce);
|
||||
}
|
||||
|
||||
if ($linkingIdToken !== '') {
|
||||
$action = $action->withLinkingIdToken($linkingIdToken);
|
||||
}
|
||||
|
||||
if ($redirectUrl !== '') {
|
||||
$action = $action->withRequestUri($redirectUrl);
|
||||
}
|
||||
|
||||
return $this->client->handleSignIn($action);
|
||||
}
|
||||
|
||||
public function createSessionCookie($idToken, $ttl): string
|
||||
{
|
||||
if ($idToken instanceof Token) {
|
||||
$idToken = $idToken->toString();
|
||||
}
|
||||
|
||||
return $this->client->createSessionCookie($idToken, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user ID from the response and queries a full UserRecord object for it.
|
||||
*
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
private function getUserRecordFromResponseAfterUserUpdate(ResponseInterface $response): UserRecord
|
||||
{
|
||||
$responseData = Json::decode((string) $response->getBody(), true);
|
||||
|
||||
if (!array_key_exists('localId', $responseData) || $responseData['localId'] === '') {
|
||||
throw new AuthError('Expected API response to contain a field "localId" being a non-empty string, got: '.gettype($responseData));
|
||||
}
|
||||
|
||||
return $this->getUser($responseData['localId']);
|
||||
}
|
||||
|
||||
private function userSessionHasBeenRevoked(UnencryptedToken $verifiedToken, UserRecord $user, ?int $leewayInSeconds = null): bool
|
||||
{
|
||||
// The timestamp, in seconds, which marks a boundary, before which Firebase ID token are considered revoked.
|
||||
$validSince = $user->tokensValidAfterTime ?? null;
|
||||
|
||||
if (!$validSince instanceof DateTimeImmutable) {
|
||||
// The user hasn't logged in yet, so there's nothing to revoke
|
||||
return false;
|
||||
}
|
||||
|
||||
$tokenAuthenticatedAt = DT::toUTCDateTimeImmutable($verifiedToken->claims()->get('auth_time'));
|
||||
|
||||
if ($leewayInSeconds !== null) {
|
||||
$tokenAuthenticatedAt = $tokenAuthenticatedAt->modify('-'.$leewayInSeconds.' seconds');
|
||||
}
|
||||
|
||||
return $tokenAuthenticatedAt->getTimestamp() < $validSince->getTimestamp();
|
||||
}
|
||||
|
||||
private static function getFirstUserRecordFromUserListResponse(ResponseInterface $response): ?UserRecord
|
||||
{
|
||||
/** @var array{users?: list<UserRecordResponseShape>} $data */
|
||||
$data = Json::decode((string) $response->getBody(), true);
|
||||
|
||||
if (!array_key_exists('users', $data)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$userData = array_shift($data['users']);
|
||||
|
||||
return $userData !== null
|
||||
? UserRecord::fromResponseData($userData)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
13
vendor/kreait/firebase-php/src/Firebase/Auth/ActionCodeSettings.php
vendored
Normal file
13
vendor/kreait/firebase-php/src/Firebase/Auth/ActionCodeSettings.php
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
interface ActionCodeSettings
|
||||
{
|
||||
/**
|
||||
* @return array<non-empty-string, bool|string>
|
||||
*/
|
||||
public function toArray(): array;
|
||||
}
|
||||
145
vendor/kreait/firebase-php/src/Firebase/Auth/ActionCodeSettings/ValidatedActionCodeSettings.php
vendored
Normal file
145
vendor/kreait/firebase-php/src/Firebase/Auth/ActionCodeSettings/ValidatedActionCodeSettings.php
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth\ActionCodeSettings;
|
||||
|
||||
use GuzzleHttp\Psr7\Utils;
|
||||
use Kreait\Firebase\Auth\ActionCodeSettings;
|
||||
use Kreait\Firebase\Exception\InvalidArgumentException;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Stringable;
|
||||
|
||||
use function array_filter;
|
||||
use function is_bool;
|
||||
use function is_string;
|
||||
use function mb_strtolower;
|
||||
|
||||
final class ValidatedActionCodeSettings implements ActionCodeSettings
|
||||
{
|
||||
private ?UriInterface $continueUrl = null;
|
||||
|
||||
private ?bool $canHandleCodeInApp = null;
|
||||
|
||||
private ?UriInterface $dynamicLinkDomain = null;
|
||||
|
||||
/**
|
||||
* @var non-empty-string|null
|
||||
*/
|
||||
private ?string $androidPackageName = null;
|
||||
|
||||
/**
|
||||
* @var non-empty-string|null
|
||||
*/
|
||||
private ?string $androidMinimumVersion = null;
|
||||
|
||||
private ?bool $androidInstallApp = null;
|
||||
|
||||
/**
|
||||
* @var non-empty-string|null
|
||||
*/
|
||||
private ?string $iOSBundleId = null;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public static function empty(): self
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<non-empty-string, mixed> $settings
|
||||
*/
|
||||
public static function fromArray(array $settings): self
|
||||
{
|
||||
$instance = new self();
|
||||
|
||||
$settings = array_filter($settings, static fn($value): bool => $value !== null);
|
||||
|
||||
foreach ($settings as $key => $value) {
|
||||
switch (mb_strtolower($key)) {
|
||||
case 'continueurl':
|
||||
case 'url':
|
||||
$instance->continueUrl = ($value !== null)
|
||||
? Utils::uriFor(self::ensureNonEmptyString($value))
|
||||
: null;
|
||||
|
||||
break;
|
||||
|
||||
case 'handlecodeinapp':
|
||||
$instance->canHandleCodeInApp = (bool) $value;
|
||||
|
||||
break;
|
||||
|
||||
case 'dynamiclinkdomain':
|
||||
$instance->dynamicLinkDomain = ($value !== null)
|
||||
? Utils::uriFor(self::ensureNonEmptyString($value))
|
||||
: null;
|
||||
|
||||
break;
|
||||
|
||||
case 'androidpackagename':
|
||||
$instance->androidPackageName = self::ensureNonEmptyString($value);
|
||||
|
||||
break;
|
||||
|
||||
case 'androidminimumversion':
|
||||
$instance->androidMinimumVersion = self::ensureNonEmptyString($value);
|
||||
|
||||
break;
|
||||
|
||||
case 'androidinstallapp':
|
||||
$instance->androidInstallApp = (bool) $value;
|
||||
|
||||
break;
|
||||
|
||||
case 'iosbundleid':
|
||||
$instance->iOSBundleId = self::ensureNonEmptyString($value);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException("Unsupported action code setting '{$key}'");
|
||||
}
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<non-empty-string, bool|non-empty-string>
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
$continueUrl = $this->continueUrl !== null ? (string) $this->continueUrl : null;
|
||||
$dynamicLinkDomain = $this->dynamicLinkDomain !== null ? (string) $this->dynamicLinkDomain : null;
|
||||
|
||||
return array_filter([
|
||||
'continueUrl' => $continueUrl,
|
||||
'canHandleCodeInApp' => $this->canHandleCodeInApp,
|
||||
'dynamicLinkDomain' => $dynamicLinkDomain,
|
||||
'androidPackageName' => $this->androidPackageName,
|
||||
'androidMinimumVersion' => $this->androidMinimumVersion,
|
||||
'androidInstallApp' => $this->androidInstallApp,
|
||||
'iOSBundleId' => $this->iOSBundleId,
|
||||
], static fn(string|bool|null $value): bool => is_bool($value) || (is_string($value) && $value !== ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
private static function ensureNonEmptyString(mixed $value): string
|
||||
{
|
||||
if ($value instanceof Stringable) {
|
||||
$value = (string) $value;
|
||||
}
|
||||
|
||||
if (!is_string($value) || $value === '') {
|
||||
throw new InvalidArgumentException('A non-empty string is required');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
327
vendor/kreait/firebase-php/src/Firebase/Auth/ApiClient.php
vendored
Normal file
327
vendor/kreait/firebase-php/src/Firebase/Auth/ApiClient.php
vendored
Normal file
@@ -0,0 +1,327 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
use Beste\Json;
|
||||
use DateInterval;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Kreait\Firebase\Auth\CreateSessionCookie\GuzzleApiClientHandler;
|
||||
use Kreait\Firebase\Auth\SignIn\GuzzleHandler;
|
||||
use Kreait\Firebase\Exception\Auth\EmailNotFound;
|
||||
use Kreait\Firebase\Exception\Auth\ExpiredOobCode;
|
||||
use Kreait\Firebase\Exception\Auth\InvalidOobCode;
|
||||
use Kreait\Firebase\Exception\Auth\OperationNotAllowed;
|
||||
use Kreait\Firebase\Exception\Auth\UserDisabled;
|
||||
use Kreait\Firebase\Exception\AuthApiExceptionConverter;
|
||||
use Kreait\Firebase\Exception\AuthException;
|
||||
use Kreait\Firebase\Request\CreateUser;
|
||||
use Kreait\Firebase\Request\UpdateUser;
|
||||
use Psr\Clock\ClockInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Stringable;
|
||||
use Throwable;
|
||||
|
||||
use function array_filter;
|
||||
use function array_map;
|
||||
use function is_array;
|
||||
use function str_contains;
|
||||
use function time;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class ApiClient
|
||||
{
|
||||
private readonly ProjectAwareAuthResourceUrlBuilder|TenantAwareAuthResourceUrlBuilder $awareAuthResourceUrlBuilder;
|
||||
|
||||
private readonly AuthResourceUrlBuilder $authResourceUrlBuilder;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $projectId
|
||||
* @param non-empty-string|null $tenantId
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly string $projectId,
|
||||
private readonly ?string $tenantId,
|
||||
private readonly ClientInterface $client,
|
||||
private readonly GuzzleHandler $signInHandler,
|
||||
private readonly ClockInterface $clock,
|
||||
private readonly AuthApiExceptionConverter $errorHandler,
|
||||
) {
|
||||
$this->awareAuthResourceUrlBuilder = $tenantId !== null
|
||||
? TenantAwareAuthResourceUrlBuilder::forProjectAndTenant($projectId, $tenantId)
|
||||
: ProjectAwareAuthResourceUrlBuilder::forProject($projectId);
|
||||
|
||||
$this->authResourceUrlBuilder = AuthResourceUrlBuilder::create();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AuthException
|
||||
*/
|
||||
public function createUser(CreateUser $request): ResponseInterface
|
||||
{
|
||||
$url = $this->authResourceUrlBuilder->getUrl('/accounts:signUp');
|
||||
|
||||
return $this->requestApi($url, Json::decode(Json::encode($request), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AuthException
|
||||
*/
|
||||
public function updateUser(UpdateUser $request): ResponseInterface
|
||||
{
|
||||
$url = $this->awareAuthResourceUrlBuilder->getUrl('/accounts:update');
|
||||
|
||||
return $this->requestApi($url, Json::decode(Json::encode($request), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<non-empty-string, mixed> $claims
|
||||
*
|
||||
* @throws AuthException
|
||||
*/
|
||||
public function setCustomUserClaims(string $uid, array $claims): ResponseInterface
|
||||
{
|
||||
$url = $this->awareAuthResourceUrlBuilder->getUrl('/accounts:update');
|
||||
|
||||
return $this->requestApi($url, [
|
||||
'localId' => $uid,
|
||||
'customAttributes' => Json::encode((object) $claims),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a user for the given email address.
|
||||
*
|
||||
* @throws AuthException
|
||||
* @throws EmailNotFound
|
||||
*/
|
||||
public function getUserByEmail(string $email): ResponseInterface
|
||||
{
|
||||
$url = $this->awareAuthResourceUrlBuilder->getUrl('/accounts:lookup');
|
||||
|
||||
return $this->requestApi($url, ['email' => [$email]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AuthException
|
||||
*/
|
||||
public function getUserByPhoneNumber(string $phoneNumber): ResponseInterface
|
||||
{
|
||||
$url = $this->awareAuthResourceUrlBuilder->getUrl('/accounts:lookup');
|
||||
|
||||
return $this->requestApi($url, ['phoneNumber' => [$phoneNumber]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AuthException
|
||||
*/
|
||||
public function getUserByProviderUid(string $providerId, string $uid): ResponseInterface
|
||||
{
|
||||
$url = $this->awareAuthResourceUrlBuilder->getUrl('/accounts:lookup');
|
||||
|
||||
return $this->requestApi($url, ['federatedUserId' => [['providerId' => $providerId, 'rawId' => $uid]]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AuthException
|
||||
*/
|
||||
public function downloadAccount(?int $batchSize = null, ?string $nextPageToken = null): ResponseInterface
|
||||
{
|
||||
$batchSize ??= 1000;
|
||||
|
||||
$urlParams = array_filter([
|
||||
'maxResults' => (string) $batchSize,
|
||||
'nextPageToken' => (string) $nextPageToken,
|
||||
], fn(string $value): bool => $value !== '');
|
||||
|
||||
$url = $this->awareAuthResourceUrlBuilder->getUrl('/accounts:batchGet', $urlParams);
|
||||
|
||||
return $this->requestApi($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AuthException
|
||||
*/
|
||||
public function deleteUser(string $uid): ResponseInterface
|
||||
{
|
||||
$url = $this->awareAuthResourceUrlBuilder->getUrl('/accounts:delete');
|
||||
|
||||
return $this->requestApi($url, ['localId' => $uid]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $uids
|
||||
*
|
||||
* @throws AuthException
|
||||
*/
|
||||
public function deleteUsers(array $uids, bool $forceDeleteEnabledUsers): ResponseInterface
|
||||
{
|
||||
$data = [
|
||||
'localIds' => $uids,
|
||||
'force' => $forceDeleteEnabledUsers,
|
||||
];
|
||||
|
||||
$url = $this->awareAuthResourceUrlBuilder->getUrl('/accounts:batchDelete');
|
||||
|
||||
return $this->requestApi($url, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|list<non-empty-string> $uids
|
||||
*
|
||||
* @throws AuthException
|
||||
*/
|
||||
public function getAccountInfo(string|array $uids): ResponseInterface
|
||||
{
|
||||
if (!is_array($uids)) {
|
||||
$uids = [$uids];
|
||||
}
|
||||
|
||||
$url = $this->awareAuthResourceUrlBuilder->getUrl('/accounts:lookup');
|
||||
|
||||
return $this->requestApi($url, ['localId' => $uids]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AuthException
|
||||
*/
|
||||
public function queryUsers(UserQuery $query): ResponseInterface
|
||||
{
|
||||
$url = $this->awareAuthResourceUrlBuilder->getUrl('/accounts:query');
|
||||
|
||||
return $this->requestApi($url, Json::decode(Json::encode($query), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AuthException
|
||||
* @throws ExpiredOobCode
|
||||
* @throws InvalidOobCode
|
||||
* @throws OperationNotAllowed
|
||||
*/
|
||||
public function verifyPasswordResetCode(string $oobCode): ResponseInterface
|
||||
{
|
||||
$url = $this->authResourceUrlBuilder->getUrl('/accounts:resetPassword');
|
||||
|
||||
return $this->requestApi($url, ['oobCode' => $oobCode]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AuthException
|
||||
* @throws ExpiredOobCode
|
||||
* @throws InvalidOobCode
|
||||
* @throws OperationNotAllowed
|
||||
* @throws UserDisabled
|
||||
*/
|
||||
public function confirmPasswordReset(string $oobCode, string $newPassword): ResponseInterface
|
||||
{
|
||||
$url = $this->authResourceUrlBuilder->getUrl('/accounts:resetPassword');
|
||||
|
||||
return $this->requestApi($url, [
|
||||
'oobCode' => $oobCode,
|
||||
'newPassword' => $newPassword,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws AuthException
|
||||
*/
|
||||
public function revokeRefreshTokens(string $uid): ResponseInterface
|
||||
{
|
||||
$url = $this->awareAuthResourceUrlBuilder->getUrl('/accounts:update');
|
||||
|
||||
return $this->requestApi($url, [
|
||||
'localId' => $uid,
|
||||
'validSince' => (string) time(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<Stringable|non-empty-string> $providers
|
||||
*
|
||||
* @throws AuthException
|
||||
*/
|
||||
public function unlinkProvider(string $uid, array $providers): ResponseInterface
|
||||
{
|
||||
$url = $this->awareAuthResourceUrlBuilder->getUrl('/accounts:update');
|
||||
$providers = array_map('strval', $providers);
|
||||
|
||||
return $this->requestApi($url, [
|
||||
'localId' => $uid,
|
||||
'deleteProvider' => $providers,
|
||||
]);
|
||||
}
|
||||
|
||||
public function createSessionCookie(string $idToken, int|DateInterval $ttl): string
|
||||
{
|
||||
return (new GuzzleApiClientHandler($this->client, $this->projectId))
|
||||
->handle(CreateSessionCookie::forIdToken($idToken, $this->tenantId, $ttl, $this->clock))
|
||||
;
|
||||
}
|
||||
|
||||
public function getEmailActionLink(string $type, string $email, ActionCodeSettings $actionCodeSettings, ?string $locale = null): string
|
||||
{
|
||||
return (new CreateActionLink\GuzzleApiClientHandler($this->client, $this->projectId))
|
||||
->handle(CreateActionLink::new($type, $email, $actionCodeSettings, $this->tenantId, $locale))
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Make that this method can be emulated.
|
||||
*/
|
||||
public function sendEmailActionLink(string $type, string $email, ActionCodeSettings $actionCodeSettings, ?string $locale = null, ?string $idToken = null): void
|
||||
{
|
||||
$createAction = CreateActionLink::new($type, $email, $actionCodeSettings, $this->tenantId, $locale);
|
||||
$sendAction = new SendActionLink($createAction, $locale);
|
||||
|
||||
if ($idToken !== null) {
|
||||
$sendAction = $sendAction->withIdTokenString($idToken);
|
||||
}
|
||||
|
||||
(new SendActionLink\GuzzleApiClientHandler($this->client, $this->projectId))->handle($sendAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Make that this method can be emulated.
|
||||
*/
|
||||
public function handleSignIn(SignIn $action): SignInResult
|
||||
{
|
||||
if ($this->tenantId !== null) {
|
||||
$action = $action->withTenantId($this->tenantId);
|
||||
}
|
||||
|
||||
return $this->signInHandler->handle($action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
*
|
||||
* @throws AuthException
|
||||
*/
|
||||
private function requestApi(string $uri, ?array $data = null): ResponseInterface
|
||||
{
|
||||
$options = [];
|
||||
$method = 'GET';
|
||||
|
||||
if (!str_contains($uri, 'projects')) {
|
||||
$data['targetProjectId'] = $this->projectId;
|
||||
}
|
||||
|
||||
if ($this->tenantId !== null && !str_contains($uri, 'tenants')) {
|
||||
$data['tenantId'] = $this->tenantId;
|
||||
}
|
||||
|
||||
if (is_array($data) && $data !== []) {
|
||||
$method = 'POST';
|
||||
$options['json'] = $data;
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->client->request($method, $uri, $options);
|
||||
} catch (Throwable $e) {
|
||||
throw $this->errorHandler->convertException($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
72
vendor/kreait/firebase-php/src/Firebase/Auth/AuthResourceUrlBuilder.php
vendored
Normal file
72
vendor/kreait/firebase-php/src/Firebase/Auth/AuthResourceUrlBuilder.php
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
use Kreait\Firebase\Util;
|
||||
|
||||
use function assert;
|
||||
use function http_build_query;
|
||||
use function str_replace;
|
||||
use function strtr;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class AuthResourceUrlBuilder
|
||||
{
|
||||
private const URL_FORMAT = 'https://identitytoolkit.googleapis.com/{version}{api}';
|
||||
|
||||
private const EMULATOR_URL_FORMAT = 'http://{host}/identitytoolkit.googleapis.com/{version}{api}';
|
||||
|
||||
private const DEFAULT_API_VERSION = 'v1';
|
||||
|
||||
/**
|
||||
* @param non-empty-string $apiVersion
|
||||
* @param non-empty-string $urlFormat
|
||||
*/
|
||||
private function __construct(
|
||||
private readonly string $apiVersion,
|
||||
private readonly string $urlFormat,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string|null $version
|
||||
*/
|
||||
public static function create(?string $version = null): self
|
||||
{
|
||||
$version ??= self::DEFAULT_API_VERSION;
|
||||
$emulatorHost = Util::authEmulatorHost();
|
||||
|
||||
$urlFormat = $emulatorHost !== null
|
||||
? str_replace('{host}', $emulatorHost, self::EMULATOR_URL_FORMAT)
|
||||
: self::URL_FORMAT;
|
||||
|
||||
return new self($version, $urlFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string|null $api
|
||||
* @param array<non-empty-string, scalar>|null $params
|
||||
*
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getUrl(?string $api = null, ?array $params = null): string
|
||||
{
|
||||
$api ??= '';
|
||||
|
||||
$url = strtr($this->urlFormat, [
|
||||
'{version}' => $this->apiVersion,
|
||||
'{api}' => $api,
|
||||
]);
|
||||
assert($url !== '');
|
||||
|
||||
if ($params !== null) {
|
||||
$url .= '?'.http_build_query($params);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
55
vendor/kreait/firebase-php/src/Firebase/Auth/CreateActionLink.php
vendored
Normal file
55
vendor/kreait/firebase-php/src/Firebase/Auth/CreateActionLink.php
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
use Kreait\Firebase\Value\Email;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class CreateActionLink
|
||||
{
|
||||
private function __construct(
|
||||
private readonly ?string $tenantId,
|
||||
private readonly ?string $locale,
|
||||
private readonly string $type,
|
||||
private readonly string $email,
|
||||
private readonly ActionCodeSettings $settings,
|
||||
) {
|
||||
}
|
||||
|
||||
public static function new(string $type, Stringable|string $email, ActionCodeSettings $settings, ?string $tenantId = null, ?string $locale = null): self
|
||||
{
|
||||
$email = Email::fromString((string) $email)->value;
|
||||
|
||||
return new self($tenantId, $locale, $type, $email, $settings);
|
||||
}
|
||||
|
||||
public function type(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function email(): string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function settings(): ActionCodeSettings
|
||||
{
|
||||
return $this->settings;
|
||||
}
|
||||
|
||||
public function tenantId(): ?string
|
||||
{
|
||||
return $this->tenantId;
|
||||
}
|
||||
|
||||
public function locale(): ?string
|
||||
{
|
||||
return $this->locale;
|
||||
}
|
||||
}
|
||||
46
vendor/kreait/firebase-php/src/Firebase/Auth/CreateActionLink/FailedToCreateActionLink.php
vendored
Normal file
46
vendor/kreait/firebase-php/src/Firebase/Auth/CreateActionLink/FailedToCreateActionLink.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth\CreateActionLink;
|
||||
|
||||
use Beste\Json;
|
||||
use InvalidArgumentException;
|
||||
use Kreait\Firebase\Auth\CreateActionLink;
|
||||
use Kreait\Firebase\Exception\AuthException;
|
||||
use Kreait\Firebase\Exception\RuntimeException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
final class FailedToCreateActionLink extends RuntimeException implements AuthException
|
||||
{
|
||||
private ?CreateActionLink $action = null;
|
||||
|
||||
private ?ResponseInterface $response = null;
|
||||
|
||||
public static function withActionAndResponse(CreateActionLink $action, ResponseInterface $response): self
|
||||
{
|
||||
$fallbackMessage = 'Failed to create action link';
|
||||
|
||||
try {
|
||||
$message = Json::decode((string) $response->getBody(), true)['error']['message'] ?? $fallbackMessage;
|
||||
} catch (InvalidArgumentException) {
|
||||
$message = $fallbackMessage;
|
||||
}
|
||||
|
||||
$error = new self($message);
|
||||
$error->action = $action;
|
||||
$error->response = $response;
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
public function action(): ?CreateActionLink
|
||||
{
|
||||
return $this->action;
|
||||
}
|
||||
|
||||
public function response(): ?ResponseInterface
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
}
|
||||
93
vendor/kreait/firebase-php/src/Firebase/Auth/CreateActionLink/GuzzleApiClientHandler.php
vendored
Normal file
93
vendor/kreait/firebase-php/src/Firebase/Auth/CreateActionLink/GuzzleApiClientHandler.php
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth\CreateActionLink;
|
||||
|
||||
use Beste\Json;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Utils;
|
||||
use InvalidArgumentException;
|
||||
use Kreait\Firebase\Auth\CreateActionLink;
|
||||
use Kreait\Firebase\Auth\ProjectAwareAuthResourceUrlBuilder;
|
||||
use Kreait\Firebase\Auth\TenantAwareAuthResourceUrlBuilder;
|
||||
use Psr\Http\Client\ClientExceptionInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
use function array_filter;
|
||||
|
||||
use const JSON_FORCE_OBJECT;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class GuzzleApiClientHandler
|
||||
{
|
||||
/**
|
||||
* @param non-empty-string $projectId
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly ClientInterface $client,
|
||||
private readonly string $projectId,
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(CreateActionLink $action): string
|
||||
{
|
||||
$request = $this->createRequest($action);
|
||||
|
||||
try {
|
||||
$response = $this->client->send($request, ['http_errors' => false]);
|
||||
} catch (ClientExceptionInterface $e) {
|
||||
throw new FailedToCreateActionLink('Failed to create action link: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
throw FailedToCreateActionLink::withActionAndResponse($action, $response);
|
||||
}
|
||||
|
||||
try {
|
||||
$data = Json::decode((string) $response->getBody(), true);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
throw new FailedToCreateActionLink('Unable to parse the response data: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
$actionCode = $data['oobLink'] ?? null;
|
||||
|
||||
if (!is_scalar($actionCode)) {
|
||||
throw new FailedToCreateActionLink('The response did not contain an action link');
|
||||
}
|
||||
|
||||
return (string) $actionCode;
|
||||
}
|
||||
|
||||
private function createRequest(CreateActionLink $action): RequestInterface
|
||||
{
|
||||
$data = [
|
||||
'requestType' => $action->type(),
|
||||
'email' => $action->email(),
|
||||
'returnOobLink' => true,
|
||||
...$action->settings()->toArray(),
|
||||
];
|
||||
|
||||
$tenantId = $action->tenantId();
|
||||
if (is_string($tenantId) && $tenantId !== '') {
|
||||
$urlBuilder = TenantAwareAuthResourceUrlBuilder::forProjectAndTenant($this->projectId, $tenantId);
|
||||
} else {
|
||||
$urlBuilder = ProjectAwareAuthResourceUrlBuilder::forProject($this->projectId);
|
||||
}
|
||||
|
||||
$url = $urlBuilder->getUrl('/accounts:sendOobCode');
|
||||
|
||||
$body = Utils::streamFor(Json::encode($data, JSON_FORCE_OBJECT));
|
||||
|
||||
$headers = array_filter([
|
||||
'Content-Type' => 'application/json; charset=UTF-8',
|
||||
'Content-Length' => (string) $body->getSize(),
|
||||
'X-Firebase-Locale' => $action->locale(),
|
||||
], fn(?string $value): bool => $value !== null);
|
||||
|
||||
return new Request('POST', $url, $headers, $body);
|
||||
}
|
||||
}
|
||||
104
vendor/kreait/firebase-php/src/Firebase/Auth/CreateSessionCookie.php
vendored
Normal file
104
vendor/kreait/firebase-php/src/Firebase/Auth/CreateSessionCookie.php
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
use Beste\Clock\SystemClock;
|
||||
use Beste\Clock\WrappingClock;
|
||||
use DateInterval;
|
||||
use Kreait\Firebase\Exception\InvalidArgumentException;
|
||||
use Lcobucci\JWT\Token;
|
||||
use Psr\Clock\ClockInterface;
|
||||
|
||||
use function is_int;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class CreateSessionCookie
|
||||
{
|
||||
private const FIVE_MINUTES = 'PT5M';
|
||||
|
||||
private const TWO_WEEKS = 'P14D';
|
||||
|
||||
private function __construct(
|
||||
private readonly string $idToken,
|
||||
private readonly ?string $tenantId,
|
||||
private readonly DateInterval $ttl,
|
||||
private readonly ClockInterface $clock,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Token|string $idToken
|
||||
* @param int|DateInterval $ttl
|
||||
*/
|
||||
public static function forIdToken($idToken, ?string $tenantId, $ttl, ?object $clock = null): self
|
||||
{
|
||||
$clock ??= SystemClock::create();
|
||||
|
||||
if (!$clock instanceof ClockInterface) {
|
||||
$clock = WrappingClock::wrapping($clock);
|
||||
}
|
||||
|
||||
if ($idToken instanceof Token) {
|
||||
$idToken = $idToken->toString();
|
||||
}
|
||||
|
||||
$ttl = self::assertValidDuration($ttl, $clock);
|
||||
|
||||
return new self($idToken, $tenantId, $ttl, $clock);
|
||||
}
|
||||
|
||||
public function idToken(): string
|
||||
{
|
||||
return $this->idToken;
|
||||
}
|
||||
|
||||
public function tenantId(): ?string
|
||||
{
|
||||
return $this->tenantId;
|
||||
}
|
||||
|
||||
public function ttl(): DateInterval
|
||||
{
|
||||
return $this->ttl;
|
||||
}
|
||||
|
||||
public function ttlInSeconds(): int
|
||||
{
|
||||
$now = $this->clock->now();
|
||||
|
||||
return $now->add($this->ttl)->getTimestamp() - $now->getTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|DateInterval $ttl
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private static function assertValidDuration($ttl, ClockInterface $clock): DateInterval
|
||||
{
|
||||
if (is_int($ttl)) {
|
||||
if ($ttl < 0) {
|
||||
throw new InvalidArgumentException('A session cookie cannot be valid for a negative amount of time');
|
||||
}
|
||||
|
||||
$ttl = new DateInterval('PT'.$ttl.'S');
|
||||
}
|
||||
|
||||
$now = $clock->now();
|
||||
|
||||
$expiresAt = $now->add($ttl);
|
||||
|
||||
$min = $now->add(new DateInterval(self::FIVE_MINUTES));
|
||||
$max = $now->add(new DateInterval(self::TWO_WEEKS));
|
||||
|
||||
if ($expiresAt >= $min && $expiresAt <= $max) {
|
||||
return $ttl;
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException('The TTL of a session must be between 5 minutes and 14 days');
|
||||
}
|
||||
}
|
||||
52
vendor/kreait/firebase-php/src/Firebase/Auth/CreateSessionCookie/FailedToCreateSessionCookie.php
vendored
Normal file
52
vendor/kreait/firebase-php/src/Firebase/Auth/CreateSessionCookie/FailedToCreateSessionCookie.php
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth\CreateSessionCookie;
|
||||
|
||||
use Beste\Json;
|
||||
use InvalidArgumentException;
|
||||
use Kreait\Firebase\Auth\CreateSessionCookie;
|
||||
use Kreait\Firebase\Exception\AuthException;
|
||||
use Kreait\Firebase\Exception\RuntimeException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Throwable;
|
||||
|
||||
final class FailedToCreateSessionCookie extends RuntimeException implements AuthException
|
||||
{
|
||||
public function __construct(
|
||||
private readonly CreateSessionCookie $action,
|
||||
private readonly ?ResponseInterface $response,
|
||||
?string $message = null,
|
||||
?int $code = null,
|
||||
?Throwable $previous = null,
|
||||
) {
|
||||
$message ??= '';
|
||||
$code ??= 0;
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
public static function withActionAndResponse(CreateSessionCookie $action, ResponseInterface $response): self
|
||||
{
|
||||
$fallbackMessage = 'Failed to create session cookie';
|
||||
|
||||
try {
|
||||
$message = Json::decode((string) $response->getBody(), true)['error']['message'] ?? $fallbackMessage;
|
||||
} catch (InvalidArgumentException) {
|
||||
$message = $fallbackMessage;
|
||||
}
|
||||
|
||||
return new self($action, $response, $message);
|
||||
}
|
||||
|
||||
public function action(): CreateSessionCookie
|
||||
{
|
||||
return $this->action;
|
||||
}
|
||||
|
||||
public function response(): ?ResponseInterface
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
}
|
||||
91
vendor/kreait/firebase-php/src/Firebase/Auth/CreateSessionCookie/GuzzleApiClientHandler.php
vendored
Normal file
91
vendor/kreait/firebase-php/src/Firebase/Auth/CreateSessionCookie/GuzzleApiClientHandler.php
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth\CreateSessionCookie;
|
||||
|
||||
use Beste\Json;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Utils;
|
||||
use InvalidArgumentException;
|
||||
use Kreait\Firebase\Auth\CreateSessionCookie;
|
||||
use Kreait\Firebase\Auth\ProjectAwareAuthResourceUrlBuilder;
|
||||
use Kreait\Firebase\Auth\TenantAwareAuthResourceUrlBuilder;
|
||||
use Psr\Http\Client\ClientExceptionInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
use function array_filter;
|
||||
|
||||
use const JSON_FORCE_OBJECT;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class GuzzleApiClientHandler
|
||||
{
|
||||
/**
|
||||
* @param non-empty-string $projectId
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly ClientInterface $client,
|
||||
private readonly string $projectId,
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(CreateSessionCookie $action): string
|
||||
{
|
||||
$request = $this->createRequest($action);
|
||||
|
||||
try {
|
||||
$response = $this->client->send($request, ['http_errors' => false]);
|
||||
} catch (ClientExceptionInterface $e) {
|
||||
throw new FailedToCreateSessionCookie($action, null, 'Connection error', 0, $e);
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
throw FailedToCreateSessionCookie::withActionAndResponse($action, $response);
|
||||
}
|
||||
|
||||
try {
|
||||
/** @var array{sessionCookie?: string|null} $data */
|
||||
$data = Json::decode((string) $response->getBody(), true);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
throw new FailedToCreateSessionCookie($action, $response, 'Unable to parse the response data: '.$e->getMessage(), 0, $e);
|
||||
}
|
||||
|
||||
$sessionCookie = $data['sessionCookie'] ?? null;
|
||||
|
||||
if ($sessionCookie !== null) {
|
||||
return $sessionCookie;
|
||||
}
|
||||
|
||||
throw new FailedToCreateSessionCookie($action, $response, 'The response did not contain a session cookie');
|
||||
}
|
||||
|
||||
private function createRequest(CreateSessionCookie $action): RequestInterface
|
||||
{
|
||||
$data = [
|
||||
'idToken' => $action->idToken(),
|
||||
'validDuration' => $action->ttlInSeconds(),
|
||||
];
|
||||
|
||||
$tenantId = $action->tenantId();
|
||||
if (is_string($tenantId) && $tenantId !== '') {
|
||||
$urlBuilder = TenantAwareAuthResourceUrlBuilder::forProjectAndTenant($this->projectId, $tenantId);
|
||||
} else {
|
||||
$urlBuilder = ProjectAwareAuthResourceUrlBuilder::forProject($this->projectId);
|
||||
}
|
||||
|
||||
$url = $urlBuilder->getUrl(':createSessionCookie');
|
||||
|
||||
$body = Utils::streamFor(Json::encode($data, JSON_FORCE_OBJECT));
|
||||
|
||||
$headers = array_filter([
|
||||
'Content-Type' => 'application/json; charset=UTF-8',
|
||||
'Content-Length' => (string) ($body->getSize() ?? ''),
|
||||
], fn($value): bool => $value !== '' && $value !== '0');
|
||||
|
||||
return new Request('POST', $url, $headers, $body);
|
||||
}
|
||||
}
|
||||
80
vendor/kreait/firebase-php/src/Firebase/Auth/CustomTokenViaGoogleCredentials.php
vendored
Normal file
80
vendor/kreait/firebase-php/src/Firebase/Auth/CustomTokenViaGoogleCredentials.php
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
use DateInterval;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use Google\Auth\SignBlobInterface;
|
||||
use Kreait\Firebase\Exception\Auth\AuthError;
|
||||
use Kreait\Firebase\Util\DT;
|
||||
use Lcobucci\JWT\Encoding\JoseEncoder;
|
||||
use Lcobucci\JWT\Token;
|
||||
use Lcobucci\JWT\Token\Parser;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class CustomTokenViaGoogleCredentials
|
||||
{
|
||||
private readonly JoseEncoder $encoder;
|
||||
|
||||
private readonly Parser $parser;
|
||||
|
||||
public function __construct(private readonly SignBlobInterface $signer, private readonly ?string $tenantId = null)
|
||||
{
|
||||
$this->encoder = new JoseEncoder();
|
||||
$this->parser = new Parser($this->encoder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Stringable|string $uid
|
||||
* @param array<non-empty-string, mixed> $claims
|
||||
*
|
||||
* @throws AuthError
|
||||
*/
|
||||
public function createCustomToken($uid, array $claims = [], ?DateTimeInterface $expiresAt = null): Token
|
||||
{
|
||||
$now = new DateTimeImmutable();
|
||||
$expiresAt = ($expiresAt !== null)
|
||||
? DT::toUTCDateTimeImmutable($expiresAt)
|
||||
: $now->add(new DateInterval('PT1H'));
|
||||
|
||||
$header = ['typ' => 'JWT', 'alg' => 'RS256'];
|
||||
$payload = [
|
||||
'iss' => $this->signer->getClientName(),
|
||||
'sub' => $this->signer->getClientName(),
|
||||
'aud' => 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit',
|
||||
'iat' => $now->getTimestamp(),
|
||||
'exp' => $expiresAt->getTimestamp(),
|
||||
'uid' => (string) $uid,
|
||||
];
|
||||
|
||||
if ($this->tenantId !== null) {
|
||||
$payload['tenant_id'] = $this->tenantId;
|
||||
}
|
||||
|
||||
if ($claims !== []) {
|
||||
$payload['claims'] = $claims;
|
||||
}
|
||||
|
||||
$base64UrlHeader = $this->base64EncodeArray($header);
|
||||
$base64UrlPayload = $this->base64EncodeArray($payload);
|
||||
|
||||
$signature = $this->signer->signBlob($base64UrlHeader.'.'.$base64UrlPayload);
|
||||
$signature = str_replace(['=', '+', '/'], ['', '-', '_'], $signature);
|
||||
|
||||
return $this->parser->parse(sprintf('%s.%s.%s', $base64UrlHeader, $base64UrlPayload, $signature));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed> $array
|
||||
*/
|
||||
private function base64EncodeArray(array $array): string
|
||||
{
|
||||
return $this->encoder->base64UrlEncode($this->encoder->jsonEncode($array));
|
||||
}
|
||||
}
|
||||
57
vendor/kreait/firebase-php/src/Firebase/Auth/DeleteUsersRequest.php
vendored
Normal file
57
vendor/kreait/firebase-php/src/Firebase/Auth/DeleteUsersRequest.php
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
use Kreait\Firebase\Exception\InvalidArgumentException;
|
||||
use Kreait\Firebase\Value\Uid;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class DeleteUsersRequest
|
||||
{
|
||||
private const MAX_BATCH_SIZE = 1000;
|
||||
|
||||
private function __construct(
|
||||
/** @var list<string> $uids */
|
||||
private readonly array $uids,
|
||||
private readonly bool $enabledUsersShouldBeForceDeleted,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iterable<Stringable|string> $uids
|
||||
*/
|
||||
public static function withUids(iterable $uids, bool $forceDeleteEnabledUsers = false): self
|
||||
{
|
||||
$validatedUids = [];
|
||||
$count = 0;
|
||||
|
||||
foreach ($uids as $uid) {
|
||||
$validatedUids[] = Uid::fromString($uid)->value;
|
||||
++$count;
|
||||
|
||||
if ($count > self::MAX_BATCH_SIZE) {
|
||||
throw new InvalidArgumentException('Only '.self::MAX_BATCH_SIZE.' users can be deleted at a time');
|
||||
}
|
||||
}
|
||||
|
||||
return new self($validatedUids, $forceDeleteEnabledUsers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function uids(): array
|
||||
{
|
||||
return $this->uids;
|
||||
}
|
||||
|
||||
public function enabledUsersShouldBeForceDeleted(): bool
|
||||
{
|
||||
return $this->enabledUsersShouldBeForceDeleted;
|
||||
}
|
||||
}
|
||||
64
vendor/kreait/firebase-php/src/Firebase/Auth/DeleteUsersResult.php
vendored
Normal file
64
vendor/kreait/firebase-php/src/Firebase/Auth/DeleteUsersResult.php
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
use Beste\Json;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
use function count;
|
||||
use function is_countable;
|
||||
|
||||
final class DeleteUsersResult
|
||||
{
|
||||
/**
|
||||
* @param list<array{
|
||||
* index: int,
|
||||
* localId: string,
|
||||
* message: string
|
||||
* }> $rawErrors
|
||||
*/
|
||||
private function __construct(
|
||||
private readonly int $successCount,
|
||||
private readonly int $failureCount,
|
||||
private readonly array $rawErrors,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function fromRequestAndResponse(DeleteUsersRequest $request, ResponseInterface $response): self
|
||||
{
|
||||
$data = Json::decode((string) $response->getBody(), true);
|
||||
$errors = $data['errors'] ?? [];
|
||||
|
||||
$failureCount = is_countable($errors) ? count($errors) : 0;
|
||||
$successCount = count($request->uids()) - $failureCount;
|
||||
|
||||
return new self($successCount, $failureCount, $errors);
|
||||
}
|
||||
|
||||
public function failureCount(): int
|
||||
{
|
||||
return $this->failureCount;
|
||||
}
|
||||
|
||||
public function successCount(): int
|
||||
{
|
||||
return $this->successCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array{
|
||||
* index: int,
|
||||
* localId: string,
|
||||
* message: string
|
||||
* }>
|
||||
*/
|
||||
public function rawErrors(): array
|
||||
{
|
||||
return $this->rawErrors;
|
||||
}
|
||||
}
|
||||
13
vendor/kreait/firebase-php/src/Firebase/Auth/IsTenantAware.php
vendored
Normal file
13
vendor/kreait/firebase-php/src/Firebase/Auth/IsTenantAware.php
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
interface IsTenantAware
|
||||
{
|
||||
public function tenantId(): ?string;
|
||||
}
|
||||
48
vendor/kreait/firebase-php/src/Firebase/Auth/MfaInfo.php
vendored
Normal file
48
vendor/kreait/firebase-php/src/Firebase/Auth/MfaInfo.php
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Kreait\Firebase\Util\DT;
|
||||
|
||||
use function array_key_exists;
|
||||
|
||||
/**
|
||||
* @phpstan-type MfaInfoResponseShape array{
|
||||
* mfaEnrollmentId: non-empty-string,
|
||||
* displayName?: non-empty-string,
|
||||
* phoneInfo?: non-empty-string,
|
||||
* enrolledAt?: non-empty-string
|
||||
* }
|
||||
*/
|
||||
final class MfaInfo
|
||||
{
|
||||
private function __construct(
|
||||
public readonly string $mfaEnrollmentId,
|
||||
public readonly ?string $displayName,
|
||||
public readonly ?string $phoneInfo,
|
||||
public readonly ?DateTimeImmutable $enrolledAt,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param MfaInfoResponseShape $data
|
||||
*/
|
||||
public static function fromResponseData(array $data): self
|
||||
{
|
||||
$enrolledAt = array_key_exists('enrolledAt', $data)
|
||||
? DT::toUTCDateTimeImmutable($data['enrolledAt'])
|
||||
: null;
|
||||
|
||||
return new self(
|
||||
$data['mfaEnrollmentId'],
|
||||
$data['displayName'] ?? null,
|
||||
$data['phoneInfo'] ?? null,
|
||||
$enrolledAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
72
vendor/kreait/firebase-php/src/Firebase/Auth/ProjectAwareAuthResourceUrlBuilder.php
vendored
Normal file
72
vendor/kreait/firebase-php/src/Firebase/Auth/ProjectAwareAuthResourceUrlBuilder.php
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
use Kreait\Firebase\Util;
|
||||
|
||||
use function http_build_query;
|
||||
use function str_replace;
|
||||
use function strtr;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class ProjectAwareAuthResourceUrlBuilder
|
||||
{
|
||||
private const URL_FORMAT = 'https://identitytoolkit.googleapis.com/{version}/projects/{projectId}{api}';
|
||||
|
||||
private const EMULATOR_URL_FORMAT = 'http://{host}/identitytoolkit.googleapis.com/{version}/projects/{projectId}{api}';
|
||||
|
||||
private const DEFAULT_API_VERSION = 'v1';
|
||||
|
||||
/**
|
||||
* @param non-empty-string $projectId
|
||||
* @param non-empty-string $apiVersion
|
||||
* @param non-empty-string $urlFormat
|
||||
*/
|
||||
private function __construct(
|
||||
private readonly string $projectId,
|
||||
private readonly string $apiVersion,
|
||||
private readonly string $urlFormat,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $projectId
|
||||
* @param non-empty-string|null $version
|
||||
*/
|
||||
public static function forProject(string $projectId, ?string $version = null): self
|
||||
{
|
||||
$version ??= self::DEFAULT_API_VERSION;
|
||||
$emulatorHost = Util::authEmulatorHost();
|
||||
|
||||
$urlFormat = $emulatorHost !== null
|
||||
? str_replace('{host}', $emulatorHost, self::EMULATOR_URL_FORMAT)
|
||||
: self::URL_FORMAT;
|
||||
|
||||
return new self($projectId, $version, $urlFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string|null $api
|
||||
* @param array<non-empty-string, scalar>|null $params
|
||||
*/
|
||||
public function getUrl(?string $api = null, ?array $params = null): string
|
||||
{
|
||||
$api ??= '';
|
||||
|
||||
$url = strtr($this->urlFormat, [
|
||||
'{version}' => $this->apiVersion,
|
||||
'{projectId}' => $this->projectId,
|
||||
'{api}' => $api,
|
||||
]);
|
||||
|
||||
if ($params !== null) {
|
||||
$url .= '?'.http_build_query($params);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
74
vendor/kreait/firebase-php/src/Firebase/Auth/SendActionLink.php
vendored
Normal file
74
vendor/kreait/firebase-php/src/Firebase/Auth/SendActionLink.php
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class SendActionLink
|
||||
{
|
||||
private ?string $idTokenString = null;
|
||||
|
||||
public function __construct(private CreateActionLink $action, private readonly ?string $locale = null)
|
||||
{
|
||||
}
|
||||
|
||||
public function type(): string
|
||||
{
|
||||
return $this->action->type();
|
||||
}
|
||||
|
||||
public function email(): string
|
||||
{
|
||||
return $this->action->email();
|
||||
}
|
||||
|
||||
public function settings(): ActionCodeSettings
|
||||
{
|
||||
return $this->action->settings();
|
||||
}
|
||||
|
||||
public function tenantId(): ?string
|
||||
{
|
||||
return $this->action->tenantId();
|
||||
}
|
||||
|
||||
public function locale(): ?string
|
||||
{
|
||||
return $this->locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* Only to be used when the API endpoint expects the ID Token of the given user.
|
||||
*
|
||||
* Currently, this seems only to be the case on VERIFY_EMAIL actions.
|
||||
*
|
||||
* @see https://github.com/firebase/firebase-js-sdk/issues/1958
|
||||
*/
|
||||
public function withIdTokenString(string $idTokenString): self
|
||||
{
|
||||
$instance = clone $this;
|
||||
$instance->action = clone $this->action;
|
||||
$instance->idTokenString = $idTokenString;
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* Only to be used when the API endpoint expects the ID Token of the given user.
|
||||
*
|
||||
* Currently seems only to be the case on VERIFY_EMAIL actions.
|
||||
*
|
||||
* @see https://github.com/firebase/firebase-js-sdk/issues/1958
|
||||
*/
|
||||
public function idTokenString(): ?string
|
||||
{
|
||||
return $this->idTokenString;
|
||||
}
|
||||
}
|
||||
46
vendor/kreait/firebase-php/src/Firebase/Auth/SendActionLink/FailedToSendActionLink.php
vendored
Normal file
46
vendor/kreait/firebase-php/src/Firebase/Auth/SendActionLink/FailedToSendActionLink.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth\SendActionLink;
|
||||
|
||||
use Beste\Json;
|
||||
use InvalidArgumentException;
|
||||
use Kreait\Firebase\Auth\SendActionLink;
|
||||
use Kreait\Firebase\Exception\AuthException;
|
||||
use Kreait\Firebase\Exception\RuntimeException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
final class FailedToSendActionLink extends RuntimeException implements AuthException
|
||||
{
|
||||
private ?SendActionLink $action = null;
|
||||
|
||||
private ?ResponseInterface $response = null;
|
||||
|
||||
public static function withActionAndResponse(SendActionLink $action, ResponseInterface $response): self
|
||||
{
|
||||
$fallbackMessage = 'Failed to send action link';
|
||||
|
||||
try {
|
||||
$message = Json::decode((string) $response->getBody(), true)['error']['message'] ?? $fallbackMessage;
|
||||
} catch (InvalidArgumentException) {
|
||||
$message = $fallbackMessage;
|
||||
}
|
||||
|
||||
$error = new self($message);
|
||||
$error->action = $action;
|
||||
$error->response = $response;
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
public function action(): ?SendActionLink
|
||||
{
|
||||
return $this->action;
|
||||
}
|
||||
|
||||
public function response(): ?ResponseInterface
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
}
|
||||
83
vendor/kreait/firebase-php/src/Firebase/Auth/SendActionLink/GuzzleApiClientHandler.php
vendored
Normal file
83
vendor/kreait/firebase-php/src/Firebase/Auth/SendActionLink/GuzzleApiClientHandler.php
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth\SendActionLink;
|
||||
|
||||
use Beste\Json;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Utils;
|
||||
use Kreait\Firebase\Auth\ProjectAwareAuthResourceUrlBuilder;
|
||||
use Kreait\Firebase\Auth\SendActionLink;
|
||||
use Kreait\Firebase\Auth\TenantAwareAuthResourceUrlBuilder;
|
||||
use Psr\Http\Client\ClientExceptionInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
use function array_filter;
|
||||
|
||||
use const JSON_FORCE_OBJECT;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class GuzzleApiClientHandler
|
||||
{
|
||||
/**
|
||||
* @param non-empty-string $projectId
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly ClientInterface $client,
|
||||
private readonly string $projectId,
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(SendActionLink $action): void
|
||||
{
|
||||
$request = $this->createRequest($action);
|
||||
|
||||
try {
|
||||
$response = $this->client->send($request, ['http_errors' => false]);
|
||||
} catch (ClientExceptionInterface $e) {
|
||||
throw new FailedToSendActionLink('Failed to send action link: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
throw FailedToSendActionLink::withActionAndResponse($action, $response);
|
||||
}
|
||||
}
|
||||
|
||||
private function createRequest(SendActionLink $action): RequestInterface
|
||||
{
|
||||
$data = [
|
||||
'requestType' => $action->type(),
|
||||
'email' => $action->email(),
|
||||
...$action->settings()->toArray(),
|
||||
];
|
||||
|
||||
$tenantId = $action->tenantId();
|
||||
if (is_string($tenantId) && $tenantId !== '') {
|
||||
$urlBuilder = TenantAwareAuthResourceUrlBuilder::forProjectAndTenant($this->projectId, $tenantId);
|
||||
$data['tenantId'] = $tenantId;
|
||||
} else {
|
||||
$urlBuilder = ProjectAwareAuthResourceUrlBuilder::forProject($this->projectId);
|
||||
}
|
||||
|
||||
$url = $urlBuilder->getUrl('/accounts:sendOobCode');
|
||||
|
||||
$idTokenString = $action->idTokenString();
|
||||
if ($idTokenString !== null) {
|
||||
$data['idToken'] = $idTokenString;
|
||||
}
|
||||
|
||||
$body = Utils::streamFor(Json::encode($data, JSON_FORCE_OBJECT));
|
||||
|
||||
$headers = array_filter([
|
||||
'Content-Type' => 'application/json; charset=UTF-8',
|
||||
'Content-Length' => (string) $body->getSize(),
|
||||
'X-Firebase-Locale' => $action->locale(),
|
||||
], fn(?string $value): bool => !in_array($value, ['', null, '0'], true));
|
||||
|
||||
return new Request('POST', $url, $headers, $body);
|
||||
}
|
||||
}
|
||||
15
vendor/kreait/firebase-php/src/Firebase/Auth/SignIn.php
vendored
Normal file
15
vendor/kreait/firebase-php/src/Firebase/Auth/SignIn.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
interface SignIn
|
||||
{
|
||||
public function withTenantId(string $tenantId): self;
|
||||
|
||||
public function tenantId(): ?string;
|
||||
}
|
||||
52
vendor/kreait/firebase-php/src/Firebase/Auth/SignIn/FailedToSignIn.php
vendored
Normal file
52
vendor/kreait/firebase-php/src/Firebase/Auth/SignIn/FailedToSignIn.php
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth\SignIn;
|
||||
|
||||
use Beste\Json;
|
||||
use InvalidArgumentException;
|
||||
use Kreait\Firebase\Auth\SignIn;
|
||||
use Kreait\Firebase\Exception\AuthException;
|
||||
use Kreait\Firebase\Exception\RuntimeException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Throwable;
|
||||
|
||||
final class FailedToSignIn extends RuntimeException implements AuthException
|
||||
{
|
||||
private ?SignIn $action = null;
|
||||
|
||||
private ?ResponseInterface $response = null;
|
||||
|
||||
public static function withActionAndResponse(SignIn $action, ResponseInterface $response): self
|
||||
{
|
||||
$fallbackMessage = 'Failed to sign in';
|
||||
|
||||
try {
|
||||
$message = Json::decode((string) $response->getBody(), true)['error']['message'] ?? $fallbackMessage;
|
||||
} catch (InvalidArgumentException) {
|
||||
$message = $fallbackMessage;
|
||||
}
|
||||
|
||||
$error = new self($message);
|
||||
$error->action = $action;
|
||||
$error->response = $response;
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
public static function fromPrevious(Throwable $e): self
|
||||
{
|
||||
return new self('Sign in failed: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
public function action(): ?SignIn
|
||||
{
|
||||
return $this->action;
|
||||
}
|
||||
|
||||
public function response(): ?ResponseInterface
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
}
|
||||
220
vendor/kreait/firebase-php/src/Firebase/Auth/SignIn/GuzzleHandler.php
vendored
Normal file
220
vendor/kreait/firebase-php/src/Firebase/Auth/SignIn/GuzzleHandler.php
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth\SignIn;
|
||||
|
||||
use Beste\Json;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\Psr7\Query;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Utils;
|
||||
use Kreait\Firebase\Auth\AuthResourceUrlBuilder;
|
||||
use Kreait\Firebase\Auth\IsTenantAware;
|
||||
use Kreait\Firebase\Auth\SignIn;
|
||||
use Kreait\Firebase\Auth\SignInAnonymously;
|
||||
use Kreait\Firebase\Auth\SignInResult;
|
||||
use Kreait\Firebase\Auth\SignInWithCustomToken;
|
||||
use Kreait\Firebase\Auth\SignInWithEmailAndOobCode;
|
||||
use Kreait\Firebase\Auth\SignInWithEmailAndPassword;
|
||||
use Kreait\Firebase\Auth\SignInWithIdpCredentials;
|
||||
use Kreait\Firebase\Auth\SignInWithRefreshToken;
|
||||
use Kreait\Firebase\Util;
|
||||
use Psr\Http\Client\ClientExceptionInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use UnexpectedValueException;
|
||||
|
||||
use function http_build_query;
|
||||
use function str_replace;
|
||||
|
||||
use const JSON_FORCE_OBJECT;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class GuzzleHandler
|
||||
{
|
||||
/**
|
||||
* @var array<non-empty-string, mixed>
|
||||
*/
|
||||
private static array $defaultBody = [
|
||||
'returnSecureToken' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array<non-empty-string, mixed>
|
||||
*/
|
||||
private static array $defaultHeaders = [
|
||||
'Content-Type' => 'application/json; charset=UTF-8',
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
private readonly string $projectId,
|
||||
private readonly ClientInterface $client,
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(SignIn $action): SignInResult
|
||||
{
|
||||
$request = $this->createApiRequest($action);
|
||||
|
||||
try {
|
||||
$response = $this->client->send($request, ['http_errors' => false]);
|
||||
} catch (ClientExceptionInterface $e) {
|
||||
throw FailedToSignIn::fromPrevious($e);
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
throw FailedToSignIn::withActionAndResponse($action, $response);
|
||||
}
|
||||
|
||||
try {
|
||||
$data = Json::decode((string) $response->getBody(), true);
|
||||
} catch (UnexpectedValueException $e) {
|
||||
throw FailedToSignIn::fromPrevious($e);
|
||||
}
|
||||
|
||||
return SignInResult::fromData($data);
|
||||
}
|
||||
|
||||
private function createApiRequest(SignIn $action): RequestInterface
|
||||
{
|
||||
return match (true) {
|
||||
$action instanceof SignInAnonymously => $this->anonymous($action),
|
||||
$action instanceof SignInWithCustomToken => $this->customToken($action),
|
||||
$action instanceof SignInWithEmailAndPassword => $this->emailAndPassword($action),
|
||||
$action instanceof SignInWithEmailAndOobCode => $this->emailAndOobCode($action),
|
||||
$action instanceof SignInWithIdpCredentials => $this->idpCredentials($action),
|
||||
$action instanceof SignInWithRefreshToken => $this->refreshToken($action),
|
||||
default => throw new FailedToSignIn(self::class.' does not support '.$action::class),
|
||||
};
|
||||
}
|
||||
|
||||
private function anonymous(SignInAnonymously $action): Request
|
||||
{
|
||||
$url = AuthResourceUrlBuilder::create()->getUrl('/accounts:signUp');
|
||||
|
||||
$body = Utils::streamFor(Json::encode($this->prepareBody($action), JSON_FORCE_OBJECT));
|
||||
|
||||
$headers = self::$defaultHeaders;
|
||||
|
||||
return new Request('POST', $url, $headers, $body);
|
||||
}
|
||||
|
||||
private function customToken(SignInWithCustomToken $action): Request
|
||||
{
|
||||
$url = AuthResourceUrlBuilder::create()->getUrl('/accounts:signInWithCustomToken');
|
||||
|
||||
$body = Utils::streamFor(
|
||||
Json::encode([...$this->prepareBody($action), 'token' => $action->customToken()], JSON_FORCE_OBJECT),
|
||||
);
|
||||
|
||||
$headers = self::$defaultHeaders;
|
||||
|
||||
return new Request('POST', $url, $headers, $body);
|
||||
}
|
||||
|
||||
private function emailAndPassword(SignInWithEmailAndPassword $action): Request
|
||||
{
|
||||
$url = AuthResourceUrlBuilder::create()->getUrl('/accounts:signInWithPassword');
|
||||
|
||||
$body = Utils::streamFor(
|
||||
Json::encode([
|
||||
...$this->prepareBody($action),
|
||||
'email' => $action->email(),
|
||||
'password' => $action->clearTextPassword(),
|
||||
'returnSecureToken' => true,
|
||||
], JSON_FORCE_OBJECT),
|
||||
);
|
||||
|
||||
$headers = self::$defaultHeaders;
|
||||
|
||||
return new Request('POST', $url, $headers, $body);
|
||||
}
|
||||
|
||||
private function emailAndOobCode(SignInWithEmailAndOobCode $action): Request
|
||||
{
|
||||
$url = AuthResourceUrlBuilder::create()->getUrl('/accounts:signInWithEmailLink');
|
||||
|
||||
$body = Utils::streamFor(
|
||||
Json::encode([
|
||||
...$this->prepareBody($action),
|
||||
'email' => $action->email(),
|
||||
'oobCode' => $action->oobCode(),
|
||||
'returnSecureToken' => true,
|
||||
], JSON_FORCE_OBJECT),
|
||||
);
|
||||
|
||||
$headers = self::$defaultHeaders;
|
||||
|
||||
return new Request('POST', $url, $headers, $body);
|
||||
}
|
||||
|
||||
private function idpCredentials(SignInWithIdpCredentials $action): Request
|
||||
{
|
||||
$url = AuthResourceUrlBuilder::create()->getUrl('/accounts:signInWithIdp');
|
||||
|
||||
$postBody = array_filter([
|
||||
'access_token' => $action->accessToken(),
|
||||
'id_token' => $action->idToken(),
|
||||
'providerId' => $action->provider(),
|
||||
'oauth_token_secret' => $action->oauthTokenSecret(),
|
||||
'nonce' => $action->rawNonce(),
|
||||
], fn(?string $value): bool => $value !== null);
|
||||
|
||||
$rawBody = array_filter([
|
||||
...$this->prepareBody($action),
|
||||
'postBody' => http_build_query($postBody),
|
||||
'returnIdpCredential' => true,
|
||||
'requestUri' => $action->requestUri(),
|
||||
'idToken' => $action->linkingIdToken(),
|
||||
], fn($value): bool => $value !== null);
|
||||
|
||||
$body = Utils::streamFor(Json::encode($rawBody, JSON_FORCE_OBJECT));
|
||||
|
||||
$headers = self::$defaultHeaders;
|
||||
|
||||
return new Request('POST', $url, $headers, $body);
|
||||
}
|
||||
|
||||
private function refreshToken(SignInWithRefreshToken $action): Request
|
||||
{
|
||||
$body = Query::build([
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $action->refreshToken(),
|
||||
]);
|
||||
|
||||
$headers = [
|
||||
'Content-Type' => 'application/x-www-form-urlencoded',
|
||||
'Accept' => 'application/json',
|
||||
];
|
||||
|
||||
$emulatorHost = Util::authEmulatorHost();
|
||||
|
||||
if ($emulatorHost !== null) {
|
||||
// The emulator host requires an api key query parameter.
|
||||
$url = str_replace('{host}', $emulatorHost, 'http://{host}/securetoken.googleapis.com/v1/token?key=any');
|
||||
} else {
|
||||
$url = 'https://securetoken.googleapis.com/v1/token';
|
||||
}
|
||||
|
||||
return new Request('POST', $url, $headers, $body);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<non-empty-string, mixed>
|
||||
*/
|
||||
private function prepareBody(SignIn $action): array
|
||||
{
|
||||
$body = self::$defaultBody;
|
||||
$body['targetProjectId'] = $this->projectId;
|
||||
|
||||
$tenantId = $action->tenantId();
|
||||
|
||||
if ($action instanceof IsTenantAware && $tenantId !== null) {
|
||||
$body['tenantId'] = $tenantId;
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
}
|
||||
35
vendor/kreait/firebase-php/src/Firebase/Auth/SignInAnonymously.php
vendored
Normal file
35
vendor/kreait/firebase-php/src/Firebase/Auth/SignInAnonymously.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class SignInAnonymously implements SignIn
|
||||
{
|
||||
private ?string $tenantId = null;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public static function new(): self
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
|
||||
public function withTenantId(string $tenantId): self
|
||||
{
|
||||
$action = clone $this;
|
||||
$action->tenantId = $tenantId;
|
||||
|
||||
return $action;
|
||||
}
|
||||
|
||||
public function tenantId(): ?string
|
||||
{
|
||||
return $this->tenantId;
|
||||
}
|
||||
}
|
||||
192
vendor/kreait/firebase-php/src/Firebase/Auth/SignInResult.php
vendored
Normal file
192
vendor/kreait/firebase-php/src/Firebase/Auth/SignInResult.php
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
use Kreait\Firebase\JWT\Token\Parser;
|
||||
use Lcobucci\JWT\Encoding\JoseEncoder;
|
||||
use Lcobucci\JWT\UnencryptedToken;
|
||||
use stdClass;
|
||||
|
||||
use function array_key_exists;
|
||||
use function assert;
|
||||
use function is_array;
|
||||
use function is_object;
|
||||
use function property_exists;
|
||||
|
||||
final class SignInResult
|
||||
{
|
||||
/**
|
||||
* @var non-empty-string|null
|
||||
*/
|
||||
private ?string $idToken = null;
|
||||
|
||||
/**
|
||||
* @var non-empty-string|null
|
||||
*/
|
||||
private ?string $accessToken = null;
|
||||
|
||||
/**
|
||||
* @var non-empty-string|null
|
||||
*/
|
||||
private ?string $refreshToken = null;
|
||||
|
||||
/**
|
||||
* @var positive-int|null
|
||||
*/
|
||||
private ?int $ttl = null;
|
||||
|
||||
/**
|
||||
* @var array<non-empty-string, mixed>
|
||||
*/
|
||||
private array $data = [];
|
||||
|
||||
/**
|
||||
* @var non-empty-string|null
|
||||
*/
|
||||
private ?string $firebaseUserId = null;
|
||||
|
||||
/**
|
||||
* @var non-empty-string|null
|
||||
*/
|
||||
private ?string $tenantId = null;
|
||||
|
||||
private readonly Parser $parser;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
$this->parser = new Parser(new JoseEncoder());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<non-empty-string, mixed> $data
|
||||
*/
|
||||
public static function fromData(array $data): self
|
||||
{
|
||||
$instance = new self();
|
||||
|
||||
$expiresIn = (int) ($data['expiresIn'] ?? $data['expires_in'] ?? null);
|
||||
|
||||
if ($expiresIn > 0) {
|
||||
$instance->ttl = $expiresIn;
|
||||
}
|
||||
|
||||
$instance->idToken = $data['idToken'] ?? $data['id_token'] ?? null;
|
||||
$instance->accessToken = $data['accessToken'] ?? $data['access_token'] ?? null;
|
||||
$instance->refreshToken = $data['refreshToken'] ?? $data['refresh_token'] ?? null;
|
||||
$instance->data = $data;
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string|null
|
||||
*/
|
||||
public function idToken(): ?string
|
||||
{
|
||||
return $this->idToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string|null
|
||||
*/
|
||||
public function firebaseUserId(): ?string
|
||||
{
|
||||
if ($this->firebaseUserId !== null) {
|
||||
return $this->firebaseUserId;
|
||||
}
|
||||
|
||||
if ($this->idToken !== null) {
|
||||
$idToken = $this->parser->parse($this->idToken);
|
||||
assert($idToken instanceof UnencryptedToken);
|
||||
|
||||
foreach (['sub', 'localId', 'user_id'] as $claim) {
|
||||
$uid = $idToken->claims()->get($claim, false);
|
||||
if (is_string($uid) && $uid !== '') {
|
||||
return $this->firebaseUserId = $uid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$localId = $this->data['localId'] ?? null;
|
||||
if (is_string($localId) && $localId !== '') {
|
||||
return $this->firebaseUserId = $localId;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string|null
|
||||
*/
|
||||
public function firebaseTenantId(): ?string
|
||||
{
|
||||
if ($this->tenantId !== null) {
|
||||
return $this->tenantId;
|
||||
}
|
||||
|
||||
if ($this->idToken !== null) {
|
||||
$idToken = $this->parser->parse($this->idToken);
|
||||
assert($idToken instanceof UnencryptedToken);
|
||||
|
||||
$firebaseClaims = $idToken->claims()->get('firebase', new stdClass());
|
||||
|
||||
if (is_object($firebaseClaims) && property_exists($firebaseClaims, 'tenant')) {
|
||||
return $this->tenantId = $firebaseClaims->tenant;
|
||||
}
|
||||
|
||||
if (is_array($firebaseClaims) && array_key_exists('tenant', $firebaseClaims)) {
|
||||
return $this->tenantId = $firebaseClaims['tenant'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string|null
|
||||
*/
|
||||
public function accessToken(): ?string
|
||||
{
|
||||
return $this->accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string|null
|
||||
*/
|
||||
public function refreshToken(): ?string
|
||||
{
|
||||
return $this->refreshToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return positive-int|null
|
||||
*/
|
||||
public function ttl(): ?int
|
||||
{
|
||||
return $this->ttl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<non-empty-string, mixed>
|
||||
*/
|
||||
public function data(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<non-empty-string, mixed>
|
||||
*/
|
||||
public function asTokenResponse(): array
|
||||
{
|
||||
return [
|
||||
'token_type' => 'Bearer',
|
||||
'access_token' => $this->accessToken,
|
||||
'id_token' => $this->idToken,
|
||||
'refresh_token' => $this->refreshToken,
|
||||
'expires_in' => $this->ttl,
|
||||
];
|
||||
}
|
||||
}
|
||||
40
vendor/kreait/firebase-php/src/Firebase/Auth/SignInWithCustomToken.php
vendored
Normal file
40
vendor/kreait/firebase-php/src/Firebase/Auth/SignInWithCustomToken.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class SignInWithCustomToken implements IsTenantAware, SignIn
|
||||
{
|
||||
private ?string $tenantId = null;
|
||||
|
||||
private function __construct(private readonly string $customToken)
|
||||
{
|
||||
}
|
||||
|
||||
public static function fromValue(string $customToken): self
|
||||
{
|
||||
return new self($customToken);
|
||||
}
|
||||
|
||||
public function withTenantId(string $tenantId): self
|
||||
{
|
||||
$action = clone $this;
|
||||
$action->tenantId = $tenantId;
|
||||
|
||||
return $action;
|
||||
}
|
||||
|
||||
public function customToken(): string
|
||||
{
|
||||
return $this->customToken;
|
||||
}
|
||||
|
||||
public function tenantId(): ?string
|
||||
{
|
||||
return $this->tenantId;
|
||||
}
|
||||
}
|
||||
45
vendor/kreait/firebase-php/src/Firebase/Auth/SignInWithEmailAndOobCode.php
vendored
Normal file
45
vendor/kreait/firebase-php/src/Firebase/Auth/SignInWithEmailAndOobCode.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class SignInWithEmailAndOobCode implements IsTenantAware, SignIn
|
||||
{
|
||||
private ?string $tenantId = null;
|
||||
|
||||
private function __construct(private readonly string $email, private readonly string $oobCode)
|
||||
{
|
||||
}
|
||||
|
||||
public static function fromValues(string $email, string $oobCode): self
|
||||
{
|
||||
return new self($email, $oobCode);
|
||||
}
|
||||
|
||||
public function withTenantId(string $tenantId): self
|
||||
{
|
||||
$action = clone $this;
|
||||
$action->tenantId = $tenantId;
|
||||
|
||||
return $action;
|
||||
}
|
||||
|
||||
public function email(): string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function oobCode(): string
|
||||
{
|
||||
return $this->oobCode;
|
||||
}
|
||||
|
||||
public function tenantId(): ?string
|
||||
{
|
||||
return $this->tenantId;
|
||||
}
|
||||
}
|
||||
45
vendor/kreait/firebase-php/src/Firebase/Auth/SignInWithEmailAndPassword.php
vendored
Normal file
45
vendor/kreait/firebase-php/src/Firebase/Auth/SignInWithEmailAndPassword.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class SignInWithEmailAndPassword implements IsTenantAware, SignIn
|
||||
{
|
||||
private ?string $tenantId = null;
|
||||
|
||||
private function __construct(private readonly string $email, private readonly string $clearTextPassword)
|
||||
{
|
||||
}
|
||||
|
||||
public static function fromValues(string $email, string $clearTextPassword): self
|
||||
{
|
||||
return new self($email, $clearTextPassword);
|
||||
}
|
||||
|
||||
public function email(): string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function clearTextPassword(): string
|
||||
{
|
||||
return $this->clearTextPassword;
|
||||
}
|
||||
|
||||
public function withTenantId(string $tenantId): self
|
||||
{
|
||||
$action = clone $this;
|
||||
$action->tenantId = $tenantId;
|
||||
|
||||
return $action;
|
||||
}
|
||||
|
||||
public function tenantId(): ?string
|
||||
{
|
||||
return $this->tenantId;
|
||||
}
|
||||
}
|
||||
125
vendor/kreait/firebase-php/src/Firebase/Auth/SignInWithIdpCredentials.php
vendored
Normal file
125
vendor/kreait/firebase-php/src/Firebase/Auth/SignInWithIdpCredentials.php
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class SignInWithIdpCredentials implements IsTenantAware, SignIn
|
||||
{
|
||||
private ?string $accessToken = null;
|
||||
|
||||
private ?string $idToken = null;
|
||||
|
||||
private ?string $linkingIdToken = null;
|
||||
|
||||
private ?string $oauthTokenSecret = null;
|
||||
|
||||
private ?string $rawNonce = null;
|
||||
|
||||
private string $requestUri = 'http://localhost';
|
||||
|
||||
private ?string $tenantId = null;
|
||||
|
||||
private function __construct(private readonly string $provider)
|
||||
{
|
||||
}
|
||||
|
||||
public static function withAccessToken(string $provider, string $accessToken): self
|
||||
{
|
||||
$instance = new self($provider);
|
||||
$instance->accessToken = $accessToken;
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
public static function withAccessTokenAndOauthTokenSecret(string $provider, string $accessToken, string $oauthTokenSecret): self
|
||||
{
|
||||
$instance = self::withAccessToken($provider, $accessToken);
|
||||
$instance->oauthTokenSecret = $oauthTokenSecret;
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
public static function withIdToken(string $provider, string $idToken): self
|
||||
{
|
||||
$instance = new self($provider);
|
||||
$instance->idToken = $idToken;
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
public function withRawNonce(string $rawNonce): self
|
||||
{
|
||||
$instance = clone $this;
|
||||
$instance->rawNonce = $rawNonce;
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
public function withLinkingIdToken(string $idToken): self
|
||||
{
|
||||
$instance = clone $this;
|
||||
$instance->linkingIdToken = $idToken;
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
public function withRequestUri(string $requestUri): self
|
||||
{
|
||||
$instance = clone $this;
|
||||
$instance->requestUri = $requestUri;
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
public function withTenantId(string $tenantId): self
|
||||
{
|
||||
$action = clone $this;
|
||||
$action->tenantId = $tenantId;
|
||||
|
||||
return $action;
|
||||
}
|
||||
|
||||
public function provider(): string
|
||||
{
|
||||
return $this->provider;
|
||||
}
|
||||
|
||||
public function oauthTokenSecret(): ?string
|
||||
{
|
||||
return $this->oauthTokenSecret;
|
||||
}
|
||||
|
||||
public function accessToken(): ?string
|
||||
{
|
||||
return $this->accessToken;
|
||||
}
|
||||
|
||||
public function idToken(): ?string
|
||||
{
|
||||
return $this->idToken;
|
||||
}
|
||||
|
||||
public function rawNonce(): ?string
|
||||
{
|
||||
return $this->rawNonce;
|
||||
}
|
||||
|
||||
public function linkingIdToken(): ?string
|
||||
{
|
||||
return $this->linkingIdToken;
|
||||
}
|
||||
|
||||
public function requestUri(): string
|
||||
{
|
||||
return $this->requestUri;
|
||||
}
|
||||
|
||||
public function tenantId(): ?string
|
||||
{
|
||||
return $this->tenantId;
|
||||
}
|
||||
}
|
||||
40
vendor/kreait/firebase-php/src/Firebase/Auth/SignInWithRefreshToken.php
vendored
Normal file
40
vendor/kreait/firebase-php/src/Firebase/Auth/SignInWithRefreshToken.php
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class SignInWithRefreshToken implements IsTenantAware, SignIn
|
||||
{
|
||||
private ?string $tenantId = null;
|
||||
|
||||
private function __construct(private readonly string $refreshToken)
|
||||
{
|
||||
}
|
||||
|
||||
public static function fromValue(string $refreshToken): self
|
||||
{
|
||||
return new self($refreshToken);
|
||||
}
|
||||
|
||||
public function withTenantId(string $tenantId): self
|
||||
{
|
||||
$action = clone $this;
|
||||
$action->tenantId = $tenantId;
|
||||
|
||||
return $action;
|
||||
}
|
||||
|
||||
public function refreshToken(): string
|
||||
{
|
||||
return $this->refreshToken;
|
||||
}
|
||||
|
||||
public function tenantId(): ?string
|
||||
{
|
||||
return $this->tenantId;
|
||||
}
|
||||
}
|
||||
75
vendor/kreait/firebase-php/src/Firebase/Auth/TenantAwareAuthResourceUrlBuilder.php
vendored
Normal file
75
vendor/kreait/firebase-php/src/Firebase/Auth/TenantAwareAuthResourceUrlBuilder.php
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
use Kreait\Firebase\Util;
|
||||
|
||||
use function http_build_query;
|
||||
use function str_replace;
|
||||
use function strtr;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class TenantAwareAuthResourceUrlBuilder
|
||||
{
|
||||
private const URL_FORMAT = 'https://identitytoolkit.googleapis.com/{version}/projects/{projectId}/tenants/{tenantId}{api}';
|
||||
|
||||
private const EMULATOR_URL_FORMAT = 'http://{host}/identitytoolkit.googleapis.com/{version}/projects/{projectId}/tenants/{tenantId}{api}';
|
||||
|
||||
private const DEFAULT_API_VERSION = 'v1';
|
||||
|
||||
/**
|
||||
* @param non-empty-string $projectId
|
||||
* @param non-empty-string $tenantId
|
||||
* @param non-empty-string $apiVersion
|
||||
* @param non-empty-string $urlFormat
|
||||
*/
|
||||
private function __construct(
|
||||
private readonly string $projectId,
|
||||
private readonly string $tenantId,
|
||||
private readonly string $apiVersion,
|
||||
private readonly string $urlFormat,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $projectId
|
||||
* @param non-empty-string $tenantId
|
||||
* @param non-empty-string|null $version
|
||||
*/
|
||||
public static function forProjectAndTenant(string $projectId, string $tenantId, ?string $version = null): self
|
||||
{
|
||||
$version ??= self::DEFAULT_API_VERSION;
|
||||
$emulatorHost = Util::authEmulatorHost();
|
||||
|
||||
$urlFormat = $emulatorHost !== null
|
||||
? str_replace('{host}', $emulatorHost, self::EMULATOR_URL_FORMAT)
|
||||
: self::URL_FORMAT;
|
||||
|
||||
return new self($projectId, $tenantId, $version, $urlFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<non-empty-string, scalar>|null $params
|
||||
*/
|
||||
public function getUrl(?string $api = null, ?array $params = null): string
|
||||
{
|
||||
$api ??= '';
|
||||
|
||||
$url = strtr($this->urlFormat, [
|
||||
'{version}' => $this->apiVersion,
|
||||
'{projectId}' => $this->projectId,
|
||||
'{tenantId}' => $this->tenantId,
|
||||
'{api}' => $api,
|
||||
]);
|
||||
|
||||
if ($params !== null) {
|
||||
$url .= '?'.http_build_query($params);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
66
vendor/kreait/firebase-php/src/Firebase/Auth/UserInfo.php
vendored
Normal file
66
vendor/kreait/firebase-php/src/Firebase/Auth/UserInfo.php
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
/**
|
||||
* Represents a user's info from a third-party identity provider
|
||||
* such as Google or Facebook.
|
||||
*
|
||||
* @phpstan-type UserInfoShape array{
|
||||
* uid: non-empty-string,
|
||||
* providerId: non-empty-string,
|
||||
* displayName?: non-empty-string,
|
||||
* email?: non-empty-string,
|
||||
* photoUrl?: non-empty-string,
|
||||
* phoneNumber?: non-empty-string
|
||||
*
|
||||
* }
|
||||
* @phpstan-type ProviderUserInfoResponseShape array{
|
||||
* rawId: non-empty-string,
|
||||
* providerId: non-empty-string,
|
||||
* displayName?: non-empty-string,
|
||||
* email?: non-empty-string,
|
||||
* federatedId?: non-empty-string,
|
||||
* photoUrl?: non-empty-string,
|
||||
* phoneNumber?: non-empty-string
|
||||
* }
|
||||
*/
|
||||
final class UserInfo
|
||||
{
|
||||
/**
|
||||
* @param non-empty-string $uid
|
||||
* @param non-empty-string $providerId
|
||||
* @param non-empty-string|null $displayName
|
||||
* @param non-empty-string|null $email
|
||||
* @param non-empty-string|null $phoneNumber
|
||||
* @param non-empty-string|null $photoUrl
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly string $uid,
|
||||
public readonly string $providerId,
|
||||
public readonly ?string $displayName,
|
||||
public readonly ?string $email,
|
||||
public readonly ?string $phoneNumber,
|
||||
public readonly ?string $photoUrl,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param ProviderUserInfoResponseShape $data
|
||||
*/
|
||||
public static function fromResponseData(array $data): self
|
||||
{
|
||||
return new self(
|
||||
$data['rawId'],
|
||||
$data['providerId'],
|
||||
$data['displayName'] ?? null,
|
||||
$data['email'] ?? null,
|
||||
$data['phoneNumber'] ?? null,
|
||||
$data['photoUrl'] ?? null,
|
||||
);
|
||||
}
|
||||
}
|
||||
53
vendor/kreait/firebase-php/src/Firebase/Auth/UserMetaData.php
vendored
Normal file
53
vendor/kreait/firebase-php/src/Firebase/Auth/UserMetaData.php
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Kreait\Firebase\Util\DT;
|
||||
|
||||
use function array_key_exists;
|
||||
|
||||
/**
|
||||
* @phpstan-type UserMetadataResponseShape array{
|
||||
* createdAt: non-empty-string,
|
||||
* lastLoginAt?: non-empty-string,
|
||||
* passwordUpdatedAt?: non-empty-string,
|
||||
* lastRefreshAt?: non-empty-string
|
||||
* }
|
||||
*/
|
||||
final class UserMetaData
|
||||
{
|
||||
public function __construct(
|
||||
public readonly DateTimeImmutable $createdAt,
|
||||
public readonly ?DateTimeImmutable $lastLoginAt,
|
||||
public readonly ?DateTimeImmutable $passwordUpdatedAt,
|
||||
public readonly ?DateTimeImmutable $lastRefreshAt,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param UserMetadataResponseShape $data
|
||||
*/
|
||||
public static function fromResponseData(array $data): self
|
||||
{
|
||||
$createdAt = DT::toUTCDateTimeImmutable($data['createdAt']);
|
||||
|
||||
$lastLoginAt = array_key_exists('lastLoginAt', $data)
|
||||
? DT::toUTCDateTimeImmutable($data['lastLoginAt'])
|
||||
: null;
|
||||
|
||||
$passwordUpdatedAt = array_key_exists('passwordUpdatedAt', $data)
|
||||
? DT::toUTCDateTimeImmutable($data['passwordUpdatedAt'])
|
||||
: null;
|
||||
|
||||
$lastRefreshAt = array_key_exists('lastRefreshAt', $data)
|
||||
? DT::toUTCDateTimeImmutable($data['lastRefreshAt'])
|
||||
: null;
|
||||
|
||||
return new self($createdAt, $lastLoginAt, $passwordUpdatedAt, $lastRefreshAt);
|
||||
}
|
||||
}
|
||||
178
vendor/kreait/firebase-php/src/Firebase/Auth/UserQuery.php
vendored
Normal file
178
vendor/kreait/firebase-php/src/Firebase/Auth/UserQuery.php
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
use function array_filter;
|
||||
|
||||
/**
|
||||
* @see https://cloud.google.com/identity-platform/docs/reference/rest/v1/projects.accounts/query#request-body
|
||||
*
|
||||
* @phpstan-type UserQueryShape array{
|
||||
* sortBy?: self::FIELD_*,
|
||||
* order?: self::ORDER_*,
|
||||
* offset?: int<0, max>,
|
||||
* limit?: positive-int,
|
||||
* filter?: array<self::FILTER_*, non-empty-string>
|
||||
* }
|
||||
*/
|
||||
class UserQuery implements JsonSerializable
|
||||
{
|
||||
final public const FIELD_CREATED_AT = 'CREATED_AT';
|
||||
|
||||
final public const FIELD_LAST_LOGIN_AT = 'LAST_LOGIN_AT';
|
||||
|
||||
final public const FIELD_NAME = 'NAME';
|
||||
|
||||
final public const FIELD_USER_EMAIL = 'USER_EMAIL';
|
||||
|
||||
final public const FIELD_USER_ID = 'USER_ID';
|
||||
|
||||
final public const FILTER_EMAIL = 'email';
|
||||
|
||||
final public const FILTER_PHONE_NUMBER = 'phoneNumber';
|
||||
|
||||
final public const FILTER_USER_ID = 'userId';
|
||||
|
||||
final public const ORDER_ASC = 'ASC';
|
||||
|
||||
final public const ORDER_DESC = 'DESC';
|
||||
|
||||
final public const MAX_LIMIT = 500;
|
||||
|
||||
/**
|
||||
* @var positive-int|null
|
||||
*/
|
||||
private ?int $limit = null;
|
||||
|
||||
/**
|
||||
* @var int<0, max>|null
|
||||
*/
|
||||
private ?int $offset = null;
|
||||
|
||||
/**
|
||||
* @var self::FIELD_*|null
|
||||
*/
|
||||
private ?string $sortBy = null;
|
||||
|
||||
/**
|
||||
* @var self::ORDER_*|null
|
||||
*/
|
||||
private ?string $order = null;
|
||||
|
||||
/**
|
||||
* @var array<self::FILTER_*, non-empty-string>|null
|
||||
*/
|
||||
private ?array $filter = null;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public static function all(): self
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UserQueryShape $data
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$query = new self();
|
||||
|
||||
$query->sortBy = $data['sortBy'] ?? null;
|
||||
$query->order = $data['order'] ?? null;
|
||||
$query->offset = $data['offset'] ?? null;
|
||||
$query->limit = $data['limit'] ?? null;
|
||||
$query->filter = $data['filter'] ?? null;
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param self::FIELD_* $sortedBy
|
||||
*/
|
||||
public function sortedBy(string $sortedBy): self
|
||||
{
|
||||
$query = clone $this;
|
||||
$query->sortBy = $sortedBy;
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function inAscendingOrder(): self
|
||||
{
|
||||
return $this->withOrder(self::ORDER_ASC);
|
||||
}
|
||||
|
||||
public function inDescendingOrder(): self
|
||||
{
|
||||
return $this->withOrder(self::ORDER_DESC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int<0, max> $offset
|
||||
*/
|
||||
public function withOffset(int $offset): self
|
||||
{
|
||||
$query = clone $this;
|
||||
$query->offset = $offset;
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param positive-int $limit
|
||||
*/
|
||||
public function withLimit(int $limit): self
|
||||
{
|
||||
$query = clone $this;
|
||||
$query->limit = $limit;
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param self::FILTER_* $field
|
||||
* @param non-empty-string $value
|
||||
*/
|
||||
public function withFilter(string $field, string $value): self
|
||||
{
|
||||
$query = clone $this;
|
||||
$query->filter = [$field => $value];
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
$data = array_filter([
|
||||
'returnUserInfo' => true,
|
||||
'limit' => $this->limit,
|
||||
'offset' => $this->offset,
|
||||
'sortBy' => $this->sortBy,
|
||||
'order' => $this->order,
|
||||
], fn(int|bool|null|string $value): bool => $value !== null);
|
||||
|
||||
if ($this->filter !== null) {
|
||||
$data['expression'] = $this->filter;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param self::ORDER_* $direction
|
||||
*/
|
||||
private function withOrder(string $direction): self
|
||||
{
|
||||
$query = clone $this;
|
||||
$query->order = $direction;
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
151
vendor/kreait/firebase-php/src/Firebase/Auth/UserRecord.php
vendored
Normal file
151
vendor/kreait/firebase-php/src/Firebase/Auth/UserRecord.php
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Auth;
|
||||
|
||||
use Beste\Json;
|
||||
use DateTimeImmutable;
|
||||
use Kreait\Firebase\Util\DT;
|
||||
|
||||
use function array_key_exists;
|
||||
use function array_map;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type ProviderUserInfoResponseShape from UserInfo
|
||||
* @phpstan-import-type UserMetadataResponseShape from UserMetaData
|
||||
* @phpstan-import-type MfaInfoResponseShape from MfaInfo
|
||||
*
|
||||
* @phpstan-type UserRecordResponseShape array{
|
||||
* localId: non-empty-string,
|
||||
* email?: non-empty-string,
|
||||
* emailVerified?: bool,
|
||||
* displayName?: non-empty-string,
|
||||
* photoUrl?: non-empty-string,
|
||||
* phoneNumber?: non-empty-string,
|
||||
* disabled?: bool,
|
||||
* passwordHash?: non-empty-string,
|
||||
* salt?: non-empty-string,
|
||||
* customAttributes?: non-empty-string,
|
||||
* tenantId?: non-empty-string,
|
||||
* providerUserInfo?: list<ProviderUserInfoResponseShape>,
|
||||
* mfaInfo?: list<MfaInfoResponseShape>,
|
||||
* createdAt: non-empty-string,
|
||||
* lastLoginAt?: non-empty-string,
|
||||
* passwordUpdatedAt?: non-empty-string,
|
||||
* lastRefreshAt?: non-empty-string,
|
||||
* validSince?: non-empty-string
|
||||
* }
|
||||
*/
|
||||
final class UserRecord
|
||||
{
|
||||
/**
|
||||
* @param non-empty-string $uid
|
||||
* @param non-empty-string|null $email
|
||||
* @param non-empty-string|null $displayName
|
||||
* @param non-empty-string|null $phoneNumber
|
||||
* @param non-empty-string|null $photoUrl
|
||||
* @param list<UserInfo> $providerData
|
||||
* @param non-empty-string|null $passwordHash
|
||||
* @param non-empty-string|null $passwordSalt
|
||||
* @param array<non-empty-string, mixed> $customClaims
|
||||
* @param non-empty-string|null $tenantId
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly string $uid,
|
||||
public readonly ?string $email,
|
||||
public readonly bool $emailVerified,
|
||||
public readonly ?string $displayName,
|
||||
public readonly ?string $phoneNumber,
|
||||
public readonly ?string $photoUrl,
|
||||
public readonly bool $disabled,
|
||||
public readonly UserMetaData $metadata,
|
||||
public readonly array $providerData,
|
||||
public readonly ?MfaInfo $mfaInfo,
|
||||
public readonly ?string $passwordHash,
|
||||
public readonly ?string $passwordSalt,
|
||||
public readonly array $customClaims,
|
||||
public readonly ?string $tenantId,
|
||||
public readonly ?DateTimeImmutable $tokensValidAfterTime,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @param UserRecordResponseShape $data
|
||||
*/
|
||||
public static function fromResponseData(array $data): self
|
||||
{
|
||||
$validSince = array_key_exists('validSince', $data)
|
||||
? DT::toUTCDateTimeImmutable($data['validSince'])
|
||||
: null;
|
||||
|
||||
$customClaims = array_key_exists('customAttributes', $data)
|
||||
? Json::decode($data['customAttributes'], true)
|
||||
: [];
|
||||
|
||||
$providerUserInfo = array_key_exists('providerUserInfo', $data)
|
||||
? self::userInfoFromResponseData($data)
|
||||
: [];
|
||||
|
||||
return new self(
|
||||
$data['localId'],
|
||||
$data['email'] ?? null,
|
||||
$data['emailVerified'] ?? false,
|
||||
$data['displayName'] ?? null,
|
||||
$data['phoneNumber'] ?? null,
|
||||
$data['photoUrl'] ?? null,
|
||||
$data['disabled'] ?? false,
|
||||
self::userMetaDataFromResponseData($data),
|
||||
$providerUserInfo,
|
||||
self::mfaInfoFromResponseData($data),
|
||||
$data['passwordHash'] ?? null,
|
||||
$data['salt'] ?? null,
|
||||
$customClaims,
|
||||
$data['tenantId'] ?? null,
|
||||
$validSince,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UserMetadataResponseShape $data
|
||||
*/
|
||||
private static function userMetaDataFromResponseData(array $data): UserMetaData
|
||||
{
|
||||
return UserMetaData::fromResponseData($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{
|
||||
* mfaInfo?: list<MfaInfoResponseShape>
|
||||
* } $data
|
||||
*/
|
||||
private static function mfaInfoFromResponseData(array $data): ?MfaInfo
|
||||
{
|
||||
if (!array_key_exists('mfaInfo', $data)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$mfaInfo = array_shift($data['mfaInfo']);
|
||||
|
||||
if ($mfaInfo === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return MfaInfo::fromResponseData($mfaInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{providerUserInfo: list<ProviderUserInfoResponseShape>} $data
|
||||
*
|
||||
* @return list<UserInfo>
|
||||
*/
|
||||
private static function userInfoFromResponseData(array $data): array
|
||||
{
|
||||
return array_map(
|
||||
static fn(array $userInfoData): UserInfo => UserInfo::fromResponseData($userInfoData),
|
||||
$data['providerUserInfo'],
|
||||
);
|
||||
}
|
||||
}
|
||||
39
vendor/kreait/firebase-php/src/Firebase/Contract/AppCheck.php
vendored
Normal file
39
vendor/kreait/firebase-php/src/Firebase/Contract/AppCheck.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Contract;
|
||||
|
||||
use Kreait\Firebase\AppCheck\AppCheckToken;
|
||||
use Kreait\Firebase\AppCheck\AppCheckTokenOptions;
|
||||
use Kreait\Firebase\AppCheck\VerifyAppCheckTokenResponse;
|
||||
use Kreait\Firebase\Exception;
|
||||
use Kreait\Firebase\Exception\AppCheck\FailedToVerifyAppCheckToken;
|
||||
use Kreait\Firebase\Exception\AppCheck\InvalidAppCheckToken;
|
||||
use Kreait\Firebase\Exception\AppCheck\InvalidAppCheckTokenOptions;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type AppCheckTokenOptionsShape from AppCheckTokenOptions
|
||||
*/
|
||||
interface AppCheck
|
||||
{
|
||||
/**
|
||||
* @param non-empty-string $appId
|
||||
* @param AppCheckTokenOptions|AppCheckTokenOptionsShape|null $options
|
||||
*
|
||||
* @throws InvalidAppCheckTokenOptions
|
||||
* @throws Exception\AppCheckException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function createToken(string $appId, $options = null): AppCheckToken;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $appCheckToken
|
||||
*
|
||||
* @throws InvalidAppCheckToken
|
||||
* @throws FailedToVerifyAppCheckToken
|
||||
* @throws Exception\AppCheckException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function verifyToken(string $appCheckToken): VerifyAppCheckTokenResponse;
|
||||
}
|
||||
463
vendor/kreait/firebase-php/src/Firebase/Contract/Auth.php
vendored
Normal file
463
vendor/kreait/firebase-php/src/Firebase/Contract/Auth.php
vendored
Normal file
@@ -0,0 +1,463 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Contract;
|
||||
|
||||
use DateInterval;
|
||||
use InvalidArgumentException;
|
||||
use Kreait\Firebase\Auth\ActionCodeSettings;
|
||||
use Kreait\Firebase\Auth\CreateActionLink\FailedToCreateActionLink;
|
||||
use Kreait\Firebase\Auth\CreateSessionCookie\FailedToCreateSessionCookie;
|
||||
use Kreait\Firebase\Auth\DeleteUsersResult;
|
||||
use Kreait\Firebase\Auth\SendActionLink\FailedToSendActionLink;
|
||||
use Kreait\Firebase\Auth\SignIn\FailedToSignIn;
|
||||
use Kreait\Firebase\Auth\SignInResult;
|
||||
use Kreait\Firebase\Auth\UserQuery;
|
||||
use Kreait\Firebase\Auth\UserRecord;
|
||||
use Kreait\Firebase\Exception;
|
||||
use Kreait\Firebase\Exception\Auth\ExpiredOobCode;
|
||||
use Kreait\Firebase\Exception\Auth\FailedToVerifySessionCookie;
|
||||
use Kreait\Firebase\Exception\Auth\FailedToVerifyToken;
|
||||
use Kreait\Firebase\Exception\Auth\InvalidOobCode;
|
||||
use Kreait\Firebase\Exception\Auth\OperationNotAllowed;
|
||||
use Kreait\Firebase\Exception\Auth\RevokedIdToken;
|
||||
use Kreait\Firebase\Exception\Auth\RevokedSessionCookie;
|
||||
use Kreait\Firebase\Exception\Auth\UserDisabled;
|
||||
use Kreait\Firebase\Exception\Auth\UserNotFound;
|
||||
use Kreait\Firebase\Request\CreateUser;
|
||||
use Kreait\Firebase\Request\UpdateUser;
|
||||
use Lcobucci\JWT\Token;
|
||||
use Lcobucci\JWT\UnencryptedToken;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Stringable;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type UserQueryShape from UserQuery
|
||||
*/
|
||||
interface Auth
|
||||
{
|
||||
/**
|
||||
* @param Stringable|non-empty-string $uid
|
||||
*
|
||||
* @throws UserNotFound
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function getUser(Stringable|string $uid): UserRecord;
|
||||
|
||||
/**
|
||||
* @param non-empty-list<Stringable|non-empty-string> $uids
|
||||
*
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*
|
||||
* @return array<non-empty-string, UserRecord|null>
|
||||
*/
|
||||
public function getUsers(array $uids): array;
|
||||
|
||||
/**
|
||||
* @param UserQuery|UserQueryShape $query
|
||||
*
|
||||
* @throws Exception\FirebaseException
|
||||
* @throws Exception\AuthException
|
||||
*
|
||||
* @return array<non-empty-string, UserRecord>
|
||||
*/
|
||||
public function queryUsers(UserQuery|array $query): array;
|
||||
|
||||
/**
|
||||
* @param positive-int $maxResults
|
||||
* @param positive-int $batchSize
|
||||
*
|
||||
* @throws Exception\FirebaseException
|
||||
* @throws Exception\AuthException
|
||||
*
|
||||
* @return Traversable<UserRecord>
|
||||
*/
|
||||
public function listUsers(int $maxResults = 1000, int $batchSize = 1000): Traversable;
|
||||
|
||||
/**
|
||||
* Creates a new user with the provided properties.
|
||||
*
|
||||
* @param array<non-empty-string, mixed>|CreateUser $properties
|
||||
*
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function createUser(array|CreateUser $properties): UserRecord;
|
||||
|
||||
/**
|
||||
* Updates the given user with the given properties.
|
||||
*
|
||||
* @param non-empty-array<non-empty-string, mixed>|UpdateUser $properties
|
||||
*
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function updateUser(Stringable|string $uid, array|UpdateUser $properties): UserRecord;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $email
|
||||
* @param Stringable|non-empty-string $password
|
||||
*
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function createUserWithEmailAndPassword(Stringable|string $email, Stringable|string $password): UserRecord;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $email
|
||||
*
|
||||
* @throws UserNotFound
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function getUserByEmail(Stringable|string $email): UserRecord;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $phoneNumber
|
||||
*
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function getUserByPhoneNumber(Stringable|string $phoneNumber): UserRecord;
|
||||
|
||||
/**
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function createAnonymousUser(): UserRecord;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $uid
|
||||
* @param Stringable|non-empty-string $newPassword
|
||||
*
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function changeUserPassword(Stringable|string $uid, Stringable|string $newPassword): UserRecord;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $uid
|
||||
* @param Stringable|non-empty-string $newEmail
|
||||
*
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function changeUserEmail(Stringable|string $uid, Stringable|string $newEmail): UserRecord;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $uid
|
||||
*
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function enableUser(Stringable|string $uid): UserRecord;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $uid
|
||||
*
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function disableUser(Stringable|string $uid): UserRecord;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $uid
|
||||
*
|
||||
* @throws UserNotFound
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function deleteUser(Stringable|string $uid): void;
|
||||
|
||||
/**
|
||||
* @param iterable<Stringable|non-empty-string> $uids
|
||||
* @param bool $forceDeleteEnabledUsers Whether to force deleting accounts that are not in disabled state. If false, only disabled accounts will be deleted, and accounts that are not disabled will be added to the errors.
|
||||
*
|
||||
* @throws Exception\AuthException
|
||||
*/
|
||||
public function deleteUsers(iterable $uids, bool $forceDeleteEnabledUsers = false): DeleteUsersResult;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $type
|
||||
* @param Stringable|non-empty-string $email
|
||||
* @param ActionCodeSettings|array<non-empty-string, mixed>|null $actionCodeSettings
|
||||
* @param non-empty-string|null $locale
|
||||
*
|
||||
* @throws FailedToCreateActionLink
|
||||
*/
|
||||
public function getEmailActionLink(string $type, Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): string;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $type
|
||||
* @param Stringable|non-empty-string $email
|
||||
* @param ActionCodeSettings|array<non-empty-string, mixed>|null $actionCodeSettings
|
||||
* @param non-empty-string|null $locale
|
||||
*
|
||||
* @throws UserNotFound
|
||||
* @throws FailedToSendActionLink
|
||||
*/
|
||||
public function sendEmailActionLink(string $type, Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): void;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $email
|
||||
* @param ActionCodeSettings|array<non-empty-string, mixed>|null $actionCodeSettings
|
||||
* @param non-empty-string|null $locale
|
||||
*
|
||||
* @throws FailedToCreateActionLink
|
||||
*/
|
||||
public function getEmailVerificationLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): string;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $email
|
||||
* @param ActionCodeSettings|array<non-empty-string, mixed>|null $actionCodeSettings
|
||||
* @param non-empty-string|null $locale
|
||||
*
|
||||
* @throws FailedToSendActionLink
|
||||
*/
|
||||
public function sendEmailVerificationLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): void;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $email
|
||||
* @param ActionCodeSettings|array<non-empty-string, mixed>|null $actionCodeSettings
|
||||
* @param non-empty-string|null $locale
|
||||
*
|
||||
* @throws FailedToCreateActionLink
|
||||
*/
|
||||
public function getPasswordResetLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): string;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $email
|
||||
* @param ActionCodeSettings|array<non-empty-string, mixed>|null $actionCodeSettings
|
||||
* @param non-empty-string|null $locale
|
||||
*
|
||||
* @throws FailedToSendActionLink
|
||||
*/
|
||||
public function sendPasswordResetLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): void;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $email
|
||||
* @param ActionCodeSettings|array<non-empty-string, mixed>|null $actionCodeSettings
|
||||
* @param non-empty-string|null $locale
|
||||
*
|
||||
* @throws FailedToCreateActionLink
|
||||
*/
|
||||
public function getSignInWithEmailLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): string;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $email
|
||||
* @param ActionCodeSettings|array<non-empty-string, mixed>|null $actionCodeSettings
|
||||
* @param non-empty-string|null $locale
|
||||
*
|
||||
* @throws FailedToSendActionLink
|
||||
*/
|
||||
public function sendSignInWithEmailLink(Stringable|string $email, $actionCodeSettings = null, ?string $locale = null): void;
|
||||
|
||||
/**
|
||||
* Sets additional developer claims on an existing user identified by the provided UID.
|
||||
*
|
||||
* @see https://firebase.google.com/docs/auth/admin/custom-claims
|
||||
*
|
||||
* @param Stringable|non-empty-string $uid
|
||||
* @param array<non-empty-string, mixed>|null $claims
|
||||
*
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function setCustomUserClaims(Stringable|string $uid, ?array $claims): void;
|
||||
|
||||
/**
|
||||
* @param array<non-empty-string, mixed> $claims
|
||||
* @param int<0, 3600>|DateInterval|non-empty-string $ttl
|
||||
*
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function createCustomToken(Stringable|string $uid, array $claims = [], int|DateInterval|string $ttl = 3600): UnencryptedToken;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $tokenString
|
||||
*/
|
||||
public function parseToken(string $tokenString): UnencryptedToken;
|
||||
|
||||
/**
|
||||
* Creates a new Firebase session cookie with the given lifetime.
|
||||
*
|
||||
* The session cookie JWT will have the same payload claims as the provided ID token.
|
||||
*
|
||||
* @param Token|non-empty-string $idToken The Firebase ID token to exchange for a session cookie
|
||||
* @param DateInterval|positive-int $ttl
|
||||
*
|
||||
* @throws InvalidArgumentException if the token or TTL is invalid
|
||||
* @throws FailedToCreateSessionCookie
|
||||
*/
|
||||
public function createSessionCookie(Token|string $idToken, DateInterval|int $ttl): string;
|
||||
|
||||
/**
|
||||
* Verifies a JWT auth token.
|
||||
*
|
||||
* Returns a token with the token's claims or rejects it if the token could not be verified.
|
||||
*
|
||||
* If checkRevoked is set to true, verifies if the session corresponding to the ID token was revoked.
|
||||
* If the corresponding user's session was invalidated, a RevokedIdToken exception is thrown.
|
||||
* If not specified the check is not applied.
|
||||
*
|
||||
* NOTE: Allowing time inconsistencies might impose a security risk. Do this only when you are not able
|
||||
* to fix your environment's time to be consistent with Google's servers.
|
||||
*
|
||||
* @param Token|non-empty-string $idToken the JWT to verify
|
||||
* @param bool $checkIfRevoked whether to check if the ID token is revoked
|
||||
* @param positive-int|null $leewayInSeconds number of seconds to allow a token to be expired, in case that there
|
||||
* is a clock skew between the signing and the verifying server
|
||||
*
|
||||
* @throws FailedToVerifyToken if the token could not be verified
|
||||
* @throws RevokedIdToken if the token has been revoked
|
||||
*/
|
||||
public function verifyIdToken(Token|string $idToken, bool $checkIfRevoked = false, ?int $leewayInSeconds = null): UnencryptedToken;
|
||||
|
||||
/**
|
||||
* Verifies a JWT session cookie.
|
||||
*
|
||||
* Returns a token with the cookie's claims or rejects it if the session cookie could not be verified.
|
||||
*
|
||||
* If checkRevoked is set to true, verifies if the session corresponding to the ID token was revoked.
|
||||
* If the corresponding user's session was invalidated, a RevokedSessionCookie exception is thrown.
|
||||
* If not specified the check is not applied.
|
||||
*
|
||||
* NOTE: Allowing time inconsistencies might impose a security risk. Do this only when you are not able
|
||||
* to fix your environment's time to be consistent with Google's servers.
|
||||
*
|
||||
* @param non-empty-string $sessionCookie
|
||||
* @param positive-int|null $leewayInSeconds
|
||||
*
|
||||
* @throws FailedToVerifySessionCookie
|
||||
* @throws RevokedSessionCookie
|
||||
*/
|
||||
public function verifySessionCookie(string $sessionCookie, bool $checkIfRevoked = false, ?int $leewayInSeconds = null): UnencryptedToken;
|
||||
|
||||
/**
|
||||
* Verifies the given password reset code and returns the associated user's email address.
|
||||
*
|
||||
* @see https://firebase.google.com/docs/reference/rest/auth#section-verify-password-reset-code
|
||||
*
|
||||
* @param non-empty-string $oobCode
|
||||
*
|
||||
* @throws ExpiredOobCode
|
||||
* @throws InvalidOobCode
|
||||
* @throws OperationNotAllowed
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function verifyPasswordResetCode(string $oobCode): string;
|
||||
|
||||
/**
|
||||
* Applies the password reset requested via the given OOB code and returns the associated user's email address.
|
||||
*
|
||||
* @see https://firebase.google.com/docs/reference/rest/auth#section-confirm-reset-password
|
||||
*
|
||||
* @param non-empty-string $oobCode the email action code sent to the user's email for resetting the password
|
||||
* @param Stringable|non-empty-string $newPassword
|
||||
* @param bool $invalidatePreviousSessions Invalidate sessions initialized with the previous credentials
|
||||
*
|
||||
* @throws ExpiredOobCode
|
||||
* @throws InvalidOobCode
|
||||
* @throws OperationNotAllowed
|
||||
* @throws UserDisabled
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function confirmPasswordReset(string $oobCode, Stringable|string $newPassword, bool $invalidatePreviousSessions = true): string;
|
||||
|
||||
/**
|
||||
* Revokes all refresh tokens for the specified user identified by the uid provided.
|
||||
* In addition to revoking all refresh tokens for a user, all ID tokens issued
|
||||
* before revocation will also be revoked on the Auth backend. Any request with an
|
||||
* ID token generated before revocation will be rejected with a token expired error.
|
||||
*
|
||||
* @param Stringable|string $uid the user whose tokens are to be revoked
|
||||
*
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function revokeRefreshTokens(Stringable|string $uid): void;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $uid
|
||||
* @param list<Stringable|non-empty-string>|Stringable|non-empty-string $provider
|
||||
*
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function unlinkProvider(Stringable|string $uid, array|Stringable|string $provider): UserRecord;
|
||||
|
||||
/**
|
||||
* @param UserRecord|Stringable|non-empty-string $user
|
||||
* @param array<non-empty-string, mixed>|null $claims
|
||||
*
|
||||
* @throws FailedToSignIn
|
||||
*/
|
||||
public function signInAsUser(UserRecord|Stringable|string $user, ?array $claims = null): SignInResult;
|
||||
|
||||
/**
|
||||
* @param Token|non-empty-string $token
|
||||
*
|
||||
* @throws FailedToSignIn
|
||||
*/
|
||||
public function signInWithCustomToken(Token|string $token): SignInResult;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $refreshToken
|
||||
*
|
||||
* @throws FailedToSignIn
|
||||
*/
|
||||
public function signInWithRefreshToken(string $refreshToken): SignInResult;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $email
|
||||
* @param Stringable|non-empty-string $clearTextPassword
|
||||
*
|
||||
* @throws FailedToSignIn
|
||||
*/
|
||||
public function signInWithEmailAndPassword(Stringable|string $email, Stringable|string $clearTextPassword): SignInResult;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $email
|
||||
* @param non-empty-string $oobCode
|
||||
*
|
||||
* @throws FailedToSignIn
|
||||
*/
|
||||
public function signInWithEmailAndOobCode(Stringable|string $email, string $oobCode): SignInResult;
|
||||
|
||||
/**
|
||||
* @throws FailedToSignIn
|
||||
*/
|
||||
public function signInAnonymously(): SignInResult;
|
||||
|
||||
/**
|
||||
* @see https://cloud.google.com/identity-platform/docs/reference/rest/v1/accounts/signInWithIdp
|
||||
*
|
||||
* @param Stringable|non-empty-string $provider
|
||||
* @param non-empty-string $accessToken
|
||||
* @param UriInterface|non-empty-string|null $redirectUrl
|
||||
* @param non-empty-string|null $oauthTokenSecret
|
||||
* @param non-empty-string|null $linkingIdToken
|
||||
* @param non-empty-string|null $rawNonce
|
||||
*
|
||||
* @throws FailedToSignIn
|
||||
*/
|
||||
public function signInWithIdpAccessToken(Stringable|string $provider, string $accessToken, $redirectUrl = null, ?string $oauthTokenSecret = null, ?string $linkingIdToken = null, ?string $rawNonce = null): SignInResult;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $provider
|
||||
* @param Token|non-empty-string $idToken
|
||||
* @param UriInterface|non-empty-string|null $redirectUrl
|
||||
* @param non-empty-string|null $linkingIdToken
|
||||
* @param non-empty-string|null $rawNonce
|
||||
*
|
||||
* @throws FailedToSignIn
|
||||
*/
|
||||
public function signInWithIdpIdToken(Stringable|string $provider, Token|string $idToken, $redirectUrl = null, ?string $linkingIdToken = null, ?string $rawNonce = null): SignInResult;
|
||||
}
|
||||
63
vendor/kreait/firebase-php/src/Firebase/Contract/Database.php
vendored
Normal file
63
vendor/kreait/firebase-php/src/Firebase/Contract/Database.php
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Contract;
|
||||
|
||||
use Kreait\Firebase\Database\Reference;
|
||||
use Kreait\Firebase\Database\RuleSet;
|
||||
use Kreait\Firebase\Database\Transaction;
|
||||
use Kreait\Firebase\Exception\DatabaseException;
|
||||
use Kreait\Firebase\Exception\InvalidArgumentException;
|
||||
use Kreait\Firebase\Exception\OutOfRangeException;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* The Firebase Realtime Database.
|
||||
*
|
||||
* @see https://firebase.google.com/docs/reference/rest/database
|
||||
*/
|
||||
interface Database
|
||||
{
|
||||
public const SERVER_TIMESTAMP = ['.sv' => 'timestamp'];
|
||||
|
||||
/**
|
||||
* Returns a Reference to the root or the specified path.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function getReference(?string $path = null): Reference;
|
||||
|
||||
/**
|
||||
* Returns a reference to the root or the path specified in url.
|
||||
*
|
||||
* @param string|UriInterface $uri
|
||||
*
|
||||
* @throws InvalidArgumentException If the URL is invalid
|
||||
* @throws OutOfRangeException If the URL is not in the same domain as the current database
|
||||
*/
|
||||
public function getReferenceFromUrl($uri): Reference;
|
||||
|
||||
/**
|
||||
* Retrieve Firebase Database Rules.
|
||||
*
|
||||
* @see https://firebase.google.com/docs/database/rest/app-management#retrieving-firebase-realtime-database-rules
|
||||
*
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function getRuleSet(): RuleSet;
|
||||
|
||||
/**
|
||||
* Update Firebase Database Rules.
|
||||
*
|
||||
* @see https://firebase.google.com/docs/database/rest/app-management#updating-firebase-realtime-database-rules
|
||||
*
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function updateRules(RuleSet $ruleSet): void;
|
||||
|
||||
/**
|
||||
* @param callable(Transaction $transaction):mixed $callable
|
||||
*/
|
||||
public function runTransaction(callable $callable): mixed;
|
||||
}
|
||||
68
vendor/kreait/firebase-php/src/Firebase/Contract/DynamicLinks.php
vendored
Normal file
68
vendor/kreait/firebase-php/src/Firebase/Contract/DynamicLinks.php
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Contract;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Kreait\Firebase\DynamicLink;
|
||||
use Kreait\Firebase\DynamicLink\CreateDynamicLink;
|
||||
use Kreait\Firebase\DynamicLink\CreateDynamicLink\FailedToCreateDynamicLink;
|
||||
use Kreait\Firebase\DynamicLink\DynamicLinkStatistics;
|
||||
use Kreait\Firebase\DynamicLink\GetStatisticsForDynamicLink;
|
||||
use Kreait\Firebase\DynamicLink\ShortenLongDynamicLink;
|
||||
use Kreait\Firebase\DynamicLink\ShortenLongDynamicLink\FailedToShortenLongDynamicLink;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
* @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
|
||||
*
|
||||
* @see https://firebase.google.com/docs/dynamic-links/rest Create Dynamic Links with the REST API
|
||||
*
|
||||
* @phpstan-import-type CreateDynamicLinkShape from CreateDynamicLink
|
||||
* @phpstan-import-type ShortenLongDynamicLinkShape from ShortenLongDynamicLink
|
||||
*/
|
||||
interface DynamicLinks
|
||||
{
|
||||
/**
|
||||
* @param Stringable|non-empty-string|CreateDynamicLink|CreateDynamicLinkShape $url
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws FailedToCreateDynamicLink
|
||||
*/
|
||||
public function createUnguessableLink(Stringable|string|CreateDynamicLink|array $url): DynamicLink;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string|CreateDynamicLink|CreateDynamicLinkShape $url
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws FailedToCreateDynamicLink
|
||||
*/
|
||||
public function createShortLink(Stringable|string|CreateDynamicLink|array $url): DynamicLink;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string|CreateDynamicLink|CreateDynamicLinkShape $actionOrParametersOrUrl
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws FailedToCreateDynamicLink
|
||||
*/
|
||||
public function createDynamicLink(Stringable|string|CreateDynamicLink|array $actionOrParametersOrUrl, ?string $suffixType = null): DynamicLink;
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string|ShortenLongDynamicLink|ShortenLongDynamicLinkShape $longDynamicLinkOrAction
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
* @throws FailedToShortenLongDynamicLink
|
||||
*/
|
||||
public function shortenLongDynamicLink(Stringable|string|ShortenLongDynamicLink|array $longDynamicLinkOrAction, ?string $suffixType = null): DynamicLink;
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
* @throws GetStatisticsForDynamicLink\FailedToGetStatisticsForDynamicLink
|
||||
*/
|
||||
public function getStatistics(Stringable|string|GetStatisticsForDynamicLink $dynamicLinkOrAction, ?int $durationInDays = null): DynamicLinkStatistics;
|
||||
}
|
||||
12
vendor/kreait/firebase-php/src/Firebase/Contract/Firestore.php
vendored
Normal file
12
vendor/kreait/firebase-php/src/Firebase/Contract/Firestore.php
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Contract;
|
||||
|
||||
use Google\Cloud\Firestore\FirestoreClient;
|
||||
|
||||
interface Firestore
|
||||
{
|
||||
public function database(): FirestoreClient;
|
||||
}
|
||||
134
vendor/kreait/firebase-php/src/Firebase/Contract/Messaging.php
vendored
Normal file
134
vendor/kreait/firebase-php/src/Firebase/Contract/Messaging.php
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Contract;
|
||||
|
||||
use Kreait\Firebase\Exception\FirebaseException;
|
||||
use Kreait\Firebase\Exception\InvalidArgumentException;
|
||||
use Kreait\Firebase\Exception\Messaging\InvalidArgument;
|
||||
use Kreait\Firebase\Exception\Messaging\InvalidMessage;
|
||||
use Kreait\Firebase\Exception\MessagingException;
|
||||
use Kreait\Firebase\Messaging\AppInstance;
|
||||
use Kreait\Firebase\Messaging\Message;
|
||||
use Kreait\Firebase\Messaging\Messages;
|
||||
use Kreait\Firebase\Messaging\MulticastSendReport;
|
||||
use Kreait\Firebase\Messaging\RegistrationToken;
|
||||
use Kreait\Firebase\Messaging\RegistrationTokens;
|
||||
use Kreait\Firebase\Messaging\Topic;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type MessageInputShape from Message
|
||||
*/
|
||||
interface Messaging
|
||||
{
|
||||
/**
|
||||
* @deprecated 7.5.0
|
||||
*/
|
||||
public const BATCH_MESSAGE_LIMIT = 500;
|
||||
|
||||
/**
|
||||
* @param Message|MessageInputShape $message
|
||||
*
|
||||
* @throws MessagingException
|
||||
* @throws FirebaseException
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return array<array-key, mixed>
|
||||
*/
|
||||
public function send(Message|array $message, bool $validateOnly = false): array;
|
||||
|
||||
/**
|
||||
* @param Message|MessageInputShape $message
|
||||
* @param RegistrationTokens|RegistrationToken|list<RegistrationToken|string>|non-empty-string $registrationTokens
|
||||
*
|
||||
* @throws InvalidArgumentException if the message is invalid or the list of registration tokens is empty
|
||||
* @throws MessagingException if the API request failed
|
||||
* @throws FirebaseException if something very unexpected happened (never :))
|
||||
*/
|
||||
public function sendMulticast(Message|array $message, RegistrationTokens|RegistrationToken|array|string $registrationTokens, bool $validateOnly = false): MulticastSendReport;
|
||||
|
||||
/**
|
||||
* @param list<Message|MessageInputShape>|Messages $messages
|
||||
*
|
||||
* @throws InvalidArgumentException if the message is invalid
|
||||
* @throws MessagingException if the API request failed
|
||||
* @throws FirebaseException if something very unexpected happened (never :))
|
||||
*/
|
||||
public function sendAll(array|Messages $messages, bool $validateOnly = false): MulticastSendReport;
|
||||
|
||||
/**
|
||||
* @param Message|MessageInputShape $message
|
||||
*
|
||||
* @throws InvalidMessage
|
||||
* @throws MessagingException
|
||||
* @throws FirebaseException
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @return array<non-empty-string, mixed>
|
||||
*/
|
||||
public function validate(Message|array $message): array;
|
||||
|
||||
/**
|
||||
* @param RegistrationTokens|RegistrationToken|list<RegistrationToken|non-empty-string>|non-empty-string $registrationTokenOrTokens
|
||||
*
|
||||
* @throws MessagingException
|
||||
* @throws FirebaseException
|
||||
*
|
||||
* @return array{
|
||||
* valid: list<non-empty-string>,
|
||||
* unknown: list<non-empty-string>,
|
||||
* invalid: list<non-empty-string>
|
||||
* }
|
||||
*/
|
||||
public function validateRegistrationTokens(RegistrationTokens|RegistrationToken|array|string $registrationTokenOrTokens): array;
|
||||
|
||||
/**
|
||||
* @param Topic|non-empty-string $topic
|
||||
* @param RegistrationTokens|RegistrationToken|list<RegistrationToken|non-empty-string>|non-empty-string $registrationTokenOrTokens
|
||||
*
|
||||
* @return array<string, array<string, string>>
|
||||
*/
|
||||
public function subscribeToTopic(string|Topic $topic, RegistrationTokens|RegistrationToken|array|string $registrationTokenOrTokens): array;
|
||||
|
||||
/**
|
||||
* @param iterable<non-empty-string|Topic> $topics
|
||||
* @param RegistrationTokens|RegistrationToken|list<RegistrationToken|non-empty-string>|non-empty-string $registrationTokenOrTokens
|
||||
*
|
||||
* @return array<string, array<string, string>>
|
||||
*/
|
||||
public function subscribeToTopics(iterable $topics, RegistrationTokens|RegistrationToken|array|string $registrationTokenOrTokens): array;
|
||||
|
||||
/**
|
||||
* @param Topic|non-empty-string $topic
|
||||
* @param RegistrationTokens|RegistrationToken|list<RegistrationToken|non-empty-string>|non-empty-string $registrationTokenOrTokens
|
||||
*
|
||||
* @return array<string, array<string, string>>
|
||||
*/
|
||||
public function unsubscribeFromTopic(string|Topic $topic, RegistrationTokens|RegistrationToken|array|string $registrationTokenOrTokens): array;
|
||||
|
||||
/**
|
||||
* @param array<non-empty-string|Topic> $topics
|
||||
* @param RegistrationTokens|RegistrationToken|list<RegistrationToken|non-empty-string>|non-empty-string $registrationTokenOrTokens
|
||||
*
|
||||
* @return array<string, array<string, string>>
|
||||
*/
|
||||
public function unsubscribeFromTopics(array $topics, RegistrationTokens|RegistrationToken|array|string $registrationTokenOrTokens): array;
|
||||
|
||||
/**
|
||||
* @param RegistrationTokens|RegistrationToken|list<RegistrationToken|non-empty-string>|non-empty-string $registrationTokenOrTokens
|
||||
*
|
||||
* @return array<string, array<string, string>>
|
||||
*/
|
||||
public function unsubscribeFromAllTopics(RegistrationTokens|RegistrationToken|array|string $registrationTokenOrTokens): array;
|
||||
|
||||
/**
|
||||
* @see https://developers.google.com/instance-id/reference/server#results
|
||||
*
|
||||
* @param RegistrationToken|non-empty-string $registrationToken
|
||||
*
|
||||
* @throws InvalidArgument if the registration token is invalid
|
||||
* @throws MessagingException
|
||||
*/
|
||||
public function getAppInstance(RegistrationToken|string $registrationToken): AppInstance;
|
||||
}
|
||||
81
vendor/kreait/firebase-php/src/Firebase/Contract/RemoteConfig.php
vendored
Normal file
81
vendor/kreait/firebase-php/src/Firebase/Contract/RemoteConfig.php
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Contract;
|
||||
|
||||
use Kreait\Firebase\Exception\RemoteConfig\ValidationFailed;
|
||||
use Kreait\Firebase\Exception\RemoteConfig\VersionNotFound;
|
||||
use Kreait\Firebase\Exception\RemoteConfigException;
|
||||
use Kreait\Firebase\RemoteConfig\FindVersions;
|
||||
use Kreait\Firebase\RemoteConfig\Template;
|
||||
use Kreait\Firebase\RemoteConfig\Version;
|
||||
use Kreait\Firebase\RemoteConfig\VersionNumber;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
* The Firebase Remote Config.
|
||||
*
|
||||
* @see https://firebase.google.com/docs/remote-config/use-config-rest
|
||||
* @see https://firebase.google.com/docs/reference/remote-config/rest
|
||||
*
|
||||
* @phpstan-import-type RemoteConfigTemplateShape from Template
|
||||
* @phpstan-import-type FindVersionsShape from FindVersions
|
||||
*/
|
||||
interface RemoteConfig
|
||||
{
|
||||
/**
|
||||
* @param Version|VersionNumber|positive-int|non-empty-string $versionNumber
|
||||
*
|
||||
* @throws RemoteConfigException if something went wrong
|
||||
*/
|
||||
public function get(Version|VersionNumber|int|string|null $versionNumber = null): Template;
|
||||
|
||||
/**
|
||||
* Validates the given template without publishing it.
|
||||
*
|
||||
* @param Template|RemoteConfigTemplateShape $template
|
||||
*
|
||||
* @throws ValidationFailed if the validation failed
|
||||
* @throws RemoteConfigException
|
||||
*/
|
||||
public function validate($template): void;
|
||||
|
||||
/**
|
||||
* @param Template|RemoteConfigTemplateShape $template
|
||||
*
|
||||
* @throws RemoteConfigException
|
||||
*
|
||||
* @return non-empty-string The etag value of the published template that can be compared to in later calls
|
||||
*/
|
||||
public function publish($template): string;
|
||||
|
||||
/**
|
||||
* Returns a version with the given number.
|
||||
*
|
||||
* @param VersionNumber|positive-int|non-empty-string $versionNumber
|
||||
*
|
||||
* @throws VersionNotFound
|
||||
* @throws RemoteConfigException if something went wrong
|
||||
*/
|
||||
public function getVersion(VersionNumber|int|string $versionNumber): Version;
|
||||
|
||||
/**
|
||||
* Returns a version with the given number.
|
||||
*
|
||||
* @param VersionNumber|positive-int|non-empty-string $versionNumber
|
||||
*
|
||||
* @throws VersionNotFound
|
||||
* @throws RemoteConfigException if something went wrong
|
||||
*/
|
||||
public function rollbackToVersion(VersionNumber|int|string $versionNumber): Template;
|
||||
|
||||
/**
|
||||
* @param FindVersions|FindVersionsShape|null $query
|
||||
*
|
||||
* @throws RemoteConfigException if something went wrong
|
||||
*
|
||||
* @return Traversable<Version>
|
||||
*/
|
||||
public function listVersions($query = null): Traversable;
|
||||
}
|
||||
15
vendor/kreait/firebase-php/src/Firebase/Contract/Storage.php
vendored
Normal file
15
vendor/kreait/firebase-php/src/Firebase/Contract/Storage.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Contract;
|
||||
|
||||
use Google\Cloud\Storage\Bucket;
|
||||
use Google\Cloud\Storage\StorageClient;
|
||||
|
||||
interface Storage
|
||||
{
|
||||
public function getStorageClient(): StorageClient;
|
||||
|
||||
public function getBucket(?string $name = null): Bucket;
|
||||
}
|
||||
26
vendor/kreait/firebase-php/src/Firebase/Contract/Transitional/FederatedUserFetcher.php
vendored
Normal file
26
vendor/kreait/firebase-php/src/Firebase/Contract/Transitional/FederatedUserFetcher.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Contract\Transitional;
|
||||
|
||||
use Kreait\Firebase\Auth\UserRecord;
|
||||
use Kreait\Firebase\Exception;
|
||||
use Kreait\Firebase\Exception\Auth\UserNotFound;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
* @TODO: This interface is intended to be integrated into the Auth interface on the next major release.
|
||||
*/
|
||||
interface FederatedUserFetcher
|
||||
{
|
||||
/**
|
||||
* @param Stringable|non-empty-string $providerId
|
||||
* @param Stringable|non-empty-string $providerUid
|
||||
*
|
||||
* @throws UserNotFound
|
||||
* @throws Exception\AuthException
|
||||
* @throws Exception\FirebaseException
|
||||
*/
|
||||
public function getUserByProviderUid(Stringable|string $providerId, Stringable|string $providerUid): UserRecord;
|
||||
}
|
||||
78
vendor/kreait/firebase-php/src/Firebase/Database.php
vendored
Normal file
78
vendor/kreait/firebase-php/src/Firebase/Database.php
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase;
|
||||
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
use Kreait\Firebase\Database\ApiClient;
|
||||
use Kreait\Firebase\Database\Reference;
|
||||
use Kreait\Firebase\Database\RuleSet;
|
||||
use Kreait\Firebase\Database\Transaction;
|
||||
use Kreait\Firebase\Exception\InvalidArgumentException;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
use function ltrim;
|
||||
use function sprintf;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class Database implements Contract\Database
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UriInterface $uri,
|
||||
private readonly ApiClient $client,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getReference(?string $path = null): Reference
|
||||
{
|
||||
if ($path === null || trim($path) === '') {
|
||||
$path = '/';
|
||||
}
|
||||
|
||||
$path = '/'.ltrim($path, '/');
|
||||
|
||||
try {
|
||||
return new Reference($this->uri->withPath($path), $this->client);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
public function getReferenceFromUrl($uri): Reference
|
||||
{
|
||||
$uri = $uri instanceof UriInterface ? $uri : new Uri($uri);
|
||||
|
||||
if (($givenHost = $uri->getHost()) !== ($dbHost = $this->uri->getHost())) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The given URI\'s host "%s" is not covered by the database for the host "%s".',
|
||||
$givenHost,
|
||||
$dbHost,
|
||||
));
|
||||
}
|
||||
|
||||
return $this->getReference($uri->getPath());
|
||||
}
|
||||
|
||||
public function getRuleSet(): RuleSet
|
||||
{
|
||||
$rules = $this->client->get('/.settings/rules');
|
||||
|
||||
return RuleSet::fromArray($rules);
|
||||
}
|
||||
|
||||
public function updateRules(RuleSet $ruleSet): void
|
||||
{
|
||||
$this->client->updateRules('/.settings/rules', $ruleSet);
|
||||
}
|
||||
|
||||
public function runTransaction(callable $callable): mixed
|
||||
{
|
||||
$transaction = new Transaction($this->client);
|
||||
|
||||
return $callable($transaction);
|
||||
}
|
||||
}
|
||||
165
vendor/kreait/firebase-php/src/Firebase/Database/ApiClient.php
vendored
Normal file
165
vendor/kreait/firebase-php/src/Firebase/Database/ApiClient.php
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database;
|
||||
|
||||
use Beste\Json;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\Psr7\Query;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
use Kreait\Firebase\Exception\DatabaseApiExceptionConverter;
|
||||
use Kreait\Firebase\Exception\DatabaseException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class ApiClient
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ClientInterface $client,
|
||||
private readonly UrlBuilder $resourceUrlBuilder,
|
||||
private readonly DatabaseApiExceptionConverter $errorHandler,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function get(string $path): mixed
|
||||
{
|
||||
$response = $this->requestApi('GET', $path);
|
||||
|
||||
return Json::decode((string) $response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseException
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getWithETag(string $path): array
|
||||
{
|
||||
$response = $this->requestApi('GET', $path, [
|
||||
'headers' => [
|
||||
'X-Firebase-ETag' => 'true',
|
||||
],
|
||||
]);
|
||||
|
||||
$value = Json::decode((string) $response->getBody(), true);
|
||||
$etag = $response->getHeaderLine('ETag');
|
||||
|
||||
return [
|
||||
'value' => $value,
|
||||
'etag' => $etag,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function set(string $path, mixed $value): mixed
|
||||
{
|
||||
$response = $this->requestApi('PUT', $path, ['json' => $value]);
|
||||
|
||||
return Json::decode((string) $response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function setWithEtag(string $path, mixed $value, string $etag): mixed
|
||||
{
|
||||
$response = $this->requestApi('PUT', $path, [
|
||||
'headers' => [
|
||||
'if-match' => $etag,
|
||||
],
|
||||
'json' => $value,
|
||||
]);
|
||||
|
||||
return Json::decode((string) $response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function removeWithEtag(string $path, string $etag): void
|
||||
{
|
||||
$this->requestApi('DELETE', $path, [
|
||||
'headers' => [
|
||||
'if-match' => $etag,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function updateRules(string $path, RuleSet $ruleSet): mixed
|
||||
{
|
||||
$rules = $ruleSet->getRules();
|
||||
$encodedRules = Json::encode((object) $rules);
|
||||
|
||||
$response = $this->requestApi('PUT', $path, [
|
||||
'body' => $encodedRules,
|
||||
]);
|
||||
|
||||
return Json::decode((string) $response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function push(string $path, mixed $value): string
|
||||
{
|
||||
$response = $this->requestApi('POST', $path, ['json' => $value]);
|
||||
|
||||
return Json::decode((string) $response->getBody(), true)['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function remove(string $path): void
|
||||
{
|
||||
$this->requestApi('DELETE', $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<array-key, mixed> $values
|
||||
*
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function update(string $path, array $values): void
|
||||
{
|
||||
$this->requestApi('PATCH', $path, ['json' => $values]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed>|null $options
|
||||
*
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
private function requestApi(string $method, string $path, ?array $options = []): ResponseInterface
|
||||
{
|
||||
$options ??= [];
|
||||
|
||||
$uri = new Uri($path);
|
||||
|
||||
$url = $this->resourceUrlBuilder->getUrl(
|
||||
$uri->getPath(),
|
||||
Query::parse($uri->getQuery()),
|
||||
);
|
||||
|
||||
$request = new Request($method, $url);
|
||||
|
||||
try {
|
||||
return $this->client->send($request, $options);
|
||||
} catch (Throwable $e) {
|
||||
throw $this->errorHandler->convertException($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
283
vendor/kreait/firebase-php/src/Firebase/Database/Query.php
vendored
Normal file
283
vendor/kreait/firebase-php/src/Firebase/Database/Query.php
vendored
Normal file
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database;
|
||||
|
||||
use Kreait\Firebase\Database\Query\Filter;
|
||||
use Kreait\Firebase\Database\Query\Filter\EndAt;
|
||||
use Kreait\Firebase\Database\Query\Filter\EndBefore;
|
||||
use Kreait\Firebase\Database\Query\Filter\EqualTo;
|
||||
use Kreait\Firebase\Database\Query\Filter\LimitToFirst;
|
||||
use Kreait\Firebase\Database\Query\Filter\LimitToLast;
|
||||
use Kreait\Firebase\Database\Query\Filter\Shallow;
|
||||
use Kreait\Firebase\Database\Query\Filter\StartAfter;
|
||||
use Kreait\Firebase\Database\Query\Filter\StartAt;
|
||||
use Kreait\Firebase\Database\Query\Sorter;
|
||||
use Kreait\Firebase\Database\Query\Sorter\OrderByChild;
|
||||
use Kreait\Firebase\Database\Query\Sorter\OrderByKey;
|
||||
use Kreait\Firebase\Database\Query\Sorter\OrderByValue;
|
||||
use Kreait\Firebase\Exception\Database\DatabaseNotFound;
|
||||
use Kreait\Firebase\Exception\Database\UnsupportedQuery;
|
||||
use Kreait\Firebase\Exception\DatabaseException;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
* A Query sorts and filters the data at a database location so only a subset of the child data is included.
|
||||
* This can be used to order a collection of data by some attribute (e.g. height of dinosaurs) as well as
|
||||
* to restrict a large list of items (e.g. chat messages) down to a number suitable for synchronizing
|
||||
* to the client. Queries are created by chaining together one or more of the filter methods
|
||||
* defined here.
|
||||
*
|
||||
* Just as with a Reference, you can receive data from a Query by using the
|
||||
* {@see getSnapshot()} or {@see getValue()} method. You will only receive
|
||||
* Snapshots for the subset of the data that matches your query.
|
||||
*/
|
||||
class Query implements Stringable
|
||||
{
|
||||
/**
|
||||
* @var Filter[]
|
||||
*/
|
||||
private array $filters = [];
|
||||
|
||||
private ?Sorter $sorter = null;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function __construct(private readonly Reference $reference, private readonly ApiClient $apiClient)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL for this location.
|
||||
*
|
||||
* @see getUri()
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string) $this->getUri();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Reference to the Query's location.
|
||||
*/
|
||||
public function getReference(): Reference
|
||||
{
|
||||
return $this->reference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a data snapshot of the current location.
|
||||
*
|
||||
* @throws UnsupportedQuery if an error occurred
|
||||
*/
|
||||
public function getSnapshot(): Snapshot
|
||||
{
|
||||
$uri = $this->getUri();
|
||||
|
||||
$pathAndQuery = $uri->getPath().'?'.$uri->getQuery();
|
||||
|
||||
try {
|
||||
$value = $this->apiClient->get($pathAndQuery);
|
||||
} catch (DatabaseNotFound $e) {
|
||||
throw $e;
|
||||
} catch (DatabaseException $e) {
|
||||
throw new UnsupportedQuery($this, $e->getMessage(), $e->getCode(), $e->getPrevious());
|
||||
}
|
||||
|
||||
if ($this->sorter !== null) {
|
||||
$value = $this->sorter->modifyValue($value);
|
||||
}
|
||||
|
||||
foreach ($this->filters as $filter) {
|
||||
$value = $filter->modifyValue($value);
|
||||
}
|
||||
|
||||
return new Snapshot($this->reference, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for {@see getSnapshot()}->getValue().
|
||||
*
|
||||
* @throws UnsupportedQuery if an error occurred
|
||||
*/
|
||||
public function getValue(): mixed
|
||||
{
|
||||
return $this->getSnapshot()->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Query with the specified ending point.
|
||||
*
|
||||
* The ending point is inclusive, so children with exactly
|
||||
* the specified value will be included in the query.
|
||||
*
|
||||
* @param scalar $value
|
||||
*/
|
||||
public function endAt($value): self
|
||||
{
|
||||
return $this->withAddedFilter(new EndAt($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Query with the specified ending point (exclusive).
|
||||
*
|
||||
* @param scalar $value
|
||||
*/
|
||||
public function endBefore($value): self
|
||||
{
|
||||
return $this->withAddedFilter(new EndBefore($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Query which includes children which match the specified value.
|
||||
*
|
||||
* @param scalar $value
|
||||
*/
|
||||
public function equalTo($value): self
|
||||
{
|
||||
return $this->withAddedFilter(new EqualTo($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Query with the specified starting point (inclusive).
|
||||
*
|
||||
* @param scalar $value
|
||||
*/
|
||||
public function startAt($value): self
|
||||
{
|
||||
return $this->withAddedFilter(new StartAt($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Query with the specified starting point (exclusive).
|
||||
*
|
||||
* @param scalar $value
|
||||
*/
|
||||
public function startAfter($value): self
|
||||
{
|
||||
return $this->withAddedFilter(new StartAfter($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new Query limited to the first specific number of children.
|
||||
*/
|
||||
public function limitToFirst(int $limit): self
|
||||
{
|
||||
return $this->withAddedFilter(new LimitToFirst($limit));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new Query object limited to the last specific number of children.
|
||||
*/
|
||||
public function limitToLast(int $limit): self
|
||||
{
|
||||
return $this->withAddedFilter(new LimitToLast($limit));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new Query object ordered by the specified child key.
|
||||
*
|
||||
* Queries can only order by one key at a time. Calling orderBy*() multiple times on
|
||||
* the same query is an error.
|
||||
*
|
||||
* @throws UnsupportedQuery if the query is already ordered
|
||||
*/
|
||||
public function orderByChild(string $childKey): self
|
||||
{
|
||||
return $this->withSorter(new OrderByChild($childKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new Query object ordered by key.
|
||||
*
|
||||
* Sorts the results of a query by their ascending key value.
|
||||
*
|
||||
* Queries can only order by one key at a time. Calling orderBy*() multiple times on
|
||||
* the same query is an error.
|
||||
*
|
||||
* @throws UnsupportedQuery if the query is already ordered
|
||||
*/
|
||||
public function orderByKey(): self
|
||||
{
|
||||
return $this->withSorter(new OrderByKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new Query object ordered by child values.
|
||||
*
|
||||
* If the children of a query are all scalar values (numbers or strings), you can order the results
|
||||
* by their (ascending) values.
|
||||
*
|
||||
* Queries can only order by one key at a time. Calling orderBy*() multiple times on
|
||||
* the same query is an error.
|
||||
*
|
||||
* @throws UnsupportedQuery if the query is already ordered
|
||||
*/
|
||||
public function orderByValue(): self
|
||||
{
|
||||
return $this->withSorter(new OrderByValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* This is an advanced feature, designed to help you work with large datasets without needing to download
|
||||
* everything. Set this to true to limit the depth of the data returned at a location. If the data at
|
||||
* the location is a JSON primitive (string, number or boolean), its value will simply be returned.
|
||||
*
|
||||
* If the data snapshot at the location is a JSON object, the values for each key will be
|
||||
* truncated to true.
|
||||
*
|
||||
* @see https://firebase.google.com/docs/reference/rest/database/#section-param-shallow
|
||||
*/
|
||||
public function shallow(): self
|
||||
{
|
||||
return $this->withAddedFilter(new Shallow());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL for this location.
|
||||
*
|
||||
* This method returns a URL that is ready to be put into a browser, curl command, or a
|
||||
* {@see Database::getReferenceFromUrl()} call. Since all of those expect the URL
|
||||
* to be url-encoded, toString() returns an encoded URL.
|
||||
*
|
||||
* Append '.json' to the URL when typed into a browser to download JSON formatted data.
|
||||
* If the location is secured (not publicly readable) you will get a permission-denied error.
|
||||
*/
|
||||
public function getUri(): UriInterface
|
||||
{
|
||||
$uri = $this->reference->getUri();
|
||||
|
||||
if ($this->sorter !== null) {
|
||||
$uri = $this->sorter->modifyUri($uri);
|
||||
}
|
||||
|
||||
foreach ($this->filters as $filter) {
|
||||
$uri = $filter->modifyUri($uri);
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
private function withAddedFilter(Filter $filter): self
|
||||
{
|
||||
$query = clone $this;
|
||||
$query->filters[] = $filter;
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
private function withSorter(Sorter $sorter): self
|
||||
{
|
||||
if ($this->sorter !== null) {
|
||||
throw new UnsupportedQuery($this, 'This query is already ordered.');
|
||||
}
|
||||
|
||||
$query = clone $this;
|
||||
$query->sorter = $sorter;
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
12
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter.php
vendored
Normal file
12
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter.php
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database\Query;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
interface Filter extends Modifier
|
||||
{
|
||||
}
|
||||
27
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter/EndAt.php
vendored
Normal file
27
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter/EndAt.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database\Query\Filter;
|
||||
|
||||
use Beste\Json;
|
||||
use Kreait\Firebase\Database\Query\Filter;
|
||||
use Kreait\Firebase\Database\Query\ModifierTrait;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class EndAt implements Filter
|
||||
{
|
||||
use ModifierTrait;
|
||||
|
||||
public function __construct(private readonly bool|float|int|string $value)
|
||||
{
|
||||
}
|
||||
|
||||
public function modifyUri(UriInterface $uri): UriInterface
|
||||
{
|
||||
return $this->appendQueryParam($uri, 'endAt', Json::encode($this->value));
|
||||
}
|
||||
}
|
||||
27
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter/EndBefore.php
vendored
Normal file
27
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter/EndBefore.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database\Query\Filter;
|
||||
|
||||
use Beste\Json;
|
||||
use Kreait\Firebase\Database\Query\Filter;
|
||||
use Kreait\Firebase\Database\Query\ModifierTrait;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class EndBefore implements Filter
|
||||
{
|
||||
use ModifierTrait;
|
||||
|
||||
public function __construct(private readonly int|float|string|bool $value)
|
||||
{
|
||||
}
|
||||
|
||||
public function modifyUri(UriInterface $uri): UriInterface
|
||||
{
|
||||
return $this->appendQueryParam($uri, 'endBefore', Json::encode($this->value));
|
||||
}
|
||||
}
|
||||
27
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter/EqualTo.php
vendored
Normal file
27
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter/EqualTo.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database\Query\Filter;
|
||||
|
||||
use Beste\Json;
|
||||
use Kreait\Firebase\Database\Query\Filter;
|
||||
use Kreait\Firebase\Database\Query\ModifierTrait;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class EqualTo implements Filter
|
||||
{
|
||||
use ModifierTrait;
|
||||
|
||||
public function __construct(private readonly bool|float|int|string $value)
|
||||
{
|
||||
}
|
||||
|
||||
public function modifyUri(UriInterface $uri): UriInterface
|
||||
{
|
||||
return $this->appendQueryParam($uri, 'equalTo', Json::encode($this->value));
|
||||
}
|
||||
}
|
||||
34
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter/LimitToFirst.php
vendored
Normal file
34
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter/LimitToFirst.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database\Query\Filter;
|
||||
|
||||
use Kreait\Firebase\Database\Query\Filter;
|
||||
use Kreait\Firebase\Database\Query\ModifierTrait;
|
||||
use Kreait\Firebase\Exception\InvalidArgumentException;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class LimitToFirst implements Filter
|
||||
{
|
||||
use ModifierTrait;
|
||||
|
||||
private readonly int $limit;
|
||||
|
||||
public function __construct(int $limit)
|
||||
{
|
||||
if ($limit < 1) {
|
||||
throw new InvalidArgumentException('Limit must be 1 or greater');
|
||||
}
|
||||
|
||||
$this->limit = $limit;
|
||||
}
|
||||
|
||||
public function modifyUri(UriInterface $uri): UriInterface
|
||||
{
|
||||
return $this->appendQueryParam($uri, 'limitToFirst', $this->limit);
|
||||
}
|
||||
}
|
||||
34
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter/LimitToLast.php
vendored
Normal file
34
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter/LimitToLast.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database\Query\Filter;
|
||||
|
||||
use Kreait\Firebase\Database\Query\Filter;
|
||||
use Kreait\Firebase\Database\Query\ModifierTrait;
|
||||
use Kreait\Firebase\Exception\InvalidArgumentException;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class LimitToLast implements Filter
|
||||
{
|
||||
use ModifierTrait;
|
||||
|
||||
private readonly int $limit;
|
||||
|
||||
public function __construct(int $limit)
|
||||
{
|
||||
if ($limit < 1) {
|
||||
throw new InvalidArgumentException('Limit must be 1 or greater');
|
||||
}
|
||||
|
||||
$this->limit = $limit;
|
||||
}
|
||||
|
||||
public function modifyUri(UriInterface $uri): UriInterface
|
||||
{
|
||||
return $this->appendQueryParam($uri, 'limitToLast', $this->limit);
|
||||
}
|
||||
}
|
||||
22
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter/Shallow.php
vendored
Normal file
22
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter/Shallow.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database\Query\Filter;
|
||||
|
||||
use Kreait\Firebase\Database\Query\Filter;
|
||||
use Kreait\Firebase\Database\Query\ModifierTrait;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class Shallow implements Filter
|
||||
{
|
||||
use ModifierTrait;
|
||||
|
||||
public function modifyUri(UriInterface $uri): UriInterface
|
||||
{
|
||||
return $this->appendQueryParam($uri, 'shallow', 'true');
|
||||
}
|
||||
}
|
||||
27
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter/StartAfter.php
vendored
Normal file
27
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter/StartAfter.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database\Query\Filter;
|
||||
|
||||
use Beste\Json;
|
||||
use Kreait\Firebase\Database\Query\Filter;
|
||||
use Kreait\Firebase\Database\Query\ModifierTrait;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class StartAfter implements Filter
|
||||
{
|
||||
use ModifierTrait;
|
||||
|
||||
public function __construct(private readonly int|float|string|bool $value)
|
||||
{
|
||||
}
|
||||
|
||||
public function modifyUri(UriInterface $uri): UriInterface
|
||||
{
|
||||
return $this->appendQueryParam($uri, 'startAfter', Json::encode($this->value));
|
||||
}
|
||||
}
|
||||
27
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter/StartAt.php
vendored
Normal file
27
vendor/kreait/firebase-php/src/Firebase/Database/Query/Filter/StartAt.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database\Query\Filter;
|
||||
|
||||
use Beste\Json;
|
||||
use Kreait\Firebase\Database\Query\Filter;
|
||||
use Kreait\Firebase\Database\Query\ModifierTrait;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class StartAt implements Filter
|
||||
{
|
||||
use ModifierTrait;
|
||||
|
||||
public function __construct(private readonly int|float|string|bool $value)
|
||||
{
|
||||
}
|
||||
|
||||
public function modifyUri(UriInterface $uri): UriInterface
|
||||
{
|
||||
return $this->appendQueryParam($uri, 'startAt', Json::encode($this->value));
|
||||
}
|
||||
}
|
||||
23
vendor/kreait/firebase-php/src/Firebase/Database/Query/Modifier.php
vendored
Normal file
23
vendor/kreait/firebase-php/src/Firebase/Database/Query/Modifier.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database\Query;
|
||||
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
interface Modifier
|
||||
{
|
||||
/**
|
||||
* Modifies the given URI and returns it.
|
||||
*/
|
||||
public function modifyUri(UriInterface $uri): UriInterface;
|
||||
|
||||
/**
|
||||
* Modifies the given value and returns it.
|
||||
*/
|
||||
public function modifyValue(mixed $value): mixed;
|
||||
}
|
||||
30
vendor/kreait/firebase-php/src/Firebase/Database/Query/ModifierTrait.php
vendored
Normal file
30
vendor/kreait/firebase-php/src/Firebase/Database/Query/ModifierTrait.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database\Query;
|
||||
|
||||
use GuzzleHttp\Psr7\Query;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
use function array_merge;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait ModifierTrait
|
||||
{
|
||||
public function modifyValue(mixed $value): mixed
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
protected function appendQueryParam(UriInterface $uri, string $key, mixed $value): UriInterface
|
||||
{
|
||||
$queryParams = array_merge(Query::parse($uri->getQuery()), [$key => $value]);
|
||||
|
||||
$queryString = Query::build($queryParams);
|
||||
|
||||
return $uri->withQuery($queryString);
|
||||
}
|
||||
}
|
||||
12
vendor/kreait/firebase-php/src/Firebase/Database/Query/Sorter.php
vendored
Normal file
12
vendor/kreait/firebase-php/src/Firebase/Database/Query/Sorter.php
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database\Query;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
interface Sorter extends Modifier
|
||||
{
|
||||
}
|
||||
45
vendor/kreait/firebase-php/src/Firebase/Database/Query/Sorter/OrderByChild.php
vendored
Normal file
45
vendor/kreait/firebase-php/src/Firebase/Database/Query/Sorter/OrderByChild.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database\Query\Sorter;
|
||||
|
||||
use Kreait\Firebase\Database\Query\ModifierTrait;
|
||||
use Kreait\Firebase\Database\Query\Sorter;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
use function is_array;
|
||||
use function JmesPath\search;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function uasort;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class OrderByChild implements Sorter
|
||||
{
|
||||
use ModifierTrait;
|
||||
|
||||
public function __construct(private readonly string $childKey)
|
||||
{
|
||||
}
|
||||
|
||||
public function modifyUri(UriInterface $uri): UriInterface
|
||||
{
|
||||
return $this->appendQueryParam($uri, 'orderBy', sprintf('"%s"', $this->childKey));
|
||||
}
|
||||
|
||||
public function modifyValue(mixed $value): mixed
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$expression = str_replace('/', '.', $this->childKey);
|
||||
|
||||
uasort($value, static fn($a, $b): int => search($expression, $a) <=> search($expression, $b));
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
36
vendor/kreait/firebase-php/src/Firebase/Database/Query/Sorter/OrderByKey.php
vendored
Normal file
36
vendor/kreait/firebase-php/src/Firebase/Database/Query/Sorter/OrderByKey.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database\Query\Sorter;
|
||||
|
||||
use Kreait\Firebase\Database\Query\ModifierTrait;
|
||||
use Kreait\Firebase\Database\Query\Sorter;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
use function is_array;
|
||||
use function ksort;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class OrderByKey implements Sorter
|
||||
{
|
||||
use ModifierTrait;
|
||||
|
||||
public function modifyUri(UriInterface $uri): UriInterface
|
||||
{
|
||||
return $this->appendQueryParam($uri, 'orderBy', '"$key"');
|
||||
}
|
||||
|
||||
public function modifyValue(mixed $value): mixed
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
ksort($value);
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
36
vendor/kreait/firebase-php/src/Firebase/Database/Query/Sorter/OrderByValue.php
vendored
Normal file
36
vendor/kreait/firebase-php/src/Firebase/Database/Query/Sorter/OrderByValue.php
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database\Query\Sorter;
|
||||
|
||||
use Kreait\Firebase\Database\Query\ModifierTrait;
|
||||
use Kreait\Firebase\Database\Query\Sorter;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
use function asort;
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class OrderByValue implements Sorter
|
||||
{
|
||||
use ModifierTrait;
|
||||
|
||||
public function modifyUri(UriInterface $uri): UriInterface
|
||||
{
|
||||
return $this->appendQueryParam($uri, 'orderBy', '"$value"');
|
||||
}
|
||||
|
||||
public function modifyValue(mixed $value): mixed
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
asort($value);
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
393
vendor/kreait/firebase-php/src/Firebase/Database/Reference.php
vendored
Normal file
393
vendor/kreait/firebase-php/src/Firebase/Database/Reference.php
vendored
Normal file
@@ -0,0 +1,393 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database;
|
||||
|
||||
use Kreait\Firebase\Exception\DatabaseException;
|
||||
use Kreait\Firebase\Exception\InvalidArgumentException;
|
||||
use Kreait\Firebase\Exception\OutOfRangeException;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Stringable;
|
||||
|
||||
use function array_fill_keys;
|
||||
use function array_keys;
|
||||
use function array_map;
|
||||
use function basename;
|
||||
use function dirname;
|
||||
use function is_array;
|
||||
use function ltrim;
|
||||
use function sprintf;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* A Reference represents a specific location in your database and can be used
|
||||
* for reading or writing data to that database location.
|
||||
*/
|
||||
class Reference implements Stringable
|
||||
{
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly UriInterface $uri,
|
||||
private readonly ApiClient $apiClient,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL for this location.
|
||||
*
|
||||
* @see getUri()
|
||||
*/
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string) $this->getUri();
|
||||
}
|
||||
|
||||
/**
|
||||
* The last part of the current path.
|
||||
*
|
||||
* For example, "ada" is the key for https://sample-app.firebaseio.example.com/users/ada.
|
||||
*
|
||||
* The key of the root Reference is null.
|
||||
*/
|
||||
public function getKey(): ?string
|
||||
{
|
||||
$key = basename($this->getPath());
|
||||
|
||||
return $key !== '' ? $key : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full path to a reference.
|
||||
*/
|
||||
public function getPath(): string
|
||||
{
|
||||
return trim($this->uri->getPath(), '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* The parent location of a Reference.
|
||||
*
|
||||
* @throws OutOfRangeException if requested for the root Reference
|
||||
*/
|
||||
public function getParent(): self
|
||||
{
|
||||
$parentPath = dirname($this->getPath());
|
||||
|
||||
if ($parentPath === '.') {
|
||||
throw new OutOfRangeException('Cannot get parent of root reference');
|
||||
}
|
||||
|
||||
return new self($this->uri->withPath('/'.ltrim($parentPath, '/')), $this->apiClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* The root location of a Reference.
|
||||
*/
|
||||
public function getRoot(): self
|
||||
{
|
||||
return new self($this->uri->withPath('/'), $this->apiClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Reference for the location at the specified relative path.
|
||||
*
|
||||
* The relative path can either be a simple child name (for example, "ada")
|
||||
* or a deeper slash-separated path (for example, "ada/name/first").
|
||||
*
|
||||
* @throws InvalidArgumentException if the path is invalid
|
||||
*/
|
||||
public function getChild(string $path): self
|
||||
{
|
||||
$childPath = sprintf('/%s/%s', trim($this->uri->getPath(), '/'), trim($path, '/'));
|
||||
|
||||
try {
|
||||
return new self($this->uri->withPath($childPath), $this->apiClient);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new Query object ordered by the specified child key.
|
||||
*
|
||||
* @see Query::orderByChild()
|
||||
*/
|
||||
public function orderByChild(string $path): Query
|
||||
{
|
||||
return $this->query()->orderByChild($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new Query object ordered by key.
|
||||
*
|
||||
* @see Query::orderByKey()
|
||||
*/
|
||||
public function orderByKey(): Query
|
||||
{
|
||||
return $this->query()->orderByKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new Query object ordered by child values.
|
||||
*
|
||||
* @see Query::orderByValue()
|
||||
*/
|
||||
public function orderByValue(): Query
|
||||
{
|
||||
return $this->query()->orderByValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new Query limited to the first specific number of children.
|
||||
*
|
||||
* @see Query::limitToFirst()
|
||||
*/
|
||||
public function limitToFirst(int $limit): Query
|
||||
{
|
||||
return $this->query()->limitToFirst($limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new Query object limited to the last specific number of children.
|
||||
*
|
||||
* @see Query::limitToLast()
|
||||
*/
|
||||
public function limitToLast(int $limit): Query
|
||||
{
|
||||
return $this->query()->limitToLast($limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Query with the specified starting point (inclusive).
|
||||
*
|
||||
* @see Query::startAt()
|
||||
*/
|
||||
public function startAt(bool|string|int|float $value): Query
|
||||
{
|
||||
return $this->query()->startAt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Query with the specified starting point (exclusive).
|
||||
*
|
||||
* @see Query::startAfter()
|
||||
*/
|
||||
public function startAfter(bool|string|int|float $value): Query
|
||||
{
|
||||
return $this->query()->startAfter($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Query with the specified ending point (inclusive).
|
||||
*
|
||||
* @see Query::endAt()
|
||||
*/
|
||||
public function endAt(bool|string|int|float $value): Query
|
||||
{
|
||||
return $this->query()->endAt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Query with the specified ending point (exclusive).
|
||||
*
|
||||
* @see Query::endBefore()
|
||||
*/
|
||||
public function endBefore(bool|string|int|float $value): Query
|
||||
{
|
||||
return $this->query()->endBefore($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Query which includes children which match the specified value.
|
||||
*
|
||||
* @see Query::equalTo()
|
||||
*/
|
||||
public function equalTo(bool|string|int|float $value): Query
|
||||
{
|
||||
return $this->query()->equalTo($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Query with shallow results.
|
||||
*
|
||||
* @see Query::shallow()
|
||||
*/
|
||||
public function shallow(): Query
|
||||
{
|
||||
return $this->query()->shallow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the keys of a reference's children.
|
||||
*
|
||||
* @throws DatabaseException if the API reported an error
|
||||
* @throws OutOfRangeException if the reference has no children with keys
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getChildKeys(): array
|
||||
{
|
||||
$snapshot = $this->shallow()->getSnapshot();
|
||||
|
||||
if (is_array($value = $snapshot->getValue())) {
|
||||
return array_map('strval', array_keys($value));
|
||||
}
|
||||
|
||||
throw new OutOfRangeException(sprintf('%s has no children with keys', $this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for {@see getSnapshot()}->getValue().
|
||||
*
|
||||
* @throws DatabaseException if the API reported an error
|
||||
*/
|
||||
public function getValue(): mixed
|
||||
{
|
||||
return $this->getSnapshot()->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write data to this database location.
|
||||
*
|
||||
* This will overwrite any data at this location and all child locations.
|
||||
*
|
||||
* Passing null for the new value is equivalent to calling {@see remove()}:
|
||||
* all data at this location or any child location will be deleted.
|
||||
*
|
||||
* @throws DatabaseException if the API reported an error
|
||||
*/
|
||||
public function set(mixed $value): self
|
||||
{
|
||||
if ($value === null) {
|
||||
$this->apiClient->remove($this->uri->getPath());
|
||||
} else {
|
||||
$this->apiClient->set($this->uri->getPath(), $value);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a data snapshot of the current location.
|
||||
*
|
||||
* @throws DatabaseException if the API reported an error
|
||||
*/
|
||||
public function getSnapshot(): Snapshot
|
||||
{
|
||||
$value = $this->apiClient->get($this->uri->getPath());
|
||||
|
||||
return new Snapshot($this, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new child location using a unique key and returns its reference.
|
||||
*
|
||||
* This is the most common pattern for adding data to a collection of items.
|
||||
*
|
||||
* If you provide a value to push(), the value will be written to the generated location.
|
||||
* If you don't pass a value, nothing will be written to the database and the child
|
||||
* will remain empty (but you can use the reference elsewhere).
|
||||
*
|
||||
* The unique key generated by push() are ordered by the current time, so the resulting
|
||||
* list of items will be chronologically sorted. The keys are also designed to be
|
||||
* unguessable (they contain 72 random bits of entropy).
|
||||
*
|
||||
* @param mixed|null $value
|
||||
*
|
||||
* @throws DatabaseException if the API reported an error
|
||||
*/
|
||||
public function push($value = null): self
|
||||
{
|
||||
$value ??= [];
|
||||
|
||||
$newKey = $this->apiClient->push($this->uri->getPath(), $value);
|
||||
$newPath = sprintf('%s/%s', $this->uri->getPath(), $newKey);
|
||||
|
||||
return new self($this->uri->withPath($newPath), $this->apiClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the data at this database location.
|
||||
*
|
||||
* Any data at child locations will also be deleted.
|
||||
*
|
||||
* @throws DatabaseException if the API reported an error
|
||||
*/
|
||||
public function remove(): self
|
||||
{
|
||||
$this->apiClient->remove($this->uri->getPath());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the data at the given locations.
|
||||
*
|
||||
* Each location can either be a simple property (for example, "name"), or a relative path
|
||||
* (for example, "name/first") from the current location to the data to remove.
|
||||
*
|
||||
* Any data at child locations will also be deleted.
|
||||
*
|
||||
* @param string[] $keys Locations to remove
|
||||
*
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function removeChildren(array $keys): self
|
||||
{
|
||||
$this->update(
|
||||
array_fill_keys($keys, null),
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes multiple values to the database at once.
|
||||
*
|
||||
* The values argument contains multiple property/value pairs that will be written to the database together.
|
||||
* Each child property can either be a simple property (for example, "name"), or a relative path
|
||||
* (for example, "name/first") from the current location to the data to update.
|
||||
*
|
||||
* As opposed to the {@see set()} method, update() can be use to selectively update only the referenced properties
|
||||
* at the current location (instead of replacing all the child properties at the current location).
|
||||
*
|
||||
* Passing null to {see update()} will remove the data at this location.
|
||||
*
|
||||
* @param array<mixed> $values
|
||||
*
|
||||
* @throws DatabaseException if the API reported an error
|
||||
*/
|
||||
public function update(array $values): self
|
||||
{
|
||||
$this->apiClient->update($this->uri->getPath(), $values);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL for this location.
|
||||
*
|
||||
* This method returns a URL that is ready to be put into a browser, curl command, or a
|
||||
* {@see Database::getReferenceFromUrl()} call. Since all of those expect the URL
|
||||
* to be url-encoded, toString() returns an encoded URL.
|
||||
*
|
||||
* Append '.json' to the URL when typed into a browser to download JSON formatted data.
|
||||
* If the location is secured (not publicly readable),
|
||||
* you will get a permission-denied error.
|
||||
*/
|
||||
public function getUri(): UriInterface
|
||||
{
|
||||
return $this->uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new query for the current reference.
|
||||
*/
|
||||
private function query(): Query
|
||||
{
|
||||
return new Query($this, $this->apiClient);
|
||||
}
|
||||
}
|
||||
103
vendor/kreait/firebase-php/src/Firebase/Database/RuleSet.php
vendored
Normal file
103
vendor/kreait/firebase-php/src/Firebase/Database/RuleSet.php
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
use function array_key_exists;
|
||||
|
||||
class RuleSet implements JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var array<string, array<mixed>>
|
||||
*/
|
||||
private readonly array $rules;
|
||||
|
||||
/**
|
||||
* @param array<string, array<mixed>> $rules
|
||||
*/
|
||||
private function __construct(array $rules)
|
||||
{
|
||||
if (!array_key_exists('rules', $rules)) {
|
||||
$rules = ['rules' => $rules];
|
||||
}
|
||||
|
||||
$this->rules = $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default rules require Authentication. They allow full read and write access
|
||||
* to authenticated users of your app. They are useful if you want data open to
|
||||
* all users of your app but don't want it open to the world.
|
||||
*
|
||||
* @see https://firebase.google.com/docs/database/security/quickstart#sample-rules
|
||||
*/
|
||||
public static function default(): self
|
||||
{
|
||||
return new self([
|
||||
'rules' => [
|
||||
'.read' => 'auth != null',
|
||||
'.write' => 'auth != null',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* During development, you can use the public rules in place of the default rules to set
|
||||
* your files publicly readable and writable. This can be useful for prototyping,
|
||||
* as you can get started without setting up Authentication.
|
||||
*
|
||||
* This level of access means anyone can read or write to your database. You should
|
||||
* configure more secure rules before launching your app.
|
||||
*
|
||||
* @see https://firebase.google.com/docs/database/security/quickstart#sample-rules
|
||||
*/
|
||||
public static function public(): self
|
||||
{
|
||||
return new self([
|
||||
'rules' => [
|
||||
'.read' => true,
|
||||
'.write' => true,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private rules disable read and write access to your database by users. With these rules,
|
||||
* you can only access the database through the Firebase console and an Admin SDK.
|
||||
*
|
||||
* @see https://firebase.google.com/docs/database/security/quickstart#sample-rules
|
||||
*/
|
||||
public static function private(): self
|
||||
{
|
||||
return new self([
|
||||
'rules' => [
|
||||
'.read' => false,
|
||||
'.write' => false,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, array<mixed>> $rules
|
||||
*/
|
||||
public static function fromArray(array $rules): self
|
||||
{
|
||||
return new self($rules);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, array<mixed>>
|
||||
*/
|
||||
public function getRules(): array
|
||||
{
|
||||
return $this->rules;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->rules;
|
||||
}
|
||||
}
|
||||
126
vendor/kreait/firebase-php/src/Firebase/Database/Snapshot.php
vendored
Normal file
126
vendor/kreait/firebase-php/src/Firebase/Database/Snapshot.php
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database;
|
||||
|
||||
use Kreait\Firebase\Exception\InvalidArgumentException;
|
||||
|
||||
use function count;
|
||||
use function is_array;
|
||||
use function JmesPath\search;
|
||||
use function str_replace;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* A Snapshot contains data from a database location.
|
||||
*
|
||||
* It is an immutable copy of the data at a database location. It cannot be modified and will never
|
||||
* change (to modify data, you always call the {@see Reference::set()}).
|
||||
*
|
||||
* You can extract the contents of the snapshot as a JavaScript object by calling
|
||||
* the {@see getValue()} method.
|
||||
*
|
||||
* Alternatively, you can traverse into the snapshot by calling {@see getChild()}
|
||||
* to return child snapshots (which you could then call {@see getValue()} on).
|
||||
*/
|
||||
class Snapshot
|
||||
{
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function __construct(private readonly Reference $reference, private readonly mixed $value)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key (last part of the path) of the location of this Snapshot.
|
||||
*
|
||||
* The last token in a database location is considered its key. For example, "ada" is the key for
|
||||
* the /users/ada/ node. Accessing the key on any Snapshot will return the key for the
|
||||
* location that generated it. However, accessing the key on the root URL of a database
|
||||
* will return null.
|
||||
*/
|
||||
public function getKey(): ?string
|
||||
{
|
||||
return $this->reference->getKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Reference for the location that generated this Snapshot.
|
||||
*/
|
||||
public function getReference(): Reference
|
||||
{
|
||||
return $this->reference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns another Snapshot for the location at the specified relative path.
|
||||
*
|
||||
* Passing a relative path to the child() method of a Snapshot returns another Snapshot for the location
|
||||
* at the specified relative path. The relative path can either be a simple child name (e.g. "ada") or a
|
||||
* deeper, slash-separated path (e.g. "ada/name/first"). If the child location has no data, an empty
|
||||
* Snapshot (that is, a Snapshot whose value is null) is returned.
|
||||
*
|
||||
* @throws InvalidArgumentException if the given child path is invalid
|
||||
*/
|
||||
public function getChild(string $path): self
|
||||
{
|
||||
$path = trim($path, '/');
|
||||
$expression = '"'.str_replace('/', '"."', $path).'"';
|
||||
|
||||
$childValue = search($expression, $this->value);
|
||||
|
||||
return new self($this->reference->getChild($path), $childValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this Snapshot contains any data.
|
||||
*
|
||||
* It is a convenience method for `$snapshot->getValue() !== null`.
|
||||
*/
|
||||
public function exists(): bool
|
||||
{
|
||||
return $this->value !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified child path has (non-null) data.
|
||||
*/
|
||||
public function hasChild(string $path): bool
|
||||
{
|
||||
$path = trim($path, '/');
|
||||
$expression = '"'.str_replace('/', '"."', $path).'"';
|
||||
|
||||
return search($expression, $this->value) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the Snapshot has any child properties.
|
||||
*
|
||||
* You can use {@see hasChildren()} to determine if a Snapshot has any children. If it does,
|
||||
* you can enumerate them using foreach(). If it does not, then either this snapshot
|
||||
* contains a primitive value (which can be retrieved with {@see getValue()}) or
|
||||
* it is empty (in which case {@see getValue()} will return null).
|
||||
*/
|
||||
public function hasChildren(): bool
|
||||
{
|
||||
return is_array($this->value) && $this->value !== [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of child properties of this Snapshot.
|
||||
*/
|
||||
public function numChildren(): int
|
||||
{
|
||||
return is_array($this->value) ? count($this->value) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data contained in this Snapshot.
|
||||
*/
|
||||
public function getValue(): mixed
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
85
vendor/kreait/firebase-php/src/Firebase/Database/Transaction.php
vendored
Normal file
85
vendor/kreait/firebase-php/src/Firebase/Database/Transaction.php
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database;
|
||||
|
||||
use Kreait\Firebase\Exception\Database\ReferenceHasNotBeenSnapshotted;
|
||||
use Kreait\Firebase\Exception\Database\TransactionFailed;
|
||||
use Kreait\Firebase\Exception\DatabaseException;
|
||||
|
||||
use function array_key_exists;
|
||||
|
||||
class Transaction
|
||||
{
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
private array $etags;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function __construct(private readonly ApiClient $apiClient)
|
||||
{
|
||||
$this->etags = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public function snapshot(Reference $reference): Snapshot
|
||||
{
|
||||
$path = $reference->getPath();
|
||||
|
||||
$result = $this->apiClient->getWithETag($path);
|
||||
|
||||
$this->etags[$path] = $result['etag'];
|
||||
|
||||
return new Snapshot($reference, $result['value']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ReferenceHasNotBeenSnapshotted
|
||||
* @throws TransactionFailed
|
||||
*/
|
||||
public function set(Reference $reference, mixed $value): void
|
||||
{
|
||||
$etag = $this->getEtagForReference($reference);
|
||||
|
||||
try {
|
||||
$this->apiClient->setWithEtag($reference->getPath(), $value, $etag);
|
||||
} catch (DatabaseException $e) {
|
||||
throw TransactionFailed::onReference($reference, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ReferenceHasNotBeenSnapshotted
|
||||
* @throws TransactionFailed
|
||||
*/
|
||||
public function remove(Reference $reference): void
|
||||
{
|
||||
$etag = $this->getEtagForReference($reference);
|
||||
|
||||
try {
|
||||
$this->apiClient->removeWithEtag($reference->getPath(), $etag);
|
||||
} catch (DatabaseException $e) {
|
||||
throw TransactionFailed::onReference($reference, $e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ReferenceHasNotBeenSnapshotted
|
||||
*/
|
||||
private function getEtagForReference(Reference $reference): string
|
||||
{
|
||||
$path = $reference->getPath();
|
||||
|
||||
if (array_key_exists($path, $this->etags)) {
|
||||
return $this->etags[$path];
|
||||
}
|
||||
|
||||
throw new ReferenceHasNotBeenSnapshotted($reference);
|
||||
}
|
||||
}
|
||||
101
vendor/kreait/firebase-php/src/Firebase/Database/UrlBuilder.php
vendored
Normal file
101
vendor/kreait/firebase-php/src/Firebase/Database/UrlBuilder.php
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Database;
|
||||
|
||||
use Kreait\Firebase\Exception\InvalidArgumentException;
|
||||
use Kreait\Firebase\Util;
|
||||
|
||||
use function http_build_query;
|
||||
use function in_array;
|
||||
use function preg_match;
|
||||
use function rtrim;
|
||||
use function strtr;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class UrlBuilder
|
||||
{
|
||||
private const EXPECTED_URL_FORMAT = '@^https://(?P<namespace>[^.]+)\.(?P<host>.+)$@';
|
||||
|
||||
/**
|
||||
* @param 'http'|'https' $scheme
|
||||
* @param non-empty-string $host
|
||||
* @param array<string, string> $defaultQueryParams
|
||||
*/
|
||||
private function __construct(
|
||||
private readonly string $scheme,
|
||||
private readonly string $host,
|
||||
private readonly array $defaultQueryParams,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $databaseUrl
|
||||
*/
|
||||
public static function create(string $databaseUrl): self
|
||||
{
|
||||
['scheme' => $scheme, 'host' => $host, 'query' => $query] = self::parseDatabaseUrl($databaseUrl);
|
||||
|
||||
return new self($scheme, $host, $query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $queryParams
|
||||
*/
|
||||
public function getUrl(string $path, array $queryParams = []): string
|
||||
{
|
||||
$allQueryParams = $this->defaultQueryParams + $queryParams;
|
||||
$path = '/'.trim($path, '/');
|
||||
|
||||
$url = strtr('{scheme}://{host}{path}?{queryParams}', [
|
||||
'{scheme}' => $this->scheme,
|
||||
'{host}' => $this->host,
|
||||
'{path}' => $path,
|
||||
'{queryParams}' => http_build_query($allQueryParams),
|
||||
]);
|
||||
|
||||
// If no queryParams are present, remove the trailing '?'
|
||||
return trim($url, '?');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $databaseUrl
|
||||
*
|
||||
* @return array{
|
||||
* scheme: 'http'|'https',
|
||||
* host: non-empty-string,
|
||||
* query: array<non-empty-string, non-empty-string>
|
||||
* }
|
||||
*/
|
||||
private static function parseDatabaseUrl(string $databaseUrl): array
|
||||
{
|
||||
$databaseUrl = rtrim($databaseUrl, '/');
|
||||
|
||||
if (preg_match(self::EXPECTED_URL_FORMAT, $databaseUrl, $matches) !== 1) {
|
||||
throw new InvalidArgumentException('Unexpected database URL format "'.$databaseUrl.'"');
|
||||
}
|
||||
|
||||
$namespace = $matches['namespace'];
|
||||
$host = $matches['host'];
|
||||
|
||||
$emulatorHost = Util::rtdbEmulatorHost();
|
||||
|
||||
if (!in_array($emulatorHost, ['', '0', null], true)) {
|
||||
return [
|
||||
'scheme' => 'http',
|
||||
'host' => $emulatorHost,
|
||||
'query' => ['ns' => $namespace],
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'scheme' => 'https',
|
||||
'host' => $namespace.'.'.$host,
|
||||
'query' => [],
|
||||
];
|
||||
}
|
||||
}
|
||||
103
vendor/kreait/firebase-php/src/Firebase/DynamicLink.php
vendored
Normal file
103
vendor/kreait/firebase-php/src/Firebase/DynamicLink.php
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase;
|
||||
|
||||
use Beste\Json;
|
||||
use GuzzleHttp\Psr7\Utils;
|
||||
use JsonSerializable;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Stringable;
|
||||
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* @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://github.com/googleapis/google-api-nodejs-client/blob/main/src/apis/firebasedynamiclinks/v1.ts
|
||||
*
|
||||
* @phpstan-type DynamicLinkWarningShape array{
|
||||
* warningCode?: non-empty-string,
|
||||
* warningDocumentLink?: non-empty-string,
|
||||
* warningMessage?: non-empty-string
|
||||
* }
|
||||
* @phpstan-type DynamicLinkShape array{
|
||||
* shortLink: non-empty-string,
|
||||
* previewLink?: non-empty-string,
|
||||
* warning?: list<DynamicLinkWarningShape>
|
||||
* }
|
||||
*/
|
||||
final class DynamicLink implements JsonSerializable, Stringable
|
||||
{
|
||||
/**
|
||||
* @param DynamicLinkShape $data
|
||||
*/
|
||||
private function __construct(private readonly array $data)
|
||||
{
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string) $this->uri();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function fromApiResponse(ResponseInterface $response): self
|
||||
{
|
||||
/** @var DynamicLinkShape $decoded */
|
||||
$decoded = Json::decode((string) $response->getBody(), true);
|
||||
|
||||
return new self($decoded);
|
||||
}
|
||||
|
||||
public function uri(): UriInterface
|
||||
{
|
||||
return Utils::uriFor($this->data['shortLink']);
|
||||
}
|
||||
|
||||
public function previewUri(): ?UriInterface
|
||||
{
|
||||
$previewLink = $this->data['previewLink'] ?? null;
|
||||
|
||||
return $previewLink !== null ? Utils::uriFor($previewLink) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function domain(): string
|
||||
{
|
||||
$uri = $this->uri();
|
||||
|
||||
return $uri->getScheme().'://'.$uri->getHost();
|
||||
}
|
||||
|
||||
public function suffix(): string
|
||||
{
|
||||
return trim($this->uri()->getPath(), '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<DynamicLinkWarningShape>
|
||||
*/
|
||||
public function warnings(): array
|
||||
{
|
||||
return $this->data['warning'] ?? [];
|
||||
}
|
||||
|
||||
public function hasWarnings(): bool
|
||||
{
|
||||
return $this->warnings() !== [];
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
81
vendor/kreait/firebase-php/src/Firebase/DynamicLink/AnalyticsInfo.php
vendored
Normal file
81
vendor/kreait/firebase-php/src/Firebase/DynamicLink/AnalyticsInfo.php
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\DynamicLink;
|
||||
|
||||
use JsonSerializable;
|
||||
use Kreait\Firebase\DynamicLink\AnalyticsInfo\GooglePlayAnalytics;
|
||||
use Kreait\Firebase\DynamicLink\AnalyticsInfo\ITunesConnectAnalytics;
|
||||
|
||||
use function array_key_exists;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type GooglePlayAnalyticsShape from GooglePlayAnalytics
|
||||
* @phpstan-import-type ITunesConnectAnalyticsShape from ITunesConnectAnalytics
|
||||
*
|
||||
* @phpstan-type AnalyticsInfoShape array{
|
||||
* googlePlayAnalytics?: GooglePlayAnalyticsShape,
|
||||
* itunesConnectAnalytics?: ITunesConnectAnalyticsShape
|
||||
* }
|
||||
*/
|
||||
final class AnalyticsInfo implements JsonSerializable
|
||||
{
|
||||
private function __construct(
|
||||
private readonly ?GooglePlayAnalytics $googlePlayAnalytics,
|
||||
private readonly ?ITunesConnectAnalytics $iTunesConnectAnalytics,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AnalyticsInfoShape $data
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
$googlePlayAnalytics = array_key_exists('googlePlayAnalytics', $data)
|
||||
? GooglePlayAnalytics::fromArray($data['googlePlayAnalytics'])
|
||||
: null;
|
||||
|
||||
$itunesConnectAnalytics = array_key_exists('itunesConnectAnalytics', $data)
|
||||
? ITunesConnectAnalytics::fromArray($data['itunesConnectAnalytics'])
|
||||
: null;
|
||||
|
||||
return new self($googlePlayAnalytics, $itunesConnectAnalytics);
|
||||
}
|
||||
|
||||
public static function new(): self
|
||||
{
|
||||
return new self(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GooglePlayAnalytics|GooglePlayAnalyticsShape $data
|
||||
*/
|
||||
public function withGooglePlayAnalyticsInfo($data): self
|
||||
{
|
||||
$gpInfo = $data instanceof GooglePlayAnalytics ? $data : GooglePlayAnalytics::fromArray($data);
|
||||
|
||||
return new self($gpInfo, $this->iTunesConnectAnalytics);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ITunesConnectAnalytics|ITunesConnectAnalyticsShape $data
|
||||
*/
|
||||
public function withItunesConnectAnalytics($data): self
|
||||
{
|
||||
$icInfo = $data instanceof ITunesConnectAnalytics ? $data : ITunesConnectAnalytics::fromArray($data);
|
||||
|
||||
return new self($this->googlePlayAnalytics, $icInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AnalyticsInfoShape
|
||||
*/
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return array_filter([
|
||||
'googlePlayAnalytics' => $this->googlePlayAnalytics?->jsonSerialize(),
|
||||
'itunesConnectAnalytics' => $this->iTunesConnectAnalytics?->jsonSerialize(),
|
||||
], fn(?array $value): bool => $value !== null);
|
||||
}
|
||||
}
|
||||
139
vendor/kreait/firebase-php/src/Firebase/DynamicLink/AnalyticsInfo/GooglePlayAnalytics.php
vendored
Normal file
139
vendor/kreait/firebase-php/src/Firebase/DynamicLink/AnalyticsInfo/GooglePlayAnalytics.php
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\DynamicLink\AnalyticsInfo;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* @phpstan-type GooglePlayAnalyticsShape array{
|
||||
* utmSource?: non-empty-string,
|
||||
* utmMedium?: non-empty-string,
|
||||
* utmCampaign?: non-empty-string,
|
||||
* utmTerm?: non-empty-string,
|
||||
* utmContent?: non-empty-string,
|
||||
* gclid?: non-empty-string
|
||||
* }
|
||||
*/
|
||||
final class GooglePlayAnalytics implements JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @param GooglePlayAnalyticsShape $data
|
||||
*/
|
||||
private function __construct(private readonly array $data)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GooglePlayAnalyticsShape $data
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public static function new(): self
|
||||
{
|
||||
return new self([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies the advertiser, site, publication, etc. that is sending traffic to your property,
|
||||
* for example: google, newsletter4, billboard.
|
||||
*
|
||||
* @see https://support.google.com/analytics/answer/1033863#parameters
|
||||
*
|
||||
* @param non-empty-string $utmSource
|
||||
*/
|
||||
public function withUtmSource(string $utmSource): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['utmSource'] = $utmSource;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The advertising or marketing medium, for example: cpc, banner, email newsletter.
|
||||
*
|
||||
* @see https://support.google.com/analytics/answer/1033863#parameters
|
||||
*
|
||||
* @param non-empty-string $utmMedium
|
||||
*/
|
||||
public function withUtmMedium(string $utmMedium): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['utmMedium'] = $utmMedium;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The individual campaign name, slogan, promo code, etc. for a product.
|
||||
*
|
||||
* @see https://support.google.com/analytics/answer/1033863#parameters
|
||||
*
|
||||
* @param non-empty-string $utmCampaign
|
||||
*/
|
||||
public function withUtmCampaign(string $utmCampaign): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['utmCampaign'] = $utmCampaign;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies paid search keywords. If you're manually tagging paid keyword campaigns, you should also use
|
||||
* utm_term to specify the keyword.
|
||||
*
|
||||
* @see https://support.google.com/analytics/answer/1033863#parameters
|
||||
*
|
||||
* @param non-empty-string $utmTerm
|
||||
*/
|
||||
public function withUtmTerm(string $utmTerm): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['utmTerm'] = $utmTerm;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to differentiate similar content, or links within the same ad. For example, if you have two call-to-action
|
||||
* links within the same email message, you can use utm_content and set different values for each, so you can tell
|
||||
* which version is more effective.
|
||||
*
|
||||
* @see https://support.google.com/analytics/answer/1033863#parameters
|
||||
*
|
||||
* @param non-empty-string $utmContent
|
||||
*/
|
||||
public function withUtmContent(string $utmContent): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['utmContent'] = $utmContent;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Google Click ID.
|
||||
*
|
||||
* @see https://support.google.com/analytics/answer/2938246?hl=en
|
||||
*
|
||||
* @param non-empty-string $gclid
|
||||
*/
|
||||
public function withGclid(string $gclid): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['gclid'] = $gclid;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
106
vendor/kreait/firebase-php/src/Firebase/DynamicLink/AnalyticsInfo/ITunesConnectAnalytics.php
vendored
Normal file
106
vendor/kreait/firebase-php/src/Firebase/DynamicLink/AnalyticsInfo/ITunesConnectAnalytics.php
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\DynamicLink\AnalyticsInfo;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* @see https://www.macstories.net/tutorials/a-comprehensive-guide-to-the-itunes-affiliate-program/
|
||||
* @see https://blog.geni.us/parameter-cheat-sheet-for-itunes-and-app-store-links/
|
||||
*
|
||||
* @phpstan-type ITunesConnectAnalyticsShape array{
|
||||
* at?: non-empty-string,
|
||||
* ct?: non-empty-string,
|
||||
* mt?: non-empty-string,
|
||||
* pt?: non-empty-string
|
||||
* }
|
||||
*/
|
||||
final class ITunesConnectAnalytics implements JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @param ITunesConnectAnalyticsShape $data
|
||||
*/
|
||||
private function __construct(private readonly array $data)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ITunesConnectAnalyticsShape $data
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public static function new(): self
|
||||
{
|
||||
return new self([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The iTunes connect/affiliate partner token.
|
||||
*
|
||||
* @see https://blog.geni.us/parameter-cheat-sheet-for-itunes-and-app-store-links/
|
||||
*
|
||||
* @param non-empty-string $affiliateToken
|
||||
*/
|
||||
public function withAffiliateToken(string $affiliateToken): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['at'] = $affiliateToken;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The iTunes connect/affiliate partner token.
|
||||
*
|
||||
* @see https://blog.geni.us/parameter-cheat-sheet-for-itunes-and-app-store-links/
|
||||
*
|
||||
* @param non-empty-string $campaignToken
|
||||
*/
|
||||
public function withCampaignToken(string $campaignToken): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['ct'] = $campaignToken;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The media type.
|
||||
*
|
||||
* @see https://blog.geni.us/parameter-cheat-sheet-for-itunes-and-app-store-links/
|
||||
*
|
||||
* @param non-empty-string $mediaType
|
||||
*/
|
||||
public function withMediaType(string $mediaType): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['mt'] = $mediaType;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The provider token.
|
||||
*
|
||||
* @see https://www.macstories.net/tutorials/a-comprehensive-guide-to-the-itunes-affiliate-program/
|
||||
*
|
||||
* @param non-empty-string $providerToken
|
||||
*/
|
||||
public function withProviderToken(string $providerToken): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['pt'] = $providerToken;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
87
vendor/kreait/firebase-php/src/Firebase/DynamicLink/AndroidInfo.php
vendored
Normal file
87
vendor/kreait/firebase-php/src/Firebase/DynamicLink/AndroidInfo.php
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\DynamicLink;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* @phpstan-type AndroidInfoShape array{
|
||||
* androidPackageName?: non-empty-string,
|
||||
* androidFallbackLink?: non-empty-string,
|
||||
* androidMinPackageVersionCode?: non-empty-string
|
||||
* }
|
||||
*/
|
||||
final class AndroidInfo implements JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @param AndroidInfoShape $data
|
||||
*/
|
||||
private function __construct(private readonly array $data)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AndroidInfoShape $data
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public static function new(): self
|
||||
{
|
||||
return new self([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The package name of the Android app to use to open the link. The app must be connected to your project from the
|
||||
* Overview page of the Firebase console. Required for the Dynamic Link to open an Android app.
|
||||
*
|
||||
* @param non-empty-string $packageName
|
||||
*/
|
||||
public function withPackageName(string $packageName): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['androidPackageName'] = $packageName;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The link to open when the app isn't installed. Specify this to do something other than install your app
|
||||
* from the Play Store when the app isn't installed, such as open the mobile web version of the content,
|
||||
* or display a promotional page for your app.
|
||||
*
|
||||
* @param non-empty-string $fallbackLink
|
||||
*/
|
||||
public function withFallbackLink(string $fallbackLink): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['androidFallbackLink'] = $fallbackLink;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The versionCode of the minimum version of your app that can open the link. If the installed app is an older
|
||||
* version, the user is taken to the Play Store to upgrade the app.
|
||||
*
|
||||
* @see https://developer.android.com/studio/publish/versioning#appversioning
|
||||
*
|
||||
* @param non-empty-string $minPackageVersionCode
|
||||
*/
|
||||
public function withMinPackageVersionCode(string $minPackageVersionCode): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['androidMinPackageVersionCode'] = $minPackageVersionCode;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
70
vendor/kreait/firebase-php/src/Firebase/DynamicLink/ApiClient.php
vendored
Normal file
70
vendor/kreait/firebase-php/src/Firebase/DynamicLink/ApiClient.php
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\DynamicLink;
|
||||
|
||||
use Beste\Json;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Psr\Http\Client\ClientExceptionInterface;
|
||||
use Psr\Http\Message\RequestFactoryInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamFactoryInterface;
|
||||
|
||||
use const JSON_FORCE_OBJECT;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class ApiClient
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ClientInterface $client,
|
||||
private readonly RequestFactoryInterface $requestFactory,
|
||||
private readonly StreamFactoryInterface $streamFactory,
|
||||
) {
|
||||
}
|
||||
|
||||
public function createDynamicLinkRequest(CreateDynamicLink $action): RequestInterface
|
||||
{
|
||||
return $this->requestFactory
|
||||
->createRequest('POST', 'https://firebasedynamiclinks.googleapis.com/v1/shortLinks')
|
||||
->withBody($this->streamFactory->createStream(Json::encode($action, JSON_FORCE_OBJECT)))
|
||||
->withHeader('Content-Type', 'application/json; charset=UTF-8')
|
||||
;
|
||||
}
|
||||
|
||||
public function createStatisticsRequest(GetStatisticsForDynamicLink $action): RequestInterface
|
||||
{
|
||||
$url = sprintf(
|
||||
'https://firebasedynamiclinks.googleapis.com/v1/%s/linkStats?durationDays=%d',
|
||||
rawurlencode($action->dynamicLink()),
|
||||
$action->durationInDays(),
|
||||
);
|
||||
|
||||
return $this->requestFactory
|
||||
->createRequest('GET', $url)
|
||||
->withHeader('Content-Type', 'application/json; charset=UTF-8')
|
||||
;
|
||||
}
|
||||
|
||||
public function createShortenLinkRequest(ShortenLongDynamicLink $action): RequestInterface
|
||||
{
|
||||
return $this->requestFactory
|
||||
->createRequest('POST', 'https://firebasedynamiclinks.googleapis.com/v1/shortLinks')
|
||||
->withBody($this->streamFactory->createStream(Json::encode($action, JSON_FORCE_OBJECT)))
|
||||
->withHeader('Content-Type', 'application/json; charset=UTF-8')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $options
|
||||
*
|
||||
* @throws ClientExceptionInterface
|
||||
*/
|
||||
public function send(RequestInterface $request, array $options = []): ResponseInterface
|
||||
{
|
||||
return $this->client->send($request, $options);
|
||||
}
|
||||
}
|
||||
177
vendor/kreait/firebase-php/src/Firebase/DynamicLink/CreateDynamicLink.php
vendored
Normal file
177
vendor/kreait/firebase-php/src/Firebase/DynamicLink/CreateDynamicLink.php
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\DynamicLink;
|
||||
|
||||
use Beste\Json;
|
||||
use JsonSerializable;
|
||||
use Kreait\Firebase\Value\Url;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type AnalyticsInfoShape from AnalyticsInfo
|
||||
* @phpstan-import-type AndroidInfoShape from AndroidInfo
|
||||
* @phpstan-import-type IOSInfoShape from IOSInfo
|
||||
* @phpstan-import-type NavigationInfoShape from NavigationInfo
|
||||
* @phpstan-import-type SocialMetaTagInfoShape from SocialMetaTagInfo
|
||||
*
|
||||
* @phpstan-type CreateDynamicLinkShape array{
|
||||
* dynamicLinkInfo: array{
|
||||
* link?: non-empty-string,
|
||||
* domainUriPrefix?: non-empty-string,
|
||||
* analyticsInfo?: AnalyticsInfoShape,
|
||||
* androidInfo?: AndroidInfoShape,
|
||||
* iosInfo?: IOSInfoShape,
|
||||
* navigationInfo?: NavigationInfoShape,
|
||||
* socialMetaTagInfo?: SocialMetaTagInfoShape
|
||||
* },
|
||||
* suffix: array{
|
||||
* option: self::WITH_*
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
final class CreateDynamicLink implements JsonSerializable
|
||||
{
|
||||
public const WITH_UNGUESSABLE_SUFFIX = 'UNGUESSABLE';
|
||||
|
||||
public const WITH_SHORT_SUFFIX = 'SHORT';
|
||||
|
||||
/**
|
||||
* @param CreateDynamicLinkShape $data
|
||||
*/
|
||||
private function __construct(private readonly array $data)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CreateDynamicLinkShape $data
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public static function new(): self
|
||||
{
|
||||
return new self([
|
||||
'dynamicLinkInfo' => [],
|
||||
'suffix' => ['option' => self::WITH_UNGUESSABLE_SUFFIX],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The link your app will open. Specify a URL that your app can handle, typically the app's content
|
||||
* or payload, which initiates app-specific logic (such as crediting the user with a coupon or
|
||||
* displaying a welcome screen). This link must be a well-formatted URL, be properly
|
||||
* URL-encoded, use either HTTP or HTTPS, and cannot be another Dynamic Link.
|
||||
*/
|
||||
public static function forUrl(Stringable|string $url): self
|
||||
{
|
||||
return new self([
|
||||
'dynamicLinkInfo' => [
|
||||
'link' => Url::fromString($url)->value,
|
||||
],
|
||||
'suffix' => ['option' => self::WITH_UNGUESSABLE_SUFFIX],
|
||||
]);
|
||||
}
|
||||
|
||||
public function withDynamicLinkDomain(Stringable|string $dynamicLinkDomain): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['dynamicLinkInfo']['domainUriPrefix'] = Url::fromString($dynamicLinkDomain)->value;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public function hasDynamicLinkDomain(): bool
|
||||
{
|
||||
return (bool) ($this->data['dynamicLinkInfo']['domainUriPrefix'] ?? null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AnalyticsInfo|AnalyticsInfoShape $data
|
||||
*/
|
||||
public function withAnalyticsInfo(AnalyticsInfo|array $data): self
|
||||
{
|
||||
$info = $data instanceof AnalyticsInfo ? $data : AnalyticsInfo::fromArray($data);
|
||||
|
||||
$data = $this->data;
|
||||
$data['dynamicLinkInfo']['analyticsInfo'] = Json::decode(Json::encode($info), true);
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AndroidInfo|AndroidInfoShape $data
|
||||
*/
|
||||
public function withAndroidInfo(AndroidInfo|array $data): self
|
||||
{
|
||||
$info = $data instanceof AndroidInfo ? $data : AndroidInfo::fromArray($data);
|
||||
|
||||
$data = $this->data;
|
||||
$data['dynamicLinkInfo']['androidInfo'] = Json::decode(Json::encode($info), true);
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IOSInfo|IOSInfoShape $data
|
||||
*/
|
||||
public function withIOSInfo(IOSInfo|array $data): self
|
||||
{
|
||||
$info = $data instanceof IOSInfo ? $data : IOSInfo::fromArray($data);
|
||||
|
||||
$data = $this->data;
|
||||
$data['dynamicLinkInfo']['iosInfo'] = Json::decode(Json::encode($info), true);
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param NavigationInfo|NavigationInfoShape $data
|
||||
*/
|
||||
public function withNavigationInfo(NavigationInfo|array $data): self
|
||||
{
|
||||
$info = $data instanceof NavigationInfo ? $data : NavigationInfo::fromArray($data);
|
||||
|
||||
$data = $this->data;
|
||||
$data['dynamicLinkInfo']['navigationInfo'] = Json::decode(Json::encode($info), true);
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SocialMetaTagInfo|SocialMetaTagInfoShape $data
|
||||
*/
|
||||
public function withSocialMetaTagInfo(SocialMetaTagInfo|array $data): self
|
||||
{
|
||||
$info = $data instanceof SocialMetaTagInfo ? $data : SocialMetaTagInfo::fromArray($data);
|
||||
|
||||
$data = $this->data;
|
||||
$data['dynamicLinkInfo']['socialMetaTagInfo'] = Json::decode(Json::encode($info), true);
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public function withUnguessableSuffix(): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['suffix']['option'] = self::WITH_UNGUESSABLE_SUFFIX;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public function withShortSuffix(): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['suffix']['option'] = self::WITH_SHORT_SUFFIX;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\DynamicLink\CreateDynamicLink;
|
||||
|
||||
use Beste\Json;
|
||||
use Kreait\Firebase\DynamicLink\CreateDynamicLink;
|
||||
use Kreait\Firebase\Exception\RuntimeException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use UnexpectedValueException;
|
||||
|
||||
final class FailedToCreateDynamicLink extends RuntimeException
|
||||
{
|
||||
private ?CreateDynamicLink $action = null;
|
||||
|
||||
private ?ResponseInterface $response = null;
|
||||
|
||||
public static function withActionAndResponse(CreateDynamicLink $action, ResponseInterface $response): self
|
||||
{
|
||||
$fallbackMessage = 'Failed to create dynamic link';
|
||||
|
||||
try {
|
||||
$message = Json::decode((string) $response->getBody(), true)['error']['message'] ?? $fallbackMessage;
|
||||
} catch (UnexpectedValueException) {
|
||||
$message = $fallbackMessage;
|
||||
}
|
||||
|
||||
$error = new self($message);
|
||||
$error->action = $action;
|
||||
$error->response = $response;
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
public function action(): ?CreateDynamicLink
|
||||
{
|
||||
return $this->action;
|
||||
}
|
||||
|
||||
public function response(): ?ResponseInterface
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
}
|
||||
50
vendor/kreait/firebase-php/src/Firebase/DynamicLink/DynamicLinkStatistics.php
vendored
Normal file
50
vendor/kreait/firebase-php/src/Firebase/DynamicLink/DynamicLinkStatistics.php
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\DynamicLink;
|
||||
|
||||
use Beste\Json;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
final class DynamicLinkStatistics
|
||||
{
|
||||
/**
|
||||
* @var array<string, list<array<string, string>>>
|
||||
*/
|
||||
private array $rawData = [];
|
||||
|
||||
private EventStatistics $events;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
$this->events = EventStatistics::fromArray([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function fromApiResponse(ResponseInterface $response): self
|
||||
{
|
||||
$data = Json::decode((string) $response->getBody(), true);
|
||||
|
||||
$link = new self();
|
||||
$link->rawData = $data;
|
||||
$link->events = EventStatistics::fromArray($data['linkEventStats'] ?? []);
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
public function eventStatistics(): EventStatistics
|
||||
{
|
||||
return $this->events;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<array<string, string>>>
|
||||
*/
|
||||
public function rawData(): array
|
||||
{
|
||||
return $this->rawData;
|
||||
}
|
||||
}
|
||||
133
vendor/kreait/firebase-php/src/Firebase/DynamicLink/EventStatistics.php
vendored
Normal file
133
vendor/kreait/firebase-php/src/Firebase/DynamicLink/EventStatistics.php
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\DynamicLink;
|
||||
|
||||
use Countable;
|
||||
use IteratorAggregate;
|
||||
use Traversable;
|
||||
|
||||
use function array_filter;
|
||||
|
||||
/**
|
||||
* @see https://firebase.google.com/docs/reference/dynamic-links/analytics#response_body
|
||||
* @see https://github.com/googleapis/google-api-nodejs-client/blob/main/src/apis/firebasedynamiclinks/v1.ts
|
||||
*
|
||||
* @phpstan-type EventStatisticsShape array{
|
||||
* linkEventStats: array{
|
||||
* count?: non-empty-string,
|
||||
* event?: non-empty-string,
|
||||
* platform?: non-empty-string
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @implements IteratorAggregate<array>
|
||||
*/
|
||||
final class EventStatistics implements Countable, IteratorAggregate
|
||||
{
|
||||
public const PLATFORM_ANDROID = 'ANDROID';
|
||||
|
||||
public const PLATFORM_DESKTOP = 'DESKTOP';
|
||||
|
||||
public const PLATFORM_IOS = 'IOS';
|
||||
|
||||
// Any click on a Dynamic Link, irrespective to how it is handled and its destinations
|
||||
public const TYPE_CLICK = 'CLICK';
|
||||
|
||||
// Attempts to redirect users, either to the App Store or Play Store to install or update the app,
|
||||
// or to some other destination
|
||||
public const TYPE_REDIRECT = 'REDIRECT';
|
||||
|
||||
// Actual installs (only supported by the Play Store)
|
||||
public const TYPE_APP_INSTALL = 'APP_INSTALL';
|
||||
|
||||
// First-opens after an install
|
||||
public const TYPE_APP_FIRST_OPEN = 'APP_FIRST_OPEN';
|
||||
|
||||
// Re-opens of an app
|
||||
public const TYPE_APP_RE_OPEN = 'APP_RE_OPEN';
|
||||
|
||||
/**
|
||||
* @param list<EventStatisticsShape> $events
|
||||
*/
|
||||
private function __construct(private readonly array $events)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<EventStatisticsShape> $events
|
||||
*/
|
||||
public static function fromArray(array $events): self
|
||||
{
|
||||
return new self($events);
|
||||
}
|
||||
|
||||
public function onAndroid(): self
|
||||
{
|
||||
return $this->filterByPlatform(self::PLATFORM_ANDROID);
|
||||
}
|
||||
|
||||
public function onDesktop(): self
|
||||
{
|
||||
return $this->filterByPlatform(self::PLATFORM_DESKTOP);
|
||||
}
|
||||
|
||||
public function onIOS(): self
|
||||
{
|
||||
return $this->filterByPlatform(self::PLATFORM_IOS);
|
||||
}
|
||||
|
||||
public function clicks(): self
|
||||
{
|
||||
return $this->filterByType(self::TYPE_CLICK);
|
||||
}
|
||||
|
||||
public function redirects(): self
|
||||
{
|
||||
return $this->filterByType(self::TYPE_REDIRECT);
|
||||
}
|
||||
|
||||
public function appInstalls(): self
|
||||
{
|
||||
return $this->filterByType(self::TYPE_APP_INSTALL);
|
||||
}
|
||||
|
||||
public function appFirstOpens(): self
|
||||
{
|
||||
return $this->filterByType(self::TYPE_APP_FIRST_OPEN);
|
||||
}
|
||||
|
||||
public function appReOpens(): self
|
||||
{
|
||||
return $this->filterByType(self::TYPE_APP_RE_OPEN);
|
||||
}
|
||||
|
||||
public function filterByType(string $type): self
|
||||
{
|
||||
return $this->filter(static fn(array $event): bool => ($event['event'] ?? null) === $type);
|
||||
}
|
||||
|
||||
public function filterByPlatform(string $platform): self
|
||||
{
|
||||
return $this->filter(static fn(array $event): bool => ($event['platform'] ?? null) === $platform);
|
||||
}
|
||||
|
||||
public function filter(callable $filter): self
|
||||
{
|
||||
return new self(array_values(array_filter($this->events, $filter)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Traversable<EventStatisticsShape>
|
||||
*/
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
yield from $this->events;
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
return array_sum(array_column($this->events, 'count'));
|
||||
}
|
||||
}
|
||||
42
vendor/kreait/firebase-php/src/Firebase/DynamicLink/GetStatisticsForDynamicLink.php
vendored
Normal file
42
vendor/kreait/firebase-php/src/Firebase/DynamicLink/GetStatisticsForDynamicLink.php
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\DynamicLink;
|
||||
|
||||
use Kreait\Firebase\Value\Url;
|
||||
use Stringable;
|
||||
|
||||
final class GetStatisticsForDynamicLink
|
||||
{
|
||||
public const DEFAULT_DURATION_IN_DAYS = 7;
|
||||
|
||||
private int $durationInDays = self::DEFAULT_DURATION_IN_DAYS;
|
||||
|
||||
private function __construct(private readonly string $dynamicLink)
|
||||
{
|
||||
}
|
||||
|
||||
public static function forLink(Stringable|string $link): self
|
||||
{
|
||||
return new self(Url::fromString($link)->value);
|
||||
}
|
||||
|
||||
public function withDurationInDays(int $durationInDays): self
|
||||
{
|
||||
$action = clone $this;
|
||||
$action->durationInDays = $durationInDays;
|
||||
|
||||
return $action;
|
||||
}
|
||||
|
||||
public function dynamicLink(): string
|
||||
{
|
||||
return $this->dynamicLink;
|
||||
}
|
||||
|
||||
public function durationInDays(): int
|
||||
{
|
||||
return $this->durationInDays;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\DynamicLink\GetStatisticsForDynamicLink;
|
||||
|
||||
use Fig\Http\Message\StatusCodeInterface as StatusCode;
|
||||
use Kreait\Firebase\DynamicLink\GetStatisticsForDynamicLink;
|
||||
use Kreait\Firebase\Exception\RuntimeException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
final class FailedToGetStatisticsForDynamicLink extends RuntimeException
|
||||
{
|
||||
private ?GetStatisticsForDynamicLink $action = null;
|
||||
|
||||
private ?ResponseInterface $response = null;
|
||||
|
||||
public static function withActionAndResponse(GetStatisticsForDynamicLink $action, ResponseInterface $response): self
|
||||
{
|
||||
['code' => $code, 'message' => $message] = self::getCodeAndMessageFromResponse($response);
|
||||
|
||||
$error = new self($message, $code);
|
||||
$error->action = $action;
|
||||
$error->response = $response;
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
public function action(): ?GetStatisticsForDynamicLink
|
||||
{
|
||||
return $this->action;
|
||||
}
|
||||
|
||||
public function response(): ?ResponseInterface
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* code: int,
|
||||
* message: string
|
||||
* }
|
||||
*/
|
||||
private static function getCodeAndMessageFromResponse(ResponseInterface $response): array
|
||||
{
|
||||
$message = match ($code = $response->getStatusCode()) {
|
||||
StatusCode::STATUS_FORBIDDEN => <<<'MSG'
|
||||
Firebase reported missing permissions to access the statistics
|
||||
for the requested Dynamic Link. Please make sure that the
|
||||
Google Dynamic Links API is enabled for your project at
|
||||
|
||||
https://console.cloud.google.com/apis/library/firebasedynamiclinks.googleapis.com
|
||||
|
||||
If the API is enabled, you or the Service Account you're using
|
||||
might be missing the required permissions. You can check by
|
||||
visiting
|
||||
|
||||
https://console.cloud.google.com/iam-admin/serviceaccounts/
|
||||
|
||||
and making sure that the Service Account has one of the following roles
|
||||
|
||||
- Firebase Admin
|
||||
- Firebase Dynamic Links Viewer
|
||||
- Firebase Dynamic Links Admin
|
||||
|
||||
MSG,
|
||||
default => <<<'MSG'
|
||||
Failed to get statistics for dynamic link. Please inspect the
|
||||
response for further details.
|
||||
|
||||
If the response type is not covered by the SDK, please create
|
||||
a new issue in the SDK's GitHub repository and include the
|
||||
HTTP Status code (`$response->getStatusCode()`) and the
|
||||
message body (`$response->getBody()->getContents()`)
|
||||
|
||||
MSG,
|
||||
};
|
||||
|
||||
return [
|
||||
'code' => $code,
|
||||
'message' => $message,
|
||||
];
|
||||
}
|
||||
}
|
||||
129
vendor/kreait/firebase-php/src/Firebase/DynamicLink/IOSInfo.php
vendored
Normal file
129
vendor/kreait/firebase-php/src/Firebase/DynamicLink/IOSInfo.php
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\DynamicLink;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* @phpstan-type IOSInfoShape array{
|
||||
* iosBundleId?: non-empty-string,
|
||||
* iosFallbackLink?: non-empty-string,
|
||||
* iosCustomScheme?: non-empty-string,
|
||||
* iosIpadFallbackLink?: non-empty-string,
|
||||
* iosIpadBundleId?: non-empty-string,
|
||||
* iosAppStoreId?: non-empty-string
|
||||
* }
|
||||
*/
|
||||
final class IOSInfo implements JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @param IOSInfoShape $data
|
||||
*/
|
||||
private function __construct(private readonly array $data)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IOSInfoShape $data
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public static function new(): self
|
||||
{
|
||||
return new self([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The bundle ID of the iOS app to use to open the link. The app must be connected to your project from the
|
||||
* Overview page of the Firebase console. Required for the Dynamic Link to open an iOS app.
|
||||
*
|
||||
* @param non-empty-string $bundleId
|
||||
*/
|
||||
public function withBundleId(string $bundleId): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['iosBundleId'] = $bundleId;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The link to open when the app isn't installed. Specify this to do something other than install your app from the
|
||||
* App Store when the app isn't installed, such as open the mobile web version of the content, or display a
|
||||
* promotional page for your app.
|
||||
*
|
||||
* @param non-empty-string $fallbackLink
|
||||
*/
|
||||
public function withFallbackLink(string $fallbackLink): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['iosFallbackLink'] = $fallbackLink;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Your app's custom URL scheme, if defined to be something other than your app's bundle ID.
|
||||
*
|
||||
* @param non-empty-string $customScheme
|
||||
*/
|
||||
public function withCustomScheme(string $customScheme): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['iosCustomScheme'] = $customScheme;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The link to open on iPads when the app isn't installed. Specify this to do something other than install your
|
||||
* app from the App Store when the app isn't installed, such as open the web version of the content, or
|
||||
* display a promotional page for your app.
|
||||
*
|
||||
* @param non-empty-string $ipadFallbackLink
|
||||
*/
|
||||
public function withIPadFallbackLink(string $ipadFallbackLink): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['iosIpadFallbackLink'] = $ipadFallbackLink;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The bundle ID of the iOS app to use on iPads to open the link. The app must be connected to your project from
|
||||
* the Overview page of the Firebase console.
|
||||
*
|
||||
* @param non-empty-string $iPadBundleId
|
||||
*/
|
||||
public function withIPadBundleId(string $iPadBundleId): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['iosIpadBundleId'] = $iPadBundleId;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Your app's App Store ID, used to send users to the App Store when the app isn't installed.
|
||||
*
|
||||
* @param non-empty-string $appStoreId
|
||||
*/
|
||||
public function withAppStoreId(string $appStoreId): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['iosAppStoreId'] = $appStoreId;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
68
vendor/kreait/firebase-php/src/Firebase/DynamicLink/NavigationInfo.php
vendored
Normal file
68
vendor/kreait/firebase-php/src/Firebase/DynamicLink/NavigationInfo.php
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\DynamicLink;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* @phpstan-type NavigationInfoShape array{
|
||||
* enableForcedRedirect?: bool
|
||||
* }
|
||||
*/
|
||||
final class NavigationInfo implements JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @param NavigationInfoShape $data
|
||||
*/
|
||||
private function __construct(private readonly array $data)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param NavigationInfoShape $data
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public static function new(): self
|
||||
{
|
||||
return new self([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* If set, skip the app preview page when the Dynamic Link is opened, and instead redirect to the app
|
||||
* or store. The app preview page (enabled by default) can more reliably send users to the most appropriate
|
||||
* destination when they open Dynamic Links in apps; however, if you expect a Dynamic Link to be opened
|
||||
* only in apps that can open Dynamic Links reliably without this page, you can disable it with this
|
||||
* parameter. Note: the app preview page is only shown on iOS currently, but may eventually be
|
||||
* shown on Android. This parameter will affect the behavior of the Dynamic Link on both
|
||||
* platforms.
|
||||
*/
|
||||
public function withForcedRedirect(): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['enableForcedRedirect'] = true;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see withForcedRedirect()
|
||||
*/
|
||||
public function withoutForcedRedirect(): self
|
||||
{
|
||||
$data = $this->data;
|
||||
unset($data['enableForcedRedirect']);
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
71
vendor/kreait/firebase-php/src/Firebase/DynamicLink/ShortenLongDynamicLink.php
vendored
Normal file
71
vendor/kreait/firebase-php/src/Firebase/DynamicLink/ShortenLongDynamicLink.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\DynamicLink;
|
||||
|
||||
use JsonSerializable;
|
||||
use Kreait\Firebase\Value\Url;
|
||||
use Stringable;
|
||||
|
||||
/**
|
||||
* @phpstan-type ShortenLongDynamicLinkShape array{
|
||||
* longDynamicLink: non-empty-string,
|
||||
* suffix: array{
|
||||
* option: self::WITH*
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
final class ShortenLongDynamicLink implements JsonSerializable
|
||||
{
|
||||
public const WITH_UNGUESSABLE_SUFFIX = 'UNGUESSABLE';
|
||||
|
||||
public const WITH_SHORT_SUFFIX = 'SHORT';
|
||||
|
||||
/**
|
||||
* @param ShortenLongDynamicLinkShape $data
|
||||
*/
|
||||
private function __construct(private readonly array $data)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* The long dynamic link that has been created as described in {@see https://firebase.google.com/docs/dynamic-links/create-manually}.
|
||||
*/
|
||||
public static function forLongDynamicLink(Stringable|string $url): self
|
||||
{
|
||||
return new self([
|
||||
'longDynamicLink' => Url::fromString($url)->value,
|
||||
'suffix' => ['option' => self::WITH_UNGUESSABLE_SUFFIX],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ShortenLongDynamicLinkShape $data
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public function withUnguessableSuffix(): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['suffix']['option'] = self::WITH_UNGUESSABLE_SUFFIX;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public function withShortSuffix(): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['suffix']['option'] = self::WITH_SHORT_SUFFIX;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\DynamicLink\ShortenLongDynamicLink;
|
||||
|
||||
use Beste\Json;
|
||||
use Kreait\Firebase\DynamicLink\ShortenLongDynamicLink;
|
||||
use Kreait\Firebase\Exception\RuntimeException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use UnexpectedValueException;
|
||||
|
||||
final class FailedToShortenLongDynamicLink extends RuntimeException
|
||||
{
|
||||
private ?ShortenLongDynamicLink $action = null;
|
||||
|
||||
private ?ResponseInterface $response = null;
|
||||
|
||||
public static function withActionAndResponse(ShortenLongDynamicLink $action, ResponseInterface $response): self
|
||||
{
|
||||
$fallbackMessage = 'Failed to shorten long dynamic link';
|
||||
|
||||
try {
|
||||
$message = Json::decode((string) $response->getBody(), true)['error']['message'] ?? $fallbackMessage;
|
||||
} catch (UnexpectedValueException) {
|
||||
$message = $fallbackMessage;
|
||||
}
|
||||
|
||||
$error = new self($message);
|
||||
$error->action = $action;
|
||||
$error->response = $response;
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
public function action(): ?ShortenLongDynamicLink
|
||||
{
|
||||
return $this->action;
|
||||
}
|
||||
|
||||
public function response(): ?ResponseInterface
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
}
|
||||
81
vendor/kreait/firebase-php/src/Firebase/DynamicLink/SocialMetaTagInfo.php
vendored
Normal file
81
vendor/kreait/firebase-php/src/Firebase/DynamicLink/SocialMetaTagInfo.php
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\DynamicLink;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* @phpstan-type SocialMetaTagInfoShape array{
|
||||
* socialTitle?: non-empty-string,
|
||||
* socialDescription?: non-empty-string,
|
||||
* socialImageLink?: non-empty-string
|
||||
* }
|
||||
*/
|
||||
final class SocialMetaTagInfo implements JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @param SocialMetaTagInfoShape $data
|
||||
*/
|
||||
private function __construct(private readonly array $data)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SocialMetaTagInfoShape $data
|
||||
*/
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public static function new(): self
|
||||
{
|
||||
return new self([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The title to use when the Dynamic Link is shared in a social post.
|
||||
*
|
||||
* @param non-empty-string $title
|
||||
*/
|
||||
public function withTitle(string $title): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['socialTitle'] = $title;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The description to use when the Dynamic Link is shared in a social post.
|
||||
*
|
||||
* @param non-empty-string $description
|
||||
*/
|
||||
public function withDescription(string $description): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['socialDescription'] = $description;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL to an image related to this link.
|
||||
*
|
||||
* @param non-empty-string $imageLink
|
||||
*/
|
||||
public function withImageLink(string $imageLink): self
|
||||
{
|
||||
$data = $this->data;
|
||||
$data['socialImageLink'] = $imageLink;
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
200
vendor/kreait/firebase-php/src/Firebase/DynamicLinks.php
vendored
Normal file
200
vendor/kreait/firebase-php/src/Firebase/DynamicLinks.php
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Kreait\Firebase\DynamicLink\ApiClient;
|
||||
use Kreait\Firebase\DynamicLink\CreateDynamicLink;
|
||||
use Kreait\Firebase\DynamicLink\CreateDynamicLink\FailedToCreateDynamicLink;
|
||||
use Kreait\Firebase\DynamicLink\DynamicLinkStatistics;
|
||||
use Kreait\Firebase\DynamicLink\GetStatisticsForDynamicLink;
|
||||
use Kreait\Firebase\DynamicLink\GetStatisticsForDynamicLink\FailedToGetStatisticsForDynamicLink;
|
||||
use Kreait\Firebase\DynamicLink\ShortenLongDynamicLink;
|
||||
use Kreait\Firebase\DynamicLink\ShortenLongDynamicLink\FailedToShortenLongDynamicLink;
|
||||
use Kreait\Firebase\Value\Url;
|
||||
use Psr\Http\Client\ClientExceptionInterface;
|
||||
use Stringable;
|
||||
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* @phpstan-import-type CreateDynamicLinkShape from CreateDynamicLink
|
||||
* @phpstan-import-type ShortenLongDynamicLinkShape from ShortenLongDynamicLink
|
||||
*/
|
||||
final class DynamicLinks implements Contract\DynamicLinks
|
||||
{
|
||||
/**
|
||||
* @param non-empty-string|null $defaultDynamicLinksDomain
|
||||
*/
|
||||
private function __construct(
|
||||
private readonly ?string $defaultDynamicLinksDomain,
|
||||
private readonly ApiClient $apiClient,
|
||||
) {
|
||||
}
|
||||
|
||||
public static function withApiClient(ApiClient $apiClient): self
|
||||
{
|
||||
return new self(null, $apiClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string $dynamicLinksDomain
|
||||
*/
|
||||
public static function withApiClientAndDefaultDomain(ApiClient $apiClient, Stringable|string $dynamicLinksDomain): self
|
||||
{
|
||||
$domainUrl = Url::fromString($dynamicLinksDomain)->value;
|
||||
|
||||
return new self($domainUrl, $apiClient);
|
||||
}
|
||||
|
||||
public function createUnguessableLink($url): DynamicLink
|
||||
{
|
||||
return $this->createDynamicLink($url, CreateDynamicLink::WITH_UNGUESSABLE_SUFFIX);
|
||||
}
|
||||
|
||||
public function createShortLink($url): DynamicLink
|
||||
{
|
||||
return $this->createDynamicLink($url, CreateDynamicLink::WITH_SHORT_SUFFIX);
|
||||
}
|
||||
|
||||
public function createDynamicLink($actionOrParametersOrUrl, ?string $suffixType = null): DynamicLink
|
||||
{
|
||||
$action = $this->ensureCreateAction($actionOrParametersOrUrl);
|
||||
|
||||
if ($this->defaultDynamicLinksDomain !== null && $action->hasDynamicLinkDomain() === false) {
|
||||
$action = $action->withDynamicLinkDomain($this->defaultDynamicLinksDomain);
|
||||
}
|
||||
|
||||
if ($suffixType === CreateDynamicLink::WITH_SHORT_SUFFIX) {
|
||||
$action = $action->withShortSuffix();
|
||||
} elseif ($suffixType === CreateDynamicLink::WITH_UNGUESSABLE_SUFFIX) {
|
||||
$action = $action->withUnguessableSuffix();
|
||||
}
|
||||
|
||||
$request = $this->apiClient->createDynamicLinkRequest($action);
|
||||
|
||||
try {
|
||||
$response = $this->apiClient->send($request, ['http_errors' => false]);
|
||||
} catch (ClientExceptionInterface $e) {
|
||||
throw new FailedToCreateDynamicLink('Failed to create dynamic link: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
return DynamicLink::fromApiResponse($response);
|
||||
}
|
||||
|
||||
throw FailedToCreateDynamicLink::withActionAndResponse($action, $response);
|
||||
}
|
||||
|
||||
public function shortenLongDynamicLink($longDynamicLinkOrAction, ?string $suffixType = null): DynamicLink
|
||||
{
|
||||
$action = $this->ensureShortenAction($longDynamicLinkOrAction);
|
||||
|
||||
if ($suffixType === ShortenLongDynamicLink::WITH_SHORT_SUFFIX) {
|
||||
$action = $action->withShortSuffix();
|
||||
} elseif ($suffixType === ShortenLongDynamicLink::WITH_UNGUESSABLE_SUFFIX) {
|
||||
$action = $action->withUnguessableSuffix();
|
||||
}
|
||||
|
||||
$request = $this->apiClient->createShortenLinkRequest($action);
|
||||
|
||||
try {
|
||||
$response = $this->apiClient->send($request, ['http_errors' => false]);
|
||||
} catch (ClientExceptionInterface $e) {
|
||||
throw new FailedToShortenLongDynamicLink('Failed to shorten long dynamic link: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
return DynamicLink::fromApiResponse($response);
|
||||
}
|
||||
|
||||
throw FailedToShortenLongDynamicLink::withActionAndResponse($action, $response);
|
||||
}
|
||||
|
||||
public function getStatistics(Stringable|string|GetStatisticsForDynamicLink $dynamicLinkOrAction, ?int $durationInDays = null): DynamicLinkStatistics
|
||||
{
|
||||
$action = $this->ensureGetStatisticsAction($dynamicLinkOrAction);
|
||||
|
||||
if ($durationInDays !== null && $durationInDays < 1) {
|
||||
throw new InvalidArgumentException('The duration in days must be a positive integer');
|
||||
}
|
||||
|
||||
if ($durationInDays !== null) {
|
||||
$action = $action->withDurationInDays($durationInDays);
|
||||
}
|
||||
|
||||
$request = $this->apiClient->createStatisticsRequest($action);
|
||||
|
||||
try {
|
||||
$response = $this->apiClient->send($request, ['http_errors' => false]);
|
||||
} catch (ClientExceptionInterface $e) {
|
||||
throw new FailedToGetStatisticsForDynamicLink('Failed to get statistics for Dynamic Link: '.$e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
return DynamicLinkStatistics::fromApiResponse($response);
|
||||
}
|
||||
|
||||
throw FailedToGetStatisticsForDynamicLink::withActionAndResponse($action, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string|CreateDynamicLink|CreateDynamicLinkShape $actionOrParametersOrUrl
|
||||
*/
|
||||
private function ensureCreateAction(Stringable|string|CreateDynamicLink|array $actionOrParametersOrUrl): CreateDynamicLink
|
||||
{
|
||||
if (is_array($actionOrParametersOrUrl)) {
|
||||
return CreateDynamicLink::fromArray($actionOrParametersOrUrl);
|
||||
}
|
||||
|
||||
if ($actionOrParametersOrUrl instanceof CreateDynamicLink) {
|
||||
return $actionOrParametersOrUrl;
|
||||
}
|
||||
|
||||
return CreateDynamicLink::forUrl((string) $actionOrParametersOrUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Stringable|non-empty-string|ShortenLongDynamicLink|ShortenLongDynamicLinkShape $actionOrParametersOrUrl
|
||||
*/
|
||||
private function ensureShortenAction(Stringable|string|ShortenLongDynamicLink|array $actionOrParametersOrUrl): ShortenLongDynamicLink
|
||||
{
|
||||
if (is_array($actionOrParametersOrUrl)) {
|
||||
return ShortenLongDynamicLink::fromArray($actionOrParametersOrUrl);
|
||||
}
|
||||
|
||||
if ($actionOrParametersOrUrl instanceof ShortenLongDynamicLink) {
|
||||
return $actionOrParametersOrUrl;
|
||||
}
|
||||
|
||||
return ShortenLongDynamicLink::forLongDynamicLink((string) $actionOrParametersOrUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throw InvalidArgumentException
|
||||
*/
|
||||
private function ensureGetStatisticsAction(Stringable|string|GetStatisticsForDynamicLink $actionOrUrl): GetStatisticsForDynamicLink
|
||||
{
|
||||
if ($actionOrUrl instanceof GetStatisticsForDynamicLink) {
|
||||
return $actionOrUrl;
|
||||
}
|
||||
|
||||
$actionOrUrl = trim((string) $actionOrUrl);
|
||||
|
||||
if ($actionOrUrl === '') {
|
||||
throw new InvalidArgumentException('A dynamic link must not be empty');
|
||||
}
|
||||
|
||||
return GetStatisticsForDynamicLink::forLink($actionOrUrl);
|
||||
}
|
||||
}
|
||||
14
vendor/kreait/firebase-php/src/Firebase/Exception/AppCheck/ApiConnectionFailed.php
vendored
Normal file
14
vendor/kreait/firebase-php/src/Firebase/Exception/AppCheck/ApiConnectionFailed.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Exception\AppCheck;
|
||||
|
||||
use Kreait\Firebase\Exception\AppCheckException;
|
||||
use Kreait\Firebase\Exception\HasErrors;
|
||||
use Kreait\Firebase\Exception\RuntimeException;
|
||||
|
||||
final class ApiConnectionFailed extends RuntimeException implements AppCheckException
|
||||
{
|
||||
use HasErrors;
|
||||
}
|
||||
12
vendor/kreait/firebase-php/src/Firebase/Exception/AppCheck/AppCheckError.php
vendored
Normal file
12
vendor/kreait/firebase-php/src/Firebase/Exception/AppCheck/AppCheckError.php
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Exception\AppCheck;
|
||||
|
||||
use Kreait\Firebase\Exception\AppCheckException;
|
||||
use Kreait\Firebase\Exception\RuntimeException;
|
||||
|
||||
final class AppCheckError extends RuntimeException implements AppCheckException
|
||||
{
|
||||
}
|
||||
12
vendor/kreait/firebase-php/src/Firebase/Exception/AppCheck/FailedToVerifyAppCheckToken.php
vendored
Normal file
12
vendor/kreait/firebase-php/src/Firebase/Exception/AppCheck/FailedToVerifyAppCheckToken.php
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Exception\AppCheck;
|
||||
|
||||
use Kreait\Firebase\Exception\AppCheckException;
|
||||
use Kreait\Firebase\Exception\RuntimeException;
|
||||
|
||||
final class FailedToVerifyAppCheckToken extends RuntimeException implements AppCheckException
|
||||
{
|
||||
}
|
||||
12
vendor/kreait/firebase-php/src/Firebase/Exception/AppCheck/InvalidAppCheckToken.php
vendored
Normal file
12
vendor/kreait/firebase-php/src/Firebase/Exception/AppCheck/InvalidAppCheckToken.php
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Exception\AppCheck;
|
||||
|
||||
use Kreait\Firebase\Exception\AppCheckException;
|
||||
use Kreait\Firebase\Exception\RuntimeException;
|
||||
|
||||
final class InvalidAppCheckToken extends RuntimeException implements AppCheckException
|
||||
{
|
||||
}
|
||||
12
vendor/kreait/firebase-php/src/Firebase/Exception/AppCheck/InvalidAppCheckTokenOptions.php
vendored
Normal file
12
vendor/kreait/firebase-php/src/Firebase/Exception/AppCheck/InvalidAppCheckTokenOptions.php
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Exception\AppCheck;
|
||||
|
||||
use Kreait\Firebase\Exception\AppCheckException;
|
||||
use Kreait\Firebase\Exception\RuntimeException;
|
||||
|
||||
final class InvalidAppCheckTokenOptions extends RuntimeException implements AppCheckException
|
||||
{
|
||||
}
|
||||
12
vendor/kreait/firebase-php/src/Firebase/Exception/AppCheck/PermissionDenied.php
vendored
Normal file
12
vendor/kreait/firebase-php/src/Firebase/Exception/AppCheck/PermissionDenied.php
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Exception\AppCheck;
|
||||
|
||||
use Kreait\Firebase\Exception\AppCheckException;
|
||||
use Kreait\Firebase\Exception\RuntimeException;
|
||||
|
||||
final class PermissionDenied extends RuntimeException implements AppCheckException
|
||||
{
|
||||
}
|
||||
54
vendor/kreait/firebase-php/src/Firebase/Exception/AppCheckApiExceptionConverter.php
vendored
Normal file
54
vendor/kreait/firebase-php/src/Firebase/Exception/AppCheckApiExceptionConverter.php
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Kreait\Firebase\Exception;
|
||||
|
||||
use Fig\Http\Message\StatusCodeInterface as StatusCode;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Kreait\Firebase\Exception\AppCheck\ApiConnectionFailed;
|
||||
use Kreait\Firebase\Exception\AppCheck\AppCheckError;
|
||||
use Kreait\Firebase\Exception\AppCheck\PermissionDenied;
|
||||
use Kreait\Firebase\Http\ErrorResponseParser;
|
||||
use Psr\Http\Client\NetworkExceptionInterface;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class AppCheckApiExceptionConverter
|
||||
{
|
||||
public function __construct(private readonly ErrorResponseParser $responseParser)
|
||||
{
|
||||
}
|
||||
|
||||
public function convertException(Throwable $exception): AppCheckException
|
||||
{
|
||||
if ($exception instanceof RequestException) {
|
||||
return $this->convertGuzzleRequestException($exception);
|
||||
}
|
||||
|
||||
if ($exception instanceof NetworkExceptionInterface) {
|
||||
return new ApiConnectionFailed('Unable to connect to the API: '.$exception->getMessage(), $exception->getCode(), $exception);
|
||||
}
|
||||
|
||||
return new AppCheckError($exception->getMessage(), $exception->getCode(), $exception);
|
||||
}
|
||||
|
||||
private function convertGuzzleRequestException(RequestException $e): AppCheckException
|
||||
{
|
||||
$message = $e->getMessage();
|
||||
$code = $e->getCode();
|
||||
$response = $e->getResponse();
|
||||
|
||||
if ($response !== null) {
|
||||
$message = $this->responseParser->getErrorReasonFromResponse($response);
|
||||
$code = $response->getStatusCode();
|
||||
}
|
||||
|
||||
return match ($code) {
|
||||
StatusCode::STATUS_UNAUTHORIZED, StatusCode::STATUS_FORBIDDEN => new PermissionDenied($message, $code, $e),
|
||||
default => new AppCheckError($message, $code, $e),
|
||||
};
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user