π Quick Start
π‘ API Configuration
URL:
https://saoauth.com/api/client/auth
1
Create Application
Register your application in the SAO AUTH panel to get your credentials.
Go to Panel2
Get Credentials
Get your App Name, Owner ID and Secret from the applications panel.
3
Integrate SDK
Download and integrate the SDK into your project using the obtained credentials.
4
Test Connection
Use the code examples to verify everything works correctly.
π API Reference
Authentication
POST
https://saoauth.com/api/client/auth
Parameters:
auth_typeβ Auth type: "license", "user_login" or "user_register"owneridβ Your Owner ID from the panelsecretβ Your App Secret from the panelkeyβ License key (for auth_type=license)usernameβ Username (for user_login / user_register)passwordβ Password min 6 characters (for user_login / user_register)hwidβ Hardware ID of the deviceversionβ Your application version
Success response:
{
"success": true,
"username": "usuario",
"session_token": "abc123...",
"expires_at": "2024-12-31T23:59:59Z"
}
π» Code Examples
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;
}
π₯ Download SDK
Select your language to view the full example and download the file.
π 01 β Auth por Licencia
β¬ Download
/*
* ============================================================
* 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
β¬ Download
/*
* ============================================================
* 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
β¬ Download
/*
* ============================================================
* 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
β¬ Download
/*
* ============================================================
* 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
β¬ Download
/*
* ============================================================
* 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
β¬ Download
/*
* ============================================================
* 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
β¬ Download
/*
* ============================================================
* 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
β¬ Download
/*
* ============================================================
* 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
β¬ Download
/*
* ============================================================
* 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
β¬ Download
/*
* ============================================================
* 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
β¬ Download
/*
* ============================================================
* 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
β¬ Download
ο»Ώ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
β¬ Download
// 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
β¬ Download
#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
β¬ Download
#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
β¬ Download
#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
β¬ Download
Archivo binario β solo disponible para descarga.
π Program.cs
β¬ Download
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
β¬ Download
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
β¬ Download
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
β¬ Download
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
β¬ Download
<?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
β¬ Download
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
β¬ Download
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
β¬ Download
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
β¬ Download
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
β¬ Download
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
β¬ Download
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
β¬ Download
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
β¬ Download
#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;
}