Refactor: Improved Typing and Type Safety, Logging and Privilege Handling #106
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
This PR introduces refactoring with focus on typing, documentation improvements, and betterprivilege handling. The changes maintain full backward compatibility - all existing APIs work exactly as before, with no breaking changes to existing logic or functionality.
Key Features
Enhanced Privilege Handling
The
@user_is_root
decorator has been re-implemented with a smarter approach that doesn't rely onos.getuid() == 0
. This is important because users can have sudo access (which is required by nmap for some ops) without being root with UID=0.The decorator now:
ctypes.windll.shell32.IsUserAnAdmin()
NmapPrivilegeError
with clear messaging when privileges are insufficientFor Unix/Linux systems requiring elevated privileges:
For Windows systems:
Enhanced Type Safety
ParamSpec
support for Python 3.10+ andtyping_extensions
fallbackNew Exception Hierarchy
Added specialized exception classes with a clean inheritance hierarchy for better error handling:
NmapError
- Base exception class for all nmap3-related errorsNmapPrivilegeError
- Raised when nmap operations require root/administrator privilegesNmapTimeoutError
- Raised when nmap commands time outNmapExecutionError
- Raised when nmap command execution failsSimplified Error Handling: All exceptions inherit from
NmapError
, allowing users to catch all nmap3-related exceptions with a single catch block:Comprehensive Logging System
Proper logging has been implemented throughout the application using Python's standard
logging
module. Each module now includes dedicated loggers for better debugging and monitoring capabilities.Logged Operations Include:
Benefits:
Improved Documentation
Code Simplification & Maintenance
require_root()
method that was superseded by the improved privilege detection approachTechnical Improvements
Typing Enhancements
Added appropriate type hints for all public methods and classes. Validated typing with
mypy
for 3.6+ compatibility.Decorator Improvements
The
@requires_root_privilege
(aliasuser_is_root
) decorator has been improved to not rely onos.getuid() == 0
. This is crucial because users can have sudo access (which nmap requires) without being root with UID=0. The decorator now properly preserves function signatures and switches from returning an error dictionary to raising aNmapPrivilegeError
when privilege requirements aren't met, which is more idiomatic in Python.Why not
os.getuid() == 0
?Many users have
sudo
access to run nmap with elevated privileges without actually being the root user (UID=0). The old approach would incorrectly reject these users. The new implementation:ctypes.windll.shell32.IsUserAnAdmin()
to detect administrator privilegesThis approach allows the library to work correctly whether users run their scripts with
sudo
or configurenmap.nmaptool = f"sudo {nmap.nmaptool}"
manually.Cross-Platform Compatibility
os.getuid() == 0
)ctypes.windll.shell32.IsUserAnAdmin()
NmapError
base class allows catching all package exceptions with a single catch blockBackward Compatibility & Non-Breaking Changes
This refactoring as tried as much as possible to not introduce any breaking changes. All existing APIs and functionality remain unchanged:
Only Minor Redundancy Removal: The
require_root()
method was commented out as it became redundant. This method was not widely used and users can now handle privilege elevation manually:Users can also use external privilege escalation libraries for more advanced scenarios.
Files Changed
nmap3/nmap3.py
- Enhanced type annotations and documentation (commented out redundantrequire_root()
method)nmap3/utils.py
- Version-aware typing utilities and improved privilege detectionnmap3/nmapparser.py
- Type annotations for parser functionsnmap3/exceptions.py
- New exception hierarchy:NmapError
base class with specialized subclasses (NmapPrivilegeError
,NmapTimeoutError
,NmapExecutionError
)Support & Compatibility
No Breaking Changes: The refactoring maintains all existing functionality while adding new capabilities. Enhanced subprocess cleanup includes proper error handling, timeout management, and cleanup procedures.
Legacy Support: Existing codebases will continue to work without any modifications. The only change is that the redundant
require_root()
method is commented out (but still visible in the source for reference), as users can now manually handle privilege elevation when needed.