Make ty happy
This commit is contained in:
@@ -116,7 +116,8 @@ async def evacuate_room(room):
|
|||||||
req = request.json
|
req = request.json
|
||||||
|
|
||||||
if (
|
if (
|
||||||
"background" in req
|
isinstance(req, dict)
|
||||||
|
and "background" in req
|
||||||
and isinstance(req["background"], bool)
|
and isinstance(req["background"], bool)
|
||||||
):
|
):
|
||||||
background = req["background"]
|
background = req["background"]
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ def _load_toml(path: Path) -> dict:
|
|||||||
except tomllib.TOMLDecodeError as e:
|
except tomllib.TOMLDecodeError as e:
|
||||||
_fatal(f"Invalid TOML configuration: {e}")
|
_fatal(f"Invalid TOML configuration: {e}")
|
||||||
|
|
||||||
|
# This will never be reached. It is here
|
||||||
|
# specifically just to please ty
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
def _read_signing_key_from_path(path_value) -> str | None:
|
def _read_signing_key_from_path(path_value) -> str | None:
|
||||||
p = Path(path_value)
|
p = Path(path_value)
|
||||||
@@ -57,7 +61,7 @@ def _validate_cat_path(cat_path: str) -> Path:
|
|||||||
|
|
||||||
|
|
||||||
def _apply_config(cfg: dict) -> None:
|
def _apply_config(cfg: dict) -> None:
|
||||||
global addr, port, server_name, signing_key, cat, support, users_can_register, db
|
global addr, port, server_name, signing_key, cat, support, users_can_register
|
||||||
|
|
||||||
if "address" in cfg:
|
if "address" in cfg:
|
||||||
addr = str(cfg["address"])
|
addr = str(cfg["address"])
|
||||||
|
|||||||
@@ -30,7 +30,16 @@ async def news_stats(event):
|
|||||||
|
|
||||||
@citadel.route("/_matrix/client/r0/citadel/rooms/<room>/closeRoom", methods=["POST"])
|
@citadel.route("/_matrix/client/r0/citadel/rooms/<room>/closeRoom", methods=["POST"])
|
||||||
async def close_room(room):
|
async def close_room(room):
|
||||||
store_response = request.json.get("store_response", True)
|
req = request.json
|
||||||
|
|
||||||
|
if (
|
||||||
|
isinstance(req, dict)
|
||||||
|
and "store_response" in req
|
||||||
|
and isinstance(req["store_response"], bool)
|
||||||
|
):
|
||||||
|
store_response = req["store_response"]
|
||||||
|
else:
|
||||||
|
store_response = True
|
||||||
|
|
||||||
operation_id = base64.b64encode(
|
operation_id = base64.b64encode(
|
||||||
bytes(
|
bytes(
|
||||||
|
|||||||
@@ -248,8 +248,19 @@ 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():
|
||||||
|
req = request.json
|
||||||
|
|
||||||
|
if (
|
||||||
|
isinstance(req, dict)
|
||||||
|
and "device_keys" in req
|
||||||
|
and isinstance(req["device_keys"], dict)
|
||||||
|
):
|
||||||
|
device_keys = req["device_keys"]
|
||||||
|
else:
|
||||||
|
device_keys = {}
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"device_keys": request.json.get("device_keys", {})
|
"device_keys": device_keys
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@@ -257,7 +268,10 @@ async def user_keys():
|
|||||||
async def invite_user_v2(room, txnId):
|
async def invite_user_v2(room, txnId):
|
||||||
invite_data = request.json
|
invite_data = request.json
|
||||||
|
|
||||||
if "event" in invite_data:
|
if (
|
||||||
|
isinstance(invite_data, dict)
|
||||||
|
and "event" in invite_data
|
||||||
|
):
|
||||||
if "room_version" in invite_data:
|
if "room_version" in invite_data:
|
||||||
if invite_data["room_version"] not in [str(i) for i in range(1, 10)]:
|
if invite_data["room_version"] not in [str(i) for i in range(1, 10)]:
|
||||||
return jsonify({
|
return jsonify({
|
||||||
@@ -292,10 +306,19 @@ async def invite_user_v2(room, txnId):
|
|||||||
@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):
|
||||||
event = request.json
|
event = request.json
|
||||||
content = event.get("content", {})
|
if (
|
||||||
|
isinstance(event, dict)
|
||||||
|
and "content" in event
|
||||||
|
and isinstance(event["content"], dict)
|
||||||
|
):
|
||||||
|
content = event["content"]
|
||||||
|
else:
|
||||||
|
content = {}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
"content" in event
|
isinstance(event, dict)
|
||||||
|
and isinstance(content, dict)
|
||||||
|
and "content" in event
|
||||||
and "membership" in content
|
and "membership" in content
|
||||||
and "state_key" in event
|
and "state_key" in event
|
||||||
and "room_id" in event
|
and "room_id" in event
|
||||||
@@ -325,7 +348,12 @@ async def space_hierachy(room):
|
|||||||
@server.route("/_matrix/federation/v1/org.matrix.msc4358/discover_common_rooms", methods=["POST"])
|
@server.route("/_matrix/federation/v1/org.matrix.msc4358/discover_common_rooms", methods=["POST"])
|
||||||
@server.route("/_matrix/federation/v1/discover_common_rooms", methods=["POST"])
|
@server.route("/_matrix/federation/v1/discover_common_rooms", methods=["POST"])
|
||||||
async def discover_common_rooms():
|
async def discover_common_rooms():
|
||||||
tags = request.json.get("room_participation_tags", [])
|
req = request.json
|
||||||
|
if isinstance(req, dict):
|
||||||
|
tags = req.get("room_participation_tags", [])
|
||||||
|
else:
|
||||||
|
tags = []
|
||||||
|
|
||||||
return jsonify({"recognised_tags": tags})
|
return jsonify({"recognised_tags": tags})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
from resolvematrix import ServerResolver
|
from resolvematrix import ServerResolver
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
|
||||||
import vona.config as config
|
import vona.config as config
|
||||||
|
import nacl.encoding
|
||||||
import nacl.signing
|
import nacl.signing
|
||||||
import time as ti
|
import time as ti
|
||||||
import hashlib
|
import hashlib
|
||||||
@@ -15,7 +17,7 @@ import re
|
|||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
|
||||||
|
|
||||||
def canonical_json(value):
|
def canonical_json(value: dict | list) -> bytes:
|
||||||
return json.dumps(
|
return json.dumps(
|
||||||
value,
|
value,
|
||||||
ensure_ascii=False,
|
ensure_ascii=False,
|
||||||
@@ -24,7 +26,7 @@ def canonical_json(value):
|
|||||||
).encode("UTF-8")
|
).encode("UTF-8")
|
||||||
|
|
||||||
|
|
||||||
def sign_json(data):
|
def sign_json(data: dict) -> dict:
|
||||||
parts = config.signing_key.split()
|
parts = config.signing_key.split()
|
||||||
base64_key = parts[2]
|
base64_key = parts[2]
|
||||||
|
|
||||||
@@ -53,7 +55,7 @@ def sign_json(data):
|
|||||||
return signed_json
|
return signed_json
|
||||||
|
|
||||||
|
|
||||||
def sign_json_without_discard(data):
|
def sign_json_without_discard(data: dict) -> dict:
|
||||||
parts = config.signing_key.split()
|
parts = config.signing_key.split()
|
||||||
base64_key = parts[2]
|
base64_key = parts[2]
|
||||||
|
|
||||||
@@ -86,7 +88,7 @@ def sign_json_without_discard(data):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def make_event_id(seed=None):
|
def make_event_id(seed: str | int | None = None) -> str:
|
||||||
if seed is not None:
|
if seed is not None:
|
||||||
random.seed(seed)
|
random.seed(seed)
|
||||||
|
|
||||||
@@ -104,7 +106,7 @@ def make_event_id(seed=None):
|
|||||||
return event_id
|
return event_id
|
||||||
|
|
||||||
|
|
||||||
def event_hash(event_object):
|
def event_hash(event_object: dict) -> str:
|
||||||
event_object = dict(event_object)
|
event_object = dict(event_object)
|
||||||
|
|
||||||
event_object.pop("unsigned", None)
|
event_object.pop("unsigned", None)
|
||||||
@@ -174,7 +176,7 @@ def redact_event(
|
|||||||
event: dict,
|
event: dict,
|
||||||
for_event_id: bool = False,
|
for_event_id: bool = False,
|
||||||
room_ver: int = 1,
|
room_ver: int = 1,
|
||||||
):
|
) -> dict:
|
||||||
# Returns a redacted event as per
|
# Returns a redacted event as per
|
||||||
# the algorithm for v1 to v11 rooms.
|
# the algorithm for v1 to v11 rooms.
|
||||||
|
|
||||||
@@ -272,7 +274,7 @@ def redact_event(
|
|||||||
def hash_and_sign_event(
|
def hash_and_sign_event(
|
||||||
event_object: dict,
|
event_object: dict,
|
||||||
room_ver: int = 1,
|
room_ver: int = 1,
|
||||||
):
|
) -> dict:
|
||||||
content_hash = event_hash(event_object)
|
content_hash = event_hash(event_object)
|
||||||
event_object["hashes"] = {"sha256": content_hash}
|
event_object["hashes"] = {"sha256": content_hash}
|
||||||
stripped_object = redact_event(
|
stripped_object = redact_event(
|
||||||
@@ -288,7 +290,7 @@ def hash_and_sign_event(
|
|||||||
def make_ref_hash(
|
def make_ref_hash(
|
||||||
event: dict,
|
event: dict,
|
||||||
room_ver: int = 3,
|
room_ver: int = 3,
|
||||||
):
|
) -> str:
|
||||||
stripped = redact_event(
|
stripped = redact_event(
|
||||||
event=event,
|
event=event,
|
||||||
for_event_id=True,
|
for_event_id=True,
|
||||||
@@ -309,7 +311,7 @@ def make_ref_hash(
|
|||||||
return "$" + evt_hash
|
return "$" + evt_hash
|
||||||
|
|
||||||
|
|
||||||
def room_version_from_id(room):
|
def room_version_from_id(room) -> str:
|
||||||
room_id_no_sigil = (
|
room_id_no_sigil = (
|
||||||
room
|
room
|
||||||
.replace("!", "")
|
.replace("!", "")
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from vona.config import server_name, the_funny_number
|
import vona.config as config
|
||||||
|
import vona.globals as globals
|
||||||
import time
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
from flask import (
|
from flask import (
|
||||||
Blueprint,
|
Blueprint,
|
||||||
@@ -13,10 +15,8 @@ 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/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
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"versions": [
|
"versions": [
|
||||||
"r0.1.0",
|
"r0.1.0",
|
||||||
@@ -32,10 +32,11 @@ async def versions():
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
# 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:{config.server_name}"
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@identity.route("/_matrix/identity/v2/account/logout", methods=["POST"])
|
@identity.route("/_matrix/identity/v2/account/logout", methods=["POST"])
|
||||||
@@ -45,98 +46,129 @@ async def logout():
|
|||||||
|
|
||||||
@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/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",
|
"public_key": globals.pubkey()
|
||||||
"error": "The public key was not found"
|
})
|
||||||
}), 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 (
|
||||||
return jsonify({"mappings": {req["addresses"][0]: f"@vona:{server_name}"}})
|
isinstance(req, dict)
|
||||||
else:
|
and "addresses" in req
|
||||||
return jsonify({"errcode": "M_INVALID_PEPPER","error": "Invalid pepper"})
|
and isinstance(req["addresses"], list)
|
||||||
|
and len(req["addresses"]) > 0
|
||||||
|
):
|
||||||
|
return jsonify({
|
||||||
|
"mappings": {
|
||||||
|
req["addresses"][0]: f"@vona:{config.server_name}"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
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": os.urandom(16).hex()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@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"]
|
||||||
else:
|
else:
|
||||||
mxid = f"@vona:{server_name}"
|
mxid = f"@vona:{config.server_name}"
|
||||||
|
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
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():
|
||||||
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({
|
||||||
"address": "abuse@matrix.org",
|
"address": "abuse@matrix.org",
|
||||||
"medium": "email",
|
"medium": "email",
|
||||||
"validated_at": the_funny_number
|
"validated_at": config.the_funny_number
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
# 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",
|
||||||
"public_keys": [
|
"public_keys": [
|
||||||
{
|
{
|
||||||
"key_validity_url": f"https://{server_name}/_matrix/identity/v2/pubkey/isvalid",
|
"key_validity_url": f"https://{config.server_name}/_matrix/identity/v2/pubkey/isvalid",
|
||||||
"public_key": "ohyeah"
|
"public_key": "ohyeah"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key_validity_url": f"https://{server_name}/_matrix/identity/v2/pubkey/ephemeral/isvalid",
|
"key_validity_url": f"https://{config.server_name}/_matrix/identity/v2/pubkey/ephemeral/isvalid",
|
||||||
"public_key": "burgerkingfootlettuce"
|
"public_key": "burgerkingfootlettuce"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -144,7 +176,6 @@ async def invite():
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
# 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"}
|
||||||
|
|||||||
Reference in New Issue
Block a user