Initial commit
This commit is contained in:
198
pkgs/SynapseRevitalization/revitalize.py
Normal file
198
pkgs/SynapseRevitalization/revitalize.py
Normal file
@@ -0,0 +1,198 @@
|
||||
from signedjson.key import read_signing_keys
|
||||
from signedjson.sign import sign_json
|
||||
import json
|
||||
|
||||
import requests
|
||||
from systemd import journal
|
||||
from get_config import read_vars
|
||||
|
||||
import datetime
|
||||
|
||||
# Importing configuration from environment variables
|
||||
config = read_vars()
|
||||
|
||||
|
||||
# Getting signing key
|
||||
with open(config["server_key_file"]) as f:
|
||||
skey = read_signing_keys(f)[0]
|
||||
|
||||
|
||||
# Defining additional functions
|
||||
def current_time():
|
||||
now = datetime.datetime.now()
|
||||
return int(now.timestamp() * 1000)
|
||||
|
||||
def parse_roomid(roomid):
|
||||
return roomid.split(":")[1]
|
||||
|
||||
def serveraddr(servername):
|
||||
x = requests.get("https://%s/.well-known/matrix/server" % servername)
|
||||
if x.status_code == 200:
|
||||
j = json.loads(x.text)
|
||||
return j["m.server"]
|
||||
else:
|
||||
journal.send(f"[WARNING] Got {x.status_code} discovering server address of {servername}")
|
||||
return False
|
||||
|
||||
|
||||
# Function for getting users' access tokens
|
||||
def get_access_token(userid):
|
||||
time = current_time() + config["auth_token_term"] * 1000
|
||||
x = requests.post(
|
||||
f"https://{config['origin_server']}/_synapse/admin/v1/users/{userid}/login",
|
||||
json={"valid_until_ms": time},
|
||||
headers={
|
||||
"Authorization": "Bearer %s" % config["admin_auth_token"],
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
).text
|
||||
if "You are not a server admin" in x:
|
||||
journal.send("ERROR! The given token doesn't belogn to the server admin!")
|
||||
exit()
|
||||
y = json.loads(x)
|
||||
return y["access_token"]
|
||||
|
||||
|
||||
# Sign Matrix federation API requests
|
||||
## From Matrix protocol documentation
|
||||
def authorization_headers(
|
||||
destination_name, request_method, request_target, content=None
|
||||
):
|
||||
origin_name = config["origin_server_name"]
|
||||
request_json = {
|
||||
"method": request_method,
|
||||
"uri": request_target,
|
||||
"origin": origin_name,
|
||||
"destination": destination_name,
|
||||
}
|
||||
|
||||
if content is not None:
|
||||
request_json["content"] = content
|
||||
|
||||
signed_json = sign_json(request_json, origin_name, skey)
|
||||
|
||||
for key, sig in signed_json["signatures"][origin_name].items():
|
||||
return 'X-Matrix origin="%s",destination="%s",key="%s",sig="%s"' % (
|
||||
origin_name,
|
||||
destination_name,
|
||||
key,
|
||||
sig,
|
||||
)
|
||||
|
||||
|
||||
# Request the last event
|
||||
def request_last_event(destination, roomid):
|
||||
servers = [destination, "matrix.org", "inex.rocks", "sibnsk.net", "kde.org"]
|
||||
for i in servers:
|
||||
journal.send(f"[info] Trying access event_to_timestamp via {i}")
|
||||
try:
|
||||
server = serveraddr(i)
|
||||
except requests.exceptions.ConnectionError:
|
||||
journal.send(f"[WARNING] {i}'s well-known's are unreachable")
|
||||
continue
|
||||
except:
|
||||
journal.send(f"[WARNING] Can't request {i}'s well-known's for unknown reason. Likely {i} is unreachable or ssl certs expired")
|
||||
continue
|
||||
if server == False:
|
||||
continue
|
||||
|
||||
res = current_time()
|
||||
auth = authorization_headers(
|
||||
i,
|
||||
"GET",
|
||||
f"/_matrix/federation/v1/timestamp_to_event/{roomid}?dir=b&ts={res}",
|
||||
)
|
||||
try:
|
||||
x = requests.get(
|
||||
f"https://{server}/_matrix/federation/v1/timestamp_to_event/{roomid}",
|
||||
params={"dir": "b", "ts": res},
|
||||
headers={"Authorization": auth},
|
||||
).text
|
||||
except requests.exceptions.ConnectionError:
|
||||
journal.send(f"[WARNING] {server} is unreachable")
|
||||
continue
|
||||
except:
|
||||
journal.send(f"[WARNING] Couldn't request timestamp_to_event from {server} for unknown reason. Likely {server} is unreachable or ssl certs expired")
|
||||
continue
|
||||
|
||||
if "M_UNRECOGNIZED" in x:
|
||||
journal.send(f"[WARNING] Trying request {server} timestamp_to_event for {roomid}: got M_UNRECOGNIZED error")
|
||||
continue
|
||||
elif "M_NOT_FOUND" in x:
|
||||
journal.send(f"[WARNING] Unable to get the last event from {roomid}. {i} doesn't know room {roomid}")
|
||||
journal.send(f"{i} says: '{x}'")
|
||||
continue
|
||||
elif "event_id" in x:
|
||||
j = json.loads(x)
|
||||
return (i, server, j["event_id"])
|
||||
else:
|
||||
journal.send(f"[WARNING] Unable to get the last event from {roomid}. Unknown error from {server}: '{x}'")
|
||||
continue
|
||||
|
||||
journal.send(f"ERROR! Unable to get the last event from {roomid}. All {servers} don't know room {roomid} or support timestamp_to_event")
|
||||
return False
|
||||
|
||||
|
||||
# Request states of specified room
|
||||
def get_states(destination, server, roomid, last_event_id):
|
||||
auth = authorization_headers(
|
||||
destination, "GET", "/_matrix/federation/v1/state/%s?event_id=%s" % (roomid, last_event_id)
|
||||
)
|
||||
return requests.get(
|
||||
f"https://{server}/_matrix/federation/v1/state/{roomid}?event_id={last_event_id}",
|
||||
headers={"Authorization": auth},
|
||||
).text
|
||||
|
||||
|
||||
# Get users list from states
|
||||
def get_users(states):
|
||||
x = json.loads(states)
|
||||
# jq .pdus.[].type
|
||||
users = []
|
||||
x = x["pdus"]
|
||||
for i in x:
|
||||
if i["type"] == "m.room.member":
|
||||
users.append(i["sender"])
|
||||
return users
|
||||
|
||||
def filter_users(users):
|
||||
x = []
|
||||
for i in users:
|
||||
if f":{config["origin_server_name"]}" in i:
|
||||
x.append(i)
|
||||
return x
|
||||
|
||||
|
||||
# Make a user join a room
|
||||
def mkjoins(roomid, users, server1, server2):
|
||||
for i in users:
|
||||
token = get_access_token(i)
|
||||
x = requests.post(
|
||||
f"https://{config['origin_server']}/_matrix/client/v3/join/{roomid}",
|
||||
params={"via": server1, "via": server2},
|
||||
headers={"Authorization": "Bearer %s" % token},
|
||||
).text
|
||||
if roomid in x:
|
||||
journal.send(f"[info] Joined {i} to {roomid}")
|
||||
journal.send(x)
|
||||
return True
|
||||
else:
|
||||
journal.send(f"[info] Failed to join {i} to {roomid}")
|
||||
journal.send(x)
|
||||
return False
|
||||
|
||||
|
||||
def revitalize(roomid, server):
|
||||
journal.send(f"Got new roomid {roomid}")
|
||||
fe = request_last_event(server, roomid)
|
||||
if fe == False:
|
||||
return False
|
||||
else:
|
||||
x = get_states(fe[0], fe[1], roomid, fe[2])
|
||||
y = get_users(x)
|
||||
z = filter_users(y)
|
||||
journal.send(f"Trying to add {z} to {roomid}")
|
||||
if mkjoins(roomid, z, server, fe[0]):
|
||||
return True
|
||||
else:
|
||||
return False
|
Reference in New Issue
Block a user