Skip to content
Merged
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
44 changes: 44 additions & 0 deletions Domains/cli/MiniProjects/FileHashr/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# FileHashr

**Contributor:** bavi404

## Description
Simple CLI tool to generate cryptographic hashes (SHA256 by default) for files or stdin. Useful for integrity checks and quick verifications.

## Features
- Hash a file or standard input
- Algorithms: sha256 (default), sha1, md5
- Output plain hash with optional filename

## Usage
```bash
# Hash a file (sha256)
python3 filehashr.py path/to/file

# Specify algorithm
python3 filehashr.py --algo sha1 path/to/file

# Read from stdin
echo "hello" | python3 filehashr.py --algo md5
```

## Arguments
- `path` (optional): Path to the file. If omitted, reads from stdin.
- `--algo` / `-a`: Hash algorithm (`sha256`, `sha1`, `md5`). Default: `sha256`.
- `--label` / `-l`: Append filename label to output when hashing a file.

## Requirements
- Python 3.8+
- No external dependencies

## Examples
```bash
python3 filehashr.py sample.txt
python3 filehashr.py -a md5 -l sample.txt
cat sample.txt | python3 filehashr.py -a sha1
```

## Notes
- For large files, the script streams in chunks to minimize memory usage.


94 changes: 94 additions & 0 deletions Domains/cli/MiniProjects/FileHashr/filehashr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#!/usr/bin/env python3
import argparse
import hashlib
import sys
from pathlib import Path


CHUNK_SIZE_BYTES = 1024 * 1024 # 1 MiB


def create_hasher(algorithm: str) -> "hashlib._Hash":
normalized = algorithm.lower()
if normalized not in {"sha256", "sha1", "md5"}:
raise ValueError(f"Unsupported algorithm: {algorithm}. Use sha256, sha1, or md5.")
return getattr(hashlib, normalized)()


def hash_file(path: Path, algorithm: str) -> str:
hasher = create_hasher(algorithm)
with path.open("rb") as file_handle:
while True:
chunk = file_handle.read(CHUNK_SIZE_BYTES)
if not chunk:
break
hasher.update(chunk)
return hasher.hexdigest()


def hash_stdin(algorithm: str) -> str:
hasher = create_hasher(algorithm)
stdin_buffer = getattr(sys.stdin, "buffer", sys.stdin)
while True:
chunk = stdin_buffer.read(CHUNK_SIZE_BYTES)
if not chunk:
break
hasher.update(chunk)
return hasher.hexdigest()


def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Generate cryptographic hash for a file or stdin (default: sha256)",
)
parser.add_argument(
"path",
nargs="?",
type=Path,
help="Path to file. If omitted, reads from stdin",
)
parser.add_argument(
"-a",
"--algo",
default="sha256",
choices=["sha256", "sha1", "md5"],
help="Hash algorithm to use",
)
parser.add_argument(
"-l",
"--label",
action="store_true",
help="Append filename to output when hashing a file",
)
return parser.parse_args()


def main() -> int:
args = parse_args()
try:
if args.path is None:
digest = hash_stdin(args.algo)
print(digest)
return 0

if not args.path.exists() or not args.path.is_file():
print(f"Error: File not found: {args.path}", file=sys.stderr)
return 2

digest = hash_file(args.path, args.algo)
if args.label:
print(f"{digest} {args.path}")
else:
print(digest)
return 0
except BrokenPipeError:
return 0
except Exception as exc: # deliberate broad to present clear CLI error
print(f"Error: {exc}", file=sys.stderr)
return 1


if __name__ == "__main__":
raise SystemExit(main())


Loading