Sfoglia il codice sorgente

Parse enabled nginx vhosts

Benoît Hubert 7 anni fa
parent
commit
0a274aa031
2 ha cambiato i file con 183 aggiunte e 8 eliminazioni
  1. 53 8
      gtk3-listdomains.py
  2. 130 0
      nginxparser.py

+ 53 - 8
gtk3-listdomains.py

@@ -2,6 +2,7 @@ import gi
 gi.require_version('Gtk', '3.0')
 from gi.repository import GLib, Gtk, GObject
 import json
+from nginxparser import loads
 import re
 import spur
 import threading
@@ -15,6 +16,7 @@ def ssh_command(command, sudo=False):
     shell = spur.SshShell(
         hostname=creds['host'],
         username=creds['user'],
+	password=creds['passphrase'],
         private_key_file=creds['ssh_key_path'])
     with shell:
         command_bits = command.split(" ")
@@ -72,36 +74,79 @@ class EntryWindow(Gtk.Window):
         self.progressbar.set_text('Done: ' + domain)
         return False
 
-    def example_target(self):
+    def get_https_domains(self):
         for d in self.domains:
             GLib.idle_add(self.get_https_subdomains_for_domain, d)
-            time.sleep(0.3)
+            time.sleep(0.4)
 
+    def get_nginx_vhosts(self):
+        for v in self.vhosts:
+            GLib.idle_add(self.get_nginx_vhost, v)
+            time.sleep(0.4)
+
+    def start_thread(self, func):
+        thread = threading.Thread(target=func)
+        thread.daemon = True
+        thread.start()
 
     def on_button_clicked(self, widget):
+        decoded = ssh_command("ls /etc/nginx/sites-enabled")
+        vhosts = decoded.split("\n")
+        vhosts.pop()
+
+        self.vhosts = vhosts
+        self.num_vhosts = len(vhosts)
+        self.vhosts_done = 0
+
         decoded = ssh_command("ls /etc/letsencrypt/live", True)
         domains = decoded.split("\n")
         domains.pop()
 
         self.domains = domains
         self.num_domains = len(domains)
-        self.num_done = 0
+        self.domains_done = 0
 
-        thread = threading.Thread(target=self.example_target)
-        thread.daemon = True
-        thread.start()
+        self.start_thread(self.get_nginx_vhosts)
+        # self.start_thread(self.get_https_domains)
 
         # subdomains = [self.get_https_subdomains_for_domain(d) for d in domains]
         # subdomains_dict = dict(zip(domains, subdomains))
         # print(subdomains_dict)
 
 
+    def get_nginx_vhost(self, vhost):
+        print(vhost)
+        vhost_file = ssh_command("cat /etc/nginx/sites-enabled/" + vhost)
+        parsed = loads(vhost_file)
+        port_subdmomains = {}
+        for server in parsed:
+            server_inner = server[1]
+            port = 0
+            subdomains = []
+            for directive in server_inner:
+                if not port and "listen" in directive:
+                    p = re.compile('(\d+)')
+                    print('listen')
+                    ports = p.findall(directive[1])
+                    port = int(ports[0])
+                if "server_name" in directive:
+                    print('server_name')
+                    print(directive)
+                    subd_trimmed = directive[1].strip()
+                    subdomains = subd_trimmed.split(' ')
+            port_subdmomains[port] = subdomains
+        print(port_subdmomains)
+        self.vhosts_done += 1
+        percent_done = self.vhosts_done * 1.0 / self.num_vhosts
+        self.progressbar.set_fraction(percent_done)
+        return False
+
     def get_https_subdomains_for_domain(self, domain):
         print(domain)
         p = re.compile('DNS:([0-9a-z-.]+)')
         cert_data = ssh_command("sudo openssl x509 -text -in /etc/letsencrypt/live/" + domain + "/fullchain.pem", True)
-        self.num_done += 1
-        percent_done = self.num_done * 1.0 / self.num_domains
+        self.domains_done += 1
+        percent_done = self.domains_done * 1.0 / self.num_domains
         # print(percent_done)
         self.progressbar.set_fraction(percent_done)
         # self.progressbar.set_text('Done: ' + domain)

+ 130 - 0
nginxparser.py

@@ -0,0 +1,130 @@
+import string
+
+from pyparsing import (
+    Literal, White, Word, alphanums, CharsNotIn, Forward, Group, SkipTo,
+    Optional, OneOrMore, ZeroOrMore, pythonStyleComment)
+
+
+class NginxParser(object):
+    """
+    A class that parses nginx configuration with pyparsing
+    """
+
+    # constants
+    left_bracket = Literal("{").suppress()
+    right_bracket = Literal("}").suppress()
+    semicolon = Literal(";").suppress()
+    space = White().suppress()
+    key = Word(alphanums + "_/")
+    value = CharsNotIn("{};")
+    value2 = CharsNotIn(";")
+    location = CharsNotIn("{};," + string.whitespace)
+    ifword = Literal("if")
+    setword = Literal("set")
+    # modifier for location uri [ = | ~ | ~* | ^~ ]
+    modifier = Literal("=") | Literal("~*") | Literal("~") | Literal("^~")
+
+    # rules
+    assignment = (key + Optional(space + value) + semicolon)
+    setblock = (setword + OneOrMore(space + value2) + semicolon)
+    block = Forward()
+    ifblock = Forward()
+    subblock = Forward()
+
+    ifblock << (
+        Group(ifword + Optional(space) + Optional(value) + SkipTo('{'))
+        + left_bracket
+        + Group(subblock)
+        + right_bracket)
+
+    subblock << ZeroOrMore(
+        Group(assignment) | block | Group(ifblock) | setblock
+    )
+
+    block << Group(
+        Group(key + Optional(space + modifier) + Optional(space + location))
+        + left_bracket
+        + Group(subblock)
+        + right_bracket
+    )
+
+    script = OneOrMore(Group(assignment) | block).ignore(pythonStyleComment)
+
+    def __init__(self, source):
+        self.source = source
+
+    def parse(self):
+        """
+        Returns the parsed tree.
+        """
+        return self.script.parseString(self.source)
+
+    def as_list(self):
+        """
+        Returns the list of tree.
+        """
+        return self.parse().asList()
+
+
+class NginxDumper(object):
+    """
+    A class that dumps nginx configuration from the provided tree.
+    """
+    def __init__(self, blocks, indentation=4):
+        self.blocks = blocks
+        self.indentation = indentation
+
+    def __iter__(self, blocks=None, current_indent=0, spacer=' '):
+        """
+        Iterates the dumped nginx content.
+        """
+        blocks = blocks or self.blocks
+        for key, values in blocks:
+            if current_indent:
+                yield spacer
+            indentation = spacer * current_indent
+            if isinstance(key, list):
+                yield indentation + spacer.join(key) + ' {'
+                for parameter in values:
+                    if isinstance(parameter[0], list):
+                        dumped = self.__iter__(
+                            [parameter],
+                            current_indent + self.indentation)
+                        for line in dumped:
+                            yield line
+                    else:
+                        dumped = spacer.join(parameter) + ';'
+                        yield spacer * (
+                            current_indent + self.indentation) + dumped
+
+                yield indentation + '}'
+            else:
+                yield spacer * current_indent + key + spacer + values + ';'
+
+    def as_string(self):
+        return '\n'.join(self)
+
+    def to_file(self, out):
+        for line in self:
+            out.write(line+"\n")
+        out.close()
+        return out
+
+
+# Shortcut functions to respect Python's serialization interface
+# (like pyyaml, picker or json)
+
+def loads(source):
+    return NginxParser(source).as_list()
+
+
+def load(_file):
+    return loads(_file.read())
+
+
+def dumps(blocks, indentation=4):
+    return NginxDumper(blocks, indentation).as_string()
+
+
+def dump(blocks, _file, indentation=4):
+    return NginxDumper(blocks, indentation).to_file(_file)