105 lines
3.7 KiB
PHP
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';
|
|
}
|
|
}
|