Make sending Matrix requests easier

This commit is contained in:
2025-10-17 17:44:41 -04:00
parent 6dd4fb04e3
commit 9ca4c913f3
5 changed files with 99 additions and 40 deletions

View File

@@ -8,7 +8,7 @@ dependencies = [
"httpx (>=0.28.1,<0.29.0)", "httpx (>=0.28.1,<0.29.0)",
"pynacl (>=1.6.0,<2.0.0)", "pynacl (>=1.6.0,<2.0.0)",
"flask[async] (>=3.1.2,<4.0.0)", "flask[async] (>=3.1.2,<4.0.0)",
"resolvematrix @ git+https://foundry.fsky.io/vel/resolvematrix.git@dev", "resolvematrix @ git+https://codeberg.org/timedout/resolvematrix.git",
] ]
authors = [ authors = [

View File

@@ -132,11 +132,9 @@ async def client():
def federation_self_test(): def federation_self_test():
try: try:
auth = globals.make_auth_header(config.server_name, "GET", "/.well-known/matrix/server") resp = globals.http_client().get(
path="/",
resp = globals.http_client.get( destination=config.server_name,
f"https://{config.server_name}/.well-known/matrix/server",
headers={"Authorization": auth}
) )
resp.raise_for_status() resp.raise_for_status()

View File

@@ -6,12 +6,12 @@ import vona.globals as globals
import vona.config as config import vona.config as config
import time import time
hammerhead = Blueprint("hammerhead", __name__) hammerhead = Blueprint("hammerhead", __name__)
# Hammerhead endpoints. Not documented, but code is at: # Hammerhead endpoints. Not documented, but code is at:
# https://codeberg.org/timedout/hammerhead/src/branch/dev/hammerhead/router/routes/hammerhead # https://codeberg.org/timedout/hammerhead/src/branch/dev/hammerhead/router/routes/hammerhead
@hammerhead.route("/_hammerhead/uptime") @hammerhead.route("/_hammerhead/uptime")
async def uptime(): async def uptime():
return jsonify({"started_at": config.the_funny_number}) return jsonify({"started_at": config.the_funny_number})

View File

@@ -1,3 +1,5 @@
from resolvematrix import ServerResolver
from types import SimpleNamespace
from collections import Counter from collections import Counter
import vona.config as config import vona.config as config
import nacl.signing import nacl.signing
@@ -10,7 +12,6 @@ import json
import re import re
version = "1.4.3" version = "1.4.3"
http_client = httpx.Client(headers={"User-Agent": f"Vona/{version}"})
def canonical_json(value): def canonical_json(value):
@@ -131,7 +132,12 @@ def pubkey() -> str:
) )
def make_auth_header(destination, method, path, content=None) -> str: def make_auth_header(
destination: str,
method: str,
path: str,
content = None
) -> str:
request_json = { request_json = {
"method": method, "method": method,
"uri": path, "uri": path,
@@ -255,6 +261,7 @@ def room_version_from_id(room_id):
return most_common_character(nums)[0] return most_common_character(nums)[0]
room_dir = { room_dir = {
"chunk": [{ "chunk": [{
"avatar_url": f"mxc://{config.server_name}/cat", "avatar_url": f"mxc://{config.server_name}/cat",
@@ -270,3 +277,72 @@ room_dir = {
}], }],
"total_room_count_estimate": 1 "total_room_count_estimate": 1
} }
class http_client:
http = httpx.Client(headers={"User-Agent": f"Vona/{version}"})
resolver = ServerResolver(client=http)
def _resolve(self, target) -> SimpleNamespace:
r = self.resolver.resolve(target)
if r.sni:
sni = r.sni
else:
sni = r.host_header
return SimpleNamespace(
base_url=r.base_url,
host_header=r.host_header,
sni=sni
)
def put(
self,
path: str,
destination: str,
headers: dict = {},
authorize: bool = True,
json: dict = {},
):
resolved = self._resolve(destination)
if authorize:
headers["Authorization"] = make_auth_header(
method="PUT",
destination=destination,
path=path,
)
headers["Host"] = resolved.host_header
return self.http.put(
f"{resolved.base_url}{path}",
headers=headers,
extensions={"sni_hostname": resolved.sni},
json=json
)
def get(
self,
path: str,
destination: str,
headers: dict = {},
authorize: bool = True,
):
resolved = self._resolve(destination)
if authorize:
headers["Authorization"] = make_auth_header(
method="GET",
destination=destination,
path=path,
)
headers["Host"] = resolved.host_header
return self.http.get(
f"{resolved.base_url}{path}",
headers=headers,
extensions={"sni_hostname": resolved.sni}
)

View File

@@ -1,16 +1,18 @@
from resolvematrix import ServerResolver
import urllib.parse, time, json, httpx
import vona.globals as globals import vona.globals as globals
import vona.config as config import vona.config as config
import urllib.parse
import httpx
import json
import time
http_client = globals.http_client http_client = globals.http_client()
def get_user_input(prompt): def get_user_input(prompt):
try: try:
return urllib.parse.quote(input(prompt).replace("\\n", "\n", count=32)) answer = input(prompt)
while "\\n" in answer:
answer = answer.replace("\\n", "\n")
return urllib.parse.quote(answer)
except Exception as e: except Exception as e:
print(f"Error reading input: {e}") print(f"Error reading input: {e}")
return None return None
@@ -21,27 +23,19 @@ room_id = get_user_input("Room ID:\n\t")
try: try:
unresolved_server_name = input("\nServer name before resolve:\n\t") server_name = input("\nServer name to join via:\n\t")
resolved_server_name = input("Server name after resolve:\n\t")
except Exception as e: except Exception as e:
print(f"Error reading server names: {e}") print(f"Error reading server names: {e}")
exit(1) exit(1)
resolver = ServerResolver(client=http_client)
try: try:
make_join_auth = globals.make_auth_header(
unresolved_server_name,
"GET",
f"/_matrix/federation/v1/make_join/{room_id}/%40{username}%3A{config.server_name}?ver=1&ver=2&ver=3&ver=4&ver=5&ver=6&ver=7&ver=8&ver=9&ver=10&ver=11&ver=12",
)
print("\nSending make_join request..") print("\nSending make_join request..")
make_join_response = http_client.get( make_join_response = http_client.get(
f"https://{resolved_server_name}/_matrix/federation/v1/make_join/{room_id}/%40{username}%3A{config.server_name}?ver=1&ver=2&ver=3&ver=4&ver=5&ver=6&ver=7&ver=8&ver=9&ver=10&ver=11&ver=12", path=f"/_matrix/federation/v1/make_join/{room_id}/%40{username}%3A{config.server_name}?ver=1&ver=2&ver=3&ver=4&ver=5&ver=6&ver=7&ver=8&ver=9&ver=10&ver=11&ver=12",
headers={ destination=server_name,
"Authorization": make_join_auth
},
) )
make_join_response.raise_for_status() make_join_response.raise_for_status()
@@ -51,7 +45,7 @@ except httpx.HTTPStatusError as e:
print(f"HTTP error occurred: {e.response.status_code} - {e.response.text}") print(f"HTTP error occurred: {e.response.status_code} - {e.response.text}")
exit(1) exit(1)
except json.JSONDecodeError: except json.JSONDecodeError:
print("Failed to decode JSON response.") print("Failed to decode response.")
exit(1) exit(1)
except Exception as e: except Exception as e:
print(f"An error occurred: {e}") print(f"An error occurred: {e}")
@@ -59,7 +53,7 @@ except Exception as e:
join_event = make_join.get("event", {}) join_event = make_join.get("event", {})
if make_join.get("room_version") in ["1", "2"]: if make_join.get("room_version", "1") in ["1", "2"]:
# NOTE: if we always make it opaque than Synapse will 500 lmao # NOTE: if we always make it opaque than Synapse will 500 lmao
join_event["event_id"] = globals.make_event_id() join_event["event_id"] = globals.make_event_id()
@@ -72,19 +66,10 @@ except ValueError:
signed_join = globals.hash_and_sign_event(join_event) signed_join = globals.hash_and_sign_event(join_event)
try: try:
send_join_auth = globals.make_auth_header(
unresolved_server_name,
"PUT",
f"/_matrix/federation/v2/send_join/{room_id}/%24doesntmatter?omit_members=true",
signed_join,
)
send_join_response = http_client.put( send_join_response = http_client.put(
f"https://{resolved_server_name}/_matrix/federation/v2/send_join/{room_id}/%24doesntmatter?omit_members=true", path=f"/_matrix/federation/v2/send_join/{room_id}/%24doesntmatter?omit_members=true",
headers={
"Authorization": send_join_auth
},
json=signed_join, json=signed_join,
destination=server_name,
) )
send_join_response.raise_for_status() send_join_response.raise_for_status()