Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

All notable changes to this project will be documented in this file.

## [0.6.6] - 2026-04-28

### Added

- Introduce TLS adjustment for legacy v6 devices

## [0.6.5] - 2026-04-28

### Added
Expand Down
22 changes: 22 additions & 0 deletions airos/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from http.cookies import SimpleCookie
import json
import logging
from ssl import SSLError
from typing import Any, Generic, TypeVar
from urllib.parse import urlparse

Expand All @@ -27,6 +28,7 @@
AirOSDeviceConnectionError,
AirOSKeyDataMissingError,
AirOSMultipleMatchesFoundException,
AirOSTLSCompatibilityError,
AirOSUrlNotFoundError,
)
from .model_map import UispAirOSProductMapper
Expand Down Expand Up @@ -256,7 +258,7 @@
self._auth_cookie = f"{morsel.key}={morsel.value}"
break

async def _request_json(

Check failure on line 261 in airos/base.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this function to reduce its Cognitive Complexity from 16 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=CoMPaTech_python-airos&issues=AZ3uUM3yMVMThjdfwXcP&open=AZ3uUM3yMVMThjdfwXcP&pullRequest=206
self,
method: str,
url: str,
Expand Down Expand Up @@ -308,6 +310,11 @@
if err.status == 404:
raise AirOSUrlNotFoundError from err
raise AirOSConnectionSetupError from err
except aiohttp.ClientConnectorSSLError as err:
if _is_tls_compatibility_error(err):
_LOGGER.exception("TLS compatibility error during API call to %s", url)
raise AirOSTLSCompatibilityError from err
raise AirOSDeviceConnectionError from err
except (TimeoutError, aiohttp.ClientError) as err:
_LOGGER.exception("Error during API call to %s", url)
raise AirOSDeviceConnectionError from err
Expand Down Expand Up @@ -512,3 +519,18 @@
ct_json=True,
authenticated=True,
)


def _is_tls_compatibility_error(err: aiohttp.ClientConnectorSSLError) -> bool:
"""Return True for known legacy airOS TLS handshake failures."""
if "SSLV3_ALERT_HANDSHAKE_FAILURE" in str(err):
return True

cause = err.__cause__
if isinstance(cause, SSLError):
message = str(cause).lower()
return (
"handshake failure" in message or "sslv3 alert handshake failure" in message
)

return False
4 changes: 4 additions & 0 deletions airos/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,7 @@ class AirOSUrlNotFoundError(AirOSException):

class AirOSMultipleMatchesFoundException(AirOSException):
"""Raised when multiple devices found for lookup."""


class AirOSTLSCompatibilityError(AirOSDeviceConnectionError):
"""The device requires legacy TLS/cipher compaitibility."""
Comment on lines +52 to +53
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Typo in docstring: "compaitibility""compatibility".

✏️ Proposed fix
-    """The device requires legacy TLS/cipher compaitibility."""
+    """The device requires legacy TLS/cipher compatibility."""
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
class AirOSTLSCompatibilityError(AirOSDeviceConnectionError):
"""The device requires legacy TLS/cipher compaitibility."""
class AirOSTLSCompatibilityError(AirOSDeviceConnectionError):
"""The device requires legacy TLS/cipher compatibility."""
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@airos/exceptions.py` around lines 52 - 53, The docstring for class
AirOSTLSCompatibilityError (which subclasses AirOSDeviceConnectionError)
contains a typo: "compaitibility" should be "compatibility"; update the class
docstring to read "The device requires legacy TLS/cipher compatibility."
ensuring the corrected spelling is used in AirOSTLSCompatibilityError.

4 changes: 4 additions & 0 deletions airos/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
AirOSDataMissingError,
AirOSDeviceConnectionError,
AirOSKeyDataMissingError,
AirOSTLSCompatibilityError,
)

_LOGGER = logging.getLogger(__name__)
Expand All @@ -38,6 +39,9 @@ async def async_get_firmware_data(
try:
await detect_device.login()
device_data = await detect_device.raw_status()
except AirOSTLSCompatibilityError:
_LOGGER.exception("TLS compatibility error during API call to %s", host)
raise
except (
AirOSConnectionSetupError,
AirOSDeviceConnectionError,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "airos"
version = "0.6.5"
version = "0.6.6ab"
license = "MIT"
description = "Ubiquiti airOS module(s) for Python 3."
readme = "README.md"
Expand Down
Loading