This commit is contained in:
2025-09-29 19:15:39 -04:00
parent 57b24e89ee
commit 69e86523fb
7 changed files with 293 additions and 268 deletions

View File

@@ -10,26 +10,26 @@ client = Blueprint("c2s", __name__)
@client.route("/_matrix/client/v3/account/password", methods=["POST"]) @client.route("/_matrix/client/v3/account/password", methods=["POST"])
@client.route('/_matrix/client/v3/user/<user>/account_data/<type>', methods=['GET', 'PUT']) @client.route("/_matrix/client/v3/user/<user>/account_data/<type>", methods=["GET", "PUT"])
@client.route('/_matrix/client/r0/user/<user>/account_data/<type>', methods=['GET', 'PUT']) @client.route("/_matrix/client/r0/user/<user>/account_data/<type>", methods=["GET", "PUT"])
@client.route('/_matrix/client/v3/sendToDevice/<event>/<txnId>', methods=["PUT"]) @client.route("/_matrix/client/v3/sendToDevice/<event>/<txnId>", methods=["PUT"])
@client.route('/_matrix/media/v3/upload/<server>/<media>', methods=["PUT"]) @client.route("/_matrix/media/v3/upload/<server>/<media>", methods=["PUT"])
@client.route('/_matrix/client/v3/thirdparty/protocols') @client.route("/_matrix/client/v3/thirdparty/protocols")
@client.route('/_matrix/client/r0/thirdparty/protocols') @client.route("/_matrix/client/r0/thirdparty/protocols")
@client.route('/_matrix/client/v3/delete_devices', methods=['POST']) @client.route("/_matrix/client/v3/delete_devices", methods=["POST"])
@client.route('/_matrix/client/r0/delete_devices', methods=['POST']) @client.route("/_matrix/client/r0/delete_devices", methods=["POST"])
@client.route('/_matrix/client/v3/logout/all', methods=['POST']) @client.route("/_matrix/client/v3/logout/all", methods=["POST"])
@client.route('/_matrix/client/v3/logout', methods=['POST']) @client.route("/_matrix/client/v3/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/<roomId>/leave", methods=["POST"])
@client.route('/_matrix/client/r0/rooms/<roomId>/leave', methods=['POST']) @client.route("/_matrix/client/r0/rooms/<roomId>/leave", methods=["POST"])
@client.route('/_matrix/client/v3/rooms/<roomId>/read_markers', methods=['POST']) @client.route("/_matrix/client/v3/rooms/<roomId>/read_markers", methods=["POST"])
@client.route('/_matrix/client/r0/rooms/<roomId>/read_markers', methods=['POST']) @client.route("/_matrix/client/r0/rooms/<roomId>/read_markers", methods=["POST"])
@client.route('/_matrix/client/v3/keys/device_signing/upload', methods=['POST']) @client.route("/_matrix/client/v3/keys/device_signing/upload", methods=["POST"])
@client.route("/_matrix/client/v3/rooms/<room>/receipt/<type>/<event>", methods=['POST']) @client.route("/_matrix/client/v3/rooms/<room>/receipt/<type>/<event>", methods=["POST"])
@client.route("/_matrix/client/v3/users/<user>/report", methods=["POST"]) @client.route("/_matrix/client/v3/users/<user>/report", methods=["POST"])
@client.route('/_matrix/client/v3/voip/turnServer') @client.route("/_matrix/client/v3/voip/turnServer")
@client.route('/_matrix/client/r0/voip/turnServer') @client.route("/_matrix/client/r0/voip/turnServer")
@client.route("/_matrix/client/v3/rooms/<r>/report/<e>") @client.route("/_matrix/client/v3/rooms/<r>/report/<e>")
@client.route("/_matrix/client/v3/rooms/<r>/report") @client.route("/_matrix/client/v3/rooms/<r>/report")
@client.route("/_matrix/client/v3/users/<u>/report") @client.route("/_matrix/client/v3/users/<u>/report")
@@ -37,7 +37,7 @@ async def empty_response(**kwargs):
return jsonify({}) return jsonify({})
@client.route('/_matrix/client/versions') @client.route("/_matrix/client/versions")
async def spec_versions(): async def spec_versions():
return jsonify({ return jsonify({
"versions": ( "versions": (
@@ -97,8 +97,8 @@ async def lock(user):
return jsonify({"locked": True}) return jsonify({"locked": True})
@client.route('/_matrix/client/v3/rooms/<roomId>/members') @client.route("/_matrix/client/v3/rooms/<roomId>/members")
@client.route('/_matrix/client/r0/rooms/<roomId>/members') @client.route("/_matrix/client/r0/rooms/<roomId>/members")
async def room_member_count(roomId): async def room_member_count(roomId):
return jsonify({ return jsonify({
"chunk": [{ "chunk": [{
@@ -126,15 +126,15 @@ async def whoami():
}) })
@client.route('/_matrix/client/v3/register', methods=['POST']) @client.route("/_matrix/client/v3/register", methods=["POST"])
@client.route('/_matrix/client/v1/register', methods=['POST']) @client.route("/_matrix/client/v1/register", methods=["POST"])
@client.route('/_matrix/client/r0/register', methods=['POST']) @client.route("/_matrix/client/r0/register", methods=["POST"])
async def register(): async def register():
if users_can_register: if users_can_register:
try: try:
data = request.get_json() data = request.get_json()
if data and 'auth' in data: if data and "auth" in data:
return jsonify({ return jsonify({
"user_id": f"@vona:{server_name}", "user_id": f"@vona:{server_name}",
"home_server": f"{server_name}", "home_server": f"{server_name}",
@@ -157,10 +157,10 @@ async def register():
}), 403 }), 403
@client.route('/_matrix/client/r0/login', methods=['GET', 'POST']) @client.route("/_matrix/client/r0/login", methods=["GET", "POST"])
@client.route('/_matrix/client/v3/login', methods=['GET', 'POST']) @client.route("/_matrix/client/v3/login", methods=["GET", "POST"])
async def login(): async def login():
if request.method == 'GET': if request.method == "GET":
return jsonify({ return jsonify({
"flows": [ "flows": [
{"type": "m.login.password"}, {"type": "m.login.password"},
@@ -178,19 +178,19 @@ async def login():
"user_id": f"@vona:{server_name}" "user_id": f"@vona:{server_name}"
}) })
@client.route('/_matrix/client/v3/account/password/email/requestToken', methods=['POST']) @client.route("/_matrix/client/v3/account/password/email/requestToken", methods=["POST"])
async def pswd_reset(): async def pswd_reset():
return jsonify({"errcode":"M_THREEPID_NOT_FOUND","error":"Email not found"}), 400 return jsonify({"errcode":"M_THREEPID_NOT_FOUND","error":"Email not found"}), 400
@client.route('/_matrix/client/v3/keys/upload', methods=['POST']) @client.route("/_matrix/client/v3/keys/upload", methods=["POST"])
async def key_upload(): async def key_upload():
return jsonify({"one_time_key_counts":{"signed_curve25519":50}}) return jsonify({"one_time_key_counts":{"signed_curve25519":50}})
@client.route("/_matrix/client/v3/room_keys/version", methods=['POST', 'GET']) @client.route("/_matrix/client/v3/room_keys/version", methods=["POST", "GET"])
@client.route("/_matrix/client/unstable/room_keys/version", methods=['POST', 'GET']) @client.route("/_matrix/client/unstable/room_keys/version", methods=["POST", "GET"])
async def room_keys(): async def room_keys():
if request.method == 'POST': if request.method == "POST":
return jsonify({"version": str(the_funny_number)}) return jsonify({"version": str(the_funny_number)})
return jsonify({ return jsonify({
@@ -259,25 +259,25 @@ async def capabilities():
}) })
@client.route('/_matrix/client/r0/pushrules/') @client.route("/_matrix/client/r0/pushrules/")
@client.route('/_matrix/client/v3/pushrules/') @client.route("/_matrix/client/v3/pushrules/")
async def pushrules(): async def pushrules():
# TODO: Actually implement this # TODO: Actually implement this
return jsonify({}) return jsonify({})
@client.route('/_matrix/client/v3/user/<user>/filter/<data>') @client.route("/_matrix/client/v3/user/<user>/filter/<data>")
@client.route('/_matrix/client/r0/user/<user>/filter/<data>') @client.route("/_matrix/client/r0/user/<user>/filter/<data>")
@client.route('/_matrix/client/v3/user/<user>/filter', methods=['POST']) @client.route("/_matrix/client/v3/user/<user>/filter", methods=["POST"])
@client.route('/_matrix/client/r0/user/<user>/filter', methods=['POST']) @client.route("/_matrix/client/r0/user/<user>/filter", methods=["POST"])
async def filter(**kwargs): async def filter(**kwargs):
return jsonify({"filter_id": "vvvooonnnaaa"}) return jsonify({"filter_id": "vvvooonnnaaa"})
@client.route('/_matrix/client/v3/join/<room>', methods=['POST']) @client.route("/_matrix/client/v3/join/<room>", methods=["POST"])
@client.route('/_matrix/client/r0/join/<room>', methods=['POST']) @client.route("/_matrix/client/r0/join/<room>", methods=["POST"])
@client.route('/_matrix/client/v3/rooms/<room>/join', methods=['POST']) @client.route("/_matrix/client/v3/rooms/<room>/join", methods=["POST"])
@client.route('/_matrix/client/v3/knock/<room>', methods=['POST']) @client.route("/_matrix/client/v3/knock/<room>", methods=["POST"])
async def join(room): async def join(room):
return jsonify({"room_id": room}) return jsonify({"room_id": room})
@@ -340,9 +340,9 @@ async def sync():
room_state.append(room_name) room_state.append(room_name)
wait_time = 0 wait_time = 0
if 'timeout' in request.args: if "timeout" in request.args:
try: try:
wait_time = int(request.args.get('timeout')) / 1000 wait_time = int(request.args.get("timeout")) / 1000
except: except:
pass pass
await asyncio.sleep(wait_time) await asyncio.sleep(wait_time)
@@ -375,13 +375,13 @@ async def sync():
}) })
@client.route('/_matrix/client/v3/rooms/<room>/send/<eventType>/<txnId>', methods=['POST', 'PUT']) @client.route("/_matrix/client/v3/rooms/<room>/send/<eventType>/<txnId>", methods=["POST", "PUT"])
@client.route('/_matrix/client/r0/rooms/<room>/send/<eventType>/<txnId>', methods=['POST', 'PUT']) @client.route("/_matrix/client/r0/rooms/<room>/send/<eventType>/<txnId>", methods=["POST", "PUT"])
async def send_message(room, eventType, txnId): async def send_message(room, eventType, txnId):
return jsonify({"event_id": globals.make_event_id()}), 200 return jsonify({"event_id": globals.make_event_id()}), 200
@client.route('/_matrix/client/v3/user_directory/search', methods=['POST']) @client.route("/_matrix/client/v3/user_directory/search", methods=["POST"])
async def user_directory(): async def user_directory():
return jsonify({ return jsonify({
"limited": False, "limited": False,
@@ -393,8 +393,8 @@ async def user_directory():
}) })
@client.route('/_matrix/client/v3/devices') @client.route("/_matrix/client/v3/devices")
@client.route('/_matrix/client/r0/devices') @client.route("/_matrix/client/r0/devices")
async def devices(): async def devices():
return jsonify({ return jsonify({
"devices": [{ "devices": [{
@@ -406,8 +406,8 @@ async def devices():
}) })
@client.route('/_matrix/client/v3/devices/<device>', methods=['GET', 'PUT', 'DELETE']) @client.route("/_matrix/client/v3/devices/<device>", methods=["GET", "PUT", "DELETE"])
@client.route('/_matrix/client/r0/devices/<device>', methods=['GET', 'PUT', 'DELETE']) @client.route("/_matrix/client/r0/devices/<device>", methods=["GET", "PUT", "DELETE"])
async def get_device(device): async def get_device(device):
if request.method == "GET": if request.method == "GET":
return jsonify({ return jsonify({
@@ -420,7 +420,7 @@ async def get_device(device):
return jsonify({}) return jsonify({})
@client.route("/_matrix/client/v3/refresh", methods=['POST']) @client.route("/_matrix/client/v3/refresh", methods=["POST"])
async def refresh(): async def refresh():
return jsonify({ return jsonify({
"access_token": "vona", "access_token": "vona",
@@ -429,21 +429,21 @@ async def refresh():
}) })
@client.route('/_matrix/client/unstable/im.nheko.summary/rooms/<roomId>/summary') @client.route("/_matrix/client/unstable/im.nheko.summary/rooms/<roomId>/summary")
@client.route('/_matrix/client/unstable/im.nheko.summary/summary/<roomId>') @client.route("/_matrix/client/unstable/im.nheko.summary/summary/<roomId>")
@client.route('/_matrix/client/v1/room_summary/<roomId>') @client.route("/_matrix/client/v1/room_summary/<roomId>")
def unstable_room_summary(roomId): def unstable_room_summary(roomId):
room = room_dir_room['chunk'][0] room = room_dir_room["chunk"][0]
return jsonify({ return jsonify({
"room_id": room['room_id'], "room_id": room["room_id"],
"avatar_url": room['avatar_url'], "avatar_url": room["avatar_url"],
"guest_can_join": room['guest_can_join'], "guest_can_join": room["guest_can_join"],
"name": room['name'], "name": room["name"],
"num_joined_members": room['num_joined_members'], "num_joined_members": room["num_joined_members"],
"topic": room['topic'], "topic": room["topic"],
"world_readable": room['world_readable'], "world_readable": room["world_readable"],
"join_rule": room['join_rule'], "join_rule": room["join_rule"],
"room_type": room['room_type'], "room_type": room["room_type"],
"membership": "join", "membership": "join",
"room_version": 2, "room_version": 2,
}) })
@@ -454,7 +454,7 @@ def unstable_room_summary(roomId):
async def room_query(room): async def room_query(room):
if request.method == "GET": if request.method == "GET":
return jsonify({ return jsonify({
"room_id": room_dir_room['chunk'][0]['room_id'], "room_id": room_dir_room["chunk"][0]["room_id"],
"servers": [server_name] "servers": [server_name]
}) })
@@ -470,7 +470,7 @@ async def room_aliases(room):
@client.route("/_matrix/client/v3/directory/list/room/<room>", methods=["GET", "PUT"]) @client.route("/_matrix/client/v3/directory/list/room/<room>", methods=["GET", "PUT"])
@client.route('/_matrix/client/r0/directory/list/room/<room>', methods=["GET", "PUT"]) @client.route("/_matrix/client/r0/directory/list/room/<room>", methods=["GET", "PUT"])
async def room_visibility(room): async def room_visibility(room):
return jsonify({"visibility": "public"}) return jsonify({"visibility": "public"})
@@ -515,25 +515,25 @@ async def search():
}) })
@client.route('/_matrix/media/v1/thumbnail/<server>/<file>') @client.route("/_matrix/media/v1/thumbnail/<server>/<file>")
@client.route('/_matrix/client/v1/media/thumbnail/<s>/<f>') @client.route("/_matrix/client/v1/media/thumbnail/<s>/<f>")
@client.route('/_matrix/media/r0/thumbnail/<server>/<file>') @client.route("/_matrix/media/r0/thumbnail/<server>/<file>")
@client.route('/_matrix/media/v3/thumbnail/<server>/<media>') @client.route("/_matrix/media/v3/thumbnail/<server>/<media>")
@client.route('/_matrix/media/v3/download/<server>/<media>/<file>') @client.route("/_matrix/media/v3/download/<server>/<media>/<file>")
@client.route('/_matrix/client/v1/media/download/<s>/<f>') @client.route("/_matrix/client/v1/media/download/<s>/<f>")
@client.route('/_matrix/media/v3/download/<server>/<media>') @client.route("/_matrix/media/v3/download/<server>/<media>")
@client.route('/_matrix/media/r0/download/<server>/<media>') @client.route("/_matrix/media/r0/download/<server>/<media>")
async def media(**kwargs): async def media(**kwargs):
return send_file(cat) return send_file(cat)
@client.route('/_matrix/client/v3/register/available') @client.route("/_matrix/client/v3/register/available")
@client.route('/_matrix/client/r0/register/available') @client.route("/_matrix/client/r0/register/available")
async def username_available(): async def username_available():
return jsonify({"available": True}) return jsonify({"available": True})
@client.route('/_matrix/media/v3/preview_url') @client.route("/_matrix/media/v3/preview_url")
async def url_preview(): async def url_preview():
return jsonify({ return jsonify({
"matrix:image:size": 102400, "matrix:image:size": 102400,
@@ -545,32 +545,32 @@ async def url_preview():
"og:title": "cool cat" "og:title": "cool cat"
}) })
@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(cat) response = send_file(cat)
response.headers['Content-Disposition'] = f'inline; filename="cat.jpg"' response.headers["Content-Disposition"] = f'inline; filename="cat.jpg"'
response.headers['Content-Type'] = 'image/jpg' response.headers["Content-Type"] = "image/jpg"
return response return response
@client.route('/_matrix/media/v3/upload', methods=['POST']) @client.route("/_matrix/media/v3/upload", methods=["POST"])
@client.route('/_matrix/media/r0/upload', methods=['POST']) @client.route("/_matrix/media/r0/upload", methods=["POST"])
@client.route('/_matrix/media/v1/create', methods=['POST']) @client.route("/_matrix/media/v1/create", methods=["POST"])
async def upload_media(): async def upload_media():
return jsonify({"content_uri": f"mxc://{server_name}/cat"}) return jsonify({"content_uri": f"mxc://{server_name}/cat"})
@client.route('/_matrix/media/v3/config') @client.route("/_matrix/media/v3/config")
async def media_config(): async def media_config():
return jsonify({"m.upload.size": the_funny_number * 69420}) return jsonify({"m.upload.size": the_funny_number * 69420})
@client.route('/_matrix/client/v3/profile/<userId>/<key>', methods=['GET', 'PUT', 'DELETE']) @client.route("/_matrix/client/v3/profile/<userId>/<key>", methods=["GET", "PUT", "DELETE"])
@client.route('/_matrix/client/r0/profile/<userId>/<key>', methods=['GET', 'PUT', 'DELETE']) @client.route("/_matrix/client/r0/profile/<userId>/<key>", methods=["GET", "PUT", "DELETE"])
async def profile_keys(userId, key): async def profile_keys(userId, key):
if request.method == 'GET': if request.method == "GET":
if key == 'avatar_url': if key == "avatar_url":
return jsonify({"avatar_url": f"mxc://{server_name}/cat"}) return jsonify({"avatar_url": f"mxc://{server_name}/cat"})
elif key == 'displayname': elif key == "displayname":
return jsonify({"displayname": "Vona"}) return jsonify({"displayname": "Vona"})
return jsonify({ return jsonify({
@@ -580,8 +580,8 @@ async def profile_keys(userId, key):
return jsonify({}) return jsonify({})
@client.route('/_matrix/client/v3/profile/<userId>') @client.route("/_matrix/client/v3/profile/<userId>")
@client.route('/_matrix/client/r0/profile/<userId>') @client.route("/_matrix/client/r0/profile/<userId>")
async def user_profile(userId): async def user_profile(userId):
return jsonify({ return jsonify({
"avatar_url": f"mxc://{server_name}/cat", "avatar_url": f"mxc://{server_name}/cat",
@@ -589,8 +589,8 @@ async def user_profile(userId):
}) })
@client.route('/_matrix/client/v3/rooms/<roomId>/messages') @client.route("/_matrix/client/v3/rooms/<roomId>/messages")
@client.route('/_matrix/client/r0/rooms/<roomId>/messages') @client.route("/_matrix/client/r0/rooms/<roomId>/messages")
async def room_messages(roomId): async def room_messages(roomId):
return jsonify({ return jsonify({
"chunk": [{ "chunk": [{
@@ -610,8 +610,8 @@ async def room_messages(roomId):
"start": f"{os.urandom(16).hex()}" "start": f"{os.urandom(16).hex()}"
}) })
@client.route('/_matrix/client/v3/keys/query', methods=['POST']) @client.route("/_matrix/client/v3/keys/query", methods=["POST"])
@client.route('/_matrix/client/r0/keys/query', methods=['POST']) @client.route("/_matrix/client/r0/keys/query", methods=["POST"])
async def query_keys(): async def query_keys():
# Should be replaced eventually # Should be replaced eventually
return jsonify({}) return jsonify({})
@@ -643,6 +643,6 @@ async def presence(user):
}) })
@client.route('/_matrix/client/r0/publicRooms', methods=["GET", "POST"]) @client.route("/_matrix/client/r0/publicRooms", methods=["GET", "POST"])
async def room_directory(): async def room_directory():
return jsonify(room_dir_room) return jsonify(room_dir_room)

View File

@@ -1,5 +1,5 @@
# Cat picture to use. Must be a JPEG (most camera photos are JPEG already anyway). # Cat picture to use. Must be a JPEG (most camera photos are JPEG already anyway).
cat = '../cat.jpg' cat = "../cat.jpg"
# Your server name. # Your server name.
server_name = "example.org" server_name = "example.org"
@@ -41,7 +41,7 @@ support = {
port = 5000 port = 5000
# The address to listen on. # The address to listen on.
addr = '127.0.0.1' addr = "127.0.0.1"
# Whether or not to enable registration. # Whether or not to enable registration.
users_can_register = False users_can_register = False

View File

@@ -1,6 +1,6 @@
from config import server_name, the_funny_number, room_dir_room from config import server_name, the_funny_number, room_dir_room
from flask import Blueprint, jsonify, request, Response from flask import Blueprint, jsonify, request, Response
from globals import vona_version, make_event_id import globals
import base64 import base64
import re import re
import os import os
@@ -16,20 +16,20 @@ custom = Blueprint("custom", __name__)
# files eventually. # files eventually.
@custom.route('/_synapse/admin/v1/suspend/<user_id>', methods=["PUT"]) @custom.route("/_synapse/admin/v1/suspend/<user_id>", methods=["PUT"])
@custom.route('/_synapse/admin/v1/deactivate/<user_id>', methods=['POST']) @custom.route("/_synapse/admin/v1/deactivate/<user_id>", methods=["POST"])
@custom.route('/_synapse/admin/v1/reset_password/<user_id>', methods=['POST']) @custom.route("/_synapse/admin/v1/reset_password/<user_id>", methods=["POST"])
@custom.route('/_synapse/admin/v1/users/<user_id>/admin', methods=["PUT"]) @custom.route("/_synapse/admin/v1/users/<user_id>/admin", methods=["PUT"])
@custom.route('/_synapse/admin/v2/users/<user_id>/delete_devices', methods=['POST']) @custom.route("/_synapse/admin/v2/users/<user_id>/delete_devices", methods=["POST"])
@custom.route('/_synapse/admin/v1/users/<user_id>/shadow_ban', methods=['DELETE', 'POST']) @custom.route("/_synapse/admin/v1/users/<user_id>/shadow_ban", methods=["DELETE", "POST"])
@custom.route('/_synapse/admin/v1/users/<user_id>/override_ratelimit', methods=['GET', 'POST', 'DELETE']) @custom.route("/_synapse/admin/v1/users/<user_id>/override_ratelimit", methods=["GET", "POST", "DELETE"])
@custom.route('/_synapse/admin/v1/media/protect/<media_id>', methods=['POST']) @custom.route("/_synapse/admin/v1/media/protect/<media_id>", methods=["POST"])
@custom.route('/_synapse/admin/v1/media/unprotect/<media_id>', methods=['POST']) @custom.route("/_synapse/admin/v1/media/unprotect/<media_id>", methods=["POST"])
@custom.route('/_synapse/admin/v1/media/quarantine/<server_name>/<media_id>', methods=['POST']) @custom.route("/_synapse/admin/v1/media/quarantine/<server_name>/<media_id>", methods=["POST"])
@custom.route('/_synapse/admin/v1/media/unquarantine/<server_name>/<media_id>', methods=['POST']) @custom.route("/_synapse/admin/v1/media/unquarantine/<server_name>/<media_id>", methods=["POST"])
@custom.route('/_dendrite/admin/purgeRoom/<roomId>', methods=['POST']) @custom.route("/_dendrite/admin/purgeRoom/<roomId>", methods=["POST"])
@custom.route('/_dendrite/admin/refreshDevices/<userId>', methods=['POST']) @custom.route("/_dendrite/admin/refreshDevices/<userId>", methods=["POST"])
@custom.route('/_dendrite/admin/fulltext/reindex') @custom.route("/_dendrite/admin/fulltext/reindex")
@custom.route("/_synapse/admin/v1/federation/destinations/<destination>/reset_connection", methods=["POST"]) @custom.route("/_synapse/admin/v1/federation/destinations/<destination>/reset_connection", methods=["POST"])
@custom.route("/_synapse/admin/v1/rooms/<room>") @custom.route("/_synapse/admin/v1/rooms/<room>")
@custom.route("/_synapse/admin/v1/rooms/<room_id>/timestamp_to_event") @custom.route("/_synapse/admin/v1/rooms/<room_id>/timestamp_to_event")
@@ -40,11 +40,11 @@ async def empty_response(**kwargs):
# Synapse # Synapse
@custom.route('/_synapse/admin/v1/server_version') @custom.route("/_synapse/admin/v1/server_version")
def synapse_version(): def synapse_version():
return jsonify({'server_version': vona_version}) return jsonify({"server_version": globals.vona_version})
@custom.route('/_synapse/admin/v2/users') @custom.route("/_synapse/admin/v2/users")
def synapse_user_list(): def synapse_user_list():
return jsonify({ return jsonify({
"users": [ "users": [
@@ -65,14 +65,14 @@ def synapse_user_list():
"total": 1 "total": 1
}) })
@custom.route('/_synapse/admin/v2/users/<user_id>', methods=['GET', 'PUT']) @custom.route("/_synapse/admin/v2/users/<user_id>", methods=["GET", "PUT"])
def synapse_user_info(user_id): def synapse_user_info(user_id):
if request.method == 'GET': if request.method == "GET":
return jsonify({"name":f"@vona:{server_name}","displayname":"Vona","threepids":[],"avatar_url":f"mxc://{server_name}/cat","is_guest":0,"admin":0,"deactivated":0,"erased":False,"shadow_banned":0,"creation_ts":the_funny_number,"last_seen_ts":the_funny_number,"appservice_id":the_funny_number,"consent_server_notice_sent":the_funny_number,"consent_version":the_funny_number,"consent_ts":the_funny_number,"external_ids":[],"user_type":"vona","locked":False,"suspended":False}) return jsonify({"name":f"@vona:{server_name}","displayname":"Vona","threepids":[],"avatar_url":f"mxc://{server_name}/cat","is_guest":0,"admin":0,"deactivated":0,"erased":False,"shadow_banned":0,"creation_ts":the_funny_number,"last_seen_ts":the_funny_number,"appservice_id":the_funny_number,"consent_server_notice_sent":the_funny_number,"consent_version":the_funny_number,"consent_ts":the_funny_number,"external_ids":[],"user_type":"vona","locked":False,"suspended":False})
return jsonify({}), 201 return jsonify({}), 201
@custom.route('/_synapse/admin/v1/whois/<user_id>') @custom.route("/_synapse/admin/v1/whois/<user_id>")
async def synapse_whois(user_id): async def synapse_whois(user_id):
return jsonify({ return jsonify({
"user_id": f"@vona:{server_name}", "user_id": f"@vona:{server_name}",
@@ -82,185 +82,204 @@ async def synapse_whois(user_id):
"connections": [{ "connections": [{
"ip":f"127.0.0.1", "ip":f"127.0.0.1",
"last_seen":the_funny_number, "last_seen":the_funny_number,
"user_agent":f"Vona/{vona_version}" "user_agent":f"Vona/{globals.vona_version}"
}] }]
}] }]
} }
} }
}) })
@custom.route('/_synapse/admin/v1/users/<user_id>/joined_rooms') @custom.route("/_synapse/admin/v1/users/<user_id>/joined_rooms")
def synapse_user_joined_rooms(user_id): def synapse_user_joined_rooms(user_id):
return jsonify({"joined_rooms":[room_dir_room['chunk'][0]['room_id']],"total":1}) return jsonify({"joined_rooms":[room_dir_room["chunk"][0]["room_id"]],"total":1})
@custom.route('/_synapse/admin/v1/users/<user_id>/sent_invite_count') @custom.route("/_synapse/admin/v1/users/<user_id>/sent_invite_count")
async def synapse_invite_count(user_id): async def synapse_invite_count(user_id):
return jsonify({"invite_count": the_funny_number}) return jsonify({"invite_count": the_funny_number})
@custom.route('/_synapse/admin/v1/users/<user_id>/accountdata') @custom.route("/_synapse/admin/v1/users/<user_id>/accountdata")
def synapse_account_data(user_id): def synapse_account_data(user_id):
return jsonify({"account_data":{"global":{}}}) return jsonify({"account_data":{"global":{}}})
@custom.route('/_synapse/admin/v1/users/<user_id>/media', methods=['GET', 'DELETE']) @custom.route("/_synapse/admin/v1/users/<user_id>/media", methods=["GET", "DELETE"])
def synapse_account_media(user_id): def synapse_account_media(user_id):
if request.method == 'GET': if request.method == "GET":
return jsonify({"media": [{"created_ts":the_funny_number,"last_access_ts":the_funny_number,"media_id":"cat","media_length":the_funny_number,"media_type":"image/jpeg","quarantined_by":"null","safe_from_quarantine":False,"upload_name":"cat.jpg"}], "total": the_funny_number}) return jsonify({"media": [{"created_ts":the_funny_number,"last_access_ts":the_funny_number,"media_id":"cat","media_length":the_funny_number,"media_type":"image/jpeg","quarantined_by":"null","safe_from_quarantine":False,"upload_name":"cat.jpg"}], "total": the_funny_number})
return jsonify({"deleted_media": ["cat"], "total": the_funny_number}) return jsonify({"deleted_media": ["cat"], "total": the_funny_number})
@custom.route('/_synapse/admin/v1/users/<user_id>/login', methods=['POST']) @custom.route("/_synapse/admin/v1/users/<user_id>/login", methods=["POST"])
def synapse_account_login(user_id): def synapse_account_login(user_id):
return jsonify({"access_token": "vona"}) return jsonify({"access_token": "vona"})
@custom.route('/_synapse/admin/v1/users/<user_id>/_allow_cross_signing_replacement_without_uia', methods=['POST']) @custom.route("/_synapse/admin/v1/users/<user_id>/_allow_cross_signing_replacement_without_uia", methods=["POST"])
def synapse_stupid_mas_bullshit(user_id): def synapse_stupid_mas_bullshit(user_id):
return jsonify({"updatable_without_uia_before_ms": the_funny_number}) return jsonify({"updatable_without_uia_before_ms": the_funny_number})
@custom.route('/_synapse/admin/v2/users/<user_id>/devices', methods=['GET', 'POST']) @custom.route("/_synapse/admin/v2/users/<user_id>/devices", methods=["GET", "POST"])
def synapse_device_list(user_id): def synapse_device_list(user_id):
if request.method == 'GET': if request.method == "GET":
return jsonify({ return jsonify({
"devices": [{ "devices": [{
"device_id": "VVOONNAA", "device_id": "VVOONNAA",
"display_name": "Vona", "display_name": "Vona",
"last_seen_ip": "127.0.0.1", "last_seen_ip": "127.0.0.1",
"last_seen_ts": the_funny_number, "last_seen_ts": the_funny_number,
"last_seen_user_agent": f"Vona/{vona_version}" "last_seen_user_agent": f"Vona/{globals.vona_version}"
}], }],
"total": 1 "total": 1
}) })
return jsonify({}) return jsonify({})
@custom.route('/_synapse/admin/v2/users/<user_id>/devices/<device_id>', methods=["GET", "PUT", "DELETE"]) @custom.route("/_synapse/admin/v2/users/<user_id>/devices/<device_id>", methods=["GET", "PUT", "DELETE"])
async def synapse_device_info(user_id, device_id): async def synapse_device_info(user_id, device_id):
if request.method == 'GET': if request.method == "GET":
return jsonify({ return jsonify({
"device_id": "VVOONNAA", "device_id": "VVOONNAA",
"display_name": "Vona", "display_name": "Vona",
"last_seen_ip": "127.0.0.1", "last_seen_ip": "127.0.0.1",
"last_seen_ts": the_funny_number, "last_seen_ts": the_funny_number,
"last_seen_user_agent": f"Vona/{vona_version}" "last_seen_user_agent": f"Vona/{globals.vona_version}"
}) })
return jsonify({}) return jsonify({})
@custom.route('/_synapse/admin/v1/users/<user_id>/pushers') @custom.route("/_synapse/admin/v1/users/<user_id>/pushers")
async def synapse_pushers(user_id): async def synapse_pushers(user_id):
return jsonify({"pushers": [], "total": the_funny_number}) return jsonify({"pushers": [], "total": the_funny_number})
@custom.route('/_synapse/admin/v1/username_available') @custom.route("/_synapse/admin/v1/username_available")
async def synapse_username_available(): async def synapse_username_available():
return jsonify({"available": True}) return jsonify({"available": True})
@custom.route('/_synapse/admin/v1/threepid/<medium>/users/<addr>') @custom.route("/_synapse/admin/v1/threepid/<medium>/users/<addr>")
@custom.route('/_synapse/admin/v1/auth_providers/<provider>/users/<ext>') @custom.route("/_synapse/admin/v1/auth_providers/<provider>/users/<ext>")
async def synapse_threepid(p, a): async def synapse_threepid(p, a):
return jsonify({"user_id": f"@vona:{server_name}"}) return jsonify({"user_id": f"@vona:{server_name}"})
@custom.route('/_synapse/admin/v1/<user_id>/redact') @custom.route("/_synapse/admin/v1/<user_id>/redact")
def synapse_redact(user_id): def synapse_redact(user_id):
return jsonify({"redact_id": os.urandom(16).hex()}) return jsonify({"redact_id": os.urandom(16).hex()})
@custom.route('/_synapse/admin/v1/user/redact_status/<redact_id>') @custom.route("/_synapse/admin/v1/user/redact_status/<redact_id>")
async def synapse_redact_status(redact_id): async def synapse_redact_status(redact_id):
return jsonify({"status":"active","failed_redactions":[]}) return jsonify({"status":"active","failed_redactions":[]})
@custom.route('/_synapse/admin/v1/experimental_features/<user_id>', methods=['GET', 'PUT']) @custom.route("/_synapse/admin/v1/experimental_features/<user_id>", methods=["GET", "PUT"])
async def synapse_experimental_features(user_id): async def synapse_experimental_features(user_id):
return jsonify({"features": {}}) return jsonify({"features": {}})
@custom.route('/_synapse/admin/v1/register', methods=['GET', 'POST']) @custom.route("/_synapse/admin/v1/register", methods=["GET", "POST"])
async def synapse_register(): async def synapse_register():
if request.method == 'GET': if request.method == "GET":
return jsonify({"nonce": os.urandom(16).hex()}) return jsonify({"nonce": os.urandom(16).hex()})
return jsonify({"access_token": "vona"}) return jsonify({"access_token": "vona"})
@custom.route('/_synapse/admin/v1/join/<roomId>', methods=['POST']) @custom.route("/_synapse/admin/v1/join/<roomId>", methods=["POST"])
async def synapse_membership_manipulation(roomId): async def synapse_membership_manipulation(roomId):
return jsonify({"room_id": room_dir_room['chunk'][0]['room_id']}) return jsonify({"room_id": room_dir_room["chunk"][0]["room_id"]})
@custom.route('/_synapse/admin/v1/account_validity/validity', methods=['POST']) @custom.route("/_synapse/admin/v1/account_validity/validity", methods=["POST"])
async def synapse_account_validity(): async def synapse_account_validity():
return jsonify({"expiration_ts": the_funny_number}) return jsonify({"expiration_ts": the_funny_number})
@custom.route('/_synapse/admin/v1/send_server_notice', methods=['POST']) @custom.route("/_synapse/admin/v1/send_server_notice", methods=["POST"])
@custom.route('/_synapse/admin/v1/send_server_notice/<txnId>', methods=["PUT"]) @custom.route("/_synapse/admin/v1/send_server_notice/<txnId>", methods=["PUT"])
async def synapse_server_notice(**kwargs): async def synapse_server_notice(**kwargs):
return jsonify({"event_id": make_event_id()}) return jsonify({"event_id": globals.make_event_id()})
@custom.route('/_synapse/admin/v1/purge_history/<room_id>/<event_id>', methods=['POST']) @custom.route("/_synapse/admin/v1/purge_history/<room_id>/<event_id>", methods=["POST"])
@custom.route('/_synapse/admin/v1/purge_history/<room_id>', methods=['POST']) @custom.route("/_synapse/admin/v1/purge_history/<room_id>", methods=["POST"])
async def synapse_purge_event(**kwargs): async def synapse_purge_event(**kwargs):
return jsonify({"purge_id": os.urandom(16).hex()}) return jsonify({"purge_id": os.urandom(16).hex()})
@custom.route('/_synapse/admin/v1/purge_history_status/<purge_id>') @custom.route("/_synapse/admin/v1/purge_history_status/<purge_id>")
def synapse_purge_status(purge_id): def synapse_purge_status(purge_id):
return jsonify({"status":"active"}) return jsonify({"status":"active"})
@custom.route('/_synapse/admin/v1/room/<room_id>/media') @custom.route("/_synapse/admin/v1/room/<room_id>/media")
def synapse_room_media(room_id): def synapse_room_media(room_id):
return jsonify({"local": [f"mxc://{server_name}/cat"], "remote": []}) return jsonify({"local": [f"mxc://{server_name}/cat"], "remote": []})
@custom.route('/_synapse/admin/v1/room/<room_id>/media/quarantine', methods=['POST']) @custom.route("/_synapse/admin/v1/room/<room_id>/media/quarantine", methods=["POST"])
def synapse_quarantine_room_media(room_id): def synapse_quarantine_room_media(room_id):
return jsonify({"num_quarantined": the_funny_number}) return jsonify({"num_quarantined": the_funny_number})
@custom.route('/_synapse/admin/v1/media/<server_name>/delete', methods=['POST']) @custom.route("/_synapse/admin/v1/media/<server_name>/delete", methods=["POST"])
@custom.route('/_synapse/admin/v1/media/<server_name>/<media_id>', methods=['DELETE']) @custom.route("/_synapse/admin/v1/media/<server_name>/<media_id>", methods=["DELETE"])
@custom.route('/_synapse/admin/v1/media/delete', methods=['POST']) @custom.route("/_synapse/admin/v1/media/delete", methods=["POST"])
async def synapse_delete_media_from_server(**kwargs): async def synapse_delete_media_from_server(**kwargs):
return jsonify({"deleted_media": ["cat"], "total": the_funny_number}) return jsonify({"deleted_media": ["cat"], "total": the_funny_number})
@custom.route('/_synapse/admin/v1/purge_media_cache', methods=['POST']) @custom.route("/_synapse/admin/v1/purge_media_cache", methods=["POST"])
async def synapse_delete_remote_media(): async def synapse_delete_remote_media():
return jsonify({"deleted": the_funny_number}) return jsonify({"deleted": the_funny_number})
@custom.route('/_synapse/admin/v1/statistics/users/media') @custom.route("/_synapse/admin/v1/statistics/users/media")
async def synapse_media_stats(): async def synapse_media_stats():
return jsonify({"users":[{"displayname":"Vona","media_count":the_funny_number,"media_length":the_funny_number,"user_id":f"@vona:{server_name}"}],"total":the_funny_number}) return jsonify({"users":[{"displayname":"Vona","media_count":the_funny_number,"media_length":the_funny_number,"user_id":f"@vona:{server_name}"}],"total":the_funny_number})
@custom.route('/_synapse/admin/v1/statistics/database/rooms') @custom.route("/_synapse/admin/v1/statistics/database/rooms")
async def synapse_room_stats(): async def synapse_room_stats():
return jsonify({ return jsonify({
"rooms": [{ "rooms": [{
"room_id": room_dir_room['chunk'][0]['room_id'], "room_id": room_dir_room["chunk"][0]["room_id"],
"estimated_size": the_funny_number * 420 "estimated_size": the_funny_number * 420
}] }]
}) })
@custom.route('/_synapse/admin/v1/background_updates/enabled', methods=['POST', 'GET']) @custom.route("/_synapse/admin/v1/background_updates/enabled", methods=["POST", "GET"])
@custom.route('/_synapse/admin/v1/background_updates/status') @custom.route("/_synapse/admin/v1/background_updates/status")
async def synapse_change_bg_update(): async def synapse_change_bg_update():
return jsonify({"enabled":False}) return jsonify({"enabled":False})
# No documentation on what Synapse actually returns for this API, so a blank dict for now. # No documentation on what Synapse actually returns for this API, so a blank dict for now.
@custom.route('/_synapse/admin/v1/background_updates/start_job', methods=['POST']) @custom.route("/_synapse/admin/v1/background_updates/start_job", methods=["POST"])
async def synapse_bg_update_start_job(): async def synapse_bg_update_start_job():
return jsonify({}) return jsonify({})
@custom.route('/_synapse/admin/v1/event_reports') @custom.route("/_synapse/admin/v1/event_reports")
async def synapse_event_reports(): async def synapse_event_reports():
return jsonify({ return jsonify({
"event_reports": [{ "event_reports": [{
"event_id": make_event_id(), "event_id": globals.make_event_id(),
"id": the_funny_number, "id": the_funny_number,
"reason": "", "reason": "",
"score": the_funny_number, "score": the_funny_number,
"received_ts": the_funny_number, "received_ts": the_funny_number,
"room_id": room_dir_room['chunk'][0]['room_id'], "room_id": room_dir_room["chunk"][0]["room_id"],
"name": room_dir_room['chunk'][0]['name'], "name": room_dir_room["chunk"][0]["name"],
"sender": f"@vona:{server_name}", "sender": f"@vona:{server_name}",
"user_id": f"@vona:{server_name}" "user_id": f"@vona:{server_name}"
}], }],
"total": the_funny_number "total": the_funny_number
}) })
@custom.route('/_synapse/admin/v1/event_reports/<report_id>', methods=['GET', 'DELETE']) @custom.route("/_synapse/admin/v1/event_reports/<report_id>", methods=["GET", "DELETE"])
async def synapse_interact_with_reported_event(report_id): async def synapse_interact_with_reported_event(report_id):
if request.method == 'GET': if request.method == "GET":
return jsonify({"event_id": make_event_id(),"event_json": {"auth_events": [],"content": {"msgtype": "m.text","body": "Number 15: Burger King Foot Lettuce.\nThe last thing you'd want in your Burger King burger is someones foot fungus, but as it turns out, that might be what you get. A 4channer uploaded a photo, anonymously to the site showcasing his feet in a plastic bin of lettuce with the statement \"This is the lettuce you eat at Burger King.\". Admittedly, he had shoes on, but thats even worse. The post went live at 11:38 PM on July 16 and a mere 20 minutes later the Burger King in question was alerted to the rogue employee. At least, I hope hes rogue. How did it happen? Well, the BK employee hadn't removed the EXIF data from the uploaded photo, which suggested that the culprit was somewhere in Mayfield Heights, Ohio. This was at 11:47. 3 minutes later, at 11:50, the Burger King branch was posted with wishes of happy unemployment. 5 minutes later, the news station was contacted by another 4channer, and 3 minutes later at 11:58 a link was posted: BK's tell us about us online forum. The foot photo, otherwise known as Exhibit A, was attached. Cleveland Seen Magazine contacted the BK in question and the next day when questioned, the breakfast shift manager said \"Oh, I know who that is, hes getting fired\". Mystery solved, by 4chan. Now we can go back to eating our fast food in peace.","format": "org.matrix.custom.html","formatted_body": "Number 15: Burger King Foot Lettuce.<br />The last thing you'd want in your Burger King burger is someones foot fungus, but as it turns out, that might be what you get. A 4channer uploaded a photo, anonymously to the site showcasing his feet in a plastic bin of lettuce with the statement &quot;This is the lettuce you eat at Burger King.&quot;. Admittedly, he had shoes on, but thats even worse. The post went live at 11:38 PM on July 16 and a mere 20 minutes later the Burger King in question was alerted to the rogue employee. At least, I hope hes rogue. How did it happen? Well, the BK employee hadn't removed the EXIF data from the uploaded photo, which suggested that the culprit was somewhere in Mayfield Heights, Ohio. This was at 11:47. 3 minutes later, at 11:50, the Burger King branch was posted with wishes of happy unemployment. 5 minutes later, the news station was contacted by another 4channer, and 3 minutes later at 11:58 a link was posted: BK's tell us about us online forum. The foot photo, otherwise known as Exhibit A, was attached. Cleveland Seen Magazine contacted the BK in question and the next day when questioned, the breakfast shift manager said &quot;Oh, I know who that is, hes getting fired&quot;. Mystery solved, by 4chan. Now we can go back to eating our fast food in peace."},"depth": the_funny_number,"hashes": {"sha256": "todo: replace with something proper"},"origin": server_name,"origin_server_ts": the_funny_number,"prev_events": [make_event_id()],"prev_state": [],"room_id": room_dir_room['chunk'][0]['room_id'],"sender": f"@vona:{server_name}","signatures": {server_name: {"ed25519:a_JaEG": base64.b64encode(os.urandom(32)).decode('utf-8')[:87]}}},"type": "m.room.message","unsigned": {"age_ts": the_funny_number},"id": the_funny_number,"reason": "vona","score": the_funny_number,"received_ts": the_funny_number,"room_id": room_dir_room['chunk'][0]['room_id'],"name": room_dir_room['chunk'][0]['name'],"sender": f"@vona:{server_name}","user_id": f"@vona:{server_name}"}) return jsonify({
"event_id": globals.make_event_id(),
"event_json": globals.hash_and_sign_event({
"auth_events": [],
"content": {
"msgtype": "m.text",
"body": "Number 15: Burger King Foot Lettuce.\nThe last thing you'd want in your Burger King burger is someones foot fungus, but as it turns out, that might be what you get. A 4channer uploaded a photo, anonymously to the site showcasing his feet in a plastic bin of lettuce with the statement \"This is the lettuce you eat at Burger King.\". Admittedly, he had shoes on, but thats even worse. The post went live at 11:38 PM on July 16 and a mere 20 minutes later the Burger King in question was alerted to the rogue employee. At least, I hope hes rogue. How did it happen? Well, the BK employee hadn't removed the EXIF data from the uploaded photo, which suggested that the culprit was somewhere in Mayfield Heights, Ohio. This was at 11:47. 3 minutes later, at 11:50, the Burger King branch was posted with wishes of happy unemployment. 5 minutes later, the news station was contacted by another 4channer, and 3 minutes later at 11:58 a link was posted: BK's tell us about us online forum. The foot photo, otherwise known as Exhibit A, was attached. Cleveland Seen Magazine contacted the BK in question and the next day when questioned, the breakfast shift manager said \"Oh, I know who that is, hes getting fired\". Mystery solved, by 4chan. Now we can go back to eating our fast food in peace.",
"format": "org.matrix.custom.html",
"formatted_body": "Number 15: Burger King Foot Lettuce.<br />The last thing you'd want in your Burger King burger is someones foot fungus, but as it turns out, that might be what you get. A 4channer uploaded a photo, anonymously to the site showcasing his feet in a plastic bin of lettuce with the statement &quot;This is the lettuce you eat at Burger King.&quot;. Admittedly, he had shoes on, but thats even worse. The post went live at 11:38 PM on July 16 and a mere 20 minutes later the Burger King in question was alerted to the rogue employee. At least, I hope hes rogue. How did it happen? Well, the BK employee hadn't removed the EXIF data from the uploaded photo, which suggested that the culprit was somewhere in Mayfield Heights, Ohio. This was at 11:47. 3 minutes later, at 11:50, the Burger King branch was posted with wishes of happy unemployment. 5 minutes later, the news station was contacted by another 4channer, and 3 minutes later at 11:58 a link was posted: BK's tell us about us online forum. The foot photo, otherwise known as Exhibit A, was attached. Cleveland Seen Magazine contacted the BK in question and the next day when questioned, the breakfast shift manager said &quot;Oh, I know who that is, hes getting fired&quot;. Mystery solved, by 4chan. Now we can go back to eating our fast food in peace."
},
"depth": the_funny_number,
"origin": server_name,
"origin_server_ts": the_funny_number,
"prev_events": [globals.make_event_id()],
"prev_state": [],
"room_id": room_dir_room["chunk"][0]["room_id"],
"sender": f"@vona:{server_name}",
"type": "m.room.message"
})
})
return jsonify({}) return jsonify({})
@@ -383,7 +402,7 @@ async def synapse_forward_extremities(room):
return jsonify({ return jsonify({
"count": 1, "count": 1,
"results": [{ "results": [{
"event_id": make_event_id(), "event_id": globals.make_event_id(),
"state_group": the_funny_number, "state_group": the_funny_number,
"depth": the_funny_number, "depth": the_funny_number,
"received_ts": the_funny_number "received_ts": the_funny_number
@@ -391,27 +410,30 @@ async def synapse_forward_extremities(room):
}) })
# Dendrite - https://element-hq.github.io/dendrite/administration/adminapi # Dendrite - https://element-hq.github.io/dendrite/administration/adminapi
@custom.route('/_dendrite/admin/evacuateUser/<userId>', methods=['POST']) @custom.route("/_dendrite/admin/evacuateUser/<userId>", methods=["POST"])
async def dendrite_evacuate_user(userId): async def dendrite_evacuate_user(userId):
return jsonify({"affected": [room_dir_room['chunk'][0]['room_id']]}) return jsonify({"affected": [room_dir_room["chunk"][0]["room_id"]]})
@custom.route('/_dendrite/admin/evacuateRoom/<roomId>', methods=['POST']) @custom.route("/_dendrite/admin/evacuateRoom/<roomId>", methods=["POST"])
async def dendrite_evacuate_room(roomId): async def dendrite_evacuate_room(roomId):
return jsonify({"affected": [f"@vona:{server_name}"]}) return jsonify({"affected": [f"@vona:{server_name}"]})
@custom.route('/_dendrite/admin/resetPassword/<userId>', methods=['POST']) @custom.route("/_dendrite/admin/resetPassword/<userId>", methods=["POST"])
async def dendrite_reset_pswd(userId): async def dendrite_reset_pswd(userId):
return jsonify({"password_updated": True}) return jsonify({"password_updated": True})
# Conduwuit/Tuwunel/Continuwuity # Conduwuit/Tuwunel/Continuwuity
@custom.route('/_continuwuity/local_user_count') @custom.route("/_continuwuity/local_user_count")
@custom.route('/_conduwuit/local_user_count') @custom.route("/_conduwuit/local_user_count")
@custom.route('/_tuwunel/local_user_count') @custom.route("/_tuwunel/local_user_count")
async def conduwuit_user_count(): async def conduwuit_user_count():
return jsonify({"count": 1}) return jsonify({"count": 1})
@custom.route('/_continuwuity/server_version') @custom.route("/_continuwuity/server_version")
@custom.route('/_conduwuit/server_version') @custom.route("/_conduwuit/server_version")
@custom.route('/_tuwunel/server_version') @custom.route("/_tuwunel/server_version")
async def conduwuit_server_version(): async def conduwuit_server_version():
return jsonify({"name":"Vona","version":vona_version}) return jsonify({
"name": "Vona",
"version":globals.vona_version
})

View File

@@ -160,7 +160,7 @@ def make_auth_header(destination, method, path, content=None) -> str:
def redact_event(event): def redact_event(event):
# Returns a redacted event as per # Returns a redacted event as per
# the algorithm for v1 rooms. # the algorithm for v1/v2 rooms.
allowed_keys = [ allowed_keys = [
"event_id", "event_id",

View File

@@ -8,7 +8,7 @@ identity = Blueprint("identity", __name__)
# I'm pretty sure only Element uses this, # I'm pretty sure only Element uses this,
# but oh well. # but oh well.
# https://spec.matrix.org/v1.16/identity-service-api/#api-version-check # https://spec.matrix.org/latest/identity-service-api/#api-version-check
@identity.route("/_matrix/identity/versions") @identity.route("/_matrix/identity/versions")
async def versions(): async def versions():
# Stolen from the vector.im identity server # Stolen from the vector.im identity server
@@ -27,70 +27,70 @@ async def versions():
}) })
# https://spec.matrix.org/v1.16/identity-service-api/#authentication # https://spec.matrix.org/latest/identity-service-api/#authentication
@identity.route("/_matrix/identity/v2/account") @identity.route("/_matrix/identity/v2/account")
async def account_info(): async def account_info():
return jsonify({"user_id": f"@vona:{server_name}"}) return jsonify({"user_id": f"@vona:{server_name}"})
@identity.route("/_matrix/identity/v2/account/logout", methods=['POST']) @identity.route("/_matrix/identity/v2/account/logout", methods=["POST"])
async def logout(): async def logout():
return jsonify({}) return jsonify({})
@identity.route("/_matrix/identity/v2/account/register", methods=['POST']) @identity.route("/_matrix/identity/v2/account/register", methods=["POST"])
async def register(): async def register():
return jsonify({"token":"vona"}) return jsonify({"token":"vona"})
# https://spec.matrix.org/v1.16/identity-service-api/#terms-of-service # https://spec.matrix.org/latest/identity-service-api/#terms-of-service
@identity.route('/_matrix/identity/v2/terms', methods=['GET', 'POST']) @identity.route("/_matrix/identity/v2/terms", methods=["GET", "POST"])
async def policies(): async def policies():
if request.method == 'GET': if request.method == "GET":
return jsonify({"policies":{}}) return jsonify({"policies":{}})
return jsonify({}) return jsonify({})
@identity.route('/_matrix/identity/v2') @identity.route("/_matrix/identity/v2")
async def status(): async def status():
return jsonify({}) return jsonify({})
@identity.route('/_matrix/identity/v2/pubkey/ephemeral/isvalid') @identity.route("/_matrix/identity/v2/pubkey/ephemeral/isvalid")
@identity.route('/_matrix/identity/v2/pubkey/isvalid') @identity.route("/_matrix/identity/v2/pubkey/isvalid")
async def pubkey_validity(): async def pubkey_validity():
return jsonify({"valid": True}) return jsonify({"valid": True})
@identity.route('/_matrix/identity/v2/pubkey/<key>') @identity.route("/_matrix/identity/v2/pubkey/<key>")
async def get_key(key): async def get_key(key):
return jsonify({ return jsonify({
"errcode": "M_NOT_FOUND", "errcode": "M_NOT_FOUND",
"error": "The public key was not found" "error": "The public key was not found"
}), 404 }), 404
@identity.route('/_matrix/identity/v2/hash_details') @identity.route("/_matrix/identity/v2/hash_details")
async def hash_details(): async def hash_details():
return jsonify({"algorithms":["none","sha256"],"lookup_pepper": "vona"}) return jsonify({"algorithms":["none","sha256"],"lookup_pepper": "vona"})
@identity.route('/_matrix/identity/v2/lookup', methods=['POST']) @identity.route("/_matrix/identity/v2/lookup", methods=["POST"])
async def lookup(): async def lookup():
req = request.json req = request.json
if "addresses" in req: if "addresses" in req:
return jsonify({"mappings": {req['addresses'][0]: f"@vona:{server_name}"}}) return jsonify({"mappings": {req["addresses"][0]: f"@vona:{server_name}"}})
else: else:
return jsonify({"errcode": "M_INVALID_PEPPER","error": "Invalid pepper"}) return jsonify({"errcode": "M_INVALID_PEPPER","error": "Invalid pepper"})
@identity.route('/_matrix/identity/v2/validate/email/requestToken', methods=['POST']) @identity.route("/_matrix/identity/v2/validate/email/requestToken", methods=["POST"])
@identity.route('/_matrix/identity/v2/validate/msisdn/requestToken', methods=['POST']) @identity.route("/_matrix/identity/v2/validate/msisdn/requestToken", methods=["POST"])
async def request_validation_token(): async def request_validation_token():
return jsonify({"sid": str(the_funny_number)}) return jsonify({"sid": str(the_funny_number)})
@identity.route('/_matrix/identity/v2/validate/email/submitToken', methods=['GET', 'POST']) @identity.route("/_matrix/identity/v2/validate/email/submitToken", methods=["GET", "POST"])
@identity.route('/_matrix/identity/v2/validate/msisdn/submitToken', methods=['GET', 'POST']) @identity.route("/_matrix/identity/v2/validate/msisdn/submitToken", methods=["GET", "POST"])
async def submit_validation_token(): async def submit_validation_token():
return jsonify({"success": True}) return jsonify({"success": True})
@identity.route('/_matrix/identity/v2/3pid/bind', methods=['POST']) @identity.route("/_matrix/identity/v2/3pid/bind", methods=["POST"])
async def threepid_bind(): async def threepid_bind():
if "mxid" in request.get_json(): if "mxid" in request.get_json():
mxid = request.get_json()["mxid"] mxid = request.get_json()["mxid"]
@@ -106,11 +106,11 @@ async def threepid_bind():
"ts": int(time.time() * 1000) "ts": int(time.time() * 1000)
})) }))
@identity.route('/_matrix/identity/v2/3pid/unbind', methods=['POST']) @identity.route("/_matrix/identity/v2/3pid/unbind", methods=["POST"])
async def threepid_unbind(): async def threepid_unbind():
return jsonify({}) return jsonify({})
@identity.route('/_matrix/identity/v2/3pid/getValidated3pid') @identity.route("/_matrix/identity/v2/3pid/getValidated3pid")
async def threepid_validated(): async def threepid_validated():
# Please email abuse@matrix.org # Please email abuse@matrix.org
return jsonify({ return jsonify({
@@ -120,8 +120,8 @@ async def threepid_validated():
}) })
# https://spec.matrix.org/v1.16/identity-service-api/#invitation-storage # https://spec.matrix.org/latest/identity-service-api/#invitation-storage
@identity.route('/_matrix/identity/v2/store-invite', methods=['POST']) @identity.route("/_matrix/identity/v2/store-invite", methods=["POST"])
async def invite(): async def invite():
return jsonify({ return jsonify({
"display_name": "Vona", "display_name": "Vona",
@@ -139,10 +139,10 @@ async def invite():
}) })
# https://spec.matrix.org/v1.16/identity-service-api/#ephemeral-invitation-signing # https://spec.matrix.org/latest/identity-service-api/#ephemeral-invitation-signing
@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 = data.get_json()
if set(d.keys()) == required_keys: if set(d.keys()) == required_keys:

View File

@@ -34,19 +34,18 @@ async def handle_logging(response):
# Discard logs for OPTIONS # Discard logs for OPTIONS
return response return response
origin = "unknown"
try: try:
if "Authorization" in request.headers: if "Authorization" in request.headers:
if request.headers["Authorization"].split()[0] == "X-Matrix": if request.headers["Authorization"].split()[0] == "X-Matrix":
origin = request.headers["Authorization"].split('origin="')[1].split('"')[0] origin = request.headers["Authorization"].split('origin="')[1].split('"')[0]
else: else:
origin = "client" origin = "client"
else:
origin = "unknown"
except: except:
origin = "unknown" pass
print(f"[{origin}] [{request.remote_addr}] [{datetime.now().strftime('%d/%b/%Y:%H:%M:%S')}] {request.method} {request.full_path} {response.status_code}") print(f'[{origin}] [{request.remote_addr}] [{datetime.now().strftime("%d/%b/%Y:%H:%M:%S")}] {request.method} {request.full_path} {response.status_code}')
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate" response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Access-Control-Allow-Origin"] = "*" response.headers["Access-Control-Allow-Origin"] = "*"
@@ -63,7 +62,7 @@ async def root():
@app.route("/_matrix/static/") @app.route("/_matrix/static/")
async def matrix_static(): async def matrix_static():
return f'<!DOCTYPE html><html lang="en"><head><title>Vona {globals.vona_version} is running</title><style>body {{font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;max-width: 40em;margin: auto;text-align: center;}}h1,p {{margin: 1.5em;}}hr {{border: none;background-color: #ccc;color: #ccc;height: 1px;width: 7em;margin-top: 4em;}}.logo {{display: block;width: 12em;height: auto;margin: 4em auto;}}</style></head><body><img src="https://matrix.org/images/matrix-logo.svg" class="logo"><h1>It works! Vona {globals.vona_version} is running</h1><p>Your Vona server is listening on this port and is ready for messages.</p><p>To use this server you\'ll need <a href="https://matrix.org/ecosystem/clients/" target="_blank"rel="noopener noreferrer">a Matrix client</a>.</p><p>Welcome to the Matrix universe :)</p><hr><p><small><a href="https://natribu.org/en/" target="_blank" rel="noopener noreferrer">matrix.org</a></small></p></body></html>' return f'<!DOCTYPE html><html lang="en"><head><title>Vona {globals.vona_version} is running</title><style>body {{font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;max-width: 40em;margin: auto;text-align: center;}}h1,p {{margin: 1.5em;}}hr {{border: none;background-color: #ccc;color: #ccc;height: 1px;width: 7em;margin-top: 4em;}}.logo {{display: block;width: 12em;height: auto;margin: 4em auto;}}</style></head><body><img src="https://matrix.org/images/matrix-logo.svg" class="logo"><h1>It works! Vona {globals.vona_version} is running</h1><p>Your Vona server is listening on this port and is ready for messages.</p><p>To use this server you\"ll need <a href="https://matrix.org/ecosystem/clients/" target="_blank"rel="noopener noreferrer">a Matrix client</a>.</p><p>Welcome to the Matrix universe :)</p><hr><p><small><a href="https://natribu.org/en/" target="_blank" rel="noopener noreferrer">matrix.org</a></small></p></body></html>'
# Error handlers # Error handlers

View File

@@ -246,32 +246,32 @@ async def keys():
} }
})) }))
@server.route('/_matrix/federation/v1/query/directory') @server.route("/_matrix/federation/v1/query/directory")
async def room_query(): async def room_query():
return jsonify({ return jsonify({
"room_id": globals.make_event_id().replace("$", "!"), "room_id": globals.make_event_id().replace("$", "!"),
"servers": [server_name] "servers": [server_name]
}) })
@server.route('/_matrix/federation/v1/media/download/<media_id>') @server.route("/_matrix/federation/v1/media/download/<media_id>")
async def download_media(media_id): async def download_media(media_id):
# Auth media requires this to be # Auth media requires this to be
# multipart despite not even using # multipart despite not even using
# it for anything. Minor annoyance. # it for anything. Minor annoyance.
with open(cat, 'rb') as img_file: with open(cat, "rb") as img_file:
image_data = img_file.read() image_data = img_file.read()
boundary = '----WebKitFormBoundary7MA4YWxkTrZu0gW' boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"
response_body = ( response_body = (
f'--{boundary}\r\n' f"--{boundary}\r\n"
f'Content-Type: application/json\r\n\r\n' f"Content-Type: application/json\r\n\r\n"
f'{{}}\r\n' f"{{}}\r\n"
f'--{boundary}\r\n' f"--{boundary}\r\n"
f'Content-Type: image/jpeg\r\n' f"Content-Type: image/jpeg\r\n"
f'Content-Disposition: attachment; filename="cat.jpg"\r\n\r\n' f'Content-Disposition: attachment; filename="cat.jpg"\r\n\r\n'
).encode() + image_data + f'\r\n--{boundary}--\r\n'.encode() ).encode() + image_data + f"\r\n--{boundary}--\r\n".encode()
response = Response(response_body, content_type=f'multipart/mixed; boundary={boundary}') response = Response(response_body, content_type=f"multipart/mixed; boundary={boundary}")
response.status_code = 200 response.status_code = 200
return response return response
@@ -353,13 +353,13 @@ async def make_join(roomId, userId):
"room_version": "2" "room_version": "2"
}) })
@server.route('/_matrix/federation/v1/publicRooms', methods=['POST', 'GET']) @server.route("/_matrix/federation/v1/publicRooms", methods=["POST", "GET"])
async def room_directory(): async def room_directory():
return jsonify(room_dir_room) return jsonify(room_dir_room)
# https://spec.matrix.org/v1.16/server-server-api/#transactions # https://spec.matrix.org/latest/server-server-api/#transactions
@server.route('/_matrix/federation/v1/send/<txnId>', methods=["PUT"]) @server.route("/_matrix/federation/v1/send/<txnId>", methods=["PUT"])
async def receive_txn(txnId): async def receive_txn(txnId):
# We will need to implement a way to store every # We will need to implement a way to store every
# event we need if we want to send events in the # event we need if we want to send events in the
@@ -372,10 +372,10 @@ async def receive_txn(txnId):
# - m.room.power_levels # - m.room.power_levels
# - m.room.third_party_invite # - m.room.third_party_invite
# #
# As per https://spec.matrix.org/v1.16/rooms/v2/#authorization-rules # As per https://spec.matrix.org/latest/rooms/v2/#authorization-rules
data = request.data.decode('utf-8') data = request.data.decode("utf-8")
parsed_data = json.loads(data) parsed_data = json.loads(data)
response = {"pdus": {}} response = {"pdus": {}}
@@ -386,23 +386,27 @@ async def receive_txn(txnId):
return jsonify(response) return jsonify(response)
@server.route('/_matrix/federation/v1/query/profile')
@server.route("/_matrix/federation/v1/query/profile")
async def user_profile(): async def user_profile():
field = request.args.get('field') field = request.args.get("field")
if field: if field:
if field == 'avatar_url': if field == "avatar_url":
return jsonify({"avatar_url":f"mxc://{server_name}/cat"}) return jsonify({"avatar_url":f"mxc://{server_name}/cat"})
elif field == 'displayname': elif field == "displayname":
return jsonify({"displayname":"Vona"}) return jsonify({"displayname":"Vona"})
return jsonify({"errcode": "M_NOT_FOUND","error": "The requested profile key does not exist."}), 404 return jsonify({
"errcode": "M_NOT_FOUND",
"error": "The requested profile key does not exist."
}), 404
return jsonify({"avatar_url": f"mxc://{server_name}/cat","displayname": "Vona"}) return jsonify({"avatar_url": f"mxc://{server_name}/cat","displayname": "Vona"})
# https://spec.matrix.org/v1.16/server-server-api/#device-management # https://spec.matrix.org/latest/server-server-api/#device-management
@server.route(f'/_matrix/federation/v1/user/devices/@/:{server_name}') @server.route(f"/_matrix/federation/v1/user/devices/@/:{server_name}")
@server.route('/_matrix/federation/v1/user/devices/<user>') @server.route("/_matrix/federation/v1/user/devices/<user>")
async def user_devices(user): async def user_devices(user):
return jsonify({ return jsonify({
"devices": [], "devices": [],
@@ -411,7 +415,7 @@ async def user_devices(user):
}) })
@server.route('/_matrix/federation/v1/user/keys/query', methods=['POST']) @server.route("/_matrix/federation/v1/user/keys/query", methods=["POST"])
async def user_keys(): async def user_keys():
try: try:
users = request.json["device_keys"] users = request.json["device_keys"]
@@ -424,12 +428,12 @@ async def user_keys():
return jsonify({"device_keys": users}) return jsonify({"device_keys": users})
@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) return invite_user(request.data)
@server.route('/_matrix/federation/v1/invite/<room>/<txnId>', methods=["PUT"]) @server.route("/_matrix/federation/v1/invite/<room>/<txnId>", methods=["PUT"])
async def invite_user_v1(room, txnId): async def invite_user_v1(room, txnId):
return [200, invite_user(request.data)] return [200, invite_user(request.data)]
@@ -470,46 +474,46 @@ def invite_user(data):
}), 403 }), 403
@server.route('/_matrix/federation/v1/hierarchy/<roomId>') @server.route("/_matrix/federation/v1/hierarchy/<roomId>")
def space_hierachy(roomId): def space_hierachy(roomId):
room = room_dir_room['chunk'][0] room = room_dir_room["chunk"][0]
return jsonify({ return jsonify({
"children": [{ "children": [{
"avatar_url": room['avatar_url'], "avatar_url": room["avatar_url"],
"children_state": [{ "children_state": [{
"content": {"via": [server_name]}, "content": {"via": [server_name]},
"origin_server_ts": the_funny_number, "origin_server_ts": the_funny_number,
"sender": f"@vona:{server_name}", "sender": f"@vona:{server_name}",
"state_key": room['room_id'], "state_key": room["room_id"],
"type": "m.space.child" "type": "m.space.child"
}], }],
"guest_can_join": room['guest_can_join'], "guest_can_join": room["guest_can_join"],
"join_rule": room['join_rule'], "join_rule": room["join_rule"],
"name": room['name'], "name": room["name"],
"num_joined_members": room['num_joined_members'], "num_joined_members": room["num_joined_members"],
"room_id": room['room_id'], "room_id": room["room_id"],
"room_type": room['room_type'], "room_type": room["room_type"],
"topic": room['topic'], "topic": room["topic"],
"world_readable": room['world_readable'] "world_readable": room["world_readable"]
}], }],
"inaccessible_children": [], "inaccessible_children": [],
"room": { "room": {
"allowed_room_ids": [], "allowed_room_ids": [],
"avatar_url": room['avatar_url'], "avatar_url": room["avatar_url"],
"children_state": [{ "children_state": [{
"content": {"via": [server_name]}, "content": {"via": [server_name]},
"origin_server_ts": the_funny_number, "origin_server_ts": the_funny_number,
"sender": f"@vona:{server_name}", "sender": f"@vona:{server_name}",
"state_key": room['room_id'], "state_key": room["room_id"],
"type": "m.space.child" "type": "m.space.child"
}], }],
"guest_can_join": room['guest_can_join'], "guest_can_join": room["guest_can_join"],
"join_rule": room['join_rule'], "join_rule": room["join_rule"],
"name": room['name'], "name": room["name"],
"num_joined_members": room['num_joined_members'], "num_joined_members": room["num_joined_members"],
"room_id": room['room_id'], "room_id": room["room_id"],
"room_type": room['room_type'], "room_type": room["room_type"],
"topic": room['topic'], "topic": room["topic"],
"world_readable": room['world_readable'] "world_readable": room["world_readable"]
} }
}) })