reconkit 0.1.0__tar.gz → 0.2.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.
- reconkit-0.2.1/.github/workflows/publish.yml +50 -0
- {reconkit-0.1.0 → reconkit-0.2.1}/.gitignore +30 -30
- {reconkit-0.1.0 → reconkit-0.2.1}/CHANGELOG.md +37 -21
- reconkit-0.2.1/LICENSE +38 -0
- reconkit-0.2.1/PKG-INFO +136 -0
- reconkit-0.2.1/README.md +107 -0
- {reconkit-0.1.0 → reconkit-0.2.1}/pyproject.toml +57 -56
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/__init__.py +22 -22
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/cli.py +247 -218
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/core/rate_limit.py +24 -24
- reconkit-0.2.1/src/reconkit/evidence/__init__.py +16 -0
- reconkit-0.2.1/src/reconkit/evidence/archives.py +108 -0
- reconkit-0.2.1/src/reconkit/evidence/custody.py +53 -0
- reconkit-0.2.1/src/reconkit/evidence/iris.py +37 -0
- reconkit-0.2.1/src/reconkit/evidence/manifest.py +98 -0
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/forensics/exif.py +16 -16
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/forensics/hashing.py +22 -22
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/forensics/identify.py +12 -12
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/forensics/strings.py +47 -47
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/noir/__init__.py +54 -54
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/noir/errors.py +29 -29
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/noir/primitives.py +154 -154
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/noir/public_api.py +225 -221
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/osint/dns.py +18 -18
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/osint/ip.py +25 -25
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/osint/whois.py +14 -14
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/scraping/extract.py +36 -36
- reconkit-0.2.1/src/reconkit/scraping/fetch.py +112 -0
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/scraping/robots.py +59 -60
- reconkit-0.2.1/tests/test_evidence_exports.py +48 -0
- {reconkit-0.1.0 → reconkit-0.2.1}/tests/test_extract_links.py +13 -13
- {reconkit-0.1.0 → reconkit-0.2.1}/tests/test_hashing.py +9 -9
- {reconkit-0.1.0 → reconkit-0.2.1}/tests/test_noir_output_contract.py +23 -23
- {reconkit-0.1.0 → reconkit-0.2.1}/tests/test_noir_primitives.py +12 -12
- {reconkit-0.1.0 → reconkit-0.2.1}/tests/test_strings.py +11 -11
- reconkit-0.1.0/LICENSE +0 -21
- reconkit-0.1.0/PKG-INFO +0 -108
- reconkit-0.1.0/README.md +0 -80
- reconkit-0.1.0/src/reconkit/scraping/fetch.py +0 -81
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/core/__init__.py +0 -0
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/forensics/__init__.py +0 -0
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/osint/__init__.py +0 -0
- {reconkit-0.1.0 → reconkit-0.2.1}/src/reconkit/scraping/__init__.py +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
publish:
|
|
13
|
+
name: Build and publish
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
environment: pypi
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
|
|
23
|
+
- name: Install release tools
|
|
24
|
+
run: python -m pip install --upgrade build twine
|
|
25
|
+
|
|
26
|
+
- name: Confirm the tag matches the package version
|
|
27
|
+
env:
|
|
28
|
+
RELEASE_TAG: ${{ github.ref_name }}
|
|
29
|
+
run: |
|
|
30
|
+
python - <<'PY'
|
|
31
|
+
import os
|
|
32
|
+
import tomllib
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
|
|
35
|
+
version = tomllib.loads(Path("pyproject.toml").read_text())["project"]["version"]
|
|
36
|
+
expected = f"v{version}"
|
|
37
|
+
if os.environ["RELEASE_TAG"] != expected:
|
|
38
|
+
raise SystemExit(f"Tag {os.environ['RELEASE_TAG']} does not match {expected}.")
|
|
39
|
+
PY
|
|
40
|
+
|
|
41
|
+
- name: Build distributions
|
|
42
|
+
run: python -m build
|
|
43
|
+
|
|
44
|
+
- name: Validate distributions
|
|
45
|
+
run: twine check dist/*
|
|
46
|
+
|
|
47
|
+
- name: Publish to PyPI
|
|
48
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
49
|
+
with:
|
|
50
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
# Byte-compiled / optimized / DLL files
|
|
2
|
-
__pycache__/
|
|
3
|
-
*.py[cod]
|
|
4
|
-
*$py.class
|
|
5
|
-
|
|
6
|
-
# C extensions
|
|
7
|
-
*.so
|
|
8
|
-
|
|
9
|
-
# Distribution / packaging
|
|
10
|
-
build/
|
|
11
|
-
dist/
|
|
12
|
-
*.egg-info/
|
|
13
|
-
.eggs/
|
|
14
|
-
|
|
15
|
-
# Virtual environments
|
|
16
|
-
.venv/
|
|
17
|
-
venv/
|
|
18
|
-
ENV/
|
|
19
|
-
|
|
20
|
-
# Test / tooling caches
|
|
21
|
-
.pytest_cache/
|
|
22
|
-
.mypy_cache/
|
|
23
|
-
.ruff_cache/
|
|
24
|
-
.coverage
|
|
25
|
-
htmlcov/
|
|
26
|
-
|
|
27
|
-
# OS / editor
|
|
28
|
-
.DS_Store
|
|
29
|
-
Thumbs.db
|
|
30
|
-
.vscode/
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
build/
|
|
11
|
+
dist/
|
|
12
|
+
*.egg-info/
|
|
13
|
+
.eggs/
|
|
14
|
+
|
|
15
|
+
# Virtual environments
|
|
16
|
+
.venv/
|
|
17
|
+
venv/
|
|
18
|
+
ENV/
|
|
19
|
+
|
|
20
|
+
# Test / tooling caches
|
|
21
|
+
.pytest_cache/
|
|
22
|
+
.mypy_cache/
|
|
23
|
+
.ruff_cache/
|
|
24
|
+
.coverage
|
|
25
|
+
htmlcov/
|
|
26
|
+
|
|
27
|
+
# OS / editor
|
|
28
|
+
.DS_Store
|
|
29
|
+
Thumbs.db
|
|
30
|
+
.vscode/
|
|
@@ -1,21 +1,37 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
|
|
5
|
-
Format: loosely based on *Keep a Changelog*. Versioning: SemVer where practical.
|
|
6
|
-
|
|
7
|
-
## [0.1
|
|
8
|
-
|
|
9
|
-
###
|
|
10
|
-
- Noir Stack
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
Format: loosely based on *Keep a Changelog*. Versioning: SemVer where practical.
|
|
6
|
+
|
|
7
|
+
## [0.2.1] - 2026-11-04
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- Replaced the MIT license with Noir Stack LLC's Proprietary Software License — Free Use, No Modification.
|
|
11
|
+
|
|
12
|
+
## [0.2.0] - 2026-11-04
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- WARC 1.1 and WACZ 1.2 exports with an index, page list, SHA-256 fixity, and data-package digest.
|
|
16
|
+
- Hash-linked chain-of-custody ledgers and Ed25519-signed manifests.
|
|
17
|
+
- DFIR-IRIS v2 evidence-registration adapter.
|
|
18
|
+
- Redirect-chain recording and conservative public-destination checks for web capture.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- Robots rules are checked at every redirect destination and fail closed by default.
|
|
22
|
+
|
|
23
|
+
## [0.1.0] - 2026-02-09
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
- Noir Stack public primitives: `EvidenceArtifact`, `EvidenceBundle`, `ProvenanceRecord`, `VerificationResult`.
|
|
27
|
+
- Domain-specific errors that describe trust boundaries and provenance constraints.
|
|
28
|
+
- Audit-grade CLI vocabulary: `evidence`, `boundary`, `verify`.
|
|
29
|
+
- Structured JSON outputs include: `decision_basis`, `verification_status`, `provenance_confidence`.
|
|
30
|
+
- `robots.txt` compliance (default) and rate limiting for web acquisition.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
- Public-facing surface and CLI terminology refactored to evidence/verification framing.
|
|
34
|
+
|
|
35
|
+
### Notes
|
|
36
|
+
- This release is intentionally conservative.
|
|
37
|
+
- The system is capable of refusing to speculate. This is a feature.
|
reconkit-0.2.1/LICENSE
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
Proprietary Software License — Free Use, No Modification
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Noir Stack LLC. All rights reserved.
|
|
4
|
+
|
|
5
|
+
## 1. Grant of License
|
|
6
|
+
|
|
7
|
+
The copyright holder grants users a non-exclusive, worldwide, royalty-free license to download, install, and use this software for personal, educational, research, and commercial purposes, subject to the conditions below.
|
|
8
|
+
|
|
9
|
+
## 2. Restrictions
|
|
10
|
+
|
|
11
|
+
Users may not, without prior written permission from the copyright holder:
|
|
12
|
+
|
|
13
|
+
- Modify, adapt, translate, or create derivative works based on the software.
|
|
14
|
+
- Redistribute, publish, sell, sublicense, or repackage the software.
|
|
15
|
+
- Remove or alter copyright, attribution, or license notices.
|
|
16
|
+
- Claim ownership or authorship of the software.
|
|
17
|
+
|
|
18
|
+
## 3. Ownership
|
|
19
|
+
|
|
20
|
+
All rights, title, and interest in the software, including its source code and associated intellectual property, remain with the copyright holder.
|
|
21
|
+
|
|
22
|
+
No ownership rights are transferred under this license.
|
|
23
|
+
|
|
24
|
+
## 4. No Warranty
|
|
25
|
+
|
|
26
|
+
The software is provided "AS IS", without warranty of any kind, express or implied, to the extent permitted by applicable law.
|
|
27
|
+
|
|
28
|
+
## 5. Limitation of Liability
|
|
29
|
+
|
|
30
|
+
To the extent permitted by applicable law, the copyright holder shall not be liable for damages arising from the use or inability to use the software.
|
|
31
|
+
|
|
32
|
+
## 6. Termination
|
|
33
|
+
|
|
34
|
+
Permission to use the software terminates upon a material violation of this license, subject to applicable law.
|
|
35
|
+
|
|
36
|
+
## 7. Additional Permissions
|
|
37
|
+
|
|
38
|
+
Any permissions not expressly granted must be obtained in writing from the copyright holder.
|
reconkit-0.2.1/PKG-INFO
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: reconkit
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Evidence collection, provenance, and preservation utilities for authorized investigations.
|
|
5
|
+
Author: reconkit
|
|
6
|
+
License: Proprietary Software License — Free Use, No Modification
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: forensics,osint,scraping,triage
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Requires-Dist: beautifulsoup4>=4.12
|
|
11
|
+
Requires-Dist: cryptography>=42
|
|
12
|
+
Requires-Dist: dnspython>=2.6
|
|
13
|
+
Requires-Dist: exifread>=3.0
|
|
14
|
+
Requires-Dist: filetype>=1.2
|
|
15
|
+
Requires-Dist: httpx>=0.27
|
|
16
|
+
Requires-Dist: ipwhois>=1.2
|
|
17
|
+
Requires-Dist: lxml>=5.1
|
|
18
|
+
Requires-Dist: python-whois>=0.9
|
|
19
|
+
Requires-Dist: rich>=13.7
|
|
20
|
+
Requires-Dist: typer>=0.12
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
23
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
27
|
+
Requires-Dist: twine>=5.1; extra == 'dev'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# ReconKit
|
|
31
|
+
|
|
32
|
+
ReconKit is a small Python toolkit for preserving authorized web observations and local file findings as reviewable evidence records. It is a collection layer, not a scanner, case-management system, or source of truth.
|
|
33
|
+
|
|
34
|
+
It complements reconnaissance tools such as SpiderFoot and BBOT, web archiving tools such as Webrecorder, and case-management platforms such as DFIR-IRIS. ReconKit focuses on the handoff between collection and review: what was collected, where it came from, what redirects occurred, what limits apply, and whether exported files have changed.
|
|
35
|
+
|
|
36
|
+
## What it provides
|
|
37
|
+
|
|
38
|
+
- Public-web capture with bounded size, rate limiting, redirect-chain recording, robots checks at every destination, and blocking of private, loopback, and reserved destinations by default.
|
|
39
|
+
- Standards-oriented WARC 1.1 and WACZ 1.2 exports. WACZ files contain a WARC, CDXJ index, page list, file-fixity manifest, and data-package digest.
|
|
40
|
+
- Append-only, hash-linked chain-of-custody ledgers.
|
|
41
|
+
- Ed25519-signed manifests that can be verified offline.
|
|
42
|
+
- A DFIR-IRIS v2 adapter that registers an exported evidence file with an existing case.
|
|
43
|
+
- Local file hashes, magic-byte identification, EXIF extraction, printable-string extraction, and small DNS/WHOIS/RDAP observations.
|
|
44
|
+
|
|
45
|
+
## What it does not claim
|
|
46
|
+
|
|
47
|
+
ReconKit records a transport observation. It does not prove the identity of a publisher, the truth of content, legal chain of custody, or attribution. A SHA-256 digest proves that bytes have not changed relative to the recorded digest; it does not prove where they originated.
|
|
48
|
+
|
|
49
|
+
Web collection is only for systems and data you own or are authorized to assess. The default public-destination restriction helps prevent accidental collection from local or private infrastructure; it is not a substitute for operational authorization.
|
|
50
|
+
|
|
51
|
+
## Install
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
python -m pip install reconkit
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
For development:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
python -m pip install -e ".[dev]"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Capture and preserve a page
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
reconkit evidence archive-warc "https://example.com" --output evidence/example.warc
|
|
67
|
+
reconkit evidence archive-wacz "https://example.com" --output evidence/example.wacz --title "Example capture"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The WACZ export follows the [WACZ 1.2 layout](https://specs.webrecorder.net/wacz/1.2.0/), so it can be validated and replayed with compatible web-archive tooling.
|
|
71
|
+
Robots rules are respected by default; use `--no-obey-robots` only when you have clear authorization for the capture.
|
|
72
|
+
|
|
73
|
+
## Sign a manifest and record custody
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from pathlib import Path
|
|
77
|
+
from reconkit.evidence import CustodyLedger, ManifestSigner, verify_manifest, write_manifest
|
|
78
|
+
|
|
79
|
+
evidence = Path("evidence/example.wacz")
|
|
80
|
+
ledger = CustodyLedger("evidence/custody.jsonl")
|
|
81
|
+
ledger.append(action="acquired", actor="analyst@example.org", artifact_path=evidence)
|
|
82
|
+
ledger.append(action="exported", actor="analyst@example.org", artifact_path=evidence)
|
|
83
|
+
assert ledger.verify()
|
|
84
|
+
|
|
85
|
+
signer = ManifestSigner.generate()
|
|
86
|
+
Path("keys/evidence-signing-key.pem").write_bytes(signer.private_pem())
|
|
87
|
+
manifest = write_manifest([evidence], "evidence/manifest.json", signer, custody_ledger=ledger.path)
|
|
88
|
+
assert verify_manifest(manifest)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Keep the private key outside the evidence directory and protect it with your organization’s key-management practices. The manifest embeds the corresponding public key so a reviewer can verify it without the private key.
|
|
92
|
+
|
|
93
|
+
## Register exported evidence in DFIR-IRIS
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
from reconkit.evidence import DFIRIRISAdapter
|
|
97
|
+
|
|
98
|
+
iris = DFIRIRISAdapter("https://iris.example.org", api_key="your-api-key")
|
|
99
|
+
iris.register(
|
|
100
|
+
case_identifier=42,
|
|
101
|
+
evidence_path="evidence/example.wacz",
|
|
102
|
+
description="Public web capture; signature and custody ledger stored alongside export.",
|
|
103
|
+
)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The adapter registers file metadata, digest, and description through DFIR-IRIS’s documented v2 evidence endpoint. Upload and retention of the evidence bytes remain controlled by the case system’s own workflow.
|
|
107
|
+
|
|
108
|
+
## Existing local commands
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
reconkit evidence acquire-web "https://example.com" --trust-boundary public-internet
|
|
112
|
+
reconkit evidence derive-links "https://example.com"
|
|
113
|
+
reconkit boundary dns example.com
|
|
114
|
+
reconkit verify file-hash .\sample.bin --algo sha256
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Development
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
pytest
|
|
121
|
+
python -m build
|
|
122
|
+
twine check dist/*
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Releases
|
|
126
|
+
|
|
127
|
+
PyPI publication is automated by GitHub Actions. After updating the version in
|
|
128
|
+
`pyproject.toml` and the changelog, push the matching annotated tag (for example,
|
|
129
|
+
`v0.3.0`). The workflow verifies that the tag and package version match, builds
|
|
130
|
+
the distributions, validates them with Twine, and publishes using the repository's
|
|
131
|
+
`PYPI_API_TOKEN` Actions secret. Ordinary branch pushes never publish a release.
|
|
132
|
+
|
|
133
|
+
## License
|
|
134
|
+
|
|
135
|
+
Copyright © 2026 Noir Stack LLC. Licensed under the
|
|
136
|
+
[Proprietary Software License — Free Use, No Modification](LICENSE).
|
reconkit-0.2.1/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# ReconKit
|
|
2
|
+
|
|
3
|
+
ReconKit is a small Python toolkit for preserving authorized web observations and local file findings as reviewable evidence records. It is a collection layer, not a scanner, case-management system, or source of truth.
|
|
4
|
+
|
|
5
|
+
It complements reconnaissance tools such as SpiderFoot and BBOT, web archiving tools such as Webrecorder, and case-management platforms such as DFIR-IRIS. ReconKit focuses on the handoff between collection and review: what was collected, where it came from, what redirects occurred, what limits apply, and whether exported files have changed.
|
|
6
|
+
|
|
7
|
+
## What it provides
|
|
8
|
+
|
|
9
|
+
- Public-web capture with bounded size, rate limiting, redirect-chain recording, robots checks at every destination, and blocking of private, loopback, and reserved destinations by default.
|
|
10
|
+
- Standards-oriented WARC 1.1 and WACZ 1.2 exports. WACZ files contain a WARC, CDXJ index, page list, file-fixity manifest, and data-package digest.
|
|
11
|
+
- Append-only, hash-linked chain-of-custody ledgers.
|
|
12
|
+
- Ed25519-signed manifests that can be verified offline.
|
|
13
|
+
- A DFIR-IRIS v2 adapter that registers an exported evidence file with an existing case.
|
|
14
|
+
- Local file hashes, magic-byte identification, EXIF extraction, printable-string extraction, and small DNS/WHOIS/RDAP observations.
|
|
15
|
+
|
|
16
|
+
## What it does not claim
|
|
17
|
+
|
|
18
|
+
ReconKit records a transport observation. It does not prove the identity of a publisher, the truth of content, legal chain of custody, or attribution. A SHA-256 digest proves that bytes have not changed relative to the recorded digest; it does not prove where they originated.
|
|
19
|
+
|
|
20
|
+
Web collection is only for systems and data you own or are authorized to assess. The default public-destination restriction helps prevent accidental collection from local or private infrastructure; it is not a substitute for operational authorization.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
python -m pip install reconkit
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
For development:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
python -m pip install -e ".[dev]"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Capture and preserve a page
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
reconkit evidence archive-warc "https://example.com" --output evidence/example.warc
|
|
38
|
+
reconkit evidence archive-wacz "https://example.com" --output evidence/example.wacz --title "Example capture"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The WACZ export follows the [WACZ 1.2 layout](https://specs.webrecorder.net/wacz/1.2.0/), so it can be validated and replayed with compatible web-archive tooling.
|
|
42
|
+
Robots rules are respected by default; use `--no-obey-robots` only when you have clear authorization for the capture.
|
|
43
|
+
|
|
44
|
+
## Sign a manifest and record custody
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from pathlib import Path
|
|
48
|
+
from reconkit.evidence import CustodyLedger, ManifestSigner, verify_manifest, write_manifest
|
|
49
|
+
|
|
50
|
+
evidence = Path("evidence/example.wacz")
|
|
51
|
+
ledger = CustodyLedger("evidence/custody.jsonl")
|
|
52
|
+
ledger.append(action="acquired", actor="analyst@example.org", artifact_path=evidence)
|
|
53
|
+
ledger.append(action="exported", actor="analyst@example.org", artifact_path=evidence)
|
|
54
|
+
assert ledger.verify()
|
|
55
|
+
|
|
56
|
+
signer = ManifestSigner.generate()
|
|
57
|
+
Path("keys/evidence-signing-key.pem").write_bytes(signer.private_pem())
|
|
58
|
+
manifest = write_manifest([evidence], "evidence/manifest.json", signer, custody_ledger=ledger.path)
|
|
59
|
+
assert verify_manifest(manifest)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Keep the private key outside the evidence directory and protect it with your organization’s key-management practices. The manifest embeds the corresponding public key so a reviewer can verify it without the private key.
|
|
63
|
+
|
|
64
|
+
## Register exported evidence in DFIR-IRIS
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from reconkit.evidence import DFIRIRISAdapter
|
|
68
|
+
|
|
69
|
+
iris = DFIRIRISAdapter("https://iris.example.org", api_key="your-api-key")
|
|
70
|
+
iris.register(
|
|
71
|
+
case_identifier=42,
|
|
72
|
+
evidence_path="evidence/example.wacz",
|
|
73
|
+
description="Public web capture; signature and custody ledger stored alongside export.",
|
|
74
|
+
)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The adapter registers file metadata, digest, and description through DFIR-IRIS’s documented v2 evidence endpoint. Upload and retention of the evidence bytes remain controlled by the case system’s own workflow.
|
|
78
|
+
|
|
79
|
+
## Existing local commands
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
reconkit evidence acquire-web "https://example.com" --trust-boundary public-internet
|
|
83
|
+
reconkit evidence derive-links "https://example.com"
|
|
84
|
+
reconkit boundary dns example.com
|
|
85
|
+
reconkit verify file-hash .\sample.bin --algo sha256
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Development
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pytest
|
|
92
|
+
python -m build
|
|
93
|
+
twine check dist/*
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Releases
|
|
97
|
+
|
|
98
|
+
PyPI publication is automated by GitHub Actions. After updating the version in
|
|
99
|
+
`pyproject.toml` and the changelog, push the matching annotated tag (for example,
|
|
100
|
+
`v0.3.0`). The workflow verifies that the tag and package version match, builds
|
|
101
|
+
the distributions, validates them with Twine, and publishes using the repository's
|
|
102
|
+
`PYPI_API_TOKEN` Actions secret. Ordinary branch pushes never publish a release.
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
Copyright © 2026 Noir Stack LLC. Licensed under the
|
|
107
|
+
[Proprietary Software License — Free Use, No Modification](LICENSE).
|
|
@@ -1,56 +1,57 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["hatchling>=1.25"]
|
|
3
|
-
build-backend = "hatchling.build"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "reconkit"
|
|
7
|
-
version = "0.1
|
|
8
|
-
description = "
|
|
9
|
-
readme = "README.md"
|
|
10
|
-
requires-python = ">=3.10"
|
|
11
|
-
license = { text = "
|
|
12
|
-
authors = [{ name = "reconkit" }]
|
|
13
|
-
keywords = ["osint", "forensics", "scraping", "triage"]
|
|
14
|
-
dependencies = [
|
|
15
|
-
"httpx>=0.27",
|
|
16
|
-
"typer>=0.12",
|
|
17
|
-
"rich>=13.7",
|
|
18
|
-
"beautifulsoup4>=4.12",
|
|
19
|
-
"lxml>=5.1",
|
|
20
|
-
"dnspython>=2.6",
|
|
21
|
-
"python-whois>=0.9",
|
|
22
|
-
"ipwhois>=1.2",
|
|
23
|
-
"exifread>=3.0",
|
|
24
|
-
"filetype>=1.2",
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"pytest
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.25"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "reconkit"
|
|
7
|
+
version = "0.2.1"
|
|
8
|
+
description = "Evidence collection, provenance, and preservation utilities for authorized investigations."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "Proprietary Software License — Free Use, No Modification" }
|
|
12
|
+
authors = [{ name = "reconkit" }]
|
|
13
|
+
keywords = ["osint", "forensics", "scraping", "triage"]
|
|
14
|
+
dependencies = [
|
|
15
|
+
"httpx>=0.27",
|
|
16
|
+
"typer>=0.12",
|
|
17
|
+
"rich>=13.7",
|
|
18
|
+
"beautifulsoup4>=4.12",
|
|
19
|
+
"lxml>=5.1",
|
|
20
|
+
"dnspython>=2.6",
|
|
21
|
+
"python-whois>=0.9",
|
|
22
|
+
"ipwhois>=1.2",
|
|
23
|
+
"exifread>=3.0",
|
|
24
|
+
"filetype>=1.2",
|
|
25
|
+
"cryptography>=42",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
dev = [
|
|
30
|
+
"build>=1.2",
|
|
31
|
+
"twine>=5.1",
|
|
32
|
+
"pytest>=8.0",
|
|
33
|
+
"pytest-asyncio>=0.23",
|
|
34
|
+
"ruff>=0.4",
|
|
35
|
+
"mypy>=1.10",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.scripts]
|
|
39
|
+
reconkit = "reconkit.cli:app"
|
|
40
|
+
|
|
41
|
+
[tool.hatch.build.targets.wheel]
|
|
42
|
+
packages = ["src/reconkit"]
|
|
43
|
+
|
|
44
|
+
[tool.pytest.ini_options]
|
|
45
|
+
addopts = "-q"
|
|
46
|
+
testpaths = ["tests"]
|
|
47
|
+
|
|
48
|
+
[tool.ruff]
|
|
49
|
+
line-length = 100
|
|
50
|
+
|
|
51
|
+
[tool.mypy]
|
|
52
|
+
python_version = "3.10"
|
|
53
|
+
warn_return_any = true
|
|
54
|
+
warn_unused_ignores = true
|
|
55
|
+
no_implicit_optional = true
|
|
56
|
+
strict_optional = true
|
|
57
|
+
ignore_missing_imports = true
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
"""reconkit.
|
|
2
|
-
|
|
3
|
-
Public API: Noir Stack / Hexarch / Judicium surface lives under `reconkit.noir`.
|
|
4
|
-
Internal modules remain available but are not the supported public interface.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
__version__ = "0.1
|
|
8
|
-
|
|
9
|
-
from reconkit.noir.primitives import ( # noqa: E402
|
|
10
|
-
EvidenceArtifact,
|
|
11
|
-
EvidenceBundle,
|
|
12
|
-
ProvenanceRecord,
|
|
13
|
-
VerificationResult,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
__all__ = [
|
|
17
|
-
"__version__",
|
|
18
|
-
"EvidenceArtifact",
|
|
19
|
-
"EvidenceBundle",
|
|
20
|
-
"ProvenanceRecord",
|
|
21
|
-
"VerificationResult",
|
|
22
|
-
]
|
|
1
|
+
"""reconkit.
|
|
2
|
+
|
|
3
|
+
Public API: Noir Stack / Hexarch / Judicium surface lives under `reconkit.noir`.
|
|
4
|
+
Internal modules remain available but are not the supported public interface.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
__version__ = "0.2.1"
|
|
8
|
+
|
|
9
|
+
from reconkit.noir.primitives import ( # noqa: E402
|
|
10
|
+
EvidenceArtifact,
|
|
11
|
+
EvidenceBundle,
|
|
12
|
+
ProvenanceRecord,
|
|
13
|
+
VerificationResult,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"__version__",
|
|
18
|
+
"EvidenceArtifact",
|
|
19
|
+
"EvidenceBundle",
|
|
20
|
+
"ProvenanceRecord",
|
|
21
|
+
"VerificationResult",
|
|
22
|
+
]
|