From 410def45c368ae500f4ac19f54de9c4c3fa0c5e1 Mon Sep 17 00:00:00 2001 From: Justin Oros Date: Sat, 18 Apr 2026 21:15:46 -0700 Subject: [PATCH] syncthing.sh: fix grep -oP portability, add curl error messages, pass shell vars as sys.argv to prevent python injection --- syncthing.sh | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/syncthing.sh b/syncthing.sh index 28d0ddf..e10c0dc 100755 --- a/syncthing.sh +++ b/syncthing.sh @@ -19,24 +19,24 @@ ST_CONTAINER="" get_apikey() { ST_CONTAINER=$(docker ps --format '{{.Names}}' | grep -i syncthing | head -1 || true) [ -n "$ST_CONTAINER" ] || die "No running Syncthing container found." - APIKEY=$(docker exec "$ST_CONTAINER" cat /var/syncthing/config/config.xml 2>/dev/null | grep -oP '(?<=)[^<]+' || true) + APIKEY=$(docker exec "$ST_CONTAINER" python3 -c "import xml.etree.ElementTree as ET; print(ET.parse('/var/syncthing/config/config.xml').find('.//apikey').text)" 2>/dev/null || true) [ -n "$APIKEY" ] || die "Could not read Syncthing API key from container '$ST_CONTAINER'." } st_get() { - curl -sf -H "X-API-Key: $APIKEY" "${ST_URL}${1}" + curl -sf -H "X-API-Key: $APIKEY" "${ST_URL}${1}" || die "API call failed: GET ${1}" } st_post() { - curl -sf -X POST -H "X-API-Key: $APIKEY" -H "Content-Type: application/json" -d "$2" "${ST_URL}${1}" + curl -sf -X POST -H "X-API-Key: $APIKEY" -H "Content-Type: application/json" -d "$2" "${ST_URL}${1}" || die "API call failed: POST ${1}" } st_put() { - curl -sf -X PUT -H "X-API-Key: $APIKEY" -H "Content-Type: application/json" -d "$2" "${ST_URL}${1}" + curl -sf -X PUT -H "X-API-Key: $APIKEY" -H "Content-Type: application/json" -d "$2" "${ST_URL}${1}" || die "API call failed: PUT ${1}" } st_delete() { - curl -sf -X DELETE -H "X-API-Key: $APIKEY" "${ST_URL}${1}" + curl -sf -X DELETE -H "X-API-Key: $APIKEY" "${ST_URL}${1}" || die "API call failed: DELETE ${1}" } check_deps() { @@ -147,13 +147,13 @@ _do_add_device() { local existing existing=$(st_get /rest/config/devices) local already - already=$(echo "$existing" | python3 -c "import sys,json; devs=json.load(sys.stdin); print(any(d['deviceID']=='${device_id}' for d in devs))") + already=$(echo "$existing" | python3 -c "import sys,json; devs=json.load(sys.stdin); print(any(d['deviceID']==sys.argv[1] for d in devs))" "$device_id") if [ "$already" = "True" ]; then warn "Device '${device_name}' is already configured." return fi local payload - payload=$(python3 -c "import json; print(json.dumps({'deviceID': '${device_id}', 'name': '${device_name}', 'addresses': ['dynamic'], 'autoAcceptFolders': False}))") + payload=$(python3 -c "import sys,json; print(json.dumps({'deviceID':sys.argv[1],'name':sys.argv[2],'addresses':['dynamic'],'autoAcceptFolders':False}))" "$device_id" "$device_name") st_post /rest/config/devices "$payload" >/dev/null info "Device '${device_name}' added." } @@ -237,11 +237,11 @@ add_folder() { local existing existing=$(st_get /rest/config/folders) local already - already=$(echo "$existing" | python3 -c "import sys,json; folders=json.load(sys.stdin); print(any(f['id']=='${FOLDER_ID}' for f in folders))") + already=$(echo "$existing" | python3 -c "import sys,json; folders=json.load(sys.stdin); print(any(f['id']==sys.argv[1] for f in folders))" "$FOLDER_ID") [ "$already" = "False" ] || die "Folder ID '${FOLDER_ID}' already exists." local payload - payload=$(python3 -c "import json; print(json.dumps({'id': '${FOLDER_ID}', 'label': '${FOLDER_LABEL}', 'path': '${FOLDER_PATH}', 'type': 'sendreceive', 'devices': []}))") + payload=$(python3 -c "import sys,json; print(json.dumps({'id':sys.argv[1],'label':sys.argv[2],'path':sys.argv[3],'type':'sendreceive','devices':[]}))" "$FOLDER_ID" "$FOLDER_LABEL" "$FOLDER_PATH") st_post /rest/config/folders "$payload" >/dev/null info "Folder '${FOLDER_LABEL}' added." } @@ -317,7 +317,7 @@ for i, d in enumerate(json.load(sys.stdin), 1): local folder_config already folder_config=$(st_get "/rest/config/folders/${folder_id}") - already=$(echo "$folder_config" | python3 -c "import sys,json; f=json.load(sys.stdin); print(any(d['deviceID']=='${device_id}' for d in f.get('devices',[])))") + already=$(echo "$folder_config" | python3 -c "import sys,json; f=json.load(sys.stdin); print(any(d['deviceID']==sys.argv[1] for d in f.get('devices',[])))" "$device_id") if [ "$already" = "True" ]; then warn "Folder '${folder_label}' is already shared with '${device_name}'." return @@ -327,9 +327,9 @@ for i, d in enumerate(json.load(sys.stdin), 1): updated=$(echo "$folder_config" | python3 -c " import sys, json f = json.load(sys.stdin) -f['devices'].append({'deviceID': '${device_id}', 'introducedBy': ''}) +f['devices'].append({'deviceID': sys.argv[1], 'introducedBy': ''}) print(json.dumps(f)) -") +" "$device_id") st_put "/rest/config/folders/${folder_id}" "$updated" >/dev/null info "Folder '${folder_label}' shared with '${device_name}'." } @@ -395,9 +395,9 @@ for i, f in enumerate(json.load(sys.stdin), 1): updated=$(echo "$folder_config" | python3 -c " import sys, json f = json.load(sys.stdin) -f['devices'] = [d for d in f['devices'] if d['deviceID'] != '${target_id}'] +f['devices'] = [d for d in f['devices'] if d['deviceID'] != sys.argv[1]] print(json.dumps(f)) -") +" "$target_id") st_put "/rest/config/folders/${folder_id}" "$updated" >/dev/null info "Folder '${folder_label}' unshared from '${target_name}'." }