<?php

declare(strict_types=1);

namespace Sethrey\SysvoteWebsite;

/**
 * Creates and verifies signed, time-limited download tokens.
 *
 * A token is only ever issued after a Stripe Checkout Session has been
 * confirmed as paid. It encodes the session id + an expiry timestamp,
 * HMAC-signed with DOWNLOAD_SECRET so it cannot be forged or tampered
 * with, and requires no database.
 */
class DownloadToken
{
    public static function issue(string $sessionId, string $secret, int $ttlSeconds = 86400): string
    {
        $expires = time() + $ttlSeconds;
        $payload = $sessionId . '|' . $expires;
        $signature = hash_hmac('sha256', $payload, $secret);

        return rtrim(strtr(base64_encode($payload . '|' . $signature), '+/', '-_'), '=');
    }

    /**
     * @return string|null The Stripe Checkout Session id if the token is valid and not expired, null otherwise.
     */
    public static function verify(string $token, string $secret): ?string
    {
        $padded = strtr($token, '-_', '+/');
        $padded .= str_repeat('=', (4 - strlen($padded) % 4) % 4);
        $decoded = base64_decode($padded, true);

        if ($decoded === false) {
            return null;
        }

        $parts = explode('|', $decoded);
        if (count($parts) !== 3) {
            return null;
        }

        [$sessionId, $expires, $signature] = $parts;
        $payload = $sessionId . '|' . $expires;
        $expectedSignature = hash_hmac('sha256', $payload, $secret);

        if (!hash_equals($expectedSignature, $signature)) {
            return null;
        }

        if ((int) $expires < time()) {
            return null;
        }

        return $sessionId;
    }
}
