def SetAlias(self): # Get the new name entered by the user newName = self.ui.NewNameTextBox.text() # If a name is entered: if newName != "": # If the alias already exists: if newName in Connection().knownDevices.keys(): # Display a warning message QMessageBox.warning( self, "Error", "Alias already exists, please enter a unique device alias", QMessageBox.Ok, ) # If the alias does not exist: else: # Get the device IMEI and remove the current alias from the dictionary IMEI = Connection().knownDevices.pop(self.target) # Add the new alias to the dictionary Connection().knownDevices[newName] = IMEI # Return the QDialog.Accepted value and close the dialog window self.accept() # If a name is not entered: else: # Display a warning message QMessageBox.warning(self, "Error", "Please enter device alias", QMessageBox.Ok)
def HandleSetRequest(self, commands): # Save the target device IMEI targetIMEI = commands.pop(0) # Save the request request = commands.pop(0) # Save the value value = commands.pop(0) # Send a SET request to the device and save the response response = Connection().SendSetRequest(targetIMEI, request, value) # Send the response to the admin application Connection().SendMessage(self.socket, str.encode(response))
def SetSpeedLimit(self, target, speedLimit): # Send the "SET <Target device IMEI> speed <Speed limit>" request message Connection().SendMessage(str.encode("SET " + target + " speed " + speedLimit)) # Receive the server response message response = self.WaitForData() # Return the response return response
def GetDeviceDetails(self, target): # Send the "GET details <IMEI>" request message Connection().SendMessage(str.encode("GET details " + target)) # Receive the device details message details = self.WaitForData() # Return the details message return details
def ListenToUser(self): # Run until the connection is closed while True: # Receive message from the admin application data = Connection().ReceiveMessage(self.socket) print(data) # If the connection was closed: if data == None: print("Closing thread...") # Close the socket self.socket.close() # End the infinite loop (close the thread) return else: # Handle the received request self.HandleUserRequest(data.decode("utf-8"))
def Exit(self): # Save all new and previous device aliases to the file self.SaveKnownDevices() # Close the connection Connection().Close() # Close the GUI window self.close()
def SetWarning(self, target, request): # Send the "SET <Target device IMEI> warning <Warning sign>" request message Connection().SendMessage(str.encode("SET " + target + " warning " + request)) # Recieve the server response message response = self.WaitForData() # Return the response return response
def GetDevices(self): # Send the "GET devices" request message Connection().SendMessage(str.encode("GET devices")) # Receive the number of available devices deviceLen = self.WaitForData() if(deviceLen == "nocon" or deviceLen == "timeout"): return None # Clear the device list Connection().deviceList.clear() if deviceLen: # Receive all available devices for i in range(int(deviceLen)): # Receive the device IMEI device = self.WaitForData() # Add it to the device list Connection().deviceList.append(device) return 'ok'
def WaitForData(self): # Wait for incoming data on the socket; timeout after 9 seconds ready = select.select([Connection().client_socket], [], [], 15) if ready[0]: try: # Read the available message data = Connection().ReceiveMessage().decode("utf-8") # Return the received message return data except: print("Lost connection to the server") # Return connection loss error return "nocon" else: print("Connection timeout") # Return timeout error return "timeout"
def GenerateDeviceList(self): displayList = [] # Loop through every device in the list for device in Connection().deviceList: # If the device is new and the IMEI is unknown: if device not in Connection().knownDevices.values(): # Add it to the list of known devices Connection( ).knownDevices[device] = device # Alias == IMEI (initially) # Find the device alias from its IMEI and add it to the list # (Search dictionary by value) displayList.append( list(Connection().knownDevices.keys())[list( Connection().knownDevices.values()).index(device)]) # Return the updated display list return displayList
def WaitForLogin(self, adminSocket, adminAddress): maxLoginAttempts = 5 # Maximum login attempts before the connection is closed loginAttemptCount = 1 # Current login attempt while True: # Check if the username and password are correct and save the return code returnCode = self.AuthenticateUser(adminSocket, adminAddress) # Username or password incorrect: if returnCode == 0: # Increment login attempt count loginAttemptCount += 1 # If the attempts exceeded the maximum: if loginAttemptCount > maxLoginAttempts: print("Too many login attempts, closing connection...") # Send a refuse message to the client Connection().SendMessage(adminSocket, b"refuse") # Close the socket adminSocket.close() return False else: # Send a no authentication (nauth) message to the client Connection().SendMessage(adminSocket, b"nauth") # Username and password correct: elif returnCode == 1: print("Authenticated") # Send an authentication (auth) message to the client Connection().SendMessage(adminSocket, b"auth") # Create a data exchange thread for the connection adminThread = AdminAppDataExchange(adminSocket) # Start the thread adminThread.start() return True # Connection closed by client: elif returnCode == 2: print("Connection closed by remote client") return False # Something went wrong: else: # Close the socket adminSocket.close() return False
def AttemptConnect(self): try: # Attempt to connect the socket to the given address and port Connection().client_socket.connect((self.serverAddress, self.serverPort)) print("Connection successful") # Return True if the connection was successful return True except: print("Connection to server unsuccessful") # Return False if an error occurred and the connection was unsuccessful return False
def ShowDetailsDialog(self): # Get the device currently selected by the user selectedDevice = self.GetSelectedDevice() # If a device is selected: if selectedDevice: # Get the IMEI for the alias from the knownDevices dictionary IMEI = Connection().knownDevices[selectedDevice] # Request details for the selected device incoming = self.dataExchange.GetDeviceDetails(IMEI) # If there is a problem with the server connection: if incoming == "nocon" or incoming == "timeout": # Display an error message QMessageBox.critical( self, "Error", "Lost connection to the web server, closing...", QMessageBox.Ok, ) # Exit the application self.Exit() # If there is a problem with the device connection: elif incoming == "nosend": # Display a warning message QMessageBox.warning(self, "Error", "Couldn't send message to device", QMessageBox.Ok) elif incoming == "notfound": # Display a warning message QMessageBox.warning(self, "Error", "Requested device not found", QMessageBox.Ok) elif incoming == "noresp": # Display a warning message QMessageBox.warning(self, "Error", "Device didn't respond", QMessageBox.Ok) else: # Split the response into separate items details = incoming.split(" ") # Convert the status to a human-readable message status = self.ConvertStatus(details[0]) # Convert the value to a human-readable message value = self.ConvertValue(details[1]) # Create a DetailsDialog() object self.detailsDialog = DetailsDialog(selectedDevice, IMEI, status, value) # Display the dialog self.detailsDialog.exec_() return True # If a device is not selected: else: # Do nothing pass
def SaveKnownDevices(self): # Open the DeviceAliases.yaml file as a writeable stream with open("./GUI_logic/DeviceAliases.yaml", "w", encoding="utf-8") as outfile: # Dump the contents of the knownDevices dictionary to the file in utf-8 format yaml.dump( Connection().knownDevices, # Known devices dictionary outfile, # Output stream default_flow_style=False, # Save collection in block style allow_unicode= True, # Save characters in unicode instead of binary )
def HandleGetRequest(self, request): # "GET devices" request if request[0] == "devices": # Calculate the amount of available devices devicesLength = len(Connection().deviceList) # Send the device length to the admin application Connection().SendMessage( self.socket, str.encode(str(devicesLength), encoding="utf-8")) # Send the IMEI of every available device to the admin application for i in Connection().deviceList: Connection().SendMessage(self.socket, str.encode(str(i), encoding="utf-8")) return # "GET details <IMEI>" request elif request[0] == "details": # Save the target device IMEI targetIMEI = request[1] # Send a "GET dtl" request to the appropriate device details = Connection().SendGetRequest(targetIMEI, "dtl") # If the device is unavailable: if not details: # Generate error details = b"error" # Send the details to the admin application Connection().SendMessage(self.socket, details) # Request unknown: else: # Do nothing print("Unknown request") return
def AuthenticateUser(self, adminSocket, adminAddress): # Receive a username from the client username = Connection().ReceiveMessage(adminSocket) if username == None: return 2 # Connection closed by client code # Receive a password from the client password = Connection().ReceiveMessage(adminSocket) # Decode the username and password to utf-8 format username = username.decode("utf-8") password = password.decode("utf-8") # If the username does not exist: if username not in self.users: print("Username not found") return 0 # Username or password incorrect code # Load the salt and password hash of the given user salt = self.users[username]["salt"] knownHash = self.users[username]["password"] # Generate a new hash with the client's password newHash = self.GetPasswordHash(password, salt) # If the hashes are the same: if newHash == knownHash: # Authorize user print("Client at ", adminAddress, " authorized") return 1 # Username and password correct code else: # Do not authorize user print("Client at ", adminAddress, " not authorized") return 0 # Username or password incorrect code
def AttemptLogin(self, username, password): print("Attempting to log in...") try: # Attempt to send the username Connection().SendMessage(str.encode(username)) except: # Return None if an error occurred return None try: # Attempt to send the password Connection().SendMessage(str.encode(password)) except: # Return None if an error occurred return None # Wait for a response from the web server data = self.WaitForData() if not data: # If no response is received, close the connection Connection().Close() else: # Return the response return data
def LoadKnownDevices(self): # Open the DeviceAliases.yaml file as a readable stream with open("./GUI_logic/DeviceAliases.yaml", "r") as stream: try: # Convert the contents of the file to a python object loaded = yaml.safe_load(stream) # Add every loaded entry to the knownDevices dictionary for key, value in loaded.items(): Connection().knownDevices[key] = value # File loading failed except yaml.YAMLError as exc: print(exc)
def AddDevice(self, socket): # Receive the device's IMEI incoming = socket.recv(22) # Split the received data for easier manipulation data = incoming.decode("utf-8").split(" ") # If the IMEI was received correctly: if data[0] == "IMEI:" and len(data) > 1: # Add the socket to the deviceList dictionary # (key == IMEI, value == socket) Connection().deviceList[data[1]] = socket print("Success") # If the IMEI was not received correctly: else: print("Something went wrong")
def SetWarning(self): # Call the SetWarning() method and save the response response = self.dataExchange.SetWarning( Connection().knownDevices[self.target], self.currentSelection) # Handle the received response result = self.HandleResponse(response) # If the response was valid: if result != None: # Return the QDialog.Accepted value and close the dialog window self.accept() # If the response was not valid: else: # Return the QDialog.Rejected value and close the dialog window self.reject()
def keyPressEvent(self, event): # If [ESC] is clicked -> close the window if event.key() == Qt.Key_Escape: try: # Close the connection, if available Connection().Close() except: pass # Return the QDialog.Rejected value and close the dialog window self.reject() # If [ENTER] is clicked -> attempt to connect if event.key() == Qt.Key_Enter: # Try to connect/login to the server self.ConnectClick()
def SetSpeedLimit(self): # Get the speed limit value entered by the user speedLimit = self.ui.SpeedLimitTextBox.text() # If a name is not entered: if speedLimit == "": # Display a warning message QMessageBox.warning(self, "Error", "Please input speed limit", QMessageBox.Ok) # If a name is entered: else: # Call the SetSpeedLimit() method and save the response response = self.dataExchange.SetSpeedLimit( Connection().knownDevices[self.target], speedLimit) # Handle the received response result = self.HandleResponse(response) # If the response was valid: if result != None: # Return the QDialog.Accepted value and close the dialog window self.accept() # If the response was not valid: else: # Return the QDialog.Rejected value and close the dialog window self.reject()