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

@@ -2,9 +2,9 @@
/**
* @brief IPS Connect remote connections API
* @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 30 May 2013
* @version SVN_VERSION_NUMBER
* @note Backwards compatibility is not possible due to the way password storage has changed
@@ -37,7 +37,7 @@ class ipsConnect
/* Set up some things we will use */
\IPS\Session\Front::i();
$this->url = \IPS\Http\Url::internal( 'applications/core/interface/ipsconnect/ipsconnect.php', 'none' );
$this->key = md5( md5( \IPS\Settings::i()->sql_user . \IPS\Settings::i()->sql_pass ) . \IPS\Settings::i()->board_start );
$this->key = \IPS\CONNECT_MASTER_KEY ?: md5( md5( \IPS\Settings::i()->sql_user . \IPS\Settings::i()->sql_pass ) . \IPS\Settings::i()->board_start );
}
/**
@@ -62,26 +62,12 @@ class ipsConnect
if( !$connect['login_enabled'] )
{
if ( $noJson and isset( \IPS\Request::i()->returnTo ) )
{
\IPS\Output::i()->redirect( \IPS\Request::i()->returnTo );
}
else
{
$this->_output( "DISABLED", array(), $noJson );
}
$this->_output( "DISABLED", array(), $noJson );
}
}
catch( \UnderflowException $e )
{
if ( $noJson and isset( \IPS\Request::i()->returnTo ) )
{
\IPS\Output::i()->redirect( \IPS\Request::i()->returnTo );
}
else
{
$this->_output( "DISABLED", array(), $noJson );
}
$this->_output( "DISABLED", array(), $noJson );
}
}
@@ -107,11 +93,48 @@ class ipsConnect
{
$this->_genericKeyCheck();
\IPS\Db::i()->replace( 'core_ipsconnect_slaves', array( 'slave_url' => \IPS\Request::i()->url, 'slave_key' => \IPS\Request::i()->ourKey, 'slave_last_access' => time() ) );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => \IPS\Db::i()->select( 'COUNT(*)', 'core_ipsconnect_slaves' )->first() ), array( 'conf_key=?', 'connect_slaves' ) );
unset( \IPS\Data\Store::i()->settings );
/* Security precaution - if we are already a slave, don't let us become a master */
try
{
$loginHandler = \IPS\Db::i()->select( '*', 'core_login_handlers', array( 'login_key=?', 'Ipsconnect' ) )->first();
$settings = json_decode( $loginHandler['login_settings'], true );
$this->_log( "NEW_SLAVE_REGISTERED", (array) \IPS\Request::i() );
if( isset( $settings['url'] ) AND $settings['url'] )
{
$this->_log( "SLAVE_REGISTRATION_DENIED", (array) \IPS\Request::i() );
$this->_output( "FAILURE", array() );
}
}
catch( \UnderflowException $e ){}
/* If we don't have a URL or key, don't try to save */
if( !isset( \IPS\Request::i()->url ) OR !\IPS\Request::i()->url OR !isset( \IPS\Request::i()->ourKey ) OR !\IPS\Request::i()->ourKey )
{
$this->_log( "SLAVE_REGISTRATION_DENIED", (array) \IPS\Request::i() );
$this->_output( "FAILURE", array() );
}
\IPS\Db::i()->replace( 'core_ipsconnect_slaves', array( 'slave_url' => \IPS\Request::i()->url, 'slave_key' => \IPS\Request::i()->ourKey, 'slave_last_access' => time(), 'slave_enabled' => 1 ) );
$this->_recountSlaves();
$this->_log( "NEW_SLAVE_REGISTERED", (array) \IPS\Request::i(), TRUE );
return NULL;
}
/**
* Disable a slave installation
*
* @return NULL
*/
public function disableSlave()
{
$this->_genericKeyCheck();
\IPS\Db::i()->update( 'core_ipsconnect_slaves', array( 'slave_enabled' => 0 ), array( 'slave_url=?', \IPS\Request::i()->url ) );
$this->_recountSlaves();
$this->_log( "NEW_SLAVE_REGISTERED", (array) \IPS\Request::i(), TRUE );
return NULL;
}
@@ -127,7 +150,7 @@ class ipsConnect
if( !\IPS\Request::i()->id OR !\IPS\Request::i()->idType )
{
$this->_log( "REQUEST_MISSING_DATA", (array) \IPS\Request::i() );
$this->_log( "REQUEST_MISSING_DATA", (array) \IPS\Request::i(), TRUE );
$this->_output( "REQUEST_MISSING_DATA" );
}
@@ -168,7 +191,7 @@ class ipsConnect
if( !\IPS\Request::i()->id OR !\IPS\Request::i()->idType )
{
$this->_log( "REQUEST_MISSING_DATA", (array) \IPS\Request::i() );
$this->_log( "REQUEST_MISSING_DATA", (array) \IPS\Request::i(), TRUE );
$this->_output( "REQUEST_MISSING_DATA" );
}
@@ -198,14 +221,14 @@ class ipsConnect
{
$this->_output( "ACCOUNT_NOT_FOUND" );
}
if ( $member->members_pass_hash != \IPS\Request::i()->password )
if ( !\IPS\Login::compareHashes( $member->members_pass_hash, (string) \IPS\Request::i()->password ) )
{
$this->_log( "WRONG_AUTH", $member );
$this->_log( "WRONG_AUTH", $member, TRUE );
$this->_output( "WRONG_AUTH" );
}
$this->_log( \IPS\Request::i()->fetchId ? "CONNECT_ID_FOUND" : "SUCCESSFUL_LOGIN", $member );
$this->_log( \IPS\Request::i()->fetchId ? "CONNECT_ID_FOUND" : "SUCCESSFUL_LOGIN", $member, TRUE );
return array(
'connect_status' => ( $member->members_bitoptions['validating'] ) ? 'VALIDATING' : 'SUCCESS',
@@ -227,7 +250,7 @@ class ipsConnect
if( !\IPS\Request::i()->id OR !\IPS\Request::i()->idType )
{
$this->_log( "REQUEST_MISSING_DATA", (array) \IPS\Request::i() );
$this->_log( "REQUEST_MISSING_DATA", (array) \IPS\Request::i(), TRUE );
$this->_output( "REQUEST_MISSING_DATA" );
}
@@ -273,7 +296,8 @@ class ipsConnect
{
if ( !$this->_genericKeyCheck( \IPS\Request::i()->id, TRUE, (bool) \IPS\Request::i()->slaveCall ) )
{
\IPS\Output::i()->redirect( \IPS\Request::i()->returnTo );
$this->checkReturnTo();
\IPS\Output::i()->redirect( \IPS\Http\Url::external( \IPS\Request::i()->returnTo ), '', 303 );
}
if( !\IPS\Request::i()->id )
@@ -281,6 +305,16 @@ class ipsConnect
$this->_output( "REQUEST_MISSING_DATA", array(), TRUE );
}
/* Security precaution - if we are a slave, this should be a slave call. If we are a master, it shouldn't be a slave call. */
if( \IPS\Db::i()->select( 'COUNT(*)', 'core_ipsconnect_slaves', array( 'slave_enabled=?', 1 ) )->first() > 0 AND \IPS\Request::i()->slaveCall )
{
$this->_output( "REQUEST_SLAVE_NOT_SLAVE", array(), TRUE );
}
elseif( \IPS\Db::i()->select( 'COUNT(*)', 'core_ipsconnect_slaves', array( 'slave_enabled=?', 1 ) )->first() == 0 AND !\IPS\Request::i()->slaveCall )
{
$this->_output( "REQUEST_NOT_SLAVE_IS_SLAVE", array(), TRUE );
}
/* Fetch the user */
$member = \IPS\Member::load( \IPS\Request::i()->id, \IPS\Request::i()->slaveCall ? 'ipsconnect_id' : NULL );
@@ -300,13 +334,13 @@ class ipsConnect
/* If this was a slave call, we just need to return to the master now */
if( \IPS\Request::i()->slaveCall )
{
\IPS\Output::i()->redirect( \IPS\Request::i()->returnTo );
\IPS\Output::i()->redirect( \IPS\Http\Url::external( \IPS\Request::i()->returnTo ), '', 303 );
}
/* This means we're at the master...figure out which slaves we need to send to */
else
{
$start = (int) \IPS\Request::i()->start;
$select = \IPS\Db::i()->select( '*', 'core_ipsconnect_slaves', array( 'slave_url!=?', \IPS\Request::i()->url ), 'slave_id', array( $start, 1 ) );
$select = \IPS\Db::i()->select( '*', 'core_ipsconnect_slaves', array( 'slave_url!=? AND slave_enabled=?', \IPS\Request::i()->url, 1 ), 'slave_id', array( $start, 1 ) );
if( $select->count() )
{
@@ -334,7 +368,7 @@ class ipsConnect
)
);
\IPS\Output::i()->redirect( $url );
\IPS\Output::i()->redirect( $url, '', 303 );
}
}
@@ -345,7 +379,7 @@ class ipsConnect
}
/* We have hit all the slave installs now, time to go home */
\IPS\Output::i()->redirect( \IPS\Request::i()->origReturn ?: \IPS\Request::i()->returnTo );
\IPS\Output::i()->redirect( \IPS\Http\Url::external( \IPS\Request::i()->origReturn ?: \IPS\Request::i()->returnTo ), '', 303 );
}
}
@@ -359,7 +393,8 @@ class ipsConnect
{
if ( !$this->_genericKeyCheck( \IPS\Request::i()->id, TRUE, (bool) \IPS\Request::i()->slaveCall ) )
{
\IPS\Output::i()->redirect( \IPS\Request::i()->returnTo );
$this->checkReturnTo();
\IPS\Output::i()->redirect( \IPS\Http\Url::external( \IPS\Request::i()->returnTo ), '', 303 );
}
if( !\IPS\Request::i()->id )
@@ -382,13 +417,13 @@ class ipsConnect
/* If this was a slave call, we just need to return to the master now */
if( \IPS\Request::i()->slaveCall )
{
\IPS\Output::i()->redirect( \IPS\Request::i()->returnTo );
\IPS\Output::i()->redirect( \IPS\Http\Url::external( \IPS\Request::i()->returnTo ), '', 303 );
}
/* This means we're at the master...figure out which slaves we need to send to */
else
{
$start = (int) \IPS\Request::i()->start;
$select = \IPS\Db::i()->select( '*', 'core_ipsconnect_slaves', array( 'slave_url!=?', \IPS\Request::i()->url ), 'slave_id', array( $start, 1 ) );
$select = \IPS\Db::i()->select( '*', 'core_ipsconnect_slaves', array( 'slave_url!=? AND slave_enabled=?', \IPS\Request::i()->url, 1 ), 'slave_id', array( $start, 1 ) );
if( $select->count() )
{
@@ -416,7 +451,7 @@ class ipsConnect
)
);
\IPS\Output::i()->redirect( $url );
\IPS\Output::i()->redirect( $url, '', 303 );
}
}
@@ -433,7 +468,28 @@ class ipsConnect
session_destroy();
/* We have hit all the slave installs now, time to go home */
\IPS\Output::i()->redirect( \IPS\Request::i()->origReturn ?: \IPS\Request::i()->returnTo );
\IPS\Output::i()->redirect( \IPS\Http\Url::external( \IPS\Request::i()->origReturn ?: \IPS\Request::i()->returnTo ), '', 303 );
}
}
/**
* Check the returnTo parameter against the referrer for a (basic) security precaution against open redirects
*
* @return void
*/
protected function checkReturnTo()
{
if( !isset( $_SERVER['HTTP_REFERER'] ) OR !$_SERVER['HTTP_REFERER'] )
{
$this->_output( "INVALID_REDIRECTION", array(), TRUE );
}
$referrer = \IPS\Http\Url::external( $_SERVER['HTTP_REFERER'] );
$returnTo = \IPS\Http\Url::external( \IPS\Http\Url::external( \IPS\Request::i()->returnTo ) );
if( $referrer->data['host'] != $returnTo->data['host'] )
{
$this->_output( "INVALID_REDIRECTION", array(), TRUE );
}
}
@@ -448,17 +504,35 @@ class ipsConnect
if( !\IPS\Request::i()->name OR !\IPS\Request::i()->email OR !\IPS\Request::i()->pass_hash OR !\IPS\Request::i()->pass_salt )
{
$this->_log( "REQUEST_MISSING_DATA", (array) \IPS\Request::i() );
$this->_log( "REQUEST_MISSING_DATA", (array) \IPS\Request::i(), TRUE );
$this->_output( "REQUEST_MISSING_DATA" );
}
/* Does this user already exist? */
$member = \IPS\Member::load( \IPS\Request::i()->email, 'email' );
if ( $member->member_id )
{
$this->_log( "ACCOUNT_EXISTS", $member, TRUE );
}
else
{
/* Does this user already exist? */
$member = \IPS\Member::load( \IPS\Request::i()->name, 'name' );
if ( $member->member_id )
{
$this->_log( "ACCOUNT_EXISTS", $member, TRUE );
}
}
if ( !$member->member_id )
{
$member = new \IPS\Member;
$member->name = \IPS\Request::i()->name;
if ( \IPS\CONNECT_NOSYNC_NAMES === FALSE )
{
$member->name = \IPS\Request::i()->name;
}
$member->email = \IPS\Request::i()->email;
$member->member_group_id = \IPS\Settings::i()->member_group;
$member->members_pass_hash = \IPS\Request::i()->pass_hash;
@@ -469,15 +543,11 @@ class ipsConnect
}
$member->ipsconnect_revalidate_url = \IPS\Request::i()->revalidateUrl;
$member->save();
$this->_log( "CREATED_ACCOUNT", $member );
}
else
{
$this->_log( "ACCOUNT_EXISTS", $member );
$this->_log( "CREATED_ACCOUNT", $member, TRUE );
}
/* Do we have any slaves to call? */
$this->_propagateRequest( array( 'do' => 'register', 'key' => '_SERVER_', 'name' => $member->name, 'email' => $member->email, 'pass_hash' => $member->members_pass_hash, 'pass_salt' => $member->members_pass_salt, 'revalidateUrl' => \IPS\Request::i()->revalidateUrl ) );
$this->_propagateRequest( array( 'do' => 'register', 'key' => '_SERVER_', 'name' => $member->name, 'email' => $member->email, 'pass_hash' => $member->members_pass_hash, 'pass_salt' => $member->members_pass_salt, 'id' => $member->member_id, 'revalidateUrl' => \IPS\Request::i()->revalidateUrl ) );
return array( 'connect_id' => $member->member_id );
}
@@ -486,6 +556,9 @@ class ipsConnect
* Validate the user
*
* @return NULL
* @note We used to call $member->validationComplete(), however this results in the user receiving validation completed
* emails from each site in the IPS Connect network which is confusing. It is sufficient to allow just the primary site to
* send the email and notify the admin.
*/
public function validate()
{
@@ -498,9 +571,7 @@ class ipsConnect
$member->ipsconnect_revalidate_url = '';
$member->save();
$member->validate();
$this->_log( "VALIDATED_ACCOUNT", $member );
$this->_log( "VALIDATED_ACCOUNT", $member, TRUE );
/* Do we have any slaves to call? */
$this->_propagateRequest( array( 'do' => 'validate', 'key' => '_SERVER_ID_', 'id' => $member->member_id ) );
@@ -524,7 +595,7 @@ class ipsConnect
{
$member->delete();
$this->_log( "DELETED_ACCOUNT", $member );
$this->_log( "DELETED_ACCOUNT", $member, TRUE );
/* Do we have any slaves to call? */
$this->_propagateRequest( array( 'do' => 'delete', 'key' => '_SERVER_ID_', 'id' => $member->member_id ) );
@@ -549,7 +620,7 @@ class ipsConnect
$member->temp_ban = ( \IPS\Request::i()->status == 1 ) ? -1 : 0;
$member->save();
$this->_log( "BANNED_ACCOUNT", $member );
$this->_log( "BANNED_ACCOUNT", $member, TRUE );
/* Do we have any slaves to call? */
$this->_propagateRequest( array( 'do' => 'ban', 'key' => '_SERVER_ID_', 'id' => $member->member_id, 'status' => \IPS\Request::i()->status ) );
@@ -575,7 +646,7 @@ class ipsConnect
{
$memberToKeep->merge( $memberToRemove );
$this->_log( "MERGED_ACCOUNT", array( 'member' => $memberToKeep, 'removed' => $memberToRemove ) );
$this->_log( "MERGED_ACCOUNT", array( 'member' => $memberToKeep, 'removed' => $memberToRemove ), TRUE );
/* Do we have any slaves to call? */
$this->_propagateRequest( array( 'do' => 'merge', 'key' => '_SERVER_ID_', 'id' => $memberToKeep->member_id, 'remove' => $memberToRemove->member_id ) );
@@ -626,7 +697,7 @@ class ipsConnect
if( !\IPS\Request::i()->email )
{
$this->_log( "REQUEST_MISSING_DATA", (array) \IPS\Request::i() );
$this->_log( "REQUEST_MISSING_DATA", (array) \IPS\Request::i(), TRUE );
$this->_output( "REQUEST_MISSING_DATA" );
}
@@ -647,12 +718,12 @@ class ipsConnect
{
try
{
$handler->changeEmail( $member, $member->email, \IPS\Request::i()->email );
$handler->changeEmail( $member, $oldEmail, \IPS\Request::i()->email );
}
catch( \BadMethodCallException $e ) {}
}
$this->_log( "CHANGED_EMAIL", array( 'member' => $member, 'oldEmail' => $oldEmail ) );
$this->_log( "CHANGED_EMAIL", array( 'member' => $member, 'oldEmail' => $oldEmail ), TRUE );
/* Do we have any slaves to call? */
$this->_propagateRequest( array( 'do' => 'changeEmail', 'key' => '_SERVER_ID_', 'id' => $member->member_id, 'email' => \IPS\Request::i()->email ) );
@@ -672,7 +743,7 @@ class ipsConnect
if( !\IPS\Request::i()->pass_salt OR ! \IPS\Request::i()->pass_hash )
{
$this->_log( "REQUEST_MISSING_DATA", (array) \IPS\Request::i() );
$this->_log( "REQUEST_MISSING_DATA", (array) \IPS\Request::i(), TRUE );
$this->_output( "REQUEST_MISSING_DATA" );
}
@@ -680,11 +751,12 @@ class ipsConnect
if( $member->member_id )
{
$member->members_pass_salt = \IPS\Request::i()->pass_salt;
$member->members_pass_hash = \IPS\Request::i()->pass_hash;
$member->members_pass_salt = \IPS\Request::i()->pass_salt;
$member->members_pass_hash = \IPS\Request::i()->pass_hash;
$member->member_login_key = '';
$member->save();
$this->_log( "CHANGED_PASSWORD", $member );
$this->_log( "CHANGED_PASSWORD", $member, TRUE );
/* Do we have any slaves to call? */
$this->_propagateRequest( array( 'do' => 'changePassword', 'key' => '_SERVER_ID_', 'id' => $member->member_id, 'pass_hash' => \IPS\Request::i()->pass_hash, 'pass_salt' => \IPS\Request::i()->pass_salt ) );
@@ -709,7 +781,7 @@ class ipsConnect
if( !\IPS\Request::i()->name )
{
$this->_log( "REQUEST_MISSING_DATA", (array) \IPS\Request::i() );
$this->_log( "REQUEST_MISSING_DATA", (array) \IPS\Request::i(), TRUE );
$this->_output( "REQUEST_MISSING_DATA" );
}
@@ -735,7 +807,7 @@ class ipsConnect
catch( \BadMethodCallException $e ) {}
}
$this->_log( "CHANGED_NAME", array( 'member' => $member, 'oldName' => $oldName ) );
$this->_log( "CHANGED_NAME", array( 'member' => $member, 'oldName' => $oldName ), TRUE );
/* Do we have any slaves to call? */
$this->_propagateRequest( array( 'do' => 'changeName', 'key' => '_SERVER_ID_', 'id' => $member->member_id, 'name' => \IPS\Request::i()->name ) );
@@ -755,7 +827,7 @@ class ipsConnect
/* Only do this if we're not a slave that is being called */
if( !\IPS\Request::i()->slaveCall )
{
$select = \IPS\Db::i()->select( '*', 'core_ipsconnect_slaves' );
$select = \IPS\Db::i()->select( '*', 'core_ipsconnect_slaves', array( 'slave_enabled=?', 1 ) );
if( $select->count() )
{
@@ -788,9 +860,8 @@ class ipsConnect
/* If this is a registered slave but the slave is telling us Connect is disabled, remove it */
if( isset( $response['status'] ) AND $response['status'] == 'DISABLED' )
{
\IPS\Db::i()->delete( 'core_ipsconnect_slaves', array( 'slave_id=?', $row['slave_id'] ) );
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => \IPS\Db::i()->select( 'COUNT(*)', 'core_ipsconnect_slaves' )->first() ), array( 'conf_key=?', 'connect_slaves' ) );
unset( \IPS\Data\Store::i()->settings );
\IPS\Db::i()->update( 'core_ipsconnect_slaves', array( 'slave_enabled' => 0 ), array( 'slave_id=?', $row['slave_id'] ) );
$this->_recountSlaves();
}
else if( !isset( $response['status'] ) OR $response['status'] != 'SUCCESS' )
{
@@ -802,7 +873,7 @@ class ipsConnect
\IPS\Db::i()->insert( 'core_ipsconnect_queue', array( 'slave_id' => $row['slave_id'], 'request_url' => http_build_query( array_merge( $queryString, array( 'slaveCall' => 1, 'key' => $key ?: ( ( isset( $queryString['key'] ) ) ? $queryString['key'] : '' ) ) ) ) ) );
/* Make sure task is enabled */
\IPS\DB::i()->update( 'core_tasks', array( 'enabled' => 1 ), "`key`='ipsconnect'" );
\IPS\Db::i()->update( 'core_tasks', array( 'enabled' => 1 ), "`key`='connect'" );
}
}
}
@@ -820,7 +891,7 @@ class ipsConnect
*/
protected function _genericKeyCheck( $extra=NULL, $noJson=FALSE, $returnOnError=FALSE )
{
if( $extra !== NULL AND \IPS\Request::i()->key != md5( $this->key . $extra ) )
if( $extra !== NULL AND !\IPS\Login::compareHashes( md5( $this->key . $extra ), (string) \IPS\Request::i()->key ) )
{
if ( $returnOnError )
{
@@ -830,7 +901,7 @@ class ipsConnect
$this->_log( "BAD_KEY" );
$this->_output( "BAD_KEY", array(), $noJson );
}
else if( $extra === NULL AND \IPS\Request::i()->key != $this->key )
else if( $extra === NULL AND !\IPS\Login::compareHashes( (string) $this->key, (string) \IPS\Request::i()->key ) )
{
if ( $returnOnError )
{
@@ -849,9 +920,10 @@ class ipsConnect
*
* @param string $message Message to log
* @param array $data Other data to log
* @param bool $debug Only log this message if debug logging is enabled
* @return void
*/
protected function _log( $message, $data=NULL )
protected function _log( $message, $data=NULL, $debug=FALSE )
{
/* If we are a slave and the request is just propagating, just return - we don't need to log */
if( \IPS\Request::i()->slaveCall )
@@ -866,7 +938,14 @@ class ipsConnect
$log[] = json_encode( $data );
}
\IPS\Log::i( LOG_INFO )->write( implode( "\n", $log ), 'ipsconnect' );
if( $debug === true )
{
\IPS\Log::debug( implode( "\n", $log ), 'ipsconnect' );
}
else
{
\IPS\Log::log( implode( "\n", $log ), 'ipsconnect' );
}
}
/**
@@ -894,6 +973,17 @@ class ipsConnect
\IPS\Output::i()->json( array_merge( array( 'status' => $status ), $data ), 200 );
}
}
/**
* Recount the number of active slaves we have
*
* @return void
*/
protected function _recountSlaves()
{
\IPS\Db::i()->update( 'core_sys_conf_settings', array( 'conf_value' => \IPS\Db::i()->select( 'COUNT(*)', 'core_ipsconnect_slaves', array( 'slave_enabled=?', 1 ) )->first() ), array( 'conf_key=?', 'connect_slaves' ) );
unset( \IPS\Data\Store::i()->settings );
}
}
/* If we have a custom.php in this directory with a class ipsConnect_custom (which should extend this class) we will load that instead */