obj.py
  1  """Module contains classes used by the Nginx Configurator."""
  2  import re
  3  
  4  from letsencrypt.plugins import common
  5  
  6  
  7  class Addr(common.Addr):
  8      r"""Represents an Nginx address, i.e. what comes after the 'listen'
  9      directive.
 10  
 11      According to the `documentation`_, this may be address[:port], port,
 12      or unix:path. The latter is ignored here.
 13  
 14      The default value if no directive is specified is \*:80 (superuser)
 15      or \*:8000 (otherwise). If no port is specified, the default is
 16      80. If no address is specified, listen on all addresses.
 17  
 18      .. _documentation:
 19         http://nginx.org/en/docs/http/ngx_http_core_module.html#listen
 20  
 21      .. todo:: Old-style nginx configs define SSL vhosts in a separate
 22                block instead of using 'ssl' in the listen directive.
 23  
 24      :param str addr: addr part of vhost address, may be hostname, IPv4, IPv6,
 25          "", or "\*"
 26      :param str port: port number or "\*" or ""
 27      :param bool ssl: Whether the directive includes 'ssl'
 28      :param bool default: Whether the directive includes 'default_server'
 29  
 30      """
 31      def __init__(self, host, port, ssl, default):
 32          super(Addr, self).__init__((host, port))
 33          self.ssl = ssl
 34          self.default = default
 35  
 36      @classmethod
 37      def fromstring(cls, str_addr):
 38          """Initialize Addr from string."""
 39          parts = str_addr.split(' ')
 40          ssl = False
 41          default = False
 42          host = ''
 43          port = ''
 44  
 45          # The first part must be the address
 46          addr = parts.pop(0)
 47  
 48          # Ignore UNIX-domain sockets
 49          if addr.startswith('unix:'):
 50              return None
 51  
 52          tup = addr.partition(':')
 53          if re.match(r'^\d+$', tup[0]):
 54              # This is a bare port, not a hostname. E.g. listen 80
 55              host = ''
 56              port = tup[0]
 57          else:
 58              # This is a host-port tuple. E.g. listen 127.0.0.1:*
 59              host = tup[0]
 60              port = tup[2]
 61  
 62          # The rest of the parts are options; we only care about ssl and default
 63          while len(parts) > 0:
 64              nextpart = parts.pop()
 65              if nextpart == 'ssl':
 66                  ssl = True
 67              elif nextpart == 'default_server':
 68                  default = True
 69  
 70          return cls(host, port, ssl, default)
 71  
 72      def __str__(self):
 73          parts = ''
 74          if self.tup[0] and self.tup[1]:
 75              parts = "%s:%s" % self.tup
 76          elif self.tup[0]:
 77              parts = self.tup[0]
 78          else:
 79              parts = self.tup[1]
 80  
 81          if self.default:
 82              parts += ' default_server'
 83          if self.ssl:
 84              parts += ' ssl'
 85  
 86          return parts
 87  
 88      def __eq__(self, other):
 89          if isinstance(other, self.__class__):
 90              return (self.tup == other.tup and
 91                      self.ssl == other.ssl and
 92                      self.default == other.default)
 93          return False
 94  
 95  
 96  class VirtualHost(object):  # pylint: disable=too-few-public-methods
 97      """Represents an Nginx Virtualhost.
 98  
 99      :ivar str filep: file path of VH
100      :ivar set addrs: Virtual Host addresses (:class:`set` of :class:`Addr`)
101      :ivar set names: Server names/aliases of vhost
102          (:class:`list` of :class:`str`)
103      :ivar list raw: The raw form of the parsed server block
104  
105      :ivar bool ssl: SSLEngine on in vhost
106      :ivar bool enabled: Virtual host is enabled
107  
108      """
109  
110      def __init__(self, filep, addrs, ssl, enabled, names, raw):
111          # pylint: disable=too-many-arguments
112          """Initialize a VH."""
113          self.filep = filep
114          self.addrs = addrs
115          self.names = names
116          self.ssl = ssl
117          self.enabled = enabled
118          self.raw = raw
119  
120      def __str__(self):
121          addr_str = ", ".join(str(addr) for addr in self.addrs)
122          return ("file: %s\n"
123                  "addrs: %s\n"
124                  "names: %s\n"
125                  "ssl: %s\n"
126                  "enabled: %s" % (self.filep, addr_str,
127                                   self.names, self.ssl, self.enabled))
128  
129      def __eq__(self, other):
130          if isinstance(other, self.__class__):
131              return (self.filep == other.filep and
132                      list(self.addrs) == list(other.addrs) and
133                      self.names == other.names and
134                      self.ssl == other.ssl and self.enabled == other.enabled)
135  
136          return False