P2P App Store Emancipation: - secubox-p2p: Package distribution via mesh peers (CGI API, RPCD, CLI) - packages.js: LuCI view with LOCAL/PEER badges, fetch/install actions - devstatus.js: Dev Status widget with Gitea commits, v1.0 progress tracking - secubox-feed: sync-content command for auto-installing content packages - ACL fix for P2P feed RPCD methods Remote Access: - secubox-app-rustdesk: Native hbbs/hbbr relay server from GitHub releases - secubox-app-guacamole: LXC Debian container with guacd + Tomcat (partial) Content Distribution: - secubox-content-pkg: Auto-package Metablogizer/Streamlit as IPKs - Auto-publish hooks in metablogizerctl and streamlitctl Mesh Media: - secubox-app-ksmbd: In-kernel SMB3 server with ksmbdctl CLI - Pre-configured shares for Jellyfin, Lyrion, Backup UI Consistency: - client-guardian: Ported to sh-page-header chip layout - auth-guardian: Ported to sh-page-header chip layout Fixes: - services.js: RPC expect unwrapping bug fix - metablogizer: Chunked upload for uhttpd 64KB limit Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
181 lines
3.9 KiB
Bash
181 lines
3.9 KiB
Bash
#!/bin/sh
|
|
# P2P Package Catalog API
|
|
# Returns local package feed as JSON for mesh distribution
|
|
|
|
echo "Content-Type: application/json"
|
|
echo "Access-Control-Allow-Origin: *"
|
|
echo "Access-Control-Allow-Methods: GET, OPTIONS"
|
|
echo ""
|
|
|
|
# Handle CORS preflight
|
|
if [ "$REQUEST_METHOD" = "OPTIONS" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
# Load P2P feed library
|
|
. /usr/lib/secubox/p2p-feed.sh 2>/dev/null
|
|
|
|
# Parse query string
|
|
parse_query() {
|
|
local query="$QUERY_STRING"
|
|
local key value
|
|
|
|
# Initialize variables
|
|
INFO_ONLY=""
|
|
PACKAGE_FILTER=""
|
|
|
|
# Parse key=value pairs
|
|
while [ -n "$query" ]; do
|
|
key="${query%%=*}"
|
|
query="${query#*=}"
|
|
value="${query%%&*}"
|
|
query="${query#*&}"
|
|
[ "$query" = "$value" ] && query=""
|
|
|
|
case "$key" in
|
|
info_only) INFO_ONLY="$value" ;;
|
|
package) PACKAGE_FILTER="$value" ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
parse_query
|
|
|
|
# Get node info
|
|
NODE_ID=$(get_local_node_id)
|
|
NODE_NAME=$(get_local_node_name)
|
|
UPDATED=$(date -Iseconds 2>/dev/null || date '+%Y-%m-%dT%H:%M:%S')
|
|
|
|
# Check if feed sharing is enabled
|
|
if ! feed_sharing_enabled; then
|
|
cat << EOF
|
|
{
|
|
"error": "feed_sharing_disabled",
|
|
"message": "Package feed sharing is disabled on this node",
|
|
"node_id": "$NODE_ID",
|
|
"node_name": "$NODE_NAME"
|
|
}
|
|
EOF
|
|
exit 0
|
|
fi
|
|
|
|
# Check if feed exists
|
|
if ! feed_exists; then
|
|
cat << EOF
|
|
{
|
|
"error": "no_feed",
|
|
"message": "No package feed found",
|
|
"node_id": "$NODE_ID",
|
|
"node_name": "$NODE_NAME"
|
|
}
|
|
EOF
|
|
exit 0
|
|
fi
|
|
|
|
FEED_HASH=$(get_feed_hash)
|
|
PKG_COUNT=$(get_package_count)
|
|
|
|
# Info only mode - just return metadata
|
|
if [ "$INFO_ONLY" = "1" ]; then
|
|
cat << EOF
|
|
{
|
|
"node_id": "$NODE_ID",
|
|
"node_name": "$NODE_NAME",
|
|
"updated": "$UPDATED",
|
|
"feed_hash": "$FEED_HASH",
|
|
"package_count": $PKG_COUNT,
|
|
"feed_url": "http://$(uci -q get network.lan.ipaddr || echo '192.168.255.1')/secubox-feed/"
|
|
}
|
|
EOF
|
|
exit 0
|
|
fi
|
|
|
|
# Filter for specific package
|
|
if [ -n "$PACKAGE_FILTER" ]; then
|
|
# Search for specific package in Packages file
|
|
PACKAGES_JSON=$(awk -v pkg="$PACKAGE_FILTER" '
|
|
BEGIN {
|
|
found = 0
|
|
first = 1
|
|
printf "["
|
|
}
|
|
|
|
/^Package:/ {
|
|
current_pkg = $2
|
|
if (current_pkg == pkg) found = 1
|
|
else found = 0
|
|
}
|
|
|
|
found && /^$/ {
|
|
if (pkg_name != "") {
|
|
if (!first) printf ","
|
|
first = 0
|
|
printf "\n{"
|
|
printf "\"name\":\"%s\"", pkg_name
|
|
printf ",\"version\":\"%s\"", pkg_version
|
|
printf ",\"architecture\":\"%s\"", pkg_arch
|
|
printf ",\"size\":%s", (pkg_size != "" ? pkg_size : "0")
|
|
printf ",\"installed_size\":%s", (pkg_isize != "" ? pkg_isize : "0")
|
|
if (pkg_sha256 != "") printf ",\"sha256\":\"%s\"", pkg_sha256
|
|
if (pkg_depends != "") printf ",\"depends\":\"%s\"", pkg_depends
|
|
if (pkg_desc != "") {
|
|
gsub(/"/, "\\\"", pkg_desc)
|
|
printf ",\"description\":\"%s\"", pkg_desc
|
|
}
|
|
if (pkg_filename != "") printf ",\"filename\":\"%s\"", pkg_filename
|
|
printf "}"
|
|
}
|
|
pkg_name = pkg_version = pkg_arch = pkg_size = pkg_isize = ""
|
|
pkg_sha256 = pkg_depends = pkg_desc = pkg_filename = ""
|
|
found = 0
|
|
}
|
|
|
|
found && /^Package:/ { pkg_name = $2 }
|
|
found && /^Version:/ { pkg_version = $2 }
|
|
found && /^Architecture:/ { pkg_arch = $2 }
|
|
found && /^Size:/ { pkg_size = $2 }
|
|
found && /^Installed-Size:/ { pkg_isize = $2 }
|
|
found && /^SHA256sum:/ { pkg_sha256 = $2 }
|
|
found && /^Depends:/ {
|
|
pkg_depends = $0
|
|
sub(/^Depends: */, "", pkg_depends)
|
|
}
|
|
found && /^Description:/ {
|
|
pkg_desc = $0
|
|
sub(/^Description: */, "", pkg_desc)
|
|
}
|
|
found && /^Filename:/ { pkg_filename = $2 }
|
|
|
|
END {
|
|
printf "\n]"
|
|
}
|
|
' "$PACKAGES_FILE")
|
|
|
|
cat << EOF
|
|
{
|
|
"node_id": "$NODE_ID",
|
|
"node_name": "$NODE_NAME",
|
|
"updated": "$UPDATED",
|
|
"feed_hash": "$FEED_HASH",
|
|
"filter": "$PACKAGE_FILTER",
|
|
"packages": $PACKAGES_JSON
|
|
}
|
|
EOF
|
|
exit 0
|
|
fi
|
|
|
|
# Full package list
|
|
PACKAGES_JSON=$(packages_to_json)
|
|
|
|
cat << EOF
|
|
{
|
|
"node_id": "$NODE_ID",
|
|
"node_name": "$NODE_NAME",
|
|
"updated": "$UPDATED",
|
|
"feed_hash": "$FEED_HASH",
|
|
"package_count": $PKG_COUNT,
|
|
"feed_url": "http://$(uci -q get network.lan.ipaddr || echo '192.168.255.1')/secubox-feed/",
|
|
"packages": $PACKAGES_JSON
|
|
}
|
|
EOF
|