diff --git a/myServer.py b/myServer.py index ecbd472..14dfc32 100755 --- a/myServer.py +++ b/myServer.py @@ -1,22 +1,22 @@ #!/usr/bin/env python ############################################################################### ## -## My Sensor UDP Server v1.0 -## @Copyright 2014 MySensors Research Project -## SCoRe Lab (www.scorelab.org) -## University of Colombo School of Computing -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. +# My Sensor UDP Server v1.0 +# @Copyright 2014 MySensors Research Project +# SCoRe Lab (www.scorelab.org) +# University of Colombo School of Computing +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. ## ############################################################################### @@ -27,11 +27,9 @@ import time import logging -lib_path = os.path.abspath('utils') -sys.path.append(lib_path) -from myParser import * -from myUser import * -from myCrypto import * +from utils.myParser import * +from utils.myUser import * +from utils.myCrypto import * logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -41,295 +39,309 @@ handler.setLevel(logging.INFO) # create a logging format -formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - \ + %(message)s') handler.setFormatter(formatter) # add the handlers to the logger logger.addHandler(handler) -#UDP Server port number should be assigned here -port=9090 +# UDP Server port number should be assigned here +port = 9090 # At present we manage connection in a dictionary. # We save connection IP and port along with user/device name -connections={} -connectionsTime={} +connections = {} +connectionsTime = {} + +# These global variables will be used to keep the server name +# and its public key +serverName = "mysensors" +serverPubkey = "" +# Database connection will be kept in this variable +database = "" -#These global variables will be used to keep the server name and its public key -serverName="mysensors" -serverPubkey="" -#Database connection will be kept in this variable -database="" # Here's a UDP version of the simplest possible SENZE protocol class mySensorUDPServer(DatagramProtocol): - - # This method will create a new user at the server based on the following SENZE - # SHARE #pubkey PEM_PUBKEY @mysensors #time timeOfRequest ^userName signatureOfTheSenze - def createUser(self,query,address): - global database - global serverName - global serverPubkey - - usr=myUser(database,serverName) - cry=myCrypto(serverName) - data=query.getData() - pubkey='';phone=''; - if 'pubkey' in data: pubkey=data['pubkey'] - if 'phone' in data: phone= data['phone'] - if cry.verifySENZE(query,pubkey): - status=usr.addUser(query.getSender(),phone,query.getSENZE(),pubkey,query.getSignature()) - if status: - st='DATA #msg UserCreated #pubkey %s ' %(serverPubkey) - else: - st='DATA #msg UserCreationFailed' - senze=cry.signSENZE(st) - self.transport.write(senze,address) - - - # This methid will remove the user at the server based on the following SENZE - # UNSHARE #pubkey @mysensors #time timeOfRequest ^userName signatureOfTheSenze - def removeUser(self,sender,pubkey,address): - global database - global serverName - - usr=myUser(database,serverName) - cry=myCrypto(serverName) - status=usr.delUser(sender,pubkey) - st="DATA #msg " - if status: - st+='UserRemoved' - else: - st+='UserCannotRemoved' - senze=cry.signSENZE(st) - self.transport.write(senze,address) - - - def shareSensors(self,query): - global connections - global database - global serverName - """ - If query comes 'SHARE #tp @user2 #time t1 ^user1 siganture' from the user1. - First we need to verify that user2 is available. - Then mysensors adds "user2" to the sensor dictionary at user1's document and - sensor name to the "user1" dictionary at user2's document. - Finally it delivers the message SHARE #tp @user2 #time t1 ^user1 signature to user2. - """ - usr=myUser(database,query.getSender()) - recipients=query.getUsers() - for recipient in recipients: - if recipient in connections.keys(): - usr.share(recipient,query.getSensors()) - forward=connections[recipient] - if forward!=0: - self.transport.write(query.getFULLSENZE(),forward) - - - def unshareSensors(self,query): - global connections - global database - usr=myUser(database,query.getSender()) - recipients=query.getUsers() - for recipient in recipients: - if recipient in connections.keys(): - usr.unShare(recipient,query.getSensors()) - forward=connections[recipient] - if forward!=0: - self.transport.write(query.getFULLSENZE(),forward) - - - def GETSenze(self,query): - global connections - global database - global serverName - - sender=query.getSender() - sensors=query.getSensors() - usr=myUser(database,serverName) - recipients=query.getUsers() - for recipient in recipients: - recipientDB=myUser(database,recipient) - if 'pubkey' in sensors: - #Since mysensors already has public key of it clients, - #it responses on behalf of the client. - pubkey=recipientDB.loadPublicKey() - if pubkey!='' : - if sender in connections.keys(): - backward=connections[sender] - senze='DATA #name %s #pubkey %s' %(recipient,pubkey) - cry=myCrypto(serverName) - senze=cry.signSENZE(senze) - self.transport.write(senze,backward) - #Otherwise GET message will forward to the recipients - else: - if recipient in connections.keys(): - forward=connections[recipient] - if forward!=0 and recipientDB.isShare(sender,query.getSensors()): - self.transport.write(query.getFULLSENZE(),forward) - - def PUTSenze(self,query): - global connections - global database - - sender=query.getSender() - usr=myUser(database,sender) - recipients=query.getUsers() - #PUT message will forward to the recipients - for recipient in recipients: - if recipient in connections.keys(): - recipientDB=myUser(database,recipient) - if recipientDB.isShare(sender,query.getSensors()): - forward=connections[recipient] - if forward!=0: - self.transport.write(query.getFULLSENZE(),forward) - - - def DATASenze(self,query): - global connections - global database - - sender=query.getSender() - usr=myUser(database,sender) - recipients=query.getUsers() - sensors=query.getSensors() - for recipient in recipients: - if recipient in connections.keys(): - recipientDB=myUser(database,recipient) - #DATA msg queries will always deliverd - if recipientDB.isAllow(sender,sensors) or "msg" in sensors: - forward=connections[recipient] - if forward!=0: - self.transport.write(query.getFULLSENZE(),forward) - - - def datagramReceived(self, datagram, address): - global serverName - global usrDatabase - - query=myParser(datagram) - recipients=query.getUsers() - sender=query.getSender() - signature=query.getSignature() - data=query.getData() - sensors=query.getSensors() - cmd=query.getCmd() - - validQuery=False - cry=myCrypto(serverName) - senderDB=myUser(database,sender) - pubkey=senderDB.loadPublicKey() - - if cmd=="SHARE" and "pubkey" in sensors and serverName in recipients: - #Create a new account - self.createUser(query,address) - validQuery=True - - elif cmd=="UNSHARE" and "pubkey" in sensors and serverName in recipients: - #Remove the account - status=False - if pubkey !="": - if cry.verifySENZE(query,pubkey): - status=self.removeUser(sender,pubkey,address) - validQuery=True - - else: - if pubkey !="": - if cry.verifySENZE(query,pubkey): - validQuery=True - - if validQuery: - connections[sender]=address - connectionsTime[sender]=time.time() - if cmd=="SHARE": + # This method will create a new user at the server based on the + # following SENZE + # SHARE #pubkey PEM_PUBKEY @mysensors #time timeOfRequest ^userName + # signatureOfTheSenze + def createUser(self, query, address): + global database + global serverName + global serverPubkey + + usr = myUser(database, serverName) + cry = myCrypto(serverName) + data = query.getData() + pubkey = '' + phone = '' + if 'pubkey' in data: + pubkey = data['pubkey'] + if 'phone' in data: + phone = data['phone'] + if cry.verifySENZE(query, pubkey): + status = usr.addUser(query.getSender(), phone, + query.getSENZE(), pubkey, + query.getSignature()) + if status: + st = 'DATA #msg UserCreated #pubkey %s ' % (serverPubkey) + else: + st = 'DATA #msg UserCreationFailed' + senze = cry.signSENZE(st) + self.transport.write(senze, address) + + # This methid will remove the user at the server based on + # the following SENZE + # UNSHARE #pubkey @mysensors #time timeOfRequest ^userName + # signatureOfTheSenze + def removeUser(self, sender, pubkey, address): + global database + global serverName + + usr = myUser(database, serverName) + cry = myCrypto(serverName) + status = usr.delUser(sender, pubkey) + st = "DATA #msg " + if status: + st += 'UserRemoved' + else: + st += 'UserCannotRemoved' + senze = cry.signSENZE(st) + self.transport.write(senze, address) + + def shareSensors(self, query): + global connections + global database + global serverName + """ + If query comes 'SHARE #tp @user2 #time t1 ^user1 siganture' + from the user1. + First we need to verify that user2 is available. + Then mysensors adds "user2" to the sensor dictionary at user1's + document and sensor name to the "user1" dictionary at user2's + document. + Finally it delivers the message SHARE #tp @user2 #time t1 ^user1 + signature to user2. + """ + usr = myUser(database, query.getSender()) + recipients = query.getUsers() + for recipient in recipients: + if recipient in connections.keys(): + usr.share(recipient, query.getSensors()) + forward = connections[recipient] + if forward != 0: + self.transport.write(query.getFULLSENZE(), forward) + + def unshareSensors(self, query): + global connections + global database + usr = myUser(database, query.getSender()) + recipients = query.getUsers() + for recipient in recipients: + if recipient in connections.keys(): + usr.unShare(recipient, query.getSensors()) + forward = connections[recipient] + if forward != 0: + self.transport.write(query.getFULLSENZE(), forward) + + def GETSenze(self, query): + global connections + global database + global serverName + + sender = query.getSender() + sensors = query.getSensors() + usr = myUser(database, serverName) + recipients = query.getUsers() + for recipient in recipients: + recipientDB = myUser(database, recipient) + if 'pubkey' in sensors: + # Since mysensors already has public key of it clients, + # it responses on behalf of the client. + pubkey = recipientDB.loadPublicKey() + if pubkey != '': + if sender in connections.keys(): + backward = connections[sender] + senze = 'DATA #name %s #pubkey %s' % (recipient, + pubkey) + cry = myCrypto(serverName) + senze = cry.signSENZE(senze) + self.transport.write(senze, backward) + # Otherwise GET message will forward to the recipients + else: + if recipient in connections.keys(): + forward = connections[recipient] + if (forward != 0 and + recipientDB.isShare(sender, query.getSensors())): + self.transport.write(query.getFULLSENZE(), forward) + + def PUTSenze(self, query): + global connections + global database + + sender = query.getSender() + usr = myUser(database, sender) + recipients = query.getUsers() + # PUT message will forward to the recipients + for recipient in recipients: + if recipient in connections.keys(): + recipientDB = myUser(database, recipient) + if recipientDB.isShare(sender, query.getSensors()): + forward = connections[recipient] + if forward != 0: + self.transport.write(query.getFULLSENZE(), forward) + + def DATASenze(self, query): + global connections + global database + + sender = query.getSender() + usr = myUser(database, sender) + recipients = query.getUsers() + sensors = query.getSensors() + for recipient in recipients: + if recipient in connections.keys(): + recipientDB = myUser(database, recipient) + # DATA msg queries will always deliverd + if recipientDB.isAllow(sender, sensors) or "msg" in sensors: + forward = connections[recipient] + if forward != 0: + self.transport.write(query.getFULLSENZE(), forward) + + def datagramReceived(self, datagram, address): + global serverName + global usrDatabase + + query = myParser(datagram) + recipients = query.getUsers() + sender = query.getSender() + signature = query.getSignature() + data = query.getData() + sensors = query.getSensors() + cmd = query.getCmd() + + validQuery = False + cry = myCrypto(serverName) + senderDB = myUser(database, sender) + pubkey = senderDB.loadPublicKey() + + if cmd == "SHARE" and "pubkey" in sensors and serverName in recipients: + # Create a new account + self.createUser(query, address) + validQuery = True + + elif (cmd == "UNSHARE" and + "pubkey" in sensors and serverName in recipients): + # Remove the account + status = False + if pubkey != "": + if cry.verifySENZE(query, pubkey): + status = self.removeUser(sender, pubkey, address) + validQuery = True + + else: + if pubkey != "": + if cry.verifySENZE(query, pubkey): + validQuery = True + + if validQuery: + connections[sender] = address + connectionsTime[sender] = time.time() + if cmd == "SHARE": self.shareSensors(query) - elif cmd=="UNSHARE": + elif cmd == "UNSHARE": self.unshareSensors(query) - elif cmd=="GET": + elif cmd == "GET": self.GETSenze(query) - elif cmd=="PUT": + elif cmd == "PUT": self.PUTSenze(query) - elif cmd=="DATA": + elif cmd == "DATA": self.DATASenze(query) - else: - senze="DATA #msg SignatureVerificationFailed" - senze=cry.signSENZE(senze) + else: + senze = "DATA #msg SignatureVerificationFailed" + senze = cry.signSENZE(senze) self.transport.write(senze, address) - #Let's send a ping to keep open the port - def sendPing(self,delay): - global connections - for recipient in connections: - forward=connections[recipient] - timeGap=time.time()-connectionsTime[recipient] - #If there are no activities messages during in an hour, let's close the connection - if (timeGap<3600): - self.transport.write("PING",forward) - else: - connections[recipient]=0 - # connectionsTime.pop(recipient,None) - reactor.callLater(delay,self.sendPing,delay=delay) - - - #This function is called when we start the protocol - def startProtocol(self): + # Let's send a ping to keep open the port + def sendPing(self, delay): + global connections + for recipient in connections: + forward = connections[recipient] + timeGap = time.time() - connectionsTime[recipient] + # If there are no activities messages during in an hour, + # let's close the connection + if (timeGap < 3600): + self.transport.write("PING", forward) + else: + connections[recipient] = 0 + # connectionsTime.pop(recipient,None) + reactor.callLater(delay, self.sendPing, delay=delay) + + # This function is called when we start the protocol + def startProtocol(self): logger.info("Server started") self.sendPing(20) def init(): -# If .servername is not there we will read the server name from keyboard -# else we will get it from .servername file - try: - if not os.path.isfile(".servername"): - serverName=raw_input("Enter the server name:") - f=open(".servername",'w') - f.write(serverName+'\n') - f.close() - else: - #The server name will be read form the .servername file - f=open(".servername","r") - serverName = f.readline().rstrip("\n") - except: - logger.error("Cannot access server name file") - raise SystemExit - - # Here we will generate public and private keys for the server - # These keys will be used to authentication - # If keys are not available yet - global serverPubkey - try: - cry=myCrypto(serverName) - if not os.path.isfile(cry.pubKeyLoc): - # Generate or loads an RSA keypair with an exponent of 65537 in PEM format - # Private key and public key was saved in the .servernamePriveKey and .servernamePubKey files - cry.generateRSA(1024) - serverPubkey=cry.loadRSAPubKey() - except: - logger.error("Cannot genereate private/public keys for the server.") - raise SystemExit + # If .servername is not there we will read the server name from keyboard + # else we will get it from .servername file + try: + if not os.path.isfile(".servername"): + serverName = raw_input("Enter the server name:") + f = open(".servername", 'w') + f.write(serverName + '\n') + f.close() + else: + # The server name will be read form the .servername file + f = open(".servername", "r") + serverName = f.readline().rstrip("\n") + except: + logger.error("Cannot access server name file") + raise SystemExit + + # Here we will generate public and private keys for the server + # These keys will be used to authentication + # If keys are not available yet + global serverPubkey + try: + cry = myCrypto(serverName) + if not os.path.isfile(cry.pubKeyLoc): + # Generate or loads an RSA keypair with an exponent of 65537 + # in PEM format + # Private key and public key was saved in the .servernamePriveKey + # and .servernamePubKey files + cry.generateRSA(1024) + serverPubkey = cry.loadRSAPubKey() + except: + logger.error("Cannot genereate private/public keys for the server.") + raise SystemExit def main(): global database global port - #Create connection to the Mongo DB + # Create connection to the Mongo DB try: - client = MongoClient('dev.localhost', 27017) - #Creating the database for the server - db = client[serverName] - collection = db['users'] - # Access the user collection from the database - database = db.users + client = MongoClient('dev.localhost', 27017) + # Creating the database for the server + db = client[serverName] + collection = db['users'] + # Access the user collection from the database + database = db.users except: - logger.error("Cannot aaccess the Mongo database.") - raise SystemExit + logger.error("Cannot aaccess the Mongo database.") + raise SystemExit reactor.listenUDP(port, mySensorUDPServer()) reactor.run() + if __name__ == '__main__': init() logger.info(serverPubkey) diff --git a/utils/User.py b/utils/User.py index bc06be9..5a7018f 100644 --- a/utils/User.py +++ b/utils/User.py @@ -8,104 +8,117 @@ import mmap # All user configuration files will be created under the following directory. -userHome= "../users/" +userHome = "../users/" + class User: - """ All user related operations are here - checkUser - Check the availability of a user - checkPass - check the PIN number - addShare - create a file in the user directory with the sensor name - - add recipient name to the file - deleteShare- remove the recipient name from the sensor file in the user directory - """ - def __init__(self,name): - self.name=name - self.path=userHome+self.name+"/" - - def checkUser(self): - if os.path.exists(self.path+"pass"): - return True - else: return False - - def checkPass(self,key): - try: - #print self.path - f=open(self.path+"pass") - line=f.readline() - f.close() - #print line - t=line.strip().split(':') - if t[1]==key: return True - else: return False - except: - return False - """ - Following function will add recipient names to - the sensor files in the user directory. - """ - def addShare(self,recipient,sensors): - try: - for sensor in sensors: - if not os.path.exists(self.path+sensor): - f=open(self.path+sensor,'w') - f.write(recipient+"\n") - f.close() - else: - if recipient not in open(self.path+sensor).read(): - f=open(self.path+sensor,'a') - f.write(recipient+"\n") - f.close() - return True - except: - return False - - """ - Following function will remove recipient names from - the sensor files in the user directory. - """ - def deleteShare(self,recipient,sensors): - try: - for sensor in sensors: - f = open(self.path+sensor,"r") - lines = f.readlines() - f.close() - if recipient+"\n" in lines: - f=open(self.path+sensor,'w') - for line in lines: - if line!=recipient+"\n": f.write(line) - f.close() - return True - except: - return False - - """ - Check the given user name is available in the - sensor file in the user directory. - """ - def isAllow(self,sender,sensors): - try: - for sensor in sensors: - if sender in open(self.path+sensor).read(): + """ All user related operations are here + checkUser - Check the availability of a user + checkPass - check the PIN number + addShare - create a file in the user directory with the sensor name + - add recipient name to the file + deleteShare- remove the recipient name from the sensor file in the + user directory + """ + + def __init__(self, name): + self.name = name + self.path = userHome + self.name + "/" + + def checkUser(self): + if os.path.exists(self.path + "pass"): + return True + else: + return False + + def checkPass(self, key): + try: + # print self.path + f = open(self.path + "pass") + line = f.readline() + f.close() + # print line + t = line.strip().split(':') + if t[1] == key: return True - return False - except: - return False - - def checkStr(self,str): - # f = open(self.path+"allow") - if str in open(self.path+"allow").read(): - return True - else: return False - #s = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) - #if str in s: return True - #else: return False - - def readSensor(self,name): - if os.path.exists(self.path+name): - values = [line.strip() for line in open(self.path+name)] - else: - values=[] - return values + else: + return False + except: + return False + + """ + Following function will add recipient names to + the sensor files in the user directory. + """ + + def addShare(self, recipient, sensors): + try: + for sensor in sensors: + if not os.path.exists(self.path + sensor): + f = open(self.path + sensor, 'w') + f.write(recipient + "\n") + f.close() + else: + if recipient not in open(self.path + sensor).read(): + f = open(self.path + sensor, 'a') + f.write(recipient + "\n") + f.close() + return True + except: + return False + + """ + Following function will remove recipient names from + the sensor files in the user directory. + """ + + def deleteShare(self, recipient, sensors): + try: + for sensor in sensors: + f = open(self.path + sensor, "r") + lines = f.readlines() + f.close() + if recipient + "\n" in lines: + f = open(self.path + sensor, 'w') + for line in lines: + if line != recipient + "\n": + f.write(line) + f.close() + return True + except: + return False + + """ + Check the given user name is available in the + sensor file in the user directory. + """ + + def isAllow(self, sender, sensors): + try: + for sensor in sensors: + if sender in open(self.path + sensor).read(): + return True + return False + except: + return False + + def checkStr(self, str): + # f = open(self.path+"allow") + if str in open(self.path + "allow").read(): + return True + else: + return False + # s = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) + # if str in s: return True + # else: return False + + def readSensor(self, name): + if os.path.exists(self.path + name): + values = [line.strip() for line in open(self.path + name)] + else: + values = [] + return values + """ u=User("kasun") @@ -117,4 +130,4 @@ def readSensor(self,name): #if u.deleteShare("u3",["tp","gps"]): print "Share deleted" else: print "FAIL delete" -""" \ No newline at end of file +""" diff --git a/utils/UserMongo.py b/utils/UserMongo.py index 10d880d..bd7a2df 100644 --- a/utils/UserMongo.py +++ b/utils/UserMongo.py @@ -12,208 +12,225 @@ class User: - database="" - usrDoc="" - """ All database related operations are here - putUser - Check the availability of a user name and create it - delUser - Remove the given user - login - Read the pin/public key and handle the login - Share - Sharing the sensors - UnShare - remove the share - - """ - def __init__(self,db,name): - self.database=db - self.name=name - doc=self.database.find_one({"name":self.name}) - if(doc): - self.usrDoc=doc - else: - doc="" - - def putUser(self,name,phone,key,pubkey): - #admin user is root. He can create main accounts. - #The other users can create sub accounts. - #Then the user name become main_account_name.subaccount_name - uname=name - if self.name!= "": - uname='%s.%s' %(self.name,name) - owner=self.name - else: - owner="root" - - doc=self.database.find_one({"name":uname}) - if(doc): - #if user name is already taken - return False - else: - #The system support pin or public key based authentication. - if pubkey!='': - #It saves public key - user = {"name":uname,"phone":phone,"publickey":pubkey,"owner":owner} - else: - #It saves SHA1 hash of the PIN - s = hashlib.sha1() - s.update(key) - key=b64encode(s.digest()) - user = {"name":uname,"phone":phone,"skey":key,"owner":owner} - post_id = self.database.insert(user) - return True - - def delUser(self,name,phone,key,pubkey): - #Owners can login and delete their accounts. - #Main accounts (owner=root) cannot delete right now. - uname=name - if self.name!= "": - uname='%s.%s' %(self.name,name) - owner=self.name - else: - owner="root" - - doc=self.database.find_one({"name":uname}) - #print uname - if not (doc): - #if the given user is not available - return False - else: - if(self.usrDoc): - post_id=self.database.remove({"name":uname,"owner":owner}) - return True - else: - return False - - def login(self,key,sig): - #doc=db.find_one({"name":self.name,"skey":key}) - if(self.usrDoc): - #PIN is compared with hash of the key - if 'skey' in self.usrDoc: - s = hashlib.sha1() - s.update(key) - key=b64encode(s.digest()) - if self.usrDoc['skey']==key: - return True - #Signature will be verified with the public key - elif 'publickey' in self.usrDoc: - cry=MyCrypto("mysensors") - if cry.verifySign(self.usrDoc['publickey'],sig,key): - return True - return False - - def loadPublicKey(self): - if(self.usrDoc): - if 'publickey' in self.usrDoc: - s=self.usrDoc['publickey'] - return str(s) - return '' - - def loadData(self,name): - if(self.usrDoc): - if name in self.usrDoc: - s=self.usrDoc[name] - return str(','.join(s)) - return '' - - def logout(self): - #This will call when user logout - if(self.usrDoc): - self.usrDoc="" - return True - else: return False - - """ - Following function will add recipient names to - the sensor array in the user dictionary. - It also add the sensor name to the recipient array in - the recipient dictionary. - """ - def share(self,recipient,sensors): - # User should loged - if not (self.usrDoc): return False - # Recipient should be available - doc=self.database.find_one({"name":recipient}) - if not doc: return False - - for sensor in sensors: - #Check the sensor is already in the shared list - if not self.isShare(recipient,[sensor]): - #check that the sensor was shared for someone else - if sensor in self.usrDoc.keys(): - self.usrDoc[sensor].append(recipient) - else: - self.usrDoc[sensor]=[recipient] - - #Tag recipient document - # Check that user was shared anything else - if self.name in doc.keys(): - if not sensor in doc[self.name]: - doc[self.name].append(sensor) - else: - doc[self.name]=[sensor] - post_id = self.database.save(doc) - post_id = self.database.save(self.usrDoc) - return True - - - """ - Following function will remove recipient names from - the sensor array in the user dictionary. - It also remove the sensor name from the recipient array in - the recipient dictionary - """ - def unShare(self,recipient,sensors): - # User must be loged - if not (self.usrDoc): return False - # Recipient should available - doc=self.database.find_one({"name":recipient}) - if not doc: return False - - for sensor in sensors: - #Check that the logged user was shared a sensor - #If so remove recipient name from the senor dictionary - if self.isShare(recipient,[sensor]): - self.usrDoc[sensor].remove(recipient) - - #Remove shared tag from recipient document - # Check that user was shared anything else - if self.name in doc.keys(): - if sensor in doc[self.name]: - doc[self.name].remove(sensor) - - #Check that the recipient was shared a sensor - #If so remove the sensor name from the recipient dictionary - if self.isAllow(recipient,[sensor]): - #print self.usrDoc[recipient] - self.usrDoc[recipient].remove(sensor) - - #Remove shared tag from recipient document - # Check that user was shared anything else - if sensor in doc.keys(): - if self.name in doc[sensor]: - #print doc[sensor] - doc[sensor].remove(self.name) - - post_id = self.database.save(doc) - post_id = self.database.save(self.usrDoc) - return True - - def isShare(self,recipient,sensors): - if not (self.usrDoc): return False - for sensor in sensors: - if not sensor in self.usrDoc.keys(): return False - if not recipient in self.usrDoc[sensor]: return False - return True - - def isAllow(self,sender,sensors): - if not (self.usrDoc): return False - for sensor in sensors: - if not sender in self.usrDoc.keys(): return False - if not sensor in self.usrDoc[sender]: return False - return True - - def countDocs(self): - if not (self.usrDoc): return False - return self.database.find().count() - + database = "" + usrDoc = "" + """ All database related operations are here + putUser - Check the availability of a user name and create it + delUser - Remove the given user + login - Read the pin/public key and handle the login + Share - Sharing the sensors + UnShare - remove the share + + """ + + def __init__(self, db, name): + self.database = db + self.name = name + doc = self.database.find_one({"name": self.name}) + if (doc): + self.usrDoc = doc + else: + doc = "" + + def putUser(self, name, phone, key, pubkey): + # admin user is root. He can create main accounts. + # The other users can create sub accounts. + # Then the user name become main_account_name.subaccount_name + uname = name + if self.name != "": + uname = '%s.%s' % (self.name, name) + owner = self.name + else: + owner = "root" + + doc = self.database.find_one({"name": uname}) + if (doc): + # if user name is already taken + return False + else: + # The system support pin or public key based authentication. + if pubkey != '': + # It saves public key + user = {"name": uname, "phone": phone, + "publickey": pubkey, "owner": owner} + else: + # It saves SHA1 hash of the PIN + s = hashlib.sha1() + s.update(key) + key = b64encode(s.digest()) + user = {"name": uname, "phone": phone, + "skey": key, "owner": owner} + post_id = self.database.insert(user) + return True + + def delUser(self, name, phone, key, pubkey): + # Owners can login and delete their accounts. + # Main accounts (owner=root) cannot delete right now. + uname = name + if self.name != "": + uname = '%s.%s' % (self.name, name) + owner = self.name + else: + owner = "root" + + doc = self.database.find_one({"name": uname}) + # print uname + if not (doc): + # if the given user is not available + return False + else: + if (self.usrDoc): + post_id = self.database.remove({"name": uname, "owner": owner}) + return True + else: + return False + + def login(self, key, sig): + # doc=db.find_one({"name":self.name,"skey":key}) + if (self.usrDoc): + # PIN is compared with hash of the key + if 'skey' in self.usrDoc: + s = hashlib.sha1() + s.update(key) + key = b64encode(s.digest()) + if self.usrDoc['skey'] == key: + return True + # Signature will be verified with the public key + elif 'publickey' in self.usrDoc: + cry = MyCrypto("mysensors") + if cry.verifySign(self.usrDoc['publickey'], sig, key): + return True + return False + + def loadPublicKey(self): + if (self.usrDoc): + if 'publickey' in self.usrDoc: + s = self.usrDoc['publickey'] + return str(s) + return '' + + def loadData(self, name): + if (self.usrDoc): + if name in self.usrDoc: + s = self.usrDoc[name] + return str(','.join(s)) + return '' + + def logout(self): + # This will call when user logout + if (self.usrDoc): + self.usrDoc = "" + return True + else: + return False + + """ + Following function will add recipient names to + the sensor array in the user dictionary. + It also add the sensor name to the recipient array in + the recipient dictionary. + """ + + def share(self, recipient, sensors): + # User should loged + if not (self.usrDoc): + return False + # Recipient should be available + doc = self.database.find_one({"name": recipient}) + if not doc: + return False + + for sensor in sensors: + # Check the sensor is already in the shared list + if not self.isShare(recipient, [sensor]): + # check that the sensor was shared for someone else + if sensor in self.usrDoc.keys(): + self.usrDoc[sensor].append(recipient) + else: + self.usrDoc[sensor] = [recipient] + + # Tag recipient document + # Check that user was shared anything else + if self.name in doc.keys(): + if sensor not in doc[self.name]: + doc[self.name].append(sensor) + else: + doc[self.name] = [sensor] + post_id = self.database.save(doc) + post_id = self.database.save(self.usrDoc) + return True + + """ + Following function will remove recipient names from + the sensor array in the user dictionary. + It also remove the sensor name from the recipient array in + the recipient dictionary + """ + + def unShare(self, recipient, sensors): + # User must be loged + if not (self.usrDoc): + return False + # Recipient should available + doc = self.database.find_one({"name": recipient}) + if not doc: + return False + + for sensor in sensors: + # Check that the logged user was shared a sensor + # If so remove recipient name from the senor dictionary + if self.isShare(recipient, [sensor]): + self.usrDoc[sensor].remove(recipient) + + # Remove shared tag from recipient document + # Check that user was shared anything else + if self.name in doc.keys(): + if sensor in doc[self.name]: + doc[self.name].remove(sensor) + + # Check that the recipient was shared a sensor + # If so remove the sensor name from the recipient dictionary + if self.isAllow(recipient, [sensor]): + # print self.usrDoc[recipient] + self.usrDoc[recipient].remove(sensor) + + # Remove shared tag from recipient document + # Check that user was shared anything else + if sensor in doc.keys(): + if self.name in doc[sensor]: + # print doc[sensor] + doc[sensor].remove(self.name) + + post_id = self.database.save(doc) + post_id = self.database.save(self.usrDoc) + return True + + def isShare(self, recipient, sensors): + if not (self.usrDoc): + return False + for sensor in sensors: + if sensor not in self.usrDoc.keys(): + return False + if recipient not in self.usrDoc[sensor]: + return False + return True + + def isAllow(self, sender, sensors): + if not (self.usrDoc): + return False + for sensor in sensors: + if sender not in self.usrDoc.keys(): + return False + if sensor not in self.usrDoc[sender]: + return False + return True + + def countDocs(self): + if not (self.usrDoc): + return False + return self.database.find().count() + + ''' #Create connection to the Mongo DB client = MongoClient('localhost', 27017) diff --git a/utils/myCrypto.py b/utils/myCrypto.py index b892202..98ab346 100644 --- a/utils/myCrypto.py +++ b/utils/myCrypto.py @@ -1,21 +1,21 @@ ############################################################################### ## -## Senze Crypto Library for My Senosr Server/Client v0.01 -## @Copyright 2014 MySensors Research Project -## SCoRe Lab (www.scorelab.org) -## University of Colombo School of Computing +# Senze Crypto Library for My Senosr Server/Client v0.01 +# @Copyright 2014 MySensors Research Project +# SCoRe Lab (www.scorelab.org) +# University of Colombo School of Computing ## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at ## -## http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 ## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. ## ############################################################################### @@ -25,217 +25,223 @@ from Crypto.Cipher import AES import time -from base64 import b64encode, b64decode +from base64 import b64encode, b64decode from Crypto.Cipher import PKCS1_OAEP from Crypto import Random import os.path + class myCrypto: - user="" - pubKeyLoc="" - privKeyLoc="" - key="" - bs=32 - - def __init__(self,name): - self.user=name - #Set the public and private key locations - self.pubKeyLoc="."+name+"PubKey.pem" - self.privKeyLoc="."+name+"PrivKey.pem" - - def generateAES(self,pin): - ''' - Generate 256 bits AES key. - param: pin the shared secret - ''' - try: - self.bs=32 - digest = SHA256.new(pin).digest() - self.key=digest - return True - except: - return False - - def pad(self, s): - return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs) - - def unpad(self, s): + user = "" + pubKeyLoc = "" + privKeyLoc = "" + key = "" + bs = 32 + + def __init__(self, name): + self.user = name + # Set the public and private key locations + self.pubKeyLoc = "."+name+"PubKey.pem" + self.privKeyLoc = "."+name+"PrivKey.pem" + + def generateAES(self, pin): + """ + Generate 256 bits AES key. + param: pin the shared secret + """ + try: + self.bs = 32 + digest = SHA256.new(pin).digest() + self.key = digest + return True + except: + return False + + def pad(self, s): + return s + (self.bs - len(s) % self.bs) * \ + chr(self.bs - len(s) % self.bs) + + def unpad(self, s): return s[:-ord(s[len(s)-1:])] - - def encrypt(self,raw): - raw = self.pad(raw) - #iv = Random.new().read(AES.block_size) - #obj = AES.new('This is a key123', AES.MODE_CBC, 'This is an IV456') - cipher = AES.new(self.key,AES.MODE_ECB) - return b64encode(cipher.encrypt(raw)) - - def decrypt(self,enc): - try: - enc = b64decode(enc) - #iv = enc[:AES.block_size] - #cipher = AES.new(self.key,AES.MODE_OFB) - cipher = AES.new(self.key,AES.MODE_ECB) - return self.unpad(cipher.decrypt(enc)) - except: - return False - - def generateRSA(self,bits): - ''' - Generate an RSA keypair with an exponent of 65537 in PEM format - param: bits The key length in bits - Save private key and public key in files - openssl pkcs8 -topk8 -inform PEM -outform PEM -in .mysensorsPrivKey.pem -out private.pem -nocrypt - ''' - newKey = RSA.generate(bits, e=65537) - publicKey = newKey.publickey().exportKey("PEM") - privateKey = newKey.exportKey("PEM") - - try: - f=open(self.privKeyLoc,'w') - f.write(privateKey) - f.close() - - f=open(self.pubKeyLoc,'w') - f.write(publicKey) - f.close() - return True - - except: - return False - - def signSENZE(self,senze): - from Crypto.Signature import PKCS1_v1_5 - ''' - param: senze to be signed - return: senze with base64 encoded signature - ''' - key = open(self.privKeyLoc,"r").read() - rsakey = RSA.importKey(key) - t=time.time() - senze ='%s #time %s ^%s' %(senze,t,self.user) - signer = PKCS1_v1_5.new(rsakey) - digest = SHA256.new("".join(senze.split())) - sign = signer.sign(digest) - senze = '%s %s' %(senze,b64encode(sign)) - return senze - - - def signData(self,data): - from Crypto.Signature import PKCS1_v1_5 - ''' - param: package Data to be signed - return: base64 encoded signature - ''' - key = open(self.privKeyLoc,"r").read() - rsakey = RSA.importKey(key) - - signer = PKCS1_v1_5.new(rsakey) - digest = SHA256.new(data) - sign = signer.sign(digest) - return b64encode(sign) - - def verifySENZE(self,query,publicKey): - from Crypto.Signature import PKCS1_v1_5 - ''' - Verifies with a public key from whom the data came that it was indeed - signed by their private key - param: public_key - param: senze - param: signature String signature to be verified - return: Boolean. True if the signaetture is valid; False otherwise. - ''' - rsakey = RSA.importKey(b64decode(publicKey)) - signer = PKCS1_v1_5.new(rsakey) - digest = SHA256.new(query.getSENZE()) - # Assumes the data is base64 encoded to begin with - if signer.verify(digest,b64decode(query.getSignature())): - return True - else: - return False - - def verifySign(self,publicKey,signature,data): - from Crypto.Signature import PKCS1_v1_5 - ''' - Verifies with a public key from whom the data came that it was indeed - signed by their private key - param: public_key - param: signature String signature to be verified - param: data - return: Boolean. True if the signature is valid; False otherwise. - ''' - rsakey = RSA.importKey(b64decode(publicKey)) - signer = PKCS1_v1_5.new(rsakey) - digest = SHA256.new(data) - # Assumes the data is base64 encoded to begin with - if signer.verify(digest,b64decode(signature)): - return True - else: - return False - - def loadRSAPubKey(self): - ''' - Reads a public key from the file - return: Base64 encoded public key - ''' - publicKey="" - #if os.path.isfile(pubKeyLoc): - publicKey = open(self.pubKeyLoc,"r").read() - return b64encode(publicKey) - #else: - # return publicKey - - def saveRSAPubKey(self,pubkey): - ''' - Saves a public key - param: public key - ''' - try: - #if not os.path.isfile(publicKeyLoc): - f=open(self.pubKeyLoc,'w') - f.write(b64decode(pubkey)) - f.close() - return True - except: - return False - - def encryptRSA(self,message): - ''' - param: message String t o be encrypted - return base64 encoded encrypted string - ''' - #h = SHA.new(message) - key = open(self.pubKeyLoc, "r").read() - rsakey = RSA.importKey(key) -# rsakey = PKCS1_v1_5.new(rsakey) - rsakey = PKCS1_OAEP.new(rsakey) - #encrypted = rsakey.encrypt(b64encode(message)) - encrypted = rsakey.encrypt(message) - return b64encode(encrypted) - #return encrypted.encode('base64') - - def decryptRSA(self,package): - ''' - param: package String to be decrypted - return decrypted string - ''' - key = open(self.privKeyLoc, "r").read() - rsakey = RSA.importKey(key) - - ''' - dsize = SHA.digest_size - sentinel = Random.new().read(15+dsize) # Let's assume that average data length is 15 - #print sentinel - cipher = PKCS1_v1_5.new(rsakey) - message = cipher.decrypt(b64decode(package),sentinel) - ''' - cipher = PKCS1_OAEP.new(rsakey) - message = cipher.decrypt(b64decode(package)) - #return b64decode(message) - return message - - -''' + + def encrypt(self, raw): + raw = self.pad(raw) + # iv = Random.new().read(AES.block_size) + # obj = AES.new('This is a key123', AES.MODE_CBC, 'This is an IV456') + cipher = AES.new(self.key, AES.MODE_ECB) + return b64encode(cipher.encrypt(raw)) + + def decrypt(self, enc): + try: + enc = b64decode(enc) + # iv = enc[:AES.block_size] + # cipher = AES.new(self.key,AES.MODE_OFB) + cipher = AES.new(self.key, AES.MODE_ECB) + return self.unpad(cipher.decrypt(enc)) + except: + return False + + def generateRSA(self, bits): + """ + Generate an RSA keypair with an exponent of 65537 in PEM format + param: bits The key length in bits + Save private key and public key in files + + openssl pkcs8 -topk8 -inform PEM -outform PEM -in .mysensorsPrivKey.pem + -out private.pem -nocrypt + """ + newKey = RSA.generate(bits, e=65537) + publicKey = newKey.publickey().exportKey("PEM") + privateKey = newKey.exportKey("PEM") + + try: + f = open(self.privKeyLoc, 'w') + f.write(privateKey) + f.close() + + f = open(self.pubKeyLoc, 'w') + f.write(publicKey) + f.close() + return True + + except: + return False + + def signSENZE(self, senze): + """ + param: senze to be signed + return: senze with base64 encoded signature + """ + from Crypto.Signature import PKCS1_v1_5 + + key = open(self.privKeyLoc, "r").read() + rsakey = RSA.importKey(key) + t = time.time() + senze = '%s #time %s ^%s' % (senze, t, self.user) + signer = PKCS1_v1_5.new(rsakey) + digest = SHA256.new("".join(senze.split())) + sign = signer.sign(digest) + senze = '%s %s' % (senze, b64encode(sign)) + return senze + + def signData(self, data): + """ + param: package Data to be signed + return: base64 encoded signature + """ + from Crypto.Signature import PKCS1_v1_5 + + key = open(self.privKeyLoc, "r").read() + rsakey = RSA.importKey(key) + + signer = PKCS1_v1_5.new(rsakey) + digest = SHA256.new(data) + sign = signer.sign(digest) + return b64encode(sign) + + def verifySENZE(self, query, publicKey): + from Crypto.Signature import PKCS1_v1_5 + """ + Verifies with a public key from whom the data came that it was indeed + signed by their private key + param: public_key + param: senze + param: signature String signature to be verified + return: Boolean. True if the signaetture is valid; False otherwise. + """ + rsakey = RSA.importKey(b64decode(publicKey)) + signer = PKCS1_v1_5.new(rsakey) + digest = SHA256.new(query.getSENZE()) + # Assumes the data is base64 encoded to begin with + if signer.verify(digest, b64decode(query.getSignature())): + return True + else: + return False + + def verifySign(self, publicKey, signature, data): + """ + Verifies with a public key from whom the data came that it was indeed + signed by their private key + param: public_key + param: signature String signature to be verified + param: data + return: Boolean. True if the signature is valid; False otherwise. + """ + from Crypto.Signature import PKCS1_v1_5 + + rsakey = RSA.importKey(b64decode(publicKey)) + signer = PKCS1_v1_5.new(rsakey) + digest = SHA256.new(data) + # Assumes the data is base64 encoded to begin with + if signer.verify(digest, b64decode(signature)): + return True + else: + return False + + def loadRSAPubKey(self): + """ + Reads a public key from the file + return: Base64 encoded public key + """ + publicKey = "" + # if os.path.isfile(pubKeyLoc): + publicKey = open(self.pubKeyLoc, "r").read() + return b64encode(publicKey) + # else: + # return publicKey + + def saveRSAPubKey(self, pubkey): + """ + Saves a public key + param: public key + """ + try: + # if not os.path.isfile(publicKeyLoc): + f = open(self.pubKeyLoc, 'w') + f.write(b64decode(pubkey)) + f.close() + return True + except: + return False + + def encryptRSA(self, message): + """ + param: message String t o be encrypted + return base64 encoded encrypted string + """ + # h = SHA.new(message) + key = open(self.pubKeyLoc, "r").read() + rsakey = RSA.importKey(key) + # rsakey = PKCS1_v1_5.new(rsakey) + rsakey = PKCS1_OAEP.new(rsakey) + # encrypted = rsakey.encrypt(b64encode(message)) + encrypted = rsakey.encrypt(message) + return b64encode(encrypted) + # return encrypted.encode('base64') + + def decryptRSA(self, package): + """ + param: package String to be decrypted + return decrypted string + """ + key = open(self.privKeyLoc, "r").read() + rsakey = RSA.importKey(key) + + """ + dsize = SHA.digest_size + sentinel = Random.new().read(15+dsize) + # Let's assume that average data length is 15 + #print sentinel + cipher = PKCS1_v1_5.new(rsakey) + message = cipher.decrypt(b64decode(package),sentinel) + """ + cipher = PKCS1_OAEP.new(rsakey) + message = cipher.decrypt(b64decode(package)) + # return b64decode(message) + return message + +""" test=myCrypto("mysensors") test.generateAES("1234hello") enc=test.encrypt("Hello123") @@ -267,4 +273,4 @@ def decryptRSA(self,package): print "-----" plain=cry.decryptRSA(enc) print plain -''' +""" diff --git a/utils/myParser.py b/utils/myParser.py index 51eb83c..c4957e7 100644 --- a/utils/myParser.py +++ b/utils/myParser.py @@ -1,21 +1,21 @@ ############################################################################### ## -## Senze parser for My Senosr Server/Client v0.01 -## @Copyright 2014 MySensors Research Project -## SCoRe Lab (www.scorelab.org) -## University of Colombo School of Computing -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. +# Senze parser for My Senosr Server/Client v0.01 +# @Copyright 2014 MySensors Research Project +# SCoRe Lab (www.scorelab.org) +# University of Colombo School of Computing +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. ## ############################################################################### import sys @@ -30,87 +30,95 @@ handler.setLevel(logging.INFO) # create a logging format -formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - \ + %(message)s') handler.setFormatter(formatter) # add the handlers to the logger logger.addHandler(handler) + class myParser: - """ - Incoming messages from websockets will be parsed - by the Parser and obtained the query parameters. - Appropriate action will be invoked by the MySensor Sever or Client. - """ - - def __init__(self,msg): - self.users=list() - self.sensors=list() - self.command="" - self.data={} - self.sender="" - self.signature="" - self.senze="" - self.fullSenze="" - - self.fullSenze=msg - tList=msg.split() - state='CLEAR' - sen="" - commandList=["SHARE","UNSHARE","PUT","GET","DATA"] - logger.info(msg) - - while tList: - word=tList.pop(0) - self.senze+=word - - if word.upper() in commandList: - self.command=word - elif word.startswith("#"): - sen=word[1:] - if not sen in self.sensors: - self.sensors.append(sen) - state='DATA' - elif word.startswith("@"): - usr=word[1:] - if not usr in self.users: - self.users.append(word[1:]) - elif word.startswith("^"): - self.sender=word[1:] - self.signature=tList.pop(0) - else: - if state=='DATA': - self.data[sen]=word - state='CLEAR' - - - def getUsers(self): - return self.users - - def getSensors(self): - return self.sensors - - def getData(self): - return self.data - - def getCmd(self): - return self.command - - def getSender(self): - return self.sender - - def getSENZE(self): - return self.senze - - def getFULLSENZE(self): - return self.fullSenze - - def getSignature(self): - return self.signature + """ + Incoming messages from websockets will be parsed + by the Parser and obtained the query parameters. + Appropriate action will be invoked by the MySensor Sever or Client. + """ + + def __init__(self, msg): + self.users = list() + self.sensors = list() + self.command = "" + self.data = {} + self.sender = "" + self.signature = "" + self.senze = "" + self.fullSenze = "" + + self.fullSenze = msg + tList = msg.split() + state = 'CLEAR' + sen = "" + commandList = ["SHARE", "UNSHARE", "PUT", "GET", "DATA"] + logger.info(msg) + + while tList: + word = tList.pop(0) + self.senze += word + + if word.upper() in commandList: + self.command = word + elif word.startswith("#"): + sen = word[1:] + if sen not in self.sensors: + self.sensors.append(sen) + state = 'DATA' + elif word.startswith("@"): + usr = word[1:] + if usr not in self.users: + self.users.append(word[1:]) + elif word.startswith("^"): + self.sender = word[1:] + self.signature = tList.pop(0) + else: + if state == 'DATA': + self.data[sen] = word + state = 'CLEAR' + + def getUsers(self): + return self.users + + def getSensors(self): + return self.sensors + + def getData(self): + return self.data + + def getCmd(self): + return self.command + + def getSender(self): + return self.sender + + def getSENZE(self): + return self.senze + + def getFULLSENZE(self): + return self.fullSenze + + def getSignature(self): + return self.signature ''' -#testData=["SHARE #pubkey LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FDbit1eVpzcXIxeS93Y2hjTkh1MzducE5RSwpSRHFBOTl6REkxeUtzOTFLNUJvNWFKWG1qOXc2cUJwdnVPdkNZQUxHcEdXVC9NUm1Ka3pLOGZUclJhVFlyY1ZMCkJsbklkMXVneWUzZDJFM3lBRFREZlNWWGlOZXpKS2MrSkErN0ExV25FZ0tacXB6ZmYvalNhZXgrR25YcWZ5d0cKeVQvR201QnhwdTc2SXFkYU9RSURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ== @mysensors ^home0 iT4zN85/JNaWiDw56gLqYFDpf6dwkfUOIkP/QlGvLOz4PF7KgJOhefEfH8xQXBmLQAOq3blIVuHIZC55CqTFevfovLcy4Ff42VEFAqMqj42Z3cmoApxgU6tzs/V5BjlrmQAry2TGQ0Qx18uqJANjuyvxMTMMwpiWRK1GM5jZch4="] - -testData=["SHARE #pubkey XXXXXXX #time t1 @mysensors ^kasun yyyyyyyyyy", +#testData = ["SHARE #pubkey LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3\ +FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FDbit1eVpzcXIxeS93Y2hjTkh1MzducE5RSwpSRHFBO\ +Tl6REkxeUtzOTFLNUJvNWFKWG1qOXc2cUJwdnVPdkNZQUxHcEdXVC9NUm1Ka3pLOGZUclJhVFlyY1ZM\ +CkJsbklkMXVneWUzZDJFM3lBRFREZlNWWGlOZXpKS2MrSkErN0ExV25FZ0tacXB6ZmYvalNhZXgrR25\ +YcWZ5d0cKeVQvR201QnhwdTc2SXFkYU9RSURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ = \ += @mysensors ^home0 iT4zN85/JNaWiDw56gLqYFDpf6dwkfUOIkP/QlGvLOz4PF7KgJOhefEfH\ +8xQXBmLQAOq3blIVuHIZC55CqTFevfovLcy4Ff42VEFAqMqj42Z3cmoApxgU6tzs/V5BjlrmQAry2TGQ\ +0Qx18uqJANjuyvxMTMMwpiWRK1GM5jZch4 = "] + +testData = ["SHARE #pubkey XXXXXXX #time t1 @mysensors ^kasun yyyyyyyyyy", "DATA #msg ErrorCode @home0 #time t3 ^mysensors XXXXXXXXX", "DATA #time t1 @mysensors ^kasun YYYYYY", "SHARE #pubkey XXXXXXX #time t1 @home0 ^kasun yyyyyyyyyy", @@ -126,7 +134,7 @@ def getSignature(self): "GET #cipher xxxlatlon @kasun #time t3 ^home0 XXXXXXXXX"] for l in testData: - m= myParser(l) + m = myParser(l) print "User List: ",m.getUsers() print "Sensors: ", m.getSensors() diff --git a/utils/myUser.py b/utils/myUser.py index 70fdb7c..0b2b8e5 100644 --- a/utils/myUser.py +++ b/utils/myUser.py @@ -1,21 +1,21 @@ ############################################################################### ## -## User Library for My Senosr Server/Client v0.01 -## @Copyright 2014 MySensors Research Project -## SCoRe Lab (www.scorelab.org) -## University of Colombo School of Computing -## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at -## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. +# User Library for My Senosr Server/Client v0.01 +# @Copyright 2014 MySensors Research Project +# SCoRe Lab (www.scorelab.org) +# University of Colombo School of Computing +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. ## ############################################################################### @@ -29,234 +29,250 @@ class myUser: - database="" - usrDoc="" - """ All database related operations are here + database = "" + usrDoc = "" + """ All database related operations are here putUser - Check the availability of a user name and create it delUser - Remove the given user - login - Read the pin/public key and handle the login + login - Read the pin/public key and handle the login Share - Sharing the sensors UnShare - remove the share - - """ - def __init__(self,db,name): - #Set the pointers to the database and user document - self.database=db - self.name=name - doc=self.database.find_one({"name":self.name}) - if(doc): - self.usrDoc=doc - else: - doc="" - - def addUser(self,name,phone,senze,pubkey,signature): - doc=self.database.find_one({"name":name}) - if(doc): - #if user name is already taken - return False - else: - #The system support public key based authentication. - #It saves public key - user = {"name":name,"phone":phone,"senze":senze,"pubkey":pubkey,"signature":signature} - post_id = self.database.insert(user) - return True + """ + + def __init__(self, db, name): + # Set the pointers to the database and user document + self.database = db + self.name = name + doc = self.database.find_one({"name": self.name}) + if (doc): + self.usrDoc = doc + else: + doc = "" + + def addUser(self, name, phone, senze, pubkey, signature): + doc = self.database.find_one({"name": name}) + if (doc): + # if user name is already taken + return False + else: + # The system support public key based authentication. + # It saves public key + user = {"name": name, "phone": phone, "senze": senze, + "pubkey": pubkey, "signature": signature} + post_id = self.database.insert(user) + return True + + def delUser(self, name, pubkey): + # Owners can remove himself + doc = self.database.find_one({"name": name, "pubkey": pubkey}) + print name + print pubkey + if not (doc): + # if the given user is not available + return False + else: + post_id = self.database.remove({"name": name, "pubkey": pubkey}) + return True + + def findUsers(self, u): + friends = [] + users = u.split(',') + # print users + for user in users: + doc = self.database.find_one({"name": user}) + # print user + if doc: + if user not in friends: + friends.append(user) + else: + doc = "" + return str(','.join(friends)) + + def login(self, key, sig, server): + # doc = db.find_one({"name":self.name,"skey":key}) + if (self.usrDoc): + # PIN is compared with hash of the key + if 'skey' in self.usrDoc: + s = hashlib.sha1() + s.update(key) + key = b64encode(s.digest()) + if self.usrDoc['skey'] == key: + return True + # Hash key is sent + elif 'hkey' in self.usrDoc: + hkey = self.usrDoc['hkey'] + s = hashlib.sha1() + s.update(hkey + sig) + tkey = b64encode(s.digest()) + if tkey == key: + return True + # Signature will be verified with the public key + elif 'publickey' in self.usrDoc: + cry = myCrypto(server) + if cry.verifySign(self.usrDoc['publickey'], sig, key): + return True + return False + + def loadPublicKey(self): + if (self.usrDoc): + if 'pubkey' in self.usrDoc: + s = self.usrDoc['pubkey'] + return str(s) + return '' + + def loadFriends(self, sensor): + friends = [] + if (self.usrDoc): + for name in self.usrDoc: + sensors = self.usrDoc[name] + # print type(sensors) + if type(sensors) is list: + if sensor in sensors: + friends.append(name) + return str(','.join(friends)) + + def loadData(self, name): + if (self.usrDoc): + if name in self.usrDoc: + s = self.usrDoc[name] + return str(','.join(s)) + return '' + + def logout(self): + # This will call when user logout + if (self.usrDoc): + self.usrDoc = "" + return True + else: + return False - def delUser(self,name,pubkey): - #Owners can remove himself - doc=self.database.find_one({"name":name,"pubkey":pubkey}) - print name - print pubkey - if not (doc): - #if the given user is not available - return False - else: - post_id=self.database.remove({"name":name,"pubkey":pubkey}) - return True - - def findUsers(self,u): - friends=[] - users=u.split(',') - #print users - for user in users: - doc=self.database.find_one({"name":user}) - #print user - if doc: - if user not in friends: - friends.append(user) - else: doc="" - return str(','.join(friends)) + """ + Following function will add recipient names to + the sensor array in the user dictionary. + It also add the sensor name to the recipient array in + the recipient dictionary. + """ - def login(self,key,sig,server): - #doc=db.find_one({"name":self.name,"skey":key}) - if(self.usrDoc): - #PIN is compared with hash of the key - if 'skey' in self.usrDoc: - s = hashlib.sha1() - s.update(key) - key=b64encode(s.digest()) - if self.usrDoc['skey']==key: - return True - #Hash key is sent - elif 'hkey' in self.usrDoc: - hkey=self.usrDoc['hkey'] - s = hashlib.sha1() - s.update(hkey+sig) - tkey=b64encode(s.digest()) - if tkey==key: - return True - #Signature will be verified with the public key - elif 'publickey' in self.usrDoc: - cry=myCrypto(server) - if cry.verifySign(self.usrDoc['publickey'],sig,key): - return True - return False - - def loadPublicKey(self): - if(self.usrDoc): - if 'pubkey' in self.usrDoc: - s=self.usrDoc['pubkey'] - return str(s) - return '' - - def loadFriends(self,sensor): - friends=[] - if(self.usrDoc): - for name in self.usrDoc: - sensors=self.usrDoc[name] - #print type(sensors) - if type(sensors) is list: - if sensor in sensors: - friends.append(name) - return str(','.join(friends)) - - def loadData(self,name): - if(self.usrDoc): - if name in self.usrDoc: - s=self.usrDoc[name] - return str(','.join(s)) - return '' - - def logout(self): - #This will call when user logout - if(self.usrDoc): - self.usrDoc="" - return True - else: return False + def share(self, recipient, sensors): + # User should loged + if not (self.usrDoc): + return False + # Recipient should be available + doc = self.database.find_one({"name": recipient}) + if not doc: + return False - """ - Following function will add recipient names to - the sensor array in the user dictionary. - It also add the sensor name to the recipient array in - the recipient dictionary. - """ - def share(self,recipient,sensors): - # User should loged - if not (self.usrDoc): return False - # Recipient should be available - doc=self.database.find_one({"name":recipient}) - if not doc: return False - - for sensor in sensors: - #Check the sensor is already in the shared list - if not self.isShare(recipient,[sensor]): - #check that the sensor was shared for someone else - if sensor in self.usrDoc.keys(): - self.usrDoc[sensor].append(recipient) - else: - self.usrDoc[sensor]=[recipient] - - #Tag recipient document - # Check that user was shared anything else - if self.name in doc.keys(): - if not sensor in doc[self.name]: - doc[self.name].append(sensor) - else: - doc[self.name]=[sensor] + for sensor in sensors: + # Check the sensor is already in the shared list + if not self.isShare(recipient, [sensor]): + # check that the sensor was shared for someone else + if sensor in self.usrDoc.keys(): + self.usrDoc[sensor].append(recipient) + else: + self.usrDoc[sensor] = [recipient] - post_id = self.database.save(doc) - post_id = self.database.save(self.usrDoc) - return True - - - """ - Following function will remove recipient names from - the sensor array in the user dictionary. - It also remove the sensor name from the recipient array in - the recipient dictionary - """ - def unShare(self,recipient,sensors): - # User must be loged - if not (self.usrDoc): return False - # Recipient should available - doc=self.database.find_one({"name":recipient}) - if not doc: return False - - for sensor in sensors: - #Check that the logged user was shared a sensor - #If so remove recipient name from the senor dictionary - if self.isShare(recipient,[sensor]): - self.usrDoc[sensor].remove(recipient) - - #Remove shared tag from recipient document - # Check that user was shared anything else - if self.name in doc.keys(): - if sensor in doc[self.name]: - doc[self.name].remove(sensor) - - #Check that the recipient was shared a sensor - #If so remove the sensor name from the recipient dictionary - if self.isAllow(recipient,[sensor]): - #print self.usrDoc[recipient] - self.usrDoc[recipient].remove(sensor) - - #Remove shared tag from recipient document - # Check that user was shared anything else - if sensor in doc.keys(): - if self.name in doc[sensor]: - #print doc[sensor] + # Tag recipient document + # Check that user was shared anything else + if self.name in doc.keys(): + if sensor not in doc[self.name]: + doc[self.name].append(sensor) + else: + doc[self.name] = [sensor] + + post_id = self.database.save(doc) + post_id = self.database.save(self.usrDoc) + return True + + """ + Following function will remove recipient names from + the sensor array in the user dictionary. + It also remove the sensor name from the recipient array in + the recipient dictionary + """ + + def unShare(self, recipient, sensors): + # User must be loged + if not (self.usrDoc): + return False + # Recipient should available + doc = self.database.find_one({"name": recipient}) + if not doc: + return False + + for sensor in sensors: + # Check that the logged user was shared a sensor + # If so remove recipient name from the senor dictionary + if self.isShare(recipient, [sensor]): + self.usrDoc[sensor].remove(recipient) + + # Remove shared tag from recipient document + # Check that user was shared anything else + if self.name in doc.keys(): + if sensor in doc[self.name]: + doc[self.name].remove(sensor) + + # Check that the recipient was shared a sensor + # If so remove the sensor name from the recipient + # dictionary + if self.isAllow(recipient, [sensor]): + # print self.usrDoc[recipient] + self.usrDoc[recipient].remove(sensor) + + # Remove shared tag from recipient document + # Check that user was shared anything else + if sensor in doc.keys(): + if self.name in doc[sensor]: + # print doc[sensor] doc[sensor].remove(self.name) - - post_id = self.database.save(doc) - post_id = self.database.save(self.usrDoc) - return True - def isShare(self,recipient,sensors): - if not (self.usrDoc): return False - for sensor in sensors: - if not sensor in self.usrDoc.keys(): return False - if not recipient in self.usrDoc[sensor]: return False - return True - - def isAllow(self,sender,sensors): - if not (self.usrDoc): return False - if not sender in self.usrDoc.keys(): return False - for sensor in sensors: - if not sensor in self.usrDoc[sender]: return False - return True - - def countDocs(self): - if not (self.usrDoc): return False - return self.database.find().count() + post_id = self.database.save(doc) + post_id = self.database.save(self.usrDoc) + return True + + def isShare(self, recipient, sensors): + if not (self.usrDoc): + return False + for sensor in sensors: + if sensor not in self.usrDoc.keys(): + return False + if recipient not in self.usrDoc[sensor]: + return False + return True + + def isAllow(self, sender, sensors): + if not (self.usrDoc): + return False + if sender not in self.usrDoc.keys(): + return False + for sensor in sensors: + if sensor not in self.usrDoc[sender]: + return False + return True + + def countDocs(self): + if not (self.usrDoc): + return False + return self.database.find().count() + - ''' #Create connection to the Mongo DB -client = MongoClient('localhost', 27017) +client = MongoClient('localhost', 27017) #Creating the database -db = client['mysensors'] -collection = db['users'] +db = client['mysensors'] +collection = db['users'] # Access the user collection from the mysensors database -usrDB = db.users -usr=myUser(usrDB,'d2') +usrDB = db.users +usr = myUser(usrDB,'d2') #print usr.countDocs() -#f=usr.loadFriends('tp') +#f = usr.loadFriends('tp') #print f -f=usr.findUsers('d2,d1,kasun,device1,nimal,d3') +f = usr.findUsers('d2,d1,kasun,device1,nimal,d3') print f -rep=usr.loadData('name') -pub=usr.loadPublicKey() +rep = usr.loadData('name') +pub = usr.loadPublicKey() print pub print rep ''' diff --git a/utils/sign.py b/utils/sign.py index 04caca8..7ed3020 100644 --- a/utils/sign.py +++ b/utils/sign.py @@ -7,4 +7,4 @@ h = SHA256.new(message) signer = PKCS1_v1_5.new(key) signature = signer.sign(h) -print 'hello' \ No newline at end of file +print 'hello'