feat(ai-gateway): Add /login command with credential validation

- CLI: aigatewayctl login [provider] - validates credentials before saving
- Rollback on auth failure (preserves previous credentials)
- Format warnings for provider-specific API key patterns
- RPCD: login method for LuCI frontend integration
- ACL: Added write permission for login method

docs: Refactor WIP.md and update HISTORY.md
- WIP.md: 1470 → 108 lines (keep only March 2026 items)
- HISTORY.md: Add entries #74-75 (Feb 2026 milestones)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-03-06 09:49:46 +01:00
parent 5b8c4cd52c
commit 70056e02ed
5 changed files with 364 additions and 1426 deletions

View File

@ -1,6 +1,6 @@
# SecuBox UI & Theme History
_Last updated: 2026-03-03 (Comprehensive Service Audit)_
_Last updated: 2026-03-06 (AI Gateway Login)_
1. **Unified Dashboard Refresh (2025-12-20)**
- Dashboard received the "sh-page-header" layout, hero stats, and SecuNav top tabs.
@ -4404,3 +4404,69 @@ git checkout HEAD -- index.html
- **Mailserver Recovery:**
- Fixed webmail.gk2.secubox.in login error by starting mailserver container
- Verified IMAP/SMTP connectivity (ports 143, 993, 25, 587, 465)
74. **February 2026 Milestones (2026-02-01 to 2026-02-28)**
- **Mesh & P2P:**
- ZKP Hamiltonian cryptographic authentication between mesh nodes
- Mesh blockchain bidirectional sync (Master ↔ Clone)
- P2P threat intelligence sharing (100+ IOC blocks)
- Yggdrasil IPv6 overlay network with LAN multicast peering
- Yggdrasil Extended Peer Discovery with gossip protocol
- MirrorNet core package (identity, reputation, mirror, gossip, health)
- Factory auto-provisioning with zero-touch device onboarding
- **AI & Security:**
- AI Gateway (Sovereignty Engine) with ANSSI CSPN compliance
- 3-tier data classification: LOCAL_ONLY, SANITIZED, CLOUD_DIRECT
- Provider hierarchy: LocalAI > Mistral EU > Claude > OpenAI > Gemini > xAI
- DNS Guard AI migration with 5 detection modules
- Threat Analyst autonomous agent with rule generation
- MCP Server with 14 tools for Claude Desktop integration
- CVE Triage agent with NVD integration
- Network Anomaly agent with 5 detection modules
- LocalRecall memory system for AI agents
- Config Advisor for ANSSI CSPN compliance checking
- **Communication:**
- Matrix Homeserver (Conduit) with E2EE mesh messaging
- VoIP (Asterisk PBX) with OVH trunk auto-provisioning
- Jabber integration with Jingle VoIP and SMS relay
- Self-hosted Jitsi Meet video conferencing
- **Media & Content:**
- PeerTube video platform with yt-dlp import
- GoToSocial Fediverse server
- Nextcloud LXC with nginx, PHP-FPM, Talk app
- HexoJS multi-instance with GitHub/Gitea integration
- MetaBlogizer KISS ULTIME MODE with one-command emancipation
- WebRadio with CrowdSec integration
- **Infrastructure:**
- HAProxy path-based ACL routing with pattern length sorting
- Mitmproxy multi-instance support (out/in)
- Vortex Hub wildcard routing
- Gandi DNS secondary setup with zone transfers
- Custom mailserver (Postfix + Dovecot in LXC)
- IoT Guard with OUI-based classification
- IP Blocklist with nftables/iptables backends
- AbuseIPDB reporter integration
- Log denoising for System Hub
- **Cloning & Deployment:**
- Cloning Station with MOKATOOL integration
- Remote device management via SSH
- Clone history and image manager
- Pre-deploy lint script for syntax validation
- **LuCI Dashboards (KISS rewrites):**
- SecuBox Dashboard, System Hub, Modules, Monitoring, Alerts, Settings
- HAProxy (vhosts, backends, stats)
- CrowdSec, Wazuh SIEM, mitmproxy WAF
- VM Manager, Cookie Tracker, CDN Cache
- InterceptoR Services Registry
- **Bug Fixes:**
- Tor Shield opkg DNS bypass
- HAProxy Portal 503 fix
- Mailserver Dovecot permissions
- MirrorNet ash compatibility
- Various POSIX shell fixes for BusyBox
75. **AI Gateway Login Command (2026-03-06)**
- CLI: `aigatewayctl login [provider]` with credential validation
- Rollback on authentication failure
- RPCD: `login` method for LuCI integration
- Format warnings for provider-specific API key patterns

File diff suppressed because it is too large Load Diff

View File

@ -169,6 +169,97 @@ method_test_provider() {
json_dump
}
# Method: login - validate credentials and save on success
method_login() {
local provider="$1"
local api_key="$2"
# Validate provider name
case "$provider" in
localai|mistral|claude|openai|gemini|xai)
;;
*)
json_init
json_add_boolean "success" "false"
json_add_string "error" "Unknown provider: $provider"
json_dump
return
;;
esac
# LocalAI doesn't need API key
if [ "$provider" = "localai" ]; then
uci set ${CONFIG}.localai.enabled='1'
uci commit ${CONFIG}
json_init
json_add_boolean "success" "true"
json_add_string "provider" "localai"
json_add_string "message" "LocalAI enabled (on-device)"
json_dump
return
fi
# API key required for cloud providers
if [ -z "$api_key" ]; then
json_init
json_add_boolean "success" "false"
json_add_string "error" "API key required"
json_dump
return
fi
# Save old values for rollback on failure
local old_key=$(uci -q get ${CONFIG}.${provider}.api_key)
local old_enabled=$(uci -q get ${CONFIG}.${provider}.enabled)
# Temporarily set credentials for testing
uci set ${CONFIG}.${provider}.api_key="$api_key"
uci set ${CONFIG}.${provider}.enabled='1'
# Test the credentials
local adapter="$LIB_DIR/providers/${provider}.sh"
local test_failed="false"
if [ -f "$adapter" ]; then
. "$adapter"
local result=$(provider_test 2>&1)
if echo "$result" | grep -qi "error\|fail\|unauthorized\|invalid"; then
test_failed="true"
# Rollback
if [ -n "$old_key" ]; then
uci set ${CONFIG}.${provider}.api_key="$old_key"
else
uci -q delete ${CONFIG}.${provider}.api_key
fi
uci set ${CONFIG}.${provider}.enabled="${old_enabled:-0}"
uci commit ${CONFIG}
json_init
json_add_boolean "success" "false"
json_add_string "error" "Authentication failed"
json_add_string "details" "$result"
json_dump
return
fi
fi
# Commit working credentials
uci commit ${CONFIG}
local class=$(uci -q get ${CONFIG}.${provider}.classification)
local model=$(uci -q get ${CONFIG}.${provider}.model)
json_init
json_add_boolean "success" "true"
json_add_string "provider" "$provider"
json_add_string "model" "$model"
json_add_string "classification" "$class"
json_dump
}
# Method: start
method_start() {
/etc/init.d/ai-gateway start >/dev/null 2>&1
@ -205,6 +296,7 @@ case "$1" in
"get_providers": {},
"get_audit_stats": {},
"classify": {"text": "string"},
"login": {"provider": "string", "api_key": "string"},
"set_provider": {"provider": "string", "enabled": "string", "api_key": "string"},
"set_offline_mode": {"mode": "string"},
"test_provider": {"provider": "string"},
@ -224,6 +316,12 @@ case "$1" in
text=$(echo "$input" | jsonfilter -e '@.text' 2>/dev/null)
method_classify "$text"
;;
login)
read -r input
provider=$(echo "$input" | jsonfilter -e '@.provider' 2>/dev/null)
api_key=$(echo "$input" | jsonfilter -e '@.api_key' 2>/dev/null)
method_login "$provider" "$api_key"
;;
set_provider)
read -r input
provider=$(echo "$input" | jsonfilter -e '@.provider' 2>/dev/null)

View File

@ -28,6 +28,7 @@ Classification:
sanitize <text> Sanitize text and show result
Provider Management:
login [provider] Authenticate with a provider (validates before saving)
provider list List configured providers
provider enable <name> Enable a provider (prompts for API key)
provider disable <name> Disable a provider
@ -191,6 +192,136 @@ cmd_provider_test() {
provider_test
}
# Login command - validates credentials before saving
cmd_login() {
local provider="$1"
local api_key="$2"
# Interactive provider selection if not provided
if [ -z "$provider" ]; then
echo "Available providers:"
echo " localai - On-device AI (no API key required)"
echo " mistral - Mistral AI (EU sovereign, GDPR compliant)"
echo " claude - Anthropic Claude"
echo " openai - OpenAI GPT"
echo " gemini - Google Gemini"
echo " xai - xAI Grok"
echo ""
printf "Provider: "
read provider
fi
# Validate provider name
case "$provider" in
localai|mistral|claude|openai|gemini|xai)
;;
*)
echo "Error: Unknown provider '$provider'"
echo "Valid providers: localai, mistral, claude, openai, gemini, xai"
return 1
;;
esac
# LocalAI doesn't need API key
if [ "$provider" = "localai" ]; then
echo "LocalAI runs on-device - no API key required"
uci set ${CONFIG}.localai.enabled='1'
uci commit ${CONFIG}
echo "✓ LocalAI enabled"
return 0
fi
# Interactive API key input if not provided
if [ -z "$api_key" ]; then
printf "API key for $provider: "
stty -echo 2>/dev/null
read -r api_key
stty echo 2>/dev/null
echo ""
fi
[ -z "$api_key" ] && { echo "Error: API key required"; return 1; }
# Validate API key format based on provider
case "$provider" in
mistral)
# Mistral keys are alphanumeric, typically 32+ chars
if [ ${#api_key} -lt 20 ]; then
echo "Warning: Mistral API key seems too short"
fi
;;
claude)
# Anthropic keys start with sk-ant-
if ! echo "$api_key" | grep -q "^sk-ant-"; then
echo "Warning: Claude API key should start with 'sk-ant-'"
fi
;;
openai)
# OpenAI keys start with sk-
if ! echo "$api_key" | grep -q "^sk-"; then
echo "Warning: OpenAI API key should start with 'sk-'"
fi
;;
esac
# Test credentials before saving
echo "Validating credentials..."
# Temporarily set credentials for testing
local old_key=$(uci -q get ${CONFIG}.${provider}.api_key)
local old_enabled=$(uci -q get ${CONFIG}.${provider}.enabled)
uci set ${CONFIG}.${provider}.api_key="$api_key"
uci set ${CONFIG}.${provider}.enabled='1'
local adapter="$LIB_DIR/providers/${provider}.sh"
if [ -f "$adapter" ]; then
. "$adapter"
local result=$(provider_test 2>&1)
if echo "$result" | grep -qi "error\|fail\|unauthorized\|invalid"; then
# Restore old values on failure
if [ -n "$old_key" ]; then
uci set ${CONFIG}.${provider}.api_key="$old_key"
else
uci -q delete ${CONFIG}.${provider}.api_key
fi
uci set ${CONFIG}.${provider}.enabled="${old_enabled:-0}"
uci commit ${CONFIG}
echo "✗ Authentication failed"
echo "$result"
return 1
fi
fi
# Commit the working credentials
uci commit ${CONFIG}
local class=$(uci -q get ${CONFIG}.${provider}.classification)
local model=$(uci -q get ${CONFIG}.${provider}.model)
echo "✓ Login successful"
echo " Provider: $provider"
echo " Model: $model"
echo " Classification: $class"
# Show sovereignty info
case "$class" in
local_only)
echo " Data: Stays on device"
;;
sanitized)
echo " Data: PII sanitized before sending to EU provider"
;;
cloud_direct)
echo " Data: May be sent to cloud (non-sensitive queries only)"
;;
esac
return 0
}
# Audit stats command
cmd_audit_stats() {
. "$LIB_DIR/audit.sh"
@ -308,6 +439,10 @@ case "${1:-}" in
shift
cmd_sanitize "$@"
;;
login)
shift
cmd_login "$@"
;;
provider)
shift
case "$1" in

View File

@ -16,6 +16,7 @@
"write": {
"ubus": {
"luci.ai-gateway": [
"login",
"set_provider",
"set_offline_mode",
"test_provider",