keys: Reformat in line with my newer commenting conventions.
authorMark Wooding <mdw@distorted.org.uk>
Sat, 5 Apr 2008 12:27:13 +0000 (13:27 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 5 Apr 2008 14:33:15 +0000 (15:33 +0100)
keys/tripe-keys.in

index 531e749..1e56282 100644 (file)
@@ -1,7 +1,31 @@
 #! @PYTHON@
-# -*-python-*-
-
-### External dependencies
+### -*-python-*-
+###
+### Key management and distribution
+###
+### (c) 2006 Straylight/Edgeware
+###
+
+###----- Licensing notice ---------------------------------------------------
+###
+### This file is part of Trivial IP Encryption (TrIPE).
+###
+### TrIPE is free software; you can redistribute it and/or modify
+### it under the terms of the GNU General Public License as published by
+### the Free Software Foundation; either version 2 of the License, or
+### (at your option) any later version.
+###
+### TrIPE is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with TrIPE; if not, write to the Free Software Foundation,
+### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+###--------------------------------------------------------------------------
+### External dependencies.
 
 import catacomb as C
 import os as OS
@@ -14,32 +38,57 @@ from cStringIO import StringIO
 from errno import *
 from stat import *
 
+###--------------------------------------------------------------------------
 ### Useful regular expressions
 
+## Match a comment or blank line.
 rx_comment = RX.compile(r'^\s*(#|$)')
+
+## Match a KEY = VALUE assignment.
 rx_keyval = RX.compile(r'^\s*([-\w]+)(?:\s+(?!=)|\s*=\s*)(|\S|\S.*\S)\s*$')
+
+## Match a ${KEY} substitution.
 rx_dollarsubst = RX.compile(r'\$\{([-\w]+)\}')
+
+## Match a @TAG@ substitution.
 rx_atsubst = RX.compile(r'@([-\w]+)@')
+
+## Match a single non-alphanumeric character.
 rx_nonalpha = RX.compile(r'\W')
+
+## Match the literal string "<SEQ>".
 rx_seq = RX.compile(r'\<SEQ\>')
 
-### Utility functions
+###--------------------------------------------------------------------------
+### Utility functions.
 
+## Exceptions.
 class SubprocessError (Exception): pass
 class VerifyError (Exception): pass
 
+## Program name and identification.
 quis = OS.path.basename(SYS.argv[0])
 PACKAGE = "@PACKAGE@"
 VERSION = "@VERSION@"
 
 def moan(msg):
+  """Report MSG to standard error."""
   SYS.stderr.write('%s: %s\n' % (quis, msg))
 
 def die(msg, rc = 1):
+  """Report MSG to standard error, and exit with code RC."""
   moan(msg)
   SYS.exit(rc)
 
 def subst(s, rx, map):
+  """
+  Substitute values into a string.
+
+  Repeatedly match RX (a compiled regular expression) against the string S.
+  For each match, extract group 1, and use it as a key to index the MAP;
+  replace the match by the result.  Finally, return the fully-substituted
+  string.
+  """
   out = StringIO()
   i = 0
   for m in rx.finditer(s):
@@ -49,6 +98,7 @@ def subst(s, rx, map):
   return out.getvalue()
 
 def rmtree(path):
+  """Delete the directory tree given by PATH."""
   try:
     st = OS.lstat(path)
   except OSError, err:
@@ -68,6 +118,7 @@ def rmtree(path):
     OS.rmdir(path)
 
 def zap(file):
+  """Delete the named FILE if it exists; otherwise do nothing."""
   try:
     OS.unlink(file)
   except OSError, err:
@@ -75,6 +126,14 @@ def zap(file):
     raise
 
 def run(args):
+  """
+  Run a subprocess whose arguments are given by the string ARGS.
+
+  The ARGS are split at word boundaries, and then subjected to configuration
+  variable substitution (see conf_subst).  Individual argument elements
+  beginning with `!' are split again into multiple arguments at word
+  boundaries.
+  """
   args = map(conf_subst, args.split())
   nargs = []
   for a in args:
@@ -89,6 +148,9 @@ def run(args):
     raise SubprocessError, rc
 
 def hexhyphens(bytes):
+  """
+  Convert a byte string BYTES into hex, with hyphens at each 4-byte boundary.
+  """
   out = StringIO()
   for i in xrange(0, len(bytes)):
     if i > 0 and i % 4 == 0: out.write('-')
@@ -96,19 +158,37 @@ def hexhyphens(bytes):
   return out.getvalue()
 
 def fingerprint(kf, ktag):
+  """
+  Compute the fingerprint of a key, using the user's selected hash.
+
+  KF is the name of a keyfile; KTAG is the tag of the key.
+  """
   h = C.gchashes[conf['fingerprint-hash']]()
   k = C.KeyFile(kf)[ktag].fingerprint(h, '-secret')
   return h.done()
 
-### Read configuration
+###--------------------------------------------------------------------------
+### The configuration file.
 
+## Exceptions.
 class ConfigFileError (Exception): pass
+
+## The configuration dictionary.
 conf = {}
 
-def conf_subst(s): return subst(s, rx_dollarsubst, conf)
+def conf_subst(s):
+  """
+  Apply configuration substitutions to S.
+
+  That is, for each ${KEY} in S, replace it with the current value of the
+  configuration variable KEY.
+  """
+  return subst(s, rx_dollarsubst, conf)
 
-## Read the file
 def conf_read(f):
+  """
+  Read the file F and insert assignments into the configuration dictionary.
+  """
   lno = 0
   for line in file(f):
     lno += 1
@@ -120,8 +200,13 @@ def conf_read(f):
     k, v = match.groups()
     conf[k] = conf_subst(v)
 
-## Sift the wreckage
 def conf_defaults():
+  """
+  Apply defaults to the configuration dictionary.
+
+  Fill in all the interesting configuration variables based on the existing
+  contents, as described in the manual.
+  """
   for k, v in [('repos-base', 'tripe-keys.tar.gz'),
                ('sig-base', 'tripe-keys.sig-<SEQ>'),
                ('repos-url', '${base-url}${repos-base}'),
@@ -166,7 +251,50 @@ def conf_defaults():
       if len(exc.args) == 0: raise
       conf[k] = '<missing-var %s>' % exc.args[0]
 
-### Commands
+###--------------------------------------------------------------------------
+### Key-management utilities.
+
+def master_keys():
+  """
+  Iterate over the master keys.
+  """
+  if not OS.path.exists('master'):
+    return
+  for k in C.KeyFile('master').itervalues():
+    if (k.type != 'tripe-keys-master' or
+        k.expiredp or
+        not k.tag.startswith('master-')):
+      continue #??
+    yield k
+
+def master_sequence(k):
+  """
+  Return the sequence number of the given master key as an integer.
+
+  No checking is done that K is really a master key.
+  """
+  return int(k.tag[7:])
+
+def max_master_sequence():
+  """
+  Find the master key with the highest sequence number and return this
+  sequence number.
+  """
+  seq = -1
+  for k in master_keys():
+    q = master_sequence(k)
+    if q > seq: seq = q
+  return seq
+
+def seqsubst(x, q):
+  """
+  Return the value of the configuration variable X, with <SEQ> replaced by
+  the value Q.
+  """
+  return rx_seq.sub(str(q), conf[x])
+
+###--------------------------------------------------------------------------
+### Commands: help [COMMAND...]
 
 def version(fp = SYS.stdout):
   fp.write('%s, %s version %s\n' % (quis, PACKAGE, VERSION))
@@ -196,25 +324,8 @@ Subcommands available:
     func, min, max, help = commands[c]
     print '%s %s' % (c, help)
 
-def master_keys():
-  if not OS.path.exists('master'):
-    return
-  for k in C.KeyFile('master').itervalues():
-    if (k.type != 'tripe-keys-master' or
-        k.expiredp or
-        not k.tag.startswith('master-')):
-      continue #??
-    yield k
-def master_sequence(k):
-  return int(k.tag[7:])
-def max_master_sequence():
-  seq = -1
-  for k in master_keys():
-    q = master_sequence(k)
-    if q > seq: seq = q
-  return seq
-def seqsubst(x, q):
-  return rx_seq.sub(str(q), conf[x])
+###--------------------------------------------------------------------------
+### Commands: newmaster
 
 def cmd_newmaster(args):
   seq = max_master_sequence() + 1
@@ -224,6 +335,9 @@ def cmd_newmaster(args):
     sig=${sig} hash=${sig-hash}''' % seq)
   run('key -kmaster extract -f-secret repos/master.pub')
 
+###--------------------------------------------------------------------------
+### Commands: setup
+
 def cmd_setup(args):
   OS.mkdir('repos')
   run('''key -krepos/param add
@@ -232,6 +346,9 @@ def cmd_setup(args):
     cipher=${cipher} hash=${hash} mac=${mac} mgf=${mgf}''')
   cmd_newmaster(args)
 
+###--------------------------------------------------------------------------
+### Commands: upload
+
 def cmd_upload(args):
 
   ## Sanitize the repository directory
@@ -284,6 +401,18 @@ def cmd_upload(args):
     rmtree('tmp')
   run('sh -c ${upload-hook}')
 
+###--------------------------------------------------------------------------
+### Commands: rebuild
+
+def cmd_rebuild(args):
+  zap('keyring.pub')
+  for i in OS.listdir('repos'):
+    if i.startswith('peer-') and i.endswith('.pub'):
+      run('key -kkeyring.pub merge %s' % OS.path.join('repos', i))
+
+###--------------------------------------------------------------------------
+### Commands: update
+
 def cmd_update(args):
   cwd = OS.getcwd()
   rmtree('tmp')
@@ -318,11 +447,8 @@ def cmd_update(args):
     rmtree('tmp')
   cmd_rebuild(args)
 
-def cmd_rebuild(args):
-  zap('keyring.pub')
-  for i in OS.listdir('repos'):
-    if i.startswith('peer-') and i.endswith('.pub'):
-      run('key -kkeyring.pub merge %s' % OS.path.join('repos', i))
+###--------------------------------------------------------------------------
+### Commands: generate TAG
 
 def cmd_generate(args):
   tag, = args
@@ -333,6 +459,9 @@ def cmd_generate(args):
       tag)
   run('key -kkeyring extract -f-secret %s %s' % (keyring_pub, tag))
 
+###--------------------------------------------------------------------------
+### Commands: clean
+
 def cmd_clean(args):
   rmtree('repos')
   rmtree('tmp')
@@ -343,8 +472,10 @@ def cmd_clean(args):
         r == 'keyring' or r == 'keyring.pub' or r.startswith('peer-')):
       zap(i)
 
-### Main driver
+###--------------------------------------------------------------------------
+### Main driver.
 
+## Exceptions.
 class UsageError (Exception): pass
 
 commands = {'help': (cmd_help, 0, 1, ''),
@@ -357,12 +488,20 @@ commands = {'help': (cmd_help, 0, 1, ''),
             'rebuild': (cmd_rebuild, 0, 0, '')}
 
 def init():
+  """
+  Load the appropriate configuration file and set up the configuration
+  dictionary.
+  """
   for f in ['tripe-keys.master', 'tripe-keys.conf']:
     if OS.path.exists(f):
       conf_read(f)
       break
   conf_defaults()
+
 def main(argv):
+  """
+  Main program: parse options and dispatch to appropriate command handler.
+  """
   try:
     opts, args = O.getopt(argv[1:], 'hvu',
                           ['help', 'version', 'usage'])
@@ -390,5 +529,8 @@ def main(argv):
       raise UsageError, (c, help)
     func(args)
 
-init()
-main(SYS.argv)
+###----- That's all, folks --------------------------------------------------
+
+if __name__ == '__main__':
+  init()
+  main(SYS.argv)