77from pathlib import Path
88from user_scanner .cli .printer import Printer
99from user_scanner .core .result import Result
10+ from types import ModuleType
1011from typing import Callable , Dict , List
1112from user_scanner .core .helpers import get_site_name , is_last_value
1213
1314
14- def load_modules (category_path : Path ):
15+ def load_modules (category_path : Path ) -> List [ ModuleType ] :
1516 modules = []
1617 for file in category_path .glob ("*.py" ):
1718 if file .name == "__init__.py" :
@@ -26,8 +27,9 @@ def load_modules(category_path: Path):
2627 return modules
2728
2829
29- def load_categories () -> Dict [str , Path ]:
30- root = Path (__file__ ).resolve ().parent .parent / "user_scan"
30+ def load_categories (is_email : bool = False ) -> Dict [str , Path ]:
31+ folder_name = "email_scan" if is_email else "user_scan"
32+ root = Path (__file__ ).resolve ().parent .parent / folder_name
3133 categories = {}
3234
3335 for subfolder in root .iterdir ():
@@ -39,33 +41,30 @@ def load_categories() -> Dict[str, Path]:
3941 return categories
4042
4143
42- def find_module (name : str ) :
44+ def find_module (name : str , is_email : bool = False ) -> List [ ModuleType ] :
4345 name = name .lower ()
4446
45- matches = [
47+ return [
4648 module
47- for category_path in load_categories ().values ()
49+ for category_path in load_categories (is_email ).values ()
4850 for module in load_modules (category_path )
4951 if module .__name__ .split ("." )[- 1 ].lower () == name
5052 ]
5153
52- return matches
5354
54- def find_category (module ) -> str | None :
55+ def find_category (module : ModuleType ) -> str | None :
5556
5657 module_file = getattr (module , '__file__' , None )
5758 if not module_file :
5859 return None
5960
6061 category = Path (module_file ).parent .name .lower ()
61- categories = load_categories ()
62- if category in categories :
62+ if category in load_categories (False ) or category in load_categories (True ):
6363 return category .capitalize ()
6464
6565 return None
6666
6767
68-
6968def worker_single (module , username : str ) -> Result :
7069 func = next ((getattr (module , f ) for f in dir (module )
7170 if f .startswith ("validate_" ) and callable (getattr (module , f ))), None )
@@ -99,7 +98,6 @@ def run_module_single(module, username: str, printer: Printer, last: bool = True
9998 return [result ]
10099
101100
102-
103101def run_checks_category (category_path : Path , username : str , printer : Printer , last : bool = True ) -> List [Result ]:
104102 modules = load_modules (category_path )
105103
@@ -196,20 +194,30 @@ def contains(a, b): return (isinstance(a, list) and b in a) or (a == b)
196194 return generic_validate (url , inner , ** kwargs )
197195
198196
199- def generate_permutations (username , pattern , limit = None ) :
197+ def generate_permutations (username : str , pattern : str , limit : int | None = None , is_email : bool = False ) -> List [ str ] :
200198 """
201199 Generate all order-based permutations of characters in `pattern`
202200 appended after `username`.
203201 """
204- permutations_set = {username }
205202
203+ if limit and limit <= 0 :
204+ return []
205+
206+ permutations_set = {username }
206207 chars = list (pattern )
207208
209+ domain = ""
210+ if is_email :
211+ username , domain = username .strip ().split ("@" )
212+
208213 # generate permutations of length 1 → len(chars)
209- for r in range (1 , len (chars ) + 1 ):
214+ for r in range (len (chars )):
210215 for combo in permutations (chars , r ):
211- permutations_set .add (username + '' .join (combo ))
216+ new = username + '' .join (combo )
217+ if is_email :
218+ new += "@" + domain
219+ permutations_set .add (new )
212220 if limit and len (permutations_set ) >= limit :
213- return list (permutations_set )[: limit ]
221+ return sorted (permutations_set )
214222
215223 return sorted (permutations_set )
0 commit comments