Skip to content

Commit 7c896d3

Browse files
committed
Keep a web app name out of the launcher's directory structure
The app name becomes a filename, and omarchy-webapp-install ran `mkdir -p "$(dirname "$DESKTOP_FILE")"` over it, so every slash turned into a directory level. Typing a URL into the Name field -- the reported way in -- wrote the launcher to `~/.local/share/applications/http:/127.0.0.1:4000/.desktop`. Removal could then never reach it. The picker lists the file but displays a name derived from the path, and the removal rebuilt a flat `$DESKTOP_DIR/$APP_NAME.desktop` from that name, so `rm -f` deleted nothing and the app stayed in the launcher with no error. Refuse a name containing a slash rather than silently renaming what the user typed, and delete the file the scan actually found instead of a path rebuilt from its display name. The second half also clears up whatever earlier versions nested, which a reconstructed path cannot address.
1 parent 43bfe9b commit 7c896d3

3 files changed

Lines changed: 98 additions & 9 deletions

File tree

bin/omarchy-webapp-install

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,15 @@ if [[ -z $APP_NAME || -z $APP_URL ]]; then
104104
exit 1
105105
fi
106106

107+
# The name becomes a filename. A slash would turn it into directory levels, so
108+
# the launcher lands somewhere omarchy-webapp-remove cannot address and the app
109+
# is stuck in the launcher. Refuse rather than silently renaming what the user
110+
# typed -- most often it is a URL entered in the name field.
111+
if [[ $APP_NAME == */* ]]; then
112+
echo "App name cannot contain '/': $APP_NAME"
113+
exit 1
114+
fi
115+
107116
if [[ -z $ICON_REF ]]; then
108117
ICON_VALUE=$(safe_icon_name "$APP_NAME")
109118
mkdir -p "$ICON_DIR"
@@ -132,8 +141,9 @@ fi
132141
EXEC_COMMAND="${CUSTOM_EXEC:-omarchy-launch-webapp $APP_URL}"
133142

134143
# Create application .desktop file
135-
DESKTOP_FILE="$HOME/.local/share/applications/$APP_NAME.desktop"
136-
mkdir -p "$(dirname "$DESKTOP_FILE")"
144+
DESKTOP_DIR="$HOME/.local/share/applications"
145+
DESKTOP_FILE="$DESKTOP_DIR/$APP_NAME.desktop"
146+
mkdir -p "$DESKTOP_DIR"
137147

138148
cat >"$DESKTOP_FILE" <<EOF
139149
[Desktop Entry]

bin/omarchy-webapp-remove

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,31 @@ ICON_DIR="$HOME/.local/share/icons/hicolor/256x256/apps"
99
OLD_ICON_DIR="$HOME/.local/share/applications/icons"
1010
DESKTOP_DIR="$HOME/.local/share/applications/"
1111

12-
if (( $# == 0 )); then
13-
# Find all web apps
14-
while IFS= read -r -d '' file; do
15-
if grep -q '^Exec=.*\(omarchy-launch-webapp\|omarchy-webapp-handler\).*' "$file"; then
16-
WEB_APPS+=("$(basename "${file%.desktop}")")
12+
# Always index the launchers, so removal deletes the file that was found rather
13+
# than a path rebuilt from the displayed name. Installs predating the name
14+
# validation could nest the launcher inside directories, and those are exactly
15+
# the ones a reconstructed path cannot reach.
16+
WEB_APP_PATHS=()
17+
while IFS= read -r -d '' file; do
18+
if grep -q '^Exec=.*\(omarchy-launch-webapp\|omarchy-webapp-handler\).*' "$file"; then
19+
WEB_APPS+=("$(basename "${file%.desktop}")")
20+
WEB_APP_PATHS+=("$file")
21+
fi
22+
done < <(find "$DESKTOP_DIR" -name '*.desktop' -print0)
23+
24+
# The launcher matching a chosen name, or empty when nothing was indexed under
25+
# it (an app removed between the scan and the pick, say).
26+
path_for_web_app() {
27+
local wanted="$1" i
28+
for i in "${!WEB_APPS[@]}"; do
29+
if [[ ${WEB_APPS[$i]} == "$wanted" ]]; then
30+
printf '%s\n' "${WEB_APP_PATHS[$i]}"
31+
return 0
1732
fi
18-
done < <(find "$DESKTOP_DIR" -name '*.desktop' -print0)
33+
done
34+
}
1935

36+
if (( $# == 0 )); then
2037
if ((${#WEB_APPS[@]})); then
2138
mapfile -t SORTED_WEB_APPS < <(printf '%s\n' "${WEB_APPS[@]}" | sort)
2239
APP_NAME=$(omarchy-menu-select "Select web app to remove" "${SORTED_WEB_APPS[@]}" -- --width 520 --maxheight 520)
@@ -34,7 +51,8 @@ if [[ -z $APP_NAME ]]; then
3451
fi
3552

3653
icon_name=$(printf '%s\n' "$APP_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^[:alnum:]]\+/-/g; s/^-//; s/-$//')
37-
rm -f "$DESKTOP_DIR/$APP_NAME.desktop"
54+
desktop_file=$(path_for_web_app "$APP_NAME")
55+
rm -f "${desktop_file:-$DESKTOP_DIR/$APP_NAME.desktop}"
3856
rm -f "$ICON_DIR/$icon_name.png" "$ICON_DIR/$APP_NAME.png" "$OLD_ICON_DIR/$APP_NAME.png"
3957

4058
if [[ ${OMARCHY_REMOVE_NOTIFY:-true} != "false" ]]; then

test/shell.d/webapp-name-test.sh

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
6+
7+
tmp_dir=$(mktemp -d)
8+
trap 'rm -rf "$tmp_dir"' EXIT
9+
mkdir -p "$tmp_dir/bin" "$tmp_dir/home"
10+
11+
for stub in gtk-update-icon-cache update-desktop-database omarchy-notification-send; do
12+
printf '#!/bin/bash\n:\n' >"$tmp_dir/bin/$stub"
13+
chmod +x "$tmp_dir/bin/$stub"
14+
done
15+
16+
run_install() {
17+
HOME="$tmp_dir/home" PATH="$tmp_dir/bin:$PATH" \
18+
"$ROOT/bin/omarchy-webapp-install" "$@"
19+
}
20+
21+
run_remove() {
22+
HOME="$tmp_dir/home" PATH="$tmp_dir/bin:$PATH" OMARCHY_REMOVE_NOTIFY=false \
23+
"$ROOT/bin/omarchy-webapp-remove" "$@"
24+
}
25+
26+
apps_dir="$tmp_dir/home/.local/share/applications"
27+
28+
# A URL typed into the name field is the reported way in. Every slash used to
29+
# become a directory level, leaving a launcher nothing could address.
30+
if run_install "http://example.test/oops" "https://example.com" hey >/dev/null 2>&1; then
31+
fail "webapp install rejects a name containing a slash"
32+
fi
33+
[[ -e "$apps_dir/http:" ]] &&
34+
fail "webapp install does not create a directory from a slashed name"
35+
pass "webapp install rejects a name that would nest the launcher"
36+
37+
# A normal name still installs and removes.
38+
run_install "Example App" "https://example.com" hey >/dev/null
39+
[[ -f "$apps_dir/Example App.desktop" ]] ||
40+
fail "webapp install writes the launcher for an ordinary name"
41+
run_remove "Example App" >/dev/null
42+
[[ -f "$apps_dir/Example App.desktop" ]] &&
43+
fail "webapp remove deletes the launcher it installed"
44+
pass "webapp install and remove round-trip an ordinary name"
45+
46+
# Anything installed by an older version can still be nested. Removal has to
47+
# reach it, which a path rebuilt from the displayed name never could.
48+
mkdir -p "$apps_dir/http:/127.0.0.1:4000"
49+
cat >"$apps_dir/http:/127.0.0.1:4000/.desktop" <<'DESKTOP'
50+
[Desktop Entry]
51+
Name=http://127.0.0.1:4000
52+
Exec=omarchy-launch-webapp https://127.0.0.1:4000
53+
Type=Application
54+
DESKTOP
55+
56+
# This is the name the picker shows for that file: the script strips .desktop
57+
# from the path and then takes the basename, which lands on the directory.
58+
run_remove "127.0.0.1:4000" >/dev/null
59+
[[ -f "$apps_dir/http:/127.0.0.1:4000/.desktop" ]] &&
60+
fail "webapp remove deletes a launcher left nested by an older install"
61+
pass "webapp remove reaches a nested legacy launcher"

0 commit comments

Comments
 (0)