voidaccess 1.7.0__tar.gz → 1.7.2__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.
- {voidaccess-1.7.0 → voidaccess-1.7.2}/PKG-INFO +12 -6
- {voidaccess-1.7.0 → voidaccess-1.7.2}/README.md +11 -5
- {voidaccess-1.7.0 → voidaccess-1.7.2}/api/routes/actors.py +42 -23
- {voidaccess-1.7.0 → voidaccess-1.7.2}/api/routes/entities.py +8 -12
- {voidaccess-1.7.0 → voidaccess-1.7.2}/api/routes/investigations.py +3126 -3453
- {voidaccess-1.7.0 → voidaccess-1.7.2}/api/routes/search.py +81 -61
- {voidaccess-1.7.0 → voidaccess-1.7.2}/config.py +13 -7
- {voidaccess-1.7.0 → voidaccess-1.7.2}/crawler/spider.py +30 -4
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/queries.py +18 -9
- {voidaccess-1.7.0 → voidaccess-1.7.2}/export/ioc_package.py +1 -1
- {voidaccess-1.7.0 → voidaccess-1.7.2}/export/misp.py +2 -3
- {voidaccess-1.7.0 → voidaccess-1.7.2}/export/sigma.py +2 -3
- {voidaccess-1.7.0 → voidaccess-1.7.2}/export/stix.py +64 -20
- {voidaccess-1.7.0 → voidaccess-1.7.2}/extractor/ner.py +136 -1
- {voidaccess-1.7.0 → voidaccess-1.7.2}/extractor/normalizer.py +186 -90
- {voidaccess-1.7.0 → voidaccess-1.7.2}/extractor/pipeline.py +74 -13
- {voidaccess-1.7.0 → voidaccess-1.7.2}/graph/__init__.py +2 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/graph/builder.py +148 -16
- {voidaccess-1.7.0 → voidaccess-1.7.2}/monitor/config.py +4 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/monitor/jobs.py +68 -11
- {voidaccess-1.7.0 → voidaccess-1.7.2}/monitor/scheduler.py +4 -6
- {voidaccess-1.7.0 → voidaccess-1.7.2}/pyproject.toml +1 -1
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/actor_profiles.py +2 -2
- voidaccess-1.7.2/tests/test_confidence_calibration.py +108 -0
- voidaccess-1.7.2/tests/test_graph_integration.py +141 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_monitor.py +11 -8
- voidaccess-1.7.2/tests/test_monitor_integration.py +150 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_regex_patterns.py +39 -44
- voidaccess-1.7.2/tests/test_stix_export.py +281 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/vector/__init__.py +2 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess/llm.py +97 -5
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess.egg-info/PKG-INFO +12 -6
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess.egg-info/SOURCES.txt +3 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess_cli/__init__.py +1 -1
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess_cli/adapters/sqlite.py +97 -6
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess_cli/commands/investigate.py +20 -17
- voidaccess-1.7.0/tests/test_stix_export.py +0 -19
- {voidaccess-1.7.0 → voidaccess-1.7.2}/LICENSE +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/analysis/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/analysis/opsec.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/analysis/patterns.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/analysis/temporal.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/api/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/api/auth.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/api/main.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/api/routes/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/api/routes/admin.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/api/routes/auth.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/api/routes/export.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/api/routes/monitors.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/api/routes/settings.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/auth/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/auth/token_blacklist.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/crawler/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/crawler/dedup.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/crawler/frontier.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/crawler/utils.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/env.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0001_initial_schema.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0002_add_investigation_status_column.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0002_add_missing_tables.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0003_add_canonical_value_and_entity_links.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0004_add_page_posted_at.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0005_add_extraction_method.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0006_add_monitor_alerts.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0007_add_actor_style_profiles.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0008_add_users_table.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0009_add_investigation_id_to_relationships.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0010_add_composite_index_entity_relationships.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0011_add_page_extraction_cache.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0013_add_graph_status.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0015_add_progress_fields.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0016_backfill_graph_status.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0017_add_user_api_keys.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0018_add_user_id_to_investigations.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0019_add_content_safety_log.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0020_add_entity_source_tracking.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0021_add_search_engine_stats.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0022_add_actor_profiles.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/migrations/versions/0023_add_investigation_metadata.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/models.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/search_engine_stats.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/db/session.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/export/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/export/snort_export.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/export/yara_export.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/extractor/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/extractor/llm_extract.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/extractor/regex_patterns.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/fingerprint/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/fingerprint/profiler.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/fingerprint/stylometry.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/graph/export.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/graph/model.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/graph/queries.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/graph/visualize.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/i18n/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/i18n/detect.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/i18n/query_expand.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/i18n/translate.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/monitor/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/monitor/_db.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/monitor/alerts.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/monitor/diff.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/scraper/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/scraper/scrape.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/scraper/scrape_js.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/search/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/search/circuit_breaker.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/search/query_builder.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/search/search.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/setup.cfg +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/blockchain.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/cache.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/cisa.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/data/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/data/onion_seeds.json +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/dns_enrichment.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/domain_reputation.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/email_reputation.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/engines.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/enrichment.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/github_scraper.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/gitlab_scraper.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/hash_reputation.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/historical_intel.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/ip_reputation.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/paste_scraper.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/pastes.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/proxy_client.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/rss_scraper.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/seed_manager.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/seeds.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/shodan.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/telegram.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/sources/virustotal.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_analysis_opsec.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_analysis_stylometry.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_analysis_temporal.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_api.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_api_monitors.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_blockchain.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_cli_proxy_config.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_config.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_crawler.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_db.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_dns_enrichment.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_domain_reputation.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_email_reputation.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_filter_e2e_manual.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_filter_parser_manual.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_fingerprint.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_github_scraper.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_gitlab_scraper.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_graph.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_hash_reputation.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_i18n.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_ip_reputation.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_llm.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_llm_utils.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_model_singleton.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_pagination.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_paste_scraper.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_proxy_client.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_rss_scraper.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_scrape_js.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_settings.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_snort_export.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_sources.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_sources_enrichment_new.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_vector.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/tests/test_yara_export.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/utils/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/utils/async_utils.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/utils/content_safety.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/utils/defang.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/utils/encryption.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/utils/enrichment_cache.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/utils/ioc_freshness.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/utils/user_keys.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/vector/embedder.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/vector/model_singleton.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/vector/search.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/vector/store.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess/config.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess/llm_utils.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess.egg-info/dependency_links.txt +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess.egg-info/entry_points.txt +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess.egg-info/requires.txt +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess.egg-info/top_level.txt +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess_cli/adapters/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess_cli/browser.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess_cli/commands/__init__.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess_cli/commands/actors.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess_cli/commands/configure.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess_cli/commands/enrich.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess_cli/commands/export.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess_cli/commands/show.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess_cli/config.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess_cli/display.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess_cli/main.py +0 -0
- {voidaccess-1.7.0 → voidaccess-1.7.2}/voidaccess_cli/tor_detect.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: voidaccess
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.2
|
|
4
4
|
Summary: Dark web OSINT CLI — automated threat intelligence from query to report
|
|
5
5
|
Author: VoidAccess
|
|
6
6
|
License-Expression: MIT
|
|
@@ -104,7 +104,16 @@ Commercial threat intelligence platforms often charge prohibitive annual fees fo
|
|
|
104
104
|
|
|
105
105
|
---
|
|
106
106
|
|
|
107
|
-
## What's New in v1.7.
|
|
107
|
+
## What's New in v1.7.2
|
|
108
|
+
- STIX export relationship generation is bounded and semantic, avoiding page-level cartesian edge explosions at larger entity counts.
|
|
109
|
+
- Repeated NER false positives for threat actor handles and organization names are filtered before persistence.
|
|
110
|
+
- MISP/Sigma/API query paths no longer use the SQLAlchemy subquery-in-`IN()` pattern that produced warnings.
|
|
111
|
+
- Optional configuration warnings are summarized once per process.
|
|
112
|
+
- Refined LLM query output is persisted as a short search string, not explanatory Markdown.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## What's New in the Previous Release
|
|
108
117
|
|
|
109
118
|
- **Dependency optional-extras split** — `sentence-transformers`, `torch`, `transformers`, `telethon`, and `playwright` are now optional extras: `voidaccess[nlp]`, `voidaccess[telegram]`, `voidaccess[js]`, and `voidaccess[all]`.
|
|
110
119
|
- **Optional clearnet ScrapingAnt integration** — paste sites and RSS feeds can now be routed through ScrapingAnt. Affects clearnet scraping only; Tor, `.onion`, GitHub, and GitLab traffic are never affected.
|
|
@@ -310,7 +319,7 @@ Export formats:
|
|
|
310
319
|
|
|
311
320
|
## Actor Intelligence
|
|
312
321
|
|
|
313
|
-
VoidAccess v1.7.
|
|
322
|
+
VoidAccess v1.7.1 persists actor profiles across investigations in `actor_profiles`, with linked aliases and infrastructure in `actor_aliases` and `actor_infrastructure`. Profiles are populated from threat actor, ransomware group, and handle entities, then enriched with co-occurring infrastructure and timeline events.
|
|
314
323
|
|
|
315
324
|
Cross-alias resolution scores five signals: shared infrastructure, shared PGP, string similarity, temporal co-activity, and co-investigation. Use `voidaccess actors` to list profiles, `voidaccess actor <handle>` for the full profile, `voidaccess actor <handle> --timeline` for chronology, and `voidaccess actor <handle> --note "text"` for analyst notes.
|
|
316
325
|
|
|
@@ -577,6 +586,3 @@ To report a security vulnerability, see [docs/SECURITY.md](docs/SECURITY.md).
|
|
|
577
586
|
|
|
578
587
|
MIT License. See [LICENSE](LICENSE) for details.
|
|
579
588
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
@@ -19,7 +19,16 @@ Commercial threat intelligence platforms often charge prohibitive annual fees fo
|
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
-
## What's New in v1.7.
|
|
22
|
+
## What's New in v1.7.2
|
|
23
|
+
- STIX export relationship generation is bounded and semantic, avoiding page-level cartesian edge explosions at larger entity counts.
|
|
24
|
+
- Repeated NER false positives for threat actor handles and organization names are filtered before persistence.
|
|
25
|
+
- MISP/Sigma/API query paths no longer use the SQLAlchemy subquery-in-`IN()` pattern that produced warnings.
|
|
26
|
+
- Optional configuration warnings are summarized once per process.
|
|
27
|
+
- Refined LLM query output is persisted as a short search string, not explanatory Markdown.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## What's New in the Previous Release
|
|
23
32
|
|
|
24
33
|
- **Dependency optional-extras split** — `sentence-transformers`, `torch`, `transformers`, `telethon`, and `playwright` are now optional extras: `voidaccess[nlp]`, `voidaccess[telegram]`, `voidaccess[js]`, and `voidaccess[all]`.
|
|
25
34
|
- **Optional clearnet ScrapingAnt integration** — paste sites and RSS feeds can now be routed through ScrapingAnt. Affects clearnet scraping only; Tor, `.onion`, GitHub, and GitLab traffic are never affected.
|
|
@@ -225,7 +234,7 @@ Export formats:
|
|
|
225
234
|
|
|
226
235
|
## Actor Intelligence
|
|
227
236
|
|
|
228
|
-
VoidAccess v1.7.
|
|
237
|
+
VoidAccess v1.7.1 persists actor profiles across investigations in `actor_profiles`, with linked aliases and infrastructure in `actor_aliases` and `actor_infrastructure`. Profiles are populated from threat actor, ransomware group, and handle entities, then enriched with co-occurring infrastructure and timeline events.
|
|
229
238
|
|
|
230
239
|
Cross-alias resolution scores five signals: shared infrastructure, shared PGP, string similarity, temporal co-activity, and co-investigation. Use `voidaccess actors` to list profiles, `voidaccess actor <handle>` for the full profile, `voidaccess actor <handle> --timeline` for chronology, and `voidaccess actor <handle> --note "text"` for analyst notes.
|
|
231
240
|
|
|
@@ -492,6 +501,3 @@ To report a security vulnerability, see [docs/SECURITY.md](docs/SECURITY.md).
|
|
|
492
501
|
|
|
493
502
|
MIT License. See [LICENSE](LICENSE) for details.
|
|
494
503
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
@@ -17,11 +17,12 @@ from __future__ import annotations
|
|
|
17
17
|
|
|
18
18
|
import logging
|
|
19
19
|
import os
|
|
20
|
+
import uuid
|
|
20
21
|
from typing import Optional
|
|
21
22
|
|
|
22
23
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
23
24
|
from pydantic import BaseModel, Field
|
|
24
|
-
from sqlalchemy import or_
|
|
25
|
+
from sqlalchemy import or_, select
|
|
25
26
|
|
|
26
27
|
from api.auth import CurrentUser, get_current_user
|
|
27
28
|
|
|
@@ -87,26 +88,22 @@ def _db_required() -> None:
|
|
|
87
88
|
raise HTTPException(status_code=503, detail="Database not configured")
|
|
88
89
|
|
|
89
90
|
|
|
90
|
-
def
|
|
91
|
+
def _user_owned_investigation_ids_select(user_id: int):
|
|
91
92
|
from db.models import Investigation
|
|
92
93
|
|
|
93
|
-
return (
|
|
94
|
-
session.query(Investigation.id)
|
|
95
|
-
.filter(Investigation.user_id == user_id)
|
|
96
|
-
.subquery()
|
|
97
|
-
)
|
|
94
|
+
return select(Investigation.id).where(Investigation.user_id == user_id)
|
|
98
95
|
|
|
99
96
|
|
|
100
97
|
def _profile_accessible(session, profile_id: str, user_id: int) -> bool:
|
|
101
98
|
"""True when at least one investigation linked to the profile is owned by the user."""
|
|
102
|
-
from db.models import ActorAlias, ActorInfrastructure
|
|
99
|
+
from db.models import ActorAlias, ActorInfrastructure
|
|
103
100
|
|
|
104
|
-
|
|
101
|
+
inv_ids_select = _user_owned_investigation_ids_select(user_id)
|
|
105
102
|
alias_match = (
|
|
106
103
|
session.query(ActorAlias.id)
|
|
107
104
|
.filter(
|
|
108
105
|
ActorAlias.actor_id == profile_id,
|
|
109
|
-
ActorAlias.source_investigation_id.in_(
|
|
106
|
+
ActorAlias.source_investigation_id.in_(inv_ids_select),
|
|
110
107
|
)
|
|
111
108
|
.first()
|
|
112
109
|
)
|
|
@@ -116,7 +113,7 @@ def _profile_accessible(session, profile_id: str, user_id: int) -> bool:
|
|
|
116
113
|
session.query(ActorInfrastructure.id)
|
|
117
114
|
.filter(
|
|
118
115
|
ActorInfrastructure.actor_id == profile_id,
|
|
119
|
-
ActorInfrastructure.source_investigation_id.in_(
|
|
116
|
+
ActorInfrastructure.source_investigation_id.in_(inv_ids_select),
|
|
120
117
|
)
|
|
121
118
|
.first()
|
|
122
119
|
)
|
|
@@ -145,20 +142,15 @@ async def list_actors(
|
|
|
145
142
|
users since the seed is public data.
|
|
146
143
|
"""
|
|
147
144
|
_db_required()
|
|
148
|
-
from sqlalchemy import select
|
|
149
|
-
|
|
150
145
|
from db.models import (
|
|
151
146
|
ActorProfile,
|
|
152
147
|
ActorAlias,
|
|
153
148
|
ActorInfrastructure,
|
|
154
|
-
Investigation,
|
|
155
149
|
)
|
|
156
150
|
|
|
157
151
|
try:
|
|
158
152
|
with _session() as session:
|
|
159
|
-
user_inv_ids =
|
|
160
|
-
session, current_user.user.id
|
|
161
|
-
)
|
|
153
|
+
user_inv_ids = _user_owned_investigation_ids_select(current_user.user.id)
|
|
162
154
|
|
|
163
155
|
# Subquery of profile IDs visible to this user
|
|
164
156
|
visible_alias = select(ActorAlias.actor_id).where(
|
|
@@ -176,13 +168,13 @@ async def list_actors(
|
|
|
176
168
|
)
|
|
177
169
|
if search:
|
|
178
170
|
pattern = f"%{search.lower()}%"
|
|
179
|
-
|
|
171
|
+
alias_select = select(ActorAlias.actor_id).where(
|
|
180
172
|
ActorAlias.alias_value.ilike(pattern)
|
|
181
173
|
)
|
|
182
174
|
q = q.filter(
|
|
183
175
|
or_(
|
|
184
176
|
ActorProfile.canonical_handle.ilike(pattern),
|
|
185
|
-
ActorProfile.id.in_(
|
|
177
|
+
ActorProfile.id.in_(alias_select),
|
|
186
178
|
)
|
|
187
179
|
)
|
|
188
180
|
|
|
@@ -258,6 +250,35 @@ async def get_actor(
|
|
|
258
250
|
return profile
|
|
259
251
|
|
|
260
252
|
|
|
253
|
+
@router.get("/{node_id}/profile")
|
|
254
|
+
async def get_actor_profile_by_node(
|
|
255
|
+
node_id: str,
|
|
256
|
+
investigation_id: str = Query(..., description="Investigation ID"),
|
|
257
|
+
current_user: CurrentUser = Depends(get_current_user),
|
|
258
|
+
) -> dict:
|
|
259
|
+
"""Return the graph actor profile for a node inside one investigation."""
|
|
260
|
+
_db_required()
|
|
261
|
+
try:
|
|
262
|
+
inv_uuid = uuid.UUID(investigation_id)
|
|
263
|
+
except ValueError:
|
|
264
|
+
raise HTTPException(status_code=422, detail="Invalid investigation ID format")
|
|
265
|
+
from db.queries import get_investigation_by_id_or_run
|
|
266
|
+
from graph import build_graph_from_db_cached, get_actor_profile
|
|
267
|
+
|
|
268
|
+
with _session() as session:
|
|
269
|
+
inv = get_investigation_by_id_or_run(session, inv_uuid)
|
|
270
|
+
if inv is None:
|
|
271
|
+
raise HTTPException(status_code=404, detail="Investigation not found")
|
|
272
|
+
if str(inv.user_id) != str(current_user.user.id):
|
|
273
|
+
raise HTTPException(status_code=403, detail="Forbidden")
|
|
274
|
+
graph = build_graph_from_db_cached(investigation_id=inv.id)
|
|
275
|
+
|
|
276
|
+
profile = get_actor_profile(graph, node_id)
|
|
277
|
+
if not profile:
|
|
278
|
+
raise HTTPException(status_code=404, detail="Graph node not found")
|
|
279
|
+
return profile
|
|
280
|
+
|
|
281
|
+
|
|
261
282
|
@router.get("/{handle}/investigations")
|
|
262
283
|
async def get_actor_investigations(
|
|
263
284
|
handle: str,
|
|
@@ -284,9 +305,7 @@ async def get_actor_investigations(
|
|
|
284
305
|
|
|
285
306
|
try:
|
|
286
307
|
with _session() as session:
|
|
287
|
-
user_inv_ids =
|
|
288
|
-
session, current_user.user.id
|
|
289
|
-
)
|
|
308
|
+
user_inv_ids = _user_owned_investigation_ids_select(current_user.user.id)
|
|
290
309
|
all_ids = [
|
|
291
310
|
uuid_value(s)
|
|
292
311
|
for s in profile.get("investigation_ids", [])
|
|
@@ -732,4 +751,4 @@ def uuid_value(s):
|
|
|
732
751
|
import uuid as _uuid
|
|
733
752
|
return _uuid.UUID(str(s))
|
|
734
753
|
except (ValueError, TypeError):
|
|
735
|
-
return None
|
|
754
|
+
return None
|
|
@@ -57,14 +57,12 @@ async def list_entities(
|
|
|
57
57
|
|
|
58
58
|
with get_session() as session:
|
|
59
59
|
user_inv_ids = (
|
|
60
|
-
|
|
61
|
-
.
|
|
62
|
-
.subquery()
|
|
60
|
+
sa.select(Investigation.id)
|
|
61
|
+
.where(Investigation.user_id == current_user.user.id)
|
|
63
62
|
)
|
|
64
63
|
linked_entity_ids = (
|
|
65
|
-
|
|
66
|
-
.
|
|
67
|
-
.subquery()
|
|
64
|
+
sa.select(InvestigationEntityLink.entity_id)
|
|
65
|
+
.where(InvestigationEntityLink.investigation_id.in_(user_inv_ids))
|
|
68
66
|
)
|
|
69
67
|
q = session.query(Entity).filter(
|
|
70
68
|
sa.or_(
|
|
@@ -749,14 +747,12 @@ def _assert_entity_accessible(session, entity_id: uuid.UUID, user_id: int) -> No
|
|
|
749
747
|
from db.models import Entity, Investigation, InvestigationEntityLink # noqa: PLC0415
|
|
750
748
|
|
|
751
749
|
user_inv_ids = (
|
|
752
|
-
|
|
753
|
-
.
|
|
754
|
-
.subquery()
|
|
750
|
+
sa.select(Investigation.id)
|
|
751
|
+
.where(Investigation.user_id == user_id)
|
|
755
752
|
)
|
|
756
753
|
linked_entity_ids = (
|
|
757
|
-
|
|
758
|
-
.
|
|
759
|
-
.subquery()
|
|
754
|
+
sa.select(InvestigationEntityLink.entity_id)
|
|
755
|
+
.where(InvestigationEntityLink.investigation_id.in_(user_inv_ids))
|
|
760
756
|
)
|
|
761
757
|
accessible = (
|
|
762
758
|
session.query(Entity.id)
|