profiles: add presets and wizard integration

This commit is contained in:
CyberMind-FR 2025-12-29 17:22:34 +01:00
parent eab24f9609
commit 3c0003614d
15 changed files with 504 additions and 3 deletions

View File

@ -22,6 +22,8 @@ These notes summarize the repository structure, conventions, and supporting tool
- `DOCS/` + `docs/`: mirrored, versioned documentation tree (design system, prompts, module templates, validation, permissions, etc.). - `DOCS/` + `docs/`: mirrored, versioned documentation tree (design system, prompts, module templates, validation, permissions, etc.).
- `EXAMPLES/` and `templates/`: snippets and scaffolding. - `EXAMPLES/` and `templates/`: snippets and scaffolding.
- CI workflows live in `.github/workflows/` (referenced from README badges). - CI workflows live in `.github/workflows/` (referenced from README badges).
- **Profiles & App Manifests**
- App manifests (`/usr/share/secubox/plugins/`) and profile presets (`/usr/share/secubox/profiles/`) feed both the SecuBox wizard UI and the `secubox-app` CLI for automated installs.
--- ---

View File

@ -223,6 +223,11 @@ Pointer: see `docs/embedded/vhost-manager.md` for the canonical version.
Pointer: see `docs/embedded/app-store.md` for the canonical version. Pointer: see `docs/embedded/app-store.md` for the canonical version.
#### **embedded/wizard-profiles.md** 🧭
*First-run wizard and OS-like profiles.*
Pointer: see `docs/embedded/wizard-profiles.md` for the canonical version.
--- ---
### 5. Tools & Scripts Documentation ### 5. Tools & Scripts Documentation

View File

@ -0,0 +1,74 @@
# SecuBox Wizard & Profiles
**Version:** 1.0.0
**Last Updated:** 2025-12-28
**Status:** Active
The SecuBox hub now includes a guided setup wizard (LuCI → SecuBox → Wizard) and profile system. Use them to finish the first-run checklist, review app manifests, and apply predefined OS-like configurations (Home, Lab, Hardened, Gateway + DMZ).
---
## First-Run Checklist
The wizard queries `luci.secubox`s `first_run_status` ubus method to determine whether critical items are configured:
1. **Administrator password** links to the LuCI password page.
2. **Timezone** dropdown populated with common timezones; applying calls `apply_first_run` with `{ timezone: "Europe/Paris" }`.
3. **Storage path** defaults to `/srv/secubox`; prepares the directory and stores it in `uci set secubox.main.storage_path`.
4. **Network mode** uses the existing Network Modes RPC to switch between `router` and `dmz` presets.
Each action can be run independently and is idempotent.
---
## App Wizards (Manifests)
Apps ship manifests under `/usr/share/secubox/plugins/<id>/manifest.json`. `secubox-app` (installed at `/usr/sbin/secubox-app`) uses the same manifests for CLI installs, and the wizard consumes the `wizard.fields` section to build forms. Example snippet:
```json
{
"id": "zigbee2mqtt",
"wizard": {
"uci": { "config": "zigbee2mqtt", "section": "main" },
"fields": [
{ "id": "serial_port", "label": "Serial Port", "uci_option": "serial_port" },
{ "id": "mqtt_host", "label": "MQTT Host", "uci_option": "mqtt_host" }
]
}
}
```
Clicking “Configure” opens a modal that writes the provided values into the specified UCI section.
---
## Profiles
Profiles are stored as JSON in `/usr/share/secubox/profiles/` and can bundle:
- `network_mode`: target SecuBox network mode (`router`, `dmz`, …)
- `apps`: manifest IDs to install via `secubox-app install <id>`
- `packages`: additional packages to ensure via opkg/apk
- `uci`: array of `{config, section, option, value}` entries applied via UCI
Baseline profiles:
| ID | Description | Highlights |
|----|-------------|------------|
| `home` | Home router + Zigbee2MQTT | Router mode, installs Zigbee2MQTT + Netdata |
| `lab` | Monitoring lab | Router mode, ensures Netifyd & Bandwidth Manager |
| `hardened` | Security-focused | Enables CrowdSec + Client Guardian |
| `gateway_dmz` | Router + DMZ segment | Switches to DMZ mode and enables VHost manager |
`apply_profile` automatically tars `/etc/config` to `/etc/secubox-profiles/backups/` before modifying settings, so the **Rollback last profile** button (or `rollback_profile` RPC) instantly restores prior UCI files.
---
## CLI References
- `secubox-app list|install|status` manage app manifests (installed by `luci-app-secubox`).
- `ubus call luci.secubox list_profiles` enumerate available profile manifests.
- `ubus call luci.secubox apply_profile '{"profile_id":"home"}'` apply a preset programmatically.
- `secubox-app` respects `SECUBOX_PLUGINS_DIR` if you need to point to custom manifest trees.
Combine the wizard UI with these commands to automate deployments or build higher-level orchestration (e.g., App Store pages, onboarding scripts).

View File

@ -28,6 +28,9 @@ These notes capture the current repository structure, conventions, and supportin
- **Docs** - **Docs**
Two mirrored trees (`docs/` and uppercase `DOCS/`) feed MkDocs and the GitHub wiki. All Markdown follows the metadata template defined in `docs/documentation-index.md`. Two mirrored trees (`docs/` and uppercase `DOCS/`) feed MkDocs and the GitHub wiki. All Markdown follows the metadata template defined in `docs/documentation-index.md`.
- **Profiles & App Manifests**
App manifests now live under `/usr/share/secubox/plugins/`, profiles under `/usr/share/secubox/profiles/`. `luci-app-secubox` exposes both through the wizard (UI) and `secubox-app` CLI (automation).
--- ---
## 2. Target Platforms & Build System ## 2. Target Platforms & Build System

View File

@ -247,6 +247,18 @@ Follow this template when creating or revising documentation:
**Size:** Short (~120 lines) **Size:** Short (~120 lines)
#### **embedded/wizard-profiles.md** 🧭
*First-run wizard + OS-like profiles.*
**Contents:**
- First-run checklist (password, timezone, storage, network mode)
- Using manifest-driven app wizards
- Baseline profiles (Home, Lab, Hardened, Gateway+DMZ) and rollback mechanics
**When to use:** Guiding new deployments or applying pre-made bundles.
**Size:** Short (~130 lines)
--- ---
### 5. Tools & Scripts Documentation ### 5. Tools & Scripts Documentation

View File

@ -0,0 +1,74 @@
# SecuBox Wizard & Profiles
**Version:** 1.0.0
**Last Updated:** 2025-12-28
**Status:** Active
The SecuBox hub now includes a guided setup wizard (LuCI → SecuBox → Wizard) and profile system. Use them to finish the first-run checklist, review app manifests, and apply predefined OS-like configurations (Home, Lab, Hardened, Gateway + DMZ).
---
## First-Run Checklist
The wizard queries `luci.secubox`s `first_run_status` ubus method to determine whether critical items are configured:
1. **Administrator password** links to the LuCI password page.
2. **Timezone** dropdown populated with common timezones; applying calls `apply_first_run` with `{ timezone: "Europe/Paris" }`.
3. **Storage path** defaults to `/srv/secubox`; prepares the directory and stores it in `uci set secubox.main.storage_path`.
4. **Network mode** uses the existing Network Modes RPC to switch between `router` and `dmz` presets.
Each action can be run independently and is idempotent.
---
## App Wizards (Manifests)
Apps ship manifests under `/usr/share/secubox/plugins/<id>/manifest.json`. `secubox-app` (installed at `/usr/sbin/secubox-app`) uses the same manifests for CLI installs, and the wizard consumes the `wizard.fields` section to build forms. Example snippet:
```json
{
"id": "zigbee2mqtt",
"wizard": {
"uci": { "config": "zigbee2mqtt", "section": "main" },
"fields": [
{ "id": "serial_port", "label": "Serial Port", "uci_option": "serial_port" },
{ "id": "mqtt_host", "label": "MQTT Host", "uci_option": "mqtt_host" }
]
}
}
```
Clicking “Configure” opens a modal that writes the provided values into the specified UCI section.
---
## Profiles
Profiles are stored as JSON in `/usr/share/secubox/profiles/` and can bundle:
- `network_mode`: target SecuBox network mode (`router`, `dmz`, …)
- `apps`: manifest IDs to install via `secubox-app install <id>`
- `packages`: additional packages to ensure via opkg/apk
- `uci`: array of `{config, section, option, value}` entries applied via UCI
Baseline profiles:
| ID | Description | Highlights |
|----|-------------|------------|
| `home` | Home router + Zigbee2MQTT | Router mode, installs Zigbee2MQTT + Netdata |
| `lab` | Monitoring lab | Router mode, ensures Netifyd & Bandwidth Manager |
| `hardened` | Security-focused | Enables CrowdSec + Client Guardian |
| `gateway_dmz` | Router + DMZ segment | Switches to DMZ mode and enables VHost manager |
`apply_profile` automatically tars `/etc/config` to `/etc/secubox-profiles/backups/` before modifying settings, so the **Rollback last profile** button (or `rollback_profile` RPC) instantly restores prior UCI files.
---
## CLI References
- `secubox-app list|install|status` manage app manifests (installed by `luci-app-secubox`).
- `ubus call luci.secubox list_profiles` enumerate available profile manifests.
- `ubus call luci.secubox apply_profile '{"profile_id":"home"}'` apply a preset programmatically.
- `secubox-app` respects `SECUBOX_PLUGINS_DIR` if you need to point to custom manifest trees.
Combine the wizard UI with these commands to automate deployments or build higher-level orchestration (e.g., App Store pages, onboarding scripts).

View File

@ -26,6 +26,10 @@ define Package/$(PKG_NAME)/install
$(call Package/luci/install,$(1)) $(call Package/luci/install,$(1))
$(INSTALL_DIR) $(1)/usr/share/secubox/plugins/zigbee2mqtt $(INSTALL_DIR) $(1)/usr/share/secubox/plugins/zigbee2mqtt
$(INSTALL_DATA) $(CURDIR)/../plugins/zigbee2mqtt/manifest.json $(1)/usr/share/secubox/plugins/zigbee2mqtt/manifest.json $(INSTALL_DATA) $(CURDIR)/../plugins/zigbee2mqtt/manifest.json $(1)/usr/share/secubox/plugins/zigbee2mqtt/manifest.json
$(INSTALL_DIR) $(1)/usr/share/secubox/profiles
for file in $(CURDIR)/../profiles/*.json; do \
$(INSTALL_DATA) $$file $(1)/usr/share/secubox/profiles/$$(basename $$file); \
done
$(INSTALL_DIR) $(1)/usr/sbin $(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(CURDIR)/../secubox-tools/secubox-app $(1)/usr/sbin/secubox-app $(INSTALL_BIN) $(CURDIR)/../secubox-tools/secubox-app $(1)/usr/sbin/secubox-app
endef endef

View File

@ -174,6 +174,23 @@ var callApplyAppWizard = rpc.declare({
params: ['app_id', 'values'] params: ['app_id', 'values']
}); });
var callListProfiles = rpc.declare({
object: 'luci.secubox',
method: 'list_profiles',
expect: { profiles: [] }
});
var callApplyProfile = rpc.declare({
object: 'luci.secubox',
method: 'apply_profile',
params: ['profile_id']
});
var callRollbackProfile = rpc.declare({
object: 'luci.secubox',
method: 'rollback_profile'
});
function formatUptime(seconds) { function formatUptime(seconds) {
if (!seconds) return '0s'; if (!seconds) return '0s';
var d = Math.floor(seconds / 86400); var d = Math.floor(seconds / 86400);
@ -222,6 +239,9 @@ return baseclass.extend({
listApps: callListApps, listApps: callListApps,
getAppManifest: callGetAppManifest, getAppManifest: callGetAppManifest,
applyAppWizard: callApplyAppWizard, applyAppWizard: callApplyAppWizard,
listProfiles: callListProfiles,
applyProfile: callApplyProfile,
rollbackProfile: callRollbackProfile,
// Utilities // Utilities
formatUptime: formatUptime, formatUptime: formatUptime,
formatBytes: formatBytes formatBytes: formatBytes

View File

@ -22,18 +22,21 @@ return view.extend({
load: function() { load: function() {
return Promise.all([ return Promise.all([
API.getFirstRunStatus(), API.getFirstRunStatus(),
API.listApps() API.listApps(),
API.listProfiles()
]); ]);
}, },
render: function(payload) { render: function(payload) {
this.firstRun = payload[0] || {}; this.firstRun = payload[0] || {};
this.appList = (payload[1] && payload[1].apps) || []; this.appList = (payload[1] && payload[1].apps) || [];
this.profileList = (payload[2] && payload[2].profiles) || [];
var container = E('div', { 'class': 'secubox-wizard-page' }, [ var container = E('div', { 'class': 'secubox-wizard-page' }, [
E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox/common.css') }), E('link', { 'rel': 'stylesheet', 'href': L.resource('secubox/common.css') }),
SecuNav.renderTabs('wizard'), SecuNav.renderTabs('wizard'),
this.renderHeader(), this.renderHeader(),
this.renderFirstRunCard(), this.renderFirstRunCard(),
this.renderProfilesCard(),
this.renderAppsCard() this.renderAppsCard()
]); ]);
return container; return container;
@ -142,6 +145,44 @@ return view.extend({
]); ]);
}, },
renderProfilesCard: function() {
var profiles = this.profileList || [];
return E('div', { 'class': 'sb-wizard-card' }, [
E('div', { 'class': 'sb-wizard-title' }, ['🧱 ', _('Profiles')]),
profiles.length ? E('div', { 'class': 'sb-app-grid' }, profiles.map(this.renderProfileCard, this)) :
E('div', { 'class': 'secubox-empty-state' }, [
E('div', { 'class': 'secubox-empty-icon' }, '📭'),
E('div', { 'class': 'secubox-empty-title' }, _('No profiles available')),
E('div', { 'class': 'secubox-empty-text' }, _('Profiles are stored in /usr/share/secubox/profiles/.'))
]),
profiles.length ? E('div', { 'class': 'right', 'style': 'margin-top:12px;' }, [
E('button', {
'class': 'cbi-button cbi-button-action',
'click': this.rollbackProfile.bind(this)
}, _('Rollback last profile'))
]) : ''
]);
},
renderProfileCard: function(profile) {
var apps = profile.apps || [];
return E('div', { 'class': 'sb-app-card' }, [
E('div', { 'class': 'sb-app-card-info' }, [
E('div', { 'class': 'sb-app-name' }, [profile.name || profile.id]),
E('div', { 'class': 'sb-app-desc' }, profile.description || ''),
E('div', { 'class': 'sb-app-desc' }, _('Network mode: %s').format(profile.network_mode || '—')),
apps.length ? E('div', { 'class': 'sb-app-desc' }, _('Apps: %s').format(apps.join(', '))) : ''
]),
E('div', { 'class': 'sb-app-actions' }, [
E('span', { 'class': 'sb-app-state' + (profile.state === 'installed' ? ' ok' : '') }, profile.state || 'n/a'),
E('button', {
'class': 'cbi-button cbi-button-action',
'click': this.applyProfile.bind(this, profile.id)
}, _('Apply'))
])
]);
},
renderAppCard: function(app) { renderAppCard: function(app) {
return E('div', { 'class': 'sb-app-card' }, [ return E('div', { 'class': 'sb-app-card' }, [
E('div', { 'class': 'sb-app-card-info' }, [ E('div', { 'class': 'sb-app-card-info' }, [
@ -241,5 +282,31 @@ return view.extend({
ui.addNotification(null, E('p', {}, _('Failed to apply wizard.')), 'error'); ui.addNotification(null, E('p', {}, _('Failed to apply wizard.')), 'error');
} }
}).catch(this.showError); }).catch(this.showError);
},
applyProfile: function(profileId) {
if (!profileId)
return;
ui.showModal(_('Applying profile…'), [E('div', { 'class': 'spinning' })]);
API.applyProfile(profileId).then(function(result) {
ui.hideModal();
if (result && result.success) {
ui.addNotification(null, E('p', {}, _('Profile applied. A reboot may be required.')), 'info');
} else {
ui.addNotification(null, E('p', {}, (result && result.error) || _('Failed to apply profile')), 'error');
}
}).catch(this.showError);
},
rollbackProfile: function() {
ui.showModal(_('Rolling back…'), [E('div', { 'class': 'spinning' })]);
API.rollbackProfile().then(function(result) {
ui.hideModal();
if (result && result.success) {
ui.addNotification(null, E('p', {}, result.message || _('Rollback completed.')), 'info');
} else {
ui.addNotification(null, E('p', {}, (result && result.error) || _('Rollback failed.')), 'error');
}
}).catch(this.showError);
} }
}); });

View File

@ -55,7 +55,11 @@ get_pkg_version() {
PKG_VERSION="$(get_pkg_version)" PKG_VERSION="$(get_pkg_version)"
PLUGIN_DIR="/usr/share/secubox/plugins" PLUGIN_DIR="/usr/share/secubox/plugins"
PROFILE_DIR="/usr/share/secubox/profiles"
PROFILE_BACKUP_DIR="/etc/secubox-profiles/backups"
DEFAULT_STORAGE_PATH="/srv/secubox" DEFAULT_STORAGE_PATH="/srv/secubox"
SECOBOX_APP="/usr/sbin/secubox-app"
OPKG_UPDATED=0
# Module registry - auto-detected from /usr/libexec/rpcd/ # Module registry - auto-detected from /usr/libexec/rpcd/
detect_modules() { detect_modules() {
@ -127,6 +131,34 @@ ensure_directory() {
[ -d "$dir" ] || mkdir -p "$dir" [ -d "$dir" ] || mkdir -p "$dir"
} }
apply_network_mode() {
local mode="$1"
[ -n "$mode" ] || return
if command -v ubus >/dev/null 2>&1; then
if ubus call luci.network-modes set_mode "{\"mode\":\"$mode\"}" >/dev/null 2>&1; then
ubus call luci.network-modes apply_mode >/dev/null 2>&1
fi
fi
}
ensure_opkg_updated() {
[ "$OPKG_UPDATED" -eq 1 ] && return
if command -v opkg >/dev/null 2>&1; then
opkg update >/dev/null 2>&1 && OPKG_UPDATED=1
fi
}
install_package_if_missing() {
local pkg="$1"
package_installed "$pkg" && return
if command -v opkg >/dev/null 2>&1; then
ensure_opkg_updated
opkg install "$pkg" >/dev/null 2>&1
elif command -v apk >/dev/null 2>&1; then
apk add "$pkg" >/dev/null 2>&1
fi
}
# Check if a module is installed (supports both opkg and apk) # Check if a module is installed (supports both opkg and apk)
check_module_installed() { check_module_installed() {
local module="$1" local module="$1"
@ -1324,6 +1356,136 @@ apply_app_wizard() {
json_add_boolean "success" 1 json_add_boolean "success" 1
json_dump json_dump
} }
list_profiles() {
ensure_directory "$PROFILE_DIR"
json_init
json_add_array "profiles"
local profile_file
for profile_file in "$PROFILE_DIR"/*.json; do
[ -f "$profile_file" ] || continue
local profile_json id name description network_mode apps state
profile_json=$(cat "$profile_file")
id=$(jsonfilter -s "$profile_json" -e '@.id' 2>/dev/null)
name=$(jsonfilter -s "$profile_json" -e '@.name' 2>/dev/null)
description=$(jsonfilter -s "$profile_json" -e '@.description' 2>/dev/null)
network_mode=$(jsonfilter -s "$profile_json" -e '@.network_mode' 2>/dev/null)
apps=$(jsonfilter -s "$profile_json" -e '@.apps[*]' 2>/dev/null)
state=$(packages_state "$profile_json")
[ -n "$id" ] || continue
json_add_object
json_add_string "id" "$id"
json_add_string "name" "$name"
json_add_string "description" "$description"
json_add_string "network_mode" "$network_mode"
json_add_string "state" "$state"
json_add_array "apps"
for app in $apps; do
json_add_string "" "$app"
done
json_close_array
json_close_object
done
json_close_array
json_dump
}
apply_profile() {
local input profile_id profile_file profile_json network_mode packages apps backup_file notes=""
read input
json_load "$input"
json_get_var profile_id profile_id
json_cleanup
[ -n "$profile_id" ] || {
json_init; json_add_boolean "success" 0; json_add_string "error" "profile_id required"; json_dump; return;
}
profile_file="$PROFILE_DIR/$profile_id.json"
if [ ! -f "$profile_file" ]; then
json_init; json_add_boolean "success" 0; json_add_string "error" "Profile not found"; json_dump; return;
fi
profile_json=$(cat "$profile_file")
ensure_directory "$PROFILE_BACKUP_DIR"
local timestamp=$(date +%Y%m%d_%H%M%S)
backup_file="$PROFILE_BACKUP_DIR/profile_${profile_id}_${timestamp}.tar.gz"
tar -czf "$backup_file" /etc/config 2>/dev/null
notes="${notes}Backup saved to $backup_file\n"
uci set secubox.profile.last_backup="$backup_file"
uci set secubox.profile.last_profile="$profile_id"
uci commit secubox
network_mode=$(jsonfilter -s "$profile_json" -e '@.network_mode' 2>/dev/null)
if [ -n "$network_mode" ]; then
notes="${notes}Switched network mode to $network_mode\n"
apply_network_mode "$network_mode"
fi
packages=$(jsonfilter -s "$profile_json" -e '@.packages[*]' 2>/dev/null)
for pkg in $packages; do
install_package_if_missing "$pkg"
notes="${notes}Ensured package $pkg\n"
done
apps=$(jsonfilter -s "$profile_json" -e '@.apps[*]' 2>/dev/null)
for app in $apps; do
if [ -x "$SECOBOX_APP" ]; then
$SECOBOX_APP install "$app" >/dev/null 2>&1 && notes="${notes}Installed app $app\n"
fi
done
json_load "$profile_json"
local uci_configs=""
if json_select uci >/dev/null 2>&1; then
local entries
json_get_keys entries
for entry in $entries; do
json_select "$entry"
local cfg section option value
json_get_var cfg config
json_get_var section section
json_get_var option option
json_get_var value value
section=${section:-main}
if [ -n "$cfg" ] && [ -n "$option" ]; then
uci set ${cfg}.${section}.${option}="$value"
uci_configs="${uci_configs} $cfg"
notes="${notes}Set ${cfg}.${section}.${option}=${value}\n"
fi
json_select ..
done
json_select ..
fi
json_cleanup
local committed=""
for cfg in $uci_configs; do
case " $committed " in
*" $cfg "*) continue;;
esac
uci commit "$cfg"
committed="$committed $cfg"
done
json_init
json_add_boolean "success" 1
json_add_array "messages"
printf '%b' "$notes" | while IFS= read -r line; do
[ -n "$line" ] && json_add_string "" "$line"
done
json_close_array
json_add_string "backup" "$backup_file"
json_dump
}
rollback_profile() {
local latest_backup
latest_backup=$(ls -t "$PROFILE_BACKUP_DIR"/profile_*.tar.gz 2>/dev/null | head -1)
if [ -z "$latest_backup" ]; then
json_init; json_add_boolean "success" 0; json_add_string "error" "No backups available"; json_dump; return;
fi
cd /
tar -xzf "$latest_backup" 2>/dev/null
/etc/init.d/network reload >/dev/null 2>&1
/etc/init.d/firewall reload >/dev/null 2>&1
/etc/init.d/dnsmasq reload >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_add_string "message" "Restored $latest_backup"
json_dump
}
case "$1" in case "$1" in
list) list)
json_init json_init
@ -1392,6 +1554,25 @@ case "$1" in
json_add_object "apply_app_wizard" json_add_object "apply_app_wizard"
json_add_string "app_id" "string" json_add_string "app_id" "string"
json_close_object json_close_object
json_add_object "list_profiles"
json_close_object
json_add_object "apply_profile"
json_add_string "profile_id" "string"
json_close_object
json_add_object "rollback_profile"
json_close_object
json_add_object "first_run_status"
json_close_object
json_add_object "apply_first_run"
json_close_object
json_add_object "list_apps"
json_close_object
json_add_object "get_app_manifest"
json_add_string "app_id" "string"
json_close_object
json_add_object "apply_app_wizard"
json_add_string "app_id" "string"
json_close_object
json_dump json_dump
;; ;;
call) call)
@ -1507,6 +1688,15 @@ case "$1" in
apply_app_wizard) apply_app_wizard)
apply_app_wizard apply_app_wizard
;; ;;
list_profiles)
list_profiles
;;
apply_profile)
apply_profile
;;
rollback_profile)
rollback_profile
;;
*) *)
echo '{"error":"Unknown method"}' echo '{"error":"Unknown method"}'
;; ;;

View File

@ -17,7 +17,8 @@
"get_theme", "get_theme",
"first_run_status", "first_run_status",
"list_apps", "list_apps",
"get_app_manifest" "get_app_manifest",
"list_profiles"
], ],
"uci": [ "uci": [
"get", "get",
@ -42,7 +43,9 @@
"clear_alerts", "clear_alerts",
"fix_permissions", "fix_permissions",
"apply_first_run", "apply_first_run",
"apply_app_wizard" "apply_app_wizard",
"apply_profile",
"rollback_profile"
], ],
"uci": [ "uci": [
"set", "set",

11
profiles/gateway_dmz.json Normal file
View File

@ -0,0 +1,11 @@
{
"id": "gateway_dmz",
"name": "Gateway + DMZ",
"description": "Router with isolated DMZ segment for exposed services.",
"network_mode": "dmz",
"apps": ["zigbee2mqtt"],
"packages": ["luci-app-vhost-manager"],
"uci": [
{ "config": "secubox", "section": "vhost_manager", "option": "enabled", "value": "1" }
]
}

12
profiles/hardened.json Normal file
View File

@ -0,0 +1,12 @@
{
"id": "hardened",
"name": "Hardened",
"description": "Security-focused preset enabling CrowdSec and Client Guardian.",
"network_mode": "router",
"apps": [],
"packages": ["luci-app-crowdsec-dashboard", "luci-app-client-guardian"],
"uci": [
{ "config": "secubox", "section": "crowdsec", "option": "enabled", "value": "1" },
{ "config": "secubox", "section": "client_guardian", "option": "enabled", "value": "1" }
]
}

12
profiles/home.json Normal file
View File

@ -0,0 +1,12 @@
{
"id": "home",
"name": "Home",
"description": "Default home router with Zigbee and monitoring enabled.",
"network_mode": "router",
"apps": ["zigbee2mqtt"],
"packages": ["luci-app-netdata-dashboard"],
"uci": [
{ "config": "secubox", "section": "netdata", "option": "enabled", "value": "1" },
{ "config": "secubox", "section": "zigbee2mqtt", "option": "enabled", "value": "1" }
]
}

12
profiles/lab.json Normal file
View File

@ -0,0 +1,12 @@
{
"id": "lab",
"name": "Lab",
"description": "Extended monitoring and DPI for test environments.",
"network_mode": "router",
"apps": [],
"packages": ["luci-app-netifyd-dashboard", "luci-app-netdata-dashboard"],
"uci": [
{ "config": "secubox", "section": "netifyd", "option": "enabled", "value": "1" },
{ "config": "secubox", "section": "bandwidth_manager", "option": "enabled", "value": "1" }
]
}