The Codebase Consistency Update

This commit is contained in:
2025-10-21 23:47:28 -04:00
parent 458d69da84
commit 6cc08fcb02
21 changed files with 339 additions and 130 deletions

View File

@@ -1 +1,2 @@
- use `resolvematrix` async instead of sync - use `resolvematrix` async instead of sync
- implement groups over federation

View File

@@ -1 +0,0 @@
# read __main__.py

View File

@@ -1,4 +1,3 @@
from flask import Flask, jsonify, request, redirect
import vona.globals as globals import vona.globals as globals
from datetime import datetime from datetime import datetime
import vona.config as config import vona.config as config
@@ -6,6 +5,14 @@ import threading
import logging import logging
import os import os
from flask import (
Flask,
jsonify,
request,
redirect,
abort,
)
from vona.federation import server from vona.federation import server
from vona.custom import custom from vona.custom import custom
from vona.identity import identity from vona.identity import identity

View File

@@ -1,7 +1,11 @@
from flask import Blueprint, jsonify
from vona.config import the_funny_number from vona.config import the_funny_number
import asyncio import asyncio
from flask import (
Blueprint,
jsonify,
)
apps = Blueprint("appservice", __name__) apps = Blueprint("appservice", __name__)
# This implements both being a homeserver and # This implements both being a homeserver and
@@ -10,6 +14,7 @@ apps = Blueprint("appservice", __name__)
# Endpoints invoked by the homeserver are put # Endpoints invoked by the homeserver are put
# lower than ones invoked by the appservice. # lower than ones invoked by the appservice.
@apps.route("/_matrix/client/v1/appservice/<app>/ping", methods=["POST"]) @apps.route("/_matrix/client/v1/appservice/<app>/ping", methods=["POST"])
async def homeserver_ping(app): async def homeserver_ping(app):
# Sleeping here makes it more realistic # Sleeping here makes it more realistic

View File

@@ -1,12 +1,23 @@
from flask import Blueprint, jsonify, request, send_file
from vona.federation import send_join 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 asyncio import asyncio
import random import random
import os import os
client = Blueprint("c2s", __name__) from flask import (
Blueprint,
jsonify,
request,
send_file,
)
client = Blueprint("client", __name__)
from .groups import groups
client.register_blueprint(groups)
@client.route("/_matrix/client/v3/account/password", methods=["POST"]) @client.route("/_matrix/client/v3/account/password", methods=["POST"])
@@ -22,10 +33,10 @@ client = Blueprint("c2s", __name__)
@client.route("/_matrix/client/v3/logout", methods=["POST"]) @client.route("/_matrix/client/v3/logout", methods=["POST"])
@client.route("/_matrix/client/r0/logout", methods=["POST"]) @client.route("/_matrix/client/r0/logout", methods=["POST"])
@client.route("/_matrix/client/v3/rooms/<room>/invite", methods=["POST"]) @client.route("/_matrix/client/v3/rooms/<room>/invite", methods=["POST"])
@client.route("/_matrix/client/v3/rooms/<roomId>/leave", methods=["POST"]) @client.route("/_matrix/client/v3/rooms/<room>/leave", methods=["POST"])
@client.route("/_matrix/client/r0/rooms/<roomId>/leave", methods=["POST"]) @client.route("/_matrix/client/r0/rooms/<room>/leave", methods=["POST"])
@client.route("/_matrix/client/v3/rooms/<roomId>/read_markers", methods=["POST"]) @client.route("/_matrix/client/v3/rooms/<room>/read_markers", methods=["POST"])
@client.route("/_matrix/client/r0/rooms/<roomId>/read_markers", methods=["POST"]) @client.route("/_matrix/client/r0/rooms/<room>/read_markers", methods=["POST"])
@client.route("/_matrix/client/v3/rooms/<room>/typing/<user>", methods=["PUT"]) @client.route("/_matrix/client/v3/rooms/<room>/typing/<user>", methods=["PUT"])
@client.route("/_matrix/client/api/v1/rooms/<room>/typing/<user>", methods=["PUT"]) @client.route("/_matrix/client/api/v1/rooms/<room>/typing/<user>", methods=["PUT"])
@client.route("/_matrix/client/v3/keys/device_signing/upload", methods=["POST"]) @client.route("/_matrix/client/v3/keys/device_signing/upload", methods=["POST"])
@@ -101,10 +112,10 @@ async def lock(user):
return jsonify({"locked": True}) return jsonify({"locked": True})
@client.route("/_matrix/client/api/v1/rooms/<roomId>/members") @client.route("/_matrix/client/api/v1/rooms/<room>/members")
@client.route("/_matrix/client/v3/rooms/<roomId>/members") @client.route("/_matrix/client/v3/rooms/<room>/members")
@client.route("/_matrix/client/r0/rooms/<roomId>/members") @client.route("/_matrix/client/r0/rooms/<room>/members")
async def room_members(roomId): async def room_members(room):
return jsonify({ return jsonify({
"chunk": [{ "chunk": [{
"content": { "content": {
@@ -112,9 +123,9 @@ async def room_members(roomId):
"displayname": "Vona", "displayname": "Vona",
"membership": "join" "membership": "join"
}, },
"event_id": globals.make_event_id(seed=roomId), "event_id": globals.make_event_id(seed=room),
"origin_server_ts": config.the_funny_number, "origin_server_ts": config.the_funny_number,
"room_id": roomId, "room_id": room,
"sender": f"@vona:{config.server_name}", "sender": f"@vona:{config.server_name}",
"state_key": f"@vona:{config.server_name}", "state_key": f"@vona:{config.server_name}",
"type": "m.room.member", "type": "m.room.member",
@@ -489,10 +500,10 @@ async def refresh():
}) })
@client.route("/_matrix/client/unstable/im.nheko.summary/rooms/<roomId>/summary") @client.route("/_matrix/client/unstable/im.nheko.summary/rooms/<room>/summary")
@client.route("/_matrix/client/unstable/im.nheko.summary/summary/<roomId>") @client.route("/_matrix/client/unstable/im.nheko.summary/summary/<room>")
@client.route("/_matrix/client/v1/room_summary/<roomId>") @client.route("/_matrix/client/v1/room_summary/<room>")
async def room_summary(roomId): async def room_summary(room):
return jsonify({ return jsonify({
"room_id": globals.make_event_id().replace("$", "!"), "room_id": globals.make_event_id().replace("$", "!"),
"avatar_url": f"mxc://{config.server_name}/cat", "avatar_url": f"mxc://{config.server_name}/cat",
@@ -504,7 +515,7 @@ async def room_summary(roomId):
"join_rule": "public", "join_rule": "public",
"room_type": "m.room", "room_type": "m.room",
"membership": "join", "membership": "join",
"room_version": globals.room_version_from_id(roomId) "room_version": globals.room_version_from_id(room)
}) })
@@ -627,10 +638,10 @@ async def media_config():
return jsonify({"m.upload.size": config.the_funny_number * 69420}) return jsonify({"m.upload.size": config.the_funny_number * 69420})
@client.route("/_matrix/client/api/v1/profile/<userId>/<key>", methods=["GET", "PUT", "DELETE"]) @client.route("/_matrix/client/api/v1/profile/<user>/<key>", methods=["GET", "PUT", "DELETE"])
@client.route("/_matrix/client/v3/profile/<userId>/<key>", methods=["GET", "PUT", "DELETE"]) @client.route("/_matrix/client/v3/profile/<user>/<key>", methods=["GET", "PUT", "DELETE"])
@client.route("/_matrix/client/r0/profile/<userId>/<key>", methods=["GET", "PUT", "DELETE"]) @client.route("/_matrix/client/r0/profile/<user>/<key>", methods=["GET", "PUT", "DELETE"])
async def profile_keys(userId, key): async def profile_keys(user, key):
if request.method == "GET": if request.method == "GET":
if key == "avatar_url": if key == "avatar_url":
return jsonify({"avatar_url": f"mxc://{config.server_name}/cat"}) return jsonify({"avatar_url": f"mxc://{config.server_name}/cat"})
@@ -645,19 +656,19 @@ async def profile_keys(userId, key):
return jsonify({}) return jsonify({})
@client.route("/_matrix/client/v3/profile/<userId>") @client.route("/_matrix/client/v3/profile/<user>")
@client.route("/_matrix/client/r0/profile/<userId>") @client.route("/_matrix/client/r0/profile/<user>")
async def user_profile(userId): async def user_profile(user):
return jsonify({ return jsonify({
"avatar_url": f"mxc://{config.server_name}/cat", "avatar_url": f"mxc://{config.server_name}/cat",
"displayname": "Vona" "displayname": "Vona"
}) })
@client.route("/_matrix/client/api/v1/rooms/<roomId>/messages") @client.route("/_matrix/client/api/v1/rooms/<room>/messages")
@client.route("/_matrix/client/v3/rooms/<roomId>/messages") @client.route("/_matrix/client/v3/rooms/<room>/messages")
@client.route("/_matrix/client/r0/rooms/<roomId>/messages") @client.route("/_matrix/client/r0/rooms/<room>/messages")
async def room_messages(roomId): async def room_messages(room):
return jsonify({ return jsonify({
"chunk": [{ "chunk": [{
"content": { "content": {
@@ -668,7 +679,7 @@ async def room_messages(roomId):
}, },
"event_id": globals.make_event_id(), "event_id": globals.make_event_id(),
"origin_server_ts": config.the_funny_number, "origin_server_ts": config.the_funny_number,
"room_id": roomId, "room_id": room,
"sender": f"@vona:{config.server_name}", "sender": f"@vona:{config.server_name}",
"type": "m.room.message" "type": "m.room.message"
}], }],

120
vona/client/groups.py Normal file
View File

@@ -0,0 +1,120 @@
import vona.globals as globals
import vona.config as config
import time
from flask import (
Blueprint,
jsonify,
request,
)
groups = Blueprint("groups", __name__)
# This implements the C2S API for groups
@groups.route("/_matrix/client/r0/groups/<group>/self/update_publicity", methods=["PUT"])
@groups.route("/_matrix/client/r0/groups/<group>/self/accept_invite", methods=["PUT"])
@groups.route("/_matrix/client/r0/groups/<group>/self/leave", methods=["PUT"])
@groups.route("/_matrix/client/r0/groups/<group>/admin/users/remove/<user>", methods=["PUT"])
@groups.route("/_matrix/client/r0/groups/<group>/admin/rooms/<room>", methods=["PUT", "DELETE"])
async def empty(**k):
return jsonify({})
@groups.route("/_matrix/client/r0/publicised_groups/<user>")
@groups.route("/_matrix/client/r0/joined_groups")
async def joined_groups(user=None):
return jsonify({
"groups": [f"+vona:{config.server_name}"]
})
@groups.route("/_matrix/client/r0/groups/<group>/summary")
async def summary(group):
return jsonify({
"profile": {
"name": "Vona",
"short_description": "",
"long_description": "",
"avatar_url": "",
"is_public": 1,
"is_openly_joinable": True
},
"users_section": {
"users": [],
"roles": {},
"total_user_count_estimate": 0
},
"rooms_section": {
"rooms": [],
"categories": {},
"total_room_count_estimate": 0
},
"user": {
"membership": "join",
"is_public": 1,
"is_privileged": 1,
"is_publicised": True
}
})
@groups.route("/_matrix/client/r0/groups/<group>/rooms")
async def rooms(group):
return jsonify({
"chunk": [],
"total_room_count_estimate": 0
})
@groups.route("/_matrix/client/r0/groups/<group>/invited_users")
async def invited_users(group):
return jsonify({
"chunk": [],
"total_user_count_estimate": 0
})
@groups.route("/_matrix/client/r0/groups/<group>/users")
async def users(group):
return jsonify({
"chunk": [
{
"user_id": f"@vona:{config.server_name}",
"displayname": "Vona",
"avatar_url": None,
"is_public": True,
"is_privileged": True,
"attestation": globals.sign_json({
"group_id": group,
"user_id": f"@vona:{config.server_name}",
"valid_until_ms": int(str(time.time() * 1000).split(".")[0])
})
}
],
"total_user_count_estimate": 1
})
@groups.route("/_matrix/client/r0/groups/<group>/profile", methods=["GET", "POST"])
async def profile(group):
if request.method == "POST":
return jsonify({})
return jsonify({
"name": "Vona",
"short_description": "",
"long_description": "",
"avatar_url": "",
"is_public": 1,
"is_openly_joinable": True
})
@groups.route("/_matrix/client/r0/create_group", methods=["POST"])
async def create_group():
return jsonify({
"group_id": f"+vona:{config.server_name}"
})

View File

@@ -1,6 +1,7 @@
import os
from pathlib import Path from pathlib import Path
import tomllib import tomllib
import os
addr: str = "127.0.0.1" addr: str = "127.0.0.1"
port: int = 5000 port: int = 5000

View File

@@ -1,4 +1,6 @@
from flask import Blueprint from flask import (
Blueprint,
)
custom = Blueprint("custom", __name__) custom = Blueprint("custom", __name__)

View File

@@ -1,8 +1,14 @@
from flask import Blueprint, jsonify, request
import vona.config as config import vona.config as config
import base64 import base64
import os import os
from flask import (
Blueprint,
jsonify,
request,
)
citadel = Blueprint("citadel", __name__) citadel = Blueprint("citadel", __name__)
# These are endpoints made by Thales Citadel # These are endpoints made by Thales Citadel

View File

@@ -1,5 +1,8 @@
from flask import Blueprint, jsonify
import vona.globals as globals import vona.globals as globals
from flask import (
Blueprint,
jsonify,
)
conduwuit = Blueprint("conduwuit", __name__) conduwuit = Blueprint("conduwuit", __name__)

View File

@@ -1,10 +1,13 @@
from flask import Blueprint, jsonify
import vona.globals as globals import vona.globals as globals
import vona.config as config import vona.config as config
from flask import (
Blueprint,
jsonify,
)
dendrite = Blueprint("dendrite", __name__) dendrite = Blueprint("dendrite", __name__)
# https://element-hq.github.io/dendrite/administration/adminapi # This implements the Dendrite admin API
@dendrite.route("/_dendrite/admin/purgeRoom/<room>", methods=["POST"]) @dendrite.route("/_dendrite/admin/purgeRoom/<room>", methods=["POST"])

View File

@@ -1,4 +1,3 @@
from flask import Blueprint, request, jsonify
from vona.config import the_funny_number 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
@@ -6,6 +5,12 @@ import vona.globals as globals
import vona.config as config import vona.config as config
import time import time
from flask import (
Blueprint,
request,
jsonify,
)
hammerhead = Blueprint("hammerhead", __name__) hammerhead = Blueprint("hammerhead", __name__)
# Hammerhead endpoints. Not documented, but code is at: # Hammerhead endpoints. Not documented, but code is at:

View File

@@ -1,24 +1,31 @@
from flask import Blueprint, jsonify, request, Response
from vona.federation import send_join 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 base64
import re import re
import os import os
from flask import (
Blueprint,
jsonify,
request,
Response,
)
synapse = Blueprint("synapse", __name__) synapse = Blueprint("synapse", __name__)
# The absolute giant known as the Synapse admin API. # The absolute giant known as the Synapse admin API.
# Very messy, needs cleaning # TODO: Very messy, needs cleaning
@synapse.route("/_synapse/admin/v1/suspend/<user_id>", methods=["PUT"]) @synapse.route("/_synapse/admin/v1/suspend/<user>", methods=["PUT"])
@synapse.route("/_synapse/admin/v1/deactivate/<user_id>", methods=["POST"]) @synapse.route("/_synapse/admin/v1/deactivate/<user>", methods=["POST"])
@synapse.route("/_synapse/admin/v1/reset_password/<user_id>", methods=["POST"]) @synapse.route("/_synapse/admin/v1/reset_password/<user>", methods=["POST"])
@synapse.route("/_synapse/admin/v1/users/<user_id>/admin", methods=["PUT"]) @synapse.route("/_synapse/admin/v1/users/<user>/admin", methods=["PUT"])
@synapse.route("/_synapse/admin/v2/users/<user_id>/delete_devices", methods=["POST"]) @synapse.route("/_synapse/admin/v2/users/<user>/delete_devices", methods=["POST"])
@synapse.route("/_synapse/admin/v1/users/<user_id>/shadow_ban", methods=["DELETE", "POST"]) @synapse.route("/_synapse/admin/v1/users/<user>/shadow_ban", methods=["DELETE", "POST"])
@synapse.route("/_synapse/admin/v1/users/<user_id>/override_ratelimit", methods=["GET", "POST", "DELETE"]) @synapse.route("/_synapse/admin/v1/users/<user>/override_ratelimit", methods=["GET", "POST", "DELETE"])
@synapse.route("/_synapse/admin/v1/media/protect/<media_id>", methods=["POST"]) @synapse.route("/_synapse/admin/v1/media/protect/<media_id>", methods=["POST"])
@synapse.route("/_synapse/admin/v1/media/unprotect/<media_id>", methods=["POST"]) @synapse.route("/_synapse/admin/v1/media/unprotect/<media_id>", methods=["POST"])
@synapse.route("/_synapse/admin/v1/media/quarantine/<s>/<media_id>", methods=["POST"]) @synapse.route("/_synapse/admin/v1/media/quarantine/<s>/<media_id>", methods=["POST"])
@@ -57,7 +64,7 @@ async def user_list():
"total": 1 "total": 1
}) })
@synapse.route("/_synapse/admin/v2/users/<user_id>", methods=["GET", "PUT"]) @synapse.route("/_synapse/admin/v2/users/<user>", methods=["GET", "PUT"])
async def user_info(user_id): async def user_info(user_id):
if request.method == "GET": if request.method == "GET":
return jsonify({ return jsonify({
@@ -84,7 +91,7 @@ async def user_info(user_id):
return jsonify({}), 201 return jsonify({}), 201
@synapse.route("/_synapse/admin/v1/whois/<user_id>") @synapse.route("/_synapse/admin/v1/whois/<user>")
async def whois(user_id): async def whois(user_id):
return jsonify({ return jsonify({
"user_id": f"@vona:{config.server_name}", "user_id": f"@vona:{config.server_name}",
@@ -101,22 +108,22 @@ async def whois(user_id):
} }
}) })
@synapse.route("/_synapse/admin/v1/users/<user_id>/joined_rooms") @synapse.route("/_synapse/admin/v1/users/<user>/joined_rooms")
async def user_joined_rooms(user_id): async def user_joined_rooms(user_id):
return jsonify({ return jsonify({
"joined_rooms": [globals.make_event_id().replace("$", "!")], "joined_rooms": [globals.make_event_id().replace("$", "!")],
"total": 1 "total": 1
}) })
@synapse.route("/_synapse/admin/v1/users/<user_id>/sent_invite_count") @synapse.route("/_synapse/admin/v1/users/<user>/sent_invite_count")
async def invite_count(user_id): async def invite_count(user_id):
return jsonify({"invite_count": config.the_funny_number}) return jsonify({"invite_count": config.the_funny_number})
@synapse.route("/_synapse/admin/v1/users/<user_id>/accountdata") @synapse.route("/_synapse/admin/v1/users/<user>/accountdata")
async def account_data(user_id): async def account_data(user_id):
return jsonify({"account_data":{"global":{}}}) return jsonify({"account_data":{"global":{}}})
@synapse.route("/_synapse/admin/v1/users/<user_id>/media", methods=["GET", "DELETE"]) @synapse.route("/_synapse/admin/v1/users/<user>/media", methods=["GET", "DELETE"])
async def account_media(user_id): async def account_media(user_id):
if request.method == "GET": if request.method == "GET":
return jsonify({ return jsonify({
@@ -138,15 +145,15 @@ async def account_media(user_id):
"total": config.the_funny_number "total": config.the_funny_number
}) })
@synapse.route("/_synapse/admin/v1/users/<user_id>/login", methods=["POST"]) @synapse.route("/_synapse/admin/v1/users/<user>/login", methods=["POST"])
async def account_login(user_id): async def account_login(user_id):
return jsonify({"access_token": "vona"}) return jsonify({"access_token": "vona"})
@synapse.route("/_synapse/admin/v1/users/<user_id>/_allow_cross_signing_replacement_without_uia", methods=["POST"]) @synapse.route("/_synapse/admin/v1/users/<user>/_allow_cross_signing_replacement_without_uia", methods=["POST"])
async def stupid_mas_bullshit(user_id): async def stupid_mas_bullshit(user_id):
return jsonify({"updatable_without_uia_before_ms": config.the_funny_number}) return jsonify({"updatable_without_uia_before_ms": config.the_funny_number})
@synapse.route("/_synapse/admin/v2/users/<user_id>/devices", methods=["GET", "POST"]) @synapse.route("/_synapse/admin/v2/users/<user>/devices", methods=["GET", "POST"])
async def device_list(user_id): async def device_list(user_id):
if request.method == "GET": if request.method == "GET":
return jsonify({ return jsonify({
@@ -162,7 +169,7 @@ async def device_list(user_id):
return jsonify({}) return jsonify({})
@synapse.route("/_synapse/admin/v2/users/<user_id>/devices/<device_id>", methods=["GET", "PUT", "DELETE"]) @synapse.route("/_synapse/admin/v2/users/<user>/devices/<device_id>", methods=["GET", "PUT", "DELETE"])
async def device_info(user_id, device_id): async def device_info(user_id, device_id):
if request.method == "GET": if request.method == "GET":
return jsonify({ return jsonify({
@@ -175,7 +182,7 @@ async def device_info(user_id, device_id):
return jsonify({}) return jsonify({})
@synapse.route("/_synapse/admin/v1/users/<user_id>/pushers") @synapse.route("/_synapse/admin/v1/users/<user>/pushers")
async def pushers(user_id): async def pushers(user_id):
return jsonify({"pushers": [], "total": config.the_funny_number}) return jsonify({"pushers": [], "total": config.the_funny_number})
@@ -188,7 +195,7 @@ async def username_available():
async def threepid(**kwargs): async def threepid(**kwargs):
return jsonify({"user_id": f"@vona:{config.server_name}"}) return jsonify({"user_id": f"@vona:{config.server_name}"})
@synapse.route("/_synapse/admin/v1/<user_id>/redact") @synapse.route("/_synapse/admin/v1/<user>/redact")
async def redact(user_id): async def redact(user_id):
return jsonify({"redact_id": os.urandom(16).hex()}) return jsonify({"redact_id": os.urandom(16).hex()})
@@ -196,7 +203,7 @@ async def redact(user_id):
async def redact_status(redact_id): async def redact_status(redact_id):
return jsonify({"status":"active","failed_redactions":[]}) return jsonify({"status":"active","failed_redactions":[]})
@synapse.route("/_synapse/admin/v1/experimental_features/<user_id>", methods=["GET", "PUT"]) @synapse.route("/_synapse/admin/v1/experimental_features/<user>", methods=["GET", "PUT"])
async def experimental_features(user_id): async def experimental_features(user_id):
return jsonify({"features": {}}) return jsonify({"features": {}})

View File

@@ -1,7 +1,12 @@
from flask import Blueprint, request, jsonify
from vona.globals import version from vona.globals import version
import vona.config as config import vona.config as config
from flask import (
Blueprint,
request,
jsonify,
)
telo = Blueprint("telodendria", __name__) telo = Blueprint("telodendria", __name__)
# The telodendria admin API as specified by # The telodendria admin API as specified by

View File

@@ -1,8 +1,18 @@
from flask import jsonify, Response, request, send_file, abort, Blueprint
import json, time, os, threading
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 time
import os
from flask import (
jsonify,
Response,
request,
send_file,
Blueprint,
)
server = Blueprint("federation", __name__) server = Blueprint("federation", __name__)
http = globals.http_client() http = globals.http_client()
@@ -12,28 +22,28 @@ class bullshit:
def get_json(): def get_json():
return {} return {}
def send_join(request, roomId) -> dict: def send_join(request, room) -> dict:
event_chain = [] event_chain = []
event_hashes = [] event_hashes = []
event_ids = [ event_ids = [
globals.make_event_id(seed=f"1_{roomId}"), globals.make_event_id(seed=f"1_{room}"),
globals.make_event_id(seed=f"2_{roomId}"), globals.make_event_id(seed=f"2_{room}"),
globals.make_event_id(seed=f"3_{roomId}"), globals.make_event_id(seed=f"3_{room}"),
globals.make_event_id(seed=f"4_{roomId}"), globals.make_event_id(seed=f"4_{room}"),
globals.make_event_id(seed=f"5_{roomId}"), globals.make_event_id(seed=f"5_{room}"),
globals.make_event_id(seed=f"6_{roomId}"), globals.make_event_id(seed=f"6_{room}"),
] ]
create_event = { create_event = {
"content": { "content": {
"m.federate": True, "m.federate": True,
"creator": f"@vona:{config.server_name}", "creator": f"@vona:{config.server_name}",
"room_version": globals.room_version_from_id(roomId) "room_version": globals.room_version_from_id(room)
}, },
"event_id": event_ids[0], "event_id": event_ids[0],
"origin_server_ts": 1, "origin_server_ts": 1,
"room_id": roomId, "room_id": room,
"sender": f"@vona:{config.server_name}", "sender": f"@vona:{config.server_name}",
"state_key": "", "state_key": "",
"depth": 1, "depth": 1,
@@ -56,7 +66,7 @@ def send_join(request, roomId) -> dict:
"state_key": f"@vona:{config.server_name}", "state_key": f"@vona:{config.server_name}",
"type": "m.room.member", "type": "m.room.member",
"event_id": event_ids[1], "event_id": event_ids[1],
"room_id": roomId, "room_id": room,
"depth": 2, "depth": 2,
"auth_events": [[ "auth_events": [[
screate_event["event_id"], screate_event["event_id"],
@@ -78,7 +88,7 @@ def send_join(request, roomId) -> dict:
} }
}, },
"origin_server_ts": 3, "origin_server_ts": 3,
"room_id": roomId, "room_id": room,
"sender": f"@vona:{config.server_name}", "sender": f"@vona:{config.server_name}",
"state_key": "", "state_key": "",
"type": "m.room.power_levels", "type": "m.room.power_levels",
@@ -113,7 +123,7 @@ def send_join(request, roomId) -> dict:
"state_key": "", "state_key": "",
"type": "m.room.join_rules", "type": "m.room.join_rules",
"event_id": event_ids[3], "event_id": event_ids[3],
"room_id": roomId, "room_id": room,
"depth": 4, "depth": 4,
"auth_events": [ "auth_events": [
[ [
@@ -148,7 +158,7 @@ def send_join(request, roomId) -> dict:
"state_key": "", "state_key": "",
"type": "m.room.guest_access", "type": "m.room.guest_access",
"event_id": event_ids[4], "event_id": event_ids[4],
"room_id": roomId, "room_id": room,
"auth_events": [ "auth_events": [
[ [
screate_event["event_id"], screate_event["event_id"],
@@ -182,7 +192,7 @@ def send_join(request, roomId) -> dict:
"origin_server_ts": 6, "origin_server_ts": 6,
"depth": 6, "depth": 6,
"event_id": event_ids[5], "event_id": event_ids[5],
"room_id": roomId, "room_id": room,
"auth_events": [ "auth_events": [
[ [
screate_event["event_id"], screate_event["event_id"],
@@ -278,16 +288,16 @@ 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/<roomId>/<eventId>", methods=["PUT"]) @server.route("/_matrix/federation/v1/send_join/<room>/<eventId>", methods=["PUT"])
async def send_join_v1(roomId, eventId): async def send_join_v1(room, eventId):
return jsonify([200, send_join(request, roomId)]) return jsonify([200, send_join(request, room)])
@server.route("/_matrix/federation/v2/send_join/<roomId>/<eventId>", methods=["PUT"]) @server.route("/_matrix/federation/v2/send_join/<room>/<eventId>", methods=["PUT"])
async def send_join_v2(roomId, eventId): async def send_join_v2(room, eventId):
return jsonify(send_join(request, roomId)) return jsonify(send_join(request, room))
@server.route("/_matrix/federation/v1/make_join/<roomId>/<userId>") @server.route("/_matrix/federation/v1/make_join/<room>/<user>")
async def make_join(roomId, userId): async def make_join(room, user):
def not_invited(): def not_invited():
return jsonify({ return jsonify({
"errcode": "M_FORBIDDEN", "errcode": "M_FORBIDDEN",
@@ -295,14 +305,14 @@ async def make_join(roomId, userId):
}), 403 }), 403
try: try:
if roomId.split(":")[1] != config.server_name: if room.split(":")[1] != config.server_name:
return not_invited() return not_invited()
except: except:
return not_invited() return not_invited()
state = send_join( state = send_join(
request=bullshit, request=bullshit,
roomId=roomId room=room
)["state"] )["state"]
join = { join = {
@@ -312,9 +322,9 @@ async def make_join(roomId, userId):
}, },
"origin": config.server_name, "origin": config.server_name,
"origin_server_ts": 7, "origin_server_ts": 7,
"room_id": roomId, "room_id": room,
"sender": userId, "sender": user,
"state_key": userId, "state_key": user,
"type": "m.room.member", "type": "m.room.member",
"depth": 7 "depth": 7
} }
@@ -341,7 +351,7 @@ async def make_join(roomId, userId):
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(roomId) "room_version": globals.room_version_from_id(room)
}) })
@@ -415,15 +425,6 @@ async def user_keys():
@server.route("/_matrix/federation/v2/invite/<room>/<txnId>", methods=["PUT"]) @server.route("/_matrix/federation/v2/invite/<room>/<txnId>", methods=["PUT"])
async def invite_user_v2(room, txnId): async def invite_user_v2(room, txnId):
return invite_user(request.data)
@server.route("/_matrix/federation/v1/invite/<room>/<txnId>", methods=["PUT"])
async def invite_user_v1(room, txnId):
return [200, invite_user(request.json)]
def invite_user(invite_data):
if "event" in invite_data: if "event" in invite_data:
if "room_version" in invite_data: if "room_version" in invite_data:
if invite_data["room_version"] not in ["1", "2"]: if invite_data["room_version"] not in ["1", "2"]:
@@ -436,7 +437,6 @@ def invite_user(invite_data):
event = invite_data.get("event", {}) event = invite_data.get("event", {})
content = event.get("content", {}) content = event.get("content", {})
# NOTE to crispycat: I know you loooooove this syntax
if ( if (
"content" in event "content" in event
and "membership" in content and "membership" in content
@@ -446,7 +446,7 @@ def invite_user(invite_data):
and event["state_key"] == f"@vona:{config.server_name}" and event["state_key"] == f"@vona:{config.server_name}"
): ):
return jsonify({ return jsonify({
"event": globals.sign_json_without_discard(invite_data["event"]), "event": globals.sign_json_without_discard(event),
"room_version": invite_data["room_version"] "room_version": invite_data["room_version"]
}) })
@@ -457,8 +457,34 @@ def invite_user(invite_data):
}), 403 }), 403
@server.route("/_matrix/federation/v1/hierarchy/<roomId>") @server.route("/_matrix/federation/v1/invite/<room>/<txnId>", methods=["PUT"])
async def space_hierachy(roomId): async def invite_user_v1(room, txnId):
event = request.json
content = event.get("content", {})
if (
"content" in event
and "membership" in content
and "state_key" in event
and "room_id" in event
and content["membership"] == "invite"
and event["state_key"] == f"@vona:{config.server_name}"
and "event_id" in event
and ":" in event["event_id"]
):
return jsonify({
"event": globals.sign_json_without_discard(event),
"room_version": invite_data["room_version"]
})
return jsonify({
"errcode": "M_FORBIDDEN",
"error": "Invalid invitation PDU"
}), 403
@server.route("/_matrix/federation/v1/hierarchy/<room>")
async def space_hierachy(room):
return jsonify({ return jsonify({
"errcode": "M_NOT_FOUND", "errcode": "M_NOT_FOUND",
"error": "Room does not exist." "error": "Room does not exist."

View File

@@ -236,14 +236,13 @@ def hash_and_sign_event(event_object):
return event_object return event_object
def room_version_from_id(room_id): def room_version_from_id(room):
room_id_no_sigil = room_id.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: if "1" not in hexadecimal_room_id and "2" not in hexadecimal_room_id:
# NOTE: v2 if impossible from room ID alone hexadecimal_room_id = "1" + hexadecimal_room_id[1:]
hexadecimal_room_id = "2" + hexadecimal_room_id[1:]
def remove_chars(s): def remove_chars(s):
return re.sub("[^12]", "", s) return re.sub("[^12]", "", s)
@@ -252,11 +251,8 @@ def room_version_from_id(room_id):
def most_common_character(s): def most_common_character(s):
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 None
return most_common_character(nums)[0] return most_common_character(nums)[0]

View File

@@ -1,7 +1,12 @@
from flask import Blueprint, jsonify, request
from vona.config import server_name, the_funny_number from vona.config import server_name, the_funny_number
import time import time
from flask import (
Blueprint,
jsonify,
request,
)
identity = Blueprint("identity", __name__) identity = Blueprint("identity", __name__)
# This implements being an identity server. # This implements being an identity server.

View File

@@ -1,4 +1,8 @@
from flask import jsonify, Blueprint, request from flask import (
jsonify,
Blueprint,
request,
)
policy = Blueprint("policy", __name__) policy = Blueprint("policy", __name__)

View File

@@ -1,7 +1,12 @@
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 time
import json
import httpx
http_client = globals.http_client() http_client = globals.http_client()
versions = [ versions = [

View File

@@ -1,25 +1,23 @@
# Generates a key in the format compatible with Synapse and Vona.
import base64 import base64
import os import os
# Generates a key in the format compatible with Synapse and Vona.
def mkchar() -> str: def mkchar() -> str:
return os.urandom(4).hex()[:1] return os.urandom(4).hex()[:1]
key = ( def random(length):
base64.b64encode(os.urandom(32)) return (
.decode("utf-8")[:43] base64.b64encode(os.urandom(length))
.replace("/", mkchar()) .decode("utf-8")[:length]
.replace("+", mkchar()) .replace("/", mkchar())
) .replace("+", mkchar())
)
key_id = (
base64.b64encode(os.urandom(32)) key = random(43)
.decode("utf-8")[:6] key_id = random(6)
.replace("/", mkchar())
.replace("+", mkchar())
)
print(f"ed25519 {key_id} {key}") print(f"ed25519 {key_id} {key}")