From 6531232cd2a0249b7d2c40e9691c5d04d083d6ec Mon Sep 17 00:00:00 2001 From: Fawwaz Anugrah Wiradhika Dharmasatya <anugrahdwfawwaz@gmail.com> Date: Thu, 6 Jun 2024 13:28:36 +0700 Subject: [PATCH] feat: handle object stored in variable (not transtive yet) --- src/lib/ACLAnalyzer.py | 63 ++++++++++++++++---------- src/lib/ASTGenerator.py | 2 - src/lib/RouteSanitizationAnalyzer.py | 68 +++++++++++++++++++++------- tests/tc1/class_views.py | 6 +-- tests/tc1/views.py | 5 +- todo.txt | 9 ++-- 6 files changed, 100 insertions(+), 53 deletions(-) diff --git a/src/lib/ACLAnalyzer.py b/src/lib/ACLAnalyzer.py index 80270b7..a33f53a 100644 --- a/src/lib/ACLAnalyzer.py +++ b/src/lib/ACLAnalyzer.py @@ -36,11 +36,8 @@ class ACLAnalyzer(): def analyze_class(self,route:ElementContext)->list[str]: - #TODO CFG method_lists = list(filter(lambda x:x['type']=='class_method' and x['parent']==route.get_base_element_name(),route.cfg.source_code_method_list)) # Remove yang ada di no check list - # class method list - class_methods = route.cfg.ast.children[-1].children for ctx in route.context: if ctx.startswith("Exempt::"): exempted = ctx.split("::")[1] @@ -50,11 +47,6 @@ class ACLAnalyzer(): # Cek setiap fungsi class_acls = [] for f in method_lists: - # Cari namanya - # start_node = None - # for cm in class_methods: - # if(cm.children[1].text.decode()==f['name']): - # start_node = cm ctx = ElementContext(f"{f['parent']}.{f['name']}",'function',route.location,[f"Parent::{f['parent']}"]) # if start_node: # ctx.set_cfg(CFGGenerator().generate(ctx)) @@ -69,7 +61,8 @@ class ACLAnalyzer(): # Cek parent nya untuk menentukaan apakah ada dekorator # Inisialisasi principal_list # if not is_route: -#print("ACL",route) + # print("ACL",route) + var_list = [] principal_list = [principal for principal in self.acl_info.principal_list] route.cfg.reset() @@ -99,14 +92,19 @@ class ACLAnalyzer(): if node.type in ['call','assignment']: # Cek call method # Format: [attribute,argument_list] | [identifier,argument_list] -#print("masuk pak eko") + # print("masuk pak eko") child_list = flatten_node(node.children) fun_name = "" for i in range(len(child_list)): if child_list[i] in [':',',',]: #TODO handle buat variabel continue - elif child_list[i] in ['=',')']: + elif child_list[i] in [')']: + fun_name = "" + elif child_list[i] == '=': + # Simpan nama variabel di left hand side + #TODO simpan line + var_list.append({'name':fun_name,'type':child_list[i+1]}) fun_name = "" elif child_list[i]=='==': # Cek left side @@ -347,15 +345,25 @@ class ACLAnalyzer(): elif components[i] in ['(',')']: # Cek apakah fungsinya dipanggil if fun_name: + parts = fun_name.split(".") + # Coba konversi dulu + # print(var_list) + if len(parts)>1: + #TODO hanya handle yg paling awal aja + # print(parts) + for var in var_list: + if parts[0]==var['name']: + parts[0] = var['type'] + fun_name = ".".join(parts) for rute in route.cfg.source_code_method_list: function_name = "" - if fun_name.split(".")[0]!='self' and rute['type']=='module_function' and rute['name']==fun_name: + if parts[0]!='self' and rute['type']=='module_function' and rute['name']==fun_name: function_name = fun_name - elif rute['type']=='class_method' and rute['name']==fun_name.split(".")[-1]: - if fun_name.split(".")[0]!='self': + elif rute['type']=='class_method' and rute['name']==parts[-1]: + if parts[0]!='self': function_name = fun_name else: - function_name = fun_name.split(".")[-1] + function_name = parts[-1] else: function_name = fun_name # Cek @@ -406,7 +414,6 @@ class ACLAnalyzer(): return principal_list def analyze_module(self,route:ElementContext)->list[list[str,list[str]]]: - #TODO CFG # Cari info semua fungsi di module method_lists = route.cfg.source_code_method_list # Remove yang ada di no check list @@ -463,6 +470,7 @@ class ACLAnalyzer(): #print("acl",acl_list) # Kasus kalau acl nya kelas atau fungsi elif acl_class.type in ['class','function']: + # print("kim no") # Cek apakah ada parent context parent_class = "" for k in acl_class.context: @@ -474,13 +482,14 @@ class ACLAnalyzer(): # Kali aja ada di module ini for function in route.cfg.source_code_method_list: if(acl_class.type=='class' and function['type']=='class_method' and function['parent']==acl_class.get_base_element_name()): - if ctx: + full_name = name + if len(name.split("."))==1 and ctx: j = 0 elmt = ctx[j] while elmt in ['(',')',',']: j+=1 elmt = ctx[j] - full_name = f"{name}.{elmt}" + full_name = f"{name}.{elmt}" if(full_name==f"{function['parent']}.{function['name']}"): # Cek apakah dia manggil fungsi yang diimport di acl #print(301 @@ -518,11 +527,11 @@ class ACLAnalyzer(): else: # Beda file, cek di import ada gak # Kali aja ada di module ini - # if name=='is_admin' and route.name=="Views.class_get_logs": - # print("Parent",parent_class) - # print("NAMA",name) - # print("ACL",acl_class) - # print("ROUTE",route) + # if name=='RoleCheck.is_admin': + # print("Parent",parent_class) + # print("NAMA",name) + # print("ACL",acl_class) + # print("ROUTE",route) # print(route.cfg.source_code) dependency_lists = route.cfg.source_code_dependency_list route_position = route.cfg.get_line_index(route.name) @@ -548,7 +557,7 @@ class ACLAnalyzer(): if m["rename"]: # Pake rename comparator = m["rename"] - if ctx: + if len(name.split("."))==1 and ctx: j = 0 elmt = ctx[j] j+=1 @@ -556,20 +565,24 @@ class ACLAnalyzer(): elmt = ctx[j] j+=1 name = f"{name}.{elmt}" + # print("nemu",name) for method in acl_class.cfg.source_code_method_list: if method['type']!='class_method' or (method['type']=='class_method' and method['parent']!=m['original']): continue + # print(f'{comparator}.{method["name"]}') if(name==f'{comparator}.{method["name"]}'): # print("GOMEN", self.acl_info.acl_context) # Cek apakah dia manggil fungsi yang diimport di acl #print(501) this_acl = None for acl in self.analyze_class(acl_class): + # print("ACL",acl) if acl[0]==name: this_acl = acl break if this_acl: acl_list = list(set(acl_list) & set(acl[1])) + # print("ACL LUST",acl_list) elif(acl_class.type=='function'): # Cukup cek apakah kelas atau fungsinya sama # print("pake nanya") @@ -605,7 +618,7 @@ class ACLAnalyzer(): # print("prev",acl_list) acl_list = list(set(acl_list) & set(self.analyze_function(acl_class,False))) # print("after",acl_list) -#print("aclku",acl_list) + # print("aclku",acl_list) # acl_list = self.acl_info.acl_context[acl_class.get_base_element_name()] return acl_list diff --git a/src/lib/ASTGenerator.py b/src/lib/ASTGenerator.py index 616f686..229e782 100644 --- a/src/lib/ASTGenerator.py +++ b/src/lib/ASTGenerator.py @@ -107,8 +107,6 @@ class ASTGenerator(): class_name = "" if node[0].parent.parent.type=='block': class_name = node[0].parent.parent.parent.children[1].text.decode() - #TODO handle decorated class method - # print(node) if(node[0].text.decode() == ctx.name.split("(")[0] or (class_name and f"{class_name}.{node[0].text.decode()}"==ctx.name.split("(")[0])): # Fungsinya ketemu ast = node[0].parent diff --git a/src/lib/RouteSanitizationAnalyzer.py b/src/lib/RouteSanitizationAnalyzer.py index b11421b..0256a60 100644 --- a/src/lib/RouteSanitizationAnalyzer.py +++ b/src/lib/RouteSanitizationAnalyzer.py @@ -59,6 +59,7 @@ class RouteSanitizationAnalyzer(): return unsanitized_methods def analyze_function(self,route:ElementContext)->bool: + var_list = [] # print("rota",route) ##print(self.project_info.acl_class) # Cek parent nya untuk menentukaan apakah ada dekorator @@ -95,12 +96,20 @@ class RouteSanitizationAnalyzer(): # Format: [attribute,argument_list] | [identifier,argument_list] child_list = flatten_node(node.children) fun_name = "" - for child in child_list: - if child in [':',',']: + # if b'rolecheck = RoleCheck()' in node.text: + # print("as",node) + # print(child_list) + for i in range(len(child_list)): + if child_list[i] in [':',',']: continue - elif child in ['=',')']: + elif child_list[i] in [')']: fun_name = "" - elif child in ['(']: + elif child_list[i] == '=': + # Simpan nama variabel di left hand side + #TODO simpan line + var_list.append({'name':fun_name,'type':child_list[i+1]}) + fun_name = "" + elif child_list[i] in ['(']: # Cek apakah fungsinya ada if fun_name: # cek buat fungsi di kelas yang sama @@ -122,7 +131,7 @@ class RouteSanitizationAnalyzer(): return True fun_name = "" else: - fun_name += child + fun_name += child_list[i] elif node.type=='while_statement': for elmt in node.children: # Skip kalau dah ':' @@ -260,7 +269,10 @@ class RouteSanitizationAnalyzer(): else: components += flatten_node(child.children) # Cek tiap componentnya - #print("comp",components) + # if b'if (rolecheck.is_admin(current_user)):' in node.text: + # print("asu",node) + # print(child_list) + # print("comp",components) fun_name = "" #print(components) for i in range(len(components)): @@ -271,18 +283,27 @@ class RouteSanitizationAnalyzer(): # Cek apakah fungsinya dipanggil #print("fun",fun_name) if fun_name: + parts = fun_name.split(".") + # Coba konversi dulu + # print(var_list) + if len(parts)>1: + #TODO hanya handle yg paling awal aja + # print(parts) + for var in var_list: + if parts[0]==var['name']: + parts[0] = var['type'] #print(route.cfg.source_code_method_list) for rute in route.cfg.source_code_method_list: function_name = "" - if fun_name.split(".")[0]!='self' and rute['type']=='module_function' and rute['name']==fun_name: - function_name = fun_name - elif rute['type']=='class_method' and rute['name']==fun_name.split(".")[-1]: - if fun_name.split(".")[0]!='self': - function_name = fun_name + if parts[0]!='self' and rute['type']=='module_function' and rute['name']==".".join(parts): + function_name = ".".join(parts) + elif rute['type']=='class_method' and rute['name']==parts[-1]: + if parts[0]!='self': + function_name = ".".join(parts) else: - function_name = fun_name.split(".")[-1] + function_name = parts[-1] else: - function_name = fun_name + function_name = ".".join(parts) #print("func",function_name) # Cek #print(function_name) @@ -361,13 +382,17 @@ class RouteSanitizationAnalyzer(): #print(acl_class.type) if(acl_class.type=='class' and function['type']=='class_method' and function['parent']==acl_class.get_base_element_name()): ##print("furu",function['name'],acl_class.get_base_element_name()) - if ctx: + #TODO hanya handle 1 accessing misal a.b, a.b.c gak bisa + full_name = name + if len(name.split("."))==1 and ctx: j = 0 elmt = ctx[j] while elmt in ['(',')',',']: j+=1 + if j >= len(ctx): + break elmt = ctx[j] - full_name = f"{name}.{elmt}" + full_name = f"{name}.{elmt}" if(full_name==f"{function['parent']}.{function['name']}"): # Cek apakah dia manggil fungsi yang diimport di acl #print(301) @@ -406,21 +431,30 @@ class RouteSanitizationAnalyzer(): if m["rename"]: # Pake rename comparator = m["rename"] - if ctx: + #TODO hanya handle 1 accessing misal a.b, a.b.c gak bisa + # print(name) + # print("asnp",name.split(".")) + if len(name.split("."))==1 and ctx: + # print("as",ctx) j = 0 elmt = ctx[j] while elmt in ['(',')',',']: j+=1 + if j >= len(ctx): + break elmt = ctx[j] name = f"{name}.{elmt}" for method in acl_class.cfg.source_code_method_list: -#print("method",method) + # print("method",method) #print("namae",name) if method['type']!='class_method' or (method['type']=='class_method' and method['parent']!=m['original']): continue + # print(f'{comparator}.{method["name"]}') + # print(name) if(name==f'{comparator}.{method["name"]}'): # Cek apakah dia manggil fungsi yang diimport di acl #print(501) + # print("masuk pak eko") return True elif(acl_class.type=='function'): #print("parent",parent_class) diff --git a/tests/tc1/class_views.py b/tests/tc1/class_views.py index 6c600ed..4c97704 100644 --- a/tests/tc1/class_views.py +++ b/tests/tc1/class_views.py @@ -10,8 +10,8 @@ views = Blueprint('views', __name__) class Views(): # @NoCheck - def __init__(self) -> None: - pass + def __init__(self,a) -> None: + self.a = a @views.route('/add', methods=['POST']) @login_required def class_add_note(self): @@ -64,7 +64,7 @@ class Views(): notes = Note.query.filter(Note.user_id==current_user.id) return jsonify(notes) @views.route('/logs', methods=['GET']) - @login_required + # @login_required def class_get_logs(self): if (RoleCheck().is_admin(current_user)): abort(403) diff --git a/tests/tc1/views.py b/tests/tc1/views.py index 7d69919..ac11e48 100644 --- a/tests/tc1/views.py +++ b/tests/tc1/views.py @@ -66,9 +66,10 @@ def get_note(): return jsonify(notes) @views.route('/logs', methods=['GET']) -@login_required +# @login_required def get_logs(): - if (RoleCheck().is_admin(current_user)): + rolecheck = RoleCheck(1) + if (rolecheck.is_admin(current_user)): abort(403) logs = Log.query.get() diff --git a/todo.txt b/todo.txt index 5a38c2d..254d508 100644 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,4 @@ -- Per NoCheck an belum dites +- Per NoCheck an sudah dites function (V) class: - function (V) @@ -7,6 +7,7 @@ module: - class (V) - class > function (V) - - routes kena nocheck? - default gak cek __init__ \ No newline at end of file +TODO +- check kalau kelasnya disimpan di variabel (V) -> cuma kalau langsung manggil kelas +- routes kena nocheck? +- default gak cek __init__ \ No newline at end of file -- GitLab