Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
matrix:
include:
- mediawiki_version: '1.39'
smw_version: dev-master
smw_version: '5.1.0'
php_version: 8.1
database_type: mysql
database_image: "mariadb:10"
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ DB_IMAGE?=""
SMW_VERSION?=4.1.3
MM_VERSION ?= 3.1.0

# PHP extensions
PHP_EXTENSIONS?=gd,zlib

# composer
# Enables "composer update" inside of extension
COMPOSER_EXT?=true
Expand Down
2 changes: 1 addition & 1 deletion extension.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"Robin van der Wiel",
"Yvar Nanlohij"
],
"version": "2.1.1",
"version": "2.1.2",
"url": "https://www.archixl.nl",
"descriptionmsg": "sic-desc",
"license-name": "GPL-2.0+",
Expand Down
7 changes: 4 additions & 3 deletions i18n/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
"sic-selection-generic-error": "Er is een fout opgetreden tijdens tekst selectie.",
"sic-show-screenshot-full-size": "Klik om de volledige grootte te bekijken",
"sic-broken-comments-below": "Er zijn opmerkingen die niet meer gekoppeld zijn aan een tekstselectie op deze pagina",
"sc-status-open": "Open",
"sc-status-completed": "Afgesloten"
}
"sc-status-open": "open",
"sc-status-completed": "afgehandeld"
}

2 changes: 1 addition & 1 deletion src/DBHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ public static function selectAllPages() : array {
foreach ( $res as $page ) {
$title = Title::newFromID( $page );
if ( $title ) {
$pages[] = $title->getText();
$pages[] = $title->getFullText();
}
}

Expand Down
10 changes: 10 additions & 0 deletions src/Store/ImageSaver.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ public function save( $data ): ?string {
$data = str_replace( ' ', '+', $data );
$data = base64_decode($data);

try {
$image = \imagecreatefromstring( $data );
} catch ( \Exception $e ) {
return null;
}

if ( $image === false ) {
return null;
}

if ( $data === false ) {
return null;
}
Expand Down
88 changes: 88 additions & 0 deletions tests/phpunit/Integration/Store/ImageSaverTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

namespace SmartComments\Tests\Integration\Store;

use MediaWiki\Extension\SmartComments\Store\ImageSaver;
use MediaWiki\Extension\SmartComments\Hooks;
use PHPUnit\Framework\TestCase;

class ImageSaverTest extends TestCase {

/**
* @var \Title|\PHPUnit\Framework\MockObject\MockObject
*/
private $titleMock;

/**
* Set up the test environment
*/
protected function setUp(): void {
parent::setUp();

$this->titleMock = $this->createMock( \Title::class );
$this->titleMock->method( 'getId' )->willReturn( 123 );

Hooks::$imageSaveDirectory = sys_get_temp_dir();
}

/**
* Test that ImageSaver returns null for invalid XSS payload
*/
public function testInvalidXssPayload(): void {
$imageSaver = new ImageSaver( $this->titleMock );

$invalidPayload = 'data:image/png;base64,PHNjcmlwdD5hbGVydCgneHNzJyk7PC9zY3JpcHQ+';

$result = $imageSaver->save( $invalidPayload );

$this->assertNull( $result, 'ImageSaver should return null for XSS payload' );
}

/**
* Test that ImageSaver returns a filename for valid payload
*/
public function testValidPayload(): void {
$imageSaver = new ImageSaver( $this->titleMock );

$validPayload = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';

$result = $imageSaver->save( $validPayload );

$this->assertNotNull( $result, 'ImageSaver should return a filename for valid payload' );

$filePath = Hooks::$imageSaveDirectory . '/' . $result;
$this->assertFileExists( $filePath, 'Image file should be created' );

if ( file_exists( $filePath ) ) {
unlink( $filePath );
}
}

/**
* Test that ImageSaver returns null for non-image data
*/
public function testNonImageData(): void {
$imageSaver = new ImageSaver( $this->titleMock );

// Base64 encoded text that's not an image
$nonImagePayload = 'data:image/png;base64,SGVsbG8gV29ybGQ=';

$result = $imageSaver->save( $nonImagePayload );

// Assert that the result is null for non-image data
$this->assertNull( $result, 'ImageSaver should return null for non-image data' );
}

/**
* Test that ImageSaver returns null for unsupported image type
*/
public function testUnsupportedImageType(): void {
$imageSaver = new ImageSaver( $this->titleMock );

$unsupportedTypePayload = 'data:image/webp;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';

$result = $imageSaver->save( $unsupportedTypePayload );

$this->assertNull( $result, 'ImageSaver should return null for unsupported image type' );
}
}
Loading