# 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):
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,
}
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):
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)
+