CLI: add 'tahoe admin generate-keypair' command

This commit is contained in:
Brian Warner 2008-09-18 17:11:33 -07:00
parent 99d5a8d8b9
commit 6607fdc586
3 changed files with 102 additions and 2 deletions

View File

@ -0,0 +1,66 @@
from twisted.python import usage
class GenerateKeypairOptions(usage.Options):
def getSynopsis(self):
return "Usage: tahoe admin generate-keypair"
def getUsage(self, width=None):
t = usage.Options.getUsage(self, width)
t += """
Generate an ECDSA192 public/private keypair, dumped to stdout as two lines of
base32-encoded text.
"""
return t
def generate_keypair(options):
from pycryptopp.publickey import ecdsa
from allmydata.util import base32
out = options.stdout
privkey = ecdsa.generate(192)
print >>out, "private: priv-v0-%s" % base32.b2a(privkey.serialize())
pubkey = privkey.get_verifying_key()
print >>out, "public: pub-v0-%s" % base32.b2a(pubkey.serialize())
class AdminCommand(usage.Options):
subCommands = [
["generate-keypair", None, GenerateKeypairOptions,
"Generate a public/private keypair, write to stdout."],
]
def postOptions(self):
if not hasattr(self, 'subOptions'):
raise usage.UsageError("must specify a subcommand")
def getSynopsis(self):
return "Usage: tahoe admin SUBCOMMAND"
def getUsage(self, width=None):
#t = usage.Options.getUsage(self, width)
t = """
Subcommands:
tahoe admin generate-keypair Generate a public/private keypair,
write to stdout.
Please run e.g. 'tahoe admin generate-keypair --help' for more details on
each subcommand.
"""
return t
subDispatch = {
"generate-keypair": generate_keypair,
}
def do_admin(options):
so = options.subOptions
so.stdout = options.stdout
so.stderr = options.stderr
f = subDispatch[options.subCommand]
return f(so)
subCommands = [
["admin", None, AdminCommand, "admin subcommands: use 'tahoe admin' for a list"],
]
dispatch = {
"admin": do_admin,
}

View File

@ -4,12 +4,13 @@ from cStringIO import StringIO
from twisted.python import usage from twisted.python import usage
from allmydata.scripts.common import BaseOptions from allmydata.scripts.common import BaseOptions
import debug, create_node, startstop_node, cli, keygen import debug, create_node, startstop_node, cli, keygen, admin
_general_commands = ( create_node.subCommands _general_commands = ( create_node.subCommands
+ keygen.subCommands + keygen.subCommands
+ debug.subCommands + debug.subCommands
+ cli.subCommands + cli.subCommands
+ admin.subCommands
) )
class Options(BaseOptions, usage.Options): class Options(BaseOptions, usage.Options):
@ -69,6 +70,8 @@ def runner(argv,
rc = startstop_node.dispatch[command](so, stdout, stderr) rc = startstop_node.dispatch[command](so, stdout, stderr)
elif command in debug.dispatch: elif command in debug.dispatch:
rc = debug.dispatch[command](so) rc = debug.dispatch[command](so)
elif command in admin.dispatch:
rc = admin.dispatch[command](so)
elif command in cli.dispatch: elif command in cli.dispatch:
rc = cli.dispatch[command](so) rc = cli.dispatch[command](so)
elif command in keygen.dispatch: elif command in keygen.dispatch:

View File

@ -4,7 +4,8 @@ from twisted.trial import unittest
from cStringIO import StringIO from cStringIO import StringIO
import urllib import urllib
from allmydata.util import fileutil, hashutil from pycryptopp.publickey import ecdsa
from allmydata.util import fileutil, hashutil, base32
from allmydata import uri from allmydata import uri
# at least import the CLI scripts, even if we don't have any real tests for # at least import the CLI scripts, even if we don't have any real tests for
@ -500,5 +501,35 @@ class Put(SystemTestMixin, CLITestMixin, unittest.TestCase):
d.addCallback(lambda (out,err): self.failUnlessEqual(out, DATA2)) d.addCallback(lambda (out,err): self.failUnlessEqual(out, DATA2))
return d return d
class Admin(unittest.TestCase):
def do_cli(self, *args, **kwargs):
argv = list(args)
stdin = kwargs.get("stdin", "")
stdout, stderr = StringIO(), StringIO()
d = threads.deferToThread(runner.runner, argv, run_by_human=False,
stdin=StringIO(stdin),
stdout=stdout, stderr=stderr)
def _done(res):
return stdout.getvalue(), stderr.getvalue()
d.addCallback(_done)
return d
def test_generate_keypair(self):
d = self.do_cli("admin", "generate-keypair")
def _done( (stdout, stderr) ):
lines = stdout.split("\n")
privkey_line = lines[0].strip()
pubkey_line = lines[1].strip()
sk_header = "private: priv-v0-"
vk_header = "public: pub-v0-"
self.failUnless(privkey_line.startswith(sk_header), privkey_line)
self.failUnless(pubkey_line.startswith(vk_header), pubkey_line)
privkey_b = base32.a2b(privkey_line[len(sk_header):])
pubkey_b = base32.a2b(pubkey_line[len(vk_header):])
sk = ecdsa.create_signing_key_from_string(privkey_b)
vk = ecdsa.create_verifying_key_from_string(pubkey_b)
self.failUnlessEqual(sk.get_verifying_key().serialize(),
vk.serialize())
d.addCallback(_done)
return d