#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
 * **************************************************************************
 * Contributions to this work were made on behalf of the GÉANT project,
 * a project that has received funding from the European Union’s Framework
 * Programme 7 under Grant Agreements No. 238875 (GN3)
 * and No. 605243 (GN3plus), Horizon 2020 research and innovation programme
 * under Grant Agreements No. 691567 (GN4-1) and No. 731122 (GN4-2).
 * On behalf of the aforementioned projects, GEANT Association is
 * the sole owner of the copyright in all material which was developed
 * by a member of the GÉANT project.
 * GÉANT Vereniging (Association) is registered with the Chamber of
 * Commerce in Amsterdam with registration number 40535155 and operates
 * in the UK as a branch of GÉANT Vereniging.
 * 
 * Registered office: Hoekenrode 3, 1102BR Amsterdam, The Netherlands.
 * UK branch address: City House, 126-130 Hills Road, Cambridge CB2 1PQ, UK
 *
 * License: see the web/copyright.inc.php file in the file structure or
 *          <base_url>/copyright.php after deploying the software

Authors:
    Tomasz Wolniewicz <twoln@umk.pl>
    Michał Gasewicz <genn@umk.pl> (Network Manager support)

Contributors:
    Steffen Klemer https://github.com/sklemer1
    ikerb7 https://github.com/ikreb7
Many thanks for multiple code fixes, feature ideas, styling remarks
much of the code provided by them in the form of pull requests
has been incorporated into the final form of this script.

This script is the main body of the CAT Linux installer.
In the generation process configuration settings are added
as well as messages which are getting translated into the language
selected by the user.

The script is meant to run both under python 2.7 and python3. It tests
for the crucial dbus module and if it does not find it and if it is not
running python3 it will try rerunning iself again with python3.
"""
import argparse
import base64
import getpass
import os
import re
import subprocess
import sys
import uuid
from shutil import copyfile

NM_AVAILABLE = True
CRYPTO_AVAILABLE = True
DEBUG_ON = False
DEV_NULL = open("/dev/null", "w")
STDERR_REDIR = DEV_NULL


def debug(msg):
    """Print debugging messages to stdout"""
    if not DEBUG_ON:
        return
    print("DEBUG:" + str(msg))


def missing_dbus():
    """Handle missing dbus module"""
    global NM_AVAILABLE
    debug("Cannot import the dbus module")
    NM_AVAILABLE = False


def byte_to_string(barray):
    """conversion utility"""
    return "".join([chr(x) for x in barray])


def get_input(prompt):
    if sys.version_info.major < 3:
        return raw_input(prompt) # pylint: disable=undefined-variable
    return input(prompt)


debug(sys.version_info.major)


try:
    import dbus
except ImportError:
    if sys.version_info.major == 3:
        missing_dbus()
    if sys.version_info.major < 3:
        try:
            subprocess.call(['python3'] + sys.argv)
        except:
            missing_dbus()
        sys.exit(0)

try:
    from OpenSSL import crypto
except ImportError:
    CRYPTO_AVAILABLE = False


if sys.version_info.major == 3 and sys.version_info.minor >= 7:
    import distro
else:
    import platform


# the function below was partially copied
# from https://ubuntuforums.org/showthread.php?t=1139057
def detect_desktop_environment():
    """
    Detect what desktop type is used. This method is prepared for
    possible future use with password encryption on supported distros
    """
    desktop_environment = 'generic'
    if os.environ.get('KDE_FULL_SESSION') == 'true':
        desktop_environment = 'kde'
    elif os.environ.get('GNOME_DESKTOP_SESSION_ID'):
        desktop_environment = 'gnome'
    else:
        try:
            shell_command = subprocess.Popen(['xprop', '-root',
                                              '_DT_SAVE_MODE'],
                                             stdout=subprocess.PIPE,
                                             stderr=subprocess.PIPE)
            out, err = shell_command.communicate()
            info = out.decode('utf-8').strip()
        except (OSError, RuntimeError):
            pass
        else:
            if ' = "xfce4"' in info:
                desktop_environment = 'xfce'
    return desktop_environment


def get_system():
    """
    Detect Linux platform. Not used at this stage.
    It is meant to enable password encryption in distros
    that can handle this well.
    """
    if sys.version_info.major == 3 and sys.version_info.minor >= 7:
        system = distro.linux_distribution()
    else:
        system = platform.linux_distribution()
    desktop = detect_desktop_environment()
    return [system[0], system[1], desktop]


def run_installer():
    """
    This is the main installer part. It tests for MN availability
    gets user credentials and starts a proper installer.
    """
    global DEBUG_ON
    global NM_AVAILABLE
    username = ''
    password = ''
    silent = False
    pfx_file = ''
    parser = argparse.ArgumentParser(description='eduroam linux installer.')
    parser.add_argument('--debug', '-d', action='store_true', dest='debug',
                        default=False, help='set debug flag')
    parser.add_argument('--username', '-u', action='store', dest='username',
                        help='set username')
    parser.add_argument('--password', '-p', action='store', dest='password',
                        help='set text_mode flag')
    parser.add_argument('--silent', '-s', action='store_true', dest='silent',
                        help='set silent flag')
    parser.add_argument('--pfxfile', action='store', dest='pfx_file',
                        help='set path to user certificate file')
    args = parser.parse_args()
    if args.debug:
        DEBUG_ON = True
        print("Running debug mode")

    if args.username:
        username = args.username
    if args.password:
        password = args.password
    if args.silent:
        silent = args.silent
    if args.pfx_file:
        pfx_file = args.pfx_file
    debug(get_system())
    debug("Calling InstallerData")
    installer_data = InstallerData(silent=silent, username=username,
                                   password=password, pfx_file=pfx_file)

    # test dbus connection
    if NM_AVAILABLE:
        config_tool = CatNMConfigTool()
        if config_tool.connect_to_nm() is None:
            NM_AVAILABLE = False
    if not NM_AVAILABLE:
        # no dbus so ask if the user will want wpa_supplicant config
        if installer_data.ask(Messages.save_wpa_conf, Messages.cont, 1):
            sys.exit(1)
    installer_data.get_user_cred()
    installer_data.save_ca()
    if NM_AVAILABLE:
        config_tool.add_connections(installer_data)
    else:
        wpa_config = WpaConf()
        wpa_config.create_wpa_conf(Config.ssids, installer_data)
    installer_data.show_info(Messages.installation_finished)


class Messages(object):
    """
    These are initial definitions of messages, but they will be
    overridden with translated strings.
    """
    quit = "Really quit?"
    username_prompt = "enter your userid"
    enter_password = "enter password"
    enter_import_password = "enter your import password"
    incorrect_password = "incorrect password"
    repeat_password = "repeat your password"
    passwords_differ = "passwords do not match"
    installation_finished = "Installation successful"
    cat_dir_exists = "Directory {} exists; some of its files may be " \
        "overwritten."
    cont = "Continue?"
    nm_not_supported = "This NetworkManager version is not supported"
    cert_error = "Certificate file not found, looks like a CAT error"
    unknown_version = "Unknown version"
    dbus_error = "DBus connection problem, a sudo might help"
    yes = "Y"
    nay = "N"
    p12_filter = "personal certificate file (p12 or pfx)"
    all_filter = "All files"
    p12_title = "personal certificate file (p12 or pfx)"
    save_wpa_conf = "NetworkManager configuration failed, " \
        "but we may generate a wpa_supplicant configuration file " \
        "if you wish. Be warned that your connection password will be saved " \
        "in this file as clear text."
    save_wpa_confirm = "Write the file"
    wrongUsernameFormat = "Error: Your username must be of the form " \
        "'xxx@institutionID' e.g. 'john@example.net'!"
    wrong_realm = "Error: your username must be in the form of 'xxx@{}'. " \
        "Please enter the username in the correct format."
    wrong_realm_suffix = "Error: your username must be in the form of " \
        "'xxx@institutionID' and end with '{}'. Please enter the username " \
        "in the correct format."
    user_cert_missing = "personal certificate file not found"
    # "File %s exists; it will be overwritten."
    # "Output written to %s"


class Config(object):
    """
    This is used to prepare settings during installer generation.
    """
    instname = ""
    profilename = ""
    url = ""
    email = ""
    title = "eduroam CAT"
    servers = []
    ssids = []
    del_ssids = []
    eap_outer = ''
    eap_inner = ''
    use_other_tls_id = False
    server_match = ''
    anonymous_identity = ''
    CA = ""
    init_info = ""
    init_confirmation = ""
    tou = ""
    sb_user_file = ""
    verify_user_realm_input = False
    user_realm = ""
    hint_user_input = False


class InstallerData(object):
    """
    General user interaction handling, supports zenity, kdialog and
    standard command-line interface
    """

    def __init__(self, silent=False, username='', password='', pfx_file=''):
        self.graphics = ''
        self.username = username
        self.password = password
        self.silent = silent
        self.pfx_file = pfx_file
        debug("starting constructor")
        if silent:
            self.graphics = 'tty'
        else:
            self.__get_graphics_support()
        self.show_info(Config.init_info.format(Config.instname,
                                               Config.email, Config.url))
        if self.ask(Config.init_confirmation.format(Config.instname,
                                                    Config.profilename),
                    Messages.cont, 1):
            sys.exit(1)
        if Config.tou != '':
            if self.ask(Config.tou, Messages.cont, 1):
                sys.exit(1)
        if os.path.exists(os.environ.get('HOME') + '/.cat_installer'):
            if self.ask(Messages.cat_dir_exists.format(
                    os.environ.get('HOME') + '/.cat_installer'),
                        Messages.cont, 1):
                sys.exit(1)
        else:
            os.mkdir(os.environ.get('HOME') + '/.cat_installer', 0o700)

    def save_ca(self):
        """
        Save CA certificate to .cat_installer directory
        (create directory if needed)
        """
        certfile = os.environ.get('HOME') + '/.cat_installer/ca.pem'
        debug("saving cert")
        with open(certfile, 'w') as cert:
            cert.write(Config.CA + "\n")

    def ask(self, question, prompt='', default=None):
        """
        Propmpt user for a Y/N reply, possibly supplying a default answer
        """
        if self.silent:
            return 0
        if self.graphics == 'tty':
            yes = Messages.yes[:1].upper()
            nay = Messages.nay[:1].upper()
            print("\n-------\n" + question + "\n")
            while True:
                tmp = prompt + " (" + Messages.yes + "/" + Messages.nay + ") "
                if default == 1:
                    tmp += "[" + yes + "]"
                elif default == 0:
                    tmp += "[" + nay + "]"
                inp = get_input(tmp)
                if inp == '':
                    if default == 1:
                        return 0
                    if default == 0:
                        return 1
                i = inp[:1].upper()
                if i == yes:
                    return 0
                if i == nay:
                    return 1
        if self.graphics == "zenity":
            command = ['zenity', '--title=' + Config.title, '--width=500',
                       '--question', '--text=' + question + "\n\n" + prompt]
        elif self.graphics == 'kdialog':
            command = ['kdialog', '--yesno', question + "\n\n" + prompt,
                       '--title=', Config.title]
        returncode = subprocess.call(command, stderr=STDERR_REDIR)
        return returncode

    def show_info(self, data):
        """
        Show a piece of information
        """
        if self.silent:
            return
        if self.graphics == 'tty':
            print(data)
            return
        if self.graphics == "zenity":
            command = ['zenity', '--info', '--width=500', '--text=' + data]
        elif self.graphics == "kdialog":
            command = ['kdialog', '--msgbox', data]
        else:
            sys.exit(1)
        subprocess.call(command, stderr=STDERR_REDIR)

    def confirm_exit(self):
        """
        Confirm exit from installer
        """
        ret = self.ask(Messages.quit)
        if ret == 0:
            sys.exit(1)

    def alert(self, text):
        """Generate alert message"""
        if self.silent:
            return
        if self.graphics == 'tty':
            print(text)
            return
        if self.graphics == 'zenity':
            command = ['zenity', '--warning', '--text=' + text]
        elif self.graphics == "kdialog":
            command = ['kdialog', '--sorry', text]
        else:
            sys.exit(1)
        subprocess.call(command, stderr=STDERR_REDIR)

    def prompt_nonempty_string(self, show, prompt, val=''):
        """
        Prompt user for input
        """
        if self.graphics == 'tty':
            if show == 0:
                while True:
                    inp = str(getpass.getpass(prompt + ": "))
                    output = inp.strip()
                    if output != '':
                        return output
            while True:
                inp = str(get_input(prompt + ": "))
                output = inp.strip()
                if output != '':
                    return output

        if self.graphics == 'zenity':
            if val == '':
                default_val = ''
            else:
                default_val = '--entry-text=' + val
            if show == 0:
                hide_text = '--hide-text'
            else:
                hide_text = ''
            command = ['zenity', '--entry', hide_text, default_val,
                       '--width=500', '--text=' + prompt]
        elif self.graphics == 'kdialog':
            if show == 0:
                hide_text = '--password'
            else:
                hide_text = '--inputbox'
            command = ['kdialog', hide_text, prompt]

        output = ''
        while not output:
            shell_command = subprocess.Popen(command, stdout=subprocess.PIPE,
                                             stderr=subprocess.PIPE)
            out, err = shell_command.communicate()
            output = out.decode('utf-8').strip()
            if shell_command.returncode == 1:
                self.confirm_exit()
        return output

    def get_user_cred(self):
        """
        Get user credentials both username/password and personal certificate
        based
        """
        if Config.eap_outer == 'PEAP' or Config.eap_outer == 'TTLS':
            self.__get_username_password()
        if Config.eap_outer == 'TLS':
            self.__get_p12_cred()

    def __get_username_password(self):
        """
        read user password and set the password property
        do nothing if silent mode is set
        """
        password = "a"
        password1 = "b"
        if self.silent:
            return
        if self.username:
            user_prompt = self.username
        elif Config.hint_user_input:
            user_prompt = '@' + Config.user_realm
        else:
            user_prompt = ''
        while True:
            self.username = self.prompt_nonempty_string(
                1, Messages.username_prompt, user_prompt)
            if self.__validate_user_name():
                break
        while password != password1:
            password = self.prompt_nonempty_string(
                0, Messages.enter_password)
            password1 = self.prompt_nonempty_string(
                0, Messages.repeat_password)
            if password != password1:
                self.alert(Messages.passwords_differ)
        self.password = password

    def __get_graphics_support(self):
        if os.environ.get('DISPLAY') is not None:
            shell_command = subprocess.Popen(['which', 'zenity'],
                                             stdout=subprocess.PIPE,
                                             stderr=subprocess.PIPE)
            shell_command.wait()
            if shell_command.returncode == 0:
                self.graphics = 'zenity'
            else:
                shell_command = subprocess.Popen(['which', 'kdialog'],
                                                 stdout=subprocess.PIPE,
                                                 stderr=subprocess.PIPE)
                shell_command.wait()
                # out, err = shell_command.communicate()
                if shell_command.returncode == 0:
                    self.graphics = 'kdialog'
                else:
                    self.graphics = 'tty'
        else:
            self.graphics = 'tty'

    def __process_p12(self):
        debug('process_p12')
        pfx_file = os.environ['HOME'] + '/.cat_installer/user.p12'
        if CRYPTO_AVAILABLE:
            debug("using crypto")
            try:
                p12 = crypto.load_pkcs12(open(pfx_file, 'rb').read(),
                                         self.password)
            except:
                debug("incorrect password")
                return False
            else:
                if Config.use_other_tls_id:
                    return True
                try:
                    self.username = p12.get_certificate().\
                        get_subject().commonName
                except:
                    self.username = p12.get_certificate().\
                        get_subject().emailAddress
                return True
        else:
            debug("using openssl")
            command = ['openssl', 'pkcs12', '-in', pfx_file, '-passin',
                       'pass:' + self.password, '-nokeys', '-clcerts']
            shell_command = subprocess.Popen(command, stdout=subprocess.PIPE,
                                             stderr=subprocess.PIPE)
            out, err = shell_command.communicate()
            if shell_command.returncode != 0:
                return False
            if Config.use_other_tls_id:
                return True
            out_str = out.decode('utf-8').strip()
            subject = re.split(r'\s*[/,]\s*',
                               re.findall(r'subject=/?(.*)$',
                                          out_str, re.MULTILINE)[0])
            cert_prop = {}
            for field in subject:
                if field:
                    cert_field = re.split(r'\s*=\s*', field)
                    cert_prop[cert_field[0].lower()] = cert_field[1]
            if cert_prop['cn'] and re.search(r'@', cert_prop['cn']):
                debug('Using cn: ' + cert_prop['cn'])
                self.username = cert_prop['cn']
            elif cert_prop['emailaddress'] and \
                    re.search(r'@', cert_prop['emailaddress']):
                debug('Using email: ' + cert_prop['emailaddress'])
                self.username = cert_prop['emailaddress']
            else:
                self.username = ''
                self.alert("Unable to extract username "
                           "from the certificate")
            return True

    def __select_p12_file(self):
        """
        prompt user for the PFX file selection
        this method is not being called in the silent mode
        therefore there is no code for this case
        """
        if self.graphics == 'tty':
            my_dir = os.listdir(".")
            p_count = 0
            pfx_file = ''
            for my_file in my_dir:
                if my_file.endswith('.p12') or my_file.endswith('*.pfx') or \
                        my_file.endswith('.P12') or my_file.endswith('*.PFX'):
                    p_count += 1
                    pfx_file = my_file
            prompt = "personal certificate file (p12 or pfx)"
            default = ''
            if p_count == 1:
                default = '[' + pfx_file + ']'

            while True:
                inp = get_input(prompt + default + ": ")
                output = inp.strip()

                if default != '' and output == '':
                    return pfx_file
                default = ''
                if os.path.isfile(output):
                    return output
                print("file not found")

        if self.graphics == 'zenity':
            command = ['zenity', '--file-selection',
                       '--file-filter=' + Messages.p12_filter +
                       ' | *.p12 *.P12 *.pfx *.PFX', '--file-filter=' +
                       Messages.all_filter + ' | *',
                       '--title=' + Messages.p12_title]
            shell_command = subprocess.Popen(command, stdout=subprocess.PIPE,
                                             stderr=subprocess.PIPE)
            cert, err = shell_command.communicate()
        if self.graphics == 'kdialog':
            command = ['kdialog', '--getopenfilename',
                       '.', '*.p12 *.P12 *.pfx *.PFX | ' +
                       Messages.p12_filter, '--title', Messages.p12_title]
            shell_command = subprocess.Popen(command, stdout=subprocess.PIPE,
                                             stderr=STDERR_REDIR)
            cert, err = shell_command.communicate()
        return cert.decode('utf-8').strip()

    def __save_sb_pfx(self):
        """write the user PFX file"""
        certfile = os.environ.get('HOME') + '/.cat_installer/user.p12'
        with open(certfile, 'wb') as cert:
            cert.write(base64.b64decode(Config.sb_user_file))

    def __get_p12_cred(self):
        """get the password for the PFX file"""
        if Config.eap_inner == 'SILVERBULLET':
            self.__save_sb_pfx()
        else:
            if self.silent:
                pfx_file = self.pfx_file
            else:
                pfx_file = self.__select_p12_file()
                try:
                    copyfile(pfx_file, os.environ['HOME'] +
                             '/.cat_installer/user.p12')
                except (OSError, RuntimeError):
                    print(Messages.user_cert_missing)
                    sys.exit(1)
        if self.silent:
            username = self.username
            if not self.__process_p12():
                sys.exit(1)
            if username:
                self.username = username
        else:
            while not self.password:
                self.password = self.prompt_nonempty_string(
                    0, Messages.enter_import_password)
                if not self.__process_p12():
                    self.alert(Messages.incorrect_password)
                    self.password = ''
            if not self.username:
                self.username = self.prompt_nonempty_string(
                    1, Messages.username_prompt)

    def __validate_user_name(self):
        # locate the @ character in username
        pos = self.username.find('@')
        debug("@ position: " + str(pos))
        # trailing @
        if pos == len(self.username) - 1:
            debug("username ending with @")
            self.alert(Messages.wrongUsernameFormat)
            return False
        # no @ at all
        if pos == -1:
            if Config.verify_user_realm_input:
                debug("missing realm")
                self.alert(Messages.wrongUsernameFormat)
                return False
            debug("No realm, but possibly correct")
            return True
        # @ at the beginning
        if pos == 0:
            debug("missing user part")
            self.alert(Messages.wrongUsernameFormat)
            return False
        pos += 1
        if Config.verify_user_realm_input:
            if Config.hint_user_input:
                if self.username.endswith('@' + Config.user_realm, pos-1):
                    debug("realm equal to the expected value")
                    return True
                debug("incorrect realm; expected:" + Config.user_realm)
                self.alert(Messages.wrong_realm.format(Config.user_realm))
                return False
            if self.username.endswith(Config.user_realm, pos):
                debug("realm ends with expected suffix")
                return True
            debug("realm suffix error; expected: " + Config.user_realm)
            self.alert(Messages.wrong_realm_suffix.format(
                Config.user_realm))
            return False
        pos1 = self.username.find('@', pos)
        if pos1 > -1:
            debug("second @ character found")
            self.alert(Messages.wrongUsernameFormat)
            return False
        pos1 = self.username.find('.', pos)
        if pos1 == pos:
            debug("a dot immediately after the @ character")
            self.alert(Messages.wrongUsernameFormat)
            return False
        debug("all passed")
        return True


class WpaConf(object):
    """
    Prepare and save wpa_supplicant config file
    """
    def __prepare_network_block(self, ssid, user_data):
        out = """network={
        ssid=\"""" + ssid + """\"
        key_mgmt=WPA-EAP
        pairwise=CCMP
        group=CCMP TKIP
        eap=""" + Config.eap_outer + """
        ca_cert=\"""" + os.environ.get('HOME') + """/.cat_installer/ca.pem\"
        identity=\"""" + user_data.username + """\"
        altsubject_match=\"""" + ";".join(Config.servers) + """\"
        phase2=\"auth=""" + Config.eap_inner + """\"
        password=\"""" + user_data.password + """\"
        anonymous_identity=\"""" + Config.anonymous_identity + """\"
}
    """
        return out

    def create_wpa_conf(self, ssids, user_data):
        """Create and save the wpa_supplicant config file"""
        wpa_conf = os.environ.get('HOME') + \
            '/.cat_installer/cat_installer.conf'
        with open(wpa_conf, 'w') as conf:
            for ssid in ssids:
                net = self.__prepare_network_block(ssid, user_data)
                conf.write(net)


class CatNMConfigTool(object):
    """
    Prepare and save NetworkManager configuration
    """
    def __init__(self):
        self.cacert_file = None
        self.settings_service_name = None
        self.connection_interface_name = None
        self.system_service_name = None
        self.nm_version = None
        self.pfx_file = None
        self.settings = None
        self.user_data = None
        self.bus = None

    def connect_to_nm(self):
        """
        connect to DBus
        """
        try:
            self.bus = dbus.SystemBus()
        except dbus.exceptions.DBusException:
            print("Can't connect to DBus")
            return None
        # main service name
        self.system_service_name = "org.freedesktop.NetworkManager"
        # check NM version
        self.__check_nm_version()
        debug("NM version: " + self.nm_version)
        if self.nm_version == "0.9" or self.nm_version == "1.0":
            self.settings_service_name = self.system_service_name
            self.connection_interface_name = \
                "org.freedesktop.NetworkManager.Settings.Connection"
            # settings proxy
            sysproxy = self.bus.get_object(
                self.settings_service_name,
                "/org/freedesktop/NetworkManager/Settings")
            # settings interface
            self.settings = dbus.Interface(sysproxy, "org.freedesktop."
                                           "NetworkManager.Settings")
        elif self.nm_version == "0.8":
            self.settings_service_name = "org.freedesktop.NetworkManager"
            self.connection_interface_name = "org.freedesktop.NetworkMana" \
                                             "gerSettings.Connection"
            # settings proxy
            sysproxy = self.bus.get_object(
                self.settings_service_name,
                "/org/freedesktop/NetworkManagerSettings")
            # settings intrface
            self.settings = dbus.Interface(
                sysproxy, "org.freedesktop.NetworkManagerSettings")
        else:
            print(Messages.nm_not_supported)
            return None
        debug("NM connection worked")
        return True

    def __check_opts(self):
        """
        set certificate files paths and test for existence of the CA cert
        """
        self.cacert_file = os.environ['HOME'] + '/.cat_installer/ca.pem'
        self.pfx_file = os.environ['HOME'] + '/.cat_installer/user.p12'
        if not os.path.isfile(self.cacert_file):
            print(Messages.cert_error)
            sys.exit(2)

    def __check_nm_version(self):
        """
        Get the NetworkManager version
        """
        try:
            proxy = self.bus.get_object(
                self.system_service_name, "/org/freedesktop/NetworkManager")
            props = dbus.Interface(proxy, "org.freedesktop.DBus.Properties")
            version = props.Get("org.freedesktop.NetworkManager", "Version")
        except dbus.exceptions.DBusException:
            version = ""
        if re.match(r'^1\.', version):
            self.nm_version = "1.0"
            return
        if re.match(r'^0\.9', version):
            self.nm_version = "0.9"
            return
        if re.match(r'^0\.8', version):
            self.nm_version = "0.8"
            return
        self.nm_version = Messages.unknown_version

    def __delete_existing_connection(self, ssid):
        """
        checks and deletes earlier connection
        """
        try:
            conns = self.settings.ListConnections()
        except dbus.exceptions.DBusException:
            print(Messages.dbus_error)
            exit(3)
        for each in conns:
            con_proxy = self.bus.get_object(self.system_service_name, each)
            connection = dbus.Interface(
                con_proxy,
                "org.freedesktop.NetworkManager.Settings.Connection")
            try:
                connection_settings = connection.GetSettings()
                if connection_settings['connection']['type'] == '802-11-' \
                                                                'wireless':
                    conn_ssid = byte_to_string(
                        connection_settings['802-11-wireless']['ssid'])
                    if conn_ssid == ssid:
                        debug("deleting connection: " + conn_ssid)
                        connection.Delete()
            except dbus.exceptions.DBusException:
                pass

    def __add_connection(self, ssid):
        debug("Adding connection: " + ssid)
        server_alt_subject_name_list = dbus.Array(Config.servers)
        server_name = Config.server_match
        if self.nm_version == "0.9" or self.nm_version == "1.0":
            match_key = 'altsubject-matches'
            match_value = server_alt_subject_name_list
        else:
            match_key = 'subject-match'
            match_value = server_name
        s_8021x_data = {
            'eap': [Config.eap_outer.lower()],
            'identity': self.user_data.username,
            'ca-cert': dbus.ByteArray(
                "file://{0}\0".format(self.cacert_file).encode('utf8')),
            match_key: match_value}
        if Config.eap_outer == 'PEAP' or Config.eap_outer == 'TTLS':
            s_8021x_data['password'] = self.user_data.password
            s_8021x_data['phase2-auth'] = Config.eap_inner.lower()
            if Config.anonymous_identity != '':
                s_8021x_data['anonymous-identity'] = Config.anonymous_identity
            s_8021x_data['password-flags'] = 0
        if Config.eap_outer == 'TLS':
            s_8021x_data['client-cert'] = dbus.ByteArray(
                "file://{0}\0".format(self.pfx_file).encode('utf8'))
            s_8021x_data['private-key'] = dbus.ByteArray(
                "file://{0}\0".format(self.pfx_file).encode('utf8'))
            s_8021x_data['private-key-password'] = self.user_data.password
            s_8021x_data['private-key-password-flags'] = 0
        s_con = dbus.Dictionary({
            'type': '802-11-wireless',
            'uuid': str(uuid.uuid4()),
            'permissions': ['user:' +
                            os.environ.get('USER')],
            'id': ssid
            })
        s_wifi = dbus.Dictionary({
            'ssid': dbus.ByteArray(ssid.encode('utf8')),
            'security': '802-11-wireless-security'
            })
        s_wsec = dbus.Dictionary({
            'key-mgmt': 'wpa-eap',
            'proto': ['rsn'],
            'pairwise': ['ccmp'],
            'group': ['ccmp', 'tkip']
            })
        s_8021x = dbus.Dictionary(s_8021x_data)
        s_ip4 = dbus.Dictionary({'method': 'auto'})
        s_ip6 = dbus.Dictionary({'method': 'auto'})
        con = dbus.Dictionary({
            'connection': s_con,
            '802-11-wireless': s_wifi,
            '802-11-wireless-security': s_wsec,
            '802-1x': s_8021x,
            'ipv4': s_ip4,
            'ipv6': s_ip6
            })
        self.settings.AddConnection(con)

    def add_connections(self, user_data):
        """Delete and then add connections to the system"""
        self.__check_opts()
        self.user_data = user_data
        for ssid in Config.ssids:
            self.__delete_existing_connection(ssid)
            self.__add_connection(ssid)
        for ssid in Config.del_ssids:
            self.__delete_existing_connection(ssid)


Messages.quit = "Chcete skutečně skončit?"
Messages.username_prompt = "zadejte své uživatelské jméno"
Messages.enter_password = "zadejte heslo"
Messages.enter_import_password = "zadejte heslo pro import"
Messages.incorrect_password = "neplatné heslo"
Messages.repeat_password = "opakujte zadání hesla"
Messages.passwords_differ = "heslo není shodné"
Messages.installation_finished = "Instalace proběhla úspěšně"
Messages.cat_dir_exisits = "Adresář {} už existuje, některé " \
    "soubory v něm budou přepsány."
Messages.cont = "Pokračovat?"
Messages.nm_not_supported = "Tato verze NetworkManageru není " \
    "podporována"
Messages.cert_error = "Soubor s certifikátem nebyl nalezen, " \
    "pravděpodobně je to chyba CAT"
Messages.unknown_version = "Neznámá verze"
Messages.dbus_error = "Problém připojení k DBus, příkaz sudo vám " \
    "může pomoci"
Messages.yes = "A"
Messages.no = "N"
Messages.p12_filter = "soubor osobního certifikátu (p12 nebo pfx)"
Messages.all_filter = "Všechny soubory"
Messages.p12_title = "soubor osobního certifikátu (p12 nebo pfx)"
Messages.save_wpa_conf = "Konfigurace NetworkManageru se nezdařila. " \
    "Pokud si přejete, můžeme vygenerovat konfigurační soubor pro " \
    "wpa-supplicant. Vaše heslo pro připojení bude v tomto souboru " \
    "uloženo v textové podobě!"
Messages.save_wpa_confirm = "Zapsat soubor"
Messages.wrongUsernameFormat = "Chyba: Vaše uživatelské jméno " \
    "musí být ve formátu 'jméno@institutionID', např. " \
    "'john@example.net'!"
Messages.wrong_realm = "Chyba: Vaše uživatelské jméno musí být " \
    "ve formátu 'jméno@{}'. Zadejte prosím uživatelské jméno ve " \
    "správném formátu."
Messages.wrong_realm_suffix = "Chyba: Vaše uživatelské jméno musí " \
    "být ve formátu 'jméno@institutionID' a končit s '{}'. Zadejte " \
    "prosím uživatelské jméno ve správném formátu."
Messages.user_cert_missing = "soubor s osobním certifikátem nebyl " \
    "nalezen"
Config.instname = "Catholic university in Ruzomberok"
Config.profilename = "Eduroam"
Config.url = "http://eduroam.ku.sk/"
Config.email = "rudolf.kollar@ku.sk"
Config.title = "eduroam CAT"
Config.server_match = "ku.sk"
Config.eap_outer = "PEAP"
Config.eap_inner = "MSCHAPV2"
Config.init_info = "Tento instalační program byl připravený pro " \
    "{0}\n\nDalší informace a komentáře:\n\nEMAIL: {1}\nWWW: " \
    "{2}\n\nInstalační program byl vytvořený pomocí programu z " \
    "projektu GEANT."
Config.init_confirmation = "Tento instalační program bude fungovat " \
    "pouze pokud jste členem organizace {0}."
Config.user_realm = "ku.sk"
Config.ssids = ['eduroam']
Config.del_ssids = []
Config.servers = ['DNS:frd1.ku.sk', 'DNS:frd2.ku.sk']
Config.use_other_tls_id = False
Config.tou = ""
Config.CA = """-----BEGIN CERTIFICATE-----
MIIEZDCCA0ygAwIBAgIBATANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UEBhMCU0sx
EjAQBgNVBAgTCVNsb3ZlbnNrbzETMBEGA1UEBxMKUnV6b21iZXJvazEqMCgGA1UE
ChMhS2F0b2xpY2thIHVuaXZlcnppdGEgdiBSdXpvbWJlcmt1MQ0wCwYDVQQLEwRV
SUtUMTYwNAYDVQQDEy1SQURJVVMgbmEgS2F0b2xpY2tlaiB1bml2ZXJ6aXRlIHYg
UnV6b21iZXJrdS4wHhcNMTMxMTI4MTMxNTQ2WhcNMjMxMTI4MTMxNTQ2WjCBqTEL
MAkGA1UEBhMCU0sxEjAQBgNVBAgTCVNsb3ZlbnNrbzETMBEGA1UEBxMKUnV6b21i
ZXJvazEqMCgGA1UEChMhS2F0b2xpY2thIHVuaXZlcnppdGEgdiBSdXpvbWJlcmt1
MQ0wCwYDVQQLEwRVSUtUMTYwNAYDVQQDEy1SQURJVVMgbmEgS2F0b2xpY2tlaiB1
bml2ZXJ6aXRlIHYgUnV6b21iZXJrdS4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQDH1vpqUAH8/DkwV9OmObcr1AwhUiaKWzPJLAEp2fN6jhnW3WsbSZIG
60hUvCEPJrwitOY4RBJpmU8WXyQe0Ev0PsD2IT1RrpFZ2r017bMtow07LuCtVKCM
LwF4BSYH0PCt5Rm61nqDq0oRhEi9cGf9jY+jT8KMXG5QuQlloFCPqFOQlLnaGVWC
Dz3e55K4nEpL9FUULTwQ/yE+HuFtI6T/8BeZgSzPwaaiap6U5QDB2vKioTgIluy8
2ra+K8gF2FDImlUASUXtTMmviht+58aLc1n7+Bg1fgAm9t7hlBbAIXqh6mC6wln3
5R9/7CJV5SsfYvhn0Ims0NgoBfy3WA8pAgMBAAGjgZQwgZEwDwYDVR0TAQH/BAUw
AwEB/zAPBgNVHQ8BAf8EBQMDBwYAMC0GA1UdHwQmMCQwIqAgoB6GHGh0dHA6Ly93
d3cua3Uuc2svZWR1cm9hbS5jcmwwHQYDVR0OBBYEFMFqn89ZI98mzwef4FWLEJw5
2zxJMB8GA1UdIwQYMBaAFMFqn89ZI98mzwef4FWLEJw52zxJMA0GCSqGSIb3DQEB
BQUAA4IBAQBqy1zrN2rbDjotmqTzyk4r4hZyzPOVf/O7HH7IjwZEleNsggMXc8Jm
QWZHzCREIkhD1zzwCPNAbn6PwxCnMVXoxVoDeRnyPxqu5mDe7blb1SpesH3s2KlY
Jmwh8LFvd0YS+CV3stkUxGJmYZor+tGJvkzKhl0yVpBUrdAlzWZECKWcsNshiQmH
F9c7S0rP/IOBRUMOpRE0QtnqcPAjP9mkRG2BRQjRVGotxgYLCGgu5QJ7bwHMIzPP
2EWVMHB2AvkqRpIKrUASpPtLXE4zCUpfh5MCAvieeAVeW8EW1PgmvCn7RNmRBQ9Z
HrWdKRIALv0nKPcJSlNJnewmN2vJFiBk
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFzTCCA7UCFDvaMZgPJrBEHAiE6GajAyVA6rWZMA0GCSqGSIb3DQEBCwUAMIGi
MQswCQYDVQQGEwJTSzERMA8GA1UECAwIU2xvdmFraWExEzARBgNVBAcMClJ1em9t
YmVyb2sxKjAoBgNVBAoMIUthdG9saWNrYSB1bml2ZXJ6aXRhIHYgUnV6b21iZXJr
dTEQMA4GA1UECwwHT0lJVEFJUzESMBAGA1UEAwwJZnJkLmt1LnNrMRkwFwYJKoZI
hvcNAQkBFgpjZXJ0QGt1LnNrMB4XDTIxMDEyNjA5MDIwMFoXDTM2MDEyMzA5MDIw
MFowgaIxCzAJBgNVBAYTAlNLMREwDwYDVQQIDAhTbG92YWtpYTETMBEGA1UEBwwK
UnV6b21iZXJvazEqMCgGA1UECgwhS2F0b2xpY2thIHVuaXZlcnppdGEgdiBSdXpv
bWJlcmt1MRAwDgYDVQQLDAdPSUlUQUlTMRIwEAYDVQQDDAlmcmQua3Uuc2sxGTAX
BgkqhkiG9w0BCQEWCmNlcnRAa3Uuc2swggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
ggIKAoICAQCzlhOScLplIodukay8+b2j2pmS/L7pgEQEWJ+o1uUFYoPWnap5Wdzv
H/iiWwtzDpqZ6xIGiW2AqIIwonI5AveaCIfniqIh2wgf8yW5vIf7rdYGB8WHnDRW
0rmGNd6UjkLFwgH2shsGJuBhbJcA4QY6eGXgPsFlta+PpzJOGcEuF/SYnovr3SQN
sQDpxdapy4z5Htlu+bn6a9xxWuhH/Gl8PUjuWj3NA4DZZMZbJe10IFknxEeqC50L
zA/Ko76d1bV0kJfC0tUICW5Xsf/J57ioPOyXHuDK+iotT5043BZyHxYI85UWAdSn
v60plpP++b0Av3trUBqUGOdaVgQRrgDmjA/ZsyShwd9vZPsoFKVAT/x1iblxvbpW
d1KML+l38SgBxqRIut+GexRm6OFJ8StrQosSF3YULtBp/d4znAnT6hZ8rf52lv3j
lIlI9ZUA+BrkheXH0G/5uhiVDMny3qDsIUxjOv0qKr2O81ZLPgk7qfS0pEVDHOPC
Gi6spapENJhT+Fp4hr5wEJwqkUQ1DSL9K03wz05idswQiaUTVKuyfiGD2ApkZ4gj
JxanYkQz1R0h5SwJwu0csWK8QRrQLhB+DH4p5Ou36yL9vPByZo7m6A5dImSTG+fM
ycnnPN34XwSfoeigc3stkO1+RNN24D1yXAWsZohaBHdqEDjzvnMdbwIDAQABMA0G
CSqGSIb3DQEBCwUAA4ICAQBpBdVu7sbY9j/3kQzOYYbAzVsoN2cKZ2zRGIvdwFS/
p1rKFCg9AgogeFh37YrSTI6hU9LhsTPTersYzo2WpKrAcssoLK1cxAgUeDa+dkoy
bKu+tmrezzsVFazByYsIvRUh+KwTLN8ZPSgPuYt2Wb95FAoOnO6VcXWZRS+lvlkH
uK9F6FzUZGzko9ElrW2l4S/TFRTs0G1/C2ATMI2nEdr5aFq1GKDsr+tI89MRcRWm
6e4/yP6ruQKLVSGSBu6NB8GNCRszcw0fbVFDZpQJ5y+Y7IUSAaf3wGLw46/Wdb6/
cmi1FWNcWgcbfdG2+4/7roYkpWtPU/0eObEbPAtZqCwH2tbFxi836u/Zf1dYtFjq
lf88+VNiGRVgTqZmLIMr7z7POu78PGRL5El7qZ0bHp1Zih5Ix5J9cgqSSp1/N0mJ
sZ6zqBk7NAh1UvPmQ7d6IH2alDROycjrLnNFeels+Qg8g/cTANQRVo2YBsjGoFCE
K2DsLJxMP4QPIgBOT97Lks/EuUbX5fJfQ+8qBGxVjWDUsUtve//SHMorK2vJ36AS
SDSdZzL+1UJBOMVvSxcNgjeUcN6wKymdeH6p5EWC9RrYbTScdowdsfavMSf1M/EJ
XTeXuhboLewRk1gmuZ24g/JAga6oukAR0cyHsDfjIRJHJtdUzvXqZ/77yB39PSiB
Og==
-----END CERTIFICATE-----
"""
run_installer()
