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 <noreply@anthropic.com>
This commit is contained in:
parent
a0d3faed9e
commit
c090308dbd
@ -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)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 <contact@cybermind.fr>
|
||||
|
||||
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
|
||||
|
||||
@ -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
|
||||
});
|
||||
274
package/secubox/luci-app-secubox-bonus/root/usr/libexec/rpcd/luci.secubox-store
Executable file
274
package/secubox/luci-app-secubox-bonus/root/usr/libexec/rpcd/luci.secubox-store
Executable file
@ -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
|
||||
@ -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": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
# SecuBox Local Package Feed\n\nThis directory is populated during build with .ipk packages.\nDo not commit built packages to git.
|
||||
@ -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 <contact@cybermind.fr>
|
||||
|
||||
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))
|
||||
@ -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 <contact@cybermind.fr>
|
||||
|
||||
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))
|
||||
@ -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 <contact@cybermind.fr>
|
||||
|
||||
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))
|
||||
@ -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 <contact@cybermind.fr>
|
||||
|
||||
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))
|
||||
@ -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 <contact@cybermind.fr>
|
||||
|
||||
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))
|
||||
@ -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 <contact@cybermind.fr>
|
||||
|
||||
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))
|
||||
@ -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 <contact@cybermind.fr>
|
||||
|
||||
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))
|
||||
@ -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 <contact@cybermind.fr>
|
||||
|
||||
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))
|
||||
@ -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 <contact@cybermind.fr>
|
||||
|
||||
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))
|
||||
@ -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 <contact@cybermind.fr>
|
||||
|
||||
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))
|
||||
@ -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 <contact@cybermind.fr>
|
||||
|
||||
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))
|
||||
@ -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 <contact@cybermind.fr>
|
||||
|
||||
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))
|
||||
@ -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 <contact@cybermind.fr>
|
||||
|
||||
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))
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user