CLI: add 'tahoe admin generate-keypair' command
This commit is contained in:
parent
99d5a8d8b9
commit
6607fdc586
|
@ -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,
|
||||||
|
}
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue