Version 4.1.19

This commit is contained in:
Neo committed 2025-12-19 05:38:56 -08:00
1 parent 28bd025b35
commit 2bd5025018
2674 files changed
+233518 -77766

No files matched your search

+173 -101
View File
@@ -2,9 +2,9 @@
/**
* @brief Converter Login Handler
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 14 Oct 2014
* @version SVN_VERSION_NUMBER
*/
@@ -76,46 +76,68 @@ class _Convert extends LoginAbstract
throw new \IPS\Login\Exception( \IPS\Member::loggedIn()->language()->addToStack( 'login_err_no_account', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $this->getLoginType( $this->authTypes ) ) ) ) ), \IPS\Login\Exception::NO_ACCOUNT );
}
/* Table switcher for new IPS4 converters */
$table = 'conv_apps';
if ( \IPS\Db::i()->checkForTable( 'convert_apps' ) )
/* Table switcher for new IPS4 converters */
try
{
$table = 'convert_apps';
}
$apps = \IPS\Db::i()->select( 'app_key', $table, array( 'login=?', 1 ) );
foreach( $apps as $sw )
{
/* loop found members */
foreach( $members as $member )
try
{
/* Check the app method exists */
if ( !method_exists( $this, $sw ) )
$apps = \IPS\Db::i()->select( 'app_key', 'convert_apps', array( 'login=?', 1 ) );
}
catch ( \IPS\Db\Exception $e )
{
if ( $e->getCode() === 1146 )
{
continue;
$apps = \IPS\Db::i()->select( 'app_key', 'conv_apps', array( 'login=?', 1 ) );
}
if ( $this->$sw( $member, $values[ 'password' ] ) )
else
{
/* Update password and return */
if ( \IPS\Db::i()->checkForColumn( 'core_members', 'misc' ) )
throw $e;
}
}
foreach( $apps as $sw )
{
/* loop found members */
foreach( $members as $member )
{
/* Check the app method exists */
if ( !method_exists( $this, $sw ) )
{
$member->misc = "";
continue;
}
$member->conv_password = "";
$member->members_pass_salt = $member->generateSalt();
$member->members_pass_hash = $member->encryptedPassword( $values[ 'password' ] );
$member->save();
$member->memberSync( 'onPassChange', array( $values[ 'password' ] ) );
return $member;
/* We still want to use the parent methods (no sense in recreating them) so copy conv_password_extra to misc */
$member->misc = $member->conv_password_extra;
$success = $this->$sw( $member, $values['password'] );
unset( $member->misc );
unset( $member->changed['misc'] );
if ( $success )
{
/* Update password and return */
$member->conv_password = NULL;
$member->conv_password_extra = NULL;
$member->members_pass_salt = $member->generateSalt();
$member->members_pass_hash = $member->encryptedPassword( $values['password'] );
$member->save();
$member->memberSync( 'onPassChange', array( $values['password'] ) );
return $member;
}
}
}
}
catch( \IPS\Db\Exception $e )
{
/* Converter tables no longer exist */
if( $e->getCode() == 1146 )
{
throw new \IPS\Login\Exception( 'generic_error', \IPS\Login\Exception::INTERNAL_ERROR );
}
}
/* Still here? Throw a password incorrect exception */
throw new \IPS\Login\Exception( 'login_err_bad_password', \IPS\Login\Exception::BAD_PASSWORD, NULL, $member );
throw new \IPS\Login\Exception( 'login_err_bad_password', \IPS\Login\Exception::BAD_PASSWORD, NULL, isset( $member ) ? $member : NULL );
}
/**
@@ -191,7 +213,7 @@ class _Convert extends LoginAbstract
* @param string $password Password from form
* @return bool
*/
protected function bbpress_standalone( $member, $password )
protected function bbpressstandalone( $member, $password )
{
return $this->bbpress( $member, $password );
}
@@ -211,7 +233,7 @@ class _Convert extends LoginAbstract
if ( \strlen( $hash ) == 32 )
{
$success = ( bool ) ( \IPS\Login::compareHashes( md5( $password ), $member->conv_password ) );
$success = ( bool ) ( \IPS\Login::compareHashes( $member->conv_password, md5( $password ) ) );
}
// Nope, not md5.
@@ -261,13 +283,10 @@ class _Convert extends LoginAbstract
* @return bool
*/
protected function cs( $member, $password )
{
$hash = $member->conv_password;
{
$encodedHashPass = base64_encode( pack( "H*", sha1( base64_decode( $member->misc ) . $password ) ) );
$single_md5_pass = md5( $password );
if ( \IPS\Login::compareHashes( $encodedHashPass, $hash ) )
if ( \IPS\Login::compareHashes( $member->conv_password, $encodedHashPass ) )
{
return TRUE;
}
@@ -284,7 +303,7 @@ class _Convert extends LoginAbstract
* @param string $password Password from form
* @return bool
*/
protected function CSAuth( $member, $password )
protected function csauth( $member, $password )
{
$wsdl = 'https://internal.auth.com/Service.asmx?wsdl';
$dest = 'https://interal.auth.com/Service.asmx';
@@ -329,6 +348,41 @@ class _Convert extends LoginAbstract
return FALSE;
}
/**
* ExpressionEngine
*
* @param \IPS\Member $member The member
* @param string $password Password from form
* @return bool
*/
protected function expressionengine( $member, $password )
{
$length = \strlen( $member->conv_password );
$providedHash = FALSE;
switch( $length )
{
/* MD5 */
case 32:
$providedHash = md5( $password );
break;
/* SHA1 */
case 40:
$providedHash = sha1( $password );
break;
/* SHA256 */
case 64:
$providedHash = hash( 'sha256', $password );
break;
/* SHA512 */
case 128:
$providedHash = hash( 'sha512', $password );
break;
}
return ( \IPS\Login::compareHashes( $member->conv_password, $providedHash ) ) ? TRUE : FALSE;
}
/**
* FudForum
*
@@ -344,11 +398,11 @@ class _Convert extends LoginAbstract
if ( \strlen( $hash ) == 40 )
{
$success = ( \IPS\Login::compareHashes( sha1( $member->misc . sha1( $password ) ), $hash ) ) ? TRUE : FALSE;
$success = ( \IPS\Login::compareHashes( $member->conv_password, sha1( $member->misc . sha1( $password ) ) ) ) ? TRUE : FALSE;
}
else
{
$success = ( \IPS\Login::compareHashes( $single_md5_pass, $hash ) ) ? TRUE : FALSE;
$success = ( \IPS\Login::compareHashes( $member->conv_password, $single_md5_pass ) ) ? TRUE : FALSE;
}
return $success;
@@ -366,19 +420,19 @@ class _Convert extends LoginAbstract
/* FusionBB Has multiple methods that can be used to check a hash, so we need to cycle through them */
/* md5( md5( salt ) . md5( pass ) ) */
if ( \IPS\Login::compareHashes( md5( md5( $member->misc ) . md5( $password ) ), $member->conv_password ) )
if ( \IPS\Login::compareHashes( $member->conv_password, md5( md5( $member->misc ) . md5( $password ) ) ) )
{
return TRUE;
}
/* md5( md5( salt ) . pass ) */
if ( \IPS\Login::compareHashes( md5( md5( $member->misc ) . $password ), $member->conv_password ) )
if ( \IPS\Login::compareHashes( $member->conv_password, md5( md5( $member->misc ) . $password ) ) )
{
return TRUE;
}
/* md5( pass ) */
if ( \IPS\Login::compareHashes( md5( $password ), $member->conv_password ) )
if ( \IPS\Login::compareHashes( $member->conv_password, md5( $password ) ) )
{
return TRUE;
}
@@ -399,7 +453,7 @@ class _Convert extends LoginAbstract
{
return TRUE;
}
else if ( \IPS\Login::compareHashes( $member->conv_password, md5( $password . $member->name ) ) )
else if ( \IPS\Login::compareHashes( $member->conv_password, md5( $password . mb_strtolower( $member->conv_password_extra ) ) ) )
{
return TRUE;
}
@@ -480,18 +534,18 @@ class _Convert extends LoginAbstract
if ( \strlen( $hash ) == 34 )
{
$success = ( $this->hashCryptPrivate( $password, $hash, $itoa64 ) === $hash ) ? TRUE : FALSE;
$success = ( \IPS\Login::compareHashes( $hash, $this->hashCryptPrivate( $password, $hash, $itoa64 ) ) ) ? TRUE : FALSE;
}
else
{
$success = ( \IPS\Login::compareHashes( $single_md5_pass, $hash ) ) ? TRUE : FALSE;
$success = ( \IPS\Login::compareHashes( $hash, $single_md5_pass ) ) ? TRUE : FALSE;
}
}
/* phpBB2 */
if ( ! $success )
if ( !$success )
{
$success = ( $this->hashCryptPrivate( $single_md5_hash, $hash, $itoa64 ) === $hash ? TRUE : FALSE );
$success = ( \IPS\Login::compareHashes( $hash, $this->hashCryptPrivate( $single_md5_pass, $hash, $itoa64 ) ) ) ? TRUE : FALSE ;
}
return $success;
@@ -504,7 +558,7 @@ class _Convert extends LoginAbstract
* @param string $password Password from form
* @return bool
*/
protected function phpbb_legacy( $member, $password )
protected function phpbblegacy( $member, $password )
{
return $this->phpbb( $member, $password );
}
@@ -518,6 +572,13 @@ class _Convert extends LoginAbstract
*/
protected function vanilla( $member, $password )
{
/* Vanilla 2.2 */
if( preg_match( '/^\$2[ay]\$(0[4-9]|[1-2][0-9]|3[0-1])\$[a-zA-Z0-9.\/]{53}/', $member->conv_password ) )
{
$ph = new PasswordHash( 8, TRUE );
return $ph->CheckPassword( $password, $member->conv_password ) ? TRUE : FALSE;
}
if ( \IPS\Login::compareHashes( $member->conv_password, md5( md5( str_replace( '&#39;', "'", html_entity_decode( $password ) ) ) . $member->misc ) ) )
{
return TRUE;
@@ -566,7 +627,7 @@ class _Convert extends LoginAbstract
*/
protected function vb5connect( $member, $password )
{
if ( strpos( $member->misc, 'blowfish' ) === FALSE and strpos( $member->misc, 'legacy' ) === FALSE )
if ( \strpos( $member->misc, 'blowfish' ) === FALSE and \strpos( $member->misc, 'legacy' ) === FALSE )
{
return $this->vbulletin( $member, $password );
}
@@ -575,6 +636,18 @@ class _Convert extends LoginAbstract
return $this->vb51connect( $member, $password );
}
}
/**
* vBulletin 5 Wrapper Method
*
* @param \IPS|Member $member
* @param string $password
* @return bool
*/
public function vbulletin5( $member, $password )
{
return $this->vb5connect( $member, $password );
}
/**
* Vbulletin 4
@@ -613,7 +686,7 @@ class _Convert extends LoginAbstract
* @param string $password Password from form
* @return bool
*/
protected function vbulletin_legacy( $member, $password )
protected function vbulletinlegacy( $member, $password )
{
return $this->vbulletin( $member, $password );
}
@@ -625,7 +698,7 @@ class _Convert extends LoginAbstract
* @param string $password Password from form
* @return bool
*/
protected function vbulletin_legacy36( $member, $password )
protected function vbulletinlegacy36( $member, $password )
{
return $this->vbulletin( $member, $password );
}
@@ -680,9 +753,9 @@ class _Convert extends LoginAbstract
* @param string $password Password from form
* @return bool
*/
protected function smf_legacy( $member, $password )
protected function smflegacy( $member, $password )
{
if ( \IPS\Login::compareHashes( sha1( strtolower( $member->name ) . $password ), $member->conv_password ) )
if ( \IPS\Login::compareHashes( $member->conv_password, sha1( strtolower( $member->name ) . $password ) ) )
{
return TRUE;
}
@@ -699,7 +772,7 @@ class _Convert extends LoginAbstract
* @param string $password Password from form
* @return bool
*/
protected function telligent_cs( $member, $password )
protected function telligentcs( $member, $password )
{
return $this->cs( $member, $password );
}
@@ -726,7 +799,7 @@ class _Convert extends LoginAbstract
{
return TRUE;
}
elseif ( $this->woltlab_legacy( $member, $password ) )
elseif ( $this->woltlablegacy( $member, $password ) )
{
return TRUE;
}
@@ -741,7 +814,7 @@ class _Convert extends LoginAbstract
* @param string $password Password from form
* @return bool
*/
protected function woltlab_legacy( $member, $password )
protected function woltlablegacy( $member, $password )
{
if ( \IPS\Login::compareHashes( $member->conv_password, sha1( $member->misc . sha1( $member->misc . sha1( $password ) ) ) ) )
{
@@ -764,7 +837,7 @@ class _Convert extends LoginAbstract
{
$success = FALSE;
if ( \IPS\Login::compareHashes( webWizAuth::HashEncode( $password . $member->misc ), $member->conv_password ) )
if ( \IPS\Login::compareHashes( $member->conv_password, webWizAuth::HashEncode( $password . $member->misc ) ) )
{
$success = TRUE;
}
@@ -865,7 +938,7 @@ class _Convert extends LoginAbstract
*/
protected function phpfusion( $member, $password )
{
return ( bool ) \IPS\Login::compareHashes( md5( md5( $password ) ), $member->conv_password );
return ( bool ) \IPS\Login::compareHashes( $member->conv_password, md5( md5( $password ) ) );
}
/**
@@ -893,7 +966,7 @@ class _Convert extends LoginAbstract
}
else
{
$success = ( \IPS\Login::compareHashes( md5( $password ), $hash ) ) ? TRUE : FALSE;
$success = ( \IPS\Login::compareHashes( $hash, md5( $password ) ) ) ? TRUE : FALSE;
}
return $success;
@@ -908,23 +981,23 @@ class _Convert extends LoginAbstract
*/
protected function punbb( $member, $password )
{
$success = false;
$hash = $member->conv_password;
$success = FALSE;
if ( \strlen( $hash ) == 40 )
if ( mb_strlen( $member->conv_password ) == 40 )
{
if ( \IPS\Login::compareHashes( $hash, sha1( $member->misc . sha1( $password ) ) ) )
/* Password with salt */
$success = \IPS\Login::compareHashes( $member->conv_password, sha1( $member->conv_password_extra . sha1( $password ) ) );
if ( !$success )
{
$success = TRUE;
}
elseif ( \IPS\Login::compareHashes( $hash, sha1( $password ) ) )
{
$success = TRUE;
/* No salt */
$success = \IPS\Login::compareHashes( $member->conv_password, sha1( $password ) );
}
}
else
{
$success = ( md5( $password ) == $hash ) ? TRUE : FALSE;
/* MD5 */
$success = \IPS\Login::compareHashes( $member->conv_password, md5( $password ) );
}
return $success;
@@ -954,20 +1027,20 @@ class _Convert extends LoginAbstract
$hash = $member->members_pass_hash;
$salt = $member->members_pass_salt;
if ( \IPS\Login::compareHashes( md5( $password ), $hash ) )
if ( \IPS\Login::compareHashes( $hash, md5( $password ) ) )
{
return TRUE;
}
// Not using md5, UBB salts the password with the password
// IPB already md5'd it though, *sigh*
if ( \IPS\Login::compareHashes( md5( md5( $salt ) . crypt( $password, $password ) ), $hash ) )
if ( \IPS\Login::compareHashes( $hash, md5( md5( $salt ) . crypt( $password, $password ) ) ) )
{
return TRUE;
}
// Now standard IPB check.
if ( \IPS\Login::compareHashes( md5( md5( $salt ) . md5( $password ) ), $hash ) )
if ( \IPS\Login::compareHashes( $hash, md5( md5( $salt ) . md5( $password ) ) ) )
{
return TRUE;
}
@@ -986,8 +1059,6 @@ class _Convert extends LoginAbstract
{
$success = FALSE;
$password = ( trim( $_POST[ 'password' ] ) != '' ) ? trim( $_POST[ 'password' ] ) : $password;
// If the hash is still md5...
if ( \strlen( $member->conv_password ) <= 32 )
{
@@ -997,7 +1068,8 @@ class _Convert extends LoginAbstract
else
{
// Init the pass class
$ph = new PasswordHash( 8, TRUE );
$ph = new PasswordHash;
$ph->PasswordHash( 8, TRUE );
// Check it
$success = $ph->CheckPassword( $password, $member->conv_password ) ? TRUE : FALSE;
@@ -1020,12 +1092,12 @@ class _Convert extends LoginAbstract
$output = '*';
// Check for correct hash
if ( substr( $setting, 0, 3 ) != '$H$' )
if ( \substr( $setting, 0, 3 ) != '$H$' )
{
return $output;
}
$count_log2 = strpos( $itoa64, $setting[3] );
$count_log2 = \strpos( $itoa64, $setting[3] );
if ( $count_log2 < 7 || $count_log2 > 30 )
{
@@ -1033,7 +1105,7 @@ class _Convert extends LoginAbstract
}
$count = 1 << $count_log2;
$salt = substr( $setting, 4, 8 );
$salt = \substr( $setting, 4, 8 );
if ( \strlen($salt) != 8 )
{
@@ -1069,7 +1141,7 @@ class _Convert extends LoginAbstract
while ( --$count );
}
$output = substr( $setting, 0, 12 );
$output = \substr( $setting, 0, 12 );
$output .= $this->_hashEncode64( $hash, 16, $itoa64 );
return $output;
@@ -1189,7 +1261,7 @@ class PasswordHash
$this->random_state = md5( microtime() . $this->random_state );
$output .= pack( 'H*', md5( $this->random_state ) );
}
$output = substr( $output, 0, $count );
$output = \substr( $output, 0, $count );
}
return $output;
@@ -1229,19 +1301,19 @@ class PasswordHash
function crypt_private( $password, $setting )
{
$output = '*0';
if ( substr( $setting, 0, 2 ) == $output )
if ( \substr( $setting, 0, 2 ) == $output )
$output = '*1';
if ( substr( $setting, 0, 3 ) != '$P$' )
if ( \substr( $setting, 0, 3 ) != '$P$' )
return $output;
$count_log2 = strpos( $this->itoa64, $setting[ 3 ] );
$count_log2 = \strpos( $this->itoa64, $setting[ 3 ] );
if ( $count_log2 < 7 || $count_log2 > 30 )
return $output;
$count = 1 << $count_log2;
$salt = substr( $setting, 4, 8 );
$salt = \substr( $setting, 4, 8 );
if ( \strlen( $salt ) != 8 )
return $output;
@@ -1270,7 +1342,7 @@ class PasswordHash
while ( -- $count );
}
$output = substr( $setting, 0, 12 );
$output = \substr( $setting, 0, 12 );
$output .= $this->encode64( $hash, 16 );
return $output;
@@ -1395,7 +1467,7 @@ class webWizAuth
for( $intPos = 1 ; $intPos <= \strlen( $strSecret ) ; $intPos = $intPos + 56 )
{
$strEncode = substr( $strSecret, $intPos - 1, 56 ); //get 56 character chunks
$strEncode = \substr( $strSecret, $intPos - 1, 56 ); //get 56 character chunks
$strEncode = self::WordToBinary( $strEncode ); //convert to binary
$strEncode = self::PadBinary( $strEncode ); //make it 512 bites
$strEncode = self::BlockToHex( $strEncode ); //convert to hex value
@@ -1406,11 +1478,11 @@ class webWizAuth
$strEncode = self::DigestHex( $strEncode, $strH[ 0 ], $strH[ 1 ], $strH[ 2 ], $strH[ 3 ], $strH[ 4 ] );
//Combine the old digest with the new digest
$strH[ 0 ] = self::HexAdd( substr( $strEncode, 0, 8 ), $strH[ 0 ] );
$strH[ 1 ] = self::HexAdd( substr( $strEncode, 8, 8 ), $strH[ 1 ] );
$strH[ 2 ] = self::HexAdd( substr( $strEncode, 16, 8 ), $strH[ 2 ] );
$strH[ 3 ] = self::HexAdd( substr( $strEncode, 24, 8 ), $strH[ 3 ] );
$strH[ 4 ] = self::HexAdd( substr( $strEncode, \strlen( $strEncode ) - ( 8 ) ), $strH[ 4 ] );
$strH[ 0 ] = self::HexAdd( \substr( $strEncode, 0, 8 ), $strH[ 0 ] );
$strH[ 1 ] = self::HexAdd( \substr( $strEncode, 8, 8 ), $strH[ 1 ] );
$strH[ 2 ] = self::HexAdd( \substr( $strEncode, 16, 8 ), $strH[ 2 ] );
$strH[ 3 ] = self::HexAdd( \substr( $strEncode, 24, 8 ), $strH[ 3 ] );
$strH[ 4 ] = self::HexAdd( \substr( $strEncode, \strlen( $strEncode ) - ( 8 ) ), $strH[ 4 ] );
}
//This is the final Hex Digest
@@ -1541,7 +1613,7 @@ class webWizAuth
$strBinary = '';
for( $intPos = 1 ; $intPos <= \strlen( $strWord ) ; $intPos = $intPos + 1 )
{
$strTemp = substr( $strWord, intval( $intPos ) - 1, 1 );
$strTemp = \substr( $strWord, intval( $intPos ) - 1, 1 );
$strBinary = $strBinary . self::IntToBinary( ord( $strTemp ) );
}
@@ -1599,7 +1671,7 @@ class webWizAuth
$strHex = '';
for( $intPos = 1 ; $intPos <= \strlen( $strBinary ) ; $intPos = $intPos + 4 )
{
$strHex = $strHex . self::BinaryToHex( substr( $strBinary, $intPos - 1, 4 ) );
$strHex = $strHex . self::BinaryToHex( \substr( $strBinary, $intPos - 1, 4 ) );
}
return $strHex;
}
@@ -1621,7 +1693,7 @@ class webWizAuth
//divide the Hex block into 16 hex words
for( $intPos = 0 ; $intPos <= ( \strlen( $strHex ) / 8 ) - 1 ; $intPos = $intPos + 1 )
{
$strWords[ intval( $intPos ) ] = substr( $strHex, ( intval( $intPos ) * 8 ) + 1 - 1, 8 );
$strWords[ intval( $intPos ) ] = \substr( $strHex, ( intval( $intPos ) * 8 ) + 1 - 1, 8 );
}
//encode the Hex words using the constants above
@@ -1782,7 +1854,7 @@ class webWizAuth
}
static protected function BinaryShift( $strBinary, $intPos )
{
return substr( $strBinary, \strlen( $strBinary ) - ( \strlen( $strBinary ) - intval( $intPos ) ) ) . substr( $strBinary, 0, intval( $intPos ) );
return \substr( $strBinary, \strlen( $strBinary ) - ( \strlen( $strBinary ) - intval( $intPos ) ) ) . \substr( $strBinary, 0, intval( $intPos ) );
}
// Function performs an exclusive or function on each position of two binary values
@@ -1791,9 +1863,9 @@ class webWizAuth
$strBinaryFinal = '';
for( $intPos = 1 ; $intPos <= \strlen( $strBin1 ) ; $intPos = $intPos + 1 )
{
switch( substr( $strBin1, intval( $intPos ) - 1, 1 ) )
switch( \substr( $strBin1, intval( $intPos ) - 1, 1 ) )
{
case substr( $strBin2, intval( $intPos ) - 1, 1 ) :
case \substr( $strBin2, intval( $intPos ) - 1, 1 ) :
$strBinaryFinal = $strBinaryFinal . "0";
break;
default :
@@ -1811,7 +1883,7 @@ class webWizAuth
$strBinaryFinal = '';
for( $intPos = 1 ; $intPos <= \strlen( $strBin1 ) ; $intPos = $intPos + 1 )
{
if ( substr( $strBin1, intval( $intPos ) - 1, 1 ) == "1" || substr( $strBin2, intval( $intPos ) - 1, 1 ) == "1" )
if ( \substr( $strBin1, intval( $intPos ) - 1, 1 ) == "1" || \substr( $strBin2, intval( $intPos ) - 1, 1 ) == "1" )
{
$strBinaryFinal = $strBinaryFinal . "1";
}
@@ -1830,7 +1902,7 @@ class webWizAuth
$strBinaryFinal = '';
for( $intPos = 1 ; $intPos <= \strlen( $strBin1 ) ; $intPos = $intPos + 1 )
{
if ( substr( $strBin1, intval( $intPos ) - 1, 1 ) == "1" && substr( $strBin2, intval( $intPos ) - 1, 1 ) == "1" )
if ( \substr( $strBin1, intval( $intPos ) - 1, 1 ) == "1" && \substr( $strBin2, intval( $intPos ) - 1, 1 ) == "1" )
{
$strBinaryFinal = $strBinaryFinal . "1";
}
@@ -1849,7 +1921,7 @@ class webWizAuth
$strBinaryFinal = '';
for( $intPos = 1 ; $intPos <= \strlen( $strBinary ) ; $intPos = $intPos + 1 )
{
if ( substr( $strBinary, intval( $intPos ) - 1, 1 ) == "1" )
if ( \substr( $strBinary, intval( $intPos ) - 1, 1 ) == "1" )
{
$strBinaryFinal = $strBinaryFinal . "0";
}
@@ -1868,7 +1940,7 @@ class webWizAuth
$strTemp = '';
for( $intPos = 1 ; $intPos <= \strlen( $strHex ) ; $intPos = $intPos + 1 )
{
$strTemp = $strTemp . self::HexToBinary( substr( $strHex, intval( $intPos ) - 1, 1 ) );
$strTemp = $strTemp . self::HexToBinary( \substr( $strHex, intval( $intPos ) - 1, 1 ) );
}
return $strTemp;
+4 -3
View File
@@ -2,9 +2,9 @@
/**
* @brief Login Exception Class
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 26 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -58,7 +58,8 @@ class _Exception extends \DomainException
{
if ( $code === static::BAD_PASSWORD and $member !== NULL )
{
$failedLogins = $member->failed_logins;
/* $member->failed_logins may not be an array explicitly when upgrading due to past bugs */
$failedLogins = is_array( $member->failed_logins ) ? $member->failed_logins : array();
$failedLogins[ \IPS\Request::i()->ipAddress() ][] = time();
$member->failed_logins = $failedLogins;
$member->save();
+5 -5
View File
@@ -2,9 +2,9 @@
/**
* @brief External Database Login Handler
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 18 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -65,7 +65,7 @@ class _External extends LoginAbstract
}
if ( $this->settings['db_extra'] )
{
$where[0] .= $this->settings['db_extra'];
$where[] = array( $this->settings['db_extra'] );
}
/* Fetch result */
@@ -226,7 +226,7 @@ class _External extends LoginAbstract
try
{
$result = $this->externalDb()->select( implode( ',', $select ), $this->settings['db_table'], $this->settings['db_extra'] )->first();
$result = $this->externalDb()->select( implode( ',', $select ), $this->settings['db_table'], ( isset( $this->settings['db_extra'] ) AND $this->settings['db_extra'] != '' ) ? array( $this->settings['db_extra'] ) : NULL )->first();
}
catch ( \UnderflowException $e )
{
@@ -394,4 +394,4 @@ class _External extends LoginAbstract
$this->externalDb()->update( $this->settings['db_table'], array( $this->settings['db_col_user'] => $newUsername ), array( $this->settings['db_col_user'] . '=?', $oldUsername ) );
}
}
}
}
+43 -24
View File
@@ -2,9 +2,9 @@
/**
* @brief Facebook Login Handler
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 18 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -28,32 +28,43 @@ class _Facebook extends LoginAbstract
*/
public static $icon = 'facebook-square';
/**
* @brief Share Service
*/
public static $shareService = 'facebook';
/**
* Get Form
*
* @param \IPS\Http\Url $url The URL for the login page
* @param \IPS\Http\Url $url The URL for the login page
* @param bool $ucp Is UCP? (as opposed to login form)
* @param \IPS\Http\Url $destination The URL to redirect to after a successful login
* @return string
*/
public function loginForm( $url, $ucp=FALSE )
public function loginForm( \IPS\Http\Url $url, $ucp = FALSE, \IPS\Http\Url $destination = NULL )
{
$url = \IPS\Http\Url::internal( 'applications/core/interface/facebook/auth.php', 'none' );
if ( $ucp )
{
$state = "ucp-" . \IPS\Session::i()->csrfKey;
}
else
{
$state = \IPS\Dispatcher::i()->controllerLocation . "-" . \IPS\Session::i()->csrfKey;
}
$scope = 'email';
if ( \IPS\Settings::i()->profile_comments )
{
$scope .= ',user_status,publish_actions';
if ( isset( $this->settings['allow_status_import'] ) and $this->settings['allow_status_import'] )
{
$scope .= ',user_posts';
}
if ( isset( $this->settings['autoshare'] ) and $this->settings['autoshare'] )
{
$scope .= ',publish_actions';
}
}
return \IPS\Theme::i()->getTemplate( 'login', 'core', 'global' )->facebook( "https://www.facebook.com/dialog/oauth?client_id={$this->settings['app_id']}&amp;scope={$scope}&amp;redirect_uri=".urlencode( $url ) . "&amp;state={$state}" );
$url = \IPS\Http\Url::external( "https://www.facebook.com/dialog/oauth" )->setQueryString( array(
'client_id' => $this->settings['app_id'],
'scope' => $scope,
'redirect_uri' => (string) \IPS\Http\Url::internal( 'applications/core/interface/facebook/auth.php', 'none', NULL, array(), \IPS\Settings::i()->logins_over_https ? \IPS\Http\Url::PROTOCOL_HTTPS : 0 ),
'state' => ( $ucp ? 'ucp' : \IPS\Dispatcher::i()->controllerLocation ) . '-' . \IPS\Session::i()->csrfKey . '-' . ( $destination ? base64_encode( $destination ) : '' )
) );
return \IPS\Theme::i()->getTemplate( 'login', 'core', 'global' )->facebook( (string) $url );
}
/**
@@ -81,7 +92,7 @@ class _Facebook extends LoginAbstract
{
$response = \IPS\Http\Url::external( "https://graph.facebook.com/oauth/access_token" )->request()->post( array(
'client_id' => $this->settings['app_id'],
'redirect_uri' => (string) \IPS\Http\Url::internal( 'applications/core/interface/facebook/auth.php', 'none' ),
'redirect_uri' => (string) \IPS\Http\Url::internal( 'applications/core/interface/facebook/auth.php', 'none', NULL, array(), \IPS\Settings::i()->logins_over_https ? \IPS\Http\Url::PROTOCOL_HTTPS : 0 ),
'client_secret' => $this->settings['app_secret'],
'code' => \IPS\Request::i()->code
) )->decodeQueryString('access_token');
@@ -110,7 +121,7 @@ class _Facebook extends LoginAbstract
$appSecretProof = hash_hmac( 'sha256', $response['access_token'], $this->settings['app_secret'] );
/* Get the user data */
$userData = \IPS\Http\Url::external( "https://graph.facebook.com/me?access_token={$response['access_token']}&appsecret_proof={$appSecretProof}" )->request()->get()->decodeJson();
$userData = \IPS\Http\Url::external( "https://graph.facebook.com/me?fields=email,id,name&access_token={$response['access_token']}&appsecret_proof={$appSecretProof}" )->request()->get()->decodeJson();
/* Find or create member */
$member = $this->createOrUpdateAccount( $member ?: \IPS\Member::load( $userData['id'], 'fb_uid' ), array(
@@ -163,11 +174,19 @@ class _Facebook extends LoginAbstract
),
);
return array(
'app_id' => new \IPS\Helpers\Form\Text( 'login_facebook_app', ( isset( $this->settings['app_id'] ) ) ? $this->settings['app_id'] : '', TRUE ),
'app_secret' => new \IPS\Helpers\Form\Text( 'login_facebook_secret', ( isset( $this->settings['app_secret'] ) ) ? $this->settings['app_secret'] : '', TRUE ),
'real_name' => new \IPS\Helpers\Form\YesNo( 'login_real_name', ( isset( $this->settings['real_name'] ) ) ? $this->settings['real_name'] : FALSE, TRUE )
$return = array(
'app_id' => new \IPS\Helpers\Form\Text( 'login_facebook_app', ( isset( $this->settings['app_id'] ) ) ? $this->settings['app_id'] : '', TRUE ),
'app_secret' => new \IPS\Helpers\Form\Text( 'login_facebook_secret', ( isset( $this->settings['app_secret'] ) ) ? $this->settings['app_secret'] : '', TRUE ),
'real_name' => new \IPS\Helpers\Form\YesNo( 'login_real_name', ( isset( $this->settings['real_name'] ) ) ? $this->settings['real_name'] : FALSE, TRUE )
);
if ( \IPS\Settings::i()->profile_comments )
{
$return['allow_status_import'] = new \IPS\Helpers\Form\YesNo( 'login_facebook_allow_status_import', ( isset( $this->settings['allow_status_import'] ) ) ? $this->settings['allow_status_import'] : FALSE, FALSE );
}
return $return;
}
/**
+20 -17
View File
@@ -2,9 +2,9 @@
/**
* @brief Google Login Handler
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 20 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -31,33 +31,35 @@ class _Google extends LoginAbstract
/**
* Get Form
*
* @param string $url The URL for the login page
* @param bool $ucp Is UCP? (as opposed to login form)
* @param \IPS\Http\Url $url The URL for the login page
* @param bool $ucp Is UCP? (as opposed to login form)
* @param \IPS\Http\Url $destination The URL to redirect to after a successful login
* @return string
*/
public function loginForm( $url, $ucp=FALSE )
public function loginForm( \IPS\Http\Url $url, $ucp = FALSE, \IPS\Http\Url $destination = NULL )
{
return \IPS\Theme::i()->getTemplate( 'login', 'core', 'global' )->google( (string) $this->_googleSignInUrl( ( $ucp ? 'ucp' : \IPS\Dispatcher::i()->controllerLocation ), $ucp ) );
return \IPS\Theme::i()->getTemplate( 'login', 'core', 'global' )->google( (string) $this->_googleSignInUrl( ( $ucp ? 'ucp' : \IPS\Dispatcher::i()->controllerLocation ), $ucp, $destination ) );
}
/**
* Get sign in URL
*
* @param string $base Controls where the user is taken back to
* @param bool $forcePrompt Force prompt? Will mean user is shown the Google site even if previously authenticated. Only to be used if a new refresh token is needed.
* @param string $base Controls where the user is taken back to
* @param bool $forcePrompt Force prompt? Will mean user is shown the Google site even if previously authenticated. Only to be used if a new refresh token is needed.
* @param \IPS\Http\Url $destination The URL to redirect to after a successful login
* @return \IPS\Http\Url
*/
protected function _googleSignInUrl( $base, $forcePrompt )
protected function _googleSignInUrl( $base, $forcePrompt, \IPS\Http\Url $destination = NULL )
{
$params = array(
'response_type' => 'code',
'client_id' => $this->settings['client_id'],
'redirect_uri' => (string) \IPS\Http\Url::internal( 'applications/core/interface/google/auth.php', 'none' ),
'redirect_uri' => (string) \IPS\Http\Url::internal( 'applications/core/interface/google/auth.php', 'none', NULL, array(), \IPS\Settings::i()->logins_over_https ? \IPS\Http\Url::PROTOCOL_HTTPS : 0 ),
'scope' => 'https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile',
'access_type' => 'offline',
'state' => $base . '-' . \IPS\Session::i()->csrfKey
'state' => $base . '-' . \IPS\Session::i()->csrfKey . '-' . ( $destination ? base64_encode( $destination ) : '' )
);
if ( $forcePrompt )
{
$params['approval_prompt'] = 'force';
@@ -89,7 +91,7 @@ class _Google extends LoginAbstract
'code' => \IPS\Request::i()->code,
'client_id' => $this->settings['client_id'],
'client_secret' => $this->settings['client_secret'],
'redirect_uri' => (string) \IPS\Http\Url::internal( 'applications/core/interface/google/auth.php', 'none' ),
'redirect_uri' => (string) \IPS\Http\Url::internal( 'applications/core/interface/google/auth.php', 'none', NULL, array(), \IPS\Settings::i()->logins_over_https ? \IPS\Http\Url::PROTOCOL_HTTPS : 0 ),
'grant_type' => 'authorization_code',
) )->decodeJson();
if ( isset( $response['error'] ) or !isset( $response['access_token'] ) )
@@ -98,8 +100,7 @@ class _Google extends LoginAbstract
}
/* Get user data */
$userData = \IPS\Http\Url::external( "https://www.googleapis.com/plus/v1/people/me?access_token={$response['access_token']}" )->request()->get()->decodeJson('id');
$email = $userData = \IPS\Http\Url::external( "https://www.googleapis.com/oauth2/v1/userinfo?access_token={$response['access_token']}" )->request()->get()->decodeJson('email');
$userData = \IPS\Http\Url::external( "https://www.googleapis.com/oauth2/v1/userinfo?access_token={$response['access_token']}" )->request()->get()->decodeJson();
/* Set member properties */
$memberProperties = array( 'google_id' => $userData['id'] );
@@ -193,12 +194,14 @@ class _Google extends LoginAbstract
if ( $response->httpResponseCode != 200 )
{
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack('login_3p_bad', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack('login_handler_Google') ) ) ) );
\IPS\Log::log( "Google oauth error: " . json_encode( $response ), 'google_oauth' );
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack( 'login_3p_bad', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( 'login_handler_Google' ) ) ) ) );
}
}
catch ( \IPS\Http\Request\Exception $e )
{
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack('login_3p_bad', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack('login_handler_Google') ) ) ) );
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack( 'login_3p_bad', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( 'login_handler_Google' ) ) ) ) );
}
return TRUE;
}
+14 -15
View File
@@ -2,9 +2,9 @@
/**
* @brief Internal Login Handler
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 13 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -173,16 +173,6 @@ class _Internal extends LoginAbstract
return FALSE;
}
/**
* [Node] Does the currently logged in user have permission to delete this node?
*
* @return bool
*/
public function canDelete()
{
return FALSE; # this is bad, mkay
}
/**
* Can a member change their email/password with this login handler?
*
@@ -255,9 +245,18 @@ class _Internal extends LoginAbstract
*/
public function changePassword( \IPS\Member $member, $newPassword )
{
$member->members_pass_salt = $member->generateSalt();
$member->members_pass_hash = $member->encryptedPassword( $newPassword );
$member->save();
/* Clear any current sessions for this user. This resolves an issue where a user resets their password in one location, but a malicious
user with access to their account can retain access in another location. */
\IPS\Db::i()->delete( 'core_sessions', array( 'member_id=?', $member->member_id ) );
\IPS\Db::i()->delete( 'core_sys_cp_sessions', array( 'session_member_id=?', $member->member_id ) );
$member->members_pass_salt = $member->generateSalt();
$member->members_pass_hash = $member->encryptedPassword( $newPassword );
$member->member_login_key = '';
/* When we reset the login key and call checkLoginKey(), it will save for us. Note that we are NOT sending an updated pass_hash cookie
here, and that is instead the responsibility of any controllers that result in the password being updated. This is a central class
and we may not be updating the current viewing user's password at this point. */
$member->checkLoginKey();
$member->memberSync( 'onPassChange', array( $newPassword ) );
}
+68 -13
View File
@@ -2,9 +2,9 @@
/**
* @brief IPS Connect Login Handler
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 18 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -55,11 +55,11 @@ class _Ipsconnect extends LoginAbstract
try
{
/* Are we being returned from a cross-domain login? */
if( \IPS\Request::i()->loginProcess == 'ipsconnect' AND \IPS\Request::i()->id AND \IPS\Request::i()->key )
if( \IPS\Request::i()->loginProcess == 'ipsconnect' AND \IPS\Request::i()->ipsconnectId AND \IPS\Request::i()->ipsconnectKey )
{
$member = \IPS\Member::load( \IPS\Request::i()->id, 'ipsconnect_id' );
$member = \IPS\Member::load( \IPS\Request::i()->ipsconnectId, 'ipsconnect_id' );
if( $member->member_id AND \IPS\Login::compareHashes( \IPS\Request::i()->key, md5( $this->settings['key'] . $member->ipsconnect_id ) ) )
if( $member->member_id AND \IPS\Login::compareHashes( \IPS\Request::i()->ipsconnectKey, md5( $this->settings['key'] . $member->ipsconnect_id ) ) )
{
return $member;
}
@@ -75,7 +75,14 @@ class _Ipsconnect extends LoginAbstract
/* No response or status is not 'SUCCESS' */
if ( empty( $response ) OR empty( $response['status'] ) OR $response['status'] != 'SUCCESS' OR !$response['pass_salt'] )
{
throw new \IPS\Login\Exception( 'generic_error', \IPS\Login\Exception::INTERNAL_ERROR );
if( isset( $response['status'] ) AND $response['status'] == 'ACCOUNT_NOT_FOUND' )
{
throw new \IPS\Login\Exception( \IPS\Member::loggedIn()->language()->addToStack('login_err_no_account', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack( $this->getLoginType( $this->authTypes ) ) ) ) ), \IPS\Login\Exception::NO_ACCOUNT );
}
else
{
throw new \IPS\Login\Exception( 'generic_error', \IPS\Login\Exception::INTERNAL_ERROR );
}
}
/* Now create a dummy user to get password hash */
@@ -154,19 +161,17 @@ class _Ipsconnect extends LoginAbstract
$this->connectSuccessful( $member );
/* If we are still here and successful, redirect to master to log us in to each installation */
$url = \IPS\Http\Url::internal( '' );
\IPS\Request::i()->ref = (string) \IPS\Http\Url::external( $this->settings['url'] )->setQueryString(
array(
'do' => 'crossLogin',
'key' => md5( $this->settings['key'] . $member->ipsconnect_id ),
'url' => \IPS\Settings::i()->base_url . '/applications/core/interface/ipsconnect/ipsconnect.php',
'id' => $member->ipsconnect_id,
'returnTo' => (string) $url->setQueryString(
'returnTo' => (string) \IPS\Login::getDestination()->setQueryString(
array(
'loginProcess' => 'ipsconnect',
'key' => md5( $this->settings['key'] . $member->ipsconnect_id ),
'id' => $member->ipsconnect_id,
'ref' => (string) \IPS\Login::getDestination()
'ipsconnectKey' => md5( $this->settings['key'] . $member->ipsconnect_id ),
'ipsconnectId' => $member->ipsconnect_id
)
)
)
@@ -240,6 +245,28 @@ class _Ipsconnect extends LoginAbstract
{
return (bool) $this->_getConnectId( $member );
}
/**
* [Node] Get whether or not this node is enabled
*
* @note Return value NULL indicates the node cannot be enabled/disabled
* @return bool|null
*/
protected function get__enabled()
{
$result = parent::get__enabled();
/* If we are not enabled, determine if we are a master installation already - if so, we can't be enabled */
if( $result === FALSE )
{
if( \IPS\Db::i()->select( 'COUNT(*)', 'core_ipsconnect_slaves', array( 'slave_enabled=?', 1 ) )->first() > 0 )
{
return NULL;
}
}
return $result;
}
/**
* Can a member change their email/password with this login handler?
@@ -266,10 +293,16 @@ class _Ipsconnect extends LoginAbstract
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack('login_error_ipsconnect_self') );
}
/* If we are already a master, we can't be a slave too */
if( \IPS\Db::i()->select( 'COUNT(*)', 'core_ipsconnect_slaves' )->first() > 0 )
{
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack('login_error_ipsconnect_master') );
}
try
{
$response = \IPS\Http\Url::external( $this->settings['url'] )
->setQueryString( array( 'do' => 'verifySettings', 'key' => $this->settings['key'], 'url' => \IPS\Settings::i()->base_url . '/applications/core/interface/ipsconnect/ipsconnect.php', 'ourKey' => md5( md5( \IPS\Settings::i()->sql_user . \IPS\Settings::i()->sql_pass ) . \IPS\Settings::i()->board_start ) ) )
->setQueryString( array( 'do' => 'verifySettings', 'key' => $this->settings['key'], 'url' => \IPS\Settings::i()->base_url . '/applications/core/interface/ipsconnect/ipsconnect.php', 'ourKey' => \IPS\CONNECT_MASTER_KEY ?: md5( md5( \IPS\Settings::i()->sql_user . \IPS\Settings::i()->sql_pass ) . \IPS\Settings::i()->board_start ) ) )
->request()
->get()
->decodeJson();
@@ -428,7 +461,9 @@ class _Ipsconnect extends LoginAbstract
'url' => \IPS\Settings::i()->base_url . '/applications/core/interface/ipsconnect/ipsconnect.php',
'id' => $connectId,
'returnTo' => (string) $redirectUrl,
) )
) ),
'',
303
);
}
}
@@ -683,4 +718,24 @@ class _Ipsconnect extends LoginAbstract
->decodeJson();
}
}
/**
* Perform an action when the login handler is disabled
*
* @return bool
*/
public function onDisable()
{
try
{
$response = \IPS\Http\Url::external( $this->settings['url'] )
->setQueryString( array( 'do' => 'disableSlave', 'key' => $this->settings['key'], 'url' => \IPS\Settings::i()->base_url . '/applications/core/interface/ipsconnect/ipsconnect.php' ) )
->request()
->get()
->decodeJson();
}
catch( \RuntimeException $e ){}
return TRUE;
}
}
+3 -3
View File
@@ -2,9 +2,9 @@
/**
* @brief LDAP Login Handler
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 18 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -99,7 +99,7 @@ class _Ldap extends LoginAbstract
protected function ldap()
{
/* Connect to server */
if ( $this->settings['server_port'] )
if ( !$this->settings['server_port'] )
{
$this->ldap = ldap_connect( $this->settings['server_host'] );
}
+17 -10
View File
@@ -2,9 +2,9 @@
/**
* @brief LinkedIn Login Handler
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 20 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -31,18 +31,19 @@ class _Linkedin extends LoginAbstract
/**
* Get Form
*
* @param string $url The URL for the login page
* @param bool $ucp Is UCP? (as opposed to login form)
* @param \IPS\Http\Url $url The URL for the login page
* @param bool $ucp Is UCP? (as opposed to login form)
* @param \IPS\Http\Url $destination The URL to redirect to after a successful login
* @return string
*/
public function loginForm( $url, $ucp=FALSE )
{
public function loginForm( \IPS\Http\Url $url, $ucp = FALSE, \IPS\Http\Url $destination = NULL )
{
return \IPS\Theme::i()->getTemplate( 'login', 'core', 'global' )->linkedin( (string) \IPS\Http\Url::external( "https://www.linkedin.com/uas/oauth2/authorization" )->setQueryString( array(
'response_type' => 'code',
'client_id' => $this->settings['api_key'],
'scope' => 'r_basicprofile r_emailaddress',
'state' => ( $ucp ? 'ucp' : \IPS\Dispatcher::i()->controllerLocation ),
'redirect_uri' => (string) \IPS\Http\Url::internal( 'applications/core/interface/linkedin/auth.php', 'none' ),
'state' => ( $ucp ? 'ucp' : \IPS\Dispatcher::i()->controllerLocation ) . '-' . \IPS\Session::i()->csrfKey . '-' . ( $destination ? base64_encode( $destination ) : '' ),
'redirect_uri' => (string) \IPS\Http\Url::internal( 'applications/core/interface/linkedin/auth.php', 'none', \IPS\Settings::i()->logins_over_https ? \IPS\Http\Url::PROTOCOL_HTTPS : 0 ),
) ) );
}
@@ -57,12 +58,18 @@ class _Linkedin extends LoginAbstract
public function authenticate( $url, $member=NULL )
{
try
{
{
/* CSRF Check */
if ( \IPS\Request::i()->state !== \IPS\Session::i()->csrfKey )
{
throw new \IPS\Login\Exception( 'CSRF_FAIL', \IPS\Login\Exception::INTERNAL_ERROR );
}
/* Get a token */
$response = \IPS\Http\Url::external( "https://www.linkedin.com/uas/oauth2/accessToken?" . http_build_query( array(
'grant_type' => 'authorization_code',
'code' => \IPS\Request::i()->code,
'redirect_uri' => (string) \IPS\Http\Url::internal( 'applications/core/interface/linkedin/auth.php', 'none' ),
'redirect_uri' => (string) \IPS\Http\Url::internal( 'applications/core/interface/linkedin/auth.php', 'none', NULL, array(), \IPS\Settings::i()->logins_over_https ? \IPS\Http\Url::PROTOCOL_HTTPS : 0 ),
'client_id' => $this->settings['api_key'],
'client_secret' => $this->settings['secret_key'],
) ) )->request()->post()->decodeJson();
+16 -9
View File
@@ -2,9 +2,9 @@
/**
* @brief Windows Live Login Handler
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 18 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -31,18 +31,19 @@ class _Live extends LoginAbstract
/**
* Get Form
*
* @param string $url The URL for the login page
* @param bool $ucp Is UCP? (as opposed to login form)
* @param \IPS\Http\Url $url The URL for the login page
* @param bool $ucp Is UCP? (as opposed to login form)
* @param \IPS\Http\Url $destination The URL to redirect to after a successful login
* @return string
*/
public function loginForm( $url, $ucp=FALSE )
{
public function loginForm( \IPS\Http\Url $url, $ucp = FALSE, \IPS\Http\Url $destination = NULL )
{
return \IPS\Theme::i()->getTemplate( 'login', 'core', 'global' )->live( (string) \IPS\Http\Url::external( 'https://login.live.com/oauth20_authorize.srf' )->setQueryString( array(
'client_id' => $this->settings['client_id'],
'scope' => 'wl.signin wl.emails wl.offline_access',
'response_type' => 'code',
'redirect_uri' => (string) \IPS\Http\Url::internal( 'applications/core/interface/microsoft/auth.php', 'none' ),
'state' => ( $ucp ? 'ucp' : \IPS\Dispatcher::i()->controllerLocation )
'redirect_uri' => (string) \IPS\Http\Url::internal( 'applications/core/interface/microsoft/auth.php', 'none', NULL, array(), \IPS\Settings::i()->logins_over_https ? \IPS\Http\Url::PROTOCOL_HTTPS : 0 ),
'state' => ( $ucp ? 'ucp' : \IPS\Dispatcher::i()->controllerLocation ) . '-' . \IPS\Session::i()->csrfKey . '-' . ( $destination ? base64_encode( $destination ) : '' )
) ) );
}
@@ -58,10 +59,16 @@ class _Live extends LoginAbstract
{
try
{
/* CSRF Check */
if ( \IPS\Request::i()->state !== \IPS\Session::i()->csrfKey )
{
throw new \IPS\Login\Exception( 'CSRF_FAIL', \IPS\Login\Exception::INTERNAL_ERROR );
}
/* Send HTTP request */
$response = \IPS\Http\Url::external( 'https://login.live.com/oauth20_token.srf' )->request()->post( array(
'client_id' => $this->settings['client_id'],
'redirect_uri' => (string) \IPS\Http\Url::internal( 'applications/core/interface/microsoft/auth.php', 'none' ),
'redirect_uri' => (string) \IPS\Http\Url::internal( 'applications/core/interface/microsoft/auth.php', 'none', NULL, array(), \IPS\Settings::i()->logins_over_https ? \IPS\Http\Url::PROTOCOL_HTTPS : 0 ),
'client_secret' => $this->settings['client_secret'],
'code' => \IPS\Request::i()->code,
'grant_type' => 'authorization_code'
+94 -18
View File
@@ -2,9 +2,9 @@
/**
* @brief Login Handler
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 13 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -158,8 +158,12 @@ class _Login
/* If there's an explicit ref value, go there */
if( !empty( \IPS\Request::i()->ref ) )
{
$ref = new \IPS\Http\Url( @base64_decode( \IPS\Request::i()->ref ) ?: \IPS\Request::i()->ref );
return $ref;
try
{
$ref = \IPS\Http\Url::createFromString( @base64_decode( \IPS\Request::i()->ref ) ?: \IPS\Request::i()->ref );
return $ref;
}
catch ( \Exception $e ) { }
}
/* Don't redirect to an external domain unless explicitly requested, and don't redirect back to ACP */
@@ -179,7 +183,7 @@ class _Login
}
}
$ref = new \IPS\Http\Url( ( isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '' ) );
$ref = isset( $_SERVER['HTTP_REFERER'] ) ? \IPS\Http\Url::createFromString( $_SERVER['HTTP_REFERER'] ) : \IPS\Http\Url::internal('');
}
return isset( $ref ) ? $ref->stripQueryString( 'csrfKey' ) : \IPS\Http\Url::internal( '' );
@@ -201,12 +205,26 @@ class _Login
}
}
$ref = NULL;
if ( isset( \IPS\Request::i()->ref ) )
{
try
{
$ref = \IPS\Http\Url::createFromString( base64_decode( \IPS\Request::i()->ref ) );
if ( !( $ref instanceof \IPS\Http\Url\Internal ) )
{
$ref = NULL;
}
}
catch ( \Exception $e ) { }
}
if ( in_array( \IPS\Settings::i()->reg_auth_type, array( 'admin', 'admin_user' ) ) )
{
return \IPS\Http\Url::internal( 'app=core&module=system&controller=register&do=validating', 'front', 'register' );
}
return \IPS\Http\Url::internal( '' );
return $ref ?: \IPS\Http\Url::internal( '' );
}
/**
@@ -229,7 +247,7 @@ class _Login
{
try
{
$this->forms[ $key ] = $handler->loginForm( $this->url );
$this->forms[ $key ] = $handler->loginForm( $this->url, FALSE, $skipReferer ? $this->url : static::getDestination() );
}
catch( \BadMethodCallException $e )
{
@@ -272,8 +290,8 @@ class _Login
$classname = 'IPS\Helpers\Form\Email';
}
$standardForm->class = 'ipsForm_vertical';
$standardForm->add( new $classname( 'auth', NULL, TRUE, array( '_loginType' => $standardTypes ), NULL, NULL, NULL, 'auth' ) );
$standardForm->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE, array(), NULL, NULL, NULL, 'password' ) );
$standardForm->add( new $classname( 'auth', NULL, TRUE, array( '_loginType' => $standardTypes, 'bypassProfanity' => TRUE ), NULL, NULL, NULL, 'auth' ) );
$standardForm->add( new \IPS\Helpers\Form\Password( 'password', NULL, TRUE, array( 'bypassProfanity' => TRUE ), NULL, NULL, NULL, 'password' ) );
/* Are we adding the referer value to the form? */
if( !$skipReferer )
@@ -380,17 +398,33 @@ class _Login
{
$removeLoginsOlderThan = \IPS\DateTime::create()->sub( new \DateInterval( 'PT' . \IPS\Settings::i()->ipb_bruteforce_period . 'M' ) );
$failedLogins = $member->failed_logins;
foreach ( $failedLogins as $ipAddress => $times )
/* The failed login data could potentially not be an array (i.e. a float) but as this code executes during the first
step of upgrading to 4.0 if we don't force it to be an array here we could end up with an error exception we can't
get past when attempting to upgrade. */
if( !is_array( $failedLogins ) )
{
foreach ( $times as $k => $v )
$failedLogins = array();
}
if ( is_array( $failedLogins ) )
{
foreach ( $failedLogins as $ipAddress => $times )
{
if ( $v < $removeLoginsOlderThan->getTimestamp() )
foreach ( $times as $k => $v )
{
unset( $failedLogins[ $ipAddress ][ $k ] );
if ( $v < $removeLoginsOlderThan->getTimestamp() )
{
unset( $failedLogins[ $ipAddress ][ $k ] );
}
}
}
$member->failed_logins = $failedLogins;
}
else
{
$member->failed_logins = array();
}
$member->failed_logins = $failedLogins;
$member->save();
}
@@ -468,7 +502,7 @@ class _Login
{
$failedLogins = $member->failed_logins[ \IPS\Request::i()->ipAddress() ];
sort( $failedLogins );
while ( count( $failedLogins ) > \IPS\Settings::i()->ipb_bruteforce_attempts )
{
array_pop( $failedLogins );
@@ -476,13 +510,31 @@ class _Login
$unlockTime = \IPS\DateTime::ts( array_pop( $failedLogins ) );
$unlockTime->add( new \DateInterval( 'PT' . \IPS\Settings::i()->ipb_bruteforce_period . 'M' ) );
$timeToUnlock = $unlockTime->diff( new DateTime() );
/* If Unlock Time is in the past, return FALSE to avoid the exception and allow login */
if ( $unlockTime->getTimestamp() < time() )
{
return FALSE;
}
}
/* Notify the member if they've been locked */
if( count( $member->failed_logins[ \IPS\Request::i()->ipAddress() ] ) == \IPS\Settings::i()->ipb_bruteforce_attempts )
{
/* Can we get a physical location */
try
{
$location = \IPS\GeoLocation::getByIp( \IPS\Request::i()->ipAddress() );
}
catch ( \Exception $e )
{
$location = \IPS\Request::i()->ipAddress();
}
\IPS\Email::buildFromTemplate( 'core', 'account_locked', array( $member, $location, isset( $unlockTime ) ? $unlockTime : NULL ), \IPS\Email::TYPE_TRANSACTIONAL )->send( $member );
}
if ( \IPS\Settings::i()->ipb_bruteforce_period and \IPS\Settings::i()->ipb_bruteforce_unlock )
{
throw new \IPS\Login\Exception( \IPS\Member::loggedIn()->language()->addToStack( 'login_err_locked_unlock', FALSE, array( 'pluralize' => array( $timeToUnlock->format('%i') ) ) ) );
}
else
@@ -501,7 +553,7 @@ class _Login
*/
public static function compareHashes( $expected, $provided )
{
if ( !is_string( $expected ) || !is_string( $provided ) )
if ( !is_string( $expected ) || !is_string( $provided ) || $expected === '*0' || $expected === '*1' || $provided === '*0' || $provided === '*1' ) // *0 and *1 are failures from crypt() - if we have ended up with an invalid hash anywhere, we will reject it to prevent a possible vulnerability from deliberately generating invalid hashes
{
return FALSE;
}
@@ -520,4 +572,28 @@ class _Login
return $status === 0;
}
/**
* Return a random string
*
* @param int $length The length of the final string
* @return string
*/
public static function generateRandomString( $length=32 )
{
$return = '';
if( function_exists( 'openssl_random_pseudo_bytes' ) )
{
$return = \substr( bin2hex( openssl_random_pseudo_bytes( ceil( $length / 2 ) ) ), 0, $length );
}
/* Fallback JUST IN CASE */
if( !$return OR \strlen( $return ) != $length )
{
$return = \substr( md5( uniqid( microtime(), true ) ) . md5( uniqid( microtime(), true ) ), 0, $length );
}
return $return;
}
}
+95 -40
View File
@@ -2,9 +2,9 @@
/**
* @brief Abstract Login Handler
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 15 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -83,11 +83,12 @@ abstract class _LoginAbstract extends \IPS\Node\Model
$obj->_new = FALSE;
/* Import data */
$databasePrefixLength = \strlen( static::$databasePrefix );
foreach ( $data as $k => $v )
{
if( static::$databasePrefix )
{
$k = \substr( $k, \strlen( static::$databasePrefix ) );
$k = \substr( $k, $databasePrefixLength );
}
$obj->$k = $v;
@@ -110,6 +111,16 @@ abstract class _LoginAbstract extends \IPS\Node\Model
return \IPS\Member::loggedIn()->language()->addToStack( $key );
}
/**
* [Node] Get the title to store in the log
*
* @return string|null
*/
public function titleForLog()
{
return $this->_logKey;
}
/**
* [Node] Get the log key
*
@@ -117,7 +128,7 @@ abstract class _LoginAbstract extends \IPS\Node\Model
*/
protected function get__logKey()
{
return "login_handler_" . ucfirst($this->key);
return \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'login_handler_' . ucfirst( $this->key ) );
}
/**
@@ -187,6 +198,16 @@ abstract class _LoginAbstract extends \IPS\Node\Model
{
$form->add( new \IPS\Helpers\Form\YesNo( 'login_acp', $this->acp ) );
}
if ( isset( static::$shareService ) )
{
try
{
$shareService = \IPS\core\ShareLinks\Service::load( static::$shareService, 'share_key' );
$form->add( new \IPS\Helpers\Form\YesNo( 'share_autoshare_' . $this->key, $shareService->autoshare ) );
}
catch ( \OutOfRangeException $e ) { }
}
}
/**
@@ -216,6 +237,11 @@ abstract class _LoginAbstract extends \IPS\Node\Model
}
}
if ( isset( $values[ 'share_autoshare_' . $this->key ] ) )
{
$save['autoshare'] = $values[ 'share_autoshare_' . $this->key ];
}
$values['settings'] = json_encode( $save );
$this->settings = $values['settings'];
@@ -229,6 +255,29 @@ abstract class _LoginAbstract extends \IPS\Node\Model
return $values;
}
/**
* [Node] Save Add/Edit Form
*
* @param array $values Values from the form
* @return void
*/
public function saveForm( $values )
{
if ( isset( $values[ 'share_autoshare_' . $this->key ] ) )
{
try
{
$shareService = \IPS\core\ShareLinks\Service::load( static::$shareService, 'share_key' );
$shareService->autoshare = $values[ 'share_autoshare_' . $this->key ];
$shareService->save();
}
catch ( \OutOfRangeException $e ) { }
unset( $values[ 'share_autoshare_' . $this->key ] );
}
parent::saveForm( $values );
}
/**
* [ActiveRecord] Save Changed Columns
*
@@ -240,17 +289,6 @@ abstract class _LoginAbstract extends \IPS\Node\Model
unset( \IPS\Data\Store::i()->loginHandlers );
}
/**
* [ActiveRecord] Delete Record
*
* @return void
*/
public function delete()
{
parent::delete();
unset( \IPS\Data\Store::i()->loginHandlers );
}
/**
* Create an account from login - checks registration is enabled, the name/email doesn't already exists and calls the spam service
*
@@ -269,7 +307,7 @@ abstract class _LoginAbstract extends \IPS\Node\Model
/* Create an account */
if ( !$member or !$member->member_id )
{
/* Is registraion enabled? */
/* Is registration enabled? */
if( !\IPS\Settings::i()->allow_reg )
{
$exception = new \IPS\Login\Exception( 'reg_disabled', \IPS\Login\Exception::REGISTRATION_DISABLED );
@@ -281,13 +319,8 @@ abstract class _LoginAbstract extends \IPS\Node\Model
/* Init */
$member = new \IPS\Member;
$member->member_group_id = \IPS\Settings::i()->member_group;
/* If we admin validation is enabled, set that flag */
if ( \IPS\Settings::i()->reg_auth_type == 'admin' or \IPS\Settings::i()->reg_auth_type == 'admin_user' )
{
$member->members_bitoptions['validating'] = TRUE;
}
$member->members_bitoptions['view_sigs'] = TRUE;
/* Set name - if it already exists, we'll leave it blank and they'll be prompted to fill it in */
if ( $name !== NULL and ( !\IPS\Settings::i()->username_characters or preg_match( '/^[' . str_replace( '\-', '-', preg_quote( \IPS\Settings::i()->username_characters, '/' ) ) . ']*$/i', $name ) ) )
{
@@ -343,14 +376,7 @@ abstract class _LoginAbstract extends \IPS\Node\Model
$member->$k = $v;
}
$member->save();
/* Users created by log in don't need to validate their email if the service provided it,
so if we admin and user validation is required, set that the user validated */
if ( \IPS\Settings::i()->reg_auth_type == 'admin_user' )
{
\IPS\Db::i()->update( 'core_validating', array( 'user_verified' => 1 ), array( 'member_id=?', $member->member_id ) );
}
/* Sync photo, etc now */
if ( $profileSync !== NULL )
{
@@ -359,15 +385,10 @@ abstract class _LoginAbstract extends \IPS\Node\Model
$sync->sync();
}
if( \IPS\Settings::i()->reg_auth_type != 'none' AND \IPS\Settings::i()->reg_auth_type != 'admin' AND !$member->members_bitoptions['bw_is_spammer'] )
/* If registration is complete, do post-registration stuff */
if ( $member->name and $member->email and !$member->members_bitoptions['bw_is_spammer'] )
{
\IPS\Email::buildFromTemplate( 'core', 'registration_validate', array( $member, \IPS\Db::i()->select( 'vid', 'core_validating', array( 'member_id=?', $member->member_id ) )->first() ) )->send( $member );
}
/* Notify the incoming mail address except if they're a spammer */
if( \IPS\Settings::i()->new_reg_notify && !$member->members_bitoptions['bw_is_spammer'] )
{
\IPS\Email::buildFromTemplate( 'core', 'registration_notify', array( $member, array() ) )->send( \IPS\Settings::i()->email_in );
$member->postRegistration( TRUE );
}
}
@@ -377,6 +398,11 @@ abstract class _LoginAbstract extends \IPS\Node\Model
foreach ( $memberProperties as $k => $v )
{
$member->$k = $v;
if( $k == 'members_pass_hash' )
{
$member->member_login_key = '';
}
}
$member->save();
}
@@ -416,6 +442,16 @@ abstract class _LoginAbstract extends \IPS\Node\Model
return TRUE;
}
/**
* Perform an action when the login handler is disabled
*
* @return bool
*/
public function onDisable()
{
return TRUE;
}
/**
* Fetch the type as a textual string
*
@@ -608,7 +644,7 @@ abstract class _LoginAbstract extends \IPS\Node\Model
{
try
{
$return[ $key ] = self::load( $key );
$return[ $key ] = static::load( $key );
}
catch ( \OutOfRangeException $e ) { }
}
@@ -616,4 +652,23 @@ abstract class _LoginAbstract extends \IPS\Node\Model
return $return;
}
}
/**
* Can a member sign in with this login handler?
* Used to ensure when a user disassociates a social login that they have some other way of logging in
*
* @param \IPS\Member $member The member
* @return bool
*/
abstract function canProcess( \IPS\Member $member );
/**
* [Node] Does the currently logged in user have permission to delete this node?
*
* @return bool
*/
public function canDelete()
{
return FALSE;
}
}
+42 -11
View File
@@ -2,9 +2,9 @@
/**
* @brief Twitter Login Handler
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 18 Mar 2013
* @version SVN_VERSION_NUMBER
*/
@@ -28,15 +28,28 @@ class _Twitter extends LoginAbstract
*/
public static $icon = 'twitter';
/**
* @brief Share Service
*/
public static $shareService = 'twitter';
/**
* Get Form
*
* @param \IPS\Http\Url $url The URL for the login page
* @param \IPS\Http\Url $url The URL for the login page
* @param bool $ucp Is UCP? (as opposed to login form)
* @param \IPS\Http\Url $destination The URL to redirect to after a successful login
* @return string
*/
public function loginForm( \IPS\Http\Url $url )
public function loginForm( \IPS\Http\Url $url, $ucp = FALSE, \IPS\Http\Url $destination = NULL )
{
return \IPS\Theme::i()->getTemplate( 'login', 'core', 'global' )->twitter( $url->setQueryString( 'loginProcess', 'twitter' ) );
$url = $url->setQueryString( 'loginProcess', 'twitter' );
if ( $destination )
{
$url = $url->setQueryString( 'ref', base64_encode( $destination ) );
}
return \IPS\Theme::i()->getTemplate( 'login', 'core', 'global' )->twitter( $url );
}
/**
@@ -59,10 +72,22 @@ class _Twitter extends LoginAbstract
/* Get a request token */
if ( !isset( \IPS\Request::i()->oauth_token ) )
{
$response = $this->sendRequest( 'get', 'https://api.twitter.com/oauth/request_token', array( 'oauth_callback' => (string) $url->setQueryString( 'loginProcess', 'twitter' ) ) )->decodeQueryString('oauth_token');
$callback = $url->setQueryString( 'loginProcess', 'twitter' )->setQueryString( 'csrf', \IPS\Session::i()->csrfKey );
if ( isset( \IPS\Request::i()->ref ) )
{
$callback = $callback->setQueryString( 'ref', \IPS\Request::i()->ref );
}
$response = $this->sendRequest( 'get', 'https://api.twitter.com/oauth/request_token', array( 'oauth_callback' => (string) $callback ) )->decodeQueryString('oauth_token');
\IPS\Output::i()->redirect( "https://api.twitter.com/oauth/authenticate?oauth_token={$response['oauth_token']}" );
}
/* CSRF Check */
if ( \IPS\Request::i()->csrf !== \IPS\Session::i()->csrfKey )
{
throw new \IPS\Login\Exception( 'CSRF_FAIL', \IPS\Login\Exception::INTERNAL_ERROR );
}
/* Authenticate */
$response = $this->sendRequest( 'post', 'https://api.twitter.com/oauth/access_token', array( 'oauth_verifier' => \IPS\Request::i()->oauth_verifier ), \IPS\Request::i()->oauth_token )->decodeQueryString('user_id');
@@ -148,13 +173,19 @@ class _Twitter extends LoginAbstract
{
try
{
$response = $this->sendRequest( 'get', 'https://api.twitter.com/oauth/request_token', array( 'oauth_callback' => (string) \IPS\Http\Url::internal( '', 'front' ) ) )->decodeQueryString('oauth_token');
return TRUE;
$response = $this->sendRequest( 'get', 'https://api.twitter.com/oauth/request_token', array( 'oauth_callback' => (string) \IPS\Http\Url::internal( '', 'front' ) ) );
if( $response->httpResponseCode != 200 )
{
\IPS\Log::log( "Twitter oauth error " . json_encode( $response ), 'twitter_oauth_error');
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack( 'login_3p_bad', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack('login_handler_Twitter') ) ) ) );
}
}
catch ( \Exception $e )
{
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack('login_3p_bad', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack('login_handler_Twitter') ) ) ) );
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack( 'login_3p_bad', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack('login_handler_Twitter') ) ) ) );
}
return TRUE;
}
/**
@@ -172,7 +203,7 @@ class _Twitter extends LoginAbstract
/* Generate the OAUTH Authorization Header */
$OAuthAuthorization = array_merge( array(
'oauth_consumer_key' => $this->settings['consumer_key'],
'oauth_nonce' => md5( uniqid() ),
'oauth_nonce' => md5( \IPS\Login::generateRandomString() ),
'oauth_signature_method'=> 'HMAC-SHA1',
'oauth_timestamp' => time(),
'oauth_token' => $token,
@@ -188,7 +219,7 @@ class _Twitter extends LoginAbstract
}
}
$signatureBaseString = mb_strtoupper( $method ) . '&' . rawurlencode( $url ) . '&' . rawurlencode( http_build_query( $OAuthAuthorization ) ) . ( count( $params ) ? ( rawurlencode( '&' ) . rawurlencode( http_build_query( $params, NULL, NULL, PHP_QUERY_RFC3986 ) ) ) : '' );
$signatureBaseString = mb_strtoupper( $method ) . '&' . rawurlencode( $url ) . '&' . rawurlencode( http_build_query( $OAuthAuthorization, NULL, '&' ) ) . ( count( $params ) ? ( rawurlencode( '&' ) . rawurlencode( http_build_query( $params, NULL, NULL, PHP_QUERY_RFC3986 ) ) ) : '' );
$signingKey = rawurlencode( $this->settings['consumer_secret'] ) . '&' . rawurlencode( $secret ?: $token );
$OAuthAuthorizationEncoded = array();
foreach ( $OAuthAuthorization as $k => $v )
+2 -2
View File
@@ -2,9 +2,9 @@
/**
* @brief Internal Login Handler
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 13 Mar 2013
* @version SVN_VERSION_NUMBER
*/
+253
View File
@@ -0,0 +1,253 @@
<?php
namespace IPS\Login;
class _Vkontakte extends LoginAbstract
{
/**
* @brief Icon
*/
public static $icon = 'vk';
/**
* Get Form
*
* @param \IPS\Http\Url $url The URL for the login page
* @return string
*/
public function loginForm( $url, $ucp=FALSE )
{
$url = \IPS\Http\Url::internal( 'applications/core/interface/vkontakte/auth.php', 'none' );
if ( $ucp )
{
$state = "ucp-" . \IPS\Session::i()->csrfKey;
}
else
{
$state = \IPS\Dispatcher::i()->controllerLocation . "-" . \IPS\Session::i()->csrfKey;
}
return \IPS\Theme::i()->getTemplate( 'login', 'core', 'global' )->vkontakte( "https://oauth.vk.com/authorize?client_id={$this->settings['app_id']}&amp;scope=email&amp;redirect_uri=".urlencode( $url ) . "&amp;state={$state}&amp;response_type=code" );
}
/**
* Authenticate
*
* @param string $url The URL for the login page
* @param \IPS\Member $member If we want to integrate this login method with an existing member, provide the member object
* @return \IPS\Member
* @throws \IPS\Login\Exception
*/
public function authenticate( $url, $member=NULL )
{
$url = $url->setQueryString( 'loginProcess', 'vkontakte' );
try
{
/* Get a token */
try
{
$response = \IPS\Http\Url::external( "https://oauth.vk.com/access_token?client_id={$this->settings['app_id']}&redirect_uri=".(string) \IPS\Http\Url::internal( 'applications/core/interface/vkontakte/auth.php', 'none' )."&client_secret={$this->settings['app_secret']}&code=".\IPS\Request::i()->code
)->request()->get()->decodeJson();
}
catch( \RuntimeException $e )
{
throw new \IPS\Login\Exception( 'generic_error', \IPS\Login\Exception::INTERNAL_ERROR );
}
/* Get the user data */
$userData = $response;
if(!isset($userData['email'])) throw new \IPS\Login\Exception( 'В вашем аккаунте ВК отсутствует email, укажите его!', \IPS\Login\Exception::INTERNAL_ERROR );
/* Find or create member */
$newMember = FALSE;
if ( $member === NULL )
{
$member = \IPS\Member::load( $userData['email'], 'email' );
if ( !$member->member_id )
{
$member = new \IPS\Member;
if ( \IPS\Settings::i()->reg_auth_type == 'admin' or \IPS\Settings::i()->reg_auth_type == 'admin_user' )
{
$member->members_bitoptions['validating'] = TRUE;
}
$member->member_group_id = \IPS\Settings::i()->member_group;
$member->email = $userData['email'];
$member->profilesync = json_encode( array( 'vkontakte' => array( 'photo' => TRUE, 'cover' => FALSE, 'status' => TRUE ) ) );
$newMember = TRUE;
$name1 = \IPS\Http\Url::external( "https://api.vk.com/method/users.get?user_id={$userData['user_id']}&v=5.29&access_token={$response['access_token']}&fields=first_name,last_name,screen_name,bdate,nickname" )->request()->get()->decodeJson();
$member->name = $name1['response'][0]['nickname'];
if ( empty($member->name) AND $this->settings['real_name'] )
{
$name = $name1['response'][0]['first_name'].' '.$name1['response'][0]['last_name'];
$existingUsername = \IPS\Member::load( $name, 'name' );
if ( !$existingUsername->member_id )
{
$member->name = $name;
}
}
}
}
$member->vk_uid = $userData['user_id'];
$member->vk_token = $response['access_token'];
$member->save();
/* Sync */
if ( $newMember )
{
if ( \IPS\Settings::i()->reg_auth_type == 'admin_user' )
{
\IPS\Db::i()->update( 'core_validating', array( 'user_verified' => 1 ), array( 'member_id=?', $member->member_id ) );
}
$sync = new \IPS\core\ProfileSync\VK( $member );
$sync->sync();
}
/* Return */
return $member;
}
catch ( \IPS\Http\Request\Exception $e )
{
throw new \IPS\Login\Exception( 'generic_error', \IPS\Login\Exception::INTERNAL_ERROR );
}
}
public static function link( \IPS\Member $member, $details )
{
try {
$userData = \IPS\Http\Url::external( "https://api.vk.com/method/users.get?uid={$details[1]}&access_token={$details[0]}&fields=first_name,last_name,screen_name,bdate,nickname" )->request()->get()->decodeJson();
$userData = $userData['response'][0];
$member->vk_id = $details[1];
$member->vk_token = $details[0];
$member->save();
}catch(\Exception $e) {}
}
/**
* ACP Settings Form
*
* @param string $url URL to redirect user to after successful submission
* @return array List of settings to save - settings will be stored to core_login_handlers.login_settings DB field
* @code
return array( 'savekey' => new \IPS\Helpers\Form\[Type]( ... ), ... );
* @endcode
*/
public function acpForm()
{
$where = array( array( 'template_group=?', 'login' ) );
$where[] = array( 'template_app=?', 'core' );
$where[] = array( 'template_location=?', 'global' );
$results = array();
$selects = \IPS\Db::i()->select( 'template_name', 'core_theme_templates', $where );
$selects->rewind();
while($selects->valid())
{
$results[ $selects->current() ] = $selects->current();
$selects->next();
}
$results = array_unique( $results );
//if(\IPS\IN_DEV) {
if(!in_array('vkontakte',$results)) {
ob_start();?>
<ips:template parameters="$url" />
<a href='{$url}' class='ipsButton ipsButton_verySmall ipsButton_fullWidth ipsSocial ipsSocial_vk' style="background-color:#56789C;">
<span class='ipsSocial_icon'><i class='fa fa-vk'></i></span>
<span class='ipsSocial_text'>{lang="login_vkontakte"}</span>
</a>
<?
$html = ob_get_contents();
ob_end_clean();
$params = array();
/* Parse the header tag */
preg_match( '/^<ips:template parameters="(.+?)?" \/>\n/', $html, $params );
/* Strip it */
$html = ( isset($params[0]) ) ? str_replace( $params[0], '', $html ) : $html;
$id=0;
\IPS\Db::i()->insert( 'core_theme_templates', array( 'template_set_id' => $id,
'template_app' => 'core',
'template_added_to' => $id,
'template_location' => 'global',
'template_group' => 'login',
'template_name' => 'vkontakte',
'template_data' => ( isset( $params[1] ) ) ? $params[1] : '',
'template_content' => $html,
'template_updated' => time(),
'template_unique_key' => md5( $id . ';' . 'core' . ';' . 'global' . ';' . 'login' . ';' . ( 'vkontakte' ) ),
'template_removable' => $id ) );
\IPS\Theme::load( \IPS\Theme::i()->defaultTheme() )->compileTemplates( 'core' );
}
/*}elseif(!in_array('vkontakte',$results)) {
\IPS\Output::i()->sidebar['actions'] = array(
'help' => array(
'link' => \IPS\Http\Url::internal( '&app=core&module=settings&controller=login&do=form&id=vkontakte' ),
'title' => 'Шаблоны не синхронизированы. Включите DEV-режим и перезагрузите страницу!',
),
);
}*/
return array(
'app_id' => new \IPS\Helpers\Form\Text( 'login_vkontakte_app', ( isset( $this->settings['app_id'] ) ) ? $this->settings['app_id'] : '', TRUE ),
'app_secret' => new \IPS\Helpers\Form\Text( 'login_vkontakte_secret', ( isset( $this->settings['app_secret'] ) ) ? $this->settings['app_secret'] : '', TRUE ),
'real_name' => new \IPS\Helpers\Form\YesNo( 'login_real_name', ( isset( $this->settings['real_name'] ) ) ? $this->settings['real_name'] : FALSE, TRUE )
);
}
/**
* Test Settings
*
* @return bool
* @throws \InvalidArgumentException
*/
public function testSettings()
{
return TRUE;
}
/**
* Can a member sign in with this login handler?
* Used to ensure when a user disassociates a social login that they have some other way of logging in
*
* @param \IPS\Member $member The member
* @return bool
*/
public function canProcess( \IPS\Member $member )
{
return ( $member->vk_id and $member->vk_token );
}
/**
* Can a member change their email/password with this login handler?
*
* @param string $type 'email' or 'password'
* @param \IPS\Member $member The member
* @return bool
*/
public function canChange( $type, \IPS\Member $member )
{
return FALSE;
}
}