MIFARE Login - Add a blacklist of known-bad cards
[uccvend-vendserver.git] / VendServer / OpenDispense.py
index 3790348..6b93058 100644 (file)
@@ -12,9 +12,21 @@ import os
 import logging
 import re
 import pwd
+import base64
+import socket
 from subprocess import Popen, PIPE
 from LDAPConnector import get_uid,get_uname, set_card_id
 
+DISPENSE_ENDPOINT = ("localhost", 11020)
+DISPSRV_MIFARE = True
+
+# A list of cards that should never be registered, and should never log in
+# - Some of these might have been registered before we knew they were duplicates
+CARD_BLACKLIST = [
+       'AAAAAA==',     # All zeroes, don't allow that.
+       'ISIjJA==', # CommBank credit cards
+       ]
+
 class OpenDispense(DispenseInterface):
        _username = ""
        _disabled = True
@@ -25,6 +37,41 @@ class OpenDispense(DispenseInterface):
                pass
 
        def authUserIdPin(self, userId, pin):
+               return self.authUserIdPin_db(userId, pin)
+               #return self.authUserIdPin_file(userId, pin)
+       
+       def authUserIdPin_db(self, userId, pin):
+               userId = int(userId)
+
+               try:
+                       # Get username (TODO: Store the user ID in the dispense database too)
+                       info = pwd.getpwuid(userId)
+               except KeyError:
+                       logging.info('getting pin for uid %d: user not in password file'%userId)
+                       return False
+               
+               sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
+               sock.connect(DISPENSE_ENDPOINT)
+               logging.debug('connected to dispsrv')
+               sockf = sock.makefile()
+               sockf.write("AUTHIDENT\n"); sockf.flush()
+               rsp = sockf.readline()
+               assert "200" in rsp
+               logging.debug('authenticated')
+               sockf.write("PIN_CHECK %s %s\n" % (info.pw_name, pin)); sockf.flush()
+               rsp = sockf.readline()
+               if not "200" in rsp:
+                       logging.info('checking pin for uid %d: Server said no - %r' % (userId, rsp))
+                       return False
+               #Login Successful
+               logging.info('accepted pin for uid %d \'%s\'' % (userId, info.pw_name))
+               self._userid = userId
+               self._loggedIn = True
+               self._disabled = False
+               self._username = info.pw_name
+               return True
+
+       def authUserIdPin_file(self, userId, pin):
                userId = int(userId)
 
                try:
@@ -67,27 +114,96 @@ class OpenDispense(DispenseInterface):
                return False
 
        def authMifareCard(self, cardId):
-               # Get the users ID
-               self._userid = get_uid(cardId)
+               self._loggedIn = False
+               self._username = None
+               if DISPSRV_MIFARE:
+                       card_base64 = base64.b64encode(cardId)
 
-               # Check for thier username
-               try:
-                       # Get info from 
-                       info = pwd.getpwuid(userId)
-               except KeyError:
-                       logging.info('getting pin for uid %d: user not in password file'%uid)
-                       return False
+                       if card_base64 in CARD_BLACKLIST:
+                               logging.info("Blacklisted card base64:%s" % (card_base64,))
+                               return False
+                       
+                       sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
+                       sock.connect(DISPENSE_ENDPOINT)
+                       logging.debug('connected to dispsrv')
+                       sockf = sock.makefile()
+                       sockf.write("AUTHIDENT\n"); sockf.flush()
+                       rsp = sockf.readline()
+                       assert "200" in rsp
+                       logging.debug('authenticated')
+                       sockf.write("AUTHCARD %s\n" % (card_base64,)); sockf.flush()
+                       rsp = sockf.readline()
+                       if not "200" in rsp:
+                               logging.info("Rejected card base64:%s" % (card_base64,))
+                               return False
+                       username = rsp.split('=')[1].strip()
+                       logging.info("Accepted card base64:%s for %s" % (card_base64,username,))
+
+                       ## Check for thier username
+                       #try:
+                       #       # Get info from the system (by username)
+                       #       info = pwd.getpwnam(username)
+                       #except KeyError:
+                       #       logging.info('getting info for user \'%s\': user not in password file' % (username,))
+                       #       return False
+                       #self._userid = info.pw_uid
+                       self._userid = None
+                       self._username = username
+               else:
+                       # Get the users ID
+                       self._userid = get_uid(cardId)
+
+                       # Check for thier username
+                       try:
+                               # Get info from the system (by UID)
+                               info = pwd.getpwuid(self._userid)
+                       except KeyError:
+                               logging.info('getting info for uid %d: user not in password file' % (self._userid,))
+                               return False
+                       self._username = info.pw_name
 
                # If we get this far all is good
                self._loggedIn = True
                self._disabled = False
-               self._username = info.pw_name
                return True
 
+        def logOut(self):
+            self._loggedIn = False
+            self._disabled = False
+            self._userId = None
+            self._username = None
+
        def addCard(self, cardId):
-               if self.isLoggedIn():
-                       set_card_id(self._userId, cardId)
-               return True
+               if not self.isLoggedIn():
+                       return False
+               if DISPSRV_MIFARE:
+                       card_base64 = base64.b64encode(cardId)
+                       if card_base64 in CARD_BLACKLIST:
+                               logging.info("Blacklisted card base64:%s" % (card_base64,))
+                               return False
+                       logging.info('Enrolling card base64:%s to uid %s (%s)' % (card_base64, self._userId, self._username))
+                       sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
+                       sock.connect(DISPENSE_ENDPOINT)
+                       sockf = sock.makefile()
+                       sockf.write("AUTHIDENT\n")
+                       sockf.flush(); rsp = sockf.readline()
+                       assert "200" in rsp
+                       sockf.write("SETEUSER %s\n" % (self._username,))
+                       sockf.flush(); rsp = sockf.readline()
+                       assert "200" in rsp
+                       sockf.write("CARD_ADD %s\n" % (card_base64,))
+                       sockf.flush(); rsp = sockf.readline()
+                       if "200" in rsp:
+                               return True
+                       else:
+                               return False
+               else:
+                       if get_uid(cardId) != None:
+                               return False
+                       else:
+                               logging.info('Enrolling card %s to uid %s (%s)' % (cardId, self._userId, self._username))
+                               set_card_id(self._userId, cardId)
+                               return True
 
        def isLoggedIn(self):
                return self._loggedIn
@@ -105,6 +221,7 @@ class OpenDispense(DispenseInterface):
                return balance
 
        def getItemInfo(self, itemId):
+               logging.debug("getItemInfo(%s)" % (itemId,))
                itemId = OpenDispenseMapping.vendingMachineToOpenDispense(itemId)
                args = ('dispense', 'iteminfo', itemId)
                info, unused = Popen(args, close_fds=True, stdout=PIPE).communicate()
@@ -141,8 +258,20 @@ class OpenDispenseMapping():
 
        @staticmethod
        def vendingMachineToOpenDispense(itemId):
+               logging.debug("vendingMachineToOpenDispense(%s)" % (itemId,))
                _mappingFile = "OpenDispenseMappings.conf"
-               fh = open(_mappingFile)
+               try:
+                       fh = open(_mappingFile)
+               except IOError:
+                       if itemId[1] == '8':
+                               return 'coke:' + itemId[0]
+                       elif itemId[1] == '5':
+                               if itemId[0] == '5':
+                                       return 'door'
+                               else:
+                                       return None
+                       else:
+                               return 'snack:' + itemId
                map = ""
                for line in fh:
                        #line = line.strip()
@@ -151,3 +280,5 @@ class OpenDispenseMapping():
                                print(map)
                return map
 
+
+# vim: noexpandtab ts=4 sw=4

UCC git Repository :: git.ucc.asn.au