@@ -27,174 +27,174 @@ |
||
| 27 | 27 | */ |
| 28 | 28 | class IdentificationVerifier implements IIdentificationVerifier |
| 29 | 29 | { |
| 30 | - /** |
|
| 31 | - * This field is an array of parameters, in key => value format, that should be appended to the Meta Wikimedia |
|
| 32 | - * Web Service Endpoint URL to query if a user is listed on the Identification Noticeboard. Note that URL encoding |
|
| 33 | - * of these values is *not* necessary; this is done automatically. |
|
| 34 | - * |
|
| 35 | - * @var string[] |
|
| 36 | - * @category Security-Critical |
|
| 37 | - */ |
|
| 38 | - private static $apiQueryParameters = array( |
|
| 39 | - 'action' => 'query', |
|
| 40 | - 'format' => 'json', |
|
| 41 | - 'prop' => 'links', |
|
| 42 | - // Populated from SiteConfiguration->getIdentificationNoticeboardPage |
|
| 43 | - 'titles' => '', |
|
| 44 | - // Username of the user to be checked, with User: prefix, goes here! Set in isIdentifiedOnWiki() |
|
| 45 | - 'pltitles' => '', |
|
| 46 | - ); |
|
| 47 | - |
|
| 48 | - private HttpHelper $httpHelper; |
|
| 49 | - private SiteConfiguration $siteConfiguration; |
|
| 50 | - private PdoDatabase $dbObject; |
|
| 51 | - |
|
| 52 | - /** |
|
| 53 | - * IdentificationVerifier constructor. |
|
| 54 | - * |
|
| 55 | - * @param HttpHelper $httpHelper |
|
| 56 | - * @param SiteConfiguration $siteConfiguration |
|
| 57 | - * @param PdoDatabase $dbObject |
|
| 58 | - */ |
|
| 59 | - public function __construct(HttpHelper $httpHelper, SiteConfiguration $siteConfiguration, PdoDatabase $dbObject) |
|
| 60 | - { |
|
| 61 | - $this->httpHelper = $httpHelper; |
|
| 62 | - $this->siteConfiguration = $siteConfiguration; |
|
| 63 | - $this->dbObject = $dbObject; |
|
| 64 | - } |
|
| 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 | - * @category Security-Critical |
|
| 72 | - * @throws EnvironmentException |
|
| 73 | - */ |
|
| 74 | - public function isUserIdentified(?string $onWikiName): bool |
|
| 75 | - { |
|
| 76 | - if ($onWikiName === null || $onWikiName === '') { |
|
| 77 | - return false; |
|
| 78 | - } |
|
| 79 | - |
|
| 80 | - if ($this->checkIdentificationCache($onWikiName)) { |
|
| 81 | - return true; |
|
| 82 | - } |
|
| 83 | - else { |
|
| 84 | - if ($this->isIdentifiedOnWiki($onWikiName)) { |
|
| 85 | - $this->cacheIdentificationStatus($onWikiName); |
|
| 86 | - |
|
| 87 | - return true; |
|
| 88 | - } |
|
| 89 | - else { |
|
| 90 | - return false; |
|
| 91 | - } |
|
| 92 | - } |
|
| 93 | - } |
|
| 94 | - |
|
| 95 | - /** |
|
| 96 | - * Checks if the given user has a valid entry in the idcache table. |
|
| 97 | - * |
|
| 98 | - * @param string $onWikiName The Wikipedia username of the user |
|
| 99 | - * |
|
| 100 | - * @category Security-Critical |
|
| 101 | - */ |
|
| 102 | - private function checkIdentificationCache(string $onWikiName): bool |
|
| 103 | - { |
|
| 104 | - $interval = $this->siteConfiguration->getIdentificationCacheExpiry(); |
|
| 105 | - |
|
| 106 | - $query = <<<SQL |
|
| 30 | + /** |
|
| 31 | + * This field is an array of parameters, in key => value format, that should be appended to the Meta Wikimedia |
|
| 32 | + * Web Service Endpoint URL to query if a user is listed on the Identification Noticeboard. Note that URL encoding |
|
| 33 | + * of these values is *not* necessary; this is done automatically. |
|
| 34 | + * |
|
| 35 | + * @var string[] |
|
| 36 | + * @category Security-Critical |
|
| 37 | + */ |
|
| 38 | + private static $apiQueryParameters = array( |
|
| 39 | + 'action' => 'query', |
|
| 40 | + 'format' => 'json', |
|
| 41 | + 'prop' => 'links', |
|
| 42 | + // Populated from SiteConfiguration->getIdentificationNoticeboardPage |
|
| 43 | + 'titles' => '', |
|
| 44 | + // Username of the user to be checked, with User: prefix, goes here! Set in isIdentifiedOnWiki() |
|
| 45 | + 'pltitles' => '', |
|
| 46 | + ); |
|
| 47 | + |
|
| 48 | + private HttpHelper $httpHelper; |
|
| 49 | + private SiteConfiguration $siteConfiguration; |
|
| 50 | + private PdoDatabase $dbObject; |
|
| 51 | + |
|
| 52 | + /** |
|
| 53 | + * IdentificationVerifier constructor. |
|
| 54 | + * |
|
| 55 | + * @param HttpHelper $httpHelper |
|
| 56 | + * @param SiteConfiguration $siteConfiguration |
|
| 57 | + * @param PdoDatabase $dbObject |
|
| 58 | + */ |
|
| 59 | + public function __construct(HttpHelper $httpHelper, SiteConfiguration $siteConfiguration, PdoDatabase $dbObject) |
|
| 60 | + { |
|
| 61 | + $this->httpHelper = $httpHelper; |
|
| 62 | + $this->siteConfiguration = $siteConfiguration; |
|
| 63 | + $this->dbObject = $dbObject; |
|
| 64 | + } |
|
| 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 | + * @category Security-Critical |
|
| 72 | + * @throws EnvironmentException |
|
| 73 | + */ |
|
| 74 | + public function isUserIdentified(?string $onWikiName): bool |
|
| 75 | + { |
|
| 76 | + if ($onWikiName === null || $onWikiName === '') { |
|
| 77 | + return false; |
|
| 78 | + } |
|
| 79 | + |
|
| 80 | + if ($this->checkIdentificationCache($onWikiName)) { |
|
| 81 | + return true; |
|
| 82 | + } |
|
| 83 | + else { |
|
| 84 | + if ($this->isIdentifiedOnWiki($onWikiName)) { |
|
| 85 | + $this->cacheIdentificationStatus($onWikiName); |
|
| 86 | + |
|
| 87 | + return true; |
|
| 88 | + } |
|
| 89 | + else { |
|
| 90 | + return false; |
|
| 91 | + } |
|
| 92 | + } |
|
| 93 | + } |
|
| 94 | + |
|
| 95 | + /** |
|
| 96 | + * Checks if the given user has a valid entry in the idcache table. |
|
| 97 | + * |
|
| 98 | + * @param string $onWikiName The Wikipedia username of the user |
|
| 99 | + * |
|
| 100 | + * @category Security-Critical |
|
| 101 | + */ |
|
| 102 | + private function checkIdentificationCache(string $onWikiName): bool |
|
| 103 | + { |
|
| 104 | + $interval = $this->siteConfiguration->getIdentificationCacheExpiry(); |
|
| 105 | + |
|
| 106 | + $query = <<<SQL |
|
| 107 | 107 | SELECT COUNT(`id`) |
| 108 | 108 | FROM `idcache` |
| 109 | 109 | WHERE `onwikiusername` = :onwikiname |
| 110 | 110 | AND DATE_ADD(`checktime`, INTERVAL {$interval}) >= NOW(); |
| 111 | 111 | SQL; |
| 112 | - $stmt = $this->dbObject->prepare($query); |
|
| 113 | - $stmt->bindValue(':onwikiname', $onWikiName, PDO::PARAM_STR); |
|
| 114 | - $stmt->execute(); |
|
| 115 | - |
|
| 116 | - // Guaranteed by the query to only return a single row with a single column |
|
| 117 | - $results = $stmt->fetch(PDO::FETCH_NUM); |
|
| 118 | - |
|
| 119 | - // I don't expect this to ever be a value other than 0 or 1 since the `onwikiusername` column is declared as a |
|
| 120 | - // unique key - but meh. |
|
| 121 | - return $results[0] != 0; |
|
| 122 | - } |
|
| 123 | - |
|
| 124 | - /** |
|
| 125 | - * Does pretty much exactly what it says on the label - this method will clear all expired idcache entries from the |
|
| 126 | - * idcache table. Meant to be called periodically by a maintenance script. |
|
| 127 | - * |
|
| 128 | - * @param SiteConfiguration $siteConfiguration |
|
| 129 | - * @param PdoDatabase $dbObject |
|
| 130 | - * |
|
| 131 | - * @return void |
|
| 132 | - */ |
|
| 133 | - public static function clearExpiredCacheEntries(SiteConfiguration $siteConfiguration, PdoDatabase $dbObject) |
|
| 134 | - { |
|
| 135 | - $interval = $siteConfiguration->getIdentificationCacheExpiry(); |
|
| 136 | - |
|
| 137 | - $query = "DELETE FROM idcache WHERE DATE_ADD(checktime, INTERVAL {$interval}) < NOW();"; |
|
| 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 | - * @category Security-Critical |
|
| 149 | - */ |
|
| 150 | - private function cacheIdentificationStatus(string $onWikiName): void |
|
| 151 | - { |
|
| 152 | - $query = <<<SQL |
|
| 112 | + $stmt = $this->dbObject->prepare($query); |
|
| 113 | + $stmt->bindValue(':onwikiname', $onWikiName, PDO::PARAM_STR); |
|
| 114 | + $stmt->execute(); |
|
| 115 | + |
|
| 116 | + // Guaranteed by the query to only return a single row with a single column |
|
| 117 | + $results = $stmt->fetch(PDO::FETCH_NUM); |
|
| 118 | + |
|
| 119 | + // I don't expect this to ever be a value other than 0 or 1 since the `onwikiusername` column is declared as a |
|
| 120 | + // unique key - but meh. |
|
| 121 | + return $results[0] != 0; |
|
| 122 | + } |
|
| 123 | + |
|
| 124 | + /** |
|
| 125 | + * Does pretty much exactly what it says on the label - this method will clear all expired idcache entries from the |
|
| 126 | + * idcache table. Meant to be called periodically by a maintenance script. |
|
| 127 | + * |
|
| 128 | + * @param SiteConfiguration $siteConfiguration |
|
| 129 | + * @param PdoDatabase $dbObject |
|
| 130 | + * |
|
| 131 | + * @return void |
|
| 132 | + */ |
|
| 133 | + public static function clearExpiredCacheEntries(SiteConfiguration $siteConfiguration, PdoDatabase $dbObject) |
|
| 134 | + { |
|
| 135 | + $interval = $siteConfiguration->getIdentificationCacheExpiry(); |
|
| 136 | + |
|
| 137 | + $query = "DELETE FROM idcache WHERE DATE_ADD(checktime, INTERVAL {$interval}) < NOW();"; |
|
| 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 | + * @category Security-Critical |
|
| 149 | + */ |
|
| 150 | + private function cacheIdentificationStatus(string $onWikiName): void |
|
| 151 | + { |
|
| 152 | + $query = <<<SQL |
|
| 153 | 153 | INSERT INTO idcache (onwikiusername) |
| 154 | 154 | VALUES (:onwikiname) |
| 155 | 155 | ON DUPLICATE KEY UPDATE |
| 156 | 156 | onwikiusername = VALUES(onwikiusername), |
| 157 | 157 | checktime = CURRENT_TIMESTAMP; |
| 158 | 158 | SQL; |
| 159 | - $stmt = $this->dbObject->prepare($query); |
|
| 160 | - $stmt->bindValue(':onwikiname', $onWikiName, PDO::PARAM_STR); |
|
| 161 | - $stmt->execute(); |
|
| 162 | - } |
|
| 163 | - |
|
| 164 | - /** |
|
| 165 | - * Queries the Wikimedia API to determine if the specified user is listed on the identification noticeboard. |
|
| 166 | - * |
|
| 167 | - * @param string $onWikiName The Wikipedia username of the user |
|
| 168 | - * |
|
| 169 | - * @throws EnvironmentException |
|
| 170 | - * @category Security-Critical |
|
| 171 | - */ |
|
| 172 | - private function isIdentifiedOnWiki(string $onWikiName): bool |
|
| 173 | - { |
|
| 174 | - $strings = new StringFunctions(); |
|
| 175 | - |
|
| 176 | - // First character of Wikipedia usernames is always capitalized. |
|
| 177 | - $onWikiName = $strings->upperCaseFirst($onWikiName); |
|
| 178 | - |
|
| 179 | - $parameters = self::$apiQueryParameters; |
|
| 180 | - $parameters['pltitles'] = 'User:' . $onWikiName; |
|
| 181 | - $parameters['titles'] = $this->siteConfiguration->getIdentificationNoticeboardPage(); |
|
| 182 | - |
|
| 183 | - try { |
|
| 184 | - $endpoint = $this->siteConfiguration->getIdentificationNoticeboardWebserviceEndpoint(); |
|
| 185 | - $response = $this->httpHelper->get($endpoint, $parameters); |
|
| 186 | - $response = json_decode($response, true); |
|
| 187 | - } |
|
| 188 | - catch (CurlException $ex) { |
|
| 189 | - // failed getting identification status, so throw a nicer error. |
|
| 190 | - $message = 'Could not contact metawiki API to determine user\' identification status. ' |
|
| 191 | - . 'This is probably a transient error, so please try again.'; |
|
| 192 | - |
|
| 193 | - throw new EnvironmentException($message); |
|
| 194 | - } |
|
| 195 | - |
|
| 196 | - $page = @array_pop($response['query']['pages']); |
|
| 197 | - |
|
| 198 | - return @$page['links'][0]['title'] === 'User:' . $onWikiName; |
|
| 199 | - } |
|
| 159 | + $stmt = $this->dbObject->prepare($query); |
|
| 160 | + $stmt->bindValue(':onwikiname', $onWikiName, PDO::PARAM_STR); |
|
| 161 | + $stmt->execute(); |
|
| 162 | + } |
|
| 163 | + |
|
| 164 | + /** |
|
| 165 | + * Queries the Wikimedia API to determine if the specified user is listed on the identification noticeboard. |
|
| 166 | + * |
|
| 167 | + * @param string $onWikiName The Wikipedia username of the user |
|
| 168 | + * |
|
| 169 | + * @throws EnvironmentException |
|
| 170 | + * @category Security-Critical |
|
| 171 | + */ |
|
| 172 | + private function isIdentifiedOnWiki(string $onWikiName): bool |
|
| 173 | + { |
|
| 174 | + $strings = new StringFunctions(); |
|
| 175 | + |
|
| 176 | + // First character of Wikipedia usernames is always capitalized. |
|
| 177 | + $onWikiName = $strings->upperCaseFirst($onWikiName); |
|
| 178 | + |
|
| 179 | + $parameters = self::$apiQueryParameters; |
|
| 180 | + $parameters['pltitles'] = 'User:' . $onWikiName; |
|
| 181 | + $parameters['titles'] = $this->siteConfiguration->getIdentificationNoticeboardPage(); |
|
| 182 | + |
|
| 183 | + try { |
|
| 184 | + $endpoint = $this->siteConfiguration->getIdentificationNoticeboardWebserviceEndpoint(); |
|
| 185 | + $response = $this->httpHelper->get($endpoint, $parameters); |
|
| 186 | + $response = json_decode($response, true); |
|
| 187 | + } |
|
| 188 | + catch (CurlException $ex) { |
|
| 189 | + // failed getting identification status, so throw a nicer error. |
|
| 190 | + $message = 'Could not contact metawiki API to determine user\' identification status. ' |
|
| 191 | + . 'This is probably a transient error, so please try again.'; |
|
| 192 | + |
|
| 193 | + throw new EnvironmentException($message); |
|
| 194 | + } |
|
| 195 | + |
|
| 196 | + $page = @array_pop($response['query']['pages']); |
|
| 197 | + |
|
| 198 | + return @$page['links'][0]['title'] === 'User:' . $onWikiName; |
|
| 199 | + } |
|
| 200 | 200 | } |
@@ -79,14 +79,12 @@ |
||
| 79 | 79 | |
| 80 | 80 | if ($this->checkIdentificationCache($onWikiName)) { |
| 81 | 81 | return true; |
| 82 | - } |
|
| 83 | - else { |
|
| 82 | + } else { |
|
| 84 | 83 | if ($this->isIdentifiedOnWiki($onWikiName)) { |
| 85 | 84 | $this->cacheIdentificationStatus($onWikiName); |
| 86 | 85 | |
| 87 | 86 | return true; |
| 88 | - } |
|
| 89 | - else { |
|
| 87 | + } else { |
|
| 90 | 88 | return false; |
| 91 | 89 | } |
| 92 | 90 | } |
@@ -18,14 +18,14 @@ |
||
| 18 | 18 | */ |
| 19 | 19 | interface IIdentificationVerifier |
| 20 | 20 | { |
| 21 | - /** |
|
| 22 | - * Checks if the given user is identified to the Wikimedia Foundation. |
|
| 23 | - * |
|
| 24 | - * @param ?string $onWikiName The Wikipedia username of the user |
|
| 25 | - * |
|
| 26 | - * @return bool |
|
| 27 | - * @throws EnvironmentException |
|
| 28 | - * @category Security-Critical |
|
| 29 | - */ |
|
| 30 | - public function isUserIdentified(?string $onWikiName): bool; |
|
| 21 | + /** |
|
| 22 | + * Checks if the given user is identified to the Wikimedia Foundation. |
|
| 23 | + * |
|
| 24 | + * @param ?string $onWikiName The Wikipedia username of the user |
|
| 25 | + * |
|
| 26 | + * @return bool |
|
| 27 | + * @throws EnvironmentException |
|
| 28 | + * @category Security-Critical |
|
| 29 | + */ |
|
| 30 | + public function isUserIdentified(?string $onWikiName): bool; |
|
| 31 | 31 | } |
| 32 | 32 | \ No newline at end of file |