feat(nextcloud): Enhance integration with WAF, backups, mail, sync URLs

- WAF-safe SSL: Route through mitmproxy_inspector, auto-add routes
- Scheduled backups: setup-backup-cron with hourly/daily/weekly support
- Email/SMTP: setup-mail command for outbound notifications
- CalDAV/CardDAV: connections command shows sync URLs for all clients
- New RPCD methods: get_connections, setup_mail, setup_backup_cron
- ACL updated with new method permissions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-03-01 09:07:19 +01:00
parent 00d92037b9
commit 0c55ef6ec1
4 changed files with 339 additions and 28 deletions

View File

@ -4044,3 +4044,26 @@ git checkout HEAD -- index.html
- `./secubox-tools/pre-deploy-lint.sh luci-app-system-hub`
- `./secubox-tools/pre-deploy-lint.sh --all`
- `./secubox-tools/quick-deploy.sh --app system-hub` (lint runs automatically)
59. **Nextcloud Integration Enhancements (2026-03-01)**
- **WAF-Safe SSL Routing:**
- `ssl-enable` now routes through `mitmproxy_inspector` backend
- Automatically adds route to `/srv/mitmproxy/haproxy-routes.json`
- Traffic flow: Client → HAProxy → mitmproxy (WAF) → Nextcloud
- Prevents WAF bypass vulnerability
- **Scheduled Backups:**
- `nextcloudctl setup-backup-cron` creates cron jobs
- Supports hourly, daily, weekly schedules (from UCI config)
- Automatic cleanup of old backups (configurable retention)
- **Email/SMTP Integration:**
- `nextcloudctl setup-mail <host> [port] [user] [pass] [from]`
- Supports Gmail, local mailserver, Mailcow configurations
- Auto-configures TLS for ports 587/465
- **CalDAV/CardDAV Connection Info:**
- `nextcloudctl connections` shows all sync URLs
- iOS, Android (DAVx5), Thunderbird instructions
- Desktop client and mobile app links
- **New RPCD Methods:**
- `get_connections` - Returns all sync URLs
- `setup_mail` - Configure SMTP via LuCI
- `setup_backup_cron` - Enable scheduled backups via LuCI

View File

@ -438,6 +438,82 @@ delete_backup() {
fi
}
# Get connection URLs (CalDAV, CardDAV, WebDAV)
get_connections() {
local http_port=$(uci_get main.http_port)
local ssl_enabled=$(uci_get ssl.enabled)
local ssl_domain=$(uci_get ssl.domain)
# Get LAN IP
local lan_ip
lan_ip=$(uci -q get network.lan.ipaddr || echo "192.168.255.1")
local base_url="http://${lan_ip}:${http_port:-8080}"
if [ "$ssl_enabled" = "1" ] && [ -n "$ssl_domain" ]; then
base_url="https://${ssl_domain}"
fi
cat <<EOF
{
"base_url": "$base_url",
"caldav": "${base_url}/remote.php/dav/calendars/<username>/",
"carddav": "${base_url}/remote.php/dav/addressbooks/users/<username>/contacts/",
"webdav": "${base_url}/remote.php/dav/files/<username>/",
"ios_server": "$base_url",
"ios_path": "/remote.php/dav",
"davx5_url": "${base_url}/remote.php/dav",
"desktop_url": "$base_url",
"ios_app": "https://apps.apple.com/app/nextcloud/id1125420102",
"android_app": "https://play.google.com/store/apps/details?id=com.nextcloud.client"
}
EOF
}
# Setup email/SMTP
setup_mail() {
local input
read -r input
local smtp_host=$(echo "$input" | jsonfilter -e '@.smtp_host' 2>/dev/null)
local smtp_port=$(echo "$input" | jsonfilter -e '@.smtp_port' 2>/dev/null)
local smtp_user=$(echo "$input" | jsonfilter -e '@.smtp_user' 2>/dev/null)
local smtp_pass=$(echo "$input" | jsonfilter -e '@.smtp_pass' 2>/dev/null)
local smtp_from=$(echo "$input" | jsonfilter -e '@.smtp_from' 2>/dev/null)
if [ -z "$smtp_host" ]; then
echo '{"success": false, "error": "SMTP host is required"}'
return
fi
if ! lxc_running; then
echo '{"success": false, "error": "Nextcloud container not running"}'
return
fi
# Build command arguments
local args="$smtp_host ${smtp_port:-587}"
[ -n "$smtp_user" ] && args="$args $smtp_user"
[ -n "$smtp_pass" ] && args="$args \"$smtp_pass\""
[ -n "$smtp_from" ] && args="$args $smtp_from"
if nextcloudctl setup-mail $args >/tmp/nextcloud-mail.log 2>&1; then
echo '{"success": true, "message": "SMTP configured successfully"}'
else
local err=$(tail -1 /tmp/nextcloud-mail.log 2>/dev/null || echo "Unknown error")
echo "{\"success\": false, \"error\": \"$err\"}"
fi
}
# Setup backup cron job
setup_backup_cron() {
if nextcloudctl setup-backup-cron >/tmp/nextcloud-cron.log 2>&1; then
echo '{"success": true, "message": "Backup cron job configured"}'
else
local err=$(tail -1 /tmp/nextcloud-cron.log 2>/dev/null || echo "Unknown error")
echo "{\"success\": false, \"error\": \"$err\"}"
fi
}
# RPCD list method
list_methods() {
cat <<'EOF'
@ -461,7 +537,10 @@ list_methods() {
"logs": {},
"list_users": {},
"reset_password": {"uid": "string", "password": "string"},
"get_storage": {}
"get_storage": {},
"get_connections": {},
"setup_mail": {"smtp_host": "string", "smtp_port": "number", "smtp_user": "string", "smtp_pass": "string", "smtp_from": "string"},
"setup_backup_cron": {}
}
EOF
}
@ -493,6 +572,9 @@ case "$1" in
list_users) list_users ;;
reset_password) reset_password ;;
get_storage) get_storage ;;
get_connections) get_connections ;;
setup_mail) setup_mail ;;
setup_backup_cron) setup_backup_cron ;;
*) echo '{"error": "Unknown method"}' ;;
esac
;;

View File

@ -3,7 +3,7 @@
"description": "Grant access to Nextcloud LXC app",
"read": {
"ubus": {
"luci.nextcloud": ["status", "get_config", "list_backups", "logs", "list_users", "get_storage"]
"luci.nextcloud": ["status", "get_config", "list_backups", "logs", "list_users", "get_storage", "get_connections"]
},
"uci": ["nextcloud"]
},
@ -23,7 +23,9 @@
"ssl_enable",
"ssl_disable",
"occ",
"reset_password"
"reset_password",
"setup_mail",
"setup_backup_cron"
]
},
"uci": ["nextcloud"]

View File

@ -101,9 +101,13 @@ Commands:
restore <name> Restore from backup
list-backups List available backups
ssl-enable <domain> Register with HAProxy for SSL
ssl-enable <domain> Register with HAProxy for SSL (via WAF)
ssl-disable Remove HAProxy registration
setup-mail <args> Configure outbound email (SMTP)
setup-backup-cron Setup scheduled backup cron job
connections Show CalDAV/CardDAV/WebDAV URLs
service-run Start service (used by init)
service-stop Stop service (used by init)
@ -976,7 +980,7 @@ cmd_ssl_enable() {
return 1
fi
log_info "Enabling SSL for $domain via HAProxy..."
log_info "Enabling SSL for $domain via HAProxy + WAF..."
# Check if HAProxy is available
if [ ! -x /usr/sbin/haproxyctl ]; then
@ -984,45 +988,83 @@ cmd_ssl_enable() {
return 1
fi
# Add vhost to HAProxy
local vhost_name="nextcloud_${domain//\./_}"
# Use haproxyctl vhost add - routes through mitmproxy_inspector by default
log_info "Adding vhost via haproxyctl..."
if ! /usr/sbin/haproxyctl vhost add "$domain" --acme; then
log_error "Failed to add HAProxy vhost"
return 1
fi
uci add haproxy vhost
uci set haproxy.@vhost[-1].name="$vhost_name"
uci set haproxy.@vhost[-1].domain="$domain"
uci set haproxy.@vhost[-1].backend="nextcloud_backend"
uci set haproxy.@vhost[-1].ssl='1'
uci set haproxy.@vhost[-1].acme='1'
uci set haproxy.@vhost[-1].enabled='1'
# Add route to mitmproxy for WAF inspection
# This ensures traffic is inspected before reaching Nextcloud
local routes_file="/srv/mitmproxy/haproxy-routes.json"
local routes_file_in="/srv/mitmproxy-in/haproxy-routes.json"
# Add backend
uci add haproxy backend
uci set haproxy.@backend[-1].name="nextcloud_backend"
uci set haproxy.@backend[-1].mode='http'
if [ -f "$routes_file" ]; then
log_info "Adding mitmproxy route for WAF inspection..."
# Use jsonfilter to check if route exists, then add if not
local existing
existing=$(jsonfilter -i "$routes_file" -e "@[\"$domain\"]" 2>/dev/null || echo "")
# Add server
uci add haproxy server
uci set haproxy.@server[-1].backend="nextcloud_backend"
uci set haproxy.@server[-1].address="127.0.0.1"
uci set haproxy.@server[-1].port="$http_port"
if [ -z "$existing" ]; then
# Add route: domain -> [127.0.0.1, port]
local tmpfile="/tmp/routes-$$.json"
# Read existing routes and add new one
if command -v python3 >/dev/null 2>&1; then
python3 -c "
import json
with open('$routes_file', 'r') as f:
routes = json.load(f)
routes['$domain'] = ['127.0.0.1', $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"
else
log_info "Python3 not available, manual route config needed"
log_info "Add to $routes_file: \"$domain\": [\"127.0.0.1\", $http_port]"
fi
else
log_info "WAF route already exists for $domain"
fi
else
log_info "mitmproxy routes file not found, creating..."
mkdir -p "$(dirname "$routes_file")"
echo "{\"$domain\": [\"127.0.0.1\", $http_port]}" > "$routes_file"
[ -d "$(dirname "$routes_file_in")" ] && cp "$routes_file" "$routes_file_in"
fi
uci commit haproxy
# Update Nextcloud config
# Update Nextcloud UCI config
uci_set ssl.enabled '1'
uci_set ssl.domain "$domain"
# Reload HAProxy
# Restart mitmproxy to load new routes
if [ -x /etc/init.d/mitmproxy ]; then
log_info "Reloading mitmproxy..."
/etc/init.d/mitmproxy restart 2>/dev/null || true
fi
# Regenerate HAProxy config and reload
log_info "Regenerating HAProxy config..."
/usr/sbin/haproxyctl generate 2>/dev/null || true
/etc/init.d/haproxy reload 2>/dev/null || true
# Add trusted domain in Nextcloud
if lxc_running; then
log_info "Configuring Nextcloud trusted domains..."
lxc_occ config:system:set trusted_domains 1 --value="$domain"
lxc_occ config:system:set overwriteprotocol --value="https"
lxc_occ config:system:set overwrite.cli.url --value="https://$domain"
fi
log_info "SSL enabled for $domain"
log_info ""
log_info "SSL enabled for $domain (with WAF inspection)"
log_info "Access Nextcloud at: https://$domain"
log_info ""
log_info "Traffic flow: Client -> HAProxy -> mitmproxy (WAF) -> Nextcloud"
}
cmd_ssl_disable() {
@ -1037,6 +1079,165 @@ cmd_ssl_disable() {
log_info "SSL disabled"
}
cmd_setup_mail() {
require_root
load_config
local smtp_host="${1:-}"
local smtp_port="${2:-587}"
local smtp_user="${3:-}"
local smtp_pass="${4:-}"
local smtp_from="${5:-}"
if [ -z "$smtp_host" ]; then
cat << 'EOF'
Usage: nextcloudctl setup-mail <smtp_host> [port] [user] [password] [from_address]
Examples:
# Gmail SMTP
nextcloudctl setup-mail smtp.gmail.com 587 user@gmail.com "app-password" user@gmail.com
# Local mailserver (secubox-app-mailserver)
nextcloudctl setup-mail 127.0.0.1 25
# Mailcow/Mailinabox
nextcloudctl setup-mail mail.example.com 587 noreply@example.com "password" noreply@example.com
Note: For Gmail, use an App Password (not your regular password).
EOF
return 1
fi
if ! lxc_running; then
log_error "Nextcloud container not running"
return 1
fi
log_info "Configuring SMTP mail settings..."
# Set mail mode to SMTP
lxc_occ config:system:set mail_smtpmode --value="smtp"
lxc_occ config:system:set mail_smtphost --value="$smtp_host"
lxc_occ config:system:set mail_smtpport --value="$smtp_port"
# Enable TLS for standard ports
if [ "$smtp_port" = "587" ] || [ "$smtp_port" = "465" ]; then
lxc_occ config:system:set mail_smtpsecure --value="tls"
fi
# Set authentication if provided
if [ -n "$smtp_user" ]; then
lxc_occ config:system:set mail_smtpauth --value="1"
lxc_occ config:system:set mail_smtpauthtype --value="LOGIN"
lxc_occ config:system:set mail_smtpname --value="$smtp_user"
fi
if [ -n "$smtp_pass" ]; then
lxc_occ config:system:set mail_smtppassword --value="$smtp_pass"
fi
# Set from address
if [ -n "$smtp_from" ]; then
lxc_occ config:system:set mail_from_address --value="${smtp_from%@*}"
lxc_occ config:system:set mail_domain --value="${smtp_from#*@}"
elif [ -n "$smtp_user" ]; then
lxc_occ config:system:set mail_from_address --value="${smtp_user%@*}"
lxc_occ config:system:set mail_domain --value="${smtp_user#*@}"
fi
log_info "SMTP configured: $smtp_host:$smtp_port"
log_info ""
log_info "Test with: nextcloudctl occ notification:test-push <username>"
}
cmd_setup_backup_cron() {
require_root
load_config
local schedule="$(uci_get backup.schedule)" || schedule="daily"
local cron_file="/etc/cron.d/nextcloud-backup"
log_info "Setting up scheduled backups: $schedule"
case "$schedule" in
hourly)
echo "0 * * * * root /usr/sbin/nextcloudctl backup auto-\$(date +\\%Y\\%m\\%d-\\%H) >/dev/null 2>&1" > "$cron_file"
;;
daily)
echo "0 3 * * * root /usr/sbin/nextcloudctl backup auto-\$(date +\\%Y\\%m\\%d) >/dev/null 2>&1" > "$cron_file"
;;
weekly)
echo "0 3 * * 0 root /usr/sbin/nextcloudctl backup auto-\$(date +\\%Y\\%m\\%d) >/dev/null 2>&1" > "$cron_file"
;;
disabled|none)
rm -f "$cron_file"
log_info "Scheduled backups disabled"
return 0
;;
*)
log_error "Unknown schedule: $schedule (use: hourly, daily, weekly, disabled)"
return 1
;;
esac
chmod 644 "$cron_file"
# Restart cron if running
/etc/init.d/cron restart 2>/dev/null || true
log_info "Backup cron job created: $cron_file"
log_info "Backups will run $schedule and keep last $(uci_get backup.keep) copies"
}
cmd_connections() {
load_config
local lan_ip
lan_ip=$(uci -q get network.lan.ipaddr || echo "192.168.1.1")
local base_url="http://${lan_ip}:${http_port}"
if [ "$ssl_enabled" = "1" ] && [ -n "$ssl_domain" ]; then
base_url="https://${ssl_domain}"
fi
cat << EOF
Nextcloud Connection URLs
=========================
Web Interface:
$base_url
CalDAV (Calendar):
$base_url/remote.php/dav/calendars/<username>/
CardDAV (Contacts):
$base_url/remote.php/dav/addressbooks/users/<username>/contacts/
WebDAV (Files):
$base_url/remote.php/dav/files/<username>/
iOS/macOS Calendar & Contacts:
Server: $base_url
Path: /remote.php/dav
Android (DAVx5):
Base URL: $base_url/remote.php/dav
Login: Your Nextcloud username and password
Thunderbird (TbSync + Provider for CalDAV & CardDAV):
Server URL: $base_url
Desktop Sync Client:
Download from: https://nextcloud.com/install/#install-clients
Server: $base_url
Mobile Apps:
iOS: https://apps.apple.com/app/nextcloud/id1125420102
Android: https://play.google.com/store/apps/details?id=com.nextcloud.client
EOF
}
cmd_service_run() {
require_root
load_config
@ -1067,6 +1268,9 @@ case "${1:-}" in
list-backups) shift; cmd_list_backups "$@" ;;
ssl-enable) shift; cmd_ssl_enable "$@" ;;
ssl-disable) shift; cmd_ssl_disable "$@" ;;
setup-mail) shift; cmd_setup_mail "$@" ;;
setup-backup-cron) shift; cmd_setup_backup_cron "$@" ;;
connections) shift; cmd_connections "$@" ;;
service-run) shift; cmd_service_run "$@" ;;
service-stop) shift; cmd_service_stop "$@" ;;
*) usage ;;