Now exceptions are derived from a common base class and return codes correspond to...
authorPhilipp Spitzer <philipp@spitzer.priv.at>
Wed, 5 Mar 2014 22:34:39 +0000 (23:34 +0100)
committerPhilipp Spitzer <philipp@spitzer.priv.at>
Wed, 5 Mar 2014 22:34:39 +0000 (23:34 +0100)
cgi-bin/dyndns.py

index a3f436b..8291ac2 100755 (executable)
@@ -38,19 +38,65 @@ system   = fields.getvalue('system')
 url      = fields.getvalue('url')
 
 
+# Base class for our exceptions
+class DynDnsError(Exception):
+       pass
+
+class AuthError(DynDnsError):
+       returncode = 'badauth'
+
+class UsernameMissing(AuthError):
+       pass
+
+class UsernameInvalid(AuthError):
+       pass
+
+class PasswordMissing(AuthError):
+       pass
+
+class PasswordWrong(AuthError):
+       pass
+
+class HostnameError(DynDnsError):
+       returncode = 'notfqdn'
+
+class HostnameMissing(HostnameError):
+       pass
+
+class PasswordWrong(HostnameError):
+       pass
+
+class IpError(DynDnsError):
+       returncode = 'badip' # not documented at dyn.com
+
+class IpMissing(IpError):
+       pass
+
+class IpInvalid(IpError):
+       pass
+
 try:
        # check username
-       user_info = pwd.getpwnam(username) # returns a key error if the user does not exist
+       if username is None:
+               raise UsernameMissing()
+       try:
+               user_info = pwd.getpwnam(username)
+       except KeyError:
+               raise UsernameInvalid()
        if user_info.pw_uid < 1000:
-               raise RuntimeError('Invalid user name')
+               raise UsernameInvalid()
 
        # check password
+       if password is None:
+               raise PasswordMissing()
        if password != PASSWORD:
-               raise RuntimeError('Invalid password')
+               raise PasswordWrong()
 
        # check hostname
+       if hostname is None:
+               raise HostnameMissing()
        if re.match(r'[-0-9a-z]+(\.[-0-9a-z]+)*$', hostname) is None:
-               raise RuntimeError('Invalid host name')
+               raise HostnameInvalid()
 
        # strip zone
        hostname = hostname.strip()
@@ -58,25 +104,30 @@ try:
                hostname = hostname[:-len(ZONE)]
 
        # check IP address
-       ip = ipaddr.IPAddress(myip) # throws axception if the IP address is not valid
+       if myip is None:
+               raise IpMissing()
+       try:
+               ip = ipaddr.IPAddress(myip) # throws an exception if the IP address is not valid
+       except ValueError:
+               raise IpInvalid()
        if isinstance(ip, ipaddr.IPv4Address):
-               type = 'A'
+               iptype = 'A'
        elif isinstance(ip, ipaddr.IPv6Address):
-               type = 'AAAA'
+               iptype = 'AAAA'
        else:
-               raise RuntimeError('Unknown IP address type')
+               raise IpInvalid() # should never happen
 
        # access granted
        print "Content-Type: text/html"
        print
-       call(['sudo', '/usr/local/bin/nsupdate_dyndns', hostname, myip, type])
-       print "OK"
+       call(['sudo', '/usr/local/bin/nsupdate_dyndns', hostname, myip, iptype])
+       print "good"
+       # Note: we should return 'nochg' in case the IP has not changed, however we don't know yet.
 
 
-except:
-       # access denied
+except DynDnsError as error:
        print "Content-Type: text/html"
-       print "Status: 403 Forbidden"
+       print "Status: 200"
        print
-       print "Denied"
+       print error.returncode