A very rudimentary implementation of a private mode with key base autorization

This commit is contained in:
Christoph Stahl 2023-03-24 13:30:33 +01:00
parent 1ac2f6bf32
commit f4389516f0
2 changed files with 49 additions and 11 deletions

View file

@ -14,6 +14,7 @@ Excerp from the help::
--room ROOM, -r ROOM
--secret SECRET, -s SECRET
--config-file CONFIG_FILE, -C CONFIG_FILE
--key KEY, -k KEY
The config file should be a json file in the following style::
@ -82,6 +83,8 @@ class State:
a room, this must be identical. Also, if a webclient wants to have
admin privileges, this must be included.
:type secret: str
:param key: An optional key, if registration on the server is limited.
:type key: Optional[str]
:param preview_duration: Amount of seconds the preview before a song be
displayed.
:type preview_duration: int
@ -98,6 +101,7 @@ class State:
room: str = ""
server: str = ""
secret: str = ""
key: Optional[str] = None
preview_duration: int = 3
last_song: Optional[datetime.datetime] = None
@ -187,16 +191,16 @@ async def handle_connect() -> None:
:rtype: None
"""
logging.info("Connected to server")
await sio.emit(
"register-client",
{
"queue": state.queue,
"recent": state.recent,
"room": state.room,
"secret": state.secret,
"config": state.get_config(),
},
)
data = {
"queue": state.queue,
"recent": state.recent,
"room": state.room,
"secret": state.secret,
"config": state.get_config(),
}
if state.key:
data["registration-key"] = state.key
await sio.emit("register-client", data)
@sio.on("get-meta-info")
@ -390,6 +394,7 @@ async def aiomain() -> None:
parser.add_argument("--room", "-r")
parser.add_argument("--secret", "-s")
parser.add_argument("--config-file", "-C", default="syng-client.json")
parser.add_argument("--key", "-k", default=None)
parser.add_argument("server")
args = parser.parse_args()
@ -406,6 +411,8 @@ async def aiomain() -> None:
if "preview_duration" in config["config"]:
state.preview_duration = config["config"]["preview_duration"]
state.key = args.key if args.key else None
if args.room:
state.room = args.room

View file

@ -16,6 +16,7 @@ from __future__ import annotations
import asyncio
import datetime
import hashlib
import logging
import os
import random
@ -350,10 +351,12 @@ async def handle_register_client(sid: str, data: dict[str, Any]) -> None:
Handle the "register-client" message.
The data dictionary should have the following keys:
- `registration_key` (Optional), a key corresponding to those stored
in `app["registration-keyfile"]`
- `room` (Optional), the requested room
- `config`, an dictionary of initial configurations
- `queue`, a list of initial entries for the queue. The entries are
encoded as a dictionary.
encoded as a dictionary.
- `recent`, a list of initial entries for the recent list. The entries
are encoded as a dictionary.
- `secret`, the secret of the room
@ -363,6 +366,9 @@ async def handle_register_client(sid: str, data: dict[str, Any]) -> None:
playback client will be replaced if and only if, the new playback
client has the same secret.
If registration is restricted, abort, if the given key is not in the
registration keyfile.
If no room is provided, a fresh room id is generated.
If the client provides a new room, or a new room id was generated, the
@ -394,6 +400,25 @@ async def handle_register_client(sid: str, data: dict[str, Any]) -> None:
client_id = gen_id(length + 1)
return client_id
if not app["public"]:
with open(app["registration-keyfile"]) as f:
raw_keys = f.readlines()
keys = [key[:64] for key in raw_keys]
if (
"registration-key" not in data
or hashlib.sha256(
data["registration-key"].encode()
).hexdigest()
not in keys
):
await sio.emit(
"client-registered",
{"success": False, "room": None},
room=sid,
)
return
room: str = data["room"] if "room" in data and data["room"] else gen_id()
async with sio.session(sid) as session:
session["room"] = room
@ -791,8 +816,14 @@ def main() -> None:
parser.add_argument("--host", "-H", default="localhost")
parser.add_argument("--port", "-p", default="8080")
parser.add_argument("--root-folder", "-r", default="syng/static/")
parser.add_argument("--registration-keyfile", "-k", default=None)
args = parser.parse_args()
app["public"] = True
if args.registration_keyfile:
app["public"] = False
app["registration-keyfile"] = args.registration_keyfile
app["root_folder"] = args.root_folder
app.add_routes(