diff --git a/src/lib/ACLAnalyzer.py b/src/lib/ACLAnalyzer.py index 80cda8c434daed6bfe145bf993a6eba7dfadb305..c6aa88ce2665bc6b80457081436afc318759d58c 100644 --- a/src/lib/ACLAnalyzer.py +++ b/src/lib/ACLAnalyzer.py @@ -3,7 +3,7 @@ from lib.ACReader import ACLData from lib.utils import format_log,flatten_node from tree_sitter import Node from .CFGGenerator import CFGGenerator,CFG -from sys import platform +from .Const import PATH_SEPARATOR class ACLAnalyzer(): def __init__(self,project:ProjectInfo,acl_info:ACLData) -> None: self.project_info:ProjectInfo = project @@ -34,7 +34,8 @@ class ACLAnalyzer(): def analyze_class(self,route:ElementContext)->list[str]: - method_lists = list(filter(lambda x:x['name']!='__init__' and x['type']=='class_method' and x['parent']==route.get_base_element_name(),route.cfg.source_code_method_list)) + file_method_list = self.project_info.dependency_manager.get(route.location).method_list + method_lists = list(filter(lambda x:x['name']!='__init__' and x['type']=='class_method' and x['parent']==route.get_base_element_name(),file_method_list)) # Remove yang ada di no check list for ctx in route.context: if ctx.startswith("Exempt::"): @@ -46,12 +47,13 @@ class ACLAnalyzer(): class_acls = [] for f in method_lists: ctx = ElementContext(f"{f['parent']}.{f['name']}",'function',route.location,[f"Parent::{f['parent']}"]) - ctx.set_cfg(CFG(f['ast'],f['ctx'],f['cursor'],route.cfg.source_code_method_list,route.cfg.source_code)) + ctx.set_cfg(CFG(f['ast'],f['ctx'],f['cursor'],route.cfg.source_code)) result = self.analyze_function(ctx) class_acls.append([ctx.name,result]) return class_acls def analyze_function(self,route:ElementContext,is_route=True)->list[str]: + file_method_list = self.project_info.dependency_manager.get(route.location).method_list # Cek parent nya untuk menentukaan apakah ada dekorator # Inisialisasi principal_list var_list = [] @@ -104,7 +106,7 @@ class ACLAnalyzer(): # Cek apakah fungsinya ada if fun_name: # cek buat fungsi di kelas yang sama - for rute in route.cfg.source_code_method_list: + for rute in file_method_list: function_name = "" if fun_name.split(".")[0]!='self' and rute['type']=='module_function' and rute['name']==fun_name: function_name = fun_name @@ -192,7 +194,7 @@ class ACLAnalyzer(): # Cek apakah fungsinya ada if fun_name: # cek buat fungsi di kelas yang sama - for rute in route.cfg.source_code_method_list: + for rute in file_method_list: function_name = "" if fun_name.split(".")[0]!='self' and rute['type']=='module_function' and rute['name']==fun_name: function_name = fun_name @@ -233,7 +235,7 @@ class ACLAnalyzer(): # Cek apakah fungsinya ada if fun_name: # cek buat fungsi di kelas yang sama - for rute in route.cfg.source_code_method_list: + for rute in file_method_list: function_name = "" if fun_name.split(".")[0]!='self' and rute['type']=='module_function' and rute['name']==fun_name: function_name = fun_name @@ -272,7 +274,7 @@ class ACLAnalyzer(): # Cek apakah fungsinya dipanggil if fun_name: # cek buat fungsi di kelas yang sama - for rute in route.cfg.source_code_method_list: + for rute in file_method_list: function_name = "" if fun_name.split(".")[0]!='self' and rute['type']=='module_function' and rute['name']==fun_name: function_name = fun_name @@ -327,7 +329,7 @@ class ACLAnalyzer(): if parts[0]==var['name']: parts[0] = var['type'] fun_name = ".".join(parts) - for rute in route.cfg.source_code_method_list: + for rute in file_method_list: function_name = "" if parts[0]!='self' and rute['type']=='module_function' and rute['name']==fun_name: function_name = fun_name @@ -383,8 +385,9 @@ class ACLAnalyzer(): return principal_list def analyze_module(self,route:ElementContext)->list[list[str,list[str]]]: + file_method_list = self.project_info.dependency_manager.get(route.location).method_list # Cari info semua fungsi di module - method_lists = [m for m in route.cfg.source_code_method_list if not (m['type']=='class_method' and m['name']=='__init__')] + method_lists = [m for m in file_method_list if not (m['type']=='class_method' and m['name']=='__init__')] # Remove yang ada di no check list for ctx in route.context: if ctx.startswith("Exempt::"): @@ -398,18 +401,19 @@ class ACLAnalyzer(): if f['type']=='class_method': #TODO class method ctx = ElementContext(f"{f['parent']}.{f['name']}",'function',route.location,[]) - ctx.set_cfg(CFG(f['ast'],f['ctx'],f['cursor'],route.cfg.source_code_method_list,route.cfg.source_code)) + ctx.set_cfg(CFG(f['ast'],f['ctx'],f['cursor'],route.cfg.source_code)) result = self.analyze_function(ctx) route_acls.append([ctx.get_base_element_name(),result]) else: ctx = ElementContext(f['name'],'function',route.location,[]) - ctx.set_cfg(CFG(f['ast'],f['ctx'],f['cursor'],route.cfg.source_code_method_list,route.cfg.source_code)) + ctx.set_cfg(CFG(f['ast'],f['ctx'],f['cursor'],route.cfg.source_code)) result = self.analyze_function(ctx) route_acls.append([ctx.get_base_element_name(),result]) return route_acls def check_acl_list(self,route:ElementContext,name:str,ctx:list[str]=[])->list[str]|None: #TODO handle variabel dan kelas dan import + file_method_list = self.project_info.dependency_manager.get(route.location).method_list # Format name: fun atau self.fun acl_list = (role for role in self.acl_info.principal_list) for acl_class in self.project_info.acl_class: @@ -443,7 +447,7 @@ class ACLAnalyzer(): if acl_class.location==route.location: # Kelas/fungsi lokal # Kali aja ada di module ini - for function in route.cfg.source_code_method_list: + for function in file_method_list: if(acl_class.type=='class' and function['type']=='class_method' and function['parent']==acl_class.get_base_element_name()): full_name = name if len(name.split("."))==1 and ctx: @@ -471,14 +475,13 @@ class ACLAnalyzer(): else: # Beda file, cek di import ada gak # Kali aja ada di module ini - dependency_lists = route.cfg.source_code_dependency_list + dependency_lists = self.project_info.dependency_manager.get(route.location).dependency_list route_position = route.cfg.get_line_index(route.name) for dependency in dependency_lists: if dependency[0 ]> route_position: break dependency_parts = dependency[1]['original'] # Module name - replacement = "\\" if platform.startswith("win") else "/" - if dependency_parts not in acl_class.location.replace(replacement,"."): + if dependency_parts not in acl_class.location.replace(PATH_SEPARATOR,"."): # Modul nya salah continue # Yang diimport class nya @@ -497,7 +500,8 @@ class ACLAnalyzer(): elmt = ctx[j] j+=1 name = f"{name}.{elmt}" - for method in acl_class.cfg.source_code_method_list: + acl_file_method_list = self.project_info.dependency_manager.get(acl_class.location).method_list + for method in acl_file_method_list: if method['type']!='class_method' or (method['type']=='class_method' and method['parent']!=m['original']): continue if(name==f'{comparator}.{method["name"]}'): @@ -519,7 +523,8 @@ class ACLAnalyzer(): tmp_name = name if parent_class: tmp_name = f"{parent_class}.{name}" - for method in acl_class.cfg.source_code_method_list: + acl_file_method_list = self.project_info.dependency_manager.get(acl_class.location).method_list + for method in acl_file_method_list: tmp_comparator = comparator # Fungsi tidal sesuai if method['type']=='module_function' and method['name']!=m['original']: @@ -538,7 +543,7 @@ class ACLAnalyzer(): if check_var in self.acl_info.acl_context: return check_var # Jika ini library - for dep in route.cfg.source_code_dependency_list: + for dep in self.project_info.dependency_manager.get(route.location).dependency_list: lib_name = dep[1]['original'] format_lib = f'lib:{lib_name}::{".".join(components[1:])}' if (components[0]==dep[1]['rename'] or components[0]==dep[1]['original']) and format_lib in self.acl_info.acl_context: diff --git a/src/lib/ACReader.py b/src/lib/ACReader.py index 5cc45e7f79ffc15f20d73e9d66212862787ed3ae..fd27005f54eb52425bc04c288a582886fa522374 100644 --- a/src/lib/ACReader.py +++ b/src/lib/ACReader.py @@ -15,14 +15,16 @@ class ACLData(): class ACReader(): - def __init__(self,path:str) -> None: + def __init__(self,path:str,req_file:str|None=None) -> None: self.acl_path:str = path + self.req_file:str = req_file # @ACL def read(self) -> ACLData: format_log("Reading ACL File...") principal_list:list[str] = [] route_acl:dict[str,list[str]] = {} acl_context:dict[str,list|dict] = {} + # Baca File ACL with open(self.acl_path) as acl_file: line_type = None for line in acl_file: diff --git a/src/lib/ASTGenerator.py b/src/lib/ASTGenerator.py index dd2d39a4e17c73a33209eeef12d423f0d18c45cc..97e78e416a967d8edfe26b707ed55755dce509c5 100644 --- a/src/lib/ASTGenerator.py +++ b/src/lib/ASTGenerator.py @@ -1,8 +1,9 @@ from tree_sitter import Language, Parser,Node,TreeCursor,Tree import tree_sitter_python as tspython from lib.custom_class import ElementContext -import re +from .DependencyManager import DependencyManager from lib.utils import format_log +import re class ASTGenerator(): def __init__(self) -> None: # Init parser @@ -52,6 +53,46 @@ class ASTGenerator(): elif node.type == 'module': classes.append({'name':function_name,'type':'module_function','ast':ast,'ctx':kongteks,'cursor':cursor}) return classes + + def get_dependency_list(self,source_code:str,source_code_method_list:list): + # Dapatkan daftar dependency beserta lokasi barisnya + deps_list = [] + for i,line in enumerate(source_code.decode().split("\n")): + if re.search(r"(from +.+ +import +.+)|(import +.+)",line): + # Dapetin nama modul + parts = line.strip().split(" ")[1:] # skip import or from statement + module_name = {"original":parts[0],"rename":None} + imported_elmts:list[dict] = [] + i = 1 + while i<len(parts): + if(parts[i]==','): + continue + elif(parts[i]=='as'): + i+=1 + if(not imported_elmts): + # Rename module + module_name["rename"] = parts[i] + else: + # Rename element terakhir + imported_elmts[-1]["rename"] = parts[i] + elif(parts[i]=='import'): + # Import element berikutnya + i+=1 + if parts[i]=='*': + for method in source_code_method_list: + if(method["type"]=='module_function'): + imported_elmts.append({"original":method["name"],"rename":None}) + elif method["type"]=='class_method': + imported_elmts.append({"original":method["parent"],"rename":None}) + break + else: + imported_elmts.append({"original":parts[i],"rename":None}) + else: + imported_elmts.append({"original":parts[i],"rename":None}) + i+=1 + # Konversi imported_elmts + deps_list.append([i,module_name,imported_elmts]) + return deps_list def parse_class(self,ctx:ElementContext)->tuple[Node|None,TreeCursor|None,str]: diff --git a/src/lib/CFGGenerator.py b/src/lib/CFGGenerator.py index 1b818d8fdec782174c080b071d3c568995709c75..e2272cf3e1fb8d6a4ca0e42302f2379fe0f7da45 100644 --- a/src/lib/CFGGenerator.py +++ b/src/lib/CFGGenerator.py @@ -3,8 +3,8 @@ from lib.ASTGenerator import ASTGenerator from lib.utils import format_log from tree_sitter import Node,TreeCursor from typing import Optional -import copy -import re +from .DependencyManager import FileInformation +from .Const import PATH_SEPARATOR class CFGGenerator(): def __init__(self): @@ -16,74 +16,24 @@ class CFGGenerator(): format_log(f"Generating CFG for {ctx.get_base_element_name()} in {ctx.location}...") ast,cursor,source_code = self.ast_parser.generate(ctx) method_list = self.ast_parser.get_all_function_info(source_code,ctx.location) - return CFG(ast,ctx,cursor,method_list,source_code) + deps_list = self.ast_parser.get_dependency_list(source_code,method_list) + dependency = FileInformation(ctx.location.split(PATH_SEPARATOR)[-1],ctx.location,deps_list,method_list) + return CFG(ast,ctx,cursor,source_code),dependency class CFG(): - def __init__(self,ast:Node,ctx:ElementContext,cursor:TreeCursor,source_code_method_list:list[dict[str,str]],source_code:str = "",next_branch:Optional[TreeCursor] = None) -> None: + def __init__(self,ast:Node,ctx:ElementContext,cursor:TreeCursor,source_code:str|bytes = "",next_branch:Optional[TreeCursor] = None) -> None: self.ast:Node = ast self.ctx:ElementContext = ctx self.cursor:TreeCursor = cursor - self.source_code:bytes = source_code + if isinstance(source_code,str): + self.source_code = source_code.encode() + else: + self.source_code:bytes = source_code self.next_branch:Optional[TreeCursor] = next_branch self.original_cursor:TreeCursor = self.cursor.copy() - self.source_code_method_list:list[dict[str,str]] = source_code_method_list - self.source_code_dependency_list:list = self.get_dependency_list() self.is_traversing:bool = False - def get_dependency_list(self): - # Dapatkan daftar dependency beserta lokasi barisnya - deps_list = [] - # # Cek apakah sudah ada - # module_name = {} - # dep_idx = -1 - # imported_elmts:list[dict] = [] - # for i in range(len(deps_list)): - # if deps_list[i][1]['original']==parts[0]: - # module_name = deps_list[i][1] - # imported_elmts = deps_list[i][2] - # dep_idx = i - # break - # if dep_idx==-1: - # module_name = {"original":parts[0],"rename":None} - # Cek apakah sudah ada - for i,line in enumerate(self.source_code.decode().split("\n")): - if re.search(r"(from +.+ +import +.+)|(import +.+)",line): - # Dapetin nama modul - parts = line.strip().split(" ")[1:] # skip import or from statement - module_name = {"original":parts[0],"rename":None} - imported_elmts:list[dict] = [] - i = 1 - while i<len(parts): - if(parts[i]==','): - continue - elif(parts[i]=='as'): - i+=1 - if(not imported_elmts): - # Rename module - module_name["rename"] = parts[i] - else: - # Rename element terakhir - imported_elmts[-1]["rename"] = parts[i] - elif(parts[i]=='import'): - # Import element berikutnya - i+=1 - if parts[i]=='*': - for method in self.source_code_method_list: - if(method["type"]=='module_function'): - imported_elmts.append({"original":method["name"],"rename":None}) - elif method["type"]=='class_method': - imported_elmts.append({"original":method["parent"],"rename":None}) - break - else: - imported_elmts.append({"original":parts[i],"rename":None}) - else: - imported_elmts.append({"original":parts[i],"rename":None}) - i+=1 - # Konversi imported_elmts - deps_list.append([i,module_name,imported_elmts]) - return deps_list - def get_line_index(self,text:str)->int: parts = text.split(".") # Pastikan tiap bagiannya terpanggi diff --git a/src/lib/Const.py b/src/lib/Const.py new file mode 100644 index 0000000000000000000000000000000000000000..96a0e7e0cdcb7b2c32c5e93f8962d51b440b5bda --- /dev/null +++ b/src/lib/Const.py @@ -0,0 +1,2 @@ +from sys import platform +PATH_SEPARATOR = "\\" if platform.startswith("win") else "/" \ No newline at end of file diff --git a/src/lib/DependencyManager.py b/src/lib/DependencyManager.py new file mode 100644 index 0000000000000000000000000000000000000000..197ea141d639a2261512caddde86fab437c4498e --- /dev/null +++ b/src/lib/DependencyManager.py @@ -0,0 +1,39 @@ +from .Const import PATH_SEPARATOR + +class FileInformation(): + def __init__(self,name,path,dependency_list,method_list): + self.name:str = name + self.path:str = path + self.dependency_list:list = dependency_list + self.method_list:list = method_list + + def __repr__(self) -> str: + return self.__str__() + + def __str__(self) -> str: + return f"FileInformation(name={self.name},path={self.path},dependency_list=[{len(self.dependency_list)} item],method_list=[{len(self.method_list)} item])" + +class DependencyManager(): + def __init__(self) -> None: + self.informations = [] + + def add(self,information): + for info in self.informations: + if info.name == information.name and info.path == information.path: + return + # Belum ada + self.informations.append(information) + + def get(self,path:str)->FileInformation|None: + name = path.split(PATH_SEPARATOR)[-1] + for info in self.informations: + if info.name == name and info.path == path: + return info + return None + + def __repr__(self) -> str: + return self.__str__() + + def __str__(self) -> str: + return f"DependencyManager(informations={self.informations})" + diff --git a/src/lib/FileReader.py b/src/lib/FileReader.py index cbd8445b646f9ae0f625485b8c55b9fa53c45c80..9ff528cf76d59f65cda9c4704bc23adb3dfda23c 100644 --- a/src/lib/FileReader.py +++ b/src/lib/FileReader.py @@ -4,7 +4,8 @@ from lib.utils import format_log from typing import Optional from lib.CFGGenerator import CFGGenerator,CFG from lib.custom_class import ElementContext -from sys import platform +from .Const import PATH_SEPARATOR +from .DependencyManager import DependencyManager,FileInformation class FileReader: ANNOTATION_PATTERN = "\S*@.+" def __init__(self, project_path:str)->None: @@ -12,13 +13,44 @@ class FileReader: self.project_path = project_path self.supported_extensions = os.getenv("SUPPORTED_EXTENSION").split("|") self.cfg_generator:CFGGenerator = CFGGenerator() + self.dependency_names = [] format_log("Project Context Gatherer initialized.") def analyze_project(self): format_log("Searching for annotation...") + # Baca requirements.txt + self.read_project_dependency() + # Baca files potential_files:list[str] = self.get_potential_files() project_information:ProjectInfo = self.search_annotation(potential_files) return project_information + + def read_project_dependency(self): + with open(f"{self.project_path}{PATH_SEPARATOR}requirements.txt") as req_file: + lines = req_file.readlines() + i = 0 + while i < len(lines): + annotation_list = self.have_annotation(lines[i]) + annotation = None if len(annotation_list)==0 else annotation_list[0] + if(annotation): + additional_context = [] + if("@ACL" in annotation): + # Ini kelas acl + # Cek jika ada keterangan tambahan + match = re.search(r'\(.*\)',lines[i]) + if match: + # Ada keterangan tambahan + additional_context = re.sub(r"[\(\) ]","",match.group(0)).split(",") + # Cari tahu jenis acl nya + i+=1 + while re.search(FileReader.ANNOTATION_PATTERN,lines[i]): + #TODO handle kalau ketemu yang lain + i+=1 + # Baca nama modul + # import_name:flask_login + module_name = additional_context[0].split(":")[1].strip() + self.dependency_names.append({"name":module_name,"ctx":additional_context}) + i+=1 def search_annotation(self,files:list[str]): project_info:ProjectInfo = ProjectInfo() @@ -56,7 +88,8 @@ class FileReader: else: continue # Tentukan parent node ini - parent = self.cfg_generator.generate(curr_node).ast.parent + tmp,_= self.cfg_generator.generate(curr_node) + parent = tmp.ast.parent if parent.type=='decorated_definition': parent = parent.parent if parent.type=='block': @@ -94,7 +127,11 @@ class FileReader: # Ini kelas biasa continue # Generate CFG jika ini acl - project_info.acl_class[-1].set_cfg(self.cfg_generator.generate(project_info.acl_class[-1])) + cfg,deps = self.cfg_generator.generate(project_info.acl_class[-1]) + project_info.acl_class[-1].set_cfg(cfg) + #Daftarkan dependency + project_info.dependency_manager.add(deps) + # project_info.dependency_manager.add(FileInformation("","",)) # Cek jika ini fungsi dalam kelas if(project_info.acl_class[-1].type=='function'): parent = project_info.acl_class[-1].cfg.ast.parent.parent @@ -129,10 +166,11 @@ class FileReader: project_info.route_class.append(ElementContext(lines[i].strip().split(" ")[1],'function',file,additional_context)) else: # Dapatkan konteks berupa cfg setiap kelas - replacement = "\\" if platform.startswith("win") else "/" - project_info.route_class.append(ElementContext(".".join(file.split(replacement)[-1].split(".")[:-1]),'module',file,additional_context)) + project_info.route_class.append(ElementContext(".".join(file.split(PATH_SEPARATOR)[-1].split(".")[:-1]),'module',file,additional_context)) # Generate CFG jika ini rute - project_info.route_class[-1].set_cfg(self.cfg_generator.generate(project_info.route_class[-1])) + cfg,deps = self.cfg_generator.generate(project_info.route_class[-1]) + project_info.route_class[-1].set_cfg(cfg) + project_info.dependency_manager.add(deps) # Cek jika ini fungsi dalam kelas if(project_info.route_class[-1].type=='function'): parent = project_info.route_class[-1].cfg.ast.parent.parent @@ -143,6 +181,16 @@ class FileReader: else: # Ini kelas biasa pass + elif re.search("\S*(from|import) +",lines[i]): + # ini modul yg diimport dan didefinisikan di requirement.txt + for lib in self.dependency_names: + if lib['name']==lines[i].split(" ")[1]: + # Bikin elemen + project_info.acl_class.append(ElementContext(lines[i],'library',file,lib['ctx'])) + cfg,deps = self.cfg_generator.generate(project_info.acl_class[-1]) + project_info.acl_class[-1].set_cfg(cfg) + # Daftarkan dependency + project_info.dependency_manager.add(deps) i+=1 return project_info @@ -154,8 +202,7 @@ class FileReader: for root, dirs, files in os.walk(self.project_path): for file in files: if(self.is_source_code_supported(file)): - separator = "\\" if platform.startswith("win") else "/" - file_list.append(f"{root}{separator}{file}") + file_list.append(f"{root}{PATH_SEPARATOR}{file}") return file_list def is_source_code_supported(self,filename:str)->bool: @@ -167,10 +214,11 @@ class ProjectInfo(): def __init__(self) -> None: self.acl_class:list[ElementContext] = [] self.route_class:list[ElementContext] = [] + self.dependency_manager:DependencyManager= DependencyManager() def __repr__(self) -> str: return self.__str__() def __str__(self) -> str: - return f"ProjectInfo(acl_class={self.acl_class},route_class={self.route_class})" + return f"ProjectInfo(acl_class={self.acl_class},route_class={self.route_class},dependency_manager={self.dependency_manager})" \ No newline at end of file diff --git a/src/lib/RouteSanitizationAnalyzer.py b/src/lib/RouteSanitizationAnalyzer.py index 20493b353598da4670b05511c9e45c75060d171f..325e1e31ecaba47e1c3769ad0d1bc91a8c3261c0 100644 --- a/src/lib/RouteSanitizationAnalyzer.py +++ b/src/lib/RouteSanitizationAnalyzer.py @@ -3,7 +3,7 @@ from lib.custom_class import ElementContext from lib.utils import format_log,flatten_node from .CFGGenerator import CFG from tree_sitter import Node -from sys import platform +from .Const import PATH_SEPARATOR class RouteSanitizationAnalyzer(): def set_project(self,project_info:ProjectInfo): self.project_info = project_info @@ -35,7 +35,8 @@ class RouteSanitizationAnalyzer(): return vuln_routes def analyze_class(self,route:ElementContext)->list[str]: - method_lists = list(filter(lambda x:x['name']!='__init__' and x['type']=='class_method' and x['parent']==route.get_base_element_name(),route.cfg.source_code_method_list)) + file_method_list = self.project_info.dependency_manager.get(route.location).method_list + method_lists = list(filter(lambda x:x['name']!='__init__' and x['type']=='class_method' and x['parent']==route.get_base_element_name(),file_method_list)) # Remove yang ada di no check list for ctx in route.context: if ctx.startswith("Exempt::"): @@ -47,13 +48,13 @@ class RouteSanitizationAnalyzer(): unsanitized_methods = [] for f in method_lists: ctx = ElementContext(f['name'],'function',route.location,[]) - ctx.set_cfg(CFG(f['ast'],f['ctx'],f['cursor'],route.cfg.source_code_method_list,route.cfg.source_code)) + ctx.set_cfg(CFG(f['ast'],f['ctx'],f['cursor'],route.cfg.source_code)) if(not self.analyze_function(ctx)): unsanitized_methods.append(f['name']) return unsanitized_methods def analyze_function(self,route:ElementContext)->bool: - print("Route",route) + file_method_list = self.project_info.dependency_manager.get(route.location).method_list var_list = [] # Cek parent nya untuk menentukaan apakah ada dekorator route.cfg.reset() @@ -93,7 +94,7 @@ class RouteSanitizationAnalyzer(): # Cek apakah fungsinya ada if fun_name: # cek buat fungsi di kelas yang sama - for rute in route.cfg.source_code_method_list: + for rute in file_method_list: function_name = "" if fun_name.split(".")[0]!='self' and rute['type']=='module_function' and rute['name']==fun_name: function_name = fun_name @@ -130,7 +131,7 @@ class RouteSanitizationAnalyzer(): # Cek apakah fungsinya ada if fun_name: # cek buat fungsi di kelas yang sama - for rute in route.cfg.source_code_method_list: + for rute in file_method_list: function_name = "" if fun_name.split(".")[0]!='self' and rute['type']=='module_function' and rute['name']==fun_name: function_name = fun_name @@ -167,7 +168,7 @@ class RouteSanitizationAnalyzer(): # Cek apakah fungsinya ada if fun_name: # cek buat fungsi di kelas yang sama - for rute in route.cfg.source_code_method_list: + for rute in file_method_list: function_name = "" if fun_name.split(".")[0]!='self' and rute['type']=='module_function' and rute['name']==fun_name: function_name = fun_name @@ -203,7 +204,7 @@ class RouteSanitizationAnalyzer(): # Cek apakah fungsinya dipanggil if fun_name: # cek buat fungsi di kelas yang sama - for rute in route.cfg.source_code_method_list: + for rute in file_method_list: function_name = "" if fun_name.split(".")[0]!='self' and rute['type']=='module_function' and rute['name']==fun_name: function_name = fun_name @@ -252,7 +253,7 @@ class RouteSanitizationAnalyzer(): for var in var_list: if parts[0]==var['name']: parts[0] = var['type'] - for rute in route.cfg.source_code_method_list: + for rute in file_method_list: function_name = "" if parts[0]!='self' and rute['type']=='module_function' and rute['name']==".".join(parts): function_name = ".".join(parts) @@ -278,8 +279,9 @@ class RouteSanitizationAnalyzer(): def analyze_module(self,route:ElementContext)->list[str]: #TODO CFG + file_method_list = self.project_info.dependency_manager.get(route.location).method_list # Cari info semua fungsi di module - method_lists = [m for m in route.cfg.source_code_method_list if not (m['type']=='class_method' and m['name']=='__init__')] + method_lists = [m for m in file_method_list if not (m['type']=='class_method' and m['name']=='__init__')] # Remove yang ada di no check list for ctx in route.context: if ctx.startswith("Exempt::"): @@ -292,7 +294,7 @@ class RouteSanitizationAnalyzer(): for f in method_lists: ctx = ElementContext(f['name'],'function',route.location,[]) # set cfg - ctx.set_cfg(CFG(f['ast'],f['ctx'],f['cursor'],route.cfg.source_code_method_list,route.cfg.source_code)) + ctx.set_cfg(CFG(f['ast'],f['ctx'],f['cursor'],route.cfg.source_code)) if(not self.analyze_function(ctx)): if f['type']=='class_method': unsanitized_methods.append(["class",f['name'],f['parent']]) @@ -302,6 +304,7 @@ class RouteSanitizationAnalyzer(): def is_in_acl_list(self,route:ElementContext,name:str,ctx:list[str]=[]): # Format name: fun atau self.fun + file_method_list = self.project_info.dependency_manager.get(route.location).method_list for acl_class in self.project_info.acl_class: acl_class.cfg.reset() if(acl_class.type=='library' and acl_class.location==route.location): @@ -332,7 +335,7 @@ class RouteSanitizationAnalyzer(): if acl_class.location==route.location: # Kelas/fungsi lokal # Kali aja ada di module ini - for function in route.cfg.source_code_method_list: + for function in file_method_list: if(acl_class.type=='class' and function['type']=='class_method' and function['parent']==acl_class.get_base_element_name()): #TODO hanya handle 1 accessing misal a.b, a.b.c gak bisa full_name = name @@ -361,14 +364,13 @@ class RouteSanitizationAnalyzer(): else: # Beda file, cek di import ada gak # Kali aja ada di module ini - dependency_lists = route.cfg.source_code_dependency_list + dependency_lists = self.project_info.dependency_manager.get(route.location).dependency_list route_position = route.cfg.get_line_index(route.name) for dependency in dependency_lists: if dependency[0 ]> route_position: break dependency_parts = dependency[1]['original'] # Module name - replacement = "\\" if platform.startswith("win") else "/" - if dependency_parts not in acl_class.location.replace(replacement,"."): + if dependency_parts not in acl_class.location.replace(PATH_SEPARATOR,"."): # Modul nya salah continue # Yang diimport class nya @@ -390,7 +392,8 @@ class RouteSanitizationAnalyzer(): break elmt = ctx[j] name = f"{name}.{elmt}" - for method in acl_class.cfg.source_code_method_list: + acl_file_method_list = self.project_info.dependency_manager.get(acl_class.location).method_list + for method in acl_file_method_list: if method['type']!='class_method' or (method['type']=='class_method' and method['parent']!=m['original']): continue if(name==f'{comparator}.{method["name"]}'): @@ -403,7 +406,8 @@ class RouteSanitizationAnalyzer(): if m["rename"]: # Pake rename comparator = m["rename"] - for method in acl_class.cfg.source_code_method_list: + acl_file_method_list = self.project_info.dependency_manager.get(acl_class.location).method_list + for method in acl_file_method_list: if method['type']=='class_method' and (f"{method['parent']}.{method['name']}"==f"{comparator}.{name}" or f"{parent_class}.{method['name']}"==f"{comparator}.{name}"): return True # Fungsi tidal sesuai diff --git a/tests/tc1/auth.py b/tests/tc1/auth.py index 2f81ba692ee86a341a5db6a273c77e2699f58e60..eb316f9d6fd04675ef64b0b93b61a58b7bd339cf 100644 --- a/tests/tc1/auth.py +++ b/tests/tc1/auth.py @@ -2,7 +2,7 @@ from flask import Blueprint, render_template, request, flash, redirect, url_for from .models import User from werkzeug.security import generate_password_hash, check_password_hash from . import db -#@ACL(login_required) +#@A\CL(login_required) from flask_login import login_user, login_required, logout_user, current_user diff --git a/tests/tc1/class_views.py b/tests/tc1/class_views.py index ff93e88ec5da4501295c2347e5c7d4f73c2b9b35..348327a9278aad10997e00b56e0e81bd8a59e57f 100644 --- a/tests/tc1/class_views.py +++ b/tests/tc1/class_views.py @@ -1,5 +1,5 @@ from flask import Blueprint, render_template, request, flash, jsonify,abort -# @ACL(login_required) +# @\ACL(login_required) from flask_login import login_required, current_user from .models import Note,Log from .db import db diff --git a/tests/tc1/requirements.txt b/tests/tc1/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..529b4ea774d0530d5d9c365a1a5bd74c3dca0d91 --- /dev/null +++ b/tests/tc1/requirements.txt @@ -0,0 +1,2 @@ +# @ACL(import_name:flask_login,login_required) +Flask-Login \ No newline at end of file diff --git a/tests/tc1/views.py b/tests/tc1/views.py index fefc7d65649d605d3513a61f2a956cb2166dccd8..86effa9a4fd6acbf4139975c4e1ffdfd60ccd41f 100644 --- a/tests/tc1/views.py +++ b/tests/tc1/views.py @@ -1,6 +1,6 @@ # @Routes from flask import Blueprint, render_template, request, flash, jsonify,abort -# @ACL(login_required) +# @A\CL(login_required) from flask_login import login_required, current_user from .models import Note,Log from .db import db