stwalkerster /
waca
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 |
||
|
0 ignored issues
–
show
Coding Style
Best Practice
introduced
by
Loading history...
|
|||
| 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 |
||
|
0 ignored issues
–
show
|
|||
| 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) { |
|
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 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 |
||
|
0 ignored issues
–
show
|
|||
| 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 |
||
|
0 ignored issues
–
show
|
|||
| 101 | if (false) { |
||
|
0 ignored issues
–
show
|
|||
| 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()) == "") { |
|
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 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()) != "") { |
|
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 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) { |
|
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 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! |
||
|
0 ignored issues
–
show
|
|||
| 158 | /** @var $xffTrustProvider IXffTrustProvider */ |
||
| 159 | global $xffTrustProvider; |
||
|
0 ignored issues
–
show
Compatibility
Best Practice
introduced
by
Use of
global functionality is not recommended; it makes your code harder to test, and less reusable.
Instead of relying on 1. Pass all data via parametersfunction myFunction($a, $b) {
// Do something
}
2. Create a class that maintains your stateclass MyClass {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
public function myFunction() {
// Do something
}
}
Loading history...
|
|||
| 160 | |||
| 161 | $errorList = array(); |
||
| 162 | |||
| 163 | // ERRORS |
||
| 164 | |||
| 165 | // TOR nodes |
||
| 166 | // TODO: Implement |
||
|
0 ignored issues
–
show
|
|||
| 167 | if (false) { |
||
|
0 ignored issues
–
show
|
|||
| 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? |
||
|
0 ignored issues
–
show
|
|||
| 200 | } |
||
| 201 | } |
||
| 202 | |||
| 203 | private function checkTitleBlacklist() |
||
| 204 | { |
||
| 205 | global $enableTitleblacklist; |
||
|
0 ignored issues
–
show
Compatibility
Best Practice
introduced
by
Use of
global functionality is not recommended; it makes your code harder to test, and less reusable.
Instead of relying on 1. Pass all data via parametersfunction myFunction($a, $b) {
// Do something
}
2. Create a class that maintains your stateclass MyClass {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
public function myFunction() {
// Do something
}
}
Loading history...
|
|||
| 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"); |
||
|
0 ignored issues
–
show
|
|||
| 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; |
||
|
0 ignored issues
–
show
Compatibility
Best Practice
introduced
by
Use of
global functionality is not recommended; it makes your code harder to test, and less reusable.
Instead of relying on 1. Pass all data via parametersfunction myFunction($a, $b) {
// Do something
}
2. Create a class that maintains your stateclass MyClass {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
public function myFunction() {
// Do something
}
}
Loading history...
|
|||
| 222 | |||
| 223 | $userexist = file_get_contents($mediawikiWebServiceEndpoint . "?action=query&list=users&ususers=" . urlencode($this->request->getName()) . "&format=php"); |
||
|
0 ignored issues
–
show
|
|||
| 224 | $ue = unserialize($userexist); |
||
| 225 | if (!isset ($ue['query']['users']['0']['missing']) && isset ($ue['query']['users']['0']['userid'])) { |
||
|
0 ignored issues
–
show
|
|||
| 226 | return true; |
||
| 227 | } |
||
| 228 | |||
| 229 | return false; |
||
| 230 | } |
||
| 231 | |||
| 232 | private function userSulExists() |
||
| 233 | { |
||
| 234 | global $mediawikiWebServiceEndpoint; |
||
|
0 ignored issues
–
show
Compatibility
Best Practice
introduced
by
Use of
global functionality is not recommended; it makes your code harder to test, and less reusable.
Instead of relying on 1. Pass all data via parametersfunction myFunction($a, $b) {
// Do something
}
2. Create a class that maintains your stateclass MyClass {
private $a;
private $b;
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
public function myFunction() {
// Do something
}
}
Loading history...
|
|||
| 235 | |||
| 236 | $reqname = str_replace("_", " ", $this->request->getName()); |
||
| 237 | $userexist = file_get_contents($mediawikiWebServiceEndpoint . "?action=query&meta=globaluserinfo&guiuser=" . urlencode($reqname) . "&format=php"); |
||
|
0 ignored issues
–
show
|
|||
| 238 | $ue = unserialize($userexist); |
||
| 239 | if (isset ($ue['query']['globaluserinfo']['id'])) { |
||
|
0 ignored issues
–
show
|
|||
| 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 |