feat(repo): Add secubox-app-repo and luci-app-repo packages
Backend package (secubox-app-repo): - repoctl CLI for managing local package repository - repo-sync script to download packages from GitHub releases - uhttpd-based server on port 8888 - UCI configuration at /etc/config/repo - RPCD handler for LuCI integration - Auto-sync cron support (configurable interval) Frontend package (luci-app-repo): - Dashboard showing repository status and package counts - Sync button to trigger package downloads - Log viewer for sync operations - Usage instructions for opkg configuration Supported architectures: - x86_64, aarch64_cortex-a72, aarch64_generic - mips_24kc, mipsel_24kc Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
276685f109
commit
9cd59b77ba
26
package/secubox/luci-app-repo/Makefile
Normal file
26
package/secubox/luci-app-repo/Makefile
Normal file
@ -0,0 +1,26 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-repo
|
||||
PKG_VERSION:=1.0.0
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_MAINTAINER:=SecuBox Team
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
|
||||
LUCI_TITLE:=LuCI Package Repository Dashboard
|
||||
LUCI_DEPENDS:=+secubox-app-repo
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/luci-app-repo/install
|
||||
$(INSTALL_DIR) $(1)/www/luci-static/resources/view/repo
|
||||
$(INSTALL_DATA) ./htdocs/luci-static/resources/view/repo/*.js $(1)/www/luci-static/resources/view/repo/
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/share/luci/menu.d
|
||||
$(INSTALL_DATA) ./root/usr/share/luci/menu.d/luci-app-repo.json $(1)/usr/share/luci/menu.d/
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
|
||||
$(INSTALL_DATA) ./root/usr/share/rpcd/acl.d/luci-app-repo.json $(1)/usr/share/rpcd/acl.d/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,luci-app-repo))
|
||||
@ -0,0 +1,203 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require dom';
|
||||
'require poll';
|
||||
'require uci';
|
||||
'require rpc';
|
||||
'require ui';
|
||||
|
||||
var callStatus = rpc.declare({
|
||||
object: 'luci.repo',
|
||||
method: 'status',
|
||||
expect: {}
|
||||
});
|
||||
|
||||
var callPackages = rpc.declare({
|
||||
object: 'luci.repo',
|
||||
method: 'packages',
|
||||
params: ['arch'],
|
||||
expect: {}
|
||||
});
|
||||
|
||||
var callSync = rpc.declare({
|
||||
object: 'luci.repo',
|
||||
method: 'sync',
|
||||
params: ['version'],
|
||||
expect: {}
|
||||
});
|
||||
|
||||
var callLogs = rpc.declare({
|
||||
object: 'luci.repo',
|
||||
method: 'logs',
|
||||
params: ['lines'],
|
||||
expect: {}
|
||||
});
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
callStatus(),
|
||||
uci.load('repo')
|
||||
]);
|
||||
},
|
||||
|
||||
formatBytes: function(bytes) {
|
||||
if (bytes === 0) return '0 B';
|
||||
var k = 1024;
|
||||
var sizes = ['B', 'KB', 'MB', 'GB'];
|
||||
var i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
|
||||
},
|
||||
|
||||
renderStatus: function(status) {
|
||||
var statusClass = status.running ? 'success' : 'danger';
|
||||
var statusText = status.running ? _('Running') : _('Stopped');
|
||||
|
||||
return E('div', { 'class': 'cbi-section' }, [
|
||||
E('h3', {}, _('Repository Status')),
|
||||
E('div', { 'class': 'table' }, [
|
||||
E('div', { 'class': 'tr' }, [
|
||||
E('div', { 'class': 'td left', 'style': 'width:200px' }, _('Server Status')),
|
||||
E('div', { 'class': 'td' }, [
|
||||
E('span', { 'class': 'label ' + statusClass }, statusText),
|
||||
status.running ? E('span', {}, ' (port ' + status.port + ')') : ''
|
||||
])
|
||||
]),
|
||||
E('div', { 'class': 'tr' }, [
|
||||
E('div', { 'class': 'td left' }, _('Version')),
|
||||
E('div', { 'class': 'td' }, status.version || '-')
|
||||
]),
|
||||
E('div', { 'class': 'tr' }, [
|
||||
E('div', { 'class': 'td left' }, _('GitHub Repository')),
|
||||
E('div', { 'class': 'td' }, status.github_repo || '-')
|
||||
]),
|
||||
E('div', { 'class': 'tr' }, [
|
||||
E('div', { 'class': 'td left' }, _('Last Sync')),
|
||||
E('div', { 'class': 'td' }, status.last_sync || _('Never'))
|
||||
]),
|
||||
E('div', { 'class': 'tr' }, [
|
||||
E('div', { 'class': 'td left' }, _('Auto Sync')),
|
||||
E('div', { 'class': 'td' }, status.auto_sync ?
|
||||
_('Every %d hours').format(status.sync_interval) : _('Disabled'))
|
||||
])
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
renderArchitectures: function(status) {
|
||||
var archs = status.architectures || {};
|
||||
var rows = [];
|
||||
|
||||
Object.keys(archs).sort().forEach(function(arch) {
|
||||
rows.push(E('div', { 'class': 'tr' }, [
|
||||
E('div', { 'class': 'td left' }, arch),
|
||||
E('div', { 'class': 'td' }, archs[arch] + ' ' + _('packages'))
|
||||
]));
|
||||
});
|
||||
|
||||
if (rows.length === 0) {
|
||||
rows.push(E('div', { 'class': 'tr' }, [
|
||||
E('div', { 'class': 'td', 'colspan': 2 }, _('No packages synced yet'))
|
||||
]));
|
||||
}
|
||||
|
||||
return E('div', { 'class': 'cbi-section' }, [
|
||||
E('h3', {}, _('Available Architectures')),
|
||||
E('div', { 'class': 'table' }, rows)
|
||||
]);
|
||||
},
|
||||
|
||||
renderActions: function(status) {
|
||||
var self = this;
|
||||
|
||||
var syncBtn = E('button', {
|
||||
'class': 'cbi-button cbi-button-action',
|
||||
'click': function() {
|
||||
ui.showModal(_('Sync Packages'), [
|
||||
E('p', {}, _('Sync packages from GitHub release?')),
|
||||
E('div', { 'class': 'right' }, [
|
||||
E('button', {
|
||||
'class': 'cbi-button',
|
||||
'click': ui.hideModal
|
||||
}, _('Cancel')),
|
||||
' ',
|
||||
E('button', {
|
||||
'class': 'cbi-button cbi-button-positive',
|
||||
'click': function() {
|
||||
ui.hideModal();
|
||||
ui.showModal(_('Syncing...'), [
|
||||
E('p', { 'class': 'spinning' }, _('Downloading packages from GitHub...'))
|
||||
]);
|
||||
callSync(status.version).then(function() {
|
||||
setTimeout(function() {
|
||||
ui.hideModal();
|
||||
window.location.reload();
|
||||
}, 3000);
|
||||
});
|
||||
}
|
||||
}, _('Sync Now'))
|
||||
])
|
||||
]);
|
||||
}
|
||||
}, _('Sync Packages'));
|
||||
|
||||
var logsBtn = E('button', {
|
||||
'class': 'cbi-button',
|
||||
'click': function() {
|
||||
callLogs(100).then(function(result) {
|
||||
var logs = (result.logs || '').split('|').join('\n');
|
||||
ui.showModal(_('Sync Logs'), [
|
||||
E('pre', { 'style': 'max-height:400px;overflow:auto;font-size:12px;' }, logs || _('No logs')),
|
||||
E('div', { 'class': 'right' }, [
|
||||
E('button', {
|
||||
'class': 'cbi-button',
|
||||
'click': ui.hideModal
|
||||
}, _('Close'))
|
||||
])
|
||||
]);
|
||||
});
|
||||
}
|
||||
}, _('View Logs'));
|
||||
|
||||
return E('div', { 'class': 'cbi-section' }, [
|
||||
E('h3', {}, _('Actions')),
|
||||
E('div', { 'class': 'cbi-value' }, [
|
||||
syncBtn, ' ', logsBtn
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
renderUsage: function(status) {
|
||||
var port = status.port || 8888;
|
||||
|
||||
return E('div', { 'class': 'cbi-section' }, [
|
||||
E('h3', {}, _('Usage')),
|
||||
E('p', {}, _('Add to /etc/opkg/customfeeds.conf:')),
|
||||
E('pre', { 'style': 'background:#f5f5f5;padding:10px;border-radius:4px;' }, [
|
||||
'# Local repository\n',
|
||||
'src/gz secubox_luci http://127.0.0.1:' + port + '/luci/{ARCH}\n\n',
|
||||
'# Or via HTTPS (external)\n',
|
||||
'src/gz secubox_luci https://repo.secubox.in/luci/{ARCH}'
|
||||
].join('')),
|
||||
E('p', {}, _('Replace {ARCH} with your architecture: x86_64, aarch64_cortex-a72, aarch64_generic, etc.'))
|
||||
]);
|
||||
},
|
||||
|
||||
render: function(data) {
|
||||
var status = data[0] || {};
|
||||
|
||||
return E('div', { 'class': 'cbi-map' }, [
|
||||
E('h2', {}, _('Package Repository')),
|
||||
E('div', { 'class': 'cbi-map-descr' },
|
||||
_('SecuBox package repository - serves OpenWrt packages locally for opkg installation.')),
|
||||
this.renderStatus(status),
|
||||
this.renderArchitectures(status),
|
||||
this.renderActions(status),
|
||||
this.renderUsage(status)
|
||||
]);
|
||||
},
|
||||
|
||||
handleSaveApply: null,
|
||||
handleSave: null,
|
||||
handleReset: null
|
||||
});
|
||||
@ -0,0 +1,14 @@
|
||||
{
|
||||
"admin/services/repo": {
|
||||
"title": "Package Repository",
|
||||
"order": 85,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "repo/dashboard"
|
||||
},
|
||||
"depends": {
|
||||
"acl": ["luci-app-repo"],
|
||||
"uci": {"repo": true}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
{
|
||||
"luci-app-repo": {
|
||||
"description": "SecuBox Package Repository Dashboard",
|
||||
"read": {
|
||||
"ubus": {
|
||||
"luci.repo": ["status", "config", "packages", "logs"]
|
||||
},
|
||||
"uci": ["repo"]
|
||||
},
|
||||
"write": {
|
||||
"ubus": {
|
||||
"luci.repo": ["sync"]
|
||||
},
|
||||
"uci": ["repo"]
|
||||
}
|
||||
}
|
||||
}
|
||||
60
package/secubox/secubox-app-repo/Makefile
Normal file
60
package/secubox/secubox-app-repo/Makefile
Normal file
@ -0,0 +1,60 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=secubox-app-repo
|
||||
PKG_VERSION:=1.0.0
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_MAINTAINER:=SecuBox Team
|
||||
PKG_LICENSE:=GPL-3.0
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/secubox-app-repo
|
||||
SECTION:=secubox
|
||||
CATEGORY:=SecuBox
|
||||
TITLE:=SecuBox Package Repository Manager
|
||||
DEPENDS:=+uhttpd +wget +gzip +coreutils-stat
|
||||
PKGARCH:=all
|
||||
endef
|
||||
|
||||
define Package/secubox-app-repo/description
|
||||
SecuBox Package Repository Manager - hosts and syncs OpenWrt packages
|
||||
from GitHub releases for local opkg installation.
|
||||
endef
|
||||
|
||||
define Package/secubox-app-repo/conffiles
|
||||
/etc/config/repo
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/secubox-app-repo/install
|
||||
$(INSTALL_DIR) $(1)/usr/sbin
|
||||
$(INSTALL_BIN) ./root/usr/sbin/repoctl $(1)/usr/sbin/
|
||||
$(INSTALL_BIN) ./root/usr/sbin/repo-sync $(1)/usr/sbin/
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/libexec/rpcd
|
||||
$(INSTALL_BIN) ./root/usr/libexec/rpcd/luci.repo $(1)/usr/libexec/rpcd/
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
|
||||
$(INSTALL_DATA) ./root/usr/share/rpcd/acl.d/luci-app-repo.json $(1)/usr/share/rpcd/acl.d/
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_BIN) ./root/etc/init.d/repo-server $(1)/etc/init.d/
|
||||
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(INSTALL_CONF) ./root/etc/config/repo $(1)/etc/config/
|
||||
endef
|
||||
|
||||
define Package/secubox-app-repo/postinst
|
||||
#!/bin/sh
|
||||
[ -n "$${IPKG_INSTROOT}" ] || {
|
||||
/etc/init.d/repo-server enable
|
||||
/etc/init.d/repo-server start
|
||||
/etc/init.d/rpcd restart
|
||||
}
|
||||
exit 0
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,secubox-app-repo))
|
||||
8
package/secubox/secubox-app-repo/root/etc/config/repo
Normal file
8
package/secubox/secubox-app-repo/root/etc/config/repo
Normal file
@ -0,0 +1,8 @@
|
||||
config repo 'main'
|
||||
option enabled '1'
|
||||
option version 'v1.0.0-beta'
|
||||
option github_repo 'gkerma/secubox-openwrt'
|
||||
option port '8888'
|
||||
option auto_sync '1'
|
||||
option sync_interval '6'
|
||||
option last_sync ''
|
||||
29
package/secubox/secubox-app-repo/root/etc/init.d/repo-server
Executable file
29
package/secubox/secubox-app-repo/root/etc/init.d/repo-server
Executable file
@ -0,0 +1,29 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=99
|
||||
STOP=10
|
||||
USE_PROCD=1
|
||||
|
||||
REPO_DIR="/srv/repo.secubox.in"
|
||||
|
||||
start_service() {
|
||||
. /lib/functions.sh
|
||||
config_load repo
|
||||
config_get enabled main enabled "1"
|
||||
config_get port main port "8888"
|
||||
|
||||
[ "$enabled" = "1" ] || return 0
|
||||
|
||||
mkdir -p "$REPO_DIR"
|
||||
|
||||
procd_open_instance
|
||||
procd_set_param command /usr/sbin/uhttpd -f -h "$REPO_DIR" -p "0.0.0.0:$port"
|
||||
procd_set_param respawn
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "repo"
|
||||
}
|
||||
137
package/secubox/secubox-app-repo/root/usr/libexec/rpcd/luci.repo
Executable file
137
package/secubox/secubox-app-repo/root/usr/libexec/rpcd/luci.repo
Executable file
@ -0,0 +1,137 @@
|
||||
#!/bin/sh
|
||||
|
||||
. /lib/functions.sh
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
REPO_DIR="/srv/repo.secubox.in"
|
||||
LOG_FILE="/var/log/repo-sync.log"
|
||||
|
||||
case "$1" in
|
||||
list)
|
||||
echo '{"status":{},"config":{},"packages":{"arch":"string"},"sync":{"version":"string"},"logs":{"lines":"number"}}'
|
||||
;;
|
||||
call)
|
||||
case "$2" in
|
||||
status)
|
||||
json_init
|
||||
|
||||
# Load config
|
||||
config_load repo
|
||||
config_get enabled main enabled "1"
|
||||
config_get version main version "unknown"
|
||||
config_get github_repo main github_repo ""
|
||||
config_get port main port "8888"
|
||||
config_get last_sync main last_sync ""
|
||||
config_get auto_sync main auto_sync "0"
|
||||
config_get sync_interval main sync_interval "6"
|
||||
|
||||
json_add_boolean "enabled" "$enabled"
|
||||
json_add_string "version" "$version"
|
||||
json_add_string "github_repo" "$github_repo"
|
||||
json_add_int "port" "$port"
|
||||
json_add_string "last_sync" "$last_sync"
|
||||
json_add_boolean "auto_sync" "$auto_sync"
|
||||
json_add_int "sync_interval" "$sync_interval"
|
||||
|
||||
# Server status
|
||||
if netstat -tln 2>/dev/null | grep -q ":$port "; then
|
||||
json_add_boolean "running" 1
|
||||
else
|
||||
json_add_boolean "running" 0
|
||||
fi
|
||||
|
||||
# Package counts by architecture
|
||||
json_add_object "architectures"
|
||||
for dir in "$REPO_DIR/luci"/*; do
|
||||
[ -d "$dir" ] || continue
|
||||
arch=$(basename "$dir")
|
||||
count=$(ls "$dir"/*.ipk 2>/dev/null | wc -l)
|
||||
json_add_int "$arch" "$count"
|
||||
done
|
||||
json_close_object
|
||||
|
||||
json_dump
|
||||
;;
|
||||
|
||||
config)
|
||||
json_init
|
||||
config_load repo
|
||||
|
||||
config_get enabled main enabled "1"
|
||||
config_get version main version ""
|
||||
config_get github_repo main github_repo ""
|
||||
config_get port main port "8888"
|
||||
config_get auto_sync main auto_sync "0"
|
||||
config_get sync_interval main sync_interval "6"
|
||||
|
||||
json_add_boolean "enabled" "$enabled"
|
||||
json_add_string "version" "$version"
|
||||
json_add_string "github_repo" "$github_repo"
|
||||
json_add_int "port" "$port"
|
||||
json_add_boolean "auto_sync" "$auto_sync"
|
||||
json_add_int "sync_interval" "$sync_interval"
|
||||
|
||||
json_dump
|
||||
;;
|
||||
|
||||
packages)
|
||||
read -r input
|
||||
json_load "$input"
|
||||
json_get_var arch arch "x86_64"
|
||||
|
||||
json_init
|
||||
json_add_string "arch" "$arch"
|
||||
json_add_array "packages"
|
||||
|
||||
dir="$REPO_DIR/luci/$arch"
|
||||
if [ -d "$dir" ]; then
|
||||
for ipk in "$dir"/*.ipk; do
|
||||
[ -f "$ipk" ] || continue
|
||||
name=$(basename "$ipk")
|
||||
size=$(stat -c%s "$ipk" 2>/dev/null || echo 0)
|
||||
json_add_object ""
|
||||
json_add_string "name" "$name"
|
||||
json_add_int "size" "$size"
|
||||
json_close_object
|
||||
done
|
||||
fi
|
||||
|
||||
json_close_array
|
||||
json_dump
|
||||
;;
|
||||
|
||||
sync)
|
||||
read -r input
|
||||
json_load "$input"
|
||||
json_get_var version version ""
|
||||
|
||||
if [ -n "$version" ]; then
|
||||
uci set repo.main.version="$version"
|
||||
uci commit repo
|
||||
fi
|
||||
|
||||
# Run sync in background
|
||||
/usr/sbin/repo-sync &
|
||||
|
||||
json_init
|
||||
json_add_boolean "started" 1
|
||||
json_add_string "message" "Sync started in background"
|
||||
json_dump
|
||||
;;
|
||||
|
||||
logs)
|
||||
read -r input
|
||||
json_load "$input"
|
||||
json_get_var lines lines 50
|
||||
|
||||
json_init
|
||||
if [ -f "$LOG_FILE" ]; then
|
||||
json_add_string "logs" "$(tail -n "$lines" "$LOG_FILE" | sed 's/"/\\"/g' | tr '\n' '|')"
|
||||
else
|
||||
json_add_string "logs" ""
|
||||
fi
|
||||
json_dump
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
131
package/secubox/secubox-app-repo/root/usr/sbin/repo-sync
Executable file
131
package/secubox/secubox-app-repo/root/usr/sbin/repo-sync
Executable file
@ -0,0 +1,131 @@
|
||||
#!/bin/sh
|
||||
# SecuBox Package Repository Sync Script
|
||||
# Syncs packages from GitHub releases to local repo
|
||||
|
||||
. /lib/functions.sh
|
||||
|
||||
REPO_DIR="/srv/repo.secubox.in"
|
||||
CONFIG_FILE="/etc/config/repo"
|
||||
LOG_FILE="/var/log/repo-sync.log"
|
||||
|
||||
log() {
|
||||
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $*"
|
||||
echo "$msg"
|
||||
echo "$msg" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Load config
|
||||
config_load repo
|
||||
config_get GITHUB_REPO main github_repo "gkerma/secubox-openwrt"
|
||||
config_get VERSION main version "v1.0.0-beta"
|
||||
config_get ENABLED main enabled "1"
|
||||
|
||||
[ "$ENABLED" = "1" ] || { log "Repo sync disabled"; exit 0; }
|
||||
|
||||
VERSION_NUM="${VERSION#v}"
|
||||
TMP_DIR="/tmp/repo-sync-$$"
|
||||
|
||||
log "Starting sync from $GITHUB_REPO $VERSION"
|
||||
|
||||
mkdir -p "$TMP_DIR"
|
||||
mkdir -p "$REPO_DIR/packages" "$REPO_DIR/luci" "$REPO_DIR/catalog"
|
||||
cd "$TMP_DIR"
|
||||
|
||||
# Architecture mappings: github-arch:opkg-arch
|
||||
ARCHS="x86-64:x86_64 aarch64-generic:aarch64_generic aarch64-cortex-a72:aarch64_cortex-a72 rockchip-armv8:aarch64_generic mips-24kc:mips_24kc mipsel-24kc:mipsel_24kc"
|
||||
|
||||
for arch_map in $ARCHS; do
|
||||
ARCH="${arch_map%%:*}"
|
||||
OPKG_ARCH="${arch_map##*:}"
|
||||
TARBALL="secubox-${VERSION_NUM}-${ARCH}.tar.gz"
|
||||
URL="https://github.com/${GITHUB_REPO}/releases/download/${VERSION}/${TARBALL}"
|
||||
|
||||
log "Downloading $TARBALL..."
|
||||
if wget -q -O "$TARBALL" "$URL" 2>/dev/null; then
|
||||
mkdir -p "$REPO_DIR/packages/$OPKG_ARCH"
|
||||
mkdir -p "$REPO_DIR/luci/$OPKG_ARCH"
|
||||
|
||||
# Extract
|
||||
mkdir -p "extract-$ARCH"
|
||||
tar -xzf "$TARBALL" -C "extract-$ARCH" 2>/dev/null
|
||||
|
||||
# Sort packages
|
||||
find "extract-$ARCH" -name '*.ipk' | while read pkg; do
|
||||
PKG_NAME="$(basename "$pkg")"
|
||||
if echo "$PKG_NAME" | grep -q '^luci-'; then
|
||||
cp "$pkg" "$REPO_DIR/luci/$OPKG_ARCH/"
|
||||
else
|
||||
cp "$pkg" "$REPO_DIR/packages/$OPKG_ARCH/"
|
||||
fi
|
||||
done
|
||||
|
||||
log " Extracted to $OPKG_ARCH"
|
||||
else
|
||||
log " Skipping $ARCH (not found)"
|
||||
fi
|
||||
done
|
||||
|
||||
# Generate Packages index
|
||||
log "Generating opkg indexes..."
|
||||
for basedir in "$REPO_DIR/packages" "$REPO_DIR/luci"; do
|
||||
for dir in "$basedir"/*; do
|
||||
[ -d "$dir" ] || continue
|
||||
cd "$dir"
|
||||
|
||||
rm -f Packages Packages.gz
|
||||
|
||||
for ipk in *.ipk 2>/dev/null; do
|
||||
[ -f "$ipk" ] || continue
|
||||
SIZE=$(stat -c%s "$ipk" 2>/dev/null || ls -l "$ipk" | awk '{print $5}')
|
||||
MD5=$(md5sum "$ipk" | cut -d' ' -f1)
|
||||
PKG=$(echo "$ipk" | sed 's/_.*//g')
|
||||
|
||||
echo "Package: $PKG"
|
||||
echo "Version: 0.0.0-r1"
|
||||
echo "Architecture: all"
|
||||
echo "Filename: $ipk"
|
||||
echo "Size: $SIZE"
|
||||
echo "MD5Sum: $MD5"
|
||||
echo ""
|
||||
done > Packages
|
||||
|
||||
gzip -9c Packages > Packages.gz
|
||||
log " $(basename "$dir"): $(grep -c '^Package:' Packages 2>/dev/null || echo 0) packages"
|
||||
done
|
||||
done
|
||||
|
||||
# Create index.html
|
||||
cat > "$REPO_DIR/index.html" << 'HTML'
|
||||
<!DOCTYPE html>
|
||||
<html><head><title>SecuBox Package Repository</title>
|
||||
<style>
|
||||
body { font-family: sans-serif; max-width: 800px; margin: 2em auto; padding: 0 1em; }
|
||||
code { background: #f0f0f0; padding: 2px 6px; border-radius: 3px; }
|
||||
pre { background: #f0f0f0; padding: 1em; overflow-x: auto; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>SecuBox Package Repository</h1>
|
||||
<p>Add to <code>/etc/opkg/customfeeds.conf</code>:</p>
|
||||
<pre>src/gz secubox_packages https://repo.secubox.in/packages/{ARCH}
|
||||
src/gz secubox_luci https://repo.secubox.in/luci/{ARCH}</pre>
|
||||
<h2>Architectures</h2>
|
||||
<ul>
|
||||
<li><a href="luci/x86_64/">x86_64</a> - x86-64 VMs</li>
|
||||
<li><a href="luci/aarch64_cortex-a72/">aarch64_cortex-a72</a> - Raspberry Pi 4</li>
|
||||
<li><a href="luci/aarch64_generic/">aarch64_generic</a> - NanoPi R4S/R5S</li>
|
||||
<li><a href="luci/mips_24kc/">mips_24kc</a> - Atheros/QCA</li>
|
||||
<li><a href="luci/mipsel_24kc/">mipsel_24kc</a> - MT7621</li>
|
||||
</ul>
|
||||
</body></html>
|
||||
HTML
|
||||
|
||||
# Cleanup
|
||||
cd /
|
||||
rm -rf "$TMP_DIR"
|
||||
|
||||
# Update last sync time
|
||||
uci set repo.main.last_sync="$(date -Iseconds)"
|
||||
uci commit repo
|
||||
|
||||
log "Sync complete"
|
||||
156
package/secubox/secubox-app-repo/root/usr/sbin/repoctl
Executable file
156
package/secubox/secubox-app-repo/root/usr/sbin/repoctl
Executable file
@ -0,0 +1,156 @@
|
||||
#!/bin/sh
|
||||
# SecuBox Package Repository Control Tool
|
||||
|
||||
. /lib/functions.sh
|
||||
|
||||
REPO_DIR="/srv/repo.secubox.in"
|
||||
CONFIG="repo"
|
||||
|
||||
usage() {
|
||||
cat << EOF
|
||||
Usage: repoctl <command> [options]
|
||||
|
||||
Commands:
|
||||
status Show repository status
|
||||
sync [version] Sync packages from GitHub release
|
||||
start Start repository server
|
||||
stop Stop repository server
|
||||
restart Restart repository server
|
||||
list [arch] List packages for architecture
|
||||
config Show current configuration
|
||||
set <key> <val> Set configuration value
|
||||
|
||||
Configuration keys:
|
||||
enabled Enable/disable repo (0/1)
|
||||
version Release version to sync (e.g., v1.0.0-beta)
|
||||
github_repo GitHub repository (e.g., gkerma/secubox-openwrt)
|
||||
port Server port (default: 8888)
|
||||
auto_sync Enable auto-sync cron (0/1)
|
||||
sync_interval Sync interval in hours (default: 6)
|
||||
|
||||
Examples:
|
||||
repoctl status
|
||||
repoctl sync v1.0.0-beta
|
||||
repoctl list x86_64
|
||||
repoctl set version v1.0.1
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
cmd_status() {
|
||||
config_load "$CONFIG"
|
||||
config_get enabled main enabled "1"
|
||||
config_get version main version "unknown"
|
||||
config_get github_repo main github_repo "gkerma/secubox-openwrt"
|
||||
config_get port main port "8888"
|
||||
config_get last_sync main last_sync "never"
|
||||
config_get auto_sync main auto_sync "0"
|
||||
|
||||
echo "SecuBox Package Repository Status"
|
||||
echo "=================================="
|
||||
echo "Enabled: $enabled"
|
||||
echo "Version: $version"
|
||||
echo "GitHub Repo: $github_repo"
|
||||
echo "Server Port: $port"
|
||||
echo "Last Sync: $last_sync"
|
||||
echo "Auto Sync: $auto_sync"
|
||||
echo ""
|
||||
|
||||
# Check server status
|
||||
if netstat -tln 2>/dev/null | grep -q ":$port "; then
|
||||
echo "Server: RUNNING (port $port)"
|
||||
else
|
||||
echo "Server: STOPPED"
|
||||
fi
|
||||
|
||||
# Package counts
|
||||
echo ""
|
||||
echo "Packages:"
|
||||
for dir in "$REPO_DIR/luci"/*; do
|
||||
[ -d "$dir" ] || continue
|
||||
arch=$(basename "$dir")
|
||||
count=$(ls "$dir"/*.ipk 2>/dev/null | wc -l)
|
||||
echo " $arch: $count packages"
|
||||
done
|
||||
}
|
||||
|
||||
cmd_sync() {
|
||||
local version="${1:-}"
|
||||
if [ -n "$version" ]; then
|
||||
uci set "$CONFIG.main.version=$version"
|
||||
uci commit "$CONFIG"
|
||||
fi
|
||||
/usr/sbin/repo-sync
|
||||
}
|
||||
|
||||
cmd_start() {
|
||||
/etc/init.d/repo-server start
|
||||
echo "Repository server started"
|
||||
}
|
||||
|
||||
cmd_stop() {
|
||||
/etc/init.d/repo-server stop
|
||||
echo "Repository server stopped"
|
||||
}
|
||||
|
||||
cmd_restart() {
|
||||
/etc/init.d/repo-server restart
|
||||
echo "Repository server restarted"
|
||||
}
|
||||
|
||||
cmd_list() {
|
||||
local arch="${1:-x86_64}"
|
||||
local dir="$REPO_DIR/luci/$arch"
|
||||
|
||||
if [ ! -d "$dir" ]; then
|
||||
echo "Architecture '$arch' not found"
|
||||
echo "Available: $(ls "$REPO_DIR/luci" 2>/dev/null | tr '\n' ' ')"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Packages for $arch:"
|
||||
ls "$dir"/*.ipk 2>/dev/null | while read pkg; do
|
||||
basename "$pkg"
|
||||
done
|
||||
}
|
||||
|
||||
cmd_config() {
|
||||
uci show "$CONFIG"
|
||||
}
|
||||
|
||||
cmd_set() {
|
||||
local key="$1"
|
||||
local value="$2"
|
||||
|
||||
[ -z "$key" ] || [ -z "$value" ] && usage
|
||||
|
||||
uci set "$CONFIG.main.$key=$value"
|
||||
uci commit "$CONFIG"
|
||||
echo "Set $key = $value"
|
||||
|
||||
# Handle auto_sync changes
|
||||
if [ "$key" = "auto_sync" ]; then
|
||||
if [ "$value" = "1" ]; then
|
||||
config_get interval main sync_interval "6"
|
||||
echo "0 */$interval * * * /usr/sbin/repo-sync >/dev/null 2>&1" > /etc/cron.d/repo-sync
|
||||
echo "Enabled auto-sync every $interval hours"
|
||||
else
|
||||
rm -f /etc/cron.d/repo-sync
|
||||
echo "Disabled auto-sync"
|
||||
fi
|
||||
/etc/init.d/cron restart 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
# Main
|
||||
case "$1" in
|
||||
status) cmd_status ;;
|
||||
sync) cmd_sync "$2" ;;
|
||||
start) cmd_start ;;
|
||||
stop) cmd_stop ;;
|
||||
restart) cmd_restart ;;
|
||||
list) cmd_list "$2" ;;
|
||||
config) cmd_config ;;
|
||||
set) cmd_set "$2" "$3" ;;
|
||||
*) usage ;;
|
||||
esac
|
||||
@ -0,0 +1,17 @@
|
||||
{
|
||||
"luci-app-repo": {
|
||||
"description": "SecuBox Package Repository",
|
||||
"read": {
|
||||
"ubus": {
|
||||
"luci.repo": ["status", "config", "packages", "logs"]
|
||||
},
|
||||
"uci": ["repo"]
|
||||
},
|
||||
"write": {
|
||||
"ubus": {
|
||||
"luci.repo": ["sync"]
|
||||
},
|
||||
"uci": ["repo"]
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user