PluginSanitizeTest.php

main 86 lines · 2.5 KB Raw
Alex Alex Commit Initial commit 01/10/2026 09:20
1<?php
2
3declare(strict_types=1);
4
5namespace ZnoteX\Tests\Security;
6
7use PHPUnit\Framework\TestCase;
8
9final class PluginSanitizeTest extends TestCase
10{
11 public function testAcceptsAnOrdinaryPluginName(): void
12 {
13 $this->assertSame('boosted_creatures', \znote_plugin_sanitize('boosted_creatures'));
14 }
15
16 public function testLowercasesAndTrims(): void
17 {
18 $this->assertSame('shop-coupons', \znote_plugin_sanitize(' Shop-Coupons '));
19 }
20
21 /** @dataProvider pathTraversalProvider */
22 public function testRejectsPathTraversalAttempts(string $malicious): void
23 {
24 $this->assertSame('', \znote_plugin_sanitize($malicious));
25 }
26
27 public static function pathTraversalProvider(): array
28 {
29 return [
30 'parent directory' => ['../../../etc/passwd'],
31 'nested traversal' => ['plugins/../../config.local.php'],
32 'absolute unix path' => ['/etc/passwd'],
33 'absolute windows path' => ['C:\\Windows\\System32'],
34 'null byte' => ["plugin\0.php"],
35 'slash' => ['foo/bar'],
36 'backslash' => ['foo\\bar'],
37 'empty string' => [''],
38 'only dots' => ['..'],
39 'too long' => [str_repeat('a', 65)],
40 ];
41 }
42
43 public function testExtensionApiRejectsAnInvalidPluginName(): void
44 {
45 $this->expectException(\InvalidArgumentException::class);
46 \ZnoteExtensionApi::plugin('../../../etc/passwd');
47 }
48
49 public function testExtensionApiAcceptsAValidPluginName(): void
50 {
51 $api = \ZnoteExtensionApi::plugin('boosted_creatures');
52 $this->assertSame('boosted_creatures', $api->name());
53 $this->assertSame('plugin', $api->kind());
54 }
55
56 /** @dataProvider relativePathTraversalProvider */
57 public function testRelativePathHelperRejectsTraversal(string $malicious): void
58 {
59 $this->assertSame('', \znote_extension_relative_path($malicious));
60 }
61
62 public static function relativePathTraversalProvider(): array
63 {
64 return [
65 'parent directory' => ['../../../etc/passwd'],
66 'nested traversal' => ['css/../../config.local.php'],
67 'absolute windows path' => ['C:\\Windows\\System32'],
68 'null byte' => ["css/style\0.css"],
69 'only dots' => ['..'],
70 'single dot segment' => ['css/./style.css'],
71 'empty string' => [''],
72 ];
73 }
74
75 public function testRelativePathHelperAcceptsAnOrdinaryAssetPath(): void
76 {
77 $this->assertSame('css/style.css', \znote_extension_relative_path('css/style.css'));
78 }
79
80 public function testRelativePathHelperNormalisesBackslashesAndLeadingSlash(): void
81 {
82 $this->assertSame('css/style.css', \znote_extension_relative_path('\\css\\style.css'));
83 $this->assertSame('css/style.css', \znote_extension_relative_path('/css/style.css/'));
84 }
85}
86
Top