示例#1
0
    def _unpack_contents(self, data):
        # the directory is serialized as a list of netstrings, one per child.
        # Each child is serialized as a list of four netstrings: (name, ro_uri,
        # rwcapdata, metadata), in which the name, ro_uri, metadata are in
        # cleartext. The 'name' is UTF-8 encoded, and should be normalized to NFC.
        # The rwcapdata is formatted as:
        # pack("16ss32s", iv, AES(H(writekey+iv), plaintext_rw_uri), mac)
        assert isinstance(data, str), (repr(data), type(data))
        # an empty directory is serialized as an empty string
        if data == "":
            return AuxValueDict()
        writeable = not self.is_readonly()
        mutable = self.is_mutable()
        children = AuxValueDict()
        position = 0
        while position < len(data):
            entries, position = split_netstring(data, 1, position)
            entry = entries[0]
            (namex_utf8, ro_uri, rwcapdata, metadata_s), subpos = split_netstring(entry, 4)
            if not mutable and len(rwcapdata) > 0:
                raise ValueError("the rwcapdata field of a dirnode in an immutable directory was not empty")

            # A name containing characters that are unassigned in one version of Unicode might
            # not be normalized wrt a later version. See the note in section 'Normalization Stability'
            # at <http://unicode.org/policies/stability_policy.html>.
            # Therefore we normalize names going both in and out of directories.
            name = normalize(namex_utf8.decode("utf-8"))

            rw_uri = ""
            if writeable:
                rw_uri = self._decrypt_rwcapdata(rwcapdata)

            # Since the encryption uses CTR mode, it currently leaks the length of the
            # plaintext rw_uri -- and therefore whether it is present, i.e. whether the
            # dirnode is writeable (ticket #925). By stripping trailing spaces in
            # Tahoe >= 1.6.0, we may make it easier for future versions to plug this leak.
            # ro_uri is treated in the same way for consistency.
            # rw_uri and ro_uri will be either None or a non-empty string.

            rw_uri = rw_uri.rstrip(' ') or None
            ro_uri = ro_uri.rstrip(' ') or None

            try:
                child = self._create_and_validate_node(rw_uri, ro_uri, name)
                if mutable or child.is_allowed_in_immutable_directory():
                    metadata = json.loads(metadata_s)
                    assert isinstance(metadata, dict)
                    children[name] = (child, metadata)
                    children.set_with_aux(name, (child, metadata), auxilliary=entry)
                else:
                    log.msg(format="mutable cap for child %(name)s unpacked from an immutable directory",
                            name=quote_output(name, encoding='utf-8'),
                            facility="tahoe.webish", level=log.UNUSUAL)
            except CapConstraintError as e:
                log.msg(format="unmet constraint on cap for child %(name)s unpacked from a directory:\n"
                               "%(message)s", message=e.args[0], name=quote_output(name, encoding='utf-8'),
                               facility="tahoe.webish", level=log.UNUSUAL)

        return children
示例#2
0
    def _unpack_contents(self, data):
        # the directory is serialized as a list of netstrings, one per child.
        # Each child is serialized as a list of four netstrings: (name, ro_uri,
        # rwcapdata, metadata), in which the name, ro_uri, metadata are in
        # cleartext. The 'name' is UTF-8 encoded, and should be normalized to NFC.
        # The rwcapdata is formatted as:
        # pack("16ss32s", iv, AES(H(writekey+iv), plaintext_rw_uri), mac)
        assert isinstance(data, str), (repr(data), type(data))
        # an empty directory is serialized as an empty string
        if data == "":
            return AuxValueDict()
        writeable = not self.is_readonly()
        mutable = self.is_mutable()
        children = AuxValueDict()
        position = 0
        while position < len(data):
            entries, position = split_netstring(data, 1, position)
            entry = entries[0]
            (namex_utf8, ro_uri, rwcapdata, metadata_s), subpos = split_netstring(entry, 4)
            if not mutable and len(rwcapdata) > 0:
                raise ValueError("the rwcapdata field of a dirnode in an immutable directory was not empty")

            # A name containing characters that are unassigned in one version of Unicode might
            # not be normalized wrt a later version. See the note in section 'Normalization Stability'
            # at <http://unicode.org/policies/stability_policy.html>.
            # Therefore we normalize names going both in and out of directories.
            name = normalize(namex_utf8.decode("utf-8"))

            rw_uri = ""
            if writeable:
                rw_uri = self._decrypt_rwcapdata(rwcapdata)

            # Since the encryption uses CTR mode, it currently leaks the length of the
            # plaintext rw_uri -- and therefore whether it is present, i.e. whether the
            # dirnode is writeable (ticket #925). By stripping trailing spaces in
            # Tahoe >= 1.6.0, we may make it easier for future versions to plug this leak.
            # ro_uri is treated in the same way for consistency.
            # rw_uri and ro_uri will be either None or a non-empty string.

            rw_uri = rw_uri.rstrip(' ') or None
            ro_uri = ro_uri.rstrip(' ') or None

            try:
                child = self._create_and_validate_node(rw_uri, ro_uri, name)
                if mutable or child.is_allowed_in_immutable_directory():
                    metadata = simplejson.loads(metadata_s)
                    assert isinstance(metadata, dict)
                    children[name] = (child, metadata)
                    children.set_with_aux(name, (child, metadata), auxilliary=entry)
                else:
                    log.msg(format="mutable cap for child %(name)s unpacked from an immutable directory",
                                   name=quote_output(name, encoding='utf-8'),
                                   facility="tahoe.webish", level=log.UNUSUAL)
            except CapConstraintError, e:
                log.msg(format="unmet constraint on cap for child %(name)s unpacked from a directory:\n"
                               "%(message)s", message=e.args[0], name=quote_output(name, encoding='utf-8'),
                               facility="tahoe.webish", level=log.UNUSUAL)
示例#3
0
 def test_split(self):
     a = netstring("hello") + netstring("world")
     self.failUnlessEqual(split_netstring(a, 2), (["hello", "world"], len(a)))
     self.failUnlessEqual(split_netstring(a, 2, required_trailer=""), (["hello", "world"], len(a)))
     self.failUnlessRaises(ValueError, split_netstring, a, 3)
     self.failUnlessRaises(ValueError, split_netstring, a+" extra", 2, required_trailer="")
     self.failUnlessEqual(split_netstring(a+" extra", 2), (["hello", "world"], len(a)))
     self.failUnlessEqual(split_netstring(a+"++", 2, required_trailer="++"),
                          (["hello", "world"], len(a)+2))
     self.failUnlessRaises(ValueError,
                           split_netstring, a+"+", 2, required_trailer="not")
示例#4
0
 def test_nested(self):
     a = netstring(b"hello") + netstring(b"world") + b"extra stuff"
     b = netstring(b"a") + netstring(b"is") + netstring(a) + netstring(b".")
     (top, pos) = split_netstring(b, 4)
     self.failUnlessEqual(len(top), 4)
     self.failUnlessEqual(top[0], b"a")
     self.failUnlessEqual(top[1], b"is")
     self.failUnlessEqual(top[2], a)
     self.failUnlessEqual(top[3], b".")
     self.failUnlessRaises(ValueError, split_netstring, a, 2, required_trailer=b"")
     bottom = split_netstring(a, 2)
     self.failUnlessEqual(bottom, ([b"hello", b"world"], len(netstring(b"hello")+netstring(b"world"))))
示例#5
0
 def test_nested(self):
     a = netstring("hello") + netstring("world") + "extra stuff"
     b = netstring("a") + netstring("is") + netstring(a) + netstring(".")
     (top, pos) = split_netstring(b, 4)
     self.failUnlessEqual(len(top), 4)
     self.failUnlessEqual(top[0], "a")
     self.failUnlessEqual(top[1], "is")
     self.failUnlessEqual(top[2], a)
     self.failUnlessEqual(top[3], ".")
     self.failUnlessRaises(ValueError, split_netstring, a, 2, required_trailer="")
     bottom = split_netstring(a, 2)
     self.failUnlessEqual(bottom, (["hello", "world"], len(netstring("hello")+netstring("world"))))
示例#6
0
 def test_split(self):
     a = netstring(b"hello") + netstring(b"world")
     for s in split_netstring(a, 2)[0]:
         self.assertIsInstance(s, bytes)
     self.failUnlessEqual(split_netstring(a, 2), ([b"hello", b"world"], len(a)))
     self.failUnlessEqual(split_netstring(a, 2, required_trailer=b""), ([b"hello", b"world"], len(a)))
     self.failUnlessRaises(ValueError, split_netstring, a, 3)
     self.failUnlessRaises(ValueError, split_netstring, a+b" extra", 2, required_trailer=b"")
     self.failUnlessEqual(split_netstring(a+b" extra", 2), ([b"hello", b"world"], len(a)))
     self.failUnlessEqual(split_netstring(a+b"++", 2, required_trailer=b"++"),
                          ([b"hello", b"world"], len(a)+2))
     self.failUnlessRaises(ValueError,
                           split_netstring, a+b"+", 2, required_trailer=b"not")
示例#7
0
 def test_split(self):
     a = netstring("hello") + netstring("world")
     self.failUnlessEqual(split_netstring(a, 2),
                          (["hello", "world"], len(a)))
     self.failUnlessEqual(split_netstring(a, 2, required_trailer=""),
                          (["hello", "world"], len(a)))
     self.failUnlessRaises(ValueError, split_netstring, a, 3)
     self.failUnlessRaises(ValueError,
                           split_netstring,
                           a + " extra",
                           2,
                           required_trailer="")
     self.failUnlessEqual(split_netstring(a + " extra", 2),
                          (["hello", "world"], len(a)))
     self.failUnlessEqual(
         split_netstring(a + "++", 2, required_trailer="++"),
         (["hello", "world"], len(a) + 2))
     self.failUnlessRaises(ValueError,
                           split_netstring,
                           a + "+",
                           2,
                           required_trailer="not")
示例#8
0
 def test_extra(self):
     a = netstring(b"hello")
     self.failUnlessEqual(split_netstring(a, 1), ([b"hello"], len(a)))
     b = netstring(b"hello") + b"extra stuff"
     self.failUnlessEqual(split_netstring(b, 1),
                          ([b"hello"], len(a)))
示例#9
0
 def test_extra(self):
     a = netstring("hello")
     self.failUnlessEqual(split_netstring(a, 1), (["hello"], len(a)))
     b = netstring("hello") + "extra stuff"
     self.failUnlessEqual(split_netstring(b, 1),
                          (["hello"], len(a)))