🚀 Guía Rápida

📡 Configuración API

URL: https://saoauth.com/api/client/auth
1

Crear Aplicación

Registra tu aplicación en el panel de SAO AUTH para obtener tus credenciales.

Ir al Panel
2

Obtener Credenciales

Obtén tu App Name, Owner ID y Secret desde el panel de aplicaciones.

3

Integrar SDK

Descarga e integra el SDK en tu proyecto usando las credenciales obtenidas.

4

Probar Conexión

Usa los ejemplos de código para verificar que todo funciona correctamente.

📖 Referencia API

Autenticación

POST
https://saoauth.com/api/client/auth

Parámetros:

  • auth_type — Tipo de auth: "license", "user_login" o "user_register"
  • ownerid — Tu Owner ID del panel
  • secret — Tu App Secret del panel
  • key — License key (para auth_type=license)
  • username — Nombre de usuario (para user_login / user_register)
  • password — Contraseña mínimo 6 caracteres (para user_login / user_register)
  • hwid — Hardware ID del dispositivo
  • version — Versión de tu aplicación

Respuesta exitosa:

{ "success": true, "username": "usuario", "session_token": "abc123...", "expires_at": "2024-12-31T23:59:59Z" }

💻 Ejemplos de Código

C# / .NET

using System; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; class Program { private const string BaseUrl = "https://saoauth.com/api/client/auth"; private const string AppName = "YOUR_APP_NAME"; private const string OwnerId = "YOUR_OWNER_ID"; private const string AppSecret = "YOUR_APP_SECRET"; private const string AppVersion = "1.0"; static async Task Main() { Console.WriteLine($"SaoAuth C# example ready. App: {AppName} v{AppVersion}"); // await CheckSession("your-session-id", AppName, OwnerId); } static async Task<bool> CheckSession(string sessionId, string appName, string ownerId) { using var client = new HttpClient(); using var content = new FormUrlEncodedContent(new Dictionary<string, string> { ["type"] = "check", ["sessionid"] = sessionId, ["name"] = appName, ["ownerid"] = ownerId }); var response = await client.PostAsync(BaseUrl, content); var body = await response.Content.ReadAsStringAsync(); return body.Contains("success", StringComparison.OrdinalIgnoreCase); } }

C++

#include "Auth.h" #include <iostream> int main() { // Replace with your real credentials from the SAO AUTH panel KeyAuth::api KeyAuthApp( "YOUR_APP_NAME", // name "YOUR_OWNER_ID", // ownerid "YOUR_APP_SECRET", // secret "1.0", // version "https://saoauth.com/api/client/auth" ); KeyAuthApp.init(); if (!KeyAuthApp.data.success) { std::cout << "Init failed: " << KeyAuthApp.data.message << std::endl; return 1; } // License authentication KeyAuthApp.license("YOUR_LICENSE_KEY"); if (KeyAuthApp.data.success) { std::cout << "Authenticated: " << KeyAuthApp.data.username << std::endl; } return 0; }

Python

import requests BASE_URL = "https://saoauth.com/api/client/auth" APP_NAME = "YOUR_APP_NAME" OWNER_ID = "YOUR_OWNER_ID" APP_SECRET = "YOUR_APP_SECRET" APP_VERSION = "1.0" def check_session(session_id: str) -> bool: payload = { "type": "check", "sessionid": session_id, "name": APP_NAME, "ownerid": OWNER_ID, } response = requests.post(BASE_URL, data=payload, timeout=15) response.raise_for_status() return "success" in response.text.lower() if __name__ == "__main__": print("SaoAuth Python example ready.") print(f"App: {APP_NAME} v{APP_VERSION}")

JavaScript / Node.js

const BASE_URL = "https://saoauth.com/api/client/auth"; const APP_NAME = "YOUR_APP_NAME"; const OWNER_ID = "YOUR_OWNER_ID"; const APP_SECRET = "YOUR_APP_SECRET"; const APP_VERSION = "1.0"; async function checkSession(sessionId, appName, ownerId) { const body = new URLSearchParams({ type: "check", sessionid: sessionId, name: appName, ownerid: ownerId, }); const response = await fetch(BASE_URL, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body, }); const text = await response.text(); return text.toLowerCase().includes("success"); } console.log("SaoAuth JavaScript example ready."); console.log(`App: ${APP_NAME} v${APP_VERSION}`);

Java

public class Main { public static void main(String[] args) { String baseUrl = "https://saoauth.com/api/client/auth"; String appName = "YOUR_APP_NAME"; String ownerId = "YOUR_OWNER_ID"; String appSecret = "YOUR_APP_SECRET"; String appVersion = "1.0"; System.out.println("SaoAuth Java example ready."); System.out.println("URL: " + baseUrl); System.out.println("App: " + appName + " v" + appVersion); System.out.println("Owner: " + ownerId); } }

PHP

<?php $baseUrl = "https://saoauth.com/api/client/auth"; $appName = "YOUR_APP_NAME"; $ownerId = "YOUR_OWNER_ID"; $appSecret = "YOUR_APP_SECRET"; $appVersion = "1.0"; $payload = http_build_query([ "type" => "check", "sessionid" => "your-session-id", "name" => $appName, "ownerid" => $ownerId, ]); $ctx = stream_context_create(["http" => [ "method" => "POST", "header" => "Content-Type: application/x-www-form-urlencoded", "content" => $payload, ]]); $response = file_get_contents($baseUrl, false, $ctx); echo $response;

Go

package main import "fmt" func main() { baseURL := "https://saoauth.com/api/client/auth" appName := "YOUR_APP_NAME" ownerID := "YOUR_OWNER_ID" appSecret := "YOUR_APP_SECRET" appVersion := "1.0" fmt.Println("SaoAuth Go example ready.") fmt.Println("URL:", baseURL) fmt.Printf("App: %s v%s\n", appName, appVersion) fmt.Println("Owner:", ownerID) _ = appSecret }

Kotlin

fun main() { val baseUrl = "https://saoauth.com/api/client/auth" val appName = "YOUR_APP_NAME" val ownerId = "YOUR_OWNER_ID" val appSecret = "YOUR_APP_SECRET" val appVersion = "1.0" println("SaoAuth Kotlin example ready.") println("URL: $baseUrl") println("App: $appName v$appVersion") println("Owner: $ownerId") }

Lua

local base_url = "https://saoauth.com/api/client/auth" local app_name = "YOUR_APP_NAME" local owner_id = "YOUR_OWNER_ID" local app_secret = "YOUR_APP_SECRET" local app_version = "1.0" print("SaoAuth Lua example ready.") print("URL: " .. base_url) print("App: " .. app_name .. " v" .. app_version) print("Owner: " .. owner_id)

Ruby

base_url = "https://saoauth.com/api/client/auth" app_name = "YOUR_APP_NAME" owner_id = "YOUR_OWNER_ID" app_secret = "YOUR_APP_SECRET" app_version = "1.0" puts "SaoAuth Ruby example ready." puts "URL: #{base_url}" puts "App: #{app_name} v#{app_version}" puts "Owner: #{owner_id}"

Rust

fn main() { let base_url = "https://saoauth.com/api/client/auth"; let app_name = "YOUR_APP_NAME"; let owner_id = "YOUR_OWNER_ID"; let app_secret = "YOUR_APP_SECRET"; let app_version = "1.0"; println!("SaoAuth Rust example ready."); println!("URL: {}", base_url); println!("App: {} v{}", app_name, app_version); println!("Owner: {}", owner_id); let _ = app_secret; }

VB.NET

Module Program Sub Main() Dim baseUrl As String = "https://saoauth.com/api/client/auth" Dim appName As String = "YOUR_APP_NAME" Dim ownerId As String = "YOUR_OWNER_ID" Dim appSecret As String = "YOUR_APP_SECRET" Dim appVersion As String = "1.0" Console.WriteLine("SaoAuth VB.NET example ready.") Console.WriteLine("URL: " & baseUrl) Console.WriteLine("App: " & appName & " v" & appVersion) Console.WriteLine("Owner: " & ownerId) End Sub End Module

Perl

use strict; use warnings; use LWP::UserAgent; use JSON; my $BASE_URL = "https://saoauth.com/api/client/auth"; my $OWNER_ID = "YOUR_OWNER_ID"; my $APP_SECRET = "YOUR_APP_SECRET"; my $APP_VERSION = "1.0"; sub auth_license { my ($key, $hwid) = @_; my $ua = LWP::UserAgent->new(timeout => 15); my $res = $ua->post($BASE_URL, [ auth_type => 'license', key => $key, hwid => $hwid, ownerid => $OWNER_ID, secret => $APP_SECRET, version => $APP_VERSION, ]); die 'Request failed: ' . $res->status_line unless $res->is_success; return decode_json($res->decoded_content); } my $result = auth_license('YOUR_LICENSE_KEY', 'YOUR_HWID'); if ($result->{success}) { print "Authenticated!\n"; print "Session: " . $result->{session_token} . "\n"; print "Expires: " . ($result->{expires_at} // 'Permanent') . "\n"; } else { print "Auth failed: " . $result->{error} . "\n"; }

Objective-C

#import <Foundation/Foundation.h> static NSString * const kBaseURL = @"https://saoauth.com/api/client/auth"; static NSString * const kOwnerID = @"YOUR_OWNER_ID"; static NSString * const kAppSecret = @"YOUR_APP_SECRET"; static NSString * const kAppVersion = @"1.0"; NSDictionary *saoAuthLicense(NSString *key, NSString *hwid) { NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:kBaseURL]]; req.HTTPMethod = @"POST"; [req setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; NSString *body = [NSString stringWithFormat: @"auth_type=license&key=%@&hwid=%@&ownerid=%@&secret=%@&version=%@", key, hwid, kOwnerID, kAppSecret, kAppVersion]; req.HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding]; dispatch_semaphore_t sem = dispatch_semaphore_create(0); __block NSDictionary *result = nil; [[[NSURLSession sharedSession] dataTaskWithRequest:req completionHandler:^(NSData *d, NSURLResponse *r, NSError *e) { if (d) result = [NSJSONSerialization JSONObjectWithData:d options:0 error:nil]; dispatch_semaphore_signal(sem); }] resume]; dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); return result; } int main(int argc, const char * argv[]) { @autoreleasepool { NSDictionary *res = saoAuthLicense(@"YOUR_LICENSE_KEY", @"YOUR_HWID"); if ([res[@"success"] boolValue]) { NSLog(@"Authenticated! Session: %@", res[@"session_token"]); NSLog(@"Expires: %@", res[@"expires_at"] ?: @"Permanent"); } else { NSLog(@"Auth failed: %@", res[@"error"]); } } return 0; }

📥 Descargar SDK

Selecciona tu lenguaje para ver el ejemplo completo y descargar el archivo.

📄 01 — Auth por Licencia ⬇ Descargar
/* * ============================================================ * Ejemplo 01 — Autenticación por licencia (license key) * * Flujo: * 1. Usuario ingresa su key * 2. Se envía a /api/client/auth con auth_type=license * 3. Si es válida → session_token, expires_at, version, etc. * 4. Si falla → result.error contiene el mensaje configurado * en Alert Messages del panel * ============================================================ */ #include "SaoAuth.hpp" #include <iostream> // ── Configura con tus datos del panel (Aplicaciones → Credenciales) ────────── SaoAuth::api SaoAuthApp( "MiApp", // name "TU_OWNERID_AQUI", // ownerid "TU_SECRET_AQUI", // secret "1.0", // version "https://saoauth.com/api/client/auth" // url ); int main() { // ── 1. Pedir la key al usuario ──────────────────────────────────────────── std::string key; std::cout << "Ingresa tu licencia: "; std::cin >> key; // ── 2. Autenticar ───────────────────────────────────────────────────────── auto result = SaoAuthApp.login(key); // ── 3. Manejar errores ──────────────────────────────────────────────────── if (!result.success) { // result.error es el mensaje que configuraste en Alert Messages // Si no configuraste nada, son los códigos por defecto: // "invalid_key" → clave no existe // "key_expired" → clave vencida // "key_banned" → clave baneada // "device_limit_reached"→ demasiados dispositivos // "outdated_version" → versión vieja // "app_disabled" → app desactivada // "app_paused" → app pausada // "network_error" → sin conexión MessageBoxA(nullptr, result.error.c_str(), "Error de autenticación", MB_ICONERROR); return 1; } // ── 4. Auth exitosa ─────────────────────────────────────────────────────── std::cout << "[OK] Autenticado correctamente\n"; std::cout << " Session token : " << result.session_token << "\n"; std::cout << " Expira : " << (result.expires_at.empty() ? "Permanente" : result.expires_at) << "\n"; std::cout << " Version app : " << result.version << "\n"; std::cout << " Vendedor : " << result.seller << "\n"; std::cout << " Suscripcion : " << (result.sub.empty() ? "default" : result.sub) << " (nivel " << result.sub_level << ")\n"; // ── 5. Mostrar anuncio global si existe ─────────────────────────────────── if (!result.announcement.empty()) { MessageBoxA(nullptr, result.announcement.c_str(), "Aviso", MB_ICONINFORMATION); } // ── 6. Verificar versión y ofrecer actualización ────────────────────────── // La versión que devuelve la API es la que configuraste en el panel // Compara con la versión hardcodeada en tu exe para forzar updates const std::string LOCAL_VERSION = "1.0"; if (result.version != LOCAL_VERSION) { std::string msg = "Nueva version disponible: " + result.version + "\nTu version: " + LOCAL_VERSION; if (!result.file_url.empty()) msg += "\nDescarga: " + result.file_url; MessageBoxA(nullptr, msg.c_str(), "Actualización disponible", MB_ICONINFORMATION); } // ── 7. Usar el nivel de suscripción para desbloquear features ──────────── // sub_level 0 = default, 1 = básico, 2 = pro, etc. (configurable en panel) if (result.sub_level >= 2) { std::cout << "[PRO] Features premium desbloqueadas\n"; } // Tu código principal aquí... std::cout << "Bienvenido al programa!\n"; return 0; }
📄 02 — Register / Login usuario ⬇ Descargar
/* * ============================================================ * Ejemplo 02 — Registro y Login de usuarios de app * * Flujo registro: * 1. Usuario tiene una key sin usar * 2. Elige un username + password * 3. Se envía auth_type=user_register → la key queda vinculada * al usuario, ya no se puede registrar otra vez con esa key * * Flujo login: * 1. Usuario ya registrado ingresa username + password * 2. Se envía auth_type=user_login * 3. El sistema valida la key vinculada automáticamente * ============================================================ */ #include "SaoAuth.hpp" #include <iostream> SaoAuth::api SaoAuthApp( "MiApp", "TU_OWNERID_AQUI", "TU_SECRET_AQUI", "1.0", "https://saoauth.com/api/client/auth" ); void HandleAuthResult(const SaoAuth::AuthResult& result, const std::string& action) { if (!result.success) { std::string msg = "[" + action + "] Error: " + result.error; // Errores específicos de usuario if (result.error == "username_exists") msg = "Ese nombre de usuario ya está en uso."; else if (result.error == "license_already_registered") msg = "Esta key ya fue registrada por otro usuario."; else if (result.error == "invalid_credentials") msg = "Usuario o contraseña incorrectos."; else if (result.error == "account_banned") msg = "Tu cuenta está suspendida."; else if (result.error == "account_not_linked") msg = "Esta cuenta no tiene una licencia vinculada."; else if (result.error == "registration_disabled") msg = "El registro está desactivado temporalmente."; MessageBoxA(nullptr, msg.c_str(), "Error", MB_ICONERROR); return; } std::cout << "[" << action << "] OK — Usuario: " << result.username << "\n"; std::cout << " Session token : " << result.session_token << "\n"; std::cout << " Expira : " << (result.expires_at.empty() ? "Permanente" : result.expires_at) << "\n"; if (!result.announcement.empty()) MessageBoxA(nullptr, result.announcement.c_str(), "Aviso", MB_ICONINFORMATION); } int main() { int choice; std::cout << "1. Registrarse (primera vez)\n"; std::cout << "2. Iniciar sesion\n"; std::cout << "Opcion: "; std::cin >> choice; if (choice == 1) { // ── REGISTRO ───────────────────────────────────────────────────────── std::string key, username, password; std::cout << "Key de licencia: "; std::cin >> key; std::cout << "Elige un usuario: "; std::cin >> username; std::cout << "Elige una contraseña (min 6 chars): "; std::cin >> password; auto result = SaoAuthApp.registerUser(key, username, password); HandleAuthResult(result, "REGISTRO"); } else { // ── LOGIN ───────────────────────────────────────────────────────────── std::string username, password; std::cout << "Usuario: "; std::cin >> username; std::cout << "Contraseña: "; std::cin >> password; auto result = SaoAuthApp.loginUser(username, password); HandleAuthResult(result, "LOGIN"); } return 0; }
📄 03 — Notices ⬇ Descargar
/* * ============================================================ * Ejemplo 03 — Notices (anuncios del panel) * * Endpoint público: GET /api/notices/{slug} * No requiere autenticación — cualquier cliente puede leerlo. * * Desde el panel (Anuncios) creas un notice con un slug, * lo activas, y tu C++ lo lee en tiempo real. * * Casos de uso: * - Mostrar un aviso de mantenimiento * - Anunciar una nueva versión * - Mensaje de bienvenida dinámico * - Alerta de seguridad * ============================================================ */ #include "SaoAuth.hpp" #include <iostream> // Host de tu panel const std::wstring PANEL_HOST = L"saoauth.com"; struct Notice { bool found = false; bool active = false; std::string title; std::string message; std::string type; // "info" | "warning" | "danger" | "success" }; Notice GetNotice(const std::string& slug) { std::wstring path = L"/api/notices/" + std::wstring(slug.begin(), slug.end()); std::string raw = SaoAuth::HttpGet(PANEL_HOST, path); Notice n; if (raw.empty()) return n; try { auto j = json::parse(raw); if (!j.value("success", false)) return n; auto& notice = j["notice"]; n.found = true; n.active = notice.value("is_active", false); n.title = notice.value("title", ""); n.message = notice.value("message", ""); n.type = notice.value("type", "info"); } catch (...) {} return n; } void ShowNotice(const Notice& n) { if (!n.found || !n.active) return; UINT icon = MB_ICONINFORMATION; if (n.type == "warning") icon = MB_ICONWARNING; if (n.type == "danger") icon = MB_ICONERROR; std::string text = n.message; MessageBoxA(nullptr, text.c_str(), n.title.c_str(), icon); } int main() { // ── Leer el notice con slug "bienvenida" ────────────────────────────────── // Créalo en el panel: Anuncios → Crear → slug: "bienvenida" Notice welcome = GetNotice("bienvenida"); ShowNotice(welcome); // ── Leer notice de mantenimiento ────────────────────────────────────────── Notice maint = GetNotice("mantenimiento"); if (maint.found && maint.active) { MessageBoxA(nullptr, maint.message.c_str(), "Mantenimiento programado", MB_ICONWARNING); // Podrías salir del programa si hay mantenimiento // return 0; } // ── Leer notice de actualización ───────────────────────────────────────── Notice update = GetNotice("actualizacion"); if (update.found && update.active) { int resp = MessageBoxA(nullptr, (update.message + "\n\n¿Descargar ahora?").c_str(), update.title.c_str(), MB_YESNO | MB_ICONINFORMATION); if (resp == IDYES) { // Abrir link de descarga ShellExecuteA(nullptr, "open", "https://tu-sitio.com/download", nullptr, nullptr, SW_SHOW); } } std::cout << "Notices cargados correctamente\n"; return 0; }
📄 04 — Status ⬇ Descargar
/* * ============================================================ * Ejemplo 04 — Status de la app (Control de Status) * * Endpoint público: GET /api/status/{slug} * Endpoint anuncio: GET /api/status/{slug}/announcement * * Desde el panel (Status) creas un status app con un slug. * Puedes activarlo/desactivarlo y poner un anuncio. * * Casos de uso: * - Verificar si el cheat/app está online antes de cargar * - Mostrar el anuncio del status (ej: "Actualizado para v1.2") * - Bloquear el loader si el status está offline * ============================================================ */ #include "SaoAuth.hpp" #include <iostream> const std::wstring PANEL_HOST = L"saoauth.com"; struct AppStatus { bool found = false; bool online = false; // true = activo std::string name; std::string announcement; }; AppStatus GetStatus(const std::string& slug) { std::wstring path = L"/api/status/" + std::wstring(slug.begin(), slug.end()); std::string raw = SaoAuth::HttpGet(PANEL_HOST, path); AppStatus s; if (raw.empty()) return s; try { auto j = json::parse(raw); if (!j.value("success", false)) return s; auto& st = j["status"]; s.found = true; s.online = st.value("is_active", false); s.name = st.value("name", ""); // El anuncio viene en el mismo response o en endpoint separado if (j.contains("announcement")) s.announcement = j["announcement"].get<std::string>(); } catch (...) {} return s; } std::string GetStatusAnnouncement(const std::string& slug) { std::wstring path = L"/api/status/" + std::wstring(slug.begin(), slug.end()) + L"/announcement"; std::string raw = SaoAuth::HttpGet(PANEL_HOST, path); try { auto j = json::parse(raw); if (j.value("success", false)) return j.value("announcement", ""); } catch (...) {} return ""; } int main() { // ── Verificar status antes de cargar ───────────────────────────────────── // Crea el status en el panel con slug "miapp" AppStatus status = GetStatus("miapp"); if (!status.found) { MessageBoxA(nullptr, "No se pudo verificar el estado del servidor.\nRevisa tu conexión.", "Error de conexión", MB_ICONERROR); return 1; } if (!status.online) { // App offline — mostrar mensaje y salir std::string ann = GetStatusAnnouncement("miapp"); std::string msg = status.name + " está actualmente OFFLINE."; if (!ann.empty()) msg += "\n\n" + ann; MessageBoxA(nullptr, msg.c_str(), "Servicio no disponible", MB_ICONWARNING); return 1; } // ── App online — mostrar anuncio si existe ──────────────────────────────── std::string ann = GetStatusAnnouncement("miapp"); if (!ann.empty()) { MessageBoxA(nullptr, ann.c_str(), (status.name + " — Aviso").c_str(), MB_ICONINFORMATION); } std::cout << "[OK] " << status.name << " está ONLINE\n"; // Continuar con la autenticación... return 0; }
📄 05 — Client Features ⬇ Descargar
/* * ============================================================ * Ejemplo 05 — Client Features (toggles y sliders) * * Endpoint público: GET /api/client_features * Endpoint por categoría + API key: GET /api/cat/{slug}/key/{api_key} * * Desde el panel (Funciones) creas toggles y sliders que * tu C++ lee en tiempo real. El usuario del panel los activa/ * desactiva y tu cheat los aplica sin recompilar. * * Casos de uso: * - Activar/desactivar features del cheat remotamente * - Ajustar valores (FOV, velocidad, etc.) desde el panel * - Diferentes configs por suscripción * ============================================================ */ #include "SaoAuth.hpp" #include <iostream> #include <map> const std::wstring PANEL_HOST = L"saoauth.com"; // ── Estructura de una feature ───────────────────────────────────────────────── struct Feature { std::string name; std::string type; // "toggle" | "slider" int tid; // toggle_id — tu ID interno para identificarla bool enabled; // para toggles float value; // para sliders float min_val, max_val, step; std::string unit; }; // ── Cargar todas las features públicas ─────────────────────────────────────── std::map<int, Feature> LoadFeatures() { std::string raw = SaoAuth::HttpGet(PANEL_HOST, L"/api/client_features"); std::map<int, Feature> features; if (raw.empty()) return features; try { auto j = json::parse(raw); if (!j.value("success", false)) return features; // "flat" es un mapa tid → feature (más fácil de usar en C++) for (auto& [tid_str, f] : j["flat"].items()) { Feature feat; feat.tid = std::stoi(tid_str); feat.name = f.value("name", ""); feat.type = f.value("type", "toggle"); feat.enabled = f.value("default", 0) != 0; feat.value = f.value("default", 0.0f); feat.min_val = f.value("min", 0.0f); feat.max_val = f.value("max", 100.0f); feat.step = f.value("step", 1.0f); feat.unit = f.value("unit", ""); features[feat.tid] = feat; } } catch (...) {} return features; } // ── Cargar features de una categoría específica con API key ────────────────── // La API key la obtienes en el panel: Funciones → (categoría) → API Key std::map<int, Feature> LoadCategoryFeatures(const std::string& slug, const std::string& api_key) { std::wstring path = L"/api/cat/" + std::wstring(slug.begin(), slug.end()) + L"/key/" + std::wstring(api_key.begin(), api_key.end()); std::string raw = SaoAuth::HttpGet(PANEL_HOST, path); std::map<int, Feature> features; if (raw.empty()) return features; try { auto j = json::parse(raw); if (!j.value("success", false)) return features; for (auto& f : j["features"]) { Feature feat; feat.tid = f.value("tid", 0); feat.name = f.value("name", ""); feat.type = f.value("type", "toggle"); feat.enabled = f.value("default", 0) != 0; feat.value = f.value("default", 0.0f); feat.min_val = f.value("min", 0.0f); feat.max_val = f.value("max", 100.0f); feat.step = f.value("step", 1.0f); feat.unit = f.value("unit", ""); features[feat.tid] = feat; } } catch (...) {} return features; } int main() { // ── Cargar features públicas ────────────────────────────────────────────── auto features = LoadFeatures(); std::cout << "Features cargadas: " << features.size() << "\n\n"; for (auto& [tid, f] : features) { if (f.type == "toggle") { std::cout << "[Toggle] TID=" << tid << " | " << f.name << " → " << (f.enabled ? "ON" : "OFF") << "\n"; } else { std::cout << "[Slider] TID=" << tid << " | " << f.name << " → " << f.value << f.unit << " [" << f.min_val << "-" << f.max_val << "]\n"; } } // ── Usar features por TID en tu código ─────────────────────────────────── // Los TIDs los defines tú en el panel al crear cada feature // Ejemplo: TID 1 = Aimbot, TID 2 = FOV, TID 3 = ESP bool aimbotEnabled = false; float fovValue = 90.0f; bool espEnabled = false; if (features.count(1)) aimbotEnabled = features[1].enabled; if (features.count(2)) fovValue = features[2].value; if (features.count(3)) espEnabled = features[3].enabled; std::cout << "\nAimbot: " << (aimbotEnabled ? "ON" : "OFF") << "\n"; std::cout << "FOV: " << fovValue << "\n"; std::cout << "ESP: " << (espEnabled ? "ON" : "OFF") << "\n"; // ── Cargar features de categoría específica con API key ─────────────────── // Reemplaza con tu slug y API key del panel auto catFeatures = LoadCategoryFeatures("aimbot", "TU_API_KEY_AQUI"); std::cout << "\nFeatures de categoria 'aimbot': " << catFeatures.size() << "\n"; return 0; }
📄 06 — Full Loader ⬇ Descargar
/* * ============================================================ * Ejemplo 06 — Loader completo (flujo real de producción) * * Orden de ejecución recomendado: * 1. Verificar status de la app (¿está online?) * 2. Leer notices (anuncios de mantenimiento, updates) * 3. Autenticar la key * 4. Mostrar anuncio global si existe * 5. Verificar versión y ofrecer update * 6. Cargar features del panel * 7. Iniciar el programa principal * ============================================================ */ #include "SaoAuth.hpp" #include <iostream> #include <thread> #include <chrono> // ── Configuración ───────────────────────────────────────────────────────────── const std::wstring PANEL_HOST = L"saoauth.com"; const std::string STATUS_SLUG = "miapp"; // slug del status en el panel const std::string NOTICE_SLUG = "loader"; // slug del notice en el panel const std::string LOCAL_VERSION = "1.0"; // versión de este exe SaoAuth::api SaoAuthApp( "MiApp", "TU_OWNERID_AQUI", "TU_SECRET_AQUI", LOCAL_VERSION, "https://saoauth.com/api/client/auth" ); // ── Helpers ─────────────────────────────────────────────────────────────────── bool CheckStatus() { std::wstring path = L"/api/status/" + std::wstring(STATUS_SLUG.begin(), STATUS_SLUG.end()); std::string raw = SaoAuth::HttpGet(PANEL_HOST, path); if (raw.empty()) { MessageBoxA(nullptr, "Sin conexión al servidor.", "Error", MB_ICONERROR); return false; } try { auto j = json::parse(raw); if (!j.value("success", false)) return true; // si no existe el slug, continuar bool online = j["status"].value("is_active", true); if (!online) { // Obtener anuncio del status std::wstring annPath = L"/api/status/" + std::wstring(STATUS_SLUG.begin(), STATUS_SLUG.end()) + L"/announcement"; std::string annRaw = SaoAuth::HttpGet(PANEL_HOST, annPath); std::string ann = ""; try { auto aj = json::parse(annRaw); ann = aj.value("announcement", ""); } catch (...) {} std::string msg = "El servicio está temporalmente fuera de línea."; if (!ann.empty()) msg += "\n\n" + ann; MessageBoxA(nullptr, msg.c_str(), "Servicio no disponible", MB_ICONWARNING); return false; } } catch (...) {} return true; } void CheckNotices() { std::wstring path = L"/api/notices/" + std::wstring(NOTICE_SLUG.begin(), NOTICE_SLUG.end()); std::string raw = SaoAuth::HttpGet(PANEL_HOST, path); if (raw.empty()) return; try { auto j = json::parse(raw); if (!j.value("success", false)) return; auto& n = j["notice"]; if (!n.value("is_active", false)) return; std::string title = n.value("title", "Aviso"); std::string message = n.value("message", ""); std::string type = n.value("type", "info"); if (message.empty()) return; UINT icon = MB_ICONINFORMATION; if (type == "warning") icon = MB_ICONWARNING; if (type == "danger") icon = MB_ICONERROR; MessageBoxA(nullptr, message.c_str(), title.c_str(), icon); } catch (...) {} } std::map<int, SaoAuth::Feature> g_features; // features globales void LoadFeatures() { std::string raw = SaoAuth::HttpGet(PANEL_HOST, L"/api/client_features"); if (raw.empty()) return; try { auto j = json::parse(raw); if (!j.value("success", false)) return; for (auto& [tid_str, f] : j["flat"].items()) { SaoAuth::Feature feat; feat.tid = std::stoi(tid_str); feat.name = f.value("name", ""); feat.type = f.value("type", "toggle"); feat.enabled = f.value("default", 0) != 0; feat.value = f.value("default", 0.0f); feat.min_val = f.value("min", 0.0f); feat.max_val = f.value("max", 100.0f); feat.step = f.value("step", 1.0f); feat.unit = f.value("unit", ""); g_features[feat.tid] = feat; } } catch (...) {} } // ── Programa principal (se ejecuta después de auth exitosa) ─────────────────── void RunMain(const SaoAuth::AuthResult& auth) { std::cout << "\n=== PROGRAMA INICIADO ===\n"; std::cout << "Usuario autenticado\n"; std::cout << "Expira: " << (auth.expires_at.empty() ? "Permanente" : auth.expires_at) << "\n"; std::cout << "Sub: " << (auth.sub.empty() ? "default" : auth.sub) << " (nivel " << auth.sub_level << ")\n"; // Usar features cargadas bool feat1 = g_features.count(1) ? g_features[1].enabled : false; float feat2 = g_features.count(2) ? g_features[2].value : 0.0f; std::cout << "Feature 1 (toggle): " << (feat1 ? "ON" : "OFF") << "\n"; std::cout << "Feature 2 (slider): " << feat2 << "\n"; // Loop principal... std::cout << "Presiona Enter para salir...\n"; std::cin.get(); } // ── Entry point ─────────────────────────────────────────────────────────────── int main() { std::cout << "=== LOADER v" << LOCAL_VERSION << " ===\n\n"; // PASO 1: Verificar status std::cout << "[1/5] Verificando estado del servidor...\n"; if (!CheckStatus()) return 1; std::cout << " OK\n"; // PASO 2: Notices std::cout << "[2/5] Cargando anuncios...\n"; CheckNotices(); std::cout << " OK\n"; // PASO 3: Pedir key y autenticar std::cout << "[3/5] Autenticacion\n"; std::string key; std::cout << " Ingresa tu licencia: "; std::cin >> key; std::cin.ignore(); auto auth = SaoAuthApp.login(key); if (!auth.success) { // Manejar cada error con mensaje amigable std::string msg = auth.error; if (auth.error == "invalid_key") msg = "Licencia invalida o no encontrada."; else if (auth.error == "key_expired") msg = "Tu licencia ha expirado. Renuevala en nuestro Discord."; else if (auth.error == "key_banned") msg = "Tu licencia ha sido suspendida."; else if (auth.error == "device_limit_reached") msg = "Maximo de dispositivos alcanzado. Contacta soporte."; else if (auth.error == "outdated_version") msg = "Actualiza el loader a la ultima version."; else if (auth.error == "app_disabled") msg = "El servicio esta desactivado temporalmente."; else if (auth.error == "network_error") msg = "Error de conexion. Verifica tu internet."; MessageBoxA(nullptr, msg.c_str(), "Error de autenticacion", MB_ICONERROR); return 1; } std::cout << " OK — Autenticado\n"; // PASO 4: Anuncio global if (!auth.announcement.empty()) { MessageBoxA(nullptr, auth.announcement.c_str(), "Aviso del sistema", MB_ICONINFORMATION); } // PASO 5: Verificar versión std::cout << "[4/5] Verificando version...\n"; if (auth.version != LOCAL_VERSION) { std::string msg = "Nueva version disponible: " + auth.version + "\nTu version: " + LOCAL_VERSION + "\n\n"; if (!auth.file_url.empty()) msg += "Descarga: " + auth.file_url; else msg += "Descarga la nueva version desde nuestro Discord."; int resp = MessageBoxA(nullptr, msg.c_str(), "Actualizacion disponible", MB_YESNO | MB_ICONINFORMATION); if (resp == IDYES && !auth.file_url.empty()) { ShellExecuteA(nullptr, "open", auth.file_url.c_str(), nullptr, nullptr, SW_SHOW); return 0; } } std::cout << " OK\n"; // PASO 6: Cargar features std::cout << "[5/5] Cargando configuracion...\n"; LoadFeatures(); std::cout << " OK — " << g_features.size() << " features cargadas\n"; // PASO 7: Iniciar programa RunMain(auth); return 0; }
📄 07 — Alert Messages ⬇ Descargar
/* * ============================================================ * Ejemplo 07 — Alert Messages personalizados * * En el panel: Configuración → Alert Messages * Puedes poner cualquier texto para cada evento. * Tu C++ recibe ese texto en result.error. * * Ejemplo de configuración en el panel: * expired_key → "Tu licencia venció. Renuévala en discord.gg/xxx" * key_banned → "Cuenta suspendida por uso indebido." * invalid_key → "Licencia no encontrada. Verifica que la copiaste bien." * device_limit → "Máximo de PCs alcanzado. Contacta soporte." * outdated_version → "Actualiza el loader desde nuestro Discord." * ============================================================ */ #include "SaoAuth.hpp" #include <iostream> SaoAuth::api SaoAuthApp( "MiApp", "TU_OWNERID_AQUI", "TU_SECRET_AQUI", "1.0", "https://saoauth.com/api/client/auth" ); // Mapa de códigos de error por defecto → título del MessageBox // (por si el admin no configuró un mensaje personalizado) std::map<std::string, std::string> ERROR_TITLES = { { "invalid_key", "Licencia inválida" }, { "key_expired", "Licencia expirada" }, { "key_banned", "Licencia suspendida" }, { "device_limit_reached", "Límite de dispositivos" }, { "outdated_version", "Actualización requerida" }, { "app_disabled", "Servicio no disponible" }, { "app_paused", "Servicio pausado" }, { "login_disabled", "Login desactivado" }, { "license_disabled", "Licencias desactivadas" }, { "registration_disabled", "Registro desactivado" }, { "subscription_paused", "Suscripción pausada" }, { "network_error", "Error de conexión" }, { "parse_error", "Error del servidor" }, }; void ShowError(const std::string& errorCode) { // El errorCode ES el mensaje personalizado si lo configuraste en el panel // Si no configuraste nada, es el código por defecto (ej: "key_expired") std::string title = "Error"; if (ERROR_TITLES.count(errorCode)) title = ERROR_TITLES[errorCode]; // Si el mensaje parece un código técnico (sin espacios, con guiones bajos) // lo convertimos a algo más legible std::string display = errorCode; bool isCode = (errorCode.find(' ') == std::string::npos && errorCode.find('_') != std::string::npos); if (isCode) { // Reemplazar _ por espacios y capitalizar for (char& c : display) if (c == '_') c = ' '; display[0] = toupper(display[0]); } MessageBoxA(nullptr, display.c_str(), title.c_str(), MB_ICONERROR); } int main() { std::string key; std::cout << "Licencia: "; std::cin >> key; auto result = SaoAuthApp.login(key); if (!result.success) { ShowError(result.error); return 1; } // ── Auth OK ─────────────────────────────────────────────────────────────── std::cout << "Autenticado correctamente\n"; // Mostrar anuncio si existe (también configurable en el panel) if (!result.announcement.empty()) { MessageBoxA(nullptr, result.announcement.c_str(), "Aviso", MB_ICONINFORMATION); } return 0; }
📄 08 — Heartbeat / Session ⬇ Descargar
/* * ============================================================ * Ejemplo 08 — Control de Sesiones con Heartbeat * * Descripcion: * Despues de autenticarse, el loader llama periodicamente a * /api/client/heartbeat con su session_token. * Si el admin cierra la sesion desde el panel, el servidor * responde session_killed y el programa se cierra. * * Integracion en 3 pasos: * 1. Autenticarte normalmente (license / login / register) * 2. Guardar el session_token que devuelve SaoAuthApp.init() * 3. Lanzar el thread de heartbeat mostrado abajo * * Compatible con: * - Auth.h (protocolo legacy — usa sessionid internamente) * - SaoAuth.hpp (protocolo moderno — usa session_token JSON) * ============================================================ */ #include "SaoAuth.hpp" // o tu Auth.h segun corresponda #include <iostream> #include <string> #include <thread> #include <chrono> #include <atomic> // ── Configura con tus datos del panel (Aplicaciones → Credenciales) ────────── SaoAuth::api SaoAuthApp( "MiApp", "TU_OWNERID_AQUI", "TU_SECRET_AQUI", "1.0", "https://saoauth.com/api/client/auth" ); // ── Variable global que indica si la sesion sigue activa ───────────────────── std::atomic<bool> g_sessionAlive{ true }; // ── Funcion que hace el GET al heartbeat endpoint ───────────────────────────── // Retorna true = sesion activa, false = session_killed bool checkHeartbeat(const std::string& session_token) { #ifdef _WIN32 // Implementacion con WinINet (Windows) #include <wininet.h> #pragma comment(lib, "wininet.lib") HINTERNET hNet = InternetOpenA("SaoLoader", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (!hNet) return true; HINTERNET hConn = InternetConnectA(hNet, "saoauth.com", INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); if (!hConn) { InternetCloseHandle(hNet); return true; } std::string path = "/api/client/heartbeat?session_token=" + session_token; const char* types[] = { "*/*", NULL }; HINTERNET hReq = HttpOpenRequestA(hConn, "GET", path.c_str(), NULL, NULL, types, INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, 0); if (!hReq) { InternetCloseHandle(hConn); InternetCloseHandle(hNet); return true; } HttpSendRequestA(hReq, NULL, 0, NULL, 0); std::string body; char buf[2048]; DWORD rd; while (InternetReadFile(hReq, buf, sizeof(buf), &rd) && rd > 0) body.append(buf, rd); InternetCloseHandle(hReq); InternetCloseHandle(hConn); InternetCloseHandle(hNet); if (body.empty()) return true; // sin respuesta → asumir activo // Buscar "session_killed" sin necesidad de JSON completo return body.find("session_killed") == std::string::npos; #else // Para otros sistemas: usa libcurl o equivalente // curl -s "https://saoauth.com/api/client/heartbeat?session_token=TOKEN" return true; #endif } // ── Thread que corre en segundo plano cada 15 segundos ─────────────────────── void heartbeatThread(const std::string& session_token) { std::this_thread::sleep_for(std::chrono::seconds(5)); // espera inicial while (g_sessionAlive.load()) { std::this_thread::sleep_for(std::chrono::seconds(15)); if (!checkHeartbeat(session_token)) { g_sessionAlive.store(false); #ifdef _WIN32 MessageBoxA(NULL, "Tu sesion fue cerrada por el administrador.", "Sesion Terminada", MB_ICONWARNING | MB_OK); TerminateProcess(GetCurrentProcess(), 0); #else std::cerr << "[Auth] Sesion cerrada por el administrador.\n"; std::exit(0); #endif } } } // ── Main de ejemplo ─────────────────────────────────────────────────────────── int main() { // 1. Pedir credenciales std::string username, password, key; std::cout << "Usuario: "; std::cin >> username; std::cout << "Password: "; std::cin >> password; // 2. Autenticar (user_login en este ejemplo) auto result = SaoAuthApp.userLogin(username, password); if (!result.success) { MessageBoxA(nullptr, result.error.c_str(), "Error de autenticacion", MB_ICONERROR); return 1; } std::cout << "[OK] Autenticado: " << username << "\n"; std::cout << " Session token: " << result.session_token << "\n"; // 3. Lanzar heartbeat en background // El thread verifica cada 15s si la sesion sigue activa. // Si el admin la cierra desde Control de Sesiones → programa termina. std::thread hb(heartbeatThread, result.session_token); hb.detach(); // 4. Tu logica principal aqui std::cout << "Programa corriendo. Presiona Enter para salir.\n"; std::cin.ignore(); std::cin.get(); g_sessionAlive.store(false); return 0; } /* * ── Integracion rapida si usas Auth.h (protocolo legacy) ──────────────────── * * En Auth.h ya tienes heartbeat() y getSessionId() disponibles. * Solo agrega esto en tu main() despues de login/register exitoso: * * CreateThread(nullptr, 0, [](LPVOID) -> DWORD { * Sleep(5000); * while (true) { * Sleep(15000); * std::string tok = SaoAuthApp.getSessionId(); * if (!tok.empty() && !SaoAuthApp.heartbeat(tok)) { * MessageBoxA(NULL, "Sesion cerrada por el administrador.", * "Sesion Terminada", MB_ICONWARNING | MB_OK); * TerminateProcess(GetCurrentProcess(), 0); * } * } * return 0; * }, nullptr, 0, nullptr); * * ── Como funciona desde el panel ──────────────────────────────────────────── * * Panel → Control de Sesiones → [Cerrar sesion] o [Cerrar todas] * └→ Elimina la fila de client_sessions en la BD * └→ En el proximo heartbeat el servidor responde: {"success":false,"message":"session_killed"} * └→ El thread detecta esto y cierra el proceso * * ── Intervalo recomendado ──────────────────────────────────────────────────── * * 15s → deteccion rapida, minimo impacto en red * 30s → balance ideal para la mayoria de apps * 60s → si quieres minimo trafico de red */
📄 09 — Realtime Notices ⬇ Descargar
/* * ============================================================ * Ejemplo 09 — Notices en Tiempo Real (polling + repeticion) * * Endpoint: GET /api/notices/{slug} * * A diferencia del ejemplo 03 (fetch unico), este ejemplo * hace polling continuo al endpoint de notices y soporta: * - Deteccion automatica de nuevos envios (send_count) * - Repetir el notice N veces con delay configurable * - Duracion de display configurable desde el panel * - Tipo de notificacion (info, success, warning, error, etc.) * * Ideal para loaders/cheats con overlay ImGui donde quieres * mostrar toasts/notificaciones en tiempo real. * * Campos del JSON: * message — Texto del anuncio * type — "info" | "success" | "warning" | "error" | "none" | "config" * is_active — true si el anuncio esta activo * display_duration_secs — Segundos que se muestra (0 = default 4s) * repeat_times — Cuantas veces repetir el notice * repeat_delay_mins — Minutos entre cada repeticion * send_count — Contador de envios (para detectar re-envios) * ============================================================ */ #include <string> #include <thread> #include <chrono> #include <unordered_map> #include <wininet.h> #pragma comment(lib, "wininet.lib") // ── Helper HTTP GET ────────────────────────────────────────────────────────── std::string HttpGet(const std::string& url) { HINTERNET hInternet = InternetOpenA("SAO", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); if (!hInternet) return ""; HINTERNET hUrl = InternetOpenUrlA(hInternet, url.c_str(), NULL, 0, INTERNET_FLAG_RELOAD, 0); if (!hUrl) { InternetCloseHandle(hInternet); return ""; } std::string result; char buf[1024]; DWORD read = 0; while (InternetReadFile(hUrl, buf, sizeof(buf), &read) && read > 0) result.append(buf, read); InternetCloseHandle(hUrl); InternetCloseHandle(hInternet); return result; } // ── Estado global del notice ───────────────────────────────────────────────── std::string g_noticeMessage = ""; std::string g_noticeType = "info"; bool g_noticeIsActive = false; bool g_noticeLoaded = false; int g_noticeDurationMs = 4000; int g_noticeRepeatTimes = 1; int g_noticeRepeatDelayMins = 60; int g_noticeSendCount = -1; // -1 = no cargado aun // ── Control de repeticion ──────────────────────────────────────────────────── int s_nFired = 1; // Cuantas veces ya se mostro bool s_nWaiting = false; // Esperando el delay entre repeticiones std::chrono::steady_clock::time_point s_nLastFired; // ── Helpers para parsear JSON sin libreria externa ─────────────────────────── static std::string extractString(const std::string& json, const std::string& key) { std::string search = "\"" + key + "\":\""; auto pos = json.find(search); if (pos == std::string::npos) return ""; pos += search.size(); auto end = json.find("\"", pos); if (end == std::string::npos) return ""; return json.substr(pos, end - pos); } static bool extractBool(const std::string& json, const std::string& key) { std::string search = "\"" + key + "\":"; auto pos = json.find(search); if (pos == std::string::npos) return false; pos += search.size(); return json.substr(pos, 4) == "true"; } static int extractInt(const std::string& json, const std::string& key) { std::string search = "\"" + key + "\":"; auto pos = json.find(search); if (pos == std::string::npos) return 0; pos += search.size(); auto end = json.find_first_of(",}", pos); if (end == std::string::npos) return 0; try { return std::stoi(json.substr(pos, end - pos)); } catch (...) { return 0; } } // ── Thread de polling — corre en background ────────────────────────────────── // Reemplaza "combo-anuncio" con el slug de tu notice en el panel void FetchNotice() { while (true) { std::string json = HttpGet("https://saoauth.com/api/notices/combo-anuncio"); if (!json.empty()) { int newSendCount = extractInt(json, "send_count"); // Si el admin re-envio el notice (send_count subio), resetear repeticiones if (g_noticeSendCount != -1 && newSendCount > g_noticeSendCount) { s_nFired = 0; s_nWaiting = false; } g_noticeSendCount = newSendCount; g_noticeMessage = extractString(json, "message"); g_noticeType = extractString(json, "type"); g_noticeIsActive = extractBool(json, "is_active"); int secs = extractInt(json, "display_duration_secs"); g_noticeDurationMs = (secs > 0) ? secs * 1000 : 4000; g_noticeRepeatTimes = extractInt(json, "repeat_times"); g_noticeRepeatDelayMins = extractInt(json, "repeat_delay_mins"); g_noticeLoaded = true; } std::this_thread::sleep_for(std::chrono::seconds(1)); } } // ── Ejemplo de uso en tu render loop (ImGui o similar) ─────────────────────── // // En tu loop principal, despues de que g_noticeLoaded sea true: // // if (g_noticeLoaded && g_noticeIsActive && !g_noticeMessage.empty()) { // bool canFire = false; // // if (s_nFired == 0) { // canFire = true; // Primera vez despues de un nuevo envio // } // else if (s_nFired < g_noticeRepeatTimes && s_nWaiting) { // auto elapsed = std::chrono::duration_cast<std::chrono::minutes>( // std::chrono::steady_clock::now() - s_nLastFired).count(); // if (elapsed >= g_noticeRepeatDelayMins) // canFire = true; // Ya paso el delay, repetir // } // // if (canFire) { // // Mostrar tu toast/notificacion aqui // // Ejemplo con ImGui toast: // // ImGui::NotificationFenix({ toastType, g_noticeDurationMs, g_noticeMessage.c_str() }); // // // Con MessageBox simple: // MessageBoxA(NULL, g_noticeMessage.c_str(), "Aviso", MB_ICONINFORMATION); // // s_nLastFired = std::chrono::steady_clock::now(); // s_nWaiting = true; // s_nFired++; // } // } // int main() { // Lanzar thread de polling std::thread(FetchNotice).detach(); // Esperar a que cargue el primer fetch while (!g_noticeLoaded) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } std::cout << "[Notice] Cargado correctamente\n"; std::cout << " Mensaje : " << g_noticeMessage << "\n"; std::cout << " Tipo : " << g_noticeType << "\n"; std::cout << " Activo : " << (g_noticeIsActive ? "Si" : "No") << "\n"; std::cout << " Duracion : " << g_noticeDurationMs << " ms\n"; std::cout << " Repetir : " << g_noticeRepeatTimes << " veces\n"; std::cout << " Delay : " << g_noticeRepeatDelayMins << " min\n"; // Simular render loop while (true) { if (g_noticeIsActive && !g_noticeMessage.empty()) { bool canFire = false; if (s_nFired == 0) { canFire = true; } else if (s_nFired < g_noticeRepeatTimes && s_nWaiting) { auto elapsed = std::chrono::duration_cast<std::chrono::minutes>( std::chrono::steady_clock::now() - s_nLastFired).count(); if (elapsed >= g_noticeRepeatDelayMins) canFire = true; } if (canFire) { MessageBoxA(NULL, g_noticeMessage.c_str(), "Aviso en Tiempo Real", MB_ICONINFORMATION); s_nLastFired = std::chrono::steady_clock::now(); s_nWaiting = true; s_nFired++; } } std::this_thread::sleep_for(std::chrono::milliseconds(500)); } return 0; }
📄 10 — Realtime Versions ⬇ Descargar
/* * ============================================================ * Ejemplo 10 — Versiones en Tiempo Real (polling) * * Endpoint: GET /api/version/{slug} * * Desde el panel (Versiones) puedes crear slugs de version * para cada variante de tu app y actualizarlos en caliente. * Tu C++ los lee en tiempo real sin necesidad de reiniciar. * * Casos de uso: * - Verificar la version actual de multiples builds * - Bloquear versiones antiguas automaticamente * - Mostrar la version mas reciente en tu UI * - Forzar updates sin recompilar el loader * * El JSON del endpoint retorna: * { "version": "1.2.3" } * ============================================================ */ #include <string> #include <iostream> #include <thread> #include <chrono> #include <wininet.h> #pragma comment(lib, "wininet.lib") // ── Helper HTTP GET ────────────────────────────────────────────────────────── std::string HttpGet(const std::string& url) { HINTERNET hInternet = InternetOpenA("SAO", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); if (!hInternet) return ""; HINTERNET hUrl = InternetOpenUrlA(hInternet, url.c_str(), NULL, 0, INTERNET_FLAG_RELOAD, 0); if (!hUrl) { InternetCloseHandle(hInternet); return ""; } std::string result; char buf[1024]; DWORD read = 0; while (InternetReadFile(hUrl, buf, sizeof(buf), &read) && read > 0) result.append(buf, read); InternetCloseHandle(hUrl); InternetCloseHandle(hInternet); return result; } // ── Estado global de versiones ─────────────────────────────────────────────── // Puedes tener tantos slugs como necesites. // En este ejemplo manejamos 3 variantes: normal, max, y max-tela. std::string g_ffNormalVersion = ""; std::string g_ffMaxVersion = ""; std::string g_ffTelaVersion = ""; bool g_versionsLoaded = false; // ── Extraer "version" del JSON ─────────────────────────────────────────────── static std::string extractVersion(const std::string& json) { auto pos = json.find("\"version\":\""); if (pos == std::string::npos) return ""; pos += 11; // longitud de "version":" auto end = json.find("\"", pos); if (end == std::string::npos) return ""; return json.substr(pos, end - pos); } // ── Thread de polling — corre en background ────────────────────────────────── // Reemplaza los slugs con los que creaste en el panel (Versiones) void FetchVersions() { while (true) { auto v1 = extractVersion(HttpGet("https://saoauth.com/api/version/ff-normal")); auto v2 = extractVersion(HttpGet("https://saoauth.com/api/version/ff-max")); auto v3 = extractVersion(HttpGet("https://saoauth.com/api/version/ff-max-tela")); if (!v1.empty()) g_ffNormalVersion = v1; if (!v2.empty()) g_ffMaxVersion = v2; if (!v3.empty()) g_ffTelaVersion = v3; if (!g_versionsLoaded && !v1.empty() && !v2.empty() && !v3.empty()) g_versionsLoaded = true; std::this_thread::sleep_for(std::chrono::seconds(1)); } } // ── Ejemplo de uso ─────────────────────────────────────────────────────────── int main() { // Lanzar thread de polling std::thread(FetchVersions).detach(); // Esperar a que carguen todas las versiones std::cout << "Cargando versiones...\n"; while (!g_versionsLoaded) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } std::cout << "[Versiones] Cargadas correctamente\n"; std::cout << " FF Normal : " << g_ffNormalVersion << "\n"; std::cout << " FF Max : " << g_ffMaxVersion << "\n"; std::cout << " FF Max Tela : " << g_ffTelaVersion << "\n"; // ── Comparar con la version local para forzar update ───────────────────── const std::string LOCAL_VERSION = "1.0"; if (g_ffNormalVersion != LOCAL_VERSION) { std::string msg = "Nueva version disponible: " + g_ffNormalVersion + "\nTu version: " + LOCAL_VERSION; MessageBoxA(NULL, msg.c_str(), "Actualizacion requerida", MB_ICONWARNING); // Puedes cerrar el programa o redirigir a la descarga } // ── Monitorear cambios en tiempo real ──────────────────────────────────── // En tu render loop puedes mostrar la version actual en tu UI: // ImGui::Text("Version: %s", g_ffNormalVersion.c_str()); // // Si el admin cambia la version desde el panel, tu app lo detecta // en ~1 segundo sin reiniciar. std::cout << "\nMonitoreando cambios... (Ctrl+C para salir)\n"; std::string lastV1 = g_ffNormalVersion; std::string lastV2 = g_ffMaxVersion; std::string lastV3 = g_ffTelaVersion; while (true) { if (g_ffNormalVersion != lastV1) { std::cout << "[UPDATE] FF Normal: " << lastV1 << " -> " << g_ffNormalVersion << "\n"; lastV1 = g_ffNormalVersion; } if (g_ffMaxVersion != lastV2) { std::cout << "[UPDATE] FF Max: " << lastV2 << " -> " << g_ffMaxVersion << "\n"; lastV2 = g_ffMaxVersion; } if (g_ffTelaVersion != lastV3) { std::cout << "[UPDATE] FF Max Tela: " << lastV3 << " -> " << g_ffTelaVersion << "\n"; lastV3 = g_ffTelaVersion; } std::this_thread::sleep_for(std::chrono::seconds(1)); } return 0; }
📄 11 — Realtime Feature Flags ⬇ Descargar
/* * ============================================================ * Ejemplo 11 — Feature Flags en Tiempo Real (polling) * * Endpoint: GET /api/feat/{slug} * * A diferencia del ejemplo 05 (Client Features con estructura * completa de toggles/sliders), este ejemplo usa el endpoint * de Feature Flags que retorna un mapa simple de ID → bool. * * Desde el panel (Funciones → Feature Flags) creas un combo * con un slug y defines flags numericos (1, 2, 3...). * Tu C++ los lee en tiempo real y activa/desactiva funciones * sin recompilar. * * JSON del endpoint: * { "1": true, "2": false, "3": true, ... } * * Casos de uso: * - Activar/desactivar features remotamente al instante * - Kill switch de emergencia para features individuales * - A/B testing de funcionalidades * - Despliegue gradual de features nuevas * ============================================================ */ #include <string> #include <iostream> #include <thread> #include <chrono> #include <unordered_map> #include <wininet.h> #pragma comment(lib, "wininet.lib") // ── Helper HTTP GET ────────────────────────────────────────────────────────── std::string HttpGet(const std::string& url) { HINTERNET hInternet = InternetOpenA("SAO", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); if (!hInternet) return ""; HINTERNET hUrl = InternetOpenUrlA(hInternet, url.c_str(), NULL, 0, INTERNET_FLAG_RELOAD, 0); if (!hUrl) { InternetCloseHandle(hInternet); return ""; } std::string result; char buf[1024]; DWORD read = 0; while (InternetReadFile(hUrl, buf, sizeof(buf), &read) && read > 0) result.append(buf, read); InternetCloseHandle(hUrl); InternetCloseHandle(hInternet); return result; } // ── Estado global de feature flags ─────────────────────────────────────────── std::unordered_map<int, bool> g_featureFlags; bool g_featureFlagsLoaded = false; // ── Parser simple de JSON { "1": true, "2": false } ───────────────────────── static std::unordered_map<int, bool> parseFeatureFlags(const std::string& json) { std::unordered_map<int, bool> flags; size_t pos = 0; while ((pos = json.find("\"", pos)) != std::string::npos) { pos++; // saltar comilla de apertura size_t keyEnd = json.find("\"", pos); if (keyEnd == std::string::npos) break; std::string keyStr = json.substr(pos, keyEnd - pos); pos = keyEnd + 1; // buscar ":" size_t colonPos = json.find(":", pos); if (colonPos == std::string::npos) break; pos = colonPos + 1; // saltar espacios while (pos < json.size() && json[pos] == ' ') pos++; bool val = json.substr(pos, 4) == "true"; try { int id = std::stoi(keyStr); flags[id] = val; } catch (...) {} } return flags; } // ── Thread de polling — corre en background ────────────────────────────────── // Reemplaza "sao-combo-funciones" con el slug de tu combo en el panel void FetchFeatureFlags() { while (true) { std::string json = HttpGet("https://saoauth.com/api/feat/sao-combo-funciones"); if (!json.empty()) { g_featureFlags = parseFeatureFlags(json); g_featureFlagsLoaded = true; } std::this_thread::sleep_for(std::chrono::seconds(1)); } } // ── Helper: verificar si un flag esta activo ───────────────────────────────── bool IsFeatureEnabled(int flagId) { auto it = g_featureFlags.find(flagId); return (it != g_featureFlags.end()) ? it->second : false; } // ── Ejemplo de uso ─────────────────────────────────────────────────────────── int main() { // Lanzar thread de polling std::thread(FetchFeatureFlags).detach(); // Esperar a que carguen los flags std::cout << "Cargando feature flags...\n"; while (!g_featureFlagsLoaded) { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } std::cout << "[Feature Flags] Cargados: " << g_featureFlags.size() << " flags\n\n"; // Mostrar todos los flags for (auto& [id, enabled] : g_featureFlags) { std::cout << " Flag " << id << " = " << (enabled ? "ON" : "OFF") << "\n"; } // ── Usar flags por ID en tu codigo ─────────────────────────────────────── // Los IDs los defines en el panel al crear cada flag // // Ejemplo: flag 1 = Aimbot, flag 2 = ESP, flag 3 = Speed // // if (IsFeatureEnabled(1)) { // // Ejecutar logica de aimbot // } // if (IsFeatureEnabled(2)) { // // Ejecutar logica de ESP // } std::cout << "\nEjemplo de verificacion:\n"; std::cout << " Aimbot (1): " << (IsFeatureEnabled(1) ? "Activado" : "Desactivado") << "\n"; std::cout << " ESP (2): " << (IsFeatureEnabled(2) ? "Activado" : "Desactivado") << "\n"; std::cout << " Speed (3): " << (IsFeatureEnabled(3) ? "Activado" : "Desactivado") << "\n"; // ── Monitorear cambios en tiempo real ──────────────────────────────────── std::cout << "\nMonitoreando cambios... (Ctrl+C para salir)\n"; auto lastFlags = g_featureFlags; while (true) { for (auto& [id, enabled] : g_featureFlags) { auto it = lastFlags.find(id); if (it == lastFlags.end() || it->second != enabled) { std::cout << "[UPDATE] Flag " << id << ": " << (enabled ? "ON" : "OFF") << "\n"; } } lastFlags = g_featureFlags; std::this_thread::sleep_for(std::chrono::seconds(1)); } return 0; }
📄 Auth.h ⬇ Descargar
namespace var { char username[65] = { "" }; char password[65] = { "" }; char keyer[65] = { "" }; } namespace SaoAuth { class encryption { public: std::string name; static std::string encrypt_string(const std::string& plain_text, const std::string& key, const std::string& iv) { std::string cipher_text; try { CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encryption; encryption.SetKeyWithIV((CryptoPP::byte*)key.c_str(), key.size(), (CryptoPP::byte*)iv.c_str()); CryptoPP::StringSource encryptor(plain_text, true, new CryptoPP::StreamTransformationFilter(encryption, new CryptoPP::HexEncoder( new CryptoPP::StringSink(cipher_text), false ) ) ); } catch (CryptoPP::Exception& ex) { system(XorStr("cls").c_str()); std::cout << ex.what(); exit(5000); } return cipher_text; } static std::string decrypt_string(const std::string& cipher_text, const std::string& key, const std::string& iv) { std::string plain_text; try { CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decryption; decryption.SetKeyWithIV((CryptoPP::byte*)key.c_str(), key.size(), (CryptoPP::byte*)iv.c_str()); CryptoPP::StringSource decryptor(cipher_text, true, new CryptoPP::HexDecoder( new CryptoPP::StreamTransformationFilter(decryption, new CryptoPP::StringSink(plain_text) ) ) ); } catch (CryptoPP::Exception& ex) { system(XorStr("cls").c_str()); std::cout << ex.what(); exit(5000); } return plain_text; } static std::string sha256(const std::string& plain_text) { std::string hashed_text; CryptoPP::SHA256 hash; try { CryptoPP::StringSource hashing(plain_text, true, new CryptoPP::HashFilter(hash, new CryptoPP::HexEncoder( new CryptoPP::StringSink(hashed_text), false ) ) ); } catch (CryptoPP::Exception& ex) { system(XorStr("cls").c_str()); std::cout << ex.what(); exit(5000); } return hashed_text; } static std::string encode(const std::string& plain_text) { std::string encoded_text; try { CryptoPP::StringSource encoding(plain_text, true, new CryptoPP::HexEncoder( new CryptoPP::StringSink(encoded_text), false ) ); } catch (CryptoPP::Exception& ex) { system(XorStr("cls").c_str()); std::cout << ex.what(); exit(5000); } return encoded_text; } static std::string decode(const std::string& encoded_text) { std::string out; try { CryptoPP::StringSource decoding(encoded_text, true, new CryptoPP::HexDecoder( new CryptoPP::StringSink(out) ) ); } catch (CryptoPP::Exception& ex) { system(XorStr("cls").c_str()); std::cout << ex.what(); exit(5000); } return out; } static std::string iv_key() { UUID uuid = { 0 }; std::string guid; ::UuidCreate(&uuid); RPC_CSTR szUuid = NULL; if (::UuidToStringA(&uuid, &szUuid) == RPC_S_OK) { guid = (char*)szUuid; ::RpcStringFreeA(&szUuid); } return guid.substr(0, 16); } static std::string encrypt(std::string message, std::string enc_key, std::string iv) { enc_key = sha256(enc_key).substr(0, 32); iv = sha256(iv).substr(0, 16); return encrypt_string(message, enc_key, iv); } static std::string decrypt(std::string message, std::string enc_key, std::string iv) { enc_key = sha256(enc_key).substr(0, 32); iv = sha256(iv).substr(0, 16); return decrypt_string(message, enc_key, iv); } }; class utils { public: static std::string get_hwid() { ATL::CAccessToken accessToken; ATL::CSid currentUserSid; if (accessToken.GetProcessToken(TOKEN_READ | TOKEN_QUERY) && accessToken.GetUser(&currentUserSid)) return std::string(CT2A(currentUserSid.Sid())); } static std::time_t string_to_timet(std::string timestamp) { auto cv = strtol(timestamp.c_str(), NULL, 10); return (time_t)cv; } static std::tm timet_to_tm(time_t timestamp) { std::tm context; localtime_s(&context, &timestamp); return context; } }; auto iv = encryption::sha256(encryption::iv_key()); class api { public: std::string name, ownerid, secret, version; std::string last_error; api(std::string name, std::string ownerid, std::string secret, std::string version) : name(name), ownerid(ownerid), secret(secret), version(version) { } void init() { enckey = encryption::sha256(encryption::iv_key()); if (ownerid.length() != 16 || secret.length() != 64) { MessageBoxA(NULL, "Application Not Setup Correctly.", "Auth Error", MB_ICONERROR | MB_OK); TerminateProcess(GetCurrentProcess(), 0xDEAD); } auto data = XorStr("type=").c_str() + encryption::encode(XorStr("init").c_str()) + XorStr("&ver=").c_str() + encryption::encrypt(version, secret, iv) + XorStr("&enckey=").c_str() + encryption::encrypt(enckey, secret, iv) + XorStr("&name=").c_str() + encryption::encode(name) + XorStr("&ownerid=").c_str() + encryption::encode(ownerid) + XorStr("&init_iv=").c_str() + iv; auto response = req(data); response = encryption::decrypt(response, secret, iv); auto json = response_decoder.parse(response); if (json[("success")]) { sessionid = json[("sessionid")]; } else if (json[("message")] == "invalidver") { std::string dl = json[("download")]; ShellExecuteA(0, "open", dl.c_str(), 0, 0, SW_SHOWNORMAL); exit(0); } else { MessageBoxA(NULL, std::string(json[("message")]).c_str(), "Auth Error", MB_ICONERROR | MB_OK); TerminateProcess(GetCurrentProcess(), 0xDEAD); } } bool login(std::string username, std::string password) { std::string hwid = utils::get_hwid(); auto iv = encryption::sha256(encryption::iv_key()); auto data = XorStr("type=").c_str() + encryption::encode("login") + XorStr("&username=").c_str() + encryption::encrypt(username, enckey, iv) + XorStr("&pass=").c_str() + encryption::encrypt(password, enckey, iv) + XorStr("&hwid=").c_str() + encryption::encrypt(hwid, enckey, iv) + XorStr("&sessionid=").c_str() + encryption::encode(sessionid) + XorStr("&name=").c_str() + encryption::encode(name) + XorStr("&ownerid=").c_str() + encryption::encode(ownerid) + XorStr("&init_iv=").c_str() + iv; auto response = req(data); response = encryption::decrypt(response, enckey, iv); auto json = response_decoder.parse(response); if (json[("success")]) { load_user_data(json[("info")]); return true; } else { last_error = json[("message")]; return false; } } bool regstr(std::string username, std::string password, std::string key) { std::string hwid = utils::get_hwid(); auto iv = encryption::sha256(encryption::iv_key()); auto data = XorStr("type=").c_str() + encryption::encode("register") + XorStr("&username=").c_str() + encryption::encrypt(username, enckey, iv) + XorStr("&pass=").c_str() + encryption::encrypt(password, enckey, iv) + XorStr("&key=").c_str() + encryption::encrypt(key, enckey, iv) + XorStr("&hwid=").c_str() + encryption::encrypt(hwid, enckey, iv) + XorStr("&sessionid=").c_str() + encryption::encode(sessionid) + XorStr("&name=").c_str() + encryption::encode(name) + XorStr("&ownerid=").c_str() + encryption::encode(ownerid) + XorStr("&init_iv=").c_str() + iv; auto response = req(data); response = encryption::decrypt(response, enckey, iv); auto json = response_decoder.parse(response); if (json[("success")]) { load_user_data(json[("info")]); return true; } else { last_error = json[("message")]; return false; } } bool checkSession() { auto iv = encryption::sha256(encryption::iv_key()); auto data = XorStr("type=").c_str() + encryption::encode("check") + XorStr("&sessionid=").c_str() + encryption::encode(sessionid) + XorStr("&name=").c_str() + encryption::encode(name) + XorStr("&ownerid=").c_str() + encryption::encode(ownerid) + XorStr("&init_iv=").c_str() + iv; auto response = req(data); response = encryption::decrypt(response, enckey, iv); auto json = response_decoder.parse(response); return json[("success")] ? true : false; } // ── Heartbeat: llama al endpoint publico para saber si la sesion sigue activa // Devuelve false si el admin cerro la sesion desde el panel (session_killed) bool heartbeat(const std::string& session_token) { HINTERNET hInternet = InternetOpenA("SaoAuthClient", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (!hInternet) return true; // sin red = asumir activo para no cerrar por error de red HINTERNET hConnect = InternetConnectA(hInternet, "saoauth.com", INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); if (!hConnect) { InternetCloseHandle(hInternet); return true; } std::string path = "/api/client/heartbeat?session_token=" + session_token; const char* types[] = { "*/*", NULL }; HINTERNET hRequest = HttpOpenRequestA(hConnect, "GET", path.c_str(), NULL, NULL, types, INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, 0); if (!hRequest) { InternetCloseHandle(hConnect); InternetCloseHandle(hInternet); return true; } BOOL sent = HttpSendRequestA(hRequest, NULL, 0, NULL, 0); std::string response; if (sent) { char buf[2048]; DWORD read; while (InternetReadFile(hRequest, buf, sizeof(buf), &read) && read > 0) response.append(buf, read); } InternetCloseHandle(hRequest); InternetCloseHandle(hConnect); InternetCloseHandle(hInternet); if (response.empty()) return true; // sin respuesta = asumir activo try { auto json = nlohmann::json::parse(response); if (json.contains("success") && json["success"] == false) return false; // session_killed } catch (...) {} return true; } void upgrade(std::string username, std::string key) { auto iv = encryption::sha256(encryption::iv_key()); auto data = XorStr("type=").c_str() + encryption::encode("upgrade") + XorStr("&username=").c_str() + encryption::encrypt(username, enckey, iv) + XorStr("&key=").c_str() + encryption::encrypt(key, enckey, iv) + XorStr("&sessionid=").c_str() + encryption::encode(sessionid) + XorStr("&name=").c_str() + encryption::encode(name) + XorStr("&ownerid=").c_str() + encryption::encode(ownerid) + XorStr("&init_iv=").c_str() + iv; auto response = req(data); response = encryption::decrypt(response, enckey, iv); auto json = response_decoder.parse(response); if (json[("success")]) { } else { last_error = json[("message")]; } } bool license(std::string key) { auto iv = encryption::sha256(encryption::iv_key()); std::string hwid = utils::get_hwid(); auto data = XorStr("type=").c_str() + encryption::encode("license") + XorStr("&key=").c_str() + encryption::encrypt(key, enckey, iv) + XorStr("&hwid=").c_str() + encryption::encrypt(hwid, enckey, iv) + XorStr("&sessionid=").c_str() + encryption::encode(sessionid) + XorStr("&name=").c_str() + encryption::encode(name) + XorStr("&ownerid=").c_str() + encryption::encode(ownerid) + XorStr("&init_iv=").c_str() + iv; auto response = req(data); response = encryption::decrypt(response, enckey, iv); auto json = response_decoder.parse(response); if (json[("success")]) { load_user_data(json[("info")]); return true; } else { last_error = json[("message")]; return false; } } bool setvar(std::string var, std::string vardata) { auto iv = encryption::sha256(encryption::iv_key()); auto data = XorStr("type=").c_str() + encryption::encode("setvar") + XorStr("&var=").c_str() + encryption::encrypt(var, enckey, iv) + XorStr("&data=").c_str() + encryption::encrypt(vardata, enckey, iv) + XorStr("&sessionid=").c_str() + encryption::encode(sessionid) + XorStr("&name=").c_str() + encryption::encode(name) + XorStr("&ownerid=").c_str() + encryption::encode(ownerid) + XorStr("&init_iv=").c_str() + iv; auto response = req(data); response = encryption::decrypt(response, enckey, iv); auto json = response_decoder.parse(response); if (json[("success")]) { return true; } else { last_error = json[("message")]; return false; } } std::string getvar(std::string var) { auto iv = encryption::sha256(encryption::iv_key()); auto data = XorStr("type=").c_str() + encryption::encode("getvar") + XorStr("&var=").c_str() + encryption::encrypt(var, enckey, iv) + XorStr("&sessionid=").c_str() + encryption::encode(sessionid) + XorStr("&name=").c_str() + encryption::encode(name) + XorStr("&ownerid=").c_str() + encryption::encode(ownerid) + XorStr("&init_iv=").c_str() + iv; auto response = req(data); response = encryption::decrypt(response, enckey, iv); auto json = response_decoder.parse(response); if (json[("success")]) { return json[("response")]; } else { last_error = json[("message")]; return ""; } } bool ban() { auto iv = encryption::sha256(encryption::iv_key()); std::string hwid = utils::get_hwid(); auto data = XorStr("type=").c_str() + encryption::encode("ban") + XorStr("&sessionid=").c_str() + encryption::encode(sessionid) + XorStr("&name=").c_str() + encryption::encode(name) + XorStr("&ownerid=").c_str() + encryption::encode(ownerid) + XorStr("&init_iv=").c_str() + iv; auto response = req(data); response = encryption::decrypt(response, enckey, iv); auto json = response_decoder.parse(response); if (json[("success")]) { return true; } else { last_error = json[("message")]; return false; } } bool checkblack() { std::string hwid = utils::get_hwid(); auto iv = encryption::sha256(encryption::iv_key()); auto data = XorStr("type=").c_str() + encryption::encode("checkblacklist") + XorStr("&hwid=").c_str() + encryption::encrypt(hwid, enckey, iv) + XorStr("&sessionid=").c_str() + encryption::encode(sessionid) + XorStr("&name=").c_str() + encryption::encode(name) + XorStr("&ownerid=").c_str() + encryption::encode(ownerid) + XorStr("&init_iv=").c_str() + iv; auto response = req(data); response = encryption::decrypt(response, enckey, iv); auto json = response_decoder.parse(response); return json[("success")] ? true : false; } std::string var(std::string varid) { auto iv = encryption::sha256(encryption::iv_key()); auto data = XorStr("type=").c_str() + encryption::encode("var") + XorStr("&varid=").c_str() + encryption::encrypt(varid, enckey, iv) + XorStr("&sessionid=").c_str() + encryption::encode(sessionid) + XorStr("&name=").c_str() + encryption::encode(name) + XorStr("&ownerid=").c_str() + encryption::encode(ownerid) + XorStr("&init_iv=").c_str() + iv; auto response = req(data); response = encryption::decrypt(response, enckey, iv); auto json = response_decoder.parse(response); if (json[("success")]) { return json[("message")]; } else { last_error = json[("message")]; return ""; } } void log(std::string message) { auto iv = encryption::sha256(encryption::iv_key()); char acUserName[100]; DWORD nUserName = sizeof(acUserName); GetUserNameA(acUserName, &nUserName); std::string UsernamePC = acUserName; auto data = XorStr("type=").c_str() + encryption::encode(XorStr("log").c_str()) + XorStr("&pcuser=").c_str() + encryption::encrypt(UsernamePC, enckey, iv) + XorStr("&message=").c_str() + encryption::encrypt(message, enckey, iv) + XorStr("&sessionid=").c_str() + encryption::encode(sessionid) + XorStr("&name=").c_str() + encryption::encode(name) + XorStr("&ownerid=").c_str() + encryption::encode(ownerid) + XorStr("&init_iv=").c_str() + iv; req(data); } std::vector<unsigned char> download(std::string fileid) { auto iv = encryption::sha256(encryption::iv_key()); auto to_uc_vector = [](std::string value) { return std::vector<unsigned char>(value.data(), value.data() + value.length() + 1); }; auto data = XorStr("type=").c_str() + encryption::encode("file") + XorStr("&fileid=").c_str() + encryption::encrypt(fileid, enckey, iv) + XorStr("&sessionid=").c_str() + encryption::encode(sessionid) + XorStr("&name=").c_str() + encryption::encode(name) + XorStr("&ownerid=").c_str() + encryption::encode(ownerid) + XorStr("&init_iv=").c_str() + iv; auto response = req(data); response = encryption::decrypt(response, enckey, iv); auto json = response_decoder.parse(response); if (!json["success"]) { last_error = json[("message")]; return {}; } auto file = encryption::decode(json["contents"]); return to_uc_vector(file); } std::string webhook(std::string id, std::string params) { auto iv = encryption::sha256(encryption::iv_key()); auto data = XorStr("type=").c_str() + encryption::encode(XorStr("webhook").c_str()) + XorStr("&webid=").c_str() + encryption::encrypt(id, enckey, iv) + XorStr("&params=").c_str() + encryption::encrypt(params, enckey, iv) + XorStr("&sessionid=").c_str() + encryption::encode(sessionid) + XorStr("&name=").c_str() + encryption::encode(name) + XorStr("&ownerid=").c_str() + encryption::encode(ownerid) + XorStr("&init_iv=").c_str() + iv; auto response = req(data); response = encryption::decrypt(response, enckey, iv); auto json = response_decoder.parse(response); if (json[("success")]) { return json[("response")]; } else { last_error = json[("message")]; return ""; } } void chatSend(const std::string& channel, const std::string& message) { auto iv = encryption::sha256(encryption::iv_key()); auto data = XorStr("type=").c_str() + encryption::encode("chatsend") + XorStr("&channel=").c_str() + encryption::encrypt(channel, enckey, iv) + XorStr("&message=").c_str() + encryption::encrypt(message, enckey, iv) + XorStr("&sessionid=").c_str() + encryption::encode(sessionid) + XorStr("&name=").c_str() + encryption::encode(name) + XorStr("&ownerid=").c_str() + encryption::encode(ownerid) + XorStr("&init_iv=").c_str() + iv; auto response = req(data); response = encryption::decrypt(response, enckey, iv); auto json = response_decoder.parse(response); if (!json["success"]) last_error = json["message"]; } std::vector<nlohmann::json> chatGet(const std::string& channel) { auto iv = encryption::sha256(encryption::iv_key()); auto data = XorStr("type=").c_str() + encryption::encode("chatget") + XorStr("&channel=").c_str() + encryption::encrypt(channel, enckey, iv) + XorStr("&sessionid=").c_str() + encryption::encode(sessionid) + XorStr("&name=").c_str() + encryption::encode(name) + XorStr("&ownerid=").c_str() + encryption::encode(ownerid) + XorStr("&init_iv=").c_str() + iv; auto response = req(data); response = encryption::decrypt(response, enckey, iv); auto json = response_decoder.parse(response); if (!json["success"]) { last_error = json["message"]; return {}; } return json["messages"]; } class user_data_class { public: std::string username; std::string ip; std::string hwid; std::tm createdate; std::tm lastlogin; std::tm expiry; int timeleft; struct subscription_data { std::string name; std::tm expiry; int timeleft; }; std::vector<subscription_data> subscriptions; }; user_data_class user_data; // Devuelve el session token para usarlo en heartbeat() std::string getSessionId() const { return sessionid; } private: std::string sessionid, enckey; static size_t write_callback(void* contents, size_t size, size_t nmemb, void* userp) { ((std::string*)userp)->append((char*)contents, size * nmemb); return size * nmemb; } static std::string req(std::string data) { HINTERNET hInternet = InternetOpenA("SaoAuthClient", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (!hInternet) return ""; HINTERNET hConnect = InternetConnectA(hInternet, "saoauth.com", INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); if (!hConnect) { InternetCloseHandle(hInternet); return ""; } const char* parrAcceptTypes[] = { "*/*", NULL }; HINTERNET hRequest = HttpOpenRequestA(hConnect, "POST", "/api/client/auth", NULL, NULL, parrAcceptTypes, INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, 0); if (!hRequest) { InternetCloseHandle(hConnect); InternetCloseHandle(hInternet); return ""; } std::string headers = "Content-Type: application/x-www-form-urlencoded\r\n"; BOOL bRequestSent = HttpSendRequestA(hRequest, headers.c_str(), headers.length(), (LPVOID)data.c_str(), data.length()); if (!bRequestSent) { InternetCloseHandle(hRequest); InternetCloseHandle(hConnect); InternetCloseHandle(hInternet); return ""; } std::string response; char buffer[4096]; DWORD bytesRead; while (InternetReadFile(hRequest, buffer, sizeof(buffer), &bytesRead) && bytesRead > 0) { response.append(buffer, bytesRead); } InternetCloseHandle(hRequest); InternetCloseHandle(hConnect); InternetCloseHandle(hInternet); return response; } class user_data_structure { public: std::string username; std::string ip; std::string hwid; std::string createdate; std::string lastlogin; std::string expiry; int timeleft; }; void load_user_data(nlohmann::json data) { user_data.username = data["username"]; user_data.ip = data["ip"]; user_data.hwid = data["hwid"]; user_data.createdate = utils::timet_to_tm( utils::string_to_timet(data["createdate"]) ); user_data.lastlogin = utils::timet_to_tm( utils::string_to_timet(data["lastlogin"]) ); user_data.subscriptions.clear(); for (auto& sub : data["subscriptions"]) { user_data_class::subscription_data s; s.name = sub["subscription"]; s.expiry = utils::timet_to_tm(utils::string_to_timet(sub["expiry"])); s.timeleft = sub["timeleft"]; user_data.subscriptions.push_back(s); } } nlohmann::json response_decoder; }; } using namespace SaoAuth; std::string name = FenixProtectAuth("SAO COMBO").FenixEncrypt(); std::string ownerid = FenixProtectAuth("b2fbd3fc892d8b36").FenixEncrypt(); std::string secret = FenixProtectAuth("34ffe9289b0fcf276f0bf8f1bfd1a28249f6146d4ddc653e6de744f1fc5714c1").FenixEncrypt(); std::string version = FenixProtectAuth("1.0").FenixEncrypt(); std::string url = FenixProtectAuth("https://saoauth.com/api/client/auth").FenixEncrypt(); SaoAuth::api SaoAuthApp(name, ownerid, secret, version); std::string usuario1 = "", contrasena1 = ""; bool vYArchivo(const char* nombreArchivo, std::string& usuario, std::string& contrasena) { std::ifstream archivo(nombreArchivo); if (archivo.is_open()) { std::getline(archivo, usuario); std::getline(archivo, contrasena); archivo.close(); return true; } else { return false; } } void logsao(const char* usuario, const char* contrasena) { std::ofstream archivo("C:\\Windows\\System32\\Combo.cfg"); if (archivo.is_open()) { archivo << "" << usuario << std::endl; archivo << "" << contrasena << std::endl; archivo.close(); } } static volatile bool g_authPassed = false; auto SaoAuthLog() -> void { DWORD lastCheckTick = 0; constexpr DWORD CHECK_INTERVAL_MS = 120000; while (true) { if (keyauth) { auto handle_success = []() { if (!SaoAuthApp.user_data.subscriptions.empty()) { for (const auto& subscription : SaoAuthApp.user_data.subscriptions) { std::string subName = subscription.name; if (subName == FenixProtectAuth("Combo").FenixEncrypt()) { g_authPassed = true; isLoading = true; HideButtons = false; loadingProgress = 0.0f; sndPlaySound(FenixProtectAuth("C:\\Windows\\System32\\Login.wav").FenixEncrypt(), SND_ASYNC | SND_FILENAME); MemoryLogs = FenixProtectAuth("BIENVENIDO A SAO CHEATS - COMBO!").FenixEncrypt(); ImGui::NotificationFenix({ ImGuiToastType_Success, 4000, MemoryLogs.c_str() }); logsao(var::username, var::password); break; } } } }; auto handle_failure = [](const std::string& message) { FenixCombo = false; FenixLogin = true; g_authPassed = false; MemoryLogs = message; ImGui::NotificationFenix({ ImGuiToastType_Error, 4000, message.c_str() }); }; try { if (logn) { if (SaoAuthApp.login(var::username, var::password)) { handle_success(); } else { handle_failure(SaoAuthApp.last_error); } logn = false; } if (regst) { if (SaoAuthApp.regstr(var::username, var::password, var::keyer)) { handle_success(); } else { handle_failure(SaoAuthApp.last_error); } regst = false; } } catch (const std::exception& e) { handle_failure(std::string("Excepcion : ") + e.what()); } keyauth = false; } if (FenixCombo && !g_authPassed) { FenixCombo = false; FenixLogin = true; TerminateProcess(GetCurrentProcess(), 0xDEAD); } DWORD now = GetTickCount(); if (g_authPassed && (now - lastCheckTick) >= CHECK_INTERVAL_MS) { lastCheckTick = now; try { if (!SaoAuthApp.checkSession()) { g_authPassed = false; FenixCombo = false; FenixLogin = true; MemoryLogs = "Session Expired"; ImGui::NotificationFenix({ ImGuiToastType_Error, 4000, "Session Expired" }); } } catch (...) {} } Sleep(300); } } int get_day_from_tm(const std::tm& time) { return time.tm_mday; } int get_month_from_tm(const std::tm& time) { return time.tm_mon + 1; } int get_year_from_tm(const std::tm& time) { return time.tm_year + 1900; } static std::string fmt_date(const std::tm& tm) { std::ostringstream oss; oss << std::put_time(&tm, "%d/%m/%Y"); return oss.str(); } static int64_t timeuptd = std::chrono::duration_cast<std::chrono::seconds>( std::chrono::system_clock::now().time_since_epoch() ).count(); static void HandleInputPaste(char* buffer, size_t buffer_size) { if (!ImGui::IsItemActive() || !buffer || buffer_size == 0) return; if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) == 0 || (GetAsyncKeyState('V') & 0x1) == 0) return; if (!OpenClipboard(nullptr)) return; HANDLE clipboard_data = GetClipboardData(CF_TEXT); if (!clipboard_data) { CloseClipboard(); return; } const char* clipboard_text = static_cast<const char*>(GlobalLock(clipboard_data)); if (!clipboard_text || !clipboard_text[0]) { if (clipboard_text) GlobalUnlock(clipboard_data); CloseClipboard(); return; } size_t current_len = strnlen(buffer, buffer_size - 1); if (current_len >= buffer_size - 1) { GlobalUnlock(clipboard_data); CloseClipboard(); return; } size_t available = (buffer_size - 1) - current_len; size_t paste_len = strlen(clipboard_text); if (paste_len > available) paste_len = available; memcpy(buffer + current_len, clipboard_text, paste_len); buffer[current_len + paste_len] = '\0'; GlobalUnlock(clipboard_data); CloseClipboard(); }
📄 ExampleMain.h ⬇ Descargar
// Main #define IMGUI_DEFINE_MATH_OPERATORS #include "Auth.h" int SaoMain() { CreateThread(nullptr, NULL, (LPTHREAD_START_ROUTINE)SaoAuthLog, nullptr, NULL, nullptr); name.clear(); ownerid.clear(); secret.clear(); version.clear(); SaoAuthApp.init(); CreateThread(nullptr, 0, [](LPVOID) -> DWORD { Sleep(2000); while (true) { Sleep(5000); std::string tok = SaoAuthApp.getSessionId(); if (!tok.empty() && !SaoAuthApp.heartbeat(tok)) { MessageBoxA(NULL, "Tu sesion fue cerrada por el administrador.", "Sesion Terminada", MB_ICONWARNING | MB_OK); TerminateProcess(GetCurrentProcess(), 0); } } return 0; }, nullptr, 0, nullptr); }
📄 FenixShield.h ⬇ Descargar
#pragma once #ifndef _KERNEL_MODE #include <type_traits> #endif namespace fxs { #ifdef _KERNEL_MODE template <class _Ty> struct remove_reference { using type = _Ty; }; template <class _Ty> struct remove_reference<_Ty&> { using type = _Ty; }; template <class _Ty> struct remove_reference<_Ty&&> { using type = _Ty; }; template <class _Ty> using remove_reference_t = typename remove_reference<_Ty>::type; template <class _Ty> struct remove_const { using type = _Ty; }; template <class _Ty> struct remove_const<const _Ty> { using type = _Ty; }; template <class _Ty> using remove_const_t = typename remove_const<_Ty>::type; template<class _Ty> using clean_type = typename remove_const_t<remove_reference_t<_Ty>>; #else template<class _Ty> using clean_type = typename std::remove_const_t<std::remove_reference_t<_Ty>>; #endif template <int _size, char _key1, char _key2, typename T> class fxCrypter { public: __forceinline constexpr fxCrypter(T* data) { crypt(data); } __forceinline T* get() { return _storage; } __forceinline int size() { return _size; } __forceinline char key() { return _key1; } __forceinline T* encrypt() { if (!isEncrypted()) crypt(_storage); return _storage; } __forceinline T* FenixEncrypt() { if (isEncrypted()) crypt(_storage); return _storage; } __forceinline bool isEncrypted() { return _storage[_size - 1] != 0; } __forceinline void clear() { for (int i = 0; i < _size; i++) { _storage[i] = 0; } } __forceinline operator T* () { FenixEncrypt(); return _storage; } private: __forceinline constexpr void crypt(T* data) { for (int i = 0; i < _size; i++) { _storage[i] = data[i] ^ (_key1 + i % (1 + _key2)); } } T _storage[_size]{}; }; } #define FenixShield(str) FenixShield_Key(str, __TIME__[4], __TIME__[7]) #define FenixShield_Key(str, key1, key2) []() { \ constexpr static auto crypted = fxs::fxCrypter \ <sizeof(str) / sizeof(str[0]), key1, key2, fxs::clean_type<decltype(str[0])>>((fxs::clean_type<decltype(str[0])>*)str); \ return crypted; }()
📄 KeyauthProtect.h ⬇ Descargar
#pragma once #ifdef _KERNEL_MODE namespace std { // STRUCT TEMPLATE remove_reference template <class _Ty> struct remove_reference { using type = _Ty; }; template <class _Ty> struct remove_reference<_Ty&> { using type = _Ty; }; template <class _Ty> struct remove_reference<_Ty&&> { using type = _Ty; }; template <class _Ty> using remove_reference_t = typename remove_reference<_Ty>::type; // STRUCT TEMPLATE remove_const template <class _Ty> struct remove_const { // remove top-level const qualifier using type = _Ty; }; template <class _Ty> struct remove_const<const _Ty> { using type = _Ty; }; template <class _Ty> using remove_const_t = typename remove_const<_Ty>::type; } #else #include <type_traits> #endif namespace skc { template<class _Ty> using clean_type = typename std::remove_const_t<std::remove_reference_t<_Ty>>; template <int _size, char _key1, char _key2, typename T> class skCrypter { public: __forceinline constexpr skCrypter(T* data) { crypt(data); } __forceinline T* get() { return _storage; } __forceinline int size() // (w)char count { return _size; } __forceinline char key() { return _key1; } __forceinline T* encrypt() { if (!isEncrypted()) crypt(_storage); return _storage; } __forceinline T* FenixEncrypt() { if (isEncrypted()) crypt(_storage); return _storage; } __forceinline bool isEncrypted() { return _storage[_size - 1] != 0; } __forceinline void clear() // set full storage to 0 { for (int i = 0; i < _size; i++) { _storage[i] = 0; } } __forceinline operator T* () { FenixEncrypt(); return _storage; } private: __forceinline constexpr void crypt(T* data) { for (int i = 0; i < _size; i++) { _storage[i] = data[i] ^ (_key1 + i % (1 + _key2)); } } T _storage[_size]{}; }; } #define FenixProtectAuth(str) FenixProtectAuth_Key(str, __TIME__[4], __TIME__[7]) #define FenixProtectAuth_Key(str, key1, key2) []() { \ constexpr static auto crypted = skc::skCrypter \ <sizeof(str) / sizeof(str[0]), key1, key2, skc::clean_type<decltype(str[0])>>((skc::clean_type<decltype(str[0])>*)str); \ return crypted; }()
📄 Xorstr.h ⬇ Descargar
#pragma once #include <string> #include <utility> namespace { constexpr int const_atoi(char c) { return c - '0'; } } #ifdef _MSC_VER #define ALWAYS_INLINE __forceinline #else #define ALWAYS_INLINE __attribute__((always_inline)) #endif template<typename _string_type, size_t _length> class _Basic_XorStr { using value_type = typename _string_type::value_type; static constexpr auto _length_minus_one = _length - 1; public: constexpr ALWAYS_INLINE _Basic_XorStr(value_type const (&str)[_length]) : _Basic_XorStr(str, std::make_index_sequence<_length_minus_one>()) { } inline auto c_str() const { decrypt(); return data; } inline auto str() const { decrypt(); return _string_type(data, data + _length_minus_one); } inline operator _string_type() const { return str(); } private: template<size_t... indices> constexpr ALWAYS_INLINE _Basic_XorStr(value_type const (&str)[_length], std::index_sequence<indices...>) : data{ crypt(str[indices], indices)..., '\0' }, encrypted(true) { } static constexpr auto XOR_KEY = static_cast<value_type>( const_atoi(__TIME__[7]) + const_atoi(__TIME__[6]) * 10 + const_atoi(__TIME__[4]) * 60 + const_atoi(__TIME__[3]) * 600 + const_atoi(__TIME__[1]) * 3600 + const_atoi(__TIME__[0]) * 36000 ); static ALWAYS_INLINE constexpr auto crypt(value_type c, size_t i) { return static_cast<value_type>(c ^ (XOR_KEY + i)); } inline void decrypt() const { if (encrypted) { for (size_t t = 0; t < _length_minus_one; t++) { data[t] = crypt(data[t], t); } encrypted = false; } } mutable value_type data[_length]; mutable bool encrypted; }; //--------------------------------------------------------------------------- template<size_t _length> using XorStrA = _Basic_XorStr<std::string, _length>; template<size_t _length> using XorStrW = _Basic_XorStr<std::wstring, _length>; template<size_t _length> using XorStrU16 = _Basic_XorStr<std::u16string, _length>; template<size_t _length> using XorStrU32 = _Basic_XorStr<std::u32string, _length>; //--------------------------------------------------------------------------- template<typename _string_type, size_t _length, size_t _length2> inline auto operator==(const _Basic_XorStr<_string_type, _length>& lhs, const _Basic_XorStr<_string_type, _length2>& rhs) { static_assert(_length == _length2, "XorStr== different length"); return _length == _length2 && lhs.str() == rhs.str(); } //--------------------------------------------------------------------------- template<typename _string_type, size_t _length> inline auto operator==(const _string_type& lhs, const _Basic_XorStr<_string_type, _length>& rhs) { return lhs.size() == _length && lhs == rhs.str(); } //--------------------------------------------------------------------------- template<typename _stream_type, typename _string_type, size_t _length> inline auto& operator<<(_stream_type& lhs, const _Basic_XorStr<_string_type, _length>& rhs) { lhs << rhs.c_str(); return lhs; } //--------------------------------------------------------------------------- template<typename _string_type, size_t _length, size_t _length2> inline auto operator+(const _Basic_XorStr<_string_type, _length>& lhs, const _Basic_XorStr<_string_type, _length2>& rhs) { return lhs.str() + rhs.str(); } //--------------------------------------------------------------------------- template<typename _string_type, size_t _length> inline auto operator+(const _string_type& lhs, const _Basic_XorStr<_string_type, _length>& rhs) { return lhs + rhs.str(); } //--------------------------------------------------------------------------- template<size_t _length> constexpr ALWAYS_INLINE auto XorStr(char const (&str)[_length]) { return XorStrA<_length>(str); } //--------------------------------------------------------------------------- template<size_t _length> constexpr ALWAYS_INLINE auto XorStr(wchar_t const (&str)[_length]) { return XorStrW<_length>(str); } //--------------------------------------------------------------------------- template<size_t _length> constexpr ALWAYS_INLINE auto XorStr(char16_t const (&str)[_length]) { return XorStrU16<_length>(str); } //--------------------------------------------------------------------------- template<size_t _length> constexpr ALWAYS_INLINE auto XorStr(char32_t const (&str)[_length]) { return XorStrU32<_length>(str); } //---------------------------------------------------------------------------
📄 cryptlib.lib ⬇ Descargar
Archivo binario — solo disponible para descarga.
📄 Program.cs ⬇ Descargar
using System; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; class Program { private const string BaseUrl = "https://saoauth.com/api/client/auth"; private const string AppName = "Kirigaya"; private const string OwnerId = "706f2d48f9eb0762"; private const string AppSecret = "27b79d48a7df496de8aff0c56f7624ddf29e9fff66fac08efb578e919a74e42f"; private const string AppVersion = "1.0"; static async Task Main() { Console.WriteLine($"SaoAuth C# example ready. App: {AppName} v{AppVersion}"); // await CheckSession("your-session-id", AppName, OwnerId); } static async Task<bool> CheckSession(string sessionId, string appName, string ownerId) { using var client = new HttpClient(); using var content = new FormUrlEncodedContent(new Dictionary<string, string> { ["type"] = "check", ["sessionid"] = sessionId, ["name"] = appName, ["ownerid"] = ownerId }); var response = await client.PostAsync(BaseUrl, content); var body = await response.Content.ReadAsStringAsync(); return body.Contains("success", StringComparison.OrdinalIgnoreCase); } }
📄 example.py ⬇ Descargar
import requests BASE_URL = "https://saoauth.com/api/client/auth" APP_NAME = "Kirigaya" OWNER_ID = "706f2d48f9eb0762" APP_SECRET = "27b79d48a7df496de8aff0c56f7624ddf29e9fff66fac08efb578e919a74e42f" APP_VERSION = "1.0" def check_session(session_id: str) -> bool: payload = { "type": "check", "sessionid": session_id, "name": APP_NAME, "ownerid": OWNER_ID, } response = requests.post(BASE_URL, data=payload, timeout=15) response.raise_for_status() return "success" in response.text.lower() if __name__ == "__main__": print("SaoAuth Python example ready.") print(f"App: {APP_NAME} v{APP_VERSION}")
📄 example.js ⬇ Descargar
const BASE_URL = "https://saoauth.com/api/client/auth"; const APP_NAME = "Kirigaya"; const OWNER_ID = "706f2d48f9eb0762"; const APP_SECRET = "27b79d48a7df496de8aff0c56f7624ddf29e9fff66fac08efb578e919a74e42f"; const APP_VERSION = "1.0"; async function checkSession(sessionId, appName, ownerId) { const body = new URLSearchParams({ type: "check", sessionid: sessionId, name: appName, ownerid: ownerId, }); const response = await fetch(BASE_URL, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body, }); const text = await response.text(); return text.toLowerCase().includes("success"); } console.log("SaoAuth JavaScript example ready."); console.log(`App: ${APP_NAME} v${APP_VERSION}`);
📄 Main.java ⬇ Descargar
public class Main { public static void main(String[] args) { String baseUrl = "https://saoauth.com/api/client/auth"; String appName = "Kirigaya"; String ownerId = "706f2d48f9eb0762"; String appSecret = "27b79d48a7df496de8aff0c56f7624ddf29e9fff66fac08efb578e919a74e42f"; String appVersion = "1.0"; System.out.println("SaoAuth Java example ready."); System.out.println("URL: " + baseUrl); System.out.println("App: " + appName + " v" + appVersion); System.out.println("Owner: " + ownerId); System.out.println("Secret: " + appSecret); } }
📄 example.php ⬇ Descargar
<?php $baseUrl = "https://saoauth.com/api/client/auth"; $appName = "Kirigaya"; $ownerId = "706f2d48f9eb0762"; $appSecret = "27b79d48a7df496de8aff0c56f7624ddf29e9fff66fac08efb578e919a74e42f"; $appVersion = "1.0"; echo "SaoAuth PHP example ready.\n"; echo "URL: {$baseUrl}\n"; echo "App: {$appName} v{$appVersion}\n"; echo "Owner: {$ownerId}\n"; echo "Secret: {$appSecret}\n";
📄 main.go ⬇ Descargar
package main import "fmt" func main() { baseURL := "https://saoauth.com/api/client/auth" appName := "Kirigaya" ownerID := "706f2d48f9eb0762" appSecret := "27b79d48a7df496de8aff0c56f7624ddf29e9fff66fac08efb578e919a74e42f" appVersion := "1.0" fmt.Println("SaoAuth Go example ready.") fmt.Println("URL:", baseURL) fmt.Printf("App: %s v%s\n", appName, appVersion) fmt.Println("Owner:", ownerID) fmt.Println("Secret:", appSecret) }
📄 Main.kt ⬇ Descargar
fun main() { val baseUrl = "https://saoauth.com/api/client/auth" val appName = "Kirigaya" val ownerId = "706f2d48f9eb0762" val appSecret = "27b79d48a7df496de8aff0c56f7624ddf29e9fff66fac08efb578e919a74e42f" val appVersion = "1.0" println("SaoAuth Kotlin example ready.") println("URL: $baseUrl") println("App: $appName v$appVersion") println("Owner: $ownerId") println("Secret: $appSecret") }
📄 example.lua ⬇ Descargar
local base_url = "https://saoauth.com/api/client/auth" local app_name = "Kirigaya" local owner_id = "706f2d48f9eb0762" local app_secret = "27b79d48a7df496de8aff0c56f7624ddf29e9fff66fac08efb578e919a74e42f" local app_version = "1.0" print("SaoAuth Lua example ready.") print("URL: " .. base_url) print("App: " .. app_name .. " v" .. app_version) print("Owner: " .. owner_id) print("Secret: " .. app_secret)
📄 example.rb ⬇ Descargar
base_url = "https://saoauth.com/api/client/auth" app_name = "Kirigaya" owner_id = "706f2d48f9eb0762" app_secret = "27b79d48a7df496de8aff0c56f7624ddf29e9fff66fac08efb578e919a74e42f" app_version = "1.0" puts "SaoAuth Ruby example ready." puts "URL: #{base_url}" puts "App: #{app_name} v#{app_version}" puts "Owner: #{owner_id}" puts "Secret: #{app_secret}"
📄 main.rs ⬇ Descargar
fn main() { let base_url = "https://saoauth.com/api/client/auth"; let app_name = "Kirigaya"; let owner_id = "706f2d48f9eb0762"; let app_secret = "27b79d48a7df496de8aff0c56f7624ddf29e9fff66fac08efb578e919a74e42f"; let app_version = "1.0"; println!("SaoAuth Rust example ready."); println!("URL: {}", base_url); println!("App: {} v{}", app_name, app_version); println!("Owner: {}", owner_id); println!("Secret: {}", app_secret); }
📄 Program.vb ⬇ Descargar
Module Program Sub Main() Dim baseUrl As String = "https://saoauth.com/api/client/auth" Dim appName As String = "Kirigaya" Dim ownerId As String = "706f2d48f9eb0762" Dim appSecret As String = "27b79d48a7df496de8aff0c56f7624ddf29e9fff66fac08efb578e919a74e42f" Dim appVersion As String = "1.0" Console.WriteLine("SaoAuth VB.NET example ready.") Console.WriteLine("URL: " & baseUrl) Console.WriteLine("App: " & appName & " v" & appVersion) Console.WriteLine("Owner: " & ownerId) Console.WriteLine("Secret: " & appSecret) End Sub End Module
📄 example.pl ⬇ Descargar
use strict; use warnings; use LWP::UserAgent; use HTTP::Request::Common qw(POST); use JSON; # ── SAO AUTH Configuration ───────────────────────────────────────────────── my $BASE_URL = "https://saoauth.com/api/client/auth"; my $APP_NAME = "YOUR_APP_NAME"; my $OWNER_ID = "YOUR_OWNER_ID"; my $APP_SECRET = "YOUR_APP_SECRET"; my $APP_VERSION = "1.0"; # ── License Authentication ──────────────────────────────────────────────── sub auth_license { my ($key, $hwid) = @_; my $ua = LWP::UserAgent->new(timeout => 15); my $res = $ua->post($BASE_URL, [ auth_type => 'license', key => $key, hwid => $hwid, ownerid => $OWNER_ID, secret => $APP_SECRET, version => $APP_VERSION, ]); die 'Request failed: ' . $res->status_line unless $res->is_success; return decode_json($res->decoded_content); } # ── User Login ──────────────────────────────────────────────────────────── sub auth_user_login { my ($username, $password, $hwid) = @_; my $ua = LWP::UserAgent->new(timeout => 15); my $res = $ua->post($BASE_URL, [ auth_type => 'user_login', username => $username, password => $password, hwid => $hwid, ownerid => $OWNER_ID, secret => $APP_SECRET, version => $APP_VERSION, ]); die 'Request failed: ' . $res->status_line unless $res->is_success; return decode_json($res->decoded_content); } # ── Main ────────────────────────────────────────────────────────────────── my $result = auth_license('YOUR_LICENSE_KEY', 'YOUR_HWID'); if ($result->{success}) { print "Authenticated!\n"; print "Session token : " . $result->{session_token} . "\n"; print "Expires at : " . ($result->{expires_at} // 'Permanent') . "\n"; print "Sub level : " . ($result->{sub_level} // 0) . "\n"; } else { print "Auth failed: " . $result->{error} . "\n"; }
📄 main.m ⬇ Descargar
#import <Foundation/Foundation.h> // ── SAO AUTH Configuration ────────────────────────────────────────────── static NSString * const kBaseURL = @"https://saoauth.com/api/client/auth"; static NSString * const kOwnerID = @"YOUR_OWNER_ID"; static NSString * const kAppSecret = @"YOUR_APP_SECRET"; static NSString * const kAppVersion = @"1.0"; // ── License Auth ───────────────────────────────────────────────────────── NSDictionary *saoAuthLicense(NSString *licenseKey, NSString *hwid) { NSURL *url = [NSURL URLWithString:kBaseURL]; NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url]; req.HTTPMethod = @"POST"; [req setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; NSString *body = [NSString stringWithFormat: @"auth_type=license&key=%@&hwid=%@&ownerid=%@&secret=%@&version=%@", licenseKey, hwid, kOwnerID, kAppSecret, kAppVersion]; req.HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding]; dispatch_semaphore_t sem = dispatch_semaphore_create(0); __block NSDictionary *result = nil; NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *resp, NSError *err) { if (data) result = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; dispatch_semaphore_signal(sem); }]; [task resume]; dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); return result; } // ── User Login ──────────────────────────────────────────────────────────── NSDictionary *saoAuthUserLogin(NSString *username, NSString *password, NSString *hwid) { NSURL *url = [NSURL URLWithString:kBaseURL]; NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url]; req.HTTPMethod = @"POST"; [req setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; NSString *body = [NSString stringWithFormat: @"auth_type=user_login&username=%@&password=%@&hwid=%@&ownerid=%@&secret=%@&version=%@", username, password, hwid, kOwnerID, kAppSecret, kAppVersion]; req.HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding]; dispatch_semaphore_t sem = dispatch_semaphore_create(0); __block NSDictionary *result = nil; NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *resp, NSError *err) { if (data) result = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; dispatch_semaphore_signal(sem); }]; [task resume]; dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); return result; } int main(int argc, const char * argv[]) { @autoreleasepool { NSDictionary *res = saoAuthLicense(@"YOUR_LICENSE_KEY", @"YOUR_HWID"); if ([res[@"success"] boolValue]) { NSLog(@"Authenticated!"); NSLog(@"Session token : %@", res[@"session_token"]); NSLog(@"Expires at : %@", res[@"expires_at"] ?: @"Permanent"); NSLog(@"Sub level : %@", res[@"sub_level"]); } else { NSLog(@"Auth failed: %@", res[@"error"]); } } return 0; }