def test_deleteSL(self): createTablesBig() stdoutFile = pref.getNoCheck( pref.CONFIG_SCRIPT_LOG_PATH) + "STDOUT_test_script_name_3.log" stderrFile = pref.getNoCheck( pref.CONFIG_SCRIPT_LOG_PATH) + "STDERR_test_script_name_3.log" open(stdoutFile, "a") # create files to be deleted open(stderrFile, "a") # create files to be deleted existsBefore1 = path.exists(stdoutFile) existsBefore2 = path.exists(stderrFile) err = tosl.ScriptLogTable().delete(3) errExp = pref.getError(pref.ERROR_SUCCESS) err2, sl = tosl.ScriptLogTable.getByID(3) errExp2 = pref.getError(pref.ERROR_SQL_RETURN_MISSING_ATTR, args=("getByID", "ScriptLog", 0, 11)) existsAfter1 = path.exists(stdoutFile) existsAfter2 = path.exists(stderrFile) self.assertEqual(existsBefore1, True) self.assertEqual(existsBefore2, True) self.assertEqual(err, errExp) self.assertEqual(err2, errExp2) self.assertEqual(existsAfter1, False) self.assertEqual(existsAfter2, False) self.assertEqual(sl, None) open(stdoutFile, "a") # recreate deleted files open(stderrFile, "a")
def login(data: dict) -> str: ''' This function is to handle the act of logging into the users account. @param dict data, the dictonary of the users input data @return a json of the error code ''' #makesure the prefs contain a username and password try: username = data[pref.getNoCheck(pref.LOGIN_USERNAME)] password = hashlib.sha256(data[pref.getNoCheck(pref.LOGIN_PASSWORD)].encode()).hexdigest() except: return jsonify(Error = pref.getError(pref.ERROR_ATTRIBUTE_NOT_FOUND).toJson()) if " " in username or ";" in username: return jsonify(Error = pref.getError(pref.ERROR_USERNAME_INVALID).toJson()) userID = tableLogin.UserTable.checkLogin(username=username, password=password) # ErrorCode = None if userID != -1: ErrorCode = pref.Success session["userID"] = userID else: ErrorCode = pref.getError(pref.ERROR_USER_AUTHENTICATION_ERROR, args=(username)) return jsonify( Error = ErrorCode.toJson() )
def test_addEntrySL(self): createEmptyTables() # need user entry first for foreign key u = tou.UserTable().createEntry("rbroders", "hella_secure_hashed_password", True) err = tou.UserTable().add(u) # uID will be 1 # need script entry for foreign key s = tos.ScriptTable().createEntry("test_script_name", "test_script_name.sh", 1, "emptry script used for testing", False) err = tos.ScriptTable().add(s) # need computer entry for foreign key c = toc.ComputerTable().createEntry( 1, "RachelsSurface", "Raquels Computer", "Rachel's wonderful awful computer", "rbroders", "idk how IPs are formatted ya yeet", False) err = toc.ComputerTable().add(c) # scriptLog entry sl = tosl.ScriptLogTable().createEntry(1, 1, 1, False) err = tosl.ScriptLogTable().add(sl) errExp = pref.getError(pref.ERROR_SUCCESS) # check stdout/stderr file creation outPath = pref.getNoCheck(pref.CONFIG_SCRIPT_LOG_PATH) + sl.stdoutFile errPath = pref.getNoCheck(pref.CONFIG_SCRIPT_LOG_PATH) + sl.stderrFile self.assertEqual(os.path.exists(outPath), True) self.assertEqual(os.path.exists(errPath), True) # check error and scriptlog ID self.assertEqual(err, errExp) self.assertEqual(sl.ID, 1)
def apiRequest(): ''' API Request /api used for all operations between frontend and backend ie RUN_SCRIPT MANAGE_SCRIPT MANAGE_COMPUTERS MANAGE_SCRIPT_LOGS SCHEDULE_SCRIPT GET_FILE request: { op: <operation:string> data: <opData:dict> } return: { Error: } ''' logger.info("api request: {}".format(request.json)) # if not("userID" in session): # session.pop("userID", None) #Makes sure user is logged in if not redirect to login userID = None try: userID = session[pref.getNoCheck(pref.REQ_VAR_USER_ID)] except: return redirect(pref.getNoCheck("/#/")) err = pref.Success #names of request vars bodyName = pref.getNoCheck(pref.REQ_VAR_BODY) dataName = pref.getNoCheck(pref.REQ_VAR_DATA) jsonOpName = pref.getNoCheck(pref.REQ_VAR_OP) try: opName = pref.CONFIG_OPERATIONS + ":" + request.json[bodyName][ jsonOpName] data = request.json[bodyName][dataName] except: err = pref.getError(pref.ERROR_INVALID_REQUEST, args=(request.json)) logger.error(err) returnValue = None if (err == pref.Success): err, op = pref.get(opName) if (err == pref.Success): apiFtn = OPS[op] returnValue = apiFtn(data) else: logger.error(err) returnValue = jsonify(Error=err.toJson(), data={}) return (returnValue, 200)
def add(entry: ScriptLog): ''' Takes a scriptLog object (which has not yet been added to the scriptLog SQL table), adds it to the table and updates scriptLog object's ID (ID is automatically generated using sqlite AUTOINCREMENT) This function is meant to take a scriptLog object generated from a call to the createEntry function. @param entry - object of class ScriptLog @return e - most recent error when executing function or Success if no error occurs ''' ID = None command = """ INSERT INTO sl (id, scriptID, userID, compID, startTime, endTime, returnVal, errorCode, stdoutFile, stderrFile, asAdmin) VALUES (NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""" data = entry.paramToList() e, ID = sqlFuncs.insert(command, data, "add", "ScriptLog") entry.ID = ID # access ID through entry object after executing this function ######### create names/files for stdoutFile, stderrFile - {STDOUT/STDERR}_SCRIPT_ID.log ######### # (1) Add names to entry object if (e == pref.getError(pref.ERROR_SUCCESS)): e, scriptName = tos.ScriptTable().getAttrByID( "name", entry.scriptID) if e == pref.getError(pref.ERROR_SUCCESS): entry.stdoutFile = "STDOUT_" + str(scriptName) + "_" + str( ID ) + ".log" # access stdoutFile through entry object after executing this function entry.stderrFile = "STDERR_" + str(scriptName) + "_" + str( ID ) + ".log" # access stderrFile through entry object after executing this function # (2) Write names to sql entry command2 = """UPDATE sl SET stdoutFile = \"""" + str( entry.stdoutFile) + """\", stderrFile = \"""" + str( entry.stderrFile) + """\" WHERE id = """ + str( ID) + """;""" e = sqlFuncs.exeCommand(command2, "add", "ScriptLog") # (3) Create files if (e == pref.getError(pref.ERROR_SUCCESS)): e = createFile( e, pref.getNoCheck(pref.CONFIG_SCRIPT_LOG_PATH), entry.stdoutFile) if (e == pref.getError(pref.ERROR_SUCCESS)): e = createFile( e, pref.getNoCheck(pref.CONFIG_SCRIPT_LOG_PATH), entry.stderrFile) if ( e != pref.getError(pref.ERROR_SUCCESS) ): # if any errors occured along the way, revert any potential changes (catch all) entry.stdoutFile = None entry.stderrFile = None return e #FIXME - should actions be undone if any errors occur along the way *thinking* - for loop
def test_setConfigFileComplex(self): err = pref.setConfigFile("tests/res/test2Conf.yaml") self.assertEqual(err.code, pref.Success.code) self.assertEqual("null", pref.getError(pref.ERROR_UNKNOWN)) self.assertEqual("/test", pref.getNoCheck(pref.CONFIG_LOGIN_ENDPOINT))
def getAllRows(command: str, commandName: str, tableName:type): ''' Executes a select command for a single row in the SQL database. Requires no extra data and returns the selected row. @param command - SQL command as a string commandName - name of the function calling exeCommand. Used for error creation. tableName - name of the table command is being executed. Used for error creation. In full word form i.e. script, not s. @return row - tuple for row selected. ''' e = pref.getError(pref.ERROR_SUCCESS) rows = None try: # attempt to create connection con = sqlite3.connect(pref.getNoCheck(pref.CONFIG_DB_PATH)) con.execute('PRAGMA foreign_keys = 1') #enable foreign keys try: # attempt to do select command and get row cur = con.cursor() cur.execute(command) rows = cur.fetchall() cur.close() except Error as err: # select failed e = pref.getError(pref.ERROR_EXECUTE_SQLITE3_COMMAND, args=(commandName, tableName, err)) # return error with specific info con.commit() con.close() except Error as err: # connection creation failed e = pref.getError(pref.ERROR_CREATE_SQLITE3_CONNECTION, args = (command, tableName, err)) # return error with specific info return e, rows
def exeCommand(command: str, commandName: str, tableName:type): ''' Executes a command in the SQL database which requires no extra data passed to the call and expects no return. @param command - SQL command as a string commandName - name of the function calling exeCommand. Used for error creation. tableName - name of the table command is being executed. Used for error creation. In full word form i.e. script, not s. @return None. ''' e = pref.getError(pref.ERROR_SUCCESS) try: # attempt to create connection con = sqlite3.connect(pref.getNoCheck(pref.CONFIG_DB_PATH)) con.execute('PRAGMA foreign_keys = 1') #enable foreign keys try: # attempt to execute some command cur = con.cursor() cur.execute(command) con.commit() except Error as err: # command execution failed e = pref.getError(pref.ERROR_EXECUTE_SQLITE3_COMMAND, args=(commandName, tableName, err)) # return error with specific info con.close() except Error as err: # connection creation failed e = pref.getError(pref.ERROR_CREATE_SQLITE3_CONNECTION, args = (command, tableName, err)) # return error with specific info return e
def delete(ID: int): ''' Removes a scriptLog entry from the database based on it's ID. Also removes the corresponding files (stdout/stderr) from directory. @param ID: int - primary key of scriptLog @return e - most recent error when executing function or Success if no error occurs ''' e, stdoutFile = ScriptLogTable.getAttrByID("stdoutFile", ID) e, stderrFile = ScriptLogTable.getAttrByID("stderrFile", ID) if (e == pref.getError(pref.ERROR_SUCCESS)): command = """DELETE FROM sl WHERE ID = """ + str(ID) + """;""" e = sqlFuncs.exeCommand(command, "delete", "ScriptLog") if ( e == pref.getError(pref.ERROR_SUCCESS) ): # If deleted from db successfully, remove corresponding stdout/stderr files path = pref.getNoCheck(pref.CONFIG_SCRIPT_LOG_PATH) try: os.remove(path + stdoutFile) os.remove(path + stderrFile) except OSError as err: e = pref.getError(pref.ERROR_FILE_NOT_FOUND, args=(str(stdoutFile) + "/" + str(stderrFile))) return e
def createEntry(name: str, fileName: str, author: int, desc: str, isAdmin: bool): ''' Creates a script object. Some parameters must be passed in, some will be calculated in this function and some can only be filled when the script is added to the SQL table (these parameters will be set to None until the script is added to the SQL table). @param name: str - use defined name to identify file fileName: str - identifying fileName author: int - primary key of user table to indicate which user created the script desc: str - user defined script description isAdmin: bool - whether or not the script requires admin access to run @return script - script object created ''' script = None # id will be set when object is added to table id = None # set dtCreated dtCreated = dt.now() # set dtModified (will be same as dtCreated initially) dtModified = dtCreated # set size filePath = str(pref.getNoCheck(pref.CONFIG_SCRIPT_PATH)) + fileName try: fileStats = os.stat(filePath) fileSizeB = fileStats.st_size except OSError as err: fileSizeB = 0.0 # set size to zero script file does not exist # create script object script = Script(None, name, fileName, author, desc, dtCreated, dtModified, fileSizeB, isAdmin) return script
def mockApp() -> app.test_client_class: pref.setAttr(pref.CONFIG_SCRIPT_PATH, "tests/res/data/scripts/") pref.setAttr(pref.CONFIG_SCRIPT_LOG_PATH, "tests/res/data/scriptLogs/") c = app.test_client() with c.session_transaction() as sess: sess[pref.getNoCheck(pref.REQ_VAR_USER_ID)] = 1 return c
def manageComputers(data: dict) -> str: logger.info("Processing Manage Computer Request") #Get vars names tableName = pref.getNoCheck(pref.TABLE_COMPUTER) #Convert to general request jsonData = manageTable(tableName, data) return jsonData
def manageScripts(data: dict) -> str: logger.info("Processing Manage Script Request") #Get vars names tableName = pref.getNoCheck(pref.TABLE_SCRIPT) #Convert to general request jsonData = manageTable(tableName, data) return jsonData
def manageTable(tableName: str, data: dict): err = pref.Success opName = pref.getNoCheck(pref.REQ_VAR_FUNC_OP) op = None opDataName = pref.getNoCheck(pref.REQ_VAR_DATA) opData = None #gets data from dict try: opData = data[opDataName] op = data[opName] except: err = pref.getError(pref.ERROR_INVALID_REQUEST, args=(data)) logger.error(err) if (err == pref.Success): jsonData = tableReqHelpers.processRequest(tableName, op, opData) else: jsonData = jsonify(Error=err.toJson()) return jsonData
def test_deleteS2(self): createTablesBig() open( pref.getNoCheck(pref.CONFIG_SCRIPT_PATH) + "sleepScript copy.sh", "a") # create file to be deleted existsBefore = path.exists( pref.getNoCheck(pref.CONFIG_SCRIPT_PATH) + "sleepScript copy.sh") err = tos.ScriptTable().delete(4) errExp = pref.getError(pref.ERROR_SUCCESS) err2, s = tos.ScriptTable.getByID(4) errExp2 = pref.getError(pref.ERROR_SQL_RETURN_MISSING_ATTR, args=("getByID", "Script", 0, 9)) existsAfter = path.exists( pref.getNoCheck(pref.CONFIG_SCRIPT_PATH) + "sleepScript copy.sh") self.assertEqual(existsBefore, True) self.assertEqual(err, errExp) self.assertEqual(err2, errExp2) self.assertEqual(existsAfter, False) self.assertEqual(s, None) open( pref.getNoCheck(pref.CONFIG_SCRIPT_PATH) + "sleepScript copy.sh", "a") # recreate deleted file
def loginRequest(): logger.info("login request") #names of request vars bodyName = pref.getNoCheck(pref.REQ_VAR_BODY) dataName = pref.getNoCheck(pref.REQ_VAR_DATA) jsonOpName = pref.getNoCheck(pref.REQ_VAR_OP) opName = pref.CONFIG_LOGIN_OPERATION + ":" + request.json[bodyName][ jsonOpName] data = request.json[bodyName][dataName] returnValue = None err, op = pref.get(opName) if (err == pref.Success): loginFtn = LOGIN_OPS[op] returnValue = loginFtn(data) else: logger.error(err) returnValue = jsonify(Error=err.toJson(), data={}) return (returnValue, 200)
def test_api_getall_scriptLogs(self): ''' Tests get all for scriptLogs ''' params = { pref.getNoCheck(pref.REQ_VAR_BODY): { pref.getNoCheck(pref.REQ_VAR_OP): pref.getAttrName( pref.getNoCheck(pref.OPERATION_MANAGE_SCRIPT_LOGS)), pref.getNoCheck(pref.REQ_VAR_DATA): { pref.getNoCheck(pref.REQ_VAR_FUNC_OP): pref.getNoCheck(pref.TABLE_OP_GET_ALL), pref.getNoCheck(pref.REQ_VAR_DATA): {} } } } rv = self.c.post('/api', json=params) self.assertEqual(rv.get_json()["Error"]["code"], 0)
def test_get_by_ID(self): ''' Tests get by id for an object that exists ''' params = { pref.getNoCheck(pref.REQ_VAR_BODY): { pref.getNoCheck(pref.REQ_VAR_OP): pref.getAttrName(pref.getNoCheck( pref.OPERATION_MANAGE_SCRIPT)), pref.getNoCheck(pref.REQ_VAR_DATA): { pref.getNoCheck(pref.REQ_VAR_FUNC_OP): pref.getNoCheck(pref.TABLE_OP_GET_BY_ID), pref.getNoCheck(pref.REQ_VAR_DATA): { pref.getNoCheck(pref.REQ_VAR_ID): 1, } } } } rv = self.c.post("/api", json=params) self.assertEqual(rv.get_json()["Error"]["code"], 0) self.assertEqual(rv.get_json()["entry"]["ID"], '1')
def test_get_by_ID_DNE(self): ''' Tests get by id for an object that doesnt exist ''' params = { pref.getNoCheck(pref.REQ_VAR_BODY): { pref.getNoCheck(pref.REQ_VAR_OP): pref.getAttrName(pref.getNoCheck( pref.OPERATION_MANAGE_SCRIPT)), pref.getNoCheck(pref.REQ_VAR_DATA): { pref.getNoCheck(pref.REQ_VAR_FUNC_OP): pref.getNoCheck(pref.TABLE_OP_GET_BY_ID), pref.getNoCheck(pref.REQ_VAR_DATA): { pref.getNoCheck(pref.REQ_VAR_ID): 99, } } } } rv = self.c.post("/api", json=params) self.assertEqual( rv.get_json()["Error"]["code"], pref.getError(pref.ERROR_SQL_RETURN_MISSING_ATTR).code)
def insert(command: str, data: tuple, commandName: str, tableName:type): ''' Executes an insert command in the SQL database which requires extra data and returns the automatically generated primary key ID. @param command - SQL command as a string data - tuple of data being inserted that is not NULL commandName - name of the function calling exeCommand. Used for error creation. tableName - name of the table command is being executed. Used for error creation. In full word form i.e. script, not s. @return ret : int - ID assigned to inserted row ''' e = pref.getError(pref.ERROR_SUCCESS) ret = None try: # attempt to create connection con = sqlite3.connect(pref.getNoCheck(pref.CONFIG_DB_PATH)) con.execute('PRAGMA foreign_keys = 1') #enable foreign keys try: # attempt to execute insert command cur = con.cursor() cur.execute(command, data) except Error as err: # command execution failed e = pref.getError(pref.ERROR_EXECUTE_SQLITE3_COMMAND, args=(commandName, tableName, err)) # return error with specific info try: # attempt to get return data command2 = """SELECT last_insert_rowid();""" cur.execute(command2) row = cur.fetchone() if row != None: ret = row[0] cur.close() except Error as err: # return gathering failed e = pref.getError(pref.ERROR_EXECUTE_SQLITE3_COMMAND, args=(commandName, tableName, err)) # return error with specific info con.commit() con.close() except Error as err: # connection creation failed e = pref.getError(pref.ERROR_CREATE_SQLITE3_CONNECTION, args = (command, tableName, err)) # return error with specific info return e, ret
def test_login_request_success(self): ''' Tests a login request with a valid login ''' params = { pref.getNoCheck(pref.REQ_VAR_BODY): { pref.getNoCheck(pref.REQ_VAR_OP): pref.getAttrName(pref.getNoCheck(pref.LOGIN_LOGIN)), pref.getNoCheck(pref.REQ_VAR_DATA): { pref.getNoCheck(pref.LOGIN_USERNAME): "unittest", pref.getNoCheck(pref.LOGIN_PASSWORD): "unittest" } } } rv = self.c.post('/login', json=params) self.assertEqual(rv.get_json()["Error"]["code"], 0)
def test_api_runScript(self): ''' Tests runScript from and endpoint perpective ''' params = { pref.getNoCheck(pref.REQ_VAR_BODY): { pref.getNoCheck(pref.REQ_VAR_OP): pref.getNoCheck(pref.OPERATION_RUN_SCRIPT), pref.getNoCheck(pref.REQ_VAR_DATA): { pref.getNoCheck(pref.REQ_VAR_SCRIPT_ID): 1, pref.getNoCheck(pref.REQ_VAR_COMPUTER_ID): 1, } } } rv = self.c.post('/api', json=params) expected = {"Error": pref.Success.toJson(), "Id": 1} print(rv.get_json()) self.assertEqual(rv.get_json(), expected)
def test_login_request_fail(self): ''' Tests a login request with a invalid login due to invalid password ''' params = { pref.getNoCheck(pref.REQ_VAR_BODY): { pref.getNoCheck(pref.REQ_VAR_OP): pref.getAttrName(pref.getNoCheck(pref.LOGIN_LOGIN)), pref.getNoCheck(pref.REQ_VAR_DATA): { pref.getNoCheck(pref.LOGIN_USERNAME): "unittest", pref.getNoCheck(pref.LOGIN_PASSWORD): "IncorrectPassword" } } } rv = self.c.post('/login', json=params) self.assertEqual( rv.get_json()["Error"]["code"], pref.getError(pref.ERROR_USER_AUTHENTICATION_ERROR).code)
def processRequest(tableName: pref.prefENUM, tableOP: pref.prefENUM, data: dict): ''' Completes a table request @param tableName the name of the table from preferences ie pref.TABLE_COMPUTER, pref.TABLE_SCRIPT, pref.TABLE_SCRIPT_LOGS @param tableOp the operation of the script pref.TABLE_OP_GET_BY_ID, pref.TABLE_OP_ADD .... @param data request data from the tableOP @return jsonfiy value contiaining error and data ''' #table classes dictionary linked to the preference value tableClasses = { pref.getNoCheck(pref.TABLE_SCRIPT): scriptTable.ScriptTable, pref.getNoCheck(pref.TABLE_SCRIPT_LOGS): scriptLogTable.ScriptLogTable, pref.getNoCheck(pref.TABLE_COMPUTER): computerTable.ComputerTable, } table = tableClasses[tableName] #Return value err = pref.Success returnVal = None #get file if (tableOP == pref.getNoCheck(pref.TABLE_OP_GET_FILE)): err = pref.Success #Gets id id = None Filetype = None FP = None try: id = data[pref.getNoCheck(pref.REQ_VAR_ID)] Filetype = data[pref.getNoCheck(pref.REQ_VAR_FILE_TYPE)] FP = data[pref.getNoCheck(pref.REQ_VAR_FP)] except: #Invalid request err = pref.getError(pref.ERROR_INVALID_REQUEST, args=(data)) logger.error(err) #gets the element by id err, entry = table.getByID(id) if (err == pref.Success): #get file file if (Filetype == pref.getNoCheck(pref.REQ_VAR_FILE_STDOUT)): scriptPath = pref.getNoCheck(pref.CONFIG_SCRIPT_LOG_PATH) filename = scriptPath + entry.stdoutFile elif (Filetype == pref.getNoCheck(pref.REQ_VAR_FILE_STDERR)): scriptPath = pref.getNoCheck(pref.CONFIG_SCRIPT_LOG_PATH) filename = scriptPath + entry.stderrFile elif (Filetype == pref.getNoCheck(pref.REQ_VAR_FILE_SCRIPT)): scriptPath = pref.getNoCheck(pref.CONFIG_SCRIPT_PATH) filename = scriptPath + entry.fileName fp = open(filename, "r") fp.seek(FP, os.SEEK_SET) fileData = "".join(fp.readlines()) newFP = fp.tell() returnVal = jsonify(Error=err.toJson(), entry=fileData, FP=newFP) #add to table elif (tableOP == pref.getNoCheck(pref.TABLE_OP_ADD)): err, entry = createObjFromReq(tableName, table, data) #Computer only used to add ssh key to computer if (err == pref.Success and tableName == pref.getNoCheck(pref.TABLE_COMPUTER)): try: username = data[pref.getNoCheck(pref.REQ_VAR_USERNAME)] password = data[pref.getNoCheck(pref.REQ_VAR_PASSWORD)] IP = data[pref.getNoCheck(pref.REQ_VAR_IP)] except: err = pref.getError(pref.ERROR_INVALID_REQUEST, args=(data)) logger.error(err) #Add ssh key to computer uer password and username if (err == pref.Success): err = ssh.sshConnection.addNewComputer(IP, username, password) #add entry to table id = -1 if (err == pref.Success): err = table.add(entry) if (err == pref.Success): id = entry.ID #return value returnVal = jsonify(Error=err.toJson(), Id=id) #delete from table elif (tableOP == pref.getNoCheck(pref.TABLE_OP_DEL)): id = None try: id = data[pref.getNoCheck(pref.REQ_VAR_ID)] except: #Invalid request err = pref.getError(pref.ERROR_INVALID_REQUEST, args=(data)) logger.error(err) #Delete from table if (err == pref.Success): err = table.delete(id) returnVal = jsonify(Error=err.toJson()) #remove from table elif (tableOP == pref.getNoCheck(pref.TABLE_OP_GET_ALL)): err, entries = table.getAll() entriesJson = [] for entry in entries: entriesJson.append(entry.toJson()) returnVal = jsonify(Error=err.toJson(), entries=entriesJson) #Get By ID elif (tableOP == pref.getNoCheck(pref.TABLE_OP_GET_BY_ID)): id = None try: id = data[pref.getNoCheck(pref.REQ_VAR_ID)] except: err = pref.getError(pref.ERROR_INVALID_REQUEST, args=(data)) #Gets the entry by id if (err == pref.Success): err, entry = table.getByID(id) #Creates return request entryResponse = None if (err == pref.Success): entryResponse = entry.toJson() returnVal = jsonify(Error=err.toJson(), entry=entryResponse) elif (tableOP == pref.getNoCheck(pref.TABLE_OP_EDIT)): err, entry = createObjFromReq(tableName, table, data, isEdit=True) try: entry.ID = data[pref.getNoCheck(pref.REQ_VAR_ID)] except: err = pref.getError(pref.ERROR_INVALID_REQUEST, args=(data)) if (err == pref.Success): err, entry = table.editEntry(entry) #create return object returnVal = jsonify(Error=err.toJson(), entry=entry.toJson()) else: #This will never happen logger.warning("DIDN'T FIND TABLE REQUEST FAILED") err = pref.getError(pref.ERROR_INVALID_REQUEST, args=(data)) returnVal = jsonify(Error=err.toJson()) return returnVal
def createObjFromReq(tableName: str, table: tableOp.Table, data: dict, isEdit: bool = False) -> Tuple[pref.Error, tableOp.Entry]: ''' creates a table object from a request data @param tableName the name of the table being use ie computer @param data tableData that the object will be created from @param isEdit only used for edit script to know if it should be overwriting a file or not @return newly created object ''' entry = None err = pref.Success if (tableName == pref.getNoCheck(pref.TABLE_COMPUTER)): #computer table #vars userID = None nickName = None desc = None username = None IP = None asAdmin = None #run add computer script try: userID = session[pref.getNoCheck(pref.REQ_VAR_USER_ID)] except: err = pref.getError(pref.ERROR_NOT_LOGGED_IN) #Retrives data from request if (err == pref.Success): try: nickName = data[pref.getNoCheck(pref.REQ_VAR_NICK_NAME)] desc = data[pref.getNoCheck(pref.REQ_VAR_DESC)] username = data[pref.getNoCheck(pref.REQ_VAR_USERNAME)] IP = data[pref.getNoCheck(pref.REQ_VAR_IP)] asAdmin = data[pref.getNoCheck(pref.REQ_VAR_IS_ADMIN)] except: err = pref.getError(pref.ERROR_INVALID_REQUEST, args=(data)) #create computer if (err == pref.Success): entry = computerTable.ComputerTable.createEntry( userID, None, nickName, desc, username, IP, asAdmin) elif (tableName == pref.getNoCheck(pref.TABLE_SCRIPT)): #script table name = None filename = None desc = None isAdmin = None scriptData = None userID = None err = pref.Success try: userID = session[pref.getNoCheck(pref.REQ_VAR_USER_ID)] except: err = pref.getError(pref.ERROR_NOT_LOGGED_IN) if (err == pref.Success): try: name = data[pref.getNoCheck(pref.REQ_VAR_NICK_NAME)] desc = data[pref.getNoCheck(pref.REQ_VAR_DESC)] filename = data[pref.getNoCheck(pref.REQ_VAR_FILE_NAME)] scriptData = data[pref.getNoCheck(pref.REQ_VAR_SCRIPT_DATA)] isAdmin = data[pref.getNoCheck(pref.REQ_VAR_IS_ADMIN)] except: err = pref.getError(pref.ERROR_INVALID_REQUEST, args=(data)) #create file in script folder. overwrite if it already exists (only for edit) try: scriptPath = pref.getNoCheck(pref.CONFIG_SCRIPT_PATH) #should it overwrite or be a new file writeMode = "x" if (isEdit): writeMode = "w" fp = open("{}{}".format(scriptPath, filename), writeMode) fp.write(scriptData) except: print("ere") err = pref.getError(pref.ERROR_CANT_CREATE_FILE, args=(name)) #create computer if (err == pref.Success): entry = scriptTable.ScriptTable.createEntry( name, filename, userID, desc, isAdmin) return err, entry
def connect(self) -> pref.Error: ''' Connects its self to the computer based on the computer object passed in init. The computer with its IP and username. Before a computer can be connected to for the first time addComputer must first be run on it. @returns the error code pref.Success if it worked ''' err = pref.Success for _ in range(1): #make sure ip isnt Blacklisted blackListFileName = pref.getNoCheck(pref.CONFIG_BLACKLIST_IP_FILE) if (blackListFileName != ""): blackList = None try: blackList = [ line.rstrip("\n") for line in open(blackListFileName) ] except: tempErr = pref.getError(pref.ERROR_FILE_NOT_FOUND, args=(blackListFileName)) logger.error(tempErr) break err = whitelistBlackList.confirmValidIP( self.computer.IP, blackList) else: logger.warning("no ip blacklist no filtering") #Create ssh client with basic autoadd settings self.ssh = paramiko.SSHClient() self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #Get Keyfile from preferences try: keyFileName = pref.getNoCheck(pref.CONFIG_PRIVATE_SSH_KEY) keyFile = paramiko.RSAKey.from_private_key_file(keyFileName) except: err = pref.getError(pref.ERROR_CANT_FIND_SSH_KEY, args=(keyFileName)) logger.error(err) break #connect to the computer #TODO test self.computer.IP, needs list of blacklisted commands try: self.ssh.connect(self.computer.IP, username=self.computer.username, pkey=keyFile, timeout=5, allow_agent=False) #Authentication error rerun addComputer on this computer to fix except paramiko.ssh_exception.AuthenticationException as e: err = pref.getError(pref.ERROR_SSH_AUTHENTICATION_FAILED, args=(self.computer.username, self.computer.IP)) logger.error(err) break #Failed to connect except: err = pref.getError(pref.ERROR_CONNECTION_FAILED, args=(self.computer.username, self.computer.IP)) logger.error(err) return err
def addNewComputer(computerIP: str, username: str, password: str) -> pref.Error: ''' adds a new computer with using its username and password @param computerIP:str ip of the computer to add as a string. @param username:str username of the computer not user adding the computer. @param password:str password of the user described above. @return err ''' #init values err = pref.Success ssh = None ftp_client = None remoteFolder = None stdin = None stdout = None stderr = None for _ in range(1): #make sure ip isnt Blacklisted blackListFileName = pref.getNoCheck(pref.CONFIG_BLACKLIST_IP_FILE) if (blackListFileName != ""): blackList = None try: blackList = [ line.rstrip("\n") for line in open(blackListFileName) ] except: tempErr = pref.getError(pref.ERROR_FILE_NOT_FOUND, args=(blackListFileName)) logger.error(tempErr) break err = whitelistBlackList.confirmValidIP(computerIP, blackList) if (err != pref.Success): logger.error(err) break else: logger.warning("no ip blacklist no filtering") #get shh public key sshKey = pref.getNoCheck(pref.CONFIG_PUBLIC_SSH_KEY) #if its empty row public sshkey empty if (sshKey == None or sshKey.strip().strip("\n") == ""): err = pref.getError(pref.ERROR_EMPTY_SSH_PUBLIC_KEY) logger.error(err) break #Create ssh client with basic autoadd settings ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #Connects to computer with password and username try: ssh.connect(computerIP, username=username, password=password, timeout=5, look_for_keys=False, allow_agent=False) ftp_client = ssh.open_sftp() #Incorrect username or password except paramiko.ssh_exception.AuthenticationException as e: err = pref.getError(pref.ERROR_SSH_AUTHENTICATION_FAILED, args=(username, computerIP)) logger.error(err) break #Connection timed out or port rejected. except: err = pref.getError(pref.ERROR_CONNECTION_FAILED, args=(username, computerIP)) logger.error(err) break #Create tempfolder on the remote computer. remoteFolder = pref.getNoCheck(pref.CONFIG_REMOTE_FOLDER) addSSHKeyScript = pref.getNoCheck(pref.CONFIG_ADD_COMPUTER_SCRIPT) resFolder = pref.getNoCheck(pref.CONFIG_RES_FOLDER) #Add ssh file to server and change permissions. err = copyFileToComputer(ftp_client, remoteFolder, resFolder, addSSHKeyScript) if (err != pref.Success): break #Run setup script with sshKey config file. try: stdin, stdout, stderr = ssh.exec_command( "sshkey=\"{}\" {}{} > /dev/null; echo $?".format( sshKey, remoteFolder, addSSHKeyScript)) except: #failed to execute script. err = pref.getError(pref.ERROR_SSH_FAILED_TO_EXECUTE_SCRIPT, args=(addSSHKeyScript)) logger.error(err) break #Check error code of script. errCode = "".join(stdout.readlines()).rstrip("\n") if (errCode != "0"): err = pref.getError( pref.ERROR_SSH_SCRIPT_FAILED_WITH_ERROR_CODE, args=(errCode)) logger.error(err) return err
def getOutput(self, stdout: paramiko.ChannelFile, stderr: paramiko.ChannelFile): ''' This should never be called from outside this class. And should be run in another thread retriving the output from the script running on the remote computer it is assumed the scriptLog is already set before this function ''' #sets it so chanels arent blocking stdout.channel.setblocking(0) stderr.channel.setblocking(0) stdout_buffer = "" stderr_buffer = "" #scriptLog folder logFolder = pref.getNoCheck(pref.CONFIG_SCRIPT_LOG_PATH) try: stdoutFile = open( "{}{}".format(logFolder, self.scriptLog.stdoutFile), "w") stderrFile = open( "{}{}".format(logFolder, self.scriptLog.stderrFile), "w") except: #Couldn't create stdout and stderr file aborting and display warning err = pref.getError(pref.ERROR_CANT_CREATE_FILE, args=("{} and {}".format( self.scriptLog.stdoutFile, self.scriptLog.stderrFile))) logger.error(err) return #writes basic info to stdout and stderr stdoutFile.write("Script Start at: {}\n".format( datetime.datetime.now())) stderrFile.write("Script Start at: {}\n".format( datetime.datetime.now())) stdoutFile.flush() stderrFile.flush() #gets the output while not stdout.channel.exit_status_ready( ) or not stderr.channel.exit_status_ready( ) or stdout.channel.recv_ready() or stderr.channel.recv_ready(): retrivedInput = False #stdout try: stdout_buffer = stdout.readline() stdoutFile.write("{}: {}".format(datetime.datetime.now(), stdout_buffer)) stdoutFile.flush() retrivedInput = True except: pass #stderr try: stderr_buffer = stderr.readline() stderrFile.write("{}: {}".format(datetime.datetime.now(), stderr_buffer)) stderrFile.flush() retrivedInput = True except: pass #sleeps to lower cpu usage if (not retrivedInput): time.sleep(pref.getNoCheck(pref.CONFIG_OUTPUT_TIMEOUT)) #writes rest of data for line in stdout.readlines(): stdoutFile.write("{}: {}".format(datetime.datetime.now(), line)) for line in stderr.readlines(): stderrFile.write("{}: {}".format(datetime.datetime.now(), line)) stdoutFile.close() stderrFile.close() #gets returnValue stdoutFile = open("{}{}".format(logFolder, self.scriptLog.stdoutFile), "r+") stdoutFile.seek(0, os.SEEK_END) end = stdoutFile.tell() buffer = "" counter = 1 while (buffer != "\n"): stdoutFile.seek(end - counter, os.SEEK_SET) buffer = stdoutFile.read(1) counter += 1 returnValue = stdoutFile.readline().split("Returned: ") err = pref.Success #Failed to get return value error reading connection losted if len(returnValue) == 1: err = pref.getError(pref.ERROR_SSH_CONNECTION_LOST, args=(self.computer.username, self.computer.IP, self.script.name)) returnValue = None logger.error(err) else: returnValue = returnValue[-1] logger.info("Complete script {} with return value {}".format( self.script.name, returnValue)) self.scriptLog.endTime = datetime.datetime.now() self.scriptLog.errorCode = err.code self.scriptLog.returnVal = returnValue self.ssh.close() #Writes return value to db scriptLogTable.ScriptLogTable.editEntry(self.scriptLog)
def run(self) -> Tuple[pref.Error, int]: ''' Runs a script based on the script passed in init''' ftp_client = None err = pref.Success for _ in range(1): #creates sftp connection try: ftp_client = self.ssh.open_sftp() except: err = pref.getError(pref.ERROR_UNKNOWN) break #Paths for scripts remoteFolder = pref.getNoCheck(pref.CONFIG_REMOTE_FOLDER) scriptFolder = pref.getNoCheck(pref.CONFIG_SCRIPT_PATH) #Checks whitelistBlackList for _ in range(1): blackListFileName = pref.getNoCheck( pref.CONFIG_BLACKLIST_CMD_FILE) if (blackListFileName != ""): blackList = None try: blackList = [ line.rstrip("\n") for line in open(blackListFileName) ] except: tempErr = pref.getError(pref.ERROR_FILE_NOT_FOUND, args=(blackListFileName)) logger.error(tempErr) break err = whitelistBlackList.confirmValidCommads( "{}{}".format(scriptFolder, self.script.fileName), blackList) if (err != pref.Success): logger.error(err) break else: logger.warning("no cmd blacklist no filtering") #Error during blacklist if err != pref.Success: logger.error(err) break #Copies script over err = copyFileToComputer(ftp_client, remoteFolder, scriptFolder, self.script.fileName) if (err != pref.Success): break #Executes script #windows echo command #echoCmd = "echo Returned $?" echoCmd = "printf \"\\n\nReturned: %d\" $?" _, stdout, stderr = self.ssh.exec_command("{}{}; {}".format( remoteFolder, self.script.fileName, echoCmd)) #creates Script logs self.scriptLog = scriptLogTable.ScriptLogTable.createEntry( self.script.ID, self.userID, self.computer.ID, self.computer.asAdmin) err = scriptLogTable.ScriptLogTable.add(self.scriptLog) if (err == pref.Success): outputThread = threading.Thread(target=self.getOutput, daemon=True, args=(stdout, stderr)) outputThread.start() id = self.scriptLog.ID if self.scriptLog != None else -1 return err, id
def test_getNoCheck(self): login = pref.getNoCheck(pref.CONFIG_LOGIN_ENDPOINT) self.assertEqual("/login", login)