add 'tahoe dump-cap' command, to show storage index, lease secrets, etc

This commit is contained in:
Brian Warner 2008-01-14 13:43:25 -07:00
parent 76ee9cccfe
commit 6ca0efeef6
2 changed files with 272 additions and 4 deletions

View File

@ -1,7 +1,7 @@
# do not import any allmydata modules at this level. Do that from inside
# individual functions instead.
import sys, struct, time
import sys, struct, time, os
from twisted.python import usage
class DumpOptions(usage.Options):
@ -187,11 +187,135 @@ def dump_SDMF_share(offset, length, config, out, err):
print >>out
class DumpCapOptions(usage.Options):
optParameters = [
["nodeid", "n", None, "storage server nodeid (ascii), to construct WE and secrets."],
["client-secret", "c", None, "client's base secret (ascii), to construct secrets"],
["client-dir", "d", None, "client's base directory, from which a -c secret will be read"],
]
def parseArgs(self, cap):
self.cap = cap
def dump_cap(config, out=sys.stdout, err=sys.stderr):
from allmydata import uri
from allmydata.util.idlib import a2b
from base64 import b32decode
cap = config.cap
u = uri.from_string(cap)
nodeid = None
if config['nodeid']:
nodeid = b32decode(config['nodeid'].upper())
secret = None
if config['client-secret']:
secret = a2b(config['client-secret'])
elif config['client-dir']:
secretfile = os.path.join(config['client-dir'], "private", "secret")
try:
secret = a2b(open(secretfile, "r").read().strip())
except EnvironmentError:
pass
print >>out
dump_uri_instance(u, nodeid, secret, out, err)
def _dump_secrets(storage_index, secret, nodeid, out):
from allmydata.util import hashutil
from allmydata.util.idlib import b2a
if secret:
crs = hashutil.my_renewal_secret_hash(secret)
print >>out, " client renewal secret:", b2a(crs)
frs = hashutil.file_renewal_secret_hash(crs, storage_index)
print >>out, " file renewal secret:", b2a(frs)
if nodeid:
renew = hashutil.bucket_renewal_secret_hash(frs, nodeid)
print >>out, " lease renewal secret:", b2a(renew)
ccs = hashutil.my_cancel_secret_hash(secret)
print >>out, " client cancel secret:", b2a(ccs)
fcs = hashutil.file_cancel_secret_hash(ccs, storage_index)
print >>out, " file cancel secret:", b2a(fcs)
if nodeid:
cancel = hashutil.bucket_cancel_secret_hash(fcs, nodeid)
print >>out, " lease cancel secret:", b2a(cancel)
def dump_uri_instance(u, nodeid, secret, out, err, show_header=True):
from allmydata import uri
from allmydata.util.idlib import b2a
from allmydata.util import hashutil
if isinstance(u, uri.CHKFileURI):
if show_header:
print >>out, "CHK File:"
print >>out, " key:", b2a(u.key)
print >>out, " UEB hash:", b2a(u.uri_extension_hash)
print >>out, " size:", u.size
print >>out, " k/N: %d/%d" % (u.needed_shares, u.total_shares)
print >>out, " storage index:", b2a(u.storage_index)
_dump_secrets(u.storage_index, secret, nodeid, out)
elif isinstance(u, uri.CHKFileVerifierURI):
if show_header:
print >>out, "CHK Verifier URI:"
print >>out, " UEB hash:", b2a(u.uri_extension_hash)
print >>out, " size:", u.size
print >>out, " k/N: %d/%d" % (u.needed_shares, u.total_shares)
print >>out, " storage index:", b2a(u.storage_index)
elif isinstance(u, uri.LiteralFileURI):
if show_header:
print >>out, "Literal File URI:"
print >>out, " data:", u.data
elif isinstance(u, uri.WriteableSSKFileURI):
if show_header:
print >>out, "SSK Writeable URI:"
print >>out, " writekey:", b2a(u.writekey)
print >>out, " readkey:", b2a(u.readkey)
print >>out, " storage index:", b2a(u.storage_index)
print >>out, " fingerprint:", b2a(u.fingerprint)
print >>out
if nodeid:
we = hashutil.ssk_write_enabler_hash(u.writekey, nodeid)
print >>out, " write_enabler:", b2a(we)
print >>out
_dump_secrets(u.storage_index, secret, nodeid, out)
elif isinstance(u, uri.ReadonlySSKFileURI):
if show_header:
print >>out, "SSK Read-only URI:"
print >>out, " readkey:", b2a(u.readkey)
print >>out, " storage index:", b2a(u.storage_index)
print >>out, " fingerprint:", b2a(u.fingerprint)
elif isinstance(u, uri.SSKVerifierURI):
if show_header:
print >>out, "SSK Verifier URI:"
print >>out, " storage index:", b2a(u.storage_index)
print >>out, " fingerprint:", b2a(u.fingerprint)
elif isinstance(u, uri.NewDirectoryURI):
if show_header:
print >>out, "Directory Writeable URI:"
dump_uri_instance(u._filenode_uri, nodeid, secret, out, err, False)
elif isinstance(u, uri.ReadonlyNewDirectoryURI):
if show_header:
print >>out, "Directory Read-only URI:"
dump_uri_instance(u._filenode_uri, nodeid, secret, out, err, False)
elif isinstance(u, uri.NewDirectoryURIVerifier):
if show_header:
print >>out, "Directory Verifier URI:"
dump_uri_instance(u._filenode_uri, nodeid, secret, out, err, False)
else:
print >>out, "unknown cap type"
subCommands = [
["dump-share", None, DumpOptions,
"Unpack and display the contents of a share (uri_extension and leases)."],
["dump-cap", None, DumpCapOptions, "Unpack a read-cap or write-cap"]
]
dispatch = {
"dump-share": dump_share,
"dump-cap": dump_cap,
}

View File

@ -1,15 +1,17 @@
from twisted.trial import unittest
from cStringIO import StringIO
from allmydata.util import fileutil
from allmydata.util import fileutil, hashutil
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 cli, tahoe_ls, tahoe_get, tahoe_put, tahoe_rm
from allmydata.scripts import tahoe_ls, tahoe_get, tahoe_put, tahoe_rm
_hush_pyflakes = [tahoe_ls, tahoe_get, tahoe_put, tahoe_rm]
from allmydata.scripts import cli, debug
class CLI(unittest.TestCase):
def test_options(self):
@ -62,3 +64,145 @@ class CLI(unittest.TestCase):
self.failUnlessEqual(o['node-url'], "http://localhost:8080/")
self.failUnlessEqual(o['dir-cap'], other_uri)
self.failUnlessEqual(o['vdrive_pathname'], "subdir")
def _dump_cap(self, *args):
out,err = StringIO(), StringIO()
config = debug.DumpCapOptions()
config.parseOptions(args)
debug.dump_cap(config, out, err)
self.failIf(err.getvalue())
output = out.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_chk_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)
self.failUnless("key: yyyoryarywdyqnyjbefoadeqbh" in output)
self.failUnless("UEB hash: hd7rwri6djiapo6itg5hcxa7ze5im7z9qwcdu8oka6qinahsbiuo" in output)
self.failUnless("size: 1234" in output)
self.failUnless("k/N: 25/100" in output)
self.failUnless("storage index: p3w849k9whqhw6b9fkf4xjs5xc" in output)
output = self._dump_cap("--client-secret", "p3w849k9whqhw6b9fkf4xjs5xc",
u.to_string())
self.failUnless("client renewal secret: pu3oy5fu4irjsudwhn6c71g87anrxi1kokt4hmxz7qh5p1895zpy" in output)
output = self._dump_cap(u.get_verifier().to_string())
self.failIf("key: " in output)
self.failUnless("UEB hash: hd7rwri6djiapo6itg5hcxa7ze5im7z9qwcdu8oka6qinahsbiuo" in output)
self.failUnless("size: 1234" in output)
self.failUnless("k/N: 25/100" in output)
self.failUnless("storage index: p3w849k9whqhw6b9fkf4xjs5xc" in 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)
self.failUnless("data: this is some data" in 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)
self.failUnless("writekey: yryonyebyryonyebyryonyebyr" in output)
self.failUnless("readkey: zhgqsyrkuywo3rha41b1d7xrar" in output)
self.failUnless("storage index: toz9zpxrzjzwoxtuq6xr3ygdze" in output)
self.failUnless("fingerprint: 959x79z6959x79z6959x79z6959x79z6959x79z6959x79z6959y" in output)
output = self._dump_cap("--client-secret", "p3w849k9whqhw6b9fkf4xjs5xc",
u.to_string())
self.failUnless("file renewal secret: xy9p89q9pkitqn4ycwu5tpt9yia7s9izsqudnb4q5jdc3rawgcny" in output)
fileutil.make_dirs("cli/test_dump_cap/private")
f = open("cli/test_dump_cap/private/secret", "w")
f.write("p3w849k9whqhw6b9fkf4xjs5xc\n")
f.close()
output = self._dump_cap("--client-dir", "cli/test_dump_cap",
u.to_string())
self.failUnless("file renewal secret: xy9p89q9pkitqn4ycwu5tpt9yia7s9izsqudnb4q5jdc3rawgcny" in output)
output = self._dump_cap("--client-dir", "cli/test_dump_cap_BOGUS",
u.to_string())
self.failIf("file renewal secret:" in output)
output = self._dump_cap("--nodeid", "tqc35esocrvejvg4mablt6aowg6tl43j",
u.to_string())
self.failUnless("write_enabler: rqk9q6w46dim5ybshqk9kotkyhqcdqmp1z6498xniuz5kkjs1w7o" in output)
self.failIf("file renewal secret:" in output)
output = self._dump_cap("--nodeid", "tqc35esocrvejvg4mablt6aowg6tl43j",
"--client-secret", "p3w849k9whqhw6b9fkf4xjs5xc",
u.to_string())
self.failUnless("write_enabler: rqk9q6w46dim5ybshqk9kotkyhqcdqmp1z6498xniuz5kkjs1w7o" in output)
self.failUnless("file renewal secret: xy9p89q9pkitqn4ycwu5tpt9yia7s9izsqudnb4q5jdc3rawgcny" in output)
self.failUnless("lease renewal secret: r3fsw67mfji3c9mtsisqdumc1pz3gquzdrh4cpu63h8du4uuedgo" in output)
u = u.get_readonly()
output = self._dump_cap(u.to_string())
self.failUnless("SSK Read-only URI:" in output)
self.failUnless("readkey: zhgqsyrkuywo3rha41b1d7xrar" in output)
self.failUnless("storage index: toz9zpxrzjzwoxtuq6xr3ygdze" in output)
self.failUnless("fingerprint: 959x79z6959x79z6959x79z6959x79z6959x79z6959x79z6959y" in output)
u = u.get_verifier()
output = self._dump_cap(u.to_string())
self.failUnless("SSK Verifier URI:" in output)
self.failUnless("storage index: toz9zpxrzjzwoxtuq6xr3ygdze" in output)
self.failUnless("fingerprint: 959x79z6959x79z6959x79z6959x79z6959x79z6959x79z6959y" in 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)
self.failUnless("writekey: yryonyebyryonyebyryonyebyr" in output)
self.failUnless("readkey: zhgqsyrkuywo3rha41b1d7xrar" in output)
self.failUnless("storage index: toz9zpxrzjzwoxtuq6xr3ygdze" in output)
self.failUnless("fingerprint: 959x79z6959x79z6959x79z6959x79z6959x79z6959x79z6959y" in output)
output = self._dump_cap("--client-secret", "p3w849k9whqhw6b9fkf4xjs5xc",
u.to_string())
self.failUnless("file renewal secret: xy9p89q9pkitqn4ycwu5tpt9yia7s9izsqudnb4q5jdc3rawgcny" in output)
output = self._dump_cap("--nodeid", "tqc35esocrvejvg4mablt6aowg6tl43j",
u.to_string())
self.failUnless("write_enabler: rqk9q6w46dim5ybshqk9kotkyhqcdqmp1z6498xniuz5kkjs1w7o" in output)
self.failIf("file renewal secret:" in output)
output = self._dump_cap("--nodeid", "tqc35esocrvejvg4mablt6aowg6tl43j",
"--client-secret", "p3w849k9whqhw6b9fkf4xjs5xc",
u.to_string())
self.failUnless("write_enabler: rqk9q6w46dim5ybshqk9kotkyhqcdqmp1z6498xniuz5kkjs1w7o" in output)
self.failUnless("file renewal secret: xy9p89q9pkitqn4ycwu5tpt9yia7s9izsqudnb4q5jdc3rawgcny" in output)
self.failUnless("lease renewal secret: r3fsw67mfji3c9mtsisqdumc1pz3gquzdrh4cpu63h8du4uuedgo" in output)
u = u.get_readonly()
output = self._dump_cap(u.to_string())
self.failUnless("Directory Read-only URI:" in output)
self.failUnless("readkey: zhgqsyrkuywo3rha41b1d7xrar" in output)
self.failUnless("storage index: toz9zpxrzjzwoxtuq6xr3ygdze" in output)
self.failUnless("fingerprint: 959x79z6959x79z6959x79z6959x79z6959x79z6959x79z6959y" in output)
u = u.get_verifier()
output = self._dump_cap(u.to_string())
self.failUnless("Directory Verifier URI:" in output)
self.failUnless("storage index: toz9zpxrzjzwoxtuq6xr3ygdze" in output)
self.failUnless("fingerprint: 959x79z6959x79z6959x79z6959x79z6959x79z6959x79z6959y" in output)