-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add --decrypt mode for password-protected PDFs #54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,32 @@ | ||
| import argparse | ||
|
|
||
|
|
||
| def get_arg_parser() -> argparse.ArgumentParser: | ||
| arg_parser = argparse.ArgumentParser( | ||
| description="Encrypt a PDF file with a password of your choice.", | ||
| epilog="For more information, visit: https://github.com/SUPAIDEAS/passifypdf" | ||
| ) | ||
| arg_parser.add_argument("-v", "--version", action="version", version="%(prog)s 1.0") | ||
| arg_parser.add_argument("-i", "--input", required=True, help="Path to the input PDF file to be encrypted") | ||
| arg_parser.add_argument("-o", "--output", required=True, help="Path where the encrypted PDF file will be saved") | ||
| arg_parser.add_argument("-p", "--passwd", required=True, type=str, help="Password to encrypt the PDF file with") | ||
| return arg_parser | ||
| import argparse | ||
|
|
||
|
|
||
| def get_arg_parser() -> argparse.ArgumentParser: | ||
| arg_parser = argparse.ArgumentParser( | ||
| description=( | ||
| "Encrypt a PDF file with a password, or decrypt an encrypted PDF " | ||
| "using --decrypt." | ||
| ), | ||
| epilog="For more information, visit: https://github.com/SUPAIDEAS/passifypdf", | ||
| ) | ||
| arg_parser.add_argument("-v", "--version", action="version", version="%(prog)s 1.0") | ||
| arg_parser.add_argument("-i", "--input", required=True, help="Path to the input PDF file") | ||
| arg_parser.add_argument( | ||
| "-o", | ||
| "--output", | ||
| required=True, | ||
| help="Path where the processed PDF file (encrypted/decrypted) will be saved", | ||
| ) | ||
| arg_parser.add_argument( | ||
| "-p", | ||
| "--passwd", | ||
| required=True, | ||
| type=str, | ||
| help="Password to encrypt/decrypt the PDF file", | ||
| ) | ||
| arg_parser.add_argument( | ||
| "--decrypt", | ||
| action="store_true", | ||
| help="Decrypt an encrypted PDF instead of encrypting a plain PDF", | ||
| ) | ||
| return arg_parser |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -1,14 +1,37 @@ | ||||||||
| """Core PDF encryption module.""" | ||||||||
| """Core PDF encryption and decryption module.""" | ||||||||
|
|
||||||||
| import sys | ||||||||
| from pathlib import Path | ||||||||
| from typing import Union | ||||||||
| from typing import Tuple, Union | ||||||||
|
|
||||||||
| from pypdf import PdfReader, PdfWriter | ||||||||
| from pypdf.errors import PdfReadError | ||||||||
|
|
||||||||
| from .cli import get_arg_parser | ||||||||
|
|
||||||||
|
|
||||||||
| def _load_pdf_reader(input_pdf: Union[str, Path]) -> Tuple[Path, PdfReader]: | ||||||||
| """Validate that input is an existing PDF file and return its reader.""" | ||||||||
| input_path = Path(input_pdf) | ||||||||
| if not input_path.exists(): | ||||||||
| raise FileNotFoundError(f"Input file '{input_pdf}' not found.") | ||||||||
|
|
||||||||
| if not input_path.is_file(): | ||||||||
| raise IsADirectoryError(f"Input path '{input_pdf}' is not a file.") | ||||||||
|
|
||||||||
| invalid_pdf_error = ValueError(f"Input file '{input_pdf}' is not a valid PDF file.") | ||||||||
| with input_path.open("rb") as source_file: | ||||||||
| if source_file.read(5) != b"%PDF-": | ||||||||
|
||||||||
| if source_file.read(5) != b"%PDF-": | |
| header_chunk = source_file.read(1024) | |
| if b"%PDF-" not in header_chunk: |
Copilot
AI
Mar 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_load_pdf_reader opens the input file to read the header, then PdfReader opens/parses it again. This adds redundant I/O for every call. If you keep the header check, consider doing it in a way that avoids double-opening (or just let PdfReader be the single source of truth for validity).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_load_pdf_readeris typed/structured to return(Path, PdfReader), but current callers use_, reader = ...and ignore thePath. Consider returning only thePdfReader(or using the path) to keep the helper’s contract minimal.