Commit 0f25cc2f authored by catch's avatar catch
Browse files

Issue #3414144 by codebymikey, smustgrave: Invalid twig token variables are...

Issue #3414144 by codebymikey, smustgrave: Invalid twig token variables are added on certain URLs and will crash the site if assertions are enabled

(cherry picked from commit b4f3d7fa)
parent 4a87e7e8
Loading
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -1700,21 +1700,23 @@ protected function getFieldTokenPlaceholder() {
   *     'foo' => array(
   *       'a' => 'value',
   *       'b' => 'value',
   *       'c.d' => 'invalid value',
   *       '&invalid' => 'invalid value',
   *     ),
   *     'bar' => array(
   *       'a' => 'value',
   *       'b' => array(
   *         'c' => value,
   *         'c' => 'value',
   *       ),
   *     ),
   *   );
   *
   * Would yield the following array of tokens:
   *   array(
   *     '%foo_a' => 'value'
   *     '%foo_b' => 'value'
   *     '%bar_a' => 'value'
   *     '%bar_b_c' => 'value'
   *     '{{ arguments.foo.a }}' => 'value',
   *     '{{ arguments.foo.b }}' => 'value',
   *     '{{ arguments.bar.a }}' => 'value',
   *     '{{ arguments.bar.b.c }}' => 'value',
   *   );
   *
   * @param $array
@@ -1729,6 +1731,10 @@ protected function getTokenValuesRecursive(array $array, array $parent_keys = []
    $tokens = [];

    foreach ($array as $param => $val) {
      if (!is_numeric($param) && preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $param) === 0) {
        // Skip as the parameter is not a valid Twig variable name.
        continue;
      }
      if (is_array($val)) {
        // Copy parent_keys array, so we don't affect other elements of this
        // iteration.
+100 −0
Original line number Diff line number Diff line
@@ -716,6 +716,106 @@ public function testGetRenderTokensWithArguments() {
    $this->assertEquals($expected, $field->getRenderTokens([]));
  }

  /**
   * @dataProvider providerTestGetRenderTokensWithQuery
   * @covers ::getRenderTokens
   * @covers ::getTokenValuesRecursive
   */
  public function testGetRenderTokensWithQuery(array $query_params, array $expected): void {
    $request = new Request($query_params);
    $this->executable->expects($this->any())
      ->method('getRequest')
      ->willReturn($request);

    $field = $this->setupTestField(['id' => 'id']);
    $field->last_render = 'last rendered output';
    $this->display->expects($this->any())
      ->method('getHandlers')
      ->willReturnMap([
        ['argument', []],
        ['field', ['id' => $field]],
      ]);

    $this->assertEquals($expected, $field->getRenderTokens([]));
  }

  /**
   * Data provider for ::testGetRenderTokensWithQuery().
   *
   * @return array
   *   Test data.
   */
  public function providerTestGetRenderTokensWithQuery(): array {
    $data = [];
    // No query parameters.
    $data[] = [
      [],
      [
        '{{ id }}' => 'last rendered output',
      ],
    ];
    // Invalid query parameters.
    $data[] = [
      [
        '&invalid' => [
          'a' => 1,
          'b' => [1, 2],
          1 => 2,
        ],
        'invalid.entry' => 'ignore me',
      ],
      [
        '{{ id }}' => 'last rendered output',
      ],
    ];
    // Process only valid query parameters.
    $data[] = [
      [
        'foo' => [
          'a' => 'value',
          'b' => 'value',
          'c.d' => 'invalid argument',
          '&invalid' => 'invalid argument',
        ],
        'bar' => [
          'a' => 'value',
          'b' => [
            'c' => 'value',
          ],
        ],
      ],
      [
        '{{ id }}' => 'last rendered output',
        '{{ arguments.foo.a }}' => 'value',
        '{{ arguments.foo.b }}' => 'value',
        '{{ arguments.bar.a }}' => 'value',
        '{{ arguments.bar.b.c }}' => 'value',
      ],
    ];
    // Supports numeric keys.
    $data[] = [
      [
        'multiple' => [
          1,
          2,
          3,
        ],
        1 => '',
        3 => '& encoded_value',
      ],
      [
        '{{ id }}' => 'last rendered output',
        '{{ arguments.multiple.0 }}' => '1',
        '{{ arguments.multiple.1 }}' => '2',
        '{{ arguments.multiple.2 }}' => '3',
        '{{ arguments.1 }}' => '',
        '{{ arguments.3 }}' => '& encoded_value',
      ],
    ];

    return $data;
  }

  /**
   * Ensures proper token replacement when generating CSS classes.
   *