<?php
// CsrfTokenTest.php
// Created: 2021-06-11
// Updated: 2024-10-02

declare(strict_types=1);

use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\CoversClass;
use Index\CsrfToken;

#[CoversClass(CsrfToken::class)]
final class CsrfTokenTest extends TestCase {
    private const SECRET_1 = 'oCtBmR7XS1dLOnGVoVi0wXwTLk7Ursn4';
    private const SECRET_2 = 'v6H37MPa8NHmxVvL4AzNSxrWLVkiTfPHouyTto1LXOfOyoqSU7EaSorjdM4gXlq3';

    private const TIMESTAMP_1 = 1689111761;
    private const TIMESTAMP_2 = 1689025361;

    private const P3M = 3 * 60;
    private const P5M = 5 * 60;
    private const P15M = 15 * 60;
    private const P30M = 30 * 60;
    private const P4M59S = (4 * 60) + 59;
    private const P5M30S = (5 * 60) + 30;
    private const P29M59S = (29 * 60) + 59;

    public function testCsrfToken(): void {
        $csrfp1 = new CsrfToken(self::SECRET_1, '8.8.8.8!12345');
        $csrfp2 = new CsrfToken(self::SECRET_2, '127.0.0.1');

        $token1 = $csrfp1->createToken(self::TIMESTAMP_1);
        $token2 = $csrfp2->createToken(self::TIMESTAMP_1);
        $token3 = $csrfp1->createToken(self::TIMESTAMP_2);
        $token4 = $csrfp2->createToken(self::TIMESTAMP_2);

        $this->assertNotEquals($token1, $token2);
        $this->assertNotEquals($token2, $token3);
        $this->assertNotEquals($token3, $token4);
        $this->assertNotEquals($token4, $token1);

        $this->assertTrue($csrfp1->verifyToken($token1, -1, self::TIMESTAMP_1 + self::P15M));
        $this->assertTrue($csrfp2->verifyToken($token2, -1, self::TIMESTAMP_1 + self::P29M59S));
        $this->assertTrue($csrfp1->verifyToken($token3, -1, self::TIMESTAMP_2 + self::P15M));
        $this->assertTrue($csrfp2->verifyToken($token4, -1, self::TIMESTAMP_2 + self::P29M59S));

        $this->assertFalse($csrfp2->verifyToken($token1, -1, self::TIMESTAMP_1 + self::P15M));
        $this->assertFalse($csrfp1->verifyToken($token2, -1, self::TIMESTAMP_1 + self::P29M59S));
        $this->assertFalse($csrfp2->verifyToken($token3, -1, self::TIMESTAMP_2 + self::P15M));
        $this->assertFalse($csrfp1->verifyToken($token4, -1, self::TIMESTAMP_2 + self::P29M59S));

        $this->assertFalse($csrfp1->verifyToken($token1, -1, self::TIMESTAMP_1 + self::P30M));
        $this->assertFalse($csrfp2->verifyToken($token2, -1, self::TIMESTAMP_1 + self::P30M));
        $this->assertFalse($csrfp1->verifyToken($token3, -1, self::TIMESTAMP_2 + self::P30M));
        $this->assertFalse($csrfp2->verifyToken($token4, -1, self::TIMESTAMP_2 + self::P30M));

        $this->assertTrue($csrfp1->verifyToken($token1, self::P5M, self::TIMESTAMP_1 + self::P3M));
        $this->assertTrue($csrfp2->verifyToken($token2, self::P5M, self::TIMESTAMP_1 + self::P4M59S));
        $this->assertTrue($csrfp1->verifyToken($token3, self::P5M, self::TIMESTAMP_2 + self::P3M));
        $this->assertTrue($csrfp2->verifyToken($token4, self::P5M, self::TIMESTAMP_2 + self::P4M59S));

        $this->assertFalse($csrfp1->verifyToken($token1, self::P5M, self::TIMESTAMP_1 + self::P5M));
        $this->assertFalse($csrfp2->verifyToken($token2, self::P5M, self::TIMESTAMP_1 + self::P5M30S));
        $this->assertFalse($csrfp1->verifyToken($token3, self::P5M, self::TIMESTAMP_2 + self::P5M));
        $this->assertFalse($csrfp2->verifyToken($token4, self::P5M, self::TIMESTAMP_2 + self::P5M30S));
    }
}