def rebuildnotificationsdb(tabledict=['queuednotifications', 'sentnotifications']): from iiutilities.dblib import sqlitemultquery from cupid.pilib import dirs runquery = False querylist = [] addentries = True table = 'queuednotifications' if table in tabledict: runquery = True querylist.append('drop table if exists ' + table) querylist.append( "create table " + table + " ( queuedtime text default '', type text default 'email', message text default '', options text default '')") table = 'sentnotifications' if table in tabledict: runquery = True querylist.append('drop table if exists ' + table) querylist.append( "create table " + table + " ( queuedtime text default '', senttime text default '', type text default 'email', message text default '', options text default '')") if runquery: print(querylist) sqlitemultquery(dirs.dbs.notifications, querylist)
def rebuildusersdata(argument=None): from pilib import gethashedentry, dirs from iiutilities.dblib import sqlitemultquery querylist = [] runquery = True querylist.append('drop table if exists users') enteringusers = True runquery = False index = 1 querylist.append( 'create table users (id integer primary key not null, name text not null, password text not null, email text not null, temp text not null, authlevel integer default 0)') if argument == 'defaults': runquery = True entries = [{'user': '******', 'password': '******', 'email': '*****@*****.**', 'authlevel': 1}, {'user': '******', 'password': '******', 'email': '*****@*****.**', 'authlevel': 4}, {'user': '******', 'password': '******', 'email': '*****@*****.**', 'authlevel': 3}] index = 1 for entry in entries: hashedentry = gethashedentry(entry['user'], entry['password']) querylist.append( "insert into users values(" + str(index) + ",'" + entry['user'] + "','" + hashedentry + "','" + entry[ 'email'] + "',''," + str(entry['authlevel']) + ")") index += 1 else: while enteringusers: validentry = True userinput = raw_input("Enter username or Q to stop: ") if userinput == 'Q': print('exiting ...') break passone = raw_input("Enter password: "******"Confirm password: "******"Enter user email") authlevelentry = raw_input("Enter authorization level (0-5)") if passone != passtwo: validentry = False print('passwords do not match') if not len(passone) >= 6: validentry = False print('passwords must be at least six characters') if not emailentry.find('@') > 0: validentry = False print('Email does not appear to be valid') if validentry: hashedentry = gethashedentry(userinput, passone) querylist.append("insert into users values(" + str( index) + ",'" + userinput + "','" + hashedentry + "','" + emailentry + "',''," + authlevelentry + ")") index += 1 runquery = True if runquery: print(querylist) sqlitemultquery(dirs.dbs.users, querylist)
def rebuildstockdb(tablelist=None): from iiutilities.dblib import sqlitemultquery from inventory.inventorylib import sysvars from iiutilities import datalib dbpath = sysvars.dirs.dbs.stock thetime = datalib.gettimestring() if not tablelist: tablelist = ['stock'] # Create databases entries or leave them empty? addentries = True querylist = [] runquery = False ### Stock table = 'stock' if table in tablelist: runquery = True querylist.append('drop table if exists ' + table) querylist.append( "create table " + table + " (partid text primary key, status text default 'active'," + "description text default '', qtyunit text default 'each', qtystock real default 0, qtyonorder real default 0," + "qtyreserved real default 0, qtyavailable real default 0, qtystatus text default '', cost real default 0," + "stockcost real default 0, onordercost real default 0, totalcost real default 0," + "stockprice real default 0, onorderprice real default 0, totalprice real default 0," + "costqty real default 1, costqtyunit text default 'each', supplier text default '', " + "supplierpart text default '', manufacturer text default '', manufacturerpart text default '', " + "notes text default '', partdata text default '', datasheet text default '', inuse integer default 1, datecreated text default '', " + "createdby text default '', inventory integer text default 'std', minqty text default 0, type text default parts," + "marginmethod text default 'type', margin real default 0, price real default 0 )") if addentries: querylist.append("insert into " + table + " values ('A001', 'active', 'WIEGMANN 12x12x6', 'each', 1, 1, 1, \ 0, '', 149.97, 0,0,0,0,0,0,1, 'each', \ 'Cascade Controls', 'N412121206C', 'Wiegmann', 'N412121206C', '', '', '', 1, '" + thetime + "', 'CCR', \ 'std', 0, 'parts', 'type', 0, 0)") querylist.append("insert into " + table + " values ('A002', 'active', 'WIEGMANN 16x16x6', 'each', 1, 1, 2, \ 0, '', 172, 0,0,0,0,0,0,1, 'each', \ 'Cascade Controls', 'N412121206C', 'Wiegmann', 'N412121206C', '', '', '', 1, '" + thetime + "', 'CCR', \ 'std', 0, 'parts', 'type', 0, 0)") querylist.append("insert into " + table + " values ('A003', 'active', 'WIEGMANN 20x20x6', 'each', 1, 1, 2, \ 0, '', 204, 0,0,0,0,0,0,1, 'each', \ 'Cascade Controls', 'N412121206C', 'Wiegmann', 'N412121206C', '', '', '', 1, '" + thetime + "', 'CCR', 'std', 0, 'parts', 'type', 0, 0)") querylist.append("insert into " + table + " values ('A004', 'active', 'WIEGMANN 20x24x6', 'each', 1, 1, 2,\ 0,'', 233, 0,0,0,0,0,0,1, 'each', \ 'Cascade Controls', 'N412121206C', 'Wiegmann', 'N412121206C', '', '', '', 1, '" + thetime + "', 'CCR', 'std', 0, 'parts', 'type', 0, 0)") querylist.append("insert into " + table + " values ('L001', 'active', 'Shop Labor', 'hour', 1, 1, 2,\ 0, '', 42, 0,0,0,0,0,0,1, 'hour', \ '', '', '', '', '', '', '', 1, '" + thetime + "', 'CCR', 'std', 0, 'labor', 'type', 0, 0)") print(querylist) print(dbpath) sqlitemultquery(dbpath, querylist)
def rebuildsessiondb(): from iiutilities.dblib import sqlitemultquery from inventorylib import sysvars querylist = [] ### Session limits table = 'sessionlimits' querylist.append('drop table if exists ' + table) querylist.append("create table " + table + " (username text primary key, sessionsallowed real default 5 )") querylist.append("insert into " + table + " values ('viewer', 5)") querylist.append("insert into " + table + " values ('controller', 5)") querylist.append("insert into " + table + " values ('administrator', 5)") querylist.append("insert into " + table + " values ('owner', 3)") querylist.append("insert into " + table + " values ('admin', 3)") querylist.append("insert into " + table + " values ('colin', 5)") ### Settings table table = 'settings' querylist.append('drop table if exists ' + table) querylist.append( "create table " + table + " (sessionlength real default 600, sessionlimitsenabled real default 1, updatefrequency real)") querylist.append("insert into " + table + " values (600,1,30)") ### Session table table = 'sessions' querylist.append('drop table if exists ' + table) querylist.append( "create table " + table + " (username text, sessionid text, sessionlength real, timecreated text, apparentIP text , realIP text)") ### Sessions summary table = 'sessionsummary' querylist.append('drop table if exists ' + table) querylist.append("create table " + table + " (username text, sessionsactive real)") querylist.append("insert into " + table + " values ('viewer', 0)") querylist.append("insert into " + table + " values ('controller', 0)") querylist.append("insert into " + table + " values ('administrator', 0)") ### Session log table = 'sessionlog' querylist.append('drop table if exists ' + table) querylist.append( "create table " + table + " (username text, sessionid text, time text, action text, apparentIP text, realIP text)") # print(querylist) sqlitemultquery(sysvars.dirs.dbs.authlog, querylist)
def recordspidata(database, valuedict, execute=False): from iiutilities import dblib, datalib # This is incomplete and hardcoded partially querylist = [] for key, value in valuedict.items(): querylist.append(dblib.makesqliteinsert('inputs', valuelist=[key, 'SPI1', 'TC', '1', 'SPITC1', value, 'F', datalib.gettimestring(), 1, '',''])) querylist.append(dblib.makesqliteinsert('ioinfo', valuelist=[key, key, ''])) if execute: dblib.sqlitemultquery(database, querylist) return querylist
def updateowfstable(database, tablename, busdevices, execute=True): from iiutilities.dblib import sqlitemultquery from iiutilities.dblib import makesqliteinsert querylist = [] for device in busdevices: # print(device.id) # print([device.address, device.family, device.id, device.type, device.crc8]) querylist.append( makesqliteinsert(tablename, [device.address, device.family, device.id, device.type, device.crc8])) # print(querylist) if execute: # print(database) # print(querylist) sqlitemultquery(database, querylist) return querylist
def updateowfstable(database, tablename, busdevices, execute=True): from iiutilities.dblib import sqlitemultquery from iiutilities.dblib import makesqliteinsert querylist = [] for device in busdevices: # print(device.id) # print([device.address, device.family, device.id, device.type, device.crc8]) querylist.append( makesqliteinsert(tablename, [ device.address, device.family, device.id, device.type, device.crc8 ])) # print(querylist) if execute: # print(database) # print(querylist) sqlitemultquery(database, querylist) return querylist
def rebuildsystemdb(tablelist=None): from iiutilities.dblib import sqlitemultquery from inventory.inventorylib import sysvars dbpath = sysvars.dirs.dbs.system if not tablelist: tablelist = ['calcs', 'uisettings'] querylist = [] runquery = False ### Calcs table = 'calcs' if table in tablelist: runquery = True querylist.append('drop table if exists ' + table) querylist.append( "create table " + table + " (item text primary key, value text, notes text, detail text)") addentries = True if addentries: querylist.append("insert into " + table + " values ('partsmargin', '0.25', '', '')") querylist.append("insert into " + table + " values ('labormargin', '0.25', '', '')") querylist.append("insert into " + table + " values ('panelsizeoverheadmultiplier', '0.15', 'Dollars per \ inch for miscellaneous parts.', '')") ### UISettings table = 'uisettings' if table in tablelist: runquery = True querylist.append('drop table if exists ' + table) querylist.append( "create table " + table + " (item text primary key, value text, notes text, detail text)") if runquery: sqlitemultquery(dbpath, querylist)
def getdatameta(database, **kwargs): settings = { 'get_time_span':True } settings.update(kwargs) tablenames = dblib.gettablenames(database) if 'metadata' in tablenames: tablenames.remove('metadata') queryarray = [] for tablename in tablenames: queryarray.append("select count(*) from '" + tablename + "'") results = dblib.sqlitemultquery(database, queryarray, **kwargs)['data'] meta = [] for result, tablename in zip(results, tablenames): this_meta = {} this_meta['tablename'] = tablename this_meta['numpoints'] = result[0][0] # Quick hacky way to know if this is an archive log or not if tablename == 'data': from os.path import split db_name = split(database)[1] types = table_name_to_type(db_name) else: types = table_name_to_type(tablename) this_meta['type'] = types['type'] this_meta['subtype'] = types['subtype'] this_meta['id'] = types['id'] if settings['get_time_span']: timespan = dblib.gettimespan(database, tablename)['seconds'] this_meta['timespan'] = timespan meta.append(this_meta) return meta
def getdatameta(database, **kwargs): settings = {'get_time_span': True} settings.update(kwargs) tablenames = dblib.gettablenames(database) if 'metadata' in tablenames: tablenames.remove('metadata') queryarray = [] for tablename in tablenames: queryarray.append("select count(*) from '" + tablename + "'") results = dblib.sqlitemultquery(database, queryarray, **kwargs)['data'] meta = [] for result, tablename in zip(results, tablenames): this_meta = {} this_meta['tablename'] = tablename this_meta['numpoints'] = result[0][0] # Quick hacky way to know if this is an archive log or not if tablename == 'data': from os.path import split db_name = split(database)[1] types = table_name_to_type(db_name) else: types = table_name_to_type(tablename) this_meta['type'] = types['type'] this_meta['subtype'] = types['subtype'] this_meta['id'] = types['id'] if settings['get_time_span']: timespan = dblib.gettimespan(database, tablename)['seconds'] this_meta['timespan'] = timespan meta.append(this_meta) return meta
def rebuildsafedb(tabledict={'usermeta':True, 'users':True, 'pathaliases':True}): """ System safe database. Contains users and other info that we do not want in the web path. """ from iiutilities import datalib, dblib from inventory import inventorylib table = 'usermeta' if table in tabledict: createentries = True querylist = ['drop table if exists ' + table] querylist.append( "create table " + table + " (user text primary key, data text)") if createentries: querylist.append("insert into " + table + " values('creese','pathalias:iiinventory')") querylist.append("insert into " + table + " values('demo','pathalias:demo')") querylist.append("insert into " + table + " values('iwalker','pathalias:isaac')") querylist.append("insert into " + table + " values('mbertram','pathalias:demo')") try: print(querylist) print(inventorylib.sysvars.dirs.dbs.safe) dblib.sqlitemultquery(inventorylib.sysvars.dirs.dbs.safe, querylist) except: print('ERROR in usermeta query') table = 'pathaliases' if table in tabledict: runquery = True createentries = True querylist =['drop table if exists ' + table] querylist.append( "create table " + table + " (alias text primary key, path text)") if createentries: querylist.append("insert into " + table + " values('iiinventory','iiinventory')") querylist.append("insert into " + table + " values('demo','demo')") try: print(querylist) print(inventorylib.sysvars.dirs.dbs.safe) dblib.sqlitemultquery(inventorylib.sysvars.dirs.dbs.safe, querylist) except: print('Error in ' + table + ' query') table = 'users' if table in tabledict: ### No default tables. Create a table as an example querylist=['drop table if exists ' + table, "create table " + table + " ( id integer primary key not null, name text unique, password text, " + "email text, accesskeywords text, authlevel integer default 1, " + "temp text, admin integer default 0)"] addentries = True if addentries: entries = [{'name': 'creese', 'password': '******', 'email': '*****@*****.**', 'accesskeywords': 'iiinventory,demo', 'authlevel':5, 'temp': '', 'admin': 1}, {'name': 'iwalker', 'password': '******', 'email': '*****@*****.**', 'accesskeywords': 'demo', 'authlevel':4, 'temp':'', 'admin': 0}, {'name': 'demo', 'password': '******', 'email': '*****@*****.**', 'accesskeywords': 'demo', 'authlevel':2, 'temp':'', 'admin': 0}, {'name': 'mbertram', 'password': '******', 'email': '*****@*****.**', 'accesskeywords': 'demo', 'authlevel': 2, 'temp': '', 'admin': 0}] index = 1 for entry in entries: hashedentry = datalib.gethashedentry(entry['name'], entry['password'], salt=inventorylib.sysvars.salt) querylist.append(dblib.makesqliteinsert(table, [index, entry['name'], hashedentry, entry['email'], entry['accesskeywords'], entry['authlevel'], '', entry['admin']])) index += 1 try: print(querylist) print(inventorylib.sysvars.dirs.dbs.safe) dblib.sqlitemultquery(inventorylib.sysvars.dirs.dbs.safe, querylist) except: print('Error in ' + table + ' query')
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 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) import inventorylib from iiutilities import dblib, datalib 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' try: try: output['remote_ip'] = environ['HTTP_X_FORWARDED_FOR'].split(',')[-1].strip() except KeyError: output['remote_ip'] = environ['REMOTE_ADDR'] except: output['remote_ip'] = 'Error getting IP address' """ Here we verify credentials of session data against those in the database. While we authenticate in the browser, this does not stop POST queries to the API without the page provided So we take the hpass stored in the dictionary and verify. * Which databases are available are stored in users table, column accesskeywords * Which one is currently in use is stored in table usermeta, data where user=username. data is json-encoded metadata pathalias field * What path extension this corresponds to is stored in pathaliases """ # I dont' think this will be used. We will get pathalias from database. Let's deal with changing it later. # First, let's get our pathalias and translate to a path, using our path reloader # if 'pathalias' in post: # output['message'] += inventorylib.reloaddatapaths(pathalias=post['pathalias']) # else: # output['message'] += 'No pathalias found in postictionary. ' wsgiauth = True authverified = False if wsgiauth: # Verfiy that session login information is legit: hashed password, with salt and username, match # hash stored in postatabase. import hashlib safe_database = dblib.sqliteDatabase(inventorylib.sysvars.dirs.dbs.safe) 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'] + '". ' user_data = {'accesskeywords':'demo','admin':False} else: # Get session hpass to verify credentials hashedpassword = post['hpass'] hname = hashlib.new('sha1') hname.update(post['username'].encode('utf-8')) hashedname = hname.hexdigest() hentry = hashlib.new('md5') hentry.update((hashedname + inventorylib.sysvars.salt + hashedpassword).encode('utf-8')) hashedentry = hentry.hexdigest() if hashedentry == user_data['password']: # successful auth output['message'] += 'Password verified. ' authverified = True # output['message'] += 'accesskeywords : ' + str(userdata) output['accesskeywords'] = user_data['accesskeywords'] if output['accesskeywords'].find(',') >= 0: accesskeywords = output['accesskeywords'].split(',') accesskeywords = [accesskeyword.strip() for accesskeyword in accesskeywords] else: accesskeywords = output['accesskeywords'].strip() path_aliases = safe_database.read_table('pathaliases') # Find usermeta entry and grab which database is selected. If one is not selected, update selection # to first that user is allowed to access try: user_meta_row = safe_database.read_table_row('usermeta', condition="user='******'username'] + "'")[0] except: print('error getting usermeta for username ' + post['username']) output['message'] += 'error getting usermeta for username ' + post['username'] user_meta_row = [] return path_alias = '' if not user_meta_row: output['message'] += 'User meta entry not found. Attempting to create. ' # assign default database default_database = accesskeywords[0] output['message'] += 'Choosing pathalias from first in keywords: ' + default_database + '. ' if any(default_database == path_alias['alias'] for path_alias in path_aliases): output['message'] += 'Verified that default alias exists in pathaliases database. ' else: output['message'] += 'ERROR: first entry in keywords (' +default_database + ') not found in aliases. ' # Insert usermeta entry. This should never happen. safe_database.insert('usermeta', {'user':post['username'], 'data':'pathalias:' + default_database}) path_alias = default_database else: output['message'] += 'User meta entry found with text ' + str(user_meta_row) + '. ' # Parse the string into json and ensure that the pathalias is in there user_meta_dict = datalib.parseoptions(user_meta_row['data']) if 'pathalias' in user_meta_dict: path_alias = user_meta_dict['pathalias'] output['message'] += 'pathalias found: ' + user_meta_dict['pathalias'] + '. ' if any(path_alias == stored_path_alias['alias'] for stored_path_alias in path_aliases): output['message'] += 'Verified that default alias exists in pathaliases database. ' if path_alias: # reload datapaths with path alias reload_message = inventorylib.reloaddatapaths(pathalias=path_alias) # DEFINITELY COMMENT THIS OUT FOR SECURITY SAKE (absolute paths are secret!!) output['message'] += reload_message else: # successful auth output['message'] += 'Failed password check. ' else: # Demo status authverified = True user_data = {'authlevel':0} else: output['message'] += 'WSGI authorization not enabled. ' if authverified or not wsgiauth: output['authorized'] = True else: output['authorized'] = False try: action = post['action'] except KeyError: output['message'] = 'no action in request' action = '' if output['authorized'] and action: output['action_allowed'] = inventorylib.check_action_auths(action, user_data['authlevel']) else: output['action_allowed'] = False if output['authorized'] and output['action_allowed']: # Stock functions if action == 'addeditpart': output['message'] += 'addpart keyword found. ' inventorylib.addeditstockpart(post, output) inventorylib.calcstockfromall() elif action == 'copypart': output['message'] += 'copypart keyword found. ' inventorylib.copystockpart(post, output) inventorylib.calcstockfromall() elif action == 'deleteparts': output['message'] += 'deleteparts keyword found. ' inventorylib.deletestockparts(post, output) inventorylib.calcstockfromall() elif action == 'gettrackedpartdata': output['message'] += 'gettrackedpartdata keyword found. ' output['data'] = inventorylib.calcstockfromall(**post)['trackedpart'] elif action =='generateorders': output['message'] += 'generate orders keyword found. ' inventorylib.generateandaddorders() # Inventory functions # Edit and add are separated, as names are autogenerated elif action == 'editinventory': output['message'] += 'editinventory keyword found. ' inventorylib.editinventory(post, output) inventorylib.calcstockfromall() elif action == 'addinventory': output['message'] += 'addinventory keyword found. ' inventorylib.createnewinventory(post, output) inventorylib.makeinventorymetadata() inventorylib.calcstockfromall() elif action == 'deleteinventories': output['message'] += 'deleteinventories keyword found. ' inventorylib.deleteinventories(post, output) inventorylib.makeinventorymetadata() inventorylib.calcstockfromall() elif action == 'addeditinventorypart': output['message'] += 'addeditinventorypart keyword found. ' inventorylib.addeditpartlist(post, output) inventorylib.makeinventorymetadata() inventorylib.calcstockfromall() elif action == 'deletepartsfrominventory': output['message'] += 'deletepartsfrominventory keyword found. ' inventorylib.deletepartsfrominventory(post, output) inventorylib.makeinventorymetadata() inventorylib.calcstockfromall() # Order functions elif action == 'editorder': output['message'] += 'editorder keyword found. ' inventorylib.editorder(post, output) inventorylib.makeordermetadata() inventorylib.calcstockfromall() elif action == 'addorder': output['message'] += 'addorder keyword found. ' inventorylib.createneworder(post, output) inventorylib.makeordermetadata() inventorylib.calcstockfromall() elif action == 'deleteorders': output['message'] += 'deleteorders keyword found. ' inventorylib.deleteorders(post, output) inventorylib.makeordermetadata() inventorylib.calcstockfromall() elif action == 'addeditorderpart': output['message'] += 'addeditorderpart keyword found. ' inventorylib.addeditpartlist(post, output) inventorylib.makeordermetadata() inventorylib.calcstockfromall() elif action == 'addeditorderparts': output['message'] += 'addeditorderparts keyword found. ' if 'partsdata' in post: post['partsdata'] = json.loads(post['partsdata']) inventorylib.addeditpartlist(post, output) inventorylib.makeordermetadata() inventorylib.calcstockfromall() elif action == 'deletepartsfromorder': output['message'] += 'deletepartsfromorder keyword found. ' inventorylib.deletepartsfromorder(post, output) inventorylib.makeordermetadata() inventorylib.calcstockfromall() # BOM functions elif action == 'copybom': output['message'] += 'copybom keyword found. ' inventorylib.copybom(post, output) inventorylib.makebommetadata() elif action == 'addeditbom': output['message'] += 'addeditbom keyword found. ' inventorylib.addeditbom(post, output) inventorylib.makebommetadata() elif action == 'addeditbomparts': output['message'] += 'addeditbomparts keyword found. ' # Operate on partsdata post['partsdata'] = json.loads(post['partsdata']) inventorylib.addeditpartlist(post, output) inventorylib.makebommetadata() elif action == 'getbomcalcs': output['message'] += 'getbomcalcs keyword found. ' inventorylib.calcbomprice(post, output) elif action == 'getquotecalcs': output['message'] += 'getquotecalcs keyword found. ' output['message'] += 'function not written yet. ' # inventorylib.calcbomprice(post, output) elif action == 'deletepartsfrombom': output['message'] += 'deletepartsfrombom keyword found. ' inventorylib.deletepartsfrombom(post, output) inventorylib.makebommetadata() elif action == 'deleteboms': output['message'] += 'deleteboms keyword found. ' inventorylib.deleteboms(post, output) inventorylib.makebommetadata() # Assembly functions elif action == 'copyassembly': output['message'] += 'copyassembly keyword found. ' inventorylib.copyassembly(post, output) inventorylib.makeassemblymetadata() inventorylib.calcstockfromall() elif action == 'copybomintoassembly': output['message'] += 'copybomintoassembly keyword found. ' inventorylib.copybomintoassembly(post, output) inventorylib.makeassemblymetadata() inventorylib.calcstockfromall() elif action == 'addeditassembly': output['message'] += 'addeditassembly keyword found. ' inventorylib.addeditassembly(post, output) inventorylib.makeassemblymetadata() inventorylib.calcstockfromall() elif action == 'addeditassemblyparts': output['message'] += 'addeditassemblypart keyword found. ' post['partsdata'] = json.loads(post['partsdata']) inventorylib.addeditpartlist(post, output) inventorylib.makeassemblymetadata() inventorylib.calcstockfromall() elif action == 'getassemblycalcs': output['message'] += 'getassemblycalcs keyword found. ' inventorylib.calcassemblyprice(post, output) elif action == 'deletepartsfromassembly': output['message'] += 'deletepartsfromassembly keyword found. ' inventorylib.deletepartsfromassembly(post, output) inventorylib.makeassemblymetadata() inventorylib.calcstockfromall() elif action == 'deleteassemblys': output['message'] += 'deleteassemblys keyword found. ' inventorylib.deleteassemblies(post, output) inventorylib.makeassemblymetadata() inventorylib.calcstockfromall() # Quotes elif action == 'deletequotes': output['message'] += 'deletequotes keyword found. ' inventorylib.deletequotes(post, output) inventorylib.makebommetadata(database=inventorylib.sysvars.dbs.quotes) elif action == 'copyquotetoboms': output['message'] += 'copyquotetoboms keyword found. ' inventorylib.copyquotetoboms(post, output) inventorylib.makebommetadata() # Export functions elif action == 'exportbomtopdf': output['message'] += 'exportbomtopdf keyword found. ' inventorylib.writepanelbomtopdf(post, output) thetime = datalib.gettimestring() cleantime = thetime.replace(' ', '_').replace(':', '_') # Get bom from boms database bom = inventorylib.sysvars.dbs.boms.read_table(post['name']) cleanbomname = post['name'].replace(' ','_').replace(':','_') filename = cleanbomname + '_' + cleantime outputroot = '/var/www/html/panelbuilder/data/downloads/' weblink = 'https://panelbuilder.interfaceinnovations.org/data/downloads/' + filename inventorylib.writepanelbomtopdf(**{'bomdata': bom, 'title': 'Bom generated from ' + post['name'] + ' ' + cleantime, 'outputfile': outputroot + filename}) output['data']['weblink'] = weblink elif action == 'exportassemblytopdf': output['message'] += 'exportassemblytopdf keyword found. ' thetime = datalib.gettimestring() cleantime = thetime.replace(' ', '_').replace(':', '_') # Get bom from boms database assemblydata = inventorylib.sysvars.dbs.assemblies.read_table(post['name']) cleanname = post['name'].replace(' ','_').replace(':','_') filename = cleanname + '_' + cleantime + '.pdf' outputroot = '/var/www/html/panelbuilder/data/downloads/' weblink = 'https://panelbuilder.interfaceinnovations.org/data/downloads/' + filename inventorylib.writepanelbomtopdf(**{'bomdata': assemblydata, 'title': 'Bom generated from ' + post['name'] + ' ' + thetime, 'format':'picklist','outputfile': outputroot + filename}) output['data'] = {'assemblydata':assemblydata} output['weblink'] = weblink # Panel builder elif action in ['panelcalcs', 'panelcalcsgenquote']: output['message'] += 'panelcalc keyword found. ' import panelbuilder for key,value in post.items(): # print(key, value) pass if 'paneldesc' in post: import json post['paneldesc'] = json.loads(post['paneldesc']) bomresults = panelbuilder.paneltobom(**post) output['data'] = {} # d needs to have a 'paneldesc' key with the panel spec data in it. output['data']['bomdescription'] = bomresults['bomdescription'] output['data']['options'] = bomresults['options'] output['data']['bomcalcs'] = inventorylib.calcbomprice({'bomdictarray':bomresults['bom']})['data'] output['message'] += bomresults['message'] # We don't actually want to return the full boms by default. We don't want this in the client, and it's # lot of data anyway if 'returnfullboms' not in post: for option, value in output['data']['options'].items(): if 'bom' in value: print('Deleting bom from option ' + str(option)) del output['data']['options'][option]['bom'] if 'flatbom' in value: print('Deleting flatbom from option ' + str(option)) del output['data']['options'][option]['flatbom'] if action == 'panelcalcsgenquote': thetime = datalib.gettimestring() cleantime = thetime.replace(' ','_').replace(':','_') outputroot = '/var/www/html/panelbuilder/data/downloads/' if 'paneltype' in post['paneldesc'] and post['paneldesc']['paneltype'] == 'brewpanel': datedquotefilename = 'panelbuilder_brew_quote_' + cleantime + '.pdf' datedbomfilename = 'panelbuilder_brew_bom_' + cleantime + '.pdf' genericquotefilename = 'panelbuilder_brew_quote.pdf' genericbomfilename = 'panelbuilder_brew_bom.pdf' elif 'paneltype' in post['paneldesc'] and post['paneldesc']['paneltype'] == 'temppanel': datedquotefilename = 'panelbuilder_temp_quote_' + cleantime + '.pdf' datedbomfilename = 'panelbuilder_temp_bom_' + cleantime + '.pdf' genericquotefilename = 'panelbuilder_temp_quote.pdf' genericbomfilename = 'panelbuilder_temp_bom.pdf' else: datedquotefilename = 'panelbuilder_quote_' + cleantime + '.pdf' datedbomfilename = 'panelbuilder_bom_' + cleantime + '.pdf' genericquotefilename = 'panelbuilder_quote.pdf' genericbomfilename = 'panelbuilder_bom.pdf' weblink = 'https://panelbuilder.interfaceinnovations.org/data/downloads/' + datedquotefilename # until we can get this to format properly in the pdf, we are going to leave it generic # description = output['data']['bomdescription'] description = 'Control panel quote generated by panelbuilder.' datedquotes = True # Create quote pdf from BOM if datedquotes: inventorylib.writepanelquotetopdf(**{'bomdata': bomresults['bom'], 'options': bomresults['options'], 'title':'Quote auto-generated by panelbuilder \t\t' + datalib.gettimestring(), 'price': str(output['data']['bomcalcs']['totalprice']), 'outputfile': outputroot + datedquotefilename, 'description':description}) inventorylib.writepanelquotetopdf(**{'bomdata': bomresults['bom'], 'options': bomresults['options'], 'title':'Quote auto-generated by panelbuilder '+ thetime, 'price': output['data']['bomcalcs']['totalprice'], 'outputfile':outputroot + genericquotefilename}) # Create database entry BOM # Create table # print('** DATABASE') # print(panelbuilder.sysvars.dirs.dbs.quotes) bomname = 'quote_' + cleantime inventorylib.addeditbom({'bomdata':{'name':bomname}, 'database':panelbuilder.sysvars.dirs.dbs.quotes}, output) # print('** BOM **') # print(bomresults['bom']) inserts = [] for part in bomresults['bom']: inserts.append(dblib.makesqliteinsert(bomname, [part['partid'],part['qty']], ['partid','qty'])) dblib.sqlitemultquery(inventorylib.sysvars.dirs.dbs.quotes, inserts) inventorylib.makebommetadata(database=inventorylib.sysvars.dbs.quotes) # inventorylib.addeditpartlist(post, output) # Create pdfs if datedquotes: inventorylib.writepanelbomtopdf(**{'bomdata': bomresults['bom'], 'options': bomresults['options'], 'title':'Quote auto-generated by panelbuilder ' + thetime, 'outputfile': outputroot + datedbomfilename}) inventorylib.writepanelbomtopdf(**{'bomdata': bomresults['bom'], 'title': 'panelbuilder BOM generated ' + thetime, 'outputfile': outputroot + genericbomfilename, 'totalprice': output['data']['bomcalcs']['totalprice']}) output['data']['quotelink'] = weblink from iiutilities.utility import gmail mymail = gmail(subject="Quote generated") mymail.message = 'Quote generated at ' + cleantime + '\r\n' if 'remote_ip' in output: mymail.message = 'IP address ' + output['remote_ip'] + '\r\n' mymail.message += bomresults['bomdescription'] mymail.recipient = '*****@*****.**' mymail.sender = 'II Panelbuilder' mymail.send() # Multi-use elif action == 'reloaditemdatafromstock': output['message'] += 'reloaditemdatafromstock keyword found. ' inventorylib.refreshpartsfromstock(post, output) if 'bomname' in post: inventorylib.recalcpartdata(bomname=post['bomname']) inventorylib.makebommetadata() elif 'assemblyame' in post: inventorylib.recalcpartdata(assemblyname=post['assemblyname']) inventorylib.makeassemblymetadata() # Generic functions elif action == 'gettablenames': dbpath = inventorylib.dbnametopath(post['database']) try: output['data'] = dblib.gettablenames(dbpath) except: output['message'] += 'Error getting table names' elif action == 'switchtablerows': dbpath = inventorylib.dbnametopath(post['database']) dblib.switchtablerows(dbpath, post['tablename'], post['row1'], post['row2'], post['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 post: dbpath = inventorylib.dbnametopath(post['database']) if dbpath: output['message'] += 'Friendly name ' + post['database'] + ' translated to path ' + dbpath + ' successfully. ' 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 = 1 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[]']): try: length = lengths[index] except IndexError: length = fixedlength try: start = starts[index] except IndexError: start = fixedstart data.append(dblib.dynamicsqliteread(dbpath, table, start, length)) 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'] = dblib.dynamicsqliteread(dbpath, 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'] = dblib.dynamicsqliteread(dbpath, post['tablename'], post['row']) output['querytime'] = time() - thetime elif 'tablename' in post: # Handle entire table output['message'] += 'Tablename keyword: ' + post['tablename'] + '. ' thetime = time() if 'condition' in post: if not post['condition'] == '': output['data'] = dblib.dynamicsqliteread(dbpath, post['tablename'], condition=post['condition']) else: output['data'] = dblib.dynamicsqliteread(dbpath, post['tablename']) else: try: output['data'] = dblib.dynamicsqliteread(dbpath, post['tablename']) except: output['message'] += 'Error retrieving data. ' else: output['message'] += 'Data query appears successful. ' output['querytime'] = time() - thetime else: output['message'] += 'Friendly name ' + post['database'] + ' unsuccessfully translated. ' else: output['message'] += 'No database present in action request' else: output['message'] = 'no command matched for action "' + action + '"' else: # status = '403 Forbidden' output['message'] += 'Not authorized for this action (or perhaps at all?) ' if 'data' in output: if output['data']: newetag = hashlib.md5(str(output['data']).encode('utf-8')).hexdigest() if 'etag' in post: if newetag == post['etag']: status = '304 Not Modified' output['data'] = '' else: newetag='' else: newetag='' if 'datasize' in post: output['datasize'] = sys.getsizeof(output['data']) output['etag'] = newetag # try: foutput = json.dumps(output, indent=1) # except: # import csv # w = csv.writer(open("/usr/lib/iicontrollibs/inventory/dumperr.log", "w")) # for key, val in output.items(): # w.writerow([key, val]) response_headers = [('Content-type', 'application/json')] response_headers.append(('Etag',newetag)) start_response(status, response_headers) return foutput.encode('utf-8')
def application(environ, start_response): 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) import inventorylib from iiutilities import dblib, datalib 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' try: try: output['remote_ip'] = environ['HTTP_X_FORWARDED_FOR'].split( ',')[-1].strip() except KeyError: output['remote_ip'] = environ['REMOTE_ADDR'] except: output['remote_ip'] = 'Error getting IP address' """ Here we verify credentials of session data against those in the database. While we authenticate in the browser, this does not stop POST queries to the API without the page provided So we take the hpass stored in the dictionary and verify. * Which databases are available are stored in users table, column accesskeywords * Which one is currently in use is stored in table usermeta, data where user=username. data is json-encoded metadata pathalias field * What path extension this corresponds to is stored in pathaliases """ # I dont' think this will be used. We will get pathalias from database. Let's deal with changing it later. # First, let's get our pathalias and translate to a path, using our path reloader # if 'pathalias' in post: # output['message'] += inventorylib.reloaddatapaths(pathalias=post['pathalias']) # else: # output['message'] += 'No pathalias found in postictionary. ' wsgiauth = True authverified = False if wsgiauth: # Verfiy that session login information is legit: hashed password, with salt and username, match # hash stored in postatabase. import hashlib safe_database = dblib.sqliteDatabase( inventorylib.sysvars.dirs.dbs.safe) 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'] + '". ' user_data = {'accesskeywords': 'demo', 'admin': False} else: # Get session hpass to verify credentials hashedpassword = post['hpass'] hname = hashlib.new('sha1') hname.update(post['username'].encode('utf-8')) hashedname = hname.hexdigest() hentry = hashlib.new('md5') hentry.update((hashedname + inventorylib.sysvars.salt + hashedpassword).encode('utf-8')) hashedentry = hentry.hexdigest() if hashedentry == user_data['password']: # successful auth output['message'] += 'Password verified. ' authverified = True # output['message'] += 'accesskeywords : ' + str(userdata) output['accesskeywords'] = user_data['accesskeywords'] if output['accesskeywords'].find(',') >= 0: accesskeywords = output['accesskeywords'].split(',') accesskeywords = [ accesskeyword.strip() for accesskeyword in accesskeywords ] else: accesskeywords = output['accesskeywords'].strip() path_aliases = safe_database.read_table('pathaliases') # Find usermeta entry and grab which database is selected. If one is not selected, update selection # to first that user is allowed to access try: user_meta_row = safe_database.read_table_row( 'usermeta', condition="user='******'username'] + "'")[0] except: print('error getting usermeta for username ' + post['username']) output[ 'message'] += 'error getting usermeta for username ' + post[ 'username'] user_meta_row = [] return path_alias = '' if not user_meta_row: output[ 'message'] += 'User meta entry not found. Attempting to create. ' # assign default database default_database = accesskeywords[0] output[ 'message'] += 'Choosing pathalias from first in keywords: ' + default_database + '. ' if any(default_database == path_alias['alias'] for path_alias in path_aliases): output[ 'message'] += 'Verified that default alias exists in pathaliases database. ' else: output[ 'message'] += 'ERROR: first entry in keywords (' + default_database + ') not found in aliases. ' # Insert usermeta entry. This should never happen. safe_database.insert( 'usermeta', { 'user': post['username'], 'data': 'pathalias:' + default_database }) path_alias = default_database else: output[ 'message'] += 'User meta entry found with text ' + str( user_meta_row) + '. ' # Parse the string into json and ensure that the pathalias is in there user_meta_dict = datalib.parseoptions( user_meta_row['data']) if 'pathalias' in user_meta_dict: path_alias = user_meta_dict['pathalias'] output[ 'message'] += 'pathalias found: ' + user_meta_dict[ 'pathalias'] + '. ' if any(path_alias == stored_path_alias['alias'] for stored_path_alias in path_aliases): output[ 'message'] += 'Verified that default alias exists in pathaliases database. ' if path_alias: # reload datapaths with path alias reload_message = inventorylib.reloaddatapaths( pathalias=path_alias) # DEFINITELY COMMENT THIS OUT FOR SECURITY SAKE (absolute paths are secret!!) output['message'] += reload_message else: # successful auth output['message'] += 'Failed password check. ' else: # Demo status authverified = True user_data = {'authlevel': 0} else: output['message'] += 'WSGI authorization not enabled. ' if authverified or not wsgiauth: output['authorized'] = True else: output['authorized'] = False try: action = post['action'] except KeyError: output['message'] = 'no action in request' action = '' if output['authorized'] and action: output['action_allowed'] = inventorylib.check_action_auths( action, user_data['authlevel']) else: output['action_allowed'] = False if output['authorized'] and output['action_allowed']: # Stock functions if action == 'addeditpart': output['message'] += 'addpart keyword found. ' inventorylib.addeditstockpart(post, output) inventorylib.calcstockfromall() elif action == 'copypart': output['message'] += 'copypart keyword found. ' inventorylib.copystockpart(post, output) inventorylib.calcstockfromall() elif action == 'deleteparts': output['message'] += 'deleteparts keyword found. ' inventorylib.deletestockparts(post, output) inventorylib.calcstockfromall() elif action == 'gettrackedpartdata': output['message'] += 'gettrackedpartdata keyword found. ' output['data'] = inventorylib.calcstockfromall( **post)['trackedpart'] elif action == 'generateorders': output['message'] += 'generate orders keyword found. ' inventorylib.generateandaddorders() # Inventory functions # Edit and add are separated, as names are autogenerated elif action == 'editinventory': output['message'] += 'editinventory keyword found. ' inventorylib.editinventory(post, output) inventorylib.calcstockfromall() elif action == 'addinventory': output['message'] += 'addinventory keyword found. ' inventorylib.createnewinventory(post, output) inventorylib.makeinventorymetadata() inventorylib.calcstockfromall() elif action == 'deleteinventories': output['message'] += 'deleteinventories keyword found. ' inventorylib.deleteinventories(post, output) inventorylib.makeinventorymetadata() inventorylib.calcstockfromall() elif action == 'addeditinventorypart': output['message'] += 'addeditinventorypart keyword found. ' inventorylib.addeditpartlist(post, output) inventorylib.makeinventorymetadata() inventorylib.calcstockfromall() elif action == 'deletepartsfrominventory': output['message'] += 'deletepartsfrominventory keyword found. ' inventorylib.deletepartsfrominventory(post, output) inventorylib.makeinventorymetadata() inventorylib.calcstockfromall() # Order functions elif action == 'editorder': output['message'] += 'editorder keyword found. ' inventorylib.editorder(post, output) inventorylib.makeordermetadata() inventorylib.calcstockfromall() elif action == 'addorder': output['message'] += 'addorder keyword found. ' inventorylib.createneworder(post, output) inventorylib.makeordermetadata() inventorylib.calcstockfromall() elif action == 'deleteorders': output['message'] += 'deleteorders keyword found. ' inventorylib.deleteorders(post, output) inventorylib.makeordermetadata() inventorylib.calcstockfromall() elif action == 'addeditorderpart': output['message'] += 'addeditorderpart keyword found. ' inventorylib.addeditpartlist(post, output) inventorylib.makeordermetadata() inventorylib.calcstockfromall() elif action == 'addeditorderparts': output['message'] += 'addeditorderparts keyword found. ' if 'partsdata' in post: post['partsdata'] = json.loads(post['partsdata']) inventorylib.addeditpartlist(post, output) inventorylib.makeordermetadata() inventorylib.calcstockfromall() elif action == 'deletepartsfromorder': output['message'] += 'deletepartsfromorder keyword found. ' inventorylib.deletepartsfromorder(post, output) inventorylib.makeordermetadata() inventorylib.calcstockfromall() # BOM functions elif action == 'copybom': output['message'] += 'copybom keyword found. ' inventorylib.copybom(post, output) inventorylib.makebommetadata() elif action == 'addeditbom': output['message'] += 'addeditbom keyword found. ' inventorylib.addeditbom(post, output) inventorylib.makebommetadata() elif action == 'addeditbomparts': output['message'] += 'addeditbomparts keyword found. ' # Operate on partsdata post['partsdata'] = json.loads(post['partsdata']) inventorylib.addeditpartlist(post, output) inventorylib.makebommetadata() elif action == 'getbomcalcs': output['message'] += 'getbomcalcs keyword found. ' inventorylib.calcbomprice(post, output) elif action == 'getquotecalcs': output['message'] += 'getquotecalcs keyword found. ' output['message'] += 'function not written yet. ' # inventorylib.calcbomprice(post, output) elif action == 'deletepartsfrombom': output['message'] += 'deletepartsfrombom keyword found. ' inventorylib.deletepartsfrombom(post, output) inventorylib.makebommetadata() elif action == 'deleteboms': output['message'] += 'deleteboms keyword found. ' inventorylib.deleteboms(post, output) inventorylib.makebommetadata() # Assembly functions elif action == 'copyassembly': output['message'] += 'copyassembly keyword found. ' inventorylib.copyassembly(post, output) inventorylib.makeassemblymetadata() inventorylib.calcstockfromall() elif action == 'copybomintoassembly': output['message'] += 'copybomintoassembly keyword found. ' inventorylib.copybomintoassembly(post, output) inventorylib.makeassemblymetadata() inventorylib.calcstockfromall() elif action == 'addeditassembly': output['message'] += 'addeditassembly keyword found. ' inventorylib.addeditassembly(post, output) inventorylib.makeassemblymetadata() inventorylib.calcstockfromall() elif action == 'addeditassemblyparts': output['message'] += 'addeditassemblypart keyword found. ' post['partsdata'] = json.loads(post['partsdata']) inventorylib.addeditpartlist(post, output) inventorylib.makeassemblymetadata() inventorylib.calcstockfromall() elif action == 'getassemblycalcs': output['message'] += 'getassemblycalcs keyword found. ' inventorylib.calcassemblyprice(post, output) elif action == 'deletepartsfromassembly': output['message'] += 'deletepartsfromassembly keyword found. ' inventorylib.deletepartsfromassembly(post, output) inventorylib.makeassemblymetadata() inventorylib.calcstockfromall() elif action == 'deleteassemblys': output['message'] += 'deleteassemblys keyword found. ' inventorylib.deleteassemblies(post, output) inventorylib.makeassemblymetadata() inventorylib.calcstockfromall() # Quotes elif action == 'deletequotes': output['message'] += 'deletequotes keyword found. ' inventorylib.deletequotes(post, output) inventorylib.makebommetadata( database=inventorylib.sysvars.dbs.quotes) elif action == 'copyquotetoboms': output['message'] += 'copyquotetoboms keyword found. ' inventorylib.copyquotetoboms(post, output) inventorylib.makebommetadata() # Export functions elif action == 'exportbomtopdf': output['message'] += 'exportbomtopdf keyword found. ' inventorylib.writepanelbomtopdf(post, output) thetime = datalib.gettimestring() cleantime = thetime.replace(' ', '_').replace(':', '_') # Get bom from boms database bom = inventorylib.sysvars.dbs.boms.read_table(post['name']) cleanbomname = post['name'].replace(' ', '_').replace(':', '_') filename = cleanbomname + '_' + cleantime outputroot = '/var/www/html/panelbuilder/data/downloads/' weblink = 'https://panelbuilder.interfaceinnovations.org/data/downloads/' + filename inventorylib.writepanelbomtopdf( **{ 'bomdata': bom, 'title': 'Bom generated from ' + post['name'] + ' ' + cleantime, 'outputfile': outputroot + filename }) output['data']['weblink'] = weblink elif action == 'exportassemblytopdf': output['message'] += 'exportassemblytopdf keyword found. ' thetime = datalib.gettimestring() cleantime = thetime.replace(' ', '_').replace(':', '_') # Get bom from boms database assemblydata = inventorylib.sysvars.dbs.assemblies.read_table( post['name']) cleanname = post['name'].replace(' ', '_').replace(':', '_') filename = cleanname + '_' + cleantime + '.pdf' outputroot = '/var/www/html/panelbuilder/data/downloads/' weblink = 'https://panelbuilder.interfaceinnovations.org/data/downloads/' + filename inventorylib.writepanelbomtopdf( **{ 'bomdata': assemblydata, 'title': 'Bom generated from ' + post['name'] + ' ' + thetime, 'format': 'picklist', 'outputfile': outputroot + filename }) output['data'] = {'assemblydata': assemblydata} output['weblink'] = weblink # Panel builder elif action in ['panelcalcs', 'panelcalcsgenquote']: output['message'] += 'panelcalc keyword found. ' import panelbuilder for key, value in post.items(): # print(key, value) pass if 'paneldesc' in post: import json post['paneldesc'] = json.loads(post['paneldesc']) bomresults = panelbuilder.paneltobom(**post) output['data'] = {} # d needs to have a 'paneldesc' key with the panel spec data in it. output['data']['bomdescription'] = bomresults['bomdescription'] output['data']['options'] = bomresults['options'] output['data']['bomcalcs'] = inventorylib.calcbomprice( {'bomdictarray': bomresults['bom']})['data'] output['message'] += bomresults['message'] # We don't actually want to return the full boms by default. We don't want this in the client, and it's # lot of data anyway if 'returnfullboms' not in post: for option, value in output['data']['options'].items(): if 'bom' in value: print('Deleting bom from option ' + str(option)) del output['data']['options'][option]['bom'] if 'flatbom' in value: print('Deleting flatbom from option ' + str(option)) del output['data']['options'][option]['flatbom'] if action == 'panelcalcsgenquote': thetime = datalib.gettimestring() cleantime = thetime.replace(' ', '_').replace(':', '_') outputroot = '/var/www/html/panelbuilder/data/downloads/' if 'paneltype' in post['paneldesc'] and post['paneldesc'][ 'paneltype'] == 'brewpanel': datedquotefilename = 'panelbuilder_brew_quote_' + cleantime + '.pdf' datedbomfilename = 'panelbuilder_brew_bom_' + cleantime + '.pdf' genericquotefilename = 'panelbuilder_brew_quote.pdf' genericbomfilename = 'panelbuilder_brew_bom.pdf' elif 'paneltype' in post['paneldesc'] and post['paneldesc'][ 'paneltype'] == 'temppanel': datedquotefilename = 'panelbuilder_temp_quote_' + cleantime + '.pdf' datedbomfilename = 'panelbuilder_temp_bom_' + cleantime + '.pdf' genericquotefilename = 'panelbuilder_temp_quote.pdf' genericbomfilename = 'panelbuilder_temp_bom.pdf' else: datedquotefilename = 'panelbuilder_quote_' + cleantime + '.pdf' datedbomfilename = 'panelbuilder_bom_' + cleantime + '.pdf' genericquotefilename = 'panelbuilder_quote.pdf' genericbomfilename = 'panelbuilder_bom.pdf' weblink = 'https://panelbuilder.interfaceinnovations.org/data/downloads/' + datedquotefilename # until we can get this to format properly in the pdf, we are going to leave it generic # description = output['data']['bomdescription'] description = 'Control panel quote generated by panelbuilder.' datedquotes = True # Create quote pdf from BOM if datedquotes: inventorylib.writepanelquotetopdf( **{ 'bomdata': bomresults['bom'], 'options': bomresults['options'], 'title': 'Quote auto-generated by panelbuilder \t\t' + datalib.gettimestring(), 'price': str(output['data']['bomcalcs']['totalprice']), 'outputfile': outputroot + datedquotefilename, 'description': description }) inventorylib.writepanelquotetopdf( **{ 'bomdata': bomresults['bom'], 'options': bomresults['options'], 'title': 'Quote auto-generated by panelbuilder ' + thetime, 'price': output['data']['bomcalcs']['totalprice'], 'outputfile': outputroot + genericquotefilename }) # Create database entry BOM # Create table # print('** DATABASE') # print(panelbuilder.sysvars.dirs.dbs.quotes) bomname = 'quote_' + cleantime inventorylib.addeditbom( { 'bomdata': { 'name': bomname }, 'database': panelbuilder.sysvars.dirs.dbs.quotes }, output) # print('** BOM **') # print(bomresults['bom']) inserts = [] for part in bomresults['bom']: inserts.append( dblib.makesqliteinsert(bomname, [part['partid'], part['qty']], ['partid', 'qty'])) dblib.sqlitemultquery(inventorylib.sysvars.dirs.dbs.quotes, inserts) inventorylib.makebommetadata( database=inventorylib.sysvars.dbs.quotes) # inventorylib.addeditpartlist(post, output) # Create pdfs if datedquotes: inventorylib.writepanelbomtopdf( **{ 'bomdata': bomresults['bom'], 'options': bomresults['options'], 'title': 'Quote auto-generated by panelbuilder ' + thetime, 'outputfile': outputroot + datedbomfilename }) inventorylib.writepanelbomtopdf( **{ 'bomdata': bomresults['bom'], 'title': 'panelbuilder BOM generated ' + thetime, 'outputfile': outputroot + genericbomfilename, 'totalprice': output['data']['bomcalcs']['totalprice'] }) output['data']['quotelink'] = weblink from iiutilities.utility import gmail mymail = gmail(subject="Quote generated") mymail.message = 'Quote generated at ' + cleantime + '\r\n' if 'remote_ip' in output: mymail.message = 'IP address ' + output[ 'remote_ip'] + '\r\n' mymail.message += bomresults['bomdescription'] mymail.recipient = '*****@*****.**' mymail.sender = 'II Panelbuilder' mymail.send() # Multi-use elif action == 'reloaditemdatafromstock': output['message'] += 'reloaditemdatafromstock keyword found. ' inventorylib.refreshpartsfromstock(post, output) if 'bomname' in post: inventorylib.recalcpartdata(bomname=post['bomname']) inventorylib.makebommetadata() elif 'assemblyame' in post: inventorylib.recalcpartdata(assemblyname=post['assemblyname']) inventorylib.makeassemblymetadata() # Generic functions elif action == 'gettablenames': dbpath = inventorylib.dbnametopath(post['database']) try: output['data'] = dblib.gettablenames(dbpath) except: output['message'] += 'Error getting table names' elif action == 'switchtablerows': dbpath = inventorylib.dbnametopath(post['database']) dblib.switchtablerows(dbpath, post['tablename'], post['row1'], post['row2'], post['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 post: dbpath = inventorylib.dbnametopath(post['database']) if dbpath: output['message'] += 'Friendly name ' + post[ 'database'] + ' translated to path ' + dbpath + ' successfully. ' 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 = 1 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[]']): try: length = lengths[index] except IndexError: length = fixedlength try: start = starts[index] except IndexError: start = fixedstart data.append( dblib.dynamicsqliteread( dbpath, table, start, length)) 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'] = dblib.dynamicsqliteread( dbpath, 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'] = dblib.dynamicsqliteread( dbpath, post['tablename'], post['row']) output['querytime'] = time() - thetime elif 'tablename' in post: # Handle entire table output['message'] += 'Tablename keyword: ' + post[ 'tablename'] + '. ' thetime = time() if 'condition' in post: if not post['condition'] == '': output['data'] = dblib.dynamicsqliteread( dbpath, post['tablename'], condition=post['condition']) else: output['data'] = dblib.dynamicsqliteread( dbpath, post['tablename']) else: try: output['data'] = dblib.dynamicsqliteread( dbpath, post['tablename']) except: output['message'] += 'Error retrieving data. ' else: output[ 'message'] += 'Data query appears successful. ' output['querytime'] = time() - thetime else: output['message'] += 'Friendly name ' + post[ 'database'] + ' unsuccessfully translated. ' else: output['message'] += 'No database present in action request' else: output[ 'message'] = 'no command matched for action "' + action + '"' else: # status = '403 Forbidden' output[ 'message'] += 'Not authorized for this action (or perhaps at all?) ' if 'data' in output: if output['data']: newetag = hashlib.md5(str( output['data']).encode('utf-8')).hexdigest() if 'etag' in post: if newetag == post['etag']: status = '304 Not Modified' output['data'] = '' else: newetag = '' else: newetag = '' if 'datasize' in post: output['datasize'] = sys.getsizeof(output['data']) output['etag'] = newetag # try: foutput = json.dumps(output, indent=1) # except: # import csv # w = csv.writer(open("/usr/lib/iicontrollibs/inventory/dumperr.log", "w")) # for key, val in output.items(): # w.writerow([key, val]) response_headers = [('Content-type', 'application/json')] response_headers.append(('Etag', newetag)) start_response(status, response_headers) return foutput.encode('utf-8')
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]
#print('enabled') polltime = dblib.sqlitedatumquery( pilib.dirs.dbs.session, 'select updatefrequency from \'settings\'') # Go through sessions and delete expired ones sessions = pilib.dirs.dbs.session.read_table('sessions') arrayquery = [] for session in sessions: sessionstart = datalib.timestringtoseconds(session['timecreated']) sessionlength = session['sessionlength'] if time.time() - sessionstart > sessionlength: arrayquery.append('delete from sessions where sessionid=\'' + session['sessionid'] + '\'') # Delete offensive sessions dblib.sqlitemultquery(pilib.dirs.dbs.session, arrayquery) # Reload surviving sessions and summarize sessions = pilib.dirs.dbs.session.read_table('sessions') sessiondictarray = [] for session in sessions: found = 0 for dict in sessiondictarray: if dict['username'] == session['username']: found = 1 index = sessiondictarray.index(dict) dict['sessions'] += 1 sessiondictarray[index] = dict if not found: sessiondictarray.append({ 'username': session['username'],
while enabled: #print('enabled') polltime = dblib.sqlitedatumquery(pilib.dirs.dbs.session, 'select updatefrequency from \'settings\'') # Go through sessions and delete expired ones sessions = pilib.dirs.dbs.session.read_table('sessions') arrayquery = [] for session in sessions: sessionstart = datalib.timestringtoseconds(session['timecreated']) sessionlength = session['sessionlength'] if time.time() - sessionstart > sessionlength: arrayquery.append('delete from sessions where sessionid=\'' + session['sessionid'] + '\'') # Delete offensive sessions dblib.sqlitemultquery(pilib.dirs.dbs.session, arrayquery) # Reload surviving sessions and summarize sessions = pilib.dirs.dbs.session.read_table('sessions') sessiondictarray = [] for session in sessions: found = 0 for dict in sessiondictarray: if dict['username'] == session['username']: found = 1 index = sessiondictarray.index(dict) dict['sessions'] += 1 sessiondictarray[index] = dict if not found: sessiondictarray.append({'username': session['username'], 'sessions': 1})