tahoe-lafs/src/allmydata/test/test_cli.py

541 lines
25 KiB
Python

import os.path
from twisted.trial import unittest
from cStringIO import StringIO
import urllib
from pycryptopp.publickey import ecdsa
from allmydata.util import fileutil, hashutil, base32
from allmydata import uri
# at least import the CLI scripts, even if we don't have any real tests for
# them yet.
from allmydata.scripts import tahoe_ls, tahoe_get, tahoe_put, tahoe_rm
from allmydata.scripts.common import DEFAULT_ALIAS, get_aliases
_hush_pyflakes = [tahoe_ls, tahoe_get, tahoe_put, tahoe_rm]
from allmydata.scripts import cli, debug, runner
from allmydata.test.common import SystemTestMixin
from twisted.internet import threads # CLI tests use deferToThread
class CLI(unittest.TestCase):
# this test case only looks at argument-processing and simple stuff.
def test_options(self):
fileutil.rm_dir("cli/test_options")
fileutil.make_dirs("cli/test_options")
fileutil.make_dirs("cli/test_options/private")
open("cli/test_options/node.url","w").write("http://localhost:8080/\n")
filenode_uri = uri.WriteableSSKFileURI(writekey="\x00"*16,
fingerprint="\x00"*32)
private_uri = uri.NewDirectoryURI(filenode_uri).to_string()
open("cli/test_options/private/root_dir.cap", "w").write(private_uri + "\n")
o = cli.ListOptions()
o.parseOptions(["--node-directory", "cli/test_options"])
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], private_uri)
self.failUnlessEqual(o.where, "")
o = cli.ListOptions()
o.parseOptions(["--node-directory", "cli/test_options",
"--node-url", "http://example.org:8111/"])
self.failUnlessEqual(o['node-url'], "http://example.org:8111/")
self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], private_uri)
self.failUnlessEqual(o.where, "")
o = cli.ListOptions()
o.parseOptions(["--node-directory", "cli/test_options",
"--dir-cap", "root"])
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], "root")
self.failUnlessEqual(o.where, "")
o = cli.ListOptions()
other_filenode_uri = uri.WriteableSSKFileURI(writekey="\x11"*16,
fingerprint="\x11"*32)
other_uri = uri.NewDirectoryURI(other_filenode_uri).to_string()
o.parseOptions(["--node-directory", "cli/test_options",
"--dir-cap", other_uri])
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], other_uri)
self.failUnlessEqual(o.where, "")
o = cli.ListOptions()
o.parseOptions(["--node-directory", "cli/test_options",
"--dir-cap", other_uri, "subdir"])
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
self.failUnlessEqual(o.aliases[DEFAULT_ALIAS], other_uri)
self.failUnlessEqual(o.where, "subdir")
def _dump_cap(self, *args):
config = debug.DumpCapOptions()
config.stdout,config.stderr = StringIO(), StringIO()
config.parseOptions(args)
debug.dump_cap(config)
self.failIf(config.stderr.getvalue())
output = config.stdout.getvalue()
return output
def test_dump_cap_chk(self):
key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
storage_index = hashutil.storage_index_hash(key)
uri_extension_hash = hashutil.uri_extension_hash("stuff")
needed_shares = 25
total_shares = 100
size = 1234
u = uri.CHKFileURI(key=key,
uri_extension_hash=uri_extension_hash,
needed_shares=needed_shares,
total_shares=total_shares,
size=size)
output = self._dump_cap(u.to_string())
self.failUnless("CHK File:" in output, output)
self.failUnless("key: aaaqeayeaudaocajbifqydiob4" in output, output)
self.failUnless("UEB hash: nf3nimquen7aeqm36ekgxomalstenpkvsdmf6fplj7swdatbv5oa" in output, output)
self.failUnless("size: 1234" in output, output)
self.failUnless("k/N: 25/100" in output, output)
self.failUnless("storage index: hdis5iaveku6lnlaiccydyid7q" in output, output)
output = self._dump_cap("--client-secret", "5s33nk3qpvnj2fw3z4mnm2y6fa",
u.to_string())
self.failUnless("client renewal secret: znxmki5zdibb5qlt46xbdvk2t55j7hibejq3i5ijyurkr6m6jkhq" in output, output)
output = self._dump_cap(u.get_verifier().to_string())
self.failIf("key: " in output, output)
self.failUnless("UEB hash: nf3nimquen7aeqm36ekgxomalstenpkvsdmf6fplj7swdatbv5oa" in output, output)
self.failUnless("size: 1234" in output, output)
self.failUnless("k/N: 25/100" in output, output)
self.failUnless("storage index: hdis5iaveku6lnlaiccydyid7q" in output, output)
prefixed_u = "http://127.0.0.1/uri/%s" % urllib.quote(u.to_string())
output = self._dump_cap(prefixed_u)
self.failUnless("CHK File:" in output, output)
self.failUnless("key: aaaqeayeaudaocajbifqydiob4" in output, output)
self.failUnless("UEB hash: nf3nimquen7aeqm36ekgxomalstenpkvsdmf6fplj7swdatbv5oa" in output, output)
self.failUnless("size: 1234" in output, output)
self.failUnless("k/N: 25/100" in output, output)
self.failUnless("storage index: hdis5iaveku6lnlaiccydyid7q" in output, output)
def test_dump_cap_lit(self):
u = uri.LiteralFileURI("this is some data")
output = self._dump_cap(u.to_string())
self.failUnless("Literal File URI:" in output, output)
self.failUnless("data: this is some data" in output, output)
def test_dump_cap_ssk(self):
writekey = "\x01" * 16
fingerprint = "\xfe" * 32
u = uri.WriteableSSKFileURI(writekey, fingerprint)
output = self._dump_cap(u.to_string())
self.failUnless("SSK Writeable URI:" in output, output)
self.failUnless("writekey: aeaqcaibaeaqcaibaeaqcaibae" in output, output)
self.failUnless("readkey: nvgh5vj2ekzzkim5fgtb4gey5y" in output, output)
self.failUnless("storage index: nt4fwemuw7flestsezvo2eveke" in output, output)
self.failUnless("fingerprint: 737p57x6737p57x6737p57x6737p57x6737p57x6737p57x6737a" in output, output)
output = self._dump_cap("--client-secret", "5s33nk3qpvnj2fw3z4mnm2y6fa",
u.to_string())
self.failUnless("file renewal secret: arpszxzc2t6kb4okkg7sp765xgkni5z7caavj7lta73vmtymjlxq" in output, output)
fileutil.make_dirs("cli/test_dump_cap/private")
f = open("cli/test_dump_cap/private/secret", "w")
f.write("5s33nk3qpvnj2fw3z4mnm2y6fa\n")
f.close()
output = self._dump_cap("--client-dir", "cli/test_dump_cap",
u.to_string())
self.failUnless("file renewal secret: arpszxzc2t6kb4okkg7sp765xgkni5z7caavj7lta73vmtymjlxq" in output, output)
output = self._dump_cap("--client-dir", "cli/test_dump_cap_BOGUS",
u.to_string())
self.failIf("file renewal secret:" in output, output)
output = self._dump_cap("--nodeid", "tqc35esocrvejvg4mablt6aowg6tl43j",
u.to_string())
self.failUnless("write_enabler: mgcavriox2wlb5eer26unwy5cw56elh3sjweffckkmivvsxtaknq" in output, output)
self.failIf("file renewal secret:" in output, output)
output = self._dump_cap("--nodeid", "tqc35esocrvejvg4mablt6aowg6tl43j",
"--client-secret", "5s33nk3qpvnj2fw3z4mnm2y6fa",
u.to_string())
self.failUnless("write_enabler: mgcavriox2wlb5eer26unwy5cw56elh3sjweffckkmivvsxtaknq" in output, output)
self.failUnless("file renewal secret: arpszxzc2t6kb4okkg7sp765xgkni5z7caavj7lta73vmtymjlxq" in output, output)
self.failUnless("lease renewal secret: 7pjtaumrb7znzkkbvekkmuwpqfjyfyamznfz4bwwvmh4nw33lorq" in output, output)
u = u.get_readonly()
output = self._dump_cap(u.to_string())
self.failUnless("SSK Read-only URI:" in output, output)
self.failUnless("readkey: nvgh5vj2ekzzkim5fgtb4gey5y" in output, output)
self.failUnless("storage index: nt4fwemuw7flestsezvo2eveke" in output, output)
self.failUnless("fingerprint: 737p57x6737p57x6737p57x6737p57x6737p57x6737p57x6737a" in output, output)
u = u.get_verifier()
output = self._dump_cap(u.to_string())
self.failUnless("SSK Verifier URI:" in output, output)
self.failUnless("storage index: nt4fwemuw7flestsezvo2eveke" in output, output)
self.failUnless("fingerprint: 737p57x6737p57x6737p57x6737p57x6737p57x6737p57x6737a" in output, output)
def test_dump_cap_directory(self):
writekey = "\x01" * 16
fingerprint = "\xfe" * 32
u1 = uri.WriteableSSKFileURI(writekey, fingerprint)
u = uri.NewDirectoryURI(u1)
output = self._dump_cap(u.to_string())
self.failUnless("Directory Writeable URI:" in output, output)
self.failUnless("writekey: aeaqcaibaeaqcaibaeaqcaibae" in output,
output)
self.failUnless("readkey: nvgh5vj2ekzzkim5fgtb4gey5y" in output, output)
self.failUnless("storage index: nt4fwemuw7flestsezvo2eveke" in output,
output)
self.failUnless("fingerprint: 737p57x6737p57x6737p57x6737p57x6737p57x6737p57x6737a" in output, output)
output = self._dump_cap("--client-secret", "5s33nk3qpvnj2fw3z4mnm2y6fa",
u.to_string())
self.failUnless("file renewal secret: arpszxzc2t6kb4okkg7sp765xgkni5z7caavj7lta73vmtymjlxq" in output, output)
output = self._dump_cap("--nodeid", "tqc35esocrvejvg4mablt6aowg6tl43j",
u.to_string())
self.failUnless("write_enabler: mgcavriox2wlb5eer26unwy5cw56elh3sjweffckkmivvsxtaknq" in output, output)
self.failIf("file renewal secret:" in output, output)
output = self._dump_cap("--nodeid", "tqc35esocrvejvg4mablt6aowg6tl43j",
"--client-secret", "5s33nk3qpvnj2fw3z4mnm2y6fa",
u.to_string())
self.failUnless("write_enabler: mgcavriox2wlb5eer26unwy5cw56elh3sjweffckkmivvsxtaknq" in output, output)
self.failUnless("file renewal secret: arpszxzc2t6kb4okkg7sp765xgkni5z7caavj7lta73vmtymjlxq" in output, output)
self.failUnless("lease renewal secret: 7pjtaumrb7znzkkbvekkmuwpqfjyfyamznfz4bwwvmh4nw33lorq" in output, output)
u = u.get_readonly()
output = self._dump_cap(u.to_string())
self.failUnless("Directory Read-only URI:" in output, output)
self.failUnless("readkey: nvgh5vj2ekzzkim5fgtb4gey5y" in output, output)
self.failUnless("storage index: nt4fwemuw7flestsezvo2eveke" in output, output)
self.failUnless("fingerprint: 737p57x6737p57x6737p57x6737p57x6737p57x6737p57x6737a" in output, output)
u = u.get_verifier()
output = self._dump_cap(u.to_string())
self.failUnless("Directory Verifier URI:" in output, output)
self.failUnless("storage index: nt4fwemuw7flestsezvo2eveke" in output, output)
self.failUnless("fingerprint: 737p57x6737p57x6737p57x6737p57x6737p57x6737p57x6737a" in output, output)
class CLITestMixin:
def do_cli(self, verb, *args, **kwargs):
nodeargs = [
"--node-directory", self.getdir("client0"),
]
argv = [verb] + nodeargs + 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
class CreateAlias(SystemTestMixin, CLITestMixin, unittest.TestCase):
def _test_webopen(self, args, expected_url):
woo = cli.WebopenOptions()
all_args = ["--node-directory", self.getdir("client0")] + list(args)
woo.parseOptions(all_args)
urls = []
rc = cli.webopen(woo, urls.append)
self.failUnlessEqual(rc, 0)
self.failUnlessEqual(len(urls), 1)
self.failUnlessEqual(urls[0], expected_url)
def test_create(self):
self.basedir = os.path.dirname(self.mktemp())
d = self.set_up_nodes()
d.addCallback(lambda res: self.do_cli("create-alias", "tahoe"))
def _done((stdout,stderr)):
self.failUnless("Alias 'tahoe' created" in stdout)
self.failIf(stderr)
aliases = get_aliases(self.getdir("client0"))
self.failUnless("tahoe" in aliases)
self.failUnless(aliases["tahoe"].startswith("URI:DIR2:"))
d.addCallback(_done)
d.addCallback(lambda res: self.do_cli("create-alias", "two"))
def _stash_urls(res):
aliases = get_aliases(self.getdir("client0"))
node_url_file = os.path.join(self.getdir("client0"), "node.url")
nodeurl = open(node_url_file, "r").read().strip()
uribase = nodeurl + "uri/"
self.tahoe_url = uribase + urllib.quote(aliases["tahoe"]) + "/"
self.tahoe_subdir_url = self.tahoe_url + "subdir/"
self.two_url = uribase + urllib.quote(aliases["two"]) + "/"
d.addCallback(_stash_urls)
d.addCallback(lambda res: self._test_webopen([], self.tahoe_url))
d.addCallback(lambda res: self._test_webopen(["/"], self.tahoe_url))
d.addCallback(lambda res: self._test_webopen(["tahoe:"], self.tahoe_url))
d.addCallback(lambda res: self._test_webopen(["tahoe:/"], self.tahoe_url))
d.addCallback(lambda res: self._test_webopen(["tahoe:subdir"],
self.tahoe_subdir_url))
d.addCallback(lambda res: self._test_webopen(["tahoe:subdir/"],
self.tahoe_subdir_url))
d.addCallback(lambda res: self._test_webopen(["two:"], self.two_url))
return d
class Put(SystemTestMixin, CLITestMixin, unittest.TestCase):
def test_unlinked_immutable_stdin(self):
# tahoe get `echo DATA | tahoe put`
# tahoe get `echo DATA | tahoe put -`
self.basedir = self.mktemp()
DATA = "data" * 100
d = self.set_up_nodes()
d.addCallback(lambda res: self.do_cli("put", stdin=DATA))
def _uploaded(res):
(stdout, stderr) = res
self.failUnless("waiting for file data on stdin.." in stderr)
self.failUnless("200 OK" in stderr)
self.readcap = stdout
self.failUnless(self.readcap.startswith("URI:CHK:"))
d.addCallback(_uploaded)
d.addCallback(lambda res: self.do_cli("get", self.readcap))
def _downloaded(res):
(stdout, stderr) = res
self.failUnlessEqual(stderr, "")
self.failUnlessEqual(stdout, DATA)
d.addCallback(_downloaded)
d.addCallback(lambda res: self.do_cli("put", "-", stdin=DATA))
d.addCallback(lambda (stdout,stderr):
self.failUnlessEqual(stdout, self.readcap))
return d
def test_unlinked_immutable_from_file(self):
# tahoe put file.txt
# tahoe put ./file.txt
# tahoe put /tmp/file.txt
# tahoe put ~/file.txt
self.basedir = os.path.dirname(self.mktemp())
# this will be "allmydata.test.test_cli/Put/test_put_from_file/RANDOM"
# and the RANDOM directory will exist. Raw mktemp returns a filename.
rel_fn = os.path.join(self.basedir, "DATAFILE")
abs_fn = os.path.abspath(rel_fn)
# we make the file small enough to fit in a LIT file, for speed
f = open(rel_fn, "w")
f.write("short file")
f.close()
d = self.set_up_nodes()
d.addCallback(lambda res: self.do_cli("put", rel_fn))
def _uploaded((stdout,stderr)):
readcap = stdout
self.failUnless(readcap.startswith("URI:LIT:"))
self.readcap = readcap
d.addCallback(_uploaded)
d.addCallback(lambda res: self.do_cli("put", "./" + rel_fn))
d.addCallback(lambda (stdout,stderr):
self.failUnlessEqual(stdout, self.readcap))
d.addCallback(lambda res: self.do_cli("put", abs_fn))
d.addCallback(lambda (stdout,stderr):
self.failUnlessEqual(stdout, self.readcap))
# we just have to assume that ~ is handled properly
return d
def test_immutable_from_file(self):
# tahoe put file.txt uploaded.txt
# tahoe - uploaded.txt
# tahoe put file.txt subdir/uploaded.txt
# tahoe put file.txt tahoe:uploaded.txt
# tahoe put file.txt tahoe:subdir/uploaded.txt
# tahoe put file.txt DIRCAP:./uploaded.txt
# tahoe put file.txt DIRCAP:./subdir/uploaded.txt
self.basedir = os.path.dirname(self.mktemp())
rel_fn = os.path.join(self.basedir, "DATAFILE")
abs_fn = os.path.abspath(rel_fn)
# we make the file small enough to fit in a LIT file, for speed
DATA = "short file"
DATA2 = "short file two"
f = open(rel_fn, "w")
f.write(DATA)
f.close()
d = self.set_up_nodes()
d.addCallback(lambda res: self.do_cli("create-alias", "tahoe"))
d.addCallback(lambda res:
self.do_cli("put", rel_fn, "uploaded.txt"))
def _uploaded((stdout,stderr)):
readcap = stdout.strip()
self.failUnless(readcap.startswith("URI:LIT:"))
self.failUnless("201 Created" in stderr, stderr)
self.readcap = readcap
d.addCallback(_uploaded)
d.addCallback(lambda res:
self.do_cli("get", "tahoe:uploaded.txt"))
d.addCallback(lambda (stdout,stderr):
self.failUnlessEqual(stdout, DATA))
d.addCallback(lambda res:
self.do_cli("put", "-", "uploaded.txt", stdin=DATA2))
def _replaced((stdout,stderr)):
readcap = stdout.strip()
self.failUnless(readcap.startswith("URI:LIT:"))
self.failUnless("200 OK" in stderr, stderr)
d.addCallback(_replaced)
d.addCallback(lambda res:
self.do_cli("put", rel_fn, "subdir/uploaded2.txt"))
d.addCallback(lambda res: self.do_cli("get", "subdir/uploaded2.txt"))
d.addCallback(lambda (stdout,stderr):
self.failUnlessEqual(stdout, DATA))
d.addCallback(lambda res:
self.do_cli("put", rel_fn, "tahoe:uploaded3.txt"))
d.addCallback(lambda res: self.do_cli("get", "tahoe:uploaded3.txt"))
d.addCallback(lambda (stdout,stderr):
self.failUnlessEqual(stdout, DATA))
d.addCallback(lambda res:
self.do_cli("put", rel_fn, "tahoe:subdir/uploaded4.txt"))
d.addCallback(lambda res:
self.do_cli("get", "tahoe:subdir/uploaded4.txt"))
d.addCallback(lambda (stdout,stderr):
self.failUnlessEqual(stdout, DATA))
def _get_dircap(res):
self.dircap = get_aliases(self.getdir("client0"))["tahoe"]
d.addCallback(_get_dircap)
d.addCallback(lambda res:
self.do_cli("put", rel_fn,
self.dircap+":./uploaded5.txt"))
d.addCallback(lambda res:
self.do_cli("get", "tahoe:uploaded5.txt"))
d.addCallback(lambda (stdout,stderr):
self.failUnlessEqual(stdout, DATA))
d.addCallback(lambda res:
self.do_cli("put", rel_fn,
self.dircap+":./subdir/uploaded6.txt"))
d.addCallback(lambda res:
self.do_cli("get", "tahoe:subdir/uploaded6.txt"))
d.addCallback(lambda (stdout,stderr):
self.failUnlessEqual(stdout, DATA))
return d
def test_mutable_unlinked(self):
# FILECAP = `echo DATA | tahoe put --mutable`
# tahoe get FILECAP, compare against DATA
# echo DATA2 | tahoe put - FILECAP
# tahoe get FILECAP, compare against DATA2
# tahoe put file.txt FILECAP
self.basedir = os.path.dirname(self.mktemp())
DATA = "data" * 100
DATA2 = "two" * 100
rel_fn = os.path.join(self.basedir, "DATAFILE")
abs_fn = os.path.abspath(rel_fn)
DATA3 = "three" * 100
f = open(rel_fn, "w")
f.write(DATA3)
f.close()
d = self.set_up_nodes()
d.addCallback(lambda res: self.do_cli("put", "--mutable", stdin=DATA))
def _created(res):
(stdout, stderr) = res
self.failUnless("waiting for file data on stdin.." in stderr)
self.failUnless("200 OK" in stderr)
self.filecap = stdout
self.failUnless(self.filecap.startswith("URI:SSK:"))
d.addCallback(_created)
d.addCallback(lambda res: self.do_cli("get", self.filecap))
d.addCallback(lambda (out,err): self.failUnlessEqual(out, DATA))
d.addCallback(lambda res: self.do_cli("put", "-", self.filecap, stdin=DATA2))
def _replaced(res):
(stdout, stderr) = res
self.failUnless("waiting for file data on stdin.." in stderr)
self.failUnless("200 OK" in stderr)
self.failUnlessEqual(self.filecap, stdout)
d.addCallback(_replaced)
d.addCallback(lambda res: self.do_cli("get", self.filecap))
d.addCallback(lambda (out,err): self.failUnlessEqual(out, DATA2))
d.addCallback(lambda res: self.do_cli("put", rel_fn, self.filecap))
def _replaced2(res):
(stdout, stderr) = res
self.failUnless("200 OK" in stderr)
self.failUnlessEqual(self.filecap, stdout)
d.addCallback(_replaced2)
d.addCallback(lambda res: self.do_cli("get", self.filecap))
d.addCallback(lambda (out,err): self.failUnlessEqual(out, DATA3))
return d
def test_mutable(self):
# echo DATA1 | tahoe put --mutable - uploaded.txt
# echo DATA2 | tahoe put - uploaded.txt # should modify-in-place
# tahoe get uploaded.txt, compare against DATA2
self.basedir = os.path.dirname(self.mktemp())
DATA1 = "data" * 100
fn1 = os.path.join(self.basedir, "DATA1")
f = open(fn1, "w")
f.write(DATA1)
f.close()
DATA2 = "two" * 100
fn2 = os.path.join(self.basedir, "DATA2")
f = open(fn2, "w")
f.write(DATA2)
f.close()
d = self.set_up_nodes()
d.addCallback(lambda res: self.do_cli("create-alias", "tahoe"))
d.addCallback(lambda res:
self.do_cli("put", "--mutable", fn1, "tahoe:uploaded.txt"))
d.addCallback(lambda res:
self.do_cli("put", fn2, "tahoe:uploaded.txt"))
d.addCallback(lambda res:
self.do_cli("get", "tahoe:uploaded.txt"))
d.addCallback(lambda (out,err): self.failUnlessEqual(out, DATA2))
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):
import sys
if sys.platform == "darwin":
# pycryptopp-0.5.7's ECDSA is broken on OS-X, it raises a C++
# exception, which halts the whole process. So skip this test.
raise unittest.SkipTest("pycryptopp-0.5.7's ECDSA raises a C++ exception on OS-X")
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