This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /* zKillboard |
||
3 | * Copyright (C) 2012-2015 EVE-KILL Team and EVSCO. |
||
4 | * |
||
5 | * This program is free software: you can redistribute it and/or modify |
||
6 | * it under the terms of the GNU Affero General Public License as published by |
||
7 | * the Free Software Foundation, either version 3 of the License, or |
||
8 | * (at your option) any later version. |
||
9 | * |
||
10 | * This program is distributed in the hope that it will be useful, |
||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
13 | * GNU Affero General Public License for more details. |
||
14 | * |
||
15 | * You should have received a copy of the GNU Affero General Public License |
||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
17 | */ |
||
18 | |||
19 | /** |
||
20 | * Various API helper functions for the website |
||
21 | */ |
||
22 | class Api |
||
23 | { |
||
24 | |||
25 | /** |
||
26 | * Checks a key for validity and KillLog access. |
||
27 | * |
||
28 | * @static |
||
29 | * @param $keyID int The keyID to be checked. |
||
30 | * @param $vCode string The vCode to be checked |
||
31 | * @return string A message, Success on success, otherwise an error. |
||
32 | */ |
||
33 | public static function checkAPI($keyID, $vCode) |
||
34 | { |
||
35 | $keyID = trim($keyID); |
||
36 | $vCode = trim($vCode); |
||
37 | if ($keyID == "" || $vCode == "") |
||
38 | return "Error, no keyID and/or vCode"; |
||
39 | $keyID = (int)$keyID; |
||
40 | if ($keyID == 0) { |
||
41 | return "Invalid keyID. Did you get the keyID and vCode mixed up?"; |
||
42 | } |
||
43 | |||
44 | $pheal = Util::getPheal($keyID, $vCode); |
||
45 | try |
||
46 | { |
||
47 | $result = $pheal->accountScope->APIKeyInfo(); |
||
48 | } |
||
49 | catch (Exception $e) |
||
50 | { |
||
51 | if (strlen($keyID) > 20) |
||
52 | return "Error, you might have mistaken keyid for the vcode"; |
||
53 | return "Error: " . $e->getCode() . " Message: " . $e->getMessage(); |
||
54 | } |
||
55 | |||
56 | $key = $result->key; |
||
57 | $accessMask = $key->accessMask; |
||
58 | $hasBits = self::hasBits($accessMask); |
||
59 | |||
60 | if (!$hasBits) { |
||
61 | return "Error, key does not have access to killlog, please modify key to add killlog access"; |
||
62 | } |
||
63 | return "success"; |
||
64 | } |
||
65 | |||
66 | /** |
||
67 | * Adds a key to the database. |
||
68 | * |
||
69 | * @static |
||
70 | * @param int $keyID |
||
71 | * @param string $vCode |
||
72 | * @param null|string $label |
||
73 | * @return string |
||
74 | */ |
||
75 | public static function addKey($keyID, $vCode, $label = null) |
||
76 | { |
||
77 | $userID = User::getUserID(); |
||
78 | if ($userID == null) $userID = 0; |
||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||
79 | |||
80 | $exists = Db::queryRow("SELECT userID, keyID, vCode FROM zz_api WHERE keyID = :keyID AND vCode = :vCode", array(":keyID" => $keyID, ":vCode" => $vCode), 0); |
||
81 | if ($exists == null) { |
||
82 | // Insert the api key |
||
83 | Db::execute("replace into zz_api (userID, keyID, vCode, label) VALUES (:userID, :keyID, :vCode, :label)", array(":userID" => $userID, ":keyID" => $keyID, ":vCode" => $vCode, ":label" => $label)); |
||
84 | } else if ($exists["userID"] == 0) { |
||
85 | // Someone already gave us this key anonymously, give it to this user |
||
86 | Db::execute("UPDATE zz_api SET userID = :userID, label = :label WHERE keyID = :keyID", array(":userID" => $userID, ":label" => $label, ":keyID" => $keyID)); |
||
87 | return "keyID $keyID previously existed in our database but has now been assigned to you."; |
||
88 | } else { |
||
89 | return "keyID $keyID is already in the database..."; |
||
90 | } |
||
91 | |||
92 | $pheal = Util::getPheal($keyID, $vCode); |
||
93 | $result = $pheal->accountScope->APIKeyInfo(); |
||
94 | $key = $result->key; |
||
95 | $keyType = $key->type; |
||
96 | |||
97 | if ($keyType == "Account") $keyType = "Character"; |
||
98 | |||
99 | $ip = IP::get(); |
||
100 | |||
101 | Log::log("API: $keyID has been added. Type: $keyType ($ip)"); |
||
102 | return "Success, your $keyType key has been added."; |
||
103 | } |
||
104 | |||
105 | /** |
||
106 | * Deletes a key owned by the currently logged in user. |
||
107 | * |
||
108 | * @static |
||
109 | * @param $keyID int |
||
110 | * @return string |
||
111 | */ |
||
112 | public static function deleteKey($keyID) |
||
113 | { |
||
114 | $userID = user::getUserID(); |
||
115 | Db::execute("DELETE FROM zz_api_characters WHERE keyID = :keyID", array(":keyID" => $keyID)); |
||
116 | Db::execute("DELETE FROM zz_api WHERE userID = :userID AND keyID = :keyID", array(":userID" => $userID, ":keyID" => $keyID)); |
||
117 | return "$keyID has been deleted"; |
||
118 | } |
||
119 | |||
120 | /** |
||
121 | * Returns a list of keys owned by the currently logged in user. |
||
122 | * |
||
123 | * @static |
||
124 | * @param $userID int |
||
125 | * @return array Returns |
||
126 | */ |
||
127 | public static function getKeys($userID) |
||
128 | { |
||
129 | if(!isset($userID)) |
||
130 | $userID = user::getUserID(); |
||
131 | |||
132 | $result = Db::query("SELECT keyID, vCode, label, lastValidation, errorCode FROM zz_api WHERE userID = :userID order by keyID", array(":userID" => $userID), 0); |
||
133 | return $result; |
||
134 | } |
||
135 | |||
136 | /** |
||
137 | * Returns an array of character keys. |
||
138 | * |
||
139 | * @static |
||
140 | * @param $userID int |
||
141 | * @return array Returns |
||
142 | */ |
||
143 | public static function getCharacterKeys($userID) |
||
144 | { |
||
145 | $result = Db::query("select c.* from zz_api_characters c left join zz_api a on (c.keyID = a.keyID) where a.userID = :userID", array(":userID" => $userID), 0); |
||
146 | return $result; |
||
147 | } |
||
148 | |||
149 | /** |
||
150 | * Returns an array of the characters assigned to this user. |
||
151 | * |
||
152 | * @static |
||
153 | * @param $userID int |
||
154 | * @return array |
||
155 | */ |
||
156 | public static function getCharacters($userID) |
||
157 | { |
||
158 | $db = Db::query("SELECT characterID FROM zz_api_characters c left join zz_api a on (c.keyID = a.keyID) where userID = :userID", array(":userID" => $userID), 0); |
||
159 | $results = Info::addInfo($db); |
||
160 | return $results; |
||
161 | } |
||
162 | |||
163 | /** |
||
164 | * Tests the access mask for KillLog access |
||
165 | * |
||
166 | * @static |
||
167 | * @param int $accessMask |
||
168 | * @return bool |
||
169 | */ |
||
170 | public static function hasBits($accessMask) |
||
171 | { |
||
172 | return ((int)($accessMask & 256) > 0); |
||
173 | } |
||
174 | |||
175 | /** |
||
176 | * API exception handling |
||
177 | * |
||
178 | * @static |
||
179 | * @param integer $keyID |
||
180 | * @param int $charID |
||
181 | * @param Exception $exception |
||
182 | * @return void |
||
183 | */ |
||
184 | public static function handleApiException($keyID, $charID, $exception) |
||
185 | { |
||
186 | $code = $exception->getCode(); |
||
187 | $message = $exception->getMessage(); |
||
188 | $clearCharacter = false; |
||
189 | $clearAllCharacters = false; |
||
190 | $clearApiEntry = false; |
||
191 | $updateCacheTime = false; |
||
192 | $demoteCharacter = false; |
||
193 | $cacheUntil = 0; |
||
194 | switch ($code) { |
||
195 | case 28: // Timeouts |
||
196 | case 904: // temp ban from ccp's api server |
||
197 | Db::execute("replace into zz_storage values ('ApiStop904', date_add(now(), interval 5 minute))"); |
||
198 | break; |
||
199 | |||
200 | case 403: |
||
201 | case 502: |
||
202 | case 503: // Service Unavailable - try again later |
||
203 | $cacheUntil = time() + 300; |
||
204 | $updateCacheTime = true; |
||
205 | break; |
||
206 | |||
207 | case 119: // Kills exhausted: retry after [{0}] |
||
208 | $cacheUntil = $exception->cached_until; |
||
0 ignored issues
–
show
The property
cached_until does not seem to exist in Exception .
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name. If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading. ![]() |
|||
209 | $updateCacheTime = true; |
||
210 | break; |
||
211 | |||
212 | case 120: // Expected beforeKillID [{0}] but supplied [{1}]: kills previously loaded. |
||
213 | $cacheUntil = $exception->cached_until; |
||
214 | $updateCacheTime = true; |
||
215 | break; |
||
216 | |||
217 | case 221: // Demote toon, illegal page access |
||
218 | $clearAllCharacters = true; |
||
219 | $clearApiEntry = true; |
||
220 | break; |
||
221 | |||
222 | case 220: |
||
223 | case 200: // Current security level not high enough. |
||
224 | // Typically happens when a key isn't a full API Key |
||
225 | $clearAllCharacters = true; |
||
226 | $clearApiEntry = true; |
||
227 | //$code = 203; // Force it to go away, no point in keeping this key |
||
228 | break; |
||
229 | |||
230 | case 522: |
||
231 | case 201: // Character does not belong to account. |
||
232 | // Typically caused by a character transfer |
||
233 | $clearCharacter = true; |
||
234 | break; |
||
235 | case 207: // Not available for NPC corporations. |
||
236 | case 209: |
||
237 | $demoteCharacter = true; |
||
238 | break; |
||
239 | |||
240 | case 222: // account has expired |
||
241 | $clearAllCharacters = true; |
||
242 | $clearApiEntry = true; |
||
243 | $cacheUntil = time() + (7 * 24 * 3600); // Try again in a week |
||
244 | break; |
||
245 | |||
246 | case 403: |
||
247 | case 211: // Login denied by account status |
||
248 | // Remove characters, will revalidate with next doPopulate |
||
249 | $clearAllCharacters = true; |
||
250 | $clearApiEntry = true; |
||
251 | break; |
||
252 | |||
253 | case 202: // API key authentication failure. |
||
254 | case 203: // Authentication failure - API is no good and will never be good again |
||
255 | case 204: // Authentication failure. |
||
256 | case 205: // Authentication failure (final pass). |
||
257 | case 210: // Authentication failure. |
||
258 | case 521: // Invalid username and/or password passed to UserData.LoginWebUser(). |
||
259 | $clearAllCharacters = true; |
||
260 | $clearApiEntry = true; |
||
261 | break; |
||
262 | |||
263 | case 500: // Internal Server Error (More CCP Issues) |
||
264 | case 520: // Unexpected failure accessing database. (More CCP issues) |
||
265 | case 404: // URL Not Found (CCP having issues...) |
||
266 | case 902: // Eve backend database temporarily disabled |
||
267 | $updateCacheTime = true; |
||
268 | $cacheUntil = time() + 3600; // Try again in an hour... |
||
269 | break; |
||
270 | |||
271 | case 0: // API Date could not be read / parsed, original exception (Something is wrong with the XML and it couldn't be parsed) |
||
272 | default: // try again in 5 minutes |
||
273 | Log::log("$keyID - Unhandled error - Code $code - $message"); |
||
274 | //$updateCacheTime = true; |
||
275 | $clearApiEntry = true; |
||
276 | //$cacheUntil = time() + 300; |
||
277 | break; |
||
278 | } |
||
279 | |||
280 | if ($demoteCharacter && $charID != 0) { |
||
281 | if (false === Db::execute("update zz_api_characters set isDirector = 'F' where characterID = :charID", array(":charID" => $charID), false)) { |
||
282 | $clearCharacter = true; |
||
283 | } |
||
284 | } |
||
285 | |||
286 | if ($clearCharacter && $charID != 0) { |
||
287 | Db::execute("delete from zz_api_characters where keyID = :keyID and characterID = :charID", array(":keyID" => $keyID, ":charID" => $charID)); |
||
288 | } |
||
289 | |||
290 | if ($clearAllCharacters) { |
||
291 | Db::execute("delete from zz_api_characters where keyID = :keyID", array(":keyID" => $keyID)); |
||
292 | } |
||
293 | |||
294 | if ($clearApiEntry) { |
||
295 | Db::execute("update zz_api set errorCode = :code where keyID = :keyID", array(":keyID" => $keyID, ":code" => $code)); |
||
296 | } |
||
297 | |||
298 | if ($updateCacheTime && $cacheUntil != 0 && $charID != 0) { |
||
299 | Db::execute("update zz_api_characters set cachedUntil = :cacheUntil where characterID = :charID", |
||
300 | array(":cacheUntil" => $cacheUntil, ":charID" => $charID)); |
||
301 | } |
||
302 | Db::execute("update zz_api_characters set errorCode = :code where keyID = :keyID and characterID = :charID", array(":keyID" => $keyID, ":charID" => $charID, ":code" => $code)); |
||
303 | } |
||
304 | |||
305 | public static function fetchApis() |
||
306 | { |
||
307 | global $baseDir; |
||
308 | |||
309 | Db::execute("delete from zz_api_characters where isDirector = ''"); // Minor cleanup |
||
310 | $fetchesPerSecond = (int) Storage::retrieve("APIFetchesPerSecond", 30); |
||
311 | $maxModulus = Db::queryField("select max(modulus) maxModulus from zz_api_characters", "maxModulus", array(), 0); |
||
312 | // If the fetchesPerSecond has changed we need to update the modulus on all rows to make sure everyone gets a turn |
||
313 | if (($maxModulus + 1) != $fetchesPerSecond) |
||
314 | { |
||
315 | Log::log("Updating modulus in zz_api_characters table..."); |
||
316 | Db::execute("update zz_api_characters set modulus = null"); |
||
317 | } |
||
318 | Db::execute("update zz_api_characters set modulus = (apiRowID % :modulus) where modulus is null", array(":modulus" => $fetchesPerSecond)); |
||
319 | |||
320 | for ($i = 0; $i < $fetchesPerSecond; $i++) |
||
321 | { |
||
322 | $command = "flock -w 60 $baseDir/cache/locks/preFetch.$i php5 $baseDir/cli.php apiFetchKillLog $i $fetchesPerSecond"; |
||
323 | $command = escapeshellcmd($command); |
||
324 | exec("$command >/dev/null 2>/dev/null &"); |
||
325 | } |
||
326 | } |
||
327 | |||
328 | public static function doApiSummary() |
||
329 | { |
||
330 | $lastActualKills = Db::queryField("select contents count from zz_storage where locker = 'actualKills'", "count", array(), 0); |
||
331 | $actualKills = Db::queryField("select count(*) count from zz_killmails where processed = 1", "count", array(), 0); |
||
332 | |||
333 | $lastTotalKills = Db::queryField("select contents count from zz_storage where locker = 'totalKills'", "count", array(), 0); |
||
334 | $totalKills = Db::queryField("select count(*) count from zz_killmails", "count", array(), 0); |
||
335 | |||
336 | Db::execute("replace into zz_storage (locker, contents) values ('totalKills', $totalKills)"); |
||
337 | Db::execute("replace into zz_storage (locker, contents) values ('actualKills', $actualKills)"); |
||
338 | Db::execute("delete from zz_storage where locker like '%KillsProcessed'"); |
||
339 | |||
340 | $actualDifference = number_format($actualKills - $lastActualKills, 0); |
||
341 | $totalDifference = number_format($totalKills - $lastTotalKills, 0); |
||
342 | |||
343 | Log::irc("|g|$actualDifference|n| mails processed | |g|$totalDifference|n| kills added"); |
||
344 | } |
||
345 | |||
346 | /** |
||
347 | * @param string $keyID string |
||
348 | * @param $charID int |
||
349 | * @param $killlog string |
||
350 | * @return int |
||
351 | */ |
||
352 | public static function processRawApi($keyID, $charID, $killlog) |
||
0 ignored issues
–
show
|
|||
353 | { |
||
354 | $count = 0; |
||
355 | foreach ($killlog->kills as $kill) { |
||
356 | $killID = $kill->killID; |
||
357 | |||
358 | $json = json_encode($kill->toArray()); |
||
359 | $hash = Util::getKillHash(null, $kill); |
||
360 | |||
361 | $inDb = Db::queryField("select count(1) count from zz_killmails where killID = :killID", "count", array(":killID" => $killID), 0); |
||
362 | if ($inDb == 0) |
||
363 | { |
||
364 | $added = Db::execute("insert ignore into zz_killmails (killID, hash, source, kill_json) values (:killID, :hash, :source, :json)", |
||
365 | array(":killID" => $killID, ":hash" => $hash, ":source" => "keyID:$keyID", ":json" => $json)); |
||
366 | $count += $added; |
||
367 | } |
||
368 | } |
||
369 | return $count; |
||
370 | } |
||
371 | } |
||
372 |