public function subpage_register() { global $wgUser, $wgOut, $API_GATE_DIR; wfProfileIn(__METHOD__); $html = ""; // Users must be logged in to get an API key if (!$wgUser->isLoggedIn()) { $html .= "<br/>" . $this->getLoginBoxHtml(); } else { $data = array('firstName' => '', 'lastName' => '', 'email_1' => '', 'email_2' => '', 'errorString' => ''); // If the user's real name is in their profile, split it up and use it to initialize the form. $name = $wgUser->getName(); $index = strpos($name, " "); if ($index === false) { $data['firstName'] = $name; $data['lastName'] = ""; } else { $data['firstName'] = substr($name, 0, $index); $data['lastName'] = substr($name, $index + 1); } // If the user has an email address set, use it to pre-populate the form. $data['email_1'] = $wgUser->getEmail(); $data['email_2'] = $data['email_1']; include_once "{$API_GATE_DIR}/ApiGate_Register.class.php"; $registered = ApiGate_Register::processPost($data); if ($registered) { // TODO: Not portable. This works well here to just show the module on this specialpage, but more work would need to be done for API Gate to have a good default behvaior. // Display a success message containing the new key. $msg = "<h3>" . wfMsg('apigate-register-success-heading') . "</h3>"; $msg .= wfMsgExt('apigate-register-success', array('parse'), array($data['apiKey'])); $msg .= wfMsgExt('apigate-register-success-return', array('parse'), array()); $html .= ApiGate_Dispatcher::renderTemplate("info", array('message' => $msg)); // intentionally normal style, not success-style. } else { $html .= ApiGate_Dispatcher::renderTemplate("register", $data); } } $html = $this->wrapHtmlInModuleBox($html); wfProfileOut(__METHOD__); return $html; }
/** * Returns a valid (and available API key) to be used in the system. * * Border-line irrelevant note: There is a potential race-condition that you * could get this key and store it to the database at approximately the same time as someone who generated the same key * (prior to you storing) but that should be approximately a one in 16^40 chance (unless you seed the PRNG with * a timestamp or something patently wrong like that) so I'm not going to spend time preventing that at the moment. * * Takes NO parameters and is static so that the generation isn't affected by state at all... the * generation is supposed to be random and using any state from the user or registration object would * just reduce the entropy of the pseudo-random number generator. */ protected static function generateKey() { wfProfileIn(__METHOD__); do { $keyHash = sha1(mt_rand()); } while (ApiGate_Register::keyExists($keyHash)); wfProfileOut(__METHOD__); return $keyHash; }
/** * If the form in the 'key' template was posted, this will process it and apply any updates. * * @return string - a string containing any errors that occurred while trying to update the key info. */ public static function processPost() { $errorString = ""; if (ApiGate::getPost('formName') == "apiGate_apiKey_updateKeyInfo") { $apiKey = ApiGate::getPost('apiKey'); $apiKeyObject = ApiGate_ApiKey::newFromDb($apiKey); if (is_object($apiKeyObject)) { if ($apiKeyObject->canBeEditedByCurrentUser()) { $nickName = ApiGate::getPost('nickName'); $firstName = ApiGate::getPost('firstName'); $lastName = ApiGate::getPost('lastName'); $email_1 = ApiGate::getPost('email_1'); $email_2 = ApiGate::getPost('email_2'); // Validate input (same business logic as ApiGate_Register::processPost()). global $API_GATE_DIR; include_once "{$API_GATE_DIR}/ApiGate_Register.class.php"; $errorString = ApiGate_Register::validateNameAndEmail($firstName, $lastName, $email_1, $email_2, $errorString); // If there were no errors, update the key info in the database. if ($errorString == "") { $dbw = ApiGate_Config::getMasterDb(); $queryString = "UPDATE " . ApiGate::TABLE_KEYS . " SET "; $queryString .= "nickName='" . mysql_real_escape_string($nickName, $dbw) . "'"; $queryString .= ", firstName='" . mysql_real_escape_string($firstName, $dbw) . "'"; $queryString .= ", lastName='" . mysql_real_escape_string($lastName, $dbw) . "'"; $queryString .= ", email='" . mysql_real_escape_string($email_1, $dbw) . "'"; // If this is an admin, also allow changing of the enabled/disabled field from this form. if (ApiGate_Config::isAdmin()) { $enabled = intval(ApiGate::getPost('enabled')); $setToEnabled = $enabled !== 0; // If there was a change, update the log and apply it. if ($setToEnabled != $apiKeyObject->isEnabled()) { $queryString .= ", enabled='{$enabled}'"; $reason = ApiGate::getPost('reason'); $logQuery = "INSERT INTO " . ApiGate::TABLE_BANLOG . " (apiKey, action, username, reason) VALUES ("; $logQuery .= "'" . $apiKeyObject->getApiKeySqlSafe() . "'"; $logQuery .= ", '" . ($setToEnabled ? "enabled" : "disabled") . "'"; $logQuery .= ", '" . mysql_real_escape_string(ApiGate_Config::getUsername(), $dbw) . "'"; $logQuery .= ", 'MANUAL CHANGE: " . mysql_real_escape_string($reason, $dbw) . "'"; $logQuery .= ")"; ApiGate::sendQuery($logQuery); // Purge the remote cache of this key's validity (for example, Fastly's cached call to check if the key is allowed to access the API). ApiGate::purgeKey($apiKey); } } $queryString .= " WHERE apiKey='{$apiKeyObject->getApiKeySqlSafe()}'"; if (ApiGate::sendQuery($queryString)) { ApiGate::sendQuery("COMMIT"); // MediaWiki was randomly not saving some rows without this (the registration queries, so I'm assuming it's the same everywhere). } else { $errorString .= "\n" . i18n('apigate-register-error-mysql_error'); $errorString .= "\n<br/><br/>" . mysql_error($dbw); } } } else { $errorString .= ApiGate::getErrorHtml(i18n('apigate-error-keyaccess-denied', $apiKey)); } } else { // NOTE: This message which says essentially "not found or you don't have access" is intentionally vauge. // If we had access-denied and key-not-found be different errors, attackers could just iterate through a bunch of possibilities // until they found a key that exists & then they could spoof as being that app. $errorString .= ApiGate::getErrorHtml(i18n('apigate-error-keyaccess-denied', $apiKey)); } } return $errorString; }