dialog_messsage = "Could not find the kodi.log file." errorTrace("managefiles.py", dialog_message + " " + log_path + ", " + dest_path) xbmcgui.Dialog().ok("Log Copy", dialog_message) # Delete the user key and cert files elif action == "user": if addon.getSetting("1_vpn_validated") == "" or xbmcgui.Dialog().yesno(addon_name, "Deleting key and certificate files will reset all VPN connections. Connections must be re-validated before use.\nContinue?"): # Reset the connection before we do anything else if isVPNConnected(): resetVPNConnections(addon) # Select the provider provider_list = [] for provider in providers: if usesUserKeys(provider): provider_list.append(getVPNDisplay(provider)) provider_list.sort() index = xbmcgui.Dialog().select("Select VPN provider", provider_list) provider_display = provider_list[index] provider = getVPNLocation(provider_display) # Get the key/cert pairs for that provider and offer up for deletion user_keys = getUserKeys(provider) user_certs = getUserCerts(provider) if len(user_keys) > 0 or len(user_certs) > 0: still_deleting = True while still_deleting: if len(user_keys) > 0 or len(user_certs) > 0: # Build a list of things to display. We should always have pairs, but if # something didn't copy or the user has messed with the dir this will cope
xbmcgui.Dialog().ok("Log Copy", dialog_message) # Delete the user key and cert files elif action == "user": if addon.getSetting("1_vpn_validated") == "" or xbmcgui.Dialog().yesno( addon_name, "Deleting key and certificate files will disconnect and reset all VPN connections. Connections must be re-validated before use. Continue?" ): # Disconnect so that live files are not being modified if isVPNConnected(): resetVPNConnections(addon) # Select the provider provider_list = [] for provider in providers: if usesUserKeys(provider): provider_list.append(getVPNDisplay(provider)) provider_list.sort() index = xbmcgui.Dialog().select("Select VPN provider", provider_list) provider_display = provider_list[index] provider = getVPNLocation(provider_display) # Get the key/cert pairs for that provider and offer up for deletion user_keys = getUserKeys(provider) user_certs = getUserCerts(provider) if len(user_keys) > 0 or len(user_certs) > 0: still_deleting = True while still_deleting: if len(user_keys) > 0 or len(user_certs) > 0: # Build a list of things to display. We should always have pairs, but if
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')