Files
moonwell-web/app/Services/VMangosAccountRegistrar.php
2026-10-03 14:33:08 +04:00

105 lines
3.7 KiB
PHP

<?php
namespace App\Services;
use App\Exceptions\DuplicateGameAccountException;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
class VMangosAccountRegistrar
{
public function __construct(private readonly VMangosSrpService $srp, private readonly AzerothCoreSrpService $siteSrp)
{
}
/**
* @return array{id: int, username: string}
*/
public function register(string $username, string $email, string $password): array
{
$normalizedUsername = $this->srp->normalizeUsername($username);
$normalizedPassword = $this->srp->normalizePassword($password);
$normalizedEmail = $this->srp->normalizeEmail($email);
[$saltHex, $verifierHex] = $this->srp->makeRegistrationData($normalizedUsername, bin2hex(random_bytes(16)));
[$siteSaltHex, $siteVerifierHex] = $this->siteSrp->makeRegistrationData($normalizedUsername, $normalizedPassword);
$connection = DB::connection(config('moonwell.auth_connection'));
return $connection->transaction(function () use (
$connection,
$normalizedEmail,
$normalizedUsername,
$saltHex,
$verifierHex,
$siteSaltHex,
$siteVerifierHex,
): array {
if ($this->accountExists($connection, 'username', $normalizedUsername)) {
throw DuplicateGameAccountException::forUsername();
}
if (
config('moonwell.registration.enforce_unique_email')
&& $normalizedEmail !== ''
&& $this->accountExists($connection, 'email', $normalizedEmail)
) {
throw DuplicateGameAccountException::forEmail();
}
try {
$accountId = (int) $connection->table('account')->insertGetId([
'username' => $normalizedUsername,
's' => $saltHex,
'v' => $verifierHex,
'expansion' => 0,
'email' => $normalizedEmail,
'joindate' => now()->toDateTimeString(),
]);
} catch (QueryException $exception) {
if ($this->isDuplicateKeyException($exception)) {
throw DuplicateGameAccountException::forUsername();
}
throw $exception;
}
$connection->table('site_credentials')->insert([
'account_id' => $accountId,
'salt_hex' => $siteSaltHex,
'verifier_hex' => $siteVerifierHex,
'created_at' => now(),
'updated_at' => now(),
]);
foreach ($connection->table('realmlist')->pluck('id') as $realmId) {
$connection->table('realmcharacters')->insertOrIgnore([
'realmid' => (int) $realmId,
'acctid' => $accountId,
'numchars' => 0,
]);
}
$connection->table('account_access')->updateOrInsert(
['id' => $accountId, 'RealmID' => (int) config('moonwell.registration.realm_id')],
['gmlevel' => (int) config('moonwell.registration.gmlevel')],
);
return [
'id' => $accountId,
'username' => $normalizedUsername,
];
}, 3);
}
private function accountExists(ConnectionInterface $connection, string $column, string $value): bool
{
return $connection->table('account')->where($column, $value)->exists();
}
private function isDuplicateKeyException(QueryException $exception): bool
{
return (string) $exception->getCode() === '23000';
}
}