summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2008-10-14 18:42:57 +0000
committerNick Mathewson <nickm@torproject.org>2008-10-14 18:42:57 +0000
commitce277674b98c0e75f5eecd95fe6ff052607a0c22 (patch)
treef3aedf29d7d8b4244e1152ea1a1019664d7fe40b
parent6caa72442dc5767dea82d8e67089748c11a7fc46 (diff)
Add some in-code documentation, fix some dead code, add a license, add a working distutils script.
git-svn-id: file:///home/or/svnrepo/updater/trunk@17092 55e972cd-5a19-0410-ae62-a4d7a52db4cd
-rw-r--r--LICENSE40
-rw-r--r--Makefile9
-rw-r--r--lib/thandy/ClientCLI.py1
-rw-r--r--lib/thandy/ServerCLI.py1
-rw-r--r--lib/thandy/SignerCLI.py1
-rw-r--r--lib/thandy/__init__.py1
-rw-r--r--lib/thandy/checkJson.py1
-rw-r--r--lib/thandy/download.py2
-rw-r--r--lib/thandy/formats.py1
-rw-r--r--lib/thandy/keys.py46
-rw-r--r--lib/thandy/master_keys.py2
-rw-r--r--lib/thandy/repository.py1
-rw-r--r--lib/thandy/tests.py1
-rw-r--r--lib/thandy/util.py1
-rw-r--r--setup.py124
15 files changed, 213 insertions, 19 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8cf439a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,40 @@
+ This file contains the license for Thandy,
+ a free software project to securely fetch and install software updates.
+
+ If you got this file as a part of a larger bundle,
+ there may be other license terms that you should be aware of.
+
+
+===============================================================================
+Thandy is distributed under this license:
+
+Copyright (c) 2008, The Tor Project, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+ * Neither the names of the copyright owners nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+===============================================================================
diff --git a/Makefile b/Makefile
index c67b8b9..aa5d6c0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,9 @@
-export PYTHONPATH=./lib
+all:
+ python setup.py build
test:
- #python -m sexp.tests
- python -m thandy.tests
+ export PYTHONPATH=./lib && python -m thandy.tests
+
+install:
+ python setup.py install \ No newline at end of file
diff --git a/lib/thandy/ClientCLI.py b/lib/thandy/ClientCLI.py
index 702ebbf..ba7fb2e 100644
--- a/lib/thandy/ClientCLI.py
+++ b/lib/thandy/ClientCLI.py
@@ -1,3 +1,4 @@
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
import os
import sys
diff --git a/lib/thandy/ServerCLI.py b/lib/thandy/ServerCLI.py
index 47fa912..2090ed9 100644
--- a/lib/thandy/ServerCLI.py
+++ b/lib/thandy/ServerCLI.py
@@ -1,3 +1,4 @@
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
import os
import sys
diff --git a/lib/thandy/SignerCLI.py b/lib/thandy/SignerCLI.py
index 4facc2e..d3af5fb 100644
--- a/lib/thandy/SignerCLI.py
+++ b/lib/thandy/SignerCLI.py
@@ -1,3 +1,4 @@
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
import os
import getopt
diff --git a/lib/thandy/__init__.py b/lib/thandy/__init__.py
index 87fd983..03b262e 100644
--- a/lib/thandy/__init__.py
+++ b/lib/thandy/__init__.py
@@ -1,3 +1,4 @@
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
__all__ = [ 'formats' ]
diff --git a/lib/thandy/checkJson.py b/lib/thandy/checkJson.py
index e6b6c6e..b5fef3d 100644
--- a/lib/thandy/checkJson.py
+++ b/lib/thandy/checkJson.py
@@ -1,3 +1,4 @@
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
import re
import sys
diff --git a/lib/thandy/download.py b/lib/thandy/download.py
index 0b22cfa..bf7dc43 100644
--- a/lib/thandy/download.py
+++ b/lib/thandy/download.py
@@ -1,4 +1,4 @@
-
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
import urllib2
import httplib
diff --git a/lib/thandy/formats.py b/lib/thandy/formats.py
index 7db1d8f..e10f0aa 100644
--- a/lib/thandy/formats.py
+++ b/lib/thandy/formats.py
@@ -1,3 +1,4 @@
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
import simplejson
import time
diff --git a/lib/thandy/keys.py b/lib/thandy/keys.py
index 5b4e072..2f433b5 100644
--- a/lib/thandy/keys.py
+++ b/lib/thandy/keys.py
@@ -1,3 +1,4 @@
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
# These require PyCrypto.
import Crypto.PublicKey.RSA
@@ -17,9 +18,8 @@ import thandy.formats
import thandy.util
class PublicKey:
+ """Abstract base class for public keys."""
def __init__(self):
- # Confusingly, these roles are the ones used for a private key to
- # remember what we're willing to do with it.
self._roles = []
def format(self):
raise NotImplemented()
@@ -32,13 +32,25 @@ class PublicKey:
def getKeyID(self):
raise NotImplemented()
def getRoles(self):
+ """Remove a list of all roles supported by this key. A role is
+ from this key. A role is a doctype,pathPattern tuple.
+ """
return self._roles
def addRole(self, role, path):
+ """Add a role to the list of roles supported by this key.
+ A role is a permission to sign a given kind of document
+ (one of thandy.format.ALL_ROLES) at a given set of relative
+ paths.
+ """
assert role in thandy.formats.ALL_ROLES
self._roles.append((role, path))
def clearRoles(self):
+ """Remove all roles from this key."""
del self._roles[:]
def hasRole(self, role, path):
+ """Return true iff this key has a role that allows it to sign
+ a document of type 'role' at location in the repository 'path'.
+ """
for r, p in self._roles:
if r == role and thandy.formats.rolePathMatches(p, path):
return True
@@ -57,6 +69,7 @@ if hex(1L).upper() == "0X1L":
return binascii.a2b_hex(h)
elif hex(1L).upper() == "0X1":
def intToBinary(number):
+ "Variant for future versions of pythons that don't append 'L'."
h = hex(long(number))
h = h[2:]
if len(h)%2:
@@ -73,9 +86,11 @@ def binaryToInt(binary):
return long(binascii.b2a_hex(binary), 16)
def intToBase64(number):
+ """Convert an int or long to a big-endian base64-encoded value."""
return thandy.formats.formatBase64(intToBinary(number))
def base64ToInt(number):
+ """Convert a big-endian base64-encoded value to a long."""
return binaryToInt(thandy.formats.parseBase64(number))
def _pkcs1_padding(m, size):
@@ -123,11 +138,14 @@ class RSAKey(PublicKey):
@staticmethod
def generate(bits=2048):
+ """Generate a new RSA key, with modulus length 'bits'."""
key = Crypto.PublicKey.RSA.generate(bits=bits, randfunc=os.urandom)
return RSAKey(key)
@staticmethod
def fromJSon(obj):
+ """Construct an RSA key from the output of the format() method.
+ """
# obj must match RSAKEY_SCHEMA
thandy.formats.RSAKEY_SCHEMA.checkMatch(obj)
@@ -150,9 +168,14 @@ class RSAKey(PublicKey):
return result
def isPrivateKey(self):
+ """Return true iff this key has private-key components"""
return hasattr(self.key, 'd')
def format(self, private=False, includeRoles=False):
+ """Returna a new object to represent this key in json format.
+ If 'private', include private-key data. If 'includeRoles',
+ include role information.
+ """
n = intToBase64(self.key.n)
e = intToBase64(self.key.e)
result = { '_keytype' : 'rsa',
@@ -168,25 +191,19 @@ class RSAKey(PublicKey):
return result
def getKeyID(self):
+ """Return the KeyID for this key.
+ """
if self.keyid == None:
d_obj = Crypto.Hash.SHA256.new()
thandy.formats.getDigest(self.format(), d_obj)
self.keyid = thandy.formats.formatHash(d_obj.digest())
return self.keyid
- def _digest(self, obj, method=None):
- if method in (None, "sha256-pkcs1"):
- d_obj = Crypto.Hash.SHA256.new()
- thandy.formats.getDigest(obj, d_obj)
- digest = d_obj.digest()
- return ("sha256-pkcs1", digest)
-
- raise UnknownMethod(method)
-
def sign(self, obj=None, digest=None):
assert _xor(obj == None, digest == None)
+ method = "sha256-pkcs1"
if digest == None:
- method, digest = self._digest(obj)
+ digest = thandy.formats.getDigest(obj)
m = _pkcs1_padding(digest, (self.key.size()+1) // 8)
sig = intToBase64(self.key.sign(m, "")[0])
return (method, sig)
@@ -194,9 +211,9 @@ class RSAKey(PublicKey):
def checkSignature(self, method, sig, obj=None, digest=None):
assert _xor(obj == None, digest == None)
if method != "sha256-pkcs1":
- raise UnknownMethod("method")
+ raise UnknownMethod(method)
if digest == None:
- method, digest = self._digest(obj, method)
+ digest = thandy.formats.getDigest(obj)
sig = base64ToInt(sig)
m = _pkcs1_padding(digest, (self.key.size()+1) // 8)
return bool(self.key.verify(m, (sig,)))
@@ -324,6 +341,7 @@ def decryptSecret(encrypted, password):
return secret
class KeyStore(thandy.formats.KeyDB):
+ """Helper to store private keys in an encrypted file."""
def __init__(self, fname, encrypted=True):
thandy.formats.KeyDB.__init__(self)
diff --git a/lib/thandy/master_keys.py b/lib/thandy/master_keys.py
index 0d455d1..4818d93 100644
--- a/lib/thandy/master_keys.py
+++ b/lib/thandy/master_keys.py
@@ -1,4 +1,4 @@
-
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
MASTER_KEYS = [
diff --git a/lib/thandy/repository.py b/lib/thandy/repository.py
index dc13f1b..32108c0 100644
--- a/lib/thandy/repository.py
+++ b/lib/thandy/repository.py
@@ -1,3 +1,4 @@
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
import thandy.formats
import thandy.util
diff --git a/lib/thandy/tests.py b/lib/thandy/tests.py
index 8b967a5..e2fb767 100644
--- a/lib/thandy/tests.py
+++ b/lib/thandy/tests.py
@@ -1,3 +1,4 @@
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
import unittest
import doctest
diff --git a/lib/thandy/util.py b/lib/thandy/util.py
index e87ed8b..2b1c572 100644
--- a/lib/thandy/util.py
+++ b/lib/thandy/util.py
@@ -1,3 +1,4 @@
+# Copyright 2008 The Tor Project, Inc. See LICENSE for licensing information.
import os
import sys
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..9fd6680
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,124 @@
+#!/usr/bin/python
+# Copyright 2008 The Tor Project. See LICENSE for licensing information.
+# $Id: setup.py,v 1.103 2007-09-15 19:06:37 nickm Exp $
+
+import sys
+
+#
+# Current Thandy version
+#
+VERSION = '0.0.1-alpha'
+# System: 0==alpha, 50==beta, 98=pre, 99==release candidate, 100==release
+VERSION_INFO = (0,0,1)
+
+for name in [ "simplejson", "Crypto" ]:
+ try:
+ __import__(name)
+ except ImportError:
+ print "Missing support for module %s"%name
+ sys.exit(1)
+
+import os, re, shutil, string, struct, sys
+
+os.umask(022)
+
+#======================================================================
+# Create startup scripts if we're installing.
+
+if not os.path.isdir("./bin"):
+ os.mkdir("./bin")
+
+SCRIPTS = []
+
+def makescripts(extrapath=None):
+ del SCRIPTS[:]
+ for script_suffix, modname in [ ("server", "ServerCLI"),
+ ("client", "ClientCLI"),
+ ("pk", "SignerCLI"), ]:
+ fname = os.path.join("./bin", "thandy-%s"%script_suffix)
+ if sys.platform == "win32":
+ fname += ".py"
+ f = open(fname, 'w')
+ f.write("#!/bin/sh\n")
+ if extrapath:
+ f.write('PYTHONPATH="$PYTHONPATH:%s"\n'%extrapath)
+ f.write('export PYTHONPATH\n')
+ f.write("%s -m thandy.%s $*\n" %(sys.executable, modname))
+ f.close()
+ SCRIPTS.append(fname)
+
+#======================================================================
+# Define a helper to let us run commands from the compiled code.
+def _haveCmd(cmdname):
+ for entry in os.environ.get("PATH", "").split(os.pathsep):
+ if os.path.exists(os.path.join(entry, cmdname)):
+ return 1
+ return 0
+
+def requirePythonDev(e=None):
+ if os.path.exists("/etc/debian_version"):
+ v = sys.version[:3]
+ print "Debian may expect you to install python%s-dev"%v
+ elif os.path.exists("/etc/redhat-release"):
+ print "Redhat may expect you to install python2-devel"
+ else:
+ print "You may be missing some 'python development' package for your"
+ print "distribution."
+
+ if e:
+ print "(Error was: %s)"%e
+
+ sys.exit(1)
+
+try:
+ from distutils.core import Command
+ from distutils.errors import DistutilsPlatformError
+ from distutils.sysconfig import get_makefile_filename
+except ImportError, e:
+ print "\nUh oh. You have Python installed, but I didn't find the distutils"
+ print "module, which is supposed to come with the standard library.\n"
+
+ requirePythonDev()
+
+try:
+ # This catches failures to install python2-dev on some redhats.
+ get_makefile_filename()
+except IOError:
+ print "\nUh oh. You have Python installed, but distutils can't find the"
+ print "Makefile it needs to build additional Python components.\n"
+
+ requirePythonDev()
+
+#======================================================================
+# Now, tell setup.py how to cope.
+import distutils.core, distutils.command.install
+from distutils.core import setup, Distribution
+
+class InstallCommand(distutils.command.install.install):
+ def run(self):
+ script_path = None
+ sys_path = map(os.path.normpath, sys.path)
+ sys_path = map(os.path.normcase, sys_path)
+ install_lib = os.path.normcase(os.path.normpath(self.install_lib))
+
+ if install_lib not in sys_path:
+ script_path = install_lib
+
+ makescripts(self.install_lib)
+
+ distutils.command.install.install.run(self)
+
+setup(name='Thandy',
+ version=VERSION,
+ license="3-clause BSD",
+ description=
+ "Thandy: Secure cross-platform update automation tool.",
+ author="Nick Mathewson",
+ author_email="nickm@freehaven.net",
+ url="http://www.torproject/org",
+ package_dir={ '' : 'lib' },
+ packages=['thandy'],
+ scripts=SCRIPTS,
+ cmdclass={'install': InstallCommand},
+)
+