A new editor needs a username and a password of at least 12 characters. A persistent login needs an unexpired key and an existing account. Removing an account revokes its persistent logins, and its sessions end.
107 lines
5.1 KiB
PHP
107 lines
5.1 KiB
PHP
<?php
|
|
namespace Xxx\Tests\Pages;
|
|
|
|
use Xxx\Tests\Support\PageTestCase;
|
|
use Xxx\Tests\Support\TestCase;
|
|
|
|
// feed.php and display.php
|
|
class FeedAndImageTest extends PageTestCase {
|
|
protected function setUp(): void {
|
|
parent::setUp();
|
|
$this->setTables(array(
|
|
'xxx' => array(
|
|
array('id' => 1, 'title' => 'Tom & "Jerry"', 'author' => 'Ann <ann>', 'date' => '2021-01-03 10:00:00',
|
|
'story' => "<p>Wait… a <strong>bold</strong>\x01 move & more.</p>"),
|
|
array('id' => 2, 'title' => 'Picture', 'date' => '2021-01-02 10:00:00', 'story' => '', 'img' => TestCase::png(), 'mime' => 'text/html'),
|
|
array('id' => 3, 'title' => 'Secret', 'date' => '2021-01-01 10:00:00', 'img' => TestCase::png(), 'mime' => 'image/png', 'hidden' => '1'),
|
|
array('id' => 4, 'title' => 'Not an image', 'img' => '<script>alert(1)</script>', 'mime' => 'image/png'),
|
|
),
|
|
'queue' => array(
|
|
array('id' => 9, 'title' => 'Waiting', 'img' => TestCase::png(), 'mime' => 'image/png'),
|
|
),
|
|
));
|
|
}
|
|
|
|
public function testTheFeedIsValidRss(): void {
|
|
$feed = $this->get('/feed');
|
|
$this->assertSame('application/rss+xml', $this->header($feed, 'Content-Type'));
|
|
$xml = simplexml_load_string($feed['body']);
|
|
$this->assertNotFalse($xml, $feed['body']);
|
|
$items = $xml->channel->item;
|
|
// The front page, then the visible stories, newest first
|
|
$this->assertSame(array('Front Page', 'Tom & "Jerry"', 'Picture', 'Not an image'),
|
|
array_map('strval', iterator_to_array($xml->xpath('/rss/channel/item/title'), FALSE)));
|
|
// The addresses come from SITE_URL
|
|
$this->assertSame('https://site.test/', (string)$xml->channel->link);
|
|
$this->assertSame('https://site.test/article?id=1', (string)$items[1]->link);
|
|
$this->assertSame('editor@site.test (Editors)', (string)$xml->channel->managingEditor);
|
|
$this->assertStringContainsString('edi', $feed['body']);
|
|
$this->assertSame('Wait… a bold move & more.', (string)$items[1]->description);
|
|
$this->assertSame('Ann <ann>', (string)$items[1]->children('http://purl.org/dc/elements/1.1/')->creator);
|
|
$this->assertSame('Image: Picture', (string)$items[2]->description);
|
|
$this->assertSame(date('D, d M Y H:i:s O', strtotime('2021-01-03 10:00:00')), (string)$xml->channel->lastBuildDate);
|
|
}
|
|
|
|
public function testAnImageIsServedWithItsRealType(): void {
|
|
$image = $this->get('/display?id=2');
|
|
$this->assertSame(200, $image['status']);
|
|
$this->assertSame(TestCase::png(), $image['body']);
|
|
$this->assertSame('image/png', $this->header($image, 'Content-Type'));
|
|
$this->assertSame('nosniff', $this->header($image, 'X-Content-Type-Options'));
|
|
$this->assertSame((string)strlen(TestCase::png()), $this->header($image, 'Content-Length'));
|
|
}
|
|
|
|
public function testDataThatIsNotAnImageIsNotServed(): void {
|
|
$image = $this->get('/display?id=4');
|
|
$this->assertSame(404, $image['status']);
|
|
$this->assertStringNotContainsString('script', $image['body']);
|
|
}
|
|
|
|
public function testAMissingImageIsNotFound(): void {
|
|
$this->assertSame(404, $this->get('/display?id=99')['status']);
|
|
$this->assertSame(404, $this->get('/display?id=1')['status']);
|
|
}
|
|
|
|
public function testHiddenImagesAreForEditorsOnly(): void {
|
|
$this->assertSame(404, $this->get('/display?id=3')['status']);
|
|
$this->loginAs();
|
|
$this->assertSame(200, $this->get('/display?id=3')['status']);
|
|
}
|
|
|
|
public function testARemovedEditorSeesNoHiddenImages(): void {
|
|
$this->loginAs();
|
|
$this->setTables(array('xxx' => $this->tables()['xxx']));
|
|
$this->assertSame(404, $this->get('/display?id=3')['status']);
|
|
}
|
|
|
|
public function testQueuedImagesNeedPermission(): void {
|
|
$this->assertSame(401, $this->get('/display?id=9&queue=1')['status']);
|
|
$this->startSession(array('allow_queue_image' => '8'));
|
|
$this->assertSame(401, $this->get('/display?id=9&queue=1')['status']);
|
|
$this->startSession(array('allow_queue_image' => '9'));
|
|
$this->assertSame(200, $this->get('/display?id=9&queue=1')['status']);
|
|
$this->loginAs();
|
|
$this->assertSame(200, $this->get('/display?id=9&queue=1')['status']);
|
|
}
|
|
|
|
public function testThePendingUploadIsShownToItsSession(): void {
|
|
$name = bin2hex(random_bytes(16));
|
|
mkdir(self::$state . '/tmp/uploads', 0700);
|
|
file_put_contents(self::$state . "/tmp/uploads/$name", TestCase::png());
|
|
$this->assertSame(404, $this->get('/display?pending=x')['status']);
|
|
$this->startSession(array('pending_upload' => $name));
|
|
$image = $this->get('/display?pending=' . substr($name, 0, 8));
|
|
$this->assertSame(200, $image['status']);
|
|
$this->assertSame(TestCase::png(), $image['body']);
|
|
$this->assertSame('private, no-store', $this->header($image, 'Cache-Control'));
|
|
}
|
|
|
|
public function testAPendingUploadMustBeAnImage(): void {
|
|
$name = bin2hex(random_bytes(16));
|
|
mkdir(self::$state . '/tmp/uploads', 0700);
|
|
file_put_contents(self::$state . "/tmp/uploads/$name", '<html>This is not an image at all.</html>');
|
|
$this->startSession(array('pending_upload' => $name));
|
|
$this->assertSame(404, $this->get('/display?pending=x')['status']);
|
|
}
|
|
}
|