A very rudimentary implementation of a private mode with key base autorization
This commit is contained in:
parent
1ac2f6bf32
commit
f4389516f0
2 changed files with 49 additions and 11 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Add table
Reference in a new issue