mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-01-19 03:06:33 +00:00
mutable: rearrange classes, putting MutableFileNode at the bottom
This commit is contained in:
parent
c595f6ccd0
commit
7cf9a13f2a
@ -159,146 +159,6 @@ def pack_offsets(verification_key_length, signature_length,
|
||||
offsets['enc_privkey'],
|
||||
offsets['EOF'])
|
||||
|
||||
# use client.create_mutable_file() to make one of these
|
||||
|
||||
class MutableFileNode:
|
||||
implements(IMutableFileNode)
|
||||
publish_class = Publish
|
||||
retrieve_class = Retrieve
|
||||
|
||||
def __init__(self, client):
|
||||
self._client = client
|
||||
self._pubkey = None # filled in upon first read
|
||||
self._privkey = None # filled in if we're mutable
|
||||
self._required_shares = None # ditto
|
||||
self._total_shares = None # ditto
|
||||
self._sharemap = {} # known shares, shnum-to-[nodeids]
|
||||
|
||||
self._current_data = None # SDMF: we're allowed to cache the contents
|
||||
self._current_roothash = None # ditto
|
||||
self._current_seqnum = None # ditto
|
||||
|
||||
def init_from_uri(self, myuri):
|
||||
# we have the URI, but we have not yet retrieved the public
|
||||
# verification key, nor things like 'k' or 'N'. If and when someone
|
||||
# wants to get our contents, we'll pull from shares and fill those
|
||||
# in.
|
||||
self._uri = IMutableFileURI(myuri)
|
||||
self._writekey = self._uri.writekey
|
||||
self._readkey = self._uri.readkey
|
||||
self._storage_index = self._uri.storage_index
|
||||
return self
|
||||
|
||||
def create(self, initial_contents):
|
||||
"""Call this when the filenode is first created. This will generate
|
||||
the keys, generate the initial shares, allocate shares, and upload
|
||||
the initial contents. Returns a Deferred that fires (with the
|
||||
MutableFileNode instance you should use) when it completes.
|
||||
"""
|
||||
self._required_shares = 3
|
||||
self._total_shares = 10
|
||||
d = defer.maybeDeferred(self._generate_pubprivkeys)
|
||||
def _generated( (pubkey, privkey) ):
|
||||
self._pubkey, self._privkey = pubkey, privkey
|
||||
pubkey_s = self._pubkey.serialize()
|
||||
privkey_s = self._privkey.serialize()
|
||||
self._writekey = hashutil.ssk_writekey_hash(privkey_s)
|
||||
self._encprivkey = self._encrypt_privkey(self._writekey, privkey_s)
|
||||
self._fingerprint = hashutil.ssk_pubkey_fingerprint_hash(pubkey_s)
|
||||
self._uri = WriteableSSKFileURI(self._writekey, self._fingerprint)
|
||||
self._readkey = self._uri.readkey
|
||||
self._storage_index = self._uri.storage_index
|
||||
# TODO: seqnum/roothash: really we mean "doesn't matter since
|
||||
# nobody knows about us yet"
|
||||
self._current_seqnum = 0
|
||||
self._current_roothash = "\x00"*32
|
||||
return self._publish(initial_contents)
|
||||
d.addCallback(_generated)
|
||||
return d
|
||||
|
||||
def _generate_pubprivkeys(self):
|
||||
# TODO: wire these up to pycryptopp
|
||||
privkey = "very private"
|
||||
pubkey = "public"
|
||||
return pubkey, privkey
|
||||
|
||||
def _publish(self, initial_contents):
|
||||
p = self.publish_class(self)
|
||||
d = p.publish(initial_contents)
|
||||
d.addCallback(lambda res: self)
|
||||
return d
|
||||
|
||||
def _encrypt_privkey(self, writekey, privkey):
|
||||
enc = AES.new(key=writekey, mode=AES.MODE_CTR, counterstart="\x00"*16)
|
||||
crypttext = enc.encrypt(privkey)
|
||||
return crypttext
|
||||
|
||||
def get_write_enabler(self, nodeid):
|
||||
return hashutil.ssk_write_enabler_hash(self._writekey, nodeid)
|
||||
def get_renewal_secret(self, nodeid):
|
||||
crs = self._client.get_renewal_secret()
|
||||
frs = hashutil.file_renewal_secret_hash(crs, self._storage_index)
|
||||
return hashutil.bucket_renewal_secret_hash(frs, nodeid)
|
||||
def get_cancel_secret(self, nodeid):
|
||||
ccs = self._client.get_cancel_secret()
|
||||
fcs = hashutil.file_cancel_secret_hash(ccs, self._storage_index)
|
||||
return hashutil.bucket_cancel_secret_hash(fcs, nodeid)
|
||||
|
||||
def get_writekey(self):
|
||||
return self._writekey
|
||||
def get_readkey(self):
|
||||
return self._readkey
|
||||
def get_storage_index(self):
|
||||
return self._storage_index
|
||||
def get_privkey(self):
|
||||
return self._privkey
|
||||
def get_encprivkey(self):
|
||||
return self._encprivkey
|
||||
def get_pubkey(self):
|
||||
return self._pubkey
|
||||
|
||||
def get_required_shares(self):
|
||||
return self._required_shares
|
||||
def get_total_shares(self):
|
||||
return self._total_shares
|
||||
|
||||
|
||||
def get_uri(self):
|
||||
return self._uri.to_string()
|
||||
|
||||
def is_mutable(self):
|
||||
return self._uri.is_mutable()
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.__class__, self.uri))
|
||||
def __cmp__(self, them):
|
||||
if cmp(type(self), type(them)):
|
||||
return cmp(type(self), type(them))
|
||||
if cmp(self.__class__, them.__class__):
|
||||
return cmp(self.__class__, them.__class__)
|
||||
return cmp(self.uri, them.uri)
|
||||
|
||||
def get_verifier(self):
|
||||
return IMutableFileURI(self._uri).get_verifier()
|
||||
|
||||
def check(self):
|
||||
verifier = self.get_verifier()
|
||||
return self._client.getServiceNamed("checker").check(verifier)
|
||||
|
||||
def download(self, target):
|
||||
#downloader = self._client.getServiceNamed("downloader")
|
||||
#return downloader.download(self.uri, target)
|
||||
raise NotImplementedError
|
||||
|
||||
def download_to_data(self):
|
||||
#downloader = self._client.getServiceNamed("downloader")
|
||||
#return downloader.download_to_data(self.uri)
|
||||
return defer.succeed("this isn't going to fool you, is it")
|
||||
|
||||
def replace(self, newdata):
|
||||
return defer.succeed(None)
|
||||
|
||||
|
||||
class Retrieve:
|
||||
def __init__(self, filenode):
|
||||
self._node = filenode
|
||||
@ -997,3 +857,142 @@ class Publish:
|
||||
# but dispatch_map will help us do it
|
||||
raise UncoordinatedWriteError("I was surprised!")
|
||||
|
||||
|
||||
# use client.create_mutable_file() to make one of these
|
||||
|
||||
class MutableFileNode:
|
||||
implements(IMutableFileNode)
|
||||
publish_class = Publish
|
||||
retrieve_class = Retrieve
|
||||
|
||||
def __init__(self, client):
|
||||
self._client = client
|
||||
self._pubkey = None # filled in upon first read
|
||||
self._privkey = None # filled in if we're mutable
|
||||
self._required_shares = None # ditto
|
||||
self._total_shares = None # ditto
|
||||
self._sharemap = {} # known shares, shnum-to-[nodeids]
|
||||
|
||||
self._current_data = None # SDMF: we're allowed to cache the contents
|
||||
self._current_roothash = None # ditto
|
||||
self._current_seqnum = None # ditto
|
||||
|
||||
def init_from_uri(self, myuri):
|
||||
# we have the URI, but we have not yet retrieved the public
|
||||
# verification key, nor things like 'k' or 'N'. If and when someone
|
||||
# wants to get our contents, we'll pull from shares and fill those
|
||||
# in.
|
||||
self._uri = IMutableFileURI(myuri)
|
||||
self._writekey = self._uri.writekey
|
||||
self._readkey = self._uri.readkey
|
||||
self._storage_index = self._uri.storage_index
|
||||
return self
|
||||
|
||||
def create(self, initial_contents):
|
||||
"""Call this when the filenode is first created. This will generate
|
||||
the keys, generate the initial shares, allocate shares, and upload
|
||||
the initial contents. Returns a Deferred that fires (with the
|
||||
MutableFileNode instance you should use) when it completes.
|
||||
"""
|
||||
self._required_shares = 3
|
||||
self._total_shares = 10
|
||||
d = defer.maybeDeferred(self._generate_pubprivkeys)
|
||||
def _generated( (pubkey, privkey) ):
|
||||
self._pubkey, self._privkey = pubkey, privkey
|
||||
pubkey_s = self._pubkey.serialize()
|
||||
privkey_s = self._privkey.serialize()
|
||||
self._writekey = hashutil.ssk_writekey_hash(privkey_s)
|
||||
self._encprivkey = self._encrypt_privkey(self._writekey, privkey_s)
|
||||
self._fingerprint = hashutil.ssk_pubkey_fingerprint_hash(pubkey_s)
|
||||
self._uri = WriteableSSKFileURI(self._writekey, self._fingerprint)
|
||||
self._readkey = self._uri.readkey
|
||||
self._storage_index = self._uri.storage_index
|
||||
# TODO: seqnum/roothash: really we mean "doesn't matter since
|
||||
# nobody knows about us yet"
|
||||
self._current_seqnum = 0
|
||||
self._current_roothash = "\x00"*32
|
||||
return self._publish(initial_contents)
|
||||
d.addCallback(_generated)
|
||||
return d
|
||||
|
||||
def _generate_pubprivkeys(self):
|
||||
# TODO: wire these up to pycryptopp
|
||||
privkey = "very private"
|
||||
pubkey = "public"
|
||||
return pubkey, privkey
|
||||
|
||||
def _publish(self, initial_contents):
|
||||
p = self.publish_class(self)
|
||||
d = p.publish(initial_contents)
|
||||
d.addCallback(lambda res: self)
|
||||
return d
|
||||
|
||||
def _encrypt_privkey(self, writekey, privkey):
|
||||
enc = AES.new(key=writekey, mode=AES.MODE_CTR, counterstart="\x00"*16)
|
||||
crypttext = enc.encrypt(privkey)
|
||||
return crypttext
|
||||
|
||||
def get_write_enabler(self, nodeid):
|
||||
return hashutil.ssk_write_enabler_hash(self._writekey, nodeid)
|
||||
def get_renewal_secret(self, nodeid):
|
||||
crs = self._client.get_renewal_secret()
|
||||
frs = hashutil.file_renewal_secret_hash(crs, self._storage_index)
|
||||
return hashutil.bucket_renewal_secret_hash(frs, nodeid)
|
||||
def get_cancel_secret(self, nodeid):
|
||||
ccs = self._client.get_cancel_secret()
|
||||
fcs = hashutil.file_cancel_secret_hash(ccs, self._storage_index)
|
||||
return hashutil.bucket_cancel_secret_hash(fcs, nodeid)
|
||||
|
||||
def get_writekey(self):
|
||||
return self._writekey
|
||||
def get_readkey(self):
|
||||
return self._readkey
|
||||
def get_storage_index(self):
|
||||
return self._storage_index
|
||||
def get_privkey(self):
|
||||
return self._privkey
|
||||
def get_encprivkey(self):
|
||||
return self._encprivkey
|
||||
def get_pubkey(self):
|
||||
return self._pubkey
|
||||
|
||||
def get_required_shares(self):
|
||||
return self._required_shares
|
||||
def get_total_shares(self):
|
||||
return self._total_shares
|
||||
|
||||
|
||||
def get_uri(self):
|
||||
return self._uri.to_string()
|
||||
|
||||
def is_mutable(self):
|
||||
return self._uri.is_mutable()
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self.__class__, self.uri))
|
||||
def __cmp__(self, them):
|
||||
if cmp(type(self), type(them)):
|
||||
return cmp(type(self), type(them))
|
||||
if cmp(self.__class__, them.__class__):
|
||||
return cmp(self.__class__, them.__class__)
|
||||
return cmp(self.uri, them.uri)
|
||||
|
||||
def get_verifier(self):
|
||||
return IMutableFileURI(self._uri).get_verifier()
|
||||
|
||||
def check(self):
|
||||
verifier = self.get_verifier()
|
||||
return self._client.getServiceNamed("checker").check(verifier)
|
||||
|
||||
def download(self, target):
|
||||
#downloader = self._client.getServiceNamed("downloader")
|
||||
#return downloader.download(self.uri, target)
|
||||
raise NotImplementedError
|
||||
|
||||
def download_to_data(self):
|
||||
#downloader = self._client.getServiceNamed("downloader")
|
||||
#return downloader.download_to_data(self.uri)
|
||||
return defer.succeed("this isn't going to fool you, is it")
|
||||
|
||||
def replace(self, newdata):
|
||||
return defer.succeed(None)
|
||||
|
Loading…
Reference in New Issue
Block a user