Jump to content
  • Chmurka
  • Boróweczka
  • Jabłuszko
  • Limonka
  • Czekoladka
  • Węgielek

Recommended Posts

Opis

Ten temat zawiera poradnik jak można dodać licencję na swój plugin sourcemod. Plugin będzie komunikował się z bazą danych na zewnętrznym serwerze, sprawdzał czy IP serwera, ID pluginu oraz specjalny hash pluginu są wpisane do SQL, jeśli tak, plugin będzie działał poprawnie, jeśli nie, plugin automatycznie się sam wyłączy. Aby w pełni zrozumieć poradnik powinieneś mieć podstawowe pojęcie o PHP, SourceModzie oraz bazach danych. Jeśli czegoś nie wiesz, śmiało pytaj w tym temacie, na pewno poszerzysz swoją wiedzę.

 

 

 

Ostrzeżenie

Poradnik jest w praktyce niepotrzebny, ponieważ jak dobrze pamiętamy, każda publikacja pluginu sourcemod zgodnie z licencją GNU General Public License (klik aby poczytać)
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami! włącznie ze skompilowanym plikiem .smx (którego w teorii nie da się odczytać ani zmodyfikować) musi zawierać kod źródłowy w pliku .sp. Więc nawet jeśli nałożymy na nasz plugin licencję to każdy będzie mógł ją zmodyfikować/usunąć. Ten temat znajduje się tutaj tylko i wyłącznie w celach edukacyjnych.

 

 

 

Kod SM

Pokrótce omówię poniższy kod, pomimo tego, że zawiera dość dobre komentarze*.  Główną funkcję CheckValidity (); umieszczamy w kodzie innego pluginu w OnPluginStart ();. Sprawdza ona czy plugin poprawnie znajduje się w bazie danych. Jeśli się znajduje, URL zwraca odpowiedź w postaci hashu, który musi się zgadzać z tym wpisanym w plugin. Jeśli się nie zgadza, plugin się wyłącza.

pluginDatabaseID - uzupełnij tą zmienną o numer ID pluginu z bazy danych (o bazie danych później)

validDatabaseResponse - uzupełnij tą zmienną o unikalny ciąg znaków(hash) z bazy danych

databaseURL - uzupełnij tą zmienną o URL, który będzie się komunikował z bazą danych

Ten kod możemy umieścić bezpośrednio w kodzie innego pluginu lub jako plik .inc. Życzę miłego czytania komentarzy, widzimy się na dole gdzie wyjaśnię jak będzie wyglądał kod PHP po stronie URL

Spoiler

#include <SteamWorks>

#pragma semicolon				1
#pragma newdecls				required



//Dane potrzebne do komunikacji z URL
  
//ID pluginu w bazie danych
char pluginDatabaseID[2] = 0;
//Odpowiedź z bazy danych jaką powinien otrzymać plugin by licencja była prawidłowa
char validDatabaseResponse[33] = "OCUVAE23NKV06VDN14RQZACMNW3XK9VE";
//URL z którego bierzemy odpowiedź czy ten serwer ma licencję
char databaseURL[64] = "http://twoja-strona.pl/url-do-skryptu-walidujacego.php";

bool pluginValid = false;



//Główna funkcja sprawdzająca poprawność licencji
public bool CheckValidity ()
{
	//Wyłączamy plugin po 70.0 sekundach jeśli odpowiedź z URL nie jest poprawna
	CreateTimer(70.0, SetFailPluginEmergency);
	
	
	
	//Tutaj korzystamy z tego https://go-code.pl/temat/58-csgo-pobranie-ip-serwera/ 
	//by pobrać IP serwera na którym jest plugin
	char NetIP[32];
	int Octets[4];
	int FullIP = GetConVarInt( FindConVar("hostip") );
	int Port = GetConVarInt( FindConVar("hostport") );
	Octets[0] = ( FullIP >> 24 ) & 0x000000FF;
	Octets[1] = ( FullIP >> 16 ) & 0x000000FF;
	Octets[2] = ( FullIP >> 8 ) & 0x000000FF;
	Octets[3] = FullIP & 0x000000FF;

	Format(NetIP, sizeof(NetIP), "%d.%d.%d.%d:%d", Octets[0], Octets[1], Octets[2], Octets[3], Port);  
	
	
	
	//Sprawdzamy czy SteamWorks (który jest potrzebny do komunikacji serwer <-> URL) jest wgrany na serwer. 
	//Jeśli nie, wyłączamy plugin
	if (GetFeatureStatus(FeatureType_Native, "SteamWorks_CreateHTTPRequest"))
	{
		PrintToServer("[ValidCheck] You need SteamWorks to use this plugin");
		CreateTimer(1.0, SetFailPluginEmergency);
		return false;
	}
	
	
	
	//Tworzymy połączenie serwer <-> URL
	Handle HTTPRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodPOST, URL);
	
	
	
	//Jeśli nie udało się nam utworzyć połączenia, ponawiamy próbę (może to być chwilowy błąd URL)
	if (!HTTPRequest)
	{
		PrintToServer("[ValidCheck] Failed to create HTTP request using url: %s", URL);
		CreateTimer(10.0, CheckValidityAgain);
		return false;
	}
	
	
	
	//Łączymy się z danym URL za pomocą poprawnych parametrów _POST / _GET
	//(musimy przesłać do URL dane o serwerze by sprawdzić czy w bazie danych są dane tego serwera)
	SteamWorks_SetHTTPRequestNetworkActivityTimeout(HTTPRequest, 10);
	SteamWorks_SetHTTPRequestGetOrPostParameter(HTTPRequest, "ip", NetIP);
	SteamWorks_SetHTTPRequestGetOrPostParameter(HTTPRequest, "pl", pluginDatabaseID);
	SteamWorks_SetHTTPRequestHeaderValue(HTTPRequest, " ", " ");
	SteamWorks_SetHTTPRequestContextValue(HTTPRequest, 10);
	SteamWorks_SetHTTPCallbacks(HTTPRequest, ReturnQueryHTTP);
	
	
	
	//Jeśli się nie udało, to jeszcze raz próbujemy
	if (!SteamWorks_SendHTTPRequest(HTTPRequest))
	{
		PrintToServer("[ValidCheck] Error with SteamWorks");
		CloseHandle(HTTPRequest);
		CreateTimer(10.0, CheckValidityAgain);
		return false;
	}
	
	return true;
}



//Task który jeszcze raz sprawdza poprawność licencji
public Action CheckValidityAgain(Handle timer)
{
	CheckValidity();
}



//Task wyłączający plugin jeśli licencja nadal nie została sprawdzona/została sprawdzona i jest zła
public Action SetFailPluginEmergency(Handle timer)
{
	if (!IsPluginValid())
		SetFailState("[ValidCheck] You do not have license to use this plugin!");
}



//Funkcja która przyjmuje odpowiedź od URL gdzie odbyło się zapytanie do bazy danych, czy ten serwer posiada licencję
public bool ReturnQueryHTTP(Handle Request, bool Fail, bool CheckSucess, EHTTPStatusCode Status, any Data)
{
	if (Fail)
	{
		PrintToServer("[ValidCheck][5] Error. Please contact plugin Author!");
		CloseHandle(Request);
		CreateTimer(10.0, CheckValidityAgain);
		return false;
	}
	
	if (!CheckSucess)
	{
		PrintToServer("[ValidCheck][0] Error with HTTP Request. Please contact plugin Author!");
		CloseHandle(Request);
		CreateTimer(10.0, CheckValidityAgain);
		return false;
	}
	
	int BodySize; 
	char BodyBuffer[10000];
	
	if (!SteamWorks_GetHTTPResponseBodySize(Request, BodySize))
	{
		PrintToServer("[ValidCheck][1] Error with HTTP answers size. Please contact plugin Author!");
		CloseHandle(Request);
		CreateTimer(10.0, CheckValidityAgain);
		return false;
	}
	if (BodySize > 10000)
	{
		PrintToServer("[ValidCheck][2] Error with HTTP answers size. Please contact plugin Author! Debug: %i", BodySize);
		CloseHandle(Request);
		CreateTimer(10.0, CheckValidityAgain);
		return false;
	}
	if (!SteamWorks_GetHTTPResponseBodyData(Request, BodyBuffer, BodySize))
	{
		PrintToServer("[ValidCheck][3] Error HTTP did not send anwser. Please contact plugin Author!");
		CloseHandle(Request);
		CreateTimer(10.0, CheckValidityAgain);
		return false;
	}
	
	
	
	//Tutaj sprawdzamy czy to co zwrócił URL zawiera odpowiedź której oczekuje plugin (validDatabaseResponse)
	if (StrContains(BodyBuffer, validDatabaseResponse, false) > -1)
	{
		PrintToServer("[ValidCheck] SUCCESS! PLUGIN WORKS");
		pluginValid = true;
	}
	else
	{
		PrintToServer("[ValidCheck][6] Error no IP in database or unique key is invalid. Please contact plugin Author!");
		pluginValid = false;
		CreateTimer(1.0, SetFailPluginEmergency);
	}
	
	CloseHandle(Request);
	return true;
}



//Funkcja po prostu zwraca czy plugin uznał się za prawidłowy (posiadający licencję) po zapytaniu URL
public bool IsPluginValid()
{
	return pluginValid;
}

 

 

 

 

Kod PHP

Kod PHP będzie przyjmował argumenty "ip" oraz "pl" oznaczające po kolei IP serwera na którym jest plugin oraz ID pluginu. Sprawdzi czy są poprawne (pod względem składni), po czym połączy się z SQL i zapyta, czy dane znajdują się w bazie danych. Jeśli się znajdują, URL wyrzuci na ekran unikalny hash pluginu, by plugin mógł porównać go sobie ze swoim hashem wpisanym na sztywno. Sprawdza to funkcja ReturnQueryHTTP w sourcepawnie w moim kodzie.

Spoiler

<?php
	if((isset($_POST['ip']) && $_POST['ip'] != "" && isset($_POST['pl']) && $_POST['pl'] != "") || (isset($_GET['ip']) && $_GET['ip'] != "" && isset($_GET['pl']) && $_GET['pl'] != ""))
	{
		//Jeśli połączenie nie odbywa się przez serwer CS, skrypt się nie wykona
		if(strpos($_SERVER['HTTP_USER_AGENT'], "Valve/Steam") === false)
		{
			die('[1] This script can not be used like that');
		}



		//Przyjmujemy argumenty z URL, albo w postaci _POST albo w _GET, zależnie co serwer przesłał
		$serverIP = isset($_POST['ip']) ? $_POST['ip'] : $_GET['ip'];
		$pluginID = isset($_POST['pl']) ? $_POST['pl'] : $_GET['pl'];



		//Sprawdzamy czy przesłane IP ma "kształt" IP poprzez REGEX**
		if(!preg_match('/^(\d+\.\d+\.\d+\.\d+):(\d+)$/', $serverIP))
		{
			die('[2] This script received bad "ip" data');
		}



		//Sprawdzamy ID pluginu czy jest samą liczbą poprzez REGEX**
		if(preg_match("/^\d+$/", $pluginID))
		{
			die('[3] This script received bad "pl" data');
		}



		//Łączymy się z bazą danych
		$SQL_HOSTNAME = "localhost";
		$SQL_USERNAME = "root";
		$SQL_PASSWORD = "";
		$SQL_DATABASE = "database";
		$SQL_TABLE = "table";

		$sqlHandle = mysqli_connect($SQL_HOSTNAME, $SQL_USERNAME, $SQL_PASSWORD, $SQL_DATABASE) or die('[4] No database connection');



		//I pytamy bazę danych, czy w tabeli z licencjami, znajduje się IP naszego serwera
		$sqlQuery = "SELECT * FROM `".$SQL_TABLE."` WHERE ip='".$server_ip."' AND plugin_id='".$plugin_id."';";
		$sqlResult = mysqli_query($sqlHandle, $sqlQuery) or die('[5] Invalid query');



		//Jeśli zwróci się nam dokładnie jeden wynik (to znaczy że plugin ma licencję i nie ma żadnych bugów w bazie to znaczy licka się nie powtarza)
		//To zwracamy unikalny hash pluginu żeby funkcja w pluginie sourcemod mogła ją porównać
		if(mysqli_num_rows($sqlResult) === 1)
		{
			$rowWithData = mysqli_fetch_assoc($sqlResult);
			die($rowWithData['plugin_hash']);
		}

		die();
	}

	die();
?>

 

 

 

 

Tabela z licencjami

Tabela z licencjami powinna wyglądać mniej więcej tak:

|     id     |     ip     |   plugin_id   |  plugin_hash  |
|            |            |               |               |
|tutaj id ze |  tutaj ip  |tutaj id plugi-|  tutaj hash   |
|standardową |  serwera   |nu             | unikalny dla  |
|autoinkreme-|            |               | każdego smx   |
|  ntacją    |            |               |               |

id - zawiera standardowy integer z autoinkrementacją niepotrzebny do działania pluginu na licencję

ip - ip serwera na którym ma działać dana licencja 

plugin_id - jest to ID pluginu (nie pojedynczego pliku) w bazie danych. Na przykład plugin nazwany "fajerwerki" będzie miał id 10 i niezależnie jaki użytkownik będzie miał na niego licencję, to plugin zawsze będzie miał id 10. Swoisty identyfikator pluginu

plugin_hash - unikalny 32 znakowy ciąg znaków dla każdego osobnego pliku smx który znajduje się i w bazie i w pluginie, musisz go wpisywać ręcznie

 

 

 

 

 

 

* - Pamiętajmy co do komentarzy - jeśli Twój kod zawiera ich za dużo, staje się nieczytelny. Nie papuguj kodu powyżej i nie pisz wszędzie swoich komentarzy. Staraj się pisać kod zgodnie z zasadami Clean Code
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!

** - Regex czyli wyrażenia regularne
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!. Jest to świetne i bardzo przydatne zagadnienie w informatyce ogółem, polecam się zagłębić

  • Lubię to! 6
  • Wow! 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

Nasza historia

Na początku byliśmy małą grupą internetowych znajomych, którzy stwierdzili, że potrzebne jest solidne forum, na którym znajdą się ludzie z dużą wiedzą programistyczną ukierunkowaną na CS:GO. Pomysł powstał na początku 2018 roku, a parę miesięcy później, 19 kwietnia, powstała ta strona internetowa. Jako alternatywna odpowiedź na inne tego typu miejsca, poważnie podeszliśmy do tematu, najpierw tłumacząc angielską dokumentację SourceMod'a na język polski, a potem pisząc rozległe poradniki i wypełniając forum najpotrzebniejszymi rzeczami dla właścicieli serwerów i programistów. Cała nasza Ekipa jest dumna z pracy jaką w to włożyliśmy i cieszymy się że zbierają się wokół nas zarówno ludzie znający tematy sourcepawn'a i konfiguracji, jak i również nowe twarze w tym "biznesie", którym z chęcią niesiemy wiedzę oraz pomoc w rozwiązywaniu problemów.

Największe modyfikacje serwerowe

×
×
  • Create New...