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,56 @@
name: CI
on:
pull_request:
push:
branches: [ master ]
jobs:
run:
runs-on: ubuntu-18.04
strategy:
fail-fast: false
matrix:
php:
- '7.3'
- '7.4'
- '8.0'
coverage: ['none']
include:
- description: 'Log Code Coverage'
php: '8.0'
coverage: 'xdebug'
name: PHP ${{ matrix.php }} ${{ matrix.description }}
steps:
- name: Checkout
uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: ~/.composer/cache/files
key: ${{ matrix.php }}
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: ${{ matrix.coverage }}
- name: Install dependencies
run: composer install
- name: Run PHPUnit tests
run: vendor/bin/phpunit
if: matrix.coverage == 'none'
- name: PHPUnit tests and Log Code coverage
run: vendor/bin/phpunit --exclude-group proxy --coverage-clover=coverage.xml
if: matrix.coverage == 'xdebug'
- name: Run codecov
uses: codecov/codecov-action@v1
if: matrix.coverage == 'xdebug'
with:
file: './coverage.xml'
fail_ci_if_error: true

View File

@@ -0,0 +1,23 @@
name: Code style
on:
pull_request:
push:
branches: [ master ]
jobs:
php-cs-fixer:
name: PHP-CodeSniffer
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
- name: Install dependencies
run: composer install
- name: Run script
run: ./vendor/bin/phpcs src --standard=psr12 -sp

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Sammy Kaye Powers <me@sammyk.me>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,40 @@
{
"name": "league\/oauth2-facebook",
"description": "Facebook OAuth 2.0 Client Provider for The PHP League OAuth2-Client",
"license": "MIT",
"authors": [
{
"name": "Sammy Kaye Powers",
"email": "me@sammyk.me",
"homepage": "http:\/\/www.sammyk.me"
}
],
"keywords": [
"oauth",
"oauth2",
"client",
"authorization",
"authentication",
"facebook"
],
"require": {
"php": ">=7.3",
"league\/oauth2-client": "^2.0"
},
"require-dev": {
"ext-json": "*",
"phpunit\/phpunit": "^9.4",
"mockery\/mockery": "~1.3.0",
"squizlabs\/php_codesniffer": "~3.0"
},
"autoload": {
"psr-4": {
"Pshowsso\\Scope68f5e85e9608b\\League\\OAuth2\\Client\\": "src\/"
}
},
"autoload-dev": {
"psr-4": {
"Pshowsso\\Scope68f5e85e9608b\\League\\OAuth2\\Client\\Test\\": "tests\/src\/"
}
}
}

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;
}
}