Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance endpoint detection, simplify jmespath queries #19

Merged
merged 1 commit into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion atom_tools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""
A cli, classes and functions for converting an atom slice to a different format
"""
__version__ = '0.1.1'
__version__ = '0.1.2'
69 changes: 43 additions & 26 deletions atom_tools/lib/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,12 @@ class OpenAPI:
Args:
dest_format (str): The destination format.
origin_type (str): The origin type.
usages (list, optional): The list of usages. Defaults to None.
usages (str): Path of the usages slice.

Attributes:
usages (AtomSlice): The usage slice.
origin_type (str): The origin type.
openapi_version (str): The OpenAPI version.
title (str): The title of the OpenAPI specification.
regex (RegexCollection): collection of regular expressions

Methods:
Expand Down Expand Up @@ -108,7 +107,7 @@ def __init__(
origin_type: str,
usages: str,
) -> None:
self.usages = AtomSlice(usages, origin_type)
self.usages: AtomSlice = AtomSlice(usages)
self.origin_type = origin_type
self.openapi_version = dest_format.replace('openapi', '')
self.title = f'OpenAPI Specification for {Path(usages).parent.stem}'
Expand Down Expand Up @@ -182,12 +181,13 @@ def process_methods(self) -> Dict[str, List[str]]:
'].*.resolvedMethod[]}')

calls = self._process_methods_helper(
'objectSlices[].{fullName: fullName, resolvedMethods: usages['
'].invokedCalls[?resolvedMethod].resolvedMethod[]}')
'objectSlices[].{fullName: fullName, resolvedMethods: usages[].*['
'][?resolvedMethod].resolvedMethod[]}')

user_defined_types = self._process_methods_helper(
'userDefinedTypes[].{fullName: name, resolvedMethods: fields['
'].name}')

for key, value in calls.items():
if method_map.get(key):
method_map[key]['resolved_methods'].extend(
Expand Down Expand Up @@ -220,13 +220,8 @@ def query_calls(self, full_name: str, resolved_methods: List[str]) -> List:
Returns:
list[dict]: List of invoked calls and argument to calls.
"""
result = self._query_calls_helper(full_name, '].invokedCalls[][]')
result = self._query_calls_helper(full_name, '].*[][][]')
calls = []
for call in result:
m = call.get('resolvedMethod', '')
if m and m in resolved_methods:
calls.append(call)
result = self._query_calls_helper(full_name, '].argToCalls[][]')
for call in result:
m = call.get('resolvedMethod', '')
if m and m in resolved_methods:
Expand Down Expand Up @@ -326,14 +321,6 @@ def process_resolved_methods(self, resolved_methods: Dict) -> Dict:

Returns:
dict: A dictionary mapping each method to its extracted endpoints.

Raises:
None

Examples:
>>> methods = {'m1': ['ep1'], 'm1': ['ep2']}
>>> OpenAPI.process_resolved_methods(methods)
{'m1': {'endpoints': ['ep1']}, 'm2': {'endpoints': ['ep2']}}
"""
resolved_map = {}
for method in resolved_methods:
Expand Down Expand Up @@ -445,7 +432,26 @@ def create_paths_item(self, paths_dict: Dict) -> Dict:
else:
paths_object[ep] = {}

return paths_object
return self.remove_nested_parameters(paths_object)

@staticmethod
def remove_nested_parameters(data: Dict) -> Dict[str, Dict | List]:
"""
Removes nested path parameters from the given data.

Args:
data (dict): The data containing nested path parameters.

Returns:
dict: The modified data with the nested path parameters removed.
"""
for value in data.values():
for v in value.values():
if isinstance(v, dict) and "parameters" in v and isinstance(
v["parameters"], list):
v["parameters"] = [param for param in v["parameters"] if
param.get("in") != "path"]
return data

@staticmethod
def determine_operations(call: Dict, params: List) -> Dict[str, Any]:
Expand Down Expand Up @@ -509,10 +515,17 @@ def create_param_object(self, ep: str, call: Dict | None) -> List[Dict]:
"""
params = self.generic_params_helper(ep) if '{' in ep else []
if not params and call:
params = [
{'name': param, 'in': 'header'}
for param in set(call.get('paramTypes', [])) if param != 'ANY'
]
ptypes = set(call.get('paramTypes', []))
if len(ptypes) > 1:
params = [
{'name': param, 'in': 'header'}
for param in ptypes if param != 'ANY'
]
else:
params = [
{'name': param, 'in': 'header'}
for param in ptypes
]
return params

def collect_methods(self) -> List:
Expand Down Expand Up @@ -579,11 +592,15 @@ def filter_matches(self, matches: List[str], code: str) -> List[str]:
):
return filtered_matches
case 'js' | 'ts' | 'javascript' | 'typescript':
if 'app.' not in code and 'route' not in code:
if (
'app.' not in code and
'route' not in code and
'ftp' not in code
):
return filtered_matches

for m in matches:
if m and m[0] not in ('.', '@') and '/' in m:
if m and m[0] not in ('.', '@', ','):
nm = m.replace('"', '').replace("'", '').lstrip('/')
filtered_matches.append(f'/{nm}')

Expand Down
3 changes: 1 addition & 2 deletions atom_tools/lib/slices.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ class AtomSlice:
import_slice: Imports a slice from a JSON file.
"""

def __init__(self, filename, language):
def __init__(self, filename: str) -> None:
self.content = self.import_slice(filename)
self.language = language
self.endpoints_regex = re.compile(r'[\'"](\S*?)[\'"]', re.IGNORECASE)

@staticmethod
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[project]
name = "atom-tools"
version = "0.1.1"
description = "Collection of tools for use with appthreat/atom."
version = "0.1.2"
description = "Collection of tools for use with AppThreat/atom."
authors = [
{ name = "Team AppThreat", email = "[email protected]" },
]
Expand Down
Loading
Loading