Skip to content

Keep TPAP on https if in-band discover says tls=0 - #10

Open
tobixen wants to merge 2 commits into
ZeliardM:feature/tpapfrom
tobixen:tpap-rv50-tls-fix
Open

tobixen wants to merge 2 commits into
ZeliardM:feature/tpapfrom
tobixen:tpap-rv50-tls-fix

Conversation

@tobixen

@tobixen tobixen commented Sep 23, 2026

Copy link
Copy Markdown

Disclaimer: The code and the text below the line were generated by Claude Opus 5.5 from the prompt:

The vacuum cleaner is now connected to the same wifi as the laptop. I also have my cellphone connected. Please see if it's possible to get connected to the vacuum. Do not start any cleaning operations now.

Having the AI generate pull requests is cheap, but reading and understanding them is not. I respect that some maintainers may want to close AI-generated pull requests without explaining why. The real value I provide here is bug discovery, reproduction and testing on a real device.


This PR targets feature/tpap (the branch behind python-kasa#1592) and adds a single commit.

Device: Tapo RV50 Pro Omni(EU), firmware 1.2.8 (Build 260811).

UDP discovery advertises "tpap": {"tls": 2, "port": 4433, ...} and is_support_https: true. But the in-band login/discover sent over https on 4433 answers:

{"result":{"sub_method":"discover","tpap_preferred":true,"mac":"…","tpap":{"tls":0,"dac":1,"noc":1,"pake":[2],"port":4433}},"error_code":0}

_discover() believes the tls=0, and the next request goes to http://<ip>:4433/. That port only speaks TLS, so the device drops the connection (Server disconnected).

Fix: if the session was bootstrapped over https and the device then says tls=0, keep TLS mode 2. That is TLS verified against the TP-Link root CA, which takes the place of the DAC proof. As a side effect, an unauthenticated tls=0 reply can no longer downgrade an https session to plaintext. Devices bootstrapped over plain http, and a missing tls value, behave as before.

Tested: with this change, kasa --host … --port 4433 --https -e tpap -df SMART.TAPOROBOVAC state authenticates and reads the robot's status (read-only commands only). I added a unit test for the tls=0 case, and tests/transports/test_tpaptransport.py passes.

🤖 Generated with Claude Code

The RV50 Pro Omni(EU), fw 1.2.8, advertises tls=2 over UDP but answers
the in-band discover over TLS with tls=0.  The transport then rebuilt
its URL as http:// on the TLS-only port 4433 and the device dropped the
connection.

When the session was bootstrapped over https and the device says tls=0,
keep TLS mode 2: TLS verified against the TP-Link root CA, which then
takes the place of the DAC proof.  This also stops an unauthenticated
tls=0 reply from downgrading the session to plaintext.  Verified against
a real RV50; a missing tls value still falls back to http as before.

Prompt: The vacuum cleaner is now connected to the same wifi as the
laptop.  I also have my cellphone connected.  Please see if it's
possible to get connected to the vacuum.  Do not start any cleaning
operations now.

Assisted-By: Claude Opus 5.5 <noreply@anthropic.com>
With gmpy2 installed (Arch's python-gmpy2, for one), ecdsa returns
point coordinates as gmpy2.mpz, and cryptography's
EllipticCurvePublicNumbers accepts only int, so the SPAKE2+ handshake
failed with "TypeError: 'mpz' object is not an instance of 'int'".
Convert to int in _xy_to_uncompressed, which all call sites use, and
convert the curve order too, so w/h/x stay plain int and _encode_w
does not rely on mpz.to_bytes (gmpy2 >= 2.2 only).

Prompt: [look into the project] and make sure my local checkout is good [as in, the observed issues fixed.  Observed issues: the TypeError from _xy_to_uncompressed in the TPAP handshake, seen from opentapovac on the system Python]

Assisted-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant