Passed
Push — newinternal-releasecandidate ( 40acd0...67549a )
by Simon
10:15
created
includes/Pages/PageXffDemo.php 2 patches
Indentation   +132 added lines, -132 removed lines patch added patch discarded remove patch
@@ -13,136 +13,136 @@
 block discarded – undo
13 13
 
14 14
 class PageXffDemo extends InternalPageBase
15 15
 {
16
-    use RequestData;
17
-
18
-    /**
19
-     * @inheritDoc
20
-     */
21
-    protected function main()
22
-    {
23
-        $this->setTemplate('xffdemo.tpl');
24
-
25
-        // requestHasForwardedIp == false
26
-        // requestProxyData
27
-        // requestRealIp == proxy
28
-        // requestForwardedIp == xff header
29
-        // forwardedOrigin  == top of the chain, assuming xff is trusted
30
-
31
-
32
-        $this->assign('demo2', [
33
-            [
34
-                'trust' => true,
35
-                'trustedlink' => true,
36
-                'ip' => '172.16.0.164',
37
-                'routable' => false,
38
-
39
-            ],[
40
-                'trust' => true,
41
-                'ip' => '198.51.100.123',
42
-                'routable' => true,
43
-                'rdns' => 'trustedproxy.example.com',
44
-
45
-            ],[
46
-                'trust' => true,
47
-                'ip' => '192.0.2.1',
48
-                'routable' => true,
49
-                'rdns' => 'client.users.example.org',
50
-                'location' => [
51
-                    'cityName' => 'San Francisco',
52
-                    'regionName' => 'California',
53
-                    'countryName' => 'United States'
54
-                ],
55
-                'showlinks' => true
56
-            ]
57
-        ]);
58
-
59
-        $this->assign('demo3', [
60
-            [
61
-                'trust' => true,
62
-                'trustedlink' => true,
63
-                'ip' => '172.16.0.164',
64
-                'routable' => false,
65
-
66
-            ],[
67
-                'trust' => false,
68
-                'ip' => '198.51.100.234',
69
-                'routable' => true,
70
-                'rdns' => 'sketchyproxy.example.com',
71
-                'showlinks' => true
72
-
73
-            ],[
74
-                'trust' => false,
75
-                'ip' => '192.0.2.1',
76
-                'routable' => true,
77
-                'rdns' => 'client.users.example.org',
78
-                'location' => [
79
-                    'cityName' => 'San Francisco',
80
-                    'regionName' => 'California',
81
-                    'countryName' => 'United States'
82
-                ],
83
-                'showlinks' => true
84
-            ]
85
-        ]);
86
-
87
-        $this->assign('demo4', [
88
-            [
89
-                'trust' => true,
90
-                'trustedlink' => true,
91
-                'ip' => '172.16.0.164',
92
-                'routable' => false,
93
-
94
-            ],[
95
-                'trust' => true,
96
-                'ip' => '198.51.100.123',
97
-                'routable' => true,
98
-                'rdns' => 'trustedproxy.example.com',
99
-            ],[
100
-                'trust' => false,
101
-                'ip' => '198.51.100.234',
102
-                'routable' => true,
103
-                'rdns' => 'sketchyproxy.example.com',
104
-                'showlinks' => true
105
-            ], [
106
-                'trust' => false,
107
-                'trustedlink' => true,
108
-                'ip' => '198.51.100.124',
109
-                'routable' => true,
110
-                'rdns' => 'trustedproxy2.example.com',
111
-                'showlinks' => true
112
-            ],[
113
-                'trust' => false,
114
-                'ip' => '192.0.2.1',
115
-                'routable' => true,
116
-                'rdns' => 'client.users.example.org',
117
-                'location' => [
118
-                    'cityName' => 'San Francisco',
119
-                    'regionName' => 'California',
120
-                    'countryName' => 'United States'
121
-                ],
122
-                'showlinks' => true
123
-            ]
124
-        ]);
125
-
126
-        $this->assign('demo1', [
127
-            [
128
-                'trust' => true,
129
-                'trustedlink' => true,
130
-                'ip' => '172.16.0.164',
131
-                'routable' => false,
132
-
133
-            ], [
134
-                'trust' => true,
135
-                'trustedlink' => true,
136
-                'ip' => '192.0.2.1',
137
-                'routable' => true,
138
-                'rdns' => 'client.users.example.org',
139
-                'location' => [
140
-                    'cityName' => 'San Francisco',
141
-                    'regionName' => 'California',
142
-                    'countryName' => 'United States'
143
-                ],
144
-                'showlinks' => true
145
-            ]
146
-        ]);
147
-    }
16
+	use RequestData;
17
+
18
+	/**
19
+	 * @inheritDoc
20
+	 */
21
+	protected function main()
22
+	{
23
+		$this->setTemplate('xffdemo.tpl');
24
+
25
+		// requestHasForwardedIp == false
26
+		// requestProxyData
27
+		// requestRealIp == proxy
28
+		// requestForwardedIp == xff header
29
+		// forwardedOrigin  == top of the chain, assuming xff is trusted
30
+
31
+
32
+		$this->assign('demo2', [
33
+			[
34
+				'trust' => true,
35
+				'trustedlink' => true,
36
+				'ip' => '172.16.0.164',
37
+				'routable' => false,
38
+
39
+			],[
40
+				'trust' => true,
41
+				'ip' => '198.51.100.123',
42
+				'routable' => true,
43
+				'rdns' => 'trustedproxy.example.com',
44
+
45
+			],[
46
+				'trust' => true,
47
+				'ip' => '192.0.2.1',
48
+				'routable' => true,
49
+				'rdns' => 'client.users.example.org',
50
+				'location' => [
51
+					'cityName' => 'San Francisco',
52
+					'regionName' => 'California',
53
+					'countryName' => 'United States'
54
+				],
55
+				'showlinks' => true
56
+			]
57
+		]);
58
+
59
+		$this->assign('demo3', [
60
+			[
61
+				'trust' => true,
62
+				'trustedlink' => true,
63
+				'ip' => '172.16.0.164',
64
+				'routable' => false,
65
+
66
+			],[
67
+				'trust' => false,
68
+				'ip' => '198.51.100.234',
69
+				'routable' => true,
70
+				'rdns' => 'sketchyproxy.example.com',
71
+				'showlinks' => true
72
+
73
+			],[
74
+				'trust' => false,
75
+				'ip' => '192.0.2.1',
76
+				'routable' => true,
77
+				'rdns' => 'client.users.example.org',
78
+				'location' => [
79
+					'cityName' => 'San Francisco',
80
+					'regionName' => 'California',
81
+					'countryName' => 'United States'
82
+				],
83
+				'showlinks' => true
84
+			]
85
+		]);
86
+
87
+		$this->assign('demo4', [
88
+			[
89
+				'trust' => true,
90
+				'trustedlink' => true,
91
+				'ip' => '172.16.0.164',
92
+				'routable' => false,
93
+
94
+			],[
95
+				'trust' => true,
96
+				'ip' => '198.51.100.123',
97
+				'routable' => true,
98
+				'rdns' => 'trustedproxy.example.com',
99
+			],[
100
+				'trust' => false,
101
+				'ip' => '198.51.100.234',
102
+				'routable' => true,
103
+				'rdns' => 'sketchyproxy.example.com',
104
+				'showlinks' => true
105
+			], [
106
+				'trust' => false,
107
+				'trustedlink' => true,
108
+				'ip' => '198.51.100.124',
109
+				'routable' => true,
110
+				'rdns' => 'trustedproxy2.example.com',
111
+				'showlinks' => true
112
+			],[
113
+				'trust' => false,
114
+				'ip' => '192.0.2.1',
115
+				'routable' => true,
116
+				'rdns' => 'client.users.example.org',
117
+				'location' => [
118
+					'cityName' => 'San Francisco',
119
+					'regionName' => 'California',
120
+					'countryName' => 'United States'
121
+				],
122
+				'showlinks' => true
123
+			]
124
+		]);
125
+
126
+		$this->assign('demo1', [
127
+			[
128
+				'trust' => true,
129
+				'trustedlink' => true,
130
+				'ip' => '172.16.0.164',
131
+				'routable' => false,
132
+
133
+			], [
134
+				'trust' => true,
135
+				'trustedlink' => true,
136
+				'ip' => '192.0.2.1',
137
+				'routable' => true,
138
+				'rdns' => 'client.users.example.org',
139
+				'location' => [
140
+					'cityName' => 'San Francisco',
141
+					'regionName' => 'California',
142
+					'countryName' => 'United States'
143
+				],
144
+				'showlinks' => true
145
+			]
146
+		]);
147
+	}
148 148
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -36,13 +36,13 @@  discard block
 block discarded – undo
36 36
                 'ip' => '172.16.0.164',
37 37
                 'routable' => false,
38 38
 
39
-            ],[
39
+            ], [
40 40
                 'trust' => true,
41 41
                 'ip' => '198.51.100.123',
42 42
                 'routable' => true,
43 43
                 'rdns' => 'trustedproxy.example.com',
44 44
 
45
-            ],[
45
+            ], [
46 46
                 'trust' => true,
47 47
                 'ip' => '192.0.2.1',
48 48
                 'routable' => true,
@@ -63,14 +63,14 @@  discard block
 block discarded – undo
63 63
                 'ip' => '172.16.0.164',
64 64
                 'routable' => false,
65 65
 
66
-            ],[
66
+            ], [
67 67
                 'trust' => false,
68 68
                 'ip' => '198.51.100.234',
69 69
                 'routable' => true,
70 70
                 'rdns' => 'sketchyproxy.example.com',
71 71
                 'showlinks' => true
72 72
 
73
-            ],[
73
+            ], [
74 74
                 'trust' => false,
75 75
                 'ip' => '192.0.2.1',
76 76
                 'routable' => true,
@@ -91,12 +91,12 @@  discard block
 block discarded – undo
91 91
                 'ip' => '172.16.0.164',
92 92
                 'routable' => false,
93 93
 
94
-            ],[
94
+            ], [
95 95
                 'trust' => true,
96 96
                 'ip' => '198.51.100.123',
97 97
                 'routable' => true,
98 98
                 'rdns' => 'trustedproxy.example.com',
99
-            ],[
99
+            ], [
100 100
                 'trust' => false,
101 101
                 'ip' => '198.51.100.234',
102 102
                 'routable' => true,
@@ -109,7 +109,7 @@  discard block
 block discarded – undo
109 109
                 'routable' => true,
110 110
                 'rdns' => 'trustedproxy2.example.com',
111 111
                 'showlinks' => true
112
-            ],[
112
+            ], [
113 113
                 'trust' => false,
114 114
                 'ip' => '192.0.2.1',
115 115
                 'routable' => true,
Please login to merge, or discard this patch.
includes/Pages/UserAuth/PageForgotPassword.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -152,7 +152,7 @@
 block discarded – undo
152 152
     {
153 153
         $user = User::getById($id, $database);
154 154
 
155
-        if ($user === false ||  $user->isCommunityUser()) {
155
+        if ($user === false || $user->isCommunityUser()) {
156 156
             throw new ApplicationLogicException("Password reset failed. Please try again.");
157 157
         }
158 158
 
Please login to merge, or discard this patch.
Indentation   +204 added lines, -204 removed lines patch added patch discarded remove patch
@@ -22,208 +22,208 @@
 block discarded – undo
22 22
 
23 23
 class PageForgotPassword extends InternalPageBase
24 24
 {
25
-    /**
26
-     * Main function for this page, when no specific actions are called.
27
-     *
28
-     * This is the forgotten password reset form
29
-     * @category Security-Critical
30
-     */
31
-    protected function main()
32
-    {
33
-        if (WebRequest::wasPosted()) {
34
-            $this->validateCSRFToken();
35
-            $username = WebRequest::postString('username');
36
-            $email = WebRequest::postEmail('email');
37
-            $database = $this->getDatabase();
38
-
39
-            if ($username === null || trim($username) === "" || $email === null || trim($email) === "") {
40
-                throw new ApplicationLogicException("Both username and email address must be specified!");
41
-            }
42
-
43
-            $user = User::getByUsername($username, $database);
44
-            $this->sendResetMail($user, $email);
45
-
46
-            SessionAlert::success('<strong>Your password reset request has been completed.</strong> If the details you have provided match our records, you should receive an email shortly.');
47
-
48
-            $this->redirect('login');
49
-        }
50
-        else {
51
-            $this->assignCSRFToken();
52
-            $this->setTemplate('forgot-password/forgotpw.tpl');
53
-        }
54
-    }
55
-
56
-    /**
57
-     * Sends a reset email if the user is authenticated
58
-     *
59
-     * @param User|boolean $user  The user located from the database, or false. Doesn't really matter, since we do the
60
-     *                            check anyway within this method and silently skip if we don't have a user.
61
-     * @param string       $email The provided email address
62
-     */
63
-    private function sendResetMail($user, $email)
64
-    {
65
-        // If the user isn't found, or the email address is wrong, skip sending the details silently.
66
-        if (!$user instanceof User) {
67
-            return;
68
-        }
69
-
70
-        if (strtolower($user->getEmail()) === strtolower($email)) {
71
-            $clientIp = $this->getXffTrustProvider()
72
-                ->getTrustedClientIp(WebRequest::remoteAddress(), WebRequest::forwardedAddress());
73
-
74
-            $this->cleanExistingTokens($user);
75
-
76
-            $hash = Base32::encodeUpper(openssl_random_pseudo_bytes(30));
77
-
78
-            $encryptionHelper = new EncryptionHelper($this->getSiteConfiguration());
79
-
80
-            $cred = new Credential();
81
-            $cred->setDatabase($this->getDatabase());
82
-            $cred->setFactor(-1);
83
-            $cred->setUserId($user->getId());
84
-            $cred->setType('reset');
85
-            $cred->setData($encryptionHelper->encryptData($hash));
86
-            $cred->setVersion(0);
87
-            $cred->setDisabled(0);
88
-            $cred->setTimeout(new DateTimeImmutable('+ 1 hour'));
89
-            $cred->setPriority(9);
90
-            $cred->save();
91
-
92
-            $this->assign("user", $user);
93
-            $this->assign("hash", $hash);
94
-            $this->assign("remoteAddress", $clientIp);
95
-
96
-            $emailContent = $this->fetchTemplate('forgot-password/reset-mail.tpl');
97
-
98
-            $this->getEmailHelper()->sendMail($user->getEmail(), "WP:ACC password reset", $emailContent);
99
-        }
100
-    }
101
-
102
-    /**
103
-     * Entry point for the reset action
104
-     *
105
-     * This is the reset password part of the form.
106
-     * @category Security-Critical
107
-     */
108
-    protected function reset()
109
-    {
110
-        $si = WebRequest::getString('si');
111
-        $id = WebRequest::getString('id');
112
-
113
-        if ($si === null || trim($si) === "" || $id === null || trim($id) === "") {
114
-            throw new ApplicationLogicException("Link not valid, please ensure it has copied correctly");
115
-        }
116
-
117
-        $database = $this->getDatabase();
118
-        $user = $this->getResettingUser($id, $database, $si);
119
-
120
-        // Dual mode
121
-        if (WebRequest::wasPosted()) {
122
-            $this->validateCSRFToken();
123
-            try {
124
-                $this->doReset($user);
125
-                $this->cleanExistingTokens($user);
126
-            }
127
-            catch (ApplicationLogicException $ex) {
128
-                SessionAlert::error($ex->getMessage());
129
-                $this->redirect('forgotPassword', 'reset', array('si' => $si, 'id' => $id));
130
-
131
-                return;
132
-            }
133
-        }
134
-        else {
135
-            $this->assignCSRFToken();
136
-            $this->assign('user', $user);
137
-            $this->setTemplate('forgot-password/forgotpwreset.tpl');
138
-        }
139
-    }
140
-
141
-    /**
142
-     * Gets the user resetting their password from the database, or throwing an exception if that is not possible.
143
-     *
144
-     * @param integer     $id       The ID of the user to retrieve
145
-     * @param PdoDatabase $database The database object to use
146
-     * @param string      $si       The reset hash provided
147
-     *
148
-     * @return User
149
-     * @throws ApplicationLogicException
150
-     */
151
-    private function getResettingUser($id, $database, $si)
152
-    {
153
-        $user = User::getById($id, $database);
154
-
155
-        if ($user === false ||  $user->isCommunityUser()) {
156
-            throw new ApplicationLogicException("Password reset failed. Please try again.");
157
-        }
158
-
159
-        $statement = $database->prepare("SELECT * FROM credential WHERE type = 'reset' AND user = :user;");
160
-        $statement->execute([':user' => $user->getId()]);
161
-
162
-        /** @var Credential $credential */
163
-        $credential = $statement->fetchObject(Credential::class);
164
-
165
-        $statement->closeCursor();
166
-
167
-        if ($credential === false) {
168
-            throw new ApplicationLogicException("Password reset failed. Please try again.");
169
-        }
170
-
171
-        $credential->setDatabase($database);
172
-
173
-        $encryptionHelper = new EncryptionHelper($this->getSiteConfiguration());
174
-        if ($encryptionHelper->decryptData($credential->getData()) != $si) {
175
-            throw new ApplicationLogicException("Password reset failed. Please try again.");
176
-        }
177
-
178
-        if ($credential->getTimeout() < new DateTimeImmutable()) {
179
-            $credential->delete();
180
-            throw new ApplicationLogicException("Password reset token expired. Please try again.");
181
-        }
182
-
183
-        return $user;
184
-    }
185
-
186
-    /**
187
-     * Performs the setting of the new password
188
-     *
189
-     * @param User $user The user to set the password for
190
-     *
191
-     * @throws ApplicationLogicException
192
-     */
193
-    private function doReset(User $user)
194
-    {
195
-        $pw = WebRequest::postString('pw');
196
-        $pw2 = WebRequest::postString('pw2');
197
-
198
-        if ($pw !== $pw2) {
199
-            throw new ApplicationLogicException('Passwords do not match!');
200
-        }
201
-
202
-        $passwordCredentialProvider = new PasswordCredentialProvider($user->getDatabase(), $this->getSiteConfiguration());
203
-        $passwordCredentialProvider->setCredential($user, 1, $pw);
204
-
205
-        SessionAlert::success('You may now log in!');
206
-        $this->redirect('login');
207
-    }
208
-
209
-    protected function isProtectedPage()
210
-    {
211
-        return false;
212
-    }
213
-
214
-    /**
215
-     * @param $user
216
-     */
217
-    private function cleanExistingTokens($user): void
218
-    {
219
-        // clean out existing reset tokens
220
-        $statement = $this->getDatabase()->prepare("SELECT * FROM credential WHERE type = 'reset' AND user = :user;");
221
-        $statement->execute([':user' => $user->getId()]);
222
-        $existing = $statement->fetchAll(PdoDatabase::FETCH_CLASS, Credential::class);
223
-
224
-        foreach ($existing as $c) {
225
-            $c->setDatabase($this->getDatabase());
226
-            $c->delete();
227
-        }
228
-    }
25
+	/**
26
+	 * Main function for this page, when no specific actions are called.
27
+	 *
28
+	 * This is the forgotten password reset form
29
+	 * @category Security-Critical
30
+	 */
31
+	protected function main()
32
+	{
33
+		if (WebRequest::wasPosted()) {
34
+			$this->validateCSRFToken();
35
+			$username = WebRequest::postString('username');
36
+			$email = WebRequest::postEmail('email');
37
+			$database = $this->getDatabase();
38
+
39
+			if ($username === null || trim($username) === "" || $email === null || trim($email) === "") {
40
+				throw new ApplicationLogicException("Both username and email address must be specified!");
41
+			}
42
+
43
+			$user = User::getByUsername($username, $database);
44
+			$this->sendResetMail($user, $email);
45
+
46
+			SessionAlert::success('<strong>Your password reset request has been completed.</strong> If the details you have provided match our records, you should receive an email shortly.');
47
+
48
+			$this->redirect('login');
49
+		}
50
+		else {
51
+			$this->assignCSRFToken();
52
+			$this->setTemplate('forgot-password/forgotpw.tpl');
53
+		}
54
+	}
55
+
56
+	/**
57
+	 * Sends a reset email if the user is authenticated
58
+	 *
59
+	 * @param User|boolean $user  The user located from the database, or false. Doesn't really matter, since we do the
60
+	 *                            check anyway within this method and silently skip if we don't have a user.
61
+	 * @param string       $email The provided email address
62
+	 */
63
+	private function sendResetMail($user, $email)
64
+	{
65
+		// If the user isn't found, or the email address is wrong, skip sending the details silently.
66
+		if (!$user instanceof User) {
67
+			return;
68
+		}
69
+
70
+		if (strtolower($user->getEmail()) === strtolower($email)) {
71
+			$clientIp = $this->getXffTrustProvider()
72
+				->getTrustedClientIp(WebRequest::remoteAddress(), WebRequest::forwardedAddress());
73
+
74
+			$this->cleanExistingTokens($user);
75
+
76
+			$hash = Base32::encodeUpper(openssl_random_pseudo_bytes(30));
77
+
78
+			$encryptionHelper = new EncryptionHelper($this->getSiteConfiguration());
79
+
80
+			$cred = new Credential();
81
+			$cred->setDatabase($this->getDatabase());
82
+			$cred->setFactor(-1);
83
+			$cred->setUserId($user->getId());
84
+			$cred->setType('reset');
85
+			$cred->setData($encryptionHelper->encryptData($hash));
86
+			$cred->setVersion(0);
87
+			$cred->setDisabled(0);
88
+			$cred->setTimeout(new DateTimeImmutable('+ 1 hour'));
89
+			$cred->setPriority(9);
90
+			$cred->save();
91
+
92
+			$this->assign("user", $user);
93
+			$this->assign("hash", $hash);
94
+			$this->assign("remoteAddress", $clientIp);
95
+
96
+			$emailContent = $this->fetchTemplate('forgot-password/reset-mail.tpl');
97
+
98
+			$this->getEmailHelper()->sendMail($user->getEmail(), "WP:ACC password reset", $emailContent);
99
+		}
100
+	}
101
+
102
+	/**
103
+	 * Entry point for the reset action
104
+	 *
105
+	 * This is the reset password part of the form.
106
+	 * @category Security-Critical
107
+	 */
108
+	protected function reset()
109
+	{
110
+		$si = WebRequest::getString('si');
111
+		$id = WebRequest::getString('id');
112
+
113
+		if ($si === null || trim($si) === "" || $id === null || trim($id) === "") {
114
+			throw new ApplicationLogicException("Link not valid, please ensure it has copied correctly");
115
+		}
116
+
117
+		$database = $this->getDatabase();
118
+		$user = $this->getResettingUser($id, $database, $si);
119
+
120
+		// Dual mode
121
+		if (WebRequest::wasPosted()) {
122
+			$this->validateCSRFToken();
123
+			try {
124
+				$this->doReset($user);
125
+				$this->cleanExistingTokens($user);
126
+			}
127
+			catch (ApplicationLogicException $ex) {
128
+				SessionAlert::error($ex->getMessage());
129
+				$this->redirect('forgotPassword', 'reset', array('si' => $si, 'id' => $id));
130
+
131
+				return;
132
+			}
133
+		}
134
+		else {
135
+			$this->assignCSRFToken();
136
+			$this->assign('user', $user);
137
+			$this->setTemplate('forgot-password/forgotpwreset.tpl');
138
+		}
139
+	}
140
+
141
+	/**
142
+	 * Gets the user resetting their password from the database, or throwing an exception if that is not possible.
143
+	 *
144
+	 * @param integer     $id       The ID of the user to retrieve
145
+	 * @param PdoDatabase $database The database object to use
146
+	 * @param string      $si       The reset hash provided
147
+	 *
148
+	 * @return User
149
+	 * @throws ApplicationLogicException
150
+	 */
151
+	private function getResettingUser($id, $database, $si)
152
+	{
153
+		$user = User::getById($id, $database);
154
+
155
+		if ($user === false ||  $user->isCommunityUser()) {
156
+			throw new ApplicationLogicException("Password reset failed. Please try again.");
157
+		}
158
+
159
+		$statement = $database->prepare("SELECT * FROM credential WHERE type = 'reset' AND user = :user;");
160
+		$statement->execute([':user' => $user->getId()]);
161
+
162
+		/** @var Credential $credential */
163
+		$credential = $statement->fetchObject(Credential::class);
164
+
165
+		$statement->closeCursor();
166
+
167
+		if ($credential === false) {
168
+			throw new ApplicationLogicException("Password reset failed. Please try again.");
169
+		}
170
+
171
+		$credential->setDatabase($database);
172
+
173
+		$encryptionHelper = new EncryptionHelper($this->getSiteConfiguration());
174
+		if ($encryptionHelper->decryptData($credential->getData()) != $si) {
175
+			throw new ApplicationLogicException("Password reset failed. Please try again.");
176
+		}
177
+
178
+		if ($credential->getTimeout() < new DateTimeImmutable()) {
179
+			$credential->delete();
180
+			throw new ApplicationLogicException("Password reset token expired. Please try again.");
181
+		}
182
+
183
+		return $user;
184
+	}
185
+
186
+	/**
187
+	 * Performs the setting of the new password
188
+	 *
189
+	 * @param User $user The user to set the password for
190
+	 *
191
+	 * @throws ApplicationLogicException
192
+	 */
193
+	private function doReset(User $user)
194
+	{
195
+		$pw = WebRequest::postString('pw');
196
+		$pw2 = WebRequest::postString('pw2');
197
+
198
+		if ($pw !== $pw2) {
199
+			throw new ApplicationLogicException('Passwords do not match!');
200
+		}
201
+
202
+		$passwordCredentialProvider = new PasswordCredentialProvider($user->getDatabase(), $this->getSiteConfiguration());
203
+		$passwordCredentialProvider->setCredential($user, 1, $pw);
204
+
205
+		SessionAlert::success('You may now log in!');
206
+		$this->redirect('login');
207
+	}
208
+
209
+	protected function isProtectedPage()
210
+	{
211
+		return false;
212
+	}
213
+
214
+	/**
215
+	 * @param $user
216
+	 */
217
+	private function cleanExistingTokens($user): void
218
+	{
219
+		// clean out existing reset tokens
220
+		$statement = $this->getDatabase()->prepare("SELECT * FROM credential WHERE type = 'reset' AND user = :user;");
221
+		$statement->execute([':user' => $user->getId()]);
222
+		$existing = $statement->fetchAll(PdoDatabase::FETCH_CLASS, Credential::class);
223
+
224
+		foreach ($existing as $c) {
225
+			$c->setDatabase($this->getDatabase());
226
+			$c->delete();
227
+		}
228
+	}
229 229
 }
Please login to merge, or discard this patch.
includes/Pages/PageLog.php 2 patches
Indentation   +58 added lines, -58 removed lines patch added patch discarded remove patch
@@ -18,62 +18,62 @@
 block discarded – undo
18 18
 
19 19
 class PageLog extends PagedInternalPageBase
20 20
 {
21
-    /**
22
-     * Main function for this page, when no specific actions are called.
23
-     */
24
-    protected function main()
25
-    {
26
-        $this->setHtmlTitle('Logs');
27
-
28
-        $filterUser = WebRequest::getString('filterUser');
29
-        $filterAction = WebRequest::getString('filterAction');
30
-        $filterObjectType = WebRequest::getString('filterObjectType');
31
-        $filterObjectId = WebRequest::getInt('filterObjectId');
32
-
33
-        $database = $this->getDatabase();
34
-
35
-        if (!array_key_exists($filterObjectType, LogHelper::getObjectTypes())) {
36
-            $filterObjectType = null;
37
-        }
38
-
39
-        $this->addJs("/api.php?action=users&all=true&targetVariable=typeaheaddata");
40
-
41
-        $logSearch = LogSearchHelper::get($database);
42
-
43
-        if ($filterUser !== null) {
44
-            $userObj = User::getByUsername($filterUser, $database);
45
-            if ($userObj !== false) {
46
-                $logSearch->byUser($userObj->getId());
47
-            } else {
48
-                $logSearch->byUser(-1);
49
-            }
50
-        }
51
-        if ($filterAction !== null) {
52
-            $logSearch->byAction($filterAction);
53
-        }
54
-        if ($filterObjectType !== null) {
55
-            $logSearch->byObjectType($filterObjectType);
56
-        }
57
-        if ($filterObjectId !== null) {
58
-            $logSearch->byObjectId($filterObjectId);
59
-        }
60
-
61
-        $this->setSearchHelper($logSearch);
62
-        $this->setupLimits();
63
-
64
-        /** @var Log[] $logs */
65
-        $logs = $logSearch->getRecordCount($count)->fetch();
66
-
67
-        list($users, $logData) = LogHelper::prepareLogsForTemplate($logs, $database, $this->getSiteConfiguration());
68
-
69
-        $this->setupPageData($count, array('filterUser' => $filterUser, 'filterAction' => $filterAction, 'filterObjectType' => $filterObjectType, 'filterObjectId' => $filterObjectId));
70
-
71
-        $this->assign("logs", $logData);
72
-        $this->assign("users", $users);
73
-
74
-        $this->assign('allLogActions', LogHelper::getLogActions($this->getDatabase()));
75
-        $this->assign('allObjectTypes', LogHelper::getObjectTypes());
76
-
77
-        $this->setTemplate("logs/main.tpl");
78
-    }
21
+	/**
22
+	 * Main function for this page, when no specific actions are called.
23
+	 */
24
+	protected function main()
25
+	{
26
+		$this->setHtmlTitle('Logs');
27
+
28
+		$filterUser = WebRequest::getString('filterUser');
29
+		$filterAction = WebRequest::getString('filterAction');
30
+		$filterObjectType = WebRequest::getString('filterObjectType');
31
+		$filterObjectId = WebRequest::getInt('filterObjectId');
32
+
33
+		$database = $this->getDatabase();
34
+
35
+		if (!array_key_exists($filterObjectType, LogHelper::getObjectTypes())) {
36
+			$filterObjectType = null;
37
+		}
38
+
39
+		$this->addJs("/api.php?action=users&all=true&targetVariable=typeaheaddata");
40
+
41
+		$logSearch = LogSearchHelper::get($database);
42
+
43
+		if ($filterUser !== null) {
44
+			$userObj = User::getByUsername($filterUser, $database);
45
+			if ($userObj !== false) {
46
+				$logSearch->byUser($userObj->getId());
47
+			} else {
48
+				$logSearch->byUser(-1);
49
+			}
50
+		}
51
+		if ($filterAction !== null) {
52
+			$logSearch->byAction($filterAction);
53
+		}
54
+		if ($filterObjectType !== null) {
55
+			$logSearch->byObjectType($filterObjectType);
56
+		}
57
+		if ($filterObjectId !== null) {
58
+			$logSearch->byObjectId($filterObjectId);
59
+		}
60
+
61
+		$this->setSearchHelper($logSearch);
62
+		$this->setupLimits();
63
+
64
+		/** @var Log[] $logs */
65
+		$logs = $logSearch->getRecordCount($count)->fetch();
66
+
67
+		list($users, $logData) = LogHelper::prepareLogsForTemplate($logs, $database, $this->getSiteConfiguration());
68
+
69
+		$this->setupPageData($count, array('filterUser' => $filterUser, 'filterAction' => $filterAction, 'filterObjectType' => $filterObjectType, 'filterObjectId' => $filterObjectId));
70
+
71
+		$this->assign("logs", $logData);
72
+		$this->assign("users", $users);
73
+
74
+		$this->assign('allLogActions', LogHelper::getLogActions($this->getDatabase()));
75
+		$this->assign('allObjectTypes', LogHelper::getObjectTypes());
76
+
77
+		$this->setTemplate("logs/main.tpl");
78
+	}
79 79
 }
Please login to merge, or discard this patch.
Braces   +2 added lines, -1 removed lines patch added patch discarded remove patch
@@ -44,7 +44,8 @@
 block discarded – undo
44 44
             $userObj = User::getByUsername($filterUser, $database);
45 45
             if ($userObj !== false) {
46 46
                 $logSearch->byUser($userObj->getId());
47
-            } else {
47
+            }
48
+            else {
48 49
                 $logSearch->byUser(-1);
49 50
             }
50 51
         }
Please login to merge, or discard this patch.
includes/Tasks/JsonApiPageBase.php 3 patches
Indentation   +53 added lines, -53 removed lines patch added patch discarded remove patch
@@ -14,68 +14,68 @@
 block discarded – undo
14 14
 
15 15
 abstract class JsonApiPageBase extends ApiPageBase implements IJsonApiAction
16 16
 {
17
-    /**
18
-     * Main function for this page, when no specific actions are called.
19
-     *
20
-     * @return void
21
-     * @throws ApiException
22
-     */
23
-    final protected function main()
24
-    {
25
-        if (headers_sent()) {
26
-            throw new ApiException('Headers have already been sent - this indicates a bug in the application!');
27
-        }
17
+	/**
18
+	 * Main function for this page, when no specific actions are called.
19
+	 *
20
+	 * @return void
21
+	 * @throws ApiException
22
+	 */
23
+	final protected function main()
24
+	{
25
+		if (headers_sent()) {
26
+			throw new ApiException('Headers have already been sent - this indicates a bug in the application!');
27
+		}
28 28
 
29
-        // javascript access control
30
-        $httpOrigin = WebRequest::origin();
29
+		// javascript access control
30
+		$httpOrigin = WebRequest::origin();
31 31
 
32
-        if ($httpOrigin !== null) {
33
-            $CORSallowed = $this->getSiteConfiguration()->getCrossOriginResourceSharingHosts();
32
+		if ($httpOrigin !== null) {
33
+			$CORSallowed = $this->getSiteConfiguration()->getCrossOriginResourceSharingHosts();
34 34
 
35
-            if (in_array($httpOrigin, $CORSallowed)) {
36
-                header("Access-Control-Allow-Origin: " . $httpOrigin);
37
-            }
38
-        }
35
+			if (in_array($httpOrigin, $CORSallowed)) {
36
+				header("Access-Control-Allow-Origin: " . $httpOrigin);
37
+			}
38
+		}
39 39
 
40
-        $responseData = $this->runApiPage();
40
+		$responseData = $this->runApiPage();
41 41
 
42
-        ob_end_clean();
43
-        print($responseData);
44
-        ob_start();
45
-    }
42
+		ob_end_clean();
43
+		print($responseData);
44
+		ob_start();
45
+	}
46 46
 
47
-    /**
48
-     * Method that runs API action
49
-     *
50
-     * @return object|array The modified API document
51
-     */
52
-    public abstract function executeApiAction();
47
+	/**
48
+	 * Method that runs API action
49
+	 *
50
+	 * @return object|array The modified API document
51
+	 */
52
+	public abstract function executeApiAction();
53 53
 
54
-    /**
55
-     * @return string
56
-     */
57
-    final public function runApiPage()
58
-    {
54
+	/**
55
+	 * @return string
56
+	 */
57
+	final public function runApiPage()
58
+	{
59 59
 
60
-        try {
61
-            $apiDocument = $this->executeApiAction();
62
-        }
63
-        catch (ApiException $ex) {
64
-            $apiDocument = [
65
-                'error' => $ex->getMessage(),
66
-            ];
67
-        }
60
+		try {
61
+			$apiDocument = $this->executeApiAction();
62
+		}
63
+		catch (ApiException $ex) {
64
+			$apiDocument = [
65
+				'error' => $ex->getMessage(),
66
+			];
67
+		}
68 68
 
69
-        $data = json_encode($apiDocument, JSON_UNESCAPED_UNICODE);
69
+		$data = json_encode($apiDocument, JSON_UNESCAPED_UNICODE);
70 70
 
71
-        $targetVar = WebRequest::getString('targetVariable');
72
-        if ($targetVar !== null && preg_match('/^[a-z]+$/', $targetVar)) {
73
-            $data = $targetVar . ' = ' . $data . ';';
74
-            header("Content-Type: text/javascript");
75
-        } else {
76
-            header("Content-Type: application/json");
77
-        }
71
+		$targetVar = WebRequest::getString('targetVariable');
72
+		if ($targetVar !== null && preg_match('/^[a-z]+$/', $targetVar)) {
73
+			$data = $targetVar . ' = ' . $data . ';';
74
+			header("Content-Type: text/javascript");
75
+		} else {
76
+			header("Content-Type: application/json");
77
+		}
78 78
 
79
-        return $data;
80
-    }
79
+		return $data;
80
+	}
81 81
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -33,7 +33,7 @@  discard block
 block discarded – undo
33 33
             $CORSallowed = $this->getSiteConfiguration()->getCrossOriginResourceSharingHosts();
34 34
 
35 35
             if (in_array($httpOrigin, $CORSallowed)) {
36
-                header("Access-Control-Allow-Origin: " . $httpOrigin);
36
+                header("Access-Control-Allow-Origin: ".$httpOrigin);
37 37
             }
38 38
         }
39 39
 
@@ -70,7 +70,7 @@  discard block
 block discarded – undo
70 70
 
71 71
         $targetVar = WebRequest::getString('targetVariable');
72 72
         if ($targetVar !== null && preg_match('/^[a-z]+$/', $targetVar)) {
73
-            $data = $targetVar . ' = ' . $data . ';';
73
+            $data = $targetVar.' = '.$data.';';
74 74
             header("Content-Type: text/javascript");
75 75
         } else {
76 76
             header("Content-Type: application/json");
Please login to merge, or discard this patch.
Braces   +2 added lines, -1 removed lines patch added patch discarded remove patch
@@ -72,7 +72,8 @@
 block discarded – undo
72 72
         if ($targetVar !== null && preg_match('/^[a-z]+$/', $targetVar)) {
73 73
             $data = $targetVar . ' = ' . $data . ';';
74 74
             header("Content-Type: text/javascript");
75
-        } else {
75
+        }
76
+        else {
76 77
             header("Content-Type: application/json");
77 78
         }
78 79
 
Please login to merge, or discard this patch.
includes/Pages/UserAuth/Login/PageU2FLogin.php 1 patch
Indentation   +22 added lines, -22 removed lines patch added patch discarded remove patch
@@ -14,20 +14,20 @@  discard block
 block discarded – undo
14 14
 
15 15
 class PageU2FLogin extends LoginCredentialPageBase
16 16
 {
17
-    protected function providerSpecificSetup()
18
-    {
19
-        $this->assign('showSignIn', false);
20
-        $this->setTemplate('login/u2f.tpl');
17
+	protected function providerSpecificSetup()
18
+	{
19
+		$this->assign('showSignIn', false);
20
+		$this->setTemplate('login/u2f.tpl');
21 21
 
22
-        if ($this->partialUser === null) {
23
-            throw new ApplicationLogicException("U2F cannot be first-stage authentication");
24
-        }
22
+		if ($this->partialUser === null) {
23
+			throw new ApplicationLogicException("U2F cannot be first-stage authentication");
24
+		}
25 25
 
26
-        $u2f = new U2FCredentialProvider($this->getDatabase(), $this->getSiteConfiguration());
27
-        $authData = json_encode($u2f->getAuthenticationData($this->partialUser));
26
+		$u2f = new U2FCredentialProvider($this->getDatabase(), $this->getSiteConfiguration());
27
+		$authData = json_encode($u2f->getAuthenticationData($this->partialUser));
28 28
 
29
-        $this->addJs('/vendor/yubico/u2flib-server/examples/assets/u2f-api.js');
30
-        $this->setTailScript($this->getCspManager()->getNonce(), <<<JS
29
+		$this->addJs('/vendor/yubico/u2flib-server/examples/assets/u2f-api.js');
30
+		$this->setTailScript($this->getCspManager()->getNonce(), <<<JS
31 31
 var request = {$authData};
32 32
 u2f.sign(request, function(data) {
33 33
     document.getElementById('authenticate').value=JSON.stringify(data);
@@ -35,19 +35,19 @@  discard block
 block discarded – undo
35 35
     document.getElementById('loginForm').submit();
36 36
 });
37 37
 JS
38
-        );
38
+		);
39 39
 
40
-    }
40
+	}
41 41
 
42
-    protected function getProviderCredentials()
43
-    {
44
-        $authenticate = WebRequest::postString("authenticate");
45
-        $request = WebRequest::postString("request");
42
+	protected function getProviderCredentials()
43
+	{
44
+		$authenticate = WebRequest::postString("authenticate");
45
+		$request = WebRequest::postString("request");
46 46
 
47
-        if ($authenticate === null || $authenticate === "" || $request === null || $request === "") {
48
-              throw new ApplicationLogicException("No authentication specified");
49
-        }
47
+		if ($authenticate === null || $authenticate === "" || $request === null || $request === "") {
48
+			  throw new ApplicationLogicException("No authentication specified");
49
+		}
50 50
 
51
-        return array(json_decode($authenticate), json_decode($request), 'u2f');
52
-    }
51
+		return array(json_decode($authenticate), json_decode($request), 'u2f');
52
+	}
53 53
 }
Please login to merge, or discard this patch.
includes/Tasks/PageBase.php 3 patches
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -249,7 +249,7 @@  discard block
 block discarded – undo
249 249
             $targetScriptName = $currentScriptName;
250 250
         }
251 251
         else {
252
-            $targetScriptName = $this->getSiteConfiguration()->getBaseUrl() . '/' . $script;
252
+            $targetScriptName = $this->getSiteConfiguration()->getBaseUrl().'/'.$script;
253 253
         }
254 254
 
255 255
         $pathInfo = array($targetScriptName);
@@ -263,7 +263,7 @@  discard block
 block discarded – undo
263 263
         $url = implode('/', $pathInfo);
264 264
 
265 265
         if (is_array($parameters) && count($parameters) > 0) {
266
-            $url .= '?' . http_build_query($parameters);
266
+            $url .= '?'.http_build_query($parameters);
267 267
         }
268 268
 
269 269
         $this->redirectUrl($url);
@@ -307,8 +307,8 @@  discard block
 block discarded – undo
307 307
      *
308 308
      * @param string $path The path (relative to the application root) of the file
309 309
      */
310
-    final protected function addJs($path){
311
-        if(in_array($path, $this->extraJs)){
310
+    final protected function addJs($path) {
311
+        if (in_array($path, $this->extraJs)) {
312 312
             // nothing to do
313 313
             return;
314 314
         }
@@ -331,7 +331,7 @@  discard block
 block discarded – undo
331 331
      */
332 332
     final protected function setHtmlTitle($title)
333 333
     {
334
-        $this->htmlTitle = $this->smarty->fetch('string:' . $title);
334
+        $this->htmlTitle = $this->smarty->fetch('string:'.$title);
335 335
     }
336 336
 
337 337
     public function execute()
Please login to merge, or discard this patch.
Braces   +3 added lines, -2 removed lines patch added patch discarded remove patch
@@ -307,8 +307,9 @@
 block discarded – undo
307 307
      *
308 308
      * @param string $path The path (relative to the application root) of the file
309 309
      */
310
-    final protected function addJs($path){
311
-        if(in_array($path, $this->extraJs)){
310
+    final protected function addJs($path)
311
+    {
312
+        if(in_array($path, $this->extraJs)) {
312 313
             // nothing to do
313 314
             return;
314 315
         }
Please login to merge, or discard this patch.
Indentation   +353 added lines, -353 removed lines patch added patch discarded remove patch
@@ -23,357 +23,357 @@
 block discarded – undo
23 23
 
24 24
 abstract class PageBase extends TaskBase implements IRoutedTask
25 25
 {
26
-    use TemplateOutput;
27
-    /** @var string Smarty template to display */
28
-    protected $template = "base.tpl";
29
-    /** @var string HTML title. Currently unused. */
30
-    protected $htmlTitle;
31
-    /** @var bool Determines if the page is a redirect or not */
32
-    protected $isRedirecting = false;
33
-    /** @var array Queue of headers to be sent on successful completion */
34
-    protected $headerQueue = array();
35
-    /** @var string The name of the route to use, as determined by the request router. */
36
-    private $routeName = null;
37
-    /** @var TokenManager */
38
-    protected $tokenManager;
39
-    /** @var ContentSecurityPolicyManager */
40
-    private $cspManager;
41
-    /** @var string[] Extra JS files to include */
42
-    private $extraJs = array();
43
-
44
-    /**
45
-     * Sets the route the request will take. Only should be called from the request router or barrier test.
46
-     *
47
-     * @param string $routeName        The name of the route
48
-     * @param bool   $skipCallableTest Don't use this unless you know what you're doing, and what the implications are.
49
-     *
50
-     * @throws Exception
51
-     * @category Security-Critical
52
-     */
53
-    final public function setRoute($routeName, $skipCallableTest = false)
54
-    {
55
-        // Test the new route is callable before adopting it.
56
-        if (!$skipCallableTest && !is_callable(array($this, $routeName))) {
57
-            throw new Exception("Proposed route '$routeName' is not callable.");
58
-        }
59
-
60
-        // Adopt the new route
61
-        $this->routeName = $routeName;
62
-    }
63
-
64
-    /**
65
-     * Gets the name of the route that has been passed from the request router.
66
-     * @return string
67
-     */
68
-    final public function getRouteName()
69
-    {
70
-        return $this->routeName;
71
-    }
72
-
73
-    /**
74
-     * Performs generic page setup actions
75
-     */
76
-    final protected function setupPage()
77
-    {
78
-        $this->setUpSmarty();
79
-
80
-        $currentUser = User::getCurrent($this->getDatabase());
81
-        $this->assign('currentUser', $currentUser);
82
-        $this->assign('loggedIn', (!$currentUser->isCommunityUser()));
83
-    }
84
-
85
-    /**
86
-     * Runs the page logic as routed by the RequestRouter
87
-     *
88
-     * Only should be called after a security barrier! That means only from execute().
89
-     */
90
-    final protected function runPage()
91
-    {
92
-        $database = $this->getDatabase();
93
-
94
-        // initialise a database transaction
95
-        if (!$database->beginTransaction()) {
96
-            throw new Exception('Failed to start transaction on primary database.');
97
-        }
98
-
99
-        try {
100
-            // run the page code
101
-            $this->{$this->getRouteName()}();
102
-
103
-            $database->commit();
104
-        }
105
-        catch (ApplicationLogicException $ex) {
106
-            // it's an application logic exception, so nothing went seriously wrong with the site. We can use the
107
-            // standard templating system for this.
108
-
109
-            // Firstly, let's undo anything that happened to the database.
110
-            $database->rollBack();
111
-
112
-            // Reset smarty
113
-            $this->setupPage();
114
-
115
-            // Set the template
116
-            $this->setTemplate('exception/application-logic.tpl');
117
-            $this->assign('message', $ex->getMessage());
118
-
119
-            // Force this back to false
120
-            $this->isRedirecting = false;
121
-            $this->headerQueue = array();
122
-        }
123
-        catch (OptimisticLockFailedException $ex) {
124
-            // it's an optimistic lock failure exception, so nothing went seriously wrong with the site. We can use the
125
-            // standard templating system for this.
126
-
127
-            // Firstly, let's undo anything that happened to the database.
128
-            $database->rollBack();
129
-
130
-            // Reset smarty
131
-            $this->setupPage();
132
-
133
-            // Set the template
134
-            $this->setTemplate('exception/optimistic-lock-failure.tpl');
135
-            $this->assign('message', $ex->getMessage());
136
-
137
-            $this->assign('debugTrace', false);
138
-
139
-            if ($this->getSiteConfiguration()->getDebuggingTraceEnabled()) {
140
-                ob_start();
141
-                var_dump(ExceptionHandler::getExceptionData($ex));
142
-                $textErrorData = ob_get_contents();
143
-                ob_end_clean();
144
-
145
-                $this->assign('exceptionData', $textErrorData);
146
-                $this->assign('debugTrace', true);
147
-            }
148
-
149
-            // Force this back to false
150
-            $this->isRedirecting = false;
151
-            $this->headerQueue = array();
152
-        }
153
-        finally {
154
-            // Catch any hanging on transactions
155
-            if ($database->hasActiveTransaction()) {
156
-                $database->rollBack();
157
-            }
158
-        }
159
-
160
-        // run any finalisation code needed before we send the output to the browser.
161
-        $this->finalisePage();
162
-
163
-        // Send the headers
164
-        $this->sendResponseHeaders();
165
-
166
-        // Check we have a template to use!
167
-        if ($this->template !== null) {
168
-            $content = $this->fetchTemplate($this->template);
169
-            ob_clean();
170
-            print($content);
171
-            ob_flush();
172
-
173
-            return;
174
-        }
175
-    }
176
-
177
-    /**
178
-     * Performs final tasks needed before rendering the page.
179
-     */
180
-    protected function finalisePage()
181
-    {
182
-        if ($this->isRedirecting) {
183
-            $this->template = null;
184
-
185
-            return;
186
-        }
187
-
188
-        $this->assign('extraJs', $this->extraJs);
189
-
190
-        // If we're actually displaying content, we want to add the session alerts here!
191
-        $this->assign('alerts', SessionAlert::getAlerts());
192
-        SessionAlert::clearAlerts();
193
-
194
-        $this->assign('htmlTitle', $this->htmlTitle);
195
-    }
196
-
197
-    /**
198
-     * @return TokenManager
199
-     */
200
-    public function getTokenManager()
201
-    {
202
-        return $this->tokenManager;
203
-    }
204
-
205
-    /**
206
-     * @param TokenManager $tokenManager
207
-     */
208
-    public function setTokenManager($tokenManager)
209
-    {
210
-        $this->tokenManager = $tokenManager;
211
-    }
212
-
213
-    /**
214
-     * @return ContentSecurityPolicyManager
215
-     */
216
-    public function getCspManager(): ContentSecurityPolicyManager
217
-    {
218
-        return $this->cspManager;
219
-    }
220
-
221
-    /**
222
-     * @param ContentSecurityPolicyManager $cspManager
223
-     */
224
-    public function setCspManager(ContentSecurityPolicyManager $cspManager): void
225
-    {
226
-        $this->cspManager = $cspManager;
227
-    }
228
-
229
-    /**
230
-     * Sends the redirect headers to perform a GET at the destination page.
231
-     *
232
-     * Also nullifies the set template so Smarty does not render it.
233
-     *
234
-     * @param string      $page   The page to redirect requests to (as used in the UR)
235
-     * @param null|string $action The action to use on the page.
236
-     * @param null|array  $parameters
237
-     * @param null|string $script The script (relative to index.php) to redirect to
238
-     */
239
-    final protected function redirect($page = '', $action = null, $parameters = null, $script = null)
240
-    {
241
-        $currentScriptName = WebRequest::scriptName();
242
-
243
-        // Are we changing script?
244
-        if ($script === null || substr($currentScriptName, -1 * count($script)) === $script) {
245
-            $targetScriptName = $currentScriptName;
246
-        }
247
-        else {
248
-            $targetScriptName = $this->getSiteConfiguration()->getBaseUrl() . '/' . $script;
249
-        }
250
-
251
-        $pathInfo = array($targetScriptName);
252
-
253
-        $pathInfo[1] = $page;
254
-
255
-        if ($action !== null) {
256
-            $pathInfo[2] = $action;
257
-        }
258
-
259
-        $url = implode('/', $pathInfo);
260
-
261
-        if (is_array($parameters) && count($parameters) > 0) {
262
-            $url .= '?' . http_build_query($parameters);
263
-        }
264
-
265
-        $this->redirectUrl($url);
266
-    }
267
-
268
-    /**
269
-     * Sends the redirect headers to perform a GET at the new address.
270
-     *
271
-     * Also nullifies the set template so Smarty does not render it.
272
-     *
273
-     * @param string $path URL to redirect to
274
-     */
275
-    final protected function redirectUrl($path)
276
-    {
277
-        // 303 See Other = re-request at new address with a GET.
278
-        $this->headerQueue[] = 'HTTP/1.1 303 See Other';
279
-        $this->headerQueue[] = "Location: $path";
280
-
281
-        $this->setTemplate(null);
282
-        $this->isRedirecting = true;
283
-    }
284
-
285
-    /**
286
-     * Sets the name of the template this page should display.
287
-     *
288
-     * @param string $name
289
-     *
290
-     * @throws Exception
291
-     */
292
-    final protected function setTemplate($name)
293
-    {
294
-        if ($this->isRedirecting) {
295
-            throw new Exception('This page has been set as a redirect, no template can be displayed!');
296
-        }
297
-
298
-        $this->template = $name;
299
-    }
300
-
301
-    /**
302
-     * Adds an extra JS file to to the page
303
-     *
304
-     * @param string $path The path (relative to the application root) of the file
305
-     */
306
-    final protected function addJs($path){
307
-        if(in_array($path, $this->extraJs)){
308
-            // nothing to do
309
-            return;
310
-        }
311
-
312
-        $this->extraJs[] = $path;
313
-    }
314
-
315
-    /**
316
-     * Main function for this page, when no specific actions are called.
317
-     * @return void
318
-     */
319
-    abstract protected function main();
320
-
321
-    /**
322
-     * Takes a smarty template string and sets the HTML title to that value
323
-     *
324
-     * @param string $title
325
-     *
326
-     * @throws SmartyException
327
-     */
328
-    final protected function setHtmlTitle($title)
329
-    {
330
-        $this->htmlTitle = $this->smarty->fetch('string:' . $title);
331
-    }
332
-
333
-    public function execute()
334
-    {
335
-        if ($this->getRouteName() === null) {
336
-            throw new Exception('Request is unrouted.');
337
-        }
338
-
339
-        if ($this->getSiteConfiguration() === null) {
340
-            throw new Exception('Page has no configuration!');
341
-        }
342
-
343
-        $this->setupPage();
344
-
345
-        $this->runPage();
346
-    }
347
-
348
-    public function assignCSRFToken()
349
-    {
350
-        $token = $this->tokenManager->getNewToken();
351
-        $this->assign('csrfTokenData', $token->getTokenData());
352
-    }
353
-
354
-    public function validateCSRFToken()
355
-    {
356
-        if (!$this->tokenManager->validateToken(WebRequest::postString('csrfTokenData'))) {
357
-            throw new ApplicationLogicException('Form token is not valid, please reload and try again');
358
-        }
359
-    }
360
-
361
-    protected function sendResponseHeaders()
362
-    {
363
-        if (headers_sent()) {
364
-            throw new ApplicationLogicException('Headers have already been sent! This is likely a bug in the application.');
365
-        }
366
-
367
-        // send the CSP headers now
368
-        header($this->getCspManager()->getHeader());
369
-
370
-        foreach ($this->headerQueue as $item) {
371
-            if (mb_strpos($item, "\r") !== false || mb_strpos($item, "\n") !== false) {
372
-                // Oops. We're not allowed to do this.
373
-                throw new Exception('Unable to split header');
374
-            }
375
-
376
-            header($item);
377
-        }
378
-    }
26
+	use TemplateOutput;
27
+	/** @var string Smarty template to display */
28
+	protected $template = "base.tpl";
29
+	/** @var string HTML title. Currently unused. */
30
+	protected $htmlTitle;
31
+	/** @var bool Determines if the page is a redirect or not */
32
+	protected $isRedirecting = false;
33
+	/** @var array Queue of headers to be sent on successful completion */
34
+	protected $headerQueue = array();
35
+	/** @var string The name of the route to use, as determined by the request router. */
36
+	private $routeName = null;
37
+	/** @var TokenManager */
38
+	protected $tokenManager;
39
+	/** @var ContentSecurityPolicyManager */
40
+	private $cspManager;
41
+	/** @var string[] Extra JS files to include */
42
+	private $extraJs = array();
43
+
44
+	/**
45
+	 * Sets the route the request will take. Only should be called from the request router or barrier test.
46
+	 *
47
+	 * @param string $routeName        The name of the route
48
+	 * @param bool   $skipCallableTest Don't use this unless you know what you're doing, and what the implications are.
49
+	 *
50
+	 * @throws Exception
51
+	 * @category Security-Critical
52
+	 */
53
+	final public function setRoute($routeName, $skipCallableTest = false)
54
+	{
55
+		// Test the new route is callable before adopting it.
56
+		if (!$skipCallableTest && !is_callable(array($this, $routeName))) {
57
+			throw new Exception("Proposed route '$routeName' is not callable.");
58
+		}
59
+
60
+		// Adopt the new route
61
+		$this->routeName = $routeName;
62
+	}
63
+
64
+	/**
65
+	 * Gets the name of the route that has been passed from the request router.
66
+	 * @return string
67
+	 */
68
+	final public function getRouteName()
69
+	{
70
+		return $this->routeName;
71
+	}
72
+
73
+	/**
74
+	 * Performs generic page setup actions
75
+	 */
76
+	final protected function setupPage()
77
+	{
78
+		$this->setUpSmarty();
79
+
80
+		$currentUser = User::getCurrent($this->getDatabase());
81
+		$this->assign('currentUser', $currentUser);
82
+		$this->assign('loggedIn', (!$currentUser->isCommunityUser()));
83
+	}
84
+
85
+	/**
86
+	 * Runs the page logic as routed by the RequestRouter
87
+	 *
88
+	 * Only should be called after a security barrier! That means only from execute().
89
+	 */
90
+	final protected function runPage()
91
+	{
92
+		$database = $this->getDatabase();
93
+
94
+		// initialise a database transaction
95
+		if (!$database->beginTransaction()) {
96
+			throw new Exception('Failed to start transaction on primary database.');
97
+		}
98
+
99
+		try {
100
+			// run the page code
101
+			$this->{$this->getRouteName()}();
102
+
103
+			$database->commit();
104
+		}
105
+		catch (ApplicationLogicException $ex) {
106
+			// it's an application logic exception, so nothing went seriously wrong with the site. We can use the
107
+			// standard templating system for this.
108
+
109
+			// Firstly, let's undo anything that happened to the database.
110
+			$database->rollBack();
111
+
112
+			// Reset smarty
113
+			$this->setupPage();
114
+
115
+			// Set the template
116
+			$this->setTemplate('exception/application-logic.tpl');
117
+			$this->assign('message', $ex->getMessage());
118
+
119
+			// Force this back to false
120
+			$this->isRedirecting = false;
121
+			$this->headerQueue = array();
122
+		}
123
+		catch (OptimisticLockFailedException $ex) {
124
+			// it's an optimistic lock failure exception, so nothing went seriously wrong with the site. We can use the
125
+			// standard templating system for this.
126
+
127
+			// Firstly, let's undo anything that happened to the database.
128
+			$database->rollBack();
129
+
130
+			// Reset smarty
131
+			$this->setupPage();
132
+
133
+			// Set the template
134
+			$this->setTemplate('exception/optimistic-lock-failure.tpl');
135
+			$this->assign('message', $ex->getMessage());
136
+
137
+			$this->assign('debugTrace', false);
138
+
139
+			if ($this->getSiteConfiguration()->getDebuggingTraceEnabled()) {
140
+				ob_start();
141
+				var_dump(ExceptionHandler::getExceptionData($ex));
142
+				$textErrorData = ob_get_contents();
143
+				ob_end_clean();
144
+
145
+				$this->assign('exceptionData', $textErrorData);
146
+				$this->assign('debugTrace', true);
147
+			}
148
+
149
+			// Force this back to false
150
+			$this->isRedirecting = false;
151
+			$this->headerQueue = array();
152
+		}
153
+		finally {
154
+			// Catch any hanging on transactions
155
+			if ($database->hasActiveTransaction()) {
156
+				$database->rollBack();
157
+			}
158
+		}
159
+
160
+		// run any finalisation code needed before we send the output to the browser.
161
+		$this->finalisePage();
162
+
163
+		// Send the headers
164
+		$this->sendResponseHeaders();
165
+
166
+		// Check we have a template to use!
167
+		if ($this->template !== null) {
168
+			$content = $this->fetchTemplate($this->template);
169
+			ob_clean();
170
+			print($content);
171
+			ob_flush();
172
+
173
+			return;
174
+		}
175
+	}
176
+
177
+	/**
178
+	 * Performs final tasks needed before rendering the page.
179
+	 */
180
+	protected function finalisePage()
181
+	{
182
+		if ($this->isRedirecting) {
183
+			$this->template = null;
184
+
185
+			return;
186
+		}
187
+
188
+		$this->assign('extraJs', $this->extraJs);
189
+
190
+		// If we're actually displaying content, we want to add the session alerts here!
191
+		$this->assign('alerts', SessionAlert::getAlerts());
192
+		SessionAlert::clearAlerts();
193
+
194
+		$this->assign('htmlTitle', $this->htmlTitle);
195
+	}
196
+
197
+	/**
198
+	 * @return TokenManager
199
+	 */
200
+	public function getTokenManager()
201
+	{
202
+		return $this->tokenManager;
203
+	}
204
+
205
+	/**
206
+	 * @param TokenManager $tokenManager
207
+	 */
208
+	public function setTokenManager($tokenManager)
209
+	{
210
+		$this->tokenManager = $tokenManager;
211
+	}
212
+
213
+	/**
214
+	 * @return ContentSecurityPolicyManager
215
+	 */
216
+	public function getCspManager(): ContentSecurityPolicyManager
217
+	{
218
+		return $this->cspManager;
219
+	}
220
+
221
+	/**
222
+	 * @param ContentSecurityPolicyManager $cspManager
223
+	 */
224
+	public function setCspManager(ContentSecurityPolicyManager $cspManager): void
225
+	{
226
+		$this->cspManager = $cspManager;
227
+	}
228
+
229
+	/**
230
+	 * Sends the redirect headers to perform a GET at the destination page.
231
+	 *
232
+	 * Also nullifies the set template so Smarty does not render it.
233
+	 *
234
+	 * @param string      $page   The page to redirect requests to (as used in the UR)
235
+	 * @param null|string $action The action to use on the page.
236
+	 * @param null|array  $parameters
237
+	 * @param null|string $script The script (relative to index.php) to redirect to
238
+	 */
239
+	final protected function redirect($page = '', $action = null, $parameters = null, $script = null)
240
+	{
241
+		$currentScriptName = WebRequest::scriptName();
242
+
243
+		// Are we changing script?
244
+		if ($script === null || substr($currentScriptName, -1 * count($script)) === $script) {
245
+			$targetScriptName = $currentScriptName;
246
+		}
247
+		else {
248
+			$targetScriptName = $this->getSiteConfiguration()->getBaseUrl() . '/' . $script;
249
+		}
250
+
251
+		$pathInfo = array($targetScriptName);
252
+
253
+		$pathInfo[1] = $page;
254
+
255
+		if ($action !== null) {
256
+			$pathInfo[2] = $action;
257
+		}
258
+
259
+		$url = implode('/', $pathInfo);
260
+
261
+		if (is_array($parameters) && count($parameters) > 0) {
262
+			$url .= '?' . http_build_query($parameters);
263
+		}
264
+
265
+		$this->redirectUrl($url);
266
+	}
267
+
268
+	/**
269
+	 * Sends the redirect headers to perform a GET at the new address.
270
+	 *
271
+	 * Also nullifies the set template so Smarty does not render it.
272
+	 *
273
+	 * @param string $path URL to redirect to
274
+	 */
275
+	final protected function redirectUrl($path)
276
+	{
277
+		// 303 See Other = re-request at new address with a GET.
278
+		$this->headerQueue[] = 'HTTP/1.1 303 See Other';
279
+		$this->headerQueue[] = "Location: $path";
280
+
281
+		$this->setTemplate(null);
282
+		$this->isRedirecting = true;
283
+	}
284
+
285
+	/**
286
+	 * Sets the name of the template this page should display.
287
+	 *
288
+	 * @param string $name
289
+	 *
290
+	 * @throws Exception
291
+	 */
292
+	final protected function setTemplate($name)
293
+	{
294
+		if ($this->isRedirecting) {
295
+			throw new Exception('This page has been set as a redirect, no template can be displayed!');
296
+		}
297
+
298
+		$this->template = $name;
299
+	}
300
+
301
+	/**
302
+	 * Adds an extra JS file to to the page
303
+	 *
304
+	 * @param string $path The path (relative to the application root) of the file
305
+	 */
306
+	final protected function addJs($path){
307
+		if(in_array($path, $this->extraJs)){
308
+			// nothing to do
309
+			return;
310
+		}
311
+
312
+		$this->extraJs[] = $path;
313
+	}
314
+
315
+	/**
316
+	 * Main function for this page, when no specific actions are called.
317
+	 * @return void
318
+	 */
319
+	abstract protected function main();
320
+
321
+	/**
322
+	 * Takes a smarty template string and sets the HTML title to that value
323
+	 *
324
+	 * @param string $title
325
+	 *
326
+	 * @throws SmartyException
327
+	 */
328
+	final protected function setHtmlTitle($title)
329
+	{
330
+		$this->htmlTitle = $this->smarty->fetch('string:' . $title);
331
+	}
332
+
333
+	public function execute()
334
+	{
335
+		if ($this->getRouteName() === null) {
336
+			throw new Exception('Request is unrouted.');
337
+		}
338
+
339
+		if ($this->getSiteConfiguration() === null) {
340
+			throw new Exception('Page has no configuration!');
341
+		}
342
+
343
+		$this->setupPage();
344
+
345
+		$this->runPage();
346
+	}
347
+
348
+	public function assignCSRFToken()
349
+	{
350
+		$token = $this->tokenManager->getNewToken();
351
+		$this->assign('csrfTokenData', $token->getTokenData());
352
+	}
353
+
354
+	public function validateCSRFToken()
355
+	{
356
+		if (!$this->tokenManager->validateToken(WebRequest::postString('csrfTokenData'))) {
357
+			throw new ApplicationLogicException('Form token is not valid, please reload and try again');
358
+		}
359
+	}
360
+
361
+	protected function sendResponseHeaders()
362
+	{
363
+		if (headers_sent()) {
364
+			throw new ApplicationLogicException('Headers have already been sent! This is likely a bug in the application.');
365
+		}
366
+
367
+		// send the CSP headers now
368
+		header($this->getCspManager()->getHeader());
369
+
370
+		foreach ($this->headerQueue as $item) {
371
+			if (mb_strpos($item, "\r") !== false || mb_strpos($item, "\n") !== false) {
372
+				// Oops. We're not allowed to do this.
373
+				throw new Exception('Unable to split header');
374
+			}
375
+
376
+			header($item);
377
+		}
378
+	}
379 379
 }
Please login to merge, or discard this patch.
smarty-plugins/modifier.relativedate.php 2 patches
Indentation   +62 added lines, -62 removed lines patch added patch discarded remove patch
@@ -16,73 +16,73 @@
 block discarded – undo
16 16
  */
17 17
 function smarty_modifier_relativedate($input)
18 18
 {
19
-    $now = new DateTime();
19
+	$now = new DateTime();
20 20
 
21
-    if (gettype($input) === 'object'
22
-        && (get_class($input) === DateTime::class || get_class($input) === DateTimeImmutable::class)
23
-    ) {
24
-        $then = $input;
25
-    }
26
-    else {
27
-        try {
28
-            $then = new DateTime($input);
29
-        }
30
-        catch(Exception $ex) {
31
-            return $input;
32
-        }
33
-    }
21
+	if (gettype($input) === 'object'
22
+		&& (get_class($input) === DateTime::class || get_class($input) === DateTimeImmutable::class)
23
+	) {
24
+		$then = $input;
25
+	}
26
+	else {
27
+		try {
28
+			$then = new DateTime($input);
29
+		}
30
+		catch(Exception $ex) {
31
+			return $input;
32
+		}
33
+	}
34 34
 
35
-    $secs = $now->getTimestamp() - $then->getTimestamp();
35
+	$secs = $now->getTimestamp() - $then->getTimestamp();
36 36
 
37
-    $second = 1;
38
-    $minute = 60 * $second;
39
-    $minuteCut = 60 * $second;
40
-    $hour = 60 * $minute;
41
-    $hourCut = 90 * $minute;
42
-    $day = 24 * $hour;
43
-    $dayCut = 48 * $hour;
44
-    $week = 7 * $day;
45
-    $weekCut = 14 * $day;
46
-    $month = 30 * $day;
47
-    $monthCut = 60 * $day;
48
-    $year = 365 * $day;
49
-    $yearCut = $year * 2;
37
+	$second = 1;
38
+	$minute = 60 * $second;
39
+	$minuteCut = 60 * $second;
40
+	$hour = 60 * $minute;
41
+	$hourCut = 90 * $minute;
42
+	$day = 24 * $hour;
43
+	$dayCut = 48 * $hour;
44
+	$week = 7 * $day;
45
+	$weekCut = 14 * $day;
46
+	$month = 30 * $day;
47
+	$monthCut = 60 * $day;
48
+	$year = 365 * $day;
49
+	$yearCut = $year * 2;
50 50
 
51
-    $pluralise = true;
51
+	$pluralise = true;
52 52
 
53
-    if ($secs <= 10) {
54
-        $output = "just now";
55
-        $pluralise = false;
56
-    }
57
-    elseif ($secs > 10 && $secs < $minuteCut) {
58
-        $output = round($secs / $second) . " second";
59
-    }
60
-    elseif ($secs >= $minuteCut && $secs < $hourCut) {
61
-        $output = round($secs / $minute) . " minute";
62
-    }
63
-    elseif ($secs >= $hourCut && $secs < $dayCut) {
64
-        $output = round($secs / $hour) . " hour";
65
-    }
66
-    elseif ($secs >= $dayCut && $secs < $weekCut) {
67
-        $output = round($secs / $day) . " day";
68
-    }
69
-    elseif ($secs >= $weekCut && $secs < $monthCut) {
70
-        $output = round($secs / $week) . " week";
71
-    }
72
-    elseif ($secs >= $monthCut && $secs < $yearCut) {
73
-        $output = round($secs / $month) . " month";
74
-    }
75
-    elseif ($secs >= $yearCut && $secs < $year * 10) {
76
-        $output = round($secs / $year) . " year";
77
-    }
78
-    else {
79
-        $output = "a long time ago";
80
-        $pluralise = false;
81
-    }
53
+	if ($secs <= 10) {
54
+		$output = "just now";
55
+		$pluralise = false;
56
+	}
57
+	elseif ($secs > 10 && $secs < $minuteCut) {
58
+		$output = round($secs / $second) . " second";
59
+	}
60
+	elseif ($secs >= $minuteCut && $secs < $hourCut) {
61
+		$output = round($secs / $minute) . " minute";
62
+	}
63
+	elseif ($secs >= $hourCut && $secs < $dayCut) {
64
+		$output = round($secs / $hour) . " hour";
65
+	}
66
+	elseif ($secs >= $dayCut && $secs < $weekCut) {
67
+		$output = round($secs / $day) . " day";
68
+	}
69
+	elseif ($secs >= $weekCut && $secs < $monthCut) {
70
+		$output = round($secs / $week) . " week";
71
+	}
72
+	elseif ($secs >= $monthCut && $secs < $yearCut) {
73
+		$output = round($secs / $month) . " month";
74
+	}
75
+	elseif ($secs >= $yearCut && $secs < $year * 10) {
76
+		$output = round($secs / $year) . " year";
77
+	}
78
+	else {
79
+		$output = "a long time ago";
80
+		$pluralise = false;
81
+	}
82 82
 
83
-    if ($pluralise) {
84
-        $output = (substr($output, 0, 2) <> "1 ") ? $output . "s ago" : $output . " ago";
85
-    }
83
+	if ($pluralise) {
84
+		$output = (substr($output, 0, 2) <> "1 ") ? $output . "s ago" : $output . " ago";
85
+	}
86 86
 
87
-    return $output;
87
+	return $output;
88 88
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -27,7 +27,7 @@  discard block
 block discarded – undo
27 27
         try {
28 28
             $then = new DateTime($input);
29 29
         }
30
-        catch(Exception $ex) {
30
+        catch (Exception $ex) {
31 31
             return $input;
32 32
         }
33 33
     }
@@ -55,25 +55,25 @@  discard block
 block discarded – undo
55 55
         $pluralise = false;
56 56
     }
57 57
     elseif ($secs > 10 && $secs < $minuteCut) {
58
-        $output = round($secs / $second) . " second";
58
+        $output = round($secs / $second)." second";
59 59
     }
60 60
     elseif ($secs >= $minuteCut && $secs < $hourCut) {
61
-        $output = round($secs / $minute) . " minute";
61
+        $output = round($secs / $minute)." minute";
62 62
     }
63 63
     elseif ($secs >= $hourCut && $secs < $dayCut) {
64
-        $output = round($secs / $hour) . " hour";
64
+        $output = round($secs / $hour)." hour";
65 65
     }
66 66
     elseif ($secs >= $dayCut && $secs < $weekCut) {
67
-        $output = round($secs / $day) . " day";
67
+        $output = round($secs / $day)." day";
68 68
     }
69 69
     elseif ($secs >= $weekCut && $secs < $monthCut) {
70
-        $output = round($secs / $week) . " week";
70
+        $output = round($secs / $week)." week";
71 71
     }
72 72
     elseif ($secs >= $monthCut && $secs < $yearCut) {
73
-        $output = round($secs / $month) . " month";
73
+        $output = round($secs / $month)." month";
74 74
     }
75 75
     elseif ($secs >= $yearCut && $secs < $year * 10) {
76
-        $output = round($secs / $year) . " year";
76
+        $output = round($secs / $year)." year";
77 77
     }
78 78
     else {
79 79
         $output = "a long time ago";
@@ -81,7 +81,7 @@  discard block
 block discarded – undo
81 81
     }
82 82
 
83 83
     if ($pluralise) {
84
-        $output = (substr($output, 0, 2) <> "1 ") ? $output . "s ago" : $output . " ago";
84
+        $output = (substr($output, 0, 2) <> "1 ") ? $output."s ago" : $output." ago";
85 85
     }
86 86
 
87 87
     return $output;
Please login to merge, or discard this patch.
includes/DataObjects/User.php 2 patches
Indentation   +567 added lines, -567 removed lines patch added patch discarded remove patch
@@ -21,160 +21,160 @@  discard block
 block discarded – undo
21 21
  */
22 22
 class User extends DataObject
23 23
 {
24
-    const STATUS_ACTIVE = 'Active';
25
-    const STATUS_SUSPENDED = 'Suspended';
26
-    const STATUS_DECLINED = 'Declined';
27
-    const STATUS_NEW = 'New';
28
-    const CREATION_MANUAL = 0;
29
-    const CREATION_OAUTH = 1;
30
-    const CREATION_BOT = 2;
31
-    private $username;
32
-    private $email;
33
-    private $status = self::STATUS_NEW;
34
-    private $onwikiname;
35
-    private $welcome_sig = "";
36
-    private $lastactive = "0000-00-00 00:00:00";
37
-    private $forcelogout = 0;
38
-    private $forceidentified = null;
39
-    private $welcome_template = 0;
40
-    private $abortpref = 0;
41
-    private $confirmationdiff = 0;
42
-    private $emailsig = "";
43
-    private $creationmode = 0;
44
-    private $skin = "main";
45
-    /** @var User Cache variable of the current user - it's never going to change in the middle of a request. */
46
-    private static $currentUser;
47
-    #region Object load methods
48
-
49
-    /**
50
-     * Gets the currently logged in user
51
-     *
52
-     * @param PdoDatabase $database
53
-     *
54
-     * @return User|CommunityUser
55
-     */
56
-    public static function getCurrent(PdoDatabase $database)
57
-    {
58
-        if (self::$currentUser === null) {
59
-            $sessionId = WebRequest::getSessionUserId();
60
-
61
-            if ($sessionId !== null) {
62
-                /** @var User $user */
63
-                $user = self::getById($sessionId, $database);
64
-
65
-                if ($user === false) {
66
-                    self::$currentUser = new CommunityUser();
67
-                }
68
-                else {
69
-                    self::$currentUser = $user;
70
-                }
71
-            }
72
-            else {
73
-                $anonymousCoward = new CommunityUser();
74
-
75
-                self::$currentUser = $anonymousCoward;
76
-            }
77
-        }
78
-
79
-        return self::$currentUser;
80
-    }
81
-
82
-    /**
83
-     * Gets a user by their user ID
84
-     *
85
-     * Pass -1 to get the community user.
86
-     *
87
-     * @param int|null    $id
88
-     * @param PdoDatabase $database
89
-     *
90
-     * @return User|false
91
-     */
92
-    public static function getById($id, PdoDatabase $database)
93
-    {
94
-        if ($id === null || $id == -1) {
95
-            return new CommunityUser();
96
-        }
97
-
98
-        /** @var User|false $user */
99
-        $user = parent::getById($id, $database);
100
-
101
-        return $user;
102
-    }
103
-
104
-    /**
105
-     * @return CommunityUser
106
-     */
107
-    public static function getCommunity()
108
-    {
109
-        return new CommunityUser();
110
-    }
111
-
112
-    /**
113
-     * Gets a user by their username
114
-     *
115
-     * @param  string      $username
116
-     * @param  PdoDatabase $database
117
-     *
118
-     * @return CommunityUser|User|false
119
-     */
120
-    public static function getByUsername($username, PdoDatabase $database)
121
-    {
122
-        global $communityUsername;
123
-        if ($username == $communityUsername) {
124
-            return new CommunityUser();
125
-        }
126
-
127
-        $statement = $database->prepare("SELECT * FROM user WHERE username = :id LIMIT 1;");
128
-        $statement->bindValue(":id", $username);
129
-
130
-        $statement->execute();
131
-
132
-        $resultObject = $statement->fetchObject(get_called_class());
133
-
134
-        if ($resultObject != false) {
135
-            $resultObject->setDatabase($database);
136
-        }
137
-
138
-        return $resultObject;
139
-    }
140
-
141
-    /**
142
-     * Gets a user by their on-wiki username.
143
-     *
144
-     * @param string      $username
145
-     * @param PdoDatabase $database
146
-     *
147
-     * @return User|false
148
-     */
149
-    public static function getByOnWikiUsername($username, PdoDatabase $database)
150
-    {
151
-        $statement = $database->prepare("SELECT * FROM user WHERE onwikiname = :id LIMIT 1;");
152
-        $statement->bindValue(":id", $username);
153
-        $statement->execute();
154
-
155
-        $resultObject = $statement->fetchObject(get_called_class());
156
-
157
-        if ($resultObject != false) {
158
-            $resultObject->setDatabase($database);
159
-
160
-            return $resultObject;
161
-        }
162
-
163
-        return false;
164
-    }
165
-
166
-    #endregion
167
-
168
-    /**
169
-     * Saves the current object
170
-     *
171
-     * @throws Exception
172
-     */
173
-    public function save()
174
-    {
175
-        if ($this->isNew()) {
176
-            // insert
177
-            $statement = $this->dbObject->prepare(<<<SQL
24
+	const STATUS_ACTIVE = 'Active';
25
+	const STATUS_SUSPENDED = 'Suspended';
26
+	const STATUS_DECLINED = 'Declined';
27
+	const STATUS_NEW = 'New';
28
+	const CREATION_MANUAL = 0;
29
+	const CREATION_OAUTH = 1;
30
+	const CREATION_BOT = 2;
31
+	private $username;
32
+	private $email;
33
+	private $status = self::STATUS_NEW;
34
+	private $onwikiname;
35
+	private $welcome_sig = "";
36
+	private $lastactive = "0000-00-00 00:00:00";
37
+	private $forcelogout = 0;
38
+	private $forceidentified = null;
39
+	private $welcome_template = 0;
40
+	private $abortpref = 0;
41
+	private $confirmationdiff = 0;
42
+	private $emailsig = "";
43
+	private $creationmode = 0;
44
+	private $skin = "main";
45
+	/** @var User Cache variable of the current user - it's never going to change in the middle of a request. */
46
+	private static $currentUser;
47
+	#region Object load methods
48
+
49
+	/**
50
+	 * Gets the currently logged in user
51
+	 *
52
+	 * @param PdoDatabase $database
53
+	 *
54
+	 * @return User|CommunityUser
55
+	 */
56
+	public static function getCurrent(PdoDatabase $database)
57
+	{
58
+		if (self::$currentUser === null) {
59
+			$sessionId = WebRequest::getSessionUserId();
60
+
61
+			if ($sessionId !== null) {
62
+				/** @var User $user */
63
+				$user = self::getById($sessionId, $database);
64
+
65
+				if ($user === false) {
66
+					self::$currentUser = new CommunityUser();
67
+				}
68
+				else {
69
+					self::$currentUser = $user;
70
+				}
71
+			}
72
+			else {
73
+				$anonymousCoward = new CommunityUser();
74
+
75
+				self::$currentUser = $anonymousCoward;
76
+			}
77
+		}
78
+
79
+		return self::$currentUser;
80
+	}
81
+
82
+	/**
83
+	 * Gets a user by their user ID
84
+	 *
85
+	 * Pass -1 to get the community user.
86
+	 *
87
+	 * @param int|null    $id
88
+	 * @param PdoDatabase $database
89
+	 *
90
+	 * @return User|false
91
+	 */
92
+	public static function getById($id, PdoDatabase $database)
93
+	{
94
+		if ($id === null || $id == -1) {
95
+			return new CommunityUser();
96
+		}
97
+
98
+		/** @var User|false $user */
99
+		$user = parent::getById($id, $database);
100
+
101
+		return $user;
102
+	}
103
+
104
+	/**
105
+	 * @return CommunityUser
106
+	 */
107
+	public static function getCommunity()
108
+	{
109
+		return new CommunityUser();
110
+	}
111
+
112
+	/**
113
+	 * Gets a user by their username
114
+	 *
115
+	 * @param  string      $username
116
+	 * @param  PdoDatabase $database
117
+	 *
118
+	 * @return CommunityUser|User|false
119
+	 */
120
+	public static function getByUsername($username, PdoDatabase $database)
121
+	{
122
+		global $communityUsername;
123
+		if ($username == $communityUsername) {
124
+			return new CommunityUser();
125
+		}
126
+
127
+		$statement = $database->prepare("SELECT * FROM user WHERE username = :id LIMIT 1;");
128
+		$statement->bindValue(":id", $username);
129
+
130
+		$statement->execute();
131
+
132
+		$resultObject = $statement->fetchObject(get_called_class());
133
+
134
+		if ($resultObject != false) {
135
+			$resultObject->setDatabase($database);
136
+		}
137
+
138
+		return $resultObject;
139
+	}
140
+
141
+	/**
142
+	 * Gets a user by their on-wiki username.
143
+	 *
144
+	 * @param string      $username
145
+	 * @param PdoDatabase $database
146
+	 *
147
+	 * @return User|false
148
+	 */
149
+	public static function getByOnWikiUsername($username, PdoDatabase $database)
150
+	{
151
+		$statement = $database->prepare("SELECT * FROM user WHERE onwikiname = :id LIMIT 1;");
152
+		$statement->bindValue(":id", $username);
153
+		$statement->execute();
154
+
155
+		$resultObject = $statement->fetchObject(get_called_class());
156
+
157
+		if ($resultObject != false) {
158
+			$resultObject->setDatabase($database);
159
+
160
+			return $resultObject;
161
+		}
162
+
163
+		return false;
164
+	}
165
+
166
+	#endregion
167
+
168
+	/**
169
+	 * Saves the current object
170
+	 *
171
+	 * @throws Exception
172
+	 */
173
+	public function save()
174
+	{
175
+		if ($this->isNew()) {
176
+			// insert
177
+			$statement = $this->dbObject->prepare(<<<SQL
178 178
 				INSERT INTO `user` ( 
179 179
 					username, email, status, onwikiname, welcome_sig, 
180 180
 					lastactive, forcelogout, forceidentified,
@@ -185,32 +185,32 @@  discard block
 block discarded – undo
185 185
 					:welcome_template, :abortpref, :confirmationdiff, :emailsig, :creationmode, :skin
186 186
 				);
187 187
 SQL
188
-            );
189
-            $statement->bindValue(":username", $this->username);
190
-            $statement->bindValue(":email", $this->email);
191
-            $statement->bindValue(":status", $this->status);
192
-            $statement->bindValue(":onwikiname", $this->onwikiname);
193
-            $statement->bindValue(":welcome_sig", $this->welcome_sig);
194
-            $statement->bindValue(":lastactive", $this->lastactive);
195
-            $statement->bindValue(":forcelogout", $this->forcelogout);
196
-            $statement->bindValue(":forceidentified", $this->forceidentified);
197
-            $statement->bindValue(":welcome_template", $this->welcome_template);
198
-            $statement->bindValue(":abortpref", $this->abortpref);
199
-            $statement->bindValue(":confirmationdiff", $this->confirmationdiff);
200
-            $statement->bindValue(":emailsig", $this->emailsig);
201
-            $statement->bindValue(":creationmode", $this->creationmode);
202
-            $statement->bindValue(":skin", $this->skin);
203
-
204
-            if ($statement->execute()) {
205
-                $this->id = (int)$this->dbObject->lastInsertId();
206
-            }
207
-            else {
208
-                throw new Exception($statement->errorInfo());
209
-            }
210
-        }
211
-        else {
212
-            // update
213
-            $statement = $this->dbObject->prepare(<<<SQL
188
+			);
189
+			$statement->bindValue(":username", $this->username);
190
+			$statement->bindValue(":email", $this->email);
191
+			$statement->bindValue(":status", $this->status);
192
+			$statement->bindValue(":onwikiname", $this->onwikiname);
193
+			$statement->bindValue(":welcome_sig", $this->welcome_sig);
194
+			$statement->bindValue(":lastactive", $this->lastactive);
195
+			$statement->bindValue(":forcelogout", $this->forcelogout);
196
+			$statement->bindValue(":forceidentified", $this->forceidentified);
197
+			$statement->bindValue(":welcome_template", $this->welcome_template);
198
+			$statement->bindValue(":abortpref", $this->abortpref);
199
+			$statement->bindValue(":confirmationdiff", $this->confirmationdiff);
200
+			$statement->bindValue(":emailsig", $this->emailsig);
201
+			$statement->bindValue(":creationmode", $this->creationmode);
202
+			$statement->bindValue(":skin", $this->skin);
203
+
204
+			if ($statement->execute()) {
205
+				$this->id = (int)$this->dbObject->lastInsertId();
206
+			}
207
+			else {
208
+				throw new Exception($statement->errorInfo());
209
+			}
210
+		}
211
+		else {
212
+			// update
213
+			$statement = $this->dbObject->prepare(<<<SQL
214 214
 				UPDATE `user` SET 
215 215
 					username = :username, email = :email, 
216 216
 					status = :status,
@@ -223,387 +223,387 @@  discard block
 block discarded – undo
223 223
                     updateversion = updateversion + 1
224 224
 				WHERE id = :id AND updateversion = :updateversion;
225 225
 SQL
226
-            );
227
-            $statement->bindValue(":forceidentified", $this->forceidentified);
228
-
229
-            $statement->bindValue(':id', $this->id);
230
-            $statement->bindValue(':updateversion', $this->updateversion);
231
-
232
-            $statement->bindValue(':username', $this->username);
233
-            $statement->bindValue(':email', $this->email);
234
-            $statement->bindValue(':status', $this->status);
235
-            $statement->bindValue(':onwikiname', $this->onwikiname);
236
-            $statement->bindValue(':welcome_sig', $this->welcome_sig);
237
-            $statement->bindValue(':lastactive', $this->lastactive);
238
-            $statement->bindValue(':forcelogout', $this->forcelogout);
239
-            $statement->bindValue(':forceidentified', $this->forceidentified);
240
-            $statement->bindValue(':welcome_template', $this->welcome_template);
241
-            $statement->bindValue(':abortpref', $this->abortpref);
242
-            $statement->bindValue(':confirmationdiff', $this->confirmationdiff);
243
-            $statement->bindValue(':emailsig', $this->emailsig);
244
-            $statement->bindValue(':creationmode', $this->creationmode);
245
-            $statement->bindValue(':skin', $this->skin);
246
-
247
-            if (!$statement->execute()) {
248
-                throw new Exception($statement->errorInfo());
249
-            }
250
-
251
-            if ($statement->rowCount() !== 1) {
252
-                throw new OptimisticLockFailedException();
253
-            }
254
-
255
-            $this->updateversion++;
256
-        }
257
-    }
258
-
259
-    #region properties
260
-
261
-    /**
262
-     * Gets the tool username
263
-     * @return string
264
-     */
265
-    public function getUsername()
266
-    {
267
-        return $this->username;
268
-    }
269
-
270
-    /**
271
-     * Sets the tool username
272
-     *
273
-     * @param string $username
274
-     */
275
-    public function setUsername($username)
276
-    {
277
-        $this->username = $username;
278
-
279
-        // If this isn't a brand new user, then it's a rename, force the logout
280
-        if (!$this->isNew()) {
281
-            $this->forcelogout = 1;
282
-        }
283
-    }
284
-
285
-    /**
286
-     * Gets the user's email address
287
-     * @return string
288
-     */
289
-    public function getEmail()
290
-    {
291
-        return $this->email;
292
-    }
293
-
294
-    /**
295
-     * Sets the user's email address
296
-     *
297
-     * @param string $email
298
-     */
299
-    public function setEmail($email)
300
-    {
301
-        $this->email = $email;
302
-    }
303
-
304
-    /**
305
-     * Gets the status (User, Admin, Suspended, etc - excludes checkuser) of the user.
306
-     * @return string
307
-     */
308
-    public function getStatus()
309
-    {
310
-        return $this->status;
311
-    }
312
-
313
-    /**
314
-     * @param string $status
315
-     */
316
-    public function setStatus($status)
317
-    {
318
-        $this->status = $status;
319
-    }
320
-
321
-    /**
322
-     * Gets the user's on-wiki name
323
-     * @return string
324
-     */
325
-    public function getOnWikiName()
326
-    {
327
-        return $this->onwikiname;
328
-    }
329
-
330
-    /**
331
-     * Sets the user's on-wiki name
332
-     *
333
-     * This can have interesting side-effects with OAuth.
334
-     *
335
-     * @param string $onWikiName
336
-     */
337
-    public function setOnWikiName($onWikiName)
338
-    {
339
-        $this->onwikiname = $onWikiName;
340
-    }
341
-
342
-    /**
343
-     * Gets the welcome signature
344
-     * @return string
345
-     */
346
-    public function getWelcomeSig()
347
-    {
348
-        return $this->welcome_sig;
349
-    }
350
-
351
-    /**
352
-     * Sets the welcome signature
353
-     *
354
-     * @param string $welcomeSig
355
-     */
356
-    public function setWelcomeSig($welcomeSig)
357
-    {
358
-        $this->welcome_sig = $welcomeSig;
359
-    }
360
-
361
-    /**
362
-     * Gets the last activity date for the user
363
-     *
364
-     * @return string
365
-     * @todo This should probably return an instance of DateTime
366
-     */
367
-    public function getLastActive()
368
-    {
369
-        return $this->lastactive;
370
-    }
371
-
372
-    /**
373
-     * Gets the user's forced logout status
374
-     *
375
-     * @return bool
376
-     */
377
-    public function getForceLogout()
378
-    {
379
-        return $this->forcelogout == 1;
380
-    }
381
-
382
-    /**
383
-     * Sets the user's forced logout status
384
-     *
385
-     * @param bool $forceLogout
386
-     */
387
-    public function setForceLogout($forceLogout)
388
-    {
389
-        $this->forcelogout = $forceLogout ? 1 : 0;
390
-    }
391
-
392
-    /**
393
-     * Returns the ID of the welcome template used.
394
-     * @return int
395
-     */
396
-    public function getWelcomeTemplate()
397
-    {
398
-        return $this->welcome_template;
399
-    }
400
-
401
-    /**
402
-     * Sets the ID of the welcome template used.
403
-     *
404
-     * @param int $welcomeTemplate
405
-     */
406
-    public function setWelcomeTemplate($welcomeTemplate)
407
-    {
408
-        $this->welcome_template = $welcomeTemplate;
409
-    }
410
-
411
-    /**
412
-     * Gets the user's abort preference
413
-     * @todo this is badly named too! Also a bool that's actually an int.
414
-     * @return int
415
-     */
416
-    public function getAbortPref()
417
-    {
418
-        return $this->abortpref;
419
-    }
420
-
421
-    /**
422
-     * Sets the user's abort preference
423
-     * @todo rename, retype, and re-comment.
424
-     *
425
-     * @param int $abortPreference
426
-     */
427
-    public function setAbortPref($abortPreference)
428
-    {
429
-        $this->abortpref = $abortPreference;
430
-    }
431
-
432
-    /**
433
-     * Gets the user's confirmation diff. Unused if OAuth is in use.
434
-     * @return int the diff ID
435
-     */
436
-    public function getConfirmationDiff()
437
-    {
438
-        return $this->confirmationdiff;
439
-    }
440
-
441
-    /**
442
-     * Sets the user's confirmation diff.
443
-     *
444
-     * @param int $confirmationDiff
445
-     */
446
-    public function setConfirmationDiff($confirmationDiff)
447
-    {
448
-        $this->confirmationdiff = $confirmationDiff;
449
-    }
450
-
451
-    /**
452
-     * Gets the users' email signature used on outbound mail.
453
-     * @todo rename me!
454
-     * @return string
455
-     */
456
-    public function getEmailSig()
457
-    {
458
-        return $this->emailsig;
459
-    }
460
-
461
-    /**
462
-     * Sets the user's email signature for outbound mail.
463
-     *
464
-     * @param string $emailSignature
465
-     */
466
-    public function setEmailSig($emailSignature)
467
-    {
468
-        $this->emailsig = $emailSignature;
469
-    }
470
-
471
-    /**
472
-     * @return int
473
-     */
474
-    public function getCreationMode()
475
-    {
476
-        return $this->creationmode;
477
-    }
478
-
479
-    /**
480
-     * @param $creationMode int
481
-     */
482
-    public function setCreationMode($creationMode)
483
-    {
484
-        $this->creationmode = $creationMode;
485
-    }
486
-
487
-    /**
488
-     * @return boolean
489
-     */
490
-    public function getUseAlternateSkin()
491
-    {
492
-        return $this->skin === 'alt';
493
-    }
494
-
495
-    /**
496
-     * @return string
497
-     */
498
-    public function getSkin()
499
-    {
500
-        return $this->skin;
501
-    }
502
-
503
-    /**
504
-     * @param $skin string
505
-     */
506
-    public function setSkin($skin)
507
-    {
508
-        $this->skin = $skin;
509
-    }
510
-
511
-    #endregion
512
-
513
-    #region user access checks
514
-
515
-    public function isActive()
516
-    {
517
-        return $this->status == self::STATUS_ACTIVE;
518
-    }
519
-
520
-    /**
521
-     * Tests if the user is identified
522
-     *
523
-     * @param IdentificationVerifier $iv
524
-     *
525
-     * @return bool
526
-     * @todo     Figure out what on earth is going on with PDO's typecasting here.  Apparently, it returns string("0") for
527
-     *       the force-unidentified case, and int(1) for the identified case?!  This is quite ugly, but probably needed
528
-     *       to play it safe for now.
529
-     * @category Security-Critical
530
-     */
531
-    public function isIdentified(IdentificationVerifier $iv)
532
-    {
533
-        if ($this->forceidentified === 0 || $this->forceidentified === "0") {
534
-            // User forced to unidentified in the database.
535
-            return false;
536
-        }
537
-        elseif ($this->forceidentified === 1 || $this->forceidentified === "1") {
538
-            // User forced to identified in the database.
539
-            return true;
540
-        }
541
-        else {
542
-            // User not forced to any particular identified status; consult IdentificationVerifier
543
-            return $iv->isUserIdentified($this->getOnWikiName());
544
-        }
545
-    }
546
-
547
-    /**
548
-     * DO NOT USE FOR TESTING IDENTIFICATION STATUS.
549
-     *
550
-     * @return bool|null
551
-     */
552
-    public function getForceIdentified() {
553
-        return $this->forceidentified;
554
-    }
555
-
556
-    /**
557
-     * Tests if the user is suspended
558
-     * @return bool
559
-     * @category Security-Critical
560
-     */
561
-    public function isSuspended()
562
-    {
563
-        return $this->status == self::STATUS_SUSPENDED;
564
-    }
565
-
566
-    /**
567
-     * Tests if the user is new
568
-     * @return bool
569
-     * @category Security-Critical
570
-     */
571
-    public function isNewUser()
572
-    {
573
-        return $this->status == self::STATUS_NEW;
574
-    }
575
-
576
-    /**
577
-     * Tests if the user has been declined access to the tool
578
-     * @return bool
579
-     * @category Security-Critical
580
-     */
581
-    public function isDeclined()
582
-    {
583
-        return $this->status == self::STATUS_DECLINED;
584
-    }
585
-
586
-    /**
587
-     * Tests if the user is the community user
588
-     *
589
-     * @todo     decide if this means logged out. I think it usually does.
590
-     * @return bool
591
-     * @category Security-Critical
592
-     */
593
-    public function isCommunityUser()
594
-    {
595
-        return false;
596
-    }
597
-
598
-    #endregion 
599
-
600
-    /**
601
-     * Gets the approval date of the user
602
-     * @return DateTime|false
603
-     */
604
-    public function getApprovalDate()
605
-    {
606
-        $query = $this->dbObject->prepare(<<<SQL
226
+			);
227
+			$statement->bindValue(":forceidentified", $this->forceidentified);
228
+
229
+			$statement->bindValue(':id', $this->id);
230
+			$statement->bindValue(':updateversion', $this->updateversion);
231
+
232
+			$statement->bindValue(':username', $this->username);
233
+			$statement->bindValue(':email', $this->email);
234
+			$statement->bindValue(':status', $this->status);
235
+			$statement->bindValue(':onwikiname', $this->onwikiname);
236
+			$statement->bindValue(':welcome_sig', $this->welcome_sig);
237
+			$statement->bindValue(':lastactive', $this->lastactive);
238
+			$statement->bindValue(':forcelogout', $this->forcelogout);
239
+			$statement->bindValue(':forceidentified', $this->forceidentified);
240
+			$statement->bindValue(':welcome_template', $this->welcome_template);
241
+			$statement->bindValue(':abortpref', $this->abortpref);
242
+			$statement->bindValue(':confirmationdiff', $this->confirmationdiff);
243
+			$statement->bindValue(':emailsig', $this->emailsig);
244
+			$statement->bindValue(':creationmode', $this->creationmode);
245
+			$statement->bindValue(':skin', $this->skin);
246
+
247
+			if (!$statement->execute()) {
248
+				throw new Exception($statement->errorInfo());
249
+			}
250
+
251
+			if ($statement->rowCount() !== 1) {
252
+				throw new OptimisticLockFailedException();
253
+			}
254
+
255
+			$this->updateversion++;
256
+		}
257
+	}
258
+
259
+	#region properties
260
+
261
+	/**
262
+	 * Gets the tool username
263
+	 * @return string
264
+	 */
265
+	public function getUsername()
266
+	{
267
+		return $this->username;
268
+	}
269
+
270
+	/**
271
+	 * Sets the tool username
272
+	 *
273
+	 * @param string $username
274
+	 */
275
+	public function setUsername($username)
276
+	{
277
+		$this->username = $username;
278
+
279
+		// If this isn't a brand new user, then it's a rename, force the logout
280
+		if (!$this->isNew()) {
281
+			$this->forcelogout = 1;
282
+		}
283
+	}
284
+
285
+	/**
286
+	 * Gets the user's email address
287
+	 * @return string
288
+	 */
289
+	public function getEmail()
290
+	{
291
+		return $this->email;
292
+	}
293
+
294
+	/**
295
+	 * Sets the user's email address
296
+	 *
297
+	 * @param string $email
298
+	 */
299
+	public function setEmail($email)
300
+	{
301
+		$this->email = $email;
302
+	}
303
+
304
+	/**
305
+	 * Gets the status (User, Admin, Suspended, etc - excludes checkuser) of the user.
306
+	 * @return string
307
+	 */
308
+	public function getStatus()
309
+	{
310
+		return $this->status;
311
+	}
312
+
313
+	/**
314
+	 * @param string $status
315
+	 */
316
+	public function setStatus($status)
317
+	{
318
+		$this->status = $status;
319
+	}
320
+
321
+	/**
322
+	 * Gets the user's on-wiki name
323
+	 * @return string
324
+	 */
325
+	public function getOnWikiName()
326
+	{
327
+		return $this->onwikiname;
328
+	}
329
+
330
+	/**
331
+	 * Sets the user's on-wiki name
332
+	 *
333
+	 * This can have interesting side-effects with OAuth.
334
+	 *
335
+	 * @param string $onWikiName
336
+	 */
337
+	public function setOnWikiName($onWikiName)
338
+	{
339
+		$this->onwikiname = $onWikiName;
340
+	}
341
+
342
+	/**
343
+	 * Gets the welcome signature
344
+	 * @return string
345
+	 */
346
+	public function getWelcomeSig()
347
+	{
348
+		return $this->welcome_sig;
349
+	}
350
+
351
+	/**
352
+	 * Sets the welcome signature
353
+	 *
354
+	 * @param string $welcomeSig
355
+	 */
356
+	public function setWelcomeSig($welcomeSig)
357
+	{
358
+		$this->welcome_sig = $welcomeSig;
359
+	}
360
+
361
+	/**
362
+	 * Gets the last activity date for the user
363
+	 *
364
+	 * @return string
365
+	 * @todo This should probably return an instance of DateTime
366
+	 */
367
+	public function getLastActive()
368
+	{
369
+		return $this->lastactive;
370
+	}
371
+
372
+	/**
373
+	 * Gets the user's forced logout status
374
+	 *
375
+	 * @return bool
376
+	 */
377
+	public function getForceLogout()
378
+	{
379
+		return $this->forcelogout == 1;
380
+	}
381
+
382
+	/**
383
+	 * Sets the user's forced logout status
384
+	 *
385
+	 * @param bool $forceLogout
386
+	 */
387
+	public function setForceLogout($forceLogout)
388
+	{
389
+		$this->forcelogout = $forceLogout ? 1 : 0;
390
+	}
391
+
392
+	/**
393
+	 * Returns the ID of the welcome template used.
394
+	 * @return int
395
+	 */
396
+	public function getWelcomeTemplate()
397
+	{
398
+		return $this->welcome_template;
399
+	}
400
+
401
+	/**
402
+	 * Sets the ID of the welcome template used.
403
+	 *
404
+	 * @param int $welcomeTemplate
405
+	 */
406
+	public function setWelcomeTemplate($welcomeTemplate)
407
+	{
408
+		$this->welcome_template = $welcomeTemplate;
409
+	}
410
+
411
+	/**
412
+	 * Gets the user's abort preference
413
+	 * @todo this is badly named too! Also a bool that's actually an int.
414
+	 * @return int
415
+	 */
416
+	public function getAbortPref()
417
+	{
418
+		return $this->abortpref;
419
+	}
420
+
421
+	/**
422
+	 * Sets the user's abort preference
423
+	 * @todo rename, retype, and re-comment.
424
+	 *
425
+	 * @param int $abortPreference
426
+	 */
427
+	public function setAbortPref($abortPreference)
428
+	{
429
+		$this->abortpref = $abortPreference;
430
+	}
431
+
432
+	/**
433
+	 * Gets the user's confirmation diff. Unused if OAuth is in use.
434
+	 * @return int the diff ID
435
+	 */
436
+	public function getConfirmationDiff()
437
+	{
438
+		return $this->confirmationdiff;
439
+	}
440
+
441
+	/**
442
+	 * Sets the user's confirmation diff.
443
+	 *
444
+	 * @param int $confirmationDiff
445
+	 */
446
+	public function setConfirmationDiff($confirmationDiff)
447
+	{
448
+		$this->confirmationdiff = $confirmationDiff;
449
+	}
450
+
451
+	/**
452
+	 * Gets the users' email signature used on outbound mail.
453
+	 * @todo rename me!
454
+	 * @return string
455
+	 */
456
+	public function getEmailSig()
457
+	{
458
+		return $this->emailsig;
459
+	}
460
+
461
+	/**
462
+	 * Sets the user's email signature for outbound mail.
463
+	 *
464
+	 * @param string $emailSignature
465
+	 */
466
+	public function setEmailSig($emailSignature)
467
+	{
468
+		$this->emailsig = $emailSignature;
469
+	}
470
+
471
+	/**
472
+	 * @return int
473
+	 */
474
+	public function getCreationMode()
475
+	{
476
+		return $this->creationmode;
477
+	}
478
+
479
+	/**
480
+	 * @param $creationMode int
481
+	 */
482
+	public function setCreationMode($creationMode)
483
+	{
484
+		$this->creationmode = $creationMode;
485
+	}
486
+
487
+	/**
488
+	 * @return boolean
489
+	 */
490
+	public function getUseAlternateSkin()
491
+	{
492
+		return $this->skin === 'alt';
493
+	}
494
+
495
+	/**
496
+	 * @return string
497
+	 */
498
+	public function getSkin()
499
+	{
500
+		return $this->skin;
501
+	}
502
+
503
+	/**
504
+	 * @param $skin string
505
+	 */
506
+	public function setSkin($skin)
507
+	{
508
+		$this->skin = $skin;
509
+	}
510
+
511
+	#endregion
512
+
513
+	#region user access checks
514
+
515
+	public function isActive()
516
+	{
517
+		return $this->status == self::STATUS_ACTIVE;
518
+	}
519
+
520
+	/**
521
+	 * Tests if the user is identified
522
+	 *
523
+	 * @param IdentificationVerifier $iv
524
+	 *
525
+	 * @return bool
526
+	 * @todo     Figure out what on earth is going on with PDO's typecasting here.  Apparently, it returns string("0") for
527
+	 *       the force-unidentified case, and int(1) for the identified case?!  This is quite ugly, but probably needed
528
+	 *       to play it safe for now.
529
+	 * @category Security-Critical
530
+	 */
531
+	public function isIdentified(IdentificationVerifier $iv)
532
+	{
533
+		if ($this->forceidentified === 0 || $this->forceidentified === "0") {
534
+			// User forced to unidentified in the database.
535
+			return false;
536
+		}
537
+		elseif ($this->forceidentified === 1 || $this->forceidentified === "1") {
538
+			// User forced to identified in the database.
539
+			return true;
540
+		}
541
+		else {
542
+			// User not forced to any particular identified status; consult IdentificationVerifier
543
+			return $iv->isUserIdentified($this->getOnWikiName());
544
+		}
545
+	}
546
+
547
+	/**
548
+	 * DO NOT USE FOR TESTING IDENTIFICATION STATUS.
549
+	 *
550
+	 * @return bool|null
551
+	 */
552
+	public function getForceIdentified() {
553
+		return $this->forceidentified;
554
+	}
555
+
556
+	/**
557
+	 * Tests if the user is suspended
558
+	 * @return bool
559
+	 * @category Security-Critical
560
+	 */
561
+	public function isSuspended()
562
+	{
563
+		return $this->status == self::STATUS_SUSPENDED;
564
+	}
565
+
566
+	/**
567
+	 * Tests if the user is new
568
+	 * @return bool
569
+	 * @category Security-Critical
570
+	 */
571
+	public function isNewUser()
572
+	{
573
+		return $this->status == self::STATUS_NEW;
574
+	}
575
+
576
+	/**
577
+	 * Tests if the user has been declined access to the tool
578
+	 * @return bool
579
+	 * @category Security-Critical
580
+	 */
581
+	public function isDeclined()
582
+	{
583
+		return $this->status == self::STATUS_DECLINED;
584
+	}
585
+
586
+	/**
587
+	 * Tests if the user is the community user
588
+	 *
589
+	 * @todo     decide if this means logged out. I think it usually does.
590
+	 * @return bool
591
+	 * @category Security-Critical
592
+	 */
593
+	public function isCommunityUser()
594
+	{
595
+		return false;
596
+	}
597
+
598
+	#endregion 
599
+
600
+	/**
601
+	 * Gets the approval date of the user
602
+	 * @return DateTime|false
603
+	 */
604
+	public function getApprovalDate()
605
+	{
606
+		$query = $this->dbObject->prepare(<<<SQL
607 607
 			SELECT timestamp 
608 608
 			FROM log 
609 609
 			WHERE objectid = :userid
@@ -612,12 +612,12 @@  discard block
 block discarded – undo
612 612
 			ORDER BY id DESC 
613 613
 			LIMIT 1;
614 614
 SQL
615
-        );
616
-        $query->execute(array(":userid" => $this->id));
615
+		);
616
+		$query->execute(array(":userid" => $this->id));
617 617
 
618
-        $data = DateTime::createFromFormat("Y-m-d H:i:s", $query->fetchColumn());
619
-        $query->closeCursor();
618
+		$data = DateTime::createFromFormat("Y-m-d H:i:s", $query->fetchColumn());
619
+		$query->closeCursor();
620 620
 
621
-        return $data;
622
-    }
621
+		return $data;
622
+	}
623 623
 }
Please login to merge, or discard this patch.
Braces   +2 added lines, -1 removed lines patch added patch discarded remove patch
@@ -549,7 +549,8 @@
 block discarded – undo
549 549
      *
550 550
      * @return bool|null
551 551
      */
552
-    public function getForceIdentified() {
552
+    public function getForceIdentified()
553
+    {
553 554
         return $this->forceidentified;
554 555
     }
555 556
 
Please login to merge, or discard this patch.
includes/Pages/Statistics/StatsUsers.php 3 patches
Indentation   +88 added lines, -88 removed lines patch added patch discarded remove patch
@@ -23,13 +23,13 @@  discard block
 block discarded – undo
23 23
 
24 24
 class StatsUsers extends InternalPageBase
25 25
 {
26
-    public function main()
27
-    {
28
-        $this->setHtmlTitle('Users :: Statistics');
26
+	public function main()
27
+	{
28
+		$this->setHtmlTitle('Users :: Statistics');
29 29
 
30
-        $database = $this->getDatabase();
30
+		$database = $this->getDatabase();
31 31
 
32
-        $query = <<<SQL
32
+		$query = <<<SQL
33 33
 SELECT
34 34
     u.id
35 35
     , u.username
@@ -45,34 +45,34 @@  discard block
 block discarded – undo
45 45
 WHERE u.status = 'Active'
46 46
 SQL;
47 47
 
48
-        $users = $database->query($query)->fetchAll(PDO::FETCH_ASSOC);
49
-        $this->assign('users', $users);
48
+		$users = $database->query($query)->fetchAll(PDO::FETCH_ASSOC);
49
+		$this->assign('users', $users);
50 50
 
51
-        $this->assign('statsPageTitle', 'Account Creation Tool users');
52
-        $this->setTemplate("statistics/users.tpl");
53
-    }
51
+		$this->assign('statsPageTitle', 'Account Creation Tool users');
52
+		$this->setTemplate("statistics/users.tpl");
53
+	}
54 54
 
55
-    /**
56
-     * Entry point for the detail action.
57
-     *
58
-     * @throws ApplicationLogicException
59
-     */
60
-    protected function detail()
61
-    {
62
-        $userId = WebRequest::getInt('user');
63
-        if ($userId === null) {
64
-            throw new ApplicationLogicException("User not found");
65
-        }
55
+	/**
56
+	 * Entry point for the detail action.
57
+	 *
58
+	 * @throws ApplicationLogicException
59
+	 */
60
+	protected function detail()
61
+	{
62
+		$userId = WebRequest::getInt('user');
63
+		if ($userId === null) {
64
+			throw new ApplicationLogicException("User not found");
65
+		}
66 66
 
67
-        $database = $this->getDatabase();
67
+		$database = $this->getDatabase();
68 68
 
69
-        $user = User::getById($userId, $database);
70
-        if ($user == false) {
71
-            throw new ApplicationLogicException('User not found');
72
-        }
69
+		$user = User::getById($userId, $database);
70
+		if ($user == false) {
71
+			throw new ApplicationLogicException('User not found');
72
+		}
73 73
 
74 74
 
75
-        $activitySummary = $database->prepare(<<<SQL
75
+		$activitySummary = $database->prepare(<<<SQL
76 76
 SELECT COALESCE(closes.mail_desc, log.action) AS action, COUNT(*) AS count
77 77
 FROM log
78 78
 INNER JOIN user ON log.user = user.id
@@ -80,14 +80,14 @@  discard block
 block discarded – undo
80 80
 WHERE user.username = :username
81 81
 GROUP BY action;
82 82
 SQL
83
-        );
84
-        $activitySummary->execute(array(":username" => $user->getUsername()));
85
-        $activitySummaryData = $activitySummary->fetchAll(PDO::FETCH_ASSOC);
83
+		);
84
+		$activitySummary->execute(array(":username" => $user->getUsername()));
85
+		$activitySummaryData = $activitySummary->fetchAll(PDO::FETCH_ASSOC);
86 86
 
87
-        $this->assign("user", $user);
88
-        $this->assign("activity", $activitySummaryData);
87
+		$this->assign("user", $user);
88
+		$this->assign("activity", $activitySummaryData);
89 89
 
90
-        $usersCreatedQuery = $database->prepare(<<<SQL
90
+		$usersCreatedQuery = $database->prepare(<<<SQL
91 91
 SELECT log.timestamp time, request.name name, request.id id
92 92
 FROM log
93 93
 INNER JOIN request ON (request.id = log.objectid AND log.objecttype = 'Request')
@@ -98,12 +98,12 @@  discard block
 block discarded – undo
98 98
     AND (emailtemplate.oncreated = '1' OR log.action = 'Closed custom-y')
99 99
 ORDER BY log.timestamp;
100 100
 SQL
101
-        );
102
-        $usersCreatedQuery->execute(array(":username" => $user->getUsername()));
103
-        $usersCreated = $usersCreatedQuery->fetchAll(PDO::FETCH_ASSOC);
104
-        $this->assign("created", $usersCreated);
101
+		);
102
+		$usersCreatedQuery->execute(array(":username" => $user->getUsername()));
103
+		$usersCreated = $usersCreatedQuery->fetchAll(PDO::FETCH_ASSOC);
104
+		$this->assign("created", $usersCreated);
105 105
 
106
-        $usersNotCreatedQuery = $database->prepare(<<<SQL
106
+		$usersNotCreatedQuery = $database->prepare(<<<SQL
107 107
 SELECT log.timestamp time, request.name name, request.id id
108 108
 FROM log
109 109
 JOIN request ON request.id = log.objectid AND log.objecttype = 'Request'
@@ -114,54 +114,54 @@  discard block
 block discarded – undo
114 114
     AND (emailtemplate.oncreated = '0' OR log.action = 'Closed custom-n' OR log.action = 'Closed 0')
115 115
 ORDER BY log.timestamp;
116 116
 SQL
117
-        );
118
-        $usersNotCreatedQuery->execute(array(":username" => $user->getUsername()));
119
-        $usersNotCreated = $usersNotCreatedQuery->fetchAll(PDO::FETCH_ASSOC);
120
-        $this->assign("notcreated", $usersNotCreated);
121
-
122
-        /** @var Log[] $logs */
123
-        $logs = LogSearchHelper::get($database)
124
-            ->byObjectType('User')
125
-            ->byObjectId($user->getId())
126
-            ->getRecordCount($logCount)
127
-            ->fetch();
128
-
129
-        if ($logCount === 0) {
130
-            $this->assign('accountlog', array());
131
-        }
132
-        else {
133
-            list($users, $logData) = LogHelper::prepareLogsForTemplate($logs, $database, $this->getSiteConfiguration());
134
-
135
-            $this->assign("accountlog", $logData);
136
-            $this->assign("users", $users);
137
-        }
138
-
139
-        $currentUser = User::getCurrent($database);
140
-        $this->assign('canApprove', $this->barrierTest('approve', $currentUser, PageUserManagement::class));
141
-        $this->assign('canDecline', $this->barrierTest('decline', $currentUser, PageUserManagement::class));
142
-        $this->assign('canRename', $this->barrierTest('rename', $currentUser, PageUserManagement::class));
143
-        $this->assign('canEditUser', $this->barrierTest('editUser', $currentUser, PageUserManagement::class));
144
-        $this->assign('canSuspend', $this->barrierTest('suspend', $currentUser, PageUserManagement::class));
145
-        $this->assign('canEditRoles', $this->barrierTest('editRoles', $currentUser, PageUserManagement::class));
146
-
147
-        $oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), $this->getSiteConfiguration());
148
-        $this->assign('oauth', $oauth);
149
-
150
-        if($user->getForceIdentified() === null) {
151
-            $idVerifier = new IdentificationVerifier($this->getHttpHelper(), $this->getSiteConfiguration(), $this->getDatabase());
152
-            $this->assign('identificationStatus', $idVerifier->isUserIdentified($user->getOnWikiName()) ? 'detected' : 'missing');
153
-        } else {
154
-            $this->assign('identificationStatus', $user->getForceIdentified() == 1 ? 'forced-on' : 'forced-off');
155
-        }
156
-
157
-        if ($oauth->isFullyLinked()) {
158
-            $this->assign('identity', $oauth->getIdentity(true));
159
-            $this->assign('identityExpired', $oauth->identityExpired());
160
-        }
161
-
162
-        $this->assign('statsPageTitle', 'Account Creation Tool users');
163
-
164
-        $this->setHtmlTitle('{$user->getUsername()|escape} :: Users :: Statistics');
165
-        $this->setTemplate("statistics/userdetail.tpl");
166
-    }
117
+		);
118
+		$usersNotCreatedQuery->execute(array(":username" => $user->getUsername()));
119
+		$usersNotCreated = $usersNotCreatedQuery->fetchAll(PDO::FETCH_ASSOC);
120
+		$this->assign("notcreated", $usersNotCreated);
121
+
122
+		/** @var Log[] $logs */
123
+		$logs = LogSearchHelper::get($database)
124
+			->byObjectType('User')
125
+			->byObjectId($user->getId())
126
+			->getRecordCount($logCount)
127
+			->fetch();
128
+
129
+		if ($logCount === 0) {
130
+			$this->assign('accountlog', array());
131
+		}
132
+		else {
133
+			list($users, $logData) = LogHelper::prepareLogsForTemplate($logs, $database, $this->getSiteConfiguration());
134
+
135
+			$this->assign("accountlog", $logData);
136
+			$this->assign("users", $users);
137
+		}
138
+
139
+		$currentUser = User::getCurrent($database);
140
+		$this->assign('canApprove', $this->barrierTest('approve', $currentUser, PageUserManagement::class));
141
+		$this->assign('canDecline', $this->barrierTest('decline', $currentUser, PageUserManagement::class));
142
+		$this->assign('canRename', $this->barrierTest('rename', $currentUser, PageUserManagement::class));
143
+		$this->assign('canEditUser', $this->barrierTest('editUser', $currentUser, PageUserManagement::class));
144
+		$this->assign('canSuspend', $this->barrierTest('suspend', $currentUser, PageUserManagement::class));
145
+		$this->assign('canEditRoles', $this->barrierTest('editRoles', $currentUser, PageUserManagement::class));
146
+
147
+		$oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), $this->getSiteConfiguration());
148
+		$this->assign('oauth', $oauth);
149
+
150
+		if($user->getForceIdentified() === null) {
151
+			$idVerifier = new IdentificationVerifier($this->getHttpHelper(), $this->getSiteConfiguration(), $this->getDatabase());
152
+			$this->assign('identificationStatus', $idVerifier->isUserIdentified($user->getOnWikiName()) ? 'detected' : 'missing');
153
+		} else {
154
+			$this->assign('identificationStatus', $user->getForceIdentified() == 1 ? 'forced-on' : 'forced-off');
155
+		}
156
+
157
+		if ($oauth->isFullyLinked()) {
158
+			$this->assign('identity', $oauth->getIdentity(true));
159
+			$this->assign('identityExpired', $oauth->identityExpired());
160
+		}
161
+
162
+		$this->assign('statsPageTitle', 'Account Creation Tool users');
163
+
164
+		$this->setHtmlTitle('{$user->getUsername()|escape} :: Users :: Statistics');
165
+		$this->setTemplate("statistics/userdetail.tpl");
166
+	}
167 167
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -147,7 +147,7 @@
 block discarded – undo
147 147
         $oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), $this->getSiteConfiguration());
148 148
         $this->assign('oauth', $oauth);
149 149
 
150
-        if($user->getForceIdentified() === null) {
150
+        if ($user->getForceIdentified() === null) {
151 151
             $idVerifier = new IdentificationVerifier($this->getHttpHelper(), $this->getSiteConfiguration(), $this->getDatabase());
152 152
             $this->assign('identificationStatus', $idVerifier->isUserIdentified($user->getOnWikiName()) ? 'detected' : 'missing');
153 153
         } else {
Please login to merge, or discard this patch.
Braces   +2 added lines, -1 removed lines patch added patch discarded remove patch
@@ -150,7 +150,8 @@
 block discarded – undo
150 150
         if($user->getForceIdentified() === null) {
151 151
             $idVerifier = new IdentificationVerifier($this->getHttpHelper(), $this->getSiteConfiguration(), $this->getDatabase());
152 152
             $this->assign('identificationStatus', $idVerifier->isUserIdentified($user->getOnWikiName()) ? 'detected' : 'missing');
153
-        } else {
153
+        }
154
+        else {
154 155
             $this->assign('identificationStatus', $user->getForceIdentified() == 1 ? 'forced-on' : 'forced-off');
155 156
         }
156 157
 
Please login to merge, or discard this patch.