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.
Files changed (342) hide show
  1. exonware/__init__.py +2 -1
  2. exonware/conf.py +2 -2
  3. exonware/xwsystem/__init__.py +115 -43
  4. exonware/xwsystem/base.py +30 -0
  5. exonware/xwsystem/caching/__init__.py +39 -13
  6. exonware/xwsystem/caching/base.py +24 -6
  7. exonware/xwsystem/caching/bloom_cache.py +2 -2
  8. exonware/xwsystem/caching/cache_manager.py +2 -1
  9. exonware/xwsystem/caching/conditional.py +2 -2
  10. exonware/xwsystem/caching/contracts.py +85 -139
  11. exonware/xwsystem/caching/decorators.py +6 -19
  12. exonware/xwsystem/caching/defs.py +2 -1
  13. exonware/xwsystem/caching/disk_cache.py +2 -1
  14. exonware/xwsystem/caching/distributed.py +2 -1
  15. exonware/xwsystem/caching/errors.py +2 -1
  16. exonware/xwsystem/caching/events.py +110 -27
  17. exonware/xwsystem/caching/eviction_strategies.py +2 -2
  18. exonware/xwsystem/caching/external_caching_python.py +701 -0
  19. exonware/xwsystem/caching/facade.py +253 -0
  20. exonware/xwsystem/caching/factory.py +300 -0
  21. exonware/xwsystem/caching/fluent.py +14 -12
  22. exonware/xwsystem/caching/integrity.py +21 -6
  23. exonware/xwsystem/caching/lfu_cache.py +2 -1
  24. exonware/xwsystem/caching/lfu_optimized.py +18 -6
  25. exonware/xwsystem/caching/lru_cache.py +7 -4
  26. exonware/xwsystem/caching/memory_bounded.py +2 -2
  27. exonware/xwsystem/caching/metrics_exporter.py +2 -2
  28. exonware/xwsystem/caching/observable_cache.py +2 -2
  29. exonware/xwsystem/caching/pluggable_cache.py +2 -2
  30. exonware/xwsystem/caching/rate_limiter.py +2 -2
  31. exonware/xwsystem/caching/read_through.py +2 -2
  32. exonware/xwsystem/caching/secure_cache.py +81 -28
  33. exonware/xwsystem/caching/serializable.py +9 -7
  34. exonware/xwsystem/caching/stats.py +2 -2
  35. exonware/xwsystem/caching/tagging.py +2 -2
  36. exonware/xwsystem/caching/ttl_cache.py +4 -3
  37. exonware/xwsystem/caching/two_tier_cache.py +6 -3
  38. exonware/xwsystem/caching/utils.py +30 -12
  39. exonware/xwsystem/caching/validation.py +2 -2
  40. exonware/xwsystem/caching/warming.py +6 -3
  41. exonware/xwsystem/caching/write_behind.py +15 -6
  42. exonware/xwsystem/config/__init__.py +11 -17
  43. exonware/xwsystem/config/base.py +5 -5
  44. exonware/xwsystem/config/contracts.py +93 -153
  45. exonware/xwsystem/config/defaults.py +3 -2
  46. exonware/xwsystem/config/defs.py +3 -2
  47. exonware/xwsystem/config/errors.py +2 -5
  48. exonware/xwsystem/config/logging.py +12 -8
  49. exonware/xwsystem/config/logging_setup.py +3 -2
  50. exonware/xwsystem/config/performance.py +73 -391
  51. exonware/xwsystem/config/performance_modes.py +9 -8
  52. exonware/xwsystem/config/version_manager.py +1 -0
  53. exonware/xwsystem/config.py +27 -0
  54. exonware/xwsystem/console/__init__.py +53 -0
  55. exonware/xwsystem/console/base.py +133 -0
  56. exonware/xwsystem/console/cli/__init__.py +61 -0
  57. exonware/xwsystem/{cli → console/cli}/args.py +27 -24
  58. exonware/xwsystem/{cli → console/cli}/base.py +18 -87
  59. exonware/xwsystem/{cli → console/cli}/colors.py +15 -13
  60. exonware/xwsystem/console/cli/console.py +98 -0
  61. exonware/xwsystem/{cli → console/cli}/contracts.py +51 -69
  62. exonware/xwsystem/console/cli/defs.py +87 -0
  63. exonware/xwsystem/console/cli/encoding.py +69 -0
  64. exonware/xwsystem/{cli → console/cli}/errors.py +8 -3
  65. exonware/xwsystem/console/cli/event_logger.py +166 -0
  66. exonware/xwsystem/{cli → console/cli}/progress.py +25 -21
  67. exonware/xwsystem/{cli → console/cli}/prompts.py +3 -2
  68. exonware/xwsystem/{cli → console/cli}/tables.py +27 -24
  69. exonware/xwsystem/console/contracts.py +113 -0
  70. exonware/xwsystem/console/defs.py +154 -0
  71. exonware/xwsystem/console/errors.py +34 -0
  72. exonware/xwsystem/console/event_logger.py +385 -0
  73. exonware/xwsystem/console/writer.py +132 -0
  74. exonware/xwsystem/contracts.py +28 -0
  75. exonware/xwsystem/data_structures/__init__.py +23 -0
  76. exonware/xwsystem/data_structures/trie.py +34 -0
  77. exonware/xwsystem/data_structures/union_find.py +144 -0
  78. exonware/xwsystem/defs.py +17 -0
  79. exonware/xwsystem/errors.py +23 -0
  80. exonware/xwsystem/facade.py +62 -0
  81. exonware/xwsystem/http_client/__init__.py +22 -1
  82. exonware/xwsystem/http_client/advanced_client.py +8 -5
  83. exonware/xwsystem/http_client/base.py +3 -2
  84. exonware/xwsystem/http_client/client.py +7 -4
  85. exonware/xwsystem/http_client/contracts.py +42 -56
  86. exonware/xwsystem/http_client/defs.py +2 -1
  87. exonware/xwsystem/http_client/errors.py +2 -1
  88. exonware/xwsystem/http_client/facade.py +156 -0
  89. exonware/xwsystem/io/__init__.py +22 -3
  90. exonware/xwsystem/io/archive/__init__.py +8 -2
  91. exonware/xwsystem/io/archive/archive.py +1 -1
  92. exonware/xwsystem/io/archive/archive_files.py +4 -7
  93. exonware/xwsystem/io/archive/archivers.py +120 -10
  94. exonware/xwsystem/io/archive/base.py +4 -5
  95. exonware/xwsystem/io/archive/codec_integration.py +1 -2
  96. exonware/xwsystem/io/archive/compression.py +1 -2
  97. exonware/xwsystem/io/archive/facade.py +263 -0
  98. exonware/xwsystem/io/archive/formats/__init__.py +2 -3
  99. exonware/xwsystem/io/archive/formats/brotli_format.py +20 -7
  100. exonware/xwsystem/io/archive/formats/lz4_format.py +20 -7
  101. exonware/xwsystem/io/archive/formats/rar.py +11 -5
  102. exonware/xwsystem/io/archive/formats/sevenzip.py +12 -6
  103. exonware/xwsystem/io/archive/formats/squashfs_format.py +1 -2
  104. exonware/xwsystem/io/archive/formats/tar.py +52 -7
  105. exonware/xwsystem/io/archive/formats/wim_format.py +11 -5
  106. exonware/xwsystem/io/archive/formats/zip.py +1 -2
  107. exonware/xwsystem/io/archive/formats/zpaq_format.py +1 -2
  108. exonware/xwsystem/io/archive/formats/zstandard.py +20 -7
  109. exonware/xwsystem/io/base.py +119 -115
  110. exonware/xwsystem/io/codec/__init__.py +4 -2
  111. exonware/xwsystem/io/codec/base.py +19 -13
  112. exonware/xwsystem/io/codec/contracts.py +59 -2
  113. exonware/xwsystem/io/codec/registry.py +67 -21
  114. exonware/xwsystem/io/common/__init__.py +1 -1
  115. exonware/xwsystem/io/common/atomic.py +29 -16
  116. exonware/xwsystem/io/common/base.py +11 -10
  117. exonware/xwsystem/io/common/lock.py +6 -5
  118. exonware/xwsystem/io/common/path_manager.py +2 -1
  119. exonware/xwsystem/io/common/watcher.py +1 -2
  120. exonware/xwsystem/io/contracts.py +301 -433
  121. exonware/xwsystem/io/contracts_1.py +1180 -0
  122. exonware/xwsystem/io/data_operations.py +279 -14
  123. exonware/xwsystem/io/defs.py +4 -3
  124. exonware/xwsystem/io/errors.py +3 -2
  125. exonware/xwsystem/io/facade.py +87 -61
  126. exonware/xwsystem/io/file/__init__.py +1 -1
  127. exonware/xwsystem/io/file/base.py +8 -9
  128. exonware/xwsystem/io/file/conversion.py +2 -3
  129. exonware/xwsystem/io/file/file.py +61 -18
  130. exonware/xwsystem/io/file/paged_source.py +8 -8
  131. exonware/xwsystem/io/file/paging/__init__.py +1 -2
  132. exonware/xwsystem/io/file/paging/byte_paging.py +4 -5
  133. exonware/xwsystem/io/file/paging/line_paging.py +2 -3
  134. exonware/xwsystem/io/file/paging/record_paging.py +2 -3
  135. exonware/xwsystem/io/file/paging/registry.py +1 -2
  136. exonware/xwsystem/io/file/source.py +13 -17
  137. exonware/xwsystem/io/filesystem/__init__.py +1 -1
  138. exonware/xwsystem/io/filesystem/base.py +1 -2
  139. exonware/xwsystem/io/filesystem/local.py +3 -4
  140. exonware/xwsystem/io/folder/__init__.py +1 -1
  141. exonware/xwsystem/io/folder/base.py +1 -2
  142. exonware/xwsystem/io/folder/folder.py +16 -7
  143. exonware/xwsystem/io/indexing/__init__.py +14 -0
  144. exonware/xwsystem/io/indexing/facade.py +443 -0
  145. exonware/xwsystem/io/path_parser.py +98 -0
  146. exonware/xwsystem/io/serialization/__init__.py +21 -3
  147. exonware/xwsystem/io/serialization/auto_serializer.py +146 -20
  148. exonware/xwsystem/io/serialization/base.py +84 -34
  149. exonware/xwsystem/io/serialization/contracts.py +50 -73
  150. exonware/xwsystem/io/serialization/defs.py +2 -1
  151. exonware/xwsystem/io/serialization/errors.py +2 -1
  152. exonware/xwsystem/io/serialization/flyweight.py +154 -7
  153. exonware/xwsystem/io/serialization/format_detector.py +15 -14
  154. exonware/xwsystem/io/serialization/formats/__init__.py +8 -5
  155. exonware/xwsystem/io/serialization/formats/binary/bson.py +15 -6
  156. exonware/xwsystem/io/serialization/formats/binary/cbor.py +5 -5
  157. exonware/xwsystem/io/serialization/formats/binary/marshal.py +5 -5
  158. exonware/xwsystem/io/serialization/formats/binary/msgpack.py +5 -5
  159. exonware/xwsystem/io/serialization/formats/binary/pickle.py +5 -5
  160. exonware/xwsystem/io/serialization/formats/binary/plistlib.py +5 -5
  161. exonware/xwsystem/io/serialization/formats/database/dbm.py +7 -7
  162. exonware/xwsystem/io/serialization/formats/database/shelve.py +7 -7
  163. exonware/xwsystem/io/serialization/formats/database/sqlite3.py +7 -7
  164. exonware/xwsystem/io/serialization/formats/tabular/__init__.py +27 -0
  165. exonware/xwsystem/io/serialization/formats/tabular/base.py +89 -0
  166. exonware/xwsystem/io/serialization/formats/tabular/csv.py +319 -0
  167. exonware/xwsystem/io/serialization/formats/tabular/df.py +249 -0
  168. exonware/xwsystem/io/serialization/formats/tabular/excel.py +291 -0
  169. exonware/xwsystem/io/serialization/formats/tabular/googlesheets.py +374 -0
  170. exonware/xwsystem/io/serialization/formats/text/__init__.py +1 -1
  171. exonware/xwsystem/io/serialization/formats/text/append_only_log.py +199 -0
  172. exonware/xwsystem/io/serialization/formats/text/configparser.py +5 -5
  173. exonware/xwsystem/io/serialization/formats/text/csv.py +7 -5
  174. exonware/xwsystem/io/serialization/formats/text/formdata.py +5 -5
  175. exonware/xwsystem/io/serialization/formats/text/json.py +65 -33
  176. exonware/xwsystem/io/serialization/formats/text/json5.py +8 -4
  177. exonware/xwsystem/io/serialization/formats/text/jsonlines.py +113 -25
  178. exonware/xwsystem/io/serialization/formats/text/multipart.py +5 -5
  179. exonware/xwsystem/io/serialization/formats/text/toml.py +8 -6
  180. exonware/xwsystem/io/serialization/formats/text/xml.py +25 -20
  181. exonware/xwsystem/io/serialization/formats/text/yaml.py +8 -6
  182. exonware/xwsystem/io/serialization/parsers/__init__.py +16 -0
  183. exonware/xwsystem/io/serialization/parsers/base.py +60 -0
  184. exonware/xwsystem/io/serialization/parsers/hybrid_parser.py +62 -0
  185. exonware/xwsystem/io/serialization/parsers/msgspec_parser.py +48 -0
  186. exonware/xwsystem/io/serialization/parsers/orjson_direct_parser.py +54 -0
  187. exonware/xwsystem/io/serialization/parsers/orjson_parser.py +62 -0
  188. exonware/xwsystem/io/serialization/parsers/pysimdjson_parser.py +55 -0
  189. exonware/xwsystem/io/serialization/parsers/rapidjson_parser.py +53 -0
  190. exonware/xwsystem/io/serialization/parsers/registry.py +91 -0
  191. exonware/xwsystem/io/serialization/parsers/standard.py +44 -0
  192. exonware/xwsystem/io/serialization/parsers/ujson_parser.py +53 -0
  193. exonware/xwsystem/io/serialization/registry.py +4 -4
  194. exonware/xwsystem/io/serialization/serializer.py +168 -79
  195. exonware/xwsystem/io/serialization/universal_options.py +367 -0
  196. exonware/xwsystem/io/serialization/utils/__init__.py +1 -2
  197. exonware/xwsystem/io/serialization/utils/path_ops.py +5 -6
  198. exonware/xwsystem/io/source_reader.py +223 -0
  199. exonware/xwsystem/io/stream/__init__.py +1 -1
  200. exonware/xwsystem/io/stream/async_operations.py +61 -14
  201. exonware/xwsystem/io/stream/base.py +1 -2
  202. exonware/xwsystem/io/stream/codec_io.py +6 -7
  203. exonware/xwsystem/ipc/__init__.py +1 -0
  204. exonware/xwsystem/ipc/async_fabric.py +4 -4
  205. exonware/xwsystem/ipc/base.py +6 -5
  206. exonware/xwsystem/ipc/contracts.py +41 -66
  207. exonware/xwsystem/ipc/defs.py +2 -1
  208. exonware/xwsystem/ipc/errors.py +2 -1
  209. exonware/xwsystem/ipc/message_queue.py +5 -2
  210. exonware/xwsystem/ipc/pipes.py +70 -34
  211. exonware/xwsystem/ipc/process_manager.py +7 -5
  212. exonware/xwsystem/ipc/process_pool.py +6 -5
  213. exonware/xwsystem/ipc/shared_memory.py +64 -11
  214. exonware/xwsystem/monitoring/__init__.py +7 -0
  215. exonware/xwsystem/monitoring/base.py +11 -8
  216. exonware/xwsystem/monitoring/contracts.py +86 -144
  217. exonware/xwsystem/monitoring/defs.py +2 -1
  218. exonware/xwsystem/monitoring/error_recovery.py +16 -3
  219. exonware/xwsystem/monitoring/errors.py +2 -1
  220. exonware/xwsystem/monitoring/facade.py +183 -0
  221. exonware/xwsystem/monitoring/memory_monitor.py +1 -0
  222. exonware/xwsystem/monitoring/metrics.py +1 -0
  223. exonware/xwsystem/monitoring/performance_manager_generic.py +7 -7
  224. exonware/xwsystem/monitoring/performance_monitor.py +1 -0
  225. exonware/xwsystem/monitoring/performance_validator.py +1 -0
  226. exonware/xwsystem/monitoring/system_monitor.py +6 -5
  227. exonware/xwsystem/monitoring/tracing.py +18 -16
  228. exonware/xwsystem/monitoring/tracker.py +2 -1
  229. exonware/xwsystem/operations/__init__.py +5 -50
  230. exonware/xwsystem/operations/base.py +3 -44
  231. exonware/xwsystem/operations/contracts.py +25 -15
  232. exonware/xwsystem/operations/defs.py +1 -1
  233. exonware/xwsystem/operations/diff.py +5 -4
  234. exonware/xwsystem/operations/errors.py +1 -1
  235. exonware/xwsystem/operations/merge.py +6 -4
  236. exonware/xwsystem/operations/patch.py +5 -4
  237. exonware/xwsystem/patterns/__init__.py +1 -0
  238. exonware/xwsystem/patterns/base.py +2 -1
  239. exonware/xwsystem/patterns/context_manager.py +2 -1
  240. exonware/xwsystem/patterns/contracts.py +215 -256
  241. exonware/xwsystem/patterns/defs.py +2 -1
  242. exonware/xwsystem/patterns/dynamic_facade.py +1 -0
  243. exonware/xwsystem/patterns/errors.py +2 -4
  244. exonware/xwsystem/patterns/handler_factory.py +2 -3
  245. exonware/xwsystem/patterns/import_registry.py +1 -0
  246. exonware/xwsystem/patterns/object_pool.py +1 -0
  247. exonware/xwsystem/patterns/registry.py +4 -43
  248. exonware/xwsystem/plugins/__init__.py +2 -1
  249. exonware/xwsystem/plugins/base.py +6 -5
  250. exonware/xwsystem/plugins/contracts.py +94 -158
  251. exonware/xwsystem/plugins/defs.py +2 -1
  252. exonware/xwsystem/plugins/errors.py +2 -1
  253. exonware/xwsystem/py.typed +3 -0
  254. exonware/xwsystem/query/__init__.py +36 -0
  255. exonware/xwsystem/query/contracts.py +56 -0
  256. exonware/xwsystem/query/errors.py +22 -0
  257. exonware/xwsystem/query/registry.py +128 -0
  258. exonware/xwsystem/runtime/__init__.py +2 -1
  259. exonware/xwsystem/runtime/base.py +4 -3
  260. exonware/xwsystem/runtime/contracts.py +39 -60
  261. exonware/xwsystem/runtime/defs.py +2 -1
  262. exonware/xwsystem/runtime/env.py +11 -9
  263. exonware/xwsystem/runtime/errors.py +2 -1
  264. exonware/xwsystem/runtime/reflection.py +3 -2
  265. exonware/xwsystem/security/__init__.py +68 -11
  266. exonware/xwsystem/security/audit.py +167 -0
  267. exonware/xwsystem/security/base.py +121 -24
  268. exonware/xwsystem/security/contracts.py +91 -146
  269. exonware/xwsystem/security/crypto.py +17 -16
  270. exonware/xwsystem/security/defs.py +2 -1
  271. exonware/xwsystem/security/errors.py +2 -1
  272. exonware/xwsystem/security/facade.py +321 -0
  273. exonware/xwsystem/security/file_security.py +330 -0
  274. exonware/xwsystem/security/hazmat.py +11 -8
  275. exonware/xwsystem/security/monitor.py +372 -0
  276. exonware/xwsystem/security/path_validator.py +140 -18
  277. exonware/xwsystem/security/policy.py +357 -0
  278. exonware/xwsystem/security/resource_limits.py +1 -0
  279. exonware/xwsystem/security/validator.py +455 -0
  280. exonware/xwsystem/shared/__init__.py +14 -1
  281. exonware/xwsystem/shared/base.py +285 -2
  282. exonware/xwsystem/shared/contracts.py +415 -126
  283. exonware/xwsystem/shared/defs.py +2 -1
  284. exonware/xwsystem/shared/errors.py +2 -2
  285. exonware/xwsystem/shared/xwobject.py +316 -0
  286. exonware/xwsystem/structures/__init__.py +1 -0
  287. exonware/xwsystem/structures/base.py +3 -2
  288. exonware/xwsystem/structures/circular_detector.py +15 -14
  289. exonware/xwsystem/structures/contracts.py +53 -76
  290. exonware/xwsystem/structures/defs.py +2 -1
  291. exonware/xwsystem/structures/errors.py +2 -1
  292. exonware/xwsystem/structures/tree_walker.py +2 -1
  293. exonware/xwsystem/threading/__init__.py +21 -4
  294. exonware/xwsystem/threading/async_primitives.py +6 -5
  295. exonware/xwsystem/threading/base.py +3 -2
  296. exonware/xwsystem/threading/contracts.py +87 -143
  297. exonware/xwsystem/threading/defs.py +2 -1
  298. exonware/xwsystem/threading/errors.py +2 -1
  299. exonware/xwsystem/threading/facade.py +175 -0
  300. exonware/xwsystem/threading/locks.py +1 -0
  301. exonware/xwsystem/threading/safe_factory.py +1 -0
  302. exonware/xwsystem/utils/__init__.py +40 -0
  303. exonware/xwsystem/utils/base.py +22 -21
  304. exonware/xwsystem/utils/contracts.py +50 -73
  305. exonware/xwsystem/utils/dt/__init__.py +19 -3
  306. exonware/xwsystem/utils/dt/base.py +5 -4
  307. exonware/xwsystem/utils/dt/contracts.py +22 -29
  308. exonware/xwsystem/utils/dt/defs.py +2 -1
  309. exonware/xwsystem/utils/dt/errors.py +2 -5
  310. exonware/xwsystem/utils/dt/formatting.py +88 -2
  311. exonware/xwsystem/utils/dt/humanize.py +10 -9
  312. exonware/xwsystem/utils/dt/parsing.py +56 -5
  313. exonware/xwsystem/utils/dt/timezone_utils.py +2 -24
  314. exonware/xwsystem/utils/errors.py +2 -4
  315. exonware/xwsystem/utils/paths.py +1 -0
  316. exonware/xwsystem/utils/string.py +49 -0
  317. exonware/xwsystem/utils/test_runner.py +139 -480
  318. exonware/xwsystem/utils/utils_contracts.py +2 -1
  319. exonware/xwsystem/utils/web.py +110 -0
  320. exonware/xwsystem/validation/__init__.py +25 -1
  321. exonware/xwsystem/validation/base.py +6 -5
  322. exonware/xwsystem/validation/contracts.py +29 -41
  323. exonware/xwsystem/validation/data_validator.py +1 -0
  324. exonware/xwsystem/validation/declarative.py +11 -8
  325. exonware/xwsystem/validation/defs.py +2 -1
  326. exonware/xwsystem/validation/errors.py +2 -1
  327. exonware/xwsystem/validation/facade.py +198 -0
  328. exonware/xwsystem/validation/fluent_validator.py +22 -19
  329. exonware/xwsystem/validation/schema_discovery.py +210 -0
  330. exonware/xwsystem/validation/type_safety.py +2 -1
  331. exonware/xwsystem/version.py +4 -4
  332. {exonware_xwsystem-0.0.1.411.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/METADATA +71 -4
  333. exonware_xwsystem-0.1.0.3.dist-info/RECORD +337 -0
  334. exonware/xwsystem/caching/USAGE_GUIDE.md +0 -779
  335. exonware/xwsystem/cli/__init__.py +0 -43
  336. exonware/xwsystem/cli/console.py +0 -113
  337. exonware/xwsystem/cli/defs.py +0 -134
  338. exonware/xwsystem/conf.py +0 -44
  339. exonware/xwsystem/security/auth.py +0 -484
  340. exonware_xwsystem-0.0.1.411.dist-info/RECORD +0 -274
  341. {exonware_xwsystem-0.0.1.411.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/WHEEL +0 -0
  342. {exonware_xwsystem-0.0.1.411.dist-info → exonware_xwsystem-0.1.0.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,372 @@
1
+ #!/usr/bin/env python3
2
+ #exonware/xwsystem/src/exonware/xwsystem/security/monitor.py
3
+ """
4
+ Company: eXonware.com
5
+ Author: Eng. Muhammad AlShehri
6
+ Email: connect@exonware.com
7
+ Version: 0.1.0.3
8
+ Generation Date: 07-Jan-2025
9
+
10
+ Security monitor implementation for XWSystem.
11
+ Implements ISecurityMonitor protocol for security monitoring and threat detection.
12
+ """
13
+
14
+ import time
15
+ from collections import defaultdict, deque
16
+ from typing import Any, Optional
17
+ from datetime import datetime, timedelta
18
+
19
+ from .base import ASecurityMonitorBase
20
+ from .contracts import ISecurityMonitor
21
+ from .defs import SecurityLevel
22
+ from ..config.logging_setup import get_logger
23
+
24
+ logger = get_logger("xwsystem.security.monitor")
25
+
26
+
27
+ class SecurityMonitor(ASecurityMonitorBase, ISecurityMonitor):
28
+ """
29
+ Security monitor implementation.
30
+
31
+ Provides comprehensive security monitoring including:
32
+ - Intrusion detection
33
+ - Failed login monitoring
34
+ - Anomaly detection
35
+ - Security alerts
36
+ - Threat level management
37
+ """
38
+
39
+ def __init__(self, security_level: SecurityLevel = SecurityLevel.MEDIUM):
40
+ """
41
+ Initialize security monitor.
42
+
43
+ Args:
44
+ security_level: Security level for monitoring
45
+ """
46
+ super().__init__()
47
+ self.security_level = security_level
48
+ self._threat_level = SecurityLevel.MEDIUM
49
+ self._security_alerts: list[dict[str, Any]] = []
50
+ self._failed_logins: dict[str, deque] = defaultdict(lambda: deque(maxlen=100))
51
+ self._event_history: deque = deque(maxlen=1000)
52
+ self._anomaly_threshold = 5.0 # Standard deviations for anomaly detection
53
+
54
+ # Intrusion detection patterns
55
+ self._intrusion_patterns = [
56
+ "multiple_failed_logins",
57
+ "unusual_access_pattern",
58
+ "privilege_escalation_attempt",
59
+ "data_exfiltration_pattern",
60
+ "command_injection_attempt",
61
+ ]
62
+
63
+ def detect_intrusion(self, event_data: dict[str, Any]) -> bool:
64
+ """
65
+ Detect intrusion attempts.
66
+
67
+ Args:
68
+ event_data: Event data to analyze
69
+
70
+ Returns:
71
+ True if intrusion detected
72
+ """
73
+ event_type = event_data.get("type", "")
74
+ user = event_data.get("user", "")
75
+ resource = event_data.get("resource", "")
76
+ timestamp = event_data.get("timestamp", time.time())
77
+
78
+ # Check for multiple failed logins
79
+ if event_type == "failed_login":
80
+ if self.monitor_failed_logins(user, max_attempts=5):
81
+ self._add_alert("intrusion", f"Multiple failed logins detected for user: {user}")
82
+ return True
83
+
84
+ # Check for unusual access patterns
85
+ if event_type == "access":
86
+ if self._check_unusual_access(user, resource, timestamp):
87
+ self._add_alert("intrusion", f"Unusual access pattern detected for user: {user}")
88
+ return True
89
+
90
+ # Check for privilege escalation attempts
91
+ if event_type == "privilege_escalation":
92
+ self._add_alert("intrusion", f"Privilege escalation attempt detected for user: {user}")
93
+ return True
94
+
95
+ # Check for command injection patterns
96
+ if "command" in event_data:
97
+ command = str(event_data["command"])
98
+ suspicious_patterns = [";", "|", "&&", "||", "`", "$(", "<", ">"]
99
+ if any(pattern in command for pattern in suspicious_patterns):
100
+ self._add_alert("intrusion", f"Command injection pattern detected for user: {user}")
101
+ return True
102
+
103
+ # Check for data exfiltration patterns
104
+ if event_type == "data_access":
105
+ data_size = event_data.get("data_size", 0)
106
+ if data_size > 100 * 1024 * 1024: # 100MB threshold
107
+ self._add_alert("intrusion", f"Large data access detected for user: {user}")
108
+ return True
109
+
110
+ return False
111
+
112
+ def monitor_failed_logins(self, user: str, max_attempts: int = 5) -> bool:
113
+ """
114
+ Monitor failed login attempts.
115
+
116
+ Args:
117
+ user: User identifier
118
+ max_attempts: Maximum allowed attempts
119
+
120
+ Returns:
121
+ True if threshold exceeded
122
+ """
123
+ now = time.time()
124
+ user_logins = self._failed_logins[user]
125
+
126
+ # Add current failed login
127
+ user_logins.append(now)
128
+
129
+ # Check attempts in last 15 minutes
130
+ cutoff_time = now - 900 # 15 minutes
131
+ recent_attempts = [t for t in user_logins if t > cutoff_time]
132
+
133
+ if len(recent_attempts) >= max_attempts:
134
+ self._add_alert("failed_login", f"User {user} exceeded {max_attempts} failed login attempts")
135
+ return True
136
+
137
+ return False
138
+
139
+ def detect_anomaly(self, behavior_data: dict[str, Any]) -> bool:
140
+ """
141
+ Detect anomalous behavior.
142
+
143
+ Args:
144
+ behavior_data: Behavior data to analyze
145
+
146
+ Returns:
147
+ True if anomaly detected
148
+ """
149
+ behavior_type = behavior_data.get("type", "")
150
+ user = behavior_data.get("user", "")
151
+ value = behavior_data.get("value", 0)
152
+
153
+ # Store event for pattern analysis
154
+ self._event_history.append({
155
+ "type": behavior_type,
156
+ "user": user,
157
+ "value": value,
158
+ "timestamp": time.time()
159
+ })
160
+
161
+ # Simple statistical anomaly detection
162
+ if len(self._event_history) < 10:
163
+ return False # Need more data
164
+
165
+ # Get recent values for this behavior type
166
+ recent_values = [
167
+ e["value"] for e in self._event_history
168
+ if e["type"] == behavior_type and isinstance(e["value"], (int, float))
169
+ ]
170
+
171
+ if len(recent_values) < 5:
172
+ return False
173
+
174
+ # Calculate mean and standard deviation
175
+ mean = sum(recent_values) / len(recent_values)
176
+ variance = sum((x - mean) ** 2 for x in recent_values) / len(recent_values)
177
+ std_dev = variance ** 0.5
178
+
179
+ if std_dev == 0:
180
+ return False
181
+
182
+ # Check if current value is anomaly (more than threshold standard deviations)
183
+ z_score = abs((value - mean) / std_dev)
184
+
185
+ if z_score > self._anomaly_threshold:
186
+ self._add_alert("anomaly", f"Anomalous behavior detected: {behavior_type} for user: {user}")
187
+ return True
188
+
189
+ return False
190
+
191
+ def get_security_alerts(self) -> list[dict[str, Any]]:
192
+ """
193
+ Get security alerts.
194
+
195
+ Returns:
196
+ List of security alerts
197
+ """
198
+ return self._security_alerts.copy()
199
+
200
+ def clear_security_alerts(self) -> None:
201
+ """Clear security alerts."""
202
+ self._security_alerts.clear()
203
+
204
+ def get_threat_level(self) -> SecurityLevel:
205
+ """
206
+ Get current threat level.
207
+
208
+ Returns:
209
+ Current threat level
210
+ """
211
+ return self._threat_level
212
+
213
+ def set_threat_level(self, level: SecurityLevel) -> None:
214
+ """
215
+ Set threat level.
216
+
217
+ Args:
218
+ level: Threat level to set
219
+ """
220
+ self._threat_level = level
221
+ logger.info(f"Threat level set to: {level.value}")
222
+
223
+ def get_security_metrics(self) -> dict[str, Any]:
224
+ """
225
+ Get security metrics.
226
+
227
+ Returns:
228
+ Security metrics dictionary
229
+ """
230
+ now = time.time()
231
+ one_hour_ago = now - 3600
232
+ one_day_ago = now - 86400
233
+
234
+ # Count alerts by severity
235
+ alert_counts = defaultdict(int)
236
+ for alert in self._security_alerts:
237
+ alert_type = alert.get("type", "unknown")
238
+ alert_counts[alert_type] += 1
239
+
240
+ # Count failed logins
241
+ recent_failed_logins = sum(
242
+ len([t for t in logins if t > one_hour_ago])
243
+ for logins in self._failed_logins.values()
244
+ )
245
+
246
+ # Count events
247
+ recent_events = len([e for e in self._event_history if e.get("timestamp", 0) > one_hour_ago])
248
+
249
+ return {
250
+ "threat_level": self._threat_level.value,
251
+ "security_level": self.security_level.value,
252
+ "total_alerts": len(self._security_alerts),
253
+ "alert_counts": dict(alert_counts),
254
+ "failed_logins_last_hour": recent_failed_logins,
255
+ "events_last_hour": recent_events,
256
+ "total_failed_login_users": len(self._failed_logins),
257
+ "monitoring_active": True,
258
+ }
259
+
260
+ def _check_unusual_access(self, user: str, resource: str, timestamp: float) -> bool:
261
+ """
262
+ Check for unusual access patterns.
263
+
264
+ Args:
265
+ user: User identifier
266
+ resource: Resource identifier
267
+ timestamp: Access timestamp
268
+
269
+ Returns:
270
+ True if unusual access detected
271
+ """
272
+ # Get user's access history
273
+ user_accesses = [
274
+ e for e in self._event_history
275
+ if e.get("user") == user and e.get("type") == "access"
276
+ ]
277
+
278
+ if len(user_accesses) < 3:
279
+ return False # Not enough history
280
+
281
+ # Check for access outside normal hours (simple heuristic)
282
+ access_time = datetime.fromtimestamp(timestamp)
283
+ hour = access_time.hour
284
+
285
+ # Normal hours: 8 AM to 8 PM
286
+ if hour < 8 or hour > 20:
287
+ # Check if this is unusual for this user
288
+ normal_hour_accesses = [
289
+ e for e in user_accesses
290
+ if 8 <= datetime.fromtimestamp(e.get("timestamp", 0)).hour <= 20
291
+ ]
292
+
293
+ if len(normal_hour_accesses) > len(user_accesses) * 0.8:
294
+ # User usually accesses during normal hours
295
+ return True
296
+
297
+ return False
298
+
299
+ def _add_alert(self, alert_type: str, message: str) -> None:
300
+ """
301
+ Add security alert.
302
+
303
+ Args:
304
+ alert_type: Alert type
305
+ message: Alert message
306
+ """
307
+ alert = {
308
+ "type": alert_type,
309
+ "message": message,
310
+ "timestamp": time.time(),
311
+ "datetime": datetime.now().isoformat(),
312
+ "severity": self._get_alert_severity(alert_type),
313
+ }
314
+
315
+ self._security_alerts.append(alert)
316
+
317
+ # Keep only last 1000 alerts
318
+ if len(self._security_alerts) > 1000:
319
+ self._security_alerts = self._security_alerts[-1000:]
320
+
321
+ logger.warning(f"Security alert [{alert_type}]: {message}")
322
+
323
+ # Update threat level based on alerts
324
+ self._update_threat_level()
325
+
326
+ def _get_alert_severity(self, alert_type: str) -> str:
327
+ """
328
+ Get alert severity.
329
+
330
+ Args:
331
+ alert_type: Alert type
332
+
333
+ Returns:
334
+ Severity level
335
+ """
336
+ severity_map = {
337
+ "intrusion": "high",
338
+ "failed_login": "medium",
339
+ "anomaly": "medium",
340
+ "privilege_escalation": "critical",
341
+ "data_exfiltration": "high",
342
+ }
343
+ return severity_map.get(alert_type, "low")
344
+
345
+ def _update_threat_level(self) -> None:
346
+ """Update threat level based on recent alerts."""
347
+ if not self._security_alerts:
348
+ self._threat_level = SecurityLevel.MEDIUM
349
+ return
350
+
351
+ # Get alerts from last hour
352
+ now = time.time()
353
+ one_hour_ago = now - 3600
354
+ recent_alerts = [
355
+ a for a in self._security_alerts
356
+ if a.get("timestamp", 0) > one_hour_ago
357
+ ]
358
+
359
+ # Count critical/high severity alerts
360
+ critical_count = sum(
361
+ 1 for a in recent_alerts
362
+ if a.get("severity") in ["critical", "high"]
363
+ )
364
+
365
+ if critical_count >= 5:
366
+ self._threat_level = SecurityLevel.CRITICAL
367
+ elif critical_count >= 2:
368
+ self._threat_level = SecurityLevel.HIGH
369
+ elif critical_count >= 1:
370
+ self._threat_level = SecurityLevel.MEDIUM
371
+ else:
372
+ self._threat_level = SecurityLevel.LOW
@@ -1,13 +1,16 @@
1
+ #exonware/xwsystem/src/exonware/xwsystem/security/path_validator.py
1
2
  """
2
3
  Enhanced path validation and security utilities.
3
4
  """
4
5
 
5
6
  import logging
6
7
  import os
8
+ import platform
7
9
  import stat
10
+ import sys
8
11
  import tempfile
9
12
  from pathlib import Path
10
- from typing import Optional, Union
13
+ from typing import Optional
11
14
 
12
15
  logger = logging.getLogger(__name__)
13
16
 
@@ -24,7 +27,7 @@ class PathValidator:
24
27
  and other path-based attacks.
25
28
  """
26
29
 
27
- # Dangerous patterns that should be blocked
30
+ # Dangerous patterns that are blocked
28
31
  DANGEROUS_PATTERNS = [
29
32
  "..", # Directory traversal
30
33
  "~", # Home directory
@@ -39,7 +42,7 @@ class PathValidator:
39
42
  ">", # Redirects
40
43
  ]
41
44
 
42
- # System paths that should be protected
45
+ # System paths that are protected
43
46
  PROTECTED_PATHS = [
44
47
  "/etc/",
45
48
  "/bin/",
@@ -57,33 +60,70 @@ class PathValidator:
57
60
 
58
61
  def __init__(
59
62
  self,
60
- base_path: Optional[Union[str, Path]] = None,
63
+ base_path: Optional[str | Path] = None,
61
64
  allow_absolute: bool = False,
62
- max_path_length: int = 4096,
65
+ max_path_length: Optional[int] = None,
63
66
  check_existence: bool = True,
67
+ enable_cache: bool = True,
68
+ max_cache_size: int = 10000,
64
69
  ):
65
70
  """
66
- Initialize path validator.
71
+ Initialize path validator with xwsystem LRUCache for O(1) validation.
67
72
 
68
73
  Args:
69
74
  base_path: Base directory to restrict operations to
70
75
  allow_absolute: Whether to allow absolute paths
71
76
  max_path_length: Maximum allowed path length
72
77
  check_existence: Whether to check if paths exist
78
+ enable_cache: Enable validation result caching (default: True)
79
+ max_cache_size: Maximum number of cached paths (default: 10000)
73
80
  """
74
81
  self.base_path = Path(base_path).resolve() if base_path else None
75
82
  self.allow_absolute = allow_absolute
76
- self.max_path_length = max_path_length
83
+ # Platform-aware path length limits using Python's native platform module
84
+ if max_path_length is None:
85
+ system = platform.system()
86
+ if system == 'Windows':
87
+ self.max_path_length = 260 # Windows MAX_PATH (extended paths can be 32767)
88
+ elif system == 'Darwin':
89
+ self.max_path_length = 1024 # macOS typical limit
90
+ else:
91
+ self.max_path_length = 4096 # Linux PATH_MAX
92
+ else:
93
+ self.max_path_length = max_path_length
77
94
  self.check_existence = check_existence
95
+
96
+ # OPTIMIZATION: Use xwsystem's production-grade LRUCache
97
+ # Benefits: Automatic LRU eviction, thread-safe RLock, statistics, battle-tested
98
+ self.enable_cache = enable_cache
99
+ self.max_cache_size = max_cache_size
100
+
101
+ if enable_cache:
102
+ # Lazy import to avoid circular dependencies
103
+ from ..caching import create_cache
104
+ # Use flexible create_cache() to allow configuration via environment/settings
105
+ # Defaults to FunctoolsLRUCache (fastest Python cache)
106
+ self._cache = create_cache(capacity=max_cache_size, namespace='xwsystem.security', name="PathValidator")
107
+ else:
108
+ self._cache = None
109
+
110
+ logger.debug(
111
+ f"PathValidator initialized with "
112
+ f"caching={'enabled (xwsystem LRUCache)' if enable_cache else 'disabled'}, "
113
+ f"capacity={max_cache_size}"
114
+ )
78
115
 
79
116
  def validate_path(
80
117
  self,
81
- path: Union[str, Path],
118
+ path: str | Path,
82
119
  for_writing: bool = False,
83
120
  create_dirs: bool = False,
84
121
  ) -> Path:
85
122
  """
86
- Validate a path for security and constraints.
123
+ Validate a path for security and constraints with O(1) caching.
124
+
125
+ First call: validates and caches (10-50μs)
126
+ Subsequent calls: cache lookup (< 1μs) ✅
87
127
 
88
128
  Args:
89
129
  path: Path to validate
@@ -100,6 +140,16 @@ class PathValidator:
100
140
  if not path:
101
141
  raise PathSecurityError("Empty path provided")
102
142
 
143
+ # FAST PATH: Check xwsystem LRUCache first (O(1) with automatic LRU eviction)
144
+ if self.enable_cache:
145
+ cache_key = f"{self.base_path}:{path}:{for_writing}:{create_dirs}"
146
+
147
+ # xwsystem LRUCache is thread-safe with RLock (reentrant)
148
+ cached_result = self._cache.get(cache_key)
149
+ if cached_result is not None:
150
+ return cached_result # O(1) cache hit! ✅
151
+
152
+ # SLOW PATH: Validate and cache
103
153
  path_obj = Path(path)
104
154
  original_path = str(path)
105
155
 
@@ -148,6 +198,11 @@ class PathValidator:
148
198
  if self.check_existence or for_writing:
149
199
  self._check_permissions(resolved_path, for_writing, create_dirs)
150
200
 
201
+ # CACHE RESULT: Store in xwsystem LRUCache (automatic eviction!)
202
+ if self.enable_cache:
203
+ # xwsystem LRUCache handles eviction automatically (no manual pruning needed!)
204
+ self._cache.put(cache_key, resolved_path)
205
+
151
206
  return resolved_path
152
207
 
153
208
  def _check_dangerous_patterns(self, path: str) -> None:
@@ -224,6 +279,8 @@ class PathValidator:
224
279
  def is_safe_filename(self, filename: str) -> bool:
225
280
  """
226
281
  Check if a filename is safe (no path components).
282
+
283
+ Uses Python's native pathlib for cross-platform validation.
227
284
 
228
285
  Args:
229
286
  filename: Filename to check
@@ -234,19 +291,44 @@ class PathValidator:
234
291
  if not filename:
235
292
  return False
236
293
 
237
- # Check for path separators
238
- if os.sep in filename or os.altsep and os.altsep in filename:
239
- return False
240
-
241
- # Check for dangerous patterns
294
+ # Use pathlib to check if it's a simple filename (no path components)
295
+ # Path.parts will have more than 1 element if there are path separators
242
296
  try:
243
- self._check_dangerous_patterns(filename)
244
- return True
245
- except PathSecurityError:
297
+ path_obj = Path(filename)
298
+ # If filename contains path separators, parts will have multiple elements
299
+ if len(path_obj.parts) > 1:
300
+ return False
301
+
302
+ # Get just the filename part (handles cross-platform separators automatically)
303
+ name_only = path_obj.name
304
+
305
+ # Check for Windows reserved filenames using native pathlib
306
+ # Python's pathlib doesn't validate reserved names, but we can check using native methods
307
+ if platform.system() == 'Windows':
308
+ # Windows reserved names (filesystem limitation, not Python limitation)
309
+ # Python doesn't provide native validation, but pathlib.stem gives us the base name
310
+ WINDOWS_RESERVED_NAMES = {
311
+ 'CON', 'PRN', 'AUX', 'NUL',
312
+ *[f'COM{i}' for i in range(1, 10)],
313
+ *[f'LPT{i}' for i in range(1, 10)]
314
+ }
315
+ # Use pathlib's native stem property (name without extension)
316
+ name_base = path_obj.stem.upper()
317
+ if name_base in WINDOWS_RESERVED_NAMES:
318
+ return False
319
+
320
+ # Check for dangerous patterns
321
+ try:
322
+ self._check_dangerous_patterns(name_only)
323
+ return True
324
+ except PathSecurityError:
325
+ return False
326
+ except (ValueError, OSError):
327
+ # Invalid path or OS error - not safe
246
328
  return False
247
329
 
248
330
  def get_safe_path(
249
- self, base_dir: Union[str, Path], filename: str, ensure_unique: bool = True
331
+ self, base_dir: str | Path, filename: str, ensure_unique: bool = True
250
332
  ) -> Path:
251
333
  """
252
334
  Generate a safe path within a base directory.
@@ -311,3 +393,43 @@ class PathValidator:
311
393
  else:
312
394
  temp_dir = tempfile.mkdtemp(prefix=prefix, suffix=suffix, dir=base_dir)
313
395
  return Path(temp_dir)
396
+
397
+ def clear_cache(self) -> int:
398
+ """
399
+ Clear validation cache.
400
+
401
+ Returns:
402
+ Number of cached items cleared
403
+ """
404
+ if not self.enable_cache:
405
+ return 0
406
+
407
+ # xwsystem LRUCache provides size() method
408
+ count = self._cache.size()
409
+ self._cache.clear()
410
+ logger.debug(f"PathValidator cache cleared ({count} items)")
411
+ return count
412
+
413
+ def get_cache_stats(self) -> dict:
414
+ """
415
+ Get cache statistics from xwsystem LRUCache.
416
+
417
+ Returns:
418
+ Dictionary with cache stats including hits/misses/evictions
419
+ """
420
+ if not self.enable_cache:
421
+ return {'enabled': False}
422
+
423
+ # xwsystem LRUCache provides comprehensive stats!
424
+ stats = self._cache.stats()
425
+ return {
426
+ 'enabled': True,
427
+ 'name': 'PathValidator',
428
+ 'size': stats['size'],
429
+ 'capacity': stats['capacity'],
430
+ 'hits': stats['hits'],
431
+ 'misses': stats['misses'],
432
+ 'evictions': stats['evictions'],
433
+ 'hit_rate': stats['hit_rate'],
434
+ 'utilization': stats['size'] / stats['capacity'] if stats['capacity'] > 0 else 0
435
+ }