Impose micro-POLA by passing only the writekey instead of the whole node object to {{{_encrypt_rw_uri()}}}. Remove DummyImmutableFileNode in nodemaker.py, which is obviated by this. Add micro-optimization by precomputing the netstring of the empty string and branching on whether the writekey is present or not outside of {{{_encrypt_rw_uri()}}}. Add doc about writekey to docstring.
fixes #967
new_contents = self.node._pack_contents(children)
return new_contents
+def _encrypt_rw_uri(writekey, rw_uri):
+ precondition(isinstance(rw_uri, str), rw_uri)
+ precondition(isinstance(writekey, str), writekey)
-def _encrypt_rw_uri(filenode, rw_uri):
- assert isinstance(rw_uri, str)
- writekey = filenode.get_writekey()
- if not writekey:
- return ""
salt = hashutil.mutable_rwcap_salt_hash(rw_uri)
key = hashutil.mutable_rwcap_key_hash(salt, writekey)
cryptor = AES(key)
# The MAC is not checked by readers in Tahoe >= 1.3.0, but we still
# produce it for the sake of older readers.
-
-def pack_children(filenode, childrenx, deep_immutable=False):
+def pack_children(childrenx, writekey, deep_immutable=False):
# initial_children must have metadata (i.e. {} instead of None)
children = {}
for (namex, (node, metadata)) in childrenx.iteritems():
"directory creation requires metadata to be a dict, not None", metadata)
children[normalize(namex)] = (node, metadata)
- return _pack_normalized_children(filenode, children, deep_immutable=deep_immutable)
+ return _pack_normalized_children(children, writekey=writekey, deep_immutable=deep_immutable)
-def _pack_normalized_children(filenode, children, deep_immutable=False):
+ZERO_LEN_NETSTR=netstring('')
+def _pack_normalized_children(children, writekey, deep_immutable=False):
"""Take a dict that maps:
children[unicode_nfc_name] = (IFileSystemNode, metadata_dict)
and pack it into a single string, for use as the contents of the backing
as the pre-packed entry, which is faster than re-packing everything each
time.
+ If writekey is provided then I will superencrypt the child's writecap with
+ writekey.
+
If deep_immutable is True, I will require that all my children are deeply
immutable, and will raise a MustBeDeepImmutableError if not.
"""
+ precondition((writekey is None) or isinstance(writekey, str), writekey)
has_aux = isinstance(children, AuxValueDict)
entries = []
if rw_uri is None:
rw_uri = ""
assert isinstance(rw_uri, str), rw_uri
-
+
# should be prevented by MustBeDeepImmutableError check above
assert not (rw_uri and deep_immutable)
if ro_uri is None:
ro_uri = ""
assert isinstance(ro_uri, str), ro_uri
+ if writekey is not None:
+ writecap = netstring(_encrypt_rw_uri(writekey, rw_uri))
+ else:
+ writecap = ZERO_LEN_NETSTR
entry = "".join([netstring(name.encode("utf-8")),
netstring(strip_prefix_for_ro(ro_uri, deep_immutable)),
- netstring(_encrypt_rw_uri(filenode, rw_uri)),
+ writecap,
netstring(simplejson.dumps(metadata))])
entries.append(netstring(entry))
return "".join(entries)
def _pack_contents(self, children):
# expects children in the same format as _unpack_contents returns
- return _pack_normalized_children(self._node, children)
+ return _pack_normalized_children(children, self._node.get_writekey())
def is_readonly(self):
return self._node.is_readonly()
from allmydata.unknown import UnknownNode
from allmydata import uri
-class DummyImmutableFileNode:
- def get_writekey(self):
- return None
-
class NodeMaker:
implements(INodeMaker)
# this returns synchronously. It starts with a "cap string".
assert isinstance(writecap, (str, type(None))), type(writecap)
assert isinstance(readcap, (str, type(None))), type(readcap)
-
+
bigcap = writecap or readcap
if not bigcap:
# maybe the writecap was hidden because we're in a readonly
def create_new_mutable_directory(self, initial_children={}):
d = self.create_mutable_file(lambda n:
- pack_children(n, initial_children))
+ pack_children(initial_children, n.get_writekey()))
d.addCallback(self._create_dirnode)
return d
def create_immutable_directory(self, children, convergence=None):
if convergence is None:
convergence = self.secret_holder.get_convergence_secret()
- n = DummyImmutableFileNode() # writekey=None
- packed = pack_children(n, children, deep_immutable=True)
+ packed = pack_children(children, None, deep_immutable=True)
uploadable = Data(packed, convergence)
d = self.uploader.upload(uploadable, history=self.history)
d.addCallback(lambda results: self.create_from_cap(None, results.uri))
kids = self._make_kids(nm, ["imm", "lit", "write", "read",
"dirwrite", "dirread"])
- packed = dirnode.pack_children(fn, kids, deep_immutable=False)
+ packed = dirnode.pack_children(kids, fn.get_writekey(), deep_immutable=False)
self.failUnlessIn("lit", packed)
kids = self._make_kids(nm, ["imm", "lit"])
- packed = dirnode.pack_children(fn, kids, deep_immutable=True)
+ packed = dirnode.pack_children(kids, fn.get_writekey(), deep_immutable=True)
self.failUnlessIn("lit", packed)
kids = self._make_kids(nm, ["imm", "lit", "write"])
self.failUnlessRaises(dirnode.MustBeDeepImmutableError,
dirnode.pack_children,
- fn, kids, deep_immutable=True)
+ kids, fn.get_writekey(), deep_immutable=True)
# read-only is not enough: all children must be immutable
kids = self._make_kids(nm, ["imm", "lit", "read"])
self.failUnlessRaises(dirnode.MustBeDeepImmutableError,
dirnode.pack_children,
- fn, kids, deep_immutable=True)
+ kids, fn.get_writekey(), deep_immutable=True)
kids = self._make_kids(nm, ["imm", "lit", "dirwrite"])
self.failUnlessRaises(dirnode.MustBeDeepImmutableError,
dirnode.pack_children,
- fn, kids, deep_immutable=True)
+ kids, fn.get_writekey(), deep_immutable=True)
kids = self._make_kids(nm, ["imm", "lit", "dirread"])
self.failUnlessRaises(dirnode.MustBeDeepImmutableError,
dirnode.pack_children,
- fn, kids, deep_immutable=True)
+ kids, fn.get_writekey(), deep_immutable=True)
class FakeMutableFile:
implements(IMutableFileNode)