1
0
forked from finn/tinyboard

syncthing.sh: fix grep -oP portability, add curl error messages, pass shell vars as sys.argv to prevent python injection

This commit is contained in:
Justin Oros
2026-04-18 21:15:46 -07:00
parent f1d818eae6
commit 410def45c3

View File

@@ -19,24 +19,24 @@ ST_CONTAINER=""
get_apikey() { get_apikey() {
ST_CONTAINER=$(docker ps --format '{{.Names}}' | grep -i syncthing | head -1 || true) ST_CONTAINER=$(docker ps --format '{{.Names}}' | grep -i syncthing | head -1 || true)
[ -n "$ST_CONTAINER" ] || die "No running Syncthing container found." [ -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 '(?<=<apikey>)[^<]+' || 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'." [ -n "$APIKEY" ] || die "Could not read Syncthing API key from container '$ST_CONTAINER'."
} }
st_get() { 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() { 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() { 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() { 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() { check_deps() {
@@ -147,13 +147,13 @@ _do_add_device() {
local existing local existing
existing=$(st_get /rest/config/devices) existing=$(st_get /rest/config/devices)
local already 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 if [ "$already" = "True" ]; then
warn "Device '${device_name}' is already configured." warn "Device '${device_name}' is already configured."
return return
fi fi
local payload 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 st_post /rest/config/devices "$payload" >/dev/null
info "Device '${device_name}' added." info "Device '${device_name}' added."
} }
@@ -237,11 +237,11 @@ add_folder() {
local existing local existing
existing=$(st_get /rest/config/folders) existing=$(st_get /rest/config/folders)
local already 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." [ "$already" = "False" ] || die "Folder ID '${FOLDER_ID}' already exists."
local payload 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 st_post /rest/config/folders "$payload" >/dev/null
info "Folder '${FOLDER_LABEL}' added." info "Folder '${FOLDER_LABEL}' added."
} }
@@ -317,7 +317,7 @@ for i, d in enumerate(json.load(sys.stdin), 1):
local folder_config already local folder_config already
folder_config=$(st_get "/rest/config/folders/${folder_id}") 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 if [ "$already" = "True" ]; then
warn "Folder '${folder_label}' is already shared with '${device_name}'." warn "Folder '${folder_label}' is already shared with '${device_name}'."
return return
@@ -327,9 +327,9 @@ for i, d in enumerate(json.load(sys.stdin), 1):
updated=$(echo "$folder_config" | python3 -c " updated=$(echo "$folder_config" | python3 -c "
import sys, json import sys, json
f = json.load(sys.stdin) f = json.load(sys.stdin)
f['devices'].append({'deviceID': '${device_id}', 'introducedBy': ''}) f['devices'].append({'deviceID': sys.argv[1], 'introducedBy': ''})
print(json.dumps(f)) print(json.dumps(f))
") " "$device_id")
st_put "/rest/config/folders/${folder_id}" "$updated" >/dev/null st_put "/rest/config/folders/${folder_id}" "$updated" >/dev/null
info "Folder '${folder_label}' shared with '${device_name}'." 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 " updated=$(echo "$folder_config" | python3 -c "
import sys, json import sys, json
f = json.load(sys.stdin) 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)) print(json.dumps(f))
") " "$target_id")
st_put "/rest/config/folders/${folder_id}" "$updated" >/dev/null st_put "/rest/config/folders/${folder_id}" "$updated" >/dev/null
info "Folder '${folder_label}' unshared from '${target_name}'." info "Folder '${folder_label}' unshared from '${target_name}'."
} }