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
6declare(strict_types=1);
7
8namespace App\Libraries\SessionVerification;
9
10use App\Exceptions\UserVerificationException;
11use App\Models\LoginAttempt;
12
13class Controller
14{
15 public static function initiate()
16 {
17 static $statusCode = 401;
18
19 app('route-section')->setError("{$statusCode}-verification");
20
21 $user = Helper::currentUserOrFail();
22 $email = $user->user_email;
23
24 $session = Helper::currentSession();
25 Helper::issue($session, $user, true);
26
27 if (is_api_request()) {
28 return response(null, $statusCode);
29 }
30
31 if (\Request::ajax()) {
32 return response([
33 'authentication' => 'verify',
34 'box' => view(
35 'users._verify_box',
36 compact('email')
37 )->render(),
38 ], $statusCode);
39 }
40
41 return ext_view('users.verify', compact('email'), null, $statusCode);
42 }
43
44 public static function reissue()
45 {
46 $session = Helper::currentSession();
47 if ($session->isVerified()) {
48 return response(null, 422);
49 }
50
51 Helper::issue($session, Helper::currentUserOrFail());
52
53 return response(['message' => osu_trans('user_verification.errors.reissued')], 200);
54 }
55
56 public static function verify()
57 {
58 $session = Helper::currentSession();
59 if ($session->isVerified()) {
60 return response(null, 204);
61 }
62
63 $key = strtr(get_string(\Request::input('verification_key')) ?? '', [' ' => '']);
64 $user = Helper::currentUserOrFail();
65 $state = State::fromSession($session);
66
67 try {
68 if ($state === null) {
69 throw new UserVerificationException('expired', true);
70 }
71 $state->verify($key);
72 } catch (UserVerificationException $e) {
73 Helper::logAttempt('input', 'fail', $e->reasonKey());
74
75 if ($e->reasonKey() === 'incorrect_key') {
76 LoginAttempt::logAttempt(\Request::getClientIp(), $user, 'verify-mismatch', $key);
77 }
78
79 if ($e->shouldReissue()) {
80 Helper::issue($session, $user);
81 }
82
83 return error_popup($e->getMessage());
84 }
85
86 Helper::logAttempt('input', 'success');
87 Helper::markVerified($session, $state);
88
89 return response(null, 204);
90 }
91
92 public static function verifyLink()
93 {
94 $state = State::fromVerifyLink(get_string(\Request::input('key')) ?? '');
95
96 if ($state === null) {
97 Helper::logAttempt('link', 'fail', 'incorrect_key');
98
99 return ext_view('accounts.verification_invalid', null, null, 404);
100 }
101
102 $session = $state->findSession();
103 // Otherwise pretend everything is okay if session is missing
104 if ($session !== null) {
105 Helper::logAttempt('link', 'success');
106 Helper::markVerified($session, $state);
107 }
108
109 return ext_view('accounts.verification_completed');
110 }
111}