def __init__(self): """ Tries to load silencer rules from the default path, or load from the SILENCER_RULES tuple if not found. """ self._inclusion_path = os.path.join(get_path_prefix(), "leap", self.INCLUSION_CONFIG_FILE) self._exclusion_path = os.path.join(get_path_prefix(), "leap", self.EXCLUSION_CONFIG_FILE) self._load_rules()
def __init__(self, userid, passwd, mdir=None): """ Initialize the plumber with all that's needed to authenticate against the provider. :param userid: user identifier, foo@bar :type userid: basestring :param passwd: the soledad passphrase :type passwd: basestring :param mdir: a path to a maildir to import :type mdir: str or None """ self.userid = userid self.passwd = passwd user, provider = userid.split('@') self.user = user self.mdir = mdir self.sol = None self._settings = Settings() provider_config_path = os.path.join(get_path_prefix(), get_provider_path(provider)) provider_config = ProviderConfig() loaded = provider_config.load(provider_config_path) if not loaded: print "could not load provider config!" return self.exit()
def get_ca_cert_path(self, about_to_download=False): """ Returns the path to the certificate for the current provider. It may raise MissingCACert if the certificate does not exists and not about_to_download :param about_to_download: defines wether we want the path to download the cert or not. This helps avoid checking if the cert exists because we are about to write it. :type about_to_download: bool :rtype: unicode """ cert_path = os.path.join(get_path_prefix(), "leap", "providers", self.get_domain(), "keys", "ca", "cacert.pem") if not about_to_download: cert_exists = os.path.exists(cert_path) error_msg = "You need to download the certificate first" leap_check(cert_exists, error_msg, MissingCACert) logger.debug("Going to verify SSL against %s" % (cert_path,)) # OpenSSL does not handle unicode. return cert_path.encode('utf-8')
def _get_gpg_bin_path(self): """ Return the path to gpg binary. :returns: the gpg binary path :rtype: str """ gpgbin = None if flags.STANDALONE: gpgbin = os.path.join(get_path_prefix(), "..", "apps", "mail", "gpg") if IS_WIN: gpgbin += ".exe" else: try: gpgbin_options = which("gpg") # gnupg checks that the path to the binary is not a # symlink, so we need to filter those and come up with # just one option. for opt in gpgbin_options: if not os.path.islink(opt): gpgbin = opt break except IndexError as e: logger.debug("Couldn't find the gpg binary!") logger.exception(e) leap_check(gpgbin is not None, "Could not find gpg binary") return gpgbin
def get_client_cert_path(self, userid, providerconfig=None, about_to_download=False): """ Returns the path to the certificate used by smtp :param userid: the user id, in user@provider form """ leap_assert(userid, "Need an userid") leap_assert(providerconfig, "We need a provider") leap_assert_type(providerconfig, ProviderConfig) username = userid.split("@")[0] cert_path = os.path.join(get_path_prefix(), "leap", "providers", providerconfig.get_domain(), "keys", "client", "smtp_%s.pem" % username) if not about_to_download: leap_assert(os.path.exists(cert_path), "You need to download the certificate first") logger.debug("Using SMTP cert %s" % (cert_path,)) return cert_path
def start_pixelated_user_agent(userid, soledad, keymanager): leap_session = LeapSessionAdapter( userid, soledad, keymanager) config = Config() leap_home = os.path.join(get_path_prefix(), 'leap') config.leap_home = leap_home leap_session.config = config services_factory = SingleUserServicesFactory( UserAgentMode(is_single_user=True)) if getattr(sys, 'frozen', False): # we are running in a |PyInstaller| bundle static_folder = os.path.join(sys._MEIPASS, 'pixelated_www') else: static_folder = os.path.abspath(pixelated_www.__path__[0]) resource = RootResource(services_factory, static_folder=static_folder) config.host = 'localhost' config.port = 9090 config.sslkey = None config.sslcert = None d = leap_session.account.callWhenReady( lambda _: _start_in_single_user_mode( leap_session, config, resource, services_factory)) return d
def get_client_cert_path(self, userid, providerconfig=None, about_to_download=False): """ Returns the path to the certificate used by smtp :param userid: the user id, in user@provider form """ leap_assert(userid, "Need an userid") leap_assert(providerconfig, "We need a provider") leap_assert_type(providerconfig, ProviderConfig) username = userid.split("@")[0] cert_path = os.path.join(get_path_prefix(), "leap", "providers", providerconfig.get_domain(), "keys", "client", "smtp_%s.pem" % username) if not about_to_download: leap_assert(os.path.exists(cert_path), "You need to download the certificate first") logger.debug("Using SMTP cert %s" % (cert_path, )) return cert_path
def _get_keys_dir(): """ Return the path where the ZMQ certificates should be stored. :rtype: str """ return os.path.join(get_path_prefix(), 'leap', 'zmq_certificates')
def start_pixelated_user_agent(userid, soledad, keymanager): leap_session = LeapSessionAdapter(userid, soledad, keymanager) config = Config() leap_home = os.path.join(get_path_prefix(), 'leap') config.leap_home = leap_home leap_session.config = config services_factory = SingleUserServicesFactory( UserAgentMode(is_single_user=True)) if getattr(sys, 'frozen', False): # we are running in a |PyInstaller| bundle static_folder = os.path.join(sys._MEIPASS, 'pixelated_www') else: static_folder = os.path.abspath(pixelated_www.__path__[0]) resource = RootResource(services_factory, static_folder=static_folder) config.host = 'localhost' config.port = 9090 config.sslkey = None config.sslcert = None d = leap_session.account.callWhenReady( lambda _: _start_in_single_user_mode(leap_session, config, resource, services_factory)) return d
def get_db_paths(uuid): """ Return the secrets and local db paths needed for soledad initialization :param uuid: uuid for user :type uuid: str :return: a tuple with secrets, local_db paths :rtype: tuple """ prefix = os.path.join(get_path_prefix(), "leap", "soledad") secrets = "%s/%s.secret" % (prefix, uuid) local_db = "%s/%s.db" % (prefix, uuid) # We remove an empty file if found to avoid complains # about the db not being properly initialized if is_file(local_db) and is_empty_file(local_db): try: os.remove(local_db) except OSError: logger.warning( "Could not remove empty file %s" % local_db) return secrets, local_db
def __init__(self, userid, soledad, keymanager): self.userid = userid self.soledad = soledad # XXX this needs to be converged with our public apis. self.nicknym = NickNym(keymanager, userid) self.mail_store = LeapMailStore(soledad) self.user_auth = Config() self.user_auth.uuid = soledad.uuid self.fresh_account = False self.incoming_mail_fetcher = None self.account = Account(soledad, userid) username, provider = userid.split('@') smtp_client_cert = os.path.join( get_path_prefix(), 'leap', 'providers', provider, 'keys', 'client', 'smtp_{username}.pem'.format(username=username)) assert (os.path.isfile(smtp_client_cert)) smtp_config = get_smtp_config(provider) smtp_host = smtp_config.host smtp_port = smtp_config.port self.smtp_config = LeapSMTPConfig(userid, smtp_client_cert, smtp_host, smtp_port)
def __init__(self, userid, soledad, keymanager): self.userid = userid self.soledad = soledad # XXX this needs to be converged with our public apis. self.nicknym = NickNym(keymanager, userid) self.mail_store = LeapMailStore(soledad) self.user_auth = Config() self.user_auth.uuid = soledad.uuid self.fresh_account = False self.incoming_mail_fetcher = None self.account = Account(soledad, userid) username, provider = userid.split('@') smtp_client_cert = os.path.join( get_path_prefix(), 'leap', 'providers', provider, 'keys', 'client', 'smtp_{username}.pem'.format( username=username)) assert(os.path.isfile(smtp_client_cert)) smtp_config = get_smtp_config(provider) smtp_host = smtp_config.host smtp_port = smtp_config.port self.smtp_config = LeapSMTPConfig( userid, smtp_client_cert, smtp_host, smtp_port)
def get_vpn_env(kls): """ Returns a dictionary with the custom env for the platform. This is mainly used for setting LD_LIBRARY_PATH to the correct path when distributing a standalone client :rtype: dict """ ld_library_path = os.path.join(get_path_prefix(), "..", "lib") ld_library_path.encode(sys.getfilesystemencoding()) return {"LD_LIBRARY_PATH": ld_library_path}
def get_vpn_env(self): """ Returns a dictionary with the custom env for the platform. This is mainly used for setting LD_LIBRARY_PATH to the correct path when distributing a standalone client :rtype: dict """ return { "DYLD_LIBRARY_PATH": os.path.join(get_path_prefix(), "..", "lib") }
def get_vpn_env(kls): """ Returns a dictionary with the custom env for the platform. This is mainly used for setting LD_LIBRARY_PATH to the correct path when distributing a standalone client :rtype: dict """ ld_library_path = os.path.join(get_path_prefix(), "..", "lib") ld_library_path.encode(sys.getfilesystemencoding()) return {"DYLD_LIBRARY_PATH": ld_library_path}
def __init__(self): """ Create the ConfigParser object and read it. """ self._settings_path = os.path.join(get_path_prefix(), "leap", self.CONFIG_NAME) self._settings = ConfigParser.ConfigParser() self._settings.read(self._settings_path) self._add_section(GENERAL_SECTION)
def get_smtp_config(provider): config_path = os.path.join(get_path_prefix(), 'leap', 'providers', provider, 'smtp-service.json') json_config = json.loads(open(config_path).read()) chosen_host = json_config['hosts'].keys()[0] hostname = json_config['hosts'][chosen_host]['hostname'] port = json_config['hosts'][chosen_host]['port'] config = Config() config.host = hostname config.port = port return config
def get_smtp_config(provider): config_path = os.path.join( get_path_prefix(), 'leap', 'providers', provider, 'smtp-service.json') json_config = json.loads(open(config_path).read()) chosen_host = json_config['hosts'].keys()[0] hostname = json_config['hosts'][chosen_host]['hostname'] port = json_config['hosts'][chosen_host]['port'] config = Config() config.host = hostname config.port = port return config
def _download_certificate_test_template(self, ifneeded, createcert): """ All download client certificate tests have the same structure, so this is a parametrized test for that. :param ifneeded: sets _download_if_needed :type ifneeded: bool :param createcert: if True it creates a dummy file to play the part of a downloaded certificate :type createcert: bool :returns: the temp eip cert path and the dummy cert contents :rtype: tuple of str, str """ pc = ProviderConfig() ec = EIPConfig() self.eb._provider_config = pc self.eb._eip_config = ec pc.get_domain = mock.MagicMock( return_value="localhost:%s" % (self.https_port)) pc.get_api_uri = mock.MagicMock( return_value="https://%s" % (pc.get_domain())) pc.get_api_version = mock.MagicMock(return_value="1") pc.get_ca_cert_path = mock.MagicMock(return_value=False) path_prefix = tempfile.mkdtemp() util.get_path_prefix = mock.MagicMock(return_value=path_prefix) EIPConfig.save = mock.MagicMock() EIPConfig.load = mock.MagicMock() self.eb._download_if_needed = ifneeded provider_dir = os.path.join(util.get_path_prefix(), "leap", "providers", "somedomain") mkdir_p(provider_dir) eip_cert_path = os.path.join(provider_dir, "cert") ec.get_client_cert_path = mock.MagicMock( return_value=eip_cert_path) cert_content = "A" if createcert: with open(eip_cert_path, "w") as ec: ec.write(cert_content) return eip_cert_path, cert_content
def _download_config_test_template(self, ifneeded, new): """ All download config tests have the same structure, so this is a parametrized test for that. :param ifneeded: sets _download_if_needed :type ifneeded: bool :param new: if True uses time.time() as mtime for the mocked eip-service file, otherwise it uses 100 (a really old mtime) :type new: float or int (will be coersed) """ pc = ProviderConfig() pc.get_domain = mock.MagicMock( return_value="localhost:%s" % (self.https_port)) self.eb._provider_config = pc pc.get_api_uri = mock.MagicMock( return_value="https://%s" % (pc.get_domain())) pc.get_api_version = mock.MagicMock(return_value="1") # This is to ignore https checking, since it's not the point # of this test pc.get_ca_cert_path = mock.MagicMock(return_value=False) path_prefix = tempfile.mkdtemp() util.get_path_prefix = mock.MagicMock(return_value=path_prefix) EIPConfig.save = mock.MagicMock() EIPConfig.load = mock.MagicMock() self.eb._download_if_needed = ifneeded provider_dir = os.path.join(util.get_path_prefix(), "leap", "providers", pc.get_domain()) mkdir_p(provider_dir) eip_config_path = os.path.join(provider_dir, "eip-service.json") with open(eip_config_path, "w") as ec: ec.write("A") # set mtime to something really new if new: os.utime(eip_config_path, (-1, time.time())) else: os.utime(eip_config_path, (-1, 100))
def get_logger(perform_rollover=False): """ Push to the app stack the needed handlers and return a Logger object. :rtype: logbook.Logger """ # NOTE: make sure that the folder exists, the logger is created before # saving settings on the first run. _base = os.path.join(get_path_prefix(), "leap") mkdir_p(_base) bitmask_log_file = os.path.join(_base, 'bitmask.log') level = logbook.WARNING if flags.DEBUG: level = logbook.NOTSET # This handler consumes logs not handled by the others null_handler = logbook.NullHandler() null_handler.push_application() silencer = SelectiveSilencerFilter() zmq_handler = SafeZMQHandler('tcp://127.0.0.1:5000', multi=True, level=level, filter=silencer.filter) zmq_handler.push_application() file_handler = logbook.RotatingFileHandler( bitmask_log_file, format_string=LOG_FORMAT, bubble=True, filter=silencer.filter, max_size=sys.maxint) if perform_rollover: file_handler.perform_rollover() file_handler.push_application() # don't use simple stream, go for colored log handler instead # stream_handler = logbook.StreamHandler(sys.stdout, # format_string=LOG_FORMAT, # bubble=True) # stream_handler.push_application() stream_handler = ColorizedStderrHandler( level=level, format_string=LOG_FORMAT, bubble=True, filter=silencer.filter) stream_handler.push_application() logger = logbook.Logger('leap') return logger
def _produce_dummy_provider_json(self): """ Creates a dummy provider json on disk in order to test behaviour around it (download if newer online, etc) :returns: the provider.json path used :rtype: str """ provider_dir = os.path.join(util.get_path_prefix(), "leap", "providers", self.pb._domain) mkdir_p(provider_dir) provider_path = os.path.join(provider_dir, "provider.json") with open(provider_path, "w") as p: p.write("A") return provider_path
def _get_gpg_bin_path(self): """ Return the path to gpg binary. :returns: the gpg binary path :rtype: str """ gpgbin = None if flags.STANDALONE: gpgbin = os.path.join( get_path_prefix(), "..", "apps", "mail", "gpg") if IS_WIN: gpgbin += ".exe" else: try: gpgbin_options = which("gpg") # gnupg checks that the path to the binary is not a # symlink, so we need to filter those and come up with # just one option. for opt in gpgbin_options: if not os.path.islink(opt): gpgbin = opt break except IndexError as e: logger.debug("Couldn't find the gpg binary!") logger.exception(e) if IS_MAC: gpgbin = os.path.abspath( os.path.join(here(), "apps", "mail", "gpg")) # During the transition towards gpg2, we can look for /usr/bin/gpg1 # binary, in case it was renamed using dpkg-divert or manually. # We could just pick gpg2, but we need to solve #7564 first. if gpgbin is None: try: gpgbin_options = which("gpg1") for opt in gpgbin_options: if not os.path.islink(opt): gpgbin = opt break except IndexError as e: logger.debug("Couldn't find the gpg1 binary!") logger.exception(e) leap_check(gpgbin is not None, "Could not find gpg1 binary") return gpgbin
def _get_gpg_bin_path(self): """ Return the path to gpg binary. :returns: the gpg binary path :rtype: str """ gpgbin = None if flags.STANDALONE: gpgbin = os.path.join(get_path_prefix(), "..", "apps", "mail", "gpg") if IS_WIN: gpgbin += ".exe" else: try: gpgbin_options = which("gpg") # gnupg checks that the path to the binary is not a # symlink, so we need to filter those and come up with # just one option. for opt in gpgbin_options: if not os.path.islink(opt): gpgbin = opt break except IndexError as e: logger.debug("Couldn't find the gpg binary!") logger.exception(e) if IS_MAC: gpgbin = os.path.abspath( os.path.join(here(), "apps", "mail", "gpg")) # During the transition towards gpg2, we can look for /usr/bin/gpg1 # binary, in case it was renamed using dpkg-divert or manually. # We could just pick gpg2, but we need to solve #7564 first. if gpgbin is None: try: gpgbin_options = which("gpg1") for opt in gpgbin_options: if not os.path.islink(opt): gpgbin = opt break except IndexError as e: logger.debug("Couldn't find the gpg1 binary!") logger.exception(e) leap_check(gpgbin is not None, "Could not find gpg1 binary") return gpgbin
def get_eipconfig_path(domain, relative=True): """ Returns relative or absolute path for EIP config. :param domain: the domain to which this eipconfig belongs to. :type domain: str :param relative: defines whether the path should be relative or absolute. :type relative: bool :returns: the path :rtype: str """ leap_assert(domain is not None, "get_eipconfig_path: We need a domain") path = os.path.join("leap", "providers", domain, "eip-service.json") if not relative: path = os.path.join(get_path_prefix(), path) return path
def get_configured_providers(self): """ Returns the configured providers based on the file structure in the settings directory. :rtype: list of str """ # TODO: check which providers have a valid certificate among # other things, not just the directories providers = [] try: providers_path = os.path.join(get_path_prefix(), "leap", "providers") providers = os.listdir(providers_path) except Exception as e: logger.debug("Error listing providers, assume there are none. %r" % (e,)) return providers
def get_client_cert_path(self, providerconfig=None, about_to_download=False): """ Returns the path to the certificate used by openvpn """ leap_assert(providerconfig, "We need a provider") leap_assert_type(providerconfig, ProviderConfig) cert_path = os.path.join(get_path_prefix(), "leap", "providers", providerconfig.get_domain(), "keys", "client", "openvpn.pem") if not about_to_download: leap_assert(os.path.exists(cert_path), "You need to download the certificate first") logger.debug("Using OpenVPN cert %s" % (cert_path, )) return cert_path
def get_client_cert_path(self, providerconfig=None, about_to_download=False): """ Returns the path to the certificate used by openvpn """ leap_assert(providerconfig, "We need a provider") leap_assert_type(providerconfig, ProviderConfig) cert_path = os.path.join(get_path_prefix(), "leap", "providers", providerconfig.get_domain(), "keys", "client", "openvpn.pem") if not about_to_download: leap_assert(os.path.exists(cert_path), "You need to download the certificate first") logger.debug("Using OpenVPN cert %s" % (cert_path,)) return cert_path
def get_db_paths(uuid): """ Return the secrets and local db paths needed for soledad initialization :param uuid: uuid for user :type uuid: str :return: a tuple with secrets, local_db paths :rtype: tuple """ prefix = os.path.join(get_path_prefix(), "leap", "soledad") secrets = "%s/%s.secret" % (prefix, uuid) local_db = "%s/%s.db" % (prefix, uuid) # We remove an empty file if found to avoid complains # about the db not being properly initialized if is_file(local_db) and is_empty_file(local_db): try: os.remove(local_db) except OSError: logger.warning("Could not remove empty file %s" % local_db) return secrets, local_db
def download_service_config(provider_config, service_config, session, download_if_needed=True): """ Downloads config for a given service. :param provider_config: an instance of ProviderConfig :type provider_config: ProviderConfig :param service_config: an instance of a particular Service config. :type service_config: BaseConfig :param session: an instance of a fetcher.session (currently we're using requests only, but it can be anything that implements that interface) :type session: requests.sessions.Session """ service_name = service_config.name service_json = "{0}-service.json".format(service_name) headers = {} mtime = get_mtime(os.path.join(util.get_path_prefix(), "leap", "providers", provider_config.get_domain(), service_json)) if download_if_needed and mtime: headers['if-modified-since'] = mtime api_version = provider_config.get_api_version() config_uri = "%s/%s/config/%s-service.json" % ( provider_config.get_api_uri(), api_version, service_name) logger.debug('Downloading %s config from: %s' % ( service_name.upper(), config_uri)) # XXX make and use @with_srp_auth decorator srp_auth = SRPAuth(provider_config) session_id = srp_auth.get_session_id() token = srp_auth.get_token() cookies = None if session_id is not None: cookies = {"_session_id": session_id} # API v2 will only support token auth, but in v1 we can send both if token is not None: headers["Authorization"] = 'Token token="{0}"'.format(token) verify = provider_config.get_ca_cert_path() if verify: verify = verify.encode(sys.getfilesystemencoding()) res = session.get(config_uri, verify=verify, headers=headers, timeout=REQUEST_TIMEOUT, cookies=cookies) res.raise_for_status() service_config.set_api_version(api_version) # Not modified service_path = ("leap", "providers", provider_config.get_domain(), service_json) if res.status_code == 304: logger.debug( "{0} definition has not been modified".format( service_name.upper())) service_config.load(os.path.join(*service_path)) else: service_definition, mtime = get_content(res) service_config.load(data=service_definition, mtime=mtime) service_config.save(service_path)
def _download_provider_info(self, *args): """ Downloads the provider.json defition """ leap_assert(self._domain, "Cannot download provider info without a domain") logger.debug("Downloading provider info for %r" % (self._domain)) # -------------------------------------------------------------- # TODO factor out with the download routines in services. # Watch out! We're handling the verify paramenter differently here. headers = {} domain = self._domain.encode(sys.getfilesystemencoding()) provider_json = os.path.join(util.get_path_prefix(), get_provider_path(domain)) if domain in PinnedProviders.domains() and \ not os.path.exists(provider_json): mkdir_p(os.path.join(os.path.dirname(provider_json), "keys", "ca")) cacert = os.path.join(os.path.dirname(provider_json), "keys", "ca", "cacert.pem") PinnedProviders.save_hardcoded(domain, provider_json, cacert) mtime = get_mtime(provider_json) if self._download_if_needed and mtime: headers['if-modified-since'] = mtime uri = "https://%s/%s" % (self._domain, "provider.json") verify = self.verify if mtime: # the provider.json exists # So, we're getting it from the api.* and checking against # the provider ca. try: provider_config = ProviderConfig() provider_config.load(provider_json) uri = provider_config.get_api_uri() + '/provider.json' verify = provider_config.get_ca_cert_path() except MissingCACert: # no ca? then download from main domain again. pass if verify: verify = verify.encode(sys.getfilesystemencoding()) logger.debug("Requesting for provider.json... " "uri: {0}, verify: {1}, headers: {2}".format( uri, verify, headers)) res = self._session.get(uri.encode('idna'), verify=verify, headers=headers, timeout=REQUEST_TIMEOUT) res.raise_for_status() logger.debug("Request status code: {0}".format(res.status_code)) min_client_version = res.headers.get(self.MIN_CLIENT_VERSION, '0') # Not modified if res.status_code == 304: logger.debug("Provider definition has not been modified") # -------------------------------------------------------------- # end refactor, more or less... # XXX Watch out, have to check the supported api yet. else: if flags.APP_VERSION_CHECK: # TODO split if not provider.supports_client(min_client_version): if self._signaler is not None: self._signaler.signal( self._signaler.prov_unsupported_client) raise UnsupportedClientVersionError() provider_definition, mtime = get_content(res) provider_config = ProviderConfig() provider_config.load(data=provider_definition, mtime=mtime) provider_config.save( ["leap", "providers", domain, "provider.json"]) if flags.API_VERSION_CHECK: # TODO split api_version = provider_config.get_api_version() if provider.supports_api(api_version): logger.debug("Provider definition has been modified") else: api_supported = ', '.join(provider.SUPPORTED_APIS) error = ('Unsupported provider API version. ' 'Supported versions are: {0}. ' 'Found: {1}.').format(api_supported, api_version) logger.error(error) if self._signaler is not None: self._signaler.signal( self._signaler.prov_unsupported_api) raise UnsupportedProviderAPI(error)
def _download_provider_info(self, *args): """ Downloads the provider.json defition """ leap_assert(self._domain, "Cannot download provider info without a domain") logger.debug("Downloading provider info for %r" % (self._domain)) # -------------------------------------------------------------- # TODO factor out with the download routines in services. # Watch out! We're handling the verify paramenter differently here. headers = {} domain = self._domain.encode(sys.getfilesystemencoding()) provider_json = os.path.join(util.get_path_prefix(), get_provider_path(domain)) if domain in PinnedProviders.domains() and \ not os.path.exists(provider_json): mkdir_p(os.path.join(os.path.dirname(provider_json), "keys", "ca")) cacert = os.path.join(os.path.dirname(provider_json), "keys", "ca", "cacert.pem") PinnedProviders.save_hardcoded(domain, provider_json, cacert) mtime = get_mtime(provider_json) if self._download_if_needed and mtime: headers['if-modified-since'] = mtime uri = "https://%s/%s" % (self._domain, "provider.json") verify = self.verify if mtime: # the provider.json exists # So, we're getting it from the api.* and checking against # the provider ca. try: provider_config = ProviderConfig() provider_config.load(provider_json) uri = provider_config.get_api_uri() + '/provider.json' verify = provider_config.get_ca_cert_path() except MissingCACert: # no ca? then download from main domain again. pass if verify: verify = verify.encode(sys.getfilesystemencoding()) logger.debug("Requesting for provider.json... " "uri: {0}, verify: {1}, headers: {2}".format( uri, verify, headers)) res = self._session.get(uri.encode('idna'), verify=verify, headers=headers, timeout=REQUEST_TIMEOUT) res.raise_for_status() logger.debug("Request status code: {0}".format(res.status_code)) min_client_version = res.headers.get(self.MIN_CLIENT_VERSION, '0') # Not modified if res.status_code == 304: logger.debug("Provider definition has not been modified") # -------------------------------------------------------------- # end refactor, more or less... # XXX Watch out, have to check the supported api yet. else: if flags.APP_VERSION_CHECK: # TODO split if not provider.supports_client(min_client_version): self._signaler.signal( self._signaler.prov_unsupported_client) raise UnsupportedClientVersionError() provider_definition, mtime = get_content(res) provider_config = ProviderConfig() provider_config.load(data=provider_definition, mtime=mtime) provider_config.save(["leap", "providers", domain, "provider.json"]) if flags.API_VERSION_CHECK: # TODO split api_version = provider_config.get_api_version() if provider.supports_api(api_version): logger.debug("Provider definition has been modified") else: api_supported = ', '.join(provider.SUPPORTED_APIS) error = ('Unsupported provider API version. ' 'Supported versions are: {0}. ' 'Found: {1}.').format(api_supported, api_version) logger.error(error) self._signaler.signal(self._signaler.prov_unsupported_api) raise UnsupportedProviderAPI(error)
def _rules_path(self): """ The configuration file for custom ignore rules. """ return os.path.join(get_path_prefix(), "leap", self.CONFIG_NAME)
import zmq try: import zmq.auth except ImportError: pass from leap.bitmask.config import flags from leap.bitmask.logs.utils import get_logger from leap.bitmask.util import get_path_prefix from leap.common.files import mkdir_p from leap.common.check import leap_assert logger = get_logger() KEYS_DIR = os.path.join(get_path_prefix(), 'leap', 'zmq_certificates') def _zmq_has_curve(): """ Return whether the current ZMQ has support for auth and CurveZMQ security. :rtype: bool Version notes: `zmq.curve_keypair()` is new in version 14.0, new in version libzmq-4.0. Requires libzmq (>= 4.0) to have been linked with libsodium. `zmq.auth` module is new in version 14.1 `zmq.has()` is new in version 14.1, new in version libzmq-4.1. """ zmq_version = zmq.zmq_version_info()
def __init__(self): settings_path = os.path.join(get_path_prefix(), "leap", self.CONFIG_NAME) self._settings = QtCore.QSettings(settings_path, QtCore.QSettings.IniFormat)
import zmq try: import zmq.auth except ImportError: pass from leap.bitmask.config import flags from leap.bitmask.util import get_path_prefix from leap.common.files import mkdir_p from leap.common.check import leap_assert logger = logging.getLogger(__name__) KEYS_DIR = os.path.join(get_path_prefix(), 'leap', 'zmq_certificates') def _zmq_has_curve(): """ Return whether the current ZMQ has support for auth and CurveZMQ security. :rtype: bool Version notes: `zmq.curve_keypair()` is new in version 14.0, new in version libzmq-4.0. Requires libzmq (>= 4.0) to have been linked with libsodium. `zmq.auth` module is new in version 14.1 `zmq.has()` is new in version 14.1, new in version libzmq-4.1. """ zmq_version = zmq.zmq_version_info()
def get_vpn_command(kls, eipconfig, providerconfig, socket_host, socket_port, openvpn_verb=1): """ Returns the platform dependant vpn launching command Might raise: OpenVPNNotFoundException, VPNLauncherException. :param eipconfig: eip configuration object :type eipconfig: EIPConfig :param providerconfig: provider specific configuration :type providerconfig: ProviderConfig :param socket_host: either socket path (unix) or socket IP :type socket_host: str :param socket_port: either string "unix" if it's a unix socket, or port otherwise :type socket_port: str :param openvpn_verb: the openvpn verbosity wanted :type openvpn_verb: int :return: A VPN command ready to be launched. :rtype: list """ leap_assert_type(eipconfig, EIPConfig) leap_assert_type(providerconfig, ProviderConfig) kwargs = {} if flags.STANDALONE: kwargs['path_extension'] = os.path.join( get_path_prefix(), "..", "apps", "eip") openvpn_possibilities = which(kls.OPENVPN_BIN, **kwargs) if len(openvpn_possibilities) == 0: raise OpenVPNNotFoundException() openvpn = first(openvpn_possibilities) args = [] args += [ '--setenv', "LEAPOPENVPN", "1", '--nobind' ] if openvpn_verb is not None: args += ['--verb', '%d' % (openvpn_verb,)] gateways = [] leap_settings = LeapSettings() domain = providerconfig.get_domain() gateway_conf = leap_settings.get_selected_gateway(domain) if gateway_conf == leap_settings.GATEWAY_AUTOMATIC: gateway_selector = VPNGatewaySelector(eipconfig) gateways = gateway_selector.get_gateways() else: gateways = [gateway_conf] if not gateways: logger.error('No gateway was found!') raise VPNLauncherException('No gateway was found!') logger.debug("Using gateways ips: {0}".format(', '.join(gateways))) for gw in gateways: args += ['--remote', gw, '1194', 'udp'] args += [ '--client', '--dev', 'tun', ############################################################## # persist-tun makes ping-restart fail because it leaves a # broken routing table ############################################################## # '--persist-tun', '--persist-key', '--tls-client', '--remote-cert-tls', 'server' ] openvpn_configuration = eipconfig.get_openvpn_configuration() for key, value in openvpn_configuration.items(): args += ['--%s' % (key,), value] user = getpass.getuser() ############################################################## # The down-root plugin fails in some situations, so we don't # drop privs for the time being ############################################################## # args += [ # '--user', user, # '--group', grp.getgrgid(os.getgroups()[-1]).gr_name # ] if socket_port == "unix": # that's always the case for linux args += [ '--management-client-user', user ] args += [ '--management-signal', '--management', socket_host, socket_port, '--script-security', '2' ] if kls.UP_SCRIPT is not None: if _has_updown_scripts(kls.UP_SCRIPT): args += [ '--up', '\"%s\"' % (kls.UP_SCRIPT,), ] if kls.DOWN_SCRIPT is not None: if _has_updown_scripts(kls.DOWN_SCRIPT): args += [ '--down', '\"%s\"' % (kls.DOWN_SCRIPT,) ] ########################################################### # For the time being we are disabling the usage of the # down-root plugin, because it doesn't quite work as # expected (i.e. it doesn't run route -del as root # when finishing, so it fails to properly # restart/quit) ########################################################### # if _has_updown_scripts(kls.OPENVPN_DOWN_PLUGIN): # args += [ # '--plugin', kls.OPENVPN_DOWN_ROOT, # '\'%s\'' % kls.DOWN_SCRIPT # for OSX # '\'script_type=down %s\'' % kls.DOWN_SCRIPT # for Linux # ] args += [ '--cert', eipconfig.get_client_cert_path(providerconfig), '--key', eipconfig.get_client_cert_path(providerconfig), '--ca', providerconfig.get_ca_cert_path() ] args += [ '--ping', '10', '--ping-restart', '30'] command_and_args = [openvpn] + args return command_and_args
def get_vpn_command(self, eipconfig=None, providerconfig=None, socket_host=None, socket_port="9876", openvpn_verb=1): """ Returns the platform dependant vpn launching command. It will look for openvpn in the regular paths and algo in path_prefix/apps/eip/ (in case standalone is set) Might raise VPNException. :param eipconfig: eip configuration object :type eipconfig: EIPConfig :param providerconfig: provider specific configuration :type providerconfig: ProviderConfig :param socket_host: either socket path (unix) or socket IP :type socket_host: str :param socket_port: either string "unix" if it's a unix socket, or port otherwise :type socket_port: str :param openvpn_verb: the openvpn verbosity wanted :type openvpn_verb: int :return: A VPN command ready to be launched :rtype: list """ leap_assert(eipconfig, "We need an eip config") leap_assert_type(eipconfig, EIPConfig) leap_assert(providerconfig, "We need a provider config") leap_assert_type(providerconfig, ProviderConfig) leap_assert(socket_host, "We need a socket host!") leap_assert(socket_port, "We need a socket port!") leap_assert(socket_port != "unix", "We cannot use unix sockets in windows!") openvpn_possibilities = which( self.OPENVPN_BIN, path_extension=os.path.join(get_path_prefix(), "..", "apps", "eip")) if len(openvpn_possibilities) == 0: raise OpenVPNNotFoundException() openvpn = first(openvpn_possibilities) args = [] args += [ '--setenv', "LEAPOPENVPN", "1" ] if openvpn_verb is not None: args += ['--verb', '%d' % (openvpn_verb,)] gateways = [] leap_settings = LeapSettings() domain = providerconfig.get_domain() gateway_conf = leap_settings.get_selected_gateway(domain) if gateway_conf == leap_settings.GATEWAY_AUTOMATIC: gateway_selector = VPNGatewaySelector(eipconfig) gateways = gateway_selector.get_gateways() else: gateways = [gateway_conf] if not gateways: logger.error('No gateway was found!') raise VPNLauncherException(self.tr('No gateway was found!')) logger.debug("Using gateways ips: {0}".format(', '.join(gateways))) for gw in gateways: args += ['--remote', gw, '1194', 'udp'] args += [ '--client', '--dev', 'tun', ############################################################## # persist-tun makes ping-restart fail because it leaves a # broken routing table ############################################################## # '--persist-tun', '--persist-key', '--tls-client', # We make it log to a file because we cannot attach to the # openvpn process' stdout since it's a process with more # privileges than we are '--log-append', 'eip.log', '--remote-cert-tls', 'server' ] openvpn_configuration = eipconfig.get_openvpn_configuration() for key, value in openvpn_configuration.items(): args += ['--%s' % (key,), value] ############################################################## # The down-root plugin fails in some situations, so we don't # drop privs for the time being ############################################################## # args += [ # '--user', getpass.getuser(), # #'--group', grp.getgrgid(os.getgroups()[-1]).gr_name # ] args += [ '--management-signal', '--management', socket_host, socket_port, '--script-security', '2' ] args += [ '--cert', eipconfig.get_client_cert_path(providerconfig), '--key', eipconfig.get_client_cert_path(providerconfig), '--ca', providerconfig.get_ca_cert_path() ] logger.debug("Running VPN with command:") logger.debug("%s %s" % (openvpn, " ".join(args))) return [openvpn] + args
def get_vpn_command(self, eipconfig=None, providerconfig=None, socket_host=None, socket_port="unix", openvpn_verb=1): """ Returns the platform dependant vpn launching command. It will look for openvpn in the regular paths and algo in path_prefix/apps/eip/ (in case standalone is set) Might raise: VPNLauncherException, OpenVPNNotFoundException. :param eipconfig: eip configuration object :type eipconfig: EIPConfig :param providerconfig: provider specific configuration :type providerconfig: ProviderConfig :param socket_host: either socket path (unix) or socket IP :type socket_host: str :param socket_port: either string "unix" if it's a unix socket, or port otherwise :type socket_port: str :param openvpn_verb: openvpn verbosity wanted :type openvpn_verb: int :return: A VPN command ready to be launched :rtype: list """ leap_assert(eipconfig, "We need an eip config") leap_assert_type(eipconfig, EIPConfig) leap_assert(providerconfig, "We need a provider config") leap_assert_type(providerconfig, ProviderConfig) leap_assert(socket_host, "We need a socket host!") leap_assert(socket_port, "We need a socket port!") kwargs = {} if flags.STANDALONE: kwargs['path_extension'] = os.path.join( get_path_prefix(), "..", "apps", "eip") openvpn_possibilities = which(self.OPENVPN_BIN, **kwargs) if len(openvpn_possibilities) == 0: raise OpenVPNNotFoundException() openvpn = first(openvpn_possibilities) args = [] pkexec = self.maybe_pkexec() if pkexec: args.append(openvpn) openvpn = first(pkexec) args += [ '--setenv', "LEAPOPENVPN", "1" ] if openvpn_verb is not None: args += ['--verb', '%d' % (openvpn_verb,)] gateways = [] leap_settings = LeapSettings() domain = providerconfig.get_domain() gateway_conf = leap_settings.get_selected_gateway(domain) if gateway_conf == leap_settings.GATEWAY_AUTOMATIC: gateway_selector = VPNGatewaySelector(eipconfig) gateways = gateway_selector.get_gateways() else: gateways = [gateway_conf] if not gateways: logger.error('No gateway was found!') raise VPNLauncherException(self.tr('No gateway was found!')) logger.debug("Using gateways ips: {0}".format(', '.join(gateways))) for gw in gateways: args += ['--remote', gw, '1194', 'udp'] args += [ '--client', '--dev', 'tun', ############################################################## # persist-tun makes ping-restart fail because it leaves a # broken routing table ############################################################## # '--persist-tun', '--persist-key', '--tls-client', '--remote-cert-tls', 'server' ] openvpn_configuration = eipconfig.get_openvpn_configuration() for key, value in openvpn_configuration.items(): args += ['--%s' % (key,), value] ############################################################## # The down-root plugin fails in some situations, so we don't # drop privs for the time being ############################################################## # args += [ # '--user', getpass.getuser(), # '--group', grp.getgrgid(os.getgroups()[-1]).gr_name # ] if socket_port == "unix": # that's always the case for linux args += [ '--management-client-user', getpass.getuser() ] args += [ '--management-signal', '--management', socket_host, socket_port, '--script-security', '2' ] plugin_path = self.maybe_down_plugin() # If we do not have the down plugin neither in the bundle # nor in the system, we do not do updown scripts. The alternative # is leaving the user without the ability to restore dns and routes # to its original state. if plugin_path and _has_updown_scripts(self.UP_DOWN_PATH): args += [ '--up', self.UP_DOWN_PATH, '--down', self.UP_DOWN_PATH, ############################################################## # For the time being we are disabling the usage of the # down-root plugin, because it doesn't quite work as # expected (i.e. it doesn't run route -del as root # when finishing, so it fails to properly # restart/quit) ############################################################## # '--plugin', plugin_path, # '\'script_type=down %s\'' % self.UP_DOWN_PATH ] args += [ '--cert', eipconfig.get_client_cert_path(providerconfig), '--key', eipconfig.get_client_cert_path(providerconfig), '--ca', providerconfig.get_ca_cert_path() ] logger.debug("Running VPN with command:") logger.debug("%s %s" % (openvpn, " ".join(args))) return [openvpn] + args
def get_vpn_command(self, eipconfig=None, providerconfig=None, socket_host=None, socket_port="unix", openvpn_verb=1): """ Returns the platform dependant vpn launching command Might raise VPNException. :param eipconfig: eip configuration object :type eipconfig: EIPConfig :param providerconfig: provider specific configuration :type providerconfig: ProviderConfig :param socket_host: either socket path (unix) or socket IP :type socket_host: str :param socket_port: either string "unix" if it's a unix socket, or port otherwise :type socket_port: str :param openvpn_verb: openvpn verbosity wanted :type openvpn_verb: int :return: A VPN command ready to be launched :rtype: list """ leap_assert(eipconfig, "We need an eip config") leap_assert_type(eipconfig, EIPConfig) leap_assert(providerconfig, "We need a provider config") leap_assert_type(providerconfig, ProviderConfig) leap_assert(socket_host, "We need a socket host!") leap_assert(socket_port, "We need a socket port!") if not self.maybe_kextloaded(): raise EIPNoTunKextLoaded kwargs = {} if flags.STANDALONE: kwargs['path_extension'] = os.path.join( get_path_prefix(), "..", "apps", "eip") openvpn_possibilities = which( self.OPENVPN_BIN, **kwargs) if len(openvpn_possibilities) == 0: raise OpenVPNNotFoundException() openvpn = first(openvpn_possibilities) args = [openvpn] args += [ '--setenv', "LEAPOPENVPN", "1" ] if openvpn_verb is not None: args += ['--verb', '%d' % (openvpn_verb,)] gateways = [] leap_settings = LeapSettings() domain = providerconfig.get_domain() gateway_conf = leap_settings.get_selected_gateway(domain) if gateway_conf == leap_settings.GATEWAY_AUTOMATIC: gateway_selector = VPNGatewaySelector(eipconfig) gateways = gateway_selector.get_gateways() else: gateways = [gateway_conf] if not gateways: logger.error('No gateway was found!') raise VPNLauncherException(self.tr('No gateway was found!')) logger.debug("Using gateways ips: {0}".format(', '.join(gateways))) for gw in gateways: args += ['--remote', gw, '1194', 'udp'] args += [ '--client', '--dev', 'tun', ############################################################## # persist-tun makes ping-restart fail because it leaves a # broken routing table ############################################################## # '--persist-tun', '--persist-key', '--tls-client', '--remote-cert-tls', 'server' ] openvpn_configuration = eipconfig.get_openvpn_configuration() for key, value in openvpn_configuration.items(): args += ['--%s' % (key,), value] user = getpass.getuser() ############################################################## # The down-root plugin fails in some situations, so we don't # drop privs for the time being ############################################################## # args += [ # '--user', user, # '--group', grp.getgrgid(os.getgroups()[-1]).gr_name # ] if socket_port == "unix": args += [ '--management-client-user', user ] args += [ '--management-signal', '--management', socket_host, socket_port, '--script-security', '2' ] if _has_updown_scripts(self.UP_SCRIPT): args += [ '--up', '\"%s\"' % (self.UP_SCRIPT,), ] if _has_updown_scripts(self.DOWN_SCRIPT): args += [ '--down', '\"%s\"' % (self.DOWN_SCRIPT,) ] # should have the down script too if _has_updown_scripts(self.OPENVPN_DOWN_PLUGIN): args += [ ########################################################### # For the time being we are disabling the usage of the # down-root plugin, because it doesn't quite work as # expected (i.e. it doesn't run route -del as root # when finishing, so it fails to properly # restart/quit) ########################################################### # '--plugin', self.OPENVPN_DOWN_PLUGIN, # '\'%s\'' % self.DOWN_SCRIPT ] # we set user to be passed to the up/down scripts args += [ '--setenv', "LEAPUSER", "%s" % (user,)] args += [ '--cert', eipconfig.get_client_cert_path(providerconfig), '--key', eipconfig.get_client_cert_path(providerconfig), '--ca', providerconfig.get_ca_cert_path() ] command, cargs = self.get_cocoasudo_ovpn_cmd() cmd_args = cargs + args logger.debug("Running VPN with command:") logger.debug("%s %s" % (command, " ".join(cmd_args))) return [command] + cmd_args