Skip to content

Commit

Permalink
Added API authentication to Gluetun control server (#2)
Browse files Browse the repository at this point in the history
* Added Gluetun API key authentication support
  • Loading branch information
FlorentLM authored Jan 18, 2025
1 parent 8e42615 commit 65ce0bf
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 7 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ services:
container_name: glueforward
environment:
GLUETUN_URL: "..."
GLUETUN_API_KEY: "..."
QBITTORRENT_URL: "..."
QBITTORRENT_USERNAME: "..."
QBITTORRENT_PASSWORD: "..."
Expand Down Expand Up @@ -45,6 +46,12 @@ services:
<td>No</td>
<td></td>
</tr>
<tr>
<td>GLUETUN_API_KEY</td>
<td>Your gluetun control server <a href="https://github.com/qdm12/gluetun-wiki/blob/main/setup/advanced/control-server.md">API key</a></td>
<td>Yes (only for gluetun up to v3.4.0)</td>
<td></td>
</tr>
<tr>
<td>QBITTORRENT_URL</td>
<td>Url to the qbittorrent web UI</td>
Expand Down
19 changes: 17 additions & 2 deletions glueforward/gluetun.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@

import httpx

from errors import RetryableGlueforwardError
from errors import GlueforwardError, RetryableGlueforwardError


class GluetunAuthFailed(GlueforwardError):
"""Exception raised when gluetun authentication fails"""

def __init__(self, *args: object) -> None:
super().__init__(*args, message="Failed to authenticate to Gluetun. See https://github.com/qdm12/gluetun-wiki/blob/main/setup/advanced/control-server.md")


class GluetunUnreachable(RetryableGlueforwardError):
Expand All @@ -27,18 +34,26 @@ class _PortForwardedResponseModel(TypedDict):
class GluetunClient:

__client: httpx.Client
__api_key: str

def __init__(self, url: str):
def __init__(self, url: str, api_key: None | str):
self.__client = httpx.Client(base_url=url)
if api_key:
self.__client.headers.update({"X-API-Key": api_key})
logging.debug("Gluetun client created with base url %s", url)

def get_has_credentials(self) -> bool:
return len(self.__api_key) > 0

def get_forwarded_port(self) -> int:
try:
response = self.__client.get(url="/v1/openvpn/portforwarded")
response.raise_for_status()
except httpx.ConnectError as exception:
raise GluetunUnreachable(self.__client.base_url) from exception
except httpx.HTTPStatusError as exception:
if exception.response.status_code == 401:
raise GluetunAuthFailed(exception.response.text)
raise GluetunGetForwardedPortFailed(
exception.response.status_code,
exception.response.text,
Expand Down
19 changes: 14 additions & 5 deletions glueforward/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,19 @@ class Application:
__success_interval: int
__retry_interval: int

def __mgetenv(self, name: str) -> str:
def __required_getenv(self, name: str) -> str:
"""Get an environment variable or exit if it is not set"""
if (value := getenv(name)) is None:
logging.critical("Environment variable %s is required", name)
sys.exit(ReturnCodes.MISSING_ENVIRONMENT_VARIABLE)
return value

def __optional_getenv(self, name: str) -> None | str:
"""Get an environment variable or warn if it is not set"""
if (value := getenv(name)) is None:
logging.warning("Environment variable %s is not defined", name)
return value

def _setup(self) -> None:
"""Setup the application"""

Expand Down Expand Up @@ -65,12 +71,15 @@ def _setup(self) -> None:
# Initialize the state
self.__retry_interval = int(getenv("RETRY_INTERVAL", str(10)))
self.__success_interval = int(getenv("SUCCESS_INTERVAL", str(60 * 5)))
self.__gluetun = GluetunClient(url=self.__mgetenv("GLUETUN_URL"))
self.__gluetun = GluetunClient(
url=self.__required_getenv("GLUETUN_URL"),
api_key=self.__optional_getenv("GLUETUN_API_KEY")
)
self.__qbittorrent = QBittorrentClient(
url=self.__mgetenv("QBITTORRENT_URL"),
url=self.__required_getenv("QBITTORRENT_URL"),
credentials={
"username": self.__mgetenv("QBITTORRENT_USERNAME"),
"password": self.__mgetenv("QBITTORRENT_PASSWORD"),
"username": self.__required_getenv("QBITTORRENT_USERNAME"),
"password": self.__required_getenv("QBITTORRENT_PASSWORD"),
},
)

Expand Down

0 comments on commit 65ce0bf

Please sign in to comment.