def setup_authentication(app, get_pw_callback): """ This sets up HTTPDigestAuth login to a flask app before each request. :param app: The flask app to add HTTPDigestAuth to. :param get_pw_callback: A function that takes a username and returns cleartext password. :return: Nothing """ auth = HTTPDigestAuth() @auth.login_required def _assert_auth_before_request(): """ Run before each request, relies on the fact that the decorator function @auth.login_required will not run this code if it fails, and if it did not stop just pass thru call by returning None """ app.logger.info(f'User: {auth.username()}') return None app.logger.info(f'Setting up {app} to require login...') auth.get_password(get_pw_callback) app.before_request(_assert_auth_before_request)
def __init__(self, name, redis_handle, redis_new_handle, app_files, sys_files, gm, startup_dict): app = Flask(name) auth = HTTPDigestAuth() auth.get_password(self.get_pw) startup_dict["DEBUG"] = True self.startup_dict = startup_dict self.app = app app.template_folder = 'flask_web_modular_py3/templates' app.static_folder = 'flask_web_modular_py3/static' app.config['SECRET_KEY'] = startup_dict["SECRET_KEY"] app.config["DEBUG"] = True app.debug = True self.users = json.loads(startup_dict["users"]) alarm_queue = AlarmQueue(redis_handle) Load_Static_Files(app, auth) Load_App_Sys_Files(app, auth, request, app_files, sys_files) Load_Redis_Access(app, auth, request, redis_handle) Load_Irrigation_Pages(app, auth, render_template, redis_handle=redis_handle, redis_new_handle=redis_new_handle, request=request, alarm_queue=alarm_queue) Load_ETO_Management(app, auth, request, app_files, sys_files, gm, redis_new_handle, render_template) Load_Site_Data(app, auth, render_template) Load_Configuration_Data(app, auth, render_template, request, app_files, sys_files, redis_handle, redis_new_handle) Load_Streaming_Data(app, auth, render_template, request, app_files, sys_files, redis_handle, redis_new_handle, gm) Load_Linux_Controller_Data(app, auth, request, render_template, redis_new_handle) Load_Statistic_Data(app, auth, render_template, request, app_files, sys_files, redis_handle, redis_new_handle, gm) Load_Process_Control(app, auth, request, render_template, redis_new_handle, redis_handle, gm) Load_Web_Socket_Handler(app, auth, render_template) search_node = gm.match_terminal_relationship("UDP_IO_SERVER")[0] ip = search_node['redis_host'] db = search_node["redis_rpc_db"] logging_key = search_node["logging_key"] redis_rpc_queue = search_node['redis_rpc_key'] redis_rpc_handle = redis.StrictRedis(host=ip, db=db, decode_responses=True) rpc_client = Redis_Rpc_Client(redis_rpc_handle, redis_rpc_queue) # find remote devices search_nodes = gm.match_relationship_list([["UDP_IO_SERVER", None]], starting_set=None, property_values=None, fetch_values=False) remote_lists = gm.match_terminal_relationship( "REMOTE_UNIT", starting_set=search_nodes) address_list = [] for i in remote_lists: address_list.append(i["modbus_address"]) Load_Modbus_Data(app, auth, request, render_template, redis_new_handle, redis_handle, rpc_client, address_list, logging_key)
class PI_Web_Server_Core(object): def __init__(self, name, site_data): redis_handle_pw = redis.StrictRedis(site_data["host"], site_data["port"], db=site_data["redis_password_db"], decode_responses=True) self.site_data = site_data startup_dict = redis_handle_pw.hgetall("web") self.qs = Query_Support(site_data) self.file_server_library = Construct_RPC_Library( self.qs, self.site_data) self.app = Flask(name) self.auth = HTTPDigestAuth() self.url_rule_class = URL_Rule_Class(self.app, self.auth) self.auth.get_password(self.get_pw) self.startup_dict = startup_dict self.app.template_folder = 'flask_templates' self.app.static_folder = 'static' self.app.config['SECRET_KEY'] = startup_dict["SECRET_KEY"] self.users = json.loads(startup_dict["users"]) Load_Static_Files(self.app, self.auth) #enable static files to be fetched self.redis_access = Load_Redis_Access( self.app, self.auth, request) #enable web access for redis operations Load_App_Sys_Files(self.app, self.auth, request, self.file_server_library) self.subsystems = [] self.modules = {} self.load_specified_modules() def load_specified_modules(self): results = self.common_qs_search(["WEB_SERVER", "WEB_SERVER"]) result = results[0] modules = result["modules"] for i in modules: if i == "monitoring": print(i) PI_Web_Monitor_Server(self) elif i == "system_control": print(i) PI_Web_System_Control(self) elif i == "mqtt_client": print(i) PI_MQTT_Client_Monitor(self) elif i == "eto": print(i) ETO_Management(self) elif i == "irrigation_scheduling": print(i) Irrigation_Scheduling(self) elif i == "irrigation_control": print(i) Load_Irrigation_Control(self) elif i == "modbus_control": print("do nothing right now") else: raise ValueError("bad web module") self.result = result if "status_function" in self.result: print(self.result["status_function"]) else: self.result["status_function"] = "" print("status function not defined") file_handle = open("flask_templates/js/status_definition.js", "w") file_handle.write('__status_option__ = "' + self.result["status_function"] + '"; \n') file_handle.close() def common_qs_search(self, search_list): # generalized graph search query_list = [] query_list = self.qs.add_match_relationship( query_list, relationship="SITE", label=self.site_data["site"]) for i in range(0, len(search_list) - 1): if type(search_list[i]) == list: query_list = self.qs.add_match_relationship( query_list, relationship=search_list[i][0], label=search_list[i][1]) else: query_list = self.qs.add_match_relationship( query_list, relationship=search_list[i]) if type(search_list[-1]) == list: query_list = self.qs.add_match_terminal( query_list, relationship=search_list[-1][0], label=search_list[-1][1]) else: query_list = self.qs.add_match_terminal( query_list, relationship=search_list[-1]) node_sets, node_sources = self.qs.match_list(query_list) return node_sources def get_pw(self, username): if username in self.users: return self.users[username] return None def generate_menu_page(self): self.subsystems.sort() self.generate_menu_template() self.generate_modal_template() def generate_default_index_page(self): self.app.add_url_rule("/", "home_page", self.links_a1) def generate_index_page(self, module, element): menu_data = self.url_rule_class.subsystems[module]["menu_data"] menu_element = menu_data[element] self.app.add_url_rule("/", "home page", menu_element[0]) def generate_site_map(self): self.links_a1 = self.auth.login_required(self.site_map_function) self.app.add_url_rule("/link_page", "/links_page", self.links_a1) def site_map_function(self): links = [] for rule in self.app.url_map.iter_rules(): # Filter out rules we can't navigate to in a browser # and rules that require parameters #url = url_for(rule.endpoint, **(rule.defaults or {})) links.append((rule.endpoint)) links.sort() return render_template("list_of_endpoints", endpoints=links) def run_http(self): self.app.run(threaded=True, use_reloader=True, host='0.0.0.0', port=self.port, debug=self.debug) def run_https(self): startup_dict = self.startup_dict self.app.run(threaded=True, use_reloader=True, host='0.0.0.0', debug=self.debug, port=self.port, ssl_context=("/data/cert.pem", "/data/key.pem")) def generate_menu_template(self): f = open(self.app.template_folder + '/menu', 'w') output_string = ''' <nav class="navbar navbar-expand-sm bg-dark navbar-dark"> <!-- Links --> <ul class="navbar-nav"> <!-- Dropdown --> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" id="navbardrop" data-toggle="dropdown">Menu</a> <div class="dropdown-menu"> ''' f.write(output_string) self.url_rule_class.subsystems for i in self.url_rule_class.subsystems: temp = ' <a class="dropdown-item" href="#" data-toggle="modal" data-target="#' + i + '">' + i + "</a>\n" f.write(temp) output_string = ''' </div> </li> </ul> <ul class="navbar-nav"> <button id="status_panel", class="btn " type="submit">Status</button> </ul> <nav class="navbar navbar-light bg-dark navbar-dark"> <span class="navbar-text" > <h4 id ="status_display"> Status: </h4> </span> </nav> </nav> ''' f.write(output_string) f.close() def generate_modal_template(self): f = open(self.app.template_folder + '/modals', 'w') for i in self.url_rule_class.subsystem_order: #print("generate_modal_template - i",i) output_string = '<!–' + i + ' –>\n' f.write(output_string) output_string = '<div class="modal fade" id=' + i + ' tabindex="-1" role="dialog" aria-labelledby="accountModalLabel" aria-hidden="true">\n' f.write(output_string) output_string = ''' <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> ''' f.write(output_string) f.write(' <h5 class="modal-title" id="accountModalLabel">' + i + '</h5>\n') output_string = ''' <button type="button" class="close" data-dismiss="modal" aria-label="close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <ul > ''' f.write(output_string) # <li><a href ='/control/display_past_system_alerts' target="_self">Current System State</a></li> sub_system_data = self.url_rule_class.subsystems[i] temp = sub_system_data["menu_data"] # for j in sub_system_data['menu_list']: data = temp[j] #print("data",data) format_output = '<li><a href=' + '"/' + i + '/' + data[ 1] + '" target="_self">' + data[2] + '</a></li>\n' f.write(format_output) output_string = ''' </ul> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> </div> </div> </div> </div> ''' f.write(output_string) f.close()