Skip to content

Sovereign Cloud - Self-Hosted Lisans Sistemi

Magnesify Sovereign Cloud (MSC), Rust programlama dili ile geliştirilmiş, kendi sunucunuzda çalıştırabileceğiniz güvenli bir lisans yönetim sistemidir. Bu sistem, yazılım lisanslarınızı merkezi olarak yönetmenizi, doğrulamanızı ve kontrol etmenizi sağlar.

🚀 Özellikler

  • Self-Hosted: Kendi sunucunuzda tam kontrol
  • Güvenli API: Admin kimlik doğrulama ile korumalı endpointler
  • IP Bazlı Lisanslama: IP adresine bağlı lisans kontrolü
  • Sürekli Güvenlik Kontrolü: Arka planda çalışan lisans doğrulama sistemi
  • CLI Arayüzü: Komut satırından kolay yönetim
  • SQLite Veritabanı: Hafif ve taşınabilir veri saklama
  • RESTful API: Modern web servisleri ile entegrasyon

🔧 Kurulum

Gereksinimler

  • Rust 1.70+
  • SQLite3
  • Linux/Unix sistem (makine ID desteği için)

⚙️ Konfigürasyon

Sistem ilk çalıştırıldığında msc.yaml dosyası otomatik olarak oluşturulur:

yaml
app:
  protocol: "http"
  token: "LUTFEN_BURAYA_LISANS_TOKENINIZI_GIRIN"
server:
  host: "127.0.0.1"
  default_port: 4050
database:
  path: "licenses.db"

Önemli: app.token alanını geçerli bir lisans tokeni ile güncelleyin.

🚀 Kullanım

Sunucuyu Başlatma

bash
# Varsayılan port (4050) ile başlatma
./msc start

# Özel port ile başlatma
./msc start --port 8080

Veritabanı Yönetimi

bash
# Veritabanı şemasını oluştur/güncelle
./msc db migrate

Kullanıcı Yönetimi

bash
# Admin kullanıcısı oluştur
./msc create user --email admin@example.com --role ADMIN

# Normal kullanıcı oluştur
./msc create user --email user@example.com --role USER

# Kullanıcı sil
./msc delete user --email user@example.com

API Anahtarı Oluşturma

bash
# Admin kullanıcısı için API anahtarı oluştur
./msc generate-key --email admin@example.com

Lisans Yönetimi

bash
# Lisans oluştur
./msc create license --product "my-app" --user "user123" --ip "192.168.1.100"

# Özel MID ile lisans oluştur
./msc create license --mid "abc123" --product "my-app" --user "user123" --ip "192.168.1.100"

# Lisans sil
./msc delete license --mid "abc123"

# Tüm lisansları listele
./msc list

🌐 API Endpointleri

Tüm API endpointleri /api/licenses prefix'i altında bulunur ve admin kimlik doğrulama gerektirir.

Kimlik Doğrulama

API isteklerinde X-API-Key header'ında geçerli bir API anahtarı gönderilmelidir:

bash
curl -H "X-API-Key: your-api-key-here" http://localhost:4050/api/licenses/list

Endpointler

1. Lisansları Listele

http
GET /api/licenses/list

Yanıt:

json
{
  "message_type": "success",
  "message": "Licenses listed successfully.",
  "endpoint": "/api/licenses/list",
  "data": [
    {
      "id": 1,
      "mid": "abc-mag-def-ghi",
      "product_id": "my-app",
      "user_id": "user123",
      "ip_address": "192.168.1.100",
      "is_active": true,
      "created_at": "2024-01-01T00:00:00Z"
    }
  ],
  "timestamp": "2024-01-01T00:00:00Z"
}

Örnek Kodlar:

Java (OkHttp):

java
import okhttp3.*;
import java.io.IOException;

public class MSCClient {
    private static final String BASE_URL = "http://localhost:4050";
    private static final String API_KEY = "your-api-key-here";
    
    public static void listLicenses() throws IOException {
        OkHttpClient client = new OkHttpClient();
        
        Request request = new Request.Builder()
            .url(BASE_URL + "/api/licenses/list")
            .addHeader("X-API-Key", API_KEY)
            .get()
            .build();
            
        try (Response response = client.newCall(request).execute()) {
            System.out.println("Response: " + response.body().string());
        }
    }
}

JavaScript (Fetch):

javascript
const BASE_URL = 'http://localhost:4050';
const API_KEY = 'your-api-key-here';

async function listLicenses() {
    try {
        const response = await fetch(`${BASE_URL}/api/licenses/list`, {
            method: 'GET',
            headers: {
                'X-API-Key': API_KEY,
                'Content-Type': 'application/json'
            }
        });
        
        const data = await response.json();
        console.log('Licenses:', data);
    } catch (error) {
        console.error('Error:', error);
    }
}

// Kullanım
listLicenses();

PHP (cURL):

php
<?php
$baseUrl = 'http://localhost:4050';
$apiKey = 'your-api-key-here';

function listLicenses() {
    global $baseUrl, $apiKey;
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $baseUrl . '/api/licenses/list');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'X-API-Key: ' . $apiKey,
        'Content-Type: application/json'
    ]);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($httpCode === 200) {
        $data = json_decode($response, true);
        echo "Licenses: " . print_r($data, true);
    } else {
        echo "Error: HTTP $httpCode";
    }
}

listLicenses();
?>

2. Lisans Oluştur

http
POST /api/licenses/create
Content-Type: application/json

{
  "product_id": "my-app",
  "user_id": "user123",
  "ip_address": "192.168.1.100"
}

Örnek Kodlar:

Java (OkHttp):

java
public static void createLicense() throws IOException {
    OkHttpClient client = new OkHttpClient();
    
    String jsonBody = "{\"product_id\":\"my-app\",\"user_id\":\"user123\",\"ip_address\":\"192.168.1.100\"}";
    RequestBody body = RequestBody.create(jsonBody, MediaType.get("application/json"));
    
    Request request = new Request.Builder()
        .url(BASE_URL + "/api/licenses/create")
        .addHeader("X-API-Key", API_KEY)
        .post(body)
        .build();
        
    try (Response response = client.newCall(request).execute()) {
        System.out.println("Response: " + response.body().string());
    }
}

JavaScript (Fetch):

javascript
async function createLicense() {
    const licenseData = {
        product_id: 'my-app',
        user_id: 'user123',
        ip_address: '192.168.1.100'
    };
    
    try {
        const response = await fetch(`${BASE_URL}/api/licenses/create`, {
            method: 'POST',
            headers: {
                'X-API-Key': API_KEY,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(licenseData)
        });
        
        const data = await response.json();
        console.log('License created:', data);
    } catch (error) {
        console.error('Error:', error);
    }
}

PHP (cURL):

php
function createLicense() {
    global $baseUrl, $apiKey;
    
    $licenseData = [
        'product_id' => 'my-app',
        'user_id' => 'user123',
        'ip_address' => '192.168.1.100'
    ];
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $baseUrl . '/api/licenses/create');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($licenseData));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'X-API-Key: ' . $apiKey,
        'Content-Type: application/json'
    ]);
    
    $response = curl_exec($ch);
    curl_close($ch);
    
    $data = json_decode($response, true);
    echo "License created: " . print_r($data, true);
}

3. Lisans Sil

http
DELETE /api/licenses/delete
Content-Type: application/json

{
  "mid": "abc-mag-def-ghi"
}

Örnek Kodlar:

Java (OkHttp):

java
public static void deleteLicense(String mid) throws IOException {
    OkHttpClient client = new OkHttpClient();
    
    String jsonBody = "{\"mid\":\"" + mid + "\"}";
    RequestBody body = RequestBody.create(jsonBody, MediaType.get("application/json"));
    
    Request request = new Request.Builder()
        .url(BASE_URL + "/api/licenses/delete")
        .addHeader("X-API-Key", API_KEY)
        .delete(body)
        .build();
        
    try (Response response = client.newCall(request).execute()) {
        System.out.println("Response: " + response.body().string());
    }
}

JavaScript (Fetch):

javascript
async function deleteLicense(mid) {
    const deleteData = { mid: mid };
    
    try {
        const response = await fetch(`${BASE_URL}/api/licenses/delete`, {
            method: 'DELETE',
            headers: {
                'X-API-Key': API_KEY,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(deleteData)
        });
        
        const data = await response.json();
        console.log('License deleted:', data);
    } catch (error) {
        console.error('Error:', error);
    }
}

PHP (cURL):

php
function deleteLicense($mid) {
    global $baseUrl, $apiKey;
    
    $deleteData = ['mid' => $mid];
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $baseUrl . '/api/licenses/delete');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($deleteData));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'X-API-Key: ' . $apiKey,
        'Content-Type: application/json'
    ]);
    
    $response = curl_exec($ch);
    curl_close($ch);
    
    $data = json_decode($response, true);
    echo "License deleted: " . print_r($data, true);
}

4. Lisans Doğrula

http
POST /api/licenses/validate
Content-Type: application/json

{
  "product_id": "my-app",
  "user_id": "user123"
}

Yanıt:

json
{
  "message_type": "success",
  "message": "License is valid.",
  "endpoint": "/api/licenses/validate",
  "data": {
    "valid": true
  },
  "timestamp": "2024-01-01T00:00:00Z"
}

Örnek Kodlar:

Java (OkHttp):

java
public static void validateLicense() throws IOException {
    OkHttpClient client = new OkHttpClient();
    
    String jsonBody = "{\"product_id\":\"my-app\",\"user_id\":\"user123\"}";
    RequestBody body = RequestBody.create(jsonBody, MediaType.get("application/json"));
    
    Request request = new Request.Builder()
        .url(BASE_URL + "/api/licenses/validate")
        .addHeader("X-API-Key", API_KEY)
        .post(body)
        .build();
        
    try (Response response = client.newCall(request).execute()) {
        String responseBody = response.body().string();
        System.out.println("Validation response: " + responseBody);
        
        // JSON parse etmek için Jackson veya Gson kullanabilirsiniz
        if (response.isSuccessful()) {
            System.out.println("License is valid!");
        } else {
            System.out.println("License validation failed!");
        }
    }
}

JavaScript (Fetch):

javascript
async function validateLicense() {
    const validateData = {
        product_id: 'my-app',
        user_id: 'user123'
    };
    
    try {
        const response = await fetch(`${BASE_URL}/api/licenses/validate`, {
            method: 'POST',
            headers: {
                'X-API-Key': API_KEY,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(validateData)
        });
        
        const data = await response.json();
        
        if (data.data && data.data.valid) {
            console.log('✅ License is valid!');
        } else {
            console.log('❌ License is invalid!');
        }
        
        console.log('Validation result:', data);
    } catch (error) {
        console.error('Error:', error);
    }
}

PHP (cURL):

php
function validateLicense() {
    global $baseUrl, $apiKey;
    
    $validateData = [
        'product_id' => 'my-app',
        'user_id' => 'user123'
    ];
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $baseUrl . '/api/licenses/validate');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($validateData));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'X-API-Key: ' . $apiKey,
        'Content-Type: application/json'
    ]);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    $data = json_decode($response, true);
    
    if ($httpCode === 200 && isset($data['data']['valid']) && $data['data']['valid']) {
        echo "✅ License is valid!\n";
    } else {
        echo "❌ License is invalid!\n";
    }
    
    echo "Validation result: " . print_r($data, true);
}

5. MID ile Lisans Getir

http
GET /api/licenses/get-by-mid/{mid}

Örnek Kodlar:

Java (OkHttp):

java
public static void getLicenseByMid(String mid) throws IOException {
    OkHttpClient client = new OkHttpClient();
    
    Request request = new Request.Builder()
        .url(BASE_URL + "/api/licenses/get-by-mid/" + mid)
        .addHeader("X-API-Key", API_KEY)
        .get()
        .build();
        
    try (Response response = client.newCall(request).execute()) {
        System.out.println("License: " + response.body().string());
    }
}

JavaScript (Fetch):

javascript
async function getLicenseByMid(mid) {
    try {
        const response = await fetch(`${BASE_URL}/api/licenses/get-by-mid/${mid}`, {
            method: 'GET',
            headers: {
                'X-API-Key': API_KEY,
                'Content-Type': 'application/json'
            }
        });
        
        const data = await response.json();
        console.log('License:', data);
    } catch (error) {
        console.error('Error:', error);
    }
}

PHP (cURL):

php
function getLicenseByMid($mid) {
    global $baseUrl, $apiKey;
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $baseUrl . '/api/licenses/get-by-mid/' . urlencode($mid));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'X-API-Key: ' . $apiKey,
        'Content-Type: application/json'
    ]);
    
    $response = curl_exec($ch);
    curl_close($ch);
    
    $data = json_decode($response, true);
    echo "License: " . print_r($data, true);
}

6. MID Prefix ile Lisansları Listele

http
GET /api/licenses/list-by-mid/{mid_prefix}

Örnek Kodlar:

Java (OkHttp):

java
public static void listLicensesByMidPrefix(String midPrefix) throws IOException {
    OkHttpClient client = new OkHttpClient();
    
    Request request = new Request.Builder()
        .url(BASE_URL + "/api/licenses/list-by-mid/" + midPrefix)
        .addHeader("X-API-Key", API_KEY)
        .get()
        .build();
        
    try (Response response = client.newCall(request).execute()) {
        System.out.println("Licenses with prefix: " + response.body().string());
    }
}

JavaScript (Fetch):

javascript
async function listLicensesByMidPrefix(midPrefix) {
    try {
        const response = await fetch(`${BASE_URL}/api/licenses/list-by-mid/${midPrefix}`, {
            method: 'GET',
            headers: {
                'X-API-Key': API_KEY,
                'Content-Type': 'application/json'
            }
        });
        
        const data = await response.json();
        console.log('Licenses with prefix:', data);
    } catch (error) {
        console.error('Error:', error);
    }
}

PHP (cURL):

php
function listLicensesByMidPrefix($midPrefix) {
    global $baseUrl, $apiKey;
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $baseUrl . '/api/licenses/list-by-mid/' . urlencode($midPrefix));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'X-API-Key: ' . $apiKey,
        'Content-Type: application/json'
    ]);
    
    $response = curl_exec($ch);
    curl_close($ch);
    
    $data = json_decode($response, true);
    echo "Licenses with prefix: " . print_r($data, true);
}

Tam Örnek: MSC Client Sınıfları

Java Client Sınıfı:

java
import okhttp3.*;
import java.io.IOException;

public class MSCClient {
    private static final String BASE_URL = "http://localhost:4050";
    private final String apiKey;
    private final OkHttpClient client;
    
    public MSCClient(String apiKey) {
        this.apiKey = apiKey;
        this.client = new OkHttpClient();
    }
    
    public String listLicenses() throws IOException {
        Request request = new Request.Builder()
            .url(BASE_URL + "/api/licenses/list")
            .addHeader("X-API-Key", apiKey)
            .get()
            .build();
            
        try (Response response = client.newCall(request).execute()) {
            return response.body().string();
        }
    }
    
    public String createLicense(String productId, String userId, String ipAddress) throws IOException {
        String jsonBody = String.format(
            "{\"product_id\":\"%s\",\"user_id\":\"%s\",\"ip_address\":\"%s\"}",
            productId, userId, ipAddress
        );
        
        RequestBody body = RequestBody.create(jsonBody, MediaType.get("application/json"));
        Request request = new Request.Builder()
            .url(BASE_URL + "/api/licenses/create")
            .addHeader("X-API-Key", apiKey)
            .post(body)
            .build();
            
        try (Response response = client.newCall(request).execute()) {
            return response.body().string();
        }
    }
    
    public String validateLicense(String productId, String userId) throws IOException {
        String jsonBody = String.format(
            "{\"product_id\":\"%s\",\"user_id\":\"%s\"}",
            productId, userId
        );
        
        RequestBody body = RequestBody.create(jsonBody, MediaType.get("application/json"));
        Request request = new Request.Builder()
            .url(BASE_URL + "/api/licenses/validate")
            .addHeader("X-API-Key", apiKey)
            .post(body)
            .build();
            
        try (Response response = client.newCall(request).execute()) {
            return response.body().string();
        }
    }
}

// Kullanım
MSCClient client = new MSCClient("your-api-key-here");
String licenses = client.listLicenses();
System.out.println(licenses);

JavaScript Client Sınıfı:

javascript
class MSCClient {
    constructor(apiKey, baseUrl = 'http://localhost:4050') {
        this.apiKey = apiKey;
        this.baseUrl = baseUrl;
    }
    
    async request(endpoint, options = {}) {
        const url = `${this.baseUrl}${endpoint}`;
        const config = {
            headers: {
                'X-API-Key': this.apiKey,
                'Content-Type': 'application/json',
                ...options.headers
            },
            ...options
        };
        
        const response = await fetch(url, config);
        return await response.json();
    }
    
    async listLicenses() {
        return await this.request('/api/licenses/list', { method: 'GET' });
    }
    
    async createLicense(productId, userId, ipAddress) {
        const data = { product_id: productId, user_id: userId, ip_address: ipAddress };
        return await this.request('/api/licenses/create', {
            method: 'POST',
            body: JSON.stringify(data)
        });
    }
    
    async validateLicense(productId, userId) {
        const data = { product_id: productId, user_id: userId };
        return await this.request('/api/licenses/validate', {
            method: 'POST',
            body: JSON.stringify(data)
        });
    }
    
    async deleteLicense(mid) {
        const data = { mid: mid };
        return await this.request('/api/licenses/delete', {
            method: 'DELETE',
            body: JSON.stringify(data)
        });
    }
}

// Kullanım
const client = new MSCClient('your-api-key-here');
client.listLicenses().then(licenses => console.log(licenses));

PHP Client Sınıfı:

php
<?php
class MSCClient {
    private $apiKey;
    private $baseUrl;
    
    public function __construct($apiKey, $baseUrl = 'http://localhost:4050') {
        $this->apiKey = $apiKey;
        $this->baseUrl = $baseUrl;
    }
    
    private function request($endpoint, $method = 'GET', $data = null) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $this->baseUrl . $endpoint);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'X-API-Key: ' . $this->apiKey,
            'Content-Type: application/json'
        ]);
        
        if ($method === 'POST') {
            curl_setopt($ch, CURLOPT_POST, true);
            if ($data) {
                curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
            }
        } elseif ($method === 'DELETE') {
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
            if ($data) {
                curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
            }
        }
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        return [
            'status' => $httpCode,
            'data' => json_decode($response, true)
        ];
    }
    
    public function listLicenses() {
        return $this->request('/api/licenses/list');
    }
    
    public function createLicense($productId, $userId, $ipAddress) {
        $data = [
            'product_id' => $productId,
            'user_id' => $userId,
            'ip_address' => $ipAddress
        ];
        return $this->request('/api/licenses/create', 'POST', $data);
    }
    
    public function validateLicense($productId, $userId) {
        $data = [
            'product_id' => $productId,
            'user_id' => $userId
        ];
        return $this->request('/api/licenses/validate', 'POST', $data);
    }
    
    public function deleteLicense($mid) {
        $data = ['mid' => $mid];
        return $this->request('/api/licenses/delete', 'DELETE', $data);
    }
}

// Kullanım
$client = new MSCClient('your-api-key-here');
$result = $client->listLicenses();
print_r($result);
?>

🔒 Güvenlik Özellikleri

1. Uygulama Bütünlük Kontrolü

  • Çalıştırılabilir dosyanın SHA256 hash'i kontrol edilir
  • .sha256 dosyası ile karşılaştırılır
  • Bütünlük ihlali durumunda sistem durdurulur

2. Sürekli Lisans Doğrulama

  • Arka planda her saniye lisans sunucusu kontrol edilir
  • DNS manipülasyonu ve IP değişiklikleri tespit edilir
  • Güvenlik ihlali durumunda sistem otomatik olarak durdurulur

3. API Key Kimlik Doğrulama

  • Tüm API endpointleri admin API key gerektirir
  • 64 karakterlik rastgele API anahtarları
  • Kullanıcı bazlı erişim kontrolü

4. IP Bazlı Lisanslama

  • Lisanslar belirli IP adreslerine bağlıdır
  • IP değişikliği durumunda lisans geçersiz hale gelir

🐛 Sorun Giderme

Yaygın Sorunlar

  1. "Güvenlik ihlali" hatası

    • .sha256 dosyasının mevcut olduğundan emin olun
    • Çalıştırılabilir dosyanın değiştirilmediğini kontrol edin
  2. "Lisans sunucusuna ulaşılamıyor"

    • İnternet bağlantınızı kontrol edin
    • DNS ayarlarınızı kontrol edin
    • Firewall ayarlarını kontrol edin
  3. "API anahtarı geçersiz"

    • Doğru API anahtarını kullandığınızdan emin olun
    • Admin kullanıcısı için API anahtarı oluşturun

Logları İzleme

bash
# Logları dosyaya yönlendir
./msc start > msc.log 2>&1 &

# Logları canlı izle
tail -f msc.log

Magnesify Sovereign Cloud - Güvenli ve güvenilir lisans yönetimi