Version 4.5.0

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

No files matched your search

+117 -22
View File
@@ -26,11 +26,11 @@ if ( file_exists( "../../constants.php" ) )
{
require "../../constants.php";
}
foreach ( array( 'FOLDER_PERMISSION_NO_WRITE' => 0755, 'FILE_PERMISSION_NO_WRITE' => 0644, 'TEMP_DIRECTORY' => sys_get_temp_dir() ) as $k => $v )
foreach ( array( 'FOLDER_PERMISSION_NO_WRITE' => 0755, 'FILE_PERMISSION_NO_WRITE' => 0644, 'IPS_FILE_PERMISSION' => 0666, 'TEMP_DIRECTORY' => sys_get_temp_dir() ) as $k => $v )
{
if ( !defined( $k ) )
if ( !\defined( $k ) )
{
define( $k, $v );
\define( $k, $v );
}
}
@@ -92,7 +92,7 @@ class Extractor
{
if ( !$file or !$container )
{
throw new Exception;
throw new Exception( "Zip file or directory to extract to was not supplied" );
}
$this->file = $file;
@@ -108,7 +108,28 @@ class Extractor
public function securityCheck( $key )
{
require "../../conf_global.php";
return $key === md5( $INFO['board_start'] . $_GET['file'] . $INFO['sql_pass'] );
$db = new mysqli( $INFO['sql_host'], $INFO['sql_user'], $INFO['sql_pass'], $INFO['sql_database'], !empty( $INFO['sql_port'] ) ? $INFO['sql_port'] : null, !empty( $INFO['sql_socket'] ) ? $INFO['sql_socket'] : null );
/* If the connection failed, do not continue */
if( $error = mysqli_connect_error() )
{
return FALSE;
}
/* Check that there is an upgrade in progress */
$query = $db->query( "SELECT conf_value FROM {$INFO['sql_tbl_prefix']}core_sys_conf_settings WHERE conf_key='setup_in_progress'" );
if( !$query )
{
return FALSE;
}
if( (bool) $query->fetch_assoc()['conf_value'] === FALSE )
{
return FALSE;
}
return $this->_compareHashes( md5( $INFO['board_start'] . $_GET['file'] . $INFO['sql_pass'] ), $key );
}
/**
@@ -124,21 +145,21 @@ class Extractor
$this->ssh = ssh2_connect( $value['server'], $value['port'] );
if ( $this->ssh === FALSE )
{
throw new Exception;
throw new Exception( "Could not connect to SCP" );
}
if ( !@ssh2_auth_password( $this->ssh, $value['un'], $value['pw'] ) )
{
throw new Exception;
throw new Exception( "Could not login to SCP" );
}
$this->sftp = @ssh2_sftp( $this->ssh );
if ( $this->sftp === FALSE )
{
throw new Exception;
throw new Exception( "Could not initiate SFTP connection" );
}
if ( $value['path'] and !@ssh2_sftp_stat( $this->sftp, $value['path'] ) )
{
throw new Exception;
throw new Exception( "Could not locate path via SFTP" );
}
$this->sftpDir = ssh2_sftp_realpath( $this->sftp, $value['path'] ) . '/';
@@ -155,11 +176,11 @@ class Extractor
}
if ( $this->ftp === FALSE )
{
throw new Exception;
throw new Exception( "Could not connect to FTP" );
}
if ( !@ftp_login( $this->ftp, $value['un'], $value['pw'] ) )
{
throw new Exception;
throw new Exception( "Could not login to FTP" );
}
if( ftp_nlist( $this->ftp, '.' ) === FALSE )
{
@@ -168,7 +189,7 @@ class Extractor
if ( !@ftp_chdir( $this->ftp, $value['path'] ) )
{
throw new Exception;
throw new Exception( "Could not change directory to {$value['path']}" );
}
}
}
@@ -196,7 +217,7 @@ class Extractor
$this->contents = $this->zip->listContent();
if ( !$this->contents )
{
throw new Exception;
throw new Exception( "Could not list the files in the zip" );
}
$done = 0;
@@ -234,11 +255,11 @@ class Extractor
}
/* Create a directory if needed */
$dir = dirname( $path );
$dir = \dirname( $path );
$directories = array( $dir );
while ( $dir != '.' )
{
$dir = dirname( $dir );
$dir = \dirname( $dir );
if ( $dir != '.' )
{
$directories[] = $dir;
@@ -273,16 +294,16 @@ class Extractor
if ( $this->sftp )
{
if ( @ssh2_scp_send( $this->ssh, $tmpFile, $this->sftpDir . $path ) === FALSE )
if ( @ssh2_scp_send( $this->ssh, $tmpFile, $this->sftpDir . $path, FILE_PERMISSION_NO_WRITE ) === FALSE )
{
throw new \Exception;
throw new \Exception( "Could not transfer file to server via SFTP" );
}
}
else
{
if ( @ftp_put( $this->ftp, $path, $tmpFile, FTP_BINARY ) === FALSE )
{
throw new \Exception;
throw new \Exception( "Could not transfer file to server via FTP" );
}
}
@@ -309,7 +330,7 @@ class Extractor
/* If the file existed before we started, we should clear it from opcache if opcache is enabled */
if( $fileExists )
{
if ( function_exists( 'opcache_invalidate' ) )
if ( \function_exists( 'opcache_invalidate' ) )
{
@opcache_invalidate( "../../{$path}" );
}
@@ -323,6 +344,78 @@ class Extractor
@\fclose( $fh );
}
}
/* !Misc Utility Methods */
/**
* Compare hashes in fixed length, time constant manner.
* This is replicated from \IPS\Login::compareHashes(), however we don't want to include framework code here.
*
* @param string $expected The expected hash
* @param string $provided The provided input
* @return boolean
*/
private function _compareHashes( $expected, $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;
}
$len = \strlen( $expected );
if ( $len !== \strlen( $provided ) )
{
return FALSE;
}
$status = 0;
for ( $i = 0; $i < $len; $i++ )
{
$status |= \ord( $expected[ $i ] ) ^ \ord( $provided[ $i ] );
}
return $status === 0;
}
}
/**
* Function to write a log file to disk
*
* @param mixed $message Exception or message to log
* @return void
*/
function writeLogFile( $message )
{
/* What are we writing? */
$date = date('r');
if ( $message instanceof \Exception )
{
$messageToLog = $date . "\n" . \get_class( $message ) . '::' . $message->getCode() . "\n" . $message->getMessage() . "\n" . $message->getTraceAsString();
}
else
{
if ( \is_array( $message ) )
{
$message = var_export( $message, TRUE );
}
$messageToLog = $date . "\n" . $message . "\n" . ( new \Exception )->getTraceAsString();
}
/* Where are we writing it? */
$dir = rtrim( __DIR__, '/' ) . '/../../uploads/logs';
/* Write it */
$header = "<?php exit; ?>\n\n";
$file = $dir . '/' . date( 'Y' ) . '_' . date( 'm' ) . '_' . date('d') . '_' . ( 'extractfailure' ) . '.php';
if ( file_exists( $file ) )
{
@\file_put_contents( $file, "\n\n-------------\n\n" . $messageToLog, FILE_APPEND );
}
else
{
@\file_put_contents( $file, $header . $messageToLog );
}
@chmod( $file, IPS_FILE_PERMISSION );
}
/* ! Controller */
@@ -333,7 +426,7 @@ try
/* Check this request came from the ACP */
if ( !$extractor->securityCheck( $_GET['key'] ) )
{
throw new Exception;
throw new Exception( "Security check failed" );
}
/* Establish an FTP connection if necessary */
@@ -351,7 +444,7 @@ try
{
@unlink( $_GET['file'] );
if ( function_exists( 'opcache_reset' ) )
if ( \function_exists( 'opcache_reset' ) )
{
@opcache_reset();
}
@@ -387,8 +480,10 @@ HTML;
HTML;
}
}
catch ( Exception $e )
catch ( Throwable $e )
{
writeLogFile( $e );
echo "<script type='text/javascript'>parent.location = parent.location + '&fail=1';</script><noscript>An error occurred. Please visit the <a href='https://remoteservices.invisionpower.com/docs/client_area' target='_blank' rel='noopener'>client area</a> to manually download the latest version. After uploading the files, <a href='index.php' target='_parent'>continue to the upgrader</a>.</noscript>";
exit;
}