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'; } }