From 482a7dd3f11a19d0fc6e22524736f744deb1ce88 Mon Sep 17 00:00:00 2001
From: Brian Warner <warner@lothar.com>
Date: Sat, 27 Aug 2011 12:50:48 -0700
Subject: [PATCH] Add 'tahoe debug dump-cap' support for MDMF, DIR2-CHK,
 DIR2-MDMF. refs #1507.

This also adds tests for all those cases, and fixes an omission in uri.py
that broke parsing of DIR2-MDMF-Verifier and DIR2-CHK-Verifier.
---
 src/allmydata/scripts/debug.py |  60 ++++++++++++--
 src/allmydata/test/test_cli.py | 141 +++++++++++++++++++++++++++++++--
 src/allmydata/uri.py           |   4 +
 3 files changed, 194 insertions(+), 11 deletions(-)

diff --git a/src/allmydata/scripts/debug.py b/src/allmydata/scripts/debug.py
index 786f058c..1cff7751 100644
--- a/src/allmydata/scripts/debug.py
+++ b/src/allmydata/scripts/debug.py
@@ -415,9 +415,9 @@ def dump_uri_instance(u, nodeid, secret, out, show_header=True):
             print >>out, "Literal File URI:"
         print >>out, " data:", quote_output(u.data)
 
-    elif isinstance(u, uri.WriteableSSKFileURI):
+    elif isinstance(u, uri.WriteableSSKFileURI): # SDMF
         if show_header:
-            print >>out, "SSK Writeable URI:"
+            print >>out, "SDMF Writeable URI:"
         print >>out, " writekey:", base32.b2a(u.writekey)
         print >>out, " readkey:", base32.b2a(u.readkey)
         print >>out, " storage index:", si_b2a(u.get_storage_index())
@@ -428,20 +428,54 @@ def dump_uri_instance(u, nodeid, secret, out, show_header=True):
             print >>out, " write_enabler:", base32.b2a(we)
             print >>out
         _dump_secrets(u.get_storage_index(), secret, nodeid, out)
-
     elif isinstance(u, uri.ReadonlySSKFileURI):
         if show_header:
-            print >>out, "SSK Read-only URI:"
+            print >>out, "SDMF Read-only URI:"
         print >>out, " readkey:", base32.b2a(u.readkey)
         print >>out, " storage index:", si_b2a(u.get_storage_index())
         print >>out, " fingerprint:", base32.b2a(u.fingerprint)
     elif isinstance(u, uri.SSKVerifierURI):
         if show_header:
-            print >>out, "SSK Verifier URI:"
+            print >>out, "SDMF Verifier URI:"
         print >>out, " storage index:", si_b2a(u.get_storage_index())
         print >>out, " fingerprint:", base32.b2a(u.fingerprint)
 
-    elif isinstance(u, uri.DirectoryURI):
+    elif isinstance(u, uri.WriteableMDMFFileURI): # MDMF
+        if show_header:
+            print >>out, "MDMF Writeable URI:"
+        print >>out, " writekey:", base32.b2a(u.writekey)
+        print >>out, " readkey:", base32.b2a(u.readkey)
+        print >>out, " storage index:", si_b2a(u.get_storage_index())
+        print >>out, " fingerprint:", base32.b2a(u.fingerprint)
+        print >>out
+        if nodeid:
+            we = hashutil.ssk_write_enabler_hash(u.writekey, nodeid)
+            print >>out, " write_enabler:", base32.b2a(we)
+            print >>out
+        _dump_secrets(u.get_storage_index(), secret, nodeid, out)
+    elif isinstance(u, uri.ReadonlyMDMFFileURI):
+        if show_header:
+            print >>out, "MDMF Read-only URI:"
+        print >>out, " readkey:", base32.b2a(u.readkey)
+        print >>out, " storage index:", si_b2a(u.get_storage_index())
+        print >>out, " fingerprint:", base32.b2a(u.fingerprint)
+    elif isinstance(u, uri.MDMFVerifierURI):
+        if show_header:
+            print >>out, "MDMF Verifier URI:"
+        print >>out, " storage index:", si_b2a(u.get_storage_index())
+        print >>out, " fingerprint:", base32.b2a(u.fingerprint)
+
+
+    elif isinstance(u, uri.ImmutableDirectoryURI): # CHK-based directory
+        if show_header:
+            print >>out, "CHK Directory URI:"
+        dump_uri_instance(u._filenode_uri, nodeid, secret, out, False)
+    elif isinstance(u, uri.ImmutableDirectoryURIVerifier):
+        if show_header:
+            print >>out, "CHK Directory Verifier URI:"
+        dump_uri_instance(u._filenode_uri, nodeid, secret, out, False)
+
+    elif isinstance(u, uri.DirectoryURI): # SDMF-based directory
         if show_header:
             print >>out, "Directory Writeable URI:"
         dump_uri_instance(u._filenode_uri, nodeid, secret, out, False)
@@ -453,6 +487,20 @@ def dump_uri_instance(u, nodeid, secret, out, show_header=True):
         if show_header:
             print >>out, "Directory Verifier URI:"
         dump_uri_instance(u._filenode_uri, nodeid, secret, out, False)
+
+    elif isinstance(u, uri.MDMFDirectoryURI): # MDMF-based directory
+        if show_header:
+            print >>out, "Directory Writeable URI:"
+        dump_uri_instance(u._filenode_uri, nodeid, secret, out, False)
+    elif isinstance(u, uri.ReadonlyMDMFDirectoryURI):
+        if show_header:
+            print >>out, "Directory Read-only URI:"
+        dump_uri_instance(u._filenode_uri, nodeid, secret, out, False)
+    elif isinstance(u, uri.MDMFDirectoryURIVerifier):
+        if show_header:
+            print >>out, "Directory Verifier URI:"
+        dump_uri_instance(u._filenode_uri, nodeid, secret, out, False)
+
     else:
         print >>out, "unknown cap type"
 
diff --git a/src/allmydata/test/test_cli.py b/src/allmydata/test/test_cli.py
index 38c84ccd..39b0f6bb 100644
--- a/src/allmydata/test/test_cli.py
+++ b/src/allmydata/test/test_cli.py
@@ -187,13 +187,13 @@ class CLI(CLITestMixin, unittest.TestCase):
         self.failUnless("Literal File URI:" in output, output)
         self.failUnless("data: 'this is some data'" in output, output)
 
-    def test_dump_cap_ssk(self):
+    def test_dump_cap_sdmf(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("SDMF 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)
@@ -227,18 +227,104 @@ class CLI(CLITestMixin, unittest.TestCase):
 
         u = u.get_readonly()
         output = self._dump_cap(u.to_string())
-        self.failUnless("SSK Read-only URI:" in output, output)
+        self.failUnless("SDMF 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_verify_cap()
         output = self._dump_cap(u.to_string())
-        self.failUnless("SSK Verifier URI:" in output, output)
+        self.failUnless("SDMF 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):
+    def test_dump_cap_mdmf(self):
+        writekey = "\x01" * 16
+        fingerprint = "\xfe" * 32
+        u = uri.WriteableMDMFFileURI(writekey, fingerprint)
+
+        output = self._dump_cap(u.to_string())
+        self.failUnless("MDMF 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")
+        fileutil.write("cli/test_dump_cap/private/secret", "5s33nk3qpvnj2fw3z4mnm2y6fa\n")
+        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("MDMF 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_verify_cap()
+        output = self._dump_cap(u.to_string())
+        self.failUnless("MDMF Verifier URI:" in output, output)
+        self.failUnless("storage index: nt4fwemuw7flestsezvo2eveke" in output, output)
+        self.failUnless("fingerprint: 737p57x6737p57x6737p57x6737p57x6737p57x6737p57x6737a" in output, output)
+
+
+    def test_dump_cap_chk_directory(self):
+        key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+        uri_extension_hash = hashutil.uri_extension_hash("stuff")
+        needed_shares = 25
+        total_shares = 100
+        size = 1234
+        u1 = uri.CHKFileURI(key=key,
+                            uri_extension_hash=uri_extension_hash,
+                            needed_shares=needed_shares,
+                            total_shares=total_shares,
+                            size=size)
+        u = uri.ImmutableDirectoryURI(u1)
+
+        output = self._dump_cap(u.to_string())
+        self.failUnless("CHK Directory URI:" 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("file renewal secret: csrvkjgomkyyyil5yo4yk5np37p6oa2ve2hg6xmk2dy7kaxsu6xq" in output, output)
+
+        u = u.get_verify_cap()
+        output = self._dump_cap(u.to_string())
+        self.failUnless("CHK Directory Verifier URI:" in output, output)
+        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)
+
+    def test_dump_cap_sdmf_directory(self):
         writekey = "\x01" * 16
         fingerprint = "\xfe" * 32
         u1 = uri.WriteableSSKFileURI(writekey, fingerprint)
@@ -282,6 +368,51 @@ class CLI(CLITestMixin, unittest.TestCase):
         self.failUnless("storage index: nt4fwemuw7flestsezvo2eveke" in output, output)
         self.failUnless("fingerprint: 737p57x6737p57x6737p57x6737p57x6737p57x6737p57x6737a" in output, output)
 
+    def test_dump_cap_mdmf_directory(self):
+        writekey = "\x01" * 16
+        fingerprint = "\xfe" * 32
+        u1 = uri.WriteableMDMFFileURI(writekey, fingerprint)
+        u = uri.MDMFDirectoryURI(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_verify_cap()
+        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)
+
+
     def _catalog_shares(self, *basedirs):
         o = debug.CatalogSharesOptions()
         o.stdout,o.stderr = StringIO(), StringIO()
diff --git a/src/allmydata/uri.py b/src/allmydata/uri.py
index d9d87354..50b04ca8 100644
--- a/src/allmydata/uri.py
+++ b/src/allmydata/uri.py
@@ -930,6 +930,8 @@ def from_string(u, deep_immutable=False, name=u"<unknown name>"):
             return DirectoryURIVerifier.init_from_string(s)
         elif s.startswith('URI:DIR2-CHK:'):
             return ImmutableDirectoryURI.init_from_string(s)
+        elif s.startswith('URI:DIR2-CHK-Verifier:'):
+            return ImmutableDirectoryURIVerifier.init_from_string(s)
         elif s.startswith('URI:DIR2-LIT:'):
             return LiteralDirectoryURI.init_from_string(s)
         elif s.startswith('URI:DIR2-MDMF:'):
@@ -940,6 +942,8 @@ def from_string(u, deep_immutable=False, name=u"<unknown name>"):
             if can_be_mutable:
                 return ReadonlyMDMFDirectoryURI.init_from_string(s)
             kind = "URI:DIR2-MDMF-RO readcap to a mutable directory"
+        elif s.startswith('URI:DIR2-MDMF-Verifier:'):
+            return MDMFDirectoryURIVerifier.init_from_string(s)
         elif s.startswith('x-tahoe-future-test-writeable:') and not can_be_writeable:
             # For testing how future writeable caps would behave in read-only contexts.
             kind = "x-tahoe-future-test-writeable: testing cap"
-- 
2.45.2