Fix zeroconf
This commit is contained in:
@@ -27,7 +27,6 @@ import os
|
|||||||
import random
|
import random
|
||||||
import requests
|
import requests
|
||||||
import sched
|
import sched
|
||||||
import signal
|
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import threading
|
import threading
|
||||||
@@ -616,8 +615,6 @@ class Session(Closeable, MessageListener, SubListener):
|
|||||||
__user_attributes = {}
|
__user_attributes = {}
|
||||||
|
|
||||||
def __init__(self, inner: Inner, address: str) -> None:
|
def __init__(self, inner: Inner, address: str) -> None:
|
||||||
signal.signal(signal.SIGINT, lambda _1, _2: self.close())
|
|
||||||
signal.signal(signal.SIGTERM, lambda _1, _2: self.close())
|
|
||||||
self.__client = Session.create_client(inner.conf)
|
self.__client = Session.create_client(inner.conf)
|
||||||
self.connection = Session.ConnectionHolder.create(address, None)
|
self.connection = Session.ConnectionHolder.create(address, None)
|
||||||
self.__inner = inner
|
self.__inner = inner
|
||||||
@@ -1108,9 +1105,12 @@ class Session(Closeable, MessageListener, SubListener):
|
|||||||
sha1 = SHA1.new()
|
sha1 = SHA1.new()
|
||||||
sha1.update(device_id.encode())
|
sha1.update(device_id.encode())
|
||||||
secret = sha1.digest()
|
secret = sha1.digest()
|
||||||
base_key = PBKDF2(secret.decode(), username.encode(), 20, 0x100)
|
base_key = PBKDF2(secret, username.encode(), 20, 0x100, hmac_hash_module=SHA1)
|
||||||
aes = AES.new(base_key, AES.MODE_ECB)
|
sha1 = SHA1.new()
|
||||||
decrypted_blob = aes.decrypt(encrypted_blob)
|
sha1.update(base_key)
|
||||||
|
key = sha1.digest() + b"\x00\x00\x00\x14"
|
||||||
|
aes = AES.new(key, AES.MODE_ECB)
|
||||||
|
decrypted_blob = bytearray(aes.decrypt(encrypted_blob))
|
||||||
l = len(decrypted_blob)
|
l = len(decrypted_blob)
|
||||||
for i in range(0, l - 0x10):
|
for i in range(0, l - 0x10):
|
||||||
decrypted_blob[l - i - 1] ^= decrypted_blob[l - i - 0x11]
|
decrypted_blob[l - i - 1] ^= decrypted_blob[l - i - 0x11]
|
||||||
@@ -1125,8 +1125,9 @@ class Session(Closeable, MessageListener, SubListener):
|
|||||||
raise IOError(
|
raise IOError(
|
||||||
TypeError(
|
TypeError(
|
||||||
"Unknown AuthenticationType: {}".format(type_int)))
|
"Unknown AuthenticationType: {}".format(type_int)))
|
||||||
le = self.read_blob_int(blob)
|
blob.read(1)
|
||||||
auth_data = blob.read(le)
|
l = self.read_blob_int(blob)
|
||||||
|
auth_data = blob.read(l)
|
||||||
return Authentication.LoginCredentials(
|
return Authentication.LoginCredentials(
|
||||||
auth_data=auth_data,
|
auth_data=auth_data,
|
||||||
typ=type_,
|
typ=type_,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from Cryptodome.Cipher import AES
|
from Cryptodome.Cipher import AES
|
||||||
from Cryptodome.Hash import HMAC, SHA1
|
from Cryptodome.Hash import HMAC, SHA1
|
||||||
|
from Cryptodome.Util import Counter
|
||||||
from librespot import util, Version
|
from librespot import util, Version
|
||||||
from librespot.core import Session
|
from librespot.core import Session
|
||||||
from librespot.crypto import DiffieHellman
|
from librespot.crypto import DiffieHellman
|
||||||
@@ -52,7 +53,7 @@ class ZeroconfServer(Closeable):
|
|||||||
__min_port = 1024
|
__min_port = 1024
|
||||||
__runner: HttpRunner
|
__runner: HttpRunner
|
||||||
__service_info: zeroconf.ServiceInfo
|
__service_info: zeroconf.ServiceInfo
|
||||||
__session: typing.Union[Session, None]
|
__session: typing.Union[Session, None] = None
|
||||||
__session_listeners = []
|
__session_listeners = []
|
||||||
__zeroconf: zeroconf.Zeroconf
|
__zeroconf: zeroconf.Zeroconf
|
||||||
|
|
||||||
@@ -143,7 +144,7 @@ class ZeroconfServer(Closeable):
|
|||||||
__socket.send(self.__eol)
|
__socket.send(self.__eol)
|
||||||
__socket.send(self.__eol)
|
__socket.send(self.__eol)
|
||||||
return
|
return
|
||||||
aes = AES.new(encryption_key[:16], AES.MODE_CTR, iv)
|
aes = AES.new(encryption_key[:16], AES.MODE_CTR, counter=Counter.new(128, initial_value=int.from_bytes(iv, "big")))
|
||||||
decrypted = aes.decrypt(encrypted)
|
decrypted = aes.decrypt(encrypted)
|
||||||
with self.__connection_lock:
|
with self.__connection_lock:
|
||||||
self.__connecting_username = username
|
self.__connecting_username = username
|
||||||
@@ -171,7 +172,7 @@ class ZeroconfServer(Closeable):
|
|||||||
def handle_get_info(self, __socket: socket.socket,
|
def handle_get_info(self, __socket: socket.socket,
|
||||||
http_version: str) -> None:
|
http_version: str) -> None:
|
||||||
info = copy.deepcopy(self.__default_get_info_fields)
|
info = copy.deepcopy(self.__default_get_info_fields)
|
||||||
info["device_id"] = self.__inner.device_id
|
info["deviceID"] = self.__inner.device_id
|
||||||
info["remoteName"] = self.__inner.device_name
|
info["remoteName"] = self.__inner.device_name
|
||||||
info["publicKey"] = base64.b64encode(
|
info["publicKey"] = base64.b64encode(
|
||||||
self.__keys.public_key_bytes()).decode()
|
self.__keys.public_key_bytes()).decode()
|
||||||
@@ -179,7 +180,14 @@ class ZeroconfServer(Closeable):
|
|||||||
with self.__connection_lock:
|
with self.__connection_lock:
|
||||||
info[
|
info[
|
||||||
"activeUser"] = self.__connecting_username if self.__connecting_username is not None else self.__session.username(
|
"activeUser"] = self.__connecting_username if self.__connecting_username is not None else self.__session.username(
|
||||||
) if self.has_valid_session() else ""
|
) if self.has_valid_session() else ""
|
||||||
|
__socket.send(http_version.encode())
|
||||||
|
__socket.send(b" 200 OK")
|
||||||
|
__socket.send(self.__eol)
|
||||||
|
__socket.send(b"Content-Type: application/json")
|
||||||
|
__socket.send(self.__eol)
|
||||||
|
__socket.send(self.__eol)
|
||||||
|
__socket.send(json.dumps(info).encode())
|
||||||
|
|
||||||
def has_valid_session(self) -> bool:
|
def has_valid_session(self) -> bool:
|
||||||
valid = self.__session and self.__session.is_valid()
|
valid = self.__session and self.__session.is_valid()
|
||||||
@@ -188,10 +196,10 @@ class ZeroconfServer(Closeable):
|
|||||||
return valid
|
return valid
|
||||||
|
|
||||||
def parse_path(self, path: str) -> dict[str, str]:
|
def parse_path(self, path: str) -> dict[str, str]:
|
||||||
url = "http://host" + path
|
url = "https://host" + path
|
||||||
parsed = {}
|
parsed = {}
|
||||||
map = urllib.parse.parse_qs(urllib.parse.urlparse(url).query)
|
params = urllib.parse.parse_qs(urllib.parse.urlparse(url).query)
|
||||||
for key, values in map.items():
|
for key, values in params.items():
|
||||||
for value in values:
|
for value in values:
|
||||||
parsed[key] = value
|
parsed[key] = value
|
||||||
return parsed
|
return parsed
|
||||||
@@ -207,6 +215,7 @@ class ZeroconfServer(Closeable):
|
|||||||
self.__socket.bind((".".join(["0"] * 4), port))
|
self.__socket.bind((".".join(["0"] * 4), port))
|
||||||
self.__socket.listen(5)
|
self.__socket.listen(5)
|
||||||
self.__zeroconf_server = zeroconf_server
|
self.__zeroconf_server = zeroconf_server
|
||||||
|
logging.info("Zeroconf HTTP server started successfully on port {}!".format(port))
|
||||||
|
|
||||||
def close(self) -> None:
|
def close(self) -> None:
|
||||||
pass
|
pass
|
||||||
@@ -223,7 +232,7 @@ class ZeroconfServer(Closeable):
|
|||||||
|
|
||||||
def __handle(self, __socket: socket.socket) -> None:
|
def __handle(self, __socket: socket.socket) -> None:
|
||||||
request = io.BytesIO(__socket.recv(1024 * 1024))
|
request = io.BytesIO(__socket.recv(1024 * 1024))
|
||||||
request_line = request.readline().split(b" ")
|
request_line = request.readline().strip().split(b" ")
|
||||||
if len(request_line) != 3:
|
if len(request_line) != 3:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
"Unexpected request line: {}".format(request_line))
|
"Unexpected request line: {}".format(request_line))
|
||||||
@@ -232,7 +241,7 @@ class ZeroconfServer(Closeable):
|
|||||||
http_version = request_line[2].decode()
|
http_version = request_line[2].decode()
|
||||||
headers = {}
|
headers = {}
|
||||||
while True:
|
while True:
|
||||||
header = request.readline()
|
header = request.readline().strip()
|
||||||
if not header:
|
if not header:
|
||||||
break
|
break
|
||||||
split = header.split(b":")
|
split = header.split(b":")
|
||||||
@@ -271,6 +280,11 @@ class ZeroconfServer(Closeable):
|
|||||||
if action == "addUser":
|
if action == "addUser":
|
||||||
if params is None:
|
if params is None:
|
||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
|
self.__zeroconf_server.handle_add_user(__socket, params, http_version)
|
||||||
|
elif action == "getInfo":
|
||||||
|
self.__zeroconf_server.handle_get_info(__socket, http_version)
|
||||||
|
else:
|
||||||
|
logging.warning("Unknown action: {}".format(action))
|
||||||
|
|
||||||
class Inner:
|
class Inner:
|
||||||
conf: typing.Final[Session.Configuration]
|
conf: typing.Final[Session.Configuration]
|
||||||
@@ -285,6 +299,6 @@ class ZeroconfServer(Closeable):
|
|||||||
self.conf = conf
|
self.conf = conf
|
||||||
self.device_name = device_name
|
self.device_name = device_name
|
||||||
self.device_id = util.random_hex_string(
|
self.device_id = util.random_hex_string(
|
||||||
40).lower() if device_id else device_id
|
40).lower() if not device_id else device_id
|
||||||
self.device_type = device_type
|
self.device_type = device_type
|
||||||
self.preferred_locale = preferred_locale
|
self.preferred_locale = preferred_locale
|
||||||
|
|||||||
Reference in New Issue
Block a user