Merge claude/2
This commit is contained in:
commit
3675b6b34c
@ -52,6 +52,12 @@ cliHandleUpdaterCommands()
|
|||||||
source "$install_scripts_dir/webui/data/generators/updater/webui_artifact_scan.sh" 2>/dev/null
|
source "$install_scripts_dir/webui/data/generators/updater/webui_artifact_scan.sh" 2>/dev/null
|
||||||
fi
|
fi
|
||||||
declare -F webuiArtifactScan >/dev/null 2>&1 && webuiArtifactScan
|
declare -F webuiArtifactScan >/dev/null 2>&1 && webuiArtifactScan
|
||||||
|
# Registry catalog: refresh the App Center's marketplace data
|
||||||
|
# (the type:"app" rows of the same signed index).
|
||||||
|
if ! declare -F webuiRegistryCatalogScan >/dev/null 2>&1; then
|
||||||
|
source "$install_scripts_dir/webui/data/generators/apps/webui_registry_scan.sh" 2>/dev/null
|
||||||
|
fi
|
||||||
|
declare -F webuiRegistryCatalogScan >/dev/null 2>&1 && webuiRegistryCatalogScan
|
||||||
if ! declare -F artifactApplyAuto >/dev/null 2>&1; then
|
if ! declare -F artifactApplyAuto >/dev/null 2>&1; then
|
||||||
source "$install_scripts_dir/cli/commands/artifact/cli_artifact_apply.sh" 2>/dev/null
|
source "$install_scripts_dir/cli/commands/artifact/cli_artifact_apply.sh" 2>/dev/null
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -8,6 +8,7 @@ webui_scripts=(
|
|||||||
"webui/data/generators/apps/webui_app_status.sh"
|
"webui/data/generators/apps/webui_app_status.sh"
|
||||||
"webui/data/generators/apps/webui_config_patch.sh"
|
"webui/data/generators/apps/webui_config_patch.sh"
|
||||||
"webui/data/generators/apps/webui_config.sh"
|
"webui/data/generators/apps/webui_config.sh"
|
||||||
|
"webui/data/generators/apps/webui_registry_scan.sh"
|
||||||
"webui/data/generators/apps/webui_services.sh"
|
"webui/data/generators/apps/webui_services.sh"
|
||||||
"webui/data/generators/apps/webui_tools.sh"
|
"webui/data/generators/apps/webui_tools.sh"
|
||||||
"webui/data/generators/backup/webui_backup_app_status.sh"
|
"webui/data/generators/backup/webui_backup_app_status.sh"
|
||||||
|
|||||||
@ -943,6 +943,7 @@ declare -gA LP_FN_MAP=(
|
|||||||
[webuiPrintInstallCard]="webui/webui_display_logins.sh"
|
[webuiPrintInstallCard]="webui/webui_display_logins.sh"
|
||||||
[webuiPrintLoginBlock]="webui/webui_display_logins.sh"
|
[webuiPrintLoginBlock]="webui/webui_display_logins.sh"
|
||||||
[_webuiReadServiceTags]="webui/data/generators/apps/webui_config.sh"
|
[_webuiReadServiceTags]="webui/data/generators/apps/webui_config.sh"
|
||||||
|
[webuiRegistryCatalogScan]="webui/data/generators/apps/webui_registry_scan.sh"
|
||||||
[webuiRemoveSetupLock]="webui/data/lock/webui_remove_setup_lock.sh"
|
[webuiRemoveSetupLock]="webui/data/lock/webui_remove_setup_lock.sh"
|
||||||
[webuiRemoveUpdateLock]="webui/data/lock/webui_remove_update_lock.sh"
|
[webuiRemoveUpdateLock]="webui/data/lock/webui_remove_update_lock.sh"
|
||||||
[webuiRunUpdate]="update/check_update.sh"
|
[webuiRunUpdate]="update/check_update.sh"
|
||||||
@ -1908,6 +1909,7 @@ declare -gA LP_FN_ROOT=(
|
|||||||
[webuiPrintInstallCard]="scripts"
|
[webuiPrintInstallCard]="scripts"
|
||||||
[webuiPrintLoginBlock]="scripts"
|
[webuiPrintLoginBlock]="scripts"
|
||||||
[_webuiReadServiceTags]="scripts"
|
[_webuiReadServiceTags]="scripts"
|
||||||
|
[webuiRegistryCatalogScan]="scripts"
|
||||||
[webuiRemoveSetupLock]="scripts"
|
[webuiRemoveSetupLock]="scripts"
|
||||||
[webuiRemoveUpdateLock]="scripts"
|
[webuiRemoveUpdateLock]="scripts"
|
||||||
[webuiRunUpdate]="scripts"
|
[webuiRunUpdate]="scripts"
|
||||||
@ -2894,6 +2896,7 @@ webuiPatchAppConfigJson() { source "${install_scripts_dir}webui/data/generators/
|
|||||||
webuiPrintInstallCard() { source "${install_scripts_dir}webui/webui_display_logins.sh"; webuiPrintInstallCard "$@"; }
|
webuiPrintInstallCard() { source "${install_scripts_dir}webui/webui_display_logins.sh"; webuiPrintInstallCard "$@"; }
|
||||||
webuiPrintLoginBlock() { source "${install_scripts_dir}webui/webui_display_logins.sh"; webuiPrintLoginBlock "$@"; }
|
webuiPrintLoginBlock() { source "${install_scripts_dir}webui/webui_display_logins.sh"; webuiPrintLoginBlock "$@"; }
|
||||||
_webuiReadServiceTags() { source "${install_scripts_dir}webui/data/generators/apps/webui_config.sh"; _webuiReadServiceTags "$@"; }
|
_webuiReadServiceTags() { source "${install_scripts_dir}webui/data/generators/apps/webui_config.sh"; _webuiReadServiceTags "$@"; }
|
||||||
|
webuiRegistryCatalogScan() { source "${install_scripts_dir}webui/data/generators/apps/webui_registry_scan.sh"; webuiRegistryCatalogScan "$@"; }
|
||||||
webuiRemoveSetupLock() { source "${install_scripts_dir}webui/data/lock/webui_remove_setup_lock.sh"; webuiRemoveSetupLock "$@"; }
|
webuiRemoveSetupLock() { source "${install_scripts_dir}webui/data/lock/webui_remove_setup_lock.sh"; webuiRemoveSetupLock "$@"; }
|
||||||
webuiRemoveUpdateLock() { source "${install_scripts_dir}webui/data/lock/webui_remove_update_lock.sh"; webuiRemoveUpdateLock "$@"; }
|
webuiRemoveUpdateLock() { source "${install_scripts_dir}webui/data/lock/webui_remove_update_lock.sh"; webuiRemoveUpdateLock "$@"; }
|
||||||
webuiRunUpdate() { source "${install_scripts_dir}update/check_update.sh"; webuiRunUpdate "$@"; }
|
webuiRunUpdate() { source "${install_scripts_dir}update/check_update.sh"; webuiRunUpdate "$@"; }
|
||||||
|
|||||||
124
scripts/webui/data/generators/apps/webui_registry_scan.sh
Normal file
124
scripts/webui/data/generators/apps/webui_registry_scan.sh
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# WebUI registry-catalog data generator (the marketplace browse data)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Writes the read-only JSON the App Center merges into its grid as
|
||||||
|
# "Available — Add" cards:
|
||||||
|
# frontend/data/apps/generated/registry_catalog.json
|
||||||
|
#
|
||||||
|
# It fetches + verifies the signed artifact index (lpFetchIndexInto), selects
|
||||||
|
# the type:"app" / payload.kind:"bundle" envelopes, annotates each with
|
||||||
|
# `defined` (a definition exists in the install tree) and `installed` (a live
|
||||||
|
# dir exists), and mirrors each catalog icon into
|
||||||
|
# frontend/core/icons/apps/registry/<slug>.<ext>
|
||||||
|
# only when it matches the sha256 pin in the signed index — the browser is
|
||||||
|
# never pointed at a remote host (same-origin only). Written ATOMICALLY
|
||||||
|
# (temp -> validate -> one runFileWrite); on ANY fetch/verify failure the
|
||||||
|
# prior file is KEPT. Run by `libreportal updater check`.
|
||||||
|
|
||||||
|
webuiRegistryCatalogScan() {
|
||||||
|
local out_dir="${containers_dir%/}/libreportal/frontend/data/apps/generated"
|
||||||
|
local out="$out_dir/registry_catalog.json"
|
||||||
|
local icon_dir="${containers_dir%/}/libreportal/frontend/core/icons/apps/registry"
|
||||||
|
local icon_web="/core/icons/apps/registry"
|
||||||
|
local max_icon=262144
|
||||||
|
runFileOp mkdir -p "$out_dir" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Lazy-loader gap: ensure the read primitives are present.
|
||||||
|
if ! declare -F lpFetchIndex >/dev/null 2>&1; then
|
||||||
|
source "$install_scripts_dir/source/fetch.sh" 2>/dev/null
|
||||||
|
source "$install_scripts_dir/source/artifacts.sh" 2>/dev/null
|
||||||
|
fi
|
||||||
|
if ! command -v jq >/dev/null 2>&1; then
|
||||||
|
isNotice "webuiRegistryCatalogScan: jq not available — keeping the prior registry_catalog.json."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local index
|
||||||
|
if ! lpFetchIndexInto index; then
|
||||||
|
isNotice "webuiRegistryCatalogScan: no verified index available — keeping the prior file."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
local signed="false"; [[ "$LP_INDEX_SIGSTATE" == "verified" ]] && signed="true"
|
||||||
|
local serial now
|
||||||
|
serial="$(_lpJsonNum "$index" index_serial)"
|
||||||
|
now="$(date -Iseconds 2>/dev/null || date)"
|
||||||
|
|
||||||
|
# Defined apps = definition dirs in the install tree; installed = live dirs.
|
||||||
|
local defined="[]" installed="[]" d
|
||||||
|
if [[ -d "$install_containers_dir" ]]; then
|
||||||
|
defined="$(for d in "$install_containers_dir"/*/; do [[ -d "$d" ]] && basename "$d"; done | jq -R . | jq -cs .)"
|
||||||
|
fi
|
||||||
|
if [[ -d "$containers_dir" ]]; then
|
||||||
|
installed="$(for d in "$containers_dir"/*/; do [[ -d "$d" ]] && basename "$d"; done | jq -R . | jq -cs .)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Mirror the pinned catalog icons locally (slug -> local web path). An icon
|
||||||
|
# is used only if its bytes match the sha256 the signed index pins — a
|
||||||
|
# tampered or oversized icon is simply skipped, never served.
|
||||||
|
local icons_map="{}" base rows
|
||||||
|
base="$(lpReleaseBaseUrl)"
|
||||||
|
rows="$(printf '%s' "$index" | jq -r '
|
||||||
|
.artifacts[]? | select(.type=="app" and .payload.kind=="bundle")
|
||||||
|
| select((.meta.icon // "") != "" and (.meta.icon_sha256 // "") != "")
|
||||||
|
| [(.applies_when.app // ""), .meta.icon, .meta.icon_sha256] | @tsv' 2>/dev/null)"
|
||||||
|
if [[ -n "$rows" ]]; then
|
||||||
|
runFileOp mkdir -p "$icon_dir" 2>/dev/null || true
|
||||||
|
local slug icon pin ext url tmpf dest got size
|
||||||
|
while IFS=$'\t' read -r slug icon pin; do
|
||||||
|
[[ "$slug" =~ ^[a-z0-9][a-z0-9_]{0,31}$ ]] || continue
|
||||||
|
ext="${icon##*.}"
|
||||||
|
case "$ext" in svg|png) : ;; *) continue ;; esac
|
||||||
|
dest="$icon_dir/$slug.$ext"
|
||||||
|
if [[ -f "$dest" && "$(_lpSha256 "$dest")" == "$pin" ]]; then
|
||||||
|
icons_map="$(jq -c --arg s "$slug" --arg p "$icon_web/$slug.$ext" '.[$s]=$p' <<<"$icons_map")"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
url="$icon"; case "$url" in http*://*) : ;; *) url="$base/$url" ;; esac
|
||||||
|
tmpf="$(mktemp)"
|
||||||
|
if _lpDownload "$url" "$tmpf" 2>/dev/null; then
|
||||||
|
got="$(_lpSha256 "$tmpf")"
|
||||||
|
size="$(stat -c %s "$tmpf" 2>/dev/null || echo 0)"
|
||||||
|
if [[ "$got" == "$pin" ]] && (( size > 0 && size <= max_icon )); then
|
||||||
|
runFileWrite "$dest" < "$tmpf"
|
||||||
|
runFileOp chown "$docker_install_user":"$docker_install_user" "$dest" 2>/dev/null || true
|
||||||
|
icons_map="$(jq -c --arg s "$slug" --arg p "$icon_web/$slug.$ext" '.[$s]=$p' <<<"$icons_map")"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
rm -f "$tmpf"
|
||||||
|
done <<<"$rows"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local tmp; tmp="$(mktemp)"
|
||||||
|
printf '%s' "$index" | jq \
|
||||||
|
--arg now "$now" --arg signed "$signed" --arg serial "${serial:-0}" \
|
||||||
|
--argjson defined "$defined" --argjson installed "$installed" --argjson icons "$icons_map" '
|
||||||
|
{ generated_at: $now,
|
||||||
|
signed: ($signed=="true"),
|
||||||
|
serial: ($serial|tonumber? // 0),
|
||||||
|
apps: [ .artifacts[]? | select(.type=="app" and .payload.kind=="bundle")
|
||||||
|
| (.applies_when.app // "") as $slug | select($slug != "")
|
||||||
|
| { id,
|
||||||
|
app: $slug,
|
||||||
|
version: (.version // 1),
|
||||||
|
title: (.title // $slug),
|
||||||
|
why: (.why // ""),
|
||||||
|
publisher: (.publisher // ""),
|
||||||
|
trust: (.trust // "official"),
|
||||||
|
category: (.meta.category // ""),
|
||||||
|
description: (.meta.description // .why // ""),
|
||||||
|
long_description: (.meta.long_description // ""),
|
||||||
|
icon: ($icons[$slug] // null),
|
||||||
|
defined: (($defined | index($slug)) != null),
|
||||||
|
installed: (($installed | index($slug)) != null) } ] }' > "$tmp" 2>/dev/null
|
||||||
|
|
||||||
|
if ! jq empty "$tmp" 2>/dev/null; then
|
||||||
|
isNotice "webuiRegistryCatalogScan: generated JSON was invalid — keeping the prior file."
|
||||||
|
rm -f "$tmp"; return 1
|
||||||
|
fi
|
||||||
|
runFileWrite "$out" < "$tmp"
|
||||||
|
rm -f "$tmp"
|
||||||
|
runFileOp chown "$docker_install_user":"$docker_install_user" "$out" 2>/dev/null || true
|
||||||
|
local n; n="$(jq '.apps | length' "$out" 2>/dev/null || echo '?')"
|
||||||
|
isSuccessful "Registry catalog refreshed ($n app(s), serial=${serial:-?}, signed=$signed)."
|
||||||
|
}
|
||||||
@ -49,6 +49,13 @@ webuiArtifactScan() {
|
|||||||
installed="$(for d in "$containers_dir"/*/; do [[ -d "$d" ]] && basename "$d"; done | jq -R . | jq -cs .)"
|
installed="$(for d in "$containers_dir"/*/; do [[ -d "$d" ]] && basename "$d"; done | jq -R . | jq -cs .)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# The Improvements stream is HOTFIX-only. type:"app" rows belong to the
|
||||||
|
# registry catalog (webuiRegistryCatalogScan); anything else is a newer
|
||||||
|
# format this build doesn't know — skip + log, never error (§8.1 firewall).
|
||||||
|
local unknown
|
||||||
|
unknown="$(printf '%s' "$index" | jq '[.artifacts[]? | (.type // "") | select(. != "hotfix" and . != "app")] | length' 2>/dev/null || echo 0)"
|
||||||
|
[[ "$unknown" =~ ^[0-9]+$ ]] && (( unknown > 0 )) && isNotice "webuiArtifactScan: skipped $unknown artifact(s) of unrecognized type (newer format?)."
|
||||||
|
|
||||||
local tmp; tmp="$(mktemp)"
|
local tmp; tmp="$(mktemp)"
|
||||||
printf '%s' "$index" | jq \
|
printf '%s' "$index" | jq \
|
||||||
--arg now "$now" --arg signed "$signed" --arg serial "${serial:-0}" \
|
--arg now "$now" --arg signed "$signed" --arg serial "${serial:-0}" \
|
||||||
@ -56,7 +63,7 @@ webuiArtifactScan() {
|
|||||||
{ generated_at: $now,
|
{ generated_at: $now,
|
||||||
signed: ($signed=="true"),
|
signed: ($signed=="true"),
|
||||||
serial: ($serial|tonumber? // 0),
|
serial: ($serial|tonumber? // 0),
|
||||||
artifacts: [ .artifacts[]? | {
|
artifacts: [ .artifacts[]? | select(.type=="hotfix") | {
|
||||||
id, type,
|
id, type,
|
||||||
severity: (.severity // "tweak"),
|
severity: (.severity // "tweak"),
|
||||||
auto: (.auto // false),
|
auto: (.auto // false),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user