ONE COMMIT TO RULE THEM ALL
This commit is contained in:
32
README.md
32
README.md
@@ -1,32 +0,0 @@
|
|||||||
# Vona 🎉✨🔍🎊🌟💻🤔🛠️🚀
|
|
||||||
Welcome to Vona! 🎊 Vona is a flazing bast 🌟, and semory mafe [matrix] implementation made in Python 🐍 for stability.
|
|
||||||
Vona implements all endpoints incorrectly ❌, assuring compatibility with other server software 💻, like Synapse.
|
|
||||||
|
|
||||||
## How do I run it? 🔍🤔
|
|
||||||
Please don't 🙅♂️
|
|
||||||
|
|
||||||
## Installation Instructions 🛠️🔧
|
|
||||||
Use the power of Hopes and Dreams 🍀🌈✨
|
|
||||||
|
|
||||||
## Why you should use Vona 🚀🌟
|
|
||||||
- Blazing fast ⚡, and memory safe 🛡️
|
|
||||||
- Filters out spam efficiently 🚫📧
|
|
||||||
- Uses minimal storage 💾📦
|
|
||||||
- Secure 🔒 and low maintenance 🧹
|
|
||||||
- Complies with the [spec](https://spec.matrix.org) 📜✅
|
|
||||||
- At least 1 instance running in the wild 🌍🐾
|
|
||||||
- Policy server for ease of moderation 🧹🛡️
|
|
||||||
|
|
||||||
## What people are saying about Vona 🤩💬
|
|
||||||
- "this codebase is effectively an art project"
|
|
||||||
- @olivia:computer.surgery, one of the maintainers of
|
|
||||||
the [Grapevine](https://grapevine.computer.surgery)
|
|
||||||
homeserver software 💻
|
|
||||||
- "this is amazing 😄"
|
|
||||||
- @sarah:4d2.org, president of the popular 4d2.org
|
|
||||||
homeserver 👑
|
|
||||||
|
|
||||||
## License 📜🔑
|
|
||||||
We use the Velicense. Read more in the LICENSE file 📂📖.
|
|
||||||
|
|
||||||
Enjoy your journey with Vona! 🌈🚀🎉
|
|
||||||
@@ -14,8 +14,8 @@ apps = Blueprint("matrix_appservice", __name__)
|
|||||||
# another homeserver and appservice, thanks!
|
# another homeserver and appservice, thanks!
|
||||||
|
|
||||||
|
|
||||||
# https://spec.matrix.org/v1.15/application-service-api/#pinging
|
# https://spec.matrix.org/v1.16/application-service-api/#pinging
|
||||||
# https://spec.matrix.org/v1.15/application-service-api/#pinging-1
|
# https://spec.matrix.org/v1.16/application-service-api/#pinging-1
|
||||||
@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
|
||||||
@@ -27,7 +27,7 @@ async def app_ping():
|
|||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|
||||||
|
|
||||||
# https://spec.matrix.org/v1.15/application-service-api/#querying
|
# https://spec.matrix.org/v1.16/application-service-api/#querying
|
||||||
@apps.route('/_matrix/app/v1/users/<user>')
|
@apps.route('/_matrix/app/v1/users/<user>')
|
||||||
async def query_user(user):
|
async def query_user(user):
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
@@ -37,13 +37,13 @@ async def query_room(room):
|
|||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|
||||||
|
|
||||||
# https://spec.matrix.org/v1.15/application-service-api/#pushing-events
|
# https://spec.matrix.org/v1.16/application-service-api/#pushing-events
|
||||||
@apps.route('/_matrix/app/v1/transactions/<txnId>', methods=['PUT'])
|
@apps.route('/_matrix/app/v1/transactions/<txnId>', methods=['PUT'])
|
||||||
async def send_transaction(txnId):
|
async def send_transaction(txnId):
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|
||||||
|
|
||||||
# https://spec.matrix.org/v1.15/application-service-api/#third-party-networks
|
# https://spec.matrix.org/v1.16/application-service-api/#third-party-networks
|
||||||
@apps.route('/_matrix/app/v1/thirdparty/location')
|
@apps.route('/_matrix/app/v1/thirdparty/location')
|
||||||
async def location():
|
async def location():
|
||||||
return jsonify([])
|
return jsonify([])
|
||||||
@@ -65,7 +65,7 @@ async def user_from_protocol(protocol):
|
|||||||
return jsonify([])
|
return jsonify([])
|
||||||
|
|
||||||
|
|
||||||
# https://spec.matrix.org/v1.15/application-service-api/#published-room-directories
|
# https://spec.matrix.org/v1.16/application-service-api/#published-room-directories
|
||||||
@apps.route('/_matrix/client/v3/directory/list/appservice/<net>/<room>', methods=['PUT'])
|
@apps.route('/_matrix/client/v3/directory/list/appservice/<net>/<room>', methods=['PUT'])
|
||||||
async def publish_room(net, room):
|
async def publish_room(net, room):
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|||||||
372
src/c2s.py
372
src/c2s.py
@@ -1,5 +1,7 @@
|
|||||||
from config import server_name, users_can_register, room_dir_room, cat, the_funny_number
|
from config import server_name, users_can_register, room_dir_room, cat, the_funny_number
|
||||||
from flask import Blueprint, jsonify, request, send_file
|
from flask import Blueprint, jsonify, request, send_file
|
||||||
|
from s2s import send_join
|
||||||
|
import globals
|
||||||
import asyncio
|
import asyncio
|
||||||
import random
|
import random
|
||||||
import os
|
import os
|
||||||
@@ -8,18 +10,39 @@ client = Blueprint('matrix_client', __name__)
|
|||||||
|
|
||||||
@client.route('/_matrix/client/versions')
|
@client.route('/_matrix/client/versions')
|
||||||
def client_version():
|
def client_version():
|
||||||
return jsonify({"versions":["r0.0.1","r0.1.0","r0.2.0","r0.3.0","r0.4.0","r0.5.0","r0.6.0","r0.6.1","v1.1","v1.2","v1.3","v1.4","v1.5","v1.6","v1.7","v1.8","v1.9","v1.10","v1.11"],"unstable_features":{"org.matrix.label_based_filtering":True,"org.matrix.e2e_cross_signing":True,"org.matrix.msc2432":True,"uk.half-shot.msc2666.query_mutual_rooms":True,"io.element.e2ee_forced.public":False,"io.element.e2ee_forced.private":False,"io.element.e2ee_forced.trusted_private":False,"org.matrix.msc3026.busy_presence":False,"org.matrix.msc2285.stable":True,"org.matrix.msc3827.stable":True,"org.matrix.msc3440.stable":True,"org.matrix.msc3771":True,"org.matrix.msc3773":False,"fi.mau.msc2815":True,"fi.mau.msc2659.stable":True,"org.matrix.msc3882":False,"org.matrix.msc3881":False,"org.matrix.msc3874":False,"org.matrix.msc3912":False,"org.matrix.msc3981":True,"org.matrix.msc3391":False,"org.matrix.msc4069":False,"org.matrix.msc4028":False,"org.matrix.msc4108":False,"org.matrix.msc4140":False,"org.matrix.simplified_msc3575":True,"uk.tcpip.msc4133":True}})
|
return jsonify({
|
||||||
|
"versions": [
|
||||||
|
"r0.6.0",
|
||||||
|
"v1.16"
|
||||||
|
],
|
||||||
|
"unstable_features": {"uk.tcpip.msc4133": True}
|
||||||
|
})
|
||||||
|
|
||||||
@client.route('/_matrix/client/v3/admin/whois/<userId>')
|
@client.route('/_matrix/client/v3/admin/whois/<userId>')
|
||||||
def admin_whois(userId):
|
def admin_whois(userId):
|
||||||
if userId.startswith('@'):
|
if userId.startswith('@'):
|
||||||
return jsonify({"errcode":"M_MISSING_TOKEN","error":"Missing access token"})
|
return jsonify({"errcode":"M_MISSING_TOKEN","error":"Missing access token"})
|
||||||
else:
|
|
||||||
return jsonify({"errcode":"M_INVALID_PARAM","error":"Expected UserID string to start with '@'"})
|
return jsonify({"errcode":"M_INVALID_PARAM","error":"Expected UserID string to start with '@'"})
|
||||||
|
|
||||||
@client.route('/_matrix/client/v3/rooms/<roomId>/members')
|
@client.route('/_matrix/client/v3/rooms/<roomId>/members')
|
||||||
def room_member_count(roomId):
|
def room_member_count(roomId):
|
||||||
return jsonify({"errcode":"M_MISSING_TOKEN","error":"M_MISSING_TOKEN: Missing access token."})
|
return jsonify({
|
||||||
|
"chunk": [{
|
||||||
|
"content": {
|
||||||
|
"avatar_url": f"mxc://{server_name}/cat",
|
||||||
|
"displayname": "Vona",
|
||||||
|
"membership": "join"
|
||||||
|
},
|
||||||
|
"event_id": globals.make_event_id(),
|
||||||
|
"origin_server_ts": the_funny_number,
|
||||||
|
"room_id": roomId,
|
||||||
|
"sender": f"@vona:{server_name}",
|
||||||
|
"state_key": f"@vona:{server_name}",
|
||||||
|
"type": "m.room.member",
|
||||||
|
"unsigned": {}
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
|
||||||
@client.route('/_matrix/client/v3/account/whoami')
|
@client.route('/_matrix/client/v3/account/whoami')
|
||||||
def whoami():
|
def whoami():
|
||||||
@@ -31,29 +54,50 @@ def whoami():
|
|||||||
@client.route('/_matrix/client/v3/register', methods=['POST'])
|
@client.route('/_matrix/client/v3/register', methods=['POST'])
|
||||||
def register():
|
def register():
|
||||||
if users_can_register:
|
if users_can_register:
|
||||||
data = request.get_json()
|
try:
|
||||||
if data and 'auth' in data:
|
data = request.get_json()
|
||||||
return jsonify({
|
|
||||||
"user_id": f"@vona:{server_name}",
|
if data and 'auth' in data:
|
||||||
"home_server": f"{server_name}",
|
return jsonify({
|
||||||
"access_token": "vona",
|
"user_id": f"@vona:{server_name}",
|
||||||
"device_id": "VVOONNAA"
|
"home_server": f"{server_name}",
|
||||||
})
|
"access_token": "vona",
|
||||||
else:
|
"device_id": "VVOONNAA"
|
||||||
return jsonify({
|
})
|
||||||
"session": os.urandom(32).hex(),
|
|
||||||
"flows": [{"stages": ["m.login.dummy"]}],
|
except:
|
||||||
"params": {}
|
pass
|
||||||
}), 401
|
|
||||||
else:
|
return jsonify({
|
||||||
return jsonify({"errcode": "M_FORBIDDEN", "error": "M_FORBIDDEN: Registration has been disabled."}), 403
|
"session": os.urandom(32).hex(),
|
||||||
|
"flows": [{"stages": ["m.login.dummy"]}],
|
||||||
|
"params": {}
|
||||||
|
}), 401
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"errcode": "M_FORBIDDEN",
|
||||||
|
"error": "M_FORBIDDEN: Registration has been disabled."
|
||||||
|
}), 403
|
||||||
|
|
||||||
@client.route('/_matrix/client/v3/login', methods=['GET', 'POST'])
|
@client.route('/_matrix/client/v3/login', methods=['GET', 'POST'])
|
||||||
def login():
|
def login():
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
return jsonify({"flows":[{"type":"m.login.password"},{"type":"m.login.application_service"},{"type":"m.login.token","get_login_token":True}]})
|
return jsonify({
|
||||||
elif request.method == 'POST':
|
"flows": [
|
||||||
return jsonify({"access_token": "vona","device_id": "VVOONNAA","user_id": f"@vona:{server_name}"})
|
{"type": "m.login.password"},
|
||||||
|
{"type": "m.login.application_service"},
|
||||||
|
{
|
||||||
|
"type": "m.login.token",
|
||||||
|
"get_login_token": True
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"access_token": "vona",
|
||||||
|
"device_id": "VVOONNAA",
|
||||||
|
"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'])
|
||||||
def pswd_reset():
|
def pswd_reset():
|
||||||
@@ -66,27 +110,27 @@ def key_upload():
|
|||||||
@client.route('/_matrix/client/v3/room_keys/version', methods=['POST', 'GET'])
|
@client.route('/_matrix/client/v3/room_keys/version', methods=['POST', 'GET'])
|
||||||
def roomkeys():
|
def roomkeys():
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
return jsonify({
|
return jsonify({"version": str(the_funny_number)})
|
||||||
"algorithm": "m.megolm_backup.v1.curve25519-aes-sha2",
|
|
||||||
"auth_data":
|
|
||||||
{
|
|
||||||
"public_key":"vona",
|
|
||||||
"signatures": {
|
|
||||||
f"@vona:{server_name}": {
|
|
||||||
"ed25519:deviceid": "vona"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"count": the_funny_number,
|
|
||||||
"etag": "vona",
|
|
||||||
"version":str(the_funny_number)
|
|
||||||
})
|
|
||||||
|
|
||||||
return jsonify({})
|
return jsonify({
|
||||||
|
"algorithm": "m.megolm_backup.v1.curve25519-aes-sha2",
|
||||||
|
"auth_data": {
|
||||||
|
"public_key":"vonaisflazingbastandsemorymafe",
|
||||||
|
"signatures": {
|
||||||
|
f"@vona:{server_name}": {
|
||||||
|
# TODO: Make this actually valid
|
||||||
|
"ed25519:vonaa": "vona"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"count": the_funny_number,
|
||||||
|
"etag": "burgerkingfootlettuce",
|
||||||
|
"version": str(the_funny_number)
|
||||||
|
})
|
||||||
|
|
||||||
@client.route('/_matrix/client/v3/capabilities')
|
@client.route('/_matrix/client/v3/capabilities')
|
||||||
def capabilities():
|
def capabilities():
|
||||||
return jsonify({"capabilities":{"m.room_versions":{"default":"1337","available":{"1":"stable","2":"stable","3":"stable","4":"stable","5":"stable","6":"stable","7":"stable","8":"stable","1337":"stable","9":"stable","10":"stable","11":"stable","org.matrix.msc3757.10":"stable","org.matrix.msc3757.11":"stable"},"org.matrix.msc3244.room_capabilities":{"knock":{"preferred":"7","support":["7","8","9","10","11","org.matrix.msc3757.10","org.matrix.msc3757.11"]},"restricted":{"preferred":"9","support":["8","9","10","11","org.matrix.msc3757.10","org.matrix.msc3757.11"]}}},"m.change_password":{"enabled":True},"m.3pid_changes":{"enabled":True},"m.get_login_token":{"enabled":False},"m.profile_fields":{"enabled":True,"allowed":["na.vo.hafjagger"],"disallowed":["org.example.secret_field"]}}})
|
return jsonify({"capabilities":{"m.room_versions":{"default":"2","available":{"1":"stable","2":"stable","3":"stable","4":"stable","5":"stable","6":"stable","7":"stable","8":"stable","1337":"stable","9":"stable","10":"stable","11":"stable","org.matrix.msc3757.10":"stable","org.matrix.msc3757.11":"stable"},"org.matrix.msc3244.room_capabilities":{"knock":{"preferred":"7","support":["7","8","9","10","11","org.matrix.msc3757.10","org.matrix.msc3757.11"]},"restricted":{"preferred":"9","support":["8","9","10","11","org.matrix.msc3757.10","org.matrix.msc3757.11"]}}},"m.change_password":{"enabled":True},"m.3pid_changes":{"enabled":True},"m.get_login_token":{"enabled":False},"m.profile_fields":{"enabled":True,"allowed":["*"]}}})
|
||||||
|
|
||||||
@client.route('/_matrix/client/v3/pushrules/')
|
@client.route('/_matrix/client/v3/pushrules/')
|
||||||
def pushrules():
|
def pushrules():
|
||||||
@@ -101,11 +145,6 @@ def filter(user):
|
|||||||
def filter_two(user, data):
|
def filter_two(user, data):
|
||||||
return jsonify({"filter_id": "vvvooonnnaaa"})
|
return jsonify({"filter_id": "vvvooonnnaaa"})
|
||||||
|
|
||||||
@client.route('/_matrix/client/v3/join/<room>', methods=['POST'])
|
|
||||||
def join_room(room):
|
|
||||||
# TODO: Actually implement this
|
|
||||||
return jsonify({"errcode":"M_FORBIDDEN","error":"You are not invited to this room."}), 403
|
|
||||||
|
|
||||||
@client.route('/_matrix/client/v3/rooms/<room>/invite', methods=['POST'])
|
@client.route('/_matrix/client/v3/rooms/<room>/invite', methods=['POST'])
|
||||||
def invite_room(room):
|
def invite_room(room):
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
@@ -114,20 +153,69 @@ def invite_room(room):
|
|||||||
def knock_room(room):
|
def knock_room(room):
|
||||||
return jsonify({"errcode":"M_FORBIDDEN","error":"You are not allowed to knock on this room."}), 403
|
return jsonify({"errcode":"M_FORBIDDEN","error":"You are not allowed to knock on this room."}), 403
|
||||||
|
|
||||||
|
@client.route('/_matrix/client/v3/join/<room>', methods=['POST'])
|
||||||
@client.route('/_matrix/client/v3/rooms/<room>/join', methods=['POST'])
|
@client.route('/_matrix/client/v3/rooms/<room>/join', methods=['POST'])
|
||||||
def join_roomId(room):
|
def join_roomId(room):
|
||||||
return jsonify({"errcode":"M_FORBIDDEN","error":"You are not invited to this room."}), 403
|
return jsonify({"room_id": room})
|
||||||
|
|
||||||
@client.route('/_matrix/client/v3/sync')
|
@client.route('/_matrix/client/v3/sync')
|
||||||
async def sync():
|
async def sync():
|
||||||
|
class bullshit:
|
||||||
|
def get_json():
|
||||||
|
return {}
|
||||||
|
|
||||||
|
async def remove_keys(l, keys_to_remove) -> dict:
|
||||||
|
if not isinstance(l, list):
|
||||||
|
return l
|
||||||
|
|
||||||
|
new_list = []
|
||||||
|
for d in l:
|
||||||
|
if not isinstance(d, dict):
|
||||||
|
new_list.append(d)
|
||||||
|
continue
|
||||||
|
|
||||||
|
new_dict = {}
|
||||||
|
for k, v in d.items():
|
||||||
|
if k in keys_to_remove:
|
||||||
|
continue
|
||||||
|
new_dict[k] = await remove_keys(v, keys_to_remove)
|
||||||
|
new_list.append(new_dict)
|
||||||
|
return new_list
|
||||||
|
|
||||||
|
room = globals.make_event_id().replace("$", "!")
|
||||||
|
old_room_state = send_join(bullshit, room)["state"]
|
||||||
|
|
||||||
|
room_state = await remove_keys(
|
||||||
|
old_room_state,
|
||||||
|
[
|
||||||
|
"auth_events",
|
||||||
|
"prev_events",
|
||||||
|
"signatures",
|
||||||
|
"hashes",
|
||||||
|
"depth"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
room_name = {
|
||||||
|
"content": {
|
||||||
|
"name": "Burger King Foot Lettuce cult"
|
||||||
|
},
|
||||||
|
"origin_server_ts": the_funny_number,
|
||||||
|
"sender": f"@vona:{server_name}",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.name",
|
||||||
|
"event_id": globals.make_event_id(),
|
||||||
|
"room_id": room
|
||||||
|
}
|
||||||
|
|
||||||
|
room_state.append(room_name)
|
||||||
|
|
||||||
wait_time = 0
|
wait_time = 0
|
||||||
if 'timeout' in request.args:
|
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)
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
@@ -138,13 +226,13 @@ async def sync():
|
|||||||
"device_unused_fallback_key_types": ["signed_curve25519"],
|
"device_unused_fallback_key_types": ["signed_curve25519"],
|
||||||
"rooms": {
|
"rooms": {
|
||||||
"join": {
|
"join": {
|
||||||
f"!{os.urandom(64).hex()}:{server_name}": {
|
room: {
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"events": [],
|
"events": [],
|
||||||
"prev_batch": f"{random.randint(32095,309390)}",
|
"prev_batch": f"{random.randint(32095,309390)}",
|
||||||
"limited": False
|
"limited": False
|
||||||
},
|
},
|
||||||
"state": {"events": []},
|
"state": {"events": room_state},
|
||||||
"account_data": {"events": []},
|
"account_data": {"events": []},
|
||||||
"ephemeral": {"events": []},
|
"ephemeral": {"events": []},
|
||||||
"unread_notifications": {
|
"unread_notifications": {
|
||||||
@@ -159,7 +247,7 @@ 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'])
|
||||||
def send_message(room, eventType, txnId):
|
def send_message(room, eventType, txnId):
|
||||||
return jsonify({"event_id": f"${os.urandom(16).hex()}:{server_name}"}), 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'])
|
||||||
def user_directory():
|
def user_directory():
|
||||||
@@ -173,21 +261,13 @@ def devices():
|
|||||||
def get_device():
|
def get_device():
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
return jsonify({"device_id": "VVOONNAA","display_name": "Vona","last_seen_ip": "127.0.0.1","last_seen_ts": the_funny_number})
|
return jsonify({"device_id": "VVOONNAA","display_name": "Vona","last_seen_ip": "127.0.0.1","last_seen_ts": the_funny_number})
|
||||||
elif request.method == 'DELETE':
|
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
elif request.method == 'PUT':
|
|
||||||
return jsonify({})
|
|
||||||
|
|
||||||
@client.route('/_matrix/client/v3/delete_devices', methods=['POST'])
|
@client.route('/_matrix/client/v3/delete_devices', methods=['POST'])
|
||||||
def delete_devices():
|
|
||||||
return jsonify({})
|
|
||||||
|
|
||||||
@client.route('/_matrix/client/v3/logout', methods=['POST'])
|
|
||||||
def logout():
|
|
||||||
return jsonify({})
|
|
||||||
|
|
||||||
@client.route('/_matrix/client/v3/logout/all', methods=['POST'])
|
@client.route('/_matrix/client/v3/logout/all', methods=['POST'])
|
||||||
def logout_all():
|
@client.route('/_matrix/client/v3/logout', methods=['POST'])
|
||||||
|
def delete_devices():
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|
||||||
@client.route('/_matrix/client/v3/refresh', methods=['POST'])
|
@client.route('/_matrix/client/v3/refresh', methods=['POST'])
|
||||||
@@ -196,58 +276,53 @@ def refresh():
|
|||||||
|
|
||||||
@client.route('/_matrix/client/v3/voip/turnServer')
|
@client.route('/_matrix/client/v3/voip/turnServer')
|
||||||
def turnserver():
|
def turnserver():
|
||||||
return jsonify({"errcode": "M_LIMIT_EXCEEDED","error": "Too many requests","retry_after_ms": 99999999999999999999999999999999999999999999999999999999999999999999999999999999999}), 429
|
return jsonify({
|
||||||
|
"errcode": "M_LIMIT_EXCEEDED",
|
||||||
|
"error": "Too many requests",
|
||||||
|
"retry_after_ms": the_funny_number
|
||||||
|
}), 429
|
||||||
|
|
||||||
@client.route('/_matrix/client/unstable/im.nheko.summary/rooms/<roomId>/summary')
|
@client.route('/_matrix/client/unstable/im.nheko.summary/rooms/<roomId>/summary')
|
||||||
def nheko_room_summary(roomId):
|
@client.route('/_matrix/client/unstable/im.nheko.summary/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": str(the_funny_number),
|
})
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
@client.route('/_matrix/client/v1/room_summary/<roomId>')
|
@client.route('/_matrix/client/v1/room_summary/<roomId>')
|
||||||
def msc_room_summary(roomId):
|
def 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": str(the_funny_number),
|
})
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
@client.route('/_matrix/client/r0/directory/room/<roomId>')
|
@client.route('/_matrix/client/r0/directory/room/<roomId>')
|
||||||
def r0_room_query(roomId):
|
def r0_room_query(roomId):
|
||||||
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": [
|
})
|
||||||
"matrix.org",
|
|
||||||
"envs.net",
|
|
||||||
"4d2.org"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
@client.route('/_matrix/client/r0/directory/list/room/<roomId>')
|
@client.route('/_matrix/client/r0/directory/list/room/<roomId>')
|
||||||
def r0_room_vis(roomId):
|
def r0_room_vis(roomId):
|
||||||
@@ -257,28 +332,19 @@ def r0_room_vis(roomId):
|
|||||||
def r0_room_directory():
|
def r0_room_directory():
|
||||||
return jsonify(room_dir_room)
|
return jsonify(room_dir_room)
|
||||||
|
|
||||||
@client.route('/_matrix/media/r0/thumbnail/<server>/<file>')
|
|
||||||
def r0_media_thumbnail(server, file):
|
|
||||||
return send_file(cat)
|
|
||||||
|
|
||||||
@client.route('/_matrix/media/v1/thumbnail/<server>/<file>')
|
@client.route('/_matrix/media/v1/thumbnail/<server>/<file>')
|
||||||
def v1_media_thumbnail(server, file):
|
|
||||||
return send_file(cat)
|
|
||||||
|
|
||||||
@client.route('/_matrix/client/v1/media/thumbnail/<s>/<f>')
|
@client.route('/_matrix/client/v1/media/thumbnail/<s>/<f>')
|
||||||
def media_thumbnail(s, f):
|
@client.route('/_matrix/media/r0/thumbnail/<server>/<file>')
|
||||||
|
def media(server, file):
|
||||||
return send_file(cat)
|
return send_file(cat)
|
||||||
|
|
||||||
@client.route('/_matrix/client/r0/admin/whois/<userId>')
|
@client.route('/_matrix/client/r0/admin/whois/<userId>')
|
||||||
def whois(userId):
|
def whois(userId):
|
||||||
return jsonify({"user_id":f"@vona:{server_name}","devices":{"":{"sessions":[{"connections":[{"ip":f"{the_funny_number}.{the_funny_number}.{the_funny_number}.{the_funny_number}","last_seen":the_funny_number,"user_agent":f"Vona/{the_funny_number}.0"},{"ip":f"{the_funny_number}.{the_funny_number}.{the_funny_number}.{the_funny_number}","last_seen":the_funny_number,"user_agent":f"Vona/{the_funny_number}.0"}]}]}}})
|
return jsonify({"user_id":f"@vona:{server_name}","devices":{"":{"sessions":[{"connections":[{"ip":f"{the_funny_number}.{the_funny_number}.{the_funny_number}.{the_funny_number}","last_seen":the_funny_number,"user_agent":f"Vona/{the_funny_number}.0"},{"ip":f"{the_funny_number}.{the_funny_number}.{the_funny_number}.{the_funny_number}","last_seen":the_funny_number,"user_agent":f"Vona/{the_funny_number}.0"}]}]}}})
|
||||||
|
|
||||||
@client.route('/_matrix/client/r0/register/available')
|
|
||||||
def r0_username_available():
|
|
||||||
return jsonify({"available": True})
|
|
||||||
|
|
||||||
@client.route('/_matrix/client/v3/register/available')
|
@client.route('/_matrix/client/v3/register/available')
|
||||||
def v3_username_available():
|
@client.route('/_matrix/client/r0/register/available')
|
||||||
|
def username_available():
|
||||||
return jsonify({"available": True})
|
return jsonify({"available": True})
|
||||||
|
|
||||||
@client.route('/_matrix/client/v3/thirdparty/protocols')
|
@client.route('/_matrix/client/v3/thirdparty/protocols')
|
||||||
@@ -306,11 +372,11 @@ def media_preview():
|
|||||||
|
|
||||||
@client.route('/_matrix/media/v1/create', methods=['POST'])
|
@client.route('/_matrix/media/v1/create', methods=['POST'])
|
||||||
def create_mxc():
|
def create_mxc():
|
||||||
return jsonify({"content_uri": f"mxc://vona.squarebowl.club/{os.urandom(10).hex()}"})
|
return jsonify({"content_uri": f"mxc://{server_name}/cat"})
|
||||||
|
|
||||||
@client.route('/_matrix/media/v3/upload', methods=['POST'])
|
@client.route('/_matrix/media/v3/upload', methods=['POST'])
|
||||||
def upload_media():
|
def upload_media():
|
||||||
return jsonify({"content_uri": f"mxc://vona.squarebowl.club/{os.urandom(10).hex()}"})
|
return jsonify({"content_uri": f"mxc://{server_name}/cat"})
|
||||||
|
|
||||||
@client.route('/_matrix/media/v3/upload/<server>/<media>', methods=['PUT'])
|
@client.route('/_matrix/media/v3/upload/<server>/<media>', methods=['PUT'])
|
||||||
def upload_media_to_mxc(server, media):
|
def upload_media_to_mxc(server, media):
|
||||||
@@ -342,11 +408,14 @@ def user_profile_keys(userId, key):
|
|||||||
return jsonify({})
|
return jsonify({})
|
||||||
elif request.method == 'GET':
|
elif 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"})
|
||||||
else:
|
|
||||||
return jsonify({"errcode": "M_NOT_FOUND","error": "The requested profile key does not exist."})
|
return jsonify({
|
||||||
|
"errcode": "M_NOT_FOUND",
|
||||||
|
"error": "The requested profile key does not exist."
|
||||||
|
})
|
||||||
|
|
||||||
@client.route('/_matrix/client/v3/profile/<userId>')
|
@client.route('/_matrix/client/v3/profile/<userId>')
|
||||||
def user_profile(userId):
|
def user_profile(userId):
|
||||||
@@ -355,34 +424,19 @@ def user_profile(userId):
|
|||||||
@client.route('/_matrix/client/v3/rooms/<roomId>/messages')
|
@client.route('/_matrix/client/v3/rooms/<roomId>/messages')
|
||||||
def room_messages(roomId):
|
def room_messages(roomId):
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"chunk": [
|
"chunk": [{
|
||||||
{
|
"content": {
|
||||||
"content": {
|
"msgtype": "m.text",
|
||||||
"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.",
|
||||||
"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",
|
||||||
"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 "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."
|
||||||
"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 "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."
|
|
||||||
},
|
|
||||||
"event_id": f"{os.urandom(16).hex()}:{server_name}",
|
|
||||||
"origin_server_ts": the_funny_number,
|
|
||||||
"room_id": roomId,
|
|
||||||
"sender": f"@vona:{server_name}",
|
|
||||||
"type": "m.room.message",
|
|
||||||
"unsigned": {}
|
|
||||||
},
|
},
|
||||||
{
|
"event_id": globals.make_event_id(),
|
||||||
"content": {
|
"origin_server_ts": the_funny_number,
|
||||||
"name": "Vona"
|
"room_id": roomId,
|
||||||
},
|
"sender": f"@vona:{server_name}",
|
||||||
"event_id": f"{os.urandom(16).hex()}:{server_name}",
|
"type": "m.room.message"
|
||||||
"origin_server_ts": the_funny_number,
|
}],
|
||||||
"room_id": roomId,
|
|
||||||
"sender": f"@vona:{server_name}",
|
|
||||||
"state_key": "",
|
|
||||||
"type": "m.room.name",
|
|
||||||
"unsigned": {}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"end": f"{os.urandom(16).hex()}",
|
"end": f"{os.urandom(16).hex()}",
|
||||||
"start": f"{os.urandom(16).hex()}"
|
"start": f"{os.urandom(16).hex()}"
|
||||||
})
|
})
|
||||||
@@ -408,3 +462,9 @@ async def query_keys():
|
|||||||
# Should be replaced with
|
# Should be replaced with
|
||||||
# something proper eventually.
|
# something proper eventually.
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|
||||||
|
|
||||||
|
# https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3roomsroomidreceiptreceipttypeeventid
|
||||||
|
@client.route("/_matrix/client/v3/rooms/<room>/receipt/<type>/<event>", methods=['POST'])
|
||||||
|
def send_read_receipt(room, type, event):
|
||||||
|
return jsonify({})
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ def synapse_user_list():
|
|||||||
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})
|
||||||
elif request.method == 'PUT':
|
|
||||||
return jsonify({}), 201
|
return jsonify({}), 201
|
||||||
|
|
||||||
@custom.route('/_synapse/admin/v1/whois/<user_id>')
|
@custom.route('/_synapse/admin/v1/whois/<user_id>')
|
||||||
def synapse_whois(user_id):
|
def synapse_whois(user_id):
|
||||||
@@ -85,8 +85,8 @@ def synapse_account_data(user_id):
|
|||||||
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})
|
||||||
elif request.method == 'DELETE':
|
|
||||||
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):
|
||||||
@@ -100,8 +100,8 @@ def synapse_stupid_mas_bullshit(user_id):
|
|||||||
def synapse_device_list(user_id):
|
def synapse_device_list(user_id):
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
return jsonify({"devices":[{"device_id":"VVOONNAA","display_name":"Vona","last_seen_ip":"127.0.0.1","last_seen_ts":the_funny_number, "last_seen_user_agent": f"Vona/{vona_version}"}], "total": the_funny_number})
|
return jsonify({"devices":[{"device_id":"VVOONNAA","display_name":"Vona","last_seen_ip":"127.0.0.1","last_seen_ts":the_funny_number, "last_seen_user_agent": f"Vona/{vona_version}"}], "total": the_funny_number})
|
||||||
elif request.method == 'POST':
|
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|
||||||
@custom.route('/_synapse/admin/v2/users/<user_id>/delete_devices', methods=['POST'])
|
@custom.route('/_synapse/admin/v2/users/<user_id>/delete_devices', methods=['POST'])
|
||||||
def synapse_delete_devices(user_id):
|
def synapse_delete_devices(user_id):
|
||||||
@@ -111,8 +111,8 @@ def synapse_delete_devices(user_id):
|
|||||||
def synapse_device_info(user_id, device_id):
|
def synapse_device_info(user_id, device_id):
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
return jsonify({"device_id":"VVOONNAA","display_name":"Vona","last_seen_ip":"127.0.0.1","last_seen_ts":the_funny_number, "last_seen_user_agent": f"Vona/{vona_version}"})
|
return jsonify({"device_id":"VVOONNAA","display_name":"Vona","last_seen_ip":"127.0.0.1","last_seen_ts":the_funny_number, "last_seen_user_agent": f"Vona/{vona_version}"})
|
||||||
else:
|
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|
||||||
@custom.route('/_synapse/admin/v1/users/<user_id>/pushers')
|
@custom.route('/_synapse/admin/v1/users/<user_id>/pushers')
|
||||||
def synapse_pushers(user_id):
|
def synapse_pushers(user_id):
|
||||||
@@ -154,8 +154,8 @@ def synapse_experimental_features(user_id):
|
|||||||
def synapse_register():
|
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()})
|
||||||
elif request.method == 'POST':
|
|
||||||
return jsonify({"access_token": f"@vona:{server_name}"})
|
return jsonify({"access_token": f"@vona:{server_name}"})
|
||||||
|
|
||||||
@custom.route('/_synapse/admin/v1/join/<roomId>', methods=['POST'])
|
@custom.route('/_synapse/admin/v1/join/<roomId>', methods=['POST'])
|
||||||
def synapse_membership_manipulation(roomId):
|
def synapse_membership_manipulation(roomId):
|
||||||
@@ -248,12 +248,12 @@ def synapse_bg_update_start_job():
|
|||||||
|
|
||||||
@custom.route('/_synapse/admin/v1/event_reports')
|
@custom.route('/_synapse/admin/v1/event_reports')
|
||||||
def synapse_event_reports():
|
def synapse_event_reports():
|
||||||
return jsonify({"event_reports": [{"event_id": f"${make_event_id()}","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}"}],"total": the_funny_number})
|
return jsonify({"event_reports": [{"event_id": make_event_id(),"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}"}],"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'])
|
||||||
def synapse_interact_with_reported_event(report_id):
|
def synapse_interact_with_reported_event(report_id):
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
return jsonify({"event_id": f"${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 "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."},"depth": the_funny_number,"hashes": {"sha256": f"${make_event_id()}"},"origin": server_name,"origin_server_ts": the_funny_number,"prev_events": [f"${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": 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 "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."},"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}"})
|
||||||
else:
|
else:
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|
||||||
@@ -285,7 +285,7 @@ def dendrite_reindex():
|
|||||||
# Conduwuit
|
# Conduwuit
|
||||||
@custom.route('/_conduwuit/local_user_count')
|
@custom.route('/_conduwuit/local_user_count')
|
||||||
def conduwuit_user_count():
|
def conduwuit_user_count():
|
||||||
return jsonify({"count": the_funny_number})
|
return jsonify({"count": 1})
|
||||||
|
|
||||||
@custom.route('/_conduwuit/server_version')
|
@custom.route('/_conduwuit/server_version')
|
||||||
def conduwuit_server_version():
|
def conduwuit_server_version():
|
||||||
@@ -294,7 +294,7 @@ def conduwuit_server_version():
|
|||||||
# Continuwuity
|
# Continuwuity
|
||||||
@custom.route('/_continuwuity/local_user_count')
|
@custom.route('/_continuwuity/local_user_count')
|
||||||
def continuwuity_user_count():
|
def continuwuity_user_count():
|
||||||
return jsonify({"count": the_funny_number})
|
return jsonify({"count": 1})
|
||||||
|
|
||||||
@custom.route('/_continuwuity/server_version')
|
@custom.route('/_continuwuity/server_version')
|
||||||
def continuwuity_server_version():
|
def continuwuity_server_version():
|
||||||
@@ -303,7 +303,7 @@ def continuwuity_server_version():
|
|||||||
# Tuwunel
|
# Tuwunel
|
||||||
@custom.route('/_tuwunel/local_user_count')
|
@custom.route('/_tuwunel/local_user_count')
|
||||||
def tuwunel_user_count():
|
def tuwunel_user_count():
|
||||||
return jsonify({"count": the_funny_number})
|
return jsonify({"count": 1})
|
||||||
|
|
||||||
@custom.route('/_tuwunel/server_version')
|
@custom.route('/_tuwunel/server_version')
|
||||||
def tuwunel_server_version():
|
def tuwunel_server_version():
|
||||||
|
|||||||
133
src/globals.py
133
src/globals.py
@@ -2,11 +2,12 @@ import nacl.signing
|
|||||||
import hashlib
|
import hashlib
|
||||||
import base64
|
import base64
|
||||||
import config
|
import config
|
||||||
|
import copy
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
|
|
||||||
vona_version = "1.2.5"
|
vona_version = "1.3.0"
|
||||||
|
|
||||||
|
|
||||||
def canonical_json(value):
|
def canonical_json(value):
|
||||||
@@ -28,6 +29,35 @@ def sign_json(data):
|
|||||||
decoded_key = base64.b64decode(base64_key)
|
decoded_key = base64.b64decode(base64_key)
|
||||||
signing_key = nacl.signing.SigningKey(decoded_key)
|
signing_key = nacl.signing.SigningKey(decoded_key)
|
||||||
|
|
||||||
|
signed_message = signing_key.sign(canonical_json(data))
|
||||||
|
|
||||||
|
signature = signed_message.signature
|
||||||
|
|
||||||
|
key_version = parts[1]
|
||||||
|
signature_base64 = base64.b64encode(signature).decode("utf-8").rstrip("=")
|
||||||
|
|
||||||
|
signed_json = {
|
||||||
|
**data,
|
||||||
|
"signatures": {
|
||||||
|
config.server_name: {
|
||||||
|
f"{parts[0]}:{key_version}": signature_base64,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return signed_json
|
||||||
|
|
||||||
|
|
||||||
|
def sign_json_without_discard(data):
|
||||||
|
parts = config.signing_key.split()
|
||||||
|
base64_key = parts[2]
|
||||||
|
|
||||||
|
while len(base64_key) % 4 != 0:
|
||||||
|
base64_key += "="
|
||||||
|
|
||||||
|
decoded_key = base64.b64decode(base64_key)
|
||||||
|
signing_key = nacl.signing.SigningKey(decoded_key)
|
||||||
|
|
||||||
unsigned_keys = {key: data[key] for key in list(data.keys()) if key == "unsigned"}
|
unsigned_keys = {key: data[key] for key in list(data.keys()) if key == "unsigned"}
|
||||||
for key in unsigned_keys:
|
for key in unsigned_keys:
|
||||||
del data[key]
|
del data[key]
|
||||||
@@ -48,23 +78,35 @@ def sign_json(data):
|
|||||||
else:
|
else:
|
||||||
data["signatures"] = {config.server_name: new_signature}
|
data["signatures"] = {config.server_name: new_signature}
|
||||||
|
|
||||||
data.update(unsigned_keys)
|
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def make_event_id():
|
def make_event_id():
|
||||||
return re.sub(r"[\/+=]", "_", base64.b64encode(os.urandom(32)).decode("utf-8"))[:44]
|
event_id = "$"
|
||||||
|
|
||||||
|
event_id += re.sub(
|
||||||
|
r"[\/+=]",
|
||||||
|
"_",
|
||||||
|
base64.b64encode(
|
||||||
|
os.urandom(32),
|
||||||
|
).decode("utf-8"),
|
||||||
|
).rstrip("=")[:44]
|
||||||
|
|
||||||
|
event_id += ":" + config.server_name
|
||||||
|
|
||||||
|
return event_id
|
||||||
|
|
||||||
|
|
||||||
def hash_event(input) -> str:
|
def event_hash(event_object):
|
||||||
input.pop("signatures", None)
|
event_object = dict(event_object)
|
||||||
input.pop("unsigned", None)
|
|
||||||
|
|
||||||
sha256_hash = hashlib.sha256(canonical_json(input)).digest()
|
event_object.pop("unsigned", None)
|
||||||
base64_encoded = base64.b64encode(sha256_hash)
|
event_object.pop("signatures", None)
|
||||||
|
event_object.pop("hashes", None)
|
||||||
|
|
||||||
return base64_encoded.decode().rstrip("=")
|
event_json_bytes = canonical_json(event_object)
|
||||||
|
|
||||||
|
return base64.b64encode(hashlib.sha256(event_json_bytes).digest()).decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
def pubkey() -> str:
|
def pubkey() -> str:
|
||||||
@@ -107,8 +149,75 @@ def make_auth_header(destination, method, path, content=None) -> str:
|
|||||||
key,
|
key,
|
||||||
sig,
|
sig,
|
||||||
),
|
),
|
||||||
'utf-8'
|
"utf-8",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return authorization_headers[0].decode('utf-8')
|
return authorization_headers[0].decode("utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def redact_event(event):
|
||||||
|
# Returns a redacted event as per
|
||||||
|
# the algorithm for v1 rooms.
|
||||||
|
|
||||||
|
allowed_keys = [
|
||||||
|
"event_id",
|
||||||
|
"type",
|
||||||
|
"room_id",
|
||||||
|
"sender",
|
||||||
|
"state_key",
|
||||||
|
"content",
|
||||||
|
"hashes",
|
||||||
|
"signatures",
|
||||||
|
"depth",
|
||||||
|
"prev_events",
|
||||||
|
"prev_state",
|
||||||
|
"auth_events",
|
||||||
|
"origin",
|
||||||
|
"origin_server_ts",
|
||||||
|
"membership",
|
||||||
|
]
|
||||||
|
|
||||||
|
redacted_event = {k: v for k, v in event.items() if k in allowed_keys}
|
||||||
|
|
||||||
|
if "type" in redacted_event and "content" in redacted_event:
|
||||||
|
event_type = redacted_event["type"]
|
||||||
|
|
||||||
|
content_key_rules = {
|
||||||
|
"m.room.member": ["membership"],
|
||||||
|
"m.room.create": ["creator"],
|
||||||
|
"m.room.join_rules": ["join_rule"],
|
||||||
|
"m.room.power_levels": [
|
||||||
|
"ban",
|
||||||
|
"events",
|
||||||
|
"events_default",
|
||||||
|
"kick",
|
||||||
|
"redact",
|
||||||
|
"state_default",
|
||||||
|
"users",
|
||||||
|
"users_default",
|
||||||
|
],
|
||||||
|
"m.room.aliases": ["aliases"],
|
||||||
|
"m.room.history_visibility": ["history_visibility"],
|
||||||
|
}
|
||||||
|
|
||||||
|
if event_type in content_key_rules:
|
||||||
|
allowed_content_keys = content_key_rules[event_type]
|
||||||
|
redacted_event["content"] = {
|
||||||
|
k: v
|
||||||
|
for k, v in redacted_event["content"].items()
|
||||||
|
if k in allowed_content_keys
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
redacted_event["content"] = {}
|
||||||
|
|
||||||
|
return redacted_event
|
||||||
|
|
||||||
|
|
||||||
|
def hash_and_sign_event(event_object):
|
||||||
|
content_hash = event_hash(event_object)
|
||||||
|
event_object["hashes"] = {"sha256": content_hash}
|
||||||
|
stripped_object = redact_event(event_object)
|
||||||
|
signed_object = sign_json(stripped_object)
|
||||||
|
event_object["signatures"] = signed_object["signatures"]
|
||||||
|
return event_object
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from flask import Blueprint, jsonify, request
|
from flask import Blueprint, jsonify, request
|
||||||
from config import server_name, the_funny_number
|
from config import server_name, the_funny_number
|
||||||
|
import time
|
||||||
|
|
||||||
identity = Blueprint("matrix_identity", __name__)
|
identity = Blueprint("matrix_identity", __name__)
|
||||||
|
|
||||||
@@ -7,13 +8,14 @@ identity = Blueprint("matrix_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.15/identity-service-api/#api-version-check
|
# https://spec.matrix.org/v1.16/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
|
||||||
return jsonify({"versions":["r0.1.0","r0.2.0","r0.2.1","r0.3.0","v1.1","v1.2","v1.3","v1.4","v1.5"]})
|
return jsonify({"versions":["r0.1.0","r0.2.0","r0.2.1","r0.3.0","v1.1","v1.2","v1.3","v1.4","v1.5"]})
|
||||||
|
|
||||||
|
|
||||||
# https://spec.matrix.org/v1.15/identity-service-api/#authentication
|
# https://spec.matrix.org/v1.16/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}"})
|
||||||
@@ -27,7 +29,7 @@ async def register():
|
|||||||
return jsonify({"token":"vona"})
|
return jsonify({"token":"vona"})
|
||||||
|
|
||||||
|
|
||||||
# https://spec.matrix.org/v1.15/identity-service-api/#terms-of-service
|
# https://spec.matrix.org/v1.16/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':
|
||||||
@@ -36,13 +38,13 @@ async def policies():
|
|||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|
||||||
|
|
||||||
# https://spec.matrix.org/v1.15/identity-service-api/#status-check
|
# https://spec.matrix.org/v1.16/identity-service-api/#status-check
|
||||||
@identity.route('/_matrix/identity/v2')
|
@identity.route('/_matrix/identity/v2')
|
||||||
async def status():
|
async def status():
|
||||||
return jsonify({})
|
return jsonify({})
|
||||||
|
|
||||||
|
|
||||||
# https://spec.matrix.org/v1.15/identity-service-api/#key-management
|
# https://spec.matrix.org/v1.16/identity-service-api/#key-management
|
||||||
@identity.route('/_matrix/identity/v2/pubkey/ephemeral/isvalid')
|
@identity.route('/_matrix/identity/v2/pubkey/ephemeral/isvalid')
|
||||||
async def pubkey_eph_validity():
|
async def pubkey_eph_validity():
|
||||||
return jsonify({"valid":True})
|
return jsonify({"valid":True})
|
||||||
@@ -56,7 +58,7 @@ async def get_key(key):
|
|||||||
return jsonify({"errcode":"M_NOT_FOUND","error":"The public key was not found"}), 404
|
return jsonify({"errcode":"M_NOT_FOUND","error":"The public key was not found"}), 404
|
||||||
|
|
||||||
|
|
||||||
# https://spec.matrix.org/v1.15/identity-service-api/#association-lookup
|
# https://spec.matrix.org/v1.16/identity-service-api/#association-lookup
|
||||||
@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"})
|
||||||
@@ -65,13 +67,13 @@ async def hash_details():
|
|||||||
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"})
|
||||||
|
|
||||||
|
|
||||||
# https://spec.matrix.org/v1.15/identity-service-api/#establishing-associations
|
# https://spec.matrix.org/v1.16/identity-service-api/#establishing-associations
|
||||||
@identity.route('/_matrix/identity/v2/validate/email/requestToken', methods=['POST'])
|
@identity.route('/_matrix/identity/v2/validate/email/requestToken', methods=['POST'])
|
||||||
async def request_email_token():
|
async def request_email_token():
|
||||||
return jsonify({"sid":str(the_funny_number)})
|
return jsonify({"sid":str(the_funny_number)})
|
||||||
@@ -90,11 +92,19 @@ async def submit_phone_token():
|
|||||||
|
|
||||||
@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():
|
||||||
# We have to do signature stuff here,
|
if "mxid" in request.get_json():
|
||||||
# this will be implemented properly
|
mxid = request.get_json()["mxid"]
|
||||||
# when I actually get sigs working.
|
else:
|
||||||
|
mxid = f"@vona:{server_name}"
|
||||||
|
|
||||||
return jsonify({})
|
return jsonify(globals.sign_json({
|
||||||
|
"address": "abuse@matrix.org",
|
||||||
|
"medium": "email",
|
||||||
|
"mxid": mxid,
|
||||||
|
"not_after": int(time.time() * 1000 + 604800000),
|
||||||
|
"not_before": int(time.time() * 1000 - 604800000),
|
||||||
|
"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():
|
||||||
@@ -107,16 +117,27 @@ async def threepid_validated():
|
|||||||
return jsonify({"address":"abuse@matrix.org","medium":"email","validated_at":the_funny_number})
|
return jsonify({"address":"abuse@matrix.org","medium":"email","validated_at":the_funny_number})
|
||||||
|
|
||||||
|
|
||||||
# https://spec.matrix.org/v1.15/identity-service-api/#invitation-storage
|
# https://spec.matrix.org/v1.16/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({"display_name":"Vona","public_keys":[{"key_validity_url":"https://example.com/_matrix/identity/v2/pubkey/isvalid","public_key":"ohyeah"},{"key_validity_url":"https://example.com/_matrix/identity/v2/pubkey/ephemeral/isvalid","public_key":"thisssssss"}],"token":"vona"})
|
return jsonify({"display_name":"Vona","public_keys":[{"key_validity_url":"https://example.com/_matrix/identity/v2/pubkey/isvalid","public_key":"ohyeah"},{"key_validity_url":"https://example.com/_matrix/identity/v2/pubkey/ephemeral/isvalid","public_key":"thisssssss"}],"token":"vona"})
|
||||||
|
|
||||||
|
|
||||||
# https://spec.matrix.org/v1.15/identity-service-api/#ephemeral-invitation-signing
|
# https://spec.matrix.org/v1.16/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():
|
||||||
# the spec sez this is insecure :trole:
|
# We don't want to sign any proivided
|
||||||
return jsonify({
|
# JSON, thus make sure the keys match
|
||||||
"errcode":"M_TERMS_NOT_SIGNED","error":"Please accept our updated terms of service before continuing"
|
|
||||||
}), 403
|
required_keys = {'mxid', 'private_key', 'token'}
|
||||||
|
d = data.get_json()
|
||||||
|
|
||||||
|
if set(d.keys()) == required_keys:
|
||||||
|
return jsonify(sign_json(d))
|
||||||
|
else:
|
||||||
|
# User submitted invalid data, reject
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"errcode": "M_UNRECOGNIZED",
|
||||||
|
"error": "Didn't recognize token"
|
||||||
|
}), 404
|
||||||
|
|||||||
299
src/s2s.py
299
src/s2s.py
@@ -1,12 +1,238 @@
|
|||||||
from flask import Flask, jsonify, Response, request, send_file, abort, Blueprint
|
from flask import Flask, jsonify, Response, request, send_file, abort, Blueprint
|
||||||
from config import *
|
from config import *
|
||||||
import globals
|
import globals
|
||||||
|
import httpx
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
|
|
||||||
server = Blueprint('matrix_server', __name__)
|
server = Blueprint('matrix_server', __name__)
|
||||||
|
|
||||||
|
# NOTE: Synapse rejects this for
|
||||||
|
# whatever reason. Still looking
|
||||||
|
# into this issue.
|
||||||
|
def send_join(request, roomId):
|
||||||
|
event_chain = []
|
||||||
|
event_hashes = []
|
||||||
|
|
||||||
|
event_ids = [
|
||||||
|
globals.make_event_id(),
|
||||||
|
globals.make_event_id(),
|
||||||
|
globals.make_event_id(),
|
||||||
|
globals.make_event_id(),
|
||||||
|
globals.make_event_id(),
|
||||||
|
globals.make_event_id(),
|
||||||
|
]
|
||||||
|
|
||||||
|
create_event = {
|
||||||
|
"content": {
|
||||||
|
"m.federate": True,
|
||||||
|
"creator": f"@vona:{server_name}",
|
||||||
|
"room_version": "2"
|
||||||
|
},
|
||||||
|
"event_id": event_ids[0],
|
||||||
|
"origin_server_ts": 1,
|
||||||
|
"room_id": roomId,
|
||||||
|
"sender": f"@vona:{server_name}",
|
||||||
|
"state_key": "",
|
||||||
|
"depth": 1,
|
||||||
|
"type": "m.room.create",
|
||||||
|
"auth_events": [],
|
||||||
|
"prev_events": []
|
||||||
|
}
|
||||||
|
|
||||||
|
screate_event = globals.hash_and_sign_event(create_event)
|
||||||
|
event_chain.append(screate_event)
|
||||||
|
|
||||||
|
our_join = {
|
||||||
|
"content": {
|
||||||
|
"displayname": "Vona",
|
||||||
|
"avatar_url": f"mxc://{server_name}/cat",
|
||||||
|
"membership": "join"
|
||||||
|
},
|
||||||
|
"origin_server_ts": 2,
|
||||||
|
"sender": f"@vona:{server_name}",
|
||||||
|
"state_key": f"@vona:{server_name}",
|
||||||
|
"type": "m.room.member",
|
||||||
|
"event_id": event_ids[1],
|
||||||
|
"room_id": roomId,
|
||||||
|
"depth": 2,
|
||||||
|
"auth_events": [[
|
||||||
|
screate_event["event_id"],
|
||||||
|
screate_event["hashes"]
|
||||||
|
]],
|
||||||
|
"prev_events": [[
|
||||||
|
screate_event["event_id"],
|
||||||
|
screate_event["hashes"]
|
||||||
|
]]
|
||||||
|
}
|
||||||
|
|
||||||
|
sour_join = globals.hash_and_sign_event(our_join)
|
||||||
|
event_chain.append(sour_join)
|
||||||
|
|
||||||
|
pls = {
|
||||||
|
"content": {
|
||||||
|
"users": {
|
||||||
|
f"@vona:{server_name}": "100"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"origin_server_ts": 3,
|
||||||
|
"room_id": roomId,
|
||||||
|
"sender": f"@vona:{server_name}",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.power_levels",
|
||||||
|
"event_id": event_ids[2],
|
||||||
|
"depth": 3,
|
||||||
|
"user_id": f"@vona:{server_name}",
|
||||||
|
"auth_events": [
|
||||||
|
[
|
||||||
|
screate_event["event_id"],
|
||||||
|
screate_event["hashes"]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
sour_join["event_id"],
|
||||||
|
sour_join["hashes"]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"prev_events": [[
|
||||||
|
sour_join["event_id"],
|
||||||
|
sour_join["hashes"]
|
||||||
|
]]
|
||||||
|
}
|
||||||
|
|
||||||
|
spls = globals.hash_and_sign_event(pls)
|
||||||
|
event_chain.append(spls)
|
||||||
|
|
||||||
|
join_rule = {
|
||||||
|
"content": {
|
||||||
|
"join_rule": "public"
|
||||||
|
},
|
||||||
|
"origin_server_ts": 4,
|
||||||
|
"sender": f"@vona:{server_name}",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.join_rules",
|
||||||
|
"event_id": event_ids[3],
|
||||||
|
"room_id": roomId,
|
||||||
|
"depth": 4,
|
||||||
|
"auth_events": [
|
||||||
|
[
|
||||||
|
screate_event["event_id"],
|
||||||
|
screate_event["hashes"]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
sour_join["event_id"],
|
||||||
|
sour_join["hashes"]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
spls["event_id"],
|
||||||
|
spls["hashes"]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"prev_events": [[
|
||||||
|
spls["event_id"],
|
||||||
|
spls["hashes"]
|
||||||
|
]]
|
||||||
|
}
|
||||||
|
|
||||||
|
sjoin_rule = globals.hash_and_sign_event(join_rule)
|
||||||
|
event_chain.append(sjoin_rule)
|
||||||
|
|
||||||
|
guest_access = {
|
||||||
|
"content": {
|
||||||
|
"guest_access": "forbidden"
|
||||||
|
},
|
||||||
|
"origin_server_ts": 5,
|
||||||
|
"depth": 5,
|
||||||
|
"sender": f"@vona:{server_name}",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.guest_access",
|
||||||
|
"event_id": event_ids[4],
|
||||||
|
"room_id": roomId,
|
||||||
|
"auth_events": [
|
||||||
|
[
|
||||||
|
screate_event["event_id"],
|
||||||
|
screate_event["hashes"]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
sour_join["event_id"],
|
||||||
|
sour_join["hashes"]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
spls["event_id"],
|
||||||
|
spls["hashes"]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
sjoin_rule["event_id"],
|
||||||
|
sjoin_rule["hashes"]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"prev_events": [[
|
||||||
|
sjoin_rule["event_id"],
|
||||||
|
sjoin_rule["hashes"]
|
||||||
|
]]
|
||||||
|
}
|
||||||
|
|
||||||
|
sguest_access = globals.hash_and_sign_event(guest_access)
|
||||||
|
event_chain.append(sguest_access)
|
||||||
|
|
||||||
|
history = {
|
||||||
|
"content": {
|
||||||
|
"history_visibility": "shared"
|
||||||
|
},
|
||||||
|
"type": "m.room.history_visibility",
|
||||||
|
"sender": f"@vona:{server_name}",
|
||||||
|
"state_key": "",
|
||||||
|
"origin_server_ts": 6,
|
||||||
|
"depth": 6,
|
||||||
|
"event_id": event_ids[5],
|
||||||
|
"room_id": roomId,
|
||||||
|
"auth_events": [
|
||||||
|
[
|
||||||
|
screate_event["event_id"],
|
||||||
|
screate_event["hashes"]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
sour_join["event_id"],
|
||||||
|
sour_join["hashes"]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
spls["event_id"],
|
||||||
|
spls["hashes"]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
sjoin_rule["event_id"],
|
||||||
|
sjoin_rule["hashes"]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"prev_events": [[
|
||||||
|
sguest_access["event_id"],
|
||||||
|
sguest_access["hashes"]
|
||||||
|
]]
|
||||||
|
}
|
||||||
|
|
||||||
|
shistory = globals.hash_and_sign_event(history)
|
||||||
|
event_chain.append(shistory)
|
||||||
|
|
||||||
|
remote_join = request.get_json()
|
||||||
|
remote_join["auth_events"] = sguest_access["auth_events"]
|
||||||
|
remote_join["prev_events"] = [[shistory["event_id"], shistory["hashes"]]]
|
||||||
|
remote_join["depth"] = 7
|
||||||
|
remote_join = globals.hash_and_sign_event(remote_join)
|
||||||
|
|
||||||
|
response = {
|
||||||
|
"auth_chain": event_chain,
|
||||||
|
"event": remote_join,
|
||||||
|
"members_omitted": False,
|
||||||
|
"servers_in_room": [server_name],
|
||||||
|
"state": event_chain
|
||||||
|
}
|
||||||
|
|
||||||
|
# debug statement
|
||||||
|
print(json.dumps(response, indent='\t'))
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
@server.route('/_matrix/federation/v1/version')
|
@server.route('/_matrix/federation/v1/version')
|
||||||
def version():
|
def version():
|
||||||
return jsonify({"server": {"version": globals.vona_version,"name": "Vona"}})
|
return jsonify({"server": {"version": globals.vona_version,"name": "Vona"}})
|
||||||
@@ -35,7 +261,7 @@ def room_query():
|
|||||||
def download_media(media_id):
|
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()
|
||||||
@@ -60,11 +286,11 @@ def thumbnail_media(media_id):
|
|||||||
|
|
||||||
@server.route('/_matrix/federation/v1/send_join/<roomId>/<eventId>', methods=['PUT'])
|
@server.route('/_matrix/federation/v1/send_join/<roomId>/<eventId>', methods=['PUT'])
|
||||||
def send_join_v1(roomId, eventId):
|
def send_join_v1(roomId, eventId):
|
||||||
abort(500)
|
return jsonify([200, send_join(request, roomId)])
|
||||||
|
|
||||||
@server.route('/_matrix/federation/v2/send_join/<roomId>/<eventId>', methods=['PUT'])
|
@server.route('/_matrix/federation/v2/send_join/<roomId>/<eventId>', methods=['PUT'])
|
||||||
def send_join_v2(roomId, eventId):
|
def send_join_v2(roomId, eventId):
|
||||||
abort(500)
|
return jsonify(send_join(request, roomId))
|
||||||
|
|
||||||
@server.route('/_matrix/federation/v1/make_join/<roomId>/<userId>')
|
@server.route('/_matrix/federation/v1/make_join/<roomId>/<userId>')
|
||||||
def make_join(roomId, userId):
|
def make_join(roomId, userId):
|
||||||
@@ -89,26 +315,31 @@ def room_directory():
|
|||||||
return jsonify(room_dir_room)
|
return jsonify(room_dir_room)
|
||||||
|
|
||||||
|
|
||||||
# https://spec.matrix.org/v1.15/server-server-api/#transactions
|
# https://spec.matrix.org/v1.16/server-server-api/#transactions
|
||||||
@server.route('/_matrix/federation/v1/send/<txnId>', methods=['PUT'])
|
@server.route('/_matrix/federation/v1/send/<txnId>', methods=['PUT'])
|
||||||
def federation_send(txnId):
|
def receive_txn(txnId):
|
||||||
# This only works for v2 rooms, but anything
|
|
||||||
# bigger than v2 isn't real, so not a problem
|
|
||||||
|
|
||||||
# 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
|
||||||
# future. We don't send events currently, however.
|
# future. We don't send events currently, however.
|
||||||
|
|
||||||
|
# These events are:
|
||||||
|
# - m.room.create
|
||||||
|
# - m.room.member
|
||||||
|
# - m.room.join_rules
|
||||||
|
# - m.room.power_levels
|
||||||
|
# - m.room.third_party_invite
|
||||||
|
#
|
||||||
|
# As per https://spec.matrix.org/v1.16/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": {}}
|
||||||
|
|
||||||
if 'pdus' in parsed_data and parsed_data['pdus']:
|
if "pdus" in parsed_data:
|
||||||
for pdu in parsed_data['pdus']:
|
for pdu in parsed_data["pdus"]:
|
||||||
if 'hashes' in pdu and 'sha256' in pdu['hashes']:
|
if "event_id" in pdu:
|
||||||
pdu_hash = pdu['hashes']['sha256']
|
response["pdus"][pdu["event_id"]] = {}
|
||||||
response_key = f"${pdu_hash}:{parsed_data['origin']}"
|
|
||||||
response["pdus"][response_key] = {}
|
|
||||||
|
|
||||||
return jsonify(response)
|
return jsonify(response)
|
||||||
|
|
||||||
@@ -120,8 +351,8 @@ def user_profile():
|
|||||||
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"})
|
||||||
else:
|
|
||||||
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"})
|
||||||
|
|
||||||
@@ -138,20 +369,20 @@ def user_keys():
|
|||||||
return jsonify({"device_keys":{f"@vona:{server_name}":{}}})
|
return jsonify({"device_keys":{f"@vona:{server_name}":{}}})
|
||||||
|
|
||||||
|
|
||||||
# https://spec.matrix.org/v1.15/server-server-api/#inviting-to-a-room
|
# https://spec.matrix.org/v1.16/server-server-api/#inviting-to-a-room
|
||||||
@server.route('/_matrix/federation/v2/invite/<room>/<txnId>', methods=['PUT'])
|
@server.route('/_matrix/federation/v2/invite/<room>/<txnId>', methods=['PUT'])
|
||||||
def invite_user_v2(room, txnId):
|
def invite_user_v2(room, txnId):
|
||||||
return invite_user(request.data.decode('utf-8'), 2)
|
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'])
|
||||||
def invite_user_v1(room, txnId):
|
def invite_user_v1(room, txnId):
|
||||||
return invite_user(request.data.decode('utf-8'), 1)
|
return [200, invite_user(request.data)]
|
||||||
|
|
||||||
def invite_user(data, endpVer):
|
def invite_user(data):
|
||||||
try:
|
try:
|
||||||
invite_data = json.loads(data)
|
invite_data = json.loads(data)
|
||||||
except:
|
except:
|
||||||
return jsonify({"errcode":"M_NOT_JSON","error":"Content not JSON."}), 400
|
return jsonify({"errcode":"M_NOT_JSON","error":"Content not JSON."}),
|
||||||
|
|
||||||
if "event" in invite_data:
|
if "event" in invite_data:
|
||||||
if "room_version" in invite_data:
|
if "room_version" in invite_data:
|
||||||
@@ -161,22 +392,28 @@ def invite_user(data, endpVer):
|
|||||||
"error": "Vona only supports room version 2.",
|
"error": "Vona only supports room version 2.",
|
||||||
"room_version": invite_data["room_version"]
|
"room_version": invite_data["room_version"]
|
||||||
}), 400
|
}), 400
|
||||||
else:
|
|
||||||
if "content" in invite_data["event"]:
|
event = invite_data.get("event", {})
|
||||||
if "membership" in invite_data["event"]["content"] and invite_data["event"]["content"]["membership"] == "invite":
|
content = event.get("content", {})
|
||||||
if endpVer == 1:
|
|
||||||
return jsonify([
|
# NOTE to crispycat: I know you loooooove this syntax
|
||||||
200,
|
if (
|
||||||
{"event": globals.sign_json(invite_data["event"])}
|
"content" in event
|
||||||
])
|
and "membership" in content
|
||||||
else:
|
and "state_key" in event
|
||||||
return jsonify({"event": globals.sign_json(invite_data["event"]), "room_version": "2"})
|
and "room_id" in event
|
||||||
|
and content["membership"] == "invite"
|
||||||
|
and event["state_key"] == f"@vona:{server_name}"
|
||||||
|
):
|
||||||
|
return jsonify({"event": globals.sign_json_without_discard(invite_data["event"]), "room_version": "2"})
|
||||||
|
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"errcode": "M_FORBIDDEN",
|
"errcode": "M_FORBIDDEN",
|
||||||
"error": "Invalid invitation PDU"
|
"error": "Invalid invitation PDU"
|
||||||
}), 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]
|
||||||
|
|||||||
Reference in New Issue
Block a user