voidaccess 1.7.2__tar.gz → 1.8.1__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.8.1/PKG-INFO +228 -0
- voidaccess-1.8.1/README.md +143 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/analysis/opsec.py +9 -3
- {voidaccess-1.7.2 → voidaccess-1.8.1}/analysis/patterns.py +0 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/analysis/temporal.py +57 -22
- {voidaccess-1.7.2 → voidaccess-1.8.1}/api/auth.py +26 -2
- voidaccess-1.8.1/api/errors.py +99 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/api/main.py +42 -17
- {voidaccess-1.7.2 → voidaccess-1.8.1}/api/routes/admin.py +16 -8
- {voidaccess-1.7.2 → voidaccess-1.8.1}/api/routes/auth.py +1 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/api/routes/entities.py +30 -7
- {voidaccess-1.7.2 → voidaccess-1.8.1}/api/routes/investigations.py +3279 -3111
- {voidaccess-1.7.2 → voidaccess-1.8.1}/api/routes/monitors.py +3 -4
- {voidaccess-1.7.2 → voidaccess-1.8.1}/api/routes/search.py +25 -7
- {voidaccess-1.7.2 → voidaccess-1.8.1}/api/routes/settings.py +7 -12
- voidaccess-1.8.1/auth/token_blacklist.py +140 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/config.py +31 -5
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0002_add_missing_tables.py +0 -2
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0003_add_canonical_value_and_entity_links.py +6 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0006_add_monitor_alerts.py +0 -2
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0007_add_actor_style_profiles.py +0 -3
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0008_add_users_table.py +0 -1
- voidaccess-1.8.1/db/migrations/versions/0009_add_investigation_id_to_relationships.py +37 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0010_add_composite_index_entity_relationships.py +0 -1
- voidaccess-1.8.1/db/migrations/versions/0018_add_user_id_to_investigations.py +38 -0
- voidaccess-1.8.1/db/migrations/versions/0024_add_investigation_step_metrics.py +37 -0
- voidaccess-1.8.1/db/migrations/versions/0025_add_cancellation_requested.py +21 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/models.py +44 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/queries.py +92 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/session.py +0 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/export/ioc_package.py +1 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/export/snort_export.py +2 -2
- {voidaccess-1.7.2 → voidaccess-1.8.1}/export/stix.py +63 -12
- {voidaccess-1.7.2 → voidaccess-1.8.1}/export/yara_export.py +1 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/extractor/__init__.py +6 -0
- voidaccess-1.8.1/extractor/confidence.py +156 -0
- voidaccess-1.8.1/extractor/entity_shape.py +375 -0
- voidaccess-1.8.1/extractor/gazetteer.py +152 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/extractor/llm_extract.py +75 -16
- {voidaccess-1.7.2 → voidaccess-1.8.1}/extractor/ner.py +19 -145
- {voidaccess-1.7.2 → voidaccess-1.8.1}/extractor/normalizer.py +356 -68
- {voidaccess-1.7.2 → voidaccess-1.8.1}/extractor/pipeline.py +128 -17
- {voidaccess-1.7.2 → voidaccess-1.8.1}/extractor/regex_patterns.py +14 -4
- voidaccess-1.8.1/extractor/relationship_extract.py +375 -0
- voidaccess-1.8.1/fingerprint/calibration.py +55 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/fingerprint/profiler.py +20 -4
- {voidaccess-1.7.2 → voidaccess-1.8.1}/fingerprint/stylometry.py +107 -12
- {voidaccess-1.7.2 → voidaccess-1.8.1}/graph/model.py +10 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/pyproject.toml +66 -44
- {voidaccess-1.7.2 → voidaccess-1.8.1}/scraper/scrape.py +31 -31
- {voidaccess-1.7.2 → voidaccess-1.8.1}/scraper/scrape_js.py +0 -2
- {voidaccess-1.7.2 → voidaccess-1.8.1}/search/__init__.py +1 -22
- voidaccess-1.8.1/search/engine_catalog.py +30 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/search/search.py +1 -19
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/__init__.py +29 -11
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/actor_profiles.py +0 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/blockchain.py +1 -1
- voidaccess-1.8.1/sources/breach_lookup.py +550 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/cache.py +0 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/cisa.py +0 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/email_reputation.py +0 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/engines.py +20 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/enrichment.py +388 -37
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/historical_intel.py +0 -3
- voidaccess-1.8.1/sources/infostealer.py +417 -0
- voidaccess-1.8.1/sources/nvd.py +245 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/pastes.py +1 -2
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/proxy_client.py +19 -15
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/rss_scraper.py +4 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/telegram.py +1 -2
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_analysis_opsec.py +50 -34
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_analysis_stylometry.py +50 -50
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_analysis_temporal.py +84 -69
- voidaccess-1.8.1/tests/test_breach_lookup.py +113 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_cli_proxy_config.py +632 -632
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_db.py +7 -6
- voidaccess-1.8.1/tests/test_extractor_llm_pipeline.py +80 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_graph.py +5 -5
- voidaccess-1.8.1/tests/test_infostealer.py +103 -0
- voidaccess-1.8.1/tests/test_nvd.py +110 -0
- voidaccess-1.8.1/tests/test_ransomlook.py +113 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_regex_patterns.py +12 -8
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_scrape_js.py +79 -79
- voidaccess-1.8.1/utils/content_dedup.py +39 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/utils/content_safety.py +0 -1
- voidaccess-1.8.1/utils/investigation_metrics.py +142 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/utils/ioc_freshness.py +1 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/vector/store.py +20 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess/llm.py +17 -8
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess/llm_utils.py +2 -4
- voidaccess-1.8.1/voidaccess.egg-info/PKG-INFO +228 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess.egg-info/SOURCES.txt +19 -0
- voidaccess-1.8.1/voidaccess.egg-info/requires.txt +71 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess_cli/__init__.py +1 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess_cli/adapters/sqlite.py +0 -6
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess_cli/commands/configure.py +9 -12
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess_cli/commands/enrich.py +35 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess_cli/commands/investigate.py +217 -28
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess_cli/commands/show.py +1 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess_cli/config.py +1 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess_cli/main.py +0 -1
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess_cli/tor_detect.py +0 -1
- voidaccess-1.7.2/PKG-INFO +0 -588
- voidaccess-1.7.2/README.md +0 -503
- voidaccess-1.7.2/auth/token_blacklist.py +0 -115
- voidaccess-1.7.2/db/migrations/versions/0009_add_investigation_id_to_relationships.py +0 -29
- voidaccess-1.7.2/db/migrations/versions/0018_add_user_id_to_investigations.py +0 -33
- voidaccess-1.7.2/voidaccess.egg-info/PKG-INFO +0 -588
- voidaccess-1.7.2/voidaccess.egg-info/requires.txt +0 -71
- {voidaccess-1.7.2 → voidaccess-1.8.1}/LICENSE +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/analysis/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/api/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/api/routes/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/api/routes/actors.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/api/routes/export.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/auth/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/crawler/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/crawler/dedup.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/crawler/frontier.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/crawler/spider.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/crawler/utils.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/__init__.py +0 -0
- {voidaccess-1.7.2/voidaccess → voidaccess-1.8.1/db/migrations}/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/env.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0001_initial_schema.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0002_add_investigation_status_column.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0004_add_page_posted_at.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0005_add_extraction_method.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0011_add_page_extraction_cache.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0013_add_graph_status.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0015_add_progress_fields.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0016_backfill_graph_status.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0017_add_user_api_keys.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0019_add_content_safety_log.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0020_add_entity_source_tracking.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0021_add_search_engine_stats.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0022_add_actor_profiles.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/migrations/versions/0023_add_investigation_metadata.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/db/search_engine_stats.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/export/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/export/misp.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/export/sigma.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/fingerprint/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/graph/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/graph/builder.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/graph/export.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/graph/queries.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/graph/visualize.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/i18n/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/i18n/detect.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/i18n/query_expand.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/i18n/translate.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/monitor/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/monitor/_db.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/monitor/alerts.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/monitor/config.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/monitor/diff.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/monitor/jobs.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/monitor/scheduler.py +0 -0
- {voidaccess-1.7.2/utils → voidaccess-1.8.1/scraper}/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/search/circuit_breaker.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/search/query_builder.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/setup.cfg +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/data/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/data/onion_seeds.json +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/dns_enrichment.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/domain_reputation.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/github_scraper.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/gitlab_scraper.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/hash_reputation.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/ip_reputation.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/paste_scraper.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/seed_manager.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/seeds.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/shodan.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/sources/virustotal.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_api.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_api_monitors.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_blockchain.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_confidence_calibration.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_config.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_crawler.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_dns_enrichment.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_domain_reputation.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_email_reputation.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_filter_e2e_manual.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_filter_parser_manual.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_fingerprint.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_github_scraper.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_gitlab_scraper.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_graph_integration.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_hash_reputation.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_i18n.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_ip_reputation.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_llm.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_llm_utils.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_model_singleton.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_monitor.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_monitor_integration.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_pagination.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_paste_scraper.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_proxy_client.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_rss_scraper.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_settings.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_snort_export.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_sources.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_sources_enrichment_new.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_stix_export.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_vector.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/tests/test_yara_export.py +0 -0
- {voidaccess-1.7.2/scraper → voidaccess-1.8.1/utils}/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/utils/async_utils.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/utils/defang.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/utils/encryption.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/utils/enrichment_cache.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/utils/user_keys.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/vector/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/vector/embedder.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/vector/model_singleton.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/vector/search.py +0 -0
- {voidaccess-1.7.2/db/migrations → voidaccess-1.8.1/voidaccess}/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess/config.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess.egg-info/dependency_links.txt +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess.egg-info/entry_points.txt +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess.egg-info/top_level.txt +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess_cli/adapters/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess_cli/browser.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess_cli/commands/__init__.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess_cli/commands/actors.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess_cli/commands/export.py +0 -0
- {voidaccess-1.7.2 → voidaccess-1.8.1}/voidaccess_cli/display.py +0 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: voidaccess
|
|
3
|
+
Version: 1.8.1
|
|
4
|
+
Summary: Dark web OSINT CLI — automated threat intelligence from query to report
|
|
5
|
+
Author: VoidAccess
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Keywords: osint,darkweb,threat-intelligence,tor,cli
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: Information Technology
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Security
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: typer==0.24.1
|
|
20
|
+
Requires-Dist: rich==15.0.0
|
|
21
|
+
Requires-Dist: textual==8.2.7
|
|
22
|
+
Requires-Dist: click==8.3.2
|
|
23
|
+
Requires-Dist: fastapi==0.136.0
|
|
24
|
+
Requires-Dist: aiohttp==3.13.5
|
|
25
|
+
Requires-Dist: aiohttp-socks==0.11.0
|
|
26
|
+
Requires-Dist: alembic==1.18.4
|
|
27
|
+
Requires-Dist: apscheduler==3.11.2
|
|
28
|
+
Requires-Dist: pillow==12.2.0
|
|
29
|
+
Requires-Dist: sqlalchemy[asyncio]==2.0.49
|
|
30
|
+
Requires-Dist: aiosqlite==0.22.1
|
|
31
|
+
Requires-Dist: filelock==3.29.0
|
|
32
|
+
Requires-Dist: numpy==2.2.6
|
|
33
|
+
Requires-Dist: langchain==0.3.25
|
|
34
|
+
Requires-Dist: langchain-openai==0.3.19
|
|
35
|
+
Requires-Dist: langchain-anthropic==0.3.22
|
|
36
|
+
Requires-Dist: langchain-google-genai==2.1.12
|
|
37
|
+
Requires-Dist: langchain-groq==0.3.8
|
|
38
|
+
Requires-Dist: langchain-ollama==0.3.10
|
|
39
|
+
Requires-Dist: python-dotenv==1.2.2
|
|
40
|
+
Requires-Dist: httpx==0.28.1
|
|
41
|
+
Requires-Dist: spacy==3.8.14
|
|
42
|
+
Requires-Dist: beautifulsoup4==4.14.3
|
|
43
|
+
Requires-Dist: feedparser==6.0.11
|
|
44
|
+
Requires-Dist: networkx==3.4.2
|
|
45
|
+
Requires-Dist: pydantic==2.13.3
|
|
46
|
+
Requires-Dist: python-jose[cryptography]==3.5.0
|
|
47
|
+
Requires-Dist: passlib[bcrypt]==1.7.4
|
|
48
|
+
Requires-Dist: slowapi==0.1.9
|
|
49
|
+
Requires-Dist: redis==7.4.0
|
|
50
|
+
Requires-Dist: pyyaml==6.0.3
|
|
51
|
+
Requires-Dist: openai==1.109.1
|
|
52
|
+
Requires-Dist: cryptography==46.0.7
|
|
53
|
+
Requires-Dist: python-dateutil==2.9.0.post0
|
|
54
|
+
Requires-Dist: langdetect==1.0.9
|
|
55
|
+
Requires-Dist: pyvis==0.3.2
|
|
56
|
+
Requires-Dist: urllib3==2.6.3
|
|
57
|
+
Requires-Dist: trafilatura==2.0.0
|
|
58
|
+
Requires-Dist: requests==2.33.1
|
|
59
|
+
Requires-Dist: python-socks[asyncio]==2.8.1
|
|
60
|
+
Requires-Dist: tldextract==5.3.1
|
|
61
|
+
Requires-Dist: stix2==3.0.2
|
|
62
|
+
Provides-Extra: dev
|
|
63
|
+
Requires-Dist: pytest; extra == "dev"
|
|
64
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
65
|
+
Provides-Extra: nlp
|
|
66
|
+
Requires-Dist: sentence-transformers>=3.0; extra == "nlp"
|
|
67
|
+
Requires-Dist: torch>=2.3; extra == "nlp"
|
|
68
|
+
Requires-Dist: transformers>=4.42; extra == "nlp"
|
|
69
|
+
Provides-Extra: vector
|
|
70
|
+
Requires-Dist: chromadb>=0.5; extra == "vector"
|
|
71
|
+
Requires-Dist: sentence-transformers>=3.0; extra == "vector"
|
|
72
|
+
Requires-Dist: torch>=2.3; extra == "vector"
|
|
73
|
+
Provides-Extra: telegram
|
|
74
|
+
Requires-Dist: telethon>=1.36; extra == "telegram"
|
|
75
|
+
Provides-Extra: js
|
|
76
|
+
Requires-Dist: playwright>=1.45; extra == "js"
|
|
77
|
+
Provides-Extra: all
|
|
78
|
+
Requires-Dist: chromadb>=0.5; extra == "all"
|
|
79
|
+
Requires-Dist: playwright>=1.45; extra == "all"
|
|
80
|
+
Requires-Dist: sentence-transformers>=3.0; extra == "all"
|
|
81
|
+
Requires-Dist: telethon>=1.36; extra == "all"
|
|
82
|
+
Requires-Dist: torch>=2.3; extra == "all"
|
|
83
|
+
Requires-Dist: transformers>=4.42; extra == "all"
|
|
84
|
+
Dynamic: license-file
|
|
85
|
+
|
|
86
|
+
<p align="center">
|
|
87
|
+
<img src="public/logo_circle.png" width="160" alt="VoidAccess logo">
|
|
88
|
+
</p>
|
|
89
|
+
|
|
90
|
+
<h1 align="center">VoidAccess</h1>
|
|
91
|
+
|
|
92
|
+
<p align="center">
|
|
93
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
|
|
94
|
+
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/Python-3.10%2B-blue.svg" alt="Python 3.10+"></a>
|
|
95
|
+
<a href="docker-compose.yml"><img src="https://img.shields.io/badge/Docker-Compose-blue.svg" alt="Docker Compose"></a>
|
|
96
|
+
<a href="https://pypi.org/project/voidaccess/"><img src="https://img.shields.io/pypi/v/voidaccess?logo=pypi&logoColor=white" alt="PyPI version"></a>
|
|
97
|
+
<a href="https://pypi.org/project/voidaccess/"><img src="https://img.shields.io/pypi/dm/voidaccess" alt="PyPI downloads"></a>
|
|
98
|
+
</p>
|
|
99
|
+
|
|
100
|
+
Self-hostable OSINT for turning dark-web research queries into structured threat intelligence. Built for security researchers, threat-intelligence teams, and authorized investigators who need collection, enrichment, relationship mapping, and export in one workflow.
|
|
101
|
+
|
|
102
|
+
## Terminal Output
|
|
103
|
+
|
|
104
|
+

|
|
105
|
+
|
|
106
|
+
## Quick Start
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
pip install voidaccess
|
|
110
|
+
voidaccess investigate "LockBit ransomware" --no-llm --no-tor --depth shallow
|
|
111
|
+
voidaccess list
|
|
112
|
+
voidaccess actors
|
|
113
|
+
voidaccess status
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+

|
|
117
|
+
|
|
118
|
+
## What It Does
|
|
119
|
+
|
|
120
|
+
- **Parallel collection** - searches Tor indexes, paste sites, code forges, security feeds, and curated `.onion` seeds.
|
|
121
|
+
- **Entity extraction** - finds IOCs, wallets, credentials, handles, vulnerabilities, actors, malware, people, and organizations.
|
|
122
|
+
- **Multi-source enrichment** - adds reputation, breach, passive DNS, sandbox, blockchain, and threat-feed context.
|
|
123
|
+
- **Actor intelligence** - persists aliases, infrastructure, notes, timelines, and cross-investigation relationships.
|
|
124
|
+
- **Relationship graphs** - builds co-occurrence graphs, communities, paths, and infrastructure clusters.
|
|
125
|
+
- **Content safety** - filters prohibited queries, URLs, content, and extracted entities at mandatory pipeline gates.
|
|
126
|
+
- **Structured exports** - produces STIX 2.1, MISP, Sigma, YARA, Snort, Suricata, CSV, Markdown, JSON, and IOC packages.
|
|
127
|
+
- **CLI and web UI** - runs locally with SQLite or as a Docker Compose stack with PostgreSQL and a browser interface.
|
|
128
|
+
|
|
129
|
+
## Pipeline
|
|
130
|
+
|
|
131
|
+
| Stage | Action |
|
|
132
|
+
|---|---|
|
|
133
|
+
| 1 | Refine the investigation query with the selected LLM |
|
|
134
|
+
| 2 | Collect from Tor search, paste sites, code forges, RSS feeds, and curated seeds in parallel |
|
|
135
|
+
| 3 | Filter noisy or irrelevant pages |
|
|
136
|
+
| 4 | Enrich the query and early indicators from threat-intelligence sources |
|
|
137
|
+
| 5 | Discover additional `.onion` links recursively |
|
|
138
|
+
| 6 | Reuse recently processed pages from the vector cache |
|
|
139
|
+
| 7 | Fetch selected pages through Tor with response-size limits |
|
|
140
|
+
| 8 | Persist newly collected content |
|
|
141
|
+
| 9 | Merge collected and enriched intelligence |
|
|
142
|
+
| 10 | Extract entities with regex, NER, and optional LLM analysis |
|
|
143
|
+
| 11 | Cross-reference entities against historical and seed datasets |
|
|
144
|
+
| 12 | Build relationships, communities, and infrastructure clusters |
|
|
145
|
+
| 13 | Generate the final intelligence summary and export-ready result |
|
|
146
|
+
|
|
147
|
+
Full pipeline behavior, timeouts, recovery, and data flow are documented in [Architecture](docs/architecture.md).
|
|
148
|
+
|
|
149
|
+
## Entity Types
|
|
150
|
+
|
|
151
|
+
| Category | Examples |
|
|
152
|
+
|---|---|
|
|
153
|
+
| Cryptocurrency | Bitcoin, Ethereum, Monero, Litecoin, Zcash, Solana, Tron, ENS |
|
|
154
|
+
| Network indicators | IPv4, IPv6, domains, URLs, `.onion` addresses, MAC addresses, PGP keys |
|
|
155
|
+
| File indicators | MD5, SHA-1, SHA-256, malware families |
|
|
156
|
+
| Credentials | Cloud keys, tokens, JWTs, API keys, stealer logs, combo-list entries |
|
|
157
|
+
| Messaging | Telegram, Discord, XMPP, Tox, Session, Matrix, Wire, ICQ, Wickr |
|
|
158
|
+
| Vulnerabilities | CVEs, MITRE ATT&CK techniques and tactics, Exploit-DB IDs |
|
|
159
|
+
| Detection content | YARA rules, Nuclei templates, Snort and Suricata indicators |
|
|
160
|
+
| Threat intelligence | Actor handles, ransomware groups, paste links, people, organizations, locations |
|
|
161
|
+
|
|
162
|
+
## Collection and Enrichment
|
|
163
|
+
|
|
164
|
+
| Layer | Sources |
|
|
165
|
+
|---|---|
|
|
166
|
+
| Dark-web search | 16+ Tor search engines and curated `.onion` seeds |
|
|
167
|
+
| Open-web collection | Pastebin, dpaste, paste.ee, Rentry, GitHub, GitLab, and curated RSS feeds |
|
|
168
|
+
| Threat feeds | AlienVault OTX, abuse.ch, MalwareBazaar, ThreatFox, URLhaus, ransomware.live, CISA KEV |
|
|
169
|
+
| IP and domain context | Shodan InternetDB, GreyNoise, AbuseIPDB, Feodo Tracker, C2IntelFeeds, crt.sh, URLScan.io, Wayback Machine, CIRCL PDNS, RDAP |
|
|
170
|
+
| File and identity context | VirusTotal, Hybrid Analysis, Have I Been Pwned, EmailRep |
|
|
171
|
+
| Blockchain | BlockCypher and Etherscan |
|
|
172
|
+
|
|
173
|
+
Sources that need API keys skip cleanly when their keys are absent. The complete key and configuration reference is in [Architecture](docs/architecture.md#13-configuration-reference).
|
|
174
|
+
|
|
175
|
+
## LLM Providers
|
|
176
|
+
|
|
177
|
+
| Provider | Typical models | Notes |
|
|
178
|
+
|---|---|---|
|
|
179
|
+
| OpenRouter | DeepSeek, Llama, Claude | Default route; free models are available |
|
|
180
|
+
| Groq | Llama | Fast hosted inference with a free tier |
|
|
181
|
+
| OpenAI | GPT models | API key required |
|
|
182
|
+
| Anthropic | Claude | Claude Haiku is the tested default |
|
|
183
|
+
| Google Gemini | Gemini Flash and Pro | Google AI Studio key required |
|
|
184
|
+
| Ollama | Any installed local model | Local and suitable for air-gapped deployments |
|
|
185
|
+
|
|
186
|
+
## CLI Reference
|
|
187
|
+
|
|
188
|
+
| Command | Description |
|
|
189
|
+
|---------|-------------|
|
|
190
|
+
| `voidaccess investigate "QUERY"` | Run an investigation |
|
|
191
|
+
| `voidaccess show` | Open the interactive entity browser |
|
|
192
|
+
| `voidaccess export INVESTIGATION_ID --format FORMAT` | Export as STIX, MISP, Sigma, YARA, Snort, Suricata, package, CSV, Markdown, or JSON |
|
|
193
|
+
| `voidaccess package INVESTIGATION_ID` | Build an IOC package ZIP |
|
|
194
|
+
| `voidaccess enrich INVESTIGATION_ID` | Re-enrich a saved investigation |
|
|
195
|
+
| `voidaccess list` | List saved investigations |
|
|
196
|
+
| `voidaccess status` | Show configuration, Tor, cache, engine, and seed status |
|
|
197
|
+
| `voidaccess actors` | List persistent actor profiles |
|
|
198
|
+
| `voidaccess actor HANDLE` | Show an actor profile |
|
|
199
|
+
| `voidaccess actor HANDLE --timeline` | Show an actor activity timeline |
|
|
200
|
+
| `voidaccess actor HANDLE --note "TEXT"` | Add an analyst note to an actor profile |
|
|
201
|
+
| `voidaccess timeline HANDLE` | Open an actor timeline directly |
|
|
202
|
+
| `voidaccess configure` | Run the setup wizard |
|
|
203
|
+
| `voidaccess configure llm` | Configure the LLM provider, model, and key |
|
|
204
|
+
| `voidaccess configure keys` | Configure enrichment API keys |
|
|
205
|
+
| `voidaccess configure tor` | Override the Tor proxy host and port |
|
|
206
|
+
| `voidaccess version` | Print the installed version |
|
|
207
|
+
|
|
208
|
+
Optional clearnet requests can use [ScrapingAnt](https://scrapingant.com/?ref=mzliyzh) with `--use-scraping-api` or `--use-proxies`; Tor, `.onion`, GitHub, and GitLab traffic are unaffected.
|
|
209
|
+
|
|
210
|
+
## Self-Hosting
|
|
211
|
+
|
|
212
|
+
Run the full PostgreSQL, Tor, FastAPI, and Next.js stack with Docker Compose. The [self-hosting guide](docs/self-hosting.md) covers guided setup, environment configuration, operations, and troubleshooting.
|
|
213
|
+
|
|
214
|
+
## Links
|
|
215
|
+
|
|
216
|
+
| | |
|
|
217
|
+
|-|-|
|
|
218
|
+
| [Self-hosting guide](docs/self-hosting.md) | Docker Compose, environment setup, operations, and troubleshooting |
|
|
219
|
+
| [Architecture](docs/architecture.md) | Pipeline internals, modules, schema, API, enrichment, graph, and configuration reference |
|
|
220
|
+
| [Contributing](CONTRIBUTING.md) | Development setup, standards, and pull requests |
|
|
221
|
+
| [Security](SECURITY.md) | Supported versions and private vulnerability reporting |
|
|
222
|
+
| [Usage policy](docs/USAGE_POLICY.md) | Authorized-use requirements and prohibited activity |
|
|
223
|
+
| [PyPI](https://pypi.org/project/voidaccess/) | Published package and release files |
|
|
224
|
+
| [GitHub](https://github.com/KatrielMoses/VoidAccess) | Source, issues, and releases |
|
|
225
|
+
|
|
226
|
+
## License
|
|
227
|
+
|
|
228
|
+
MIT. Use VoidAccess only for authorized security research and threat-intelligence work; see the [Usage Policy](docs/USAGE_POLICY.md).
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="public/logo_circle.png" width="160" alt="VoidAccess logo">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">VoidAccess</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
|
|
9
|
+
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/Python-3.10%2B-blue.svg" alt="Python 3.10+"></a>
|
|
10
|
+
<a href="docker-compose.yml"><img src="https://img.shields.io/badge/Docker-Compose-blue.svg" alt="Docker Compose"></a>
|
|
11
|
+
<a href="https://pypi.org/project/voidaccess/"><img src="https://img.shields.io/pypi/v/voidaccess?logo=pypi&logoColor=white" alt="PyPI version"></a>
|
|
12
|
+
<a href="https://pypi.org/project/voidaccess/"><img src="https://img.shields.io/pypi/dm/voidaccess" alt="PyPI downloads"></a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
Self-hostable OSINT for turning dark-web research queries into structured threat intelligence. Built for security researchers, threat-intelligence teams, and authorized investigators who need collection, enrichment, relationship mapping, and export in one workflow.
|
|
16
|
+
|
|
17
|
+
## Terminal Output
|
|
18
|
+
|
|
19
|
+

|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install voidaccess
|
|
25
|
+
voidaccess investigate "LockBit ransomware" --no-llm --no-tor --depth shallow
|
|
26
|
+
voidaccess list
|
|
27
|
+
voidaccess actors
|
|
28
|
+
voidaccess status
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+

|
|
32
|
+
|
|
33
|
+
## What It Does
|
|
34
|
+
|
|
35
|
+
- **Parallel collection** - searches Tor indexes, paste sites, code forges, security feeds, and curated `.onion` seeds.
|
|
36
|
+
- **Entity extraction** - finds IOCs, wallets, credentials, handles, vulnerabilities, actors, malware, people, and organizations.
|
|
37
|
+
- **Multi-source enrichment** - adds reputation, breach, passive DNS, sandbox, blockchain, and threat-feed context.
|
|
38
|
+
- **Actor intelligence** - persists aliases, infrastructure, notes, timelines, and cross-investigation relationships.
|
|
39
|
+
- **Relationship graphs** - builds co-occurrence graphs, communities, paths, and infrastructure clusters.
|
|
40
|
+
- **Content safety** - filters prohibited queries, URLs, content, and extracted entities at mandatory pipeline gates.
|
|
41
|
+
- **Structured exports** - produces STIX 2.1, MISP, Sigma, YARA, Snort, Suricata, CSV, Markdown, JSON, and IOC packages.
|
|
42
|
+
- **CLI and web UI** - runs locally with SQLite or as a Docker Compose stack with PostgreSQL and a browser interface.
|
|
43
|
+
|
|
44
|
+
## Pipeline
|
|
45
|
+
|
|
46
|
+
| Stage | Action |
|
|
47
|
+
|---|---|
|
|
48
|
+
| 1 | Refine the investigation query with the selected LLM |
|
|
49
|
+
| 2 | Collect from Tor search, paste sites, code forges, RSS feeds, and curated seeds in parallel |
|
|
50
|
+
| 3 | Filter noisy or irrelevant pages |
|
|
51
|
+
| 4 | Enrich the query and early indicators from threat-intelligence sources |
|
|
52
|
+
| 5 | Discover additional `.onion` links recursively |
|
|
53
|
+
| 6 | Reuse recently processed pages from the vector cache |
|
|
54
|
+
| 7 | Fetch selected pages through Tor with response-size limits |
|
|
55
|
+
| 8 | Persist newly collected content |
|
|
56
|
+
| 9 | Merge collected and enriched intelligence |
|
|
57
|
+
| 10 | Extract entities with regex, NER, and optional LLM analysis |
|
|
58
|
+
| 11 | Cross-reference entities against historical and seed datasets |
|
|
59
|
+
| 12 | Build relationships, communities, and infrastructure clusters |
|
|
60
|
+
| 13 | Generate the final intelligence summary and export-ready result |
|
|
61
|
+
|
|
62
|
+
Full pipeline behavior, timeouts, recovery, and data flow are documented in [Architecture](docs/architecture.md).
|
|
63
|
+
|
|
64
|
+
## Entity Types
|
|
65
|
+
|
|
66
|
+
| Category | Examples |
|
|
67
|
+
|---|---|
|
|
68
|
+
| Cryptocurrency | Bitcoin, Ethereum, Monero, Litecoin, Zcash, Solana, Tron, ENS |
|
|
69
|
+
| Network indicators | IPv4, IPv6, domains, URLs, `.onion` addresses, MAC addresses, PGP keys |
|
|
70
|
+
| File indicators | MD5, SHA-1, SHA-256, malware families |
|
|
71
|
+
| Credentials | Cloud keys, tokens, JWTs, API keys, stealer logs, combo-list entries |
|
|
72
|
+
| Messaging | Telegram, Discord, XMPP, Tox, Session, Matrix, Wire, ICQ, Wickr |
|
|
73
|
+
| Vulnerabilities | CVEs, MITRE ATT&CK techniques and tactics, Exploit-DB IDs |
|
|
74
|
+
| Detection content | YARA rules, Nuclei templates, Snort and Suricata indicators |
|
|
75
|
+
| Threat intelligence | Actor handles, ransomware groups, paste links, people, organizations, locations |
|
|
76
|
+
|
|
77
|
+
## Collection and Enrichment
|
|
78
|
+
|
|
79
|
+
| Layer | Sources |
|
|
80
|
+
|---|---|
|
|
81
|
+
| Dark-web search | 16+ Tor search engines and curated `.onion` seeds |
|
|
82
|
+
| Open-web collection | Pastebin, dpaste, paste.ee, Rentry, GitHub, GitLab, and curated RSS feeds |
|
|
83
|
+
| Threat feeds | AlienVault OTX, abuse.ch, MalwareBazaar, ThreatFox, URLhaus, ransomware.live, CISA KEV |
|
|
84
|
+
| IP and domain context | Shodan InternetDB, GreyNoise, AbuseIPDB, Feodo Tracker, C2IntelFeeds, crt.sh, URLScan.io, Wayback Machine, CIRCL PDNS, RDAP |
|
|
85
|
+
| File and identity context | VirusTotal, Hybrid Analysis, Have I Been Pwned, EmailRep |
|
|
86
|
+
| Blockchain | BlockCypher and Etherscan |
|
|
87
|
+
|
|
88
|
+
Sources that need API keys skip cleanly when their keys are absent. The complete key and configuration reference is in [Architecture](docs/architecture.md#13-configuration-reference).
|
|
89
|
+
|
|
90
|
+
## LLM Providers
|
|
91
|
+
|
|
92
|
+
| Provider | Typical models | Notes |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| OpenRouter | DeepSeek, Llama, Claude | Default route; free models are available |
|
|
95
|
+
| Groq | Llama | Fast hosted inference with a free tier |
|
|
96
|
+
| OpenAI | GPT models | API key required |
|
|
97
|
+
| Anthropic | Claude | Claude Haiku is the tested default |
|
|
98
|
+
| Google Gemini | Gemini Flash and Pro | Google AI Studio key required |
|
|
99
|
+
| Ollama | Any installed local model | Local and suitable for air-gapped deployments |
|
|
100
|
+
|
|
101
|
+
## CLI Reference
|
|
102
|
+
|
|
103
|
+
| Command | Description |
|
|
104
|
+
|---------|-------------|
|
|
105
|
+
| `voidaccess investigate "QUERY"` | Run an investigation |
|
|
106
|
+
| `voidaccess show` | Open the interactive entity browser |
|
|
107
|
+
| `voidaccess export INVESTIGATION_ID --format FORMAT` | Export as STIX, MISP, Sigma, YARA, Snort, Suricata, package, CSV, Markdown, or JSON |
|
|
108
|
+
| `voidaccess package INVESTIGATION_ID` | Build an IOC package ZIP |
|
|
109
|
+
| `voidaccess enrich INVESTIGATION_ID` | Re-enrich a saved investigation |
|
|
110
|
+
| `voidaccess list` | List saved investigations |
|
|
111
|
+
| `voidaccess status` | Show configuration, Tor, cache, engine, and seed status |
|
|
112
|
+
| `voidaccess actors` | List persistent actor profiles |
|
|
113
|
+
| `voidaccess actor HANDLE` | Show an actor profile |
|
|
114
|
+
| `voidaccess actor HANDLE --timeline` | Show an actor activity timeline |
|
|
115
|
+
| `voidaccess actor HANDLE --note "TEXT"` | Add an analyst note to an actor profile |
|
|
116
|
+
| `voidaccess timeline HANDLE` | Open an actor timeline directly |
|
|
117
|
+
| `voidaccess configure` | Run the setup wizard |
|
|
118
|
+
| `voidaccess configure llm` | Configure the LLM provider, model, and key |
|
|
119
|
+
| `voidaccess configure keys` | Configure enrichment API keys |
|
|
120
|
+
| `voidaccess configure tor` | Override the Tor proxy host and port |
|
|
121
|
+
| `voidaccess version` | Print the installed version |
|
|
122
|
+
|
|
123
|
+
Optional clearnet requests can use [ScrapingAnt](https://scrapingant.com/?ref=mzliyzh) with `--use-scraping-api` or `--use-proxies`; Tor, `.onion`, GitHub, and GitLab traffic are unaffected.
|
|
124
|
+
|
|
125
|
+
## Self-Hosting
|
|
126
|
+
|
|
127
|
+
Run the full PostgreSQL, Tor, FastAPI, and Next.js stack with Docker Compose. The [self-hosting guide](docs/self-hosting.md) covers guided setup, environment configuration, operations, and troubleshooting.
|
|
128
|
+
|
|
129
|
+
## Links
|
|
130
|
+
|
|
131
|
+
| | |
|
|
132
|
+
|-|-|
|
|
133
|
+
| [Self-hosting guide](docs/self-hosting.md) | Docker Compose, environment setup, operations, and troubleshooting |
|
|
134
|
+
| [Architecture](docs/architecture.md) | Pipeline internals, modules, schema, API, enrichment, graph, and configuration reference |
|
|
135
|
+
| [Contributing](CONTRIBUTING.md) | Development setup, standards, and pull requests |
|
|
136
|
+
| [Security](SECURITY.md) | Supported versions and private vulnerability reporting |
|
|
137
|
+
| [Usage policy](docs/USAGE_POLICY.md) | Authorized-use requirements and prohibited activity |
|
|
138
|
+
| [PyPI](https://pypi.org/project/voidaccess/) | Published package and release files |
|
|
139
|
+
| [GitHub](https://github.com/KatrielMoses/VoidAccess) | Source, issues, and releases |
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
MIT. Use VoidAccess only for authorized security research and threat-intelligence work; see the [Usage Policy](docs/USAGE_POLICY.md).
|
|
@@ -8,6 +8,7 @@ from __future__ import annotations
|
|
|
8
8
|
import logging
|
|
9
9
|
import re
|
|
10
10
|
from collections import Counter
|
|
11
|
+
from datetime import timezone
|
|
11
12
|
from typing import Optional
|
|
12
13
|
|
|
13
14
|
logger = logging.getLogger(__name__)
|
|
@@ -65,11 +66,16 @@ def detect_timezone_leak(texts_with_timestamps: list[dict]) -> dict:
|
|
|
65
66
|
if ts is None:
|
|
66
67
|
continue
|
|
67
68
|
if hasattr(ts, "utcoffset") and ts.utcoffset() is not None:
|
|
68
|
-
# Convert to
|
|
69
|
-
|
|
69
|
+
# Convert to an explicit, host-independent reference frame. Using
|
|
70
|
+
# tz=None here made results depend on the analyst server's zone.
|
|
71
|
+
utc_ts = ts.astimezone(timezone.utc)
|
|
70
72
|
posting_hours.append(utc_ts.hour)
|
|
71
73
|
else:
|
|
72
|
-
|
|
74
|
+
# Naive timestamps have no information with which to convert. The
|
|
75
|
+
# ingestion contract treats them as UTC; make that assumption
|
|
76
|
+
# explicit instead of allowing the host timezone to leak in.
|
|
77
|
+
utc_ts = ts.replace(tzinfo=timezone.utc) if hasattr(ts, "replace") else ts
|
|
78
|
+
posting_hours.append(utc_ts.hour)
|
|
73
79
|
|
|
74
80
|
if not posting_hours:
|
|
75
81
|
return {
|
|
@@ -10,8 +10,9 @@ from __future__ import annotations
|
|
|
10
10
|
import logging
|
|
11
11
|
import math
|
|
12
12
|
from collections import defaultdict
|
|
13
|
-
from datetime import date, datetime
|
|
14
|
-
from
|
|
13
|
+
from datetime import date, datetime
|
|
14
|
+
from statistics import median
|
|
15
|
+
from typing import Optional
|
|
15
16
|
|
|
16
17
|
logger = logging.getLogger(__name__)
|
|
17
18
|
|
|
@@ -124,44 +125,78 @@ def compute_activity_stats(timeline: list[dict]) -> dict:
|
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
|
|
127
|
-
|
|
128
|
+
POISSON_ALPHA = 0.01
|
|
128
129
|
MIN_DATA_POINTS = 10
|
|
129
|
-
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _poisson_lower_tail(count: int, rate: float) -> float:
|
|
133
|
+
"""Return P(X <= count) for X ~ Poisson(rate), without scipy."""
|
|
134
|
+
if rate <= 0:
|
|
135
|
+
return 1.0 if count >= 0 else 0.0
|
|
136
|
+
term = math.exp(-rate)
|
|
137
|
+
total = term
|
|
138
|
+
for k in range(1, count + 1):
|
|
139
|
+
term *= rate / k
|
|
140
|
+
total += term
|
|
141
|
+
return min(1.0, max(0.0, total))
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _poisson_upper_tail(count: int, rate: float) -> float:
|
|
145
|
+
"""Return P(X >= count) for X ~ Poisson(rate)."""
|
|
146
|
+
if count <= 0:
|
|
147
|
+
return 1.0
|
|
148
|
+
if rate <= 0:
|
|
149
|
+
return 0.0
|
|
150
|
+
return min(1.0, max(0.0, 1.0 - _poisson_lower_tail(count - 1, rate)))
|
|
130
151
|
|
|
131
152
|
|
|
132
153
|
def detect_anomalies(
|
|
133
154
|
timeline: list[dict],
|
|
134
|
-
|
|
155
|
+
alpha: float = POISSON_ALPHA,
|
|
156
|
+
z_threshold: float | None = None,
|
|
135
157
|
) -> list[dict]:
|
|
136
158
|
"""
|
|
137
|
-
Flag
|
|
159
|
+
Flag unusually rare daily counts under a Poisson event-count model.
|
|
138
160
|
|
|
139
|
-
|
|
140
|
-
|
|
161
|
+
The baseline rate is the median daily count, which is robust to the very
|
|
162
|
+
spikes this function is intended to detect. ``z_threshold`` remains an
|
|
163
|
+
ignored compatibility parameter for callers of the old API; decisions are
|
|
164
|
+
now made from Poisson tail probabilities and ``alpha``.
|
|
165
|
+
|
|
166
|
+
Returns dictionaries containing ``poisson_p_value`` and ``expected_rate``.
|
|
167
|
+
Returns [] for timelines with fewer than 10 data points.
|
|
141
168
|
"""
|
|
142
169
|
if len(timeline) < MIN_DATA_POINTS:
|
|
143
170
|
return []
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
171
|
+
if z_threshold is not None:
|
|
172
|
+
logger.debug("detect_anomalies: z_threshold is deprecated; using Poisson alpha=%s", alpha)
|
|
173
|
+
if not 0.0 < alpha < 1.0:
|
|
174
|
+
raise ValueError("alpha must be between 0 and 1")
|
|
175
|
+
|
|
176
|
+
counts = [max(0, int(entry.get("count", 0))) for entry in timeline]
|
|
177
|
+
rate = float(median(counts))
|
|
178
|
+
if rate == 0.0 and not any(counts):
|
|
150
179
|
return []
|
|
151
180
|
|
|
152
181
|
anomalies: list[dict] = []
|
|
153
|
-
for entry in timeline:
|
|
154
|
-
count
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
182
|
+
for entry, count in zip(timeline, counts):
|
|
183
|
+
if count > rate:
|
|
184
|
+
p_value = _poisson_upper_tail(count, rate)
|
|
185
|
+
anomaly_type = "spike"
|
|
186
|
+
elif count < rate:
|
|
187
|
+
p_value = _poisson_lower_tail(count, rate)
|
|
188
|
+
anomaly_type = "drop"
|
|
189
|
+
else:
|
|
190
|
+
p_value = 1.0
|
|
191
|
+
anomaly_type = "variation"
|
|
192
|
+
if p_value <= alpha:
|
|
159
193
|
anomalies.append(
|
|
160
194
|
{
|
|
161
195
|
"date": entry["date"],
|
|
162
196
|
"count": count,
|
|
163
|
-
"
|
|
164
|
-
"
|
|
197
|
+
"poisson_p_value": float(p_value),
|
|
198
|
+
"expected_rate": rate,
|
|
199
|
+
"type": anomaly_type,
|
|
165
200
|
}
|
|
166
201
|
)
|
|
167
202
|
|
|
@@ -8,6 +8,7 @@ Flow:
|
|
|
8
8
|
4. POST /auth/reset-password → sets new password, clears must_reset flag
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
+
import logging
|
|
11
12
|
import secrets
|
|
12
13
|
from datetime import datetime, timedelta, timezone
|
|
13
14
|
from typing import Optional
|
|
@@ -22,7 +23,9 @@ from sqlalchemy.orm import Session
|
|
|
22
23
|
from config import JWT_SECRET
|
|
23
24
|
from db.models import User
|
|
24
25
|
from db.session import get_session, get_db
|
|
25
|
-
from auth.token_blacklist import is_token_revoked
|
|
26
|
+
from auth.token_blacklist import is_token_revoked, BlacklistUnavailableError
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
26
29
|
|
|
27
30
|
# Config — single canonical source from config.py
|
|
28
31
|
SECRET = JWT_SECRET
|
|
@@ -130,7 +133,28 @@ async def get_current_user(
|
|
|
130
133
|
raise credentials_exception
|
|
131
134
|
|
|
132
135
|
if token_payload.jti:
|
|
133
|
-
|
|
136
|
+
# Fail closed when revocation was opted in (REDIS_URL set) but the
|
|
137
|
+
# blacklist store is unreachable: we cannot confirm the token has not
|
|
138
|
+
# been revoked, so we refuse rather than silently honour it. Enforcement
|
|
139
|
+
# resumes automatically once Redis is reachable again. When REDIS_URL is
|
|
140
|
+
# unset, is_token_revoked() simply returns False (disabled by design).
|
|
141
|
+
try:
|
|
142
|
+
token_revoked = await is_token_revoked(token_payload.jti)
|
|
143
|
+
except BlacklistUnavailableError:
|
|
144
|
+
logger.warning(
|
|
145
|
+
"Token revocation store unavailable — failing closed (rejecting "
|
|
146
|
+
"authentication). Restore Redis, or unset REDIS_URL to disable "
|
|
147
|
+
"blacklist enforcement (fail-open by design)."
|
|
148
|
+
)
|
|
149
|
+
raise HTTPException(
|
|
150
|
+
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
|
151
|
+
detail=(
|
|
152
|
+
"Authentication temporarily unavailable: the token revocation "
|
|
153
|
+
"store is unreachable."
|
|
154
|
+
),
|
|
155
|
+
headers={"WWW-Authenticate": "Bearer"},
|
|
156
|
+
)
|
|
157
|
+
if token_revoked:
|
|
134
158
|
raise revoked_exception
|
|
135
159
|
|
|
136
160
|
user = db.query(User).filter(
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""
|
|
2
|
+
api/errors.py — Safe error responses: public generic message, private detailed log.
|
|
3
|
+
|
|
4
|
+
All internal/unhandled errors surfaced to API clients must go through these
|
|
5
|
+
helpers so that:
|
|
6
|
+
|
|
7
|
+
* the client only ever sees a generic message plus a correlation ID, and
|
|
8
|
+
* the full exception (message + traceback) is logged server-side, tagged
|
|
9
|
+
with the same correlation ID, for the operator to correlate.
|
|
10
|
+
|
|
11
|
+
This is the standard "public error, private log" split. Never place a raw
|
|
12
|
+
exception object or its string representation into a response body — a raw
|
|
13
|
+
message can leak database connection fragments, internal file paths, the
|
|
14
|
+
reason an enrichment provider call failed (which may include partial
|
|
15
|
+
credential material for a malformed key), or other implementation details
|
|
16
|
+
that make the system easier to probe. Use these helpers instead.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import logging
|
|
22
|
+
import uuid
|
|
23
|
+
from typing import Optional
|
|
24
|
+
|
|
25
|
+
from fastapi import HTTPException, Request
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger("voidaccess.api.errors")
|
|
28
|
+
|
|
29
|
+
# Generic, safe message shown to clients for any unhandled/internal error.
|
|
30
|
+
GENERIC_ERROR_MESSAGE = (
|
|
31
|
+
"An internal error occurred. Reference the correlation ID when contacting support."
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def new_correlation_id() -> str:
|
|
36
|
+
"""Return a fresh correlation ID for a single failed request."""
|
|
37
|
+
return uuid.uuid4().hex
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def log_exception(
|
|
41
|
+
exc: BaseException,
|
|
42
|
+
*,
|
|
43
|
+
context: str = "",
|
|
44
|
+
request: Optional[Request] = None,
|
|
45
|
+
correlation_id: Optional[str] = None,
|
|
46
|
+
level: int = logging.ERROR,
|
|
47
|
+
) -> str:
|
|
48
|
+
"""Log the full exception detail server-side, tagged with a correlation ID.
|
|
49
|
+
|
|
50
|
+
Returns the correlation ID so the caller can echo it (and only it) back to
|
|
51
|
+
the client. The full message and traceback stay in the server log only.
|
|
52
|
+
"""
|
|
53
|
+
correlation_id = correlation_id or new_correlation_id()
|
|
54
|
+
|
|
55
|
+
where = context
|
|
56
|
+
if request is not None:
|
|
57
|
+
try:
|
|
58
|
+
where = f"{request.method} {request.url.path}"
|
|
59
|
+
if context:
|
|
60
|
+
where = f"{where} ({context})"
|
|
61
|
+
except Exception: # never let logging path-extraction raise
|
|
62
|
+
where = context
|
|
63
|
+
|
|
64
|
+
logger.log(
|
|
65
|
+
level,
|
|
66
|
+
"[correlation_id=%s] Internal error in %s: %s",
|
|
67
|
+
correlation_id,
|
|
68
|
+
where or "request",
|
|
69
|
+
exc,
|
|
70
|
+
exc_info=exc,
|
|
71
|
+
)
|
|
72
|
+
return correlation_id
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def safe_detail(correlation_id: str, message: str = GENERIC_ERROR_MESSAGE) -> str:
|
|
76
|
+
"""A generic ``detail`` string safe to return to clients, with the ID appended."""
|
|
77
|
+
return f"{message} (correlation ID: {correlation_id})"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def safe_error_body(correlation_id: str, message: str = GENERIC_ERROR_MESSAGE) -> dict:
|
|
81
|
+
"""A generic JSON body safe to return to clients (generic message + ID)."""
|
|
82
|
+
return {"detail": message, "correlation_id": correlation_id}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def internal_http_exception(
|
|
86
|
+
exc: BaseException,
|
|
87
|
+
*,
|
|
88
|
+
request: Optional[Request] = None,
|
|
89
|
+
context: str = "",
|
|
90
|
+
status_code: int = 500,
|
|
91
|
+
) -> HTTPException:
|
|
92
|
+
"""Log ``exc`` in full and build an ``HTTPException`` with a safe body.
|
|
93
|
+
|
|
94
|
+
Raise the returned exception from a route handler:
|
|
95
|
+
|
|
96
|
+
raise internal_http_exception(exc, context="create_monitor")
|
|
97
|
+
"""
|
|
98
|
+
correlation_id = log_exception(exc, context=context, request=request)
|
|
99
|
+
return HTTPException(status_code=status_code, detail=safe_detail(correlation_id))
|