Пример #1
0
def checkForGitUpdates(vpn_provider, cached):
    # Download the metadata file, compare it to the existing timestamp and return True if there's an update
    t = int(time.time())
    if getVPNProviderUpdateTime() == 0:
        setVPNProviderUpdate("false")
        setVPNProviderUpdateTime(t)
    else:
        # Return the value from cache if it's less than a day old
        if cached and t - getVPNProviderUpdateTime() < 86400:
            if getVPNProviderUpdate() == "true": return True
            else: return False
    setVPNProviderUpdate("false")
    if vpn_provider == "" or isUserDefined(vpn_provider): return False
    metadata = getGitMetaData(vpn_provider)
    if metadata is None:
        # Can't get to github, trace it but pretend there's no update
        errorTrace("vpnproviders.py", "No metadata was returned for " + vpn_provider)
        return False
    git_timestamp, version, total_files, file_list = parseGitMetaData(metadata)
    try:
        last_file = open(getUserDataPath("Downloads" + "/" + vpn_provider + "/METADATA.txt"), 'r')
        last = last_file.readlines()
        last_file.close()
        if last[0] == git_timestamp: return False
        setVPNProviderUpdate("true")
        setVPNProviderUpdateTime(t)
        return True
    except:
        # Tried to read the existing file and it likely didn't exist
        # Return true as this means nothing has been downloaded
        return True
Пример #2
0
def deleteTestFile():
    try:
        if xbmcvfs.exists(getTestFilePath()):
            xbmcvfs.delete(getTestFilePath())
    except Exception as e:
        errorTrace("platform.py", "Couldn't delete test file")
        errorTrace("platform.py", str(e))
Пример #3
0
def copySystemdFiles():
    # Delete any existing openvpn.service and copy openvpn service file to config directory
    service_source = getAddonPath(True, "openvpn.service")
    service_dest = getSystemdPath("system.d/openvpn.service")
    debugTrace("Copying openvpn.service " + service_source + " to " +
               service_dest)
    if not fakeSystemd():
        if xbmcvfs.exists(service_dest): xbmcvfs.delete(service_dest)
        xbmcvfs.copy(service_source, service_dest)
        if not xbmcvfs.exists(service_dest):
            raise IOError('Failed to copy service ' + service_source + " to " +
                          service_dest)

    # Delete any existing openvpn.config and copy first VPN to openvpn.config
    config_source = sudo_setting = xbmcaddon.Addon(
        getID()).getSetting("1_vpn_validated")
    if service_source == "":
        errorTrace("platform.py", "Nothing has been validated")
    config_dest = getSystemdPath("openvpn.config")
    debugTrace("Copying openvpn.config " + config_source + " to " +
               config_dest)
    if not fakeSystemd():
        if xbmcvfs.exists(config_dest): xbmcvfs.delete(config_dest)
        xbmcvfs.copy(config_source, config_dest)
        if not xbmcvfs.exists(config_dest):
            raise IOError('Failed to copy service ovpn ' + config_source +
                          " to " + config_dest)
Пример #4
0
def deleteTestFile():
    try:
        if xbmcvfs.exists(getTestFilePath()):
            xbmcvfs.delete(getTestFilePath())
    except Exception as e:
        errorTrace("platform.py", "Couldn't delete test file")
        errorTrace("platform.py", str(e))
Пример #5
0
def getVPNConnectionStatus():
    # Open the openvpn output file and parse it for known phrases
    # Return 'connected', 'auth failed', 'network failed', 'error' or ''

    if fakeConnection(): return connection_status.UNKNOWN

    # **** ADD MORE PLATFORMS HERE ****
    # Might not need to mess with this too much if the log output from different platform openvpns are the same

    p = getPlatform()
    if p == platforms.LINUX or p == platforms.RPI or p == platforms.WINDOWS:
        path = getVPNLogFilePath()
        state = connection_status.UNKNOWN
        if xbmcvfs.exists(path):
            debugTrace("Reading log file")
            log = open(path, 'r')
            lines = log.readlines()
            for line in lines:
                if "Initialization Sequence Completed" in line:
                    state = connection_status.CONNECTED
                    break
                if "AUTH_FAILED" in line:
                    state = connection_status.AUTH_FAILED
                if "private key password verification failed" in line:
                    state = connection_status.AUTH_FAILED
                if "TLS Error" in line:
                    state = connection_status.NETWORK_FAILED
                if "Connection timed out" in line:
                    state = connection_status.TIMEOUT
                if "Inactivity timeout" in line:
                    state = connection_status.TIMEOUT
                if "Error opening configuration file" in line:
                    state = connection_status.FILE_ERROR
                if p == platforms.WINDOWS and "ROUTE" in line and "Access is denied" in line:
                    # This is a Windows, not running Kodi as administrator error
                    state = connection_status.ACCESS_DENIED
                    break
                if p == platforms.WINDOWS and "FlushIpNetTable" in line and "Access is denied" in line:
                    # This is a Windows, not running Kodi as administrator error
                    state = connection_status.ACCESS_DENIED
                    break
                #if "ERROR: Linux route" in line:
                # state = connection_status.ROUTE_FAILED
                # This tests for a Linux route failure, only it's commented out as
                # it can legitimately fail if the route already exists.  If it fails
                # for other reasons, I can't tell the different just yet.
                # break
            log.close()
            # Haven't found what's expected so return an empty stream
            if not state == connection_status.UNKNOWN:
                debugTrace("VPN connection status is " + str(state))
            return state
        else:
            errorTrace(
                "platform.py",
                "Tried to get VPN connection status but log file didn't exist")
            return connection_status.ERROR
Пример #6
0
def getipstack(json_data):
    try:
        ip = json_data["ip"]
        country = json_data["country_name"]
        region = json_data["region_name"]
        city = json_data["city"]       
        return ip, country, region, city, "Unknown"
    except Exception as e:
        errorTrace("ipinfo.py", "Couldn't parse JSON data " + str(json_data))
        errorTrace("ipinfo.py", str(e))
        return None, None, None, None, None 
Пример #7
0
def getVPNConnectionStatus():
    # Open the openvpn output file and parse it for known phrases
    # Return 'connected', 'auth failed', 'network failed', 'error' or ''

    if fakeConnection(): return connection_status.UNKNOWN

    # **** ADD MORE PLATFORMS HERE ****
    # Might not need to mess with this too much if the log output from different platform openvpns are the same
    
    p = getPlatform()
    if p == platforms.LINUX or p == platforms.RPI or p == platforms.WINDOWS:
        path = getVPNLogFilePath()
        state = connection_status.UNKNOWN
        if xbmcvfs.exists(path):
            debugTrace("Reading log file")
            log = open(path,'r')
            lines = log.readlines()
            for line in lines:
                if "Initialization Sequence Completed" in line:
                    state = connection_status.CONNECTED
                    break
                if "AUTH_FAILED" in line:
                    state = connection_status.AUTH_FAILED
                if "private key password verification failed" in line:
                    state = connection_status.AUTH_FAILED
                if "TLS Error" in line:
                    state = connection_status.NETWORK_FAILED
                if "Connection timed out" in line:
                    state = connection_status.TIMEOUT
                if "Inactivity timeout" in line:
                    state = connection_status.TIMEOUT
                if "Error opening configuration file" in line:
                    state = connection_status.FILE_ERROR
                if p == platforms.WINDOWS and "ROUTE" in line and "Access is denied" in line:
                    # This is a Windows, not running Kodi as administrator error
                    state = connection_status.ACCESS_DENIED
                    break
                if p == platforms.WINDOWS and "FlushIpNetTable" in line and "Access is denied" in line:
                    # This is a Windows, not running Kodi as administrator error
                    state = connection_status.ACCESS_DENIED
                    break
                #if "ERROR: Linux route" in line:
                    # state = connection_status.ROUTE_FAILED
                    # This tests for a Linux route failure, only it's commented out as
                    # it can legitimately fail if the route already exists.  If it fails
                    # for other reasons, I can't tell the different just yet.
                    # break
            log.close()
            # Haven't found what's expected so return an empty stream
            if not state == connection_status.UNKNOWN: debugTrace("VPN connection status is " + str(state))
            return state
        else:
            errorTrace("platform.py", "Tried to get VPN connection status but log file didn't exist")
            return connection_status.ERROR
Пример #8
0
def getGitMetaData(vpn_provider):
    try:
        # Download the update time stamp and list of files available
        download_url = "https://raw.githubusercontent.com/Zomboided/service.vpn.manager.providers/master/" + vpn_provider + "/METADATA.txt"
        download_url = download_url.replace(" ", "%20")
        return urllib2.urlopen(download_url)
    except Exception as e:
        # Can't get the list so return null
        errorTrace("vpnproviders.py", "Can't get the metadata from Github for " + vpn_provider)
        errorTrace("vpnproviders.py", str(e))
        return None
Пример #9
0
def getipstack(json_data):
    try:
        ip = json_data["ip"]
        country = json_data["country_name"]
        region = json_data["region_name"]
        city = json_data["city"]       
        return ip, country, region, city, "Unknown"
    except Exception as e:
        errorTrace("ipinfo.py", "Couldn't parse JSON data " + str(json_data))
        errorTrace("ipinfo.py", str(e))
        return None, None, None, None, None 
Пример #10
0
def fakeItTillYouMakeIt(fake):
    try:
        if fake:
            if not fakeConnection():
                f = open(getUserDataPath(fake_name),'w')
                f.close()
        else:
            if fakeConnection():
                xbmcvfs.delete(getUserDataPath(fake_name))
    except Exception as e:
        errorTrace("platform.py", "fakeItTillYouMakeIt " + str(fake) + " failed")
        errorTrace("platform.py", str(e))
Пример #11
0
def getIPAPI(json_data):
    try:
        ip = json_data["query"]
        country = json_data["country"]
        region = json_data["regionName"]
        city = json_data["city"]
        isp = json_data["isp"]        
        return ip, country, region, city, isp
    except Exception as e:
        errorTrace("ipinfo.py", "Couldn't parse JSON data " + str(json_data))
        errorTrace("ipinfo.py", str(e))
        return None, None, None, None, None               
Пример #12
0
def getGitMetaData(vpn_provider):
    try:
        # Download the update time stamp and list of files available
        debugTrace("Getting git metadata for " + vpn_provider)
        download_url = "https://raw.githubusercontent.com/Zomboided/service.vpn.manager.providers/master/" + vpn_provider + "/METADATA.txt"
        download_url = download_url.replace(" ", "%20")
        return urllib2.urlopen(download_url)
    except Exception as e:
        # Can't get the list so return null
        errorTrace("vpnproviders.py", "Can't get the metadata from Github for " + vpn_provider)
        errorTrace("vpnproviders.py", str(e))
        return None
Пример #13
0
def fakeItTillYouMakeIt(fake):
    try:
        if fake:
            if not fakeConnection():
                f = open(getUserDataPath(fake_name),'w')
                f.close()
        else:
            if fakeConnection():
                xbmcvfs.delete(getUserDataPath(fake_name))
    except Exception as e:
        errorTrace("platform.py", "fakeItTillYouMakeIt " + str(fake) + " failed")
        errorTrace("platform.py", str(e))
Пример #14
0
def getIPAPI(json_data):
    try:
        ip = json_data["query"]
        country = json_data["country"]
        region = json_data["regionName"]
        city = json_data["city"]
        isp = json_data["isp"]        
        return ip, country, region, city, isp
    except Exception as e:
        errorTrace("ipinfo.py", "Couldn't parse JSON data " + str(json_data))
        errorTrace("ipinfo.py", str(e))
        return None, None, None, None, None               
Пример #15
0
def writeVPNLog():
    # Write the openvpn output log to the error file
    try:
        log_file = open(getVPNLogFilePath(), 'r')
        log_output = log_file.readlines()
        log_file.close()
        infoTrace("platform.py", "VPN log file start >>>")
        for line in log_output:
            infoPrint(line)
        infoTrace("platform.py", "<<< VPN log file end")
    except Exception as e:
        errorTrace("platform.py", "Couldn't write VPN error log")
        errorTrace("platform.py", str(e))
Пример #16
0
def writeVPNLog():
    # Write the openvpn output log to the error file
    try:
        log_file = open(getVPNLogFilePath(), 'r')
        log_output = log_file.readlines()
        log_file.close()
        infoTrace("platform.py", "VPN log file start >>>")
        for line in log_output:
            infoPrint(line)
        infoTrace("platform.py", "<<< VPN log file end")
    except Exception as e:
        errorTrace("platform.py", "Couldn't write VPN error log")
        errorTrace("platform.py", str(e))
Пример #17
0
def writeTestFile():
    # Write the command test output to the error file
    try:
        log_file = open(getTestFilePath(), 'r')
        log_output = log_file.readlines()
        log_file.close()
        infoTrace("platform.py", "Command test file start >>>")
        for line in log_output:
            infoPrint(line)
        infoTrace("platform.py", "<<< Command test file end")
    except Exception as e:
        errorTrace("platform.py", "Couldn't write test file")
        errorTrace("platform.py", str(e))        
Пример #18
0
def writeTestFile():
    # Write the command test output to the error file
    try:
        log_file = open(getTestFilePath(), 'r')
        log_output = log_file.readlines()
        log_file.close()
        infoTrace("platform.py", "Command test file start >>>")
        for line in log_output:
            infoPrint(line)
        infoTrace("platform.py", "<<< Command test file end")
    except Exception as e:
        errorTrace("platform.py", "Couldn't write test file")
        errorTrace("platform.py", str(e))
Пример #19
0
def getIPInfoFrom(source):
    # Generate request to find out where this IP is based
    # Successful return is ip, country, region, city, isp
    # No info generated from call is "no info", "unknown", "unknown", "unknown", url response
    # Or general error is "error", "error", "error", reason, url response
    link = ""
    try:
        # Determine the URL, make the call and read the response
        url = getIPSourceURL(source)
        if url == "": return "error", "error", "error", "unknown source", ""
        req = urllib2.Request(url)
        req.add_header(
            "User-Agent",
            "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0"
        )
        response = urllib2.urlopen(req, timeout=10)
        link = response.read()
        response.close()
    except Exception as e:
        errorTrace("ipinfo.py", "Couldn't connect to IP provider " + source)
        errorTrace("ipinfo.py", str(e))
        recordError(source)
        return "error", "error", "error", "call failed", link

    try:
        # This makes stupid regex easier
        link = link.replace("\n", "")
        debugTrace("IP provider " + source + " returned " + link)
        # Call the right routine to parse the reply using regex
        # These all return JSON so probably a JSON parser should really be used
        if source == "ipinfo.io": match = getipinfo(link)
        if source == "IP-API": match = getIPAPI(link)
        if source == "freegeoip.net": match = getFreeGeoIP(link)

        if not match == None:
            recordWorking(source)
            for ip, country, region, city, isp in match:
                return ip, country, region, city, isp
        else:
            errorTrace(
                "ipinfo.py",
                "No matches found for IP provider " + "source" + " " + link)
            recordError(source)
            return "no info", "unknown location", "unknown location", "no matches", link
    except Exception as e:
        errorTrace(
            "ipinfo.py",
            "Couldn't parse response from IP provider " + source + " " + link)
        errorTrace("ipinfo.py", str(e))
        recordError(source)
        return "error", "error", "error", "parse failed", link
Пример #20
0
def writeKeyPass(key_pass_name, password):   
    # Return the password being used for a given key file
    try:
        if xbmcvfs.exists(key_pass_name):
            xbmcvfs.delete(key_pass_name)
        debugTrace("Writing key password file " + key_pass_name)
        pass_file = open(key_pass_name, 'w')
        pass_file.write(password)
        pass_file.close()
        return True
    except Exception as e:
        errorTrace("vpnproviders.py", "Failed to write key password file to userdata")
        errorTrace("vpnproviders.py", str(e))
        return False
Пример #21
0
def writeKeyPass(key_pass_name, password):   
    # Return the password being used for a given key file
    try:
        if xbmcvfs.exists(key_pass_name):
            xbmcvfs.delete(key_pass_name)
        debugTrace("Writing key password file " + key_pass_name)
        pass_file = open(key_pass_name, 'w')
        pass_file.write(password)
        pass_file.close()
        return True
    except Exception as e:
        errorTrace("vpnproviders.py", "Failed to write key password file to userdata")
        errorTrace("vpnproviders.py", str(e))
        return False
Пример #22
0
def populateSupportingFromGit(vpn_provider):
    # Copy all files from download to the directory that are not .ovpn, ignoring the metadata
    try:
        filelist = getDownloadList(vpn_provider, "*")
        debugTrace("Copying supporting files into addon directory for " + vpn_provider)
        for file in filelist:
            if not file.endswith(".ovpn") and not file.endswith("METADATA.txt"):
                name = os.path.basename(file)
                fullname = getAddonPath(True, vpn_provider + "/" + name)
                xbmcvfs.copy(file, fullname)
                if not xbmcvfs.exists(fullname): raise IOError('Failed to copy supporting file ' + file + " to " + fullname)
        return True
    except Exception as e:
        errorTrace("vpnproviders.py", "Can't copy " + file + " for VPN " + vpn_provider)
        errorTrace("vpnproviders.py", str(e))
        return False
Пример #23
0
def populateSupportingFromGit(vpn_provider):
    # Copy all files from download to the directory that are not .ovpn, ignoring the metadata
    try:
        filelist = getDownloadList(vpn_provider, "*")
        debugTrace("Copying supporting files into addon directory for " + vpn_provider)
        for file in filelist:
            if not file.endswith(".ovpn") and not file.endswith("METADATA.txt"):
                name = os.path.basename(file)
                fullname = getAddonPath(True, vpn_provider + "/" + name)
                xbmcvfs.copy(file, fullname)
                if not xbmcvfs.exists(fullname): raise IOError('Failed to copy supporting file ' + file + " to " + fullname)
        return True
    except Exception as e:
        errorTrace("vpnproviders.py", "Can't copy " + file + " for VPN " + vpn_provider)
        errorTrace("vpnproviders.py", str(e))
        return False
Пример #24
0
def popupSysBox():
    if not getID() == "":
        addon = xbmcaddon.Addon(getID())
        dialog_text_l = ""
        dialog_text_r = ""
        data_left = getSystemData(addon, True, True, False, False)
        data_right = getSystemData(addon, False, False, False, True)
        for line in data_left:
            if line.startswith("[B]") and not dialog_text_l == "": dialog_text_l = dialog_text_l + "\n"
            dialog_text_l = dialog_text_l + line + "\n"
        for line in data_right:
            if line.startswith("[B]") and not dialog_text_r == "": dialog_text_r = dialog_text_r + "\n"
            dialog_text_r = dialog_text_r + line + "\n"    
        showInfoBox("System Information", dialog_text_l, dialog_text_r)
    else:
        errorTrace("sysbox.py", "VPN service is not ready")
Пример #25
0
def clearUserData():
    # Deleting everything here, but not deleting 'DEFAULT.txt' as
    # any existing user and password info will get deleted
    path = getUserDataPath("UserDefined" + "/*.*")
    debugTrace("Deleting contents of User Defined directory" + path)
    files = glob.glob(path)
    try:
        for file in files:
            if not file.endswith("DEFAULT.txt") and xbmcvfs.exists(file):
                debugTrace("Deleting " + file)
                xbmcvfs.delete(file)
    except Exception as e:
        errorTrace("import.py", "Couldn't clear the UserDefined directory")
        errorTrace("import.py", str(e))
        return False
    return True
Пример #26
0
def clearUserData():
    # Deleting everything here, but not deleting 'DEFAULT.txt' as 
    # any existing user and password info will get deleted
    path = getUserDataPath("UserDefined" + "/*.*")
    debugTrace("Deleting contents of User Defined directory" + path)
    files = glob.glob(path)
    try:
        for file in files:
            if not file.endswith("DEFAULT.txt") and xbmcvfs.exists(file): 
                debugTrace("Deleting " + file)
                xbmcvfs.delete(file)
    except Exception as e:
        errorTrace("import.py", "Couldn't clear the UserDefined directory")
        errorTrace("import.py", str(e))
        return False
    return True
Пример #27
0
def popupSysBox():
    if not getID() == "":
        addon = xbmcaddon.Addon(getID())
        dialog_text_l = ""
        dialog_text_r = ""
        data_left = getSystemData(addon, True, True, False, False)
        data_right = getSystemData(addon, False, False, False, True)
        for line in data_left:
            if line.startswith("[B]") and not dialog_text_l == "":
                dialog_text_l = dialog_text_l + "\n"
            dialog_text_l = dialog_text_l + line + "\n"
        for line in data_right:
            if line.startswith("[B]") and not dialog_text_r == "":
                dialog_text_r = dialog_text_r + "\n"
            dialog_text_r = dialog_text_r + line + "\n"
        showInfoBox("System Information", dialog_text_l, dialog_text_r)
    else:
        errorTrace("sysbox.py", "VPN service is not ready")
Пример #28
0
def writeVPNConfiguration(ovpn):
    # Write the openvpn configuration to the error file
    try:
        if xbmcvfs.exists(ovpn):
            ovpn_file = open(ovpn, 'r')
            ovpn_output = ovpn_file.readlines()
            ovpn_file.close()
            infoTrace("vpnplatform.py",
                      "VPN configuration " + ovpn + " start >>>")
            for line in ovpn_output:
                infoPrint(line)
            infoTrace("vpnplatform.py", "<<< VPN configuration file end")
        else:
            infoTrace("vpnplatform.py",
                      "No VPN configuration " + ovpn + " exists to write")
    except Exception as e:
        errorTrace("vpnplatform.py", "Couldn't write VPN error log")
        errorTrace("vpnplatform.py", str(e))
Пример #29
0
def checkPidofCommand(addon):
    # Disable this for now as kodi.bin may not exist on all systems
    return True
    # Only necessary with Linux, sees if pidof is installed/working
    p = getPlatform()
    if p == platforms.RPI or p == platforms.LINUX:
        # Issue Linux command
        command = getPidofPath() + " kodi.bin > " + getTestFilePath(
        ) + " 2>&1 &"
        if useSudo(): command = "sudo " + command
        infoTrace("platform.py", "Testing pidof with : " + command)
        os.system(command)
    else:
        return True

    # Waiting for the log file to appear
    xbmc.sleep(1000)
    i = 0
    while not xbmcvfs.exists(getTestFilePath()) and i < 10:
        xbmc.sleep(1000)
        i = i + 1
    # If the log file appears, check it's what we expect
    if xbmcvfs.exists(getTestFilePath()):
        log_file = open(getTestFilePath(), 'r')
        log_file_lines = log_file.readlines()
        log_file.close()
        # If this worked, the first line should be a number
        for line in log_file_lines:
            line = line.strip()
            if line.isdigit():
                deleteTestFile()
                return True
        # Write the log file in case there's something in it
        errorTrace("platform.py", "Ran pidof command and it failed")
        writeTestFile()
        dialog_msg = "The command 'pidof' is required to run this add-on.  Please install it and ensure it's available on the command path."
    else:
        errorTrace("platform.py",
                   "Ran pidof command and the log didn't appear")
        dialog_msg = "The 'pidof' command isn't writing out a response.  Try changing the Kodi log directory setting in Settings-Debug menu and retry."

    # Display an error message
    xbmcgui.Dialog().ok(addon.getAddonInfo("name"), dialog_msg)
    return False
Пример #30
0
def getIPInfoFrom(source):
    # Generate request to find out where this IP is based
    # Successful return is ip, country, region, city, isp 
    # No info generated from call is "no info", "unknown", "unknown", "unknown", url response
    # Or general error is "error", "error", "error", reason, url response
    link = ""
    try:
        # Determine the URL, make the call and read the response
        url = getIPSourceURL(source)
        if url == "": return "error", "error", "error", "unknown source", ""
        req = urllib2.Request(url)
        req.add_header("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0")
        response = urllib2.urlopen(req, timeout = 10)
        link = response.read()
        response.close()
    except Exception as e:
        errorTrace("ipinfo.py", "Couldn't connect to IP provider " + source)
        errorTrace("ipinfo.py", str(e))
        recordError(source)
        return "error", "error", "error", "call failed", link
        
    try:
        # This makes stupid regex easier
        link = link.replace("\n","")
        debugTrace("IP provider " + source + " returned " + link)
        # Call the right routine to parse the reply using regex
        # These all return JSON so probably a JSON parser should really be used
        if source == "ipinfo.io": match = getipinfo(link)
        if source == "IP-API": match = getIPAPI(link)
        if source == "freegeoip.net": match = getFreeGeoIP(link)
        
        if not match == None:
            recordWorking(source)
            for ip, country, region, city, isp in match:
                return ip, country, region, city, isp
        else:
            errorTrace("ipinfo.py", "No matches found for IP provider " + "source" + " " + link)
            recordError(source)
            return "no info", "unknown location", "unknown location", "no matches", link
    except Exception as e:
        errorTrace("ipinfo.py", "Couldn't parse response from IP provider " + source + " " + link)
        errorTrace("ipinfo.py", str(e))
        recordError(source)
        return "error", "error", "error", "parse failed", link
Пример #31
0
def copySystemdFiles():
    # Delete any existing openvpn.service and copy openvpn service file to config directory
    service_source = getAddonPath(True, "openvpn.service")
    service_dest = getSystemdPath("system.d/openvpn.service")
    debugTrace("Copying openvpn.service " + service_source + " to " + service_dest)
    if not fakeSystemd():
        if xbmcvfs.exists(service_dest): xbmcvfs.delete(service_dest)
        xbmcvfs.copy(service_source, service_dest)
        if not xbmcvfs.exists(service_dest): raise IOError('Failed to copy service ' + service_source + " to " + service_dest)
    
    # Delete any existing openvpn.config and copy first VPN to openvpn.config
    config_source = sudo_setting = xbmcaddon.Addon("service.vpn.manager").getSetting("1_vpn_validated")
    if service_source == "": errorTrace("platform.py", "Nothing has been validated")
    config_dest = getSystemdPath("openvpn.config")
    debugTrace("Copying openvpn.config " + config_source + " to " + config_dest)
    if not fakeSystemd():
        if xbmcvfs.exists(config_dest): xbmcvfs.delete(config_dest)
        xbmcvfs.copy(config_source, config_dest)
        if not xbmcvfs.exists(config_dest): raise IOError('Failed to copy service ovpn ' + config_source + " to " + config_dest)
Пример #32
0
def checkPidofCommand(addon):
    # Disable this for now as kodi.bin may not exist on all systems
    return True
    # Only necessary with Linux, sees if pidof is installed/working
    p = getPlatform()
    if p == platforms.RPI or p == platforms.LINUX:
        # Issue Linux command
        command = getPidofPath() + " kodi.bin > " + getTestFilePath() + " 2>&1 &"
        if useSudo() : command = "sudo " + command
        infoTrace("platform.py", "Testing pidof with : " + command)
        os.system(command)
    else:
        return True
        
    # Waiting for the log file to appear            
    xbmc.sleep(1000)
    i = 0
    while not xbmcvfs.exists(getTestFilePath()) and i < 10:
        xbmc.sleep(1000)
        i = i + 1
    # If the log file appears, check it's what we expect
    if xbmcvfs.exists(getTestFilePath()):
        log_file = open(getTestFilePath(), 'r')
        log_file_lines = log_file.readlines()
        log_file.close()
        # If this worked, the first line should be a number
        for line in log_file_lines:
            line = line.strip()
            if line.isdigit():
                deleteTestFile()
                return True
        # Write the log file in case there's something in it
        errorTrace("platform.py", "Ran pidof command and it failed")            
        writeTestFile()
        dialog_msg = "The command 'pidof' is required to run this add-on.  Please install it and ensure it's available on the command path."
    else:
        errorTrace("platform.py", "Ran pidof command and the log didn't appear")
        dialog_msg = "The 'pidof' command isn't writing out a response.  Try changing the Kodi log directory setting in Settings-Debug menu and retry."
    
    # Display an error message
    xbmcgui.Dialog().ok(addon.getAddonInfo("name"), dialog_msg)
    return False
Пример #33
0
def checkKillallCommand(addon):
    # Only necessary with Linux, sees if killall is installed/working
    p = getPlatform()
    if p == platforms.RPI or p == platforms.LINUX:
        # Issue Linux command
        command = getKillallPath() + " vpnmanagertest > " + getTestFilePath(
        ) + " 2>&1 &"
        if useSudo(): command = "sudo " + command
        infoTrace("platform.py", "Testing killall with : " + command)
        os.system(command)
    else:
        return True

    # Waiting for the log file to appear
    xbmc.sleep(1000)
    i = 0
    while not xbmcvfs.exists(getTestFilePath()) and i < 10:
        xbmc.sleep(1000)
        i = i + 1
    # If the log file appears, check it's what we expect
    if xbmcvfs.exists(getTestFilePath()):
        log_file = open(getTestFilePath(), 'r')
        log_file_lines = log_file.readlines()
        log_file.close()
        # Look for a phrase we'd expect to see if the call
        # worked and a killall error message was displayed
        for line in log_file_lines:
            if "vpnmanagertest" in line:
                deleteTestFile()
                return True
        # Write the log file in case there's something in it
        errorTrace("platform.py", "Ran killall command and it failed")
        writeTestFile()
        dialog_msg = "The command 'killall' is required to run this add-on.  Please install it and ensure it's available on the command path."
    else:
        errorTrace("platform.py",
                   "Ran killall command and the log didn't appear")
        dialog_msg = "The 'killall' command isn't writing out a response.  Try changing the Kodi log directory setting in Settings-Debug menu and retry."

    # Display an error message
    xbmcgui.Dialog().ok(addon.getAddonInfo("name"), dialog_msg)
    return False
Пример #34
0
def copyUserDefinedFiles():
    # Copy everything in the user directory to the addon directory
    infoTrace("vpnproviders.py",
              "Copying user defined files from userdata directory")
    source_path = getUserDataPath((user_def_str) + "/")
    dest_path = getAddonPath(True, user_def_str + "/")
    # Get the list of connection profiles and another list of strings to abuse for the selection screen
    try:
        files = getUserDataList(user_def_str, "*")
        if len(files) == 0:
            errorTrace(
                "vpnproviders.py",
                "No User Defined files available to copy from " + source_path)
            return False
        for file in files:
            name = file[file.rfind(getSeparator()) + 1:]
            dest_file = dest_path + getSeparator() + name
            xbmcvfs.copy(file, dest_file)
            if not xbmcvfs.exists(dest_file):
                raise IOError('Failed to copy user def file ' + file + " to " +
                              dest_file)
        return True
    except Exception as e:
        errorTrace(
            "vpnproviders.py",
            "Error copying files from " + source_path + " to " + dest_path)
        errorTrace("vpnproviders.py", str(e))
        return False
Пример #35
0
def checkKillallCommand(addon):
    # Only necessary with Linux, sees if killall is installed/working
    p = getPlatform()
    if p == platforms.RPI or p == platforms.LINUX:
        # Issue Linux command
        command = getKillallPath() + " vpnmanagertest > " + getTestFilePath() + " 2>&1 &"
        if useSudo() : command = "sudo " + command
        infoTrace("platform.py", "Testing killall with : " + command)
        os.system(command)
    else:
        return True
        
    # Waiting for the log file to appear            
    xbmc.sleep(1000)
    i = 0
    while not xbmcvfs.exists(getTestFilePath()) and i < 10:
        xbmc.sleep(1000)
        i = i + 1
    # If the log file appears, check it's what we expect
    if xbmcvfs.exists(getTestFilePath()):
        log_file = open(getTestFilePath(), 'r')
        log_file_lines = log_file.readlines()
        log_file.close()
        # Look for a phrase we'd expect to see if the call
        # worked and a killall error message was displayed
        for line in log_file_lines:
            if "vpnmanagertest" in line:
                deleteTestFile()
                return True
        # Write the log file in case there's something in it
        errorTrace("platform.py", "Ran killall command and it failed")            
        writeTestFile()
        dialog_msg = "The command 'killall' is required to run this add-on.  Please install it and ensure it's available on the command path."
    else:
        errorTrace("platform.py", "Ran killall command and the log didn't appear")
        dialog_msg = "The 'killall' command isn't writing out a response.  Try changing the Kodi log directory setting in Settings-Debug menu and retry."
    
    # Display an error message
    xbmcgui.Dialog().ok(addon.getAddonInfo("name"), dialog_msg)
    return False
Пример #36
0
def checkVPNCommand(addon):
    # Issue the openvpn command and see if the output is a bunch of commands
    if not fakeConnection():
        p = getPlatform()
        # Issue the openvpn command, expecting to get the options screen back
        if p == platforms.RPI or p == platforms.LINUX:
            # Issue Linux command
            command = getOpenVPNPath() + " > " + getVPNLogFilePath(
            ) + " 2>&1 &"
            if useSudo(): command = "sudo " + command
            infoTrace("platform.py", "Testing openvpn with : " + command)
            os.system(command)
        elif p == platforms.WINDOWS:
            # Issue Windows command
            command = getOpenVPNPath()
            infoTrace("platform.py", "Testing openvpn with : " + command)
            args = shlex.split(command)
            outfile = open(getVPNLogFilePath(), 'w')
            proc = subprocess.Popen(args,
                                    stdout=outfile,
                                    creationflags=subprocess.SW_HIDE,
                                    shell=True)
        else:
            errorTrace("platform.py", "Unsupported platform " + str(p))

        # **** ADD MORE PLATFORMS HERE ****

        # Waiting for the log file to appear
        xbmc.sleep(1000)
        i = 0
        while not xbmcvfs.exists(getVPNLogFilePath()) and i < 10:
            xbmc.sleep(1000)
            i = i + 1
        # If the log file appears, check it's what we expect
        if xbmcvfs.exists(getVPNLogFilePath()):
            log_file = open(getVPNLogFilePath(), 'r')
            log_file_lines = log_file.readlines()
            log_file.close()
            # Look for a phrase we'd expect to see if the call
            # worked and the list of options was displayed
            for line in log_file_lines:
                if "General Options" in line:
                    return True
            # Write the log file in case there's something in it
            errorTrace("platform.py", "Ran openvpn command and it failed")
            writeVPNLog()
            dialog_msg = "The OpenVPN executable isn't working.  Check the log, then from a command line prompt type 'openvpn' and fix any problems reported."
        else:
            errorTrace("platform.py",
                       "Ran openvpn command and VPN log didn't appear")
            dialog_msg = "The OpenVPN executable isn't writing out a log.  Try changing the Kodi log directory setting in Settings-Debug menu and retry."

        # Display an error message
        xbmcgui.Dialog().ok(addon.getAddonInfo("name"), dialog_msg)
        return False

    else:
        return True
Пример #37
0
def isVPNTaskRunning():
    # Return True if the VPN task is still running, or the VPN connection is still active
    # Return False if the VPN task is no longer running and the connection is not active

    if fakeConnection(): return True

    p = getPlatform()
    if p == platforms.LINUX or p == platforms.RPI:
        try:
            command = "pidof openvpn"
            if useSudo(): command = "sudo " + command
            debugTrace("(Linux) Checking VPN task with " + command)
            pid = os.system(command)
            # This horrible call returns 0 if it finds a process, it's not returning the PID number
            if xbmcaddon.Addon("service.vpn.manager").getSetting(
                    "alt_pid_check") == "true":
                if pid > 0: return True
            else:
                if pid == 0: return True
            debugTrace("(Linux) Didn't find a running process")
            return False
        except Exception as e:
            errorTrace("platform.py", "VPN task list failed")
            errorTrace("platform.py", str(e))
            return False
    if p == platforms.WINDOWS:
        try:
            command = 'tasklist /FI "IMAGENAME eq OPENVPN.EXE"'
            debugTrace("(Windows) Checking VPN task with " + command)
            args = shlex.split(command)
            out = subprocess.check_output(args,
                                          creationflags=subprocess.SW_HIDE,
                                          shell=True).strip()
            if "openvpn.exe" in out:
                return True
            else:
                debugTrace("(Windows) Didn't find a running process")
                return False
        except Exception as e:
            errorTrace("platform.py", "VPN task list failed")
            errorTrace("platform.py", str(e))
            return False

    # **** ADD MORE PLATFORMS HERE ****

    return False
Пример #38
0
def startVPN(vpn_profile):
    # Call the platform VPN to start the VPN

    # Remove the log file to avoid reading out of date info
    log_file = getVPNLogFilePath()
    try:
        if xbmcvfs.exists(log_file):
            xbmcvfs.delete(log_file)
            xbmc.sleep(500)
            i = 0
            while xbmcvfs.exists(log_file) and i < 10:
                xbmc.sleep(1000)
                i = i + 1
            if i == 10:
                errorTrace(
                    "vpnplatform.py", "Tried to delete VPN log file " +
                    log_file + " and it didn't go after 10 seconds")
            else:
                debugTrace("Deleted the VPN log file " + log_file +
                           " before starting a new connection")
        else:
            debugTrace("No VPN log file " + log_file +
                       " exists to be deleted before starting connection")
    except Exception as e:
        errorTrace(
            "vpnplatform.py",
            "Something bad happened trying to delete the existing VPN log file"
        )
        errorTrace("common.py", str(e))

    # Even if something bad has happened with the log file, we're going to try to start the VPN anyway...
    if not fakeConnection():
        p = getPlatform()
        if p == platforms.RPI or p == platforms.LINUX:
            command = getOpenVPNPath(
            ) + " \"" + vpn_profile + "\" > " + log_file + " 2>&1 &"
            if useSudo(): command = "sudo " + command
            debugTrace("(Linux) Starting VPN with " + command)
            os.system(command)
        if p == platforms.WINDOWS:
            command = getOpenVPNPath() + " \"" + vpn_profile + "\""
            debugTrace("(Windows) Starting VPN with " + command)
            args = shlex.split(command)
            outfile = open(log_file, 'w')
            proc = subprocess.Popen(args,
                                    stdout=outfile,
                                    creationflags=subprocess.SW_HIDE,
                                    shell=True)

        # **** ADD MORE PLATFORMS HERE ****

    else:
        # This bit is just to help with debug during development.
        command = getOpenVPNPath() + " \"" + vpn_profile + "\" > " + log_file
        debugTrace("Faking starting VPN with " + command)
    return
Пример #39
0
def isVPNTaskRunning():
    # Return True if the VPN task is still running, or the VPN connection is still active
    # Return False if the VPN task is no longer running and the connection is not active
    
    if fakeConnection(): return True
    
    p = getPlatform()
    if p == platforms.LINUX or p == platforms.RPI:
        try:
            command = "pidof openvpn"
            if useSudo() : command = "sudo " + command
            debugTrace("(Linux) Checking VPN task with " + command)
            pid = os.system(command)
            # This horrible call returns 0 if it finds a process, it's not returning the PID number
            if xbmcaddon.Addon("service.vpn.manager").getSetting("alt_pid_check") == "true":
                if pid > 0 : return True
            else:
                if pid == 0 : return True
            debugTrace("(Linux) Didn't find a running process")
            return False
        except Exception as e:
            errorTrace("platform.py", "VPN task list failed")
            errorTrace("platform.py", str(e))
            return False
    if p == platforms.WINDOWS:
        try:
            command = 'tasklist /FI "IMAGENAME eq OPENVPN.EXE"'
            debugTrace("(Windows) Checking VPN task with " + command)
            args = shlex.split(command)
            out = subprocess.check_output(args, creationflags=subprocess.SW_HIDE, shell=True).strip()
            if "openvpn.exe" in out:
                return True
            else:
                debugTrace("(Windows) Didn't find a running process")
                return False
        except Exception as e:
            errorTrace("platform.py", "VPN task list failed")
            errorTrace("platform.py", str(e))
            return False

    # **** ADD MORE PLATFORMS HERE ****
    
    return False
Пример #40
0
def checkVPNCommand(addon):
    # Issue the openvpn command and see if the output is a bunch of commands
    if not fakeConnection():
        p = getPlatform()
        # Issue the openvpn command, expecting to get the options screen back
        if p == platforms.RPI or p == platforms.LINUX:
            # Issue Linux command
            command = getOpenVPNPath() + " > " + getVPNLogFilePath() + " &"
            if useSudo() : command = "sudo " + command
            infoTrace("platform.py", "Testing openvpn with : " + command)
            os.system(command)
        elif p == platforms.WINDOWS:
            # Issue Windows command
            command=getOpenVPNPath()
            infoTrace("platform.py", "Testing openvpn with : " + command)
            args = shlex.split(command)
            outfile = open(getVPNLogFilePath(),'w')
            proc = subprocess.Popen(args, stdout=outfile, creationflags=subprocess.SW_HIDE, shell=True)
        else:
            errorTrace("platform.py", "Unsupported platform " + str(p))
            
        # **** ADD MORE PLATFORMS HERE ****
                
        # Waiting for the log file to appear            
        xbmc.sleep(1000)
        i = 0
        while not xbmcvfs.exists(getVPNLogFilePath()) and i < 10:
            xbmc.sleep(1000)
            i = i + 1
        # If the log file appears, check it's what we expect
        if xbmcvfs.exists(getVPNLogFilePath()):
            log_file = open(getVPNLogFilePath(), 'r')
            log_file_lines = log_file.readlines()
            log_file.close()
            # Look for a phrase we'd expect to see if the call
            # worked and the list of options was displayed
            for line in log_file_lines:
                if "General Options" in line:
                    return True
            # Write the log file in case there's something in it
            errorTrace("platform.py", "Ran openvpn command and it failed")            
            writeVPNLog()
            dialog_msg = "The OpenVPN executable isn't working.  Check the log, then from a command line prompt type 'openvpn' and fix any problems reported."
        else:
            errorTrace("platform.py", "Ran openvpn command and VPN log didn't appear")
            dialog_msg = "The OpenVPN executable isn't writing out a log.  Try changing the Kodi log directory setting in Settings-Debug menu and retry."
        
        # Display an error message
        xbmcgui.Dialog().ok(addon.getAddonInfo("name"), dialog_msg)
        return False
        
    else: return True
Пример #41
0
def copyUserDefinedFiles():    
    # Copy everything in the user directory to the addon directory
    infoTrace("vpnproviders.py", "Copying user defined files from userdata directory")
    source_path = getUserDataPath((user_def_str)+"/")
    dest_path = getAddonPath(True, user_def_str + "/")
    # Get the list of connection profiles and another list of strings to abuse for the selection screen    
    try:
        files = getUserDataList(user_def_str, "*")
        if len(files) == 0:
            errorTrace("vpnproviders.py", "No User Defined files available to copy from " + source_path)
            return False
        for file in files:
            name = file[file.rfind(getSeparator())+1:]
            dest_file = dest_path + getSeparator() + name
            xbmcvfs.copy(file, dest_file)
            if not xbmcvfs.exists(dest_file): raise IOError('Failed to copy user def file ' + file + " to " + dest_file)
        return True
    except Exception as e:
        errorTrace("vpnproviders.py", "Error copying files from " + source_path + " to " + dest_path)
        errorTrace("vpnproviders.py", str(e))
        return False
Пример #42
0
def refreshFromGit(vpn_provider, progress):
    addon = xbmcaddon.Addon("service.vpn.manager")
    infoTrace(
        "vpnproviders.py", "Checking downloaded ovpn files for " +
        vpn_provider + " with GitHub files")
    progress_title = "Updating files for " + vpn_provider
    try:
        # Create the download directories if required
        path = getUserDataPath("Downloads/")
        if not xbmcvfs.exists(path): xbmcvfs.mkdir(path)
        path = getUserDataPath("Downloads/" + vpn_provider + "/")
        if not xbmcvfs.exists(path): xbmcvfs.mkdir(path)
    except Exception as e:
        # Can't create the download directory
        errorTrace("vpnproviders.py",
                   "Can't create the download directory " + path)
        errorTrace("vpnproviders.py", str(e))
        return False

    # Download the metadata file
    metadata = getGitMetaData(vpn_provider)
    if metadata == None: return False
    git_timestamp, version, total_files, file_list = parseGitMetaData(metadata)
    timestamp = ""

    try:
        addon_version = int(
            addon.getSetting("version_number").replace(".", ""))
    except:
        addon_version = int(addon.getAddonInfo("version").replace(".", ""))
    if addon_version < int(version):
        errorTrace(
            "vpnproviders.py", "VPN Manager version is " + str(addon_version) +
            " and version " + version + " is needed for this VPN.")
        return False

    try:
        # Get the timestamp from the previous update
        last_file = open(
            getUserDataPath("Downloads" + "/" + vpn_provider +
                            "/METADATA.txt"), 'r')
        last = last_file.readlines()
        last_file.close()
        # If there's a metadata file in the user directory but we had a problem with Github, just
        # return True as there's a likelihood that there's something interesting to work with
        if file_list is None:
            if progress is not None:
                progress_message = "Unable to download files, using existing files."
                progress.update(10, progress_title, progress_message)
                infoTrace(
                    "vpnproviders.py",
                    "Couldn't download files so using existing files for " +
                    vpn_provider)
                xbmc.sleep(1000)
            return True
        timestamp = last[0]
    except Exception as e:
        # If the metadata can't be read and there's nothing we can get from Github, return
        # badness, otherwise we can read from Github and should just carry on.
        if file_list is None:
            errorTrace(
                "vpnproviders.py",
                "Couldn't download any files from Github for " + vpn_provider)
            return False

    # Check the timestamp and if it's not the same clear out the directory for new files
    if timestamp == git_timestamp:
        debugTrace("VPN provider " + vpn_provider +
                   " up to date, timestamp is " + git_timestamp)
        if progress is not None:
            progress_message = "VPN provider files don't need updating"
            progress.update(10, progress_title, progress_message)
            xbmc.sleep(500)
        return True
    else:
        timestamp = git_timestamp
    debugTrace("VPN provider " + vpn_provider +
               " needs updating, deleting existing files")
    # Clear download files for this VPN
    existing = glob.glob(
        getUserDataPath("Downloads" + "/" + vpn_provider + "/*.*"))
    for file in existing:
        try:
            xbmcvfs.delete(file)
        except:
            pass

    # Download and store the updated files
    error_count = 0
    file_count = 0
    progress_count = float(1)
    progress_inc = float(99 / float(total_files))
    for file in file_list:
        try:
            #debugTrace("Downloading " + file)
            if progress is not None:
                progress_count += progress_inc
                if progress.iscanceled(): return False
                progress_message = "Downloading " + file
                progress.update(int(progress_count), progress_title,
                                progress_message)
            download_url = "https://raw.githubusercontent.com/Zomboided/service.vpn.manager.providers/master/" + vpn_provider + "/" + file
            download_url = download_url.replace(" ", "%20")
            git_file = urllib2.urlopen(download_url)
            file = file.strip(' \n')
            output = open(
                getUserDataPath("Downloads" + "/" + vpn_provider + "/" + file),
                'w')
            for line in git_file:
                output.write(line)
            output.close()
        except Exception as e:
            errorTrace("vpnproviders.py", "Can't download " + file)
            errorTrace("vpnproviders.py", str(e))
            error_count += 1
            # Bail after 5 failures as it's likely something bad is happening.  Don't fail
            # immediately because it could just be an error with one or two locations
            if error_count > 5: return False
        # Uncomment the next line to make testing NordVPN download easier....
        # if file_count == 20: break
        file_count += 1
    debugTrace("Processed " + str(file_count) + " files for " + vpn_provider)

    # Write the update timestamp
    debugTrace("Updated VPN provider " + vpn_provider + " new timestamp is " +
               timestamp)
    output = open(
        getUserDataPath("Downloads" + "/" + vpn_provider + "/METADATA.txt"),
        'w')
    output.write(timestamp + "\n")
    output.close()
    if progress is not None:
        progress_message = "VPN provider files have been updated"
        progress.update(10, progress_title, progress_message)
        xbmc.sleep(500)
    return True
Пример #43
0
def updateVPNFiles(vpn_provider):
    # If the OVPN files aren't generated then they need to be updated with location info    
    
    infoTrace("vpnproviders.py", "Updating VPN profiles for " + vpn_provider)
    # Get the list of VPN profile files
    if isUserDefined(vpn_provider):
        ovpn_connections = getAddonList(vpn_provider, "*.ovpn")
    else:
        ovpn_connections = getDownloadList(vpn_provider, "*.ovpn")

    # See if there's a port override going on
    addon = xbmcaddon.Addon("service.vpn.manager")
    if addon.getSetting("default_udp") == "true":
        portUDP = ""
    else:
        portUDP = addon.getSetting("alternative_udp_port")
        
    if addon.getSetting("default_tcp") == "true":
        portTCP = ""
    else:
        portTCP = addon.getSetting("alternative_tcp_port")

    # Get the logging level
    verb_value = addon.getSetting("openvpn_verb")
    if verb_value == "":
        verb_value = "1"
        addon.setSetting("openvpn_verb", verb_value)

    # Open a translate file
    try:
        debugTrace("Opening translate file for " + vpn_provider)
        translate_file = open(getAddonPath(True, vpn_provider + "/TRANSLATE.txt"), 'w')
        debugTrace("Opened translate file for " + vpn_provider)
    except Exception as e:
        errorTrace("vpnproviders.py", "Couldn't open the translate file for " + vpn_provider)
        errorTrace("vpnproviders.py", str(e))
        return False
        
    for connection in ovpn_connections:
        try:
            f = open(connection, 'r')
            debugTrace("Processing file " + connection)
            lines = f.readlines()
            f.close()
            if isUserDefined(vpn_provider):
                f = open(connection, 'w')
            else:
                f = open(getAddonPath(True, vpn_provider + "/" + os.path.basename(connection)), 'w')
            # Get the profile friendly name in case we need to generate key/cert names
            name = connection[connection.rfind(getSeparator())+1:connection.rfind(".ovpn")]
            translate_location = name
            translate_server = ""
            server_count = 0
            
            found_up = False
            found_down = False
            found_script_sec = False
            found_block_dns = False
            found_ping = False
            found_verb = False
            proto = "udp"
            
            # Update the necessary values in the ovpn file
            for line in lines:
                
                line = line.strip(' \t\n\r')
                
                # Update path to pass.txt
                if not isUserDefined(vpn_provider) or addon.getSetting("user_def_credentials") == "true":
                    if line.startswith("auth-user-pass"):
                        line = "auth-user-pass " + getAddonPathWrapper(vpn_provider + "/" + "pass.txt")               

                # Update port numbers
                if line.startswith("remote "):
                    server_count += 1
                    tokens = line.split()
                    port = ""
                    for newline in lines:
                        if newline.startswith("proto "):
                            if "tcp" in newline:
                                proto = "tcp"
                                if not portTCP == "": port = portTCP
                                break
                            if "udp" in newline:
                                proto = "udp"
                                if not portUDP == "": port = portUDP
                                break
                    if not port == "":
                        line = "remote " + tokens[1] + " " + port + "\n"
                    if translate_server == "": translate_server = tokens[1]

                        
                # Update user cert and key                
                if not isUserDefined(vpn_provider) and usesUserKeys(vpn_provider):
                    if line.startswith("cert "):
                        line = "cert " + getUserDataPathWrapper(vpn_provider + "/" + getCertName(vpn_provider, name))
                    if line.startswith("key "):
                        line = "key " + getUserDataPathWrapper(vpn_provider + "/" + getKeyName(vpn_provider, name))
                
                # Update key password (if there is one)
                if not isUserDefined(vpn_provider) or usesKeyPass(vpn_provider):
                    if line.startswith("askpass"):
                        line = "askpass " + getUserDataPathWrapper(vpn_provider + "/" + getKeyPass(vpn_provider))
                
                # For user defined profile we need to replace any path tags with the addon dir path
                if isUserDefined(vpn_provider):
                    line = line.replace("#PATH", getAddonPathWrapper(vpn_provider))
                
                # Set the logging level
                if line.startswith("verb "):
                    line = "verb " + verb_value
                    found_verb = True
    
                if line.startswith("up "):
                    found_up = True
                if line.startswith("down "):
                    found_down = True
                if line.startswith("script-security "):
                    found_script_sec = True
                if line.startswith("block-outside-dns"):
                    found_block_dns = True
            
                if line.startswith("ping"):
                    found_ping = True
                
                f.write(line + "\n")
            
            if not found_block_dns and getPlatform() == platforms.WINDOWS and addon.getSetting("block_outside_dns") == "true":
                f.write("block-outside-dns\n")
                
            if addon.getSetting("up_down_script") == "true":
                if not found_script_sec: f.write("script-security 2\n")
                if not found_up: f.write(getUpParam(vpn_provider)+"\n")
                if not found_down: f.write(getDownParam(vpn_provider)+"\n")
            
            if not found_ping and addon.getSetting("force_ping") == "true":
                if proto == "tcp":
                    f.write("ping 10\n")
                    f.write("ping-exit 60\n")
                else:
                    f.write("ping 5\n")
                    f.write("ping-exit 30\n")
                f.write("ping-timer-rem\n")
            
            if not found_verb:
                f.write("verb " + verb_value + "\n")
            
            f.close()
                                
            if server_count > 1: translate_server = translate_server + " & " + str(server_count - 1) + " more"
            translate_file.write(translate_location + "," + translate_server + " (" + proto.upper() + ")\n")
            
        except Exception as e:
            errorTrace("vpnproviders.py", "Failed to update ovpn file")
            errorTrace("vpnproviders.py", str(e))
            translate_file.close()
            return False

    # Write the location to server translation file
    translate_file.close()

    # Flag that the files have been generated            
    writeGeneratedFile(vpn_provider)
            
    return True    
Пример #44
0
def getIPInfoFrom(source):
    # Generate request to find out where this IP is based
    # Successful return is ip, country, region, city, isp 
    # Otherwise error strings are returned for the caller to parse
    try:
        # Determine the URL, make the call and read the response
        url = getIPSourceURL(source)
        if url == "": return "error", "error", "error", "unknown source", ""
        if ifHTTPTrace(): debugTrace("Using " + url)
        req = urllib2.Request(url)
        req.add_header("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0")
        response = urllib2.urlopen(req, timeout = 10)
        json_data = json.load(response)   
        response.close()
        if ifJSONTrace(): infoTrace("ipinfo.py", "JSON received is \n" + json.dumps(json_data, indent=4))
    except urllib2.HTTPError as e:
        errorTrace("ipinfo.py", "Couldn't connect to IP provider " + source)
        errorTrace("ipinfo.py", "API call was " + url)
        errorTrace("ipinfo.py", "Response was " + str(e.code) + " " + e.reason)
        errorTrace("ipinfo.py", e.read())
        recordError(source)
        return "error", "unknown location", "unknown location", "call failed", "unknown ISP"
    except Exception as e:
        errorTrace("ipinfo.py", "Couldn't connect to IP provider " + source)
        errorTrace("ipinfo.py", "API call was " + url)
        errorTrace("ipinfo.py", "Response was " + str(type(e)) + " " + str(e))
        recordError(source)
        return "no response", "error", "error", "connection failed", "unknown ISP"
        
    try:
        if source == "ipinfo.io": ip, country, region, city, isp = getipinfo(json_data)
        if source == "IP-API": ip, country, region, city, isp = getIPAPI(json_data)
        if source == "ipstack": ip, country, region, city, isp = getipstack(json_data)
        if not ip == None:
            recordWorking(source)
            return ip, country, region, city, isp
        else:
            errorTrace("ipinfo.py", "Couldn't get data from " + "source")
            recordError(source)
            return "no info", "unknown location", "unknown location", "no matches", "unknown ISP"
    except Exception as e:
        errorTrace("ipinfo.py", "Couldn't parse response from IP provider " + source)
        errorTrace("ipinfo.py", str(e))
        recordError(source)
        return "error", "error", "error", "parse failed", "unknown ISP"
Пример #45
0
def generateOVPNFiles(vpn_provider, alternative_locations_name):
    # Generate the OVPN files for a VPN provider using the template and update with location info

    infoTrace(
        "vpnproviders.py", "Generating OVPN files for " + vpn_provider +
        " using list " + alternative_locations_name)

    # See if there's a port override going on
    addon = xbmcaddon.Addon("service.vpn.manager")
    if addon.getSetting("default_udp") == "true":
        portUDP = ""
    else:
        portUDP = addon.getSetting("alternative_udp_port")

    if addon.getSetting("default_tcp") == "true":
        portTCP = ""
    else:
        portTCP = addon.getSetting("alternative_tcp_port")

    # Get the logging level
    verb_value = addon.getSetting("openvpn_verb")
    if verb_value == "":
        verb_value = "1"
        addon.setSetting("openvpn_verb", verb_value)

    # Load ovpn template
    try:
        template_path = getTemplateFile(vpn_provider)
        debugTrace("Opening template file " + template_path)
        template_file = open(template_path, 'r')
        template = template_file.readlines()
        template_file.close()
    except Exception as e:
        errorTrace("vpnproviders.py",
                   "Couldn't open the template file for " + vpn_provider)
        errorTrace("vpnproviders.py", str(e))
        return False

    # Open a translate file
    try:
        debugTrace("Opening translate file for " + vpn_provider)
        translate_file = open(
            getAddonPath(True, vpn_provider + "/TRANSLATE.txt"), 'w')
        debugTrace("Opened translate file for " + vpn_provider)
    except Exception as e:
        errorTrace("vpnproviders.py",
                   "Couldn't open the translate file for " + vpn_provider)
        errorTrace("vpnproviders.py", str(e))
        return False

    if getPlatform() == platforms.WINDOWS and addon.getSetting(
            "block_outside_dns") == "true":
        template.append("block-outside-dns")

    if addon.getSetting("force_ping") == "true":
        template.append("ping #PINGSPEED")
        template.append("ping-exit #PINGEXIT")
        template.append("ping-timer-rem")

    if addon.getSetting("up_down_script") == "true":
        template.append("script-security 2")
        template.append(getUpParam(vpn_provider))
        template.append(getDownParam(vpn_provider))

    # Load locations file
    if not alternative_locations_name == "":
        if alternative_locations_name == "User":
            locations_name = getUserDataPath(vpn_provider + "/LOCATIONS.txt")
        else:
            locations_name = getAddonPath(
                True, vpn_provider + "/LOCATIONS " +
                alternative_locations_name + ".txt")
    else:
        locations_name = getAddonPath(True, vpn_provider + "/LOCATIONS.txt")

    try:
        debugTrace("Opening locations file for " + vpn_provider + "\n" +
                   locations_name)
        locations_file = open(locations_name, 'r')
        debugTrace("Opened locations file for " + vpn_provider)
        locations = locations_file.readlines()
        locations_file.close()
    except Exception as e:
        errorTrace(
            "vpnproviders.py", "Couldn't open the locations file for " +
            vpn_provider + "\n" + locations_name)
        errorTrace("vpnproviders.py", str(e))
        translate_file.close()
        return False

    # For each location, generate an OVPN file using the template
    for location in locations:
        try:
            location_values = location.split(",")
            geo = location_values[0]
            servers = location_values[1].split()
            proto = location_values[2]
            ports = (location_values[3].strip(' \t\n\r')).split()
            port = ""

            # Initialise the set of values that can be modified by the location file tuples
            ca_cert = "ca.crt"
            ta_key = "ta.key"
            crl_pem = "crl.pem"
            dh_parm = "dh.pem"
            user1 = ""
            user2 = ""
            user_key = getUserDataPathWrapper(vpn_provider + "/" +
                                              getKeyName(vpn_provider, geo))
            user_cert = getUserDataPathWrapper(vpn_provider + "/" +
                                               getCertName(vpn_provider, geo))
            user_pass = getUserDataPathWrapper(
                vpn_provider + "/" + getKeyPassName(vpn_provider, geo))
            remove_flags = ""
            if proto == "udp":
                ping_speed = "5"
                ping_exit = "30"
            else:
                ping_speed = "10"
                ping_exit = "60"

            if len(location_values) > 4:
                # The final location value is a list of multiple x=y declarations.
                # These need to be parsed out and modified.
                modifier_tuples = (location_values[4].strip(' \t\n\r')).split()
                # Loop through all of the values splitting them into name value pairs
                for modifier in modifier_tuples:
                    pair = modifier.split("=")
                    if "#CERT" in pair[0]: ca_cert = pair[1].strip()
                    if "#REMOVE" in pair[0]: remove_flags = pair[1].strip()
                    if "#TLSKEY" in pair[0]: ta_key = pair[1].strip()
                    if "#USERKEY" in pair[0]: user_key = pair[1].strip()
                    if "#USERCERT" in pair[0]: user_cert = pair[1].strip()
                    if "#USERPASS" in pair[0]: user_pass = pair[1].strip()
                    if "#CRLVERIFY" in pair[0]: crl_pem = pair[1].strip()
                    if "#DH" in pair[0]: dh_parm = pair[1].strip()
                    if "#USER1" in pair[0]: user1 = pair[1].strip()
                    if "#USER2" in pair[0]: user2 = pair[1].strip()
                    if "#PINGSPEED" in pair[0]: ping_speed = pair[1].strip()
                    if "#PINGEXIT" in pair[0]: ping_exit = pair[1].strip()
            if proto == "udp" and not portUDP == "": port = portUDP
            if proto == "tcp" and not portTCP == "": port = portTCP
            if port == "" and len(ports) == 1: port = ports[0]
        except Exception as e:
            errorTrace(
                "vpnproviders.py", "Location file for " + vpn_provider +
                " invalid on line\n" + location)
            errorTrace("vpnproviders.py", str(e))
            translate_file.close()
            return False

        try:
            ovpn_file = open(
                getAddonPath(True, vpn_provider + "/" + geo + ".ovpn"), 'w')
            translate_location = geo
            if proto == "tcp":
                servprot = "tcp-client"
            else:
                servprot = proto

            # Do a replace on the tags in the template with data from the location file
            for line in template:
                output_line = line.strip(' \t\n\r')
                # Must check to see if there's a remove tag on the line before looking for other tags
                if "#REMOVE" in output_line:
                    if output_line[output_line.index("#REMOVE") +
                                   7] in remove_flags:
                        # Remove the line if it's a flag this location doesn't care about
                        output_line = ""
                    else:
                        # Delete the tag if this location doesn't want this line removed
                        output_line = output_line.replace(
                            "#REMOVE" +
                            output_line[output_line.index("#REMOVE") + 7], "")
                output_line = output_line.replace("#PROTO", proto)
                output_line = output_line.replace("#SERVPROT", servprot)
                # If there are multiple servers then we'll need to duplicate the server
                # line (which starts with 'remote ') and fix the server.  The rest of the
                # code will deal with the port which is the same for all lines (although
                # this assumption might not be true for all VPN providers...)
                if output_line.startswith("remote "):
                    server_template = output_line
                    server_lines = ""
                    i = 0
                    for server in servers:
                        if i == 0: translate_server = server
                        if not server_lines == "":
                            server_lines = server_lines + "\n"
                        server_lines = server_lines + server_template.replace(
                            "#SERVER", server)
                        if port == "":
                            server_lines = server_lines.replace(
                                "#PORT", ports[i])
                        i = i + 1
                    if i > 1:
                        translate_server = translate_server + " & " + str(
                            i - 1) + " more"
                    output_line = server_lines
                # There might be other places we use server and port, so still the do the replace
                output_line = output_line.replace("#SERVER", servers[0])
                output_line = output_line.replace("#PORT", port)
                # Pass is always generated by the add-on so will be in the addon directory
                if "#PASS" in output_line:
                    output_line = output_line.replace(
                        "#PASS",
                        getAddonPathWrapper(vpn_provider + "/" + "pass.txt"))
                # These flags are files that can be over ridden in the user data directory
                if "#CERT" in output_line:
                    output_line = output_line.replace(
                        "#CERT",
                        getBestPathWrapper(vpn_provider + "/" + ca_cert))
                if "#TLSKEY" in output_line:
                    output_line = output_line.replace(
                        "#TLSKEY",
                        getBestPathWrapper(vpn_provider + "/" + ta_key))
                if "#CRLVERIFY" in output_line:
                    output_line = output_line.replace(
                        "#CRLVERIFY",
                        getBestPathWrapper(vpn_provider + "/" + crl_pem))
                if "#DH" in output_line:
                    output_line = output_line.replace(
                        "#DH",
                        getBestPathWrapper(vpn_provider + "/" + dh_parm))
                # User files are managed by the add-on so will be in the user directory (set above)
                output_line = output_line.replace("#USERKEY", user_key)
                output_line = output_line.replace("#USERCERT", user_cert)
                output_line = output_line.replace("#USERPASS", user_pass)
                # Path is the add-on path, not the user directory
                if "#PATH" in output_line:
                    output_line = output_line.replace(
                        "#PATH", getAddonPathWrapper(vpn_provider + "/"))
                output_line = output_line.replace("#USER1", user1)
                output_line = output_line.replace("#USER2", user2)
                output_line = output_line.replace("#PINGSPEED", ping_speed)
                output_line = output_line.replace("#PINGEXIT", ping_exit)
                # Overwrite the verb value with the one in the settings
                if output_line.startswith("verb "):
                    output_line = "verb " + verb_value
                # This is a little hack to remove a tag that doesn't work with TCP but is needed for UDP
                # Could do this with a #REMOVE, but doing it here is less error prone.
                if "explicit-exit-notify" in line and proto == "tcp":
                    output_line = ""
                if not output_line == "": ovpn_file.write(output_line + "\n")
            ovpn_file.close()
            debugTrace("Wrote location " + geo + " " + proto)
            translate_file.write(translate_location + "," + translate_server +
                                 " (" + proto.upper() + ")\n")
        except Exception as e:
            errorTrace(
                "vpnproviders.py", "Can't write a location file for " +
                vpn_provider + " failed on line\n" + location)
            errorTrace("vpnproviders.py", str(e))
            translate_file.close()
            return False

    # Write the location to server translation file
    translate_file.close()

    # Flag that the files have been generated
    writeGeneratedFile(vpn_provider)

    return True
Пример #46
0
def copyKeyAndCert(vpn_provider, ovpn_name, user_key, user_cert):
    # Copy the user key and cert to the userdata directory
    key_dest = getUserDataPath(vpn_provider + "/" +
                               getKeyName(vpn_provider, ovpn_name))
    key_source = user_key
    cert_dest = getUserDataPath(vpn_provider + "/" +
                                getCertName(vpn_provider, ovpn_name))
    cert_source = user_cert
    if key_source == cert_source:
        # This means that a .ovpn was selected
        try:
            debugTrace("Extracing key and cert from " + key_source + " to " +
                       key_dest + " and " + cert_dest)
            ovpn_file = open(key_source, 'r')
            ovpn = ovpn_file.readlines()
            ovpn_file.close()
            debugTrace("Checking directory path exists for key and cert " +
                       os.path.dirname(key_dest))
            if not os.path.exists(os.path.dirname(key_dest)):
                infoTrace("vpnprovider.py",
                          "Creating " + os.path.dirname(key_dest))
                os.makedirs(os.path.dirname(key_dest))
                xbmc.sleep(500)
                # Loop around waiting for the directory to be created.  After 10 seconds we'll carry
                # on and let he open file calls fail and throw an exception
                t = 0
                while not os.path.exists(os.path.dirname(key_dest)):
                    if t == 9:
                        errorTrace(
                            "vpnprovider.py",
                            "Waited 10 seconds to create directory but it never appeared"
                        )
                        break
                    xbmc.sleep(1000)
                    t += 1
            key_file = open(key_dest, 'w')
            cert_file = open(cert_dest, 'w')
            key = False
            cert = False
            key_count = 0
            cert_count = 0
            for line in ovpn:
                line = line.strip(' \t\n\r')
                if line.startswith("<key>"): key = True
                elif line.startswith("</key>"): key = False
                elif line.startswith("<cert>"): cert = True
                elif line.startswith("</cert>"): cert = False
                else:
                    if key:
                        key_file.write(line + "\n")
                        key_count += 1
                    if cert:
                        cert_file.write(line + "\n")
                        cert_count += 1
            key_file.close()
            cert_file.close()
            if key_count > 0 and cert_count > 0:
                return True
            else:
                # Couldn't extract key and/or cert, delete any remains and return error
                errorTrace(
                    "vpnproviders.py",
                    "Failed to extract user key or cert file from ovpn.  Key size was "
                    + str(key_count) + " and cert size was " + str(cert_count))
                if xbmcvfs.exists(key_dest): xbmcvfs.delete(key_dest)
                if xbmcvfs.exists(cert_dest): xbmcvfs.delete(cert_dest)
                return False
        except Exception as e:
            errorTrace("vpnproviders.py",
                       "Failed to copy user key or cert file to userdata")
            errorTrace("vpnproviders.py", str(e))
            return False
    else:
        # Individual key and crt files were selected
        try:
            debugTrace("Copying key " + key_source + " to " + key_dest)
            if xbmcvfs.exists(key_dest): xbmcvfs.delete(key_dest)
            xbmcvfs.copy(key_source, key_dest)
            if not xbmcvfs.exists(key_dest):
                raise IOError('Failed to copy key ' + key_source + " to " +
                              key_dest)
            debugTrace("Copying cert " + cert_source + " to " + cert_dest)
            if xbmcvfs.exists(cert_dest): xbmcvfs.delete(cert_dest)
            xbmcvfs.copy(cert_source, cert_dest)
            if not xbmcvfs.exists(cert_dest):
                raise IOError('Failed to copy cert ' + cert_source + " to " +
                              cert_dest)
            return True
        except Exception as e:
            errorTrace("vpnproviders.py",
                       "Failed to copy user key or cert file to userdata")
            errorTrace("vpnproviders.py", str(e))
            return False
Пример #47
0
def generateOVPNFiles(vpn_provider, alternative_locations_name):
    # Generate the OVPN files for a VPN provider using the template and update with location info
    
    infoTrace("vpnproviders.py", "Generating OVPN files for " + vpn_provider + " using list " + alternative_locations_name)

    # See if there's a port override going on
    addon = xbmcaddon.Addon("service.vpn.manager")
    if addon.getSetting("default_udp") == "true":
        portUDP = ""
    else:
        portUDP = addon.getSetting("alternative_udp_port")
        
    if addon.getSetting("default_tcp") == "true":
        portTCP = ""
    else:
        portTCP = addon.getSetting("alternative_tcp_port")

    # Get the logging level
    verb_value = addon.getSetting("openvpn_verb")
    if verb_value == "":
        verb_value = "1"
        addon.setSetting("openvpn_verb", verb_value)
        
    # Load ovpn template
    try:
        template_path = getTemplateFile(vpn_provider)
        debugTrace("Opening template file " + template_path)
        template_file = open(template_path, 'r')
        template = template_file.readlines()
        template_file.close()
    except Exception as e:
        errorTrace("vpnproviders.py", "Couldn't open the template file for " + vpn_provider)
        errorTrace("vpnproviders.py", str(e))
        return False

    # Open a translate file
    try:
        debugTrace("Opening translate file for " + vpn_provider)
        translate_file = open(getAddonPath(True, vpn_provider + "/TRANSLATE.txt"), 'w')
        debugTrace("Opened translate file for " + vpn_provider)
    except Exception as e:
        errorTrace("vpnproviders.py", "Couldn't open the translate file for " + vpn_provider)
        errorTrace("vpnproviders.py", str(e))
        return False
        
    if getPlatform() == platforms.WINDOWS and addon.getSetting("block_outside_dns") == "true":
        template.append("block-outside-dns")
    
    if addon.getSetting("force_ping") == "true":
        template.append("ping #PINGSPEED")
        template.append("ping-exit #PINGEXIT")
        template.append("ping-timer-rem")
    
    if addon.getSetting("up_down_script") == "true":
        template.append("script-security 2")
        template.append(getUpParam(vpn_provider))
        template.append(getDownParam(vpn_provider))
        
    # Load locations file
    if not alternative_locations_name == "":
        if alternative_locations_name == "User":
            locations_name = getUserDataPath(vpn_provider + "/LOCATIONS.txt")
        else:
            locations_name = getAddonPath(True, vpn_provider + "/LOCATIONS " + alternative_locations_name + ".txt")
    else:
        locations_name = getAddonPath(True, vpn_provider + "/LOCATIONS.txt")

    try:
        debugTrace("Opening locations file for " + vpn_provider + "\n" + locations_name)
        locations_file = open(locations_name, 'r')
        debugTrace("Opened locations file for " + vpn_provider)
        locations = locations_file.readlines()
        locations_file.close()
    except Exception as e:
        errorTrace("vpnproviders.py", "Couldn't open the locations file for " + vpn_provider + "\n" + locations_name)
        errorTrace("vpnproviders.py", str(e))
        translate_file.close()
        return False

    # For each location, generate an OVPN file using the template
    for location in locations:
        try:
            location_values = location.split(",")
            geo = location_values[0]
            servers = location_values[1].split()
            proto = location_values[2]
            ports = (location_values[3].strip(' \t\n\r')).split()
            port = ""

            # Initialise the set of values that can be modified by the location file tuples
            ca_cert = "ca.crt"
            ta_key = "ta.key"
            crl_pem = "crl.pem"
            dh_parm = "dh.pem"
            user1 = ""
            user2 = ""
            user_key = getUserDataPathWrapper(vpn_provider + "/" + getKeyName(vpn_provider, geo))
            user_cert = getUserDataPathWrapper(vpn_provider + "/" + getCertName(vpn_provider, geo))
            user_pass = getUserDataPathWrapper(vpn_provider + "/" + getKeyPassName(vpn_provider, geo))
            remove_flags = ""
            if proto == "udp":
                ping_speed = "5"
                ping_exit = "30"
            else:
                ping_speed = "10"
                ping_exit = "60"
            
            if len(location_values) > 4: 
                # The final location value is a list of multiple x=y declarations.
                # These need to be parsed out and modified.
                modifier_tuples = (location_values[4].strip(' \t\n\r')).split()
                # Loop through all of the values splitting them into name value pairs
                for modifier in modifier_tuples:
                    pair = modifier.split("=")
                    if "#CERT" in pair[0]: ca_cert = pair[1].strip()
                    if "#REMOVE" in pair[0]: remove_flags = pair[1].strip()
                    if "#TLSKEY" in pair[0]: ta_key = pair[1].strip()
                    if "#USERKEY" in pair[0]: user_key = pair[1].strip()
                    if "#USERCERT" in pair[0]: user_cert = pair[1].strip()
                    if "#USERPASS" in pair[0]: user_pass = pair[1].strip()
                    if "#CRLVERIFY" in pair[0]: crl_pem = pair[1].strip()
                    if "#DH" in pair[0]: dh_parm = pair[1].strip()
                    if "#USER1" in pair[0]: user1 = pair[1].strip()
                    if "#USER2" in pair[0]: user2 = pair[1].strip()
                    if "#PINGSPEED" in pair[0]: ping_speed = pair[1].strip()
                    if "#PINGEXIT" in pair[0]: ping_exit = pair[1].strip()
            if proto == "udp" and not portUDP == "": port = portUDP
            if proto == "tcp" and not portTCP == "": port = portTCP
            if port == "" and len(ports) == 1: port = ports[0]
        except Exception as e:
            errorTrace("vpnproviders.py", "Location file for " + vpn_provider + " invalid on line\n" + location)
            errorTrace("vpnproviders.py", str(e))
            translate_file.close()
            return False
            
        try:
            ovpn_file = open(getAddonPath(True, vpn_provider + "/" + geo + ".ovpn"), 'w')
            translate_location = geo
            if proto == "tcp":
                servprot = "tcp-client"
            else:
                servprot = proto

            # Do a replace on the tags in the template with data from the location file
            for line in template:
                output_line = line.strip(' \t\n\r')
                # Must check to see if there's a remove tag on the line before looking for other tags
                if "#REMOVE" in output_line:
                    if output_line[output_line.index("#REMOVE")+7] in remove_flags:
                        # Remove the line if it's a flag this location doesn't care about
                        output_line = ""
                    else:
                        # Delete the tag if this location doesn't want this line removed
                        output_line = output_line.replace("#REMOVE" + output_line[output_line.index("#REMOVE")+7], "")
                output_line = output_line.replace("#PROTO", proto)
                output_line = output_line.replace("#SERVPROT", servprot)
                # If there are multiple servers then we'll need to duplicate the server
                # line (which starts with 'remote ') and fix the server.  The rest of the
                # code will deal with the port which is the same for all lines (although
                # this assumption might not be true for all VPN providers...)
                if output_line.startswith("remote "):
                    server_template = output_line
                    server_lines = ""
                    i = 0
                    for server in servers:
                        if i == 0: translate_server = server
                        if not server_lines == "" : server_lines = server_lines + "\n"
                        server_lines = server_lines + server_template.replace("#SERVER", server)
                        if port == "":
                            server_lines = server_lines.replace("#PORT", ports[i])
                        i = i + 1
                    if i > 1: translate_server = translate_server + " & " + str(i - 1) + " more"
                    output_line = server_lines
                # There might be other places we use server and port, so still the do the replace
                output_line = output_line.replace("#SERVER", servers[0])
                output_line = output_line.replace("#PORT", port)
                # Pass is always generated by the add-on so will be in the addon directory
                if "#PASS" in output_line: output_line = output_line.replace("#PASS", getAddonPathWrapper(vpn_provider + "/" + "pass.txt"))
                # These flags are files that can be over ridden in the user data directory
                if "#CERT" in output_line: output_line = output_line.replace("#CERT", getBestPathWrapper(vpn_provider + "/" + ca_cert))
                if "#TLSKEY" in output_line: output_line = output_line.replace("#TLSKEY", getBestPathWrapper(vpn_provider + "/" + ta_key))
                if "#CRLVERIFY" in output_line: output_line = output_line.replace("#CRLVERIFY", getBestPathWrapper(vpn_provider + "/" + crl_pem))
                if "#DH" in output_line: output_line = output_line.replace("#DH", getBestPathWrapper(vpn_provider + "/" + dh_parm))
                # User files are managed by the add-on so will be in the user directory (set above)
                output_line = output_line.replace("#USERKEY", user_key)
                output_line = output_line.replace("#USERCERT", user_cert)
                output_line = output_line.replace("#USERPASS", user_pass)
                # Path is the add-on path, not the user directory
                if "#PATH" in output_line: output_line = output_line.replace("#PATH", getAddonPathWrapper(vpn_provider + "/"))
                output_line = output_line.replace("#USER1", user1)
                output_line = output_line.replace("#USER2", user2)
                output_line = output_line.replace("#PINGSPEED", ping_speed)
                output_line = output_line.replace("#PINGEXIT", ping_exit)
                # Overwrite the verb value with the one in the settings
                if output_line.startswith("verb "):
                    output_line = "verb " + verb_value
                # This is a little hack to remove a tag that doesn't work with TCP but is needed for UDP
                # Could do this with a #REMOVE, but doing it here is less error prone.
                if "explicit-exit-notify" in line and proto == "tcp": output_line = ""
                if not output_line == "" : ovpn_file.write(output_line + "\n")
            ovpn_file.close()
            debugTrace("Wrote location " + geo + " " + proto)
            translate_file.write(translate_location + "," + translate_server + " (" + proto.upper() + ")\n")
        except Exception as e:
            errorTrace("vpnproviders.py", "Can't write a location file for " + vpn_provider + " failed on line\n" + location)
            errorTrace("vpnproviders.py", str(e))
            translate_file.close()
            return False
    
    # Write the location to server translation file
    translate_file.close()
    
    # Flag that the files have been generated
    writeGeneratedFile(vpn_provider)

    return True
Пример #48
0
def updateVPNFiles(vpn_provider):
    # If the OVPN files aren't generated then they need to be updated with location info

    infoTrace("vpnproviders.py", "Updating VPN profiles for " + vpn_provider)
    # Get the list of VPN profile files
    if isUserDefined(vpn_provider):
        ovpn_connections = getAddonList(vpn_provider, "*.ovpn")
    else:
        ovpn_connections = getDownloadList(vpn_provider, "*.ovpn")

    # See if there's a port override going on
    addon = xbmcaddon.Addon("service.vpn.manager")
    if addon.getSetting("default_udp") == "true":
        portUDP = ""
    else:
        portUDP = addon.getSetting("alternative_udp_port")

    if addon.getSetting("default_tcp") == "true":
        portTCP = ""
    else:
        portTCP = addon.getSetting("alternative_tcp_port")

    # Get the logging level
    verb_value = addon.getSetting("openvpn_verb")
    if verb_value == "":
        verb_value = "1"
        addon.setSetting("openvpn_verb", verb_value)

    # Open a translate file
    try:
        debugTrace("Opening translate file for " + vpn_provider)
        translate_file = open(
            getAddonPath(True, vpn_provider + "/TRANSLATE.txt"), 'w')
        debugTrace("Opened translate file for " + vpn_provider)
    except Exception as e:
        errorTrace("vpnproviders.py",
                   "Couldn't open the translate file for " + vpn_provider)
        errorTrace("vpnproviders.py", str(e))
        return False

    for connection in ovpn_connections:
        try:
            f = open(connection, 'r')
            debugTrace("Processing file " + connection)
            lines = f.readlines()
            f.close()
            if isUserDefined(vpn_provider):
                f = open(connection, 'w')
            else:
                f = open(
                    getAddonPath(
                        True,
                        vpn_provider + "/" + os.path.basename(connection)),
                    'w')
            # Get the profile friendly name in case we need to generate key/cert names
            name = connection[connection.rfind(getSeparator()) +
                              1:connection.rfind(".ovpn")]
            translate_location = name
            translate_server = ""
            server_count = 0

            found_up = False
            found_down = False
            found_script_sec = False
            found_block_dns = False
            found_ping = False
            proto = "udp"

            # Update the necessary values in the ovpn file
            for line in lines:

                line = line.strip(' \t\n\r')

                # Update path to pass.txt
                if not isUserDefined(vpn_provider) or addon.getSetting(
                        "user_def_credentials") == "true":
                    if line.startswith("auth-user-pass"):
                        line = "auth-user-pass " + getAddonPathWrapper(
                            vpn_provider + "/" + "pass.txt")

                # Update port numbers
                if line.startswith("remote "):
                    server_count += 1
                    tokens = line.split()
                    port = ""
                    for newline in lines:
                        if newline.startswith("proto "):
                            if "tcp" in newline:
                                proto = "tcp"
                                if not portTCP == "": port = portTCP
                                break
                            if "udp" in newline:
                                proto = "udp"
                                if not portUDP == "": port = portUDP
                                break
                    if not port == "":
                        line = "remote " + tokens[1] + " " + port + "\n"
                    if translate_server == "": translate_server = tokens[1]

                # Update user cert and key
                if not isUserDefined(vpn_provider) and usesUserKeys(
                        vpn_provider):
                    if line.startswith("cert "):
                        line = "cert " + getUserDataPathWrapper(
                            vpn_provider + "/" +
                            getCertName(vpn_provider, name))
                    if line.startswith("key "):
                        line = "key " + getUserDataPathWrapper(
                            vpn_provider + "/" +
                            getKeyName(vpn_provider, name))

                # Update key password (if there is one)
                if not isUserDefined(vpn_provider) or usesKeyPass(
                        vpn_provider):
                    if line.startswith("askpass"):
                        line = "askpass " + getUserDataPathWrapper(
                            vpn_provider + "/" + getKeyPass(vpn_provider))

                # For user defined profile we need to replace any path tags with the addon dir path
                if isUserDefined(vpn_provider):
                    line = line.replace("#PATH",
                                        getAddonPathWrapper(vpn_provider))

                # Set the logging level
                if line.startswith("verb "):
                    line = "verb " + verb_value

                if line.startswith("up "):
                    found_up = True
                if line.startswith("down "):
                    found_down = True
                if line.startswith("script-security "):
                    found_script_sec = True
                if line.startswith("block-outside-dns"):
                    found_block_dns = True

                if line.startswith("ping"):
                    found_ping = True

                f.write(line + "\n")

            if not found_block_dns and getPlatform(
            ) == platforms.WINDOWS and addon.getSetting(
                    "block_outside_dns") == "true":
                f.write("block-outside-dns\n")

            if addon.getSetting("up_down_script") == "true":
                if not found_script_sec: f.write("script-security 2\n")
                if not found_up: f.write(getUpParam(vpn_provider) + "\n")
                if not found_down: f.write(getDownParam(vpn_provider) + "\n")

            if not found_ping and addon.getSetting("force_ping") == "true":
                if proto == "tcp":
                    f.write("ping 10\n")
                    f.write("ping-exit 60\n")
                else:
                    f.write("ping 5\n")
                    f.write("ping-exit 30\n")
                f.write("ping-timer-rem\n")

            f.close()

            if server_count > 1:
                translate_server = translate_server + " & " + str(
                    server_count - 1) + " more"
            translate_file.write(translate_location + "," + translate_server +
                                 " (" + proto.upper() + ")\n")

        except Exception as e:
            errorTrace("vpnproviders.py", "Failed to update ovpn file")
            errorTrace("vpnproviders.py", str(e))
            translate_file.close()
            return False

    # Write the location to server translation file
    translate_file.close()

    # Flag that the files have been generated
    writeGeneratedFile(vpn_provider)

    return True
Пример #49
0
def importWizard():    
    addon = xbmcaddon.Addon("service.vpn.manager")
    addon_name = addon.getAddonInfo("name")

    errorMessage = ""
    success = False
    cancel = False

    xbmcgui.Dialog().ok(addon_name, "The User Defined import wizard helps you set up an unsupported VPN provider.  It may not work without additional user intervention.  You should review the import log and subsequent VPN logs to debug any problems.")

    # Warn the user that files will be deleted and kittens will be harmed
    if xbmcgui.Dialog().yesno(addon_name, "Any existing User Defined settings and files will be deleted. Do you want to continue?", "", ""):
        removeGeneratedFiles()
        success = clearUserData()
        addon.setSetting("vpn_provider", "User Defined")
        if not success: errorMessage = "Could not clear the UserDefined directory. Check the log."
    else:
        success = False
        errorMessage = "Import wizard has not been run, no settings or files have been changed."

    # Get the list of files to be used
    if success:
        if xbmcgui.Dialog().yesno(addon_name, "Select ALL files needed to connect to the VPN provider, including .ovpn, .key and .crt files.  Select a directory (sub directories are ignored) or select multiple files within a directory?.", "", "", "Directory", "Files"):
            directory_input = False
            files = xbmcgui.Dialog().browse(1, "Select all VPN provider files", "files", "", False, False, "", True)
        else:
            directory_input = True
            dname = xbmcgui.Dialog().browse(0, "Select a directory containing VPN provider files", "files", "", False, False, "", False)
            debugTrace("Import from directory " + dname)
            dirs, files = xbmcvfs.listdir(dname)
            
        # Separate the selected files into ovpn files and other files
        ovpn_files = []
        other_files = []
        for name in files:
            if directory_input:
                name = dname + name
            debugTrace("Found file " + name)
            if name.endswith(".ovpn"):
                ovpn_files.append(name)
            else:
                other_files.append(name)
        if len(ovpn_files) == 0:
            success = False
            errorMessage = "No .ovpn files found.  You must provide at least one .ovpn file."
            
    # Copy and modify the ovpn files
    if success:
        
        # Create some logs to write out later
        summary = []
        detail = []
       
        summary.append("Importing selected files to User Defined directory, " + getUserDataPath("UserDefined/") + "\n")
        summary.append("at " + time.strftime('%Y-%m-%d %H:%M:%S') + "\n")
        detail.append("\n=== Import details ===\n\n")
        
        update = False
        rename = False
        if xbmcgui.Dialog().yesno(addon_name, "Update the .ovpn files to best guess values and determine the best User Defined provider settings (recommended)?", "", ""):
            update = True
            detail.append("Updating the .ovpn files to best guess settings\n")
            if xbmcgui.Dialog().yesno(addon_name, "Rename the .ovpn files to indicate either a UDP or TCP connection type to allow filtering of connections?", "", ""):
                rename = True
                detail.append("Files will be renamed to indicate UDP or TCP\n")        
            
        # Display dialog to show progress of copying files
        dialog_step = 100/(len(ovpn_files) + len(other_files))
        progress = xbmcgui.DialogProgress()
        progress_title = "Copying User Defined files."
        progress.create(addon_name,progress_title) 
        prog_step = 0
        xbmc.sleep(500)
        try:
            dest_path = getUserDataPath("UserDefined/")
            debugTrace("Checking directory path exists before copying " + dest_path)
            if not os.path.exists(dest_path):
                infoTrace("import.py", "Creating " + dest_path)
                os.makedirs(os.path.dirname(dest_path))
                xbmc.sleep(500)
                # Loop around waiting for the directory to be created.  After 10 seconds we'll carry 
                # on and let he open file calls fail and throw an exception
                t = 0
                while not os.path.exists(os.path.dirname(dest_path)):
                    if t == 9:
                        errorTrace("vpnprovider.py", "Waited 10 seconds to create directory but it never appeared")
                        break
                    xbmc.sleep(1000)
                    t += 1
            other_files_count = []
            for fname in other_files:
                path, dest_name = os.path.split(fname)
                dest_name = getUserDataPath("UserDefined/" + dest_name)
                # Report file being copied, then do it
                progress_message = "Copying " + fname
                progress.update(prog_step, progress_title, progress_message)
                xbmc.sleep(100)
                prog_step += dialog_step
                infoTrace("import.py", "Copying " + fname + " to " + dest_name)
                detail.append("Copying " + fname + " to " + dest_name + "\n")
                xbmcvfs.copy(fname, dest_name)
                if not xbmcvfs.exists(dest_name): raise IOError('Failed to copy user def file ' + fname + " to " + dest_name)
                other_files_count.append(0)
                if progress.iscanceled():
                    cancel = True
                    break
            auth_count = 0
            auth_found = 0
            cert_count = 0
            cert_found = 0
            multiple_certs = False
            last_cert_found = ""
            ecert_count = 0
            key_count = 0
            key_found = 0
            key_pass_found = 0
            key_pass_count = 0
            multiple_keys = False
            last_key_found = ""
            ekey_count = 0
            if not cancel:
                metadata = getGitMetaData("UserDefined")
                mods = []
                if not metadata == None:
                    for line in metadata:
                        line = line.strip(' \t\n\r')
                        mods.append(line)
                for oname in ovpn_files:
                    path, dest_name = os.path.split(oname)
                    dest_name = getUserDataPath("UserDefined/" + dest_name)

                    # Update dialog to saywhat's happening
                    if update:
                        progress_message = "Copying and updating " + oname
                    else:
                        progress_message = "Copying " + oname
                    progress.update(prog_step, progress_title, progress_message)
                    xbmc.sleep(100)
                    prog_step += dialog_step

                    # Copy the ovpn file
                    infoTrace("import.py", "Copying " + oname + " to " + dest_name)
                    detail.append("Copying " + oname + " to " + dest_name + "\n")
                    xbmcvfs.copy(oname, dest_name)
                    if not xbmcvfs.exists(dest_name): raise IOError('Failed to copy user def ovpn ' + oname + " to " + dest_name)
                    
                    if update:
                        # Read the copied file in and then overwrite it with any updates needed
                        # Was doing a read from source and write here but this failed on Linux over an smb mount (file not found)
                        auth = False
                        keypass = False
                        infoTrace("import.py", "Updating " + dest_name)
                        detail.append("Updating " + dest_name + "\n")
                        source_file = open(dest_name, 'r')
                        source = source_file.readlines()
                        source_file.close()
                        dest_file = open(dest_name, 'w')
                        proto = "UDP"
                        flags = [False, False, False, False, False]
                        for line in source:
                            line = line.strip(' \t\n\r')
                            old_line = line
                            i = 0
                            # Look for each non ovpn file uploaded and update it to make sure the path is good
                            for fname in other_files:
                                path, name = os.path.split(fname)
                                if not line.startswith("#"):
                                    params = line.split()
                                    if len(params) == 2:
                                        # Remove the separator in order to get any fully qualified filename as space delimited
                                        params[1].replace(getSeparator(), " ")
                                        # Add in a leading space for unqualified filenames
                                        params[1] = " " + params[1]
                                        if params[1].endswith(" " + name):
                                            old_line = line
                                            line = params[0] + " " + "#PATH" + getSeparatorOutput() + name
                                            detail.append("  Found " + name + ", old line was : " + old_line + "\n")
                                            detail.append("  New line is " + line + "\n")
                                            other_files_count[i] += 1
                                            if line.startswith("auth-user-pass"):
                                                auth_found += 1
                                                auth = True
                                            if line.startswith("cert "):
                                                cert_found += 1
                                            if line.startswith("key "):
                                                key_found += 1
                                            if line.startswith("askpass "):
                                                key_pass_found += 1
                                                keypass = True
                                i += 1
                            # Do some tag counting to determine authentication methods to use
                            if not line.startswith("#"):
                                for mod in mods:
                                    flag, verb, parms = mod.split(",")
                                    if flag == "1" and line.startswith(verb) and parms in line: flags[0] = True
                                    if flag == "3" and line.startswith(verb): flags[2] = True
                                    if flag == "4" and line.startswith(verb): line = verb + " " + parms
                                    if flag == "5" and not flags[4] and verb in line: 
                                        detail.append("  WARNING, " + parms + "\n")
                                        flags[4] = True
                                if line.startswith("auth-user-pass"):
                                    auth_count += 1
                                    if not auth: line = "auth-user-pass #PATH" + getSeparatorOutput() + "pass.txt"
                                if line.startswith("cert "):
                                    cert_count += 1
                                    if not last_cert_found == old_line:
                                        if not last_cert_found == "":
                                            multiple_certs = True
                                        last_cert_found = old_line
                                if line.startswith("key "):
                                    key_count += 1
                                    if not last_key_found == old_line:
                                        if not last_key_found == "":
                                            multiple_keys = True
                                        last_key_found = old_line
                                if line.startswith("askpass"):
                                    key_pass_count += 1
                                    if not keypass: line = "askpass #PATH" + getSeparatorOutput() + "key.txt"
                                if line.startswith("proto "):
                                    if "tcp" in (line.lower()): proto = "TCP"
                                if line.startswith("<cert>"):
                                    ecert_count += 1
                                if line.startswith("<key>"):
                                    ekey_count += 1
                            if not flags[2]: dest_file.write(line+"\n")
                            flags[2] = False
                        for mod in mods:
                            flag, verb, parms = mod.split(",")
                            if flag == "2":
                                dest_file.write(verb+"\n")
                        dest_file.close()
                        flags[4] = False
                        if flags[0]:
                            if xbmcvfs.exists(dest_name):
                                xbmcvfs.delete(dest_name)
                            detail.append("  wARNING, couldn't import file as it contains errors or is unsupported\n")
                        elif rename:
                            proto = " (" + proto + ").ovpn"
                            new_name = dest_name.replace(".ovpn", proto)   
                            if not xbmcvfs.exists(new_name):
                                xbmcvfs.rename(dest_name, new_name)
                                detail.append("  Renamed to " + new_name + "\n")
                            else:
                                detail.append("  WARNING, couldn't rename file to " + new_name + " as a file with that name already exists\n")

                    if progress.iscanceled():
                        cancel = True
                        break
                        
        except Exception as e:
            errorTrace("import.py", "Failed to copy (or update) file")
            errorTrace("import.py", str(e))
            success = False
            errorMessage = "Failed to copy (or update) selected files.  Check the log."
            
        progress_message = "Outputting results of import wizard"
        progress.update(100, progress_title, progress_message)
        xbmc.sleep(500)   
        
        # General import results
        summary.append("\n=== Summary of import ===\n\n")
        if cancel:
            summary.append("Import was cancelled\n")
        else:
            summary.append("Imported " + str(len(ovpn_files)) + " .ovpn files and " + str(len(other_files)) + " other files.\n")
            summary.append("\nYou should understand any WARNINGs below, and validate that the .ovpn files imported have been updated correctly.\n\n")
            summary.append("If the VPN connection fails view the VPN log to determine why, using Google to understand the errors if necessary.\n")
            summary.append("You can fix problems either by editing your local files and re-importing, or by editing the contents of the User Defined directory.\n\n")
            
            if update:
                # Report on how user names and passwords will be handled
                if auth_count > 0:
                    if auth_found > 0:
                        # Not using a password as resolved by file
                        addon.setSetting("user_def_credentials", "false")
                        summary.append("The auth-user-pass tag was found " + str(auth_count) + " times, but was resolved using a supplied file so user name and password don't need to be entered.\n")
                        if not auth_found == auth_count:
                            summary.append("  WARNING : The auth-user-pass tag was found " + str(auth_count) + " times, but only resolved using a supplied file " + str(auth_found) + " times. Some connections may not work.\n")
                    else:
                        # Using a password as auth-user-pass tag was found
                        addon.setSetting("user_def_credentials", "true")
                        summary.append("The auth-user-pass tag was found " + str(auth_count) + " times so assuming user name and password authentication is used.\n")
                    if auth_count < len(ovpn_files):
                        summary.append("  WARNING : The auth-user-pass tag was only found in " + str(auth_count) + " .ovpn files, out of " + str(len(ovpn_files)) + ". Some connections may not work.\n")
                else:
                    # Not using a password as no auth-user-pass tag was found
                    addon.setSetting("user_def_credentials", "false")
                    summary.append("No auth-user-pass tag was found, so assuming user name and password is not needed.\n")
                
                # Report on how keys and certs will be handled
                if (cert_count > 0 or key_count > 0):
                    summary.append("The key tag was found " + str(key_count) + " times, and the cert tag was found " + str(cert_count) + " times.\n")
                    if cert_found > 0 or key_found > 0:
                        # Key and cert resolved by file so not asking user for them
                        addon.setSetting("user_def_keys", "None")
                        summary.append("The key and certificate don't need to be requested as the key tags were resolved using a supplied file " + str(key_found) + " times, and the cert tags were resolved using a supplied file " + str(cert_found) + " times.\n")
                        if (not cert_found == cert_count) or (not key_found == key_count):
                            summary.append("  WARNING : The key or cert tags were not resolved by a supplied file for all occurrences. Some connections may not work.\n")
                    else:
                        if multiple_certs or multiple_keys:
                            # Key and cert tags found with different file names, but no files supplied.  Assume multiple files, user supplied
                            addon.setSetting("user_def_keys", "Multiple")
                            summary.append("Found key and cert tags with multiple filenames, but no key or certificate files were supplied. These will be requested during connection.\n")
                        else:
                            # Key and cert tags found with same file names, but no files supplied.  Assume single file, user supplied
                            addon.setSetting("user_def_keys", "Single")
                            summary.append("Found key and cert tags all with the same filename, but no key or certificate files were supplied. These will be requested during connection.\n")
                    if cert_count < len(ovpn_files) or key_count < len(ovpn_files):
                        summary.append("  WARNING : The key tag was found " + str(key_count) + " times, and the cert tag was found " + str(cert_count) + " times. Expected to find one of each in all " + str(len(ovpn_files)) + " .ovpn files. Some connections may not work.\n") 
                else:
                    # Embedded key and certs found, so not asking user for them
                    addon.setSetting("user_def_keys", "None")
                    if (ekey_count > 0 or ecert_count > 0):
                        if ekey_count == ecert_count and key_count == len(ovpn_files):
                            summary.append("Using embedded user keys and certificates so keys and certs don't need to be entered.\n")
                        else:
                            summary.append("  WARNING : Using embedded user keys and certificates, but found " + str(ekey_count) + " keys and " + str(ecert_count) + " certificates in " + str(len(ovpn_files)) + " .ovpn files. There should be one of each in all .ovpn files otherwise some connections may not work.\n")
                    else:
                        summary.append("No user key or cert tags were found so assuming this type of authentication is not used.\n")
                
                # Report on how key passwords will be handled
                if key_pass_count > 0:
                    if key_pass_found > 0:
                        # Not using a password as resolved by file
                        addon.setSetting("user_def_key_password", "false")
                        summary.append("The askpass tag was found " + str(auth_count) + " times, but was resolved using a supplied file so the key password doesn't need to be entered.\n")
                        if not key_pass_found == key_pass_count:
                            summary.append("  WARNING : The askpass tag was found " + str(key_pass_count) + " times, but only resolved using a supplied file " + str(key_pass_found) + " times. Some connections may not work.\n")
                    else:
                        # Using a password as auth-user-pass tag was found
                        addon.setSetting("user_def_key_password", "true")
                        summary.append("The askpass tag was found " + str(key_pass_count) + " times so assuming key password authentication is used.\n")
                    if key_pass_count < len(ovpn_files):
                        summary.append("  WARNING : The askpass tag was only found in " + str(key_pass_count) + " .ovpn files, out of " + str(len(ovpn_files)) + ". Some connections may not work, or you may be asked to enter a password when it's not necessary.\n")
                else:
                    # Not using a password as no askpass tag was found
                    addon.setSetting("user_def_key_password", "false")
                    summary.append("No askpass tag was found, so assuming key password is not needed.\n")

                
                # Report how many times each of the non .ovpn files were used
                i = 0
                for oname in other_files:
                    summary.append("File " + oname + " was found and used in .ovpn files " + str(other_files_count[i]) + " times.\n")
                    if not other_files_count[i] == len(ovpn_files):
                        if other_files_count[i] == 0:
                            summary.append("  WARNING : " + oname + " was not used to update any .ovpn files and could be unused.\n")
                        else:
                            summary.append("  WARNING : The number of updates for " + oname + " was different to the number of .ovpn files, " + str(len(ovpn_files)) + ", which could be a problem.\n")
                    i += 1
            else:
                summary.append("None of the files were updated during import.\n")
        
        # Open a log file so all changes can be recorded without fouling up the kodi log       
        log_name = getImportLogPath()
        if xbmcvfs.exists(log_name): xbmcvfs.delete(log_name) 
        log_file = open(log_name, 'w') 
        for line in summary:
            log_file.write(line)
        for line in detail:
            log_file.write(line)
        log_file.close()
        
        progress.close()
        xbmc.sleep(100)
        
    if success:
        if xbmcgui.Dialog().yesno(addon_name, "Import wizard finished.  You should view the import log to review any issues, enter your user ID and password (if necessary) and then try and validate a VPN connection.", "", "", "OK", "Import Log"):
            popupImportLog()
    else:
        xbmcgui.Dialog().ok(addon_name, errorMessage)
        
    return success
Пример #50
0
def importWizard():
    addon = xbmcaddon.Addon("service.vpn.manager")
    addon_name = addon.getAddonInfo("name")

    errorMessage = ""
    success = False
    cancel = False

    xbmcgui.Dialog().ok(
        addon_name,
        "The User Defined import wizard helps you set up an unsupported VPN provider.  It may not work without additional user intervention.  You should review the import log and subsequent VPN logs to debug any problems."
    )

    # Warn the user that files will be deleted and kittens will be harmed
    if xbmcgui.Dialog().yesno(
            addon_name,
            "Any existing User Defined settings and files will be deleted. Do you want to continue?",
            "", ""):
        removeGeneratedFiles()
        success = clearUserData()
        addon.setSetting("vpn_provider", "User Defined")
        if not success:
            errorMessage = "Could not clear the UserDefined directory. Check the log."
    else:
        success = False
        errorMessage = "Import wizard has not been run, no settings or files have been changed."

    # Get the list of files to be used
    if success:
        if xbmcgui.Dialog().yesno(
                addon_name,
                "Select ALL files needed to connect to the VPN provider, including .ovpn, .key and .crt files.  Select a directory (sub directories are ignored) or select multiple files within a directory?.",
                "", "", "Directory", "Files"):
            directory_input = False
            files = xbmcgui.Dialog().browse(1, "Select all VPN provider files",
                                            "files", "", False, False, "",
                                            True)
        else:
            directory_input = True
            dname = xbmcgui.Dialog().browse(
                0, "Select a directory containing VPN provider files", "files",
                "", False, False, "", False)
            debugTrace("Import from directory " + dname)
            dirs, files = xbmcvfs.listdir(dname)

        # Separate the selected files into ovpn files and other files
        ovpn_files = []
        other_files = []
        for name in files:
            if directory_input:
                name = dname + name
            debugTrace("Found file " + name)
            if name.endswith(".ovpn"):
                ovpn_files.append(name)
            else:
                other_files.append(name)
        if len(ovpn_files) == 0:
            success = False
            errorMessage = "No .ovpn files found.  You must provide at least one .ovpn file."

    # Copy and modify the ovpn files
    if success:

        # Create some logs to write out later
        summary = []
        detail = []

        summary.append("Importing selected files to User Defined directory, " +
                       getUserDataPath("UserDefined/") + "\n")
        summary.append("at " + time.strftime('%Y-%m-%d %H:%M:%S') + "\n")
        detail.append("\n=== Import details ===\n\n")

        update = False
        rename = False
        if xbmcgui.Dialog().yesno(
                addon_name,
                "Update the .ovpn files to best guess values and determine the best User Defined provider settings (recommended)?",
                "", ""):
            update = True
            detail.append("Updating the .ovpn files to best guess settings\n")
            if xbmcgui.Dialog().yesno(
                    addon_name,
                    "Rename the .ovpn files to indicate either a UDP or TCP connection type to allow filtering of connections?",
                    "", ""):
                rename = True
                detail.append("Files will be renamed to indicate UDP or TCP\n")

        # Display dialog to show progress of copying files
        dialog_step = 100 / (len(ovpn_files) + len(other_files))
        progress = xbmcgui.DialogProgress()
        progress_title = "Copying User Defined files."
        progress.create(addon_name, progress_title)
        prog_step = 0
        xbmc.sleep(500)
        try:
            dest_path = getUserDataPath("UserDefined/")
            debugTrace("Checking directory path exists before copying " +
                       dest_path)
            if not os.path.exists(dest_path):
                infoTrace("import.py", "Creating " + dest_path)
                os.makedirs(os.path.dirname(dest_path))
                xbmc.sleep(500)
                # Loop around waiting for the directory to be created.  After 10 seconds we'll carry
                # on and let he open file calls fail and throw an exception
                t = 0
                while not os.path.exists(os.path.dirname(dest_path)):
                    if t == 9:
                        errorTrace(
                            "vpnprovider.py",
                            "Waited 10 seconds to create directory but it never appeared"
                        )
                        break
                    xbmc.sleep(1000)
                    t += 1
            other_files_count = []
            for fname in other_files:
                path, dest_name = os.path.split(fname)
                dest_name = getUserDataPath("UserDefined/" + dest_name)
                # Report file being copied, then do it
                progress_message = "Copying " + fname
                progress.update(prog_step, progress_title, progress_message)
                xbmc.sleep(100)
                prog_step += dialog_step
                infoTrace("import.py", "Copying " + fname + " to " + dest_name)
                detail.append("Copying " + fname + " to " + dest_name + "\n")
                xbmcvfs.copy(fname, dest_name)
                if not xbmcvfs.exists(dest_name):
                    raise IOError('Failed to copy user def file ' + fname +
                                  " to " + dest_name)
                other_files_count.append(0)
                if progress.iscanceled():
                    cancel = True
                    break
            auth_count = 0
            auth_found = 0
            cert_count = 0
            cert_found = 0
            multiple_certs = False
            last_cert_found = ""
            ecert_count = 0
            key_count = 0
            key_found = 0
            key_pass_found = 0
            key_pass_count = 0
            multiple_keys = False
            last_key_found = ""
            ekey_count = 0
            if not cancel:
                metadata = getGitMetaData("UserDefined")
                mods = []
                if not metadata == None:
                    for line in metadata:
                        line = line.strip(' \t\n\r')
                        mods.append(line)
                for oname in ovpn_files:
                    path, dest_name = os.path.split(oname)
                    dest_name = getUserDataPath("UserDefined/" + dest_name)

                    # Update dialog to saywhat's happening
                    if update:
                        progress_message = "Copying and updating " + oname
                    else:
                        progress_message = "Copying " + oname
                    progress.update(prog_step, progress_title,
                                    progress_message)
                    xbmc.sleep(100)
                    prog_step += dialog_step

                    # Copy the ovpn file
                    infoTrace("import.py",
                              "Copying " + oname + " to " + dest_name)
                    detail.append("Copying " + oname + " to " + dest_name +
                                  "\n")
                    xbmcvfs.copy(oname, dest_name)
                    if not xbmcvfs.exists(dest_name):
                        raise IOError('Failed to copy user def ovpn ' + oname +
                                      " to " + dest_name)

                    if update:
                        # Read the copied file in and then overwrite it with any updates needed
                        # Was doing a read from source and write here but this failed on Linux over an smb mount (file not found)
                        auth = False
                        keypass = False
                        infoTrace("import.py", "Updating " + dest_name)
                        detail.append("Updating " + dest_name + "\n")
                        source_file = open(dest_name, 'r')
                        source = source_file.readlines()
                        source_file.close()
                        dest_file = open(dest_name, 'w')
                        proto = "UDP"
                        flags = [False, False, False, False, False]
                        for line in source:
                            line = line.strip(' \t\n\r')
                            old_line = line
                            i = 0
                            # Look for each non ovpn file uploaded and update it to make sure the path is good
                            for fname in other_files:
                                path, name = os.path.split(fname)
                                if not line.startswith("#"):
                                    params = line.split()
                                    if len(params) == 2:
                                        # Remove the separator in order to get any fully qualified filename as space delimited
                                        params[1].replace(getSeparator(), " ")
                                        # Add in a leading space for unqualified filenames
                                        params[1] = " " + params[1]
                                        if params[1].endswith(" " + name):
                                            old_line = line
                                            line = params[
                                                0] + " " + "#PATH" + getSeparatorOutput(
                                                ) + name
                                            detail.append("  Found " + name +
                                                          ", old line was : " +
                                                          old_line + "\n")
                                            detail.append("  New line is " +
                                                          line + "\n")
                                            other_files_count[i] += 1
                                            if line.startswith(
                                                    "auth-user-pass"):
                                                auth_found += 1
                                                auth = True
                                            if line.startswith("cert "):
                                                cert_found += 1
                                            if line.startswith("key "):
                                                key_found += 1
                                            if line.startswith("askpass "):
                                                key_pass_found += 1
                                                keypass = True
                                i += 1
                            # Do some tag counting to determine authentication methods to use
                            if not line.startswith("#"):
                                for mod in mods:
                                    flag, verb, parms = mod.split(",")
                                    if flag == "1" and line.startswith(
                                            verb) and parms in line:
                                        flags[0] = True
                                    if flag == "3" and line.startswith(verb):
                                        flags[2] = True
                                    if flag == "4" and line.startswith(verb):
                                        line = verb + " " + parms
                                    if flag == "5" and not flags[
                                            4] and verb in line:
                                        detail.append("  WARNING, " + parms +
                                                      "\n")
                                        flags[4] = True
                                if line.startswith("auth-user-pass"):
                                    auth_count += 1
                                    if not auth:
                                        line = "auth-user-pass #PATH" + getSeparatorOutput(
                                        ) + "pass.txt"
                                if line.startswith("cert "):
                                    cert_count += 1
                                    if not last_cert_found == old_line:
                                        if not last_cert_found == "":
                                            multiple_certs = True
                                        last_cert_found = old_line
                                if line.startswith("key "):
                                    key_count += 1
                                    if not last_key_found == old_line:
                                        if not last_key_found == "":
                                            multiple_keys = True
                                        last_key_found = old_line
                                if line.startswith("askpass"):
                                    key_pass_count += 1
                                    if not keypass:
                                        line = "askpass #PATH" + getSeparatorOutput(
                                        ) + "key.txt"
                                if line.startswith("proto "):
                                    if "tcp" in (line.lower()): proto = "TCP"
                                if line.startswith("<cert>"):
                                    ecert_count += 1
                                if line.startswith("<key>"):
                                    ekey_count += 1
                            if not flags[2]: dest_file.write(line + "\n")
                            flags[2] = False
                        for mod in mods:
                            flag, verb, parms = mod.split(",")
                            if flag == "2":
                                dest_file.write(verb + "\n")
                        dest_file.close()
                        flags[4] = False
                        if flags[0]:
                            if xbmcvfs.exists(dest_name):
                                xbmcvfs.delete(dest_name)
                            detail.append(
                                "  wARNING, couldn't import file as it contains errors or is unsupported\n"
                            )
                        elif rename:
                            proto = " (" + proto + ").ovpn"
                            new_name = dest_name.replace(".ovpn", proto)
                            if not xbmcvfs.exists(new_name):
                                xbmcvfs.rename(dest_name, new_name)
                                detail.append("  Renamed to " + new_name +
                                              "\n")
                            else:
                                detail.append(
                                    "  WARNING, couldn't rename file to " +
                                    new_name +
                                    " as a file with that name already exists\n"
                                )

                    if progress.iscanceled():
                        cancel = True
                        break

        except Exception as e:
            errorTrace("import.py", "Failed to copy (or update) file")
            errorTrace("import.py", str(e))
            success = False
            errorMessage = "Failed to copy (or update) selected files.  Check the log."

        progress_message = "Outputting results of import wizard"
        progress.update(100, progress_title, progress_message)
        xbmc.sleep(500)

        # General import results
        summary.append("\n=== Summary of import ===\n\n")
        if cancel:
            summary.append("Import was cancelled\n")
        else:
            summary.append("Imported " + str(len(ovpn_files)) +
                           " .ovpn files and " + str(len(other_files)) +
                           " other files.\n")
            summary.append(
                "\nYou should understand any WARNINGs below, and validate that the .ovpn files imported have been updated correctly.\n\n"
            )
            summary.append(
                "If the VPN connection fails view the VPN log to determine why, using Google to understand the errors if necessary.\n"
            )
            summary.append(
                "You can fix problems either by editing your local files and re-importing, or by editing the contents of the User Defined directory.\n\n"
            )

            if update:
                # Report on how user names and passwords will be handled
                if auth_count > 0:
                    if auth_found > 0:
                        # Not using a password as resolved by file
                        addon.setSetting("user_def_credentials", "false")
                        summary.append(
                            "The auth-user-pass tag was found " +
                            str(auth_count) +
                            " times, but was resolved using a supplied file so user name and password don't need to be entered.\n"
                        )
                        if not auth_found == auth_count:
                            summary.append(
                                "  WARNING : The auth-user-pass tag was found "
                                + str(auth_count) +
                                " times, but only resolved using a supplied file "
                                + str(auth_found) +
                                " times. Some connections may not work.\n")
                    else:
                        # Using a password as auth-user-pass tag was found
                        addon.setSetting("user_def_credentials", "true")
                        summary.append(
                            "The auth-user-pass tag was found " +
                            str(auth_count) +
                            " times so assuming user name and password authentication is used.\n"
                        )
                    if auth_count < len(ovpn_files):
                        summary.append(
                            "  WARNING : The auth-user-pass tag was only found in "
                            + str(auth_count) + " .ovpn files, out of " +
                            str(len(ovpn_files)) +
                            ". Some connections may not work.\n")
                else:
                    # Not using a password as no auth-user-pass tag was found
                    addon.setSetting("user_def_credentials", "false")
                    summary.append(
                        "No auth-user-pass tag was found, so assuming user name and password is not needed.\n"
                    )

                # Report on how keys and certs will be handled
                if (cert_count > 0 or key_count > 0):
                    summary.append("The key tag was found " + str(key_count) +
                                   " times, and the cert tag was found " +
                                   str(cert_count) + " times.\n")
                    if cert_found > 0 or key_found > 0:
                        # Key and cert resolved by file so not asking user for them
                        addon.setSetting("user_def_keys", "None")
                        summary.append(
                            "The key and certificate don't need to be requested as the key tags were resolved using a supplied file "
                            + str(key_found) +
                            " times, and the cert tags were resolved using a supplied file "
                            + str(cert_found) + " times.\n")
                        if (not cert_found == cert_count) or (not key_found
                                                              == key_count):
                            summary.append(
                                "  WARNING : The key or cert tags were not resolved by a supplied file for all occurrences. Some connections may not work.\n"
                            )
                    else:
                        if multiple_certs or multiple_keys:
                            # Key and cert tags found with different file names, but no files supplied.  Assume multiple files, user supplied
                            addon.setSetting("user_def_keys", "Multiple")
                            summary.append(
                                "Found key and cert tags with multiple filenames, but no key or certificate files were supplied. These will be requested during connection.\n"
                            )
                        else:
                            # Key and cert tags found with same file names, but no files supplied.  Assume single file, user supplied
                            addon.setSetting("user_def_keys", "Single")
                            summary.append(
                                "Found key and cert tags all with the same filename, but no key or certificate files were supplied. These will be requested during connection.\n"
                            )
                    if cert_count < len(ovpn_files) or key_count < len(
                            ovpn_files):
                        summary.append(
                            "  WARNING : The key tag was found " +
                            str(key_count) +
                            " times, and the cert tag was found " +
                            str(cert_count) +
                            " times. Expected to find one of each in all " +
                            str(len(ovpn_files)) +
                            " .ovpn files. Some connections may not work.\n")
                else:
                    # Embedded key and certs found, so not asking user for them
                    addon.setSetting("user_def_keys", "None")
                    if (ekey_count > 0 or ecert_count > 0):
                        if ekey_count == ecert_count and key_count == len(
                                ovpn_files):
                            summary.append(
                                "Using embedded user keys and certificates so keys and certs don't need to be entered.\n"
                            )
                        else:
                            summary.append(
                                "  WARNING : Using embedded user keys and certificates, but found "
                                + str(ekey_count) + " keys and " +
                                str(ecert_count) + " certificates in " +
                                str(len(ovpn_files)) +
                                " .ovpn files. There should be one of each in all .ovpn files otherwise some connections may not work.\n"
                            )
                    else:
                        summary.append(
                            "No user key or cert tags were found so assuming this type of authentication is not used.\n"
                        )

                # Report on how key passwords will be handled
                if key_pass_count > 0:
                    if key_pass_found > 0:
                        # Not using a password as resolved by file
                        addon.setSetting("user_def_key_password", "false")
                        summary.append(
                            "The askpass tag was found " + str(auth_count) +
                            " times, but was resolved using a supplied file so the key password doesn't need to be entered.\n"
                        )
                        if not key_pass_found == key_pass_count:
                            summary.append(
                                "  WARNING : The askpass tag was found " +
                                str(key_pass_count) +
                                " times, but only resolved using a supplied file "
                                + str(key_pass_found) +
                                " times. Some connections may not work.\n")
                    else:
                        # Using a password as auth-user-pass tag was found
                        addon.setSetting("user_def_key_password", "true")
                        summary.append(
                            "The askpass tag was found " +
                            str(key_pass_count) +
                            " times so assuming key password authentication is used.\n"
                        )
                    if key_pass_count < len(ovpn_files):
                        summary.append(
                            "  WARNING : The askpass tag was only found in " +
                            str(key_pass_count) + " .ovpn files, out of " +
                            str(len(ovpn_files)) +
                            ". Some connections may not work, or you may be asked to enter a password when it's not necessary.\n"
                        )
                else:
                    # Not using a password as no askpass tag was found
                    addon.setSetting("user_def_key_password", "false")
                    summary.append(
                        "No askpass tag was found, so assuming key password is not needed.\n"
                    )

                # Report how many times each of the non .ovpn files were used
                i = 0
                for oname in other_files:
                    summary.append("File " + oname +
                                   " was found and used in .ovpn files " +
                                   str(other_files_count[i]) + " times.\n")
                    if not other_files_count[i] == len(ovpn_files):
                        if other_files_count[i] == 0:
                            summary.append(
                                "  WARNING : " + oname +
                                " was not used to update any .ovpn files and could be unused.\n"
                            )
                        else:
                            summary.append(
                                "  WARNING : The number of updates for " +
                                oname +
                                " was different to the number of .ovpn files, "
                                + str(len(ovpn_files)) +
                                ", which could be a problem.\n")
                    i += 1
            else:
                summary.append(
                    "None of the files were updated during import.\n")

        # Open a log file so all changes can be recorded without fouling up the kodi log
        log_name = getImportLogPath()
        if xbmcvfs.exists(log_name): xbmcvfs.delete(log_name)
        log_file = open(log_name, 'w')
        for line in summary:
            log_file.write(line)
        for line in detail:
            log_file.write(line)
        log_file.close()

        progress.close()
        xbmc.sleep(100)

    if success:
        if xbmcgui.Dialog().yesno(
                addon_name,
                "Import wizard finished.  You should view the import log to review any issues, enter your user ID and password (if necessary) and then try and validate a VPN connection.",
                "", "", "OK", "Import Log"):
            popupImportLog()
    else:
        xbmcgui.Dialog().ok(addon_name, errorMessage)

    return success
Пример #51
0
def copyKeyAndCert(vpn_provider, ovpn_name, user_key, user_cert):
    # Copy the user key and cert to the userdata directory
    key_dest = getUserDataPath(vpn_provider + "/" + getKeyName(vpn_provider, ovpn_name))
    key_source = user_key
    cert_dest = getUserDataPath(vpn_provider + "/" + getCertName(vpn_provider, ovpn_name))
    cert_source = user_cert
    if key_source == cert_source:
        # This means that a .ovpn was selected
        try:
            debugTrace("Extracing key and cert from " + key_source + " to " + key_dest + " and " + cert_dest)
            ovpn_file = open(key_source, 'r')
            ovpn = ovpn_file.readlines()
            ovpn_file.close()
            debugTrace("Checking directory path exists for key and cert " + os.path.dirname(key_dest))
            if not os.path.exists(os.path.dirname(key_dest)):
                infoTrace("vpnprovider.py", "Creating " + os.path.dirname(key_dest))
                os.makedirs(os.path.dirname(key_dest))
                xbmc.sleep(500)
                # Loop around waiting for the directory to be created.  After 10 seconds we'll carry 
                # on and let he open file calls fail and throw an exception
                t = 0
                while not os.path.exists(os.path.dirname(key_dest)):
                    if t == 9:
                        errorTrace("vpnprovider.py", "Waited 10 seconds to create directory but it never appeared")
                        break
                    xbmc.sleep(1000)
                    t += 1
            key_file = open(key_dest, 'w')
            cert_file = open(cert_dest, 'w')
            key = False
            cert = False
            key_count = 0
            cert_count = 0
            for line in ovpn:
                line = line.strip(' \t\n\r')
                if line.startswith("<key>"): key = True
                elif line.startswith("</key>"): key = False
                elif line.startswith("<cert>"): cert = True
                elif line.startswith("</cert>"): cert = False
                else:
                    if key: 
                        key_file.write(line + "\n")
                        key_count += 1
                    if cert: 
                        cert_file.write(line + "\n")
                        cert_count += 1
            key_file.close()
            cert_file.close()
            if key_count > 0 and cert_count > 0:
                return True
            else:
                # Couldn't extract key and/or cert, delete any remains and return error
                errorTrace("vpnproviders.py", "Failed to extract user key or cert file from ovpn.  Key size was " + str(key_count) + " and cert size was " + str(cert_count))
                if xbmcvfs.exists(key_dest): xbmcvfs.delete(key_dest)
                if xbmcvfs.exists(cert_dest): xbmcvfs.delete(cert_dest)
                return False
        except Exception as e:
            errorTrace("vpnproviders.py", "Failed to copy user key or cert file to userdata")
            errorTrace("vpnproviders.py", str(e))
            return False  
    else:
        # Individual key and crt files were selected
        try:
            debugTrace("Copying key " + key_source + " to " + key_dest)
            if xbmcvfs.exists(key_dest): xbmcvfs.delete(key_dest)
            xbmcvfs.copy(key_source, key_dest)
            if not xbmcvfs.exists(key_dest): raise IOError('Failed to copy key ' + key_source + " to " + key_dest)
            debugTrace("Copying cert " + cert_source + " to " + cert_dest)
            if xbmcvfs.exists(cert_dest): xbmcvfs.delete(cert_dest)
            xbmcvfs.copy(cert_source, cert_dest)
            if not xbmcvfs.exists(cert_dest): raise IOError('Failed to copy cert ' + cert_source + " to " + cert_dest)
            return True
        except Exception as e:
            errorTrace("vpnproviders.py", "Failed to copy user key or cert file to userdata")
            errorTrace("vpnproviders.py", str(e))
            return False
Пример #52
0
def refreshFromGit(vpn_provider, progress):
    addon = xbmcaddon.Addon("service.vpn.manager")
    infoTrace("vpnproviders.py", "Checking downloaded ovpn files for " + vpn_provider + " with GitHub files")
    progress_title = "Updating files for " + vpn_provider
    try:
        # Create the download directories if required
        path = getUserDataPath("Downloads/")
        if not xbmcvfs.exists(path): xbmcvfs.mkdir(path)
        path = getUserDataPath("Downloads/" + vpn_provider + "/")
        if not xbmcvfs.exists(path): xbmcvfs.mkdir(path)
    except Exception as e:
        # Can't create the download directory
        errorTrace("vpnproviders.py", "Can't create the download directory " + path)
        errorTrace("vpnproviders.py", str(e))
        return False
    
    # Download the metadata file
    metadata = getGitMetaData(vpn_provider)
    if metadata == None: return False
    git_timestamp, version, total_files, file_list = parseGitMetaData(metadata)
    timestamp = ""

    try:
        addon_version = int(addon.getSetting("version_number").replace(".",""))
    except:
        addon_version = int(addon.getAddonInfo("version").replace(".", ""))
    if addon_version < int(version):
        errorTrace("vpnproviders.py", "VPN Manager version is " + str(addon_version) + " and version " + version + " is needed for this VPN.")
        return False  
    
    try:
        # Get the timestamp from the previous update
        last_file = open(getUserDataPath("Downloads" + "/" + vpn_provider + "/METADATA.txt"), 'r')
        last = last_file.readlines()
        last_file.close()
        # If there's a metadata file in the user directory but we had a problem with Github, just
        # return True as there's a likelihood that there's something interesting to work with
        if file_list is None: 
            if progress is not None:
                progress_message = "Unable to download files, using existing files."
                progress.update(10, progress_title, progress_message)
                infoTrace("vpnproviders.py", "Couldn't download files so using existing files for " + vpn_provider)
                xbmc.sleep(1000)
            return True
        timestamp = last[0]
    except Exception as e:
        # If the metadata can't be read and there's nothing we can get from Github, return
        # badness, otherwise we can read from Github and should just carry on.
        if file_list is None: 
            errorTrace("vpnproviders.py", "Couldn't download any files from Github for " + vpn_provider)
            return False
        
    # Check the timestamp and if it's not the same clear out the directory for new files
    if timestamp == git_timestamp:                
        debugTrace("VPN provider " + vpn_provider + " up to date, timestamp is " + git_timestamp)
        if progress is not None:
            progress_message = "VPN provider files don't need updating"
            progress.update(10, progress_title, progress_message)
            xbmc.sleep(500)
        return True
    else: timestamp = git_timestamp
    debugTrace("VPN provider " + vpn_provider + " needs updating, deleting existing files")
    # Clear download files for this VPN
    existing = glob.glob(getUserDataPath("Downloads" + "/" + vpn_provider + "/*.*"))
    for file in existing:
        try: xbmcvfs.delete(file)
        except: pass

    # Download and store the updated files        
    error_count = 0
    file_count = 0
    progress_count = float(1)
    progress_inc = float(99/float(total_files))
    for file in file_list:
        try:
            #debugTrace("Downloading " + file)
            if progress is not None:
                progress_count += progress_inc
                if progress.iscanceled(): return False
                progress_message = "Downloading " + file
                progress.update(int(progress_count), progress_title, progress_message)
            download_url = "https://raw.githubusercontent.com/Zomboided/service.vpn.manager.providers/master/" + vpn_provider + "/" + file
            download_url = download_url.replace(" ", "%20")
            git_file = urllib2.urlopen(download_url)
            file = file.strip(' \n')
            output = open(getUserDataPath("Downloads" + "/" + vpn_provider + "/" + file), 'w')
            for line in git_file:
                output.write(line)
            output.close()
        except Exception as e:
            errorTrace("vpnproviders.py", "Can't download " + file)
            errorTrace("vpnproviders.py", str(e))
            error_count += 1
            # Bail after 5 failures as it's likely something bad is happening.  Don't fail
            # immediately because it could just be an error with one or two locations
            if error_count > 5: return False
        # Uncomment the next line to make testing NordVPN download easier....
        # if file_count == 20: break
        file_count += 1
    debugTrace("Processed " + str(file_count) + " files for " + vpn_provider)
                
    # Write the update timestamp
    debugTrace("Updated VPN provider " + vpn_provider + " new timestamp is " + timestamp)
    output = open(getUserDataPath("Downloads" + "/" + vpn_provider + "/METADATA.txt"), 'w')
    output.write(timestamp + "\n")
    output.close()
    if progress is not None:
        progress_message = "VPN provider files updated, removing old ones"
        progress.update(10, progress_title, progress_message)
        # Delete any generated files and reset the connection
        removeGeneratedFiles()
        # Adjust 11 below if changing number of conn_max
        i = 1
        while i < 11:
            addon.setSetting(str(i) + "_vpn_validated", "")
            addon.setSetting(str(i) + "_vpn_validated_friendly", "")
            i = i + 1
        xbmc.sleep(500)
    return True
Пример #53
0
def getIPInfoFrom(source):
    # Generate request to find out where this IP is based
    # Successful return is ip, country, region, city, isp 
    # Otherwise error strings are returned for the caller to parse
    try:
        # Determine the URL, make the call and read the response
        url = getIPSourceURL(source)
        if url == "": return "error", "error", "error", "unknown source", ""
        if ifHTTPTrace(): debugTrace("Using " + url)
        req = urllib2.Request(url)
        req.add_header("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0")
        response = urllib2.urlopen(req, timeout = 10)
        json_data = json.load(response)   
        response.close()
        if ifJSONTrace(): infoTrace("ipinfo.py", "JSON received is \n" + json.dumps(json_data, indent=4))
    except urllib2.HTTPError as e:
        errorTrace("ipinfo.py", "Couldn't connect to IP provider " + source)
        errorTrace("ipinfo.py", "API call was " + url)
        errorTrace("ipinfo.py", "Response was " + str(e.code) + " " + e.reason)
        errorTrace("ipinfo.py", e.read())
        recordError(source)
        return "error", "unknown location", "unknown location", "call failed", "unknown ISP"
    except Exception as e:
        errorTrace("ipinfo.py", "Couldn't connect to IP provider " + source)
        errorTrace("ipinfo.py", "API call was " + url)
        errorTrace("ipinfo.py", "Response was " + str(type(e)) + " " + str(e))
        recordError(source)
        return "no response", "error", "error", "connection failed", "unknown ISP"
        
    try:
        if source == "ipinfo.io": ip, country, region, city, isp = getipinfo(json_data)
        if source == "IP-API": ip, country, region, city, isp = getIPAPI(json_data)
        if source == "ipstack": ip, country, region, city, isp = getipstack(json_data)
        
        if not ip == None:
            recordWorking(source)
            return ip, country, region, city, isp
        else:
            errorTrace("ipinfo.py", "Couldn't get data from " + "source")
            recordError(source)
            return "no info", "unknown location", "unknown location", "no matches", "unknown ISP"
    except Exception as e:
        errorTrace("ipinfo.py", "Couldn't parse response from IP provider " + source)
        errorTrace("ipinfo.py", str(e))
        recordError(source)
        return "error", "error", "error", "parse failed", "unknown ISP"