Diffstat (limited to 'backend/python/src/clipperz.py') (more/less context) (ignore whitespace changes)
-rw-r--r-- | backend/python/src/clipperz.py | 19 |
1 files changed, 8 insertions, 11 deletions
diff --git a/backend/python/src/clipperz.py b/backend/python/src/clipperz.py index c8d91de..bd5d030 100644 --- a/backend/python/src/clipperz.py +++ b/backend/python/src/clipperz.py @@ -1,708 +1,705 @@ -# +# # Copyright 2008-2011 Clipperz Srl # -# This file is part of Clipperz's Javascript Crypto Library. -# Javascript Crypto Library provides web developers with an extensive -# and efficient set of cryptographic functions. The library aims to -# obtain maximum execution speed while preserving modularity and -# reusability. +# This file is part of Clipperz Community Edition. +# Clipperz Community Edition is an online password manager. # For further information about its features and functionalities please -# refer to http://www.clipperz.com +# refer to http://www.clipperz.com. # -# * Javascript Crypto Library is free software: you can redistribute +# * Clipperz Community Edition is free software: you can redistribute # it and/or modify it under the terms of the GNU Affero General Public # License as published by the Free Software Foundation, either version # 3 of the License, or (at your option) any later version. # -# * Javascript Crypto Library is distributed in the hope that it will +# * Clipperz Community Edition is distributed in the hope that it will # be useful, but WITHOUT ANY WARRANTY; without even the implied # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the GNU Affero General Public License for more details. # # * You should have received a copy of the GNU Affero General Public -# License along with Javascript Crypto Library. If not, see +# License along with Clipperz Community Edition. If not, see # <http://www.gnu.org/licenses/>. -# +# import os import cgi import wsgiref.handlers import datetime import uuid import random import hashlib import logging from google.appengine.api import users from google.appengine.ext import webapp from google.appengine.ext import db from google.appengine.ext.webapp import template from django.utils import simplejson #============================================================================== sessionTimeout = datetime.timedelta(minutes=-2) def randomSeed(): return hex(random.getrandbits(32*8))[2:-1] def clipperzHash(aString): #logging.info(">>> string: " + aString) firstRound = hashlib.sha256() firstRound.update(aString) #logging.info("firstRound: " + firstRound.hexdigest() + " - " + firstRound.digest()) result = hashlib.sha256() result.update(firstRound.digest()) #logging.info("<<< finalResul: " + result.hexdigest()) return result.hexdigest() #============================================================================== class User(db.Model): username = db.StringProperty() srp_s = db.StringProperty() srp_v = db.StringProperty() header = db.TextProperty() statistics = db.TextProperty() auth_version= db.StringProperty() version = db.StringProperty() lock = db.StringProperty() def updateCredentials(self, someCredentials): self.username = someCredentials['C'] self.srp_s = someCredentials['s'] self.srp_v = someCredentials['v'] self.auth_version = someCredentials['version'] def update(self, someData): self.header = someData['header'] self.statistics = someData['statistics'] self.version = someData['version'] self.lock = someData['lock'] #------------------------------------------------------------------------------ class Record(db.Model): user = db.ReferenceProperty(User) reference = db.StringProperty() data = db.TextProperty() version = db.StringProperty() creation_date = db.DateTimeProperty(auto_now_add=True) update_date = db.DateTimeProperty(auto_now_add=True) access_date = db.DateTimeProperty(auto_now_add=True) #------------------------------------------------------------------------------ class RecordVersion(db.Model): record = db.ReferenceProperty(Record) reference = db.StringProperty() header = db.TextProperty() data = db.TextProperty() version = db.StringProperty() previousVersionKey = db.StringProperty() previousVersion = db.SelfReferenceProperty() creation_date = db.DateTimeProperty(auto_now_add=True) update_date = db.DateTimeProperty(auto_now_add=True) access_date = db.DateTimeProperty(auto_now_add=True) def update(self, someData): recordData = someData['record']; self.parent().reference = recordData['reference'] self.parent().data = recordData['data'] self.parent().version = recordData['version'] self.parent().update_date = datetime.datetime.now() recordVersionData = someData['currentRecordVersion']; self.reference = recordVersionData ['reference'] self.data = recordVersionData ['data'] self.version = recordVersionData ['version'] #self.previous_version = #recordVersionData ['previousVersion'] self.previous_version_key = recordVersionData ['previousVersionKey'] self.update_date = datetime.datetime.now() #------------------------------------------------------------------------------ class OneTimePassword(db.Model): user = db.ReferenceProperty(User) status = db.StringProperty() reference = db.StringProperty() keyValue = db.StringProperty() keyChecksum = db.StringProperty() data = db.TextProperty() version = db.StringProperty() creation_date = db.DateTimeProperty(auto_now_add=True) request_date = db.DateTimeProperty() usage_date = db.DateTimeProperty() def update(self, someParameters, aStatus): self.reference = someParameters['reference'] self.keyValue = someParameters['key'] self.keyChecksum = someParameters['keyChecksum'] self.data = someParameters['data'] self.version = someParameters['version'] self.status = aStatus def reset(self, aStatus): self.data = "" self.status = aStatus return self #------------------------------------------------------------------------------ class Session(db.Expando): sessionId = db.StringProperty() access_date = db.DateTimeProperty() #============================================================================== class MainPage(webapp.RequestHandler): def get(self): path = os.path.join(os.path.dirname(__file__), 'static%s' % self.request.path) self.response.out.write(template.render(path, {})) #============================================================================== class XHR(webapp.RequestHandler): #========================================================================== def get(self): logging.info("self.request.path: " + self.request.path) if self.request.path == "/dump": session = self.getSession() userData = {} offline_data_placeholder = "" user = db.Query(User).filter('username =', session.C).get() userData['users'] = { 'catchAllUser': { '__masterkey_test_value__': 'masterkey', 's': '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00', 'v': '112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00' } } records = {} for currentRecord in db.Query(Record).ancestor(user): versions = {} for currentVersion in db.Query(RecordVersion).ancestor(currentRecord): versions[currentVersion.reference] ={ 'header': currentVersion.header, 'data': currentVersion.data, 'version': currentVersion.version, 'creationDate': str(currentVersion.creation_date), 'updateDate': str(currentVersion.update_date), 'accessDate': str(currentVersion.access_date) } records[currentRecord.reference] = { 'data': currentRecord.data, 'version': currentRecord.version, 'creationDate': str(currentRecord.creation_date), 'updateDate': str(currentRecord.update_date), 'accessDate': str(currentRecord.access_date), 'currentVersion': currentVersion.reference, 'versions': versions } userData['users'][user.username] = { 's': user.srp_s, 'v': user.srp_v, 'version': user.auth_version, 'maxNumberOfRecords': '100', 'userDetails': user.header, 'statistics': user.statistics, 'userDetailsVersion': user.version, 'records': records } offline_data_placeholder = offline_data_placeholder + "_clipperz_dump_data_ = " + simplejson.dumps(userData, indent=4) + "\n" offline_data_placeholder = offline_data_placeholder + "Clipperz.PM.Proxy.defaultProxy = new Clipperz.PM.Proxy.Offline();" + "\n" offline_data_placeholder = offline_data_placeholder + "Clipperz.Crypto.PRNG.defaultRandomGenerator().fastEntropyAccumulationForTestingPurpose();" + "\n" path = os.path.join(os.path.dirname(__file__), 'static/dump.html') self.response.headers.add_header('Content-Type', 'text/html') self.response.headers.add_header('Content-Disposition', 'attachment', filename='Clipperz.html') self.response.out.write(template.render(path, {'offline_data_placeholder': offline_data_placeholder})) #========================================================================== def post(self): method = self.request.get('method') parameters = simplejson.loads(self.request.get('parameters')) session = self.getSession() result = {}; #---------------------------------------------------------------------- if method == 'registration': message = parameters['message']; if message == 'completeRegistration': user = User() user.updateCredentials(parameters['credentials']) user.update(parameters['user']) user.put() result['lock'] = user.lock result['result'] = "done" #---------------------------------------------------------------------- elif method == 'handshake': srp_g = 2L srp_n = long("0x%s" % "115b8b692e0e045692cf280b436735c77a5a9e8a9e7ed56c965f87db5b2a2ece3", 16) message = parameters['message']; #------------------------------------------------------------------ if message == 'connect': session.C = parameters['parameters']['C'] session.A = parameters['parameters']['A'] user = db.Query(User).filter('username =', session.C).get() if user != None: try: optId = session.otpId oneTimePassword = db.Query(OneTimePassword).filter('keyValue =', optId).get() if oneTimePassword.parent().username != user.username: oneTimePassword.reset('DISABLED').put() raise Exception, "User missmatch between the current session and 'One Time Password' user" elif oneTimePassword.status != 'REQUESTED': oneTimePassword.reset('DISABLED').put() raise Exception, "Tring to use an 'One Time Password' in the wrong state" oneTimePassword.reset("USED").put() result['oneTimePassword'] = oneTimePassword.reference except Exception, detail: logging.error("connect.optId: " + str(detail)) session.s = user.srp_s session.v = user.srp_v else: session.s = "112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00" session.v = "112233445566778899aabbccddeeff00112233445566778899aabbccddeeff00" session.b = randomSeed() session.B = hex(long("0x%s" % session.v, 16) + pow(srp_g, long("0x%s" %session.b, 16), srp_n))[2:-1] result['s'] = session.s result['B'] = session.B #------------------------------------------------------------------ elif message == 'credentialCheck': B = long("0x%s" % session.B, 16) b = long("0x%s" % session.b, 16) A = long("0x%s" % session.A, 16) v = long("0x%s" % session.v, 16) u = long("0x%s" % clipperzHash(str(B)), 16) n = srp_n S = pow((A * pow(v, u, n)), b, n) K = clipperzHash(str(S)) M1 = clipperzHash(str(A) + str(B) + K) if M1 == parameters['parameters']['M1']: session.K = K M2 = clipperzHash(str(A) + M1 + K) result['M2'] = M2 result["connectionId"] = "" result["loginInfo"] = {} result["loginInfo"]["latest"] = {} result["loginInfo"]["current"] = {} result["offlineCopyNeeded"] = "false"; result["lock"] = "----"; else: result['error'] = "?" #------------------------------------------------------------------ elif message == 'oneTimePassword': oneTimePassword = db.Query(OneTimePassword).filter("keyValue =", parameters["parameters"]["oneTimePasswordKey"]).get() if oneTimePassword != None: if oneTimePassword.status == 'ACTIVE': if oneTimePassword.keyChecksum == parameters['parameters']['oneTimePasswordKeyChecksum']: #session.userId = str(oneTimePassword.parent().username) session.otpId = str(oneTimePassword.keyValue) result['data'] = oneTimePassword.data result['version'] = oneTimePassword.version oneTimePassword.reset('REQUESTED').put() else: oneTimePassword.reset('DISABLED').put() raise Exception, "The requested One Time Password has been disabled, due to a wrong keyChecksum" else: raise Exception, "The requested One Time Password was not active" else: raise Exception, "The requested One Time Password has not been found" #---------------------------------------------------------------------- elif method == 'message': if parameters['srpSharedSecret'] == session.K: message = parameters['message'] if message == 'getUserDetails': # {"message":"getUserDetails", "srpSharedSecret":"f18e5cf7c3a83b67d4db9444af813ee48c13daf4f8f6635397d593e52ba89a08", "parameters":{}} user = db.Query(User).filter('username =', session.C).get() result['header'] = user.header; result['statistics'] = user.statistics; result['version'] = user.version; elif message == "addNewRecords": user = db.Query(User).filter('username =', session.C).get() result = db.run_in_transaction(self.addNewRecords, session, user, parameters) """ user = db.Query(User).filter('username =', session.C).get() user.update(parameters['parameters']['user']) for recordParameter in parameters['parameters']['records']: record = Record(parent=user) record.put() recordVersion = RecordVersion(parent=record) recordVersion.put() recordVersion.update(recordParameter) record.put() recordVersion.put() user.put(); result['lock'] = user.lock result['result'] = 'done' """ elif message == 'getRecordDetail': record = db.Query(Record).ancestor(db.Query(User).filter('username =', session.C).get()).filter('reference =', parameters["parameters"]["reference"]).get() recordVersion = db.Query(RecordVersion).ancestor(record).get() result['currentVersion'] = {} result['currentVersion']['reference'] = recordVersion.reference result['currentVersion']['data'] = recordVersion.data result['currentVersion']['header'] = recordVersion.header result['currentVersion']['version'] = recordVersion.version result['currentVersion']['creationDate'] = str(recordVersion.creation_date) result['currentVersion']['updateDate'] = str(recordVersion.update_date) result['currentVersion']['accessDate'] = str(recordVersion.access_date) result['reference'] = record.reference result['data'] = record.data result['version'] = record.version result['creationDate'] = str(record.creation_date) result['updateDate'] = str(record.update_date) result['accessDate'] = str(record.access_date) result['oldestUsedEncryptedVersion'] = "---" elif message == 'updateData': user = db.Query(User).filter('username =', session.C).get() user.update(parameters['parameters']['user']) for recordParameter in parameters['parameters']['records']: logging.info('reference =' + recordParameter['record']['reference']) record = db.Query(Record).ancestor(user).filter('reference =', recordParameter['record']['reference']).get() recordVersion = db.Query(RecordVersion).ancestor(record).get() recordVersion.update(recordParameter) recordVersion.put() recordVersion.parent().put() user.put(); result['lock'] = user.lock result['result'] = 'done' elif message == 'deleteRecords': user = db.Query(User).filter('username =', session.C).get() user.update(parameters['parameters']['user']) for recordReference in parameters['parameters']['recordReferences']: record = db.Query(Record).ancestor(user).filter('reference =', recordReference).get() #recordVersion = db.Query(RecordVersion).ancestor(record).get() db.delete(db.Query(RecordVersion).ancestor(record)) record.delete() user.put() result['lock'] = user.lock result['result'] = 'done' elif message == 'deleteUser': user = db.Query(User).filter('username =', session.C).get() db.delete(db.Query(RecordVersion).ancestor(user)) db.delete(db.Query(Record).ancestor(user)) user.delete() elif message == 'addNewOneTimePassword': user = db.Query(User).filter('username =', session.C).get() user.update(parameters['parameters']['user']) oneTimePassword = OneTimePassword(parent=user) oneTimePassword.update(parameters['parameters']['oneTimePassword'], "ACTIVE") oneTimePassword.put() user.put() result['lock'] = user.lock result['result'] = 'done' elif message == 'updateOneTimePasswords': user = db.Query(User).filter('username =', session.C).get() user.update(parameters['parameters']['user']) validOtpReferences = parameters['parameters']['oneTimePasswords'] for currentOtp in db.Query(OneTimePassword).ancestor(user): if currentOtp.reference in validOtpReferences: pass else: currentOtp.delete() user.put() result['result'] = user.lock elif message == 'getOneTimePasswordsDetails': pass elif message == 'getLoginHistory': result["result"] = [] elif message == 'upgradeUserCredentials': user = db.Query(User).filter('username =', session.C).get() user.updateCredentials(parameters['parameters']['credentials']) user.update(parameters['parameters']['user']) for oneTimePasswordReference in parameters['parameters']['oneTimePasswords']: oneTimePassword = db.Query(OneTimePassword).ancestor(user).filter("reference =", oneTimePasswordReference).get() if oneTimePassword != None: oneTimePassword.data = parameters['parameters']['oneTimePasswords'][oneTimePasswordReference] oneTimePassword.put() user.put() result['lock'] = user.lock result['result'] = 'done' """ $user = new user(); $user->Get($_SESSION["userId"]); $otp = new onetimepassword(); updateUserCredentials($parameters["parameters"]["credentials"], $user); updateUserData($parameters["parameters"]["user"], $user); $otpList = $parameters["parameters"]["oneTimePasswords"]; foreach($otpList as $otpReference=>$otpData) { $otpList = $otp->GetList(array(array("reference", "=", $otpReference))); $currentOtp = $otpList[0]; $currentOtp->data = $otpData; $currentOtp->Save(); } $user->Save(); $result["lock"] = $user->lock; $result["result"] = "done"; """ #============================================================= """ java.util.Map result; try { java.util.Map credentials; if (someParameters.get("credentials") != null) { credentials = (java.util.Map)someParameters.get("credentials"); } else { credentials = someParameters; } aUser.setUsername((java.lang.String)credentials.get("C")); aUser.setSrpS((java.lang.String)credentials.get("s")); aUser.setSrpV((java.lang.String)credentials.get("v")); aUser.setVersion((java.lang.String)credentials.get("version")); if (someParameters.get("user") != null) { com.clipperz.dataModel.EncoderHelper.updateWithMap(aUser, (java.util.Map)someParameters.get("user")); } if (someParameters.get("oneTimePasswords") != null) { java.util.Map updatedOneTimePasswords; java.util.List usersOneTimePasswords; int i,c; updatedOneTimePasswords = (java.util.Map)someParameters.get("oneTimePasswords"); usersOneTimePasswords = com.clipperz.dataModel.OneTimePassword.oneTimePasswordsForUser(this.user()); c = usersOneTimePasswords.size(); for (i=0; i<c; i++) { com.clipperz.dataModel.OneTimePassword currentOneTimePassword; currentOneTimePassword = (com.clipperz.dataModel.OneTimePassword)usersOneTimePasswords.get(i); if (updatedOneTimePasswords.get(currentOneTimePassword.getReference()) != null) { currentOneTimePassword.setData((java.lang.String)updatedOneTimePasswords.get(currentOneTimePassword.getReference())); } } } result = new java.util.Hashtable(); this.dataContext().commitChanges(); result.put("lock", this.user().getNewLock()); result.put("result", "done"); } catch(java.lang.Exception exception) { this.dataContext().rollbackChanges(); logger.error(exception); throw exception; } return result; """ elif message == 'echo': result['result'] = parameters; else: result['error'] = "Wrong shared secret!" #---------------------------------------------------------------------- elif method == 'logout': result['method'] = 'logout' #---------------------------------------------------------------------- else: result['method'] = 'PRRRRRR' #---------------------------------------------------------------------- self.saveSession(session) self.response.out.write(simplejson.dumps(result)) #========================================================================== def addNewRecords (self, aSession, aUser, someParameters): result = {} #user = db.Query(User).filter('username =', aSession.C).get() aUser.update(someParameters['parameters']['user']) for recordParameter in someParameters['parameters']['records']: record = Record(parent=aUser) record.put() recordVersion = RecordVersion(parent=record) recordVersion.put() recordVersion.update(recordParameter) record.put() recordVersion.put() aUser.put(); result['lock'] = aUser.lock result['result'] = 'done' return result #========================================================================== def getSession(self): #logging.info(">>> getSession (%d) => %s" % (db.Query(Session).count(), str(map(lambda v: v.sessionId, db.Query(Session).fetch(100)))) ) result = None try: sessionId = self.request.cookies['sessionId'] except: sessionId = None #logging.info("wannabe sessionId: " + str(sessionId)) if sessionId != None: #query = db.Query(Session) #query.filter('sessionId =', sessionId) #result = query.get() #result = db.Query(Session).filter('sessionId =', str(sessionId)).filter('access_date >', (datetime.datetime.utcnow() - sessionTimeout)).get() result = db.Query(Session).filter('sessionId =', str(sessionId)).get() #logging.info("searching session on datastore. Found: " + str(result)) if result == None: sessionId = str(uuid.uuid4()) #logging.info("creating a new session with sessionId=" + str(sessionId)) result = Session(sessionId=sessionId) result.access_date = datetime.datetime.utcnow() result.put() #logging.info("<<< getSession (%d)" % db.Query(Session).count()) return result #========================================================================== def saveSession(self, aSession): #logging.info(">>> saveSession (%d)" % db.Query(Session).count()) #self.response.set_cookie('sessionId', aSession.sessionId, max_age=360, path='/', domain='example.org', secure=True) aSession.put() self.response.headers.add_header('Set-Cookie', 'sessionId=' + str(aSession.sessionId), path='/') self.cleanOldSessions() #logging.info("<<< saveSession (%d)" % db.Query(Session).count()) #========================================================================== def cleanOldSessions(self): query = db.Query(Session).filter('accessDate <', (datetime.datetime.utcnow() - sessionTimeout)) expiredSessions = query.count(); if expiredSessions != 0: #logging.info("deleting %d sessions" % expiredSessions) pass """ try: db.delete(query) except Exception, exception: logging.error("some issues raised while deleting the expired sessions") logging.error("exception type: " + str(type(exception))) logging.error("exception: " + str(exception)) """ pass #============================================================================== def main(): application = webapp.WSGIApplication([('/xhr', XHR), ('/dump', XHR), ('/.*', MainPage)], debug=True) wsgiref.handlers.CGIHandler().run(application) if __name__ == "__main__": main() |