🚀 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 Panel2
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 panelsecret— Tu App Secret del panelkey— 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 dispositivoversion— 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(¤tUserSid))
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, ×tamp);
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("¶ms=").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;
}