Skip to content

EGate is a lightweight, HWID-locked license key system with a built-in admin panel, REST API, and optional web UI — perfect for protecting paid features in apps or scripts. Built for Vercel + GitHub

License

Notifications You must be signed in to change notification settings

eman225511/EGate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

53 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🔐 EGate

HWID-Locked License Key System & Admin Dashboard
Modern, serverless, and secure. Protect your premium apps, bots, or scripts.

License: MIT Made by Eman

Deploy to Vercel

EGate is a modern, serverless license key system with HWID binding, admin key management, and a simple web UI.
Protect your premium CLI tools, desktop apps, bots, or scripts with ease.


📦 Features

  • Serverless — Powered by Vercel Functions
  • 🔒 HWID Binding — Lock license keys to a single device
  • Email Binding — Associate email addresses with license keys (one-to-one)
  • �🔁 User HWID Reset — One reset per 24 hours (configurable)
  • 🛠️ Admin Panel — Create, delete, inspect, or purge keys (password protected)
  • 🐙 GitHub Storage — All keys are stored in your private repo's keys.json
  • 🌐 Simple Web UI — HTML frontend for users and admins

🎛️ Admin Panel

EGate Admin Panel — A dedicated web-based admin interface for managing your EGate API with enhanced features and a modern UI.

Features:

  • 🖥️ Modern Web Interface — Clean, responsive admin dashboard
  • 🔑 Key Management — Create, view, delete, and manage license keys
  • 🔐 Secure Authentication — Protected admin access

Perfect for: Users who prefer a dedicated admin interface over the built-in web UI for managing their EGate license system.

🌐 Live Demo: EGate-Admin-Panel.vercel.app
Repository: github.com/eman225511/EGate-Admin-Panel


⚙️ Environment Variables

How to set these in Vercel

Go to Vercel Dashboard → Project → Settings → Environment Variables

Set these in your Vercel Project Settings > Environment Variables

Name Required Example Description
ADMIN_PASSWORD supersecret123 Password for admin endpoints
GITHUB_TOKEN ghp_xxx GitHub PAT with repo access
GITHUB_OWNER eman225511 Your GitHub username
GITHUB_REPO EGate-Keys Repo where keys.json lives
GITHUB_BRANCH main (default) Branch for keys.json

🚀 Quickstart

  1. Fork or clone this repo to your private GitHub account.

  2. Ensure a keys.json file exists at the root (just {} for empty).

  3. Import to Vercel and set the required environment variables above.

  4. Deploy and visit your API/UI at:

    https://your-vercel-app.vercel.app/
    

🛠️ Requirements

  • Vercel account (for serverless API & frontend)
  • GitHub account with a private repo containing keys.json ({})
  • GitHub Personal Access Token (PAT) with repo access (for reading/writing keys)

2. ⚡ Setup & Deploy

All-in-one: This repo contains both the API (serverless functions) and the optional web frontend. Vercel will serve both from the same project.

  1. Fork or clone this repo to your private GitHub account.
  2. In your repo, ensure there is a keys.json file at the root (just {} for empty).
  3. Go to Vercel and import your private repo.
  4. In Vercel, set the required environment variables (see table above):
    • ADMIN_PASSWORD, GITHUB_TOKEN, GITHUB_OWNER, GITHUB_REPO, and optionally GITHUB_BRANCH.
  5. Deploy the project.
  6. Visit your deployed API and frontend at:
https://your-vercel-app.vercel.app/

🔌 API Endpoints

All requests are GET with query parameters. All endpoints are served from your Vercel deployment, e.g. https://your-vercel-app.vercel.app/api/ENDPOINT.

/verify — Key Verification & HWID Binding

Purpose: Verify a license key and bind it to a hardware ID (HWID) on first use, or validate existing HWID binding.

Parameters:

  • key (required) — The license key to verify (e.g., ABCD-1234-EFGH)
  • hwid (required) — Hardware ID to bind/verify (e.g., device MAC address, CPU ID, etc.)

Behavior:

  • First call: Binds the key to the provided HWID and returns key bound to hwid
  • Subsequent calls: If HWID matches, returns key verified
  • If HWID does not match, returns hwid mismatch (403)
  • If key not found, returns key not found (404)

Example Request:

GET /api/verify?key=ABCD-1234-EFGH&hwid=MAC-00-11-22-33-44-55

Response Examples:

"key bound to hwid"
"key verified"
"hwid mismatch"
"key not found"

/reset — HWID Reset (User)

Purpose: Reset the HWID binding for a key, allowing it to be bound to a new device. Limited to once every 24 hours per key.

Parameters:

  • key (required) — The license key to reset

Cooldown: 24 hours (configurable in api/reset.js)

Example Request:

GET /api/reset?key=ABCD-1234-EFGH

Response Examples:

"hwid reset"
"cooldown: try again in X hours"
"key not found"

Customization: To change the cooldown period, edit line 3 in api/reset.js:

const Reset_Delay_Hours = 24; // Change this for a different delay

/make (Admin Only)

Purpose: Generate a new random license key.

Parameters:

  • admin (required) — Admin password (set via ADMIN_PASSWORD environment variable)

Example Request:

GET /api/make?admin=supersecret123

Response Examples:

<new-key-string>
"invalid admin password"

/info (Admin Only)

Purpose: View information about a specific license key.

Parameters:

  • key (required) — The license key to inspect
  • admin (required) — Admin password

Example Request:

GET /api/info?key=ABCD-1234-EFGH&admin=supersecret123

Response Examples:

{
  "hwid": "MAC-00-11-22-33-44-55",
  "last_reset": "2025-01-20T15:45:00.000Z"
}
"Key not found"
"Forbidden"

/delete (Admin Only)

Purpose: Permanently delete a specific license key.

Parameters:

  • key (required) — The license key to delete
  • admin (required) — Admin password

Example Request:

GET /api/delete?key=ABCD-1234-EFGH&admin=supersecret123

Response Examples:

"Key deleted"
"Key not found"
"Forbidden"

/deleteAll (Admin Only)

Purpose: DANGER ZONE — Permanently delete ALL license keys. Use with extreme caution!

Parameters:

  • admin (required) — Admin password

Example Request:

GET /api/deleteAll?admin=supersecret123

Response Examples:

"All keys deleted"
"Forbidden"

/adminReset (Admin Only)

Purpose: Instantly reset the HWID for any key (no cooldown, admin only).

Parameters:

  • key (required) — The license key to reset
  • admin (required) — Admin password

Example Request:

GET /api/adminReset?key=ABCD-1234-EFGH&admin=supersecret123

Response Examples:

"admin hwid reset successful"
"key not found"
"Forbidden"

/dump (Admin Only)

Purpose: Fetch and return the full keys.json contents as JSON. Useful for backup, inspection, or exporting all license keys at once.

Parameters:

  • key (required) — Admin password (same as ADMIN_PASSWORD env var)

Example Request: GET /api/dump?admin=YOUR_PASSWORD

Returns the current keys.json from the GitHub repo. Requires admin password via query string.

Query Parameters:

  • admin – Required. Admin password (set in ADMIN_PASSWORD environment variable).

Response:

{
  "keys": {
    "exampleKey": {
      "hwid": "1234567890",
      "created": "2025-07-31T00:00:00Z",
    }
  }
}
Errors:
	403 Forbidden – if password is invalid
	500 Internal Server Error – if GitHub fetch fails

/bindEmail — Email Binding

Purpose: Bind an email address to a license key. Each email can only be bound to one key, and each key can only have one email.

Parameters:

  • key (required) — The license key to bind the email to
  • email (required) — Email address to bind (must be valid format)

Behavior:

  • Validates email format using regex
  • Prevents duplicate email bindings across keys
  • Prevents multiple emails per key
  • Records binding timestamp

Example Request:

GET /api/bindEmail?key=ABCD-1234-EFGH&email=user@example.com

Response Examples:

"email successfully bound to key"
"email already bound to another key"
"key already has email bound: user@example.com"
"invalid email format"
"key not found"

/checkKey — Key Information (Public)

Purpose: Get basic information about a license key without requiring admin access.

Parameters:

  • key (required) — The license key to check

Example Request:

GET /api/checkKey?key=ABCD-1234-EFGH

Response Examples:

{
  "exists": true,
  "hasEmail": true,
  "email": "user@example.com",
  "hasHwid": true,
  "created": "2025-08-03T12:34:56.789Z",
  "emailBoundAt": "2025-08-03T13:00:00.123Z"
}
{
  "error": "key not found"
}

/resetEmail (Admin Only)

Purpose: Reset the email binding for a license key, allowing a new email to be bound. This is an admin-only operation.

Parameters:

  • key (required) — The license key to reset email for
  • admin (required) — Admin password

Behavior:

  • Removes the email binding from the specified key
  • Records the reset timestamp in email_reset_at
  • Removes the email_bound_at timestamp
  • Only works if the key currently has an email bound

Example Request:

GET /api/resetEmail?key=ABCD-1234-EFGH&admin=supersecret123

Response Examples:

"email reset successfully"
"key has no email bound"
"key not found"
"Forbidden"

ping.js

A lightweight endpoint to verify if the EGate API is online. Useful for uptime checks or basic health monitoring.

➤ Method

GET

➤ Example Request GET https://your-egate.vercel.app/api/ping

➤ Example Response

{
  "status": "ok",
  "timestamp": "2025-08-01T01:23:45.678Z"
}

💻 API Usage Examples

Python

import requests

BASE = "https://your-vercel-app.vercel.app/api"
ADMIN_PASSWORD = "supersecret123"

# Helper: Print status and body
def print_response(resp):
    print(f"Status: {resp.status_code}")
    print(f"Body: {resp.text}")

# Example 1: Verify a key and bind HWID (first time)
def verify_key(key, hwid):
    resp = requests.get(f"{BASE}/verify", params={"key": key, "hwid": hwid})
    print_response(resp)
    return resp.text

# Example 2: Reset HWID (user)
def reset_hwid(key):
    resp = requests.get(f"{BASE}/reset", params={"key": key})
    print_response(resp)
    return resp.text

# Example 3: Generate new key (admin)
def create_new_key():
    resp = requests.get(f"{BASE}/make", params={"admin": ADMIN_PASSWORD})
    print_response(resp)
    return resp.text

# Example 4: Get key information (admin)
def get_key_info(key):
    resp = requests.get(f"{BASE}/info", params={"key": key, "admin": ADMIN_PASSWORD})
    print_response(resp)
    try:
        return resp.json()
    except Exception:
        return resp.text

# Example 5: Force reset HWID (admin)
def admin_reset_hwid(key):
    resp = requests.get(f"{BASE}/adminReset", params={"key": key, "admin": ADMIN_PASSWORD})
    print_response(resp)
    return resp.text

def delete_key(key):
    resp = requests.get(f"{BASE}/delete", params={"key": key, "admin": ADMIN_PASSWORD})
    print_response(resp)
    return resp.text

# Example 6: Bind email to key
def bind_email(key, email):
    resp = requests.get(f"{BASE}/bindEmail", params={"key": key, "email": email})
    print_response(resp)
    return resp.text

# Example 7: Check key information (public)
def check_key_info(key):
    resp = requests.get(f"{BASE}/checkKey", params={"key": key})
    print_response(resp)
    try:
        return resp.json()
    except Exception:
        return resp.text

# Example 8: Reset email binding (admin)
def reset_email(key):
    resp = requests.get(f"{BASE}/resetEmail", params={"key": key, "admin": ADMIN_PASSWORD})
    print_response(resp)
    return resp.text

# Usage example:
if __name__ == "__main__":
    # Create a new key
    new_key = create_new_key().strip()
    # Bind email to key
    bind_email(new_key, "user@example.com")
    # Check key info (public endpoint)
    key_info = check_key_info(new_key)
    # Verify and bind the key
    verify_key(new_key, "MAC-00-11-22-33-44-55")
    # Get admin key info
    get_key_info(new_key)
    # Reset email binding (admin)
    reset_email(new_key)
    # Bind new email
    bind_email(new_key, "newemail@example.com")
    # Admin HWID reset
    admin_reset_hwid(new_key)

# Example 9: Delete a specific key (admin)
def delete_key(key):
    resp = requests.get(f"{BASE}/delete", params={"key": key, "admin": ADMIN_PASSWORD})
    print_response(resp)
    return resp.text

# Usage example:
if __name__ == "__main__":
    # Generate a new key
    new_key_response = create_new_key()
    # Extract key from response (assumes format "New key: XXXX-YYYY-ZZZZ")
    if "New key:" in new_key_response:
        key = new_key_response.split("New key: ")[1].strip()
        # Verify and bind the key
        verify_key(key, "MAC-00-11-22-33-44-55")
        # Get key information
        info = get_key_info(key)
        # Reset HWID (admin)
        admin_reset_hwid(key)

JavaScript (Node.js)

const BASE = "https://your-vercel-app.vercel.app/api";
const ADMIN_PASSWORD = "supersecret123";

// Helper: Print status and body
async function printResponse(response) {
    console.log('Status:', response.status);
    const text = await response.text();
    console.log('Body:', text);
    return text;
}

// Example 1: Verify key with async/await and status check
async function verifyKey(key, hwid) {
    try {
        const response = await fetch(`${BASE}/verify?key=${key}&hwid=${hwid}`);
        await printResponse(response);
        if (response.status === 200) {
            // Success
        } else {
            // Handle error
        }
    } catch (error) {
        console.error('Error verifying key:', error);
    }
}

// Example 2: Create new key (admin)
async function createNewKey() {
    try {
        const response = await fetch(`${BASE}/make?admin=${ADMIN_PASSWORD}`);
        await printResponse(response);
    } catch (error) {
        console.error('Error creating key:', error);
    }
}

// Example 3: Get key info with error handling
async function getKeyInfo(key) {
    try {
        const response = await fetch(`${BASE}/info?key=${key}&admin=${ADMIN_PASSWORD}`);
        const text = await printResponse(response);
        try {
            const jsonResult = JSON.parse(text);
            console.log('Key Info (JSON):', jsonResult);
            return jsonResult;
        } catch {
            return text;
        }
    } catch (error) {
        console.error('Error getting key info:', error);
    }
}

// Example 4: Complete workflow
async function exampleWorkflow() {
    // Create a new key
    const response = await fetch(`${BASE}/make?admin=${ADMIN_PASSWORD}`);
    const newKeyResponse = await printResponse(response);
    if (newKeyResponse && newKeyResponse.includes('New key:')) {
        const key = newKeyResponse.split('New key: ')[1].trim();
        // Verify the key with different HWIDs
        await verifyKey(key, 'device-001');
        await verifyKey(key, 'device-002'); // This should fail
        // Get key information
        await getKeyInfo(key);
        // Reset HWID as admin
        const resetResponse = await fetch(`${BASE}/adminReset?key=${key}&admin=${ADMIN_PASSWORD}`);
        await printResponse(resetResponse);
    }
}

// Run the workflow
exampleWorkflow();

JavaScript (Browser/Frontend)

const API_BASE = "https://your-vercel-app.vercel.app/api";

// Example license verification form handler
document.getElementById('verifyForm').addEventListener('submit', async (e) => {
    e.preventDefault();
    
    const key = document.getElementById('keyInput').value;
    const hwid = document.getElementById('hwidInput').value;
    
    try {
        const response = await fetch(`${API_BASE}/verify?key=${key}&hwid=${hwid}`);
        const result = await response.text();
        
        document.getElementById('result').textContent = result;
        
        if (result.includes('verified')) {
            document.getElementById('result').className = 'success';
        } else {
            document.getElementById('result').className = 'error';
        }
    } catch (error) {
        document.getElementById('result').textContent = 'Network error: ' + error.message;
        document.getElementById('result').className = 'error';
    }
});

// Example admin panel functions
class EGateAdmin {
    constructor(apiBase, adminPassword) {
        this.api = apiBase;
        this.password = adminPassword;
    }
    
    async createKey() {
        const response = await fetch(`${this.api}/make?admin=${this.password}`);
        return await response.text();
    }
    
    async deleteKey(key) {
        const response = await fetch(`${this.api}/delete?key=${key}&admin=${this.password}`);
        return await response.text();
    }
    
    async getKeyInfo(key) {
        const response = await fetch(`${this.api}/info?key=${key}&admin=${this.password}`);
        const text = await response.text();
        try {
            return JSON.parse(text);
        } catch {
            return text;
        }
    }
}

// Usage
const admin = new EGateAdmin(API_BASE, 'yourpassword');

curl (Command Line)

# Set your API base URL
API_BASE="https://your-vercel-app.vercel.app/api"
ADMIN_PASSWORD="supersecret123"

# Example 1: Verify a key and bind HWID (shows status)
curl -i -G "$API_BASE/verify" \
  --data-urlencode "key=ABCD-1234-EFGH" \
  --data-urlencode "hwid=MAC-00-11-22-33-44-55"

# Example 2: Reset HWID (user)
curl -i -G "$API_BASE/reset" \
  --data-urlencode "key=ABCD-1234-EFGH"

# Example 3: Create new key (admin)
curl -i -G "$API_BASE/make" \
  --data-urlencode "admin=${ADMIN_PASSWORD}"

# Example 4: Get key information (admin) - formatted JSON output
curl -i -G "$API_BASE/info" \
  --data-urlencode "key=ABCD-1234-EFGH" \
  --data-urlencode "admin=${ADMIN_PASSWORD}" | jq '.'

# Example 5: Force reset HWID (admin)
curl -i -G "$API_BASE/adminReset" \
  --data-urlencode "key=ABCD-1234-EFGH" \
  --data-urlencode "admin=${ADMIN_PASSWORD}"

# Example 6: Delete a key (admin)
curl -i -G "$API_BASE/delete" \
  --data-urlencode "key=ABCD-1234-EFGH" \
  --data-urlencode "admin=${ADMIN_PASSWORD}"

# Example 7: Batch operations script (shows status)
#!/bin/bash
API_BASE="https://your-vercel-app.vercel.app/api"
ADMIN_PASSWORD="supersecret123"

echo "Creating 5 new keys..."
for i in {1..5}; do
    echo "Key $i:"
    curl -i -s -G "$API_BASE/make" --data-urlencode "admin=${ADMIN_PASSWORD}"
    echo
done

echo -e "\nDone creating keys!"

PowerShell (Windows)

# PowerShell examples for Windows users
$API_BASE = "https://your-vercel-app.vercel.app/api"
$ADMIN_PASSWORD = "supersecret123"

# Helper: Print status and body
function Print-ApiResponse {
    param($Response)
    Write-Host "Status: $($Response.StatusCode)" -ForegroundColor Yellow
    Write-Host "Body: $($Response.Content.ReadAsStringAsync().Result)" -ForegroundColor Cyan
}

# Function to verify a key
function Verify-EGateKey {
    param(
        [string]$Key,
        [string]$HWID
    )
    $uri = "$API_BASE/verify?key=$Key&hwid=$HWID"
    try {
        $response = Invoke-WebRequest -Uri $uri -Method Get
        Print-ApiResponse $response
        return $response.Content
    }
    catch {
        Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red
    }
}

# Function to create a new key
function New-EGateKey {
    $uri = "$API_BASE/make?admin=$ADMIN_PASSWORD"
    try {
        $response = Invoke-WebRequest -Uri $uri -Method Get
        Print-ApiResponse $response
        return $response.Content
    }
    catch {
        Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red
    }
}

# Function to get key information
function Get-EGateKeyInfo {
    param([string]$Key)
    $uri = "$API_BASE/info?key=$Key&admin=$ADMIN_PASSWORD"
    try {
        $response = Invoke-WebRequest -Uri $uri -Method Get
        Print-ApiResponse $response
        return $response.Content
    }
    catch {
        Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red
    }
}

# Example usage
$newKey = New-EGateKey
if ($newKey -match "New key: (.+)") {
    $keyValue = $matches[1].Trim()
    Write-Host "Extracted key: $keyValue"
    # Verify the key
    Verify-EGateKey -Key $keyValue -HWID "WIN-PC-12345"
    # Get key info
    Get-EGateKeyInfo -Key $keyValue
}

Tip: Always check both the HTTP status code and the response body for errors or success. The API uses standard status codes for error handling, so robust clients should not assume 200 for all responses.


📊 Response Codes & Error Handling

HTTP Status Codes

API endpoints return standard HTTP status codes. The most common are:

Status Code Meaning
200 Success
400 Bad Request (missing/invalid parameters)
403 Forbidden (wrong admin password, HWID mismatch)
404 Not Found (key not found)
405 Method Not Allowed
429 Too Many Requests (cooldown active)
500 Internal Server Error

Check both the status code and response body for the result.

Common Response Messages

Response When/Why
"key bound to hwid" First-time verification, HWID is now bound
"key verified" HWID matches, key is valid
"hwid mismatch" HWID does not match bound HWID (403)
"key not found" Key does not exist (404)
"hwid reset" HWID reset successful
"cooldown: try again in X hours" HWID reset attempted too soon (429)
"invalid admin password" Wrong admin password (403, /make)
"Forbidden" Wrong admin password (403, admin endpoints)
"Key deleted" Key deleted (admin)
"All keys deleted" All keys deleted (admin)
"admin hwid reset successful" Admin forced HWID reset

Error Handling Best Practices

Python Example with Comprehensive Error Handling

import requests
import time
from typing import Dict, Union

class EGateClient:
    def __init__(self, api_base: str, admin_password: str = None):
        self.api_base = api_base
        self.admin_password = admin_password
    
    def verify_key(self, key: str, hwid: str) -> Dict[str, Union[str, bool]]:
        """Verify a key with comprehensive error handling"""
        try:
            response = requests.get(
                f"{self.api_base}/verify",
                params={"key": key, "hwid": hwid},
                timeout=10
            )
            
            result = response.text.strip()
            
            if "key verified and hwid bound" in result:
                return {"success": True, "message": result, "bound": True}
            elif "key and hwid verified" in result:
                return {"success": True, "message": result, "bound": False}
            elif "invalid key" in result:
                return {"success": False, "error": "INVALID_KEY", "message": result}
            elif "hwid mismatch" in result:
                return {"success": False, "error": "HWID_MISMATCH", "message": result}
            else:
                return {"success": False, "error": "UNKNOWN", "message": result}
                
        except requests.exceptions.Timeout:
            return {"success": False, "error": "TIMEOUT", "message": "Request timed out"}
        except requests.exceptions.RequestException as e:
            return {"success": False, "error": "NETWORK", "message": str(e)}
    
    def reset_hwid_with_retry(self, key: str, max_retries: int = 3) -> Dict[str, Union[str, bool]]:
        """Reset HWID with automatic retry on cooldown"""
        for attempt in range(max_retries):
            try:
                response = requests.get(f"{self.api_base}/reset", params={"key": key})
                result = response.text.strip()
                
                if "hwid reset successful" in result:
                    return {"success": True, "message": result}
                elif "reset cooldown active" in result:
                    # Extract hours from message if possible
                    import re
                    hours_match = re.search(r'(\d+(?:\.\d+)?)\s*hours?', result)
                    if hours_match and attempt < max_retries - 1:
                        hours = float(hours_match.group(1))
                        if hours <= 1:  # Only wait if it's reasonable
                            print(f"Cooldown active, waiting {hours * 3600:.0f} seconds...")
                            time.sleep(hours * 3600)
                            continue
                    return {"success": False, "error": "COOLDOWN", "message": result}
                else:
                    return {"success": False, "error": "OTHER", "message": result}
                    
            except Exception as e:
                if attempt == max_retries - 1:
                    return {"success": False, "error": "NETWORK", "message": str(e)}
                time.sleep(2 ** attempt)  # Exponential backoff
        
        return {"success": False, "error": "MAX_RETRIES", "message": "Max retries exceeded"}

# Usage example
client = EGateClient("https://your-app.vercel.app/api", "admin123")

# Verify with error handling
result = client.verify_key("ABCD-1234", "device-001")
if result["success"]:
    print(f"✅ Verification successful: {result['message']}")
else:
    print(f"❌ Verification failed: {result['error']} - {result['message']}")

JavaScript Example with Promise-based Error Handling

class EGateAPI {
    constructor(baseUrl, adminPassword = null) {
        this.baseUrl = baseUrl;
        this.adminPassword = adminPassword;
    }
    
    async makeRequest(endpoint, params = {}) {
        const url = new URL(`${this.baseUrl}/${endpoint}`);
        Object.keys(params).forEach(key => {
            if (params[key] !== null && params[key] !== undefined) {
                url.searchParams.append(key, params[key]);
            }
        });
        
        try {
            const response = await fetch(url, { method: 'GET' });
            
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}: ${response.statusText}`);
            }
            
            const text = await response.text();
            return { success: true, data: text };
            
        } catch (error) {
            return { success: false, error: error.message };
        }
    }
    
    async verifyKey(key, hwid) {
        const result = await this.makeRequest('verify', { key, hwid });
        
        if (!result.success) {
            return { success: false, error: 'NETWORK_ERROR', message: result.error };
        }
        
        const message = result.data.trim();
        
        if (message.includes('key verified and hwid bound')) {
            return { success: true, status: 'BOUND', message };
        } else if (message.includes('key and hwid verified')) {
            return { success: true, status: 'VERIFIED', message };
        } else if (message.includes('invalid key')) {
            return { success: false, error: 'INVALID_KEY', message };
        } else if (message.includes('hwid mismatch')) {
            return { success: false, error: 'HWID_MISMATCH', message };
        } else {
            return { success: false, error: 'UNKNOWN', message };
        }
    }
    
    async createKeyWithValidation() {
        if (!this.adminPassword) {
            return { success: false, error: 'NO_ADMIN_PASSWORD', message: 'Admin password required' };
        }
        
        const result = await this.makeRequest('make', { admin: this.adminPassword });
        
        if (!result.success) {
            return { success: false, error: 'NETWORK_ERROR', message: result.error };
        }
        
        const message = result.data.trim();
        
        if (message.includes('New key:')) {
            const key = message.replace('New key:', '').trim();
            return { success: true, key, message };
        } else if (message.includes('forbidden')) {
            return { success: false, error: 'UNAUTHORIZED', message };
        } else {
            return { success: false, error: 'UNKNOWN', message };
        }
    }
}

// Usage with proper error handling
async function handleLicenseVerification(api, licenseKey, deviceId) {
    try {
        const result = await api.verifyKey(licenseKey, deviceId);
        
        if (result.success) {
            switch (result.status) {
                case 'BOUND':
                    console.log('🔗 License bound to this device');
                    return true;
                case 'VERIFIED':
                    console.log('✅ License verified successfully');
                    return true;
            }
        } else {
            switch (result.error) {
                case 'INVALID_KEY':
                    console.log('❌ Invalid license key');
                    break;
                case 'HWID_MISMATCH':
                    console.log('⚠️ License is bound to a different device');
                    // Offer HWID reset option
                    break;
                case 'NETWORK_ERROR':
                    console.log('🌐 Network error:', result.message);
                    // Implement retry logic
                    break;
                default:
                    console.log('❓ Unknown error:', result.message);
            }
            return false;
        }
    } catch (error) {
        console.error('💥 Unexpected error:', error);
        return false;
    }
}

🌐 Web UI (index.html, reset.html)

🌐 Main Page

  • 🔐 Check Key
  • 🔁 Reset HWID
  • 📧 Bind Email to Key
  • 🧑‍💼 Admin Panel (make, delete, inspect, force reset keys)

📌 Configure your API URL: In index.html, set your deployed API base URL on line 126:

const API = "https://key-sys-web.vercel.app/api";

🌐 User Reset Page

A standalone page for users to easily reset their HWID binding without needing the full admin panel.

🔗 reset.html

  • Purpose: Allows end-users to reset their license key's HWID using just the key (no admin login required).
  • Endpoint Called: GET /api/reset?key=YOUR_LICENSE_KEY
  • Validates: Cooldown and key existence.
  • Displays: Clear feedback messages (e.g. "hwid reset", "cooldown", "key not found").

🧪 Usage

  1. Upload reset.html to the root of your Vercel deployment (same folder as index.html).
  2. Users visit: https://your-vercel-app.vercel.app/reset.html
  3. Enter license key and hit Reset HWID.

📦 Developer Notes

  • Works with your existing /api/reset endpoint (GET-based).
  • Handles all common status codes:
  • 200 → success: ✅ hwid reset
  • 429 → cooldown active: ❌ cooldown: try again in X hours
  • 404 → invalid key: ❌ key not found
  • 500 → server error

🗂️ Project Structure

EGate/
├── api/                        # 🔌 Serverless API endpoints (Vercel Functions)
│   ├── make.js                 # 🔑 Generate new license keys (admin)
│   ├── verify.js               # ✅ Verify keys & bind/validate HWID
│   ├── reset.js                # 🔄 User HWID reset (24h cooldown)
│   ├── info.js                 # 📋 Get key information (admin)
│   ├── delete.js               # 🗑️ Delete specific key (admin)
│   ├── deleteAll.js            # ☠️ Delete all keys (admin)
│   ├── adminReset.js           # 🛠️ Force HWID reset, no cooldown (admin)
│   ├── bindEmail.js            # 📧 Bind email to license key
│   ├── resetEmail.js           # 📧 Reset email binding (admin)
│   ├── checkKey.js             # 🔍 Get public key information
│   ├── dump.js                 # 📥 Export all keys (admin)
│   └── ping.js                 # 🏓 Health check endpoint
├── utils/
│   └── github.js               # 🐙 GitHub API integration utilities
├── keys.json                   # 📦 License keys database (JSON format)
├── index.html                  # 🌐 Web UI & admin dashboard
├── reset.html                  # 🔄 Standalone HWID reset page
├── package.json                # 📄 Project dependencies & metadata
├── vercel.json                 # ⚙️ Vercel deployment configuration (auto-generated)
└── README.md                   # 📖 This documentation file

File Descriptions

API Endpoints (/api/ folder)

  • make.js - Creates new random license keys with timestamp. Requires admin authentication.
  • verify.js - Core verification logic. Binds keys to HWID on first use, validates on subsequent calls.
  • reset.js - Allows users to reset their HWID binding once every 24 hours.
  • info.js - Returns detailed information about a key (creation date, HWID, email, reset history).
  • delete.js - Removes a specific license key from the system.
  • deleteAll.js - Nuclear option - removes ALL keys (admin only, use with caution).
  • adminReset.js - Instant HWID reset for customer support scenarios.
  • bindEmail.js - Binds an email address to a license key (one-to-one relationship).
  • resetEmail.js - Resets email binding for a key, allowing new email assignment (admin only).
  • checkKey.js - Returns basic key information without requiring admin access.
  • dump.js - Exports all license key data as JSON (admin only).
  • ping.js - Health check endpoint for monitoring uptime.

Utilities (/utils/ folder)

  • github.js - Handles all GitHub API operations (read/write keys.json, authentication).

Core Files

  • keys.json - The database file stored in your GitHub repo. Structure:
    {
      "ABCD-1234-EFGH": {
        "created": "2025-01-15T10:30:00.000Z",
        "hwid": "MAC-00-11-22-33-44-55",
        "last_reset": "2025-01-20T15:45:00.000Z",
        "email": "user@example.com",
        "email_bound_at": "2025-01-16T09:15:30.000Z",
        "email_reset_at": "2025-01-22T10:30:15.000Z"
      }
    }
  • index.html - Complete web interface with user verification form and admin panel.

Configuration Files

  • package.json - Defines the project as a Node.js application for Vercel.

🧪 Testing & Tips

  • Use Postman, Insomnia, curl, or the provided frontend to test endpoints
  • All API endpoints are GET-based and require the correct query parameters
  • HWID resets are locked to 24h (unless using /adminReset as admin)
  • All data is stored in your private GitHub repo's keys.json file
  • Vercel serves both the API and the web UI from the same deployment

🤝 Contribute & Get Help

GitHub stars GitHub forks

📄 License

MIT License — Made with ❤️ by Eman

About

EGate is a lightweight, HWID-locked license key system with a built-in admin panel, REST API, and optional web UI — perfect for protecting paid features in apps or scripts. Built for Vercel + GitHub

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published