Failed Conditions
Push — newinternal ( 216d62...410e59 )
by Simon
05:28 queued 13s
created

PageForgotPassword::main()   A

Complexity

Conditions 6
Paths 3

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 14
c 0
b 0
f 0
dl 0
loc 22
rs 9.2222
cc 6
nc 3
nop 0
1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 *                                                                            *
5
 * All code in this file is released into the public domain by the ACC        *
6
 * Development Team. Please see team.json for a list of contributors.         *
7
 ******************************************************************************/
8
9
namespace Waca\Pages\UserAuth;
10
11
use Waca\DataObjects\User;
12
use Waca\Exceptions\ApplicationLogicException;
13
use Waca\PdoDatabase;
14
use Waca\Security\CredentialProviders\PasswordCredentialProvider;
15
use Waca\SessionAlert;
16
use Waca\Tasks\InternalPageBase;
17
use Waca\WebRequest;
18
19
class PageForgotPassword extends InternalPageBase
20
{
21
    /**
22
     * Main function for this page, when no specific actions are called.
23
     *
24
     * This is the forgotten password reset form
25
     * @category Security-Critical
26
     */
27
    protected function main()
28
    {
29
        if (WebRequest::wasPosted()) {
30
            $this->validateCSRFToken();
31
            $username = WebRequest::postString('username');
32
            $email = WebRequest::postEmail('email');
33
            $database = $this->getDatabase();
34
35
            if ($username === null || trim($username) === "" || $email === null || trim($email) === "") {
36
                throw new ApplicationLogicException("Both username and email address must be specified!");
37
            }
38
39
            $user = User::getByUsername($username, $database);
40
            $this->sendResetMail($user, $email);
41
42
            SessionAlert::success('<strong>Your password reset request has been completed.</strong> Please check your e-mail.');
43
44
            $this->redirect('login');
45
        }
46
        else {
47
            $this->assignCSRFToken();
48
            $this->setTemplate('forgot-password/forgotpw.tpl');
49
        }
50
    }
51
52
    /**
53
     * Sends a reset email if the user is authenticated
54
     *
55
     * @param User|boolean $user  The user located from the database, or false. Doesn't really matter, since we do the
56
     *                            check anyway within this method and silently skip if we don't have a user.
57
     * @param string       $email The provided email address
58
     */
59
    private function sendResetMail($user, $email)
60
    {
61
        // If the user isn't found, or the email address is wrong, skip sending the details silently.
62
        if (!$user instanceof User) {
63
            return;
64
        }
65
66
        if (strtolower($user->getEmail()) === strtolower($email)) {
67
            $clientIp = $this->getXffTrustProvider()
68
                ->getTrustedClientIp(WebRequest::remoteAddress(), WebRequest::forwardedAddress());
69
70
            $this->assign("user", $user);
71
            $this->assign("hash", $user->getForgottenPasswordHash());
72
            $this->assign("remoteAddress", $clientIp);
73
74
            $emailContent = $this->fetchTemplate('forgot-password/reset-mail.tpl');
75
76
            $this->getEmailHelper()->sendMail($user->getEmail(), "", $emailContent);
77
        }
78
    }
79
80
    /**
81
     * Entry point for the reset action
82
     *
83
     * This is the reset password part of the form.
84
     * @category Security-Critical
85
     */
86
    protected function reset()
87
    {
88
        $si = WebRequest::getString('si');
89
        $id = WebRequest::getString('id');
90
91
        if ($si === null || trim($si) === "" || $id === null || trim($id) === "") {
92
            throw new ApplicationLogicException("Link not valid, please ensure it has copied correctly");
93
        }
94
95
        $database = $this->getDatabase();
96
        $user = $this->getResettingUser($id, $database, $si);
0 ignored issues
show
Bug introduced by
$id of type string is incompatible with the type integer expected by parameter $id of Waca\Pages\UserAuth\Page...ord::getResettingUser(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

96
        $user = $this->getResettingUser(/** @scrutinizer ignore-type */ $id, $database, $si);
Loading history...
97
98
        // Dual mode
99
        if (WebRequest::wasPosted()) {
100
            $this->validateCSRFToken();
101
            try {
102
                $this->doReset($user);
103
            }
104
            catch (ApplicationLogicException $ex) {
105
                SessionAlert::error($ex->getMessage());
106
                $this->redirect('forgotPassword', 'reset', array('si' => $si, 'id' => $id));
107
108
                return;
109
            }
110
        }
111
        else {
112
            $this->assignCSRFToken();
113
            $this->assign('user', $user);
114
            $this->setTemplate('forgot-password/forgotpwreset.tpl');
115
        }
116
    }
117
118
    /**
119
     * Gets the user resetting their password from the database, or throwing an exception if that is not possible.
120
     *
121
     * @param integer     $id       The ID of the user to retrieve
122
     * @param PdoDatabase $database The database object to use
123
     * @param string      $si       The reset hash provided
124
     *
125
     * @return User
126
     * @throws ApplicationLogicException
127
     */
128
    private function getResettingUser($id, $database, $si)
129
    {
130
        $user = User::getById($id, $database);
131
132
        if ($user === false || $user->getForgottenPasswordHash() !== $si || $user->isCommunityUser()) {
133
            throw new ApplicationLogicException("User not found");
134
        }
135
136
        return $user;
137
    }
138
139
    /**
140
     * Performs the setting of the new password
141
     *
142
     * @param User $user The user to set the password for
143
     *
144
     * @throws ApplicationLogicException
145
     */
146
    private function doReset(User $user)
147
    {
148
        $pw = WebRequest::postString('pw');
149
        $pw2 = WebRequest::postString('pw2');
150
151
        if ($pw !== $pw2) {
152
            throw new ApplicationLogicException('Passwords do not match!');
153
        }
154
155
        $passwordCredentialProvider = new PasswordCredentialProvider($user->getDatabase(), $this->getSiteConfiguration());
156
        $passwordCredentialProvider->setCredential($user, 1, $pw);
157
158
        SessionAlert::success('You may now log in!');
159
        $this->redirect('login');
160
    }
161
162
    protected function isProtectedPage()
163
    {
164
        return false;
165
    }
166
}
167