diff --git a/vona/__main__.py b/vona/__main__.py index a25b0a6..46e49cc 100644 --- a/vona/__main__.py +++ b/vona/__main__.py @@ -44,7 +44,7 @@ async def validate_json(): try: request.get_json(force=True) - except Exception as e: + except Exception: return jsonify({"error": "Content not JSON.", "errcode": "M_NOT_JSON"}), 400 diff --git a/vona/client/__init__.py b/vona/client/__init__.py index 6b087f1..ec78af3 100644 --- a/vona/client/__init__.py +++ b/vona/client/__init__.py @@ -621,7 +621,7 @@ async def url_preview(): @client.route("/_matrix/client/v1/media/preview_url") async def media_preview(): 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" return response diff --git a/vona/custom/hammerhead.py b/vona/custom/hammerhead.py index a4e4089..55ac560 100644 --- a/vona/custom/hammerhead.py +++ b/vona/custom/hammerhead.py @@ -1,4 +1,3 @@ -from vona.config import the_funny_number from datetime import datetime, timezone from vona.federation import send_join import vona.globals as globals @@ -7,7 +6,6 @@ import time from flask import ( Blueprint, - request, jsonify, ) diff --git a/vona/custom/synapse.py b/vona/custom/synapse.py index 002f37f..91d171c 100644 --- a/vona/custom/synapse.py +++ b/vona/custom/synapse.py @@ -2,15 +2,12 @@ from vona.federation import send_join import vona.globals as globals import vona.config as config -import base64 -import re import os from flask import ( Blueprint, jsonify, request, - Response, ) synapse = Blueprint("synapse", __name__) @@ -99,7 +96,7 @@ async def whois(user_id): "": { "sessions": [{ "connections": [{ - "ip":f"127.0.0.1", + "ip":"127.0.0.1", "last_seen":config.the_funny_number, "user_agent":f"Vona/{globals.version}" }] diff --git a/vona/federation/__init__.py b/vona/federation/__init__.py index 6618e6d..f888ef0 100644 --- a/vona/federation/__init__.py +++ b/vona/federation/__init__.py @@ -1,16 +1,14 @@ +import vona.federation.rooms as rooms import vona.globals as globals import vona.config as config -import threading import json import time -import os from flask import ( jsonify, Response, request, - send_file, Blueprint, ) @@ -23,210 +21,8 @@ class bullshit: return {} def send_join(request, room) -> dict: - event_chain = [] - event_hashes = [] - - 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 + if globals.room_version_from_id(room) in ["1", "2"]: + return rooms.v1_v2(request, room) @server.route("/_matrix/federation/v1/version") @@ -288,27 +84,39 @@ async def thumbnail_media(media_id): "error": "Cat is too cute to thumbnail" }), 418 + @server.route("/_matrix/federation/v1/send_join//", methods=["PUT"]) 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)]) + @server.route("/_matrix/federation/v2/send_join//", methods=["PUT"]) async def send_join_v2(room, eventId): return jsonify(send_join(request, room)) + @server.route("/_matrix/federation/v1/make_join//") 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({ "errcode": "M_FORBIDDEN", "error": "You are not invited to this room." }), 403 - try: - if room.split(":")[1] != config.server_name: - return not_invited() - except: - return not_invited() + + room_ver = globals.room_version_from_id(room) state = send_join( request=bullshit, @@ -329,29 +137,43 @@ async def make_join(room, user): "depth": 7 } - join["auth_events"] = [ - [ - state[0]["event_id"], - state[0]["hashes"] - ], - [ - state[2]["event_id"], - state[2]["hashes"] - ], - [ - state[3]["event_id"], - state[3]["hashes"] - ] - ] + if room_ver in ["1", "2"]: + join["event_id"] = globals.make_event_id(seed=f"{user}+{room}") + + join["auth_events"] = [ + [ + state[0]["event_id"], + state[0]["hashes"] + ], + [ + state[2]["event_id"], + state[2]["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({ "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"] ): return jsonify({ - "event": globals.sign_json_without_discard(event), - "room_version": invite_data["room_version"] + "event": globals.sign_json_without_discard(event) }) return jsonify({ @@ -550,7 +371,12 @@ async def state_ids(room): event_ids = [] 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: return jsonify({ diff --git a/vona/federation/rooms.py b/vona/federation/rooms.py new file mode 100644 index 0000000..4293a13 --- /dev/null +++ b/vona/federation/rooms.py @@ -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 diff --git a/vona/globals/__init__.py b/vona/globals/__init__.py index 25b4e65..e053f87 100644 --- a/vona/globals/__init__.py +++ b/vona/globals/__init__.py @@ -7,7 +7,6 @@ import hashlib import base64 import random import httpx -import copy import json import re @@ -263,14 +262,15 @@ def make_ref_hash( def room_version_from_id(room): room_id_no_sigil = room.replace("!", "") - 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: - hexadecimal_room_id = "1" + hexadecimal_room_id[1:] + versions = [str(i) for i in range(1, 3)] + + if not any(ver in hexadecimal_room_id for ver in versions): + hexadecimal_room_id = "2" + hexadecimal_room_id[1:] def remove_chars(s): - return re.sub("[^12]", "", s) + return re.sub(f"[^{''.join(versions)}]", "", s) nums = remove_chars(hexadecimal_room_id) @@ -278,9 +278,9 @@ def room_version_from_id(room): s = s.replace(" ", "").lower() counts = Counter(s) 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 = { diff --git a/vona/identity/__init__.py b/vona/identity/__init__.py index 66ffb5d..fd3b8e9 100644 --- a/vona/identity/__init__.py +++ b/vona/identity/__init__.py @@ -133,11 +133,11 @@ async def invite(): "public_keys": [ { "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", - "public_key":"thisssssss" + "public_key": "burgerkingfootlettuce" } ], "token": "vona" @@ -148,10 +148,10 @@ async def invite(): @identity.route("/_matrix/identity/v2/sign-ed25519", methods=["POST"]) async def invite_signing(): required_keys = {"mxid", "private_key", "token"} - d = data.get_json() + d = request.data.get_json() if set(d.keys()) == required_keys: - return jsonify(sign_json(d)) + return jsonify(globals.sign_json(d)) else: return jsonify({ "errcode": "M_UNRECOGNIZED",