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:
parent
5b8c4cd52c
commit
70056e02ed
@ -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
|
||||
|
||||
1488
.claude/WIP.md
1488
.claude/WIP.md
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
"write": {
|
||||
"ubus": {
|
||||
"luci.ai-gateway": [
|
||||
"login",
|
||||
"set_provider",
|
||||
"set_offline_mode",
|
||||
"test_provider",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user