SF.net SVN: fclient: [493] trunk/fcp2/src/fcp2/key.py
Status: Pre-Alpha
Brought to you by:
jurner
|
From: <jU...@us...> - 2008-07-05 10:44:43
|
Revision: 493
http://fclient.svn.sourceforge.net/fclient/?rev=493&view=rev
Author: jUrner
Date: 2008-07-05 03:44:51 -0700 (Sat, 05 Jul 2008)
Log Message:
-----------
another rework of the key module
Modified Paths:
--------------
trunk/fcp2/src/fcp2/key.py
Modified: trunk/fcp2/src/fcp2/key.py
===================================================================
--- trunk/fcp2/src/fcp2/key.py 2008-07-04 08:27:51 UTC (rev 492)
+++ trunk/fcp2/src/fcp2/key.py 2008-07-05 10:44:51 UTC (rev 493)
@@ -2,7 +2,9 @@
import os, sys
import base64
+import posixpath
import re
+import urllib
import urlparse
#--> rel import hack
@@ -24,9 +26,6 @@
_ReMatchExact = '\A%s\Z'
KeyTypesAll = {}
-# save url chars as defined in [freenet/src/support/URLEncoder.java]
-SafeURLChars = '*-_./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz'
-
#**************************************************************************************
# freenet base64 for keys
#**************************************************************************************
@@ -46,14 +45,15 @@
return base64.b64decode(string, altchars)
-def stripKey(key):
- """Strips all uri stuff from a key
- @param key: (str) key to strip
- @return: (str) key
- """
- result = urlparse.urlsplit(key)[2]
- if result.startswith('/'):
- result = result[1:]
+def keyNormkey(string):
+ """"""
+ result = urlparse.urlsplit(string)[2]
+ while result.startswith('/'):
+ result = result[1: ]
+ while result.endswith('/'):
+ result = result[ :-1]
+ if result:
+ result += '/'
return result
#**************************************************************************************
@@ -65,40 +65,19 @@
# encode: - for + and ~ for / see: [freenet/support/base64.java]
#
#**************************************************************************************
-#TODO: too bad, can not move this to types.py ...cross import
-class TypeKey(object):
- """key type for type conversions
+class TypeKey(type):
+ """Metaclass for freenet keys"""
- >>> key = TypeKey.fcpToPython('CHK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo')
- >>> key.toString()
- 'CHK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/'
- >>> key = TypeKey.fcpToPython('CHK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/')
- >>> key.toString()
- 'CHK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/'
-
- >>> key = TypeKey.fcpToPython('SSK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo-1')
- >>> key.toString()
- 'SSK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo-1/'
- >>> key = TypeKey.fcpToPython('SSK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo-1/')
- >>> key.toString()
- 'SSK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo-1/'
-
- >>> key = TypeKey.fcpToPython('USK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/0')
- >>> key.toString()
- 'USK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/0/'
- >>> key = TypeKey.fcpToPython('USK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/0/')
- >>> key.toString()
- 'USK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/0/'
-
- >>> key = TypeKey.fcpToPython('KSK@abcde')
- >>> key.toString()
- 'KSK@abcde/'
- >>> key = TypeKey.fcpToPython('KSK@abcde/')
- >>> key.toString()
- 'KSK@abcde/'
-
- """
-
+ def __new__(klass, name, bases, kws):
+ """Registers a key type to L{KeyTypesAll}
+ @note: if KeyType of the the key type is None it will not get registered
+ """
+
+ newClass = type.__new__(klass, name, bases, kws)
+ if newClass.KeyType is not None:
+ KeyTypesAll[newClass.KeyType] = newClass
+ return newClass
+
@classmethod
def fcpToPython(clss, string):
"""converts a fcp key to a python key
@@ -107,9 +86,8 @@
@raise ValueError: if the string can not be converted
@note: use this method to convert an arbirary key to the corrosponding python key object
"""
- key = stripKey(string)
for clssKeyType in KeyTypesAll.values():
- result = clssKeyType.fromString(key)
+ result = clssKeyType.fromString(string)
if result is not None:
return result
raise ValueError('Invalid key: %s' % string)
@@ -120,24 +98,10 @@
@return: (str) fcp key
"""
return key.toString()
-
-#****************************************************************************************
-#
-#***************************************************************************************
-class _KeyMeta(type):
- """Metaclass for freenet keys"""
-
- def __new__(klass, name, bases, kws):
- """Registers a key type to L{KeyTypesAll}
- @note: if KeyType of the the key type is None it will not get registered
- """
-
- newClass = type.__new__(klass, name, bases, kws)
- if newClass.KeyType is not None:
- KeyTypesAll[newClass.KeyType] = newClass
- return newClass
-
+#**************************************************************************************
+#
+#**************************************************************************************
def Key(string):
"""creates a key object from a string
@return: (L{_KeyBase})
@@ -151,7 +115,7 @@
"""Base class for freenet keys
"""
- __metaclass__ = _KeyMeta
+ __metaclass__ = TypeKey
KeyType = None
def __eq__(self, other):
@@ -161,8 +125,10 @@
return self.pytoString() != other.toString()
@classmethod
- def fromString(clss, string):
+ def fromString(clss, string, isQuoted=True):
"""should create a key object from a string
+ @param string:
+ @param isQuoted: (bool) if True, the string is assumed to be already quoted
"""
raise NotImplementedError()
@@ -170,6 +136,7 @@
"""should return the key as string"""
raise NotImplementedError()
+
class KeyCHK(_KeyBase):
""""""
@@ -180,36 +147,46 @@
(?P<cryptoKey>[a-z0-9\-~]+?),
(?P<extra>[a-z0-9\-~]+?)
)
- (?: / (?P<docName>[^/]+?)? (?: /)?)?
+ /
+ (
+ (?P<docName> (?: [^/]+?)) /
+ ((?P<tail>.+) /)?
+ )?
'''
+ KeyPattern = re.compile(_ReMatchExact % _key_pattern_, re.I | re.X)
KeyType = consts.ConstKeyType.CHK
- KeyPattern = re.compile(_key_pattern_, re.I | re.X)
- ExactKeyPattern = re.compile(_ReMatchExact % _key_pattern_, re.I | re.X)
-
- def __init__(self, keyData=None, docName=None):
+
+ def __init__(self, keyData=None, docName=None, tail=None):
"""Creates a CHK key
@param keyData: (str) key data or None
@param docName: (str) docName to add to the key or None
+ @param tail: (str) for containers, path to item in container or None
"""
self.keyData = keyData
self.docName = docName
+ self.tail = tail
def toString(self):
- out = self.KeyType
- if self.keyData is not None:
- out += self.keyData + '/'
+ if self.keyData is None:
+ out = [self.KeyType, ]
+ else:
+ out = [self.KeyType + self.keyData, ]
if self.docName is not None:
- out += self.docName + '/'
- return out
+ out.append(urllib.quote(self.docName))
+ if self.tail is not None:
+ out.append(urllib.quote(self.tail))
+ return posixpath.join(*out)
@classmethod
def fromString(clss, string):
- result = clss.ExactKeyPattern.match(stripKey(string))
+ key = keyNormkey(string)
+ key = urllib.unquote(key)
+ result = clss.KeyPattern.match(key)
if result is not None:
d = result.groupdict()
- key = clss(d['keyData'], docName=d['docName'])
- return key
+ return clss(d['keyData'], docName=d['docName'], tail=d['tail'])
+
class KeySSK(_KeyBase):
@@ -220,73 +197,89 @@
(?P<cryptoKey>[a-z0-9\-~]+?),
(?P<extra>[a-z0-9\-~]+?)
)
+ /
(
- (?: / (?P<docName>[^/]+?))
- -
- (?: (?P<edition>[\d]+))
+ (?: (?P<docName>[^/]+?)) - (?: (?P<edition>[\d]+)) /
+ ((?P<tail>.+) /)?
)?
- (?: /)?
'''
+ KeyPattern = re.compile(_ReMatchExact % _key_pattern_, re.I | re.X)
KeyType = consts.ConstKeyType.SSK
- KeyPattern = re.compile(_key_pattern_, re.I | re.X)
- ExactKeyPattern = re.compile(_ReMatchExact % _key_pattern_, re.I | re.X)
+
+ def __init__(self, keyData=None, docName=None, edition=0, tail=None):
+ """Creates a SSK key
- def __init__(self, keyData, docName=None, edition=0):
+ @param keyData: (str) key data or None
+ @param docName: (str) docName to add to the key or None
+ @param edition: (int) desired edition
+ @param tail: (str) for containers, path to item in container or None
+ """
self.docName = docName
self.edition = edition
self.keyData = keyData
+ self.tail = tail
def toString(self):
- out = self.KeyType
- if self.keyData is not None:
- out += self.keyData + '/'
+ if self.keyData is None:
+ out = [self.KeyType, ]
+ else:
+ out = [self.KeyType + self.keyData, ]
if self.docName is not None:
if self.edition is None:
raise ValueError('no edition number specified')
- out += self.docName + '-' + str(self.edition) + '/'
- return out
-
+ out.append(urllib.quote(self.docName + '-' + str(self.edition)))
+ if self.tail is not None:
+ out.append(urllib.quote(self.tail))
+ return posixpath.join(*out)
+
@classmethod
def fromString(clss, string):
- result = clss.ExactKeyPattern.match(stripKey(string))
+ key = keyNormkey(string)
+ key = urllib.unquote(key)
+ result = clss.KeyPattern.match(key)
if result is not None:
d = result.groupdict()
edition = d['edition']
if edition is not None:
edition = int(edition)
- return clss(d['keyData'], d['docName'], edition=edition)
+ return clss(d['keyData'], docName=d['docName'], edition=edition, tail=d['tail'])
+
+
-
-
+#TODO: current impl is to not allow slashes in KSKs. have to check if the node enforces this
class KeyKSK(_KeyBase):
_key_pattern_ = '''
(?P<keyType>KSK@)
- (?P<docName>[^/]+?)
- (?: /)?
+ (?P<docName>[^/]+?) /
'''
+ KeyPattern = re.compile(_ReMatchExact % _key_pattern_, re.I | re.X)
KeyType = consts.ConstKeyType.KSK
- KeyPattern = re.compile(_key_pattern_, re.I | re.X)
- ExactKeyPattern = re.compile(_ReMatchExact % _key_pattern_, re.I | re.X)
+
-
def __init__(self, docName):
+ """Creates a KSK key
+
+ @param docName: (str) docName to add to the key or None
+ """
self.docName = docName
def toString(self):
- out = self.KeyType
- if self.docName is not None:
- out += self.docName + '/'
- return out
+ if self.docName is None:
+ return self.KeyType
+ return self.KeyType + urllib.quote(self.docName)
+
@classmethod
- def fromString(clss, string):
- result = clss.ExactKeyPattern.match(stripKey(string))
+ def fromString(clss, string, isQuoted=True):
+ key = keyNormkey(string)
+ key = urllib.unquote(key)
+ result = clss.KeyPattern.match(key)
if result is not None:
d = result.groupdict()
return clss(docName=d['docName'])
-#TODO: is docName obligatory?
+
class KeyUSK(_KeyBase):
_key_pattern_ = '''
(?P<keyType>USK@)
@@ -295,53 +288,58 @@
(?P<cryptoKey>[a-z0-9\-~]+?),
(?P<extra>[a-z0-9\-~]+?)
)
+ /
(
- (?: / (?P<docName>[^/]+?) )
- (?: / (?P<edition>-?[\d]+))
+ (?P<docName>[^/]+?) /
+ (?P<edition>-?\d+) /
+ ((?P<tail>.+) /)?
)?
- (?: /)?
'''
-
+ KeyPattern = re.compile(_ReMatchExact % _key_pattern_, re.I | re.X)
KeyType = consts.ConstKeyType.USK
- KeyPattern = re.compile(_key_pattern_, re.I | re.X)
- ExactKeyPattern = re.compile(_ReMatchExact % _key_pattern_, re.I | re.X)
-
- def __init__(self, keyData, docName=None, edition=0):
+
+ def __init__(self, keyData=None, docName=None, edition=-1, tail=None):
"""Creates a USK key
- @param keyData: (str) public key
- @param docName: (str) docName
- @param edition: (int) edition number
+
+ @param keyData: (str) key data or None
+ @param docName: (str) docName to add to the key or None
+ @param edition: (int) desired edition
+ @param tail: (str) for containers, path to item in container or None
"""
self.edition = edition
self.docName = docName
self.keyData = keyData
+ self.tail = tail
def toString(self):
- out = self.KeyType
- if self.keyData is not None:
- out += self.keyData + '/'
+ if self.keyData is None:
+ out = [self.KeyType, ]
+ else:
+ out = [self.KeyType + self.keyData, ]
if self.docName is not None:
- out += self.docName + '/'
- if self.edition is not None:
- out += str(self.edition) + '/'
- return out
+ if self.edition is None:
+ raise ValueError('no edition number specified')
+ out.append(urllib.quote(self.docName))
+ out.append(urllib.quote(str(self.edition)))
+ if self.tail is not None:
+ out.append(urllib.quote(self.tail))
+ return posixpath.join(*out)
@classmethod
- def fromString(clss, string):
- result = clss.ExactKeyPattern.match(stripKey(string))
+ def fromString(clss, string, isQuoted=True):
+ key = keyNormkey(string)
+ key = urllib.unquote(key)
+ result = clss.KeyPattern.match(key)
if result is not None:
d = result.groupdict()
edition = d['edition']
if edition is not None:
edition = int(edition)
- return clss(d['keyData'], d['docName'], edition=edition)
+ return clss(d['keyData'], docName=d['docName'], edition=edition, tail=d['tail'])
+
__all__ = [i for i in dir() if i[0].isupper() and not i.startswith('_')]
-#*****************************************************************************
-#
-#*****************************************************************************
-if __name__ == '__main__':
- import doctest
- #print 'doctests failed: %s/%s' % doctest.testmod()
+__all__.append('base64UrlsaveDecode')
+__all__.append('keyNormkey')
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|