#!/usr/bin/env python """ DNS ID Generator Author: Sean B. Palmer, inamidst.com """ import cgitb; cgitb.enable() import sys, os, re, sha, cgi, textwrap from base64 import b32encode form = cgi.FieldStorage() form.__call__ = lambda s: form[s].value PATH_INFO = os.environ.get('PATH_INFO', '') QUERY_STRING = os.environ.get('QUERY_STRING', '') REQUEST_URI = os.environ.get('REQUEST_URI', '') script = os.path.basename(REQUEST_URI.rstrip('/')).split('?')[0] r_encode = re.compile(r'([^A-Za-z0-9-])') r_email = re.compile(r'''(?x)^ [A-Za-z0-9!#$%&'*+/=?^`{|+~_-]+ (\.[A-Za-z0-9!#$%&'*+/=?^`{|+~_-]+)* @ ([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9]\.)* ([A-Za-z]|[A-Za-z][A-Za-z0-9-]*[A-Za-z0-9]) $''') base = 'com.inamidst.mbox.' def validate(email): if r_email.match(email): return True return False def base32(email, base=base): hash = sha.new(email).digest() part = b32encode(hash[:10]).lower() return base + part.rstrip('=\n') def sha1sum(email, base=base): return base + sha.new(email).hexdigest() def encode(part): assert part[0].isalpha() or part[0].isdigit(), part assert part[-1].isalpha() or part[-1].isdigit(), part if len(part) < 3: return part middle = r_encode.sub(lambda m: '--%02X' % ord(m.group(1)), part[1:-1]) return part[0] + middle + part[-1] def multipart(email, base=base): # This is the grit-teeth function name, host = email.split('@') name = encode(name) hostparts = list(reversed(host.split('.'))) emailparts = frozenset(hostparts + [encode(name)]) sep, i = 'at', 0 while sep in emailparts: if i >= 1000000: raise ValueError("Sorry, your email address is too whacky") sep = 'sep' + str(i) i += 1 parts = [sep] + list(hostparts) + [sep, name] return base + '.'.join(parts) def serve(status, headers, body): sys.stdout.write("Status: %s\r\n" % status) for header in headers.iteritems(): sys.stdout.write("%s: %s\r\n" % header) sys.stdout.write("\r\n") sys.stdout.write(str(body)) sys.exit() def redirect(uri, temp=False): if not uri.startswith('http:'): from urlparse import urljoin domain = os.environ.get('SERVER_NAME', 'localhost') uri = urljoin('http://' + domain + REQUEST_URI, uri) status = (301, 307)[temp] headers = {'Location': uri, 'Content-Type': 'text/html'} body = 'go!' % uri serve(status, headers, body) def error(msg): body = '

%s

' % cgi.escape(msg) serve(501, {'Content-Type': 'text/html'}, body) def dnsid(email): result = [] if not validate(email): result.append("Sorry, %s is not allowed by this system." % email) result.append("If you're sure that it's a valid email, please ") result.append("contact me at http://inamidst.com/sbp/contact ") result.append("and ask me to laxen the allowed values. Thanks.") return '\n'.join(result) result.append("The owner of %s may use any of these DNS IDs: " % email) result.append("") result.append(" base32: %s" % base32(email)) result.append(" sha1sum: %s" % sha1sum(email)) result.append(" multipart: %s" % multipart(email)) result.append("") result.append("-- ") result.append("Sean B. Palmer, inamidst.com") result.append("") return '\n'.join(result) def homepage(): print "Content-Type: text/html" print print textwrap.dedent("""\ DNS ID Service

DNS ID Service

This service converts email addresses into backwards domains starting with "com.inamidst.mbox" for the owner of the email address to use. See below for further details, including alternate ways to create these identifiers.

Email:

DNS ID?

Usually, domain names are used in email addresses and HTTP URIs in the form "example.com", with the top level domain (.com, .net, .co.uk etc.) coming at the end. You may also have subdomains such as "myname.example.com", and very occasionally you see ridiculous examples such as "this.is.a.host.at.example.com".

Some systems, however, use these addresses—just the domain names, with no paths—as local identifiers. For example, the Java package-name convention makes use of this kind of identifier. Indeed, this service was written in response to a discussion about TAG issue siteData-36, one of the possible solutions for which is to use these reversed domain names as identifiers in HTTP header values.

The advantage that these types of identifier have over HTTP URIs is that they're much more compact. The disadvantage is that people are much less likely to own domains than they are to have, say, an email address. Domain names were used as part of the tag: URI proposal too, and the authors of that proposal got around it simply by allowing emails too. But in most other systems, this flexibility isn't possible. That's where this service comes in.

About This Service

If you have an email address but no domain or subdomain, you can simply have a subdomain at this site that contains your email address encoded inside. You can use any one of three different variants of different length and obfuscation level.

This is powered by a CGI written in Python. It does require that you put your email address in, of course, which means that it'll show up in my server logs. I won't distribute or sell these addresses or anything, but if you still want one of these DNS IDs without divulging your email address, you still can. Simply download the source, save it as dnsid.py, and then run it a la ./dnsid.py name@example.org to generate the DNS IDs.

This was mainly written as a programming exercise rather than a service for heavy use, but anyone is welcome to use it as long as they don't expect hosting or any warranty etc. If you have any questions, do feel free to contact me.

Sean B. Palmer
""") def runcgi(script=script): if QUERY_STRING: if form.has_key('email'): if script: script += '/' redirect('./' + script + form('email')) else: print error("Needed an email form key.") elif len(PATH_INFO) > 1: headers = {'Content-Type': 'text/plain'} serve(200, headers, dnsid(PATH_INFO.lstrip('/'))) else: homepage() def help(argv): return ("Usage: %s \n" % argv[0]) + __doc__.strip() def run(argv=None): if argv is None: argv = sys.argv if len(argv) == 2: print dnsid(argv[1]) else: print help(argv) def main(): if os.environ.has_key('SCRIPT_NAME'): runcgi() else: run() if __name__=="__main__": main()