2023-07-08 05:55:48 -04:00
2023-07-23 13:44:41 -04:00
import os
2023-07-08 05:55:48 -04:00
import subprocess
import csv
import time
2023-07-14 16:45:27 -04:00
import requests
import datetime
2023-07-08 05:55:48 -04:00
import hardcoded_variables
def delete_block_media ( ) :
# Take media_id from user
media_id = input ( " \n Enter the media_id of the media you would like to delete and block on your server. (Example: For this media https://matrix.perthchat.org/_matrix/media/r0/download/matrix.org/eDmjusOjnHyFPOYGxlrOsULJ the media_id is ' eDmjusOjnHyFPOYGxlrOsULJ ' ): " )
remote_server = input ( " \n Enter the remote servers URL without the ' https:// ' (Example: matrix.org): " )
# find filesystem_id from database
command_collect_filesystem_id = " ssh " + hardcoded_variables . homeserver_url + """ " /matrix/postgres/bin/cli-non-interactive --dbname=synapse -t -c ' SELECT DISTINCT filesystem_id FROM remote_media_cache WHERE media_id = ' \\ ' ' """ + media_id + """ ' \\ ' " | xargs """
print ( command_collect_filesystem_id )
process_collect_filesystem_id = subprocess . run ( [ command_collect_filesystem_id ] , shell = True , stdout = subprocess . PIPE , universal_newlines = True )
filesystem_id = process_collect_filesystem_id . stdout
print ( process_collect_filesystem_id . stdout )
# list the target files on disk
command_collect_thumbnails = " ssh " + hardcoded_variables . homeserver_url + ' " find /matrix/synapse/storage/media-store/remote_thumbnail/ ' + remote_server + ' / ' + filesystem_id [ : 2 ] + " / " + filesystem_id [ 2 : 4 ] + " / " + filesystem_id [ 4 : ] . rstrip ( ) + """ -type f -printf ' % p \\ n ' \" """
print ( command_collect_thumbnails )
process_collect_thumbnails = subprocess . run ( [ command_collect_thumbnails ] , shell = True , stdout = subprocess . PIPE , universal_newlines = True )
remote_thumbnails_list = process_collect_thumbnails . stdout
print ( remote_thumbnails_list )
command_content_location = " ssh " + hardcoded_variables . homeserver_url + ' " ls /matrix/synapse/storage/media-store/remote_content/ ' + remote_server + ' / ' + filesystem_id [ : 2 ] + " / " + filesystem_id [ 2 : 4 ] + " / " + filesystem_id [ 4 : ] . rstrip ( ) + ' " '
print ( command_content_location )
process_content_location = subprocess . run ( [ command_content_location ] , shell = True , stdout = subprocess . PIPE , universal_newlines = True )
remote_content_location = process_content_location . stdout
print ( remote_content_location )
# Zero the target files on disk then chattr +i them
for line in remote_thumbnails_list . split ( ' \n ' ) :
if line :
command_zero_thumbnails = ' ssh ' + hardcoded_variables . homeserver_url + ' " true > ' + line + ' " '
print ( command_zero_thumbnails )
process_zero_thumbnails = subprocess . run ( command_zero_thumbnails , shell = True )
print ( process_zero_thumbnails . stdout )
command_make_thumbnail_immutable = ' ssh ' + hardcoded_variables . homeserver_url + ' " chattr +i ' + line + ' " '
print ( command_make_thumbnail_immutable )
process_make_thumbnail_immutable = subprocess . run ( command_make_thumbnail_immutable , shell = True )
print ( process_make_thumbnail_immutable . stdout )
command_zero_media = ' ssh ' + hardcoded_variables . homeserver_url + ' " true > ' + remote_content_location . rstrip ( ) + ' " '
print ( command_zero_media )
process_remove_media = subprocess . run ( command_zero_media , shell = True )
print ( process_remove_media . stdout )
command_make_content_immutable = ' ssh ' + hardcoded_variables . homeserver_url + ' " chattr +i ' + remote_content_location . rstrip ( ) + ' " '
print ( command_make_content_immutable )
process_make_content_immutable = subprocess . run ( command_make_content_immutable , shell = True )
print ( process_make_content_immutable . stdout )
# Example, first use the media_id to find the filesystem_id:
# $ ssh matrix.perthchat.org "/matrix/postgres/bin/cli-non-interactive --dbname=synapse -t -c 'SELECT DISTINCT filesystem_id FROM remote_media_cache WHERE media_id = '\''eDmjusOjnHyFPOYGxlrOsULJ'\'" | xargs
# ehckzWWeUkDhhPfNFkcfCFNv
# Then use that filesystem_id to locate the remote file and all it's thumbnails:
# $ ssh matrix.perthchat.org "find /matrix/synapse/storage/media-store/remote_thumbnail/matrix.org/eh/ck/zWWeUkDhhPfNFkcfCFNv -type f -printf '%p\n'"
#/matrix/synapse/storage/media-store/remote_thumbnail/matrix.org/eh/ck/zWWeUkDhhPfNFkcfCFNv/32-32-image-jpeg-crop
#/matrix/synapse/storage/media-store/remote_thumbnail/matrix.org/eh/ck/zWWeUkDhhPfNFkcfCFNv/640-480-image-jpeg-scale
# ...
# $ ssh matrix.perthchat.org "ls /matrix/synapse/storage/media-store/remote_content/matrix.org/eh/ck/zWWeUkDhhPfNFkcfCFNv"
# /matrix/synapse/storage/media-store/remote_content/matrix.org/eh/ck/zWWeUkDhhPfNFkcfCFNv
# Then zero each file and make it immutable:
# $ ssh matrix.perthchat.org "true > /matrix/synapse/storage/media-store/remote_thumbnail/matrix.org/eh/ck/zWWeUkDhhPfNFkcfCFNv/32-32-image-jpeg-crop"
# $ ssh matrix.perthchat.org "chattr +i /matrix/synapse/storage/media-store/remote_thumbnail/matrix.org/eh/ck/zWWeUkDhhPfNFkcfCFNv/32-32-image-jpeg-crop"
# $ ssh matrix.perthchat.org "true > /matrix/synapse/storage/media-store/remote_thumbnail/matrix.org/eh/ck/zWWeUkDhhPfNFkcfCFNv/640-480-image-jpeg-scale"
# $ ssh matrix.perthchat.org "chattr +i /matrix/synapse/storage/media-store/remote_thumbnail/matrix.org/eh/ck/zWWeUkDhhPfNFkcfCFNv/640-480-image-jpeg-scale"
# ...
# $ ssh matrix.perthchat.org "true > /matrix/synapse/storage/media-store/remote_content/matrix.org/eh/ck/zWWeUkDhhPfNFkcfCFNv"
# $ ssh matrix.perthchat.org "chattr +i /matrix/synapse/storage/media-store/remote_content/matrix.org/eh/ck/zWWeUkDhhPfNFkcfCFNv"
def purge_remote_media_repo ( ) :
2023-07-14 16:45:27 -04:00
purge_from = int ( input ( " \n Enter the number of days to purge from: " ) )
purge_too = int ( input ( " \n Enter the number of days to purge too: " ) )
2023-07-08 05:55:48 -04:00
2023-07-14 16:45:27 -04:00
while purge_from > = purge_too :
# Calculate the epoch timestamp for 'purge_from' days ago
epoch_time = int ( ( datetime . datetime . now ( ) - datetime . timedelta ( days = purge_from ) ) . timestamp ( ) )
# Convert to milliseconds (as per your original code)
epoch_time_millis = epoch_time * 1000
# Make the request
headers = { " Authorization " : " Bearer " + hardcoded_variables . access_token }
url = f " https:// { hardcoded_variables . homeserver_url } /_synapse/admin/v1/purge_media_cache "
params = { " before_ts " : epoch_time_millis }
response = requests . post ( url , headers = headers , params = params )
print ( response . text )
purge_from - = 1
2023-07-08 05:55:48 -04:00
time . sleep ( 2 )
# This loop is quite slow, our server was having disk issues.
print ( " Done! :) " )
# Example:
# $ date --date '149 days ago' +%s
# 1589442217
# $ curl -X POST --header "Authorization: Bearer ACCESS_TOKEN" 'https://matrix.perthchat.org/_synapse/admin/v1/purge_media_cache?before_ts=1589439628000'
def prepare_database_copy_of_multiple_rooms ( ) :
print ( " Preparing database copying of events from multiple rooms selected \n " )
print ( " This command needs to be run on the target server as root, it will setup postgres commands to download the join-leave events and all-events from a list of rooms. \n \n It mounts a ramdisk beforehand at /matrix/postgres/data/ramdisk \n \n This function is only compatible with Spantaleevs Matrix deploy script: https://github.com/spantaleev/matrix-docker-ansible-deploy \n " )
database_copy_list_location = input ( " Please enter the path of the file containing a newline seperated list of room ids: " )
with open ( database_copy_list_location , newline = ' ' ) as f :
reader = csv . reader ( f )
data = list ( reader )
make_ramdisk_command = " mkdir /matrix/postgres/data/ramdisk; mount -t ramfs -o size=512m ramfs /matrix/postgres/data/ramdisk; chown -R matrix:matrix /matrix/postgres/data/ramdisk "
make_ramdisk_command_process = subprocess . run ( [ make_ramdisk_command ] , shell = True , stdout = subprocess . PIPE , universal_newlines = True )
print ( make_ramdisk_command_process . stdout )
x = 0
while x < = ( len ( data ) - 1 ) :
print ( data [ x ] [ 0 ] )
roomid_trimmed = data [ x ] [ 0 ]
roomid_trimmed = roomid_trimmed . replace ( ' ! ' , ' ' )
roomid_trimmed = roomid_trimmed . replace ( ' : ' , ' - ' )
os . mkdir ( " /matrix/postgres/data/ramdisk/ " + roomid_trimmed )
touch_command = " touch /matrix/postgres/data/ramdisk/ " + roomid_trimmed + " /dump_room_data.sql "
touch_command_process = subprocess . run ( [ touch_command ] , shell = True , stdout = subprocess . PIPE , universal_newlines = True )
print ( touch_command_process . stdout )
sql_file_contents = " \ set ROOMID ' " + data [ x ] [ 0 ] + " ' \n COPY (SELECT * FROM current_state_events JOIN room_memberships ON room_memberships.event_id = current_state_events.event_id WHERE current_state_events.room_id = : ' ROOMID ' ) TO ' /var/lib/postgresql/data/ramdisk/ " + roomid_trimmed + " /user_join-leave.csv ' WITH CSV HEADER; \n COPY (SELECT * FROM event_json WHERE room_id=: ' ROOMID ' ) TO ' /var/lib/postgresql/data/ramdisk/ " + roomid_trimmed + " /room_events.csv ' WITH CSV HEADER; "
print ( sql_file_contents )
sql_file_location = " /matrix/postgres/data/ramdisk/ " + roomid_trimmed + " /dump_room_data.sql "
sql_file = open ( sql_file_location , " w+ " )
sql_file . write ( sql_file_contents )
sql_file . close ( )
x + = 1
#print(x)
time . sleep ( 1 )
chown_command = " chown -R matrix:matrix /matrix/postgres/data/ramdisk; docker restart matrix-postgres "
chown_command_process = subprocess . run ( [ chown_command ] , shell = True , stdout = subprocess . PIPE , universal_newlines = True )
print ( chown_command_process . stdout )
print ( " \n The sql query files have been generated, as postgres user in container run: \n # docker exec -it matrix-postgres /bin/bash \n bash-5.0$ export PGPASSWORD=your-db-password \n bash-5.0$ for f in /var/lib/postgresql/data/ramdisk/*/dump_room_data.sql; do psql --host=127.0.0.1 --port=5432 --username=synapse -w -f $f; done \n \n After copying the data to a cloud location law enforcement can access, clean up the ramdisk like so: \n # rm -r /matrix/postgres/data/ramdisk/* \n # umount /matrix/postgres/data/ramdisk " )
2023-08-20 07:10:54 -04:00
def get_reported_events ( limit = 100 , _from = 0 , dir = ' b ' , user_id = None , room_id = None ) :
url = f " https:// { hardcoded_variables . homeserver_url } /_synapse/admin/v1/event_reports "
headers = {
" Content-Type " : " application/json " ,
" Authorization " : f " Bearer { hardcoded_variables . access_token } "
}
params = {
' limit ' : limit ,
' from ' : _from ,
' dir ' : dir
}
if user_id :
params [ ' user_id ' ] = user_id
if room_id :
params [ ' room_id ' ] = room_id
response = requests . get ( url , headers = headers , params = params )
if response . status_code == 200 :
return response . json ( )
else :
print ( f " Error fetching reported events: { response . status_code } , { response . text } " )
return None
def paginate_reported_events ( limit = 100 , dir = ' b ' , user_id = None , room_id = None ) :
_from = 0
all_reports = [ ]
while True :
reports = get_reported_events ( limit = limit , _from = _from , dir = dir , user_id = user_id , room_id = room_id )
if not reports or " event_reports " not in reports :
break
all_reports . extend ( reports [ " event_reports " ] )
if " next_token " in reports :
_from = reports [ " next_token " ]
else :
break
return all_reports
def get_event_report_details ( preset_report_id = ' ' ) :
if preset_report_id == ' ' :
report_id = input ( " \n Enter the report_id of the report you wish to query (Example: 56): " )
elif preset_report_id != ' ' :
report_id = preset_report_id
url = f " https:// { hardcoded_variables . homeserver_url } /_synapse/admin/v1/event_reports/ { report_id } "
headers = {
" Content-Type " : " application/json " ,
" Authorization " : f " Bearer { hardcoded_variables . access_token } "
}
response = requests . get ( url , headers = headers )
if response . status_code == 200 :
return response . json ( )
else :
print ( f " Error fetching event report details: { response . status_code } , { response . text } " )
return None
2023-08-23 06:36:40 -04:00
def send_server_notice ( preset_user_id = ' ' , preset_message = ' ' , txnId = None , event_type = " m.room.message " , state_key = None ) :
"""
Sends a server notice to a given user .
Args :
- user_id ( str ) : The Matrix ID of the user to send the notice to , e . g . " @target_user:server_name " .
- message ( str ) : The message to be sent as a notice .
- txnId ( str , optional ) : A unique transaction ID . If provided , retransmissions with the same txnId will be ignored .
- event_type ( str , optional ) : The type of event . Defaults to " m.room.message " .
- state_key ( str , optional ) : Setting this will result in a state event being sent .
Returns :
- dict : A dictionary containing the response from the server .
"""
# Take user_id from user if not provided
if preset_user_id == ' ' :
user_id = input ( " \n Enter the user_id of the user you would like to send the server notice to: " )
elif preset_user_id != ' ' :
user_id = preset_user_id
# Take message from user if not provided
if preset_message == ' ' :
message = input ( " \n Enter the message you would like to send to the user: " )
elif preset_message != ' ' :
message = preset_message
# Construct the URL based on whether a txnId is provided
if txnId :
url = f " https:// { hardcoded_variables . homeserver_url } /_synapse/admin/v1/send_server_notice/ { txnId } "
else :
url = f " https:// { hardcoded_variables . homeserver_url } /_synapse/admin/v1/send_server_notice "
headers = {
" Content-Type " : " application/json " ,
" Authorization " : f " Bearer { hardcoded_variables . access_token } "
}
# Construct the request body
data = {
" user_id " : user_id ,
" content " : {
" msgtype " : " m.text " ,
" body " : message
}
}
if event_type :
data [ " type " ] = event_type
if state_key :
data [ " state_key " ] = state_key
# Send the request
response = requests . put ( url , headers = headers , json = data ) if txnId else requests . post ( url , headers = headers , json = data )
if response . status_code == 200 :
return response . json ( )
else :
print ( f " Error sending server notice: { response . status_code } , { response . text } " )
return None