def displayStatus():
    _, ip, country, isp = getIPInfo(addon)
    if isVPNConnected():
        debugTrace("VPN is connected, displaying the connection info")
        if fakeConnection():
            xbmcgui.Dialog().ok(
                addon_name, "Faked connection to a VPN in " + country +
                "\nUsing profile " + getVPNProfileFriendly() +
                "\nExternal IP address is " + ip + "\nService Provider is " +
                isp)
        else:
            server = getVPNServer()
            if not server == "": server = ", " + server + "\n"
            else: server = "\n"
            xbmcgui.Dialog().ok(
                addon_name,
                "Connected to a VPN in " + country + "\nUsing profile " +
                getVPNProfileFriendly() + server + "External IP address is " +
                ip + "\nService Provider is " + isp)
    else:
        debugTrace("VPN is not connected, displaying the connection info")
        xbmcgui.Dialog().ok(
            addon_name,
            "Disconnected from VPN.\nNetwork location is " + country +
            ".\nIP address is " + ip + ".\nService Provider is " + isp)
    return
def displayStatus():
    # Create a busy dialog whilst the data is retrieved.  It
    # could take a while to deduce that the network is bad...
    xbmc.executebuiltin('ActivateWindow(busydialognocancel)')
    try:
        _, ip, country, isp = getIPInfo(addon)
        if isVPNConnected():
            debugTrace("VPN is connected, displaying the connection info")
            xbmc.executebuiltin('Dialog.Close(busydialognocancel)')
            if fakeConnection():
                # Kodi18 bug, this should be a single multi line call, but \n doesn't work
                xbmcgui.Dialog().ok(addon_name,
                                    "[B]Faked connection to a VPN[/B]",
                                    "Using " + ip + ", located in " + country,
                                    "Service Provider is " + isp)
            else:
                server = getVPNServer()
                if not server == "": server = ", " + server + "\n"
                else: server = "\n"
                # Kodi18 bug, this should be a single multi line call, but \n doesn't work
                xbmcgui.Dialog().ok(addon_name, "[B]Connected to a VPN[/B]",
                                    "Using " + ip + ", located in " + country,
                                    "Service Provider is " + isp)
        else:
            debugTrace("VPN is not connected, displaying the connection info")
            xbmc.executebuiltin('Dialog.Close(busydialognocancel)')
            # Kodi18 bug, this should be a single multi line call, but \n doesn't work
            xbmcgui.Dialog().ok(addon_name, "[B]Disconnected from VPN[/B]",
                                "Using " + ip + ", located in " + country,
                                "Service Provider is " + isp)
    except Exception:
        xbmc.executebuiltin('Dialog.Close(busydialognocancel)')
    return
Exemple #3
0
def getUserDataPathWrapper(path):
    # This function resets the VPN profiles to the standard VPN Manager install
    # location as per OpenELEC, or to the platform install location
    force_default_install = fakeConnection()    
    if force_default_install:
        return "/storage/.kodi/userdata/addon_data/service.purevpn.monitor/" + path        
    else:
        return getUserDataPath(path)        
def getUserDataPathWrapper(path):
    # This function resets the VPN profiles to the standard VPN Manager install
    # location as per OpenELEC, or to the platform install location
    force_default_install = fakeConnection()    
    if force_default_install:
        return "/storage/.kodi/userdata/addon_data/service.vpn.manager/" + path        
    else:
        return getUserDataPath(path)        
Exemple #5
0
def listConnections():
    # Start with the disconnect option
    url = base_url + "?disconnect"
    if getVPNProfileFriendly() == "":
        li = xbmcgui.ListItem("[COLOR ffff0000](Disconnected)[/COLOR]",
                              iconImage=getIconPath() + "disconnected.png")
    else:
        li = xbmcgui.ListItem("[COLOR ffff0000]Disconnect[/COLOR]",
                              iconImage=getIconPath() + "unlocked.png")
    xbmcplugin.addDirectoryItem(handle=addon_handle, url=url, listitem=li)

    # We should have a VPN set up by now, but don't list if we haven't.
    vpn_provider = addon.getSetting("vpn_provider")
    debugTrace("Listing the connections available for " + vpn_provider)
    if vpn_provider != "":
        # Get the list of connections and add them to the directory
        all_connections = getAddonList(vpn_provider, "*.ovpn")
        ovpn_connections = getFilteredProfileList(
            all_connections, addon.getSetting("vpn_protocol"), None)
        connections = getFriendlyProfileList(ovpn_connections, "", "")
        inc = 0
        for connection in ovpn_connections:
            url = base_url + "?change?" + ovpn_connections[inc]
            conn_text = ""
            conn_primary = ""
            i = 1
            # Adjust 10 and 11 below if changing number of conn_max
            while (i < 11):
                if addon.getSetting(
                        str(i) +
                        "_vpn_validated_friendly") == connections[inc]:
                    conn_primary = " (" + str(i) + ")"
                    i = 10
                i = i + 1

            if getVPNProfileFriendly() == connections[inc] and isVPNConnected(
            ):
                conn_text = "[COLOR ff00ff00]" + connections[
                    inc] + conn_primary + " (Connected)[/COLOR]"
                if fakeConnection():
                    icon = getIconPath() + "faked.png"
                else:
                    icon = getIconPath() + "connected.png"
            else:
                if not conn_primary == "":
                    conn_text = "[COLOR ff0099ff]" + connections[
                        inc] + conn_primary + "[/COLOR]"
                else:
                    conn_text = connections[inc] + conn_primary
                icon = getIconPath() + "locked.png"
            li = xbmcgui.ListItem(conn_text, iconImage=icon)
            xbmcplugin.addDirectoryItem(handle=addon_handle,
                                        url=url,
                                        listitem=li)
            inc = inc + 1
    xbmcplugin.endOfDirectory(addon_handle)
    return
def getAddonPathWrapper(path):
    # This function resets the VPN profiles to the standard VPN Manager install
    # location as per OpenELEC, or to the platform install location
    force_default_install = fakeConnection()
    if force_default_install:
        return "/storage/.kodi/addons/service.vpn.manager/" + path        
    else:
        if getPlatform() == platforms.WINDOWS:
            return getAddonPath(True, path).replace("\\", "\\\\")
        else:
            return getAddonPath(True, path)
def getUserDataPathWrapper(path):
    # This function resets the VPN profiles to the standard VPN Manager install
    # location as per OpenELEC, or to the platform install location
    force_default_install = fakeConnection()
    if force_default_install:
        return "/storage/.kodi/userdata/addon_data/service.vpn.manager/" + path
    else:
        if getPlatform() == platforms.WINDOWS:
            return getUserDataPath(path).replace("\\", "\\\\")
        else:
            return getUserDataPath(path)
Exemple #8
0
def startVPNConnection(vpn_profile):  
    # Start the VPN, wait for connection, return the result

    startVPN(vpn_profile)
    debugTrace("Waiting for VPN to connect")
    i = 0
    loop_max = 77
    if fakeConnection(): loop_max = 2

    while i <= loop_max:
        xbmc.sleep(2000)
        state = getVPNConnectionStatus()
        if not state == connection_status.UNKNOWN: break
        i = i + 2

    if fakeConnection(): state = connection_status.CONNECTED
    
    if state == connection_status.CONNECTED:
        setVPNProfile(getVPNRequestedProfile())
        setVPNProfileFriendly(getVPNRequestedProfileFriendly())
        setVPNState("started")
        debugTrace("VPN connection to " + getVPNProfile() + " successful")

    return state
Exemple #9
0
def connectVPN(connection_order, vpn_profile):

    # Don't know where this was called from so using plugin name to get addon handle
    addon = xbmcaddon.Addon("service.vpn.manager")
    addon_name = addon.getAddonInfo("name")

    # If we've not arrived here though the addon (because we've used the add-on setting
    # on the option menu), we want to surpress running the wizard as there's no need.
    addon.setSetting("vpn_wizard_run", "true")

    # Check openvpn installed and runs
    if not addon.getSetting("checked_openvpn") == "true":        
        if checkVPNInstall(addon): addon.setSetting("checked_openvpn", "true")
        else: return

    if not addon.getSetting("ran_openvpn") == "true":
        stopVPN()    
        if checkVPNCommand(addon): addon.setSetting("ran_openvpn", "true")
        else: return
    
    # The VPN protocol can be blank if this is a new run and the wizard is being used.
    # Force it to UDP as that's the most optimal and let them change in the settings.
    vpn_protocol = addon.getSetting("vpn_protocol")
    if vpn_protocol == "":
        addon.setSetting("vpn_protocol", "UDP")
        vpn_protocol = "UDP"
    
    # Do some stuff to set up text used in dialog windows
    connection_title = ""
    
    # Adjust strings below if changing number of conn_max
    if connection_order == "0" : connection_title = ""
    if connection_order == "1" : connection_title = " first"
    if connection_order == "2" : connection_title = " second"
    if connection_order == "3" : connection_title = " third"
    if connection_order == "4" : connection_title = " fourth"
    if connection_order == "5" : connection_title = " fifth"
    if connection_order == "6" : connection_title = " sixth"
    if connection_order == "7" : connection_title = " seventh"
    if connection_order == "8" : connection_title = " eighth"
    if connection_order == "9" : connection_title = " ninth"
    if connection_order == "10" : connection_title = " tenth"
    
    state = ""
    
    forceCycleLock()
    
    # Display a progress dialog box (put this on the screen quickly before doing other stuff)
    progress = xbmcgui.DialogProgress()
    progress_title = "Connecting to" + connection_title + " VPN."
    progress.create(addon_name,progress_title) 

    debugTrace(progress_title)
        
    # Pause the monitor service
    progress_message = "Pausing VPN monitor."
    progress.update(1, progress_title, progress_message)
    if not stopService():
        progress.close()
        # Display error result in an ok dialog
        errorTrace("common.py", "VPN monitor service is not running, can't start VPN")
        xbmcgui.Dialog().ok(progress_title, "Error, Service not running.\nCheck log and re-enable.")
        return

    if not progress.iscanceled():
        progress_message = "VPN monitor paused."
        debugTrace(progress_message)
        progress.update(5, progress_title, progress_message)
        xbmc.sleep(500)
        
    # Stop any active VPN connection
    if not progress.iscanceled():
        progress_message = "Stopping any active VPN connection."    
        progress.update(6, progress_title, progress_message)
        stopVPNConnection()

    if not progress.iscanceled():
        progress_message = "Disconnected from VPN."
        progress.update(10, progress_title, progress_message)
        xbmc.sleep(500)
        
    # Install the VPN provider    
    existing_connection = ""
    if not progress.iscanceled():
    
        vpn_provider = addon.getSetting("vpn_provider")
    
        # This is some code to copy the user name from a default file rather than use the user entered values.
        # It exists to help development where swapping between providers constantly is tedious.
        default_path = getUserDataPath(getVPNLocation(vpn_provider) + "/DEFAULT.txt")
        if connection_order == "1" and xbmcvfs.exists(default_path):
            default_file = open(default_path, 'r')
            default = default_file.readlines()
            default_file.close()
            default_value = default[0].strip(' \t\n\r')
            addon.setSetting("vpn_username", default_value)
            default_value = default[1].strip(' \t\n\r')
            addon.setSetting("vpn_password", default_value)  

        # Reset the username/password if it's not being used
        if not usesPassAuth(vpn_provider):
            addon.setSetting("vpn_username", "")
            addon.setSetting("vpn_password", "")  
                
        vpn_username = addon.getSetting("vpn_username")
        vpn_password = addon.getSetting("vpn_password")
        
        # Reset the setting indicating we've a good configuration for just this connection
        if not connection_order == "0":
            existing_connection = addon.getSetting(connection_order + "_vpn_validated")
            addon.setSetting(connection_order + "_vpn_validated", "")
            addon.setSetting(connection_order + "_vpn_validated_friendly", "")
        last_provider = addon.getSetting("vpn_provider_validated")
        last_credentials = addon.getSetting("vpn_username_validated") + " " + addon.getSetting("vpn_password_validated")
        if last_provider == "" : last_provider = "?"
        
        # Provider or credentials we've used previously have changed so we need to reset all validated connections
        vpn_credentials = vpn_username + " " + vpn_password
        if not last_provider == vpn_provider:
            last_credentials = "?"
        if not last_credentials == vpn_credentials:
            debugTrace("Credentials have changed since last time lthrough so need to revalidate")
            resetVPNConfig(addon, 1)   
    
    # Generate or fix the OVPN files if we've not done this previously
    provider_gen = True
    if not progress.iscanceled():
        if not ovpnFilesAvailable(getVPNLocation(vpn_provider)):

            # Fetch the list of locations available.  If there are multiple, the user can select
            locations = getLocationFiles(getVPNLocation(vpn_provider))            
            default_label = "Default"
            i = 0            
            for location in locations:
                locations[i] = location[location.index("LOCATIONS")+10:location.index(".txt")]
                if locations[i] == "" : locations[i] = default_label
                i = i + 1
            selected_profile = ""
            if len(locations) == 0: errorTrace("common.py", "No LOCATIONS.txt files found in VPN directory.  Cannot generate ovpn files.")
            if len(locations) > 1:
                selected_location = xbmcgui.Dialog().select("Select connections profile", locations)
                selected_profile = locations[selected_location]
                if selected_profile == default_label : selected_profile = ""
            
            addon.setSetting("vpn_locations_list", selected_profile)
            progress_message = "Setting up VPN provider " + vpn_provider + "."
            progress.update(11, progress_title, progress_message)
            # Delete any old files in other directories
            debugTrace("Deleting all generated ovpn files")
            removeGeneratedFiles()
            # Generate new ones
            try:
                provider_gen = fixOVPNFiles(getVPNLocation(vpn_provider), selected_profile)
            except:
                errorTrace("Couldn't generate new .ovpn files")
                provider_gen = False
            xbmc.sleep(500)

    if provider_gen:
        if not progress.iscanceled():
            progress_message = "Using VPN provider " + vpn_provider
            progress.update(15, progress_title, progress_message)
            xbmc.sleep(500)
                            
        # Set up user credentials file
        if not progress.iscanceled() and usesPassAuth(vpn_provider):
            credentials_path = getCredentialsPath(addon)
            debugTrace("Attempting to use the credentials in " + credentials_path)
            if (not last_credentials == vpn_credentials) or (not xbmcvfs.exists(credentials_path)) or (not connectionValidated(addon)):
                progress_message = "Configuring authentication settings for user " + vpn_username + "."
                progress.update(16, progress_title, progress_message)
                provider_gen = writeCredentials(addon)

    got_keys = True
    keys_copied = True
    cancel_attempt = False
    cancel_clear = False
    if provider_gen:
        ovpn_name = ""
        if not progress.iscanceled():
            if usesPassAuth(vpn_provider):
                progress_message = "Using authentication settings for user " + vpn_username + "."
            else:
                progress_message = "User authentication not used with " + vpn_provider + "."
            progress.update(19, progress_title, progress_message)
            xbmc.sleep(500)

        # Display the list of connections
        if not progress.iscanceled():

            if not connection_order == "0":
                debugTrace("Displaying list of connections")
                all_connections = getProfileList(vpn_provider)
                ovpn_connections = getFilteredProfileList(all_connections, vpn_protocol, addon)
                ovpn_connections.sort()
                connections = getFriendlyProfileList(vpn_provider, ovpn_connections)
                
                if len(connections) > 0:
                    if existing_connection == "":
                        cancel_text = "[I]Cancel connection attempt[/I]"
                    else:
                        cancel_text = "[I]Cancel connection attempt and clear connection[/I]"
                        cancel_clear = True
                    connections.append(cancel_text)
                    selected_connection = xbmcgui.Dialog().select("Select " + connection_title + " VPN profile", connections)                  
                
                    # Based on the value selected, get the path name to the ovpn file
                    ovpn_name = connections[selected_connection]
                    if ovpn_name == cancel_text:
                        ovpn_name = ""
                        cancel_attempt = True
                    else:
                        ovpn_connection = ovpn_connections[selected_connection]
            else:
                ovpn_name = getFriendlyProfileName(vpn_provider, vpn_profile)
                ovpn_connection = vpn_profile

        if not progress.iscanceled() and not ovpn_name == "":
            # Fetch the key from the user if one is needed
            if usesUserKeys(getVPNLocation(vpn_provider)):                
                # If a key already exists, skip asking for it
                if not (gotKeys(getVPNLocation(vpn_provider), ovpn_name)):
                    # Stick out a helpful message if this is first time through
                    if not gotKeys(getVPNLocation(vpn_provider), ""):
                        xbmcgui.Dialog().ok(addon_name, vpn_provider + " provides unique key and certificate files to authenticate, typically called [I]client.key and client.crt[/I] or [I]user.key and user.crt[/I].  Make these files available on an accessable drive or USB key.")                
                    # Get the last directory browsed to avoid starting from the top
                    start_dir = xbmcgui.Window(10000).getProperty("VPN_Manager_User_Directory")
                    if usesSingleKey(getVPNLocation(vpn_provider)): select_title = "Select the user key file to use for all connections"
                    else: select_title = "Select the user key file to use for this individual connection"
                    key_file = xbmcgui.Dialog().browse(1, select_title, "files", ".key", False, False, start_dir, False)
                    if key_file.endswith(".key"):
                        start_dir = os.path.dirname(key_file) + getSeparator()
                        if usesSingleKey(getVPNLocation(vpn_provider)): select_title = "Select the user certificate file to use for all connections"
                        else: select_title = "Select the user certificate file to use for this individual connection"
                        crt_file = xbmcgui.Dialog().browse(1, select_title, "files", ".crt", False, False, start_dir, False)                    
                        if crt_file.endswith(".crt"):
                            start_dir = os.path.dirname(crt_file) + getSeparator()
                            xbmcgui.Window(10000).setProperty("VPN_Manager_User_Directory", start_dir)
                            keys_copied = copyKeyAndCert(getVPNLocation(vpn_provider), ovpn_name, key_file, crt_file)
                            got_keys = keys_copied
                        else:
                            got_keys = False
                    else:
                        got_keys = False

        # Try and connect to the VPN provider using the entered credentials        
        if not progress.iscanceled() and not ovpn_name == "" and got_keys:    
            progress_message = "Connecting using profile " + ovpn_name + "."
            debugTrace(progress_message)
            
            # Start the connection and wait a second before starting to check the state
            startVPN(ovpn_connection)
            
            i = 0
            # Bad network takes over a minute to spot so loop for a bit longer (each loop is 2 seconds)
            loop_max = 38
            if fakeConnection(): loop_max = 2
            percent = 20
            while i <= loop_max:
                progress.update(percent, progress_title, progress_message)
                xbmc.sleep(2000)
                state = getVPNConnectionStatus()
                if not (state == connection_status.UNKNOWN or state == connection_status.TIMEOUT) : break
                if progress.iscanceled(): break
                i = i + 1
                percent = percent + 2

    # Mess with the state to make it look as if we've connected to a VPN
    if fakeConnection() and not progress.iscanceled() and provider_gen and not ovpn_name == "" and got_keys: state = connection_status.CONNECTED
    
    # Determine what happened during the connection attempt        
    if state == connection_status.CONNECTED :
        # Success, VPN connected! Display an updated progress window whilst we work out where we're connected to
        progress_message = "Connected, restarting VPN monitor."
        progress.update(97, progress_title, progress_message)
        # Set the final message to indicate success
        progress_message = "Connected, VPN monitor restarted."
        _, ip, country, isp = getIPInfo(addon)
        dialog_message = "Connected to a VPN in " + country + ".\nUsing profile " + ovpn_name + ".\nExternal IP address is " + ip + ".\nService Provider is " + isp + "."
        infoTrace("common.py", dialog_message)
        if ifDebug(): writeVPNLog()
        # Store that setup has been validated and the credentials used
        setVPNProfile(ovpn_connection)
        setVPNProfileFriendly(ovpn_name)
        if not connection_order == "0":
            addon.setSetting("vpn_provider_validated", vpn_provider)
            addon.setSetting("vpn_username_validated", vpn_username)
            addon.setSetting("vpn_password_validated", vpn_password)
            addon.setSetting(connection_order + "_vpn_validated", ovpn_connection)
            addon.setSetting(connection_order + "_vpn_validated_friendly", ovpn_name)
        setVPNState("started")
        setVPNRequestedProfile("")
        setVPNRequestedProfileFriendly("")
        setVPNLastConnectedProfile("")
        setVPNLastConnectedProfileFriendly("")
        setConnectionErrorCount(0)
        # Indicate to the service that it should update its settings
        updateService()        
    elif progress.iscanceled() or cancel_attempt:
        # User pressed cancel.  Don't change any of the settings as we've no idea how far we got
        # down the path of installing the VPN, configuring the credentials or selecting the connection
        # We're assuming here that if the VPN or user ID has been changed, then the connections are invalid
        # already.  If the cancel happens during the connection validation, we can just use the existing one.
        # Set the final message to indicate user cancelled operation
        progress_message = "Cancelling connection attempt, restarting VPN monitor."
        progress.update(97, progress_title, progress_message)
        # Set the final message to indicate cancellation
        progress_message = "Cancelling connection attempt, VPN monitor restarted."
        # Restore the previous connection info 
        dialog_message = "Cancelled connection attempt.\n"
        if not connection_order == "0":
            if not isVPNConnected():
                if cancel_clear:
                    dialog_message = dialog_message + "This connection has been removed from the list of valid connections."
                else:
                    dialog_message = dialog_message + "This connection has not been validated."
                resetVPNConfig(addon, int(connection_order))
        else:
            dialog_message = dialog_message + "Please reconnect."
        
        # Don't know how far we got, if we were trying to connect and then got cancelled,
        # there might still be an instance of openvpn running we need to kill
        stopVPN()
    else:
        # An error occurred, The current connection is already invalidated.  The VPN credentials might 
        # be ok, but if they need re-entering, the user must update them which will force a reset.  
        progress_message = "Error connecting to VPN, restarting VPN monitor."
        progress.update(97, progress_title, progress_message)
        xbmc.sleep(500)
        # Set the final message to show an error occurred
        progress_message = "Error connecting to VPN, VPN monitor restarted."
        # First set of errors happened prior to trying to connect
        if not provider_gen:
            dialog_message = "Error creating OVPN or credentials file for provider.\nCheck log to determine cause of failure."
        elif not got_keys:
            if not keys_copied:
                dialog_message = "Failed to copy supplied user key and cert files.\nCheck log and retry."
            else:
                dialog_message = "User key and certificate files are required, but were not provided.  Locate the files and try again."
        elif ovpn_name == "":
            dialog_message = "No unused VPN profiles were available for " + vpn_protocol + " protocol.\nChange VPN provider settings."
        else:
            # This second set of errors happened because we tried to connect and failed
            if state == connection_status.AUTH_FAILED: 
                dialog_message = "Error connecting to VPN, authentication failed.\nCheck your username and password."
                credentials_path = getCredentialsPath(addon)
                if not connection_order == "0":
                    addon.setSetting("vpn_username_validated", "")
                    addon.setSetting("vpn_password_validated", "")
            elif state == connection_status.NETWORK_FAILED: 
                dialog_message = "Error connecting to VPN, could not estabilish connection.\nCheck your username, password and network connectivity and retry."
            elif state == connection_status.TIMEOUT:
                dialog_message = "Error connecting to VPN, connection has timed out.\nTry using a different VPN profile or retry."
            else:
                dialog_message = "Error connecting to VPN, something unexpected happened.\nRetry to check openvpn operation and then check log."
                addon.setSetting("ran_openvpn", "false")
            
            # Output what when wrong with the VPN to the log
            writeVPNLog()

        if not connection_order == "0" :
            resetVPNConfig(addon, int(connection_order))
        
        errorTrace("common.py", dialog_message)

        # The VPN might be having a spaz still so we want to ensure it's stopped
        stopVPN()

    # Restart service
    if not startService():
        progress.close()
        errorTrace("common.py", "VPN monitor service is not running, VPN has started")
        dialog_message = "Error, Service not running.\nCheck log and reboot."        
    else:
        # Close out the final progress dialog
        progress.update(100, progress_title, progress_message)
        xbmc.sleep(500)
        progress.close()
    
    freeCycleLock()

    # Display connection result in an ok dialog
    xbmcgui.Dialog().ok(progress_title, dialog_message)
    
    # Refresh the screen if this is not being done on settings screen
    if connection_order == "0" : xbmc.executebuiltin('Container.Refresh')