2007-01-17 04:29:59 +00:00
|
|
|
|
2008-01-03 23:55:43 +00:00
|
|
|
import re, urllib
|
2007-07-21 22:40:36 +00:00
|
|
|
from zope.interface import implements
|
|
|
|
from twisted.python.components import registerAdapter
|
2009-02-18 21:46:55 +00:00
|
|
|
from allmydata.storage.server import si_a2b, si_b2a
|
2008-02-15 02:45:12 +00:00
|
|
|
from allmydata.util import base32, hashutil
|
2009-01-07 19:24:51 +00:00
|
|
|
from allmydata.interfaces import IURI, IDirnodeURI, IFileURI, IImmutableFileURI, \
|
2010-01-27 06:44:30 +00:00
|
|
|
IVerifierURI, IMutableFileURI, IDirectoryURI, IReadonlyDirectoryURI, \
|
|
|
|
MustBeDeepImmutableError, MustBeReadonlyError, CapConstraintError
|
2007-07-12 23:17:49 +00:00
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
class BadURIError(CapConstraintError):
|
2009-07-15 06:45:10 +00:00
|
|
|
pass
|
|
|
|
|
2010-01-27 07:03:09 +00:00
|
|
|
# The URI shall be an ASCII representation of a reference to the file/directory.
|
|
|
|
# It shall contain enough information to retrieve and validate the contents.
|
|
|
|
# It shall be expressed in a limited character set (currently base32 plus ':' and
|
|
|
|
# capital letters, but future URIs might use a larger charset).
|
|
|
|
|
|
|
|
# TODO:
|
|
|
|
# - rename all of the *URI classes/interfaces to *Cap
|
|
|
|
# - make variable and method names consistently use _uri for an URI string,
|
|
|
|
# and _cap for a Cap object (decoded URI)
|
|
|
|
# - remove the human_encoding methods?
|
2007-01-17 04:29:59 +00:00
|
|
|
|
2008-02-15 02:27:47 +00:00
|
|
|
BASE32STR_128bits = '(%s{25}%s)' % (base32.BASE32CHAR, base32.BASE32CHAR_3bits)
|
|
|
|
BASE32STR_256bits = '(%s{51}%s)' % (base32.BASE32CHAR, base32.BASE32CHAR_1bits)
|
2007-12-19 00:44:24 +00:00
|
|
|
|
2008-01-03 23:55:43 +00:00
|
|
|
SEP='(?::|%3A)'
|
|
|
|
NUMBER='([0-9]+)'
|
2008-12-17 00:49:30 +00:00
|
|
|
NUMBER_IGNORE='(?:[0-9]+)'
|
2011-08-07 00:44:36 +00:00
|
|
|
OPTIONAL_EXTENSION_FIELD = '(' + SEP + '[0-9' + SEP + ']+|)'
|
2007-12-19 00:44:24 +00:00
|
|
|
|
2010-01-27 07:03:09 +00:00
|
|
|
# "human-encoded" URIs are allowed to come with a leading
|
2008-11-26 00:57:37 +00:00
|
|
|
# 'http://127.0.0.1:(8123|3456)/uri/' that will be ignored.
|
2010-01-27 07:03:09 +00:00
|
|
|
# Note that nothing in the Tahoe code currently uses the human encoding.
|
2008-12-17 00:49:30 +00:00
|
|
|
OPTIONALHTTPLEAD=r'(?:https?://(?:[^:/]+)(?::%s)?/uri/)?' % NUMBER_IGNORE
|
2007-12-19 00:44:24 +00:00
|
|
|
|
2007-06-02 01:48:01 +00:00
|
|
|
|
2007-07-21 22:40:36 +00:00
|
|
|
class _BaseURI:
|
|
|
|
def __hash__(self):
|
2008-09-23 18:52:49 +00:00
|
|
|
return self.to_string().__hash__()
|
2010-01-27 07:03:09 +00:00
|
|
|
|
2008-09-23 18:52:49 +00:00
|
|
|
def __eq__(self, them):
|
|
|
|
if isinstance(them, _BaseURI):
|
|
|
|
return self.to_string() == them.to_string()
|
|
|
|
else:
|
|
|
|
return False
|
2010-01-27 07:03:09 +00:00
|
|
|
|
2008-09-23 18:52:49 +00:00
|
|
|
def __ne__(self, them):
|
|
|
|
if isinstance(them, _BaseURI):
|
|
|
|
return self.to_string() != them.to_string()
|
|
|
|
else:
|
|
|
|
return True
|
2010-01-27 07:03:09 +00:00
|
|
|
|
2008-01-03 23:55:43 +00:00
|
|
|
def to_human_encoding(self):
|
2008-11-26 00:57:37 +00:00
|
|
|
return 'http://127.0.0.1:3456/uri/'+self.to_string()
|
2007-07-21 22:40:36 +00:00
|
|
|
|
2008-11-13 03:17:25 +00:00
|
|
|
def get_storage_index(self):
|
|
|
|
return self.storage_index
|
|
|
|
|
2010-01-27 07:03:09 +00:00
|
|
|
|
2007-07-21 22:40:36 +00:00
|
|
|
class CHKFileURI(_BaseURI):
|
2009-01-07 19:24:51 +00:00
|
|
|
implements(IURI, IImmutableFileURI)
|
2007-07-21 22:40:36 +00:00
|
|
|
|
2009-11-04 17:24:53 +00:00
|
|
|
BASE_STRING='URI:CHK:'
|
2008-02-15 02:27:47 +00:00
|
|
|
STRING_RE=re.compile('^URI:CHK:'+BASE32STR_128bits+':'+
|
|
|
|
BASE32STR_256bits+':'+NUMBER+':'+NUMBER+':'+NUMBER+
|
2008-01-03 23:55:43 +00:00
|
|
|
'$')
|
|
|
|
HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'CHK'+SEP+
|
2008-02-15 02:27:47 +00:00
|
|
|
BASE32STR_128bits+SEP+BASE32STR_256bits+SEP+NUMBER+
|
2008-01-03 23:55:43 +00:00
|
|
|
SEP+NUMBER+SEP+NUMBER+'$')
|
|
|
|
|
|
|
|
def __init__(self, key, uri_extension_hash, needed_shares, total_shares,
|
|
|
|
size):
|
|
|
|
self.key = key
|
|
|
|
self.uri_extension_hash = uri_extension_hash
|
|
|
|
self.needed_shares = needed_shares
|
|
|
|
self.total_shares = total_shares
|
|
|
|
self.size = size
|
2008-02-01 19:27:37 +00:00
|
|
|
self.storage_index = hashutil.storage_index_hash(self.key)
|
2009-07-15 06:45:10 +00:00
|
|
|
if not len(self.storage_index) == 16: # sha256 hash truncated to 128
|
|
|
|
raise BadURIError("storage index must be 16 bytes long")
|
2008-01-03 23:55:43 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def init_from_human_encoding(cls, uri):
|
|
|
|
mo = cls.HUMAN_RE.search(uri)
|
2009-07-15 06:45:10 +00:00
|
|
|
if not mo:
|
2010-01-27 06:44:30 +00:00
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
2008-02-15 02:27:47 +00:00
|
|
|
return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)),
|
2008-01-03 23:55:43 +00:00
|
|
|
int(mo.group(3)), int(mo.group(4)), int(mo.group(5)))
|
2007-07-21 22:40:36 +00:00
|
|
|
|
2008-01-03 05:12:15 +00:00
|
|
|
@classmethod
|
|
|
|
def init_from_string(cls, uri):
|
2008-01-03 23:55:43 +00:00
|
|
|
mo = cls.STRING_RE.search(uri)
|
2009-07-15 06:45:10 +00:00
|
|
|
if not mo:
|
2010-01-27 06:44:30 +00:00
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
2008-02-15 02:27:47 +00:00
|
|
|
return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)),
|
2008-01-03 23:55:43 +00:00
|
|
|
int(mo.group(3)), int(mo.group(4)), int(mo.group(5)))
|
2007-07-22 01:23:15 +00:00
|
|
|
|
|
|
|
def to_string(self):
|
2007-07-21 22:40:36 +00:00
|
|
|
assert isinstance(self.needed_shares, int)
|
|
|
|
assert isinstance(self.total_shares, int)
|
|
|
|
assert isinstance(self.size, (int,long))
|
|
|
|
|
2008-01-03 23:55:43 +00:00
|
|
|
return ('URI:CHK:%s:%s:%d:%d:%d' %
|
2008-02-15 02:27:47 +00:00
|
|
|
(base32.b2a(self.key),
|
|
|
|
base32.b2a(self.uri_extension_hash),
|
2007-07-21 22:40:36 +00:00
|
|
|
self.needed_shares,
|
|
|
|
self.total_shares,
|
|
|
|
self.size))
|
|
|
|
|
|
|
|
def is_readonly(self):
|
|
|
|
return True
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2007-07-21 22:40:36 +00:00
|
|
|
def is_mutable(self):
|
|
|
|
return False
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2007-07-21 22:40:36 +00:00
|
|
|
def get_readonly(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def get_size(self):
|
|
|
|
return self.size
|
|
|
|
|
2008-12-08 19:44:11 +00:00
|
|
|
def get_verify_cap(self):
|
2007-10-15 23:16:39 +00:00
|
|
|
return CHKFileVerifierURI(storage_index=self.storage_index,
|
|
|
|
uri_extension_hash=self.uri_extension_hash,
|
|
|
|
needed_shares=self.needed_shares,
|
|
|
|
total_shares=self.total_shares,
|
|
|
|
size=self.size)
|
|
|
|
|
|
|
|
class CHKFileVerifierURI(_BaseURI):
|
|
|
|
implements(IVerifierURI)
|
|
|
|
|
2009-11-18 16:42:38 +00:00
|
|
|
BASE_STRING='URI:CHK-Verifier:'
|
2008-02-15 02:27:47 +00:00
|
|
|
STRING_RE=re.compile('^URI:CHK-Verifier:'+BASE32STR_128bits+':'+
|
|
|
|
BASE32STR_256bits+':'+NUMBER+':'+NUMBER+':'+NUMBER)
|
2008-01-03 23:55:43 +00:00
|
|
|
HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'CHK-Verifier'+SEP+
|
2008-02-15 02:27:47 +00:00
|
|
|
BASE32STR_128bits+SEP+BASE32STR_256bits+SEP+NUMBER+
|
2008-01-03 23:55:43 +00:00
|
|
|
SEP+NUMBER+SEP+NUMBER)
|
2007-12-05 00:38:31 +00:00
|
|
|
|
2008-01-03 23:55:43 +00:00
|
|
|
def __init__(self, storage_index, uri_extension_hash,
|
2007-12-05 00:38:31 +00:00
|
|
|
needed_shares, total_shares, size):
|
2008-01-03 23:55:43 +00:00
|
|
|
assert len(storage_index) == 16
|
2007-12-05 00:38:31 +00:00
|
|
|
self.storage_index = storage_index
|
|
|
|
self.uri_extension_hash = uri_extension_hash
|
|
|
|
self.needed_shares = needed_shares
|
|
|
|
self.total_shares = total_shares
|
|
|
|
self.size = size
|
2007-10-15 23:16:39 +00:00
|
|
|
|
2008-01-03 23:55:43 +00:00
|
|
|
@classmethod
|
|
|
|
def init_from_human_encoding(cls, uri):
|
|
|
|
mo = cls.HUMAN_RE.search(uri)
|
2010-01-27 06:44:30 +00:00
|
|
|
if not mo:
|
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
2008-02-15 02:27:47 +00:00
|
|
|
return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)),
|
2008-01-03 23:55:43 +00:00
|
|
|
int(mo.group(3)), int(mo.group(4)), int(mo.group(5)))
|
|
|
|
|
2008-01-03 05:12:15 +00:00
|
|
|
@classmethod
|
|
|
|
def init_from_string(cls, uri):
|
2008-01-03 23:55:43 +00:00
|
|
|
mo = cls.STRING_RE.search(uri)
|
2010-01-27 06:44:30 +00:00
|
|
|
if not mo:
|
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
2009-02-18 21:46:55 +00:00
|
|
|
return cls(si_a2b(mo.group(1)), base32.a2b(mo.group(2)),
|
2008-01-03 23:55:43 +00:00
|
|
|
int(mo.group(3)), int(mo.group(4)), int(mo.group(5)))
|
2007-10-15 23:16:39 +00:00
|
|
|
|
|
|
|
def to_string(self):
|
|
|
|
assert isinstance(self.needed_shares, int)
|
|
|
|
assert isinstance(self.total_shares, int)
|
|
|
|
assert isinstance(self.size, (int,long))
|
|
|
|
|
2008-01-03 23:55:43 +00:00
|
|
|
return ('URI:CHK-Verifier:%s:%s:%d:%d:%d' %
|
2009-02-18 21:46:55 +00:00
|
|
|
(si_b2a(self.storage_index),
|
2008-02-15 02:27:47 +00:00
|
|
|
base32.b2a(self.uri_extension_hash),
|
2007-10-15 23:16:39 +00:00
|
|
|
self.needed_shares,
|
|
|
|
self.total_shares,
|
|
|
|
self.size))
|
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
def is_readonly(self):
|
|
|
|
return True
|
|
|
|
|
|
|
|
def is_mutable(self):
|
|
|
|
return False
|
|
|
|
|
|
|
|
def get_readonly(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def get_verify_cap(self):
|
|
|
|
return self
|
|
|
|
|
2007-10-15 23:16:39 +00:00
|
|
|
|
2007-07-21 22:40:36 +00:00
|
|
|
class LiteralFileURI(_BaseURI):
|
2009-01-07 19:24:51 +00:00
|
|
|
implements(IURI, IImmutableFileURI)
|
2007-07-21 22:40:36 +00:00
|
|
|
|
2009-11-04 17:24:53 +00:00
|
|
|
BASE_STRING='URI:LIT:'
|
2008-02-15 02:27:47 +00:00
|
|
|
STRING_RE=re.compile('^URI:LIT:'+base32.BASE32STR_anybytes+'$')
|
|
|
|
HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'LIT'+SEP+base32.BASE32STR_anybytes+'$')
|
2008-01-03 23:55:43 +00:00
|
|
|
|
2007-07-21 22:40:36 +00:00
|
|
|
def __init__(self, data=None):
|
|
|
|
if data is not None:
|
2009-11-12 00:22:33 +00:00
|
|
|
assert isinstance(data, str)
|
2007-07-21 22:40:36 +00:00
|
|
|
self.data = data
|
|
|
|
|
2008-01-03 23:55:43 +00:00
|
|
|
@classmethod
|
|
|
|
def init_from_human_encoding(cls, uri):
|
|
|
|
mo = cls.HUMAN_RE.search(uri)
|
2010-01-27 06:44:30 +00:00
|
|
|
if not mo:
|
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
2008-02-15 02:27:47 +00:00
|
|
|
return cls(base32.a2b(mo.group(1)))
|
2008-01-03 23:55:43 +00:00
|
|
|
|
2008-01-03 05:12:15 +00:00
|
|
|
@classmethod
|
|
|
|
def init_from_string(cls, uri):
|
2008-01-03 23:55:43 +00:00
|
|
|
mo = cls.STRING_RE.search(uri)
|
2010-01-27 06:44:30 +00:00
|
|
|
if not mo:
|
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
2008-02-15 02:27:47 +00:00
|
|
|
return cls(base32.a2b(mo.group(1)))
|
2007-07-21 22:40:36 +00:00
|
|
|
|
|
|
|
def to_string(self):
|
2008-02-15 02:27:47 +00:00
|
|
|
return 'URI:LIT:%s' % base32.b2a(self.data)
|
2007-07-21 22:40:36 +00:00
|
|
|
|
|
|
|
def is_readonly(self):
|
|
|
|
return True
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2007-07-21 22:40:36 +00:00
|
|
|
def is_mutable(self):
|
|
|
|
return False
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2007-07-21 22:40:36 +00:00
|
|
|
def get_readonly(self):
|
|
|
|
return self
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2008-11-13 03:17:25 +00:00
|
|
|
def get_storage_index(self):
|
|
|
|
return None
|
2007-07-21 22:40:36 +00:00
|
|
|
|
2008-12-08 19:44:11 +00:00
|
|
|
def get_verify_cap(self):
|
2007-10-15 23:16:39 +00:00
|
|
|
# LIT files need no verification, all the data is present in the URI
|
|
|
|
return None
|
|
|
|
|
2007-07-21 22:40:36 +00:00
|
|
|
def get_size(self):
|
|
|
|
return len(self.data)
|
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2007-11-01 22:15:29 +00:00
|
|
|
class WriteableSSKFileURI(_BaseURI):
|
|
|
|
implements(IURI, IMutableFileURI)
|
|
|
|
|
2008-01-03 23:55:43 +00:00
|
|
|
BASE_STRING='URI:SSK:'
|
2008-02-15 02:27:47 +00:00
|
|
|
STRING_RE=re.compile('^'+BASE_STRING+BASE32STR_128bits+':'+
|
|
|
|
BASE32STR_256bits+'$')
|
2008-01-03 23:55:43 +00:00
|
|
|
HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'SSK'+SEP+
|
2008-02-15 02:27:47 +00:00
|
|
|
BASE32STR_128bits+SEP+BASE32STR_256bits+'$')
|
2008-01-03 23:55:43 +00:00
|
|
|
|
2008-01-03 05:12:15 +00:00
|
|
|
def __init__(self, writekey, fingerprint):
|
2007-11-01 22:15:29 +00:00
|
|
|
self.writekey = writekey
|
|
|
|
self.readkey = hashutil.ssk_readkey_hash(writekey)
|
|
|
|
self.storage_index = hashutil.ssk_storage_index_hash(self.readkey)
|
2008-01-03 23:55:43 +00:00
|
|
|
assert len(self.storage_index) == 16
|
2007-11-01 22:15:29 +00:00
|
|
|
self.fingerprint = fingerprint
|
|
|
|
|
2008-01-03 05:12:15 +00:00
|
|
|
@classmethod
|
|
|
|
def init_from_human_encoding(cls, uri):
|
2008-01-03 23:55:43 +00:00
|
|
|
mo = cls.HUMAN_RE.search(uri)
|
2009-07-15 06:45:10 +00:00
|
|
|
if not mo:
|
2010-01-27 06:44:30 +00:00
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
2008-02-15 02:27:47 +00:00
|
|
|
return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)))
|
2008-01-03 05:12:15 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def init_from_string(cls, uri):
|
2008-01-03 23:55:43 +00:00
|
|
|
mo = cls.STRING_RE.search(uri)
|
2009-07-15 06:45:10 +00:00
|
|
|
if not mo:
|
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
2008-02-15 02:27:47 +00:00
|
|
|
return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)))
|
2007-11-01 22:15:29 +00:00
|
|
|
|
|
|
|
def to_string(self):
|
|
|
|
assert isinstance(self.writekey, str)
|
|
|
|
assert isinstance(self.fingerprint, str)
|
2008-02-15 02:27:47 +00:00
|
|
|
return 'URI:SSK:%s:%s' % (base32.b2a(self.writekey),
|
|
|
|
base32.b2a(self.fingerprint))
|
2007-11-01 22:15:29 +00:00
|
|
|
|
2007-12-03 21:52:42 +00:00
|
|
|
def __repr__(self):
|
|
|
|
return "<%s %s>" % (self.__class__.__name__, self.abbrev())
|
|
|
|
|
|
|
|
def abbrev(self):
|
2008-02-15 02:27:47 +00:00
|
|
|
return base32.b2a(self.writekey[:5])
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2009-01-31 02:31:10 +00:00
|
|
|
def abbrev_si(self):
|
|
|
|
return base32.b2a(self.storage_index)[:5]
|
2007-12-03 21:52:42 +00:00
|
|
|
|
2007-11-01 22:15:29 +00:00
|
|
|
def is_readonly(self):
|
|
|
|
return False
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2007-11-01 22:15:29 +00:00
|
|
|
def is_mutable(self):
|
|
|
|
return True
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2007-11-01 22:15:29 +00:00
|
|
|
def get_readonly(self):
|
|
|
|
return ReadonlySSKFileURI(self.readkey, self.fingerprint)
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2008-12-08 19:44:11 +00:00
|
|
|
def get_verify_cap(self):
|
2007-11-01 22:15:29 +00:00
|
|
|
return SSKVerifierURI(self.storage_index, self.fingerprint)
|
|
|
|
|
2011-08-07 00:44:36 +00:00
|
|
|
def get_extension_params(self):
|
|
|
|
return []
|
|
|
|
|
|
|
|
def set_extension_params(self, params):
|
|
|
|
pass
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2007-11-01 22:15:29 +00:00
|
|
|
class ReadonlySSKFileURI(_BaseURI):
|
|
|
|
implements(IURI, IMutableFileURI)
|
|
|
|
|
2008-01-03 23:55:43 +00:00
|
|
|
BASE_STRING='URI:SSK-RO:'
|
2008-02-15 02:27:47 +00:00
|
|
|
STRING_RE=re.compile('^URI:SSK-RO:'+BASE32STR_128bits+':'+BASE32STR_256bits+'$')
|
|
|
|
HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'SSK-RO'+SEP+BASE32STR_128bits+SEP+BASE32STR_256bits+'$')
|
2008-01-03 23:55:43 +00:00
|
|
|
|
2008-01-03 05:12:15 +00:00
|
|
|
def __init__(self, readkey, fingerprint):
|
2007-11-01 22:15:29 +00:00
|
|
|
self.readkey = readkey
|
|
|
|
self.storage_index = hashutil.ssk_storage_index_hash(self.readkey)
|
2008-01-03 23:55:43 +00:00
|
|
|
assert len(self.storage_index) == 16
|
2007-11-01 22:15:29 +00:00
|
|
|
self.fingerprint = fingerprint
|
|
|
|
|
2008-01-03 23:55:43 +00:00
|
|
|
@classmethod
|
|
|
|
def init_from_human_encoding(cls, uri):
|
|
|
|
mo = cls.HUMAN_RE.search(uri)
|
2009-07-15 06:45:10 +00:00
|
|
|
if not mo:
|
2010-01-27 06:44:30 +00:00
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
2008-02-15 02:27:47 +00:00
|
|
|
return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)))
|
2008-01-03 23:55:43 +00:00
|
|
|
|
2008-01-03 05:12:15 +00:00
|
|
|
@classmethod
|
|
|
|
def init_from_string(cls, uri):
|
2008-01-03 23:55:43 +00:00
|
|
|
mo = cls.STRING_RE.search(uri)
|
2009-07-15 06:45:10 +00:00
|
|
|
if not mo:
|
2010-01-27 06:44:30 +00:00
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
2008-02-15 02:27:47 +00:00
|
|
|
return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)))
|
2007-11-01 22:15:29 +00:00
|
|
|
|
|
|
|
def to_string(self):
|
|
|
|
assert isinstance(self.readkey, str)
|
|
|
|
assert isinstance(self.fingerprint, str)
|
2008-02-15 02:27:47 +00:00
|
|
|
return 'URI:SSK-RO:%s:%s' % (base32.b2a(self.readkey),
|
|
|
|
base32.b2a(self.fingerprint))
|
2007-11-01 22:15:29 +00:00
|
|
|
|
2007-12-03 21:52:42 +00:00
|
|
|
def __repr__(self):
|
|
|
|
return "<%s %s>" % (self.__class__.__name__, self.abbrev())
|
|
|
|
|
|
|
|
def abbrev(self):
|
2008-02-15 02:27:47 +00:00
|
|
|
return base32.b2a(self.readkey[:5])
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2009-01-31 02:31:10 +00:00
|
|
|
def abbrev_si(self):
|
|
|
|
return base32.b2a(self.storage_index)[:5]
|
2007-12-03 21:52:42 +00:00
|
|
|
|
2007-11-01 22:15:29 +00:00
|
|
|
def is_readonly(self):
|
|
|
|
return True
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2007-11-01 22:15:29 +00:00
|
|
|
def is_mutable(self):
|
|
|
|
return True
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2007-11-01 22:15:29 +00:00
|
|
|
def get_readonly(self):
|
|
|
|
return self
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2008-12-08 19:44:11 +00:00
|
|
|
def get_verify_cap(self):
|
2007-11-01 22:15:29 +00:00
|
|
|
return SSKVerifierURI(self.storage_index, self.fingerprint)
|
|
|
|
|
2011-08-07 00:44:36 +00:00
|
|
|
def get_extension_params(self):
|
|
|
|
return []
|
|
|
|
|
|
|
|
def set_extension_params(self, params):
|
|
|
|
pass
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2007-11-01 22:15:29 +00:00
|
|
|
class SSKVerifierURI(_BaseURI):
|
|
|
|
implements(IVerifierURI)
|
|
|
|
|
2008-01-03 23:55:43 +00:00
|
|
|
BASE_STRING='URI:SSK-Verifier:'
|
2008-02-15 02:27:47 +00:00
|
|
|
STRING_RE=re.compile('^'+BASE_STRING+BASE32STR_128bits+':'+BASE32STR_256bits+'$')
|
2008-03-04 21:27:45 +00:00
|
|
|
HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'SSK-Verifier'+SEP+BASE32STR_128bits+SEP+BASE32STR_256bits+'$')
|
2008-01-03 23:55:43 +00:00
|
|
|
|
2008-01-03 05:12:15 +00:00
|
|
|
def __init__(self, storage_index, fingerprint):
|
2008-01-03 23:55:43 +00:00
|
|
|
assert len(storage_index) == 16
|
2007-11-01 22:15:29 +00:00
|
|
|
self.storage_index = storage_index
|
|
|
|
self.fingerprint = fingerprint
|
|
|
|
|
2008-01-03 23:55:43 +00:00
|
|
|
@classmethod
|
|
|
|
def init_from_human_encoding(cls, uri):
|
|
|
|
mo = cls.HUMAN_RE.search(uri)
|
2010-01-27 06:44:30 +00:00
|
|
|
if not mo:
|
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
2009-02-18 21:46:55 +00:00
|
|
|
return cls(si_a2b(mo.group(1)), base32.a2b(mo.group(2)))
|
2008-01-03 23:55:43 +00:00
|
|
|
|
2008-01-03 05:12:15 +00:00
|
|
|
@classmethod
|
|
|
|
def init_from_string(cls, uri):
|
2008-01-03 23:55:43 +00:00
|
|
|
mo = cls.STRING_RE.search(uri)
|
2010-01-27 06:44:30 +00:00
|
|
|
if not mo:
|
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
2009-02-18 21:46:55 +00:00
|
|
|
return cls(si_a2b(mo.group(1)), base32.a2b(mo.group(2)))
|
2007-11-01 22:15:29 +00:00
|
|
|
|
|
|
|
def to_string(self):
|
|
|
|
assert isinstance(self.storage_index, str)
|
|
|
|
assert isinstance(self.fingerprint, str)
|
2009-02-18 21:46:55 +00:00
|
|
|
return 'URI:SSK-Verifier:%s:%s' % (si_b2a(self.storage_index),
|
2008-02-15 02:27:47 +00:00
|
|
|
base32.b2a(self.fingerprint))
|
2007-11-01 22:15:29 +00:00
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
def is_readonly(self):
|
|
|
|
return True
|
|
|
|
|
|
|
|
def is_mutable(self):
|
|
|
|
return False
|
|
|
|
|
|
|
|
def get_readonly(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def get_verify_cap(self):
|
|
|
|
return self
|
|
|
|
|
2011-08-07 00:44:36 +00:00
|
|
|
def get_extension_params(self):
|
|
|
|
return []
|
|
|
|
|
|
|
|
def set_extension_params(self, params):
|
|
|
|
pass
|
|
|
|
|
2011-08-27 18:33:57 +00:00
|
|
|
class WriteableMDMFFileURI(_BaseURI):
|
2011-08-07 00:44:36 +00:00
|
|
|
implements(IURI, IMutableFileURI)
|
|
|
|
|
|
|
|
BASE_STRING='URI:MDMF:'
|
|
|
|
STRING_RE=re.compile('^'+BASE_STRING+BASE32STR_128bits+':'+BASE32STR_256bits+OPTIONAL_EXTENSION_FIELD+'$')
|
|
|
|
HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'MDMF'+SEP+BASE32STR_128bits+SEP+BASE32STR_256bits+OPTIONAL_EXTENSION_FIELD+'$')
|
|
|
|
|
|
|
|
def __init__(self, writekey, fingerprint, params=[]):
|
|
|
|
self.writekey = writekey
|
|
|
|
self.readkey = hashutil.ssk_readkey_hash(writekey)
|
|
|
|
self.storage_index = hashutil.ssk_storage_index_hash(self.readkey)
|
|
|
|
assert len(self.storage_index) == 16
|
|
|
|
self.fingerprint = fingerprint
|
|
|
|
self.extension = params
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def init_from_human_encoding(cls, uri):
|
|
|
|
mo = cls.HUMAN_RE.search(uri)
|
|
|
|
if not mo:
|
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
|
|
|
params = filter(lambda x: x != '', re.split(SEP, mo.group(3)))
|
|
|
|
return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)), params)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def init_from_string(cls, uri):
|
|
|
|
mo = cls.STRING_RE.search(uri)
|
|
|
|
if not mo:
|
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
|
|
|
params = mo.group(3)
|
|
|
|
params = filter(lambda x: x != '', params.split(":"))
|
|
|
|
return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)), params)
|
|
|
|
|
|
|
|
def to_string(self):
|
|
|
|
assert isinstance(self.writekey, str)
|
|
|
|
assert isinstance(self.fingerprint, str)
|
|
|
|
ret = 'URI:MDMF:%s:%s' % (base32.b2a(self.writekey),
|
|
|
|
base32.b2a(self.fingerprint))
|
|
|
|
if self.extension:
|
|
|
|
ret += ":"
|
|
|
|
ret += ":".join(self.extension)
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return "<%s %s>" % (self.__class__.__name__, self.abbrev())
|
|
|
|
|
|
|
|
def abbrev(self):
|
|
|
|
return base32.b2a(self.writekey[:5])
|
|
|
|
|
|
|
|
def abbrev_si(self):
|
|
|
|
return base32.b2a(self.storage_index)[:5]
|
|
|
|
|
|
|
|
def is_readonly(self):
|
|
|
|
return False
|
|
|
|
|
|
|
|
def is_mutable(self):
|
|
|
|
return True
|
|
|
|
|
|
|
|
def get_readonly(self):
|
|
|
|
return ReadonlyMDMFFileURI(self.readkey, self.fingerprint, self.extension)
|
|
|
|
|
|
|
|
def get_verify_cap(self):
|
|
|
|
return MDMFVerifierURI(self.storage_index, self.fingerprint, self.extension)
|
|
|
|
|
|
|
|
def get_extension_params(self):
|
|
|
|
return self.extension
|
|
|
|
|
|
|
|
def set_extension_params(self, params):
|
|
|
|
params = map(str, params)
|
|
|
|
self.extension = params
|
|
|
|
|
|
|
|
class ReadonlyMDMFFileURI(_BaseURI):
|
|
|
|
implements(IURI, IMutableFileURI)
|
|
|
|
|
|
|
|
BASE_STRING='URI:MDMF-RO:'
|
|
|
|
STRING_RE=re.compile('^' +BASE_STRING+BASE32STR_128bits+':'+BASE32STR_256bits+OPTIONAL_EXTENSION_FIELD+'$')
|
|
|
|
HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'MDMF-RO'+SEP+BASE32STR_128bits+SEP+BASE32STR_256bits+OPTIONAL_EXTENSION_FIELD+'$')
|
|
|
|
|
|
|
|
def __init__(self, readkey, fingerprint, params=[]):
|
|
|
|
self.readkey = readkey
|
|
|
|
self.storage_index = hashutil.ssk_storage_index_hash(self.readkey)
|
|
|
|
assert len(self.storage_index) == 16
|
|
|
|
self.fingerprint = fingerprint
|
|
|
|
self.extension = params
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def init_from_human_encoding(cls, uri):
|
|
|
|
mo = cls.HUMAN_RE.search(uri)
|
|
|
|
if not mo:
|
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
|
|
|
params = mo.group(3)
|
|
|
|
params = filter(lambda x: x!= '', re.split(SEP, params))
|
|
|
|
return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)), params)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def init_from_string(cls, uri):
|
|
|
|
mo = cls.STRING_RE.search(uri)
|
|
|
|
if not mo:
|
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
|
|
|
|
|
|
|
params = mo.group(3)
|
|
|
|
params = filter(lambda x: x != '', params.split(":"))
|
|
|
|
return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)), params)
|
|
|
|
|
|
|
|
def to_string(self):
|
|
|
|
assert isinstance(self.readkey, str)
|
|
|
|
assert isinstance(self.fingerprint, str)
|
|
|
|
ret = 'URI:MDMF-RO:%s:%s' % (base32.b2a(self.readkey),
|
|
|
|
base32.b2a(self.fingerprint))
|
|
|
|
if self.extension:
|
|
|
|
ret += ":"
|
|
|
|
ret += ":".join(self.extension)
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return "<%s %s>" % (self.__class__.__name__, self.abbrev())
|
|
|
|
|
|
|
|
def abbrev(self):
|
|
|
|
return base32.b2a(self.readkey[:5])
|
|
|
|
|
|
|
|
def abbrev_si(self):
|
|
|
|
return base32.b2a(self.storage_index)[:5]
|
|
|
|
|
|
|
|
def is_readonly(self):
|
|
|
|
return True
|
|
|
|
|
|
|
|
def is_mutable(self):
|
|
|
|
return True
|
|
|
|
|
|
|
|
def get_readonly(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def get_verify_cap(self):
|
|
|
|
return MDMFVerifierURI(self.storage_index, self.fingerprint, self.extension)
|
|
|
|
|
|
|
|
def get_extension_params(self):
|
|
|
|
return self.extension
|
|
|
|
|
|
|
|
def set_extension_params(self, params):
|
|
|
|
params = map(str, params)
|
|
|
|
self.extension = params
|
|
|
|
|
|
|
|
class MDMFVerifierURI(_BaseURI):
|
|
|
|
implements(IVerifierURI)
|
|
|
|
|
|
|
|
BASE_STRING='URI:MDMF-Verifier:'
|
|
|
|
STRING_RE=re.compile('^'+BASE_STRING+BASE32STR_128bits+':'+BASE32STR_256bits+OPTIONAL_EXTENSION_FIELD+'$')
|
|
|
|
HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'MDMF-Verifier'+SEP+BASE32STR_128bits+SEP+BASE32STR_256bits+OPTIONAL_EXTENSION_FIELD+'$')
|
|
|
|
|
|
|
|
def __init__(self, storage_index, fingerprint, params=[]):
|
|
|
|
assert len(storage_index) == 16
|
|
|
|
self.storage_index = storage_index
|
|
|
|
self.fingerprint = fingerprint
|
|
|
|
self.extension = params
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def init_from_human_encoding(cls, uri):
|
|
|
|
mo = cls.HUMAN_RE.search(uri)
|
|
|
|
if not mo:
|
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
|
|
|
params = mo.group(3)
|
|
|
|
params = filter(lambda x: x != '', re.split(SEP, params))
|
|
|
|
return cls(si_a2b(mo.group(1)), base32.a2b(mo.group(2)), params)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def init_from_string(cls, uri):
|
|
|
|
mo = cls.STRING_RE.search(uri)
|
|
|
|
if not mo:
|
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
|
|
|
params = mo.group(3)
|
|
|
|
params = filter(lambda x: x != '', params.split(":"))
|
|
|
|
return cls(si_a2b(mo.group(1)), base32.a2b(mo.group(2)), params)
|
|
|
|
|
|
|
|
def to_string(self):
|
|
|
|
assert isinstance(self.storage_index, str)
|
|
|
|
assert isinstance(self.fingerprint, str)
|
|
|
|
ret = 'URI:MDMF-Verifier:%s:%s' % (si_b2a(self.storage_index),
|
|
|
|
base32.b2a(self.fingerprint))
|
|
|
|
if self.extension:
|
|
|
|
ret += ':'
|
|
|
|
ret += ":".join(self.extension)
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
def is_readonly(self):
|
|
|
|
return True
|
|
|
|
|
|
|
|
def is_mutable(self):
|
|
|
|
return False
|
|
|
|
|
|
|
|
def get_readonly(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def get_verify_cap(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def get_extension_params(self):
|
|
|
|
return self.extension
|
|
|
|
|
2009-07-17 01:01:03 +00:00
|
|
|
class _DirectoryBaseURI(_BaseURI):
|
2007-12-03 21:52:42 +00:00
|
|
|
implements(IURI, IDirnodeURI)
|
|
|
|
def __init__(self, filenode_uri=None):
|
|
|
|
self._filenode_uri = filenode_uri
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return "<%s %s>" % (self.__class__.__name__, self.abbrev())
|
|
|
|
|
2008-01-03 23:55:43 +00:00
|
|
|
@classmethod
|
|
|
|
def init_from_string(cls, uri):
|
|
|
|
mo = cls.BASE_STRING_RE.search(uri)
|
2009-07-15 06:45:10 +00:00
|
|
|
if not mo:
|
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
2008-01-03 23:55:43 +00:00
|
|
|
bits = uri[mo.end():]
|
|
|
|
fn = cls.INNER_URI_CLASS.init_from_string(
|
|
|
|
cls.INNER_URI_CLASS.BASE_STRING+bits)
|
|
|
|
return cls(fn)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def init_from_human_encoding(cls, uri):
|
|
|
|
mo = cls.BASE_HUMAN_RE.search(uri)
|
2009-07-15 06:45:10 +00:00
|
|
|
if not mo:
|
|
|
|
raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
|
2008-01-03 23:55:43 +00:00
|
|
|
bits = uri[mo.end():]
|
|
|
|
while bits and bits[-1] == '/':
|
|
|
|
bits = bits[:-1]
|
|
|
|
fn = cls.INNER_URI_CLASS.init_from_string(
|
|
|
|
cls.INNER_URI_CLASS.BASE_STRING+urllib.unquote(bits))
|
|
|
|
return cls(fn)
|
|
|
|
|
|
|
|
def to_string(self):
|
|
|
|
fnuri = self._filenode_uri.to_string()
|
|
|
|
mo = re.match(self.INNER_URI_CLASS.BASE_STRING, fnuri)
|
|
|
|
assert mo, fnuri
|
|
|
|
bits = fnuri[mo.end():]
|
|
|
|
return self.BASE_STRING+bits
|
|
|
|
|
2007-12-03 21:52:42 +00:00
|
|
|
def abbrev(self):
|
|
|
|
return self._filenode_uri.to_string().split(':')[2][:5]
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2009-01-31 02:31:10 +00:00
|
|
|
def abbrev_si(self):
|
2010-02-22 03:36:52 +00:00
|
|
|
si = self._filenode_uri.get_storage_index()
|
|
|
|
if si is None:
|
|
|
|
return "<LIT>"
|
|
|
|
return base32.b2a(si)[:5]
|
2007-11-01 22:15:29 +00:00
|
|
|
|
2007-12-03 21:52:42 +00:00
|
|
|
def is_mutable(self):
|
|
|
|
return True
|
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
def get_filenode_cap(self):
|
|
|
|
return self._filenode_uri
|
|
|
|
|
2008-12-08 19:44:11 +00:00
|
|
|
def get_verify_cap(self):
|
2009-07-17 01:01:03 +00:00
|
|
|
return DirectoryURIVerifier(self._filenode_uri.get_verify_cap())
|
2007-12-03 21:52:42 +00:00
|
|
|
|
2008-11-13 03:17:25 +00:00
|
|
|
def get_storage_index(self):
|
|
|
|
return self._filenode_uri.get_storage_index()
|
|
|
|
|
2009-07-17 01:01:03 +00:00
|
|
|
class DirectoryURI(_DirectoryBaseURI):
|
|
|
|
implements(IDirectoryURI)
|
2008-01-03 23:55:43 +00:00
|
|
|
|
|
|
|
BASE_STRING='URI:DIR2:'
|
|
|
|
BASE_STRING_RE=re.compile('^'+BASE_STRING)
|
|
|
|
BASE_HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'DIR2'+SEP)
|
|
|
|
INNER_URI_CLASS=WriteableSSKFileURI
|
|
|
|
|
2007-11-01 22:15:29 +00:00
|
|
|
def __init__(self, filenode_uri=None):
|
|
|
|
if filenode_uri:
|
|
|
|
assert not filenode_uri.is_readonly()
|
2009-07-17 01:01:03 +00:00
|
|
|
_DirectoryBaseURI.__init__(self, filenode_uri)
|
2007-11-01 22:15:29 +00:00
|
|
|
|
|
|
|
def is_readonly(self):
|
|
|
|
return False
|
2007-12-03 21:52:42 +00:00
|
|
|
|
2007-11-01 22:15:29 +00:00
|
|
|
def get_readonly(self):
|
2009-07-17 01:01:03 +00:00
|
|
|
return ReadonlyDirectoryURI(self._filenode_uri.get_readonly())
|
2007-11-01 22:15:29 +00:00
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2009-07-17 01:01:03 +00:00
|
|
|
class ReadonlyDirectoryURI(_DirectoryBaseURI):
|
|
|
|
implements(IReadonlyDirectoryURI)
|
2008-01-03 23:55:43 +00:00
|
|
|
|
|
|
|
BASE_STRING='URI:DIR2-RO:'
|
|
|
|
BASE_STRING_RE=re.compile('^'+BASE_STRING)
|
|
|
|
BASE_HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'DIR2-RO'+SEP)
|
|
|
|
INNER_URI_CLASS=ReadonlySSKFileURI
|
|
|
|
|
2007-11-01 22:15:29 +00:00
|
|
|
def __init__(self, filenode_uri=None):
|
|
|
|
if filenode_uri:
|
|
|
|
assert filenode_uri.is_readonly()
|
2009-07-17 01:01:03 +00:00
|
|
|
_DirectoryBaseURI.__init__(self, filenode_uri)
|
2007-11-01 22:15:29 +00:00
|
|
|
|
|
|
|
def is_readonly(self):
|
|
|
|
return True
|
2007-12-03 21:52:42 +00:00
|
|
|
|
2007-11-01 22:15:29 +00:00
|
|
|
def get_readonly(self):
|
|
|
|
return self
|
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2009-11-04 17:24:53 +00:00
|
|
|
class _ImmutableDirectoryBaseURI(_DirectoryBaseURI):
|
|
|
|
def __init__(self, filenode_uri=None):
|
|
|
|
if filenode_uri:
|
|
|
|
assert isinstance(filenode_uri, self.INNER_URI_CLASS), filenode_uri
|
2010-01-27 06:44:30 +00:00
|
|
|
assert not filenode_uri.is_mutable()
|
2009-11-04 17:24:53 +00:00
|
|
|
_DirectoryBaseURI.__init__(self, filenode_uri)
|
|
|
|
|
|
|
|
def is_readonly(self):
|
|
|
|
return True
|
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
def is_mutable(self):
|
|
|
|
return False
|
|
|
|
|
2009-11-04 17:24:53 +00:00
|
|
|
def get_readonly(self):
|
|
|
|
return self
|
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2009-11-04 17:24:53 +00:00
|
|
|
class ImmutableDirectoryURI(_ImmutableDirectoryBaseURI):
|
|
|
|
BASE_STRING='URI:DIR2-CHK:'
|
|
|
|
BASE_STRING_RE=re.compile('^'+BASE_STRING)
|
|
|
|
BASE_HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'DIR2-CHK'+SEP)
|
|
|
|
INNER_URI_CLASS=CHKFileURI
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2009-11-04 17:24:53 +00:00
|
|
|
def get_verify_cap(self):
|
|
|
|
vcap = self._filenode_uri.get_verify_cap()
|
|
|
|
return ImmutableDirectoryURIVerifier(vcap)
|
|
|
|
|
|
|
|
|
|
|
|
class LiteralDirectoryURI(_ImmutableDirectoryBaseURI):
|
|
|
|
BASE_STRING='URI:DIR2-LIT:'
|
|
|
|
BASE_STRING_RE=re.compile('^'+BASE_STRING)
|
|
|
|
BASE_HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'DIR2-LIT'+SEP)
|
|
|
|
INNER_URI_CLASS=LiteralFileURI
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2009-11-04 17:24:53 +00:00
|
|
|
def get_verify_cap(self):
|
|
|
|
# LIT caps have no verifier, since they aren't distributed
|
|
|
|
return None
|
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2011-08-07 00:44:36 +00:00
|
|
|
class MDMFDirectoryURI(_DirectoryBaseURI):
|
|
|
|
implements(IDirectoryURI)
|
|
|
|
|
|
|
|
BASE_STRING='URI:DIR2-MDMF:'
|
|
|
|
BASE_STRING_RE=re.compile('^'+BASE_STRING)
|
|
|
|
BASE_HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'DIR2-MDMF'+SEP)
|
2011-08-27 18:33:57 +00:00
|
|
|
INNER_URI_CLASS=WriteableMDMFFileURI
|
2011-08-07 00:44:36 +00:00
|
|
|
|
|
|
|
def __init__(self, filenode_uri=None):
|
|
|
|
if filenode_uri:
|
|
|
|
assert not filenode_uri.is_readonly()
|
|
|
|
_DirectoryBaseURI.__init__(self, filenode_uri)
|
|
|
|
|
|
|
|
def is_readonly(self):
|
|
|
|
return False
|
|
|
|
|
|
|
|
def get_readonly(self):
|
|
|
|
return ReadonlyMDMFDirectoryURI(self._filenode_uri.get_readonly())
|
|
|
|
|
|
|
|
def get_verify_cap(self):
|
|
|
|
return MDMFDirectoryURIVerifier(self._filenode_uri.get_verify_cap())
|
|
|
|
|
|
|
|
|
|
|
|
class ReadonlyMDMFDirectoryURI(_DirectoryBaseURI):
|
|
|
|
implements(IReadonlyDirectoryURI)
|
|
|
|
|
|
|
|
BASE_STRING='URI:DIR2-MDMF-RO:'
|
|
|
|
BASE_STRING_RE=re.compile('^'+BASE_STRING)
|
|
|
|
BASE_HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'DIR2-MDMF-RO'+SEP)
|
|
|
|
INNER_URI_CLASS=ReadonlyMDMFFileURI
|
|
|
|
|
|
|
|
def __init__(self, filenode_uri=None):
|
|
|
|
if filenode_uri:
|
|
|
|
assert filenode_uri.is_readonly()
|
|
|
|
_DirectoryBaseURI.__init__(self, filenode_uri)
|
|
|
|
|
|
|
|
def is_readonly(self):
|
|
|
|
return True
|
|
|
|
|
|
|
|
def get_readonly(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def get_verify_cap(self):
|
|
|
|
return MDMFDirectoryURIVerifier(self._filenode_uri.get_verify_cap())
|
|
|
|
|
2009-11-12 00:22:33 +00:00
|
|
|
def wrap_dirnode_cap(filecap):
|
|
|
|
if isinstance(filecap, WriteableSSKFileURI):
|
|
|
|
return DirectoryURI(filecap)
|
|
|
|
if isinstance(filecap, ReadonlySSKFileURI):
|
|
|
|
return ReadonlyDirectoryURI(filecap)
|
|
|
|
if isinstance(filecap, CHKFileURI):
|
|
|
|
return ImmutableDirectoryURI(filecap)
|
|
|
|
if isinstance(filecap, LiteralFileURI):
|
|
|
|
return LiteralDirectoryURI(filecap)
|
2011-08-27 18:33:57 +00:00
|
|
|
if isinstance(filecap, WriteableMDMFFileURI):
|
2011-08-07 00:44:36 +00:00
|
|
|
return MDMFDirectoryURI(filecap)
|
|
|
|
if isinstance(filecap, ReadonlyMDMFFileURI):
|
|
|
|
return ReadonlyMDMFDirectoryURI(filecap)
|
2010-01-27 06:44:30 +00:00
|
|
|
assert False, "cannot interpret as a directory cap: %s" % filecap.__class__
|
|
|
|
|
2011-08-07 00:44:36 +00:00
|
|
|
class MDMFDirectoryURIVerifier(_DirectoryBaseURI):
|
|
|
|
implements(IVerifierURI)
|
|
|
|
|
|
|
|
BASE_STRING='URI:DIR2-MDMF-Verifier:'
|
|
|
|
BASE_STRING_RE=re.compile('^'+BASE_STRING)
|
|
|
|
BASE_HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'DIR2-MDMF-Verifier'+SEP)
|
|
|
|
INNER_URI_CLASS=MDMFVerifierURI
|
|
|
|
|
|
|
|
def __init__(self, filenode_uri=None):
|
|
|
|
if filenode_uri:
|
|
|
|
assert IVerifierURI.providedBy(filenode_uri)
|
|
|
|
self._filenode_uri = filenode_uri
|
|
|
|
|
|
|
|
def get_filenode_cap(self):
|
|
|
|
return self._filenode_uri
|
|
|
|
|
|
|
|
def is_mutable(self):
|
|
|
|
return False
|
2009-11-04 17:24:53 +00:00
|
|
|
|
2009-07-17 01:01:03 +00:00
|
|
|
class DirectoryURIVerifier(_DirectoryBaseURI):
|
2007-11-01 22:15:29 +00:00
|
|
|
implements(IVerifierURI)
|
|
|
|
|
2008-01-03 23:55:43 +00:00
|
|
|
BASE_STRING='URI:DIR2-Verifier:'
|
|
|
|
BASE_STRING_RE=re.compile('^'+BASE_STRING)
|
|
|
|
BASE_HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'DIR2-Verifier'+SEP)
|
|
|
|
INNER_URI_CLASS=SSKVerifierURI
|
|
|
|
|
2007-11-01 22:15:29 +00:00
|
|
|
def __init__(self, filenode_uri=None):
|
|
|
|
if filenode_uri:
|
2009-11-11 22:45:42 +00:00
|
|
|
assert IVerifierURI.providedBy(filenode_uri)
|
2007-11-01 22:15:29 +00:00
|
|
|
self._filenode_uri = filenode_uri
|
|
|
|
|
2009-11-11 22:25:42 +00:00
|
|
|
def get_filenode_cap(self):
|
2007-11-02 01:35:54 +00:00
|
|
|
return self._filenode_uri
|
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
def is_mutable(self):
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
2009-11-04 17:24:53 +00:00
|
|
|
class ImmutableDirectoryURIVerifier(DirectoryURIVerifier):
|
|
|
|
implements(IVerifierURI)
|
|
|
|
BASE_STRING='URI:DIR2-CHK-Verifier:'
|
|
|
|
BASE_STRING_RE=re.compile('^'+BASE_STRING)
|
|
|
|
BASE_HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'DIR2-CHK-VERIFIER'+SEP)
|
|
|
|
INNER_URI_CLASS=CHKFileVerifierURI
|
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
|
2009-07-03 01:07:49 +00:00
|
|
|
class UnknownURI:
|
2010-01-27 06:44:30 +00:00
|
|
|
def __init__(self, uri, error=None):
|
2009-07-03 01:07:49 +00:00
|
|
|
self._uri = uri
|
2010-01-27 06:44:30 +00:00
|
|
|
self._error = error
|
|
|
|
|
2009-07-03 01:07:49 +00:00
|
|
|
def to_string(self):
|
|
|
|
return self._uri
|
2007-11-01 22:15:29 +00:00
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
def get_readonly(self):
|
|
|
|
return None
|
|
|
|
|
|
|
|
def get_error(self):
|
|
|
|
return self._error
|
|
|
|
|
|
|
|
def get_verify_cap(self):
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
ALLEGED_READONLY_PREFIX = 'ro.'
|
|
|
|
ALLEGED_IMMUTABLE_PREFIX = 'imm.'
|
|
|
|
|
|
|
|
def from_string(u, deep_immutable=False, name=u"<unknown name>"):
|
|
|
|
if not isinstance(u, str):
|
|
|
|
raise TypeError("unknown URI type: %s.." % str(u)[:100])
|
|
|
|
|
|
|
|
# We allow and check ALLEGED_READONLY_PREFIX or ALLEGED_IMMUTABLE_PREFIX
|
|
|
|
# on all URIs, even though we would only strictly need to do so for caps of
|
|
|
|
# new formats (post Tahoe-LAFS 1.6). URIs that are not consistent with their
|
|
|
|
# prefix are treated as unknown. This should be revisited when we add the
|
|
|
|
# new cap formats. See <http://allmydata.org/trac/tahoe/ticket/833#comment:31>.
|
|
|
|
s = u
|
|
|
|
can_be_mutable = can_be_writeable = not deep_immutable
|
|
|
|
if s.startswith(ALLEGED_IMMUTABLE_PREFIX):
|
|
|
|
can_be_mutable = can_be_writeable = False
|
|
|
|
s = s[len(ALLEGED_IMMUTABLE_PREFIX):]
|
|
|
|
elif s.startswith(ALLEGED_READONLY_PREFIX):
|
|
|
|
can_be_writeable = False
|
|
|
|
s = s[len(ALLEGED_READONLY_PREFIX):]
|
|
|
|
|
|
|
|
error = None
|
|
|
|
kind = "cap"
|
|
|
|
try:
|
|
|
|
if s.startswith('URI:CHK:'):
|
|
|
|
return CHKFileURI.init_from_string(s)
|
|
|
|
elif s.startswith('URI:CHK-Verifier:'):
|
|
|
|
return CHKFileVerifierURI.init_from_string(s)
|
|
|
|
elif s.startswith('URI:LIT:'):
|
|
|
|
return LiteralFileURI.init_from_string(s)
|
|
|
|
elif s.startswith('URI:SSK:'):
|
|
|
|
if can_be_writeable:
|
|
|
|
return WriteableSSKFileURI.init_from_string(s)
|
|
|
|
kind = "URI:SSK file writecap"
|
|
|
|
elif s.startswith('URI:SSK-RO:'):
|
|
|
|
if can_be_mutable:
|
|
|
|
return ReadonlySSKFileURI.init_from_string(s)
|
|
|
|
kind = "URI:SSK-RO readcap to a mutable file"
|
|
|
|
elif s.startswith('URI:SSK-Verifier:'):
|
|
|
|
return SSKVerifierURI.init_from_string(s)
|
2011-08-07 00:44:36 +00:00
|
|
|
elif s.startswith('URI:MDMF:'):
|
2011-08-27 18:33:57 +00:00
|
|
|
return WriteableMDMFFileURI.init_from_string(s)
|
2011-08-07 00:44:36 +00:00
|
|
|
elif s.startswith('URI:MDMF-RO:'):
|
|
|
|
return ReadonlyMDMFFileURI.init_from_string(s)
|
|
|
|
elif s.startswith('URI:MDMF-Verifier:'):
|
|
|
|
return MDMFVerifierURI.init_from_string(s)
|
2010-01-27 06:44:30 +00:00
|
|
|
elif s.startswith('URI:DIR2:'):
|
|
|
|
if can_be_writeable:
|
|
|
|
return DirectoryURI.init_from_string(s)
|
|
|
|
kind = "URI:DIR2 directory writecap"
|
|
|
|
elif s.startswith('URI:DIR2-RO:'):
|
|
|
|
if can_be_mutable:
|
|
|
|
return ReadonlyDirectoryURI.init_from_string(s)
|
|
|
|
kind = "URI:DIR2-RO readcap to a mutable directory"
|
|
|
|
elif s.startswith('URI:DIR2-Verifier:'):
|
|
|
|
return DirectoryURIVerifier.init_from_string(s)
|
|
|
|
elif s.startswith('URI:DIR2-CHK:'):
|
|
|
|
return ImmutableDirectoryURI.init_from_string(s)
|
2011-08-27 19:50:48 +00:00
|
|
|
elif s.startswith('URI:DIR2-CHK-Verifier:'):
|
|
|
|
return ImmutableDirectoryURIVerifier.init_from_string(s)
|
2010-01-27 06:44:30 +00:00
|
|
|
elif s.startswith('URI:DIR2-LIT:'):
|
|
|
|
return LiteralDirectoryURI.init_from_string(s)
|
2011-08-07 00:44:36 +00:00
|
|
|
elif s.startswith('URI:DIR2-MDMF:'):
|
|
|
|
if can_be_writeable:
|
|
|
|
return MDMFDirectoryURI.init_from_string(s)
|
|
|
|
kind = "URI:DIR2-MDMF directory writecap"
|
|
|
|
elif s.startswith('URI:DIR2-MDMF-RO:'):
|
|
|
|
if can_be_mutable:
|
|
|
|
return ReadonlyMDMFDirectoryURI.init_from_string(s)
|
|
|
|
kind = "URI:DIR2-MDMF-RO readcap to a mutable directory"
|
2011-08-27 19:50:48 +00:00
|
|
|
elif s.startswith('URI:DIR2-MDMF-Verifier:'):
|
|
|
|
return MDMFDirectoryURIVerifier.init_from_string(s)
|
2010-01-27 06:44:30 +00:00
|
|
|
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"
|
|
|
|
elif s.startswith('x-tahoe-future-test-mutable:') and not can_be_mutable:
|
|
|
|
# For testing how future mutable readcaps would behave in immutable contexts.
|
|
|
|
kind = "x-tahoe-future-test-mutable: testing cap"
|
|
|
|
else:
|
|
|
|
return UnknownURI(u)
|
|
|
|
|
|
|
|
# We fell through because a constraint was not met.
|
|
|
|
# Prefer to report the most specific constraint.
|
|
|
|
if not can_be_mutable:
|
|
|
|
error = MustBeDeepImmutableError(kind + " used in an immutable context", name)
|
|
|
|
else:
|
|
|
|
error = MustBeReadonlyError(kind + " used in a read-only context", name)
|
2011-08-09 00:11:17 +00:00
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
except BadURIError, e:
|
|
|
|
error = e
|
|
|
|
|
|
|
|
return UnknownURI(u, error=error)
|
2007-06-02 01:48:01 +00:00
|
|
|
|
2008-01-11 03:43:42 +00:00
|
|
|
def is_uri(s):
|
|
|
|
try:
|
2010-01-27 06:44:30 +00:00
|
|
|
from_string(s, deep_immutable=False)
|
2008-01-11 03:43:42 +00:00
|
|
|
return True
|
|
|
|
except (TypeError, AssertionError):
|
|
|
|
return False
|
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
def is_literal_file_uri(s):
|
|
|
|
if not isinstance(s, str):
|
|
|
|
return False
|
|
|
|
return (s.startswith('URI:LIT:') or
|
|
|
|
s.startswith(ALLEGED_READONLY_PREFIX + 'URI:LIT:') or
|
|
|
|
s.startswith(ALLEGED_IMMUTABLE_PREFIX + 'URI:LIT:'))
|
|
|
|
|
|
|
|
def has_uri_prefix(s):
|
|
|
|
if not isinstance(s, str):
|
|
|
|
return False
|
|
|
|
return (s.startswith("URI:") or
|
|
|
|
s.startswith(ALLEGED_READONLY_PREFIX + 'URI:') or
|
|
|
|
s.startswith(ALLEGED_IMMUTABLE_PREFIX + 'URI:'))
|
|
|
|
|
|
|
|
|
|
|
|
# These take the same keyword arguments as from_string above.
|
|
|
|
|
|
|
|
def from_string_dirnode(s, **kwargs):
|
|
|
|
u = from_string(s, **kwargs)
|
2007-07-21 22:40:36 +00:00
|
|
|
assert IDirnodeURI.providedBy(u)
|
|
|
|
return u
|
2007-01-17 04:29:59 +00:00
|
|
|
|
2007-07-21 22:40:36 +00:00
|
|
|
registerAdapter(from_string_dirnode, str, IDirnodeURI)
|
2007-01-17 04:29:59 +00:00
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
def from_string_filenode(s, **kwargs):
|
|
|
|
u = from_string(s, **kwargs)
|
2007-07-21 22:40:36 +00:00
|
|
|
assert IFileURI.providedBy(u)
|
|
|
|
return u
|
|
|
|
|
|
|
|
registerAdapter(from_string_filenode, str, IFileURI)
|
2007-01-17 04:29:59 +00:00
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
def from_string_mutable_filenode(s, **kwargs):
|
|
|
|
u = from_string(s, **kwargs)
|
2007-11-01 22:15:29 +00:00
|
|
|
assert IMutableFileURI.providedBy(u)
|
|
|
|
return u
|
|
|
|
registerAdapter(from_string_mutable_filenode, str, IMutableFileURI)
|
|
|
|
|
2010-01-27 06:44:30 +00:00
|
|
|
def from_string_verifier(s, **kwargs):
|
|
|
|
u = from_string(s, **kwargs)
|
2007-10-15 23:16:39 +00:00
|
|
|
assert IVerifierURI.providedBy(u)
|
|
|
|
return u
|
|
|
|
registerAdapter(from_string_verifier, str, IVerifierURI)
|
|
|
|
|
2007-01-17 04:29:59 +00:00
|
|
|
|
2007-06-12 01:25:18 +00:00
|
|
|
def pack_extension(data):
|
|
|
|
pieces = []
|
|
|
|
for k in sorted(data.keys()):
|
|
|
|
value = data[k]
|
|
|
|
if isinstance(value, (int, long)):
|
|
|
|
value = "%d" % value
|
|
|
|
assert isinstance(value, str), k
|
|
|
|
assert re.match(r'^[a-zA-Z_\-]+$', k)
|
2008-01-03 23:55:43 +00:00
|
|
|
pieces.append(k + ':' + hashutil.netstring(value))
|
|
|
|
uri_extension = ''.join(pieces)
|
2007-06-12 01:25:18 +00:00
|
|
|
return uri_extension
|
|
|
|
|
|
|
|
def unpack_extension(data):
|
|
|
|
d = {}
|
|
|
|
while data:
|
2008-01-03 23:55:43 +00:00
|
|
|
colon = data.index(':')
|
2007-06-12 01:25:18 +00:00
|
|
|
key = data[:colon]
|
|
|
|
data = data[colon+1:]
|
|
|
|
|
2008-01-03 23:55:43 +00:00
|
|
|
colon = data.index(':')
|
2007-06-12 01:25:18 +00:00
|
|
|
number = data[:colon]
|
|
|
|
length = int(number)
|
|
|
|
data = data[colon+1:]
|
|
|
|
|
|
|
|
value = data[:length]
|
2008-01-03 23:55:43 +00:00
|
|
|
assert data[length] == ','
|
2007-06-12 01:25:18 +00:00
|
|
|
data = data[length+1:]
|
|
|
|
|
|
|
|
d[key] = value
|
|
|
|
|
|
|
|
# convert certain things to numbers
|
2008-01-03 23:55:43 +00:00
|
|
|
for intkey in ('size', 'segment_size', 'num_segments',
|
|
|
|
'needed_shares', 'total_shares'):
|
2007-06-12 01:25:18 +00:00
|
|
|
if intkey in d:
|
|
|
|
d[intkey] = int(d[intkey])
|
|
|
|
return d
|
|
|
|
|
2007-06-12 01:38:21 +00:00
|
|
|
|
|
|
|
def unpack_extension_readable(data):
|
|
|
|
unpacked = unpack_extension(data)
|
2008-02-06 19:48:19 +00:00
|
|
|
unpacked["UEB_hash"] = hashutil.uri_extension_hash(data)
|
2007-06-12 01:38:21 +00:00
|
|
|
for k in sorted(unpacked.keys()):
|
2008-01-03 23:55:43 +00:00
|
|
|
if 'hash' in k:
|
2008-02-15 02:27:47 +00:00
|
|
|
unpacked[k] = base32.b2a(unpacked[k])
|
2007-06-12 01:38:21 +00:00
|
|
|
return unpacked
|
2007-06-25 20:23:51 +00:00
|
|
|
|