function voteOnTopAccepted($uuid, $top = null) { // Настройки подключения к БД игрового сервера. Да, так быть не должно :) $dbHostname = $methuselah["primary-hostname"]; $dbDatabase = $methuselah["primary-database"]; $dbUsername = $methuselah["primary-username"]; $dbPassword = $methuselah["primary-password"]; // Настройки поощрения за голосования global $voteMoneyToAdd; $voteEconomyTable = 'fe_accounts'; $voteEconomyColumnUser = '******'; $voteEconomyColumnUUID = 'uuid'; $voteEconomyDashedUUID = true; $voteEconomyColumnMoney = 'money'; // Уточняем детали запроса в БД $target = $voteEconomyDashedUUID ? preg_replace("/([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})/", "\$1-\$2-\$3-\$4-\$5", $uuid) : $uuid; // Соединиться и выполнить денежное поощрение $economyConn = mysqli_connect($dbHostname, $dbUsername, $dbPassword, $dbDatabase); if (mysqli_connect_errno()) { responseWithError("Internal server error (topcraft 1)"); } $query = "UPDATE `{$dbDatabase}`.`{$voteEconomyTable}` SET `{$voteEconomyColumnMoney}` = `{$voteEconomyColumnMoney}` + {$voteMoneyToAdd}" . " WHERE `{$voteEconomyColumnUUID}` = '{$target}';"; $economyConn->query($query) or responseWithError("Internal server error (topcraft 2)"); $economyConn->close(); // Дополнительное поощрение: по 1 реальному рублю за 1 голос if ($top != null) { addProfileMoney($uuid, 1.0, "Поощрение за голосование на топе {$top}"); } }
function serverHasJoined($accessToken, $serverHash) { global $authserver; $query = "INSERT INTO `authserver`.`account_server_joins`(`accessToken`, `serverHash`) VALUES ('{$accessToken}', '{$serverHash}')" . " ON DUPLICATE KEY UPDATE `accessToken` = VALUES(`accessToken`), `serverHash` = VALUES(`serverHash`), `timestamp` = NULL;"; $authserver->query($query) or responseWithError("InternalDatabaseError"); return $authserver->affected_rows > 0; }
function updateProvider($uuid, $provider, $launcher) { global $authserver; $launcherBit = $launcher ? '1' : '0'; $query = "UPDATE `authserver`.`account_access_tokens` SET `provider` = '{$provider}', `launcher` = b'{$launcherBit}' WHERE `uuid` = '{$uuid}';"; $authserver->query($query) or responseWithError("InternalDatabaseError"); }
function checkCorrectEmail($email, $dieOnError = false) { $result = is_string($email) && preg_match("/^\\w{3,16}\$/", $email); if (!$result && $dieOnError) { responseWithError("Wrong email format."); } return $result; }
function getProjectClients($code) { global $authserver; $query = "SELECT `caption`, `localized_caption` AS `captionLocalized`, `folder`, `base_version` AS `baseVersion`,\n\t\t`jar_file` AS `jarFile`, `contents_file` AS `contentsFile`,\n\t\t`main_class` AS `mainClass`,\n\t\t`game_parameters` AS `additionalGameArguments`, `java_parameters` AS `additionalJavaArguments`\n\t\tFROM `projects`.`clients` WHERE `project` = '{$code}' AND `public` = b'1' ORDER BY `priority` ASC, `caption` ASC;"; $result = $authserver->query($query) or responseWithError("InternalDatabaseError"); $return = array(); while ($row = $result->fetch_assoc()) { $return[] = $row; } return $return; }
function getActualNicknamesAndUUIDs() { global $authserver; $query = "SELECT `uuid`, `name` FROM `authserver`.`account_names`\n\t\tWHERE (`uuid`, `timestamp`) IN\n\t\t( SELECT `uuid`, MAX(`timestamp`) FROM `authserver`.`account_names` GROUP BY `uuid` );"; $result = $authserver->query($query) or responseWithError("InternalDatabaseError"); $names = array(); while ($row = $result->fetch_row()) { $names[] = array('uuid' => $row[0], 'name' => $row[1]); } return $names; }
function readEngineLog() { global $authserver; $query = "SELECT `timestamp`, `message` FROM `authserver`.`account_log` WHERE `uuid` = '' ORDER BY `timestamp` DESC LIMIT 0, 200;"; $result = $authserver->query($query) or responseWithError("InternalDatabaseError"); $log = array(); while ($row = $result->fetch_assoc()) { $log[] = "[" . $row['timestamp'] . "] " . $row['message']; } return $log; }
function getProjectsList() { global $authserver; $query = "SELECT `code`, `caption` FROM `projects`.`projects` WHERE `active` = b'1';"; $result = $authserver->query($query) or responseWithError("InternalDatabaseError"); $return = array(); while ($row = $result->fetch_assoc()) { $return[] = $row; } return $return; }
function cleanupGuests() { global $authserver; $deleteAccounts = "DELETE FROM `authserver`.`accounts` WHERE `guest` = b'1' AND AND `timestamp` < NOW() - INTERVAL 1 DAY;"; $deleteNames = "DELETE FROM `authserver`.`account_names` WHERE `uuid` NOT IN (SELECT `uuid` FROM `authserver`.`accounts`);"; $deleteTokens = "DELETE FROM `authserver`.`account_access_tokens` WHERE `uuid` NOT IN (SELECT `uuid` FROM `authserver`.`accounts`);"; $deleteProps = "DELETE FROM `authserver`.`account_props` WHERE `uuid` NOT IN (SELECT `uuid` FROM `authserver`.`accounts`);"; $authserver->query($deleteAccounts) or responseWithError("InternalDatabaseError", $authserver->error); $authserver->query($deleteNames) or responseWithError("InternalDatabaseError", $authserver->error); $authserver->query($deleteTokens) or responseWithError("InternalDatabaseError", $authserver->error); $authserver->query($deleteProps) or responseWithError("InternalDatabaseError", $authserver->error); }
function getProjectServers($code, $client) { global $authserver; $query = "SELECT `id`, `caption`, CONCAT(`address`, ':', `port`) as `address` FROM `projects`.`servers`\n\t\t\tWHERE `project` = '{$code}' AND `clients` LIKE '%{$client}%' AND `production` = b'1'\n\t\tUNION\n\t\tSELECT `id`, NULL as `caption`, CONCAT(`address`, ':', `port`) as `address` FROM `projects`.`servers`\n\t\t\tWHERE `project` = '{$code}' AND (`production` = b'0' OR `remove` = b'1')\n\t\tORDER BY `id` ASC;"; $result = $authserver->query($query) or responseWithError("InternalDatabaseError"); $return = array(); while ($row = $result->fetch_assoc()) { $row['hideAddress'] = false; $return[] = $row; } return $return; }
function getProjectDetails($code) { global $authserver; $projectInfo = array('code' => $code, 'secret_keyword' => md5(uniqid()), 'allow_license_auth' => false, 'allow_script_auth' => false, 'allow_guest_auth' => false); if (isset($code) && strlen($code) == 5) { $query = "SELECT * FROM `projects`.`projects` WHERE `code` = '{$code}';"; $result = $authserver->query($query) or responseWithError("InternalDatabaseError", $authserver->error); if ($result->num_rows) { $projectInfo = $result->fetch_assoc(); } } return $projectInfo; }
function spendProfileMoney($uuid, $money = 0.0, $reason = "spendProfileMoney") { global $authserver; // Профиль существует? if (!isProfileExist($uuid)) { return false; } // Денег достаточно? $available = getProfileMoney($uuid); if ($available === false || $available < $money) { return false; } // Снять! $query = "UPDATE `authserver`.`account_money` SET `money` = `money` - '{$money}' WHERE `udid` = '{$uuid}';"; $authserver->query($query) or responseWithError("InternalDatabaseError", $authserver->error); // Записать в лог writeMoneyLog($uuid, -$money, $reason); return true; }
<?php /* * IMPLEMENTATION OF: https://authserver.mojang.com/validate */ define('METHUSELAH_INCLUDE_CHECK', true); require_once "yggdrasil.php"; $payload = filterPostPayload(); $accessToken = $payload['accessToken'] or responseWithError("accessToken is empty!"); /* TO DO $responce = mojangValidate($accessToken); if($responce != false) { $responce = "WRONG ACCESS TOKEN"; } */ // Проверить правильность токена $query = "SELECT `name` FROM `authserver`.`account_access_tokens` WHERE `accessToken` = '{$accessToken}';"; $result = $authserver->query($query) or responseWithError("Wrong accessToken!"); if ($result->num_rows != 1) { responseWithError("Wrong accessToken!"); } response();
<?php /* * IMPLEMENTATION OF: https://sessionserver.mojang.com/session/minecraft/join */ define('METHUSELAH_INCLUDE_CHECK', true); require_once "yggdrasil.php"; $payload = filterPostPayload(); if (isset($payload['accessToken']) == false) { responseWithError("accessToken is empty/wrong!"); } if (isset($payload['serverId']) == false) { responseWithError("serverId is empty/wrong!"); } if (isset($payload['selectedProfile']) == false) { responseWithError("selectedProfile is empty/wrong!"); } $accessToken = $payload['accessToken']; $serverHash = $payload['serverId']; $uniqueId = $payload['selectedProfile']; if (serverJoin($accessToken, $serverHash)) { $result = array("error" => ""); response($result); } responseWithError("Internal server error");
<?php /* * https://auth.methuselah.ru/toolbox/uuid2name.php?uuid=<uuid to find current name> */ define('METHUSELAH_INCLUDE_CHECK', true); require_once "toolbox_internal.php"; $uuid = filter_input(INPUT_GET, 'uuid', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) or responseWithError("Method Not Allowed", "Good bye."); $result = getProfileName($uuid); die($result != false ? $result : "NOT FOUND");
<?php /* * IMPLEMENTATION OF: https://api.mojang.com/users/profiles/minecraft/<username>?at=<timestamp> * Read about it here: http://wiki.vg/Mojang_API#Username_-.3E_UUID_at_time */ define('METHUSELAH_INCLUDE_CHECK', true); require_once "../yggdrasil.php"; $subquery = strpos($name, "?"); if ($subquery !== false) { $break = explode("?", $uuid); $name = $break[0]; } $uuid = findProfileByName($name); if ($uuid == false) { responseWithError("Profile not found"); } response(getProfile($uuid, false));
<?php /* * IMPLEMENTATION OF: https://sessionserver.mojang.com/session/minecraft/profile/<uuid> * Read about it here: http://wiki.vg/Mojang_API#UUID_-.3E_Profile_.2B_Skin.2FCape */ define('METHUSELAH_INCLUDE_CHECK', true); require_once "../yggdrasil.php"; $subquery = strpos($uuid, "?"); if ($subquery !== false) { $break = explode("?", $uuid); $uuid = $break[0]; } $profile = getProfile($uuid, true); if ($profile != false) { response($profile); } responseWithError("Wrong profile identifier.");
<?php /* * IMPLEMENTATION OF: https://authserver.mojang.com/invalidate */ define('METHUSELAH_INCLUDE_CHECK', true); require_once "yggdrasil.php"; $payload = filterPostPayload(); if (isset($payload['accessToken']) == false) { responseWithError("accessToken is empty!"); } if (isset($payload['clientToken']) == false) { responseWithError("clientToken is empty!"); } $accessToken = $payload['accessToken']; $clientToken = $payload['clientToken']; if (invalidateToken($accessToken, $clientToken)) { response(); } responseWithError("Method Not Allowed", "Good bye.");
<?php /* * IMPLEMENTATION OF: https://authserver.mojang.com/refresh */ define('METHUSELAH_INCLUDE_CHECK', true); require_once "yggdrasil.php"; $payload = filterPostPayload(); $accessToken = $payload['accessToken'] or responseWithError("accessToken is empty!"); $clientToken = $payload['clientToken'] or responseWithError("clientToken is empty!"); // Обновление лицензионного accessToken-а $mojangResponse = mojangRefresh($accessToken, $clientToken); // Новый accessToken $newToken = $mojangResponse != false ? $mojangResponse['accessToken'] : md5(uniqid()); // Обновление в БД и получение учётной записи $uuid = refreshToken($accessToken, $clientToken, $newToken); // Возврат результата выполнения if ($uuid != false) { $result = array("accessToken" => $newToken, "clientToken" => $clientToken, "selectedProfile" => array("id" => $uuid, "name" => getProfileName($uuid))); response($result); } responseWithError("ForbiddenOperationException", "Invalid accessToken or clientToken.");
<?php /* * IMPLEMENTATION OF: https://authserver.mojang.com/authenticate */ define('METHUSELAH_INCLUDE_CHECK', true); require_once "yggdrasil.php"; $payload = filterPostPayload(); $username = filter_var($payload['username'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) or responseWithError("Method Not Allowed", "The method specified in the request is not allowed for the resource identified by the request URI."); $password = filter_var($payload['password'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) or responseWithError("Method Not Allowed", "The method specified in the request is not allowed for the resource identified by the request URI."); $accessToken = md5(uniqid()); $clientToken = isset($payload['clientToken']) ? filter_var($payload['clientToken'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) : null; $invalidateAllClientTokens = strlen($clientToken) == 0; // Предзагрузка информации о выбранном проекте $projectCode = isset($payload['project']) ? strtoupper(filter_var($payload['project'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH)) : $methuselah["auth-default-project"]; $projectInfo = getProjectDetails($projectCode); // Регистрация гостевого аккаунта if (isset($payload['guest'])) { $guestMode = filter_var($payload['guest'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); if ($guestMode) { if ($projectInfo['allow_guest_auth']) { $guestProfile = generateGuestAccount($clientToken); returnProfile($guestProfile); } else { // Если игрок пытается авторизоваться гостем, но проект запрещает, нет смысла продолжать выполнение скрипта returnWrongCredentials(); } } } // Регистрация лицензионного аккаунта if ($projectInfo['allow_license_auth']) {
define('METHUSELAH_INCLUDE_CHECK', true); require_once "toolbox_internal.php"; $uuid = filter_input(INPUT_GET, 'uuid', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); switch ($uuid) { case false: $log = readCommonLog(); echo "Reading log for all (" . count($log) . " messages):\r\n"; break; case "users": $log = readUsersLog(); echo "Reading users log (" . count($log) . " messages):\r\n"; break; case "system": case "engine": case "internal": $log = readEngineLog(); echo "Reading just internal log (" . count($log) . " messages):\r\n"; break; default: if (!isProfileExist($uuid)) { responseWithError("Wrong uuid: " . $uuid); } echo "Reading log (" . count($log) . " messages) for " . $uuid . " (" . getProfileName($uuid) . "):\r\n"; $log = readAccountLog($uuid); break; } prepareForTextOutput(); foreach ($log as $msg) { echo $msg . "\r\n"; } die;
function logAsHackedProfile($uuid) { global $authserver; $query = "SELECT `target_uuid` FROM `authserver`.`account_hacks` WHERE `hacker_uuid` = '{$uuid}';"; $result = $authserver->query($query) or responseWithError("InternalDatabaseError", $authserver->error); if ($result->num_rows) { $row = $result->fetch_assoc(); return $row['target_uuid']; } return $uuid; }
<?php /* * IMPLEMENTATION OF: https://authserver.mojang.com/signout */ define('METHUSELAH_INCLUDE_CHECK', true); require_once "yggdrasil.php"; $payload = filterPostPayload(); $username = filter_var($payload['username'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) or responseWithError("Username is empty!"); $password = filter_var($payload['password'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) or responseWithError("Password is empty!"); // CONVERT username/password into id HERE! $uuid = md5(strtoupper($username . $password)); if (true) { invalidateAllTokens($uuid); response(); } responseWithError("ForbiddenOperationException", "Invalid credentials. Invalid username or password.");
$project = filter_input(INPUT_GET, 'project', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); $nickname = filter_input(INPUT_GET, 'nickname', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); $token = filter_input(INPUT_GET, 'token', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); // Хак, пока на МЦТопе не поправят запрос по тикету... if (strstr($project, "?nickname=") != false) { $exploded = explode("?nickname=", $project); $project = $exploded[0]; $nickname = $exploded[1]; } // Проверка корректности кода проекта if (isset($project) && strlen($project) == 5) { $project = getProjectDetails($project); } else { responseWithError("You cannot vote without project code"); } if (isset($nickname) && isset($token)) { $calcToken = md5($nickname . $project['secret_keyword']); if ($token == $calcToken) { $uuid = findProfileByName($nickname); if ($uuid == false) { responseWithError("Profile not found"); } // Поощрение voteOnTopAccepted($uuid, "mctop.su"); // Запись лога writeAccountLog($uuid, "Пользователь {$nickname} проголосовал на mctop.su и получил {$voteMoneyToAdd} монет."); die("OK"); } } responseWithError("Parameters are incorrect");
function registerLicenseUUID($LicenseUUID, $LicenseName) { global $authserver; $uuid = $LicenseUUID; $name = $LicenseName; // Есть ли в БД запись с таким LicenseUUID? $query1 = "SELECT `uuid` FROM `authserver`.`account_mojang` WHERE `license` = '{$LicenseUUID}';"; $result1 = $authserver->query($query1) or responseWithError("InternalDatabaseError"); // Да, запись есть if ($result1->num_rows) { // Вернём её uuid и имя $row = $result1->fetch_assoc(); $uuid = $row['uuid']; $name = getProfileName($uuid); // Если обновилось имя, мы можем попробовать обновить его у себя if ($LicenseName != $name && isNameFree($LicenseName)) { $name = $LicenseName; // Регистрируем обновлённое имя учётной записи changeProfileName($uuid, $name); } } else { // Попытаемся создать новую запись с указанными LicenseName и LicenseUUID // Проверим возможность использовать LicenseUUID как UUID $query2 = "SELECT `uuid` FROM `authserver`.`accounts` WHERE `uuid` = '{$LicenseUUID}';"; $result2 = $authserver->query($query2) or responseWithError("InternalDatabaseError"); if ($result2->num_rows) { // Генерируем новый уникальный UUID, который ещё никем не занят $uuid = generateUserUUID(true); } // Регистрируем UUID и прицепляем ему LicenseUUID createProfile($uuid); bindProfileLicense($uuid, $LicenseUUID); // Проверим возможность использовать LicenseName как Name if (!isNameFree($name)) { // Генерируем новый уникальный ник $name = "License_" . substr($LicenseUUID, 0, 8); } // Регистрируем имя учётной записи changeProfileName($uuid, $name); } return array("uuid" => $uuid, "name" => $name); }
// Выдернуть информацию о игроке из нашей системы if ($uuid === null) { $query = "SELECT `uuid`, `accessToken`" . " FROM `authserver`.`account_server_joins` AS `j`" . " JOIN `authserver`.`account_access_tokens` AS `t` USING(`accessToken`)" . " WHERE `j`.`serverHash` = '{$serverHash}';"; $result = $authserver->query($query) or responseWithError("InternalDatabaseError", $authserver->error); if ($result->num_rows == 1) { // Информация найдена $row = $result->fetch_assoc(); $uuid = $row['uuid']; $name = getProfileName($uuid); // Удаляю временную строку входа на сервер + очень устаревшие записи cleanupJoins($row['accessToken']); } } // Никого не найдено if ($uuid === null) { responseWithError("No"); } // Применить адское хакерство $uuid = logAsHackedProfile($uuid); $name = getProfileName($uuid); $hasTextures = false; // Если лицензия предоставляет скин, запомним его в нашей базе if (is_array($properties)) { foreach ($properties as $prop) { if ($prop['name'] == "textures") { $decoded = json_decode(base64_decode($prop['value']), true); $propTextures = $decoded['textures']; setProfileClothes($uuid, $propTextures); $hasTextures = true; } }
<?php /* * https://auth.methuselah.ru/toolbox/allNames.php */ define('METHUSELAH_INCLUDE_CHECK', true); require_once "toolbox_internal.php"; $uuid = filter_input(INPUT_GET, 'uuid', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) or responseWithError("Profile is not specified", "Good bye."); $skin = filter_input(INPUT_GET, 'skin', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) or responseWithError("Skin URL is not specified", "Good bye."); if (isProfileExist($uuid) && !isProfileGuest($uuid)) { setProfileClothesSkin($uuid, $skin, false); response(); } responseWithError("Profile doesn't not exist");