Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 55 additions & 14 deletions ee/maintained-apps/ingesters/winget/ingester.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,12 +348,26 @@ func (i *wingetIngester) ingestOne(ctx context.Context, input inputApp) (*mainta
}

// TODO - consider UpgradeCode here?
existsTemplate := "SELECT 1 FROM programs WHERE name = '%s' AND publisher = '%s';"
if input.FuzzyMatchName {
existsTemplate = "SELECT 1 FROM programs WHERE name LIKE '%s %%' AND publisher = '%s';"
var existsQuery string
switch {
case input.FuzzyMatchName.Custom != "":
existsQuery = fmt.Sprintf(
"SELECT 1 FROM programs WHERE name LIKE '%s' AND publisher = '%s';",
input.FuzzyMatchName.Custom, publisher,
)
case input.FuzzyMatchName.Enabled:
existsQuery = fmt.Sprintf(
"SELECT 1 FROM programs WHERE name LIKE '%s %%' AND publisher = '%s';",
name, publisher,
)
default:
existsQuery = fmt.Sprintf(
"SELECT 1 FROM programs WHERE name = '%s' AND publisher = '%s';",
name, publisher,
)
Comment on lines +351 to +367
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Escape SQL literals before composing existsQuery.

Line 355, Line 360, and Line 365 interpolate raw strings into SQL literals. A single quote in publisher, name, or custom pattern can break the query (and can become injection-prone). Please escape values before formatting.

Suggested fix
 	// TODO - consider UpgradeCode here?
 	var existsQuery string
+	sqlEscape := func(v string) string {
+		return strings.ReplaceAll(v, "'", "''")
+	}
+	safeName := sqlEscape(name)
+	safePublisher := sqlEscape(publisher)
 	switch {
 	case input.FuzzyMatchName.Custom != "":
 		existsQuery = fmt.Sprintf(
 			"SELECT 1 FROM programs WHERE name LIKE '%s' AND publisher = '%s';",
-			input.FuzzyMatchName.Custom, publisher,
+			sqlEscape(input.FuzzyMatchName.Custom), safePublisher,
 		)
 	case input.FuzzyMatchName.Enabled:
 		existsQuery = fmt.Sprintf(
 			"SELECT 1 FROM programs WHERE name LIKE '%s %%' AND publisher = '%s';",
-			name, publisher,
+			safeName, safePublisher,
 		)
 	default:
 		existsQuery = fmt.Sprintf(
 			"SELECT 1 FROM programs WHERE name = '%s' AND publisher = '%s';",
-			name, publisher,
+			safeName, safePublisher,
 		)
 	}

As per coding guidelines, "Review all SQL queries for possible SQL injection."

Also applies to: 370-370

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ee/maintained-apps/ingesters/winget/ingester.go` around lines 351 - 367, The
existsQuery construction currently injects raw values
(input.FuzzyMatchName.Custom, name, publisher) into SQL via fmt.Sprintf
(existsQuery), which allows quotes/injection; change to use parameterized
queries instead of interpolation: build the SQL with placeholders (e.g., "SELECT
1 FROM programs WHERE name LIKE ? AND publisher = ?" or the driver-specific
$1/$2 style) for the three branches (the cases for input.FuzzyMatchName.Custom,
input.FuzzyMatchName.Enabled, and default) and pass the corresponding arguments
when executing the query (the code that uses existsQuery should call
db.QueryRow/Query with the args), or if you must keep string composition,
properly escape single quotes in the values before inserting; update the code
paths that execute existsQuery accordingly so no raw name/publisher/custom
strings are interpolated.

}
out.Queries = maintained_apps.FMAQueries{
Exists: fmt.Sprintf(existsTemplate, name, publisher),
Exists: existsQuery,
}
out.InstallScript = installScript
processedUninstallScript, err := preProcessUninstallScript(uninstallScript, productCode)
Expand Down Expand Up @@ -433,23 +447,50 @@ func isFileType(installerType string) bool {
return ok
}

// fuzzyMatch supports three JSON representations:
// - false (or omitted): exact match on programs.name
// - true: automatic LIKE pattern "name LIKE '<unique_identifier> %'"
// - "<pattern>": a custom LIKE pattern used verbatim, e.g. "Mozilla Firefox % ESR %"
type fuzzyMatch struct {
Enabled bool // true when the JSON value is the boolean `true`
Custom string // non-empty when the JSON value is a string pattern
}

func (f *fuzzyMatch) UnmarshalJSON(data []byte) error {
// Try boolean first (handles true, false, and omitted-via-zero-value).
var b bool
if err := json.Unmarshal(data, &b); err == nil {
f.Enabled = b
f.Custom = ""
return nil
}
// Try string.
var s string
if err := json.Unmarshal(data, &s); err == nil {
f.Custom = s
f.Enabled = s != ""
return nil
}
return fmt.Errorf("fuzzy_match_name must be a boolean or a string, got %s", string(data))
}

type inputApp struct {
Name string `json:"name"`
Slug string `json:"slug"`
// PackageIdentifier is the identifier used by winget. It's composed of a vendor part (e.g.
// AgileBits) and an app part (e.g. 1Password), joined by a "."
PackageIdentifier string `json:"package_identifier"`
// The value matching programs.name for the primary app package in osquery
UniqueIdentifier string `json:"unique_identifier"`
InstallScriptPath string `json:"install_script_path"`
UninstallScriptPath string `json:"uninstall_script_path"`
InstallerArch string `json:"installer_arch"`
InstallerType string `json:"installer_type"`
InstallerScope string `json:"installer_scope"`
InstallerLocale string `json:"installer_locale"`
ProgramPublisher string `json:"program_publisher"`
UninstallType string `json:"uninstall_type"`
FuzzyMatchName bool `json:"fuzzy_match_name"`
UniqueIdentifier string `json:"unique_identifier"`
InstallScriptPath string `json:"install_script_path"`
UninstallScriptPath string `json:"uninstall_script_path"`
InstallerArch string `json:"installer_arch"`
InstallerType string `json:"installer_type"`
InstallerScope string `json:"installer_scope"`
InstallerLocale string `json:"installer_locale"`
ProgramPublisher string `json:"program_publisher"`
UninstallType string `json:"uninstall_type"`
FuzzyMatchName fuzzyMatch `json:"fuzzy_match_name"`
// Whether to use "no_check" instead of the app's hash (e.g. for non-pinned download URLs)
IgnoreHash bool `json:"ignore_hash"`
DefaultCategories []string `json:"default_categories"`
Expand Down
68 changes: 68 additions & 0 deletions ee/maintained-apps/ingesters/winget/ingester_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,80 @@
package winget

import (
"encoding/json"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestFuzzyMatchUnmarshalJSON(t *testing.T) {
tests := []struct {
name string
input string
wantEnabled bool
wantCustom string
wantErr bool
}{
{
name: "boolean true",
input: `{"fuzzy_match_name": true}`,
wantEnabled: true,
wantCustom: "",
},
{
name: "boolean false",
input: `{"fuzzy_match_name": false}`,
wantEnabled: false,
wantCustom: "",
},
{
name: "omitted defaults to disabled",
input: `{}`,
wantEnabled: false,
wantCustom: "",
},
{
name: "custom LIKE pattern string",
input: `{"fuzzy_match_name": "Mozilla Firefox % ESR %"}`,
wantEnabled: true,
wantCustom: "Mozilla Firefox % ESR %",
},
{
name: "empty string treated as disabled",
input: `{"fuzzy_match_name": ""}`,
wantEnabled: false,
wantCustom: "",
},
{
name: "invalid type (number)",
input: `{"fuzzy_match_name": 42}`,
wantErr: true,
},
{
name: "invalid type (array)",
input: `{"fuzzy_match_name": [1,2]}`,
wantErr: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var out struct {
FuzzyMatchName fuzzyMatch `json:"fuzzy_match_name"`
}
err := json.Unmarshal([]byte(tt.input), &out)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
assert.Equal(t, tt.wantEnabled, out.FuzzyMatchName.Enabled)
assert.Equal(t, tt.wantCustom, out.FuzzyMatchName.Custom)
})
}
}

func TestBuildUpgradeCodeBasedUninstallScript(t *testing.T) {
tests := []struct {
name string
Expand Down
2 changes: 1 addition & 1 deletion ee/maintained-apps/inputs/homebrew/abstract.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Abstract",
"unique_identifier": "com.SweetScape.010Editor",
"unique_identifier": "com.elasticprojects.abstract-desktop",
"token": "abstract",
"installer_format": "zip",
"slug": "abstract/darwin",
Expand Down
8 changes: 3 additions & 5 deletions ee/maintained-apps/inputs/homebrew/teleport-suite.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
{
"name": "Teleport Suite",
"unique_identifier": "com.gravitational.teleport",
"unique_identifier": "com.gravitational.teleport.tsh",
"token": "teleport-suite",
"installer_format": "pkg",
"slug": "teleport-suite/darwin",
"default_categories": [
"Developer tools"
],
"default_categories": ["Developer tools"],
"uninstall_script_path": "ee/maintained-apps/inputs/homebrew/scripts/teleport-suite-uninstall.sh"
}
}
3 changes: 2 additions & 1 deletion ee/maintained-apps/inputs/winget/010-editor.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"name": "010 Editor",
"slug": "010-editor/windows",
"package_identifier": "SweetScape.010Editor",
"unique_identifier": "010 Editor 16.0.2 (64-bit)",
"unique_identifier": "010 Editor",
"fuzzy_match_name": true,
"installer_arch": "x64",
"installer_type": "exe",
"installer_scope": "machine",
Expand Down
3 changes: 2 additions & 1 deletion ee/maintained-apps/inputs/winget/7-zip.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"name": "7-zip",
"slug": "7-zip/windows",
"package_identifier": "7zip.7zip",
"unique_identifier": "7-Zip 25.01 (x64)",
"unique_identifier": "7-Zip",
"fuzzy_match_name": true,
"installer_arch": "x64",
"installer_type": "msi",
"installer_scope": "machine",
Expand Down
3 changes: 2 additions & 1 deletion ee/maintained-apps/inputs/winget/airtame.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"name": "Airtame",
"slug": "airtame/windows",
"package_identifier": "Airtame.Airtame",
"unique_identifier": "Airtame 4.15.0",
"unique_identifier": "Airtame",
"fuzzy_match_name": true,
"installer_arch": "x86",
"installer_type": "exe",
"installer_scope": "machine",
Expand Down
3 changes: 2 additions & 1 deletion ee/maintained-apps/inputs/winget/firefox@esr.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"name": "Mozilla Firefox ESR",
"slug": "firefox@esr/windows",
"package_identifier": "Mozilla.Firefox.ESR",
"unique_identifier": "Mozilla Firefox 140.7.1 ESR (x64 en-US)",
"unique_identifier": "Mozilla Firefox ESR",
"fuzzy_match_name": "Mozilla Firefox % ESR %",
"install_script_path": "ee/maintained-apps/inputs/winget/scripts/firefox_esr_install.ps1",
"uninstall_script_path": "ee/maintained-apps/inputs/winget/scripts/firefox_esr_uninstall.ps1",
"installer_arch": "x64",
Expand Down
3 changes: 2 additions & 1 deletion ee/maintained-apps/inputs/winget/gimp.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"name": "GIMP",
"slug": "gimp/windows",
"package_identifier": "GIMP.GIMP.3",
"unique_identifier": "GIMP 3.0.8-2",
"unique_identifier": "GIMP",
"fuzzy_match_name": true,
"install_script_path": "ee/maintained-apps/inputs/winget/scripts/gimp_install.ps1",
"uninstall_script_path": "ee/maintained-apps/inputs/winget/scripts/gimp_uninstall.ps1",
"installer_arch": "x64",
Expand Down
3 changes: 2 additions & 1 deletion ee/maintained-apps/inputs/winget/notion.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"name": "Notion",
"slug": "notion/windows",
"package_identifier": "Notion.Notion",
"unique_identifier": "Notion 6.1.0",
"unique_identifier": "Notion",
"fuzzy_match_name": true,
"installer_arch": "x64",
"installer_type": "exe",
"installer_scope": "user",
Expand Down
3 changes: 2 additions & 1 deletion ee/maintained-apps/inputs/winget/postman.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"name": "Postman",
"slug": "postman/windows",
"package_identifier": "Postman.Postman",
"unique_identifier": "Postman x64 11.75.4",
"unique_identifier": "Postman x64",
"fuzzy_match_name": true,
"installer_arch": "x64",
"installer_type": "exe",
"installer_scope": "user",
Expand Down
3 changes: 2 additions & 1 deletion ee/maintained-apps/inputs/winget/putty.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"name": "PuTTY",
"slug": "putty/windows",
"package_identifier": "PuTTY.PuTTY",
"unique_identifier": "PuTTY release 0.83 (x64)",
"unique_identifier": "PuTTY release",
"fuzzy_match_name": true,
"installer_arch": "x64",
"installer_type": "msi",
"installer_scope": "machine",
Expand Down
6 changes: 2 additions & 4 deletions ee/maintained-apps/outputs/010-editor/windows.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
{
"version": "16.0.4",
"queries": {
"exists": "SELECT 1 FROM programs WHERE name = '010 Editor 16.0.2 (64-bit)' AND publisher = 'SweetScape Software';",
"exists": "SELECT 1 FROM programs WHERE name LIKE '010 Editor %' AND publisher = 'SweetScape Software';",
"patch": ""
},
"installer_url": "https://download.sweetscape.com/010EditorWin64Installer16.0.4.exe",
"install_script_ref": "5764f801",
"uninstall_script_ref": "07227ac7",
"sha256": "36bae5d17aac1919ac3b66ce22954794b36a058b459290440a7fed9ff2b379be",
"default_categories": [
"Developer tools"
]
"default_categories": ["Developer tools"]
}
],
"refs": {
Expand Down
6 changes: 2 additions & 4 deletions ee/maintained-apps/outputs/7-zip/windows.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
{
"version": "26.00",
"queries": {
"exists": "SELECT 1 FROM programs WHERE name = '7-Zip 25.01 (x64)' AND publisher = 'Igor Pavlov';",
"exists": "SELECT 1 FROM programs WHERE name LIKE '7-Zip %' AND publisher = 'Igor Pavlov';",
"patch": ""
},
"installer_url": "https://7-zip.org/a/7z2600-x64.msi",
"install_script_ref": "8959087b",
"uninstall_script_ref": "a94a6acc",
"sha256": "c388d0444871ca11b21237001af158cfddad7e137851795e5b65cee69b518495",
"default_categories": [
"Productivity"
],
"default_categories": ["Productivity"],
"upgrade_code": "{23170F69-40C1-2702-0000-000004000000}"
}
],
Expand Down
8 changes: 3 additions & 5 deletions ee/maintained-apps/outputs/abstract/darwin.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,18 @@
{
"version": "98.6.3",
"queries": {
"exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.SweetScape.010Editor';",
"exists": "SELECT 1 FROM apps WHERE bundle_identifier = 'com.elasticprojects.abstract-desktop';",
"patch": ""
},
"installer_url": "https://downloads.goabstract.com/mac/Abstract-98.6.3.zip",
"install_script_ref": "40f16970",
"uninstall_script_ref": "e76ec506",
"sha256": "9bccf9b6a748039f69bb28f7aec453dc236035caf9cfba131fba92aeeaaca060",
"default_categories": [
"Productivity"
]
"default_categories": ["Productivity"]
}
],
"refs": {
"40f16970": "#!/bin/sh\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath $INSTALLER_PATH)\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n if ! osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ $EUID -eq 0 && \"$console_user\" == \"root\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ $EUID -eq 0 && \"$console_user\" == \"root\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Try to launch the application\n if osascript -e \"tell application id \\\"$bundle_id\\\" to activate\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'com.SweetScape.010Editor'\nif [ -d \"$APPDIR/Abstract.app\" ]; then\n\tsudo mv \"$APPDIR/Abstract.app\" \"$TMPDIR/Abstract.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Abstract.app\" \"$APPDIR\"\nrelaunch_application 'com.SweetScape.010Editor'\n",
"40f16970": "#!/bin/sh\n\n# variables\nAPPDIR=\"/Applications/\"\nTMPDIR=$(dirname \"$(realpath $INSTALLER_PATH)\")\n# functions\n\nquit_and_track_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local timeout_duration=10\n\n # check if the application is running\n if ! osascript -e \"application id \\\"$bundle_id\\\" is running\" 2>/dev/null; then\n eval \"export $var_name=0\"\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ $EUID -eq 0 && \"$console_user\" == \"root\" ]]; then\n echo \"Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'.\"\n eval \"export $var_name=0\"\n return\n fi\n\n # App was running, mark it for relaunch\n eval \"export $var_name=1\"\n echo \"Application '$bundle_id' was running; will relaunch after installation.\"\n\n echo \"Quitting application '$bundle_id'...\"\n\n # try to quit the application within the timeout period\n local quit_success=false\n SECONDS=0\n while (( SECONDS < timeout_duration )); do\n if osascript -e \"tell application id \\\"$bundle_id\\\" to quit\" >/dev/null 2>&1; then\n if ! pgrep -f \"$bundle_id\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' quit successfully.\"\n quit_success=true\n break\n fi\n fi\n sleep 1\n done\n\n if [[ \"$quit_success\" = false ]]; then\n echo \"Application '$bundle_id' did not quit.\"\n fi\n}\n\n\nrelaunch_application() {\n local bundle_id=\"$1\"\n local var_name=\"APP_WAS_RUNNING_$(echo \"$bundle_id\" | tr '.-' '__')\"\n local was_running\n\n # Check if the app was running before installation\n eval \"was_running=\\$$var_name\"\n if [[ \"$was_running\" != \"1\" ]]; then\n return\n fi\n\n local console_user\n console_user=$(stat -f \"%Su\" /dev/console)\n if [[ $EUID -eq 0 && \"$console_user\" == \"root\" ]]; then\n echo \"Not logged into a non-root GUI; skipping relaunching application ID '$bundle_id'.\"\n return\n fi\n\n echo \"Relaunching application '$bundle_id'...\"\n\n # Try to launch the application\n if osascript -e \"tell application id \\\"$bundle_id\\\" to activate\" >/dev/null 2>&1; then\n echo \"Application '$bundle_id' relaunched successfully.\"\n else\n echo \"Failed to relaunch application '$bundle_id'.\"\n fi\n}\n\n\n# extract contents\nunzip \"$INSTALLER_PATH\" -d \"$TMPDIR\"\n# copy to the applications folder\nquit_and_track_application 'com.elasticprojects.abstract-desktop'\nif [ -d \"$APPDIR/Abstract.app\" ]; then\n\tsudo mv \"$APPDIR/Abstract.app\" \"$TMPDIR/Abstract.app.bkp\"\nfi\nsudo cp -R \"$TMPDIR/Abstract.app\" \"$APPDIR\"\nrelaunch_application 'com.elasticprojects.abstract-desktop'\n",
"e76ec506": "#!/bin/sh\n\n# variables\nAPPDIR=\"/Applications/\"\nLOGGED_IN_USER=$(scutil <<< \"show State:/Users/ConsoleUser\" | awk '/Name :/ { print $3 }')\n# functions\n\ntrash() {\n local logged_in_user=\"$1\"\n local target_file=\"$2\"\n local timestamp=\"$(date +%Y-%m-%d-%s)\"\n local rand=\"$(jot -r 1 0 99999)\"\n\n # replace ~ with /Users/$logged_in_user\n if [[ \"$target_file\" == ~* ]]; then\n target_file=\"/Users/$logged_in_user${target_file:1}\"\n fi\n\n local trash=\"/Users/$logged_in_user/.Trash\"\n local file_name=\"$(basename \"${target_file}\")\"\n\n if [[ -e \"$target_file\" ]]; then\n echo \"removing $target_file.\"\n mv -f \"$target_file\" \"$trash/${file_name}_${timestamp}_${rand}\"\n else\n echo \"$target_file doesn't exist.\"\n fi\n}\n\nsudo rm -rf \"$APPDIR/Abstract.app\"\ntrash $LOGGED_IN_USER '~/Library/Application Support/Abstract'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.elasticprojects.abstract-desktop'\ntrash $LOGGED_IN_USER '~/Library/Caches/com.elasticprojects.abstract-desktop.ShipIt'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.elasticprojects.abstract-desktop.helper.plist'\ntrash $LOGGED_IN_USER '~/Library/Preferences/com.elasticprojects.abstract-desktop.plist'\ntrash $LOGGED_IN_USER '~/Library/Saved Application State/com.elasticprojects.abstract-desktop.savedState'\n"
}
}
6 changes: 2 additions & 4 deletions ee/maintained-apps/outputs/airtame/windows.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
{
"version": "4.15.0",
"queries": {
"exists": "SELECT 1 FROM programs WHERE name = 'Airtame 4.15.0' AND publisher = 'Airtame';",
"exists": "SELECT 1 FROM programs WHERE name LIKE 'Airtame %' AND publisher = 'Airtame';",
"patch": ""
},
"installer_url": "https://downloads.airtame.com/app/latest/win/Airtame-4.15.0-setup.exe",
"install_script_ref": "8a919fae",
"uninstall_script_ref": "1e649d42",
"sha256": "1c627548a1cea11e1998c6814b5d731ee6a955db3253d244cc0ccfb95d52edd7",
"default_categories": [
"Productivity"
]
"default_categories": ["Productivity"]
}
],
"refs": {
Expand Down
4 changes: 2 additions & 2 deletions ee/maintained-apps/outputs/apps.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@
"name": "Amazon Chime",
"slug": "amazon-chime/darwin",
"platform": "darwin",
"unique_identifier": "com.runningwithcrayons.Alfred",
"unique_identifier": "com.amazon.Amazon-Chime",
"description": "Amazon Chime is a communications service that lets you meet, chat, and place business calls inside and outside your organization."
},
{
Expand Down Expand Up @@ -257,7 +257,7 @@
"name": "Beyond Compare",
"slug": "beyond-compare/darwin",
"platform": "darwin",
"unique_identifier": "com.scootersoftware.BeyondCompare",
"unique_identifier": "com.ScooterSoftware.BeyondCompare",
"description": "Beyond Compare is an app used to compare files and folders."
},
{
Expand Down
Loading
Loading