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 datamain
						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…
					
					
				
		Reference in New Issue