exonware-xwsystem 0.0.1.411__py3-none-any.whl → 0.1.0.3__py3-none-any.whl
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.
- exonware/__init__.py +2 -1
- exonware/conf.py +2 -2
- exonware/xwsystem/__init__.py +115 -43
- exonware/xwsystem/base.py +30 -0
- exonware/xwsystem/caching/__init__.py +39 -13
- exonware/xwsystem/caching/base.py +24 -6
- exonware/xwsystem/caching/bloom_cache.py +2 -2
- exonware/xwsystem/caching/cache_manager.py +2 -1
- exonware/xwsystem/caching/conditional.py +2 -2
- exonware/xwsystem/caching/contracts.py +85 -139
- exonware/xwsystem/caching/decorators.py +6 -19
- exonware/xwsystem/caching/defs.py +2 -1
- exonware/xwsystem/caching/disk_cache.py +2 -1
- exonware/xwsystem/caching/distributed.py +2 -1
- exonware/xwsystem/caching/errors.py +2 -1
- exonware/xwsystem/caching/events.py +110 -27
- exonware/xwsystem/caching/eviction_strategies.py +2 -2
- exonware/xwsystem/caching/external_caching_python.py +701 -0
- exonware/xwsystem/caching/facade.py +253 -0
- exonware/xwsystem/caching/factory.py +300 -0
- exonware/xwsystem/caching/fluent.py +14 -12
- exonware/xwsystem/caching/integrity.py +21 -6
- exonware/xwsystem/caching/lfu_cache.py +2 -1
- exonware/xwsystem/caching/lfu_optimized.py +18 -6
- exonware/xwsystem/caching/lru_cache.py +7 -4
- exonware/xwsystem/caching/memory_bounded.py +2 -2
- exonware/xwsystem/caching/metrics_exporter.py +2 -2
- exonware/xwsystem/caching/observable_cache.py +2 -2
- exonware/xwsystem/caching/pluggable_cache.py +2 -2
- exonware/xwsystem/caching/rate_limiter.py +2 -2
- exonware/xwsystem/caching/read_through.py +2 -2
- exonware/xwsystem/caching/secure_cache.py +81 -28
- exonware/xwsystem/caching/serializable.py +9 -7
- exonware/xwsystem/caching/stats.py +2 -2
- exonware/xwsystem/caching/tagging.py +2 -2
- exonware/xwsystem/caching/ttl_cache.py +4 -3
- exonware/xwsystem/caching/two_tier_cache.py +6 -3
- exonware/xwsystem/caching/utils.py +30 -12
- exonware/xwsystem/caching/validation.py +2 -2
- exonware/xwsystem/caching/warming.py +6 -3
- exonware/xwsystem/caching/write_behind.py +15 -6
- exonware/xwsystem/config/__init__.py +11 -17
- exonware/xwsystem/config/base.py +5 -5
- exonware/xwsystem/config/contracts.py +93 -153
- exonware/xwsystem/config/defaults.py +3 -2
- exonware/xwsystem/config/defs.py +3 -2
- exonware/xwsystem/config/errors.py +2 -5
- exonware/xwsystem/config/logging.py +12 -8
- exonware/xwsystem/config/logging_setup.py +3 -2
- exonware/xwsystem/config/performance.py +73 -391
- exonware/xwsystem/config/performance_modes.py +9 -8
- exonware/xwsystem/config/version_manager.py +1 -0
- exonware/xwsystem/config.py +27 -0
- exonware/xwsystem/console/__init__.py +53 -0
- exonware/xwsystem/console/base.py +133 -0
- exonware/xwsystem/console/cli/__init__.py +61 -0
- exonware/xwsystem/{cli → console/cli}/args.py +27 -24
- exonware/xwsystem/{cli → console/cli}/base.py +18 -87
- exonware/xwsystem/{cli → console/cli}/colors.py +15 -13
- exonware/xwsystem/console/cli/console.py +98 -0
- exonware/xwsystem/{cli → console/cli}/contracts.py +51 -69
- exonware/xwsystem/console/cli/defs.py +87 -0
- exonware/xwsystem/console/cli/encoding.py +69 -0
- exonware/xwsystem/{cli → console/cli}/errors.py +8 -3
- exonware/xwsystem/console/cli/event_logger.py +166 -0
- exonware/xwsystem/{cli → console/cli}/progress.py +25 -21
- exonware/xwsystem/{cli → console/cli}/prompts.py +3 -2
- exonware/xwsystem/{cli → console/cli}/tables.py +27 -24
- exonware/xwsystem/console/contracts.py +113 -0
- exonware/xwsystem/console/defs.py +154 -0
- exonware/xwsystem/console/errors.py +34 -0
- exonware/xwsystem/console/event_logger.py +385 -0
- exonware/xwsystem/console/writer.py +132 -0
- exonware/xwsystem/contracts.py +28 -0
- exonware/xwsystem/data_structures/__init__.py +23 -0
- exonware/xwsystem/data_structures/trie.py +34 -0
- exonware/xwsystem/data_structures/union_find.py +144 -0
- exonware/xwsystem/defs.py +17 -0
- exonware/xwsystem/errors.py +23 -0
- exonware/xwsystem/facade.py +62 -0
- exonware/xwsystem/http_client/__init__.py +22 -1
- exonware/xwsystem/http_client/advanced_client.py +8 -5
- exonware/xwsystem/http_client/base.py +3 -2
- exonware/xwsystem/http_client/client.py +7 -4
- exonware/xwsystem/http_client/contracts.py +42 -56
- exonware/xwsystem/http_client/defs.py +2 -1
- exonware/xwsystem/http_client/errors.py +2 -1
- exonware/xwsystem/http_client/facade.py +156 -0
- exonware/xwsystem/io/__init__.py +22 -3
- exonware/xwsystem/io/archive/__init__.py +8 -2
- exonware/xwsystem/io/archive/archive.py +1 -1
- exonware/xwsystem/io/archive/archive_files.py +4 -7
- exonware/xwsystem/io/archive/archivers.py +120 -10
- exonware/xwsystem/io/archive/base.py +4 -5
- exonware/xwsystem/io/archive/codec_integration.py +1 -2
- exonware/xwsystem/io/archive/compression.py +1 -2
- exonware/xwsystem/io/archive/facade.py +263 -0
- exonware/xwsystem/io/archive/formats/__init__.py +2 -3
- exonware/xwsystem/io/archive/formats/brotli_format.py +20 -7
- exonware/xwsystem/io/archive/formats/lz4_format.py +20 -7
- exonware/xwsystem/io/archive/formats/rar.py +11 -5
- exonware/xwsystem/io/archive/formats/sevenzip.py +12 -6
- exonware/xwsystem/io/archive/formats/squashfs_format.py +1 -2
- exonware/xwsystem/io/archive/formats/tar.py +52 -7
- exonware/xwsystem/io/archive/formats/wim_format.py +11 -5
- exonware/xwsystem/io/archive/formats/zip.py +1 -2
- exonware/xwsystem/io/archive/formats/zpaq_format.py +1 -2
- exonware/xwsystem/io/archive/formats/zstandard.py +20 -7
- exonware/xwsystem/io/base.py +119 -115
- exonware/xwsystem/io/codec/__init__.py +4 -2
- exonware/xwsystem/io/codec/base.py +19 -13
- exonware/xwsystem/io/codec/contracts.py +59 -2
- exonware/xwsystem/io/codec/registry.py +67 -21
- exonware/xwsystem/io/common/__init__.py +1 -1
- exonware/xwsystem/io/common/atomic.py +29 -16
- exonware/xwsystem/io/common/base.py +11 -10
- exonware/xwsystem/io/common/lock.py +6 -5
- exonware/xwsystem/io/common/path_manager.py +2 -1
- exonware/xwsystem/io/common/watcher.py +1 -2
- exonware/xwsystem/io/contracts.py +301 -433
- exonware/xwsystem/io/contracts_1.py +1180 -0
- exonware/xwsystem/io/data_operations.py +279 -14
- exonware/xwsystem/io/defs.py +4 -3
- exonware/xwsystem/io/errors.py +3 -2
- exonware/xwsystem/io/facade.py +87 -61
- exonware/xwsystem/io/file/__init__.py +1 -1
- exonware/xwsystem/io/file/base.py +8 -9
- exonware/xwsystem/io/file/conversion.py +2 -3
- exonware/xwsystem/io/file/file.py +61 -18
- exonware/xwsystem/io/file/paged_source.py +8 -8
- exonware/xwsystem/io/file/paging/__init__.py +1 -2
- exonware/xwsystem/io/file/paging/byte_paging.py +4 -5
- exonware/xwsystem/io/file/paging/line_paging.py +2 -3
- exonware/xwsystem/io/file/paging/record_paging.py +2 -3
- exonware/xwsystem/io/file/paging/registry.py +1 -2
- exonware/xwsystem/io/file/source.py +13 -17
- exonware/xwsystem/io/filesystem/__init__.py +1 -1
- exonware/xwsystem/io/filesystem/base.py +1 -2
- exonware/xwsystem/io/filesystem/local.py +3 -4
- exonware/xwsystem/io/folder/__init__.py +1 -1
- exonware/xwsystem/io/folder/base.py +1 -2
- exonware/xwsystem/io/folder/folder.py +16 -7
- exonware/xwsystem/io/indexing/__init__.py +14 -0
- exonware/xwsystem/io/indexing/facade.py +443 -0
- exonware/xwsystem/io/path_parser.py +98 -0
- exonware/xwsystem/io/serialization/__init__.py +21 -3
- exonware/xwsystem/io/serialization/auto_serializer.py +146 -20
- exonware/xwsystem/io/serialization/base.py +84 -34
- exonware/xwsystem/io/serialization/contracts.py +50 -73
- exonware/xwsystem/io/serialization/defs.py +2 -1
- exonware/xwsystem/io/serialization/errors.py +2 -1
- exonware/xwsystem/io/serialization/flyweight.py +154 -7
- exonware/xwsystem/io/serialization/format_detector.py +15 -14
- exonware/xwsystem/io/serialization/formats/__init__.py +8 -5
- exonware/xwsystem/io/serialization/formats/binary/bson.py +15 -6
- exonware/xwsystem/io/serialization/formats/binary/cbor.py +5 -5
- exonware/xwsystem/io/serialization/formats/binary/marshal.py +5 -5
- exonware/xwsystem/io/serialization/formats/binary/msgpack.py +5 -5
- exonware/xwsystem/io/serialization/formats/binary/pickle.py +5 -5
- exonware/xwsystem/io/serialization/formats/binary/plistlib.py +5 -5
- exonware/xwsystem/io/serialization/formats/database/dbm.py +7 -7
- exonware/xwsystem/io/serialization/formats/database/shelve.py +7 -7
- exonware/xwsystem/io/serialization/formats/database/sqlite3.py +7 -7
- exonware/xwsystem/io/serialization/formats/tabular/__init__.py +27 -0
- exonware/xwsystem/io/serialization/formats/tabular/base.py +89 -0
- exonware/xwsystem/io/serialization/formats/tabular/csv.py +319 -0
- exonware/xwsystem/io/serialization/formats/tabular/df.py +249 -0
- exonware/xwsystem/io/serialization/formats/tabular/excel.py +291 -0
- exonware/xwsystem/io/serialization/formats/tabular/googlesheets.py +374 -0
- exonware/xwsystem/io/serialization/formats/text/__init__.py +1 -1
- exonware/xwsystem/io/serialization/formats/text/append_only_log.py +199 -0
- exonware/xwsystem/io/serialization/formats/text/configparser.py +5 -5
- exonware/xwsystem/io/serialization/formats/text/csv.py +7 -5
- exonware/xwsystem/io/serialization/formats/text/formdata.py +5 -5
- exonware/xwsystem/io/serialization/formats/text/json.py +65 -33
- exonware/xwsystem/io/serialization/formats/text/json5.py +8 -4
- exonware/xwsystem/io/serialization/formats/text/jsonlines.py +113 -25
- exonware/xwsystem/io/serialization/formats/text/multipart.py +5 -5
- exonware/xwsystem/io/serialization/formats/text/toml.py +8 -6
- exonware/xwsystem/io/serialization/formats/text/xml.py +25 -20
- exonware/xwsystem/io/serialization/formats/text/yaml.py +8 -6
- exonware/xwsystem/io/serialization/parsers/__init__.py +16 -0
- exonware/xwsystem/io/serialization/parsers/base.py +60 -0
- exonware/xwsystem/io/serialization/parsers/hybrid_parser.py +62 -0
- exonware/xwsystem/io/serialization/parsers/msgspec_parser.py +48 -0
- exonware/xwsystem/io/serialization/parsers/orjson_direct_parser.py +54 -0
- exonware/xwsystem/io/serialization/parsers/orjson_parser.py +62 -0
- exonware/xwsystem/io/serialization/parsers/pysimdjson_parser.py +55 -0
- exonware/xwsystem/io/serialization/parsers/rapidjson_parser.py +53 -0
- exonware/xwsystem/io/serialization/parsers/registry.py +91 -0
- exonware/xwsystem/io/serialization/parsers/standard.py +44 -0
- exonware/xwsystem/io/serialization/parsers/ujson_parser.py +53 -0
- exonware/xwsystem/io/serialization/registry.py +4 -4
- exonware/xwsystem/io/serialization/serializer.py +168 -79
- exonware/xwsystem/io/serialization/universal_options.py +367 -0
- exonware/xwsystem/io/serialization/utils/__init__.py +1 -2
- exonware/xwsystem/io/serialization/utils/path_ops.py +5 -6
- exonware/xwsystem/io/source_reader.py +223 -0
- exonware/xwsystem/io/stream/__init__.py +1 -1
- exonware/xwsystem/io/stream/async_operations.py +61 -14
- exonware/xwsystem/io/stream/base.py +1 -2
- exonware/xwsystem/io/stream/codec_io.py +6 -7
- exonware/xwsystem/ipc/__init__.py +1 -0
- exonware/xwsystem/ipc/async_fabric.py +4 -4
- exonware/xwsystem/ipc/base.py +6 -5
- exonware/xwsystem/ipc/contracts.py +41 -66
- exonware/xwsystem/ipc/defs.py +2 -1
- exonware/xwsystem/ipc/errors.py +2 -1
- exonware/xwsystem/ipc/message_queue.py +5 -2
- exonware/xwsystem/ipc/pipes.py +70 -34
- exonware/xwsystem/ipc/process_manager.py +7 -5
- exonware/xwsystem/ipc/process_pool.py +6 -5
- exonware/xwsystem/ipc/shared_memory.py +64 -11
- exonware/xwsystem/monitoring/__init__.py +7 -0
- exonware/xwsystem/monitoring/base.py +11 -8
- exonware/xwsystem/monitoring/contracts.py +86 -144
- exonware/xwsystem/monitoring/defs.py +2 -1
- exonware/xwsystem/monitoring/error_recovery.py +16 -3
- exonware/xwsystem/monitoring/errors.py +2 -1
- exonware/xwsystem/monitoring/facade.py +183 -0
- exonware/xwsystem/monitoring/memory_monitor.py +1 -0
- exonware/xwsystem/monitoring/metrics.py +1 -0
- exonware/xwsystem/monitoring/performance_manager_generic.py +7 -7
- exonware/xwsystem/monitoring/performance_monitor.py +1 -0
- exonware/xwsystem/monitoring/performance_validator.py +1 -0
- exonware/xwsystem/monitoring/system_monitor.py +6 -5
- exonware/xwsystem/monitoring/tracing.py +18 -16
- exonware/xwsystem/monitoring/tracker.py +2 -1
- exonware/xwsystem/operations/__init__.py +5 -50
- exonware/xwsystem/operations/base.py +3 -44
- exonware/xwsystem/operations/contracts.py +25 -15
- exonware/xwsystem/operations/defs.py +1 -1
- exonware/xwsystem/operations/diff.py +5 -4
- exonware/xwsystem/operations/errors.py +1 -1
- exonware/xwsystem/operations/merge.py +6 -4
- exonware/xwsystem/operations/patch.py +5 -4
- exonware/xwsystem/patterns/__init__.py +1 -0
- exonware/xwsystem/patterns/base.py +2 -1
- exonware/xwsystem/patterns/context_manager.py +2 -1
- exonware/xwsystem/patterns/contracts.py +215 -256
- exonware/xwsystem/patterns/defs.py +2 -1
- exonware/xwsystem/patterns/dynamic_facade.py +1 -0
- exonware/xwsystem/patterns/errors.py +2 -4
- exonware/xwsystem/patterns/handler_factory.py +2 -3
- exonware/xwsystem/patterns/import_registry.py +1 -0
- exonware/xwsystem/patterns/object_pool.py +1 -0
- exonware/xwsystem/patterns/registry.py +4 -43
- exonware/xwsystem/plugins/__init__.py +2 -1
- exonware/xwsystem/plugins/base.py +6 -5
- exonware/xwsystem/plugins/contracts.py +94 -158
- exonware/xwsystem/plugins/defs.py +2 -1
- exonware/xwsystem/plugins/errors.py +2 -1
- exonware/xwsystem/py.typed +3 -0
- exonware/xwsystem/query/__init__.py +36 -0
- exonware/xwsystem/query/contracts.py +56 -0
- exonware/xwsystem/query/errors.py +22 -0
- exonware/xwsystem/query/registry.py +128 -0
- exonware/xwsystem/runtime/__init__.py +2 -1
- exonware/xwsystem/runtime/base.py +4 -3
- exonware/xwsystem/runtime/contracts.py +39 -60
- exonware/xwsystem/runtime/defs.py +2 -1
- exonware/xwsystem/runtime/env.py +11 -9
- exonware/xwsystem/runtime/errors.py +2 -1
- exonware/xwsystem/runtime/reflection.py +3 -2
- exonware/xwsystem/security/__init__.py +68 -11
- exonware/xwsystem/security/audit.py +167 -0
- exonware/xwsystem/security/base.py +121 -24
- exonware/xwsystem/security/contracts.py +91 -146
- exonware/xwsystem/security/crypto.py +17 -16
- exonware/xwsystem/security/defs.py +2 -1
- exonware/xwsystem/security/errors.py +2 -1
- exonware/xwsystem/security/facade.py +321 -0
- exonware/xwsystem/security/file_security.py +330 -0
- exonware/xwsystem/security/hazmat.py +11 -8
- exonware/xwsystem/security/monitor.py +372 -0
- exonware/xwsystem/security/path_validator.py +140 -18
- exonware/xwsystem/security/policy.py +357 -0
- exonware/xwsystem/security/resource_limits.py +1 -0
- exonware/xwsystem/security/validator.py +455 -0
- exonware/xwsystem/shared/__init__.py +14 -1
- exonware/xwsystem/shared/base.py +285 -2
- exonware/xwsystem/shared/contracts.py +415 -126
- exonware/xwsystem/shared/defs.py +2 -1
- exonware/xwsystem/shared/errors.py +2 -2
- exonware/xwsystem/shared/xwobject.py +316 -0
- exonware/xwsystem/structures/__init__.py +1 -0
- exonware/xwsystem/structures/base.py +3 -2
- exonware/xwsystem/structures/circular_detector.py +15 -14
- exonware/xwsystem/structures/contracts.py +53 -76
- exonware/xwsystem/structures/defs.py +2 -1
- exonware/xwsystem/structures/errors.py +2 -1
- exonware/xwsystem/structures/tree_walker.py +2 -1
- exonware/xwsystem/threading/__init__.py +21 -4
- exonware/xwsystem/threading/async_primitives.py +6 -5
- exonware/xwsystem/threading/base.py +3 -2
- exonware/xwsystem/threading/contracts.py +87 -143
- exonware/xwsystem/threading/defs.py +2 -1
- exonware/xwsystem/threading/errors.py +2 -1
- exonware/xwsystem/threading/facade.py +175 -0
- exonware/xwsystem/threading/locks.py +1 -0
- exonware/xwsystem/threading/safe_factory.py +1 -0
- exonware/xwsystem/utils/__init__.py +40 -0
- exonware/xwsystem/utils/base.py +22 -21
- exonware/xwsystem/utils/contracts.py +50 -73
- exonware/xwsystem/utils/dt/__init__.py +19 -3
- exonware/xwsystem/utils/dt/base.py +5 -4
- exonware/xwsystem/utils/dt/contracts.py +22 -29
- exonware/xwsystem/utils/dt/defs.py +2 -1
- exonware/xwsystem/utils/dt/errors.py +2 -5
- exonware/xwsystem/utils/dt/formatting.py +88 -2
- exonware/xwsystem/utils/dt/humanize.py +10 -9
- exonware/xwsystem/utils/dt/parsing.py +56 -5
- exonware/xwsystem/utils/dt/timezone_utils.py +2 -24
- exonware/xwsystem/utils/errors.py +2 -4
- exonware/xwsystem/utils/paths.py +1 -0
- exonware/xwsystem/utils/string.py +49 -0
- exonware/xwsystem/utils/test_runner.py +139 -480
- exonware/xwsystem/utils/utils_contracts.py +2 -1
- exonware/xwsystem/utils/web.py +110 -0
- exonware/xwsystem/validation/__init__.py +25 -1
- exonware/xwsystem/validation/base.py +6 -5
- exonware/xwsystem/validation/contracts.py +29 -41
- exonware/xwsystem/validation/data_validator.py +1 -0
- exonware/xwsystem/validation/declarative.py +11 -8
- exonware/xwsystem/validation/defs.py +2 -1
- exonware/xwsystem/validation/errors.py +2 -1
- exonware/xwsystem/validation/facade.py +198 -0
- exonware/xwsystem/validation/fluent_validator.py +22 -19
- exonware/xwsystem/validation/schema_discovery.py +210 -0
- exonware/xwsystem/validation/type_safety.py +2 -1
- exonware/xwsystem/version.py +4 -4
- {exonware_xwsystem-0.0.1.411.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/METADATA +71 -4
- exonware_xwsystem-0.1.0.3.dist-info/RECORD +337 -0
- exonware/xwsystem/caching/USAGE_GUIDE.md +0 -779
- exonware/xwsystem/cli/__init__.py +0 -43
- exonware/xwsystem/cli/console.py +0 -113
- exonware/xwsystem/cli/defs.py +0 -134
- exonware/xwsystem/conf.py +0 -44
- exonware/xwsystem/security/auth.py +0 -484
- exonware_xwsystem-0.0.1.411.dist-info/RECORD +0 -274
- {exonware_xwsystem-0.0.1.411.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/WHEEL +0 -0
- {exonware_xwsystem-0.0.1.411.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
#exonware/xwsystem/src/exonware/xwsystem/security/file_security.py
|
|
4
|
+
|
|
5
|
+
Secure File Operations for xwsystem.
|
|
6
|
+
|
|
7
|
+
Provides generic file security operations that can be used by any library:
|
|
8
|
+
- Path validation (REUSES xwsystem.security.PathValidator)
|
|
9
|
+
- Resource limits (REUSES xwsystem.security.resource_limits)
|
|
10
|
+
- File permission checks
|
|
11
|
+
- Secure read/write operations
|
|
12
|
+
|
|
13
|
+
Company: eXonware.com
|
|
14
|
+
Author: Eng. Muhammad AlShehri
|
|
15
|
+
Email: connect@exonware.com
|
|
16
|
+
Version: 0.1.0.3
|
|
17
|
+
Generation Date: 26-Jan-2025
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import os
|
|
21
|
+
import stat
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import Optional, List
|
|
24
|
+
from .path_validator import PathValidator, PathSecurityError
|
|
25
|
+
from .resource_limits import get_resource_limits, GenericLimitError
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class FileSecurityError(Exception):
|
|
29
|
+
"""Base exception for file security errors."""
|
|
30
|
+
def __init__(self, message: str, path: Optional[str] = None, context: Optional[dict] = None):
|
|
31
|
+
super().__init__(message)
|
|
32
|
+
self.path = path
|
|
33
|
+
self.context = context or {}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class FileSizeLimitError(FileSecurityError):
|
|
37
|
+
"""Exception raised when file size exceeds limit."""
|
|
38
|
+
def __init__(self, message: str, size: int, limit: int, path: Optional[str] = None):
|
|
39
|
+
super().__init__(message, path=path, context={'size': size, 'limit': limit})
|
|
40
|
+
self.size = size
|
|
41
|
+
self.limit = limit
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class FileIOError(FileSecurityError):
|
|
45
|
+
"""Exception raised when file I/O operations fail."""
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class FileSecurity:
|
|
50
|
+
"""
|
|
51
|
+
Secure file operations with validation and limits.
|
|
52
|
+
|
|
53
|
+
Generic file security class that can be used by any library.
|
|
54
|
+
REUSES xwsystem security features for consistency.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def __init__(
|
|
58
|
+
self,
|
|
59
|
+
max_file_size: int = 100 * 1024 * 1024, # 100MB default
|
|
60
|
+
allowed_directories: Optional[List[str]] = None,
|
|
61
|
+
allow_absolute_paths: bool = False
|
|
62
|
+
):
|
|
63
|
+
"""
|
|
64
|
+
Initialize file security.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
max_file_size: Maximum file size in bytes
|
|
68
|
+
allowed_directories: List of allowed base directories
|
|
69
|
+
allow_absolute_paths: If True, allow absolute paths
|
|
70
|
+
"""
|
|
71
|
+
self._max_file_size = max_file_size
|
|
72
|
+
self._allowed_directories = allowed_directories
|
|
73
|
+
self._allow_absolute_paths = allow_absolute_paths
|
|
74
|
+
self._path_validator = PathValidator(
|
|
75
|
+
base_path=Path(allowed_directories[0]).resolve() if allowed_directories else None,
|
|
76
|
+
allow_absolute=allow_absolute_paths,
|
|
77
|
+
enable_cache=True
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
def validate_file_path(
|
|
81
|
+
self,
|
|
82
|
+
path: str | Path,
|
|
83
|
+
operation: str = "access",
|
|
84
|
+
check_exists: bool = False
|
|
85
|
+
) -> Path:
|
|
86
|
+
"""
|
|
87
|
+
Validate file path for security.
|
|
88
|
+
|
|
89
|
+
REUSES xwsystem PathValidator for consistency.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
path: File path to validate
|
|
93
|
+
operation: Operation being performed
|
|
94
|
+
check_exists: If True, check if file exists
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
Validated Path object
|
|
98
|
+
|
|
99
|
+
Raises:
|
|
100
|
+
PathSecurityError: If path is invalid
|
|
101
|
+
FileIOError: If file doesn't exist (when check_exists=True)
|
|
102
|
+
"""
|
|
103
|
+
path_obj = Path(path)
|
|
104
|
+
|
|
105
|
+
# Check for absolute paths
|
|
106
|
+
if path_obj.is_absolute() and not self._allow_absolute_paths:
|
|
107
|
+
raise PathSecurityError(
|
|
108
|
+
"Absolute paths are not allowed",
|
|
109
|
+
path=str(path),
|
|
110
|
+
context={'operation': operation}
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# REUSE xwsystem PathValidator
|
|
114
|
+
try:
|
|
115
|
+
validated_path = self._path_validator.validate_path(str(path), for_writing=(operation == "write"))
|
|
116
|
+
except PathSecurityError as e:
|
|
117
|
+
raise PathSecurityError(
|
|
118
|
+
f"Path validation failed: {e}",
|
|
119
|
+
path=str(path),
|
|
120
|
+
context={'operation': operation}
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
validated_path = Path(validated_path)
|
|
124
|
+
|
|
125
|
+
# Check if file exists (if required)
|
|
126
|
+
if check_exists and not validated_path.exists():
|
|
127
|
+
raise FileIOError(
|
|
128
|
+
f"File does not exist: {validated_path}",
|
|
129
|
+
path=str(validated_path)
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
return validated_path
|
|
133
|
+
|
|
134
|
+
def check_file_size(self, path: str | Path) -> int:
|
|
135
|
+
"""
|
|
136
|
+
Check file size and validate against limits.
|
|
137
|
+
|
|
138
|
+
REUSES xwsystem resource limits for consistency.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
path: File path
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
File size in bytes
|
|
145
|
+
|
|
146
|
+
Raises:
|
|
147
|
+
FileSizeLimitError: If file exceeds size limit
|
|
148
|
+
FileIOError: If file cannot be accessed
|
|
149
|
+
"""
|
|
150
|
+
path_obj = self.validate_file_path(path, operation="size_check", check_exists=True)
|
|
151
|
+
|
|
152
|
+
try:
|
|
153
|
+
size = path_obj.stat().st_size
|
|
154
|
+
except OSError as e:
|
|
155
|
+
raise FileIOError(
|
|
156
|
+
f"Cannot access file: {e}",
|
|
157
|
+
path=str(path_obj)
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# REUSE xwsystem resource limits for consistency
|
|
161
|
+
resource_limits = get_resource_limits()
|
|
162
|
+
max_file_size = min(self._max_file_size, resource_limits.max_file_size)
|
|
163
|
+
|
|
164
|
+
if size > max_file_size:
|
|
165
|
+
raise FileSizeLimitError(
|
|
166
|
+
f"File size {size} exceeds limit {max_file_size}",
|
|
167
|
+
size=size,
|
|
168
|
+
limit=max_file_size,
|
|
169
|
+
path=str(path_obj)
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
return size
|
|
173
|
+
|
|
174
|
+
def validate_file_permissions(
|
|
175
|
+
self,
|
|
176
|
+
path: str | Path,
|
|
177
|
+
required_permission: str = "read"
|
|
178
|
+
) -> None:
|
|
179
|
+
"""
|
|
180
|
+
Validate file permissions.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
path: File path
|
|
184
|
+
required_permission: Required permission ('read', 'write', 'execute')
|
|
185
|
+
|
|
186
|
+
Raises:
|
|
187
|
+
FileIOError: If file doesn't have required permissions
|
|
188
|
+
"""
|
|
189
|
+
path_obj = self.validate_file_path(path, operation="permission_check", check_exists=True)
|
|
190
|
+
|
|
191
|
+
try:
|
|
192
|
+
file_stat = path_obj.stat()
|
|
193
|
+
file_mode = file_stat.st_mode
|
|
194
|
+
except OSError as e:
|
|
195
|
+
raise FileIOError(
|
|
196
|
+
f"Cannot access file permissions: {e}",
|
|
197
|
+
path=str(path_obj)
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# Check permissions
|
|
201
|
+
if required_permission == "read":
|
|
202
|
+
if not os.access(path_obj, os.R_OK):
|
|
203
|
+
raise FileIOError(
|
|
204
|
+
"File does not have read permission",
|
|
205
|
+
path=str(path_obj)
|
|
206
|
+
)
|
|
207
|
+
elif required_permission == "write":
|
|
208
|
+
if not os.access(path_obj, os.W_OK):
|
|
209
|
+
raise FileIOError(
|
|
210
|
+
"File does not have write permission",
|
|
211
|
+
path=str(path_obj)
|
|
212
|
+
)
|
|
213
|
+
elif required_permission == "execute":
|
|
214
|
+
if not os.access(path_obj, os.X_OK):
|
|
215
|
+
raise FileIOError(
|
|
216
|
+
"File does not have execute permission",
|
|
217
|
+
path=str(path_obj)
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
def secure_read_file(self, path: str | Path) -> bytes:
|
|
221
|
+
"""
|
|
222
|
+
Securely read a file with validation.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
path: File path
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
File contents as bytes
|
|
229
|
+
|
|
230
|
+
Raises:
|
|
231
|
+
PathSecurityError: If path is invalid
|
|
232
|
+
FileSizeLimitError: If file exceeds size limit
|
|
233
|
+
FileIOError: If file cannot be read
|
|
234
|
+
"""
|
|
235
|
+
# Validate path
|
|
236
|
+
validated_path = self.validate_file_path(path, operation="read", check_exists=True)
|
|
237
|
+
|
|
238
|
+
# Check file size
|
|
239
|
+
self.check_file_size(validated_path)
|
|
240
|
+
|
|
241
|
+
# Check permissions
|
|
242
|
+
self.validate_file_permissions(validated_path, required_permission="read")
|
|
243
|
+
|
|
244
|
+
# Read file
|
|
245
|
+
try:
|
|
246
|
+
with open(validated_path, 'rb') as f:
|
|
247
|
+
return f.read()
|
|
248
|
+
except OSError as e:
|
|
249
|
+
raise FileIOError(
|
|
250
|
+
f"Cannot read file: {e}",
|
|
251
|
+
path=str(validated_path)
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
def secure_write_file(
|
|
255
|
+
self,
|
|
256
|
+
path: str | Path,
|
|
257
|
+
data: bytes,
|
|
258
|
+
check_size: bool = True
|
|
259
|
+
) -> None:
|
|
260
|
+
"""
|
|
261
|
+
Securely write a file with validation.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
path: File path
|
|
265
|
+
data: Data to write
|
|
266
|
+
check_size: If True, check data size against limit
|
|
267
|
+
|
|
268
|
+
Raises:
|
|
269
|
+
PathSecurityError: If path is invalid
|
|
270
|
+
FileSizeLimitError: If data exceeds size limit
|
|
271
|
+
FileIOError: If file cannot be written
|
|
272
|
+
"""
|
|
273
|
+
# Validate path
|
|
274
|
+
validated_path = self.validate_file_path(path, operation="write")
|
|
275
|
+
|
|
276
|
+
# Check data size
|
|
277
|
+
if check_size and len(data) > self._max_file_size:
|
|
278
|
+
raise FileSizeLimitError(
|
|
279
|
+
f"Data size {len(data)} exceeds limit {self._max_file_size}",
|
|
280
|
+
size=len(data),
|
|
281
|
+
limit=self._max_file_size,
|
|
282
|
+
path=str(validated_path)
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
# Create parent directory if needed
|
|
286
|
+
validated_path.parent.mkdir(parents=True, exist_ok=True)
|
|
287
|
+
|
|
288
|
+
# Write file
|
|
289
|
+
try:
|
|
290
|
+
with open(validated_path, 'wb') as f:
|
|
291
|
+
f.write(data)
|
|
292
|
+
except OSError as e:
|
|
293
|
+
raise FileIOError(
|
|
294
|
+
f"Cannot write file: {e}",
|
|
295
|
+
path=str(validated_path)
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
def is_safe_path(self, path: str | Path) -> bool:
|
|
299
|
+
"""
|
|
300
|
+
Check if path is safe (doesn't raise exception).
|
|
301
|
+
|
|
302
|
+
Args:
|
|
303
|
+
path: Path to check
|
|
304
|
+
|
|
305
|
+
Returns:
|
|
306
|
+
True if path is safe
|
|
307
|
+
"""
|
|
308
|
+
try:
|
|
309
|
+
self.validate_file_path(path, operation="check")
|
|
310
|
+
return True
|
|
311
|
+
except (PathSecurityError, FileIOError):
|
|
312
|
+
return False
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
# Global file security instance
|
|
316
|
+
_file_security: Optional[FileSecurity] = None
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def get_file_security() -> FileSecurity:
|
|
320
|
+
"""Get global file security instance."""
|
|
321
|
+
global _file_security
|
|
322
|
+
if _file_security is None:
|
|
323
|
+
_file_security = FileSecurity()
|
|
324
|
+
return _file_security
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def set_file_security(security: FileSecurity) -> None:
|
|
328
|
+
"""Set global file security instance."""
|
|
329
|
+
global _file_security
|
|
330
|
+
_file_security = security
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
#exonware/xwsystem/src/exonware/xwsystem/security/hazmat.py
|
|
1
2
|
"""
|
|
2
3
|
Company: eXonware.com
|
|
3
4
|
Author: Eng. Muhammad AlShehri
|
|
4
5
|
Email: connect@exonware.com
|
|
5
|
-
Version: 0.0.
|
|
6
|
+
Version: 0.1.0.3
|
|
6
7
|
Generation Date: September 04, 2025
|
|
7
8
|
|
|
8
9
|
Hazardous Materials (Hazmat) Layer - Low-level cryptographic primitives.
|
|
@@ -20,8 +21,10 @@ Features:
|
|
|
20
21
|
- Low-level cryptographic operations
|
|
21
22
|
"""
|
|
22
23
|
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
23
26
|
import os
|
|
24
|
-
from typing import Any, Optional
|
|
27
|
+
from typing import Any, Optional
|
|
25
28
|
|
|
26
29
|
from cryptography.hazmat.primitives import hashes, serialization
|
|
27
30
|
from cryptography.hazmat.primitives.asymmetric import rsa, ec, ed25519, x25519, padding
|
|
@@ -510,7 +513,7 @@ class X509Certificate:
|
|
|
510
513
|
Provides parsing, validation, and creation of X.509 certificates.
|
|
511
514
|
"""
|
|
512
515
|
|
|
513
|
-
def __init__(self, cert_data:
|
|
516
|
+
def __init__(self, cert_data: bytes | str):
|
|
514
517
|
"""
|
|
515
518
|
Initialize with certificate data.
|
|
516
519
|
|
|
@@ -576,7 +579,7 @@ class X509Certificate:
|
|
|
576
579
|
"""Get signature algorithm name."""
|
|
577
580
|
return self._cert.signature_algorithm_oid._name
|
|
578
581
|
|
|
579
|
-
def verify_signature(self, ca_cert:
|
|
582
|
+
def verify_signature(self, ca_cert: X509Certificate) -> bool:
|
|
580
583
|
"""
|
|
581
584
|
Verify certificate signature against CA certificate.
|
|
582
585
|
|
|
@@ -618,17 +621,17 @@ class X509Certificate:
|
|
|
618
621
|
return self._cert.public_bytes(serialization.Encoding.DER)
|
|
619
622
|
|
|
620
623
|
@staticmethod
|
|
621
|
-
def load_pem(pem_data:
|
|
624
|
+
def load_pem(pem_data: bytes | str) -> X509Certificate:
|
|
622
625
|
"""Load certificate from PEM data."""
|
|
623
626
|
return X509Certificate(pem_data)
|
|
624
627
|
|
|
625
628
|
@staticmethod
|
|
626
|
-
def load_der(der_data: bytes) ->
|
|
629
|
+
def load_der(der_data: bytes) -> X509Certificate:
|
|
627
630
|
"""Load certificate from DER data."""
|
|
628
631
|
return X509Certificate(der_data)
|
|
629
632
|
|
|
630
633
|
@staticmethod
|
|
631
|
-
def load_from_file(file_path: str) ->
|
|
634
|
+
def load_from_file(file_path: str) -> X509Certificate:
|
|
632
635
|
"""Load certificate from file."""
|
|
633
636
|
with open(file_path, 'rb') as f:
|
|
634
637
|
return X509Certificate(f.read())
|
|
@@ -712,5 +715,5 @@ def secure_random(length: int) -> bytes:
|
|
|
712
715
|
|
|
713
716
|
def is_cryptography_available() -> bool:
|
|
714
717
|
"""Check if cryptography library is available."""
|
|
715
|
-
# Lazy installation system
|
|
718
|
+
# Lazy installation system provides cryptography when available
|
|
716
719
|
return True
|