Skip to content

Commit

Permalink
Fix encryption without key in status call
Browse files Browse the repository at this point in the history
  • Loading branch information
ofalvai committed Feb 28, 2022
1 parent c9456c6 commit 0bc4773
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 4 deletions.
10 changes: 7 additions & 3 deletions custom_components/candy/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,13 @@ async def status_with_retry(self) -> Union[WashingMachineStatus, TumbleDryerStat
async def status(self) -> Union[WashingMachineStatus, TumbleDryerStatus, DishwasherStatus, OvenStatus]:
url = _status_url(self.device_ip, self.use_encryption)
async with self.session.get(url) as resp:
if self.encryption_key != "":
resp_hex = await resp.text() # Response is hex encoded encrypted data
decrypted_text = decrypt(self.encryption_key.encode(), bytes.fromhex(resp_hex))
if self.use_encryption:
resp_hex = await resp.text() # Response is hex encoded, either encrypted or not
if self.encryption_key != "":
decrypted_text = decrypt(self.encryption_key.encode(), bytes.fromhex(resp_hex))
else:
# Response is just hex encoded without encryption (details in detect_encryption())
decrypted_text = bytes.fromhex(resp_hex)
resp_json = json.loads(decrypted_text)
else:
resp_json = await resp.json(content_type="text/html")
Expand Down
36 changes: 35 additions & 1 deletion tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from aresponses import ResponsesMockServer

from custom_components.candy.client import CandyClient, detect_encryption, Encryption
from custom_components.candy.client.model import MachineState, WashProgramState, WashingMachineStatus
from custom_components.candy.client.model import MachineState, WashProgramState, WashingMachineStatus, DishwasherStatus
from .common import *


Expand Down Expand Up @@ -132,3 +132,37 @@ async def test_detect_encryption_without_key(aresponses: ResponsesMockServer):
assert key is None

aresponses.assert_plan_strictly_followed()


@pytest.mark.asyncio
async def test_status_encryption_with_key(aresponses: ResponsesMockServer):
aresponses.add(
TEST_IP,
"/http-read.json",
response="2F7C6B441B390C094C3C42093A023429764B1A403343714A6B3D503902342E073D535B6F086854653240386F2E0C23283714243F4B250A0D1A7313085D416B4C5E78686F6A3E191C570D662C1E0B657B76434361344071611A0454390C2026333D120E6F0368484A14443B44644114353503151E4D25084A026B016F416E4D485D53353F5C23163D562613774F53656D597B68441B0F1B071A73137D4F4F4A4B5D78431D4B251F1A592413774F337263787C6B4430683D104C3B50091F1A657B76414361344071611A0641280327282E263E11391B705A581A653C47646A6505311D00346A3E191A4C6B0B6F5D416B4C5E78686F6B2F153C5124546F5741767364534D403343714A7520423E3E022B35764B437C1B66756231401300041034133D1F12281B705A581A653C47646A650E24140F0956250A4A026B016F416E4D485D5333284A2F0C4A026B016F416E4D485D5322255C29133D486B0B6F5D416B4C5E78686F4B7B5A521A7B136160694E487603536F0368484A14443B4464413572764B437F1B6675623140133F59417D6365534D403343714A4A7C13774F53656D597B68441B384E4A026B016F416E4D485D53137A1B705A5B1A653C47646A65336C535B6F086854653240386F1F5A657B763F3401756854653240386F1F5272636E53506F3440711535434C"
)

async with aiohttp.ClientSession() as session:
client = CandyClient(session, device_ip=TEST_IP, encryption_key="TqaM9Jxh8I1MmcGA", use_encryption=True)
status = await client.status()

assert type(status) is DishwasherStatus

aresponses.assert_plan_strictly_followed()


@pytest.mark.asyncio
async def test_status_encryption_without_key(aresponses: ResponsesMockServer):
aresponses.add(
TEST_IP,
"/http-read.json",
response="7B0D0A20202020227374617475734C6176617472696365223A7B0D0A2020202020202020202020202257694669537461747573223A2230222C0D0A20202020202020202020202022457272223A22323535222C0D0A202020202020202020202020224D6163684D64223A2232222C0D0A202020202020202020202020225072223A223133222C0D0A2020202020202020202020202250725068223A2235222C0D0A20202020202020202020202022534C6576656C223A22323535222C0D0A2020202020202020202020202254656D70223A2230222C0D0A202020202020202020202020225370696E5370223A2230222C0D0A202020202020202020202020224F707431223A2230222C0D0A202020202020202020202020224F707432223A2230222C0D0A202020202020202020202020224F707433223A2230222C0D0A202020202020202020202020224F707434223A2230222C0D0A202020202020202020202020224F707435223A2230222C0D0A202020202020202020202020224F707436223A2230222C0D0A202020202020202020202020224F707437223A2230222C0D0A202020202020202020202020224F707438223A2230222C0D0A20202020202020202020202022537465616D223A2230222C0D0A2020202020202020202020202244727954223A2230222C0D0A2020202020202020202020202244656C56616C223A22323535222C0D0A2020202020202020202020202252656D54696D65223A223130222C0D0A202020202020202020202020225265636970654964223A2230222C0D0A20202020202020202020202022436865636B55705374617465223A2230220D0A202020207D0D0A7D"
)

async with aiohttp.ClientSession() as session:
client = CandyClient(session, device_ip=TEST_IP, encryption_key="", use_encryption=True)
status = await client.status()

assert type(status) is WashingMachineStatus

aresponses.assert_plan_strictly_followed()

0 comments on commit 0bc4773

Please sign in to comment.