1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
|
"""
Proton VPN Session API.
Copyright (c) 2023 Proton AG
This file is part of Proton VPN.
Proton VPN is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Proton VPN is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ProtonVPN. If not, see <https://www.gnu.org/licenses/>.
"""
from __future__ import annotations
from dataclasses import dataclass
import platform
from typing import Optional
import distro
from proton.sso import ProtonSSO
from proton.vpn import logging
from proton.vpn.connection import VPNCredentials
from proton.vpn.session import VPNSession
from proton.vpn.session.utils import to_semver_build_metadata_format
logger = logging.getLogger(__name__)
CPU_ARCHITECTURE = to_semver_build_metadata_format(platform.machine())
DISTRIBUTION_ID = distro.id()
DISTRIBUTION_VERSION = distro.version()
@dataclass
class ClientTypeMetadata: # pylint: disable=missing-class-docstring
type: str
version: str
architecture: str = CPU_ARCHITECTURE
class SessionHolder:
"""Holds the current session object, initializing it lazily when requested."""
def __init__(
self, client_type_metadata: ClientTypeMetadata,
session: VPNSession = None
):
self._proton_sso = ProtonSSO(
appversion=self._get_app_version_header_value(client_type_metadata),
user_agent=f"ProtonVPN/{client_type_metadata.version} "
f"(Linux; {DISTRIBUTION_ID}/{DISTRIBUTION_VERSION})"
)
self._session = session
def get_session_for(self, username: str) -> VPNSession:
"""
Returns the session for the specified user.
:param username: Proton account username.
:return:
"""
self._session = self._proton_sso.get_session(
account_name=username,
override_class=VPNSession
)
return self._session
@property
def session(self) -> VPNSession:
"""Returns the current session object."""
if not self._session:
self._session = self._proton_sso.get_default_session(
override_class=VPNSession
)
return self._session
@property
def user_tier(self) -> Optional[int]:
"""Returns the user tier, if the session is already loaded."""
if self.session.loaded:
return self.session.vpn_account.max_tier
return None
@property
def vpn_credentials(self) -> Optional[VPNCredentials]:
"""Returns the VPN credentials, if the session is already loaded."""
if self.session.loaded:
return self.session.vpn_account.vpn_credentials
return None
@staticmethod
def _get_app_version_header_value(client_type_metadata: ClientTypeMetadata) -> str:
app_version = f"linux-vpn-{client_type_metadata.type}@{client_type_metadata.version}"
if client_type_metadata.architecture:
app_version = f"{app_version}+{client_type_metadata.architecture}"
return app_version
|