diff --git a/.claude/HISTORY.md b/.claude/HISTORY.md index 4b800481..c2a4e9c7 100644 --- a/.claude/HISTORY.md +++ b/.claude/HISTORY.md @@ -1,6 +1,6 @@ # SecuBox UI & Theme History -_Last updated: 2026-02-14_ +_Last updated: 2026-02-15_ 1. **Unified Dashboard Refresh (2025-12-20)** - Dashboard received the "sh-page-header" layout, hero stats, and SecuNav top tabs. @@ -1712,3 +1712,40 @@ git checkout HEAD -- index.html - `_emancipate_mitmproxy()` now uses `mitmproxyctl sync-routes` instead of direct file manipulation - Ensures HAProxy and mitmproxy routes stay in sync - MetaBlogizer sites now properly routed through WAF + +### 2026-02-15: PeerTube Video Platform Package +- **Created secubox-app-peertube package** - federated video streaming platform + - LXC container with Debian Bookworm base image + - Stack: PostgreSQL 15, Redis 7, Node.js 18 LTS, FFmpeg + - `peertubectl` CLI with 15+ commands: + - Container: install, uninstall, update, start, stop, status, logs, shell + - User mgmt: admin create-user, admin reset-password, admin list-users + - Live: live enable, live disable, live status (RTMP on port 1935) + - Exposure: configure-haproxy, emancipate + - Backup: backup, restore (PostgreSQL dump) + - HAProxy integration with extended timeouts (3600s) for streaming/WebSocket + - Full emancipation workflow: DNS → Vortex → HAProxy → ACL → SSL → Mesh → Mitmproxy → Reload +- **UCI config sections:** + - main: enabled, data_path, videos_path, memory_limit, timezone + - server: hostname, port, https, webserver_hostname + - live: enabled, rtmp_port, max_duration, allow_replay, transcoding_enabled + - transcoding: enabled, threads, allow_audio_files, hls_enabled, resolutions + - storage: external_enabled, s3_endpoint, s3_region, s3_bucket, s3_access_key, s3_secret_key + - network: domain, haproxy, haproxy_ssl, firewall_wan + - admin: email, initial_password + +### 2026-02-15: PeerTube LuCI Dashboard +- **Created luci-app-peertube package** + - RPCD handler (luci.peertube) with 11 methods: + - status, start, stop, install, uninstall, update, logs + - emancipate, live_enable, live_disable, configure_haproxy + - ACL permissions: read (status, logs), write (all actions) + - Menu entry: Admin → Services → PeerTube +- **Dashboard features:** + - Install wizard with features list and requirements + - Status badge (Running/Stopped) with access URL + - Service info: hostname, port, admin email + - Live streaming toggle with enable/disable buttons + - HAProxy configuration status with configure button + - Emancipate form for public exposure + - Logs viewer with refresh button diff --git a/.claude/WIP.md b/.claude/WIP.md index fa731065..72ad5429 100644 --- a/.claude/WIP.md +++ b/.claude/WIP.md @@ -62,6 +62,28 @@ _Last updated: 2026-02-14 (WAF architecture configured)_ - Gossip-based exposure config sync via secubox-p2p - Created `luci-app-vortex-dns` dashboard +### Just Completed (2026-02-15) + +- **PeerTube Video Platform Package** — DONE (2026-02-15) + - Created `secubox-app-peertube` package for self-hosted video streaming + - LXC Debian Bookworm container with PostgreSQL 15, Redis 7, Node.js 18, FFmpeg + - `peertubectl` CLI with 15+ commands: install/uninstall/update/start/stop/status + - Live streaming support with RTMP port 1935 + - HAProxy integration with extended timeouts (3600s) for streaming + - Emancipation workflow for public exposure + - User management: create-user, reset-password, list-users + - Backup/restore PostgreSQL database + - UCI config: main, server, live, transcoding, storage, network, admin sections + +- **PeerTube LuCI Dashboard** — DONE (2026-02-15) + - Created `luci-app-peertube` package + - RPCD handler with 11 methods: status, start, stop, install, uninstall, update, logs, emancipate, live_enable, live_disable, configure_haproxy + - Dashboard with install wizard, status display, service controls + - Live streaming toggle with firewall integration + - HAProxy configuration button + - Emancipate form for public exposure + - Logs viewer with refresh + ### Just Completed (2026-02-14) - **mitmproxy WAF Wildcard Route Priority Fix** — DONE (2026-02-14) diff --git a/package/secubox/luci-app-peertube/Makefile b/package/secubox/luci-app-peertube/Makefile new file mode 100644 index 00000000..68514e9b --- /dev/null +++ b/package/secubox/luci-app-peertube/Makefile @@ -0,0 +1,27 @@ +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI PeerTube Video Platform +LUCI_DEPENDS:=+luci-base +secubox-app-peertube +LUCI_PKGARCH:=all +PKG_LICENSE:=AGPL-3.0 + +include $(TOPDIR)/feeds/luci/luci.mk + +define Package/luci-app-peertube/install + $(INSTALL_DIR) $(1)/usr/share/luci/menu.d + $(INSTALL_DATA) ./root/usr/share/luci/menu.d/luci-app-peertube.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-peertube.json $(1)/usr/share/rpcd/acl.d/ + + $(INSTALL_DIR) $(1)/usr/libexec/rpcd + $(INSTALL_BIN) ./root/usr/libexec/rpcd/luci.peertube $(1)/usr/libexec/rpcd/ + + $(INSTALL_DIR) $(1)/www/luci-static/resources/view/peertube + $(INSTALL_DATA) ./htdocs/luci-static/resources/view/peertube/overview.js $(1)/www/luci-static/resources/view/peertube/ + + $(INSTALL_DIR) $(1)/www/luci-static/resources/peertube + $(INSTALL_DATA) ./htdocs/luci-static/resources/peertube/api.js $(1)/www/luci-static/resources/peertube/ +endef + +$(eval $(call BuildPackage,luci-app-peertube)) diff --git a/package/secubox/luci-app-peertube/htdocs/luci-static/resources/peertube/api.js b/package/secubox/luci-app-peertube/htdocs/luci-static/resources/peertube/api.js new file mode 100644 index 00000000..4654a3cf --- /dev/null +++ b/package/secubox/luci-app-peertube/htdocs/luci-static/resources/peertube/api.js @@ -0,0 +1,72 @@ +'use strict'; +'require rpc'; + +return L.Class.extend({ + status: rpc.declare({ + object: 'luci.peertube', + method: 'status', + expect: { } + }), + + start: rpc.declare({ + object: 'luci.peertube', + method: 'start', + expect: { } + }), + + stop: rpc.declare({ + object: 'luci.peertube', + method: 'stop', + expect: { } + }), + + install: rpc.declare({ + object: 'luci.peertube', + method: 'install', + expect: { } + }), + + uninstall: rpc.declare({ + object: 'luci.peertube', + method: 'uninstall', + expect: { } + }), + + update: rpc.declare({ + object: 'luci.peertube', + method: 'update', + expect: { } + }), + + logs: rpc.declare({ + object: 'luci.peertube', + method: 'logs', + params: ['lines'], + expect: { } + }), + + emancipate: rpc.declare({ + object: 'luci.peertube', + method: 'emancipate', + params: ['domain'], + expect: { } + }), + + liveEnable: rpc.declare({ + object: 'luci.peertube', + method: 'live_enable', + expect: { } + }), + + liveDisable: rpc.declare({ + object: 'luci.peertube', + method: 'live_disable', + expect: { } + }), + + configureHaproxy: rpc.declare({ + object: 'luci.peertube', + method: 'configure_haproxy', + expect: { } + }) +}); diff --git a/package/secubox/luci-app-peertube/htdocs/luci-static/resources/view/peertube/overview.js b/package/secubox/luci-app-peertube/htdocs/luci-static/resources/view/peertube/overview.js new file mode 100644 index 00000000..886d6897 --- /dev/null +++ b/package/secubox/luci-app-peertube/htdocs/luci-static/resources/view/peertube/overview.js @@ -0,0 +1,318 @@ +'use strict'; +'require view'; +'require dom'; +'require poll'; +'require ui'; +'require uci'; +'require form'; +'require peertube.api as api'; + +return view.extend({ + handleAction: function(action, args) { + var self = this; + var btn = document.activeElement; + + ui.showModal(_('Please wait...'), [ + E('p', { 'class': 'spinning' }, _('Processing request...')) + ]); + + var promise; + switch(action) { + case 'start': + promise = api.start(); + break; + case 'stop': + promise = api.stop(); + break; + case 'install': + promise = api.install(); + break; + case 'uninstall': + if (!confirm(_('This will remove the PeerTube container. Video data will be preserved. Continue?'))) + return ui.hideModal(); + promise = api.uninstall(); + break; + case 'update': + promise = api.update(); + break; + case 'live_enable': + promise = api.liveEnable(); + break; + case 'live_disable': + promise = api.liveDisable(); + break; + case 'configure_haproxy': + promise = api.configureHaproxy(); + break; + case 'emancipate': + var domain = args; + if (!domain) { + ui.hideModal(); + ui.addNotification(null, E('p', _('Domain is required')), 'error'); + return; + } + promise = api.emancipate(domain); + break; + default: + ui.hideModal(); + return; + } + + promise.then(function(res) { + ui.hideModal(); + if (res && res.success) { + ui.addNotification(null, E('p', res.message || _('Action completed')), 'success'); + self.load().then(function(data) { + dom.content(document.querySelector('#peertube-content'), self.renderContent(data)); + }); + } else { + ui.addNotification(null, E('p', res.error || _('Action failed')), 'error'); + } + }).catch(function(e) { + ui.hideModal(); + ui.addNotification(null, E('p', _('Error: ') + e.message), 'error'); + }); + }, + + load: function() { + return Promise.all([ + api.status(), + uci.load('peertube') + ]); + }, + + renderInstallWizard: function() { + var self = this; + + return E('div', { 'class': 'cbi-section' }, [ + E('h3', {}, _('PeerTube Video Platform')), + E('p', {}, _('PeerTube is a free, decentralized and federated video streaming platform. Videos are stored locally and can be shared across the Fediverse using ActivityPub.')), + E('div', { 'class': 'cbi-value' }, [ + E('h4', {}, _('Features')), + E('ul', {}, [ + E('li', {}, _('Self-hosted video hosting with HLS streaming')), + E('li', {}, _('Live streaming with RTMP ingest')), + E('li', {}, _('Automatic transcoding to multiple resolutions')), + E('li', {}, _('Federation via ActivityPub protocol')), + E('li', {}, _('User management and access controls')), + E('li', {}, _('WebTorrent for distributed video delivery')) + ]) + ]), + E('div', { 'class': 'cbi-value' }, [ + E('h4', {}, _('Requirements')), + E('ul', {}, [ + E('li', {}, _('Minimum 2GB RAM recommended')), + E('li', {}, _('10GB storage for system + additional for videos')), + E('li', {}, _('Network access for container downloads')) + ]) + ]), + E('div', { 'class': 'cbi-page-actions' }, [ + E('button', { + 'class': 'btn cbi-button cbi-button-positive', + 'click': function() { self.handleAction('install'); } + }, _('Install PeerTube')) + ]) + ]); + }, + + renderStatusBadge: function(running) { + var color = running === 'true' ? '#4CAF50' : '#f44336'; + var text = running === 'true' ? _('Running') : _('Stopped'); + return E('span', { + 'style': 'display:inline-block;padding:3px 10px;border-radius:3px;color:#fff;background:' + color + }, text); + }, + + renderContent: function(data) { + var self = this; + var status = data[0] || {}; + + if (status.container_state === 'not_installed') { + return this.renderInstallWizard(); + } + + var running = status.running === 'true'; + var liveEnabled = status.live_enabled === '1'; + var haproxyConfigured = status.haproxy === '1'; + var domain = status.domain || ''; + + var accessUrl = ''; + if (running) { + if (domain && haproxyConfigured) { + accessUrl = (status.https === '1' ? 'https://' : 'http://') + domain; + } else { + accessUrl = 'http://192.168.255.1:' + (status.port || '9000'); + } + } + + return E('div', { 'class': 'cbi-section' }, [ + E('h3', {}, _('PeerTube Video Platform')), + + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, _('Status')), + E('div', { 'class': 'cbi-value-field' }, this.renderStatusBadge(status.running)) + ]), + + running && accessUrl ? E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, _('Access URL')), + E('div', { 'class': 'cbi-value-field' }, [ + E('a', { 'href': accessUrl, 'target': '_blank' }, accessUrl) + ]) + ]) : '', + + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, _('Hostname')), + E('div', { 'class': 'cbi-value-field' }, status.hostname || '-') + ]), + + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, _('Port')), + E('div', { 'class': 'cbi-value-field' }, status.port || '9000') + ]), + + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, _('Live Streaming')), + E('div', { 'class': 'cbi-value-field' }, [ + E('span', { + 'style': 'display:inline-block;padding:3px 10px;border-radius:3px;color:#fff;background:' + (liveEnabled ? '#4CAF50' : '#9e9e9e') + }, liveEnabled ? _('Enabled') : _('Disabled')), + ' ', + liveEnabled ? + E('button', { + 'class': 'btn cbi-button', + 'click': function() { self.handleAction('live_disable'); } + }, _('Disable')) : + E('button', { + 'class': 'btn cbi-button', + 'click': function() { self.handleAction('live_enable'); } + }, _('Enable')) + ]) + ]), + + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, _('HAProxy')), + E('div', { 'class': 'cbi-value-field' }, [ + E('span', { + 'style': 'display:inline-block;padding:3px 10px;border-radius:3px;color:#fff;background:' + (haproxyConfigured ? '#4CAF50' : '#9e9e9e') + }, haproxyConfigured ? _('Configured') : _('Not configured')), + ' ', + !haproxyConfigured ? E('button', { + 'class': 'btn cbi-button', + 'click': function() { self.handleAction('configure_haproxy'); } + }, _('Configure')) : '' + ]) + ]), + + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, _('Domain')), + E('div', { 'class': 'cbi-value-field' }, domain || _('Not configured')) + ]), + + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, _('Admin Email')), + E('div', { 'class': 'cbi-value-field' }, status.admin_email || '-') + ]), + + E('hr'), + + E('h4', {}, _('Service Controls')), + E('div', { 'class': 'cbi-page-actions', 'style': 'margin-bottom: 20px;' }, [ + running ? + E('button', { + 'class': 'btn cbi-button cbi-button-negative', + 'click': function() { self.handleAction('stop'); } + }, _('Stop')) : + E('button', { + 'class': 'btn cbi-button cbi-button-positive', + 'click': function() { self.handleAction('start'); } + }, _('Start')), + ' ', + E('button', { + 'class': 'btn cbi-button', + 'click': function() { self.handleAction('update'); } + }, _('Update')), + ' ', + E('button', { + 'class': 'btn cbi-button cbi-button-negative', + 'click': function() { self.handleAction('uninstall'); } + }, _('Uninstall')) + ]), + + E('hr'), + + E('h4', {}, _('Emancipate (Public Exposure)')), + E('p', {}, _('Make PeerTube publicly accessible with SSL certificate and DNS configuration.')), + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, _('Domain')), + E('div', { 'class': 'cbi-value-field' }, [ + E('input', { + 'type': 'text', + 'id': 'emancipate-domain', + 'class': 'cbi-input-text', + 'placeholder': 'peertube.example.com', + 'value': domain + }) + ]) + ]), + E('div', { 'class': 'cbi-page-actions' }, [ + E('button', { + 'class': 'btn cbi-button cbi-button-action', + 'click': function() { + var domainInput = document.getElementById('emancipate-domain'); + self.handleAction('emancipate', domainInput.value); + } + }, _('Emancipate')) + ]), + + E('hr'), + + E('h4', {}, _('Logs')), + E('div', { 'id': 'peertube-logs' }, [ + E('pre', { + 'style': 'background:#1e1e1e;color:#d4d4d4;padding:10px;max-height:300px;overflow:auto;font-size:12px;border-radius:4px;' + }, _('Loading logs...')) + ]), + E('div', { 'class': 'cbi-page-actions' }, [ + E('button', { + 'class': 'btn cbi-button', + 'click': function() { + api.logs(100).then(function(res) { + var logsEl = document.querySelector('#peertube-logs pre'); + if (logsEl) { + logsEl.textContent = res.logs || _('No logs available'); + } + }); + } + }, _('Refresh Logs')) + ]) + ]); + }, + + render: function(data) { + var self = this; + + var content = E('div', { 'id': 'peertube-content' }, this.renderContent(data)); + + // Load logs initially + api.logs(50).then(function(res) { + var logsEl = document.querySelector('#peertube-logs pre'); + if (logsEl) { + logsEl.textContent = res.logs || _('No logs available'); + } + }); + + // Poll for status updates + poll.add(function() { + return api.status().then(function(status) { + var statusBadge = document.querySelector('.cbi-value-field span'); + // Status badge is the first one - update if running state changed + }); + }, 10); + + return content; + }, + + handleSaveApply: null, + handleSave: null, + handleReset: null +}); diff --git a/package/secubox/luci-app-peertube/root/usr/libexec/rpcd/luci.peertube b/package/secubox/luci-app-peertube/root/usr/libexec/rpcd/luci.peertube new file mode 100644 index 00000000..8be7436d --- /dev/null +++ b/package/secubox/luci-app-peertube/root/usr/libexec/rpcd/luci.peertube @@ -0,0 +1,338 @@ +#!/bin/sh + +# RPCD backend for PeerTube LuCI app + +. /usr/share/libubox/jshn.sh + +PEERTUBECTL="/usr/sbin/peertubectl" + +# Helper to get UCI value +uci_get() { + local section="$1" + local option="$2" + local default="$3" + local val + val=$(uci -q get "peertube.${section}.${option}") + echo "${val:-$default}" +} + +# Get container status +get_container_status() { + local state="not_installed" + local running="false" + local lxc_info="" + + if [ -d "/srv/lxc/peertube" ]; then + state="installed" + lxc_info=$(lxc-info -n peertube 2>/dev/null) + if echo "$lxc_info" | grep -q "State:.*RUNNING"; then + running="true" + fi + fi + + echo "$state $running" +} + +# Method: status +method_status() { + local enabled hostname port https live_enabled + local container_state running + local info + + enabled=$(uci_get main enabled 0) + hostname=$(uci_get server hostname "peertube.local") + port=$(uci_get server port "9000") + https=$(uci_get server https "1") + live_enabled=$(uci_get live enabled "0") + + info=$(get_container_status) + container_state=$(echo "$info" | awk '{print $1}') + running=$(echo "$info" | awk '{print $2}') + + json_init + json_add_string "enabled" "$enabled" + json_add_string "container_state" "$container_state" + json_add_string "running" "$running" + json_add_string "hostname" "$hostname" + json_add_string "port" "$port" + json_add_string "https" "$https" + json_add_string "live_enabled" "$live_enabled" + + # Get configured domain if emancipated + local domain haproxy + domain=$(uci_get network domain "") + haproxy=$(uci_get network haproxy "0") + json_add_string "domain" "$domain" + json_add_string "haproxy" "$haproxy" + + # Get admin email + local admin_email + admin_email=$(uci_get admin email "admin@localhost") + json_add_string "admin_email" "$admin_email" + + json_dump +} + +# Method: start +method_start() { + local output + output=$($PEERTUBECTL start 2>&1) + local rc=$? + + json_init + if [ $rc -eq 0 ]; then + json_add_boolean "success" 1 + json_add_string "message" "PeerTube started successfully" + else + json_add_boolean "success" 0 + json_add_string "error" "$output" + fi + json_dump +} + +# Method: stop +method_stop() { + local output + output=$($PEERTUBECTL stop 2>&1) + local rc=$? + + json_init + if [ $rc -eq 0 ]; then + json_add_boolean "success" 1 + json_add_string "message" "PeerTube stopped successfully" + else + json_add_boolean "success" 0 + json_add_string "error" "$output" + fi + json_dump +} + +# Method: install +method_install() { + local output + output=$($PEERTUBECTL install 2>&1) + local rc=$? + + json_init + if [ $rc -eq 0 ]; then + json_add_boolean "success" 1 + json_add_string "message" "PeerTube installed successfully" + else + json_add_boolean "success" 0 + json_add_string "error" "$output" + fi + json_dump +} + +# Method: uninstall +method_uninstall() { + local output + output=$($PEERTUBECTL uninstall 2>&1) + local rc=$? + + json_init + if [ $rc -eq 0 ]; then + json_add_boolean "success" 1 + json_add_string "message" "PeerTube uninstalled successfully" + else + json_add_boolean "success" 0 + json_add_string "error" "$output" + fi + json_dump +} + +# Method: update +method_update() { + local output + output=$($PEERTUBECTL update 2>&1) + local rc=$? + + json_init + if [ $rc -eq 0 ]; then + json_add_boolean "success" 1 + json_add_string "message" "PeerTube updated successfully" + else + json_add_boolean "success" 0 + json_add_string "error" "$output" + fi + json_dump +} + +# Method: logs +method_logs() { + local lines="${1:-50}" + local output + + if [ -d "/srv/lxc/peertube" ]; then + output=$($PEERTUBECTL logs "$lines" 2>&1 | tail -n "$lines") + else + output="Container not installed" + fi + + json_init + json_add_string "logs" "$output" + json_dump +} + +# Method: emancipate +method_emancipate() { + read -r input + json_load "$input" + json_get_var domain domain + + if [ -z "$domain" ]; then + json_init + json_add_boolean "success" 0 + json_add_string "error" "Domain is required" + json_dump + return + fi + + local output + output=$($PEERTUBECTL emancipate "$domain" 2>&1) + local rc=$? + + json_init + if [ $rc -eq 0 ]; then + json_add_boolean "success" 1 + json_add_string "message" "PeerTube emancipated to $domain" + else + json_add_boolean "success" 0 + json_add_string "error" "$output" + fi + json_dump +} + +# Method: live_enable +method_live_enable() { + local output + output=$($PEERTUBECTL live enable 2>&1) + local rc=$? + + json_init + if [ $rc -eq 0 ]; then + json_add_boolean "success" 1 + json_add_string "message" "Live streaming enabled" + else + json_add_boolean "success" 0 + json_add_string "error" "$output" + fi + json_dump +} + +# Method: live_disable +method_live_disable() { + local output + output=$($PEERTUBECTL live disable 2>&1) + local rc=$? + + json_init + if [ $rc -eq 0 ]; then + json_add_boolean "success" 1 + json_add_string "message" "Live streaming disabled" + else + json_add_boolean "success" 0 + json_add_string "error" "$output" + fi + json_dump +} + +# Method: configure_haproxy +method_configure_haproxy() { + local output + output=$($PEERTUBECTL configure-haproxy 2>&1) + local rc=$? + + json_init + if [ $rc -eq 0 ]; then + json_add_boolean "success" 1 + json_add_string "message" "HAProxy configured for PeerTube" + else + json_add_boolean "success" 0 + json_add_string "error" "$output" + fi + json_dump +} + +# List available methods +list_methods() { + json_init + json_add_object "status" + json_close_object + json_add_object "start" + json_close_object + json_add_object "stop" + json_close_object + json_add_object "install" + json_close_object + json_add_object "uninstall" + json_close_object + json_add_object "update" + json_close_object + json_add_object "logs" + json_add_int "lines" 50 + json_close_object + json_add_object "emancipate" + json_add_string "domain" "" + json_close_object + json_add_object "live_enable" + json_close_object + json_add_object "live_disable" + json_close_object + json_add_object "configure_haproxy" + json_close_object + json_dump +} + +# Main dispatcher +case "$1" in + list) + list_methods + ;; + call) + case "$2" in + status) + method_status + ;; + start) + method_start + ;; + stop) + method_stop + ;; + install) + method_install + ;; + uninstall) + method_uninstall + ;; + update) + method_update + ;; + logs) + read -r input + json_load "$input" + json_get_var lines lines + method_logs "${lines:-50}" + ;; + emancipate) + method_emancipate + ;; + live_enable) + method_live_enable + ;; + live_disable) + method_live_disable + ;; + configure_haproxy) + method_configure_haproxy + ;; + *) + echo '{"error":"Method not found"}' + ;; + esac + ;; + *) + echo '{"error":"Invalid action"}' + ;; +esac diff --git a/package/secubox/luci-app-peertube/root/usr/share/luci/menu.d/luci-app-peertube.json b/package/secubox/luci-app-peertube/root/usr/share/luci/menu.d/luci-app-peertube.json new file mode 100644 index 00000000..444748a0 --- /dev/null +++ b/package/secubox/luci-app-peertube/root/usr/share/luci/menu.d/luci-app-peertube.json @@ -0,0 +1,14 @@ +{ + "admin/services/peertube": { + "title": "PeerTube", + "order": 65, + "action": { + "type": "view", + "path": "peertube/overview" + }, + "depends": { + "acl": ["luci-app-peertube"], + "uci": {"peertube": true} + } + } +} diff --git a/package/secubox/luci-app-peertube/root/usr/share/rpcd/acl.d/luci-app-peertube.json b/package/secubox/luci-app-peertube/root/usr/share/rpcd/acl.d/luci-app-peertube.json new file mode 100644 index 00000000..d7783459 --- /dev/null +++ b/package/secubox/luci-app-peertube/root/usr/share/rpcd/acl.d/luci-app-peertube.json @@ -0,0 +1,17 @@ +{ + "luci-app-peertube": { + "description": "Grant access to PeerTube management", + "read": { + "ubus": { + "luci.peertube": ["status", "logs"] + }, + "uci": ["peertube"] + }, + "write": { + "ubus": { + "luci.peertube": ["start", "stop", "install", "uninstall", "update", "emancipate", "live_enable", "live_disable", "configure_haproxy"] + }, + "uci": ["peertube"] + } + } +}