SF.net SVN: fclient: [307] trunk/sandbox/fcp2/key.py
Status: Pre-Alpha
Brought to you by:
jurner
From: <ju...@us...> - 2008-03-04 17:38:15
|
Revision: 307 http://fclient.svn.sourceforge.net/fclient/?rev=307&view=rev Author: jurner Date: 2008-03-04 09:38:18 -0800 (Tue, 04 Mar 2008) Log Message: ----------- new key module providing more in depth handling of freenet keys Added Paths: ----------- trunk/sandbox/fcp2/key.py Added: trunk/sandbox/fcp2/key.py =================================================================== --- trunk/sandbox/fcp2/key.py (rev 0) +++ trunk/sandbox/fcp2/key.py 2008-03-04 17:38:18 UTC (rev 307) @@ -0,0 +1,272 @@ +"""Fcp keys""" + +import os, sys +import base64 +import re +import urlparse + +#--> rel import hack +class _RelImportHack(object): + def __init__(self, n): + fpath = os.path.abspath(__file__) + for i in xrange(n): fpath = os.path.dirname(fpath) + sys.path.insert(0, fpath) + def __del__(self): sys.path.pop(0) +hack = _RelImportHack(2) + +from fcp2 import consts + + +del hack +#<-- rel import hack +#************************************************************************************** +# consts +#************************************************************************************** +ReMatchExact = '\A%s\Z' + +#************************************************************************************** +# freenet base64 for keys +#************************************************************************************** +def base64UrlsaveDecode(string): + """Decodes a base64 urlsave encoded string as encoded by freenet + @param string: string to decode + @return: decoded string + + @raise TypeError: if the string can not be decoded + @note: this function handles non-standard encoding as used by freenet (see: freenet/src/support/base64.java) + """ + # freenet uses - for + and ~ for / + altchars = '-~' + + # padding may be ommitted or not + padding = 4 - len(string) % 4 + if padding: + string += '=' * padding + return base64.b64decode(string, altchars) + + +def stripKey(key): + """Strips all uri stuff from a key + @param key: (str) key to strip + @return: (str) key + """ + return urlparse.urlsplit(key)[2] + +#**************************************************************************************** +# freenet keys +# +# KeyType@32 bytes hash, 32 bytes encryption key, 5 bytes extra +# +# all byte components are base64 encoded. Freenet uses base64 without padding +# along with the following altchars for urlsave encode: - for + and ~ for / +# see: freenet/support/base64.java +# +# so a key as the user gets it to see is: +# KeyType@43 bytes, 43 bytes, 7 bytes ..of [A-Za-z0-9\-~] +# +# see: [freenet/src/support/base64.java] +# +#*************************************************************************************** +class KeyBase(object): + """ + >>> key = KeyBase.fcpToPython('CHK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo') + >>> key.pythonToFcp() + 'CHK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/' + >>> key = KeyBase.fcpToPython('CHK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/') + >>> key.pythonToFcp() + 'CHK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/' + + >>> key = KeyBase.fcpToPython('SSK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo') + >>> key.pythonToFcp() + 'SSK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/' + >>> key = KeyBase.fcpToPython('SSK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/') + >>> key.pythonToFcp() + 'SSK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/' + + >>> key = KeyBase.fcpToPython('USK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/0') + >>> key.pythonToFcp() + 'USK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/0/' + >>> key = KeyBase.fcpToPython('USK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/0/') + >>> key.pythonToFcp() + 'USK@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,AAAAAAA/foo/0/' + + >>> key = KeyBase.fcpToPython('KSK@abcde') + >>> key.pythonToFcp() + 'KSK@abcde/' + >>> key = KeyBase.fcpToPython('KSK@abcde/') + >>> key.pythonToFcp() + 'KSK@abcde/' + + """ + + KeyTypesAll = {} + + @classmethod + def fcpToPython(clss, string): + key = stripKey(string) + for clssKeyType in clss.KeyTypesAll.values(): + result = clssKeyType.fromString(key) + if result is not None: + return result + + + +class CHK(KeyBase): + """""" + _key_pattern_ = ''' + (?P<keyType>CHK@) + (?P<keyData> + (?P<hash>[a-z0-9\-~]{43}), + (?P<cryptoKey>[a-z0-9\-~]{43}), + (?P<extra>[a-z0-9\-~]{7}) + ) + (?: / (?P<filename>[^/]+?) (?: /)?)? + ''' + KeyType = consts.KeyType.CHK + KeyPattern = re.compile(_key_pattern_, re.I | re.X) + ExactKeyPattern = re.compile(ReMatchExact % _key_pattern_, re.I | re.X) + + def __init__(self, filename=None): + """Creates a CHK key + + @param filename: (str) filename to add to the key or None + """ + self.keyData = None + self.filename = filename + + def pythonToFcp(self): + out = self.KeyType + if self.keyData is not None: + out += self.keyData + '/' + if self.filename is not None: + out += self.filename + '/' + return out + + @classmethod + def fromString(clss, string): + result = clss.ExactKeyPattern.match(string) + if result is not None: + d = result.groupdict() + clss = clss(filename=d['filename']) + clss.keyData = d['keyData'] + return clss + + +KeyBase.KeyTypesAll[CHK.KeyType] = CHK + + +class SSK(KeyBase): + _key_pattern_ = ''' + (?P<keyType>SSK@) + (?P<keyData> + (?P<hash>[a-z0-9\-~]{43}), + (?P<cryptoKey>[a-z0-9\-~]{43}), + (?P<extra>[a-z0-9\-~]{7}) + ) + (?: / (?P<filename>[^/]+?)) + (?: /)? + ''' + KeyType = consts.KeyType.SSK + KeyPattern = re.compile(_key_pattern_, re.I | re.X) + ExactKeyPattern = re.compile(ReMatchExact % _key_pattern_, re.I | re.X) + + def __init__(self, keyData, filename): + self.filename = filename + self.keyData = keyData + + def pythonToFcp(self): + out = self.KeyType + if self.keyData is not None: + out += self.keyData + '/' + if self.filename is not None: + out += self.filename + '/' + return out + + @classmethod + def fromString(clss, string): + result = clss.ExactKeyPattern.match(string) + if result is not None: + d = result.groupdict() + return clss(d['keyData'], d['filename']) + +KeyBase.KeyTypesAll[SSK.KeyType] = SSK + + +class KSK(KeyBase): + _key_pattern_ = ''' + (?P<keyType>KSK@) + (?P<filename>[^/]+?) + (?: /)? + ''' + KeyType = consts.KeyType.KSK + KeyPattern = re.compile(_key_pattern_, re.I | re.X) + ExactKeyPattern = re.compile(ReMatchExact % _key_pattern_, re.I | re.X) + + + def __init__(self, filename): + self.filename = filename + + def pythonToFcp(self): + out = self.KeyType + if self.filename is not None: + out += self.filename + '/' + return out + + @classmethod + def fromString(clss, string): + result = clss.ExactKeyPattern.match(string) + if result is not None: + d = result.groupdict() + clss = clss(filename=d['filename']) + return clss + + +KeyBase.KeyTypesAll[KSK.KeyType] = KSK + + +class USK(KeyBase): + _key_pattern_ = ''' + (?P<keyType>USK@) + (?P<keyData> + (?P<hash>[a-z0-9\-~]{43}), + (?P<cryptoKey>[a-z0-9\-~]{43}), + (?P<extra>[a-z0-9\-~]{7}) + ) + (?: / (?P<filename>[^/]+?) ) + (?: / (?P<edition>[\d]+)) + (?: /)? + ''' + + KeyType = consts.KeyType.USK + KeyPattern = re.compile(_key_pattern_, re.I | re.X) + ExactKeyPattern = re.compile(ReMatchExact % _key_pattern_, re.I | re.X) + + def __init__(self, keyData, filename, edition=0): + self.edition = edition + self.filename = filename + self.keyData = keyData + + def pythonToFcp(self): + out = self.KeyType + if self.keyData is not None: + out += self.keyData + '/' + if self.filename is not None: + out += self.filename + '/' + if self.edition is not None: + out += self.edition + '/' + return out + + @classmethod + def fromString(clss, string): + result = clss.ExactKeyPattern.match(string) + if result is not None: + d = result.groupdict() + return clss(d['keyData'], d['filename'], edition=d['edition']) + +KeyBase.KeyTypesAll[USK.KeyType] = USK +#***************************************************************************** +# +#***************************************************************************** +if __name__ == '__main__': + import doctest + doctest.testmod() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |