Skip to content

Commit

Permalink
Enforce strict namespace rules
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonkelly committed Dec 11, 2023
1 parent 4bd3ada commit d568986
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG-WIP.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@
- `craft\services\Users::unshunMessageForUser()` now has a `void` return type, and throws an `InvalidElementException` in case of failure.
- `craft\services\Users::unsuspendUser()` now has a `void` return type, and throws an `InvalidElementException` in case of failure.
- `craft\services\Users::verifyEmailForUser()` now has a `void` return type, and throws an `InvalidElementException` in case of failure.
- `craft\web\View::setNamespace()` now throws an `InvalidArgumentException` for namespaces that don’t confirm to HTML `id` attribute rules (possibly followed by sets of properly-formatted strings wrapped in square brackets). ([#13943](https://github.com/craftcms/cms/issues/13943))
- Deprecated the `_elements/element.twig` control panel template. `elementChip()` or `elementCard()` should be used instead.
- Deprecated the `cp.elements.element` control panel template hook.
- Deprecated `craft\events\DefineElementInnerHtmlEvent`.
Expand Down
8 changes: 8 additions & 0 deletions src/web/View.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
use Twig\TemplateWrapper;
use yii\base\Arrayable;
use yii\base\Exception;
use yii\base\InvalidArgumentException;
use yii\base\Model;
use yii\base\NotSupportedException;
use yii\web\AssetBundle as YiiAssetBundle;
Expand Down Expand Up @@ -1438,6 +1439,13 @@ public function getNamespace(): ?string
*/
public function setNamespace(?string $namespace): void
{
if (
$namespace !== null &&
!preg_match('/^[A-Za-z][A-Za-z0-9\-_:.]*(\[[A-Za-z][A-Za-z0-9\-_:.]*])*$/', $namespace)
) {
throw new InvalidArgumentException(sprintf('Invalid namespace ("%s"). Namespaces must begin with a letter, and may be followed by letters, numbers, hyphens, underscores, colons, and periods (possibly followed by sets of correctly-formatted strings wrapped in square brackets).', $namespace));
}

$this->_namespace = $namespace;
}

Expand Down
46 changes: 46 additions & 0 deletions tests/unit/web/ViewTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use UnitTester;
use yii\base\Event;
use yii\base\Exception;
use yii\base\InvalidArgumentException;

/**
* Unit tests for the View class
Expand Down Expand Up @@ -307,6 +308,26 @@ public function testNamespaceInputId(string $expected, string $string, ?string $
self::assertSame($expected, $this->view->namespaceInputId($string, $namespace));
}

/**
* @dataProvider setNamespaceDataProvider
* @param string|null $namespace
* @param bool $isValid
*/
public function testSetNamespace(?string $namespace, bool $isValid): void
{
$oldNamespace = $this->view->getNamespace();

if (!$isValid) {
self::expectException(InvalidArgumentException::class);
}

$this->view->setNamespace($namespace);
self::assertEquals($namespace, $this->view->getNamespace());

$this->view->setNamespace($oldNamespace);
self::assertEquals($oldNamespace, $this->view->getNamespace());
}

/**
* @dataProvider getTemplateRootsDataProvider
* @param array $expected
Expand Down Expand Up @@ -602,6 +623,31 @@ public static function namespaceInputIdDataProvider(): array
];
}

/**
* @return array
*/
public static function setNamespaceDataProvider(): array
{
return [
[null, true],
['foo', true],
['foo[bar]', true],
['foo[bar][baz]', true],
['foo[bar0:baz.1-_]', true],
['', false],
['0', false],
['1', false],
['foo[]', false],
['foo[0]', false],
['foo[1]', false],
['foo[bar][]', false],
['foo[bar][0]', false],
['foo[bar][1]', false],
['foo[bar', false],
[' foo', false],
];
}

/**
* @return array
*/
Expand Down

0 comments on commit d568986

Please sign in to comment.