Skip to content
This repository has been archived by the owner on Jul 10, 2021. It is now read-only.

Commit

Permalink
Added password hash validation to messages.
Browse files Browse the repository at this point in the history
  • Loading branch information
kfdm committed Aug 23, 2009
1 parent 39a2c02 commit 6a57eef
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 13 deletions.
40 changes: 34 additions & 6 deletions gntp.py
Expand Up @@ -38,6 +38,29 @@ def set_password(self,password,encryptAlgo='MD5'):
self.info['keyHashAlgorithmID'] = encryptAlgo.upper()
self.info['keyHash'] = keyHash.upper()
self.info['salt'] = salt.upper()
def _decode_hex(self,value):
result = ''
for i in range(0,len(value),2):
tmp = int(value[i:i+2],16)
result += chr(tmp)
return result
def validate_password(self):
if not self.info.get('keyHash',None):
return True
if not self.password:
raise GNTPParseError('Missing Password')

password = self.password.encode('utf8')
saltHash = self._decode_hex(self.info['salt'])

keyBasis = password+saltHash
key = hashlib.md5(keyBasis).digest()
keyHash = hashlib.md5(key).hexdigest()

if not keyHash.upper() == self.info['keyHash'].upper():
raise GNTPParseError('Invalid Hash')
return True


def format_info(self):
info = u'GNTP/%s %s'%(
Expand Down Expand Up @@ -75,10 +98,11 @@ def add_header(self,key,value):
self.headers[key] = value

class GNTPRegister(_GNTPBase):
def __init__(self,data=None):
def __init__(self,data=None,password=None):
_GNTPBase.__init__(self,'REGISTER')
self.headers = {}
self.notifications = []
self.password = password
self.requiredHeaders = [
'Application-Name',
'Notifications-Count'
Expand All @@ -103,6 +127,7 @@ def decode(self,data):
self.raw = data
parts = self.raw.split('\r\n\r\n')
self.info = self.parse_info(data)
self.validate_password()
self.headers = self.parse_dict(parts[0])

if len(parts) > 1:
Expand Down Expand Up @@ -143,10 +168,11 @@ def __str__(self):
return self.encode()

class GNTPNotice(_GNTPBase):
def __init__(self,data=None,app=None,name=None,title=None):
def __init__(self,data=None,app=None,name=None,title=None,password=None):
_GNTPBase.__init__(self,'NOTIFY')
self.headers = {}
self.resources = {}
self.password = password
self.requiredHeaders = [
'Application-Name',
'Notification-Name',
Expand All @@ -169,6 +195,7 @@ def decode(self,data):
self.raw = data
parts = self.raw.split('\r\n\r\n')
self.info = self.parse_info(data)
self.validate_password()
self.headers = self.parse_dict(parts[0])
if len(parts) > 1:
print 'Extra parts'
Expand Down Expand Up @@ -235,15 +262,15 @@ def __init__(self,data=None):
if data:
self.decode(data)

def parse_gntp(data,debug=False):
def parse_gntp(data,password=None,debug=False):
match = re.match('GNTP/(?P<version>\d+\.\d+) (?P<messagetype>REGISTER|NOTIFY|\-OK|\-ERROR)',data,re.IGNORECASE)
if not match:
raise GNTPParseError('INVALID_GNTP_INFO')
info = match.groupdict()
if info['messagetype'] == 'REGISTER':
return GNTPRegister(data)
elif info['messagetype'] == 'NOTICE':
return GNTPNotice(data)
return GNTPRegister(data,password=password)
elif info['messagetype'] == 'NOTIFY':
return GNTPNotice(data,password=password)
elif info['messagetype'] == '-OK':
return GNTPResponse(data)
elif info['messagetype'] == '-ERROR':
Expand All @@ -252,4 +279,5 @@ def parse_gntp(data,debug=False):
print '----'
print self.data
print '----'
print info
raise GNTPParseError('INVALID_GNTP_MESSAGE')
5 changes: 5 additions & 0 deletions local.py
@@ -1,6 +1,11 @@
import gntp
import Growl

GNTPParseError = gntp.GNTPParseError
GNTPOK = gntp.GNTPOK
GNTPError = gntp.GNTPError
parse_gntp = gntp.parse_gntp

class GNTPRegister(gntp.GNTPRegister):
def send(self):
print 'Sending Local Registration'
Expand Down
15 changes: 8 additions & 7 deletions server.py
Expand Up @@ -22,15 +22,15 @@ def handle(self):
self.data = self.read()

try:
message = parse_gntp(self.data)
message = gntp.parse_gntp(self.data,self.server.growl_password)
message.send()

response = GNTPOK()
response = gntp.GNTPOK()
self.write(response.encode())
except GNTPError:
except gntp.GNTPError:
if self.server.growl_debug:
traceback.print_exc()
response = GNTPError()
response = gntp.GNTPError()
self.write(response.encode())

if __name__ == "__main__":
Expand All @@ -40,16 +40,17 @@ def handle(self):
parser.add_option("-p","--port",dest="port",help="port to listen on",type="int",default=23053)
parser.add_option("-r","--regrowl",dest='regrowl',help="ReGrowl on local OSX machine",action="store_true",default=False)
parser.add_option("-d","--debug",dest='debug',help="Print raw growl packets",action="store_true",default=False)
parser.add_option("-P","--password",dest='password',help="Network password",default=None)
(options, args) = parser.parse_args()

if options.regrowl:
from local import GNTPRegister,GNTPNotice
from gntp import GNTPParseError,GNTPOK,GNTPError,parse_gntp
import local as gntp
else:
from gntp import *
import gntp

server = GNTPServer((options.host, options.port), GNTPHandler)
server.growl_debug = options.debug
server.growl_password = options.password

sa = server.socket.getsockname()
print "Listening for GNTP on", sa[0], "port", sa[1], "..."
Expand Down

0 comments on commit 6a57eef

Please sign in to comment.