jseye 1.0.2__tar.gz → 1.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {jseye-1.0.2/jseye.egg-info → jseye-1.0.3}/PKG-INFO +2 -1
- {jseye-1.0.2 → jseye-1.0.3}/jseye/__init__.py +1 -1
- {jseye-1.0.2 → jseye-1.0.3}/jseye/modules/harvest.py +13 -2
- {jseye-1.0.2 → jseye-1.0.3}/jseye/modules/js_download.py +58 -3
- {jseye-1.0.2 → jseye-1.0.3}/jseye/modules/tiered_analysis.py +9 -3
- {jseye-1.0.2 → jseye-1.0.3/jseye.egg-info}/PKG-INFO +2 -1
- {jseye-1.0.2 → jseye-1.0.3}/jseye.egg-info/requires.txt +1 -0
- {jseye-1.0.2 → jseye-1.0.3}/pyproject.toml +3 -2
- {jseye-1.0.2 → jseye-1.0.3}/LICENSE +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/MANIFEST.in +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/README.md +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/__main__.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/banner.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/cli.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/data/regex.yaml +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/data/vendor_blacklist.txt +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/installer.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/modules/__init__.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/modules/analyze_ast.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/modules/analyze_regex.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/modules/correlate.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/modules/js_filter.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/modules/linkfinder.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/modules/secrets.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/modules/sinks.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/pipeline.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/utils/__init__.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/utils/cache.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/utils/fs.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/utils/hashing.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/utils/logger.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye/utils/shell.py +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye.egg-info/SOURCES.txt +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye.egg-info/dependency_links.txt +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye.egg-info/entry_points.txt +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/jseye.egg-info/top_level.txt +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/scripts/ast_parser.js +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/setup.cfg +0 -0
- {jseye-1.0.2 → jseye-1.0.3}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jseye
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.3
|
|
4
4
|
Summary: JavaScript Intelligence & Attack Surface Discovery Tool
|
|
5
5
|
Home-page: https://github.com/letchupkt/jseye
|
|
6
6
|
Author: Lakshmikanthan K
|
|
@@ -32,6 +32,7 @@ Requires-Dist: pyyaml>=6.0
|
|
|
32
32
|
Requires-Dist: requests>=2.28.0
|
|
33
33
|
Requires-Dist: urllib3>=1.26.0
|
|
34
34
|
Requires-Dist: jsbeautifier>=1.14.0
|
|
35
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
35
36
|
Provides-Extra: dev
|
|
36
37
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
37
38
|
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
@@ -17,10 +17,12 @@ console = Console()
|
|
|
17
17
|
class URLHarvester:
|
|
18
18
|
"""Harvest URLs from multiple sources in parallel"""
|
|
19
19
|
|
|
20
|
-
def __init__(self, output_dir: Path):
|
|
20
|
+
def __init__(self, output_dir: Path, cache_manager=None):
|
|
21
21
|
self.output_dir = output_dir
|
|
22
|
+
self.cache_manager = cache_manager
|
|
22
23
|
self.deduplicator = DeduplicatorHash()
|
|
23
24
|
self.timeout = 120 # 2 minutes per tool
|
|
25
|
+
self.performance_stats = {}
|
|
24
26
|
|
|
25
27
|
async def run_tool_async(self, tool_name: str, domain: str) -> List[str]:
|
|
26
28
|
"""Run a single tool asynchronously"""
|
|
@@ -174,4 +176,13 @@ class URLHarvester:
|
|
|
174
176
|
except Exception as e:
|
|
175
177
|
log_progress(f"{tool_name} failed for {domain}: {e}")
|
|
176
178
|
|
|
177
|
-
return self.deduplicator.deduplicate_list(all_urls)
|
|
179
|
+
return self.deduplicator.deduplicate_list(all_urls)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def get_performance_stats(self) -> Dict:
|
|
183
|
+
"""Get performance statistics"""
|
|
184
|
+
return self.performance_stats
|
|
185
|
+
|
|
186
|
+
def harvest_urls_parallel(self, domains: List[str]) -> List[str]:
|
|
187
|
+
"""Alias for harvest_urls for backward compatibility"""
|
|
188
|
+
return self.harvest_urls(domains)
|
|
@@ -18,13 +18,13 @@ from ..utils.cache import JSEyeCache
|
|
|
18
18
|
class JSDownloader:
|
|
19
19
|
"""Download JavaScript files with caching and parallel processing"""
|
|
20
20
|
|
|
21
|
-
def __init__(self, output_dir: Path):
|
|
21
|
+
def __init__(self, output_dir: Path, cache_manager=None):
|
|
22
22
|
self.output_dir = output_dir
|
|
23
23
|
self.js_dir = output_dir / "js_files"
|
|
24
24
|
ensure_dir(self.js_dir)
|
|
25
25
|
|
|
26
26
|
# Initialize cache
|
|
27
|
-
self.cache = JSEyeCache(output_dir)
|
|
27
|
+
self.cache = cache_manager if cache_manager else JSEyeCache(output_dir)
|
|
28
28
|
|
|
29
29
|
# Download settings
|
|
30
30
|
self.max_file_size = 3 * 1024 * 1024 # 3MB limit
|
|
@@ -34,6 +34,8 @@ class JSDownloader:
|
|
|
34
34
|
self.session_headers = {
|
|
35
35
|
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
self.performance_stats = {}
|
|
37
39
|
|
|
38
40
|
async def download_js_file_async(self, session: aiohttp.ClientSession, url: str) -> Dict:
|
|
39
41
|
"""Download a single JavaScript file asynchronously with caching"""
|
|
@@ -275,4 +277,57 @@ class JSDownloader:
|
|
|
275
277
|
successful = len([r for r in results if r['status'] == 'success'])
|
|
276
278
|
log_progress(f"Sequential download complete: {successful}/{len(urls)} successful")
|
|
277
279
|
|
|
278
|
-
return results
|
|
280
|
+
return results
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def get_performance_stats(self) -> Dict:
|
|
284
|
+
"""Get performance statistics"""
|
|
285
|
+
return self.performance_stats
|
|
286
|
+
|
|
287
|
+
def download_js_files_parallel(self, urls: List[str], max_files: int = 200) -> List[Dict]:
|
|
288
|
+
"""Alias for async download - backward compatibility"""
|
|
289
|
+
urls_to_download = urls[:max_files]
|
|
290
|
+
return asyncio.run(self.download_js_files_async(urls_to_download))
|
|
291
|
+
|
|
292
|
+
async def download_js_files_async(self, urls: List[str]) -> List[Dict]:
|
|
293
|
+
"""Async wrapper for download_js_files_parallel"""
|
|
294
|
+
return await self.download_js_files_parallel_internal(urls)
|
|
295
|
+
|
|
296
|
+
async def download_js_files_parallel_internal(self, urls: List[str]) -> List[Dict]:
|
|
297
|
+
"""Internal parallel download method"""
|
|
298
|
+
log_progress(f">> Downloading {len(urls)} JavaScript files in parallel...")
|
|
299
|
+
|
|
300
|
+
# Create semaphore to limit concurrent downloads
|
|
301
|
+
semaphore = asyncio.Semaphore(self.max_concurrent)
|
|
302
|
+
|
|
303
|
+
async def download_with_semaphore(url):
|
|
304
|
+
async with semaphore:
|
|
305
|
+
async with aiohttp.ClientSession(headers=self.session_headers) as session:
|
|
306
|
+
return await self.download_js_file_async(session, url)
|
|
307
|
+
|
|
308
|
+
# Download all files in parallel
|
|
309
|
+
tasks = [download_with_semaphore(url) for url in urls]
|
|
310
|
+
results = await asyncio.gather(*tasks, return_exceptions=True)
|
|
311
|
+
|
|
312
|
+
# Filter out exceptions
|
|
313
|
+
valid_results = []
|
|
314
|
+
for i, result in enumerate(results):
|
|
315
|
+
if isinstance(result, Exception):
|
|
316
|
+
log_progress(f"Download exception for {urls[i]}: {result}")
|
|
317
|
+
valid_results.append({
|
|
318
|
+
'url': urls[i],
|
|
319
|
+
'filepath': None,
|
|
320
|
+
'size': 0,
|
|
321
|
+
'status': 'exception',
|
|
322
|
+
'error': str(result)
|
|
323
|
+
})
|
|
324
|
+
else:
|
|
325
|
+
valid_results.append(result)
|
|
326
|
+
|
|
327
|
+
# Count successful downloads
|
|
328
|
+
successful = len([r for r in valid_results if r['status'] == 'success'])
|
|
329
|
+
cached = len([r for r in valid_results if 'cached_at' in r])
|
|
330
|
+
|
|
331
|
+
log_progress(f"[C] Download complete: {successful} new, {cached} cached, {len(valid_results)} total")
|
|
332
|
+
|
|
333
|
+
return valid_results
|
|
@@ -17,15 +17,16 @@ from .secrets import SecretsDetector
|
|
|
17
17
|
|
|
18
18
|
class TieredAnalysisEngine:
|
|
19
19
|
"""
|
|
20
|
-
|
|
20
|
+
>> TIERED ANALYSIS MODEL
|
|
21
21
|
|
|
22
22
|
Tier 1: Regex + AST + LinkFinder + Secrets (HEAVY) - Top 20%
|
|
23
23
|
Tier 2: Regex + LinkFinder (MEDIUM) - Next 30%
|
|
24
24
|
Tier 3: Regex only (FAST) - Remaining 50%
|
|
25
25
|
"""
|
|
26
26
|
|
|
27
|
-
def __init__(self, output_dir: Path):
|
|
27
|
+
def __init__(self, output_dir: Path, cache_manager=None):
|
|
28
28
|
self.output_dir = output_dir
|
|
29
|
+
self.cache_manager = cache_manager
|
|
29
30
|
self.regex_analyzer = RegexAnalyzer(output_dir)
|
|
30
31
|
self.ast_analyzer = ASTAnalyzer(output_dir)
|
|
31
32
|
self.linkfinder = LinkFinderIntegration(output_dir)
|
|
@@ -301,4 +302,9 @@ class TieredAnalysisEngine:
|
|
|
301
302
|
'secrets': secrets,
|
|
302
303
|
'sinks': sinks,
|
|
303
304
|
'functions': functions
|
|
304
|
-
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def get_performance_stats(self) -> Dict:
|
|
309
|
+
"""Get performance statistics"""
|
|
310
|
+
return self.analysis_stats
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jseye
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.3
|
|
4
4
|
Summary: JavaScript Intelligence & Attack Surface Discovery Tool
|
|
5
5
|
Home-page: https://github.com/letchupkt/jseye
|
|
6
6
|
Author: Lakshmikanthan K
|
|
@@ -32,6 +32,7 @@ Requires-Dist: pyyaml>=6.0
|
|
|
32
32
|
Requires-Dist: requests>=2.28.0
|
|
33
33
|
Requires-Dist: urllib3>=1.26.0
|
|
34
34
|
Requires-Dist: jsbeautifier>=1.14.0
|
|
35
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
35
36
|
Provides-Extra: dev
|
|
36
37
|
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
37
38
|
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "jseye"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.3"
|
|
8
8
|
description = "JavaScript Intelligence & Attack Surface Discovery Tool"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -35,7 +35,8 @@ dependencies = [
|
|
|
35
35
|
"pyyaml>=6.0",
|
|
36
36
|
"requests>=2.28.0",
|
|
37
37
|
"urllib3>=1.26.0",
|
|
38
|
-
"jsbeautifier>=1.14.0"
|
|
38
|
+
"jsbeautifier>=1.14.0",
|
|
39
|
+
"aiohttp>=3.8.0"
|
|
39
40
|
]
|
|
40
41
|
|
|
41
42
|
[project.optional-dependencies]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|