- Catalog block now shows the official catalog as a pinned row #1 (verified badge + its URL from the generated data). Removing it opens the shared confirmation dialog with a REQUIRED tickbox (generalized to accept custom checkbox text) — it only hides official apps from browsing; system updates are unaffected. Backed by a new CFG_CATALOG_OFFICIAL_ENABLED flag the scan honors. - Trimmed the info-banner wording per feedback. - Config option sections: the body (after the divider, before the buttons) now sits in a darker boxed panel (bg + border), matching the content-box look used elsewhere. Applies to regular grids + the block editors; scoped to the main config editor. Signed-off-by: librelad <librelad@digitalangels.vip> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
130 lines
6.3 KiB
Bash
130 lines
6.3 KiB
Bash
#!/bin/bash
|
|
#
|
|
# Catalog sources — the ordered list of app-catalog URLs the App Center browses.
|
|
# ---------------------------------------------------------------------------
|
|
# SOURCE OF TRUTH = the CFG_CATALOG_1..9 config vars in configs/general/
|
|
# general_catalogs (edited from the WebUI Catalog Sources block, like domains).
|
|
# registry_catalog.json is a GENERATED artifact derived from these + the official
|
|
# source — rebuilt by webuiRegistryCatalogScan on config save + `updater check`.
|
|
#
|
|
# Source #1 is ALWAYS the official catalog, synthesized live from
|
|
# CFG_RELEASE_BASE_URL / CFG_RELEASE_CHANNEL (pinned, NOT in general_catalogs).
|
|
# Each extra slot CFG_CATALOG_<N> maps to source idx <N+1> (a stable id the Add
|
|
# dialog / `app add --source` can reference) and is UNVERIFIED third-party.
|
|
#
|
|
# Priority = official first, then slots 1..9 ascending; the highest-priority
|
|
# source offering an app is the default (Add dialog can pick another).
|
|
#
|
|
# SCOPE: browse + add only. System updates/hotfixes still resolve from the
|
|
# official CFG_RELEASE_BASE_URL alone (lpFetchIndex untouched) — a third-party
|
|
# catalog can never become a system-update channel.
|
|
|
|
CATALOG_MAX_SLOTS=9
|
|
|
|
# Extra (third-party) sources as a JSON array [{idx,name,base,channel}] in slot
|
|
# order, skipping empty slots. A slot value is "url" or "url|channel".
|
|
catalogExtraSourcesJson() {
|
|
command -v jq >/dev/null 2>&1 || { echo '[]'; return 0; }
|
|
local arr='[]' n var val url channel host
|
|
for (( n=1; n<=CATALOG_MAX_SLOTS; n++ )); do
|
|
var="CFG_CATALOG_${n}"; val="${!var:-}"
|
|
[[ -z "$val" ]] && continue
|
|
url="${val%%|*}"
|
|
channel="stable"; [[ "$val" == *"|"* ]] && channel="${val##*|}"
|
|
[[ "$url" =~ ^https?://[^[:space:]/]+ ]] || continue
|
|
url="${url%/}"
|
|
host="${url#*://}"; host="${host%%/*}"
|
|
arr="$(jq -c --argjson i "$(( n + 1 ))" --arg name "$host" --arg base "$url" --arg ch "$channel" \
|
|
'. + [ { idx:$i, name:$name, base:$base, channel:$ch } ]' <<<"$arr")"
|
|
done
|
|
printf '%s' "$arr"
|
|
}
|
|
|
|
# The full ordered source list as a JSON array. Each:
|
|
# {idx,name,base,channel,official,trust,enabled}. The official source can be
|
|
# switched off for browsing via CFG_CATALOG_OFFICIAL_ENABLED (default on) —
|
|
# extras are always enabled (an empty slot is simply absent).
|
|
catalogSourcesJson() {
|
|
local off_base off_channel extras off_enabled
|
|
off_base="$(lpReleaseBaseUrl)"; off_base="${off_base%/}"
|
|
off_channel="$(lpReleaseChannel)"
|
|
off_enabled="true"; [[ "${CFG_CATALOG_OFFICIAL_ENABLED:-true}" == "false" ]] && off_enabled="false"
|
|
extras="$(catalogExtraSourcesJson)"
|
|
jq -cn --arg base "$off_base" --arg channel "$off_channel" --argjson oe "$off_enabled" --argjson extras "$extras" '
|
|
[ { idx: 1, name: "LibrePortal Official", base: $base, channel: $channel,
|
|
official: true, trust: "official", enabled: $oe } ]
|
|
+ ( $extras | map( . + { official: false, trust: "community", enabled: true } ) )'
|
|
}
|
|
|
|
# One ENABLED source per line (compact JSON), priority order — for `while read`.
|
|
catalogEnabledSources() { catalogSourcesJson | jq -c '.[] | select(.enabled)'; }
|
|
|
|
# Human-readable listing for the CLI.
|
|
catalogSourceList() {
|
|
catalogSourcesJson | jq -r '.[] |
|
|
"[\(.idx)] \(.name) — \(.base)/\(.channel) (\(if .official then "official ✓" else "unverified" end)\(if .enabled then "" else ", off" end))"'
|
|
}
|
|
|
|
# Fetch a THIRD-PARTY catalog index. Deliberately NOT verified against the
|
|
# official key and does NOT touch the anti-rollback serial — community sources
|
|
# are UNVERIFIED (their payloads are still sha256-pinned at add time by the pin
|
|
# carried in this index). Echoes the index JSON; non-zero on failure.
|
|
catalogFetchCommunityIndex() {
|
|
local base="$1" channel="$2" tmp idx json
|
|
base="${base%/}"
|
|
[[ -n "$base" && -n "$channel" ]] || return 1
|
|
command -v jq >/dev/null 2>&1 || return 1
|
|
[[ -n "$(_lpFetchTool)" ]] || return 1
|
|
tmp="$(mktemp -d)"; idx="$tmp/index.json"
|
|
if ! _lpDownload "$base/$channel/index.json" "$idx" 2>/dev/null; then rm -rf "$tmp"; return 1; fi
|
|
json="$(cat "$idx")"; rm -rf "$tmp"
|
|
jq empty <<<"$json" 2>/dev/null || return 1
|
|
printf '%s' "$json"
|
|
}
|
|
|
|
# --- Mutations: write the CFG_CATALOG_<N> vars via the config system ---------
|
|
|
|
# catalogSourceAdd <url> [channel] — into the first free slot.
|
|
catalogSourceAdd() {
|
|
local url="$1" channel="$2"
|
|
if [[ ! "$url" =~ ^https?://[^[:space:]/]+ ]]; then
|
|
isError "catalog: source URL must be http(s)://…"; return 1
|
|
fi
|
|
url="${url%/}"
|
|
local stored="$url"; [[ -n "$channel" && "$channel" != "stable" ]] && stored="$url|$channel"
|
|
if catalogSourcesJson | jq -e --arg b "$url" 'any(.[]; .base==$b)' >/dev/null 2>&1; then
|
|
isNotice "catalog: '$url' is already a source."; return 0
|
|
fi
|
|
local n var
|
|
for (( n=1; n<=CATALOG_MAX_SLOTS; n++ )); do
|
|
var="CFG_CATALOG_${n}"
|
|
if [[ -z "${!var:-}" ]]; then
|
|
updateConfigOption "$var" "$stored" >/dev/null || { isError "catalog: failed to write $var."; return 1; }
|
|
isSuccessful "catalog: added source '$url' (slot $n)."
|
|
catalogRefresh
|
|
return 0
|
|
fi
|
|
done
|
|
isError "catalog: all $CATALOG_MAX_SLOTS catalog slots are full — remove one first."; return 1
|
|
}
|
|
|
|
# catalogSourceRemove <idx> — idx 1 = official (fixed); idx N+1 = CFG_CATALOG_N.
|
|
catalogSourceRemove() {
|
|
local idx="$1"
|
|
[[ "$idx" =~ ^[0-9]+$ ]] || { isError "catalog: <idx> must be a number."; return 1; }
|
|
(( idx == 1 )) && { isError "catalog: source 1 is the official catalog and can't be removed."; return 1; }
|
|
local slot=$(( idx - 1 )) var="CFG_CATALOG_$(( idx - 1 ))"
|
|
(( slot < 1 || slot > CATALOG_MAX_SLOTS )) && { isError "catalog: no source with idx $idx."; return 1; }
|
|
[[ -z "${!var:-}" ]] && { isError "catalog: no source with idx $idx."; return 1; }
|
|
updateConfigOption "$var" "" >/dev/null || { isError "catalog: failed to clear $var."; return 1; }
|
|
isSuccessful "catalog: removed source $idx."
|
|
catalogRefresh
|
|
}
|
|
|
|
# Re-run the App Center browse scan so a source change reflects immediately.
|
|
catalogRefresh() {
|
|
declare -F webuiRegistryCatalogScan >/dev/null 2>&1 || \
|
|
source "${install_scripts_dir}webui/data/generators/apps/webui_registry_scan.sh" 2>/dev/null
|
|
declare -F webuiRegistryCatalogScan >/dev/null 2>&1 && webuiRegistryCatalogScan
|
|
}
|