# SPDX-License-Identifier: Apache-2.0 # Copyright (c) 2025 Allaun """Standard Hashing Tool for NoDupeLabs. Provides cryptographic hashing capabilities as a tool. """ import sys import os from typing import List, Dict, Any, Optional, Callable # Standard High-Assurance Import Pattern for standalone tools try: from nodupe.core.tool_system.base import Tool, ToolMetadata from .hasher_logic import FileHasher except (ImportError, ValueError): # Stand-alone mode: resolve parent paths manually current_dir = os.path.dirname(os.path.abspath(__file__)) project_root = os.path.abspath(os.path.join(current_dir, "../../../")) if project_root not in sys.path: sys.path.insert(0, project_root) from nodupe.core.tool_system.base import Tool, ToolMetadata from nodupe.tools.hashing.hasher_logic import FileHasher class StandardHashingTool(Tool): """Standard hashing tool using hashlib (ISO/IEC 10118-3 Compliant).""" @property def name(self) -> str: """Get tool name. Returns: Tool name identifier """ return "hashing_standard" @property def version(self) -> str: """Get tool version. Returns: Version string in semver format """ return "1.0.0" @property def dependencies(self) -> List[str]: """Tool dependencies.""" return [] @property def metadata(self) -> ToolMetadata: """Get tool metadata (ISO 19770-2 compliant).""" return ToolMetadata( name=self.name, version=self.version, software_id=f"org.nodupe.tool.{self.name.lower()}", description="Cryptographic hashing aspect compliant with ISO/IEC 10118-3:2018", author="NoDupeLabs", license="Apache-2.0", dependencies=self.dependencies, tags=["security", "hashing", "integrity", "ISO-10118-3"] ) @property def api_methods(self) -> Dict[str, Callable[..., Any]]: """Get API methods exposed by this tool. Returns: Dictionary mapping method names to callable functions """ return { 'hash_file': self.hasher.hash_file, 'hash_string': self.hasher.hash_string, 'hash_bytes': self.hasher.hash_bytes, 'get_algorithms': self.hasher.get_available_algorithms, 'check_iso_compliance': self.check_iso_compliance } def __init__(self): """Initialize the tool.""" self.hasher = FileHasher() def check_iso_compliance(self, algorithm: str) -> Dict[str, Any]: """Verify if an algorithm is standardized under ISO/IEC 10118-3.""" iso_algorithms = { "sha224", "sha256", "sha384", "sha512", "sha512_224", "sha512_256", "sha3-224", "sha3-256", "sha3-384", "sha3-512", "shake128", "shake256", "ripemd160", "whirlpool" } normalized = algorithm.lower().replace("-", "") is_compliant = normalized in [a.replace("-", "") for a in iso_algorithms] return { "algorithm": algorithm, "is_iso_compliant": is_compliant, "standard": "ISO/IEC 10118-3:2018" if is_compliant else "N/A" } def initialize(self, container: Any) -> None: """Initialize the tool and register services.""" container.register_service('hasher_service', self.hasher) def shutdown(self) -> None: """Shutdown the tool.""" def run_standalone(self, args: List[str]) -> int: """Execute hashing in stand-alone mode.""" import argparse parser = argparse.ArgumentParser(description=self.describe_usage()) parser.add_argument("file", help="The file you want to verify") parser.add_argument("--algo", default="sha256", help="The math rule to use (default: sha256)") if not args: parser.print_help() return 0 parsed = parser.parse_args(args) try: self.hasher.set_algorithm(parsed.algo) result = self.hasher.hash_file(parsed.file) print(f"Digital Fingerprint: {result}") return 0 except Exception as e: print(f"Error: {e}") return 1 def describe_usage(self) -> str: """Plain language description.""" return ( "This component creates a unique 'digital fingerprint' for a file. " "If the file changes by even one letter, this fingerprint will change. " "It is used to prove that a backup is an exact copy of the original." ) def get_capabilities(self) -> Dict[str, Any]: """Get tool capabilities.""" return { 'algorithms': self.hasher.get_available_algorithms(), 'features': ['file_hashing', 'string_hashing', 'byte_hashing'] } def register_tool(): """Register the hashing tool.""" return StandardHashingTool() if __name__ == "__main__": plugin = StandardHashingTool() sys.exit(plugin.run_standalone(sys.argv[1:]))