1
|
|
|
<?php |
2
|
|
|
/****************************************************************************** |
3
|
|
|
* Wikipedia Account Creation Assistance tool * |
4
|
|
|
* * |
5
|
|
|
* All code in this file is released into the public domain by the ACC * |
6
|
|
|
* Development Team. Please see team.json for a list of contributors. * |
7
|
|
|
******************************************************************************/ |
8
|
|
|
|
9
|
|
|
namespace Waca; |
10
|
|
|
|
11
|
|
|
use PDO; |
12
|
|
|
|
13
|
|
|
use Waca\Exceptions\CurlException; |
14
|
|
|
use Waca\Exceptions\EnvironmentException; |
15
|
|
|
use Waca\Helpers\HttpHelper; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Class IdentificationVerifier |
19
|
|
|
* |
20
|
|
|
* Handles automatically verifying if users are identified with the Wikimedia Foundation or not. Intended to be used |
21
|
|
|
* as necessary by the User class when a user's "forceidentified" attribute is NULL. |
22
|
|
|
* |
23
|
|
|
* @package Waca |
24
|
|
|
* @author Andrew "FastLizard4" Adams |
25
|
|
|
* @category Security-Critical |
26
|
|
|
*/ |
27
|
|
|
class IdentificationVerifier |
28
|
|
|
{ |
29
|
|
|
/** |
30
|
|
|
* This field is an array of parameters, in key => value format, that should be appended to the Meta Wikimedia |
31
|
|
|
* Web Service Endpoint URL to query if a user is listed on the Identification Noticeboard. Note that URL encoding |
32
|
|
|
* of these values is *not* necessary; this is done automatically. |
33
|
|
|
* |
34
|
|
|
* @var string[] |
35
|
|
|
* @category Security-Critical |
36
|
|
|
*/ |
37
|
|
|
private static $apiQueryParameters = array( |
38
|
|
|
'action' => 'query', |
39
|
|
|
'format' => 'json', |
40
|
|
|
'prop' => 'links', |
41
|
|
|
'titles' => 'Access to nonpublic information policy/Noticeboard', |
42
|
|
|
// Username of the user to be checked, with User: prefix, goes here! Set in isIdentifiedOnWiki() |
43
|
|
|
'pltitles' => '', |
44
|
|
|
); |
45
|
|
|
/** @var HttpHelper */ |
46
|
|
|
private $httpHelper; |
47
|
|
|
/** @var SiteConfiguration */ |
48
|
|
|
private $siteConfiguration; |
49
|
|
|
/** @var PdoDatabase */ |
50
|
|
|
private $dbObject; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* IdentificationVerifier constructor. |
54
|
|
|
* |
55
|
|
|
* @param HttpHelper $httpHelper |
56
|
|
|
* @param SiteConfiguration $siteConfiguration |
57
|
|
|
* @param PdoDatabase $dbObject |
58
|
|
|
*/ |
59
|
1 |
|
public function __construct(HttpHelper $httpHelper, SiteConfiguration $siteConfiguration, PdoDatabase $dbObject) |
60
|
|
|
{ |
61
|
1 |
|
$this->httpHelper = $httpHelper; |
62
|
1 |
|
$this->siteConfiguration = $siteConfiguration; |
63
|
1 |
|
$this->dbObject = $dbObject; |
64
|
1 |
|
} |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* Checks if the given user is identified to the Wikimedia Foundation. |
68
|
|
|
* |
69
|
|
|
* @param string $onWikiName The Wikipedia username of the user |
70
|
|
|
* |
71
|
|
|
* @return bool |
72
|
|
|
* @category Security-Critical |
73
|
|
|
*/ |
74
|
|
|
public function isUserIdentified($onWikiName) |
75
|
|
|
{ |
76
|
|
|
if ($this->checkIdentificationCache($onWikiName)) { |
77
|
|
|
return true; |
78
|
|
|
} |
79
|
|
|
else { |
80
|
|
|
if ($this->isIdentifiedOnWiki($onWikiName)) { |
81
|
|
|
$this->cacheIdentificationStatus($onWikiName); |
82
|
|
|
|
83
|
|
|
return true; |
84
|
|
|
} |
85
|
|
|
else { |
86
|
|
|
return false; |
87
|
|
|
} |
88
|
|
|
} |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Checks if the given user has a valid entry in the idcache table. |
93
|
|
|
* |
94
|
|
|
* @param string $onWikiName The Wikipedia username of the user |
95
|
|
|
* |
96
|
|
|
* @return bool |
97
|
|
|
* @category Security-Critical |
98
|
|
|
*/ |
99
|
|
|
private function checkIdentificationCache($onWikiName) |
100
|
|
|
{ |
101
|
|
|
$interval = $this->siteConfiguration->getIdentificationCacheExpiry(); |
102
|
|
|
|
103
|
|
|
$query = <<<SQL |
104
|
|
|
SELECT COUNT(`id`) |
105
|
|
|
FROM `idcache` |
106
|
|
|
WHERE `onwikiusername` = :onwikiname |
107
|
|
|
AND DATE_ADD(`checktime`, INTERVAL {$interval}) >= NOW(); |
108
|
|
|
SQL; |
109
|
|
|
$stmt = $this->dbObject->prepare($query); |
110
|
|
|
$stmt->bindValue(':onwikiname', $onWikiName, PDO::PARAM_STR); |
111
|
|
|
$stmt->execute(); |
112
|
|
|
|
113
|
|
|
// Guaranteed by the query to only return a single row with a single column |
114
|
|
|
$results = $stmt->fetch(PDO::FETCH_NUM); |
115
|
|
|
|
116
|
|
|
// I don't expect this to ever be a value other than 0 or 1 since the `onwikiusername` column is declared as a |
117
|
|
|
// unique key - but meh. |
118
|
|
|
return $results[0] != 0; |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
/** |
122
|
|
|
* Does pretty much exactly what it says on the label - this method will clear all expired idcache entries from the |
123
|
|
|
* idcache table. Meant to be called periodically by a maintenance script. |
124
|
|
|
* |
125
|
|
|
* @param SiteConfiguration $siteConfiguration |
126
|
|
|
* @param PdoDatabase $dbObject |
127
|
|
|
* |
128
|
|
|
* @return void |
129
|
|
|
*/ |
130
|
|
|
public static function clearExpiredCacheEntries(SiteConfiguration $siteConfiguration, PdoDatabase $dbObject) |
131
|
|
|
{ |
132
|
|
|
$interval = $siteConfiguration->getIdentificationCacheExpiry(); |
133
|
|
|
|
134
|
|
|
$query = <<<SQL |
135
|
|
|
DELETE FROM `idcache` |
136
|
|
|
WHERE DATE_ADD(`checktime`, INTERVAL {$interval}) < NOW(); |
137
|
|
|
SQL; |
138
|
|
|
$dbObject->prepare($query)->execute(); |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* This method will add an entry to the idcache that the given Wikipedia user has been verified as identified. This |
143
|
|
|
* is so we don't have to hit the API every single time we check. The cache entry is valid for as long as specified |
144
|
|
|
* in the ACC configuration (validity enforced by checkIdentificationCache() and clearExpiredCacheEntries()). |
145
|
|
|
* |
146
|
|
|
* @param string $onWikiName The Wikipedia username of the user |
147
|
|
|
* |
148
|
|
|
* @return void |
149
|
|
|
* @category Security-Critical |
150
|
|
|
*/ |
151
|
|
|
private function cacheIdentificationStatus($onWikiName) |
152
|
|
|
{ |
153
|
|
|
$query = <<<SQL |
154
|
|
|
INSERT INTO `idcache` |
155
|
|
|
(`onwikiusername`) |
156
|
|
|
VALUES |
157
|
|
|
(:onwikiname) |
158
|
|
|
ON DUPLICATE KEY UPDATE |
159
|
|
|
`onwikiusername` = VALUES(`onwikiusername`), |
160
|
|
|
`checktime` = CURRENT_TIMESTAMP; |
161
|
|
|
SQL; |
162
|
|
|
$stmt = $this->dbObject->prepare($query); |
163
|
|
|
$stmt->bindValue(':onwikiname', $onWikiName, PDO::PARAM_STR); |
164
|
|
|
$stmt->execute(); |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* Queries the Wikimedia API to determine if the specified user is listed on the identification noticeboard. |
169
|
|
|
* |
170
|
|
|
* @param string $onWikiName The Wikipedia username of the user |
171
|
|
|
* |
172
|
|
|
* @return bool |
173
|
|
|
* @throws EnvironmentException |
174
|
|
|
* @category Security-Critical |
175
|
|
|
*/ |
176
|
1 |
|
private function isIdentifiedOnWiki($onWikiName) |
177
|
|
|
{ |
178
|
1 |
|
$strings = new StringFunctions(); |
179
|
|
|
|
180
|
|
|
// First character of Wikipedia usernames is always capitalized. |
181
|
1 |
|
$onWikiName = $strings->ucfirst($onWikiName); |
182
|
|
|
|
183
|
1 |
|
$parameters = self::$apiQueryParameters; |
184
|
1 |
|
$parameters['pltitles'] = "User:" . $onWikiName; |
185
|
|
|
|
186
|
|
|
try { |
187
|
1 |
|
$endpoint = $this->siteConfiguration->getMetaWikimediaWebServiceEndpoint(); |
188
|
1 |
|
$response = $this->httpHelper->get($endpoint, $parameters); |
189
|
1 |
|
$response = json_decode($response, true); |
190
|
1 |
|
} catch (CurlException $ex) { |
191
|
|
|
// failed getting identification status, so throw a nicer error. |
192
|
|
|
$m = 'Could not contact metawiki API to determine user\' identification status. ' |
193
|
|
|
. 'This is probably a transient error, so please try again.'; |
194
|
|
|
|
195
|
|
|
throw new EnvironmentException($m, 0, $ex); |
|
|
|
|
196
|
|
|
} |
197
|
|
|
|
198
|
1 |
|
$page = @array_pop($response['query']['pages']); |
199
|
|
|
|
200
|
1 |
|
return @$page['links'][0]['title'] === "User:" . $onWikiName; |
201
|
|
|
} |
202
|
|
|
} |
203
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.