The slash guard was the only thing keeping a name out of the directory structure, and nothing tested it: deleting it left the suite green, because creating the launcher directly in the applications directory already makes the redirect fail on its own, with a raw bash error instead of the message. The assertion is on the message now, alongside the traversal case the guard actually closes -- on quattro a name of `../../../../escaped` writes its launcher clean outside the applications directory. The interactive prompt read the name, fetched the favicon, wrote it and updated the icon cache before the name was ever checked, so a URL typed into the Name field left an icon behind on every attempt. Validating as soon as the name is read covers both paths from one place. Removing by name also scanned unconditionally, so a machine with no applications directory printed a find error where omarchy-remove-gaming-xbox-cloud does not hide stderr. 🤖 Generated by Opus 5 in Claude Code. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
62 lines
2.0 KiB
Bash
Executable File
62 lines
2.0 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# omarchy:summary=Remove a web app desktop launcher
|
|
# omarchy:args=[name]
|
|
|
|
set -e
|
|
|
|
ICON_DIR="$HOME/.local/share/icons/hicolor/256x256/apps"
|
|
OLD_ICON_DIR="$HOME/.local/share/applications/icons"
|
|
DESKTOP_DIR="$HOME/.local/share/applications/"
|
|
|
|
# Always index the launchers, so removal deletes the file that was found rather
|
|
# than a path rebuilt from the displayed name. Installs predating the name
|
|
# validation could nest the launcher inside directories, and those are exactly
|
|
# the ones a reconstructed path cannot reach.
|
|
WEB_APP_PATHS=()
|
|
while IFS= read -r -d '' file; do
|
|
if grep -q '^Exec=.*\(omarchy-launch-webapp\|omarchy-webapp-handler\).*' "$file"; then
|
|
WEB_APPS+=("$(basename "${file%.desktop}")")
|
|
WEB_APP_PATHS+=("$file")
|
|
fi
|
|
done < <(find "$DESKTOP_DIR" -name '*.desktop' -print0 2>/dev/null)
|
|
|
|
# The launcher matching a chosen name, or empty when nothing was indexed under
|
|
# it (an app removed between the scan and the pick, say).
|
|
path_for_web_app() {
|
|
local wanted="$1" i
|
|
for i in "${!WEB_APPS[@]}"; do
|
|
if [[ ${WEB_APPS[$i]} == "$wanted" ]]; then
|
|
printf '%s\n' "${WEB_APP_PATHS[$i]}"
|
|
return 0
|
|
fi
|
|
done
|
|
}
|
|
|
|
if (( $# == 0 )); then
|
|
if ((${#WEB_APPS[@]})); then
|
|
mapfile -t SORTED_WEB_APPS < <(printf '%s\n' "${WEB_APPS[@]}" | sort)
|
|
APP_NAME=$(omarchy-menu-select "Select web app to remove" "${SORTED_WEB_APPS[@]}" -- --width 520 --maxheight 520)
|
|
else
|
|
echo "No web apps to remove."
|
|
exit 1
|
|
fi
|
|
else
|
|
APP_NAME="$*"
|
|
fi
|
|
|
|
if [[ -z $APP_NAME ]]; then
|
|
echo "You must select a web app to remove."
|
|
exit 1
|
|
fi
|
|
|
|
icon_name=$(printf '%s\n' "$APP_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^[:alnum:]]\+/-/g; s/^-//; s/-$//')
|
|
desktop_file=$(path_for_web_app "$APP_NAME")
|
|
rm -f "${desktop_file:-$DESKTOP_DIR/$APP_NAME.desktop}"
|
|
rm -f "$ICON_DIR/$icon_name.png" "$ICON_DIR/$APP_NAME.png" "$OLD_ICON_DIR/$APP_NAME.png"
|
|
|
|
if [[ ${OMARCHY_REMOVE_NOTIFY:-true} != "false" ]]; then
|
|
omarchy-notification-send -g "Web app removed" "$APP_NAME"
|
|
fi
|
|
update-desktop-database "$DESKTOP_DIR" &>/dev/null
|