mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-02-01 00:45:52 +00:00
add 'tahoe dump-cap' command, to show storage index, lease secrets, etc
This commit is contained in:
parent
76ee9cccfe
commit
6ca0efeef6
@ -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,
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user