<?php

declare(strict_types=1);

namespace PhpOffice\PhpSpreadsheetTests\Writer\Html;

use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Html;
use PhpOffice\PhpSpreadsheetTests\Functional;

class XssVulnerabilityTest extends Functional\AbstractFunctional
{
    public static function providerXssRichText(): array
    {
        return [
            'basic text no problem' => ['Hello, I am safely viewing your site', 'Hello, I am safely viewing your site'],
            'link eliminated' => ["<a href='Visit Google'>Google is here</a>", "&lt;a href='Visit Google'&gt;Google is here&lt;/a&gt;"],
            'script tag' => ["Hello, I am trying to <script>alert('Hack');</script> your site", "Hello, I am trying to &lt;script&gt;alert('Hack');&lt;/script&gt; your site"],
            'script tag with quotes' => ['Hello, I am trying to <script>alert("Hack");</script> your site', 'Hello, I am trying to &lt;script&gt;alert(&quot;Hack&quot;);&lt;/script&gt; your site'],
            'javascript tag no hex' => ["<a href='javascript:alert(1)'>CLICK</a>", "&lt;a href='javascript:alert(1)'&gt;CLICK&lt;/a&gt;"],
            'javascript tag' => ["<a href='&#x2000;javascript:alert(1)'>CLICK</a>", "&lt;a href='&amp;#x2000;javascript:alert(1)'&gt;CLICK&lt;/a&gt;"],
            'with unicode' => ['<a href="\u0001java\u0003script:alert(1)">CLICK</a>', '&lt;a href=&quot;\u0001java\u0003script:alert(1)&quot;&gt;CLICK&lt;/a&gt;'],
            'inline css' => ['<li style="list-style-image: url(javascript:alert(0))">', '&lt;li style=&quot;list-style-image: url(javascript:alert(0))&quot;&gt;'],
            'char value chevron' => ["\x3cscript src=http://www.example.com/malicious-code.js\x3e\x3c/script\x3e", '&lt;script src=http://www.example.com/malicious-code.js&gt;&lt;/script&gt;'],
            'hexadecimal html' => ['<IMG SRC=&#106&#x61&#x76&#x61&#x73&#109&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>', '&lt;IMG SRC=&amp;#106&amp;#x61&amp;#x76&amp;#x61&amp;#x73&amp;#109&amp;#x72&amp;#x69&amp;#x70&amp;#x74&amp;#x3A&amp;#x61&amp;#x6C&amp;#x65&amp;#x72&amp;#x74&amp;#x28&amp;#x27&amp;#x58&amp;#x53&amp;#x53&amp;#x27&amp;#x29&gt;'],
            'iframe' => ['<iframe width="560" onclick="alert(\'xss\')" height="315" src="https://www.youtube.com/embed/whatever?rel=0&controls=0&showinfo=0" frameborder="0" allowfullscreen></iframe>', '&lt;iframe width=&quot;560&quot; onclick=&quot;alert(\'xss\')&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/whatever?rel=0&amp;controls=0&amp;showinfo=0&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;'],
        ];
    }

    #[\PHPUnit\Framework\Attributes\DataProvider('providerXssRichText')]
    public function testXssInComment(string $xssTextString, ?string $expected = null): void
    {
        $spreadsheet = new Spreadsheet();
        $startCell = '<td class="column0 style0 s">';
        $cellText = 'XSS Test';
        $endCell = $cellText . '</td>';

        $richText = new RichText();
        $richText->createText($xssTextString);

        $spreadsheet->getActiveSheet()->getCell('A1')
            ->setValue($cellText);

        $spreadsheet->getActiveSheet()
            ->getComment('A1')
            ->setText($richText);

        $writer = new Html($spreadsheet);
        $eol = $writer->getLineEnding();
        if ($expected === null) { // whole comment stripped away
            $expected = $startCell . $endCell;
        } else {
            $expected = $startCell . '<a class="comment-indicator"></a><div class="comment">' . $expected . '</div>' . $eol . $endCell;
        }

        $verify = $writer->generateHtmlAll();
        // Ensure that executable js has been stripped from the comments
        self::assertStringContainsString($expected, $verify);
        $spreadsheet->disconnectWorksheets();
    }

    public function testXssInFontName(): void
    {
        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();
        $sheet->getCell('A1')->setValue('here');
        $used = 'Calibri</style><script type="text/javascript">alert("hello");</script><style type="text/css">';
        $expected = "font-family:'Calibri&lt;/style&gt;&lt;script type=&quot;text/javascript&quot;&gt;alert(&quot;hello&quot;);&lt;/script&gt;&lt;style type=&quot;text/css&quot;&gt;'";
        $sheet->getStyle('A1')->getFont()->setName($used);

        $writer = new Html($spreadsheet);
        $verify = $writer->generateHtmlAll();
        // Ensure that executable js has been stripped
        self::assertStringNotContainsString($used, $verify);
        self::assertStringContainsString($expected, $verify);
        $spreadsheet->disconnectWorksheets();
    }
}
