1<?php
2
3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0.
4// See the LICENCE file in the repository root for full licence text.
5
6namespace App\Http\Middleware;
7
8use App\Libraries\SessionVerification;
9use App\Models\Country;
10use App\Models\UserCountryHistory;
11use Carbon\Carbon;
12use Closure;
13use Illuminate\Contracts\Auth\Guard;
14
15class UpdateUserInfo
16{
17 protected $auth;
18
19 public function __construct(Guard $auth)
20 {
21 $this->auth = $auth;
22 }
23
24 public function handle($request, Closure $next)
25 {
26 $user = $this->auth->user();
27
28 if ($user !== null) {
29 $token = $user->token();
30 $shouldUpdate = $token === null || $token->client->password_client;
31
32 if ($shouldUpdate) {
33 $isInactive = $user->isInactive();
34 if ($isInactive) {
35 $isVerified = SessionVerification\Helper::currentSession()->isVerified();
36 }
37
38 if (!$isInactive || $isVerified) {
39 $recordedLastVisit = $user->getRawAttribute('user_lastvisit');
40 $currentLastVisit = time();
41
42 if ($currentLastVisit - $recordedLastVisit > 300) {
43 $user->update([
44 'user_lastvisit' => $currentLastVisit,
45 ], ['skipValidations' => true]);
46
47 if ($token !== null) {
48 UserCountryHistory::upsert([
49 'country_acronym' => request_country($request) ?? Country::UNKNOWN,
50 'user_id' => $user->getKey(),
51 'year_month' => format_month_column(new \DateTime()),
52 ], [
53 'country_acronym',
54 'user_id',
55 'year_month',
56 ], [
57 'count' => db_unsigned_increment('count', 1),
58 ]);
59 }
60 }
61 }
62
63 if ($token === null) {
64 $this->recordSession($request);
65 }
66 }
67 }
68
69 return $next($request);
70 }
71
72 private function recordSession($request)
73 {
74 // Add metadata to session to help user recognize this login location
75 $countryCode = request_country($request);
76 $country = $countryCode === null ? null : app('countries')->byCode($countryCode);
77 $request->session()->put('meta', [
78 'agent' => $request->header('User-Agent'),
79 'country' => [
80 'code' => $country?->acronym ?? Country::UNKNOWN,
81 'name' => presence($country?->name) ?? 'Unknown',
82 ],
83 'ip' => $request->ip(),
84 'last_visit' => Carbon::now(),
85 ]);
86 }
87}