Version 4.7.23

This commit is contained in:
Neo committed 2025-12-19 16:21:27 -08:00
1 parent 7124a02564
commit 25ddeb65d6
1791 files changed
+76990 -44452

No files matched your search

+9 -6
View File
@@ -159,20 +159,23 @@ class _Encrypt
}
/**
* Decript
* Decrypt
*
* @param string|null $encryptionKey Custom decryption key
* @return string
*/
public function decrypt()
public function decrypt( ?string $encryptionKey=NULL ): string
{
$keyToUse = $encryptionKey ?? static::key();
if ( $this->tag )
{
return openssl_decrypt( $this->cipher, 'aes-128-gcm', static::key(), 0, $this->iv, $this->tag );
return openssl_decrypt( $this->cipher, 'aes-128-gcm', $keyToUse, 0, $this->iv, $this->tag );
}
elseif ( $this->hmac )
{
$decrypted = openssl_decrypt( $this->cipher, 'aes-128-cbc', static::key(), OPENSSL_RAW_DATA, $this->iv );
if ( hash_equals( $this->hmac, hash_hmac( 'sha256', $this->cipher, static::key(), TRUE ) ) )
$decrypted = openssl_decrypt( $this->cipher, 'aes-128-cbc', $keyToUse, OPENSSL_RAW_DATA, $this->iv );
if ( hash_equals( $this->hmac, hash_hmac( 'sha256', $this->cipher, $keyToUse, TRUE ) ) )
{
return $decrypted;
}
@@ -181,7 +184,7 @@ class _Encrypt
else
{
require_once \IPS\ROOT_PATH . '/system/3rd_party/AES/AES.php';
return \AesCtr::decrypt( $this->cipher, static::key(), 256 );
return \AesCtr::decrypt( $this->cipher, $keyToUse, 256 );
}
}
}
@@ -0,0 +1,45 @@
<?php
/**
* @brief A HTMLPurifier Attribute Definition used for attributes which must be internal URLs or Integers (such as data-fileid for attachments)
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @since 21 October 2024
*/
namespace IPS\Text;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* A HTMLPurifier Attribute Definition used for attributes which must be internal URLs or Integers (such as data-fileid for attachments)
*/
class _HtmlPurifierIntOrInternalLink extends HtmlPurifierInternalLinkDef
{
/**
* Validate
*
* @param string $value
* @param \HTMLPurifier_Config $config
* @param \HTMLPurifier_Context $context
* @return bool|string
*/
public function validate( $value, $config, $context )
{
$parentCheck = parent::validate( $value, $config, $context );
if( $parentCheck !== FALSE )
{
return $parentCheck;
}
$integer = new \HTMLPurifier_AttrDef_Integer( false );
return $integer->validate( $value, $config, $context );
}
}
+8 -1
View File
@@ -50,7 +50,14 @@ class _HtmlPurifierInternalLinkDef extends \HTMLPurifier_AttrDef_URI
public function validate($uri, $config, $context)
{
/* Create the URL */
$url = \IPS\Http\Url::createFromString( str_replace( array( '%7B___base_url___%7D/', '{___base_url___}/' ), \IPS\Settings::i()->base_url, $uri ) );
try
{
$url = \IPS\Http\Url::createFromString( str_replace( array( '%7B___base_url___%7D/', '{___base_url___}/' ), \IPS\Settings::i()->base_url, $uri ) );
}
catch( \IPS\Http\Url\Exception $e )
{
return FALSE;
}
/* If it's not internal, we can stop now */
if ( !( $url instanceof \IPS\Http\Url\Internal ) )
+40 -12
View File
@@ -11,6 +11,9 @@
namespace IPS\Text;
/* To prevent PHP errors (extending class does not exist) revealing path */
use function preg_replace;
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
@@ -640,8 +643,8 @@ class _Parser
$def->addAttribute( 'img', 'data-emoticon', 'Bool' ); // Identifies emoticons and stops lightbox running on them
/* Attachments (set by _parseAElement, _parseImgElement and "insert existing attachment") - Gallery/Downloads use the full URL rather than an ID, hence Text */
$def->addAttribute( 'a', 'data-fileid', 'Text' );
$def->addAttribute( 'img', 'data-fileid', 'Text' );
$def->addAttribute( 'a', 'data-fileid', new HtmlPurifierIntOrInternalLink() );
$def->addAttribute( 'img', 'data-fileid', new HtmlPurifierIntOrInternalLink() );
$def->addAttribute( 'a', 'data-fileext', 'Text' );
/* Existing media (inserted with data-extension by the JS so that _getFile is able to locate) */
@@ -656,7 +659,7 @@ class _Parser
/* iFrames (used by embeddableMedia) */
$def->addAttribute( 'iframe', 'data-controller', new \HTMLPurifier_AttrDef_Enum( array( 'core.front.core.autosizeiframe' ) ) ); // used in core/global/embed/iframe.phtml
$def->addAttribute( 'iframe', 'data-embedid', 'Text' ); // used in core/global/embed/iframe.phtml
$def->addAttribute( 'iframe', 'data-embedauthorid', 'Text' ); // used for embed notifications
$def->addAttribute( 'iframe', 'data-embedauthorid', 'Number' ); // used for embed notifications
$def->addAttribute( 'iframe', 'data-embedcontent', 'Text' ); // used in embeddableMedia
$def->addAttribute( 'iframe', 'allowfullscreen', 'Text' ); // Some services will specify this property
@@ -2061,8 +2064,21 @@ class _Parser
*/
protected function _parseSourceElement( \DOMElement $element, \DOMElement $originalElement = NULL )
{
$parentIsVideo = function( \DOMElement $element ) use ( &$parentIsVideo ) {
if( $element->tagName === 'video' )
{
return TRUE;
}
elseif( $element->parentNode !== NULL AND $element->parentNode instanceof \DOMElement )
{
return $parentIsVideo( $element->parentNode );
}
return FALSE;
};
/* We only want to do this for videos */
if( $originalElement !== NULL AND $originalElement->parentNode->tagName !== 'video' )
if( $originalElement !== NULL AND !$parentIsVideo( $originalElement ) )
{
return $element;
}
@@ -2088,7 +2104,7 @@ class _Parser
* Parse <iframe> element
*
* @param \DOMElement $element The element
* @return bool
* @return \DOMElement
*/
protected function _parseIframeElement( \DOMElement $element )
{
@@ -2096,7 +2112,7 @@ class _Parser
{
$src = \IPS\Http\Url::createFromString( $element->getAttribute('src') );
if( mb_strpos( $src->data['host'], 'youtube.com' ) !== FALSE )
if( mb_strpos( $src->data['host'], 'youtube.com' ) !== FALSE OR mb_strpos( $src->data['host'], 'youtube-nocookie.com' ) !== FALSE )
{
/* If this is a youtube link, let's strip auto-play... */
$src = $src->stripQueryString( 'autoplay' );
@@ -2105,7 +2121,7 @@ class _Parser
$element->setAttribute( 'src', static::blankPage() );
}
else if ( $src instanceof \IPS\Http\Url\Internal )
{
{
/* If this is an internal embed, replace src and controller for lazy loading */
if ( \IPS\Settings::i()->lazy_load_enabled )
{
@@ -3051,7 +3067,7 @@ class _Parser
{
if ( $bbcode->permissionCheck( $member, $area ) )
{
list( $app, $tag ) = explode( '_', $key );
[ $app, $tag ] = explode( '_', $key );
$return[ $tag ] = $bbcode->getConfiguration();
}
}
@@ -3287,6 +3303,7 @@ class _Parser
'tiktok.com' => array( 'https://www.tiktok.com/oembed', static::EMBED_VIDEO ),
'm.tiktok.com' => array( 'https://www.tiktok.com/oembed', static::EMBED_VIDEO ),
'vm.tiktok.com' => array( 'https://www.tiktok.com/oembed', static::EMBED_VIDEO ),
'bsky.app' => [ 'https://embed.bsky.app/oembed', static::EMBED_TWEET ]
);
/* Can we support Facebook and Instagram oembeds? */
@@ -3977,9 +3994,15 @@ class _Parser
protected static function _internalEmbed( \IPS\Http\Url $url, $iframe=FALSE, $member=NULL )
{
/* If this URL has a #comment-123 fragment, change it to the findComment URL so the comment embeds rather than the item */
if ( isset( $url->data['fragment'] ) and mb_strstr( $url->data['fragment'], 'comment-' ) and empty( $url->queryString['do'] ) )
if ( isset( $url->data['fragment'] ) and mb_stristr( $url->data['fragment'], 'comment-' ) and empty( $url->queryString['do'] ) )
{
$url = $url->setQueryString( array( 'do' => 'findComment', 'comment' => str_replace( 'comment-', '', $url->data['fragment'] ) ) );
$url = $url->setQueryString( array( 'do' => 'findComment', 'comment' => preg_replace( '#(find)?comment-#i', '', $url->data['fragment'] ) ) );
}
/* And for reviews */
if ( isset( $url->data['fragment'] ) and mb_stristr( $url->data['fragment'], 'review-' ) and empty( $url->queryString['do'] ) )
{
$url = $url->setQueryString( array( 'do' => 'findReview', 'review' => preg_replace( '#(find)?review-#i', '', $url->data['fragment'] ) ) );
}
/* Get the "real" query string (whatever the query string is, plus what we can get from decoding the FURL) */
@@ -4168,11 +4191,16 @@ class _Parser
{
return (string) $url;
}
$width = (int) $width;
$height = (int) $height;
$maxImageDims = \IPS\Settings::i()->attachment_image_size ? explode( 'x', \IPS\Settings::i()->attachment_image_size ) : array( 1000, 750 );
$widthToUse = $width;
$heightToUse = $height;
$maxImageDims = array_map('intval', $maxImageDims);
/* 0x0 means unlimited, so only do these calculations if a specific size has been set */
if( \intval( $maxImageDims[0] ) !== 0 || \intval( $maxImageDims[1] ) !== 0 )
{
@@ -4195,7 +4223,7 @@ class _Parser
if ( $widthToUse > $maxImageDims[0] )
{
$heightToUse = floor( $maxImageDims[0] * ( $heightToUse / $widthToUse ) );
$heightToUse = floor( $maxImageDims[0] * ( $heightToUse / $widthToUse ) );
$widthToUse = $maxImageDims[0];
}
}
@@ -4255,7 +4283,7 @@ class _Parser
if( $element->tagName == $matches[1] )
{
/* Break up the definition into name and value */
list( $attribute, $value ) = explode( '=', trim( $matches[2] ) );
[ $attribute, $value ] = explode( '=', trim( $matches[2] ) );
/* Remove quotes */
$value = str_replace( array( '"', "'" ), '', $value );