def parsedbvn(dbvn): from cupid import pilib # print('DBVN: ') # print(dbvn) """ databasename:tablename:valuename:condition """ split = dbvn.split(':') dbname = split[0].strip() dbpath = pilib.dbnametopath(dbname) if not dbpath: # print("error getting dbpath, for dbname: " + dbname) return None tablename = split[1].strip() valuename = split[2].strip() # Have to beware of conditions with colons in them. if len(split) == 4: condition = split[3] elif len(split) > 4: condition = ':'.join(split[3:]) else: condition = None return { 'dbname': dbname, 'dbpath': dbpath, 'tablename': tablename, 'valuename': valuename, 'condition': condition }
def parsedbvn(dbvn): from cupid import pilib # print('DBVN: ') # print(dbvn) """ databasename:tablename:valuename:condition """ split = dbvn.split(':') dbname = split[0].strip() dbpath = pilib.dbnametopath(dbname) if not dbpath: # print("error getting dbpath, for dbname: " + dbname) return None tablename = split[1].strip() valuename = split[2].strip() # Have to beware of conditions with colons in them. if len(split) == 4: condition = split[3] elif len(split) > 4: condition = ':'.join(split[3:]) else: condition = None return {'dbname':dbname,'dbpath':dbpath,'tablename':tablename,'valuename':valuename,'condition':condition}
def updatehardwareinfo(databasename='systemdb'): from subprocess import check_output from cupid import pilib from iiutilities import datalib from iiutilities import dblib import json data = check_output(['cat', '/proc/cpuinfo']).decode('utf-8') items = data.split('\n') hw_dict = {} for item in items: try: hw_dict[item.split(':')[0].strip()] = item.split(':')[1].strip() except: pass # print('HW DICT') # print(hw_dict) dictstring = json.dumps(hw_dict) dbpath = None try: dbpath = pilib.dbnametopath(databasename) # print(dbpath) except: pass if dbpath: time = datalib.gettimestring() dblib.sqliteinsertsingle( dbpath, 'versions', ['cpuinfo', dictstring, time, ''], ['item', 'version', 'updatetime', 'versiontime'], ) if 'Revision' in hw_dict and dbpath: versiondetail = piversiontoversionname(hw_dict['Revision']) dblib.sqliteinsertsingle( dbpath, 'versions', ['versionname', versiondetail['versionname'], time, ''], ['item', 'version', 'updatetime', 'versiontime'], ) dblib.sqliteinsertsingle( dbpath, 'versions', ['memory', versiondetail['memory'], time, ''], ['item', 'version', 'updatetime', 'versiontime'], ) return dictstring
def updatehardwareinfo(databasename='systemdb'): from subprocess import check_output from cupid import pilib from iiutilities import datalib from iiutilities import dblib import json data = check_output(['cat','/proc/cpuinfo']).decode('utf-8') items = data.split('\n') hw_dict = {} for item in items: try: hw_dict[item.split(':')[0].strip()] = item.split(':')[1].strip() except: pass # print('HW DICT') # print(hw_dict) dictstring = json.dumps(hw_dict) dbpath = None try: dbpath = pilib.dbnametopath(databasename) # print(dbpath) except: pass if dbpath: time = datalib.gettimestring() dblib.sqliteinsertsingle(dbpath,'versions',['cpuinfo', dictstring, time, ''],['item', 'version', 'updatetime', 'versiontime'],) if 'Revision' in hw_dict and dbpath: versiondetail = piversiontoversionname(hw_dict['Revision']) dblib.sqliteinsertsingle(dbpath, 'versions', ['versionname', versiondetail['versionname'], time, ''],['item', 'version', 'updatetime', 'versiontime'],) dblib.sqliteinsertsingle(dbpath, 'versions', ['memory', versiondetail['memory'], time, ''],['item', 'version', 'updatetime', 'versiontime'],) return dictstring
def application(environ, start_response): import cgi import json import hashlib # Set top folder to allow import of modules import os, sys, inspect top_folder = \ os.path.split(os.path.realpath(os.path.abspath(os.path.split(inspect.getfile(inspect.currentframe()))[0])))[0] if top_folder not in sys.path: sys.path.insert(0, top_folder) from cupid.pilib import dynamicsqliteread, gettablenames, sqlitequery, switchtablerows, dbnametopath from time import time post_env = environ.copy() post_env['QUERY_STRING'] = '' post = cgi.FieldStorage( fp=environ['wsgi.input'], environ=post_env, keep_blank_values=True ) formname = post.getvalue('name') output = {} d = {} for k in post.keys(): d[k] = post.getvalue(k) status = '200 OK' # Run stuff as requested # We use the dynamic function to allow various # types of queries output['data'] = [] output['message'] = '' # Need to do auths in here. try: action = d['action'] except KeyError: output['message'] = 'no action in request' else: if action == 'gettablenames': dbpath = dbnametopath(d['database']) try: output['data'] = gettablenames(dbpath) except: output['message'] += 'Error getting table names' elif action == 'switchtablerows': dbpath = dbnametopath(d['database']) switchtablerows(dbpath, d['tablename'], d['row1'], d['row2'], d['uniqueindex']) elif action == 'modwsgistatus': output['processgroup'] = repr(environ['mod_wsgi.process_group']) output['multithread'] = repr(environ['wsgi.multithread']) elif action == 'gettabledata': output['message']+='Gettabledata. ' if 'database' in d: dbpath = dbnametopath(d['database']) if dbpath: output['message'] += 'Friendly name ' + d['database'] + ' translated to path ' + dbpath + ' successfully. ' if 'tablenames[]' in d: # Get multiple tables output['message'] += 'Multiple tables. ' data = [] if 'start' in d: fixedstart = int(d['start']) else: fixedstart = 0 if 'length' in d: fixedlength = int(d['length']) else: fixedlength = 1 if 'lengths[]' in d: lengths = map(int, d['lengths[]']) else: lengths = [] if 'starts[]' in d: starts = map(int, d['starts']) else: starts = [] for index, table in enumerate(d['tablenames[]']): try: length = lengths[index] except IndexError: length = fixedlength try: start = starts[index] except IndexError: start = fixedstart data.append(dynamicsqliteread(dbpath, table, start, length)) output['data']=data elif 'length' in d: # Handle table row subset output['message']+='Length keyword. ' if not 'start' in d: d['start'] = 0 thetime = time(); output['data'] = dynamicsqliteread(dbpath, d['tablename'], d['start'], d['length']) output['querytime'] = time() - thetime elif 'row' in d: # Handle table row output['message'] += 'Row keyword. ' + str(d['row']) thetime = time(); output['data'] = dynamicsqliteread(dbpath, d['tablename'], d['row']) output['querytime'] = time() - thetime elif 'tablename' in d: # Handle entire table output['message'] += 'Tablename keyword: ' + d['tablename'] thetime = time(); if 'condition' in d: if not d['condition'] == '': output['data'] = dynamicsqliteread(dbpath, d['tablename'], condition=d['condition']) else: output['data'] = dynamicsqliteread(dbpath, d['tablename']) else: try: output['data'] = dynamicsqliteread(dbpath, d['tablename']) except: output['message'] += 'Error retrieving data. ' else: output['message'] += 'Data query appears successful. ' output['querytime'] = time() - thetime else: output['message'] += 'Friendly name ' + d['database'] + ' unsuccessfully translated. ' else: output['message'] += 'No database present in action request' else: output['message'] = 'no command matched for action ' + action if output['data']: newetag = hashlib.md5(str(output['data'])).hexdigest() if 'etag' in d: if newetag == d['etag']: status = '304 Not Modified' output['data'] = '' else: newetag='' if 'datasize' in d: output['datasize'] = sys.getsizeof(output['data']) output['etag'] = newetag foutput = json.dumps(output, indent=1) response_headers = [('Content-type', 'application/json')] response_headers.append(('Etag',newetag)) start_response(status, response_headers) return [foutput]
def application(environ, start_response): import cgi import json import os, sys, inspect # Set top folder to allow import of modules top_folder = os.path.split( os.path.realpath( os.path.abspath( os.path.split(inspect.getfile(inspect.currentframe()))[0])))[0] if top_folder not in sys.path: sys.path.insert(0, top_folder) from cupid import pilib, controllib from iiutilities import dblib, utility, datalib # post_env = environ.copy() # post_env['QUERY_STRING'] = '' # post = cgi.FieldStorage( # fp=environ['wsgi.input'], # environ=post_env, # keep_blank_values=True # ) # # formname=post.getvalue('name') # output = {} # output['message'] = 'Output Message: ' # for k in post.keys(): # d[k] = post.getvalue(k) try: request_body_size = int(environ.get('CONTENT_LENGTH', 0)) except ValueError: request_body_size = 0 request_body = environ['wsgi.input'].read(request_body_size) post = json.loads(request_body.decode('utf-8')) output = {} output['message'] = '' status = '200 OK' wsgiauth = True authverified = False if wsgiauth: # Verfiy that session login information is legit: hashed password, with salt and username, match # hash stored in database. import hashlib safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.users) if 'username' in post and post['username']: output['message'] += 'Session user is ' + post['username'] + '. ' else: output['message'] += 'No session user found. ' post['username'] = '' if post['username']: try: condition = "name='" + post['username'] + "'" user_data = safe_database.read_table_row( 'users', condition=condition)[0] except: output[ 'message'] += 'Error in user sqlite query for session user "' + post[ 'username'] + '". ' output[ 'message'] += 'Condition: ' + condition + '. Path: ' + pilib.dirs.dbs.safe user_data = {'accesskeywords': 'demo', 'admin': False} else: # Get session hpass to verify credentials hashedpassword = post['hpass'] hname = hashlib.new('sha1') hname.update(post['username']) hashedname = hname.hexdigest() hentry = hashlib.new('md5') hentry.update(hashedname + pilib.salt + hashedpassword) hashedentry = hentry.hexdigest() if hashedentry == user_data['password']: # successful auth output['message'] += 'Password verified. ' authverified = True # TODO: implement usermeta else: # Demo status authverified = True user_data = {'authlevel': 0} else: output['message'] += 'WSGI authorization not enabled. ' if authverified or not wsgiauth: output['authorized'] = True try: action = post['action'] except KeyError: output['message'] = 'no action in request' action = '' else: output['message'] += '{} action keyword found'.format(action) if output['authorized'] and action: output['action_allowed'] = pilib.check_action_auths( action, user_data['authlevel']) else: output['action_allowed'] = False if output['authorized'] and output['action_allowed']: output['message'] += 'Found action. ' if action == 'testdbvn': from iiutilities.dblib import dbvntovalue try: output['data'] = dbvntovalue(post['dbvn']) except: output['message'] += 'Error in dbvn evaluation. ' output['data'] = 'error' else: output['message'] += 'Seems to have worked out. ' elif action == 'testlogical': from iiutilities.datalib import evaldbvnformula try: output['data'] = evaldbvnformula(post['logical']) except: output['message'] += 'Error in logical evaluation. ' output['data'] = 'error' else: output['message'] += 'Seems to have worked out. ' elif action == 'testmodule': output['message'] += 'Testing module: ' if 'modulename' in post: import cupid.cupidunittests output['message'] += post['modulename'] output['data'] = cupid.cupidunittests.testmodule( post['modulename']) else: output['message'] += 'Modulename not found. ' elif action == 'testfunction': output['message'] += 'Testing function: ' if 'testname' in post: import cupid.cupidunittests output['message'] += post['testname'] # output['data'] = cupid.tests.testfunction(d['testname']) output['data'] = cupid.cupidunittests.testfunction( post['testname']) # output['data'] = str(cupid.tests.testfunction('systemstatus')) else: output['message'] += 'Testname not found. ' elif action == 'modifychannelalarm': controllib.handle_modify_channel_alarm(post, output) from cupid.actions import processactions # process only this action. processactions(name=post['actionname']) elif action == 'modifychannel': controllib.handle_modify_channel(post, output) elif action == 'getalarmscount': control_db = dblib.sqliteDatabase(pilib.dirs.dbs.control) actions = control_db.read_table('actions') output['data'] = { 'totalalarms': len(actions), 'channelalarms': 0, 'activealarms': 0, 'activechannelalarms': 0 } for action in actions: if action['conditiontype'] == 'channel': output['data']['channelalarms'] += 1 if action['active']: output['data']['activechannelalarms'] += 1 if action['active']: output['data']['activealarms'] += 1 elif action == 'copy_log_to_archive': pilib.app_copy_log_to_archive(post, output) elif action == 'getlogscount': logtablenames = dblib.sqliteDatabase( pilib.dirs.dbs.log).get_table_names() output['data'] = {'logscount': len(logtablenames)} elif action == 'test_action': output['message'] += 'Testing action. ' controldb = dblib.sqliteDatabase(pilib.dirs.dbs.control) actiondict = controldb.read_table('actions', condition='"name"=\'' + post['actionname'] + "'")[0] from cupid.actions import action test_action = action(actiondict) test_action.test() elif action == 'update_network': safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe) safe_database.set_single_value('wireless', 'password', post['password'], "SSID='" + post['ssid'] + "'") elif action == 'add_network': safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe) insert = {'SSID': post['ssid'], 'auto': 1, 'priority': 1} if 'password' in post: insert['password'] = post['password'] safe_database.insert('wireless', insert) elif action == 'delete_network': safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe) safe_database.delete('wireless', "SSID='" + post['ssid'] + "'") # elif action == 'dump': # # this has to go. # if 'database' in d: # dbpath = pilib.dbnametopath(d['database']) # if dbpath: # if 'tablelist' in d and 'outputfile' in d: # dbpath = pilib.dbnametopath(d['database']) # dblib.sqlitedatadump(dbpath, d['tablelist'], d['outputfile']) # output['message'] = 'data dumped' # elif 'tablename' in d and 'outputfile' in d: # dblib.sqlitedatadump(dbpath, [d['tablename']], d['outputfile']) # output['message'] = 'data dumped. ' # else: # output['message'] += 'keys not present for dump. ' # else: # output['message'] += 'keys not present for dump. ' # else: # output['message'] += 'keys not present for dump. ' elif action in ['userdelete', 'useradd', 'usermodify']: """ This needs to be consolidate with the other useradd, modify algorithm written already. Probably do this when we update the user permissions interface. """ # Ensure that we are authorized for this action if action == 'userdelete': try: dblib.sqlitequery( pilib.dirs.dbs.users, "delete from users where name='" + post['usertodelete'] + "'") except: output['message'] += 'Error in delete query. ' else: output['message'] += 'Successful delete query. ' elif action == 'usermodify': if 'usertomodify' in post: querylist = [] if 'newpass' in post: from pilib import salt # Get session hpass to verify credentials hashedpassword = post['newpass'] hname = hashlib.new('sha1') hname.update(post['usertomodify']) hashedname = hname.hexdigest() hentry = hashlib.new('md5') hentry.update(hashedname + salt + hashedpassword) hashedentry = hentry.hexdigest() querylist.append('update users set password='******'" + post['usertomodify'] + "'") if 'newemail' in post: querylist.append("update users set email='" + post['newemail'] + "' where name='" + post['usertomodify'] + "'") if 'newauthlevel' in post: querylist.append("update users set authlevel='" + post['newauthlevel'] + "' where name='" + post['usertomodify'] + "'") try: dblib.sqlitemultquery(pilib.dirs.dbs.users, querylist) except: output[ 'message'] += 'Error in modify/add query: ' + ",".join( querylist) else: output[ 'message'] += 'Successful modify/add query. ' + ",".join( querylist) else: output['message'] += 'Need usertomodify in query. ' elif action == 'useradd': try: username = post['newusername'] except: username = '******' try: newemail = post['newemail'] except: newemail = '*****@*****.**' try: newauthlevel = post['newauthlevel'] except: newauthlevel = 0 query = "insert into users values(NULL,'" + username + "','','" + newemail + "',''," + str( newauthlevel) + ")" try: dblib.sqlitequery(pilib.dirs.dbs.users, query) except: output[ 'message'] += "Error in useradd sqlite query: " + query + ' . ' else: output['message'] += "Successful query: " + query + ' . ' elif action == 'getfiletext': try: filepath = post['filepath'] if 'numlines' in post: numlines = int(post['numlines']) else: numlines = 9999 output['message'] += 'Using numlines: ' + str( numlines) + ' for read action. ' if 'startposition' in post: startposition = post['startposition'] else: startposition = 'end' output[ 'message'] += 'Reading from position ' + startposition + '. ' except KeyError: output[ 'message'] += 'Sufficient keys for action getfile text do not exist. ' except: output['message'] += 'Uncaught error in getfiletext. ' else: try: file = open(filepath) lines = file.readlines() except: output[ 'message'] += 'Error reading file in getfiletext action. ' else: output['data'] = [] if startposition == 'end': try: output['data'] = datalib.tail(file, numlines)[0] except: output['message'] += 'Error in tail read. ' else: linecount = 0 for line in lines: linecount += 1 if linecount > numlines: break else: output['data'].append(line) elif action == 'getmbtcpdata': try: clientIP = post['clientIP'] register = post['register'] length = post['length'] except KeyError: output[ 'message'] += 'Sufficient keys do not exist for the command. Requires clientIP, register, and length. ' else: from iiutilities.netfun import readMBcodedaddresses # try: output['response'] = readMBcodedaddresses( clientIP, int(register), int(length)) elif action == 'queuemessage': output['message'] += 'Queue message. ' if 'message' in post: try: dblib.sqliteinsertsingle( pilib.dirs.dbs.motes, 'queuedmessages', [datalib.gettimestring(), post['message']]) except: import traceback exc_type, exc_value, exc_traceback = sys.exc_info() output[ 'message'] += 'Error in queue insert query: {}. '.format( traceback.format_exc()) else: output['message'] += 'Message insert successful' else: output['message'] += 'No message present. ' elif action == 'setsystemflag' and 'systemflag' in post: database = pilib.dirs.dbs.system dblib.setsinglevalue(database, 'systemflags', 'value', 1, "name=\'" + post['systemflag'] + "'") elif action == 'rundaemon': from cupiddaemon import rundaemon rundaemon() # TODO: Eliminate this scary thing. elif action == 'setvalue': utility.log(pilib.dirs.logs.control, "Setting value in wsgi", 1, 1) # we use the auxiliary 'setsinglecontrolvalue' to add additional actions to update if all(k in post for k in ('database', 'table', 'valuename', 'value')): dbpath = pilib.dbnametopath(post['database']) if dbpath: output[ 'message'] += 'Carrying out setvalue for value ' + post[ 'valuename'] + ' on ' + post[ 'table'] + ' in ' + dbpath if 'condition' in post: pilib.setsinglecontrolvalue(dbpath, post['table'], post['valuename'], post['value'], post['condition']) elif 'index' in post: condition = 'rowid= ' + post['index'] pilib.setsinglecontrolvalue(dbpath, post['table'], post['valuename'], post['value'], condition) else: pilib.setsinglecontrolvalue(dbpath, post['table'], post['valuename'], post['value']) else: output[ 'message'] += 'Problem translating dbpath from friendly name: ' + post[ 'database'] else: output['message'] += 'Insufficient data for setvalue ' elif action == 'updateioinfo': if all(k in post for k in ['database', 'ioid', 'value']): query = dblib.makesqliteinsert('ioinfo', [post['ioid'], post['value']], ['id', 'name']) try: dblib.sqlitequery(pilib.dirs.dbs.control, query) except: output[ 'message'] += 'Error in updateioinfo query execution: ' + query + '. into database: ' + pilib.dirs.dbs.control output['message'] += 'ioid: ' + post['ioid'] + ' . ' else: output['message'] += 'Executed updateioinfo query. ' else: output[ 'message'] += 'Insufficient data for updateioinfo query ! ' # TODO: properly incorporate and test channel class functions here, and then sub it. elif action == 'modify_channel': controllib.app_modify_channel(post, output) elif action == 'deletechannelbyname' and 'database' in post and 'channelname' in post: dbpath = pilib.dbnametopath(post['database']) dblib.sqlitequery( dbpath, 'delete channelname from channels where name=\"' + post['channelname'] + '\"') elif action == 'updatecameraimage': output['message'] += 'Take camera image keyword. ' import cupid.camera if 'width' in post: width = post['width'] else: width = 800 try: values = cupid.camera.takesnap(width=width) except: output['message'] += 'Error taking image. ' else: output['message'] += 'Appears successful. Path : ' + values[ 'imagepath'] + '. Timestamp : ' + values['timestamp'] + '. ' output['data'] = values elif action == 'getcurrentcamtimestamp': output['message'] += 'getcurrentcamtimestamp keyword found. ' try: with open('/var/www/webcam/images/current.jpg.timestamp') as f: data = f.read() except: output['message'] += 'Error reading file as requested. ' else: output['data'] = data else: output[ 'message'] += 'Action keyword present(' + action + '), but not handled. ' else: output[ 'message'] += 'Authentication unsuccessful or action not authorized.' status = '401 Not Authorized' foutput = json.dumps(output, indent=1) response_headers = [('Content-type', 'application/json')] start_response(status, response_headers) return [foutput]
def application(environ, start_response): import cgi import json import hashlib # Set top folder to allow import of modules import os, sys, inspect top_folder = \ os.path.split(os.path.realpath(os.path.abspath(os.path.split(inspect.getfile(inspect.currentframe()))[0])))[0] if top_folder not in sys.path: sys.path.insert(0, top_folder) from cupid import pilib from iiutilities import dblib from time import time try: request_body_size = int(environ.get('CONTENT_LENGTH', 0)) except ValueError: request_body_size = 0 request_body = environ['wsgi.input'].read(request_body_size) try: post = json.loads(request_body.decode('utf-8')) except: print('Error decoding: ') print(request_body.decode('utf-8')) post = {} output = {'message': ''} status = '200 OK' # Run stuff as requested # We use the dynamic function to allow various # types of queries output['data'] = [] output['message'] = '' wsgiauth = True authverified = False if wsgiauth: # Verfiy that session login information is legit: hashed password, with salt and username, match # hash stored in database. import hashlib safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.users) if 'username' in post and post['username']: output['message'] += 'Session user is ' + post['username'] + '. ' else: output['message'] += 'No session user found. ' post['username'] = '' if post['username']: condition = "name='" + post['username'] + "'" user_data = safe_database.read_table_row('users', condition=condition)[0] try: condition = "name='" + post['username'] + "'" user_data = safe_database.read_table_row( 'users', condition=condition)[0] except: output[ 'message'] += 'Error in user sqlite query for session user "' + post[ 'username'] + '". ' # output['message'] += 'Condition {}'.format(condition) output[ 'message'] += 'Condition: ' + condition + '. Path: ' + pilib.dirs.dbs.safe user_data = {'accesskeywords': 'demo', 'admin': False} else: # Get session hpass to verify credentials hashedpassword = post['hpass'] hname = hashlib.new('sha1') hname.update(post['username']) hashedname = hname.hexdigest() hentry = hashlib.new('md5') hentry.update(hashedname + pilib.salt + hashedpassword) hashedentry = hentry.hexdigest() if hashedentry == user_data['password']: # successful auth output['message'] += 'Password verified. ' authverified = True # TODO: implement usermeta else: output['message'] += 'WSGI authorization not enabled. ' if authverified or not wsgiauth: try: action = post['action'] except KeyError: output['message'] = 'no action in request' else: if action == 'gettablenames': dbpath = pilib.dbnametopath(post['database']) try: output['data'] = dblib.gettablenames(dbpath) except: output['message'] += 'Error getting table names' elif action == 'modwsgistatus': output['processgroup'] = repr( environ['mod_wsgi.process_group']) output['multithread'] = repr(environ['wsgi.multithread']) elif action == 'gettabledata': output['message'] += 'Gettabledata. ' if 'database' in post: dbpath = pilib.dbnametopath(post['database']) if dbpath: output['message'] += 'Friendly name ' + post[ 'database'] + ' translated to path ' + dbpath + ' successfully. ' the_database = dblib.sqliteDatabase(dbpath) if 'tablenames' in post: # Get multiple tables output['message'] += 'Multiple tables. ' data = [] if 'start' in post: fixedstart = int(post['start']) else: fixedstart = 0 if 'length' in post: fixedlength = int(post['length']) else: fixedlength = 0 if 'lengths' in post: lengths = map(int, post['lengths[]']) else: lengths = [] if 'starts' in post: starts = map(int, post['starts']) else: starts = [] for index, table in enumerate(post['tablenames']): output[ 'message'] += 'Reading table {}. '.format( table) try: length = lengths[index] except IndexError: length = fixedlength try: start = starts[index] except IndexError: start = fixedstart if not fixedlength: # get all rows if length not specified db_data = the_database.read_table(table) else: db_data = the_database.read_table_rows( table, start, length) output[ 'message'] += 'Read {} rows of data. '.format( len(db_data)) data.append(db_data) output['data'] = data elif 'length' in post: # Handle table row subset output['message'] += 'Length keyword. ' if not 'start' in post: post['start'] = 0 thetime = time() output['data'] = the_database.read_table_rows( post['tablename'], post['start'], post['length']) output['querytime'] = time() - thetime elif 'row' in post: # Handle table row output['message'] += 'Row keyword. ' + str( post['row']) thetime = time() output['data'] = the_database.read_table_rows( post['tablename'], post['row']) output['querytime'] = time() - thetime elif 'tablename' in post: # Handle entire table output[ 'message'] += 'Tablename keyword: {}. '.format( post['tablename']) thetime = time() if 'condition' in post: if not post['condition'] == '': output[ 'message'] += 'Condition : "{}" .'.format( post['condition']) output['data'] = the_database.read_table( post['tablename'], condition=post['condition']) else: output['data'] = the_database.read_table( post['tablename']) else: try: output['data'] = the_database.read_table( post['tablename']) except: output[ 'message'] += 'Error retrieving data. ' else: output[ 'message'] += 'Data query appears successful. ' # output['message'] += str(output['data'][0]) output['querytime'] = time() - thetime else: output['message'] += 'Friendly name ' + post[ 'database'] + ' unsuccessfully translated. ' else: output[ 'message'] += 'No database present in action request' elif action == 'get_archive_info': from iiutilities.utility import get_directory_listing directory_list = get_directory_listing(pilib.dirs.archive) output['data'] = {} output['data']['lognames'] = [] for filename in directory_list['filenames']: if filename[-3:] == '.db': output['data']['lognames'].append(filename[:-3]) else: directory_list['filenames'].remove(filename) output['data']['metadata'] = [] output['message'] += 'Retrieved db logs {}. '.format( directory_list['filenames']) for filename, logname in zip(directory_list['filenames'], output['data']['lognames']): archive_db = dblib.sqliteDatabase(pilib.dirs.archive + filename) try: metadata = archive_db.read_table('metadata')[0] except: output[ 'message'] += 'Error retrieving metadata for log table {}. '.format( filename) output['data']['metadata'].append({}) else: metadata['name'] = logname output['data']['metadata'].append(metadata) else: output['message'] = 'no command matched for action ' + action else: output['message'] += 'Authentication unsuccessful' if output['data']: newetag = hashlib.md5(str(output['data'])).hexdigest() if 'etag' in post: if newetag == post['etag']: status = '304 Not Modified' output['data'] = '' else: newetag = '' if 'datasize' in post: output['datasize'] = sys.getsizeof(output['data']) output['etag'] = newetag try: foutput = json.dumps(output, indent=1) except: print('*** THERE WAS AN ERROR DECODING DATA ***') print(output) foutput = json.dumps({'message': 'Error in json dumps'}) response_headers = [('Content-type', 'application/json')] response_headers.append(('Etag', newetag)) start_response(status, response_headers) return [foutput]
def offact(self): from iiutilities import dblib, datalib, utility from cupid import pilib if self.actiontype == 'email': # process email action # TODO: This really needs to queue the email action in case we are not online. self.statusmsg +='Processing email alert.' email = self.actiondetail # message = 'Alert has gone inactive for ' + self.name + '. Criterion ' + self.variablename + ' in ' + self.tablename + ' has value ' + str(self.variablevalue) + ' with a criterion of ' + str(self.criterion) + ' with an operator of ' + self.operator + '. This alarm status has been of since ' + self.offtime + '.' message = 'Alert for alarm ' + self.name + ' . Off time of ' + self.offtime + '. Current time of ' \ + datalib.gettimestring() if self.conditiontype == 'value': message += ' Value: ' + str(self.value) + self.actiondatadict['operator'] + str( self.actiondatadict['criterion']) import socket hostname = socket.gethostname() subject = 'CuPID ' + hostname + ' Alert : Alarm Off - ' + self.name try: actionmail = utility.gmail(message=message, subject=subject, recipient=email) actionmail.send() except: self.statusmsg += 'Error sending email. ' else: self.statusmsg += 'Mail sent. ' elif self.actiontype == 'indicator': # process indicator action self.statusmsg +='Processing indicator off action.' indicatorname = self.actiondetail dblib.setsinglevalue(pilib.dirs.dbs.control, 'indicators', 'status', 0, 'name=\'' + indicatorname+ '\'') print('INDICATORNAME = "' + indicatorname + '"') # dblib.sqlitequery(pilib.dirs.dbs.control, 'update indicators set status=0 where name = ' + indicatorname) elif self.actiontype == 'output': self.statusmsg += 'Processing output off action. ' dblib.setsinglevalue(pilib.dirs.dbs.control, 'outputs', 'value', '0', condition='"id"=\'' + self.actiondetail + "'") # This should be the generic handler that we migrate to elif self.actiontype == 'setvalue': # to set a value, we need at minimum: # dbname, tablename, valuename, setmethod and either: # setmethod = increment, incrementvalue=1 # setmethod = value dbvndict = datalib.parsedbvn(self.actiondetail) dbpath = pilib.dbnametopath(dbvndict['dbname']) # Special set formula? if 'setvalueformula' in self.actiondatadict: # Stuff that we don't know yet. dblib.setsinglevalue(dbpath, dbvndict['tablename'], dbvndict['valuename'], 'formulastuff here', dbvndict['condition']) else: """ TODO: Fix this hack. We cannot currently single quote in the database entry because it breaks the reinsert. So for now, we have to add quotes on either side of the string literal before executing the sqlite query. """ if dbvndict['condition']: querycondition = dbvndict['condition'].split('=')[0] + "='" + dbvndict['condition'].split('=')[1] + "'" # print('FIXED CONDITION') # print(querycondition) else: querycondition = None dblib.setsinglevalue(dbpath, dbvndict['tablename'], dbvndict['valuename'], '0', querycondition)
def onact(self): from iiutilities import dblib, datalib, utility from cupid import pilib if self.actiontype == 'email': # process email action self.statusmsg += 'Processing email alert. ' email = self.actiondetail # Special messages if self.conditiontype == 'channel': message = 'Channel alarm for ' + self.name + ' is active with value of ' + str(self.value) + '. ' if 'PV_low' in self.actiondatadict: message += 'Low alarm: ' + str(self.actiondatadict['PV_low'] + '. ') if 'PV_high' in self.actiondatadict: message += 'High alarm: ' + str(self.actiondatadict['PV_high'] + '. ') elif self.conditiontype == 'value': # message = 'Alert is active for ' + self.name + '. Criterion ' + self.variablename + ' in ' + self.tablename + ' has value ' + str(self.variablevalue) + ' with a criterion of ' + str(self.criterion) + ' with an operator of ' + self.operator + '. This alarm status has been on since ' + self.ontime + '.' message = 'Alert for alarm ' + self.name + ' . On time of ' + self.ontime + '. Current time of ' \ + datalib.gettimestring() message += ' Value: ' + str(self.value) + self.actiondatadict['operator'] + str(self.actiondatadict['criterion']) else: # message = 'Alert is active for ' + self.name + '. Criterion ' + self.variablename + ' in ' + self.tablename + ' has value ' + str(self.variablevalue) + ' with a criterion of ' + str(self.criterion) + ' with an operator of ' + self.operator + '. This alarm status has been on since ' + self.ontime + '.' message = 'Alert for alarm ' + self.name + ' . On time of ' + self.ontime + '. Current time of ' \ + datalib.gettimestring() import socket hostname = socket.gethostname() subject = 'CuPID ' + hostname + ' Alert : Alarm On - ' + self.name try: actionmail = utility.gmail(message=message, subject=subject, recipient=email) actionmail.send() except: self.statusmsg += 'Error sending email. ' else: self.statusmsg += 'Mail sent. ' elif self.actiontype == 'indicator': # process indicator action self.statusmsg += 'Processing indicator on action. ' indicatorname = self.actiondetail dblib.sqlitequery(pilib.dirs.dbs.control, 'update indicators set status=1 where name = \'' + indicatorname + '\'') elif self.actiontype == 'output': self.statusmsg += 'Processing output on action. ' dblib.setsinglevalue(pilib.dirs.dbs.control, 'outputs', 'value', '1', condition='"id"=\'' + self.actiondetail + "'") elif self.actiontype == 'mote_command': settings = { 'no_duplicates':True, 'retries':5 } settings.update(self.actiondatadict) self.statusmsg += 'Processing command on action. ' destination = self.actiondatadict['destination'] message = self.actiondatadict['message'] command_id = '{}_{}'.format(destination, message) command = {'queuedtime': datalib.gettimestring(), 'destination': destination, 'status': 'new', 'message': message, 'commandid':command_id, } command['options'] = json.dumps({'retries':settings['retries']}) insert = True if settings['no_duplicates']: # Check to see if commands exist with our command id. condition = "commandid='{}'".format(command_id) matching_commands = pilib.dbs.motes.read_table('commands',condition=condition) if matching_commands: self.statusmsg += '{} matching commands are already queued. Not inserting. '.format(len(matching_commands)) insert = False if insert: self.statusmsg += 'Inserting command. ' pilib.dbs.motes.settings['quiet'] = False pilib.dbs.motes.insert('commands',command) # This should be the generic handler that we migrate to elif self.actiontype == 'setvalue': # to set a value, we need at minimum: # dbname, tablename, valuename, setmethod and either: # setmethod = increment, incrementvalue=1 # setmethod = value dbvndict = datalib.parsedbvn(self.actiondetail) dbpath = pilib.dbnametopath(dbvndict['dbname']) # Special set formula? if 'setvalueformula' in self.actiondatadict: # Stuff that we don't know yet. dblib.setsinglevalue(dbpath, dbvndict['tablename'], dbvndict['valuename'], 'formulastuff here', dbvndict['condition']) else: """ TODO: Fix this hack. We cannot currently single quote in the database entry because it breaks the reinsert. So for now, we have to add quotes on either side of the string literal before executing the sqlite query. """ if dbvndict['condition']: querycondition = dbvndict['condition'].split('=')[0] + "='" + dbvndict['condition'].split('=')[1] + "'" # print('FIXED CONDITION') # print(querycondition) else: querycondition = None dblib.setsinglevalue(dbpath, dbvndict['tablename'], dbvndict['valuename'], '1', querycondition)
def application(environ, start_response): import cgi import json import os, sys, inspect # Set top folder to allow import of modules top_folder = os.path.split(os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0])))[0] if top_folder not in sys.path: sys.path.insert(0,top_folder) from cupid import pilib, controllib from iiutilities import dblib, utility, datalib # post_env = environ.copy() # post_env['QUERY_STRING'] = '' # post = cgi.FieldStorage( # fp=environ['wsgi.input'], # environ=post_env, # keep_blank_values=True # ) # # formname=post.getvalue('name') # output = {} # output['message'] = 'Output Message: ' # for k in post.keys(): # d[k] = post.getvalue(k) try: request_body_size = int(environ.get('CONTENT_LENGTH', 0)) except ValueError: request_body_size = 0 request_body = environ['wsgi.input'].read(request_body_size) post = json.loads(request_body.decode('utf-8')) output = {} output['message'] = '' status = '200 OK' wsgiauth = True authverified = False if wsgiauth: # Verfiy that session login information is legit: hashed password, with salt and username, match # hash stored in database. import hashlib safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.users) if 'username' in post and post['username']: output['message'] += 'Session user is ' + post['username'] + '. ' else: output['message'] += 'No session user found. ' post['username'] = '' if post['username']: try: condition = "name='" + post['username'] + "'" user_data = safe_database.read_table_row('users', condition=condition)[0] except: output['message'] += 'Error in user sqlite query for session user "' + post['username'] + '". ' output['message'] += 'Condition: ' + condition + '. Path: ' + pilib.dirs.dbs.safe user_data = {'accesskeywords': 'demo', 'admin': False} else: # Get session hpass to verify credentials hashedpassword = post['hpass'] hname = hashlib.new('sha1') hname.update(post['username']) hashedname = hname.hexdigest() hentry = hashlib.new('md5') hentry.update(hashedname + pilib.salt + hashedpassword) hashedentry = hentry.hexdigest() if hashedentry == user_data['password']: # successful auth output['message'] += 'Password verified. ' authverified = True # TODO: implement usermeta else: # Demo status authverified = True user_data = {'authlevel':0} else: output['message'] += 'WSGI authorization not enabled. ' if authverified or not wsgiauth: output['authorized'] = True try: action = post['action'] except KeyError: output['message'] = 'no action in request' action = '' else: output['message'] += '{} action keyword found'.format(action) if output['authorized'] and action: output['action_allowed'] = pilib.check_action_auths(action, user_data['authlevel']) else: output['action_allowed'] = False if output['authorized'] and output['action_allowed']: output['message'] += 'Found action. ' if action == 'testdbvn': from iiutilities.dblib import dbvntovalue try: output['data'] = dbvntovalue(post['dbvn']) except: output['message'] += 'Error in dbvn evaluation. ' output['data'] = 'error' else: output['message'] += 'Seems to have worked out. ' elif action == 'testlogical': from iiutilities.datalib import evaldbvnformula try: output['data'] = evaldbvnformula(post['logical']) except: output['message'] += 'Error in logical evaluation. ' output['data'] = 'error' else: output['message'] += 'Seems to have worked out. ' elif action == 'testmodule': output['message'] += 'Testing module: ' if 'modulename' in post: import cupid.cupidunittests output['message'] += post['modulename'] output['data'] = cupid.cupidunittests.testmodule(post['modulename']) else: output['message'] += 'Modulename not found. ' elif action == 'testfunction': output['message'] += 'Testing function: ' if 'testname' in post: import cupid.cupidunittests output['message'] += post['testname'] # output['data'] = cupid.tests.testfunction(d['testname']) output['data'] = cupid.cupidunittests.testfunction(post['testname']) # output['data'] = str(cupid.tests.testfunction('systemstatus')) else: output['message'] += 'Testname not found. ' elif action == 'modifychannelalarm': controllib.handle_modify_channel_alarm(post, output) from cupid.actions import processactions # process only this action. processactions(name=post['actionname']) elif action == 'modifychannel': controllib.handle_modify_channel(post, output) elif action == 'getalarmscount': control_db = dblib.sqliteDatabase(pilib.dirs.dbs.control) actions = control_db.read_table('actions') output['data'] = {'totalalarms':len(actions),'channelalarms':0, 'activealarms':0, 'activechannelalarms':0} for action in actions: if action['conditiontype'] == 'channel': output['data']['channelalarms'] += 1 if action['active']: output['data']['activechannelalarms'] += 1 if action['active']: output['data']['activealarms'] += 1 elif action == 'copy_log_to_archive': pilib.app_copy_log_to_archive(post, output) elif action == 'getlogscount': logtablenames = dblib.sqliteDatabase(pilib.dirs.dbs.log).get_table_names() output['data'] = {'logscount':len(logtablenames)} elif action == 'test_action': output['message'] += 'Testing action. ' controldb = dblib.sqliteDatabase(pilib.dirs.dbs.control) actiondict = controldb.read_table('actions',condition='"name"=\'' + post['actionname'] + "'")[0] from cupid.actions import action test_action = action(actiondict) test_action.test() elif action == 'update_network': safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe) safe_database.set_single_value('wireless', 'password', post['password'], "SSID='" + post['ssid'] + "'") elif action == 'add_network': safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe) insert = {'SSID':post['ssid'], 'auto':1, 'priority':1} if 'password' in post: insert['password'] = post['password'] safe_database.insert('wireless',insert) elif action == 'delete_network': safe_database = dblib.sqliteDatabase(pilib.dirs.dbs.safe) safe_database.delete('wireless', "SSID='" + post['ssid'] + "'") # elif action == 'dump': # # this has to go. # if 'database' in d: # dbpath = pilib.dbnametopath(d['database']) # if dbpath: # if 'tablelist' in d and 'outputfile' in d: # dbpath = pilib.dbnametopath(d['database']) # dblib.sqlitedatadump(dbpath, d['tablelist'], d['outputfile']) # output['message'] = 'data dumped' # elif 'tablename' in d and 'outputfile' in d: # dblib.sqlitedatadump(dbpath, [d['tablename']], d['outputfile']) # output['message'] = 'data dumped. ' # else: # output['message'] += 'keys not present for dump. ' # else: # output['message'] += 'keys not present for dump. ' # else: # output['message'] += 'keys not present for dump. ' elif action in ['userdelete', 'useradd', 'usermodify']: """ This needs to be consolidate with the other useradd, modify algorithm written already. Probably do this when we update the user permissions interface. """ # Ensure that we are authorized for this action if action == 'userdelete': try: dblib.sqlitequery(pilib.dirs.dbs.users, "delete from users where name='" + post['usertodelete'] + "'") except: output['message'] += 'Error in delete query. ' else: output['message'] += 'Successful delete query. ' elif action == 'usermodify': if 'usertomodify' in post: querylist=[] if 'newpass' in post: from pilib import salt # Get session hpass to verify credentials hashedpassword = post['newpass'] hname = hashlib.new('sha1') hname.update(post['usertomodify']) hashedname = hname.hexdigest() hentry = hashlib.new('md5') hentry.update(hashedname + salt + hashedpassword) hashedentry = hentry.hexdigest() querylist.append('update users set password='******'" + post['usertomodify'] + "'") if 'newemail' in post: querylist.append("update users set email='" + post['newemail'] + "' where name='" + post['usertomodify'] + "'") if 'newauthlevel' in post: querylist.append("update users set authlevel='" + post['newauthlevel'] + "' where name='" + post['usertomodify'] + "'") try: dblib.sqlitemultquery(pilib.dirs.dbs.users, querylist) except: output['message'] += 'Error in modify/add query: ' + ",".join(querylist) else: output['message'] += 'Successful modify/add query. ' + ",".join(querylist) else: output['message'] += 'Need usertomodify in query. ' elif action == 'useradd': try: username = post['newusername'] except: username = '******' try: newemail = post['newemail'] except: newemail = '*****@*****.**' try: newauthlevel = post['newauthlevel'] except: newauthlevel = 0 query = "insert into users values(NULL,'" + username + "','','" + newemail + "',''," + str(newauthlevel) + ")" try: dblib.sqlitequery(pilib.dirs.dbs.users, query) except: output['message'] += "Error in useradd sqlite query: " + query + ' . ' else: output['message'] += "Successful query: " + query + ' . ' elif action == 'getfiletext': try: filepath = post['filepath'] if 'numlines' in post: numlines = int(post['numlines']) else: numlines = 9999 output['message'] += 'Using numlines: ' + str(numlines) + ' for read action. ' if 'startposition' in post: startposition = post['startposition'] else: startposition = 'end' output['message'] += 'Reading from position ' + startposition + '. ' except KeyError: output['message'] += 'Sufficient keys for action getfile text do not exist. ' except: output['message'] += 'Uncaught error in getfiletext. ' else: try: file = open(filepath) lines = file.readlines() except: output['message'] += 'Error reading file in getfiletext action. ' else: output['data'] = [] if startposition == 'end': try: output['data'] = datalib.tail(file, numlines)[0] except: output['message'] += 'Error in tail read. ' else: linecount = 0 for line in lines: linecount += 1 if linecount > numlines: break else: output['data'].append(line) elif action == 'getmbtcpdata': try: clientIP = post['clientIP'] register = post['register'] length = post['length'] except KeyError: output['message'] += 'Sufficient keys do not exist for the command. Requires clientIP, register, and length. ' else: from iiutilities.netfun import readMBcodedaddresses # try: output['response'] = readMBcodedaddresses(clientIP, int(register), int(length)) elif action == 'queuemessage': output['message'] += 'Queue message. ' if 'message' in post: try: dblib.sqliteinsertsingle(pilib.dirs.dbs.motes, 'queuedmessages', [datalib.gettimestring(), post['message']]) except: import traceback exc_type, exc_value, exc_traceback = sys.exc_info() output['message'] += 'Error in queue insert query: {}. '.format(traceback.format_exc()) else: output['message'] += 'Message insert successful' else: output['message'] += 'No message present. ' elif action == 'setsystemflag' and 'systemflag' in post: database = pilib.dirs.dbs.system dblib.setsinglevalue(database, 'systemflags', 'value', 1, "name=\'" + post['systemflag'] + "'") elif action == 'rundaemon': from cupiddaemon import rundaemon rundaemon() # TODO: Eliminate this scary thing. elif action == 'setvalue': utility.log(pilib.dirs.logs.control, "Setting value in wsgi", 1, 1) # we use the auxiliary 'setsinglecontrolvalue' to add additional actions to update if all(k in post for k in ('database', 'table', 'valuename', 'value')): dbpath = pilib.dbnametopath(post['database']) if dbpath: output['message'] += 'Carrying out setvalue for value ' + post['valuename'] + ' on ' + post['table'] + ' in ' + dbpath if 'condition' in post: pilib.setsinglecontrolvalue(dbpath, post['table'], post['valuename'], post['value'], post['condition']) elif 'index' in post: condition = 'rowid= ' + post['index'] pilib.setsinglecontrolvalue(dbpath, post['table'], post['valuename'], post['value'], condition) else: pilib.setsinglecontrolvalue(dbpath, post['table'], post['valuename'], post['value']) else: output['message'] += 'Problem translating dbpath from friendly name: ' + post['database'] else: output['message'] += 'Insufficient data for setvalue ' elif action == 'updateioinfo': if all(k in post for k in ['database', 'ioid', 'value']): query = dblib.makesqliteinsert('ioinfo', [post['ioid'], post['value']], ['id', 'name']) try: dblib.sqlitequery(pilib.dirs.dbs.control, query) except: output['message'] += 'Error in updateioinfo query execution: ' + query +'. into database: ' + pilib.dirs.dbs.control output['message'] += 'ioid: ' + post['ioid'] + ' . ' else: output['message'] += 'Executed updateioinfo query. ' else: output['message'] += 'Insufficient data for updateioinfo query ! ' # TODO: properly incorporate and test channel class functions here, and then sub it. elif action == 'modify_channel': controllib.app_modify_channel(post, output) elif action == 'deletechannelbyname' and 'database' in post and 'channelname' in post: dbpath = pilib.dbnametopath(post['database']) dblib.sqlitequery(dbpath, 'delete channelname from channels where name=\"' + post['channelname'] + '\"') elif action == 'updatecameraimage': output['message'] += 'Take camera image keyword. ' import cupid.camera if 'width' in post: width = post['width'] else: width = 800 try: values = cupid.camera.takesnap(width=width) except: output['message'] += 'Error taking image. ' else: output['message'] += 'Appears successful. Path : ' + values['imagepath'] + '. Timestamp : ' + values['timestamp'] + '. ' output['data'] = values elif action == 'getcurrentcamtimestamp': output['message'] += 'getcurrentcamtimestamp keyword found. ' try: with open('/var/www/webcam/images/current.jpg.timestamp') as f: data = f.read() except: output['message'] += 'Error reading file as requested. ' else: output['data'] = data else: output['message'] += 'Action keyword present(' + action + '), but not handled. ' else: output['message'] += 'Authentication unsuccessful or action not authorized.' status = '401 Not Authorized' foutput = json.dumps(output, indent=1) response_headers = [('Content-type', 'application/json')] start_response(status, response_headers) return [foutput]