$input */ public function create(array $input): User { if ((setting('disable_registration') ?: '0') == '1') { throw ValidationException::withMessages([ 'registration' => __('Registration is disabled.'), ]); } $ip = request()->ip() ?? '127.0.0.1'; if (! filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6)) { $ip = '127.0.0.1'; } $matchingIpCount = User::query() ->where('ip_current', '=', $ip) ->orWhere('ip_register', '=', $ip) ->count(); $maxAccountsPerIpSetting = setting('max_accounts_per_ip'); setting('hotel_home_room'); $maxAccountsPerIp = (int) (is_string($maxAccountsPerIpSetting) ? $maxAccountsPerIpSetting : '99'); if ($matchingIpCount >= $maxAccountsPerIp) { throw ValidationException::withMessages([ 'registration' => __('You have reached the max amount of allowed account'), ]); } $this->validate($input); $startCreditsSetting = setting('start_credits'); $hotelHomeRoomSetting = setting('hotel_home_room'); /** @var User $user */ $user = User::create([ 'username' => $input['username'], 'mail' => $input['mail'], 'password' => Hash::make(is_string($input['password']) ? $input['password'] : ''), 'account_created' => time(), 'last_login' => time(), 'motto' => setting('start_motto') ?: 'Welcome to the hotel!', 'look' => $input['look'] ?? setting('start_look') ?: 'hr-100-61.hd-180-1.ch-210-66.lg-270-110.sh-305-62', 'credits' => (int) (is_string($startCreditsSetting) ? $startCreditsSetting : '1000'), 'auth_ticket' => '', 'home_room' => (int) (is_string($hotelHomeRoomSetting) ? $hotelHomeRoomSetting : '0'), 'ip_register' => $ip, 'ip_current' => $ip, ]); $user->update([ 'referral_code' => sprintf('%d%s', $user->id, Str::random(8)), ]); if (setting('requires_beta_code')) { WebsiteBetaCode::where('code', '=', $input['beta_code'])->update([ 'user_id' => $user->id, ]); } // Referral if (isset($input['referral_code'])) { /** @var User|null $referralUser */ $referralUser = User::query() ->where('referral_code', '=', $input['referral_code']) ->first(); // Only process referral if users have different IPs if ($referralUser !== null && ($referralUser->ip_current != $user->ip_current && $referralUser->ip_register != $user->ip_register)) { $referralUser->referrals()->updateOrCreate(['user_id' => $referralUser->id], [ 'referrals_total' => $referralUser->referrals !== null ? $referralUser->referrals->referrals_total + 1 : 1, ]); $referralUser->userReferrals()->create([ 'referred_user_id' => $user->id, 'referred_user_ip' => $ip, ]); } } if (setting('enable_discord_webhook') === '1') { $discordRanksSetting = setting('discord_webhook_ranks', '[]'); $discordRanks = json_decode($discordRanksSetting, true) ?? []; $shouldNotify = false; if (! empty($discordRanks)) { $shouldNotify = in_array($user->rank, $discordRanks); } else { $minStaffRank = (int) setting('min_staff_rank', 3); $shouldNotify = $user->rank >= $minStaffRank; } if ($shouldNotify) { $this->sendDiscordWebhook($user->username, $ip, $user->mail); } } return $user; } /** * @param array $inputs * * @return array */ private function validate(array $inputs): array { $usernameRegexSetting = setting('username_regex'); $usernameRegex = is_string($usernameRegexSetting) ? $usernameRegexSetting : '/^[a-zA-Z0-9_.-]+$/'; $rules = [ 'username' => ['required', 'string', 'regex:' . $usernameRegex, 'max:25', Rule::unique('users'), new WebsiteWordfilterRule], 'mail' => ['required', 'string', 'email', 'max:255', Rule::unique('users')], 'password' => $this->passwordRules(), 'beta_code' => ['sometimes', 'string', new BetaCodeRule], 'terms' => ['required', 'accepted'], 'g-recaptcha-response' => ['sometimes', 'string', new GoogleRecaptchaRule], 'look' => ['sometimes', 'string'], ]; if (! empty($inputs['cf-turnstile-response'])) { $rules['cf-turnstile-response'] = [app(Turnstile::class)]; } $messages = [ 'g-recaptcha-response.required' => __('The Google recaptcha must be completed'), 'g-recaptcha-response.string' => __('The google recaptcha was submitted with an invalid type'), ]; return Validator::make($inputs, $rules, $messages)->validate(); } private function sendDiscordWebhook(string $username, string $ip, string $email): void { if (setting('discord_webhook_url') === '') { Log::error('Discord webhook url not provided', ['Please provide a discord webhook url before being able to send any webhook requests.']); return; } $discordWebhookUrl = setting('discord_webhook_url'); $hotelNameSetting = setting('hotel_name'); try { Http::asJson()->post(is_string($discordWebhookUrl) ? $discordWebhookUrl : '', [ 'username' => sprintf('%s Bot', is_string($hotelNameSetting) ? $hotelNameSetting : 'Hotel'), 'content' => "User: {$username} has just registered, with the IP: {$ip} and E-mail: {$email}", ]); } catch (\Exception $e) { Log::error('Failed to send Discord webhook notification', [ 'username' => $username, 'ip' => $ip, 'email' => $email, 'error' => $e->getMessage(), ]); } } }