From c090308dbde056395ddd4ca5a94ac7091583b757 Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Sun, 11 Jan 2026 09:15:19 +0100 Subject: [PATCH] feat: Add local package store to luci-app-secubox-bonus - Add embed_local_feed() to local-build.sh that copies built packages into bonus app as /www/secubox-feed/ for offline installation - Generate Packages index and apps-local.json manifest for opkg - Add RPCD backend (luci.secubox-store) for package install/remove - Add LuCI view for browsing and managing local packages - Fix OPENWRT_ONLY_PACKAGES to allow secubox-app-* wrappers in SDK build - Remove experimental python3-* packages (unfinished mitmproxy native plan) - Set rootfs partition size to 16GB for larger overlay - Bump luci-app-secubox-bonus to v0.2.0 Co-Authored-By: Claude Opus 4.5 --- .claude/settings.local.json | 4 +- .../secubox/luci-app-secubox-bonus/Makefile | 58 +++- .../resources/view/secubox-bonus/store.js | 287 ++++++++++++++++++ .../root/usr/libexec/rpcd/luci.secubox-store | 274 +++++++++++++++++ .../luci/menu.d/luci-app-secubox-bonus.json | 14 + .../rpcd/acl.d/luci-app-secubox-bonus.json | 22 ++ .../root/www/secubox-feed/.gitkeep | 1 + package/secubox/mitmproxy/Makefile | 90 ------ package/secubox/python3-aioquic/Makefile | 47 --- package/secubox/python3-h11/Makefile | 41 --- package/secubox/python3-h2/Makefile | 45 --- package/secubox/python3-hpack/Makefile | 41 --- package/secubox/python3-hyperframe/Makefile | 41 --- package/secubox/python3-kaitaistruct/Makefile | 42 --- package/secubox/python3-ldap3/Makefile | 44 --- package/secubox/python3-mitmproxy-rs/Makefile | 46 --- .../secubox/python3-publicsuffix2/Makefile | 42 --- package/secubox/python3-pylsqpack/Makefile | 41 --- package/secubox/python3-wsproto/Makefile | 44 --- package/secubox/python3-zstandard/Makefile | 46 --- secubox-tools/local-build.sh | 195 +++++++++++- 21 files changed, 834 insertions(+), 631 deletions(-) create mode 100644 package/secubox/luci-app-secubox-bonus/htdocs/luci-static/resources/view/secubox-bonus/store.js create mode 100755 package/secubox/luci-app-secubox-bonus/root/usr/libexec/rpcd/luci.secubox-store create mode 100644 package/secubox/luci-app-secubox-bonus/root/usr/share/luci/menu.d/luci-app-secubox-bonus.json create mode 100644 package/secubox/luci-app-secubox-bonus/root/usr/share/rpcd/acl.d/luci-app-secubox-bonus.json create mode 100644 package/secubox/luci-app-secubox-bonus/root/www/secubox-feed/.gitkeep delete mode 100644 package/secubox/mitmproxy/Makefile delete mode 100644 package/secubox/python3-aioquic/Makefile delete mode 100644 package/secubox/python3-h11/Makefile delete mode 100644 package/secubox/python3-h2/Makefile delete mode 100644 package/secubox/python3-hpack/Makefile delete mode 100644 package/secubox/python3-hyperframe/Makefile delete mode 100644 package/secubox/python3-kaitaistruct/Makefile delete mode 100644 package/secubox/python3-ldap3/Makefile delete mode 100644 package/secubox/python3-mitmproxy-rs/Makefile delete mode 100644 package/secubox/python3-publicsuffix2/Makefile delete mode 100644 package/secubox/python3-pylsqpack/Makefile delete mode 100644 package/secubox/python3-wsproto/Makefile delete mode 100644 package/secubox/python3-zstandard/Makefile diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 15649f6d..f1320ca8 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -466,7 +466,9 @@ "WebFetch(domain:pypi.org)", "Bash(/usr/bin/rsync:*)", "Bash(for d in /home/reepost/CyberMindStudio/_files/secubox-openwrt/package/secubox/python3-*)", - "Bash(if [ ! -f \"$d/Makefile\" ])" + "Bash(if [ ! -f \"$d/Makefile\" ])", + "Bash(for pkg in crowdsec-firewall-bouncer mitmproxy python3-aioquic python3-h11 python3-h2 python3-hpack python3-hyperframe python3-kaitaistruct python3-ldap3 python3-mitmproxy-rs python3-publicsuffix2 python3-pylsqpack python3-wsproto python3-zstandard secubox-app-crowdsec secubox-app-mitmproxy secubox-app-ndpid secubox-app-netifyd secubox-app-nodogsplash)", + "Bash(while read dir)" ] } } diff --git a/package/secubox/luci-app-secubox-bonus/Makefile b/package/secubox/luci-app-secubox-bonus/Makefile index 36f5c3dc..0a14a361 100644 --- a/package/secubox/luci-app-secubox-bonus/Makefile +++ b/package/secubox/luci-app-secubox-bonus/Makefile @@ -1,22 +1,60 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-secubox-bonus -PKG_VERSION:=0.1.0 -PKG_RELEASE:=2 +PKG_VERSION:=0.2.0 +PKG_RELEASE:=1 PKG_ARCH:=all PKG_LICENSE:=Apache-2.0 PKG_MAINTAINER:=CyberMind -LUCI_TITLE:=LuCI - SecuBox Bonus Content & Documentation -LUCI_DESCRIPTION:=SecuBox marketing content, documentation website, and local mirror. Includes demo pages, tutorials, blog articles, development guides, and multilingual content for SecuBox modules. Accessible at /luci-static/secubox/ -LUCI_DEPENDS:=+luci-base +LUCI_TITLE:=LuCI - SecuBox Bonus Content & Local Package Store +LUCI_DESCRIPTION:=SecuBox documentation, local package repository, and app store. Includes all SecuBox packages as a local opkg feed for offline installation. Accessible at /luci-static/secubox/ +LUCI_DEPENDS:=+luci-base +rpcd +luci-lib-jsonc LUCI_PKGARCH:=all -# File permissions -# Format: path:owner:group:mode -# - Static files (HTML/CSS/JS): 644 (readable by all, set automatically by luci.mk) -# No executable scripts in this package - include $(TOPDIR)/feeds/luci/luci.mk +define Package/luci-app-secubox-bonus/install + # Documentation and static content + $(INSTALL_DIR) $(1)/www/luci-static/secubox + $(CP) ./htdocs/luci-static/secubox/* $(1)/www/luci-static/secubox/ + + # Local package feed (populated by build) + $(INSTALL_DIR) $(1)/www/secubox-feed + if [ -d ./root/www/secubox-feed ] && [ -n "$$$$(ls -A ./root/www/secubox-feed 2>/dev/null)" ]; then \ + $(CP) ./root/www/secubox-feed/* $(1)/www/secubox-feed/; \ + fi + + # RPCD backend for package management + $(INSTALL_DIR) $(1)/usr/libexec/rpcd + $(INSTALL_BIN) ./root/usr/libexec/rpcd/luci.secubox-store $(1)/usr/libexec/rpcd/ + + # ACL permissions + $(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d + $(INSTALL_DATA) ./root/usr/share/rpcd/acl.d/luci-app-secubox-bonus.json $(1)/usr/share/rpcd/acl.d/ + + # LuCI menu entry + $(INSTALL_DIR) $(1)/usr/share/luci/menu.d + $(INSTALL_DATA) ./root/usr/share/luci/menu.d/luci-app-secubox-bonus.json $(1)/usr/share/luci/menu.d/ + + # JavaScript view + $(INSTALL_DIR) $(1)/www/luci-static/resources/view/secubox-bonus + $(INSTALL_DATA) ./htdocs/luci-static/resources/view/secubox-bonus/*.js $(1)/www/luci-static/resources/view/secubox-bonus/ +endef + +define Package/luci-app-secubox-bonus/postinst +#!/bin/sh +[ -n "$${IPKG_INSTROOT}" ] || { + # Add local feed to opkg if not already present + if ! grep -q "secubox-feed" /etc/opkg/customfeeds.conf 2>/dev/null; then + echo "src/gz secubox file:///www/secubox-feed" >> /etc/opkg/customfeeds.conf + fi + # Restart rpcd to load new backend + /etc/init.d/rpcd restart + rm -rf /tmp/luci-modulecache /tmp/luci-indexcache 2>/dev/null + echo "SecuBox Bonus & Package Store installed." +} +exit 0 +endef + # call BuildPackage - OpenWrt buildroot diff --git a/package/secubox/luci-app-secubox-bonus/htdocs/luci-static/resources/view/secubox-bonus/store.js b/package/secubox/luci-app-secubox-bonus/htdocs/luci-static/resources/view/secubox-bonus/store.js new file mode 100644 index 00000000..4d0622bc --- /dev/null +++ b/package/secubox/luci-app-secubox-bonus/htdocs/luci-static/resources/view/secubox-bonus/store.js @@ -0,0 +1,287 @@ +'use strict'; +'require view'; +'require rpc'; +'require ui'; +'require poll'; + +var callListPackages = rpc.declare({ + object: 'luci.secubox-store', + method: 'list_packages', + expect: { packages: [] } +}); + +var callInstallPackage = rpc.declare({ + object: 'luci.secubox-store', + method: 'install_package', + params: ['package'], + expect: { success: false } +}); + +var callRemovePackage = rpc.declare({ + object: 'luci.secubox-store', + method: 'remove_package', + params: ['package'], + expect: { success: false } +}); + +var callGetFeedStatus = rpc.declare({ + object: 'luci.secubox-store', + method: 'get_feed_status', + expect: {} +}); + +// Icon mapping +var iconMap = { + 'shield': '\u{1F6E1}', + 'lock': '\u{1F512}', + 'activity': '\u{1F4CA}', + 'filter': '\u{1F50D}', + 'users': '\u{1F465}', + 'wifi': '\u{1F4F6}', + 'server': '\u{1F5A5}', + 'box': '\u{1F4E6}', + 'radio': '\u{1F4FB}', + 'message-square': '\u{1F4AC}', + 'eye': '\u{1F441}', + 'bar-chart-2': '\u{1F4CA}', + 'settings': '\u{2699}', + 'globe': '\u{1F310}', + 'cpu': '\u{1F4BB}', + 'film': '\u{1F3AC}', + 'monitor': '\u{1F5B5}', + 'key': '\u{1F511}', + 'palette': '\u{1F3A8}', + 'package': '\u{1F4E6}' +}; + +// Category colors +var categoryColors = { + 'security': '#e74c3c', + 'network': '#3498db', + 'vpn': '#9b59b6', + 'iot': '#27ae60', + 'monitoring': '#f39c12', + 'system': '#34495e', + 'media': '#e91e63', + 'theme': '#00bcd4', + 'secubox': '#2ecc71', + 'utility': '#95a5a6' +}; + +function formatSize(bytes) { + if (bytes < 1024) return bytes + ' B'; + if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; + return (bytes / (1024 * 1024)).toFixed(1) + ' MB'; +} + +function getIcon(iconName) { + return iconMap[iconName] || '\u{1F4E6}'; +} + +function getCategoryColor(category) { + return categoryColors[category] || '#95a5a6'; +} + +return view.extend({ + load: function() { + return Promise.all([ + callListPackages(), + callGetFeedStatus() + ]); + }, + + renderPackageCard: function(pkg) { + var self = this; + var icon = getIcon(pkg.icon); + var color = getCategoryColor(pkg.category); + + var card = E('div', { 'class': 'package-card', 'data-category': pkg.category }, [ + E('div', { 'class': 'package-header' }, [ + E('span', { 'class': 'package-icon', 'style': 'background-color: ' + color }, icon), + E('div', { 'class': 'package-title' }, [ + E('h3', {}, pkg.name), + E('span', { 'class': 'package-version' }, 'v' + pkg.version) + ]) + ]), + E('p', { 'class': 'package-description' }, pkg.description || 'SecuBox package'), + E('div', { 'class': 'package-meta' }, [ + E('span', { 'class': 'package-category' }, pkg.category), + E('span', { 'class': 'package-size' }, formatSize(pkg.size || 0)) + ]), + E('div', { 'class': 'package-actions' }, [ + pkg.installed + ? E('button', { + 'class': 'btn cbi-button cbi-button-remove', + 'click': ui.createHandlerFn(self, 'handleRemove', pkg.name) + }, 'Remove') + : E('button', { + 'class': 'btn cbi-button cbi-button-action', + 'click': ui.createHandlerFn(self, 'handleInstall', pkg.name) + }, 'Install'), + pkg.installed + ? E('span', { 'class': 'status-installed' }, '\u2713 Installed') + : E('span', { 'class': 'status-available' }, 'Available') + ]) + ]); + + return card; + }, + + handleInstall: function(pkgName, ev) { + var btn = ev.currentTarget; + btn.disabled = true; + btn.textContent = 'Installing...'; + + return callInstallPackage(pkgName).then(function(result) { + if (result.success) { + ui.addNotification(null, E('p', {}, 'Package ' + pkgName + ' installed successfully. Refreshing...')); + window.location.reload(); + } else { + ui.addNotification(null, E('p', {}, 'Failed to install ' + pkgName + ': ' + (result.error || 'Unknown error')), 'error'); + btn.disabled = false; + btn.textContent = 'Install'; + } + }).catch(function(err) { + ui.addNotification(null, E('p', {}, 'Error: ' + err.message), 'error'); + btn.disabled = false; + btn.textContent = 'Install'; + }); + }, + + handleRemove: function(pkgName, ev) { + var btn = ev.currentTarget; + + if (!confirm('Remove package ' + pkgName + '?')) + return; + + btn.disabled = true; + btn.textContent = 'Removing...'; + + return callRemovePackage(pkgName).then(function(result) { + if (result.success) { + ui.addNotification(null, E('p', {}, 'Package ' + pkgName + ' removed successfully. Refreshing...')); + window.location.reload(); + } else { + ui.addNotification(null, E('p', {}, 'Failed to remove ' + pkgName + ': ' + (result.error || 'Unknown error')), 'error'); + btn.disabled = false; + btn.textContent = 'Remove'; + } + }).catch(function(err) { + ui.addNotification(null, E('p', {}, 'Error: ' + err.message), 'error'); + btn.disabled = false; + btn.textContent = 'Remove'; + }); + }, + + filterPackages: function(category) { + var cards = document.querySelectorAll('.package-card'); + cards.forEach(function(card) { + if (category === 'all' || card.dataset.category === category) { + card.style.display = ''; + } else { + card.style.display = 'none'; + } + }); + + var btns = document.querySelectorAll('.filter-btn'); + btns.forEach(function(btn) { + btn.classList.remove('active'); + if (btn.dataset.category === category) { + btn.classList.add('active'); + } + }); + }, + + render: function(data) { + var packages = data[0].packages || data[0] || []; + var feedStatus = data[1] || {}; + var self = this; + + // Get unique categories + var categories = ['all']; + packages.forEach(function(pkg) { + if (pkg.category && categories.indexOf(pkg.category) === -1) { + categories.push(pkg.category); + } + }); + + // Sort packages: installed first, then by name + packages.sort(function(a, b) { + if (a.installed !== b.installed) return b.installed ? 1 : -1; + return a.name.localeCompare(b.name); + }); + + var installedCount = packages.filter(function(p) { return p.installed; }).length; + + var view = E('div', { 'class': 'secubox-store' }, [ + E('style', {}, [ + '.secubox-store { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }', + '.store-header { margin-bottom: 20px; padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 10px; color: white; }', + '.store-header h2 { margin: 0 0 10px 0; }', + '.store-stats { display: flex; gap: 20px; }', + '.store-stats span { background: rgba(255,255,255,0.2); padding: 5px 15px; border-radius: 20px; }', + '.filter-bar { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 20px; }', + '.filter-btn { padding: 8px 16px; border: 1px solid #ddd; border-radius: 20px; background: white; cursor: pointer; transition: all 0.2s; }', + '.filter-btn:hover { background: #f0f0f0; }', + '.filter-btn.active { background: #667eea; color: white; border-color: #667eea; }', + '.package-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }', + '.package-card { background: white; border: 1px solid #e0e0e0; border-radius: 10px; padding: 20px; transition: box-shadow 0.2s; }', + '.package-card:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.1); }', + '.package-header { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }', + '.package-icon { width: 48px; height: 48px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 24px; color: white; }', + '.package-title h3 { margin: 0; font-size: 16px; }', + '.package-version { color: #888; font-size: 12px; }', + '.package-description { color: #666; font-size: 14px; margin-bottom: 12px; line-height: 1.4; }', + '.package-meta { display: flex; gap: 10px; margin-bottom: 15px; }', + '.package-category { background: #f0f0f0; padding: 3px 10px; border-radius: 12px; font-size: 12px; text-transform: capitalize; }', + '.package-size { color: #888; font-size: 12px; }', + '.package-actions { display: flex; align-items: center; gap: 10px; }', + '.package-actions .btn { padding: 8px 20px; }', + '.status-installed { color: #27ae60; font-weight: 500; }', + '.status-available { color: #888; }', + '.cbi-button-remove { background: #e74c3c !important; border-color: #e74c3c !important; color: white !important; }', + '.cbi-button-remove:hover { background: #c0392b !important; }', + '.no-packages { text-align: center; padding: 40px; color: #888; }' + ].join('\n')), + + E('div', { 'class': 'store-header' }, [ + E('h2', {}, 'SecuBox Package Store'), + E('p', {}, 'Install and manage SecuBox packages from the local repository'), + E('div', { 'class': 'store-stats' }, [ + E('span', {}, packages.length + ' packages available'), + E('span', {}, installedCount + ' installed'), + feedStatus.feed_configured + ? E('span', {}, '\u2713 Feed configured') + : E('span', {}, '\u26A0 Feed not configured') + ]) + ]), + + E('div', { 'class': 'filter-bar' }, + categories.map(function(cat) { + return E('button', { + 'class': 'filter-btn' + (cat === 'all' ? ' active' : ''), + 'data-category': cat, + 'click': function() { self.filterPackages(cat); } + }, cat === 'all' ? 'All' : cat.charAt(0).toUpperCase() + cat.slice(1)); + }) + ), + + packages.length > 0 + ? E('div', { 'class': 'package-grid' }, + packages.map(function(pkg) { + return self.renderPackageCard(pkg); + }) + ) + : E('div', { 'class': 'no-packages' }, [ + E('p', {}, 'No packages found in local feed.'), + E('p', {}, 'The local package feed may not be populated yet.') + ]) + ]); + + return view; + }, + + handleSaveApply: null, + handleSave: null, + handleReset: null +}); diff --git a/package/secubox/luci-app-secubox-bonus/root/usr/libexec/rpcd/luci.secubox-store b/package/secubox/luci-app-secubox-bonus/root/usr/libexec/rpcd/luci.secubox-store new file mode 100755 index 00000000..28ded3cb --- /dev/null +++ b/package/secubox/luci-app-secubox-bonus/root/usr/libexec/rpcd/luci.secubox-store @@ -0,0 +1,274 @@ +#!/bin/sh +# SPDX-License-Identifier: Apache-2.0 +# SecuBox Local Package Store - RPCD Backend +# Manages installation/removal of packages from local feed + +. /usr/share/libubox/jshn.sh + +FEED_DIR="/www/secubox-feed" +APPS_JSON="$FEED_DIR/apps-local.json" + +# List available packages from local feed +list_packages() { + if [ -f "$APPS_JSON" ]; then + # Read apps-local.json and add installation status + local packages=$(cat "$APPS_JSON") + + json_init + json_add_boolean "success" 1 + json_add_string "feed_url" "/secubox-feed" + json_add_array "packages" + + # Parse apps-local.json and check each package + local pkg_list=$(jsonfilter -s "$packages" -e '@.packages[*].name' 2>/dev/null) + + for name in $pkg_list; do + local pkg_data=$(jsonfilter -s "$packages" -e "@.packages[@.name='$name']" 2>/dev/null) + local version=$(echo "$pkg_data" | jsonfilter -e '@.version' 2>/dev/null) + local filename=$(echo "$pkg_data" | jsonfilter -e '@.filename' 2>/dev/null) + local size=$(echo "$pkg_data" | jsonfilter -e '@.size' 2>/dev/null) + local category=$(echo "$pkg_data" | jsonfilter -e '@.category' 2>/dev/null) + local icon=$(echo "$pkg_data" | jsonfilter -e '@.icon' 2>/dev/null) + local description=$(echo "$pkg_data" | jsonfilter -e '@.description' 2>/dev/null) + + # Check if installed + local installed=0 + if opkg list-installed 2>/dev/null | grep -q "^${name} "; then + installed=1 + fi + + json_add_object "" + json_add_string "name" "$name" + json_add_string "version" "$version" + json_add_string "filename" "$filename" + json_add_int "size" "${size:-0}" + json_add_string "category" "$category" + json_add_string "icon" "$icon" + json_add_string "description" "$description" + json_add_boolean "installed" "$installed" + json_close_object + done + + json_close_array + json_dump + else + json_init + json_add_boolean "success" 0 + json_add_string "error" "Local feed not found" + json_add_array "packages" + json_close_array + json_dump + fi +} + +# Install a package from local feed +install_package() { + local pkg_name="$1" + + if [ -z "$pkg_name" ]; then + json_init + json_add_boolean "success" 0 + json_add_string "error" "Package name required" + json_dump + return + fi + + # Find the package file + local pkg_file=$(ls "$FEED_DIR/${pkg_name}_"*.ipk 2>/dev/null | head -1) + + if [ -z "$pkg_file" ] || [ ! -f "$pkg_file" ]; then + json_init + json_add_boolean "success" 0 + json_add_string "error" "Package file not found: $pkg_name" + json_dump + return + fi + + # Update opkg lists first + opkg update 2>/dev/null || true + + # Install the package + local output + output=$(opkg install "$pkg_file" 2>&1) + local result=$? + + json_init + if [ $result -eq 0 ]; then + json_add_boolean "success" 1 + json_add_string "message" "Package installed successfully" + json_add_string "package" "$pkg_name" + + # Clear LuCI cache + rm -rf /tmp/luci-modulecache /tmp/luci-indexcache 2>/dev/null + else + json_add_boolean "success" 0 + json_add_string "error" "$output" + fi + json_add_string "output" "$output" + json_dump +} + +# Remove a package +remove_package() { + local pkg_name="$1" + + if [ -z "$pkg_name" ]; then + json_init + json_add_boolean "success" 0 + json_add_string "error" "Package name required" + json_dump + return + fi + + # Check if installed + if ! opkg list-installed 2>/dev/null | grep -q "^${pkg_name} "; then + json_init + json_add_boolean "success" 0 + json_add_string "error" "Package not installed: $pkg_name" + json_dump + return + fi + + # Remove the package + local output + output=$(opkg remove "$pkg_name" 2>&1) + local result=$? + + json_init + if [ $result -eq 0 ]; then + json_add_boolean "success" 1 + json_add_string "message" "Package removed successfully" + json_add_string "package" "$pkg_name" + + # Clear LuCI cache + rm -rf /tmp/luci-modulecache /tmp/luci-indexcache 2>/dev/null + else + json_add_boolean "success" 0 + json_add_string "error" "$output" + fi + json_add_string "output" "$output" + json_dump +} + +# Get package info +get_package_info() { + local pkg_name="$1" + + if [ -z "$pkg_name" ]; then + json_init + json_add_boolean "success" 0 + json_add_string "error" "Package name required" + json_dump + return + fi + + json_init + json_add_boolean "success" 1 + json_add_string "name" "$pkg_name" + + # Check if installed + local installed_info=$(opkg list-installed "$pkg_name" 2>/dev/null) + if [ -n "$installed_info" ]; then + json_add_boolean "installed" 1 + json_add_string "installed_version" "$(echo "$installed_info" | cut -d' ' -f3)" + else + json_add_boolean "installed" 0 + fi + + # Get info from feed + if [ -f "$APPS_JSON" ]; then + local pkg_data=$(cat "$APPS_JSON" | jsonfilter -e "@.packages[@.name='$pkg_name']" 2>/dev/null) + if [ -n "$pkg_data" ]; then + json_add_string "feed_version" "$(echo "$pkg_data" | jsonfilter -e '@.version' 2>/dev/null)" + json_add_string "description" "$(echo "$pkg_data" | jsonfilter -e '@.description' 2>/dev/null)" + json_add_string "category" "$(echo "$pkg_data" | jsonfilter -e '@.category' 2>/dev/null)" + json_add_int "size" "$(echo "$pkg_data" | jsonfilter -e '@.size' 2>/dev/null)" + fi + fi + + json_dump +} + +# Get feed status +get_feed_status() { + json_init + + if [ -d "$FEED_DIR" ]; then + json_add_boolean "feed_exists" 1 + json_add_string "feed_path" "$FEED_DIR" + + local pkg_count=$(ls -1 "$FEED_DIR"/*.ipk 2>/dev/null | wc -l) + json_add_int "package_count" "$pkg_count" + + if [ -f "$APPS_JSON" ]; then + json_add_boolean "index_exists" 1 + local generated=$(jsonfilter -i "$APPS_JSON" -e '@.generated' 2>/dev/null) + json_add_string "generated" "$generated" + else + json_add_boolean "index_exists" 0 + fi + + # Check if feed is in opkg config + if grep -q "secubox-feed" /etc/opkg/customfeeds.conf 2>/dev/null; then + json_add_boolean "feed_configured" 1 + else + json_add_boolean "feed_configured" 0 + fi + else + json_add_boolean "feed_exists" 0 + fi + + json_dump +} + +# Main dispatcher +case "$1" in + list) + json_init + json_add_object "list_packages" + json_close_object + json_add_object "install_package" + json_add_string "package" "str" + json_close_object + json_add_object "remove_package" + json_add_string "package" "str" + json_close_object + json_add_object "get_package_info" + json_add_string "package" "str" + json_close_object + json_add_object "get_feed_status" + json_close_object + json_dump + ;; + call) + case "$2" in + list_packages) + list_packages + ;; + install_package) + read -r input + pkg=$(echo "$input" | jsonfilter -e '@.package') + install_package "$pkg" + ;; + remove_package) + read -r input + pkg=$(echo "$input" | jsonfilter -e '@.package') + remove_package "$pkg" + ;; + get_package_info) + read -r input + pkg=$(echo "$input" | jsonfilter -e '@.package') + get_package_info "$pkg" + ;; + get_feed_status) + get_feed_status + ;; + *) + echo '{"error":"Unknown method"}' + ;; + esac + ;; + *) + echo '{"error":"Invalid action"}' + ;; +esac diff --git a/package/secubox/luci-app-secubox-bonus/root/usr/share/luci/menu.d/luci-app-secubox-bonus.json b/package/secubox/luci-app-secubox-bonus/root/usr/share/luci/menu.d/luci-app-secubox-bonus.json new file mode 100644 index 00000000..cad4ec01 --- /dev/null +++ b/package/secubox/luci-app-secubox-bonus/root/usr/share/luci/menu.d/luci-app-secubox-bonus.json @@ -0,0 +1,14 @@ +{ + "admin/secubox/local-packages": { + "title": "Local Packages", + "order": 19, + "action": { + "type": "view", + "path": "secubox-bonus/store" + }, + "depends": { + "acl": ["luci-app-secubox-bonus"], + "uci": {} + } + } +} diff --git a/package/secubox/luci-app-secubox-bonus/root/usr/share/rpcd/acl.d/luci-app-secubox-bonus.json b/package/secubox/luci-app-secubox-bonus/root/usr/share/rpcd/acl.d/luci-app-secubox-bonus.json new file mode 100644 index 00000000..f3155e44 --- /dev/null +++ b/package/secubox/luci-app-secubox-bonus/root/usr/share/rpcd/acl.d/luci-app-secubox-bonus.json @@ -0,0 +1,22 @@ +{ + "luci-app-secubox-bonus": { + "description": "Grant access to SecuBox local package store", + "read": { + "ubus": { + "luci.secubox-store": [ + "list_packages", + "get_package_info", + "get_feed_status" + ] + } + }, + "write": { + "ubus": { + "luci.secubox-store": [ + "install_package", + "remove_package" + ] + } + } + } +} diff --git a/package/secubox/luci-app-secubox-bonus/root/www/secubox-feed/.gitkeep b/package/secubox/luci-app-secubox-bonus/root/www/secubox-feed/.gitkeep new file mode 100644 index 00000000..817f2de7 --- /dev/null +++ b/package/secubox/luci-app-secubox-bonus/root/www/secubox-feed/.gitkeep @@ -0,0 +1 @@ +# SecuBox Local Package Feed\n\nThis directory is populated during build with .ipk packages.\nDo not commit built packages to git. diff --git a/package/secubox/mitmproxy/Makefile b/package/secubox/mitmproxy/Makefile deleted file mode 100644 index 375fafce..00000000 --- a/package/secubox/mitmproxy/Makefile +++ /dev/null @@ -1,90 +0,0 @@ -# -# Copyright (C) 2025 CyberMind.fr (SecuBox) -# -# This is free software, licensed under the MIT License. -# -# mitmproxy - Native build for OpenWrt -# Provides mitmproxy, mitmdump, and mitmweb binaries -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=mitmproxy -PKG_VERSION:=10.0.0 -PKG_RELEASE:=1 - -PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz -PKG_SOURCE_URL:=https://github.com/mitmproxy/mitmproxy/archive/refs/tags/v$(PKG_VERSION).tar.gz? -PKG_HASH:=c1884a3b6c33dca05488e483f19dd13cefac6367e16bdf5961c8a9ff4105b9cc - -PKG_LICENSE:=MIT -PKG_LICENSE_FILES:=LICENSE -PKG_MAINTAINER:=CyberMind - -PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) - -include $(INCLUDE_DIR)/package.mk -include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk - -define Package/mitmproxy - SECTION:=net - CATEGORY:=Network - SUBMENU:=SecuBox Apps - TITLE:=Interactive HTTPS Proxy - URL:=https://mitmproxy.org/ - DEPENDS:= \ - +python3 \ - +python3-asyncio \ - +python3-logging \ - +python3-openssl \ - +python3-urllib \ - +python3-email \ - +python3-codecs \ - +python3-ctypes \ - +python3-multiprocessing \ - +python3-mitmproxy-rs \ - +python3-cryptography \ - +python3-pyopenssl \ - +python3-tornado \ - +python3-flask \ - +python3-h11 \ - +python3-h2 \ - +python3-wsproto \ - +python3-aioquic \ - +python3-kaitaistruct \ - +python3-publicsuffix2 \ - +python3-ldap3 \ - +python3-passlib \ - +python3-msgpack \ - +python3-sortedcontainers \ - +python3-pyparsing \ - +python3-ruamel-yaml \ - +python3-certifi -endef - -define Package/mitmproxy/description - mitmproxy is an interactive TLS-capable intercepting HTTP proxy - for penetration testers and software developers. - - This package provides: - - mitmproxy: Interactive console interface - - mitmdump: Command-line dumping tool - - mitmweb: Web-based interface - - Native build for OpenWrt with all dependencies. -endef - -define Build/Compile - $(call Py3Build/Compile) -endef - -define Py3Package/mitmproxy/install - $(INSTALL_DIR) $(1)/usr/bin - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/mitmproxy $(1)/usr/bin/ - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/mitmdump $(1)/usr/bin/ - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/mitmweb $(1)/usr/bin/ -endef - -$(eval $(call Py3Package,mitmproxy)) -$(eval $(call BuildPackage,mitmproxy)) -$(eval $(call BuildPackage,mitmproxy-src)) diff --git a/package/secubox/python3-aioquic/Makefile b/package/secubox/python3-aioquic/Makefile deleted file mode 100644 index f8182c9f..00000000 --- a/package/secubox/python3-aioquic/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# -# Copyright (C) 2025 CyberMind.fr (SecuBox) -# -# This is free software, licensed under the MIT License. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=python3-aioquic -PKG_VERSION:=1.0.0 -PKG_RELEASE:=1 - -PYPI_NAME:=aioquic -PKG_HASH:=ed31c2b5afa98c5b6cafa4f36149deaf1dff6c5a69701eadd27167415f9f1660 - -PKG_LICENSE:=BSD-3-Clause -PKG_LICENSE_FILES:=LICENSE -PKG_MAINTAINER:=CyberMind - -include $(TOPDIR)/feeds/packages/lang/python/pypi.mk -include $(INCLUDE_DIR)/package.mk -include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk - -define Package/python3-aioquic - SECTION:=lang - CATEGORY:=Languages - SUBMENU:=Python - TITLE:=QUIC and HTTP/3 implementation - URL:=https://github.com/aiortc/aioquic - DEPENDS:= \ - +python3-light \ - +python3-asyncio \ - +python3-cryptography \ - +python3-certifi \ - +python3-pylsqpack \ - +libopenssl -endef - -define Package/python3-aioquic/description - aioquic is a library for QUIC (RFC 9000) and HTTP/3 (RFC 9114). - It is built on top of asyncio for Python's async/await support. - Used by mitmproxy for QUIC and HTTP/3 interception. -endef - -$(eval $(call Py3Package,python3-aioquic)) -$(eval $(call BuildPackage,python3-aioquic)) -$(eval $(call BuildPackage,python3-aioquic-src)) diff --git a/package/secubox/python3-h11/Makefile b/package/secubox/python3-h11/Makefile deleted file mode 100644 index 00705e95..00000000 --- a/package/secubox/python3-h11/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -# -# Copyright (C) 2025 CyberMind.fr (SecuBox) -# -# This is free software, licensed under the MIT License. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=python3-h11 -PKG_VERSION:=0.14.0 -PKG_RELEASE:=1 - -PYPI_NAME:=h11 -PKG_HASH:=f5383af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03 - -PKG_LICENSE:=MIT -PKG_LICENSE_FILES:=LICENSE.txt -PKG_MAINTAINER:=CyberMind - -include $(TOPDIR)/feeds/packages/lang/python/pypi.mk -include $(INCLUDE_DIR)/package.mk -include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk - -define Package/python3-h11 - SECTION:=lang - CATEGORY:=Languages - SUBMENU:=Python - TITLE:=Pure-Python HTTP/1.1 protocol implementation - URL:=https://github.com/python-hyper/h11 - DEPENDS:=+python3-light -endef - -define Package/python3-h11/description - h11 is a pure-Python, bring-your-own-I/O implementation - of the HTTP/1.1 protocol. It is used by mitmproxy for - HTTP/1.1 parsing and generation. -endef - -$(eval $(call Py3Package,python3-h11)) -$(eval $(call BuildPackage,python3-h11)) -$(eval $(call BuildPackage,python3-h11-src)) diff --git a/package/secubox/python3-h2/Makefile b/package/secubox/python3-h2/Makefile deleted file mode 100644 index 69589b56..00000000 --- a/package/secubox/python3-h2/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright (C) 2025 CyberMind.fr (SecuBox) -# -# This is free software, licensed under the MIT License. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=python3-h2 -PKG_VERSION:=4.1.0 -PKG_RELEASE:=1 - -PYPI_NAME:=h2 -PKG_HASH:=a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb - -PKG_LICENSE:=MIT -PKG_LICENSE_FILES:=LICENSE -PKG_MAINTAINER:=CyberMind - -include $(TOPDIR)/feeds/packages/lang/python/pypi.mk -include $(INCLUDE_DIR)/package.mk -include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk - -define Package/python3-h2 - SECTION:=lang - CATEGORY:=Languages - SUBMENU:=Python - TITLE:=HTTP/2 State Machine for Python - URL:=https://github.com/python-hyper/h2 - DEPENDS:= \ - +python3-light \ - +python3-hyperframe \ - +python3-hpack -endef - -define Package/python3-h2/description - h2 is a pure-Python implementation of a HTTP/2 protocol stack. - It provides a state machine that manages the HTTP/2 connection, - allowing for high-performance HTTP/2 applications. - Used by mitmproxy for HTTP/2 support. -endef - -$(eval $(call Py3Package,python3-h2)) -$(eval $(call BuildPackage,python3-h2)) -$(eval $(call BuildPackage,python3-h2-src)) diff --git a/package/secubox/python3-hpack/Makefile b/package/secubox/python3-hpack/Makefile deleted file mode 100644 index 16528cbb..00000000 --- a/package/secubox/python3-hpack/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -# -# Copyright (C) 2025 CyberMind.fr (SecuBox) -# -# This is free software, licensed under the MIT License. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=python3-hpack -PKG_VERSION:=4.0.0 -PKG_RELEASE:=1 - -PYPI_NAME:=hpack -PKG_HASH:=fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095 - -PKG_LICENSE:=MIT -PKG_LICENSE_FILES:=LICENSE -PKG_MAINTAINER:=CyberMind - -include $(TOPDIR)/feeds/packages/lang/python/pypi.mk -include $(INCLUDE_DIR)/package.mk -include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk - -define Package/python3-hpack - SECTION:=lang - CATEGORY:=Languages - SUBMENU:=Python - TITLE:=HPACK header compression for HTTP/2 - URL:=https://github.com/python-hyper/hpack - DEPENDS:=+python3-light -endef - -define Package/python3-hpack/description - hpack implements the HPACK header compression algorithm - for HTTP/2, as specified in RFC 7541. - Used by h2 for HTTP/2 support in mitmproxy. -endef - -$(eval $(call Py3Package,python3-hpack)) -$(eval $(call BuildPackage,python3-hpack)) -$(eval $(call BuildPackage,python3-hpack-src)) diff --git a/package/secubox/python3-hyperframe/Makefile b/package/secubox/python3-hyperframe/Makefile deleted file mode 100644 index b079f8a7..00000000 --- a/package/secubox/python3-hyperframe/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -# -# Copyright (C) 2025 CyberMind.fr (SecuBox) -# -# This is free software, licensed under the MIT License. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=python3-hyperframe -PKG_VERSION:=6.0.1 -PKG_RELEASE:=1 - -PYPI_NAME:=hyperframe -PKG_HASH:=ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914 - -PKG_LICENSE:=MIT -PKG_LICENSE_FILES:=LICENSE -PKG_MAINTAINER:=CyberMind - -include $(TOPDIR)/feeds/packages/lang/python/pypi.mk -include $(INCLUDE_DIR)/package.mk -include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk - -define Package/python3-hyperframe - SECTION:=lang - CATEGORY:=Languages - SUBMENU:=Python - TITLE:=HTTP/2 framing layer for Python - URL:=https://github.com/python-hyper/hyperframe - DEPENDS:=+python3-light -endef - -define Package/python3-hyperframe/description - hyperframe is a pure-Python HTTP/2 framing layer implementation. - It provides a low-level pure-Python API for working with HTTP/2 frames. - Used by h2 for HTTP/2 support in mitmproxy. -endef - -$(eval $(call Py3Package,python3-hyperframe)) -$(eval $(call BuildPackage,python3-hyperframe)) -$(eval $(call BuildPackage,python3-hyperframe-src)) diff --git a/package/secubox/python3-kaitaistruct/Makefile b/package/secubox/python3-kaitaistruct/Makefile deleted file mode 100644 index 73581148..00000000 --- a/package/secubox/python3-kaitaistruct/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -# -# Copyright (C) 2025 CyberMind.fr (SecuBox) -# -# This is free software, licensed under the MIT License. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=python3-kaitaistruct -PKG_VERSION:=0.10 -PKG_RELEASE:=1 - -PYPI_NAME:=kaitaistruct -PKG_HASH:=a044dee29173d6afbacf27bcac39daf89b654dd418cfa009ab82d9178a9ae52a - -PKG_LICENSE:=MIT -PKG_LICENSE_FILES:=LICENSE -PKG_MAINTAINER:=CyberMind - -include $(TOPDIR)/feeds/packages/lang/python/pypi.mk -include $(INCLUDE_DIR)/package.mk -include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk - -define Package/python3-kaitaistruct - SECTION:=lang - CATEGORY:=Languages - SUBMENU:=Python - TITLE:=Kaitai Struct runtime for Python - URL:=https://kaitai.io/ - DEPENDS:=+python3-light -endef - -define Package/python3-kaitaistruct/description - Kaitai Struct is a declarative language for describing - binary data structures. This package provides the Python - runtime library for parsing binary formats. - Used by mitmproxy for binary protocol analysis. -endef - -$(eval $(call Py3Package,python3-kaitaistruct)) -$(eval $(call BuildPackage,python3-kaitaistruct)) -$(eval $(call BuildPackage,python3-kaitaistruct-src)) diff --git a/package/secubox/python3-ldap3/Makefile b/package/secubox/python3-ldap3/Makefile deleted file mode 100644 index 3c299fe6..00000000 --- a/package/secubox/python3-ldap3/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright (C) 2025 CyberMind.fr (SecuBox) -# -# This is free software, licensed under the MIT License. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=python3-ldap3 -PKG_VERSION:=2.9.1 -PKG_RELEASE:=1 - -PYPI_NAME:=ldap3 -PKG_HASH:=f3e7fc4718e3f09dda568b57100095e0ce58633bcabbed8667ce3f8fbaa4229f - -PKG_LICENSE:=LGPL-3.0 -PKG_LICENSE_FILES:=LICENSE.txt -PKG_MAINTAINER:=CyberMind - -include $(TOPDIR)/feeds/packages/lang/python/pypi.mk -include $(INCLUDE_DIR)/package.mk -include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk - -define Package/python3-ldap3 - SECTION:=lang - CATEGORY:=Languages - SUBMENU:=Python - TITLE:=LDAP v3 client library - URL:=https://github.com/cannatag/ldap3 - DEPENDS:= \ - +python3-light \ - +python3-pyasn1 -endef - -define Package/python3-ldap3/description - ldap3 is a pure Python LDAP v3 client library conforming - to RFC 4510 and RFC 4511. It supports LDAP operations, - connection pooling, and TLS. - Used by mitmproxy for LDAP proxy support. -endef - -$(eval $(call Py3Package,python3-ldap3)) -$(eval $(call BuildPackage,python3-ldap3)) -$(eval $(call BuildPackage,python3-ldap3-src)) diff --git a/package/secubox/python3-mitmproxy-rs/Makefile b/package/secubox/python3-mitmproxy-rs/Makefile deleted file mode 100644 index 079b6462..00000000 --- a/package/secubox/python3-mitmproxy-rs/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -# -# Copyright (C) 2025 CyberMind.fr (SecuBox) -# -# This is free software, licensed under the MIT License. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=python3-mitmproxy-rs -PKG_VERSION:=0.5.2 -PKG_RELEASE:=1 - -PYPI_NAME:=mitmproxy_rs -PKG_HASH:=7583bea1ff5ea8e96c5cf12127e1698c52725f1dfdac6802891a4675b7287ba5 - -PKG_LICENSE:=MIT -PKG_LICENSE_FILES:=LICENSE -PKG_MAINTAINER:=CyberMind - -PKG_BUILD_DEPENDS:=python-maturin/host - -include $(TOPDIR)/feeds/packages/lang/python/pypi.mk -include $(INCLUDE_DIR)/package.mk -include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk - -define Package/python3-mitmproxy-rs - SECTION:=lang - CATEGORY:=Languages - SUBMENU:=Python - TITLE:=Rust components for mitmproxy - URL:=https://github.com/mitmproxy/mitmproxy_rs - DEPENDS:= \ - +python3-light \ - +python3-asyncio \ - $(RUST_ARCH_DEPENDS) -endef - -define Package/python3-mitmproxy-rs/description - The mitmproxy_rs package contains mitmproxy's Rust components, - including WireGuard Mode and Local Redirect Mode support. - Built with PyO3 for Python bindings. -endef - -$(eval $(call Py3Package,python3-mitmproxy-rs)) -$(eval $(call BuildPackage,python3-mitmproxy-rs)) -$(eval $(call BuildPackage,python3-mitmproxy-rs-src)) diff --git a/package/secubox/python3-publicsuffix2/Makefile b/package/secubox/python3-publicsuffix2/Makefile deleted file mode 100644 index 5bf86b72..00000000 --- a/package/secubox/python3-publicsuffix2/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -# -# Copyright (C) 2025 CyberMind.fr (SecuBox) -# -# This is free software, licensed under the MIT License. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=python3-publicsuffix2 -PKG_VERSION:=2.20191221 -PKG_RELEASE:=1 - -PYPI_NAME:=publicsuffix2 -PKG_HASH:=00f8cc31aa8d0d5592a5ced19cccba7de428ebca985db26ac852d920ddd6fe7b - -PKG_LICENSE:=MIT -PKG_LICENSE_FILES:=LICENSE -PKG_MAINTAINER:=CyberMind - -include $(TOPDIR)/feeds/packages/lang/python/pypi.mk -include $(INCLUDE_DIR)/package.mk -include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk - -define Package/python3-publicsuffix2 - SECTION:=lang - CATEGORY:=Languages - SUBMENU:=Python - TITLE:=Public Suffix List implementation - URL:=https://github.com/nexB/python-publicsuffix2 - DEPENDS:=+python3-light -endef - -define Package/python3-publicsuffix2/description - publicsuffix2 is a Python library to get the public suffix - of a domain using Mozilla's Public Suffix List. It's useful - for extracting registered domain from URLs. - Used by mitmproxy for domain parsing and cookie handling. -endef - -$(eval $(call Py3Package,python3-publicsuffix2)) -$(eval $(call BuildPackage,python3-publicsuffix2)) -$(eval $(call BuildPackage,python3-publicsuffix2-src)) diff --git a/package/secubox/python3-pylsqpack/Makefile b/package/secubox/python3-pylsqpack/Makefile deleted file mode 100644 index 17633d88..00000000 --- a/package/secubox/python3-pylsqpack/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -# -# Copyright (C) 2025 CyberMind.fr (SecuBox) -# -# This is free software, licensed under the MIT License. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=python3-pylsqpack -PKG_VERSION:=0.3.18 -PKG_RELEASE:=1 - -PYPI_NAME:=pylsqpack -PKG_HASH:=45ae55e721877505f4d5ccd49591d69353f2a548a8673dfafb251d385b3c097f - -PKG_LICENSE:=BSD-3-Clause -PKG_LICENSE_FILES:=LICENSE -PKG_MAINTAINER:=CyberMind - -include $(TOPDIR)/feeds/packages/lang/python/pypi.mk -include $(INCLUDE_DIR)/package.mk -include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk - -define Package/python3-pylsqpack - SECTION:=lang - CATEGORY:=Languages - SUBMENU:=Python - TITLE:=QPACK encoder/decoder for HTTP/3 - URL:=https://github.com/aiortc/pylsqpack - DEPENDS:=+python3-light -endef - -define Package/python3-pylsqpack/description - pylsqpack provides Python bindings for ls-qpack, the QPACK - encoder and decoder used in HTTP/3 for header compression. - Required by aioquic for QUIC/HTTP3 support. -endef - -$(eval $(call Py3Package,python3-pylsqpack)) -$(eval $(call BuildPackage,python3-pylsqpack)) -$(eval $(call BuildPackage,python3-pylsqpack-src)) diff --git a/package/secubox/python3-wsproto/Makefile b/package/secubox/python3-wsproto/Makefile deleted file mode 100644 index 01ab875e..00000000 --- a/package/secubox/python3-wsproto/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright (C) 2025 CyberMind.fr (SecuBox) -# -# This is free software, licensed under the MIT License. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=python3-wsproto -PKG_VERSION:=1.2.0 -PKG_RELEASE:=1 - -PYPI_NAME:=wsproto -PKG_HASH:=ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065 - -PKG_LICENSE:=MIT -PKG_LICENSE_FILES:=LICENSE -PKG_MAINTAINER:=CyberMind - -include $(TOPDIR)/feeds/packages/lang/python/pypi.mk -include $(INCLUDE_DIR)/package.mk -include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk - -define Package/python3-wsproto - SECTION:=lang - CATEGORY:=Languages - SUBMENU:=Python - TITLE:=WebSocket protocol implementation - URL:=https://github.com/python-hyper/wsproto - DEPENDS:= \ - +python3-light \ - +python3-h11 -endef - -define Package/python3-wsproto/description - wsproto is a pure-Python WebSocket protocol library. - It provides a state machine for implementing WebSocket - clients and servers without I/O. - Used by mitmproxy for WebSocket support. -endef - -$(eval $(call Py3Package,python3-wsproto)) -$(eval $(call BuildPackage,python3-wsproto)) -$(eval $(call BuildPackage,python3-wsproto-src)) diff --git a/package/secubox/python3-zstandard/Makefile b/package/secubox/python3-zstandard/Makefile deleted file mode 100644 index a6bd908b..00000000 --- a/package/secubox/python3-zstandard/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -# -# Copyright (C) 2025 CyberMind.fr (SecuBox) -# -# This is free software, licensed under the MIT License. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=python3-zstandard -PKG_VERSION:=0.23.0 -PKG_RELEASE:=1 - -PYPI_NAME:=zstandard -PKG_HASH:=b2d8c62d08e7255f68f7a740bae85b3c9b8e5466baa9cbf7f57f1cde0ac6bc09 - -PKG_LICENSE:=BSD-3-Clause -PKG_LICENSE_FILES:=LICENSE -PKG_MAINTAINER:=CyberMind - -PKG_BUILD_DEPENDS:=python-cffi/host - -include $(TOPDIR)/feeds/packages/lang/python/pypi.mk -include $(INCLUDE_DIR)/package.mk -include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk - -define Package/python3-zstandard - SECTION:=lang - CATEGORY:=Languages - SUBMENU:=Python - TITLE:=Zstandard compression bindings - URL:=https://github.com/indygreg/python-zstandard - DEPENDS:= \ - +python3-light \ - +python3-cffi \ - +libzstd -endef - -define Package/python3-zstandard/description - Python bindings to the Zstandard (zstd) compression library. - Provides both CFFI and C extension backends for optimal performance. - Required by mitmproxy for compressed content handling. -endef - -$(eval $(call Py3Package,python3-zstandard)) -$(eval $(call BuildPackage,python3-zstandard)) -$(eval $(call BuildPackage,python3-zstandard-src)) diff --git a/secubox-tools/local-build.sh b/secubox-tools/local-build.sh index 7c6b6c17..d8886129 100755 --- a/secubox-tools/local-build.sh +++ b/secubox-tools/local-build.sh @@ -51,16 +51,12 @@ declare -A DEVICE_PROFILES=( # Packages that must be built in the OpenWrt buildroot (toolchain) instead of the SDK. # These packages compile native code and need system libraries not available in SDK. +# NOTE: secubox-app-* wrappers are PKGARCH:=all (shell scripts) and CAN be built in SDK. OPENWRT_ONLY_PACKAGES=( - "netifyd" - "crowdsec" - "secubox-app-crowdsec" - "secubox-app-netifyd" - "secubox-app-ndpid" - "secubox-app-nodogsplash" - "secubox-app-mitmproxy" - "mitmproxy" - "nodogsplash" + "netifyd" # C++ native binary + "crowdsec" # Go binary + "crowdsec-firewall-bouncer" # Go binary + "nodogsplash" # C native binary ) # Helper functions @@ -1002,6 +998,183 @@ collect_artifacts() { return 0 } +# Embed built packages into luci-app-secubox-bonus as local feed +embed_local_feed() { + print_header "Embedding Local Package Feed" + + local feed_dir="$SCRIPT_DIR/../package/secubox/luci-app-secubox-bonus/root/www/secubox-feed" + local pkg_ext="${PKG_EXT:-ipk}" + local src_dir="$BUILD_DIR/$ARCH" + + # Clean and create feed directory + rm -rf "$feed_dir" + mkdir -p "$feed_dir" + + # Check if we have packages to embed + if [[ ! -d "$src_dir" ]] || [[ -z "$(ls -A "$src_dir"/*.${pkg_ext} 2>/dev/null)" ]]; then + print_warning "No packages found to embed in local feed" + return 0 + fi + + # Copy all built packages + print_info "Copying packages to local feed..." + cp "$src_dir"/*.${pkg_ext} "$feed_dir/" 2>/dev/null || true + + local pkg_count=$(ls -1 "$feed_dir"/*.${pkg_ext} 2>/dev/null | wc -l) + print_info "Copied $pkg_count packages" + + # Generate Packages index for opkg + print_info "Generating Packages index..." + ( + cd "$feed_dir" + for pkg in *.${pkg_ext}; do + [[ -f "$pkg" ]] || continue + + # Extract control file from package + local control="" + if [[ "$pkg_ext" == "ipk" ]]; then + control=$(tar -xzOf "$pkg" ./control.tar.gz 2>/dev/null | tar -xzOf - ./control 2>/dev/null || \ + ar -p "$pkg" control.tar.gz 2>/dev/null | tar -xzOf - ./control 2>/dev/null || \ + ar -p "$pkg" control.tar.zst 2>/dev/null | zstd -d 2>/dev/null | tar -xOf - ./control 2>/dev/null || true) + fi + + if [[ -n "$control" ]]; then + echo "$control" + echo "Filename: $pkg" + echo "Size: $(stat -c%s "$pkg")" + echo "SHA256sum: $(sha256sum "$pkg" | cut -d' ' -f1)" + echo "" + fi + done > Packages + + # Create compressed index + gzip -k Packages 2>/dev/null || true + ) + + # Generate apps-local.json for appstore UI + print_info "Generating local apps manifest..." + generate_local_apps_json "$feed_dir" + + print_success "Local feed embedded with $pkg_count packages" + echo " Feed location: /www/secubox-feed/" + echo " opkg config: src/gz secubox file:///www/secubox-feed" + + return 0 +} + +# Generate apps-local.json from built packages +generate_local_apps_json() { + local feed_dir="$1" + local json_file="$feed_dir/apps-local.json" + local pkg_ext="${PKG_EXT:-ipk}" + + cat > "$json_file" << 'HEADER' +{ + "feed_url": "/secubox-feed", + "generated": "TIMESTAMP", + "packages": [ +HEADER + sed -i "s/TIMESTAMP/$(date -Iseconds)/" "$json_file" + + local first=true + for pkg in "$feed_dir"/*.${pkg_ext}; do + [[ -f "$pkg" ]] || continue + local filename=$(basename "$pkg") + local name=$(echo "$filename" | sed 's/_[0-9].*$//') + local version=$(echo "$filename" | sed 's/^[^_]*_//; s/_[^_]*$//') + local size=$(stat -c%s "$pkg") + + # Determine category and description based on package name + local category="utility" + local description="" + local icon="" + local luci_app="" + + case "$name" in + luci-app-crowdsec*) + category="security"; icon="shield"; description="CrowdSec security monitoring";; + luci-app-mitmproxy*) + category="security"; icon="lock"; description="HTTPS proxy and traffic inspection";; + luci-app-bandwidth*) + category="network"; icon="activity"; description="Bandwidth monitoring and control";; + luci-app-traffic*) + category="network"; icon="filter"; description="Traffic shaping and QoS";; + luci-app-client*) + category="network"; icon="users"; description="Client management and monitoring";; + luci-app-network*) + category="network"; icon="wifi"; description="Network configuration";; + luci-app-wireguard*) + category="vpn"; icon="shield"; description="WireGuard VPN dashboard";; + luci-app-vhost*) + category="network"; icon="server"; description="Virtual host management";; + luci-app-secubox*) + category="system"; icon="box"; description="SecuBox system component";; + luci-app-zigbee*) + category="iot"; icon="radio"; description="Zigbee device management";; + luci-app-mqtt*) + category="iot"; icon="message-square"; description="MQTT bridge";; + luci-app-ndpid*) + category="security"; icon="eye"; description="Deep packet inspection";; + luci-app-netdata*) + category="monitoring"; icon="bar-chart-2"; description="System monitoring dashboard";; + luci-app-system*) + category="system"; icon="settings"; description="System management";; + luci-app-cdn*) + category="network"; icon="globe"; description="CDN caching";; + luci-app-ksm*) + category="system"; icon="cpu"; description="Kernel memory management";; + luci-app-media*) + category="media"; icon="film"; description="Media streaming";; + luci-app-magicmirror*) + category="iot"; icon="monitor"; description="Smart mirror display";; + luci-app-auth*) + category="security"; icon="key"; description="Authentication management";; + luci-theme-*) + category="theme"; icon="palette"; description="LuCI theme";; + secubox-app-*) + category="secubox"; icon="package"; description="SecuBox backend service";; + secubox-core*) + category="system"; icon="box"; description="SecuBox core components";; + *) + category="utility"; icon="package"; description="SecuBox package";; + esac + + # Check if this package has a corresponding luci-app + if [[ "$name" =~ ^secubox-app- ]]; then + local app_name="${name#secubox-app-}" + luci_app="luci-app-${app_name}" + fi + + if [[ "$first" == "true" ]]; then + first=false + else + echo "," >> "$json_file" + fi + + cat >> "$json_file" << ENTRY + { + "name": "$name", + "version": "$version", + "filename": "$filename", + "size": $size, + "category": "$category", + "icon": "$icon", + "description": "$description", + "installed": false, + "luci_app": $([ -n "$luci_app" ] && echo "\"$luci_app\"" || echo "null") + } +ENTRY + done + + cat >> "$json_file" << 'FOOTER' + + ] +} +FOOTER + + print_success "Generated apps-local.json" +} + # Run validation run_validation() { print_header "Running Validation" @@ -1177,9 +1350,11 @@ run_build() { configure_packages "$single_package" || return 1 build_packages "$single_package" || return 1 collect_artifacts || return 1 + embed_local_feed || return 1 print_header "Build Complete!" print_success "Packages available in: $BUILD_DIR/$ARCH/" + print_info "Local feed embedded in luci-app-secubox-bonus" return 0 } @@ -1385,7 +1560,7 @@ CONFIG_TARGET_PER_DEVICE_ROOTFS=y CONFIG_TARGET_ROOTFS_SQUASHFS=y CONFIG_TARGET_ROOTFS_EXT4FS=y CONFIG_TARGET_KERNEL_PARTSIZE=32 -CONFIG_TARGET_ROOTFS_PARTSIZE=512 +CONFIG_TARGET_ROOTFS_PARTSIZE=16384 # Disable GDB in toolchain (fixes build issues) # CONFIG_GDB is not set