From f2c6e6b5ca6569b027654c165dc61c728af1f58f Mon Sep 17 00:00:00 2001 From: Blatzar <46196380+Blatzar@users.noreply.github.com> Date: Sat, 19 Sep 2020 11:30:15 +0200 Subject: [PATCH] Flag to skip ssl validation (#45) Flag to skip ssl validation (#45) --- ChangeLog.txt | 5 ++++- docs/examples.rst | 14 +++++++++++++- pySmartDL/download.py | 6 +++--- pySmartDL/pySmartDL.py | 19 +++++++++++++++---- 4 files changed, 35 insertions(+), 9 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 5e0556f..6309fba 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -5,6 +5,9 @@ Below you find a list with the added features, changes and fixes for each version. ====================== +(Version 1.3.5 beta; ????) +- NEW: Flag to ignore ssl certificates. + (Version 1.3.4 beta; ????) - NEW: Added official support for Python 3.8. - FIX: Bug #41 @@ -72,4 +75,4 @@ each version. - FIX: Few more bugfixes. (Version 1.0.0 alpha; 01/01/14) -- first alpha beta release \ No newline at end of file +- first alpha beta release diff --git a/docs/examples.rst b/docs/examples.rst index 5b077dd..e122a1d 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -154,4 +154,16 @@ Example with passing `blocking=False` to `obj.start()`:: else: print("Download failed with the following exceptions:") for e in obj.get_errors(): - print(unicode(e)) \ No newline at end of file + print(unicode(e)) + +============================== +Example 8: No ssl verification +============================== +:: + + from pySmartDL import SmartDL + + obj = SmartDL("https://github.com/iTaybb/pySmartDL/raw/master/test/7za920.zip", verify=False) + obj.start() + + # Do something with obj.get_dest() diff --git a/pySmartDL/download.py b/pySmartDL/download.py index b21b759..4f47517 100644 --- a/pySmartDL/download.py +++ b/pySmartDL/download.py @@ -1,10 +1,9 @@ import os import urllib.request, urllib.error, urllib.parse import time - from . import utils -def download(url, dest, requestArgs=None, startByte=0, endByte=None, timeout=4, shared_var=None, thread_shared_cmds=None, logger=None, retries=3): +def download(url, dest, requestArgs=None, context=None, startByte=0, endByte=None, timeout=4, shared_var=None, thread_shared_cmds=None, logger=None, retries=3): "The basic download function that runs at each thread." logger = logger or utils.DummyLogger() req = urllib.request.Request(url, **requestArgs) @@ -12,7 +11,8 @@ def download(url, dest, requestArgs=None, startByte=0, endByte=None, timeout=4, req.add_header('Range', 'bytes={:.0f}-{:.0f}'.format(startByte, endByte)) logger.info("Downloading '{}' to '{}'...".format(url, dest)) try: - urlObj = urllib.request.urlopen(req, timeout=timeout) + # Context is used to skip ssl validation if verify is False. + urlObj = urllib.request.urlopen(req, timeout=timeout, context=context) except urllib.error.HTTPError as e: if e.code == 416: ''' diff --git a/pySmartDL/pySmartDL.py b/pySmartDL/pySmartDL.py index 4a622cf..719da12 100644 --- a/pySmartDL/pySmartDL.py +++ b/pySmartDL/pySmartDL.py @@ -14,6 +14,7 @@ import multiprocessing.dummy as multiprocessing from ctypes import c_int import json +import ssl from . import utils from .control_thread import ControlThread @@ -22,7 +23,7 @@ __all__ = ['SmartDL', 'utils'] __version_mjaor__ = 1 __version_minor__ = 3 -__version_micro__ = 4 +__version_micro__ = 5 __version__ = "{}.{}.{}".format(__version_mjaor__, __version_minor__, __version_micro__) class HashFailedException(Exception): @@ -68,6 +69,8 @@ class SmartDL: :param request_args: Arguments to be passed to a new urllib.request.Request instance in dictionary form. See `urllib.request docs `_ for options. :type request_args: dict :rtype: `SmartDL` instance + :param verify: If ssl certificates should be validated. + :type verify: bool .. NOTE:: The provided dest may be a folder or a full path name (including filename). The workflow is: @@ -78,7 +81,7 @@ class SmartDL: * If no path is provided, `%TEMP%/pySmartDL/` will be used. ''' - def __init__(self, urls, dest=None, progress_bar=True, fix_urls=True, threads=5, timeout=5, logger=None, connect_default_logger=False, request_args=None): + def __init__(self, urls, dest=None, progress_bar=True, fix_urls=True, threads=5, timeout=5, logger=None, connect_default_logger=False, request_args=None, verify=True): if logger: self.logger = logger elif connect_default_logger: @@ -141,6 +144,13 @@ def __init__(self, urls, dest=None, progress_bar=True, fix_urls=True, threads=5, self.logger.info("Creating a ThreadPool of {} thread(s).".format(self.threads_count)) self.pool = utils.ManagedThreadPoolExecutor(self.threads_count) + + if verify: + self.context = None + else: + self.context = ssl.create_default_context() + self.context.check_hostname = False + self.context.verify_mode = ssl.CERT_NONE def __str__(self): return 'SmartDL(r"{}", dest=r"{}")'.format(self.url, self.dest) @@ -250,11 +260,11 @@ def start(self, blocking=None): self.logger.info("Destination '%s' already exists, and the hash matches. No need to download." % self.dest) self.status = 'finished' return - + self.logger.info("Downloading '{}' to '{}'...".format(self.url, self.dest)) req = urllib.request.Request(self.url, **self.requestArgs) try: - urlObj = urllib.request.urlopen(req, timeout=self.timeout) + urlObj = urllib.request.urlopen(req, timeout=self.timeout, context=self.context) except (urllib.error.HTTPError, urllib.error.URLError, socket.timeout) as e: self.errors.append(e) if self.mirrors: @@ -292,6 +302,7 @@ def start(self, blocking=None): self.url, self.dest+".%.3d" % i, self.requestArgs, + self.context, arg[0], arg[1], self.timeout,