Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# AI contributor guide for this repo

This project is a Python OSINT tool that maps a Steam user’s friend network, enriches it with graph metrics, and exports Gephi‑ready CSVs plus lightweight "probable friends" and IRL/location estimates.

## Big picture
- Entrypoints
- `app.py` — primary CLI with modes (full/basic/graphi) and optional SteamHistory support. Saves `scan.json`, exports CSVs, writes `estimates.json`, and logs to `run.log`.
- `start.py` — simple wizard subset (legacy), focused on scan + Gephi CSVs + probable friends.
- `gui.py` — optional PyWebView UI that calls Python via a `Bridge` API; static HTML/JS in `ui/` (currently demo‑level wiring).
- Core modules (in `vapora/`)
- `steam_api.py` — HTTP wrapper + RPM rate limiter; vanity resolver; batched summaries/bans; optional group list.
- `scanner.py` — breadth‑first crawl up to `depth`, with `max_nodes` cap, producing a serializable `state` dict.
- `enricher.py` — cleans edges, builds `networkx` graph, computes degree/betweenness/modularity, exports CSVs under `graphi/`.
- `probable_friends.py` — ranks close associates using mutuals/Jaccard/shared groups; writes `probable_friends.csv`.
- `irl.py` — IRL friend probability and possible location inference from the scanned network; outputs are embedded in `estimates.json`.
- `steamhistory.py` — helpers to ingest normalized SteamHistory JSON and derive duration‑based closeness (fallback when network signals are absent).
- `utils.py` — small helpers (timestamps, open folder, simple file logger).

State contract (produced by `scanner.scan_network` and consumed elsewhere):
- `state = { seed: str, nodes: {steamid: {...}}, edges: [{a,b,type}], visited: [..], queue: [..], meta: {depth} }`
- `nodes[steamid]` contains at least: `friends: [steamid]`, `personaname`, `profileurl`, `is_public`, optional `bans`, `groups`, and location codes.
- `edges[i]` has `a`, `b`, and `type` in `{friend|group}`. `enricher._clean_edges` removes duplicates/dangling edges.

Important repo conventions
- Config source of truth: `vapora/config_default.yaml`. CLI can persist user profiles to `profiles/*.yaml`.
- Output layout: `outputs/<steamid64>/<yyyymmdd_hhmmss>/` containing `scan.json`, `run.log`, optional `estimates.json`, and a `graphi/` folder with `nodes.csv` and `edges.csv`.
- Note: folder name is `graphi` in code (typo vs README’s "gephi"). Keep code/doc consistent or fix both together.
- Modes gate features (see `app._mode_caps`):
- `full`: graphi + estimates + SteamHistory fallback
- `basic`: estimates + SteamHistory only (no CSVs)
- `graphi`: CSV export only (no estimates/SH)
- Identifiers: Accepts SteamID2/3/64, profile URLs, or vanity; resolve via `ids.parse_any_steam_input` + `SteamAPI.ensure_steam64_from_vanity`.
- Rate limiting: simple in‑process windowed RPM limiter in `steam_api.RateLimiter.wait()` used by every call.

## Developer workflows
- Prereqs: Python 3.10+, a Steam Web API key.
- Setup (Windows PowerShell)
- Create venv and install deps, then run the CLI:
- `python -m venv .venv; .venv\Scripts\Activate.ps1; pip install -r requirements.txt; python app.py`
- On first run, paste `STEAM_API_KEY` when prompted (stored in `.env` next to the script).
- Quick wizard (legacy): `python start.py`.
- Optional GUI: `gui.py` uses PyWebView; install `pywebview` to use it, then `python gui.py`. The current `ui/app.js` is a demo; the Python `Bridge` is the source of truth for actions.
- Debugging tips
- Use recent outputs via menu options in CLI, or open the newest run dir under `outputs/`.
- Inspect `run.log` for step‑by‑step notes (scan, exports, estimates).
- If APIs look slow/noisy, lower `depth`/`max_nodes`, or raise `rate_limit_rpm` (default 120).

## Extending the tool (patterns)
- New analysis that uses the scanned network:
- Add a pure function `def analyze(state: Dict, out_dir: Path, **opts) -> Path|Dict` under `vapora/`.
- Consume the `state` contract above; don’t make new network calls unless necessary.
- Write results next to existing outputs (e.g., `out_dir / "your_feature.json"`).
- Wire it in `app.run_scan` and/or `gui.Bridge.run_scan` behind a mode/config flag.
- Exporters: follow `enricher.export_gephi(state, out_dir, hub_percentile)`; keep CSV schemas stable.
- Steam API calls: prefer adding thin wrappers in `SteamAPI` and reuse the existing batching + limiter.

## External dependencies and IO
- HTTP: `requests` to official Web API endpoints only; no scraping.
- Graph/communities: `networkx`, `python-louvain`.
- CLI UX: `questionary`, `rich` (Windows‑safe colors configured), `tqdm` for progress.
- Optional GUI: `pywebview` (not listed in requirements.txt by default).

## Gotchas to know
- Output folder is `graphi/` in code. If the README says `gephi/`, that’s a known mismatch.
- Group links can explode edge count on large public groups; consider toggling `include_group_links` off.
- Private profiles are silently kept with `is_public=False`; group membership lookups are skipped when `skip_private_profiles=true`.
- `requirements.txt` omits `pywebview` (GUI) and `colorama` (used in `start.py`); install them explicitly if needed.

## Handy references
- Examples:
- BFS scan: `vapora/scanner.py: scan_network(...)`
- CSV export: `vapora/enricher.py: export_gephi(...)`
- Probable friends: `vapora/probable_friends.py: compute_probable_friends(...)`
- IRL estimates + locations: `vapora/irl.py`
- SteamHistory helpers: `vapora/steamhistory.py`
- Config defaults and flags: `vapora/config_default.yaml`
Empty file added AGENTS.md
Empty file.
278 changes: 278 additions & 0 deletions README copy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
<p align="center">
<a href="https://github.com/Microck/vapora">
<img src="assets/vapora.png" alt="vapora Logo" width="300">
</a>
</p>

<p align="center">an OSINT tool for gathering information on Steam users' friends lists. </p>

<p align="center">
<a href="https://github.com/Microck/vapora/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/github/license/Microck/vapora?style=flat-square" /></a>
<a href="https://github.com/Microck/vapora/stargazers"><img alt="Stars" src="https://img.shields.io/github/stars/Microck/vapora?style=flat-square" /></a>
<a href="https://github.com/Microck/vapora/issues"><img alt="Issues" src="https://img.shields.io/github/issues/Microck/vapora?style=flat-square" /></a>
</p>

---

## tl;dr
interactive python tool to map a steam user’s friend network, enrich it with community metrics, and export gephi‑ready csvs & a “probable friends” report:

- install python 3.10+
- get a steam api key (free): https://steamcommunity.com/dev/apikey
- `pip install -r requirements.txt`
- `python start.py` → paste key → choose preset → paste steam url → done
- open the folder in gephi (see how‑to below)

---

## features

- blue terminal wizard (reads ascii from `assets/banner.txt`)
- works with steamid64 or profile url (auto vanity resolver)
- safe presets:
- inner circle (fast) → depth 1, ~200–300 nodes
- community map (default) → depth 2, ~500 nodes
- custom → full control with explanations
- dry‑run estimator (samples seed friends to predict node counts)
- resume last run + recent targets menu
- rate‑limit handling, retries, progress bars
- automatic cleaning (no phantom nodes in gephi)
- gephi‑ready exports (no html):
- `gephi/nodes.csv` | label + metrics
- `gephi/edges.csv` | `friend` vs `group` edges
- `probable_friends.csv` | ranked close‑associate guesses
- enrichment for osint:
- degree (popularity)
- betweenness centrality (bridges / hubs)
- modularity class (communities; louvain)
- “is_hub” flag (top percentile of betweenness)
- cross‑platform; outputs per target with timestamp
- optional packaged exe (pyinstaller) for windows

---

## how it works

1. the wizard collects:
- steam api key (stores to `.env`; can skip if already set)
- target (steamid64 or profile url)
- preset / custom config (depth, caps, rate limit, etc.)
2. scanner hits the steam web api (depth‑limited bfs).
3. cleaner removes dangling edges; keeps `Kind = friend|group`.
4. enricher computes degree, betweenness, modularity, is_hub.
5. probable‑friends analyzer ranks likely close associates.
6. exports gephi csvs + raw scan json into a dated folder.

no scraping; only public web‑api endpoints. private data is skipped.

---

## layout

```
.
├─ start.py # cli wizard
├─ vapora-X.X.X.exe # windows executable
├─ .env.example # steam api key placeholder
├─ requirements.txt
├─ assets/
│ └─ banner.txt
├─ vapora/
│ ├─ steam_api.py # api wrapper + rate limiting + vanity resolver
│ ├─ scanner.py # bfs crawler (depth, caps, resume)
│ ├─ enricher.py # clean + metrics + gephi csv export
│ ├─ probable_friends.py # close-associate ranking
│ ├─ utils.py # helpers (paths, time, io)
│ └─ config_default.yaml # defaults with inline docs
├─ profiles/ # saved config profiles
├─ outputs/ # results
├─ .gitignore
├─ LICENSE
└─ README.md
```

outputs per run:
```
outputs/<steamid64>/<yyyymmdd_hhmmss>/
├─ gephi/
│ ├─ nodes.csv
│ └─ edges.csv
├─ probable_friends.csv
├─ scan.json
└─ run.log
```

---

## installation

prereqs
- python 3.10+
- steam api key: https://steamcommunity.com/dev/apikey

clone + install
```bash
git clone https://github.com/Microck/vapora.git
cd vapora

python -m venv .venv
# windows
.venv\Scripts\activate
# macos/linux
source .venv/bin/activate

pip install -r requirements.txt
```

set your key
- copy `.env.example` → `.env` and paste your key, or
- just run the wizard; it can create `.env` for you

---

## quickstart

```bash
python start.py
```

you’ll see:
- a short tip + link to get your api key
- menu:
- scan by steamid64
- scan by profile url (vanity / full)
- presets (inner circle / community map / custom)
- config (guided editor with recommended defaults)
- dry‑run estimate
- resume last run
- recent targets
- run

after the run it asks to open the output folder. the readme below explains
how to import into gephi.

---

## configuration

the wizard shows a one‑liner help for each option and saves your choices to
`profiles/` so you can reuse them later.

defaults (also in `vapora/config_default.yaml`):
```yaml
depth: 2 # 1 = only friends; 2 = friends of friends, 3 = you get how it goes
max_nodes: 500 # hard cap; keeps graphs tidy
rate_limit_rpm: 120 # requests per minute
skip_private_profiles: true
include_group_links: true # group edges (toggle off in gephi if noisy)
include_game_overlap: false
hub_percentile: 0.99 # top 1% betweenness → is_hub=true
weights: # probable-friends scoring
mutual: 1.0
jaccard: 1.0
groups: 0.5
games: 0.5
```

advanced:
- hub threshold is adjustable (percentile) from the wizard “advanced” section.
- profiles can be saved/loaded with a name.

---

## output files schemas

`gephi/nodes.csv`
- Id
- Label
- degree
- betweenness
- modularity_class
- is_seed (true/false)
- is_hub (true/false)
- is_banned (true/false)
- is_public (true/false)

`gephi/edges.csv`
- Source
- Target
- Kind (`friend` | `group`)

`probable_friends.csv` (ranked)
- candidate_steamid
- score
- mutual_count
- jaccard_with_seed
- shared_groups
- shared_games

---

## gephi how‑to (step‑by‑step)

1) open gephi → new project
2) import `gephi/nodes.csv` as “nodes table”
3) import `gephi/edges.csv` as “edges table” (undirected, append)
4) layout → forceatlas 2
- scaling 25
- linlog ✓
- prevent overlap ✓
- run 20–30s → stop, then “noverlap” a few seconds
5) appearance
- nodes → partition → `modularity_class` → apply (color communities)
- nodes → ranking → `betweenness` → apply (size hubs: 8–50)
6) optional filter
- filters → edges → attributes → partition → `Kind` → select `friend`
- toggle `friend` vs `group` to see core friendships vs shared context

---

## probable friends

aim: guess close associates of the seed using public signals:
- mutual friend count with seed (triadic closure)
- neighbor‑set jaccard with seed
- shared groups bonus
- shared games bonus (if public)

weights are tunable in config. the analyzer skips private data silently.

---

## tips for osint in gephi

- start with `Kind = friend` (skeleton); toggle `group` later for context
- “degree range” filter (min 2–3) removes tails and reveals the core
- “k‑core” (k=3→6) finds inner circles (mutually connected cliques)
- gatekeepers: large betweenness nodes between different colors
- leaders: isolate one color (partition filter) then size by degree

---

## troubleshooting

- forbidden / “verify key” → check `.env` contains a valid `STEAM_API_KEY`
- gephi stuck at 0% → lower `max_nodes` (default 500), use `Kind=friend`
- “ghost nodes” → we export clean edges; import nodes first, then edges
- slow scans → reduce `depth`, ensure `rate_limit_rpm` ≥ 60

---


## faq

- does this scrape?
no, it uses the official web api; private data is skipped.

- is this allowed?
use a legitimate api key and respect rate limits; do not bypass restrictions.

---

## license


mit © microck — see [license](LICENSE)



Loading