You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pixelfed/app/Support/CursorToken.php

64 lines
1.6 KiB
PHP

<?php
namespace App\Support;
class CursorToken
{
public static function encode(?string $laravelCursor, string $ctx, int $hops, int $ttlSeconds = 300): ?string
{
if (! $laravelCursor) {
return null;
}
$payload = [
'c' => $laravelCursor,
'h' => $hops,
'e' => time() + $ttlSeconds,
'x' => $ctx,
];
$json = json_encode($payload, JSON_UNESCAPED_SLASHES);
$b64 = rtrim(strtr(base64_encode($json), '+/', '-_'), '=');
$sig = hash_hmac('sha256', $b64, config('app.key'));
return $b64.'.'.$sig;
}
public static function decode(string $token, string $ctx): array
{
[$b64, $sig] = array_pad(explode('.', $token, 2), 2, null);
if (! $b64 || ! $sig) {
abort(400, 'Invalid cursor.');
}
$expected = hash_hmac('sha256', $b64, config('app.key'));
if (! hash_equals($expected, $sig)) {
abort(400, 'Invalid cursor.');
}
$json = base64_decode(strtr($b64, '-_', '+/'), true);
if ($json === false) {
abort(400, 'Invalid cursor.');
}
$payload = json_decode($json, true);
if (! is_array($payload)) {
abort(400, 'Invalid cursor.');
}
if (($payload['x'] ?? null) !== $ctx) {
abort(400, 'Cursor does not match this query.');
}
if (($payload['e'] ?? 0) < time()) {
abort(400, 'Cursor expired.');
}
return [
'cursor' => (string) ($payload['c'] ?? ''),
'hops' => (int) ($payload['h'] ?? 0),
];
}
}