Utility Scripts for the Synapse Admin API

A bunch of scripts easing up admin tasks and bigger API usage.

For example:
 - login/logout of a user and saving the credentials to a file
 - querying a matrix server for account data
 - local filtering operations on the account data for rooms and users
 - deleting users via admin API based on the filtered data
 - deleting rooms via admin API based on the filtered data
main
Peery 1 year ago
commit effa70c19d

@ -0,0 +1,20 @@
#!/bin/bash
input_file=$1
output_file=$3
pattern=$2
if [ -z $input_file -o -z $pattern ]; then
echo "input file: $input_file, pattern: $pattern"
echo "Usage: $0 <./path/to/matrix-rooms.txt> <PATTERN> [./path/to/output.txt]"
exit 0
fi
#echo "Converting matrix account data into a comprehensive room list ..."
if [ -z $output_file ]; then
jq ".rooms.join | [to_entries[] | {\"room_id\": .key, \"room_name\": .value.state.events[] | select(.type == \"m.room.name\").content.name, \"users\": [.value.state.events[] | select(.type == \"m.room.member\") | {\"user_id\": .sender, \"displayname\": .content.displayname}]} | select(.users[].displayname | match(\"$pattern\")?)] | group_by(.room_id) | map({room_id: .[0].room_id, room_name: .[0].room_name, matches: length, users: .[0].users})" "$input_file"
else
jq ".rooms.join | [to_entries[] | {\"room_id\": .key, \"room_name\": .value.state.events[] | select(.type == \"m.room.name\").content.name, \"users\": [.value.state.events[] | select(.type == \"m.room.member\") | {\"user_id\": .sender, \"displayname\": .content.displayname}]} | select(.users[].displayname | match(\"$pattern\")?)] | group_by(.room_id) | map({room_id: .[0].room_id, room_name: .[0].room_name, matches: length, users: .[0].users})" "$input_file" > $output_file
fi

@ -0,0 +1,18 @@
#!/bin/bash
input_file=$1
output_file=$3
pattern=$2
if [ -z $input_file -o -z $pattern ]; then
echo "input file: $input_file, pattern: $pattern"
echo "Usage: $0 <./path/to/matrix-rooms.txt> <PATTERN> [./path/to/output.txt]"
exit 0
fi
echo "Converting matrix account data into a comprehensive room list ..."
if [ -z $output_file ]; then
jq ".rooms.join | [to_entries[] | {\"room_id\": .key, \"room_name\": .value.state.events[] | select(.type == \"m.room.name\").content.name} | select(.room_name | match(\"$pattern\"))]" $input_file
else
jq ".rooms.join | [to_entries[] | {\"room_id\": .key, \"room_name\": .value.state.events[] | select(.type == \"m.room.name\").content.name} | select(.room_name | match(\"$pattern\"))]" $input_file > $output_file
fi

@ -0,0 +1,20 @@
#!/bin/bash
input_file=$1
output_file=$3
pattern=$2
if [ -z $input_file -o -z $pattern ]; then
echo "input file: $input_file, pattern: $pattern"
echo "Usage: $0 <./path/to/matrix-rooms.txt> <PATTERN> [./path/to/output.txt]"
exit 0
fi
#echo "Converting matrix account data into a comprehensive room list ..."
if [ -z $output_file ]; then
jq ".rooms.join | [to_entries[] | {\"room_id\": .key, \"room_name\": .value.state.events[] | select(.type == \"m.room.name\").content.name, \"users\": [.value.state.events[] | select(.type == \"m.room.member\") | {\"user_id\": .sender, \"displayname\": .content.displayname}]} | select(.users[].user_id | match(\"$pattern\"))] | group_by(.room_id) | map({room_id: .[0].room_id, room_name: .[0].room_name, matches: length, users: .[0].users})" "$input_file"
else
jq ".rooms.join | [to_entries[] | {\"room_id\": .key, \"room_name\": .value.state.events[] | select(.type == \"m.room.name\").content.name, \"users\": [.value.state.events[] | select(.type == \"m.room.member\") | {\"user_id\": .sender, \"displayname\": .content.displayname}]} | select(.users[].user_id | match(\"$pattern\"))] | group_by(.room_id) | map({room_id: .[0].room_id, room_name: .[0].room_name, matches: length, users: .[0].users})" "$input_file" > $output_file
fi

@ -0,0 +1,19 @@
#!/bin/bash
input_file=$1
output_file=$3
pattern=$2
if [ -z $input_file -o -z $pattern ]; then
echo "input file: $input_file, pattern: $pattern"
echo "Usage: $0 <./path/to/matrix-rooms.txt> <PATTERN> [./path/to/output.txt]"
exit 0
fi
#echo "Converting matrix account data into a comprehensive room list ..."
if [ -z $output_file ]; then
jq ".rooms.join | [to_entries[] | .value.state.events[] | select(.type == \"m.room.member\") | {\"user_id\": .sender, \"displayname\": .content.displayname}] | unique_by(.user_id) | map(select(.displayname | match(\"$pattern\")?))" "$input_file"
else
jq ".rooms.join | [to_entries[] | .value.state.events[] | select(.type == \"m.room.member\") | {\"user_id\": .sender, \"displayname\": .content.displayname}] | unique_by(.user_id) | map(select(.displayname | match(\"$pattern\")?))" "$input_file" > "$output_file"
fi

@ -0,0 +1,19 @@
#!/bin/bash
input_file=$1
output_file=$3
pattern=$2
if [ -z $input_file -o -z $pattern ]; then
echo "input file: $input_file, pattern: $pattern"
echo "Usage: $0 <./path/to/matrix-rooms.txt> <PATTERN> [./path/to/output.txt]"
exit 0
fi
#echo "Converting matrix account data into a comprehensive room list ..."
if [ -z $output_file ]; then
jq ".rooms.join | [to_entries[] | .value.state.events[] | select(.type == \"m.room.member\") | {\"user_id\": .sender, \"displayname\": .content.displayname}] | unique_by(.user_id) | map(select(.user_id | match(\"$pattern\")))" "$input_file"
else
jq ".rooms.join | [to_entries[] | .value.state.events[] | select(.type == \"m.room.member\") | {\"user_id\": .sender, \"displayname\": .content.displayname}] | unique_by(.user_id) | map(select(.user_id | match(\"$pattern\")))" "$input_file" > "$output_file"
fi

@ -0,0 +1,20 @@
#!/bin/bash
domain=$1
output_file=$2
read -p "User: " user
read -p "Password: " password
if [ -e $output_file ]; then
output_file=matrix-login.txt
fi
if [ -z $domain -o -z $user -o -z $password ]; then
echo "Domain: $domain, User: $user, Password: $password"
echo "Usage: $0 \"https://matrix.server\" <OUTPUT_FILE>"
exit 0
fi
echo "Querying homeserver for new login data ..."
echo curl -XPOST -d "{\"type\":\"m.login.password\", \"user\":\"$user\", \"password\":\"$password\"}" "$domain/_matrix/client/r0/login" -o "$output_file"
curl -XPOST -d "{\"type\":\"m.login.password\", \"user\":\"$user\", \"password\":\"$password\"}" "$domain/_matrix/client/r0/login" -o "$output_file"

@ -0,0 +1,16 @@
#!/bin/bash
set -e
domain=$1
login_data=$2
if [ -z $domain -o -z $login_data ]; then
echo "Usage: $0 \"https://matrix.server\" <LOGIN_FILE>"
exit 0
fi
token=$(cat $login_data | jq -r '.access_token')
echo "Logging user out ..."
curl -XPOST -H "Authorization: Bearer $token" "$domain/_matrix/client/r0/logout"

@ -0,0 +1,72 @@
#!/bin/bash
#'
#This Bash script takes a json array of form [{"room_id": "!asdX:domain.com", "room_name": "nameX"}, {"room_id": "!asdY:domain.com", "room_name": "nameY"}] and iterates over them with the delete room api which is exclusive to Synapse.
#This array is supplied as a file parameter and created with another script (see filter_account_data_rooms_for_pattern.sh)
#
#See: https://matrix-org.github.io/synapse/latest/admin_api/rooms.html#delete-room-api
#
#'
set -e
domain=$1
login_file=$2
input_file=$3
output_folder=$4
if [ -z "$domain" -o ! -e "$input_file" -o ! -e "$login_file" ]; then
echo "Domain: $domain, login file: $login_file, input file: $input_file, output folder: $output_folder"
echo "Usage: $0 http(s)://<DOMAIN> <LOGIN_FILE> <INPUT_FILE> [OUTPUT_FOLDER]"
exit 1
fi
if [ ! -z "$output_folder" -a ! -d "$output_folder" ]; then
echo "The given output folder ($output_folder) is not a valid directory! Creating it ..."
mkdir $output_folder
fi
#echo "Querying homeserver for new login data ..."
#echo curl -XPOST -d "{\"type\":\"m.login.password\", \"user\":\"$user\", \"password\":\"$password\"}" "$domain/_matrix/client/r0/login" -o "$output_file"
#curl --globoff -XGET -H "Authorization: Bearer $token" "$domain/_matrix/client/r0/sync?filter={\"room\":{\"timeline\":{\"limit\":1}}}"
ROOM_COUNT=$(jq '. | length' "$input_file")
echo "Found $ROOM_COUNT rooms to delete in the input file. Example: "
echo $(jq '.[0]' "$input_file")
echo
echo "Other Example: "
echo $(jq '.[-1]' "$input_file")
echo
read -p "Is this looking correct? (y/n) " reply
if [ "$reply" != "y" -a "$reply" != "Y" ]; then
echo "Aborting ..."
exit 0
fi
token=$(jq -r '.access_token' "$login_file")
for ((i = 0; i < $ROOM_COUNT; i++ ));do
room_json=$(jq ".[$i]" "$input_file")
room_name=$(echo $room_json | jq -r '.room_name')
room_id=$(echo $room_json | jq -r '.room_id')
room_id_enc=$(echo $room_json | jq -r '.room_id' | sed 's/!/%21/g' | sed 's/:/%3A/g') # room id has to be URL encoded (bootleg version)
echo "Currently purging room $room_name with ID: $room_id ..."
if [ -d "$output_folder" ]; then
output_file="$output_folder/$room_id_enc-delete_result.txt"
fi
if [ ! -z "$output_file" ]; then
echo curl --globoff -XDELETE -H "Authorization: Bearer $token" -d "{\"block\": false, \"purge\": true}" "$domain/_synapse/admin/v2/rooms/$room_id_enc" -o "$output_file"
curl --globoff -XDELETE -H "Authorization: Bearer $token" -d "{\"block\": false, \"purge\": true}" "$domain/_synapse/admin/v2/rooms/$room_id_enc" -o "$output_file"
else
echo curl --globoff -XDELETE -H "Authorization: Bearer $token" -d "{\"block\": false, \"purge\": true}" "$domain/_synapse/admin/v2/rooms/$room_id_enc"
curl --globoff -XDELETE -H "Authorization: Bearer $token" -d "{\"block\": false, \"purge\": true}" "$domain/_synapse/admin/v2/rooms/$room_id_enc"
fi
echo "Sleeping for 5 seconds ..."
sleep 5
done

@ -0,0 +1,68 @@
#!/bin/bash
#'
#This Bash script takes a json array of form [{"user_id": "@asdX:domain.com", "displayname": "nameX"}, {"user_id": "@asdY:domain.com", "displayname": null}] and iterates over them with the delete user api which is exclusive to Synapse.
#This array is supplied as a file parameter and created with another script (see filter_users_by_*.sh)
#
#See: https://matrix-org.github.io/synapse/latest/admin_api/user_admin_api.html#deactivate-account
#
#'
set -e
domain=$1
login_file=$2
input_file=$3
output_folder=$4
if [ -z "$domain" -o ! -e "$input_file" -o ! -e "$login_file" ]; then
echo "Domain: $domain, login file: $login_file, input file: $input_file, output folder: $output_folder"
echo "Usage: $0 http(s)://<DOMAIN> <LOGIN_FILE> <INPUT_FILE> [OUTPUT_FOLDER]"
exit 1
fi
if [ ! -z "$output_folder" -a ! -d "$output_folder" ]; then
echo "The given output folder ($output_folder) is not a valid directory! Creating it ..."
mkdir $output_folder
fi
USER_COUNT=$(jq '. | length' "$input_file")
echo "Found $USER_COUNT users to delete in the input file. Example: "
echo $(jq '.[0]' "$input_file")
echo
echo "Other Example: "
echo $(jq '.[-1]' "$input_file")
echo
read -p "Is this looking correct? (y/n) " reply
if [ "$reply" != "y" -a "$reply" != "Y" ]; then
echo "Aborting ..."
exit 0
fi
token=$(jq -r '.access_token' "$login_file")
for ((i = 0; i < $USER_COUNT; i++ ));do
user_json=$(jq ".[$i]" "$input_file")
user_displayname=$(echo $user_json | jq -r '.displayname')
user_id=$(echo $user_json | jq -r '.user_id')
user_id_enc=$(echo $user_json | jq -r '.user_id' | sed 's/@/%40/g' | sed 's/:/%3A/g') # user id has to be URL encoded (bootleg version)
echo "Currently purging user $user_displayname with ID: $user_id ..."
if [ -d "$output_folder" ]; then
output_file="$output_folder/$user_id_enc-delete_result.txt"
fi
if [ ! -z "$output_file" ]; then
echo curl --globoff -XDELETE -H "Authorization: Bearer [TOKEN]" -d "{\"erase\": true}" "$domain/_synapse/admin/v1/deactivate/$user_id_enc" -o "$output_file"
curl --globoff -XDELETE -H "Authorization: Bearer $token" -d "{\"erase\": true}" "$domain/_synapse/admin/v1/deactivate/$user_id_enc" -o "$output_file"
else
echo curl --globoff -XDELETE -H "Authorization: Bearer [TOKEN]" -d "{\"erase\": true}" "$domain/_synapse/admin/v1/deactivate/$user_id_enc"
curl --globoff -XDELETE -H "Authorization: Bearer $token" -d "{\"erase\": true}" "$domain/_synapse/admin/v1/deactivate/$user_id_enc"
fi
echo "Sleeping for 5 seconds ..."
sleep 5
done

@ -0,0 +1,38 @@
#!/bin/bash
domain=$2
login_data=$1
output_file=$3
if [ -z $output_file ]; then
output_file=matrix-rooms.txt
fi
if [ -z $domain -o ! -f $login_data ]; then
echo "domain: $domain login: $login_data"
echo "Usage: $0 ./path/to/matrix-login.txt \"https://matrix.server\""
exit 0
fi
token=$(cat $login_data | jq -r '.access_token')
# Queries for a list of room IDs
# jq '.rooms.join'
# Querying for a list of displaynames
# TODO why are there null's in the list?
# TODO how do I ALSO get the room ID?
# TODO can I just select() in jq to select the room IDs?
# jq '.rooms.join | .[].state.events[].content.channel' matrix-rooms.txt | grep -v null | less
# Lists all room names out of the m.room.name state event as an array
# jq '.rooms.join | [.[].state.events[] | select(.type == "m.room.name").content.name]'
# List all room IDs with room names as objects {"room_name": x, "room_id": y}
# jq '.rooms.join | to_entries[] | {"room_id": .key, "room_name": .value.state.events[] | select(.type == "m.room.name").content.name}'
echo "Querying homeserver for room data. This might take a while ..."
echo curl --globoff -XGET -H "Authorization: Bearer [YOUR TOKEN]" "$domain/_matrix/client/r0/sync?filter={"room":{"timeline":{"limit":1}}}" -o "$output_file"
curl --globoff -XGET -H "Authorization: Bearer $token" "$domain/_matrix/client/r0/sync?filter={\"room\":{\"timeline\":{\"limit\":1}}}" -o "$output_file"
Loading…
Cancel
Save