minor code clean-up in dirnode.py

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
This commit is contained in:
Zooko O'Whielacronx 2010-07-13 23:02:55 -07:00
parent 11077ea74d
commit 6e8477114e
3 changed files with 27 additions and 26 deletions

View File

@ -171,12 +171,10 @@ class Adder:
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)
@ -187,8 +185,7 @@ def _encrypt_rw_uri(filenode, rw_uri):
# 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():
@ -196,10 +193,11 @@ def pack_children(filenode, childrenx, deep_immutable=False):
"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
@ -208,9 +206,13 @@ def _pack_normalized_children(filenode, children, deep_immutable=False):
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 = []
@ -231,7 +233,7 @@ def _pack_normalized_children(filenode, children, deep_immutable=False):
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)
@ -239,9 +241,13 @@ def _pack_normalized_children(filenode, children, deep_immutable=False):
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)
@ -368,7 +374,7 @@ class DirectoryNode:
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()

View File

@ -8,10 +8,6 @@ from allmydata.dirnode import DirectoryNode, pack_children
from allmydata.unknown import UnknownNode
from allmydata import uri
class DummyImmutableFileNode:
def get_writekey(self):
return None
class NodeMaker:
implements(INodeMaker)
@ -47,7 +43,7 @@ class NodeMaker:
# 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
@ -97,15 +93,14 @@ class NodeMaker:
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))

View File

@ -1246,33 +1246,33 @@ class Packing(unittest.TestCase):
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)