diff options
Diffstat (limited to 'wrappers')
| -rw-r--r-- | wrappers/python/eduvpn_common/loader.py | 12 | ||||
| -rw-r--r-- | wrappers/python/eduvpn_common/main.py | 43 | ||||
| -rw-r--r-- | wrappers/python/eduvpn_common/server.py | 63 | ||||
| -rw-r--r-- | wrappers/python/eduvpn_common/types.py | 54 |
4 files changed, 118 insertions, 54 deletions
diff --git a/wrappers/python/eduvpn_common/loader.py b/wrappers/python/eduvpn_common/loader.py index 1090619..f0f31d6 100644 --- a/wrappers/python/eduvpn_common/loader.py +++ b/wrappers/python/eduvpn_common/loader.py @@ -5,7 +5,7 @@ from ctypes import CDLL, c_char_p, c_int, c_void_p, cdll from eduvpn_common import __version__ from eduvpn_common.types import ( - ConfigError, + cToken, DataError, ReadRxBytes, VPNStateChange, @@ -67,6 +67,7 @@ def initialize_functions(lib: CDLL) -> None: c_char_p ], c_void_p lib.Deregister.argtypes, lib.Deregister.restype = [c_char_p], None + lib.FreeConfig.argtypes, lib.FreeConfig.restype = [c_void_p], None lib.FreeDiscoOrganizations.argtypes, lib.FreeDiscoOrganizations.restype = [ c_void_p ], None @@ -81,17 +82,20 @@ def initialize_functions(lib: CDLL) -> None: c_char_p, c_char_p, c_int, - ], ConfigError + cToken, + ], DataError lib.GetConfigInstituteAccess.argtypes, lib.GetConfigInstituteAccess.restype = [ c_char_p, c_char_p, c_int, - ], ConfigError + cToken, + ], DataError lib.GetConfigSecureInternet.argtypes, lib.GetConfigSecureInternet.restype = [ c_char_p, c_char_p, c_int, - ], ConfigError + cToken, + ], DataError lib.GetDiscoOrganizations.argtypes, lib.GetDiscoOrganizations.restype = [ c_char_p ], DataError diff --git a/wrappers/python/eduvpn_common/main.py b/wrappers/python/eduvpn_common/main.py index 3cb45e1..304e2e8 100644 --- a/wrappers/python/eduvpn_common/main.py +++ b/wrappers/python/eduvpn_common/main.py @@ -1,13 +1,14 @@ import threading -from ctypes import c_int +from ctypes import cast, c_void_p, c_int, pointer from typing import Any, Callable, Dict, Iterator, List, Optional, Tuple from eduvpn_common.discovery import DiscoOrganizations, DiscoServers, get_disco_organizations, get_disco_servers from eduvpn_common.event import EventHandler from eduvpn_common.loader import initialize_functions, load_lib -from eduvpn_common.server import Profiles, Server, get_transition_server, get_servers +from eduvpn_common.server import Profiles, Config, Token, encode_tokens, get_config, Server, get_transition_server, get_servers from eduvpn_common.state import State, StateType from eduvpn_common.types import ReadRxBytes, VPNStateChange, decode_res, encode_args, get_data_error, get_bool +from eduvpn_common.types import VPNStateChange, ReadRXBytes, cToken, decode_res, encode_args, get_data_error, get_bool class EduVPN(object): @@ -219,26 +220,27 @@ class EduVPN(object): if remove_err: raise remove_err - def get_config(self, identifier: str, func: Any, prefer_tcp: bool = False) -> Tuple[str, str]: + def get_config(self, identifier: str, func: Any, prefer_tcp: bool = False, tokens: Optional[Token] = None) -> Optional[Config]: """Get an OpenVPN/WireGuard configuration from the server :param identifier: str: The identifier of the server, e.g. URL or ORG ID :param func: Any: The Go function to call :param prefer_tcp: bool: (Default value = False): Whether or not to prefer TCP + :param tokens: Optional[Token] (Default value = None): The OAuth tokens if available :meta private: :raises WrappedError: An error by the Go library :return: The configuration and configuration type ('openvpn' or 'wireguard') - :rtype: Tuple[str, str] + :rtype: Config """ # Because it could be the case that a profile callback is started, store a threading event # In the constructor, we have defined a wait event for Ask_Profile, this waits for this event to be set # The event is set in self.set_profile self.profile_event = threading.Event() - config, config_type, config_err = self.go_function(func, identifier, prefer_tcp) + config, config_err = self.go_function(func, identifier, prefer_tcp, encode_tokens(tokens), decode_func=lambda lib, x: get_data_error(lib, x, get_config)) self.profile_event = None self.location_event = None @@ -246,49 +248,55 @@ class EduVPN(object): if config_err: raise config_err - return config, config_type + return config def get_config_custom_server( - self, url: str, prefer_tcp: bool = False - ) -> Tuple[str, str]: + self, url: str, prefer_tcp: bool = False, tokens: Optional[Token] = None + ) -> Optional[Config]: """Get an OpenVPN/WireGuard configuration from a custom server :param url: str: The URL of the custom server :param prefer_tcp: bool: (Default value = False): Whether or not to prefer TCP + :param tokens: Optional[Token] (Default value = None): The OAuth tokens if available :raises WrappedError: An error by the Go library :return: The configuration and configuration type ('openvpn' or 'wireguard') - :rtype: Tuple[str, str] + :rtype: Config """ - return self.get_config(url, self.lib.GetConfigCustomServer, prefer_tcp) + return self.get_config(url, self.lib.GetConfigCustomServer, prefer_tcp, tokens) def get_config_institute_access( - self, url: str, prefer_tcp: bool = False - ) -> Tuple[str, str]: + self, url: str, prefer_tcp: bool = False, tokens: Optional[Token] = None + ) -> Optional[Config]: """Get an OpenVPN/WireGuard configuration from an institute access server :param url: str: The URL of the institute access server. Use the one from Discovery :param prefer_tcp: bool: (Default value = False): Whether or not to prefer TCP + :param tokens: Optional[Token] (Default value = None): The OAuth tokens if available :raises WrappedError: An error by the Go library :return: The configuration and configuration type ('openvpn' or 'wireguard') - :rtype: Tuple[str, str] + :rtype: Config """ - return self.get_config(url, self.lib.GetConfigInstituteAccess, prefer_tcp) + return self.get_config(url, self.lib.GetConfigInstituteAccess, prefer_tcp, tokens) def get_config_secure_internet( - self, org_id: str, prefer_tcp: bool = False - ) -> Tuple[str, str]: + self, org_id: str, prefer_tcp: bool = False, tokens: Optional[Token] = None + ) -> Optional[Config]: """Get an OpenVPN/WireGuard configuration from a secure internet server :param org_id: str: The organization ID of the secure internet server. Use the one from Discovery :param prefer_tcp: bool: (Default value = False): Whether or not to prefer TCP + :param tokens: Optional[Token] (Default value = None): The OAuth tokens if available :raises WrappedError: An error by the Go library + + :return: The configuration and configuration type ('openvpn' or 'wireguard') + :rtype: Config """ - return self.get_config(org_id, self.lib.GetConfigSecureInternet, prefer_tcp) + return self.get_config(org_id, self.lib.GetConfigSecureInternet, prefer_tcp, tokens) def go_back(self) -> None: """Go back in the FSM""" @@ -539,7 +547,6 @@ def state_callback(name: bytes, old_state: int, new_state: int, data: Any) -> in return 1 return 0 - def add_as_global_object(eduvpn: EduVPN) -> bool: """Add the provided parameter to the global objects lists so we can call the callback diff --git a/wrappers/python/eduvpn_common/server.py b/wrappers/python/eduvpn_common/server.py index 380623d..d10584e 100644 --- a/wrappers/python/eduvpn_common/server.py +++ b/wrappers/python/eduvpn_common/server.py @@ -2,7 +2,7 @@ from ctypes import CDLL, POINTER, c_void_p, cast from datetime import datetime from typing import List, Optional, Type -from eduvpn_common.types import cServer, cServerLocations, cServerProfiles, cServers +from eduvpn_common.types import cConfig, cServer, cServerLocations, cServerProfiles, cServers, cToken class Profile: @@ -20,6 +20,34 @@ class Profile: def __str__(self): return self.display_name +class Token: + """The class that represents oauth Tokens + + :param: access: str: The access token + :param: refresh: str: The refresh token + :param: expired: int: The expire unix time + """ + def __init__(self, access: str, refresh: str, expired: int): + self.access = access + self.refresh = refresh + self.expires = expired + + +class Config: + """The class that represents an OpenVPN/WireGuard config + + :param: config: str: The config string + :param: config_type: str: The type of config, openvpn/wireguard + :param: tokens: Optional[Token]: The tokens + """ + def __init__(self, config: str, config_type: str, tokens: Optional[Token]): + self.config = config + self.config_type = config_type + self.tokens = tokens + + def __str__(self): + return self.config + class Profiles: """The class that represents a list of profiles @@ -347,3 +375,36 @@ def get_locations(lib: CDLL, ptr: c_void_p) -> Optional[List[str]]: lib.FreeSecureLocations(ptr) return location_list return None + + +def get_config(lib: CDLL, ptr: c_void_p) -> Optional[Config]: + """Get the config from the Go library as a C structure and return a Python usable structure + + :param lib: CDLL: The Go shared library + :param ptr: c_void_p: The C pointer to the confg structure + + :meta private: + + :return: The configuration if there is any + :rtype: Optional[Config] + """ + # TODO: FREE + if ptr: + config = cast(ptr, POINTER(cConfig)).contents + cfg = config.config.decode("utf-8") + cfg_type = config.config_type.decode("utf-8") + tokens = None + if config.token: + token_struct = config.token.contents + tokens = Token(token_struct.access.decode("utf-8"), token_struct.refresh.decode("utf-8"), token_struct.expired) + + config_class = Config(cfg, cfg_type, tokens) + lib.FreeConfig(ptr) + return config_class + return None + +def encode_tokens(arg: Optional[Token]) -> cToken: + if arg is None: + return cToken("".encode("utf-8"), "".encode("utf-8"), 0) + return cToken(arg.access.encode("utf-8"), arg.refresh.encode("utf-8"), arg.expires) + diff --git a/wrappers/python/eduvpn_common/types.py b/wrappers/python/eduvpn_common/types.py index 7e3ce9a..e4f8e26 100644 --- a/wrappers/python/eduvpn_common/types.py +++ b/wrappers/python/eduvpn_common/types.py @@ -15,6 +15,24 @@ from typing import Any, Callable, Iterator, List, Optional, Tuple from eduvpn_common.error import ErrorLevel, WrappedError +class cToken(Structure): + """The C type that represents the Token as forwarded to the Go library + + :meta private: + """ + _fields_ = [ + ("access", c_char_p), + ("refresh", c_char_p), + ("expired", c_ulonglong), + ] + + +class cConfig(Structure): + """The C type that represents the data that gets by the Go library returned when a config is obtained + + :meta private: + """ + _fields_ = [("config", c_char_p), ("config_type", c_char_p), ("token", POINTER(cToken))] class cError(Structure): """The C type that represents the Error as returned by the Go library @@ -156,19 +174,10 @@ class DataError(Structure): _fields_ = [("data", c_void_p), ("error", c_void_p)] -class ConfigError(Structure): - """The C type that represents the data that gets by the Go library returned when a config is obtained - - :meta private: - """ - _fields_ = [("config", c_void_p), ("config_type", c_void_p), ("error", c_void_p)] - - # The type for a Go state change callback VPNStateChange = CFUNCTYPE(c_int, c_char_p, c_int, c_int, c_void_p) ReadRxBytes = CFUNCTYPE(c_ulonglong) - def encode_args(args: List[Any], types: List[Any]) -> Iterator[Any]: """Encode the arguments ready to be used by the Go library @@ -182,8 +191,11 @@ def encode_args(args: List[Any], types: List[Any]) -> Iterator[Any]: """ for arg, t in zip(args, types): # c_char_p needs the str to be encoded to bytes - if t is c_char_p: - arg = arg.encode("utf-8") + encode_map = { + c_char_p: lambda x: x.encode("utf-8"), + } + if t in encode_map: + arg = encode_map[t](arg) yield arg @@ -201,7 +213,6 @@ def decode_res(res: Any) -> Any: c_int: get_bool, c_void_p: get_error, DataError: get_data_error, - ConfigError: get_config_error, } return decode_map.get(res, lambda lib, x: x) @@ -268,25 +279,6 @@ def get_error(lib: CDLL, ptr: c_void_p) -> Optional[WrappedError]: return wrapped -def get_config_error( - lib: CDLL, config_error: ConfigError -) -> Tuple[str, str, Optional[WrappedError]]: - """Convert a C config structure to a Python usable config structure - - :param lib: CDLL: The Go shared library - :param config_error: ConfigError: The config error structure - - :meta private: - - :return: The configuration, configuration type ('openvpn'/'wireguard') and an optional error - :rtype: Tuple[str, str, Optional[WrappedError]] - """ - config = get_ptr_string(lib, config_error.config) - config_type = get_ptr_string(lib, config_error.config_type) - err = get_error(lib, config_error.error) - return config, config_type, err - - def get_data_error( lib: CDLL, data_error: DataError, data_conv: Callable = get_ptr_string ) -> Tuple[Any, Optional[WrappedError]]: |
