d291dcdc74
agent_api (HTTP server), agent_log (structured logging), agent_events (event bus), agent_console (GameConsole), agent_replay (snapshots), agent_vision (depth/segmentation), agent_fbx (bone remapping), agent_auth (multi-agent), agent_analytics (feature flags + tracking) All modules compile clean with mono. Binary uploaded to S3 v1.0.0. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
177 lines
5.3 KiB
C++
177 lines
5.3 KiB
C++
#include "agent_auth.h"
|
|
|
|
#include "core/crypto/crypto_core.h"
|
|
#include "core/os/os.h"
|
|
#include "core/string/print_string.h"
|
|
|
|
AgentAuth *AgentAuth::singleton = nullptr;
|
|
|
|
AgentAuth::AgentAuth() {
|
|
singleton = this;
|
|
}
|
|
|
|
AgentAuth::~AgentAuth() {
|
|
singleton = nullptr;
|
|
}
|
|
|
|
void AgentAuth::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("register_agent", "name", "permissions"), &AgentAuth::register_agent, DEFVAL(PERM_ALL));
|
|
ClassDB::bind_method(D_METHOD("unregister_agent", "token"), &AgentAuth::unregister_agent);
|
|
ClassDB::bind_method(D_METHOD("validate_token", "token"), &AgentAuth::validate_token);
|
|
ClassDB::bind_method(D_METHOD("check_permission", "token", "perm"), &AgentAuth::check_permission);
|
|
ClassDB::bind_method(D_METHOD("get_agents"), &AgentAuth::get_agents);
|
|
ClassDB::bind_method(D_METHOD("get_audit_log", "count"), &AgentAuth::get_audit_log, DEFVAL(100));
|
|
ClassDB::bind_method(D_METHOD("get_agent_info", "token"), &AgentAuth::get_agent_info);
|
|
ClassDB::bind_method(D_METHOD("set_max_requests_per_minute", "max"), &AgentAuth::set_max_requests_per_minute);
|
|
|
|
BIND_ENUM_CONSTANT(PERM_READ);
|
|
BIND_ENUM_CONSTANT(PERM_WRITE);
|
|
BIND_ENUM_CONSTANT(PERM_EXECUTE);
|
|
BIND_ENUM_CONSTANT(PERM_ALL);
|
|
}
|
|
|
|
Dictionary AgentAuth::register_agent(const String &p_name, uint32_t p_permissions) {
|
|
MutexLock lock(auth_mutex);
|
|
|
|
AgentSession session;
|
|
session.agent_id = vformat("agent_%d", OS::get_singleton()->get_ticks_msec());
|
|
session.agent_name = p_name;
|
|
session.token = _generate_token();
|
|
session.permissions = p_permissions;
|
|
session.connected_at = OS::get_singleton()->get_ticks_msec();
|
|
session.last_activity = session.connected_at;
|
|
|
|
sessions[session.token] = session;
|
|
|
|
Dictionary result;
|
|
result["agent_id"] = session.agent_id;
|
|
result["token"] = session.token;
|
|
result["permissions"] = session.permissions;
|
|
|
|
print_line(vformat("AgentAuth: Registered agent '%s' (id: %s)", p_name, session.agent_id));
|
|
return result;
|
|
}
|
|
|
|
void AgentAuth::unregister_agent(const String &p_token) {
|
|
MutexLock lock(auth_mutex);
|
|
if (sessions.has(p_token)) {
|
|
print_line(vformat("AgentAuth: Unregistered agent '%s'", sessions[p_token].agent_name));
|
|
sessions.erase(p_token);
|
|
}
|
|
}
|
|
|
|
bool AgentAuth::validate_token(const String &p_token) {
|
|
MutexLock lock(auth_mutex);
|
|
return sessions.has(p_token);
|
|
}
|
|
|
|
bool AgentAuth::check_permission(const String &p_token, Permission p_perm) {
|
|
MutexLock lock(auth_mutex);
|
|
if (!sessions.has(p_token)) {
|
|
return false;
|
|
}
|
|
return (sessions[p_token].permissions & (uint32_t)p_perm) != 0;
|
|
}
|
|
|
|
void AgentAuth::record_activity(const String &p_token, const String &p_method, const String &p_path, int p_status) {
|
|
MutexLock lock(auth_mutex);
|
|
|
|
// Update session activity.
|
|
if (sessions.has(p_token)) {
|
|
sessions[p_token].last_activity = OS::get_singleton()->get_ticks_msec();
|
|
sessions[p_token].request_count++;
|
|
}
|
|
|
|
// Add to audit log.
|
|
AuditEntry entry;
|
|
entry.timestamp_msec = OS::get_singleton()->get_ticks_msec();
|
|
entry.agent_id = sessions.has(p_token) ? sessions[p_token].agent_id : "unknown";
|
|
entry.method = p_method;
|
|
entry.path = p_path;
|
|
entry.status_code = p_status;
|
|
audit_log.push_back(entry);
|
|
|
|
if (audit_log.size() > MAX_AUDIT) {
|
|
audit_log.remove_at(0);
|
|
}
|
|
}
|
|
|
|
bool AgentAuth::check_rate_limit(const String &p_token) {
|
|
MutexLock lock(auth_mutex);
|
|
if (!sessions.has(p_token)) {
|
|
return false;
|
|
}
|
|
|
|
// Simple rate limiting: check requests in the last minute.
|
|
// For a proper implementation, use a sliding window counter.
|
|
// This simplified version just checks total requests.
|
|
const AgentSession &session = sessions[p_token];
|
|
uint64_t elapsed = OS::get_singleton()->get_ticks_msec() - session.connected_at;
|
|
if (elapsed == 0) {
|
|
return true;
|
|
}
|
|
|
|
float minutes = (float)elapsed / 60000.0f;
|
|
float rate = (float)session.request_count / MAX(minutes, 0.01f);
|
|
|
|
return rate <= (float)max_requests_per_minute;
|
|
}
|
|
|
|
Array AgentAuth::get_agents() const {
|
|
Array result;
|
|
for (const KeyValue<String, AgentSession> &kv : sessions) {
|
|
Dictionary dict;
|
|
dict["agent_id"] = kv.value.agent_id;
|
|
dict["name"] = kv.value.agent_name;
|
|
dict["permissions"] = kv.value.permissions;
|
|
dict["connected_at"] = kv.value.connected_at;
|
|
dict["last_activity"] = kv.value.last_activity;
|
|
dict["request_count"] = kv.value.request_count;
|
|
result.push_back(dict);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Array AgentAuth::get_audit_log(int p_count) const {
|
|
Array result;
|
|
int start = MAX(0, audit_log.size() - p_count);
|
|
for (int i = start; i < audit_log.size(); i++) {
|
|
Dictionary dict;
|
|
dict["timestamp_msec"] = audit_log[i].timestamp_msec;
|
|
dict["agent_id"] = audit_log[i].agent_id;
|
|
dict["method"] = audit_log[i].method;
|
|
dict["path"] = audit_log[i].path;
|
|
dict["status_code"] = audit_log[i].status_code;
|
|
result.push_back(dict);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Dictionary AgentAuth::get_agent_info(const String &p_token) const {
|
|
Dictionary dict;
|
|
if (sessions.has(p_token)) {
|
|
const AgentSession &s = sessions[p_token];
|
|
dict["agent_id"] = s.agent_id;
|
|
dict["name"] = s.agent_name;
|
|
dict["permissions"] = s.permissions;
|
|
dict["connected_at"] = s.connected_at;
|
|
dict["last_activity"] = s.last_activity;
|
|
dict["request_count"] = s.request_count;
|
|
}
|
|
return dict;
|
|
}
|
|
|
|
String AgentAuth::_generate_token() {
|
|
// Generate a random hex token.
|
|
uint8_t bytes[32];
|
|
for (int i = 0; i < 32; i++) {
|
|
bytes[i] = (uint8_t)(Math::rand() % 256);
|
|
}
|
|
|
|
String token;
|
|
for (int i = 0; i < 32; i++) {
|
|
token += vformat("%02x", bytes[i]);
|
|
}
|
|
return "agent_" + token;
|
|
}
|