Failed Conditions
Branch newinternal (104de7)
by Simon
09:33
created

includes/Validation/RequestValidationHelper.php (2 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
namespace Waca\Validation;
3
4
use Exception;
5
use Waca\DataObjects\Request;
6
use Waca\Helpers\Interfaces\IBanHelper;
7
use Waca\PdoDatabase;
8
use Waca\Providers\Interfaces\IAntiSpoofProvider;
9
use Waca\Providers\Interfaces\IXffTrustProvider;
10
11
/**
12
 * Performs the validation of an incoming request.
13
 */
14
class RequestValidationHelper
15
{
16
	/** @var IBanHelper */
17
	private $banHelper;
18
	/** @var Request */
19
	private $request;
20
	private $emailConfirmation;
21
	/** @var PdoDatabase */
22
	private $database;
23
	/** @var IAntiSpoofProvider */
24
	private $antiSpoofProvider;
25
26
	/**
27
	 * Summary of __construct
28
	 *
29
	 * @param IBanHelper         $banHelper
30
	 * @param Request            $request
31
	 * @param string             $emailConfirmation
32
	 * @param PdoDatabase        $database
33
	 * @param IAntiSpoofProvider $antiSpoofProvider
34
	 */
35
	public function __construct(
36
		IBanHelper $banHelper,
37
		Request $request,
38
		$emailConfirmation,
39
		PdoDatabase $database,
40
		IAntiSpoofProvider $antiSpoofProvider
41
	) {
42
		$this->banHelper = $banHelper;
43
		$this->request = $request;
44
		$this->emailConfirmation = $emailConfirmation;
45
		$this->database = $database;
46
		$this->antiSpoofProvider = $antiSpoofProvider;
47
	}
48
49
	/**
50
	 * Summary of validateName
51
	 * @return ValidationError[]
52
	 */
53
	public function validateName()
54
	{
55
		$errorList = array();
56
57
		// ERRORS
58
		// name is empty
59
		if (trim($this->request->getName()) == "") {
60
			$errorList[ValidationError::NAME_EMPTY] = new ValidationError(ValidationError::NAME_EMPTY);
61
		}
62
63
		// name is banned
64
		$ban = $this->banHelper->nameIsBanned($this->request->getName());
65
		if ($ban != false) {
66
			$errorList[ValidationError::BANNED] = new ValidationError(ValidationError::BANNED);
67
		}
68
69
		// username already exists
70
		// TODO: implement
71
		if ($this->userExists()) {
72
			$errorList[ValidationError::NAME_EXISTS] = new ValidationError(ValidationError::NAME_EXISTS);
73
		}
74
75
		// username part of SUL account
76
		// TODO: implement
77
		if ($this->userSulExists()) {
78
			// using same error slot as name exists - it's the same sort of error, and we probably only want to show one.
79
			$errorList[ValidationError::NAME_EXISTS] = new ValidationError(ValidationError::NAME_EXISTS_SUL);
80
		}
81
82
		// username is numbers
83 View Code Duplication
		if (preg_match("/^[0-9]+$/", $this->request->getName()) === 1) {
84
			$errorList[ValidationError::NAME_NUMONLY] = new ValidationError(ValidationError::NAME_NUMONLY);
85
		}
86
87
		// username can't contain #@/<>[]|{}
88
		if (preg_match("/[" . preg_quote("#@/<>[]|{}", "/") . "]/", $this->request->getName()) === 1) {
89
			$errorList[ValidationError::NAME_INVALIDCHAR] = new ValidationError(ValidationError::NAME_INVALIDCHAR);
90
		}
91
92
		// existing non-closed request for this name
93
		// TODO: implement
94
		if ($this->nameRequestExists()) {
95
			$errorList[ValidationError::OPEN_REQUEST_NAME] = new ValidationError(ValidationError::OPEN_REQUEST_NAME);
96
		}
97
98
		// WARNINGS
99
		// name has to be sanitised
100
		// TODO: implement
101
		if (false) {
0 ignored issues
show
Avoid IF statements that are always true or false
Loading history...
102
			$errorList[ValidationError::NAME_SANITISED] = new ValidationError(ValidationError::NAME_SANITISED, false);
103
		}
104
105
		return $errorList;
106
	}
107
108
	/**
109
	 * Summary of validateEmail
110
	 * @return ValidationError[]
111
	 */
112
	public function validateEmail()
113
	{
114
		$errorList = array();
115
116
		// ERRORS
117
118
		// Email is banned
119
		$ban = $this->banHelper->emailIsBanned($this->request->getEmail());
120
		if ($ban != false) {
121
			$errorList[ValidationError::BANNED] = new ValidationError(ValidationError::BANNED);
122
		}
123
124
		// email addresses must match
125
		if ($this->request->getEmail() != $this->emailConfirmation) {
126
			$errorList[ValidationError::EMAIL_MISMATCH] = new ValidationError(ValidationError::EMAIL_MISMATCH);
127
		}
128
129
		// email address must be validly formed
130 View Code Duplication
		if (trim($this->request->getEmail()) == "") {
131
			$errorList[ValidationError::EMAIL_EMPTY] = new ValidationError(ValidationError::EMAIL_EMPTY);
132
		}
133
134
		// email address must be validly formed
135
		if (!filter_var($this->request->getEmail(), FILTER_VALIDATE_EMAIL)) {
136 View Code Duplication
			if (trim($this->request->getEmail()) != "") {
137
				$errorList[ValidationError::EMAIL_INVALID] = new ValidationError(ValidationError::EMAIL_INVALID);
138
			}
139
		}
140
141
		// email address can't be wikimedia/wikipedia .com/org
142 View Code Duplication
		if (preg_match('/.*@.*wiki(m.dia|p.dia)\.(org|com)/i', $this->request->getEmail()) === 1) {
143
			$errorList[ValidationError::EMAIL_WIKIMEDIA] = new ValidationError(ValidationError::EMAIL_WIKIMEDIA);
144
		}
145
146
		// WARNINGS
147
148
		return $errorList;
149
	}
150
151
	/**
152
	 * Summary of validateOther
153
	 * @return ValidationError[]
154
	 */
155
	public function validateOther()
156
	{
157
		// @todo remove me!
158
		/** @var $xffTrustProvider IXffTrustProvider */
159
		global $xffTrustProvider;
160
161
		$errorList = array();
162
163
		// ERRORS
164
165
		// TOR nodes
166
		// TODO: Implement
167
		if (false) {
0 ignored issues
show
Avoid IF statements that are always true or false
Loading history...
168
			$errorList[ValidationError::BANNED] = new ValidationError(ValidationError::BANNED_TOR);
169
		}
170
171
		// IP banned
172
		$trustedIp = $xffTrustProvider->getTrustedClientIp($this->request->getIp(), $this->request->getForwardedIp());
173
		$ban = $this->banHelper->ipIsBanned($trustedIp);
174
		if ($ban != false) {
175
			$errorList[ValidationError::BANNED] = new ValidationError(ValidationError::BANNED);
176
		}
177
178
		// WARNINGS
179
180
		// Antispoof check
181
		$this->checkAntiSpoof();
182
183
		// Blacklist check
184
		$this->checkTitleBlacklist();
185
186
		return $errorList;
187
	}
188
189
	private function checkAntiSpoof()
190
	{
191
		try {
192
			if (count($this->antiSpoofProvider->getSpoofs($this->request->getName())) > 0) {
193
				// If there were spoofs an Admin should handle the request.
194
				$this->request->setStatus("Flagged users");
195
			}
196
		}
197
		catch (Exception $ex) {
198
			// hrm.
199
			// TODO: log this?
200
		}
201
	}
202
203
	private function checkTitleBlacklist()
204
	{
205
		global $enableTitleblacklist;
206
		if ($enableTitleblacklist == 1) {
207
			$apiResult = file_get_contents("https://en.wikipedia.org/w/api.php?action=titleblacklist&tbtitle=" . urlencode($this->request->getName()) . "&tbaction=new-account&tbnooverride&format=php");
208
209
			$data = unserialize($apiResult);
210
211
			$requestIsOk = $data['titleblacklist']['result'] == "ok";
212
213
			if (!$requestIsOk) {
214
				$this->request->setStatus("Flagged users");
215
			}
216
		}
217
	}
218
219
	private function userExists()
220
	{
221
		global $mediawikiWebServiceEndpoint;
222
223
		$userexist = file_get_contents($mediawikiWebServiceEndpoint . "?action=query&list=users&ususers=" . urlencode($this->request->getName()) . "&format=php");
224
		$ue = unserialize($userexist);
225
		if (!isset ($ue['query']['users']['0']['missing']) && isset ($ue['query']['users']['0']['userid'])) {
226
			return true;
227
		}
228
229
		return false;
230
	}
231
232
	private function userSulExists()
233
	{
234
		global $mediawikiWebServiceEndpoint;
235
236
		$reqname = str_replace("_", " ", $this->request->getName());
237
		$userexist = file_get_contents($mediawikiWebServiceEndpoint . "?action=query&meta=globaluserinfo&guiuser=" . urlencode($reqname) . "&format=php");
238
		$ue = unserialize($userexist);
239
		if (isset ($ue['query']['globaluserinfo']['id'])) {
240
			return true;
241
		}
242
243
		return false;
244
	}
245
246
	private function nameRequestExists()
247
	{
248
		$query = "SELECT COUNT(id) FROM request WHERE status != 'Closed' AND name = :name;";
249
		$statement = $this->database->prepare($query);
250
		$statement->execute(array(':name' => $this->request->getName()));
251
252
		if (!$statement) {
253
			return false;
254
		}
255
256
		return $statement->fetchColumn() > 0;
257
	}
258
}
259