osintkit 0.1.2 → 0.1.4

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.
Files changed (55) hide show
  1. package/LICENSE +0 -0
  2. package/bin/osintkit.js +30 -13
  3. package/osintkit/__init__.py +1 -1
  4. package/osintkit/__main__.py +22 -1
  5. package/osintkit/__pycache__/__init__.cpython-311.pyc +0 -0
  6. package/osintkit/__pycache__/cli.cpython-311.pyc +0 -0
  7. package/osintkit/__pycache__/config.cpython-311.pyc +0 -0
  8. package/osintkit/__pycache__/profiles.cpython-311.pyc +0 -0
  9. package/osintkit/__pycache__/risk.cpython-311.pyc +0 -0
  10. package/osintkit/__pycache__/scanner.cpython-311.pyc +0 -0
  11. package/osintkit/cli.py +82 -4
  12. package/osintkit/modules/__pycache__/__init__.cpython-311.pyc +0 -0
  13. package/osintkit/modules/__pycache__/breach.cpython-311.pyc +0 -0
  14. package/osintkit/modules/__pycache__/brokers.cpython-311.pyc +0 -0
  15. package/osintkit/modules/__pycache__/certs.cpython-311.pyc +0 -0
  16. package/osintkit/modules/__pycache__/dark_web.cpython-311.pyc +0 -0
  17. package/osintkit/modules/__pycache__/gravatar.cpython-311.pyc +0 -0
  18. package/osintkit/modules/__pycache__/harvester.cpython-311.pyc +0 -0
  19. package/osintkit/modules/__pycache__/hibp.cpython-311.pyc +0 -0
  20. package/osintkit/modules/__pycache__/hibp_kanon.cpython-311.pyc +0 -0
  21. package/osintkit/modules/__pycache__/holehe.cpython-311.pyc +0 -0
  22. package/osintkit/modules/__pycache__/libphonenumber_info.cpython-311.pyc +0 -0
  23. package/osintkit/modules/__pycache__/paste.cpython-311.pyc +0 -0
  24. package/osintkit/modules/__pycache__/phone.cpython-311.pyc +0 -0
  25. package/osintkit/modules/__pycache__/sherlock.cpython-311.pyc +0 -0
  26. package/osintkit/modules/__pycache__/social.cpython-311.pyc +0 -0
  27. package/osintkit/modules/__pycache__/wayback.cpython-311.pyc +0 -0
  28. package/osintkit/modules/gravatar.py +0 -0
  29. package/osintkit/modules/libphonenumber_info.py +0 -0
  30. package/osintkit/modules/sherlock.py +0 -0
  31. package/osintkit/modules/stage2/__init__.py +0 -0
  32. package/osintkit/modules/stage2/__pycache__/__init__.cpython-311.pyc +0 -0
  33. package/osintkit/modules/stage2/__pycache__/github_api.cpython-311.pyc +0 -0
  34. package/osintkit/modules/stage2/__pycache__/hunter.cpython-311.pyc +0 -0
  35. package/osintkit/modules/stage2/__pycache__/leakcheck.cpython-311.pyc +0 -0
  36. package/osintkit/modules/stage2/__pycache__/numverify.cpython-311.pyc +0 -0
  37. package/osintkit/modules/stage2/__pycache__/securitytrails.cpython-311.pyc +0 -0
  38. package/osintkit/modules/stage2/github_api.py +0 -0
  39. package/osintkit/modules/stage2/hunter.py +0 -0
  40. package/osintkit/modules/stage2/leakcheck.py +0 -0
  41. package/osintkit/modules/stage2/numverify.py +0 -0
  42. package/osintkit/modules/stage2/securitytrails.py +0 -0
  43. package/osintkit/output/__pycache__/__init__.cpython-311.pyc +0 -0
  44. package/osintkit/output/__pycache__/html_writer.cpython-311.pyc +0 -0
  45. package/osintkit/output/__pycache__/json_writer.cpython-311.pyc +0 -0
  46. package/osintkit/output/__pycache__/md_writer.cpython-311.pyc +0 -0
  47. package/osintkit/output/md_writer.py +0 -0
  48. package/package.json +8 -2
  49. package/postinstall.js +69 -50
  50. package/pyproject.toml +1 -1
  51. package/osintkit/__pycache__/__init__.cpython-310.pyc +0 -0
  52. package/osintkit/__pycache__/__main__.cpython-310.pyc +0 -0
  53. package/osintkit/__pycache__/__main__.cpython-311.pyc +0 -0
  54. package/osintkit/__pycache__/cli.cpython-310.pyc +0 -0
  55. package/osintkit/__pycache__/risk.cpython-310.pyc +0 -0
package/LICENSE CHANGED
File without changes
package/bin/osintkit.js CHANGED
@@ -1,41 +1,58 @@
1
1
  #!/usr/bin/env node
2
- const { spawn } = require('child_process');
2
+ const { spawn, spawnSync } = require('child_process');
3
3
  const path = require('path');
4
4
  const fs = require('fs');
5
5
 
6
- // The npm package root is one level up from bin/
7
6
  const packageDir = path.dirname(path.dirname(__filename));
7
+ const isWin = process.platform === 'win32';
8
+
9
+ const venvPython = isWin
10
+ ? path.join(packageDir, '.venv', 'Scripts', 'python.exe')
11
+ : path.join(packageDir, '.venv', 'bin', 'python3');
12
+
13
+ // If venv doesn't exist yet, run postinstall first (self-healing first run)
14
+ if (!fs.existsSync(venvPython)) {
15
+ const postinstall = path.join(packageDir, 'postinstall.js');
16
+ if (fs.existsSync(postinstall)) {
17
+ console.log('osintkit: first run — setting up Python environment...');
18
+ const r = spawnSync(process.execPath, [postinstall], {
19
+ stdio: 'inherit',
20
+ cwd: packageDir,
21
+ });
22
+ if (!fs.existsSync(venvPython)) {
23
+ console.error('\nosintkit: setup failed. Run manually:');
24
+ console.error(` node ${postinstall}`);
25
+ process.exit(1);
26
+ }
27
+ }
28
+ }
8
29
 
9
- // Prefer venv Python (installed by postinstall), fall back to system Python
10
30
  function findPython() {
31
+ // Prefer venv Python (Unix + Windows)
11
32
  const venvCandidates = [
12
33
  path.join(packageDir, '.venv', 'bin', 'python3'),
13
34
  path.join(packageDir, '.venv', 'bin', 'python'),
35
+ path.join(packageDir, '.venv', 'Scripts', 'python.exe'),
14
36
  path.join(packageDir, 'venv', 'bin', 'python3'),
15
- path.join(packageDir, 'venv', 'bin', 'python'),
37
+ path.join(packageDir, 'venv', 'Scripts', 'python.exe'),
16
38
  ];
17
39
  for (const p of venvCandidates) {
18
40
  if (fs.existsSync(p)) return p;
19
41
  }
20
-
21
42
  // Fall back to system Python
22
- const systemCandidates = ['python3.11', 'python3', 'python'];
43
+ const systemCandidates = isWin ? ['python', 'python3'] : ['python3.11', 'python3', 'python'];
23
44
  for (const bin of systemCandidates) {
24
- try {
25
- require('child_process').execSync(`${bin} --version`, { stdio: 'ignore' });
26
- return bin;
27
- } catch (_) {}
45
+ const r = spawnSync(bin, ['--version'], { stdio: 'pipe' });
46
+ if (r.status === 0) return bin;
28
47
  }
29
48
  return 'python3';
30
49
  }
31
50
 
32
51
  const pythonBin = findPython();
33
-
34
- // Always set PYTHONPATH so the package is importable regardless of install method
35
52
  const env = {
36
53
  ...process.env,
37
54
  PYTHONPATH: process.env.PYTHONPATH
38
- ? `${packageDir}:${process.env.PYTHONPATH}`
55
+ ? `${packageDir}${path.delimiter}${process.env.PYTHONPATH}`
39
56
  : packageDir,
40
57
  };
41
58
 
@@ -1,3 +1,3 @@
1
1
  """osintkit - OSINT CLI tool for personal digital footprint analysis."""
2
2
 
3
- __version__ = "0.1.2"
3
+ __version__ = "0.1.4"
@@ -1,4 +1,25 @@
1
1
  """Entry point for python -m osintkit"""
2
- from osintkit.cli import app
2
+ import sys
3
+
4
+ # CLI shortcuts — intercept before Typer parses argv:
5
+ # osintkit → osintkit list
6
+ # osintkit <id> → osintkit open <id>
7
+ # osintkit -v → osintkit version
8
+ _KNOWN_COMMANDS = {
9
+ "new", "list", "refresh", "open", "export",
10
+ "setup", "delete", "version", "update", "tag",
11
+ }
3
12
 
13
+ if len(sys.argv) == 1:
14
+ # bare `osintkit` → show list
15
+ sys.argv.append("list")
16
+ elif len(sys.argv) == 2:
17
+ arg = sys.argv[1]
18
+ if arg in ("-v",):
19
+ sys.argv[1] = "version"
20
+ elif not arg.startswith("-") and arg not in _KNOWN_COMMANDS:
21
+ # `osintkit <id>` → open that profile
22
+ sys.argv = [sys.argv[0], "open", arg]
23
+
24
+ from osintkit.cli import app
4
25
  app()
package/osintkit/cli.py CHANGED
@@ -424,9 +424,11 @@ def new():
424
424
 
425
425
 
426
426
  @app.command()
427
- def list():
428
- """List all profiles."""
429
- profiles = store.list()
427
+ def list(
428
+ filter_tag: Optional[str] = typer.Option(None, "--tag", "-t", help="Filter by tag"),
429
+ ):
430
+ """List all profiles. Filter with --tag <name>."""
431
+ profiles = store.list(tag=filter_tag)
430
432
 
431
433
  if not profiles:
432
434
  console.print("\n[yellow]No profiles found.[/yellow]")
@@ -664,12 +666,88 @@ def delete(profile_ref: str = typer.Argument(None, help="Profile ID or name")):
664
666
 
665
667
  @app.command()
666
668
  def version():
667
- """Show version."""
669
+ """Show version. Also available as: osintkit -v"""
668
670
  if _update_thread:
669
671
  _update_thread.join(timeout=4)
670
672
  console.print(f"osintkit v{__version__}")
671
673
  _print_update_notice()
672
674
 
673
675
 
676
+ @app.command()
677
+ def update():
678
+ """Check for updates and install the latest version."""
679
+ import subprocess
680
+
681
+ console.print("\n[bold]Checking for updates...[/bold]")
682
+
683
+ if _update_thread:
684
+ _update_thread.join(timeout=5)
685
+
686
+ if _update_available:
687
+ console.print(f"[cyan]New version available: {_update_available}[/cyan]")
688
+ console.print(f"[dim]Current: {__version__}[/dim]\n")
689
+ if Confirm.ask("Install now?", default=True):
690
+ console.print("[dim]Running: npm install -g osintkit[/dim]\n")
691
+ result = subprocess.run(["npm", "install", "-g", "osintkit"], check=False)
692
+ if result.returncode == 0:
693
+ console.print(f"\n[green]✓[/green] Updated to osintkit {_update_available}")
694
+ console.print("[dim]Restart your terminal for changes to take effect.[/dim]")
695
+ else:
696
+ console.print("\n[red]Update failed.[/red] Try manually: npm install -g osintkit")
697
+ else:
698
+ console.print(f"[green]✓[/green] Already on latest version (v{__version__})")
699
+
700
+
701
+ @app.command()
702
+ def tag(
703
+ profile_ref: str = typer.Argument(..., help="Profile ID or name"),
704
+ add: Optional[str] = typer.Option(None, "--add", "-a", help="Tag to add"),
705
+ remove: Optional[str] = typer.Option(None, "--remove", "-r", help="Tag to remove"),
706
+ list_tags: bool = typer.Option(False, "--list", "-l", help="List tags on profile"),
707
+ ):
708
+ """Add, remove, or list tags on a profile.
709
+
710
+ Examples:
711
+ osintkit tag abc123 --add client
712
+ osintkit tag abc123 --remove client
713
+ osintkit tag abc123 --list
714
+ osintkit list --tag client (filter list by tag)
715
+ """
716
+ profile = store.get(profile_ref)
717
+ if not profile:
718
+ profiles = store.list()
719
+ for p in profiles:
720
+ if p.name and p.name.lower() == profile_ref.lower():
721
+ profile = p
722
+ break
723
+ if not profile:
724
+ console.print(f"[red]Profile not found: {profile_ref}[/red]")
725
+ raise typer.Exit(1)
726
+
727
+ if add:
728
+ if add not in profile.tags:
729
+ profile.tags.append(add)
730
+ store.update(profile)
731
+ console.print(f"[green]✓[/green] Added tag '{add}' to {profile.name or profile.id}")
732
+ else:
733
+ console.print(f"[yellow]Tag '{add}' already exists[/yellow]")
734
+
735
+ elif remove:
736
+ if remove in profile.tags:
737
+ profile.tags.remove(remove)
738
+ store.update(profile)
739
+ console.print(f"[green]✓[/green] Removed tag '{remove}' from {profile.name or profile.id}")
740
+ else:
741
+ console.print(f"[yellow]Tag '{remove}' not found[/yellow]")
742
+
743
+ else:
744
+ # Default: list tags
745
+ if profile.tags:
746
+ console.print(f"\nTags on [cyan]{profile.name or profile.id}[/cyan]: " +
747
+ ", ".join(f"[bold]{t}[/bold]" for t in profile.tags))
748
+ else:
749
+ console.print(f"[dim]No tags on {profile.name or profile.id}[/dim]")
750
+
751
+
674
752
  if __name__ == "__main__":
675
753
  app()
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "osintkit",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "OSINT CLI for personal digital footprint analysis",
5
5
  "bin": {
6
6
  "osintkit": "./bin/osintkit.js"
@@ -17,7 +17,13 @@
17
17
  "README.md",
18
18
  "postinstall.js"
19
19
  ],
20
- "keywords": ["osint", "security", "privacy", "cli", "recon"],
20
+ "keywords": [
21
+ "osint",
22
+ "security",
23
+ "privacy",
24
+ "cli",
25
+ "recon"
26
+ ],
21
27
  "author": "",
22
28
  "license": "MIT",
23
29
  "engines": {
package/postinstall.js CHANGED
@@ -1,75 +1,94 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * osintkit postinstall — installs all Python dependencies automatically.
4
- *
5
- * Runs after `npm install -g osintkit`.
6
- * Installs:
7
- * 1. Core Python deps (typer, rich, httpx, pydantic, etc.) from requirements.txt
8
- * 2. Optional OSINT tools (maigret, holehe, sherlock) from requirements-tools.txt
9
- *
10
- * Uses --break-system-packages on Linux/macOS where needed (Python 3.11+).
11
- * Falls back gracefully if pip isn't available.
3
+ * osintkit postinstall — creates a venv inside the package dir and installs
4
+ * all Python dependencies into it. The npm shim (bin/osintkit.js) will then
5
+ * always find and use this venv's Python, avoiding any system Python confusion.
12
6
  */
13
7
 
14
- const { execSync } = require('child_process');
8
+ const { spawnSync } = require('child_process');
15
9
  const path = require('path');
16
10
  const fs = require('fs');
17
11
 
18
12
  const packageDir = __dirname;
13
+ const venvDir = path.join(packageDir, '.venv');
19
14
  const req = path.join(packageDir, 'requirements.txt');
20
15
  const reqTools = path.join(packageDir, 'requirements-tools.txt');
21
16
 
22
- function findPip() {
23
- for (const bin of ['pip3', 'pip']) {
24
- try {
25
- execSync(`${bin} --version`, { stdio: 'ignore' });
26
- return bin;
27
- } catch (_) {}
17
+ // Platform-aware paths inside the venv
18
+ const isWin = process.platform === 'win32';
19
+ const venvPython = isWin
20
+ ? path.join(venvDir, 'Scripts', 'python.exe')
21
+ : path.join(venvDir, 'bin', 'python3');
22
+ const venvPip = isWin
23
+ ? path.join(venvDir, 'Scripts', 'pip.exe')
24
+ : path.join(venvDir, 'bin', 'pip3');
25
+
26
+ function findSystemPython() {
27
+ const candidates = isWin
28
+ ? ['python', 'python3']
29
+ : ['python3.13', 'python3.12', 'python3.11', 'python3.10', 'python3'];
30
+ for (const bin of candidates) {
31
+ const r = spawnSync(bin, ['--version'], { encoding: 'utf8' });
32
+ if (r.status === 0) {
33
+ // Must be >= 3.10
34
+ const match = (r.stdout || r.stderr || '').match(/Python (\d+)\.(\d+)/);
35
+ if (match && (parseInt(match[1]) > 3 || parseInt(match[2]) >= 10)) {
36
+ return bin;
37
+ }
38
+ }
28
39
  }
29
40
  return null;
30
41
  }
31
42
 
32
- function pipInstall(pip, requirementsFile, label) {
33
- if (!fs.existsSync(requirementsFile)) {
34
- console.log(` ⚠️ ${label}: requirements file not found, skipping`);
35
- return;
36
- }
43
+ function run(cmd, args, opts = {}) {
44
+ const r = spawnSync(cmd, args, { encoding: 'utf8', cwd: packageDir, ...opts });
45
+ return r;
46
+ }
37
47
 
38
- const flags = ['-r', requirementsFile, '-q', '--disable-pip-version-check'];
48
+ console.log('\nosintkit: setting up Python environment...\n');
39
49
 
40
- // Try with --break-system-packages first (needed on modern Linux/macOS)
41
- try {
42
- execSync(`${pip} install ${flags.join(' ')} --break-system-packages`, {
43
- stdio: 'pipe',
44
- cwd: packageDir,
45
- });
46
- console.log(` ✅ ${label} installed`);
47
- return;
48
- } catch (_) {}
50
+ // Step 1: find a usable Python 3.10+
51
+ const sysPython = findSystemPython();
52
+ if (!sysPython) {
53
+ console.log(' ❌ Python 3.10+ not found.');
54
+ console.log(' Install from https://python.org then re-run: npm install -g osintkit\n');
55
+ process.exit(0);
56
+ }
57
+ console.log(` ✅ Found Python: ${sysPython}`);
49
58
 
50
- // Fall back without the flag (works on older systems / virtual envs)
51
- try {
52
- execSync(`${pip} install ${flags.join(' ')}`, {
53
- stdio: 'pipe',
54
- cwd: packageDir,
55
- });
56
- console.log(`${label} installed`);
57
- return;
58
- } catch (err) {
59
- console.log(` ⚠️ ${label}: could not install (${err.message.split('\n')[0]})`);
59
+ // Step 2: create venv (skip if already exists)
60
+ if (!fs.existsSync(venvPython)) {
61
+ console.log(` 🔧 Creating venv at ${venvDir} ...`);
62
+ const r = run(sysPython, ['-m', 'venv', venvDir]);
63
+ if (r.status !== 0) {
64
+ console.log(' ❌ Failed to create venv.');
65
+ console.log(` ${(r.stderr || '').trim()}`);
66
+ console.log(' Try: python3 -m venv .venv (in the package dir)\n');
67
+ process.exit(0);
60
68
  }
69
+ console.log(' ✅ Venv created');
70
+ } else {
71
+ console.log(' ✅ Venv already exists');
61
72
  }
62
73
 
63
- console.log('\nosintkit: installing Python dependencies...\n');
74
+ // Step 3: upgrade pip inside venv
75
+ run(venvPython, ['-m', 'pip', 'install', '--upgrade', 'pip', '-q']);
64
76
 
65
- const pip = findPip();
66
- if (!pip) {
67
- console.log(' ⚠️ pip not found — skipping Python dependency install.');
68
- console.log(' Run manually: pip3 install -r requirements.txt -r requirements-tools.txt');
69
- process.exit(0);
77
+ // Step 4: install deps into venv
78
+ function pipInstall(requirementsFile, label) {
79
+ if (!fs.existsSync(requirementsFile)) return;
80
+ console.log(` 📦 Installing ${label}...`);
81
+ const r = run(venvPython, ['-m', 'pip', 'install', '-r', requirementsFile, '-q', '--disable-pip-version-check']);
82
+ if (r.status === 0) {
83
+ console.log(` ✅ ${label} installed`);
84
+ } else {
85
+ const err = (r.stderr || r.stdout || '').trim().split('\n').slice(-3).join('\n');
86
+ console.log(` ❌ ${label} failed:\n ${err}`);
87
+ console.log(` Fix: ${venvPython} -m pip install -r ${requirementsFile}`);
88
+ }
70
89
  }
71
90
 
72
- pipInstall(pip, req, 'Core dependencies');
73
- pipInstall(pip, reqTools, 'OSINT tools (maigret, holehe, sherlock)');
91
+ pipInstall(req, 'Core dependencies (typer, rich, httpx...)');
92
+ pipInstall(reqTools, 'OSINT tools (maigret, holehe, sherlock)');
74
93
 
75
- console.log('\nosintkit ready. Run: osintkit new\n');
94
+ console.log('\n ✅ osintkit ready. Run: osintkit new\n');
package/pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "osintkit"
3
- version = "0.1.2"
3
+ version = "0.1.4"
4
4
  description = "OSINT CLI tool for personal digital footprint analysis"
5
5
  authors = ["Your Name <you@example.com>"]
6
6
  license = "MIT"