X-Git-Url: http://gitweb.michael.orlitzky.com/?p=untangle-https-backup.git;a=blobdiff_plain;f=src%2Funtangle%2Funtangle.py;h=8ce4fb7f39b3017c49cfdd0295787ac047319862;hp=f8fd795aa49dbb3533d8f7a45d005a4d80f0b584;hb=HEAD;hpb=4139a215c947d187f2c30004088cfe58d294c6fb diff --git a/src/untangle/untangle.py b/src/untangle/untangle.py index f8fd795..8ce4fb7 100644 --- a/src/untangle/untangle.py +++ b/src/untangle/untangle.py @@ -18,12 +18,14 @@ class Untangle: self.host = s['host'] self.username = s.get('username', 'admin') self.password = s['password'] - self.version = int(s.get('version', '12')) + self.timeout = s.get('timeout', 300) self.base_url = 'https://' + self.host + '/' # This never changes # Sanity check the numerical version. - if self.version not in [9, 11]: - msg = 'Invalid version "' + str(self.version) + '" ' + self.version = s.get('version', '14.1') + if self.version not in ['9', '10', '11', '12', '13', '13.1', + '14', '14.1']: + msg = 'Invalid version "' + self.version + '" ' msg += 'in section "' + s.name + '"' raise configparser.ParsingError(msg) @@ -38,7 +40,25 @@ class Untangle: msg += 'in section "' + s.name + '"' raise configparser.ParsingError(msg) - # + # Sanity check the integer "timeout" parameter. We want to + # bail if either the given parameter is not an integer, or if + # it's negative. To handle both at the same time, we try to + # parse an integer... + timeout = s.get('timeout', 300) + try: + self.timeout = int(timeout) + except: + # ...and set self.timeout to a negative value if we can't... + self.timeout = -1 + + # Now we check to see if the timeout value is negative. That + # will happen if it was either negative to begin with, or + # non-integer (and we set it negative). + if self.timeout < 0: + msg = 'Invalid value "' + timeout + '" for timeout ' + msg += 'in section "' + s.name + '"' + raise configparser.ParsingError(msg) + # Finally, create a URL opener to make HTTPS requests. # # First, create a cookie jar that we'll attach to our URL @@ -48,10 +68,10 @@ class Untangle: # SSL mumbo jumbo to make it ignore the certificate's hostname # when verify_cert = False. - if self.verify_cert: - ssl_ctx = ssl.create_default_context() - else: - ssl_ctx = ssl._create_unverified_context() + ssl_ctx = ssl.create_default_context() + if not self.verify_cert: + ssl_ctx.check_hostname = False + ssl_ctx.verify_mode = ssl.CERT_NONE https_handler = urllib.request.HTTPSHandler(context=ssl_ctx) @@ -60,6 +80,15 @@ class Untangle: self.opener = urllib.request.build_opener(https_handler, cookie_proc) + def open(self, url, data=None): + """ + A wrapper around ``self.opener.open()`` that uses our + configurable socket "timeout" value. Without the timeout + parameter, it seems we can wait forever in some corner cases. + """ + return self.opener.open(url, data, self.timeout) + + def login(self): """ Perform the HTTPS request to log in to the Untangle web admin @@ -69,7 +98,7 @@ class Untangle: url = self.base_url + login_path post_vars = {'username': self.username, 'password': self.password } post_data = urllib.parse.urlencode(post_vars).encode('ascii') - self.opener.open(url, post_data) + self.open(url, post_data) def get_backup(self): @@ -77,13 +106,16 @@ class Untangle: Version-agnostic get-me-a-backup method. Dispatches to the actual implementation based on ``self.version``. """ - if self.version == 9: + if self.version == '9': return self.get_backup_v9() - elif self.version == 11: - return self.get_backup_v11() - elif self.version == 12: - # The procedure for v12 is the same as for v11. - return self.get_backup_v11() + elif self.version in ['10', '11', '12', '13']: + # The procedure for v11, v12, or v13 is the same as for v10. + return self.get_backup_v10() + elif self.version in ['13.1', '14', '14.1']: + # But the minor update v13.1 moved the backup URL. + return self.get_backup_v13_1() + else: + raise ValueError('unknown version %s' % self.version) def get_backup_v9(self): @@ -97,21 +129,36 @@ class Untangle: url = self.base_url + '/webui/backup' post_vars = {'action': 'requestBackup'} post_data = urllib.parse.urlencode(post_vars).encode('ascii') - self.opener.open(url, post_data) + self.open(url, post_data) url = self.base_url + 'webui/backup?action=initiateDownload' - with self.opener.open(url) as response: + with self.open(url) as response: + return response.read() + + + def get_backup_v10(self): + """ + Retrieve a backup from Untangle version 10. + + Returns the binary HTTPS response (i.e. the file). + """ + url = self.base_url + '/webui/download' + post_vars = {'type': 'backup'} + post_data = urllib.parse.urlencode(post_vars).encode('ascii') + with self.open(url, post_data) as response: return response.read() - def get_backup_v11(self): + def get_backup_v13_1(self): """ - Retrieve a backup from Untangle version 11. + Retrieve a backup from Untangle version 13.1. This + differs from v13 (and v12, and v11,...) by only one word + in the URL: "webui" becomes "admin". Returns the binary HTTPS response (i.e. the file). """ - url = self.base_url + '/webui/download?type=backup' + url = self.base_url + '/admin/download' post_vars = {'type': 'backup'} post_data = urllib.parse.urlencode(post_vars).encode('ascii') - with self.opener.open(url, post_data) as response: + with self.open(url, post_data) as response: return response.read()