Fix cookie-jar pollution; remove dead QR login code; add tests

The reauth flow ran validate_jsessionid against HA's shared aiohttp
session, then update_cookies({"JSESSIONID": ...}) added the new value
with no domain. aiohttp's cookie jar still held the previous
JSESSIONID pinned to smartthingsfind.samsung.com (set via Set-Cookie
during the previous load), and aiohttp prefers the more-specific
domain match — so the *stale* cookie went out, Samsung returned no
_csrf header, and the user saw "Cookie was rejected by SmartThings
Find" even though their cookie was fine.

Two fixes:

* validate_jsessionid now runs in an isolated aiohttp.ClientSession
  with its own jar, so the shared HA jar can't shadow the cookie
  under test.

* async_setup_entry clear_domain()s the smartthingsfind.samsung.com
  cookies before reseating JSESSIONID with response_url, otherwise
  the same shadowing breaks the entry reload that follows a
  successful UI reauth.

Also remove the QR-code login code (do_login_stage_one / _two,
gen_qr_code_base64, the legacy URL constants and qrcode/base64/
random/string/re/asyncio/io/timedelta imports) — Samsung migrated
account.samsung.com to a SPA-driven IAM/OAuth2 flow months ago, so
the QR scrape no longer works and nothing in the integration
references those helpers anymore. Drops the qrcode/pillow/requests
manifest requirements.

Tests: a minimal conftest stubs the homeassistant.* imports the
integration uses, and four async tests cover validate_jsessionid
including the regression case where a domain-bound stale cookie
sits in the shared jar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jeena 2026-05-05 06:44:59 +00:00
parent 7457a8284b
commit 4c26792c37
6 changed files with 287 additions and 227 deletions

View file

@ -1,6 +1,7 @@
from datetime import timedelta
import logging
import aiohttp
from yarl import URL
from homeassistant.core import HomeAssistant
from homeassistant.helpers.typing import ConfigType
from homeassistant.const import Platform
@ -39,7 +40,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
jsessionid = entry.data[CONF_JSESSIONID]
session = async_get_clientsession(hass)
session.cookie_jar.update_cookies({"JSESSIONID": jsessionid})
# The shared HA session may already hold a JSESSIONID for this domain
# from a previous load (set via Set-Cookie). Clear it first; otherwise
# a bare update_cookies adds an unscoped duplicate and aiohttp ships the
# older, domain-matched (stale) value, breaking auth after a UI reauth.
session.cookie_jar.clear_domain("smartthingsfind.samsung.com")
session.cookie_jar.update_cookies(
{"JSESSIONID": jsessionid},
response_url=URL("https://smartthingsfind.samsung.com/"),
)
active_smarttags = entry.options.get(CONF_ACTIVE_MODE_SMARTTAGS, CONF_ACTIVE_MODE_SMARTTAGS_DEFAULT)
active_others = entry.options.get(CONF_ACTIVE_MODE_OTHERS, CONF_ACTIVE_MODE_OTHERS_DEFAULT)