-
-
Notifications
You must be signed in to change notification settings - Fork 221
Add klap support for TAPO protocol by splitting out Transports and Protocols #557
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@staticmethod | ||
def create_key_pair(key_size: int = 1024): | ||
"""Create a key pair.""" | ||
private_key = rsa.generate_private_key(public_exponent=65537, key_size=key_size) |
Check failure
Code scanning / CodeQL
Use of weak cryptographic key
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #557 +/- ##
==========================================
+ Coverage 75.76% 79.50% +3.74%
==========================================
Files 34 36 +2
Lines 2876 2991 +115
Branches 751 777 +26
==========================================
+ Hits 2179 2378 +199
+ Misses 640 541 -99
- Partials 57 72 +15 ☔ View full report in Codecov by Sentry. |
dd5c584
to
f28ff9b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a couple of very brief comments, mostly about things to make it easier to review.
Tests have now been added and the test framework is working with the new tapo devices. I will add more tests but wanted to get this in to ease review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's quite a bit of code to review and test, but here's the first round of comments. In general, separating the concerns of the encryption and the transport sounds good to me 👍
A couple of things:
- Update the PR title to be more descriptive.
- Class naming: let's try to avoid useless
TPLink*
,Smart
etc. prefixes where feasible, that pattern came from the pyhs100 project to keep backwards compatibility, but we should not introduce any more of them. - Using a self-created str<->(protocol, transport) mapping feels wrong and potentially error-prone when new versions will be deployed. I think we should decide soon what's a good abstraction for the discovery-like information to device instances..
@@ -22,11 +22,13 @@ | |||
] | |||
|
|||
|
|||
@device_iot |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if it would be better to run these tests on all devices for now, just to keep the interfaces consistent.
In the future, it makes sense to separate common interfaces as discussed elsewhere to avoid mixing implementation & interfaces like we currently do by inheriting from Smart*
for the new devices.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review @rytilahti. I know it was a lot and I thought hard about how to make it smaller but couldn’t come up with anything that made much sense.
Most of the comments are agreeable and doable and I will hopefully get sorted Monday. There is one question I have to clarify with you first. I restricted these tests with @device_iot
as a short term measure to keep the PR from getting bigger (yes I know :-). Currently too many tests access sysinfo and break.
So I think we have two options:
- Move all the SMART fixtures into a different directory so they don’t run on all tests.
- Restrict them for now with
@device_iot
and then gradually re-enable test_file by test_file as we introduce the interfaces.
I prefer 2. because it will mean we have a single test suite and a good interface. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, so those tests that test for specific payloads (like those schema checks in test_smartdevice) should only be tested against "device_iot"/"legacy" payloads, and indeed worth guarding for the time being.
Even then, we probably want to keep the "smart" fixtures separated from the legacy ones, so creating a new directory to host them from the get-go is a good idea if that's simple to achieve. If not, let's keep it simple for the time being and revisit it later.
But maybe the more generic ones (like testing for state_attributes structure, tests for cli outputs, ..) could still test everything if doing so doesn't require too many changes?
c097f8f
to
404e008
Compare
class TPLinkKlap(TPLinkProtocol): | ||
def _sha1(payload: bytes) -> bytes: | ||
digest = hashes.Hash(hashes.SHA1()) # noqa: S303 | ||
digest.update(payload) |
Check failure
Code scanning / CodeQL
Use of a broken or weak cryptographic hashing algorithm on sensitive data
def md5(payload: bytes) -> bytes: | ||
"""Return an md5 hash of the payload.""" | ||
digest = hashes.Hash(hashes.MD5()) # noqa: S303 | ||
digest.update(payload) |
Check failure
Code scanning / CodeQL
Use of a broken or weak cryptographic hashing algorithm on sensitive data
HI @rytilahti, I had a bit of time today to address this review. There's still work needed on the test framework but I think it will be better to perfect that in further PRs. After we get this in we can hopefully start to focus on separate streams, i.e. TAPO PRs, test framework PRs, test coverage PRs, fixture PRs and interface PRs. I hope we have the baseline now :) |
404e008
to
53ac5ca
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking good, I added some extra comments on top of the few already existing unresolveds. @sdb9696 take a look and see what makes sense to fix prior merging this so that we can start again having smaller PRs :-)
53ac5ca
to
63310d3
Compare
|
||
def _sha1(payload: bytes) -> str: | ||
sha1_algo = hashlib.sha1() # noqa: S324 | ||
sha1_algo.update(payload) |
Check failure
Code scanning / CodeQL
Use of a broken or weak cryptographic hashing algorithm on sensitive data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, let's get this merged. Thanks @sdb9696! 🥇
Hi @rytilahti , I've addressed most of the comments from today and the open ones I missed from the other day (for some reason they keep becoming hidden for me in github). If we're good to merge this now I'll go through afterwards and collate all of the "Subsequent PR" items we discussed and add them to the discussion so we don't lose sight of them. |
I think github sometimes loses track of things when doing force pushes but it may be just a feeling. :-) |
This PR adds KLAP support for the TAPO/SMART protocol. The way the encryption works is that the the original message that worked with #552 is instead encrypted with KLAP:
As the current klapprotocol implementation assumes the old kasa style of request/response this PR proposes to separate the transport from the protocol. The changes are:
TplinkKlap
toTPlinkIotProtocol
. It seems this is the distinction in the discovery result, device_type beginning withIOT.
uses the old protocol, device_type beginning withSMART.
uses the new.TPLinkAes
toTPLinkSmartProtocol
.TPLinkKlap
into a newTPLinkKlapTransport
class.TPLinkAes
into a newTPLinkAesTransport
class.SMART.
devices so there's a TPLinkKlapTransportV2 class derived from TPLinkKlapTransport that overrides the three hash functions.A good starting point to understand the changes here should be the
get_protocol_from_connection_name
diff in device_factory.py