Add complete backend implementation for Gitea integration and local backups with admin permissions: RPCD Methods (luci.secubox-p2p): - get_gitea_config / set_gitea_config - Gitea server configuration - create_gitea_repo - Create new Gitea repository via API - list_gitea_repos - List user's Gitea repositories - get_gitea_commits - Fetch commit history - push_gitea_backup - Push config/packages/scripts to Gitea - pull_gitea_backup - Restore from Gitea commit - create_local_backup - Create local backup snapshot - list_local_backups - List available local backups - restore_local_backup - Restore from local backup UCI Config (secubox-p2p): - gitea section: server_url, repo_name, access_token, auto_backup options - backup section: backup_dir, max_backups, auto_cleanup Frontend (hub.js): - Updated createGiteaRepo() to use backend API - Updated backup functions to use backend storage - Added refreshGiteaCommits() for real API calls - Load function now fetches Gitea config and backup list Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
621 lines
21 KiB
Bash
621 lines
21 KiB
Bash
#!/bin/sh
|
|
# SecuBox P2P RPCD Handler
|
|
|
|
. /usr/share/libubox/jshn.sh
|
|
|
|
P2P_CMD="/usr/sbin/secubox-p2p"
|
|
|
|
case "$1" in
|
|
list)
|
|
cat <<EOF
|
|
{
|
|
"get_peers": {},
|
|
"get_settings": {},
|
|
"get_services": {},
|
|
"get_shared_services": {},
|
|
"discover": { "timeout": 5 },
|
|
"add_peer": { "address": "string", "name": "string" },
|
|
"remove_peer": { "peer_id": "string" },
|
|
"set_settings": { "settings": "object" },
|
|
"sync_catalog": {},
|
|
"broadcast_command": { "command": "string" },
|
|
"get_dns_config": {},
|
|
"set_dns_config": { "config": "object" },
|
|
"get_wireguard_config": {},
|
|
"set_wireguard_config": { "config": "object" },
|
|
"get_haproxy_config": {},
|
|
"set_haproxy_config": { "config": "object" },
|
|
"get_registry": {},
|
|
"register_url": { "short_url": "string", "target_url": "string" },
|
|
"health_check": {},
|
|
"get_gitea_config": {},
|
|
"set_gitea_config": { "config": "object" },
|
|
"create_gitea_repo": { "name": "string", "description": "string", "private": true, "init_readme": true },
|
|
"list_gitea_repos": {},
|
|
"get_gitea_commits": { "limit": 20 },
|
|
"push_gitea_backup": { "message": "string", "components": "object" },
|
|
"pull_gitea_backup": { "commit_sha": "string" },
|
|
"create_local_backup": { "name": "string", "components": "object" },
|
|
"list_local_backups": {},
|
|
"restore_local_backup": { "backup_id": "string" }
|
|
}
|
|
EOF
|
|
;;
|
|
|
|
call)
|
|
case "$2" in
|
|
get_peers)
|
|
$P2P_CMD peers
|
|
;;
|
|
|
|
get_settings)
|
|
$P2P_CMD settings
|
|
;;
|
|
|
|
get_services)
|
|
$P2P_CMD services
|
|
;;
|
|
|
|
get_shared_services)
|
|
$P2P_CMD shared-services
|
|
;;
|
|
|
|
discover)
|
|
read input
|
|
timeout=$(echo "$input" | jsonfilter -e '@.timeout' 2>/dev/null || echo "5")
|
|
$P2P_CMD discover "$timeout"
|
|
;;
|
|
|
|
add_peer)
|
|
read input
|
|
address=$(echo "$input" | jsonfilter -e '@.address')
|
|
name=$(echo "$input" | jsonfilter -e '@.name')
|
|
if [ -n "$address" ]; then
|
|
$P2P_CMD add-peer "$address" "$name"
|
|
else
|
|
echo '{"success":false,"error":"Address required"}'
|
|
fi
|
|
;;
|
|
|
|
remove_peer)
|
|
read input
|
|
peer_id=$(echo "$input" | jsonfilter -e '@.peer_id')
|
|
if [ -n "$peer_id" ]; then
|
|
$P2P_CMD remove-peer "$peer_id"
|
|
else
|
|
echo '{"success":false,"error":"Peer ID required"}'
|
|
fi
|
|
;;
|
|
|
|
set_settings)
|
|
read input
|
|
settings=$(echo "$input" | jsonfilter -e '@.settings')
|
|
$P2P_CMD set-settings "$settings"
|
|
;;
|
|
|
|
sync_catalog)
|
|
$P2P_CMD sync
|
|
;;
|
|
|
|
broadcast_command)
|
|
read input
|
|
command=$(echo "$input" | jsonfilter -e '@.command')
|
|
$P2P_CMD broadcast "$command"
|
|
;;
|
|
|
|
get_dns_config)
|
|
cat <<EOF
|
|
{
|
|
"enabled": $(uci -q get secubox-p2p.dns.enabled || echo 0),
|
|
"primary_dns": "$(uci -q get secubox-p2p.dns.primary_dns || echo "127.0.0.1:53")",
|
|
"sync_enabled": $(uci -q get secubox-p2p.dns.sync_enabled || echo 1),
|
|
"base_domain": "$(uci -q get secubox-p2p.dns.base_domain || echo "sb.local")"
|
|
}
|
|
EOF
|
|
;;
|
|
|
|
set_dns_config)
|
|
read input
|
|
enabled=$(echo "$input" | jsonfilter -e '@.config.enabled')
|
|
primary_dns=$(echo "$input" | jsonfilter -e '@.config.primary_dns')
|
|
base_domain=$(echo "$input" | jsonfilter -e '@.config.base_domain')
|
|
|
|
[ -n "$enabled" ] && uci set secubox-p2p.dns.enabled="$enabled"
|
|
[ -n "$primary_dns" ] && uci set secubox-p2p.dns.primary_dns="$primary_dns"
|
|
[ -n "$base_domain" ] && uci set secubox-p2p.dns.base_domain="$base_domain"
|
|
uci commit secubox-p2p
|
|
|
|
echo '{"success":true}'
|
|
;;
|
|
|
|
get_wireguard_config)
|
|
cat <<EOF
|
|
{
|
|
"enabled": $(uci -q get secubox-p2p.wireguard.enabled || echo 0),
|
|
"listen_port": $(uci -q get secubox-p2p.wireguard.listen_port || echo 51820),
|
|
"network_cidr": "$(uci -q get secubox-p2p.wireguard.network_cidr || echo "10.100.0.0/24")",
|
|
"auto_configure": $(uci -q get secubox-p2p.wireguard.auto_configure || echo 1)
|
|
}
|
|
EOF
|
|
;;
|
|
|
|
set_wireguard_config)
|
|
read input
|
|
enabled=$(echo "$input" | jsonfilter -e '@.config.enabled')
|
|
listen_port=$(echo "$input" | jsonfilter -e '@.config.listen_port')
|
|
network_cidr=$(echo "$input" | jsonfilter -e '@.config.network_cidr')
|
|
|
|
[ -n "$enabled" ] && uci set secubox-p2p.wireguard.enabled="$enabled"
|
|
[ -n "$listen_port" ] && uci set secubox-p2p.wireguard.listen_port="$listen_port"
|
|
[ -n "$network_cidr" ] && uci set secubox-p2p.wireguard.network_cidr="$network_cidr"
|
|
uci commit secubox-p2p
|
|
|
|
echo '{"success":true}'
|
|
;;
|
|
|
|
get_haproxy_config)
|
|
cat <<EOF
|
|
{
|
|
"enabled": $(uci -q get secubox-p2p.haproxy.enabled || echo 0),
|
|
"strategy": "$(uci -q get secubox-p2p.haproxy.strategy || echo "round-robin")",
|
|
"health_check": $(uci -q get secubox-p2p.haproxy.health_check || echo 1),
|
|
"failover": $(uci -q get secubox-p2p.haproxy.failover || echo 1)
|
|
}
|
|
EOF
|
|
;;
|
|
|
|
set_haproxy_config)
|
|
read input
|
|
enabled=$(echo "$input" | jsonfilter -e '@.config.enabled')
|
|
strategy=$(echo "$input" | jsonfilter -e '@.config.strategy')
|
|
|
|
[ -n "$enabled" ] && uci set secubox-p2p.haproxy.enabled="$enabled"
|
|
[ -n "$strategy" ] && uci set secubox-p2p.haproxy.strategy="$strategy"
|
|
uci commit secubox-p2p
|
|
|
|
echo '{"success":true}'
|
|
;;
|
|
|
|
get_registry)
|
|
cat <<EOF
|
|
{
|
|
"base_url": "$(uci -q get secubox-p2p.registry.base_url || echo "sb.local")",
|
|
"cache_enabled": $(uci -q get secubox-p2p.registry.cache_enabled || echo 1),
|
|
"cache_ttl": $(uci -q get secubox-p2p.registry.cache_ttl || echo 300),
|
|
"services": []
|
|
}
|
|
EOF
|
|
;;
|
|
|
|
register_url)
|
|
read input
|
|
short_url=$(echo "$input" | jsonfilter -e '@.short_url')
|
|
target_url=$(echo "$input" | jsonfilter -e '@.target_url')
|
|
|
|
if [ -n "$short_url" ] && [ -n "$target_url" ]; then
|
|
# Store in UCI or file
|
|
echo "{\"success\":true,\"registered_url\":\"$(uci -q get secubox-p2p.registry.base_url)/${short_url}\"}"
|
|
else
|
|
echo '{"success":false,"error":"short_url and target_url required"}'
|
|
fi
|
|
;;
|
|
|
|
health_check)
|
|
local peers_online=0
|
|
local peers_total=0
|
|
local services_running=0
|
|
|
|
# Count online peers
|
|
if [ -f /tmp/secubox-p2p-peers.json ]; then
|
|
peers_total=$(jsonfilter -i /tmp/secubox-p2p-peers.json -e '@.peers[*]' 2>/dev/null | wc -l)
|
|
peers_online=$(jsonfilter -i /tmp/secubox-p2p-peers.json -e '@.peers[*].status' 2>/dev/null | grep -c "online" || echo 0)
|
|
fi
|
|
|
|
# Count running services
|
|
for svc in dnsmasq uhttpd crowdsec haproxy; do
|
|
pgrep "$svc" >/dev/null 2>&1 && services_running=$((services_running + 1))
|
|
done
|
|
|
|
cat <<EOF
|
|
{
|
|
"status": "healthy",
|
|
"peers_online": $peers_online,
|
|
"peers_total": $peers_total,
|
|
"services_running": $services_running,
|
|
"dns_federation": $(uci -q get secubox-p2p.dns.enabled || echo 0),
|
|
"wireguard_mesh": $(uci -q get secubox-p2p.wireguard.enabled || echo 0),
|
|
"haproxy": $(uci -q get secubox-p2p.haproxy.enabled || echo 0)
|
|
}
|
|
EOF
|
|
;;
|
|
|
|
get_gitea_config)
|
|
cat <<EOF
|
|
{
|
|
"enabled": $(uci -q get secubox-p2p.gitea.enabled || echo 0),
|
|
"server_url": "$(uci -q get secubox-p2p.gitea.server_url || echo "")",
|
|
"repo_name": "$(uci -q get secubox-p2p.gitea.repo_name || echo "secubox-backup")",
|
|
"repo_owner": "$(uci -q get secubox-p2p.gitea.repo_owner || echo "")",
|
|
"auto_backup": $(uci -q get secubox-p2p.gitea.auto_backup || echo 0),
|
|
"backup_interval": $(uci -q get secubox-p2p.gitea.backup_interval || echo 3600),
|
|
"backup_on_change": $(uci -q get secubox-p2p.gitea.backup_on_change || echo 1),
|
|
"include_configs": $(uci -q get secubox-p2p.gitea.include_configs || echo 1),
|
|
"include_packages": $(uci -q get secubox-p2p.gitea.include_packages || echo 1),
|
|
"include_scripts": $(uci -q get secubox-p2p.gitea.include_scripts || echo 1),
|
|
"has_token": $([ -n "$(uci -q get secubox-p2p.gitea.access_token)" ] && echo "true" || echo "false")
|
|
}
|
|
EOF
|
|
;;
|
|
|
|
set_gitea_config)
|
|
read input
|
|
server_url=$(echo "$input" | jsonfilter -e '@.config.server_url' 2>/dev/null)
|
|
repo_name=$(echo "$input" | jsonfilter -e '@.config.repo_name' 2>/dev/null)
|
|
repo_owner=$(echo "$input" | jsonfilter -e '@.config.repo_owner' 2>/dev/null)
|
|
access_token=$(echo "$input" | jsonfilter -e '@.config.access_token' 2>/dev/null)
|
|
enabled=$(echo "$input" | jsonfilter -e '@.config.enabled' 2>/dev/null)
|
|
auto_backup=$(echo "$input" | jsonfilter -e '@.config.auto_backup' 2>/dev/null)
|
|
backup_interval=$(echo "$input" | jsonfilter -e '@.config.backup_interval' 2>/dev/null)
|
|
|
|
[ -n "$server_url" ] && uci set secubox-p2p.gitea.server_url="$server_url"
|
|
[ -n "$repo_name" ] && uci set secubox-p2p.gitea.repo_name="$repo_name"
|
|
[ -n "$repo_owner" ] && uci set secubox-p2p.gitea.repo_owner="$repo_owner"
|
|
[ -n "$access_token" ] && uci set secubox-p2p.gitea.access_token="$access_token"
|
|
[ -n "$enabled" ] && uci set secubox-p2p.gitea.enabled="$enabled"
|
|
[ -n "$auto_backup" ] && uci set secubox-p2p.gitea.auto_backup="$auto_backup"
|
|
[ -n "$backup_interval" ] && uci set secubox-p2p.gitea.backup_interval="$backup_interval"
|
|
uci commit secubox-p2p
|
|
|
|
echo '{"success":true}'
|
|
;;
|
|
|
|
create_gitea_repo)
|
|
read input
|
|
repo_name=$(echo "$input" | jsonfilter -e '@.name' 2>/dev/null)
|
|
description=$(echo "$input" | jsonfilter -e '@.description' 2>/dev/null)
|
|
is_private=$(echo "$input" | jsonfilter -e '@.private' 2>/dev/null)
|
|
init_readme=$(echo "$input" | jsonfilter -e '@.init_readme' 2>/dev/null)
|
|
|
|
server_url=$(uci -q get secubox-p2p.gitea.server_url)
|
|
access_token=$(uci -q get secubox-p2p.gitea.access_token)
|
|
|
|
if [ -z "$server_url" ] || [ -z "$access_token" ]; then
|
|
echo '{"success":false,"error":"Gitea server URL and access token required"}'
|
|
exit 0
|
|
fi
|
|
|
|
if [ -z "$repo_name" ]; then
|
|
echo '{"success":false,"error":"Repository name required"}'
|
|
exit 0
|
|
fi
|
|
|
|
# Create repo via Gitea API
|
|
api_url="${server_url}/api/v1/user/repos"
|
|
[ "$is_private" = "true" ] && private_val="true" || private_val="false"
|
|
[ "$init_readme" = "true" ] && readme_val="true" || readme_val="false"
|
|
|
|
response=$(curl -s -X POST "$api_url" \
|
|
-H "Authorization: token $access_token" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"name\":\"$repo_name\",\"description\":\"$description\",\"private\":$private_val,\"auto_init\":$readme_val}" \
|
|
2>/dev/null)
|
|
|
|
if echo "$response" | jsonfilter -e '@.id' >/dev/null 2>&1; then
|
|
clone_url=$(echo "$response" | jsonfilter -e '@.clone_url' 2>/dev/null)
|
|
html_url=$(echo "$response" | jsonfilter -e '@.html_url' 2>/dev/null)
|
|
owner=$(echo "$response" | jsonfilter -e '@.owner.login' 2>/dev/null)
|
|
|
|
# Save repo config
|
|
uci set secubox-p2p.gitea.repo_name="$repo_name"
|
|
uci set secubox-p2p.gitea.repo_owner="$owner"
|
|
uci set secubox-p2p.gitea.enabled=1
|
|
uci commit secubox-p2p
|
|
|
|
cat <<EOF
|
|
{
|
|
"success": true,
|
|
"repo_name": "$repo_name",
|
|
"clone_url": "$clone_url",
|
|
"html_url": "$html_url",
|
|
"owner": "$owner"
|
|
}
|
|
EOF
|
|
else
|
|
error_msg=$(echo "$response" | jsonfilter -e '@.message' 2>/dev/null || echo "Failed to create repository")
|
|
echo "{\"success\":false,\"error\":\"$error_msg\"}"
|
|
fi
|
|
;;
|
|
|
|
list_gitea_repos)
|
|
server_url=$(uci -q get secubox-p2p.gitea.server_url)
|
|
access_token=$(uci -q get secubox-p2p.gitea.access_token)
|
|
|
|
if [ -z "$server_url" ] || [ -z "$access_token" ]; then
|
|
echo '{"success":false,"repos":[],"error":"Gitea not configured"}'
|
|
exit 0
|
|
fi
|
|
|
|
response=$(curl -s "${server_url}/api/v1/user/repos" \
|
|
-H "Authorization: token $access_token" \
|
|
2>/dev/null)
|
|
|
|
if [ -n "$response" ]; then
|
|
echo "{\"success\":true,\"repos\":$response}"
|
|
else
|
|
echo '{"success":false,"repos":[],"error":"Failed to fetch repositories"}'
|
|
fi
|
|
;;
|
|
|
|
get_gitea_commits)
|
|
read input
|
|
limit=$(echo "$input" | jsonfilter -e '@.limit' 2>/dev/null || echo "20")
|
|
|
|
server_url=$(uci -q get secubox-p2p.gitea.server_url)
|
|
access_token=$(uci -q get secubox-p2p.gitea.access_token)
|
|
repo_owner=$(uci -q get secubox-p2p.gitea.repo_owner)
|
|
repo_name=$(uci -q get secubox-p2p.gitea.repo_name)
|
|
|
|
if [ -z "$server_url" ] || [ -z "$access_token" ] || [ -z "$repo_owner" ] || [ -z "$repo_name" ]; then
|
|
echo '{"success":false,"commits":[],"error":"Gitea repository not configured"}'
|
|
exit 0
|
|
fi
|
|
|
|
response=$(curl -s "${server_url}/api/v1/repos/${repo_owner}/${repo_name}/commits?limit=${limit}" \
|
|
-H "Authorization: token $access_token" \
|
|
2>/dev/null)
|
|
|
|
if [ -n "$response" ] && echo "$response" | jsonfilter -e '@[0].sha' >/dev/null 2>&1; then
|
|
echo "{\"success\":true,\"commits\":$response}"
|
|
else
|
|
echo '{"success":false,"commits":[],"error":"Failed to fetch commits or repository empty"}'
|
|
fi
|
|
;;
|
|
|
|
push_gitea_backup)
|
|
read input
|
|
message=$(echo "$input" | jsonfilter -e '@.message' 2>/dev/null || echo "SecuBox backup $(date +%Y%m%d-%H%M%S)")
|
|
components=$(echo "$input" | jsonfilter -e '@.components' 2>/dev/null)
|
|
|
|
server_url=$(uci -q get secubox-p2p.gitea.server_url)
|
|
access_token=$(uci -q get secubox-p2p.gitea.access_token)
|
|
repo_owner=$(uci -q get secubox-p2p.gitea.repo_owner)
|
|
repo_name=$(uci -q get secubox-p2p.gitea.repo_name)
|
|
|
|
if [ -z "$server_url" ] || [ -z "$access_token" ] || [ -z "$repo_owner" ] || [ -z "$repo_name" ]; then
|
|
echo '{"success":false,"error":"Gitea repository not configured"}'
|
|
exit 0
|
|
fi
|
|
|
|
# Create backup directory
|
|
backup_dir="/tmp/secubox-gitea-backup-$$"
|
|
mkdir -p "$backup_dir"
|
|
|
|
# Collect configs
|
|
if [ "$(uci -q get secubox-p2p.gitea.include_configs)" = "1" ]; then
|
|
mkdir -p "$backup_dir/configs"
|
|
cp -r /etc/config/secubox* "$backup_dir/configs/" 2>/dev/null
|
|
cp -r /etc/config/network "$backup_dir/configs/" 2>/dev/null
|
|
cp -r /etc/config/firewall "$backup_dir/configs/" 2>/dev/null
|
|
cp -r /etc/config/wireless "$backup_dir/configs/" 2>/dev/null
|
|
fi
|
|
|
|
# Collect package list
|
|
if [ "$(uci -q get secubox-p2p.gitea.include_packages)" = "1" ]; then
|
|
mkdir -p "$backup_dir/packages"
|
|
opkg list-installed > "$backup_dir/packages/installed.txt" 2>/dev/null
|
|
fi
|
|
|
|
# Collect scripts
|
|
if [ "$(uci -q get secubox-p2p.gitea.include_scripts)" = "1" ]; then
|
|
mkdir -p "$backup_dir/scripts"
|
|
cp -r /etc/secubox/scripts/* "$backup_dir/scripts/" 2>/dev/null
|
|
fi
|
|
|
|
# Create manifest
|
|
cat > "$backup_dir/manifest.json" <<MANIFEST
|
|
{
|
|
"timestamp": "$(date -Iseconds)",
|
|
"hostname": "$(uci -q get system.@system[0].hostname || echo "secubox")",
|
|
"version": "$(cat /etc/secubox-version 2>/dev/null || echo "unknown")",
|
|
"message": "$message"
|
|
}
|
|
MANIFEST
|
|
|
|
# Push each file via Gitea API
|
|
pushed_files=0
|
|
api_base="${server_url}/api/v1/repos/${repo_owner}/${repo_name}/contents"
|
|
|
|
for file in $(find "$backup_dir" -type f); do
|
|
rel_path="${file#$backup_dir/}"
|
|
content=$(base64 "$file" | tr -d '\n')
|
|
|
|
# Check if file exists (to update vs create)
|
|
existing=$(curl -s "${api_base}/${rel_path}" \
|
|
-H "Authorization: token $access_token" 2>/dev/null)
|
|
sha=$(echo "$existing" | jsonfilter -e '@.sha' 2>/dev/null)
|
|
|
|
if [ -n "$sha" ]; then
|
|
# Update existing file
|
|
curl -s -X PUT "${api_base}/${rel_path}" \
|
|
-H "Authorization: token $access_token" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"message\":\"$message\",\"content\":\"$content\",\"sha\":\"$sha\"}" \
|
|
>/dev/null 2>&1
|
|
else
|
|
# Create new file
|
|
curl -s -X POST "${api_base}/${rel_path}" \
|
|
-H "Authorization: token $access_token" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"message\":\"$message\",\"content\":\"$content\"}" \
|
|
>/dev/null 2>&1
|
|
fi
|
|
pushed_files=$((pushed_files + 1))
|
|
done
|
|
|
|
# Cleanup
|
|
rm -rf "$backup_dir"
|
|
|
|
echo "{\"success\":true,\"files_pushed\":$pushed_files,\"message\":\"$message\"}"
|
|
;;
|
|
|
|
pull_gitea_backup)
|
|
read input
|
|
commit_sha=$(echo "$input" | jsonfilter -e '@.commit_sha' 2>/dev/null)
|
|
|
|
server_url=$(uci -q get secubox-p2p.gitea.server_url)
|
|
access_token=$(uci -q get secubox-p2p.gitea.access_token)
|
|
repo_owner=$(uci -q get secubox-p2p.gitea.repo_owner)
|
|
repo_name=$(uci -q get secubox-p2p.gitea.repo_name)
|
|
|
|
if [ -z "$server_url" ] || [ -z "$access_token" ] || [ -z "$repo_owner" ] || [ -z "$repo_name" ]; then
|
|
echo '{"success":false,"error":"Gitea repository not configured"}'
|
|
exit 0
|
|
fi
|
|
|
|
# Get file tree at commit
|
|
ref_param=""
|
|
[ -n "$commit_sha" ] && ref_param="?ref=$commit_sha"
|
|
|
|
tree=$(curl -s "${server_url}/api/v1/repos/${repo_owner}/${repo_name}/contents${ref_param}" \
|
|
-H "Authorization: token $access_token" 2>/dev/null)
|
|
|
|
if [ -z "$tree" ]; then
|
|
echo '{"success":false,"error":"Failed to fetch repository contents"}'
|
|
exit 0
|
|
fi
|
|
|
|
# Create restore directory
|
|
restore_dir="/tmp/secubox-restore-$$"
|
|
mkdir -p "$restore_dir"
|
|
restored_files=0
|
|
|
|
# Download configs directory
|
|
configs=$(curl -s "${server_url}/api/v1/repos/${repo_owner}/${repo_name}/contents/configs${ref_param}" \
|
|
-H "Authorization: token $access_token" 2>/dev/null)
|
|
|
|
if echo "$configs" | jsonfilter -e '@[0].name' >/dev/null 2>&1; then
|
|
mkdir -p "$restore_dir/configs"
|
|
for file_info in $(echo "$configs" | jsonfilter -e '@[*].name'); do
|
|
file_content=$(curl -s "${server_url}/api/v1/repos/${repo_owner}/${repo_name}/contents/configs/${file_info}${ref_param}" \
|
|
-H "Authorization: token $access_token" 2>/dev/null)
|
|
content_b64=$(echo "$file_content" | jsonfilter -e '@.content' 2>/dev/null)
|
|
if [ -n "$content_b64" ]; then
|
|
echo "$content_b64" | base64 -d > "$restore_dir/configs/$file_info"
|
|
restored_files=$((restored_files + 1))
|
|
fi
|
|
done
|
|
|
|
# Apply configs (with backup)
|
|
if [ -d "$restore_dir/configs" ]; then
|
|
cp -r /etc/config /etc/config.bak.$(date +%Y%m%d%H%M%S) 2>/dev/null
|
|
for cfg in "$restore_dir"/configs/secubox*; do
|
|
[ -f "$cfg" ] && cp "$cfg" /etc/config/ 2>/dev/null
|
|
done
|
|
fi
|
|
fi
|
|
|
|
# Cleanup
|
|
rm -rf "$restore_dir"
|
|
|
|
echo "{\"success\":true,\"files_restored\":$restored_files,\"commit\":\"${commit_sha:-HEAD}\"}"
|
|
;;
|
|
|
|
create_local_backup)
|
|
read input
|
|
backup_name=$(echo "$input" | jsonfilter -e '@.name' 2>/dev/null || echo "backup-$(date +%Y%m%d-%H%M%S)")
|
|
|
|
backup_base=$(uci -q get secubox-p2p.backup.backup_dir || echo "/etc/secubox/backups")
|
|
mkdir -p "$backup_base"
|
|
|
|
backup_dir="$backup_base/$backup_name"
|
|
mkdir -p "$backup_dir"
|
|
|
|
# Backup configs
|
|
mkdir -p "$backup_dir/configs"
|
|
cp -r /etc/config/secubox* "$backup_dir/configs/" 2>/dev/null
|
|
cp /etc/config/network "$backup_dir/configs/" 2>/dev/null
|
|
cp /etc/config/firewall "$backup_dir/configs/" 2>/dev/null
|
|
cp /etc/config/wireless "$backup_dir/configs/" 2>/dev/null
|
|
|
|
# Backup package list
|
|
opkg list-installed > "$backup_dir/packages.txt" 2>/dev/null
|
|
|
|
# Create manifest
|
|
cat > "$backup_dir/manifest.json" <<MANIFEST
|
|
{
|
|
"name": "$backup_name",
|
|
"timestamp": "$(date -Iseconds)",
|
|
"hostname": "$(uci -q get system.@system[0].hostname || echo "secubox")",
|
|
"version": "$(cat /etc/secubox-version 2>/dev/null || echo "unknown")"
|
|
}
|
|
MANIFEST
|
|
|
|
# Cleanup old backups
|
|
max_backups=$(uci -q get secubox-p2p.backup.max_backups || echo 10)
|
|
if [ "$(uci -q get secubox-p2p.backup.auto_cleanup)" = "1" ]; then
|
|
ls -1dt "$backup_base"/*/ 2>/dev/null | tail -n +$((max_backups + 1)) | xargs rm -rf 2>/dev/null
|
|
fi
|
|
|
|
backup_size=$(du -sh "$backup_dir" 2>/dev/null | cut -f1)
|
|
echo "{\"success\":true,\"backup_id\":\"$backup_name\",\"path\":\"$backup_dir\",\"size\":\"$backup_size\"}"
|
|
;;
|
|
|
|
list_local_backups)
|
|
backup_base=$(uci -q get secubox-p2p.backup.backup_dir || echo "/etc/secubox/backups")
|
|
mkdir -p "$backup_base"
|
|
|
|
echo '{"success":true,"backups":['
|
|
first=1
|
|
for dir in "$backup_base"/*/; do
|
|
[ -d "$dir" ] || continue
|
|
backup_id=$(basename "$dir")
|
|
if [ -f "$dir/manifest.json" ]; then
|
|
timestamp=$(jsonfilter -i "$dir/manifest.json" -e '@.timestamp' 2>/dev/null || echo "")
|
|
hostname=$(jsonfilter -i "$dir/manifest.json" -e '@.hostname' 2>/dev/null || echo "")
|
|
else
|
|
timestamp=""
|
|
hostname=""
|
|
fi
|
|
size=$(du -sh "$dir" 2>/dev/null | cut -f1)
|
|
[ $first -eq 1 ] || echo ","
|
|
first=0
|
|
echo "{\"id\":\"$backup_id\",\"timestamp\":\"$timestamp\",\"hostname\":\"$hostname\",\"size\":\"$size\"}"
|
|
done
|
|
echo ']}'
|
|
;;
|
|
|
|
restore_local_backup)
|
|
read input
|
|
backup_id=$(echo "$input" | jsonfilter -e '@.backup_id' 2>/dev/null)
|
|
|
|
backup_base=$(uci -q get secubox-p2p.backup.backup_dir || echo "/etc/secubox/backups")
|
|
backup_dir="$backup_base/$backup_id"
|
|
|
|
if [ ! -d "$backup_dir" ]; then
|
|
echo '{"success":false,"error":"Backup not found"}'
|
|
exit 0
|
|
fi
|
|
|
|
# Create pre-restore backup
|
|
pre_restore="$backup_base/pre-restore-$(date +%Y%m%d-%H%M%S)"
|
|
mkdir -p "$pre_restore/configs"
|
|
cp -r /etc/config/secubox* "$pre_restore/configs/" 2>/dev/null
|
|
|
|
# Restore configs
|
|
restored=0
|
|
if [ -d "$backup_dir/configs" ]; then
|
|
for cfg in "$backup_dir"/configs/*; do
|
|
[ -f "$cfg" ] && cp "$cfg" /etc/config/ 2>/dev/null && restored=$((restored + 1))
|
|
done
|
|
fi
|
|
|
|
echo "{\"success\":true,\"files_restored\":$restored,\"pre_restore_backup\":\"$pre_restore\"}"
|
|
;;
|
|
|
|
*)
|
|
echo '{"error":"Unknown method"}'
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|