Fix zeroconf

This commit is contained in:
kokarare1212
2021-09-14 19:23:10 +09:00
parent dac25540b2
commit c2bfa04c35
2 changed files with 33 additions and 18 deletions

View File

@@ -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_,

View File

@@ -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()
@@ -180,6 +181,13 @@ class ZeroconfServer(Closeable):
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