From 1b7c4afc84bf55acef350fdc5479e7213c78eaa4 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Fri, 1 Apr 2016 17:38:25 -0400 Subject: [PATCH] Reorganize the source code into a package. --- bin/untangle-https-backup | 114 ++++---------------------------------- setup.py | 6 +- src/untangle/__init__.py | 1 + src/untangle/untangle.py | 90 ++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 106 deletions(-) create mode 100644 src/untangle/__init__.py create mode 100644 src/untangle/untangle.py diff --git a/bin/untangle-https-backup b/bin/untangle-https-backup index 669c282..c01c419 100755 --- a/bin/untangle-https-backup +++ b/bin/untangle-https-backup @@ -1,110 +1,20 @@ #!/usr/bin/python3 """ -Back up Untangle configurations over HTTPS. +Back up Untangle configurations via the web admin UI. """ from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser import configparser -import http.cookiejar from os import chmod -import ssl +from urllib.error import HTTPError, URLError from sys import stderr -import urllib.parse -import urllib.request +from untangle.untangle import Untangle # Define a few exit codes. EXIT_OK = 0 EXIT_BACKUPS_FAILED = 1 - -class Untangle: - - def __init__(self, s): - """ - Initialize this Untangle object with a ConfigParser section. - """ - self.name = s.name - self.host = s['host'] - self.username = s.get('username', 'admin') - self.password = s['password'] - self.version = int(s.get('version', '11')) - 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) + '" ' - msg += 'in section "' + s.name + '"' - raise configparser.ParsingError(msg) - - # Sanity check the boolean verify_cert parameter. - vc = s.get('verify_cert', 'False') - if vc == 'True': - self.verify_cert = True - elif vc == 'False': - self.verify_cert = False - else: - msg = 'Invalid value "' + vc + '" for verify_cert ' - 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 - # opener thingy. - cj = http.cookiejar.CookieJar() - cookie_proc = urllib.request.HTTPCookieProcessor(cj) - - # 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() - - https_handler = urllib.request.HTTPSHandler(context=ssl_ctx) - - # Now Create a URL opener, and tell it to use our cookie jar - # and SSL context. We keep this around for future requests. - self.opener = urllib.request.build_opener(https_handler, cookie_proc) - - - def login(self): - login_path = 'auth/login?url=/setup/welcome.do&realm=Administrator' - 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) - - - def get_backup(self): - if self.version == 9: - return self.get_backup_v9() - elif self.version == 11: - return self.get_backup_v11() - - - def get_backup_v9(self): - 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) - - url = self.base_url + 'webui/backup?action=initiateDownload' - with self.opener.open(url) as response: - return response.read() - - - def get_backup_v11(self): - url = self.base_url + '/webui/download?type=backup' - post_vars = {'type': 'backup'} - post_data = urllib.parse.urlencode(post_vars).encode('ascii') - with self.opener.open(url, post_data) as response: - return response.read() - - - # Create an argument parser using our docsctring as its description. parser = ArgumentParser(description = __doc__, formatter_class = ArgumentDefaultsHelpFormatter) @@ -123,23 +33,21 @@ config = configparser.ConfigParser() config.read(args.config_file) for section in config.sections(): - untangle = Untangle(config[section]) + u = Untangle(config[section]) try: - untangle.login() - backup = untangle.get_backup() - filename = untangle.name + '.backup' + u.login() + backup = u.get_backup() + filename = u.name + '.backup' with open(filename, 'wb') as f: f.write(backup) chmod(filename, 0o600) - except urllib.error.URLError as e: - msg = untangle.name + ': ' + str(e.reason) - msg += ' from ' + untangle.host + except URLError as e: + msg = u.name + ': ' + str(e.reason) + ' from ' + u.host print(msg, file=stderr) status = EXIT_BACKUPS_FAILED - except urllib.error.HTTPError as e: - msg = untangle.name + ': ' + 'HTTP error ' + str(e.code) - msg += ' from ' + untangle.host + except HTTPError as e: + msg = u.name + ': ' + 'HTTP error ' + str(e.code) + ' from ' + u.host print(msg, file=stderr) status = EXIT_BACKUPS_FAILED diff --git a/setup.py b/setup.py index fc4a778..6a475b5 100644 --- a/setup.py +++ b/setup.py @@ -7,8 +7,8 @@ setup( author_email = 'michael@orlitzky.com', url = 'http://michael.orlitzky.com/code/untangle-https-backup.php', scripts = ['bin/untangle-https-backup'], + packages = ['untangle'], + package_dir = {'untangle': 'src/untangle'}, description = 'Back up Untangle configurations via the web admin UI', - long_description=open('doc/README').read(), - license = 'doc/LICENSE', - requires = 'argparse' + license = 'doc/LICENSE' ) diff --git a/src/untangle/__init__.py b/src/untangle/__init__.py new file mode 100644 index 0000000..8076a85 --- /dev/null +++ b/src/untangle/__init__.py @@ -0,0 +1 @@ +# <3 git diff --git a/src/untangle/untangle.py b/src/untangle/untangle.py new file mode 100644 index 0000000..09c5723 --- /dev/null +++ b/src/untangle/untangle.py @@ -0,0 +1,90 @@ +import configparser +import http.cookiejar +import ssl +import urllib.parse +import urllib.request + +class Untangle: + + def __init__(self, s): + """ + Initialize this Untangle object with a ConfigParser section. + """ + self.name = s.name + self.host = s['host'] + self.username = s.get('username', 'admin') + self.password = s['password'] + self.version = int(s.get('version', '11')) + 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) + '" ' + msg += 'in section "' + s.name + '"' + raise configparser.ParsingError(msg) + + # Sanity check the boolean verify_cert parameter. + vc = s.get('verify_cert', 'False') + if vc == 'True': + self.verify_cert = True + elif vc == 'False': + self.verify_cert = False + else: + msg = 'Invalid value "' + vc + '" for verify_cert ' + 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 + # opener thingy. + cj = http.cookiejar.CookieJar() + cookie_proc = urllib.request.HTTPCookieProcessor(cj) + + # 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() + + https_handler = urllib.request.HTTPSHandler(context=ssl_ctx) + + # Now Create a URL opener, and tell it to use our cookie jar + # and SSL context. We keep this around for future requests. + self.opener = urllib.request.build_opener(https_handler, cookie_proc) + + + def login(self): + login_path = 'auth/login?url=/setup/welcome.do&realm=Administrator' + 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) + + + def get_backup(self): + if self.version == 9: + return self.get_backup_v9() + elif self.version == 11: + return self.get_backup_v11() + + + def get_backup_v9(self): + 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) + + url = self.base_url + 'webui/backup?action=initiateDownload' + with self.opener.open(url) as response: + return response.read() + + + def get_backup_v11(self): + url = self.base_url + '/webui/download?type=backup' + post_vars = {'type': 'backup'} + post_data = urllib.parse.urlencode(post_vars).encode('ascii') + with self.opener.open(url, post_data) as response: + return response.read() -- 2.43.2