51 lines
2.0 KiB
PHP
51 lines
2.0 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\GameAccount;
|
|
use Carbon\CarbonImmutable;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class LauncherGameTicketService
|
|
{
|
|
private const string ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
|
|
public function __construct(private readonly VMangosSrpService $srp) {}
|
|
|
|
/** @return array{account: string, ticket: string, expires_at: string} */
|
|
public function issue(GameAccount $account, string $launcherSessionToken, int $clientBuild): array
|
|
{
|
|
$username = $this->srp->normalizeUsername((string) $account->username);
|
|
if (preg_match('/^[A-Z0-9]{3,16}$/D', $username) !== 1) {
|
|
throw new \RuntimeException('Account name is incompatible with the 1.12.1 client.');
|
|
}
|
|
|
|
$ticket = '';
|
|
for ($i = 0; $i < 16; $i++) {
|
|
$ticket .= self::ALPHABET[random_int(0, strlen(self::ALPHABET) - 1)];
|
|
}
|
|
|
|
[$saltHex, $verifierHex] = $this->srp->makeRegistrationData($username, $ticket);
|
|
$now = CarbonImmutable::now('UTC');
|
|
$expires = $now->addSeconds(max(5, min(60, (int) config('moonwell.launcher.game_ticket_ttl'))));
|
|
|
|
DB::connection(config('moonwell.auth_connection'))->table('launcher_ticket')->upsert([[
|
|
'account_id' => (int) $account->id,
|
|
'generation_id' => random_bytes(16),
|
|
'srp_salt' => hex2bin($saltHex),
|
|
'srp_verifier' => hex2bin(str_pad($verifierHex, 64, '0', STR_PAD_LEFT)),
|
|
'client_build' => $clientBuild,
|
|
'launcher_session_hash' => hash('sha256', $launcherSessionToken, true),
|
|
'issued_at' => $now->format('Y-m-d H:i:s.u'),
|
|
'expires_at' => $expires->format('Y-m-d H:i:s.u'),
|
|
'claim_nonce' => null,
|
|
]], ['account_id'], ['generation_id', 'srp_salt', 'srp_verifier', 'client_build', 'launcher_session_hash', 'issued_at', 'expires_at', 'claim_nonce']);
|
|
|
|
return [
|
|
'account' => $username,
|
|
'ticket' => $ticket,
|
|
'expires_at' => $expires->format('Y-m-d\TH:i:s\Z'),
|
|
];
|
|
}
|
|
}
|