Version 4.1.19
This commit is contained in:
1 parent
28bd025b35
commit
2bd5025018
2674 files changed
+233518
-77766
No files matched your search
+173
-101
@@ -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( ''', "'", 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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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']}&scope={$scope}&redirect_uri=".urlencode( $url ) . "&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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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,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
|
||||
*/
|
||||
|
||||
@@ -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']}&scope=email&redirect_uri=".urlencode( $url ) . "&state={$state}&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;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user