Invision Power Services, Inc.
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 31 Jul 2017
*/
// This file deliberately exists outside of the framework
// and MUST NOT call init.php
@ini_set('display_errors', 'off');
if ( file_exists( "../../constants.php" ) )
{
require "../../constants.php";
}
if ( !defined( 'ROOT_PATH' ) )
{
define( 'ROOT_PATH', str_replace( 'admin/upgrade', '', __DIR__ ) );
}
require "../../conf_global.php";
/**
* Compare hashes in fixed length, time constant manner.
*
* @param string $expected The expected hash
* @param string $provided The provided input
* @return boolean
*/
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;
}
/**
* Get CiCloud User
*
* @return string|NULL
*/
function getCicUsername(): ?string
{
if ( preg_match( '/^\/var\/www\/html\/(.+?)(?:\/|$)/i', ROOT_PATH, $matches ) )
{
return $matches[1];
}
return NULL;
}
/**
* 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 = "\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 */
try
{
/* Check this request came from the ACP */
if ( !getCicUsername() OR compareHashes( md5( getCicUsername() . $INFO['sql_pass'] ), $_GET['key'] ) === FALSE )
{
throw new Exception( "Security check failed" );
}
/* We are done if last_auto_upgrade exists and is both older than the current time but updated less than ten minutes ago. */
$done = ( isset( $INFO['last_auto_upgrade'] ) AND $INFO['last_auto_upgrade'] < time() AND ( $INFO['last_auto_upgrade'] > time() - ( 10 * 60 ) ) );
$adsess = $_GET['adsess'] ?? '';
if ( $done )
{
if ( function_exists( 'opcache_reset' ) )
{
@opcache_reset();
}
$siteurl = $INFO['base_url'] ?? $INFO['board_url'];
$upgradeUrl = rtrim( $siteurl, '/' ) . "/admin/upgrade/";
echo <<
HTML;
}
/* Nope, redirect to the next batch */
else
{
if ( !isset( $_GET['counter'] ) )
{
$_GET['counter'] = 0;
}
$i = 1 + $_GET['counter'];
$url = "extractCic.php?counter={$i}&key={$_GET['key']}&adsess={$adsess}";
echo <<
HTML;
}
}
catch ( Throwable $e )
{
writeLogFile( $e );
echo "";
exit;
}
?>