Prepare for room v3+, misc bugfixes

This commit is contained in:
2025-10-24 23:42:29 -04:00
parent b71096663c
commit f23a74de5c
8 changed files with 288 additions and 254 deletions

View File

@@ -44,7 +44,7 @@ async def validate_json():
try: try:
request.get_json(force=True) request.get_json(force=True)
except Exception as e: except Exception:
return jsonify({"error": "Content not JSON.", "errcode": "M_NOT_JSON"}), 400 return jsonify({"error": "Content not JSON.", "errcode": "M_NOT_JSON"}), 400

View File

@@ -621,7 +621,7 @@ async def url_preview():
@client.route("/_matrix/client/v1/media/preview_url") @client.route("/_matrix/client/v1/media/preview_url")
async def media_preview(): async def media_preview():
response = send_file(config.cat) response = send_file(config.cat)
response.headers["Content-Disposition"] = f'inline; filename="cat.jpg"' response.headers["Content-Disposition"] = 'inline; filename="cat.jpg"'
response.headers["Content-Type"] = "image/jpg" response.headers["Content-Type"] = "image/jpg"
return response return response

View File

@@ -1,4 +1,3 @@
from vona.config import the_funny_number
from datetime import datetime, timezone from datetime import datetime, timezone
from vona.federation import send_join from vona.federation import send_join
import vona.globals as globals import vona.globals as globals
@@ -7,7 +6,6 @@ import time
from flask import ( from flask import (
Blueprint, Blueprint,
request,
jsonify, jsonify,
) )

View File

@@ -2,15 +2,12 @@ from vona.federation import send_join
import vona.globals as globals import vona.globals as globals
import vona.config as config import vona.config as config
import base64
import re
import os import os
from flask import ( from flask import (
Blueprint, Blueprint,
jsonify, jsonify,
request, request,
Response,
) )
synapse = Blueprint("synapse", __name__) synapse = Blueprint("synapse", __name__)
@@ -99,7 +96,7 @@ async def whois(user_id):
"": { "": {
"sessions": [{ "sessions": [{
"connections": [{ "connections": [{
"ip":f"127.0.0.1", "ip":"127.0.0.1",
"last_seen":config.the_funny_number, "last_seen":config.the_funny_number,
"user_agent":f"Vona/{globals.version}" "user_agent":f"Vona/{globals.version}"
}] }]

View File

@@ -1,16 +1,14 @@
import vona.federation.rooms as rooms
import vona.globals as globals import vona.globals as globals
import vona.config as config import vona.config as config
import threading
import json import json
import time import time
import os
from flask import ( from flask import (
jsonify, jsonify,
Response, Response,
request, request,
send_file,
Blueprint, Blueprint,
) )
@@ -23,210 +21,8 @@ class bullshit:
return {} return {}
def send_join(request, room) -> dict: def send_join(request, room) -> dict:
event_chain = [] if globals.room_version_from_id(room) in ["1", "2"]:
event_hashes = [] return rooms.v1_v2(request, room)
event_ids = [
globals.make_event_id(seed=f"1_{room}"),
globals.make_event_id(seed=f"2_{room}"),
globals.make_event_id(seed=f"3_{room}"),
globals.make_event_id(seed=f"4_{room}"),
globals.make_event_id(seed=f"5_{room}"),
globals.make_event_id(seed=f"6_{room}"),
]
create_event = {
"content": {
"m.federate": True,
"creator": f"@vona:{config.server_name}",
"room_version": globals.room_version_from_id(room)
},
"event_id": event_ids[0],
"origin_server_ts": 1,
"room_id": room,
"sender": f"@vona:{config.server_name}",
"state_key": "",
"depth": 1,
"type": "m.room.create",
"auth_events": [],
"prev_events": []
}
screate_event = globals.hash_and_sign_event(create_event)
event_chain.append(screate_event)
our_join = {
"content": {
"displayname": "Vona",
"avatar_url": f"mxc://{config.server_name}/cat",
"membership": "join"
},
"origin_server_ts": 2,
"sender": f"@vona:{config.server_name}",
"state_key": f"@vona:{config.server_name}",
"type": "m.room.member",
"event_id": event_ids[1],
"room_id": room,
"depth": 2,
"auth_events": [[
screate_event["event_id"],
screate_event["hashes"]
]],
"prev_events": [[
screate_event["event_id"],
screate_event["hashes"]
]]
}
sour_join = globals.hash_and_sign_event(our_join)
event_chain.append(sour_join)
pls = {
"content": {
"users": {
f"@vona:{config.server_name}": "100"
}
},
"origin_server_ts": 3,
"room_id": room,
"sender": f"@vona:{config.server_name}",
"state_key": "",
"type": "m.room.power_levels",
"event_id": event_ids[2],
"depth": 3,
"user_id": f"@vona:{config.server_name}",
"auth_events": [
[
screate_event["event_id"],
screate_event["hashes"]
],
[
sour_join["event_id"],
sour_join["hashes"]
]
],
"prev_events": [[
sour_join["event_id"],
sour_join["hashes"]
]]
}
spls = globals.hash_and_sign_event(pls)
event_chain.append(spls)
join_rule = {
"content": {
"join_rule": "public"
},
"origin_server_ts": 4,
"sender": f"@vona:{config.server_name}",
"state_key": "",
"type": "m.room.join_rules",
"event_id": event_ids[3],
"room_id": room,
"depth": 4,
"auth_events": [
[
screate_event["event_id"],
screate_event["hashes"]
],
[
sour_join["event_id"],
sour_join["hashes"]
],
[
spls["event_id"],
spls["hashes"]
]
],
"prev_events": [[
spls["event_id"],
spls["hashes"]
]]
}
sjoin_rule = globals.hash_and_sign_event(join_rule)
event_chain.append(sjoin_rule)
guest_access = {
"content": {
"guest_access": "forbidden"
},
"origin_server_ts": 5,
"depth": 5,
"sender": f"@vona:{config.server_name}",
"state_key": "",
"type": "m.room.guest_access",
"event_id": event_ids[4],
"room_id": room,
"auth_events": [
[
screate_event["event_id"],
screate_event["hashes"]
],
[
sour_join["event_id"],
sour_join["hashes"]
],
[
spls["event_id"],
spls["hashes"]
]
],
"prev_events": [[
sjoin_rule["event_id"],
sjoin_rule["hashes"]
]]
}
sguest_access = globals.hash_and_sign_event(guest_access)
event_chain.append(sguest_access)
history = {
"content": {
"history_visibility": "shared"
},
"type": "m.room.history_visibility",
"sender": f"@vona:{config.server_name}",
"state_key": "",
"origin_server_ts": 6,
"depth": 6,
"event_id": event_ids[5],
"room_id": room,
"auth_events": [
[
screate_event["event_id"],
screate_event["hashes"]
],
[
sour_join["event_id"],
sour_join["hashes"]
],
[
spls["event_id"],
spls["hashes"]
]
],
"prev_events": [[
sguest_access["event_id"],
sguest_access["hashes"]
]]
}
shistory = globals.hash_and_sign_event(history)
event_chain.append(shistory)
remote_join = request.get_json()
response = {
"auth_chain": event_chain,
"event": remote_join,
"members_omitted": False,
"servers_in_room": [config.server_name],
"state": event_chain
}
return response
@server.route("/_matrix/federation/v1/version") @server.route("/_matrix/federation/v1/version")
@@ -288,27 +84,39 @@ async def thumbnail_media(media_id):
"error": "Cat is too cute to thumbnail" "error": "Cat is too cute to thumbnail"
}), 418 }), 418
@server.route("/_matrix/federation/v1/send_join/<room>/<eventId>", methods=["PUT"]) @server.route("/_matrix/federation/v1/send_join/<room>/<eventId>", methods=["PUT"])
async def send_join_v1(room, eventId): async def send_join_v1(room, eventId):
if globals.room_version_from_id(room) not in ["1", "2"]:
return jsonify({
"errcode": "M_INCOMPATIBLE_ROOM_VERSION",
"error": "This room is not v1 or v2."
}), 400
return jsonify([200, send_join(request, room)]) return jsonify([200, send_join(request, room)])
@server.route("/_matrix/federation/v2/send_join/<room>/<eventId>", methods=["PUT"]) @server.route("/_matrix/federation/v2/send_join/<room>/<eventId>", methods=["PUT"])
async def send_join_v2(room, eventId): async def send_join_v2(room, eventId):
return jsonify(send_join(request, room)) return jsonify(send_join(request, room))
@server.route("/_matrix/federation/v1/make_join/<room>/<user>") @server.route("/_matrix/federation/v1/make_join/<room>/<user>")
async def make_join(room, user): async def make_join(room, user):
def not_invited(): if ":" in room:
if room.split(":")[1] != config.server_name:
return jsonify({
"errcode": "M_FORBIDDEN",
"error": "You are not invited to this room."
}), 403
else:
return jsonify({ return jsonify({
"errcode": "M_FORBIDDEN", "errcode": "M_FORBIDDEN",
"error": "You are not invited to this room." "error": "You are not invited to this room."
}), 403 }), 403
try:
if room.split(":")[1] != config.server_name: room_ver = globals.room_version_from_id(room)
return not_invited()
except:
return not_invited()
state = send_join( state = send_join(
request=bullshit, request=bullshit,
@@ -329,29 +137,43 @@ async def make_join(room, user):
"depth": 7 "depth": 7
} }
join["auth_events"] = [ if room_ver in ["1", "2"]:
[ join["event_id"] = globals.make_event_id(seed=f"{user}+{room}")
state[0]["event_id"],
state[0]["hashes"] join["auth_events"] = [
], [
[ state[0]["event_id"],
state[2]["event_id"], state[0]["hashes"]
state[2]["hashes"] ],
], [
[ state[2]["event_id"],
state[3]["event_id"], state[2]["hashes"]
state[3]["hashes"] ],
] [
] state[3]["event_id"],
state[3]["hashes"]
]
]
join["prev_events"] = [[
state[5]["event_id"],
state[5]["hashes"]
]]
else:
join["auth_events"] = [
globals.make_ref_hash(state[0], int(room_ver)),
globals.make_ref_hash(state[2], int(room_ver)),
globals.make_ref_hash(state[3], int(room_ver)),
]
join["prev_events"] = [
globals.make_ref_hash(state[5], int(room_ver)),
]
join["prev_events"] = [[
state[5]["event_id"],
state[5]["hashes"]
]]
return jsonify({ return jsonify({
"event": globals.hash_and_sign_event(join), "event": globals.hash_and_sign_event(join),
"room_version": globals.room_version_from_id(room) "room_version": room_ver
}) })
@@ -475,8 +297,7 @@ async def invite_user_v1(room, txnId):
and ":" in event["event_id"] and ":" in event["event_id"]
): ):
return jsonify({ return jsonify({
"event": globals.sign_json_without_discard(event), "event": globals.sign_json_without_discard(event)
"room_version": invite_data["room_version"]
}) })
return jsonify({ return jsonify({
@@ -550,7 +371,12 @@ async def state_ids(room):
event_ids = [] event_ids = []
for event in state: for event in state:
event_ids.append(event["event_id"]) if "event_id" in event:
event_ids.append(event["event_id"])
else:
event_ids.append(
globals.make_ref_hash(event)
)
if evt in event_ids: if evt in event_ids:
return jsonify({ return jsonify({

213
vona/federation/rooms.py Normal file
View File

@@ -0,0 +1,213 @@
import vona.globals as globals
import vona.config as config
# This file is responsible for creating Matrix rooms.
# Room V3+
# TODO
# Room V1/V2
def v1_v2(request, room) -> dict:
event_chain = []
event_ids = [
globals.make_event_id(seed=f"1_{room}"),
globals.make_event_id(seed=f"2_{room}"),
globals.make_event_id(seed=f"3_{room}"),
globals.make_event_id(seed=f"4_{room}"),
globals.make_event_id(seed=f"5_{room}"),
globals.make_event_id(seed=f"6_{room}"),
]
create_event = {
"content": {
"m.federate": True,
"creator": f"@vona:{config.server_name}",
"room_version": globals.room_version_from_id(room)
},
"event_id": event_ids[0],
"origin_server_ts": 1,
"room_id": room,
"sender": f"@vona:{config.server_name}",
"state_key": "",
"depth": 1,
"type": "m.room.create",
"auth_events": [],
"prev_events": []
}
screate_event = globals.hash_and_sign_event(create_event)
event_chain.append(screate_event)
our_join = {
"content": {
"displayname": "Vona",
"avatar_url": f"mxc://{config.server_name}/cat",
"membership": "join"
},
"origin_server_ts": 2,
"sender": f"@vona:{config.server_name}",
"state_key": f"@vona:{config.server_name}",
"type": "m.room.member",
"event_id": event_ids[1],
"room_id": room,
"depth": 2,
"auth_events": [[
screate_event["event_id"],
screate_event["hashes"]
]],
"prev_events": [[
screate_event["event_id"],
screate_event["hashes"]
]]
}
sour_join = globals.hash_and_sign_event(our_join)
event_chain.append(sour_join)
pls = {
"content": {
"users": {
f"@vona:{config.server_name}": "100"
}
},
"origin_server_ts": 3,
"room_id": room,
"sender": f"@vona:{config.server_name}",
"state_key": "",
"type": "m.room.power_levels",
"event_id": event_ids[2],
"depth": 3,
"user_id": f"@vona:{config.server_name}",
"auth_events": [
[
screate_event["event_id"],
screate_event["hashes"]
],
[
sour_join["event_id"],
sour_join["hashes"]
]
],
"prev_events": [[
sour_join["event_id"],
sour_join["hashes"]
]]
}
spls = globals.hash_and_sign_event(pls)
event_chain.append(spls)
join_rule = {
"content": {
"join_rule": "public"
},
"origin_server_ts": 4,
"sender": f"@vona:{config.server_name}",
"state_key": "",
"type": "m.room.join_rules",
"event_id": event_ids[3],
"room_id": room,
"depth": 4,
"auth_events": [
[
screate_event["event_id"],
screate_event["hashes"]
],
[
sour_join["event_id"],
sour_join["hashes"]
],
[
spls["event_id"],
spls["hashes"]
]
],
"prev_events": [[
spls["event_id"],
spls["hashes"]
]]
}
sjoin_rule = globals.hash_and_sign_event(join_rule)
event_chain.append(sjoin_rule)
guest_access = {
"content": {
"guest_access": "forbidden"
},
"origin_server_ts": 5,
"depth": 5,
"sender": f"@vona:{config.server_name}",
"state_key": "",
"type": "m.room.guest_access",
"event_id": event_ids[4],
"room_id": room,
"auth_events": [
[
screate_event["event_id"],
screate_event["hashes"]
],
[
sour_join["event_id"],
sour_join["hashes"]
],
[
spls["event_id"],
spls["hashes"]
]
],
"prev_events": [[
sjoin_rule["event_id"],
sjoin_rule["hashes"]
]]
}
sguest_access = globals.hash_and_sign_event(guest_access)
event_chain.append(sguest_access)
history = {
"content": {
"history_visibility": "shared"
},
"type": "m.room.history_visibility",
"sender": f"@vona:{config.server_name}",
"state_key": "",
"origin_server_ts": 6,
"depth": 6,
"event_id": event_ids[5],
"room_id": room,
"auth_events": [
[
screate_event["event_id"],
screate_event["hashes"]
],
[
sour_join["event_id"],
sour_join["hashes"]
],
[
spls["event_id"],
spls["hashes"]
]
],
"prev_events": [[
sguest_access["event_id"],
sguest_access["hashes"]
]]
}
shistory = globals.hash_and_sign_event(history)
event_chain.append(shistory)
remote_join = request.get_json()
response = {
"auth_chain": event_chain,
"event": remote_join,
"members_omitted": False,
"servers_in_room": [config.server_name],
"state": event_chain
}
return response

View File

@@ -7,7 +7,6 @@ import hashlib
import base64 import base64
import random import random
import httpx import httpx
import copy
import json import json
import re import re
@@ -263,14 +262,15 @@ def make_ref_hash(
def room_version_from_id(room): def room_version_from_id(room):
room_id_no_sigil = room.replace("!", "") room_id_no_sigil = room.replace("!", "")
hexadecimal_room_id = bytes(room_id_no_sigil, "utf-8").hex() hexadecimal_room_id = bytes(room_id_no_sigil, "utf-8").hex()
if "1" not in hexadecimal_room_id and "2" not in hexadecimal_room_id: versions = [str(i) for i in range(1, 3)]
hexadecimal_room_id = "1" + hexadecimal_room_id[1:]
if not any(ver in hexadecimal_room_id for ver in versions):
hexadecimal_room_id = "2" + hexadecimal_room_id[1:]
def remove_chars(s): def remove_chars(s):
return re.sub("[^12]", "", s) return re.sub(f"[^{''.join(versions)}]", "", s)
nums = remove_chars(hexadecimal_room_id) nums = remove_chars(hexadecimal_room_id)
@@ -278,9 +278,9 @@ def room_version_from_id(room):
s = s.replace(" ", "").lower() s = s.replace(" ", "").lower()
counts = Counter(s) counts = Counter(s)
most_common = counts.most_common(1) most_common = counts.most_common(1)
return most_common[0] if most_common else None return most_common[0] if most_common else ("2",)
return most_common_character(nums)[0] return str(most_common_character(nums)[0])
room_dir = { room_dir = {

View File

@@ -133,11 +133,11 @@ async def invite():
"public_keys": [ "public_keys": [
{ {
"key_validity_url": f"https://{server_name}/_matrix/identity/v2/pubkey/isvalid", "key_validity_url": f"https://{server_name}/_matrix/identity/v2/pubkey/isvalid",
"public_key":"ohyeah" "public_key": "ohyeah"
}, },
{ {
"key_validity_url": f"https://{server_name}/_matrix/identity/v2/pubkey/ephemeral/isvalid", "key_validity_url": f"https://{server_name}/_matrix/identity/v2/pubkey/ephemeral/isvalid",
"public_key":"thisssssss" "public_key": "burgerkingfootlettuce"
} }
], ],
"token": "vona" "token": "vona"
@@ -148,10 +148,10 @@ async def invite():
@identity.route("/_matrix/identity/v2/sign-ed25519", methods=["POST"]) @identity.route("/_matrix/identity/v2/sign-ed25519", methods=["POST"])
async def invite_signing(): async def invite_signing():
required_keys = {"mxid", "private_key", "token"} required_keys = {"mxid", "private_key", "token"}
d = data.get_json() d = request.data.get_json()
if set(d.keys()) == required_keys: if set(d.keys()) == required_keys:
return jsonify(sign_json(d)) return jsonify(globals.sign_json(d))
else: else:
return jsonify({ return jsonify({
"errcode": "M_UNRECOGNIZED", "errcode": "M_UNRECOGNIZED",