Skip to content

Commit

Permalink
Merge pull request #12 from enerBit/ssl_bug
Browse files Browse the repository at this point in the history
fix ssl bug by using truststore package
  • Loading branch information
elpablete authored Nov 6, 2024
2 parents cdbc156 + a1681ff commit a98ee90
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 24 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,13 @@ Para poder hacer uso de la librería DSO se debe hacer lo siguiente
Para ello se debe importar el constructor de la siguiente forma:

```txt
from enerbitdso.enerbit import DSOConnector
from enerbitdso.enerbit import DSOClient
```

La inicialización se debe hacer asi:

```txt
ebconnector = enerbit.DSOConnector(
ebconnector = enerbit.DSOClient(
api_base_url="https://dso.enerbit.me/",
api_username="usuario_del_DSO",
api_password="contraseña_del_DSO",
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dependencies = [
"urlpath>=1.2.0",
"typer>=0.12.5",
"tzdata>=2024.2",
"truststore>=0.10.0",
]

[project.scripts]
Expand Down
2 changes: 1 addition & 1 deletion src/enerbitdso/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.14
0.1.15
34 changes: 25 additions & 9 deletions src/enerbitdso/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import operator
import pathlib
import sys
import zoneinfo

import typer
import zoneinfo
from rich.console import Console

from enerbitdso import enerbit, formats
Expand Down Expand Up @@ -54,14 +54,24 @@ def fetch(
formats=DATE_FORMATS,
show_default="today",
),
out_format: OutputFormat = typer.Option("jsonl", help="Output file format", case_sensitive=False),
frt_file: pathlib.Path = typer.Option(None, help="Path file with one frt code per line"),
out_format: OutputFormat = typer.Option(
"jsonl", help="Output file format", case_sensitive=False
),
frt_file: pathlib.Path = typer.Option(
None, help="Path file with one frt code per line"
),
frts: list[str] = typer.Argument(None, help="List of frt codes separated by ' '"),
):
try:
ebclient = enerbit.get_client(api_base_url, api_username, api_password)
ebconnector = enerbit.DSOClient(
api_base_url=api_base_url,
api_username=api_username,
api_password=api_password,
)
except Exception:
err_console.print(f"Failed to authenticate to '{api_base_url}' as '{api_username}'")
err_console.print(
f"Failed to authenticate to '{api_base_url}' as '{api_username}'"
)
raise typer.Exit(code=1)

today = dt.datetime.now(TZ_INFO).replace(**DATE_PARTS_TO_START_DAY)
Expand All @@ -74,6 +84,9 @@ def fetch(
else:
until = until.astimezone(TZ_INFO)

if frts is None:
frts = []

if not operator.xor(frt_file is not None, len(frts) != 0):
err_console.print("Can't use '--FRT_FILE' and 'FRTS' on the same call")
raise typer.Exit(code=1)
Expand All @@ -82,16 +95,19 @@ def fetch(
with open(frt_file, "r") as frts_src:
frts = frts_src.read().splitlines()

err_console.print(f"Fetching usages for {len(frts)} frts since={since} until={until}")
err_console.print(
f"Fetching usages for {len(frts)} frts since={since} until={until}"
)

ebconnector = enerbit.DSOConnector(api_base_url=api_base_url, api_username=api_username, api_password=api_password)
header = True
for i, f in enumerate(frts):
try:
usage_records = ebconnector.fetch_schedule_usage_records_large_interval(f, since=since, until=until)
usage_records = ebconnector.fetch_schedule_usage_records_large_interval(
f, since=since, until=until
)
except Exception:
err_console.print(f"Failed to fetch usage records for frt code '{f}'")
# err_console.print_exception()
err_console.print_exception()
continue

match out_format:
Expand Down
28 changes: 24 additions & 4 deletions src/enerbitdso/enerbit.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import datetime as dt
import logging
import math
import ssl

import httpx
import pydantic
import truststore
import urlpath

logger = logging.getLogger(__name__)

SSL_CONTEXT = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)

TIMEOUT = httpx.Timeout(5, read=60)

Expand Down Expand Up @@ -41,9 +44,14 @@ class ScheduleMeasurementRecord(pydantic.BaseModel):
def get_auth_token(base_url, username, password):
path = "/auth/token/"
data = {"username": username, "password": password}
with httpx.Client(base_url=base_url, timeout=TIMEOUT) as client:
with httpx.Client(base_url=base_url, timeout=TIMEOUT, verify=SSL_CONTEXT) as client:
response = client.post(path, data=data)
response.raise_for_status()
try:
response.raise_for_status()
except httpx.HTTPStatusError as e:
logger.error(f"Failed to authenticate: {e}")
logger.error(f"Response: {response.text}")
raise
token = response.json()["access_token"]
return token

Expand All @@ -52,7 +60,7 @@ def get_client(base_url, username, password):
url = str(urlpath.URL(base_url))
token = get_auth_token(url, username, password)
auth = {"Authorization": f"Bearer {token}"}
return httpx.Client(base_url=url, headers=auth, timeout=TIMEOUT)
return httpx.Client(base_url=url, headers=auth, timeout=TIMEOUT, verify=SSL_CONTEXT)


def scale_measurement_records(records: list[ScheduleMeasurementRecord], scale: float):
Expand Down Expand Up @@ -85,6 +93,12 @@ def get_schedule_usage_records(
"period-number": 1,
}
response = client.get(path, params=params)
try:
response.raise_for_status()
except httpx.HTTPStatusError as e:
logger.error(f"Failed to fetch usage records: {e}")
logger.error(f"Response: {response.text}")
raise
response.raise_for_status()
records = response.json()
records = sorted(records, key=lambda r: r["time_start"])
Expand All @@ -103,6 +117,12 @@ def get_schedule_measurement_records(
"frt-code": frt_code,
}
response = client.get(path, params=params)
try:
response.raise_for_status()
except httpx.HTTPStatusError as e:
logger.error(f"Failed to fetch measurement records: {e}")
logger.error(f"Response: {response.text}")
raise
response.raise_for_status()
records = response.json()
records = sorted(records, key=lambda r: r["time_local_utc"])
Expand All @@ -113,7 +133,7 @@ def get_schedule_measurement_records(
return measurement_records


class DSOConnector:
class DSOClient:
def __init__(
self, api_username: str, api_password: pydantic.SecretStr, api_base_url: str
) -> None:
Expand Down
14 changes: 7 additions & 7 deletions tests/test_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from unittest.mock import patch

from enerbitdso.enerbit import (
DSOConnector,
DSOClient,
)

from .mocked_responses import (
Expand All @@ -27,7 +27,7 @@ def test_get_all_usage_records(self, mock_get_auth_token):
frontier = "Frt" + "".join(random.choices("0123456789", k=5))
create_mocked_usages(frt_code=frontier, since=since_month, until=until_month)
mock_get_auth_token.return_value = "my_token"
ebconnector = DSOConnector(
ebconnector = DSOClient(
api_base_url="https://dso.enerbit.me/",
api_username="test",
api_password="test",
Expand All @@ -51,7 +51,7 @@ def test_get_part_usage_records(self, mock_get_auth_token):
frontier = "Frt" + "".join(random.choices("0123456789", k=5))
create_mocked_usages(frt_code=frontier, since=since_month, until=until_month)
mock_get_auth_token.return_value = "my_token"
ebconnector = DSOConnector(
ebconnector = DSOClient(
api_base_url="https://dso.enerbit.me/",
api_username="test",
api_password="test",
Expand All @@ -78,7 +78,7 @@ def test_get_empty_usage_records(self, mock_get_auth_token):
frontier = "Frt" + "".join(random.choices("0123456789", k=5))
create_mocked_usages(frt_code=frontier, since=since_month, until=until_month)
mock_get_auth_token.return_value = "my_token"
ebconnector = DSOConnector(
ebconnector = DSOClient(
api_base_url="https://dso.enerbit.me/",
api_username="test",
api_password="test",
Expand All @@ -100,7 +100,7 @@ def test_get_all_schedule_records(self, mock_get_auth_token):
frontier = "Frt" + "".join(random.choices("0123456789", k=5))
create_mocked_usages(frt_code=frontier, since=since_month, until=until_month)
mock_get_auth_token.return_value = "my_token"
ebconnector = DSOConnector(
ebconnector = DSOClient(
api_base_url="https://dso.enerbit.me/",
api_username="test",
api_password="test",
Expand All @@ -124,7 +124,7 @@ def test_get_part_schedule_records(self, mock_get_auth_token):
frontier = "Frt" + "".join(random.choices("0123456789", k=5))
create_mocked_usages(frt_code=frontier, since=since_month, until=until_month)
mock_get_auth_token.return_value = "my_token"
ebconnector = DSOConnector(
ebconnector = DSOClient(
api_base_url="https://dso.enerbit.me/",
api_username="test",
api_password="test",
Expand All @@ -151,7 +151,7 @@ def test_get_empty_schedule_records(self, mock_get_auth_token):
frontier = "Frt" + "".join(random.choices("0123456789", k=5))
create_mocked_usages(frt_code=frontier, since=since_month, until=until_month)
mock_get_auth_token.return_value = "my_token"
ebconnector = DSOConnector(
ebconnector = DSOClient(
api_base_url="https://dso.enerbit.me/",
api_username="test",
api_password="test",
Expand Down
13 changes: 12 additions & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a98ee90

Please sign in to comment.