fix(users,routing): Add gitea/jellyfin support and fix mitmproxy routes
secubox-users: - Add gitea and jellyfin to supported services list - Add create/update/delete handlers for gitea (via API) and jellyfin - Update CLI help and status display to include new services luci-app-secubox-users: - Add jellyfin service checkbox and badge in frontend - Update RPCD handler to check jellyfin service status mitmproxy routing fix: - nextcloudctl: Use host LAN IP instead of 127.0.0.1 for WAF routes (mitmproxy runs in container, can't reach host's localhost) - metablogizerctl: Same fix for mitmproxy route registration - mitmproxyctl: Fix sync_metablogizer_routes to use host IP This fixes 502/403 errors when accessing services through HAProxy->mitmproxy because the mitmproxy container couldn't route to 127.0.0.1 on the host. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
518891d538
commit
2bb40d9419
@ -117,7 +117,8 @@ return view.extend({
|
||||
E('label', { 'style': 'margin-left:10px;' }, [E('input', { 'type': 'checkbox', 'id': 'svc-jabber', 'checked': true }), ' Jabber']),
|
||||
E('label', { 'style': 'margin-left:10px;' }, [E('input', { 'type': 'checkbox', 'id': 'svc-matrix', 'checked': true }), ' Matrix']),
|
||||
E('label', { 'style': 'margin-left:10px;' }, [E('input', { 'type': 'checkbox', 'id': 'svc-email', 'checked': true }), ' Email']),
|
||||
E('label', { 'style': 'margin-left:10px;' }, [E('input', { 'type': 'checkbox', 'id': 'svc-gitea', 'checked': true }), ' Gitea'])
|
||||
E('label', { 'style': 'margin-left:10px;' }, [E('input', { 'type': 'checkbox', 'id': 'svc-gitea', 'checked': true }), ' Gitea']),
|
||||
E('label', { 'style': 'margin-left:10px;' }, [E('input', { 'type': 'checkbox', 'id': 'svc-jellyfin', 'checked': true }), ' Jellyfin'])
|
||||
])
|
||||
])
|
||||
]),
|
||||
@ -138,6 +139,7 @@ return view.extend({
|
||||
if (document.getElementById('svc-matrix').checked) services.push('matrix');
|
||||
if (document.getElementById('svc-email').checked) services.push('email');
|
||||
if (document.getElementById('svc-gitea').checked) services.push('gitea');
|
||||
if (document.getElementById('svc-jellyfin').checked) services.push('jellyfin');
|
||||
|
||||
if (!username) {
|
||||
ui.addNotification(null, E('p', {}, _('Username required')), 'error');
|
||||
@ -266,7 +268,8 @@ return view.extend({
|
||||
this.renderServiceBadge('Matrix', services.matrix),
|
||||
this.renderServiceBadge('Jabber', services.jabber),
|
||||
this.renderServiceBadge('Email', services.email),
|
||||
this.renderServiceBadge('Gitea', services.gitea)
|
||||
this.renderServiceBadge('Gitea', services.gitea),
|
||||
this.renderServiceBadge('Jellyfin', services.jellyfin)
|
||||
]),
|
||||
E('p', { 'style': 'color:#666;' }, _('Domain: %s | Users: %d').format(status.domain, status.user_count))
|
||||
]));
|
||||
|
||||
@ -17,6 +17,7 @@ check_service() {
|
||||
jabber) [ -x /usr/sbin/jabberctl ] && lxc-info -n jabber 2>/dev/null | grep -q "RUNNING" && echo "1" || echo "0" ;;
|
||||
email) [ -x /usr/sbin/mailserverctl ] && lxc-info -n mailserver 2>/dev/null | grep -q "RUNNING" && echo "1" || echo "0" ;;
|
||||
gitea) [ -x /usr/sbin/giteactl ] && lxc-info -n gitea 2>/dev/null | grep -q "RUNNING" && echo "1" || echo "0" ;;
|
||||
jellyfin) [ -x /usr/sbin/jellyfinctl ] && lxc-info -n jellyfin 2>/dev/null | grep -q "RUNNING" && echo "1" || echo "0" ;;
|
||||
*) echo "0" ;;
|
||||
esac
|
||||
}
|
||||
@ -32,6 +33,7 @@ get_status() {
|
||||
local jb_running=$(check_service jabber)
|
||||
local em_running=$(check_service email)
|
||||
local gt_running=$(check_service gitea)
|
||||
local jf_running=$(check_service jellyfin)
|
||||
|
||||
cat <<EOFJ
|
||||
{
|
||||
@ -44,7 +46,8 @@ get_status() {
|
||||
"matrix": $mx_running,
|
||||
"jabber": $jb_running,
|
||||
"email": $em_running,
|
||||
"gitea": $gt_running
|
||||
"gitea": $gt_running,
|
||||
"jellyfin": $jf_running
|
||||
}
|
||||
}
|
||||
EOFJ
|
||||
|
||||
@ -867,7 +867,11 @@ _emancipate_mitmproxy() {
|
||||
local port=$(uci_get site_${name}.port)
|
||||
local routes_file="/srv/mitmproxy-in/haproxy-routes.json"
|
||||
|
||||
log_info "[WAF] Adding route: $domain -> 127.0.0.1:$port"
|
||||
# Get the host's LAN IP (mitmproxy runs in container, can't reach 127.0.0.1 on host)
|
||||
local host_ip
|
||||
host_ip=$(uci -q get network.lan.ipaddr || echo "192.168.255.1")
|
||||
|
||||
log_info "[WAF] Adding route: $domain -> $host_ip:$port"
|
||||
|
||||
# Direct JSON update - most reliable method
|
||||
if [ -f "$routes_file" ] && command -v python3 >/dev/null 2>&1; then
|
||||
@ -877,7 +881,7 @@ import sys
|
||||
try:
|
||||
with open('$routes_file', 'r') as f:
|
||||
routes = json.load(f)
|
||||
routes['$domain'] = ['127.0.0.1', $port]
|
||||
routes['$domain'] = ['$host_ip', $port]
|
||||
with open('$routes_file', 'w') as f:
|
||||
json.dump(routes, f, indent=2)
|
||||
print('Route added successfully')
|
||||
@ -892,7 +896,7 @@ except Exception as e:
|
||||
|
||||
# Fallback: Use centralized secubox-route if available
|
||||
if command -v secubox-route >/dev/null 2>&1; then
|
||||
if secubox-route add "$domain" "127.0.0.1" "$port" "metablogizer" 2>&1; then
|
||||
if secubox-route add "$domain" "$host_ip" "$port" "metablogizer" 2>&1; then
|
||||
log_info "[WAF] Route registered via secubox-route"
|
||||
return 0
|
||||
fi
|
||||
|
||||
@ -1482,6 +1482,10 @@ sync_metablogizer_routes() {
|
||||
|
||||
log_info "Scanning MetaBlogizer sites..."
|
||||
|
||||
# Get host IP (mitmproxy runs in container, can't reach 127.0.0.1 on host)
|
||||
local host_ip
|
||||
host_ip=$(uci -q get network.lan.ipaddr || echo "192.168.255.1")
|
||||
|
||||
# Get all metablogizer sites
|
||||
local sites_file="/tmp/mb_sites.tmp"
|
||||
uci show metablogizer 2>/dev/null | grep "=site$" | cut -d'=' -f1 | cut -d'.' -f2 > "$sites_file"
|
||||
@ -1503,9 +1507,9 @@ sync_metablogizer_routes() {
|
||||
fi
|
||||
echo "$domain" >> "$added_file"
|
||||
|
||||
# Output JSON fragment
|
||||
echo "\"$domain\": [\"127.0.0.1\", $port]"
|
||||
log_info " $domain -> 127.0.0.1:$port (metablogizer)"
|
||||
# Output JSON fragment (use host IP, not 127.0.0.1)
|
||||
echo "\"$domain\": [\"$host_ip\", $port]"
|
||||
log_info " $domain -> $host_ip:$port (metablogizer)"
|
||||
done < "$sites_file"
|
||||
|
||||
rm -f "$sites_file"
|
||||
|
||||
@ -997,9 +997,15 @@ cmd_ssl_enable() {
|
||||
|
||||
# Add route to mitmproxy for WAF inspection
|
||||
# This ensures traffic is inspected before reaching Nextcloud
|
||||
# NOTE: Nextcloud uses host network (lxc.net.0.type=none) so it listens on 192.168.255.1
|
||||
# mitmproxy runs in its own container, so it can't reach 127.0.0.1 on the host
|
||||
local routes_file="/srv/mitmproxy/haproxy-routes.json"
|
||||
local routes_file_in="/srv/mitmproxy-in/haproxy-routes.json"
|
||||
|
||||
# Get the host's LAN IP (where Nextcloud is accessible from mitmproxy container)
|
||||
local host_ip
|
||||
host_ip=$(uci -q get network.lan.ipaddr || echo "192.168.255.1")
|
||||
|
||||
if [ -f "$routes_file" ]; then
|
||||
log_info "Adding mitmproxy route for WAF inspection..."
|
||||
# Use jsonfilter to check if route exists, then add if not
|
||||
@ -1007,7 +1013,7 @@ cmd_ssl_enable() {
|
||||
existing=$(jsonfilter -i "$routes_file" -e "@[\"$domain\"]" 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$existing" ]; then
|
||||
# Add route: domain -> [127.0.0.1, port]
|
||||
# Add route: domain -> [host_ip, port]
|
||||
local tmpfile="/tmp/routes-$$.json"
|
||||
# Read existing routes and add new one
|
||||
if command -v python3 >/dev/null 2>&1; then
|
||||
@ -1015,17 +1021,17 @@ cmd_ssl_enable() {
|
||||
import json
|
||||
with open('$routes_file', 'r') as f:
|
||||
routes = json.load(f)
|
||||
routes['$domain'] = ['127.0.0.1', $http_port]
|
||||
routes['$domain'] = ['$host_ip', $http_port]
|
||||
with open('$tmpfile', 'w') as f:
|
||||
json.dump(routes, f, indent=2)
|
||||
"
|
||||
mv "$tmpfile" "$routes_file"
|
||||
# Also update the in-container copy
|
||||
[ -f "$routes_file_in" ] && cp "$routes_file" "$routes_file_in"
|
||||
log_info "Added WAF route: $domain -> 127.0.0.1:$http_port"
|
||||
log_info "Added WAF route: $domain -> $host_ip:$http_port"
|
||||
else
|
||||
log_info "Python3 not available, manual route config needed"
|
||||
log_info "Add to $routes_file: \"$domain\": [\"127.0.0.1\", $http_port]"
|
||||
log_info "Add to $routes_file: \"$domain\": [\"$host_ip\", $http_port]"
|
||||
fi
|
||||
else
|
||||
log_info "WAF route already exists for $domain"
|
||||
@ -1033,7 +1039,7 @@ with open('$tmpfile', 'w') as f:
|
||||
else
|
||||
log_info "mitmproxy routes file not found, creating..."
|
||||
mkdir -p "$(dirname "$routes_file")"
|
||||
echo "{\"$domain\": [\"127.0.0.1\", $http_port]}" > "$routes_file"
|
||||
echo "{\"$domain\": [\"$host_ip\", $http_port]}" > "$routes_file"
|
||||
[ -d "$(dirname "$routes_file_in")" ] && cp "$routes_file" "$routes_file_in"
|
||||
fi
|
||||
|
||||
|
||||
@ -51,6 +51,8 @@ check_service() {
|
||||
matrix) [ -x /usr/sbin/matrixctl ] && lxc-info -n matrix 2>/dev/null | grep -q "RUNNING" ;;
|
||||
jabber) [ -x /usr/sbin/jabberctl ] && lxc-info -n jabber 2>/dev/null | grep -q "RUNNING" ;;
|
||||
email) [ -x /usr/sbin/mailserverctl ] && lxc-info -n mailserver 2>/dev/null | grep -q "RUNNING" ;;
|
||||
gitea) [ -x /usr/sbin/giteactl ] && lxc-info -n gitea 2>/dev/null | grep -q "RUNNING" ;;
|
||||
jellyfin) [ -x /usr/sbin/jellyfinctl ] && lxc-info -n jellyfin 2>/dev/null | grep -q "RUNNING" ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
@ -86,6 +88,23 @@ create_on_service() {
|
||||
email)
|
||||
mailserverctl add-user "$email" "$password" 2>/dev/null
|
||||
;;
|
||||
gitea)
|
||||
giteactl admin create-user --username "$username" --password "$password" --email "$email" 2>/dev/null
|
||||
;;
|
||||
jellyfin)
|
||||
# Jellyfin user creation via API
|
||||
local jf_ip=$(uci -q get jellyfin.main.ip_address || echo "192.168.255.31")
|
||||
local jf_port=$(uci -q get jellyfin.main.port || echo "8096")
|
||||
local jf_api_key=$(uci -q get jellyfin.main.api_key)
|
||||
if [ -n "$jf_api_key" ]; then
|
||||
curl -s -X POST "http://${jf_ip}:${jf_port}/Users/New" \
|
||||
-H "X-Emby-Token: ${jf_api_key}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"Name\":\"${username}\",\"Password\":\"${password}\"}" 2>/dev/null
|
||||
else
|
||||
log_warn "Jellyfin: No API key configured"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
@ -118,6 +137,40 @@ update_password_on_service() {
|
||||
sed -i "/^${email}:/d" /srv/lxc/mailserver/rootfs/etc/dovecot/users 2>/dev/null
|
||||
mailserverctl add-user "$email" "$password" 2>/dev/null
|
||||
;;
|
||||
gitea)
|
||||
# Gitea password update via API
|
||||
local gitea_url=$(uci -q get gitea.main.url 2>/dev/null || echo "http://192.168.255.1:3001")
|
||||
local gitea_token=$(uci -q get gitea.main.token 2>/dev/null)
|
||||
if [ -n "$gitea_token" ]; then
|
||||
curl -s -X PATCH \
|
||||
-H "Authorization: token $gitea_token" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"login_name\":\"$username\",\"password\":\"$password\"}" \
|
||||
"${gitea_url}/api/v1/admin/users/${username}" 2>/dev/null
|
||||
else
|
||||
log_warn "Gitea: No API token configured"
|
||||
fi
|
||||
;;
|
||||
jellyfin)
|
||||
# Jellyfin password update via API
|
||||
local jf_ip=$(uci -q get jellyfin.main.ip_address || echo "192.168.255.31")
|
||||
local jf_port=$(uci -q get jellyfin.main.port || echo "8096")
|
||||
local jf_api_key=$(uci -q get jellyfin.main.api_key)
|
||||
if [ -n "$jf_api_key" ]; then
|
||||
# Get user ID first
|
||||
local user_id=$(curl -s "http://${jf_ip}:${jf_port}/Users" \
|
||||
-H "X-Emby-Token: ${jf_api_key}" 2>/dev/null | \
|
||||
jsonfilter -e "@[?(@.Name=='${username}')].Id" 2>/dev/null)
|
||||
if [ -n "$user_id" ]; then
|
||||
curl -s -X POST "http://${jf_ip}:${jf_port}/Users/${user_id}/Password" \
|
||||
-H "X-Emby-Token: ${jf_api_key}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"NewPw\":\"${password}\"}" 2>/dev/null
|
||||
fi
|
||||
else
|
||||
log_warn "Jellyfin: No API key configured"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
@ -147,6 +200,35 @@ delete_from_service() {
|
||||
sed -i "/^${email}:/d" /srv/lxc/mailserver/rootfs/etc/dovecot/users 2>/dev/null
|
||||
sed -i "/${email}/d" /srv/lxc/mailserver/rootfs/etc/postfix/vmailbox 2>/dev/null
|
||||
;;
|
||||
gitea)
|
||||
# Gitea user deletion via API
|
||||
local gitea_url=$(uci -q get gitea.main.url 2>/dev/null || echo "http://192.168.255.1:3001")
|
||||
local gitea_token=$(uci -q get gitea.main.token 2>/dev/null)
|
||||
if [ -n "$gitea_token" ]; then
|
||||
curl -s -X DELETE \
|
||||
-H "Authorization: token $gitea_token" \
|
||||
"${gitea_url}/api/v1/admin/users/${username}" 2>/dev/null
|
||||
else
|
||||
log_warn "Gitea: No API token configured - manual deletion required"
|
||||
fi
|
||||
;;
|
||||
jellyfin)
|
||||
# Jellyfin user deletion via API
|
||||
local jf_ip=$(uci -q get jellyfin.main.ip_address || echo "192.168.255.31")
|
||||
local jf_port=$(uci -q get jellyfin.main.port || echo "8096")
|
||||
local jf_api_key=$(uci -q get jellyfin.main.api_key)
|
||||
if [ -n "$jf_api_key" ]; then
|
||||
local user_id=$(curl -s "http://${jf_ip}:${jf_port}/Users" \
|
||||
-H "X-Emby-Token: ${jf_api_key}" 2>/dev/null | \
|
||||
jsonfilter -e "@[?(@.Name=='${username}')].Id" 2>/dev/null)
|
||||
if [ -n "$user_id" ]; then
|
||||
curl -s -X DELETE "http://${jf_ip}:${jf_port}/Users/${user_id}" \
|
||||
-H "X-Emby-Token: ${jf_api_key}" 2>/dev/null
|
||||
fi
|
||||
else
|
||||
log_warn "Jellyfin: No API key configured - manual deletion required"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
@ -172,7 +254,7 @@ cmd_add() {
|
||||
|
||||
# Default to all services if not specified
|
||||
if [ -z "$services" ]; then
|
||||
services=$(uci_get main.default_services || echo "nextcloud peertube jabber matrix email")
|
||||
services=$(uci_get main.default_services || echo "nextcloud peertube jabber matrix email gitea jellyfin")
|
||||
else
|
||||
services=$(echo "$services" | tr ',' ' ')
|
||||
fi
|
||||
@ -440,7 +522,7 @@ cmd_status() {
|
||||
echo ""
|
||||
|
||||
echo "Available Services:"
|
||||
for svc in nextcloud peertube jabber matrix email; do
|
||||
for svc in nextcloud peertube jabber matrix email gitea jellyfin; do
|
||||
if check_service "$svc"; then
|
||||
echo -e " ${GREEN}●${NC} $svc"
|
||||
else
|
||||
@ -470,7 +552,7 @@ Commands:
|
||||
status Show status and available services
|
||||
|
||||
Services (comma-separated):
|
||||
nextcloud, peertube, jabber, matrix, email
|
||||
nextcloud, peertube, jabber, matrix, email, gitea, jellyfin
|
||||
|
||||
Examples:
|
||||
secubox-users add alice # All services, generated password
|
||||
|
||||
Loading…
Reference in New Issue
Block a user