Version 4.5.0

This commit is contained in:
Neo committed 2025-12-19 05:51:58 -08:00
1 parent 1a0c7fd3c2
commit f79dcf067a
3791 files changed
+248032 -76372

No files matched your search

+68 -18
View File
@@ -11,7 +11,7 @@
namespace IPS\Login\Handler\OAuth2;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -32,6 +32,9 @@ class _LinkedIn extends \IPS\Login\Handler\OAuth2
return 'login_handler_Linkedin';
}
/**
* @brief Enable AdminCP logins by default
*/
protected static $enableAcpLoginByDefault = FALSE;
/**
@@ -140,7 +143,7 @@ class _LinkedIn extends \IPS\Login\Handler\OAuth2
protected function scopesToRequest( $additional=NULL )
{
return array(
'r_basicprofile',
'r_liteprofile',
'r_emailaddress',
);
}
@@ -202,10 +205,15 @@ class _LinkedIn extends \IPS\Login\Handler\OAuth2
{
if ( isset( $this->settings['real_name'] ) and $this->settings['real_name'] )
{
return (string) $this->_userData( $accessToken )['formattedName'];
return $this->_getProfileName( $accessToken );
}
return NULL;
}
/**
* @brief Cached email address to make sure we don't request more than once
*/
protected $_cachedEmail = NULL;
/**
* Get authenticated user's email address
@@ -216,7 +224,22 @@ class _LinkedIn extends \IPS\Login\Handler\OAuth2
*/
protected function authenticatedEmail( $accessToken )
{
return $this->_userData( $accessToken )['emailAddress'];
if ( $this->_cachedEmail === NULL )
{
$response = \IPS\Http\Url::external( "https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))" )
->request()
->setHeaders( array( 'Authorization' => "Bearer {$accessToken}" ) )
->get()
->decodeJson();
if ( isset( $response['errorCode'] ) )
{
throw new \IPS\Login\Exception( $response['message'], \IPS\Login\Exception::INTERNAL_ERROR );
}
$this->_cachedEmail = $response['elements'][0]['handle~']['emailAddress'];
}
return $this->_cachedEmail;
}
/**
@@ -231,18 +254,29 @@ class _LinkedIn extends \IPS\Login\Handler\OAuth2
*/
public function userProfilePhoto( \IPS\Member $member )
{
if ( !( $link = $this->_link( $member ) ) )
if ( !( $link = $this->_link( $member ) ) or ( $link['token_expires'] and $link['token_expires'] < time() ) )
{
throw new \IPS\Login\Exception( NULL, \IPS\Login\Exception::INTERNAL_ERROR );
}
$userData = $this->_userData( $link['token_access_token'] );
if ( isset( $userData['pictureUrls'] ) AND isset( $userData['pictureUrls']['_total'] ) AND $userData['pictureUrls']['_total'] )
if( !isset( $this->_userData( $link['token_access_token'] )['profilePicture'] ) )
{
foreach ( $this->_userData( $link['token_access_token'] )['pictureUrls']['values'] as $picture )
return NULL;
}
$userData = $this->_userData( $link['token_access_token'] )['profilePicture']['displayImage~']['elements'];
foreach( array_reverse( $userData ) as $_userData )
{
if ( isset( $_userData['identifiers'] ) )
{
return \IPS\Http\Url::external( $picture );
foreach( $_userData['identifiers'] as $identifier )
{
if( isset( $identifier['identifier'] ) AND $identifier['identifier'] )
{
return \IPS\Http\Url::external( $identifier['identifier'] );
}
}
}
}
return NULL;
@@ -260,28 +294,44 @@ class _LinkedIn extends \IPS\Login\Handler\OAuth2
*/
public function userProfileName( \IPS\Member $member )
{
if ( !( $link = $this->_link( $member ) ) )
if ( !( $link = $this->_link( $member ) ) or ( $link['token_expires'] and $link['token_expires'] < time() ) )
{
throw new \IPS\Login\Exception( NULL, \IPS\Login\Exception::INTERNAL_ERROR );
}
return $this->_userData( $link['token_access_token'] )['formattedName'];
return $this->_getProfileName( $link['token_access_token'] );
$preferredLocale = $this->_userData( $link['token_access_token'] )['firstName']['preferredLocale']['language'] . '_' . $this->_userData( $link['token_access_token'] )['firstName']['preferredLocale']['country'];
}
/**
* Get the user's profile name
*
* @param string $accessToken Access token
* @return string
*/
protected function _getProfileName( $accessToken )
{
$preferredLocale = $this->_userData( $accessToken )['firstName']['preferredLocale']['language'] . '_' . $this->_userData( $accessToken )['firstName']['preferredLocale']['country'];
return ( $this->_userData( $accessToken )['firstName']['localized'][ $preferredLocale ] . ' ' . $this->_userData( $accessToken )['lastName']['localized'][ $preferredLocale ] );
}
/**
* Get link to user's remote profile
* May return NULL if server doesn't support this
*
* @param string $identifier The ID Nnumber/string from remote service
* @param string $identifier The ID Number/string from remote service
* @param string $username The username from remote service
* @return \IPS\Http\Url|NULL
* @throws \IPS\Login\Exception The token is invalid and the user needs to reauthenticate
* @throws \DomainException General error where it is safe to show a message to the user
* @throws \RuntimeException Unexpected error from service
* @note You have to apply to LinkedIn's Partnership program manually to get the profile data necessary to generate the public profile URL (specifically, the vanityName field). As such, we can't generate the URL to your profile beginning with the v2 API.
*/
public function userLink( $identifier, $username )
{
return \IPS\Http\Url::external( "https://www.linkedin.com/in/" )->setQueryString( 'id', $identifier );
return NULL;
}
/**
@@ -327,13 +377,13 @@ class _LinkedIn extends \IPS\Login\Handler\OAuth2
{
if ( !isset( $this->_cachedUserData[ $accessToken ] ) )
{
$response = \IPS\Http\Url::external( "https://api.linkedin.com/v1/people/~:(id,formattedName,emailAddress,picture-urls::(original),member-url-resources)" )
->setQueryString( array( 'format' => 'json' ) )
$response = \IPS\Http\Url::external( "https://api.linkedin.com/v2/me" )
->setQueryString( 'projection', '(id,firstName,lastName,vanityName,profilePicture(displayImage~:playableStreams))' )
->request()
->setHeaders( array( 'Authorization' => "Bearer {$accessToken}" ) )
->get()
->decodeJson();
if ( isset( $response['errorCode'] ) )
{
throw new \IPS\Login\Exception( $response['message'], \IPS\Login\Exception::INTERNAL_ERROR );