This commit is contained in:
2025-10-20 14:10:54 +02:00
parent 75ca8fd840
commit d2c1970ef8
732 changed files with 101915 additions and 2 deletions

View File

@@ -0,0 +1,20 @@
<?php
namespace Pshowsso\Scope68f5e85e9608b\League\OAuth2\Client\Grant;
class FbExchangeToken extends AbstractGrant
{
public function __toString(): string
{
return 'fb_exchange_token';
}
protected function getRequiredRequestParameters(): array
{
return ['fb_exchange_token'];
}
protected function getName(): string
{
return 'fb_exchange_token';
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Pshowsso\Scope68f5e85e9608b\League\OAuth2\Client\Provider;
class AppSecretProof
{
/**
* The app secret proof to sign requests made to the Graph API
* @see https://developers.facebook.com/docs/graph-api/securing-requests#appsecret_proof
*
* @param string $appSecret
* @param string $accessToken
* @return string
*/
public static function create(string $appSecret, string $accessToken): string
{
return hash_hmac('sha256', $accessToken, $appSecret);
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Pshowsso\Scope68f5e85e9608b\League\OAuth2\Client\Provider\Exception;
use Exception;
class FacebookProviderException extends Exception
{
}

View File

@@ -0,0 +1,168 @@
<?php
namespace Pshowsso\Scope68f5e85e9608b\League\OAuth2\Client\Provider;
use Pshowsso\Scope68f5e85e9608b\League\OAuth2\Client\Token\AccessToken;
use Pshowsso\Scope68f5e85e9608b\League\OAuth2\Client\Provider\Exception\FacebookProviderException;
use Pshowsso\Scope68f5e85e9608b\League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use Pshowsso\Scope68f5e85e9608b\League\OAuth2\Client\Token\AccessTokenInterface;
use Pshowsso\Scope68f5e85e9608b\Psr\Http\Message\ResponseInterface;
/**
* @method FacebookUser getResourceOwner(AccessToken $token)
*/
class Facebook extends AbstractProvider
{
/**
* Production Graph API URL.
*
* @const string
*/
protected const BASE_FACEBOOK_URL = 'https://www.facebook.com/';
/**
* Beta tier URL of the Graph API.
*
* @const string
*/
protected const BASE_FACEBOOK_URL_BETA = 'https://www.beta.facebook.com/';
/**
* Production Graph API URL.
*
* @const string
*/
protected const BASE_GRAPH_URL = 'https://graph.facebook.com/';
/**
* Beta tier URL of the Graph API.
*
* @const string
*/
protected const BASE_GRAPH_URL_BETA = 'https://graph.beta.facebook.com/';
/**
* Regular expression used to check for graph API version format
*
* @const string
*/
protected const GRAPH_API_VERSION_REGEX = '~^v\d+\.\d+$~';
/**
* The Graph API version to use for requests.
*
* @var string
*/
protected $graphApiVersion;
/**
* A toggle to enable the beta tier URL's.
*
* @var boolean
*/
private $enableBetaMode = \false;
/**
* The fields to look up when requesting the resource owner
*
* @var string[]
*/
protected $fields;
/**
* @param array $options
* @param array $collaborators
*
* @throws \InvalidArgumentException
*/
public function __construct($options = [], array $collaborators = [])
{
parent::__construct($options, $collaborators);
if (empty($options['graphApiVersion'])) {
$message = 'The "graphApiVersion" option not set. Please set a default Graph API version.';
throw new \InvalidArgumentException($message);
}
if (!preg_match(self::GRAPH_API_VERSION_REGEX, $options['graphApiVersion'])) {
$message = 'The "graphApiVersion" must start with letter "v" followed by version number, ie: "v2.4".';
throw new \InvalidArgumentException($message);
}
$this->graphApiVersion = $options['graphApiVersion'];
if (!empty($options['enableBetaTier']) && $options['enableBetaTier'] === \true) {
$this->enableBetaMode = \true;
}
if (!empty($options['fields']) && is_array($options['fields'])) {
$this->fields = $options['fields'];
} else {
$this->fields = ['id', 'name', 'first_name', 'last_name', 'email', 'hometown', 'picture.type(large){url,is_silhouette}', 'gender', 'age_range'];
// backwards compatibility less than 2.8
if (version_compare(substr($this->graphApiVersion, 1), '2.8') < 0) {
$this->fields[] = 'bio';
}
}
}
public function getBaseAuthorizationUrl(): string
{
return $this->getBaseFacebookUrl() . $this->graphApiVersion . '/dialog/oauth';
}
public function getBaseAccessTokenUrl(array $params): string
{
return $this->getBaseGraphUrl() . $this->graphApiVersion . '/oauth/access_token';
}
public function getDefaultScopes(): array
{
return ['public_profile', 'email'];
}
public function getResourceOwnerDetailsUrl(AccessToken $token): string
{
$appSecretProof = AppSecretProof::create($this->clientSecret, $token->getToken());
return $this->getBaseGraphUrl() . $this->graphApiVersion . '/me?fields=' . implode(',', $this->fields) . '&access_token=' . $token . '&appsecret_proof=' . $appSecretProof;
}
public function getAccessToken($grant = 'authorization_code', array $params = []): AccessTokenInterface
{
if (isset($params['refresh_token'])) {
throw new FacebookProviderException('Facebook does not support token refreshing.');
}
return parent::getAccessToken($grant, $params);
}
/**
* Exchanges a short-lived access token with a long-lived access-token.
*/
public function getLongLivedAccessToken(string $accessToken): AccessTokenInterface
{
$params = ['fb_exchange_token' => $accessToken];
return $this->getAccessToken('fb_exchange_token', $params);
}
protected function createResourceOwner(array $response, AccessToken $token): FacebookUser
{
return new FacebookUser($response);
}
protected function checkResponse(ResponseInterface $response, $data): void
{
if (empty($data['error'])) {
return;
}
$message = $data['error']['type'] . ': ' . $data['error']['message'];
throw new IdentityProviderException($message, $data['error']['code'], $data);
}
/**
* @inheritdoc
*/
protected function getContentType(ResponseInterface $response): string
{
$type = parent::getContentType($response);
// Fix for Facebook's pseudo-JSONP support
if (strpos($type, 'javascript') !== \false) {
return 'application/json';
}
// Fix for Facebook's pseudo-urlencoded support
if (strpos($type, 'plain') !== \false) {
return 'application/x-www-form-urlencoded';
}
return $type;
}
/**
* Get the base Facebook URL.
*/
protected function getBaseFacebookUrl(): string
{
return $this->enableBetaMode ? static::BASE_FACEBOOK_URL_BETA : static::BASE_FACEBOOK_URL;
}
/**
* Get the base Graph API URL.
*/
protected function getBaseGraphUrl(): string
{
return $this->enableBetaMode ? static::BASE_GRAPH_URL_BETA : static::BASE_GRAPH_URL;
}
}

View File

@@ -0,0 +1,193 @@
<?php
namespace Pshowsso\Scope68f5e85e9608b\League\OAuth2\Client\Provider;
class FacebookUser implements ResourceOwnerInterface
{
/**
* @var array
*/
protected $data;
/**
* @param array $response
*/
public function __construct(array $response)
{
$this->data = $response;
if (!empty($response['picture']['data']['url'])) {
$this->data['picture_url'] = $response['picture']['data']['url'];
}
if (isset($response['picture']['data']['is_silhouette'])) {
$this->data['is_silhouette'] = $response['picture']['data']['is_silhouette'];
}
if (!empty($response['cover']['source'])) {
$this->data['cover_photo_url'] = $response['cover']['source'];
}
}
/**
* Returns the ID for the user as a string if present.
*
* @return string|null
*/
public function getId(): ?string
{
return $this->getField('id');
}
/**
* Returns the name for the user as a string if present.
*
* @return string|null
*/
public function getName(): ?string
{
return $this->getField('name');
}
/**
* Returns the first name for the user as a string if present.
*
* @return string|null
*/
public function getFirstName(): ?string
{
return $this->getField('first_name');
}
/**
* Returns the last name for the user as a string if present.
*
* @return string|null
*/
public function getLastName(): ?string
{
return $this->getField('last_name');
}
/**
* Returns the email for the user as a string if present.
*
* @return string|null
*/
public function getEmail(): ?string
{
return $this->getField('email');
}
/**
* Returns the current location of the user as an array.
*
* @return array|null
*/
public function getHometown(): ?array
{
return $this->getField('hometown');
}
/**
* Returns the "about me" bio for the user as a string if present.
*
* @return string|null
* @deprecated The bio field was removed in Graph v2.8
*/
public function getBio(): ?string
{
return $this->getField('bio');
}
/**
* Returns if user has not defined a specific avatar
*
* @return boolean
*/
public function isDefaultPicture(): bool
{
return $this->getField('is_silhouette');
}
/**
* Returns the profile picture of the user as a string if present.
*
* @return string|null
*/
public function getPictureUrl(): ?string
{
return $this->getField('picture_url');
}
/**
* Returns the cover photo URL of the user as a string if present.
*
* @return string|null
* @deprecated
*/
public function getCoverPhotoUrl(): ?string
{
return $this->getField('cover_photo_url');
}
/**
* Returns the gender for the user as a string if present.
*
* @return string|null
*/
public function getGender(): ?string
{
return $this->getField('gender');
}
/**
* Returns the locale of the user as a string if available.
*
* @return string|null
* @deprecated
*/
public function getLocale(): ?string
{
return $this->getField('locale');
}
/**
* Returns the Facebook URL for the user as a string if available.
*
* @return string|null
*/
public function getLink(): ?string
{
return $this->getField('link');
}
/**
* Returns the current timezone offset from UTC (from -24 to 24)
*
* @return float|null
* @deprecated
*/
public function getTimezone(): ?float
{
return $this->getField('timezone');
}
/**
* Returns the lower bound of the user's age range
*
* @return integer|null
*/
public function getMinAge(): ?int
{
return $this->data['age_range']['min'] ?? null;
}
/**
* Returns the upper bound of the user's age range
*
* @return integer|null
*/
public function getMaxAge(): ?int
{
return $this->data['age_range']['max'] ?? null;
}
/**
* Returns all the data obtained about the user.
*
* @return array
*/
public function toArray(): array
{
return $this->data;
}
/**
* Returns a field from the Graph node data.
*
* @return mixed|null
*/
private function getField(string $key)
{
return $this->data[$key] ?? null;
}
}