hypern 0.3.7__cp310-cp310-win32.whl → 0.3.9__cp310-cp310-win32.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 (37) hide show
  1. hypern/__init__.py +21 -1
  2. hypern/application.py +29 -36
  3. hypern/args_parser.py +4 -23
  4. hypern/database/sqlalchemy/__init__.py +4 -0
  5. hypern/database/{addons/sqlalchemy/__init__.py → sqlalchemy/config.py} +0 -5
  6. hypern/database/{sql → sqlx}/query.py +1 -1
  7. hypern/datastructures.py +2 -2
  8. hypern/hypern.cp310-win32.pyd +0 -0
  9. hypern/hypern.pyi +3 -5
  10. hypern/worker.py +265 -21
  11. {hypern-0.3.7.dist-info → hypern-0.3.9.dist-info}/METADATA +16 -14
  12. {hypern-0.3.7.dist-info → hypern-0.3.9.dist-info}/RECORD +19 -36
  13. {hypern-0.3.7.dist-info → hypern-0.3.9.dist-info}/WHEEL +1 -1
  14. hypern/database/addons/__init__.py +0 -5
  15. hypern/database/addons/sqlalchemy/fields/__init__.py +0 -14
  16. hypern/database/addons/sqlalchemy/fields/color.py +0 -16
  17. hypern/database/addons/sqlalchemy/fields/daterange.py +0 -23
  18. hypern/database/addons/sqlalchemy/fields/datetime.py +0 -22
  19. hypern/database/addons/sqlalchemy/fields/encrypted.py +0 -58
  20. hypern/database/addons/sqlalchemy/fields/password.py +0 -171
  21. hypern/database/addons/sqlalchemy/fields/ts_vector.py +0 -46
  22. hypern/database/addons/sqlalchemy/fields/unicode.py +0 -15
  23. hypern/database/nosql/__init__.py +0 -25
  24. hypern/database/nosql/addons/__init__.py +0 -4
  25. hypern/database/nosql/addons/color.py +0 -16
  26. hypern/database/nosql/addons/daterange.py +0 -30
  27. hypern/database/nosql/addons/encrypted.py +0 -53
  28. hypern/database/nosql/addons/password.py +0 -134
  29. hypern/database/nosql/addons/unicode.py +0 -10
  30. hypern/security.py +0 -44
  31. hypern/ws.py +0 -16
  32. /hypern/database/{addons/sqlalchemy → sqlalchemy}/repository.py +0 -0
  33. /hypern/database/{sql → sqlx}/__init__.py +0 -0
  34. /hypern/database/{sql → sqlx}/field.py +0 -0
  35. /hypern/database/{sql → sqlx}/migrate.py +0 -0
  36. /hypern/database/{sql → sqlx}/model.py +0 -0
  37. {hypern-0.3.7.dist-info → hypern-0.3.9.dist-info}/licenses/LICENSE +0 -0
@@ -1,134 +0,0 @@
1
- from mongoengine.base import BaseField
2
- import weakref
3
- from passlib.context import CryptContext
4
- import re
5
- from typing import Optional, Any
6
-
7
-
8
- class PasswordField(BaseField):
9
- """
10
- A custom password field using passlib for hashing and weakref for reference management.
11
- Supports multiple hashing schemes and automatic upgrade of hash algorithms.
12
- """
13
-
14
- # Class-level password context - shared across all instances
15
- pwd_context = CryptContext(
16
- # List of hashing schemes in order of preference
17
- schemes=["argon2", "pbkdf2_sha256", "bcrypt_sha256"],
18
- # Mark argon2 as default
19
- default="argon2",
20
- # Argon2 parameters
21
- argon2__rounds=4,
22
- argon2__memory_cost=65536,
23
- argon2__parallelism=2,
24
- # PBKDF2 parameters
25
- pbkdf2_sha256__rounds=29000,
26
- )
27
-
28
- def __init__(
29
- self,
30
- min_length: int = 8,
31
- require_number: bool = False,
32
- require_special: bool = False,
33
- require_uppercase: bool = False,
34
- require_lowercase: bool = False,
35
- **kwargs,
36
- ):
37
- """
38
- Initialize the password field with validation rules.
39
-
40
- Args:
41
- min_length: Minimum password length
42
- require_number: Require at least one number
43
- require_special: Require at least one special character
44
- require_uppercase: Require at least one uppercase letter
45
- require_lowercase: Require at least one lowercase letter
46
- """
47
- self.min_length = min_length
48
- self.require_number = require_number
49
- self.require_special = require_special
50
- self.require_uppercase = require_uppercase
51
- self.require_lowercase = require_lowercase
52
-
53
- # Use weakref to store references to parent documents
54
- self.instances = weakref.WeakKeyDictionary()
55
-
56
- kwargs["required"] = True
57
- super(PasswordField, self).__init__(**kwargs)
58
-
59
- def validate_password(self, password: str) -> tuple[bool, str]:
60
- """Validate password strength."""
61
-
62
- if len(password) < self.min_length:
63
- return False, f"Password must be at least {self.min_length} characters long"
64
-
65
- if self.require_number and not re.search(r"\d", password):
66
- return False, "Password must contain at least one number"
67
-
68
- if self.require_special and not re.search(r"[!@#$%^&*(),.?\":{}|<>]", password):
69
- return False, "Password must contain at least one special character"
70
-
71
- if self.require_uppercase and not re.search(r"[A-Z]", password):
72
- return False, "Password must contain at least one uppercase letter"
73
-
74
- if self.require_lowercase and not re.search(r"[a-z]", password):
75
- return False, "Password must contain at least one lowercase letter"
76
-
77
- return True, ""
78
-
79
- def hash_password(self, password: str) -> str:
80
- """Hash password using the configured passlib context."""
81
- return self.pwd_context.hash(password)
82
-
83
- def verify_password(self, password: str, hash: str) -> tuple[bool, Optional[str]]:
84
- """
85
- Verify password and return tuple of (is_valid, new_hash).
86
- new_hash is provided if the hash needs to be upgraded.
87
- """
88
- try:
89
- is_valid = self.pwd_context.verify(password, hash)
90
- # Check if the hash needs to be upgraded
91
- if is_valid and self.pwd_context.needs_update(hash):
92
- return True, self.hash_password(password)
93
- return is_valid, None
94
- except Exception:
95
- return False, None
96
-
97
- def __get__(self, instance, owner):
98
- """Custom getter using weakref."""
99
- if instance is None:
100
- return self
101
- return self.instances.get(instance)
102
-
103
- def __set__(self, instance, value):
104
- """Custom setter using weakref."""
105
- if value and isinstance(value, str):
106
- # Validate and hash new password
107
- is_valid, error = self.validate_password(value)
108
- if not is_valid:
109
- raise ValueError(error)
110
- hashed = self.hash_password(value)
111
- self.instances[instance] = hashed
112
- instance._data[self.name] = hashed
113
- else:
114
- # If it's already hashed or None
115
- self.instances[instance] = value
116
- instance._data[self.name] = value
117
-
118
- def to_mongo(self, value: str) -> Optional[str]:
119
- """Convert to MongoDB-compatible value."""
120
- if value is None:
121
- return None
122
- return self.hash_password(value)
123
-
124
- def to_python(self, value: str) -> str:
125
- """Convert from MongoDB to Python."""
126
- return value
127
-
128
- def prepare_query_value(self, op, value: Any) -> Optional[str]:
129
- """Prepare value for database operations."""
130
- if value is None:
131
- return None
132
- if op == "exact":
133
- return self.hash_password(value)
134
- return value
@@ -1,10 +0,0 @@
1
- from mongoengine import StringField
2
-
3
-
4
- class UnicodeField(StringField):
5
- def validate(self, value):
6
- try:
7
- value.encode("utf-8")
8
- except UnicodeEncodeError:
9
- self.error("Value must be valid Unicode")
10
- return True
hypern/security.py DELETED
@@ -1,44 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- from abc import ABC, abstractmethod
3
- from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
4
- from cryptography.hazmat.backends import default_backend
5
- from base64 import b64encode, b64decode
6
-
7
- import typing
8
-
9
-
10
- class EDEngine(ABC):
11
- @abstractmethod
12
- def encrypt(self, data: str) -> str:
13
- raise NotImplementedError("Method not implemented")
14
-
15
- @abstractmethod
16
- def decrypt(self, data: str) -> str:
17
- raise NotImplementedError("Method not implemented")
18
-
19
-
20
- class AESEngine(EDEngine):
21
- def __init__(self, secret_key: bytes, iv: bytes, padding_class: typing.Type) -> None:
22
- super().__init__()
23
- self.secret_key = secret_key
24
- self.iv = iv
25
- self.padding = padding_class(128)
26
-
27
- def encrypt(self, data: str) -> bytes:
28
- bytes_data = data.encode("utf-8")
29
- encryptor = Cipher(algorithms.AES(self.secret_key), modes.GCM(self.iv), backend=default_backend()).encryptor()
30
- padder = self.padding.padder()
31
- padded_data = padder.update(bytes_data) + padder.finalize()
32
- enctyped_data = encryptor.update(padded_data) + encryptor.finalize()
33
- tag = encryptor.tag
34
- return b64encode(tag + enctyped_data)
35
-
36
- def decrypt(self, data: bytes) -> str:
37
- data = b64decode(data)
38
- tag = data[:16]
39
- encrypted_data = data[16:]
40
- decryptor = Cipher(algorithms.AES(self.secret_key), modes.GCM(self.iv, tag), backend=default_backend()).decryptor()
41
- unpadder = self.padding.unpadder()
42
- decrypted_data = decryptor.update(encrypted_data) + decryptor.finalize()
43
- unpadded_data = unpadder.update(decrypted_data) + unpadder.finalize()
44
- return unpadded_data.decode("utf-8")
hypern/ws.py DELETED
@@ -1,16 +0,0 @@
1
- from .hypern import WebsocketRoute as WebsocketRouteInternal, WebSocketSession
2
-
3
-
4
- class WebsocketRoute:
5
- def __init__(self) -> None:
6
- self.routes = []
7
-
8
- def on(self, path):
9
- def wrapper(func):
10
- self.routes.append(WebsocketRouteInternal(path, func))
11
- return func
12
-
13
- return wrapper
14
-
15
-
16
- __all__ = ["WebsocketRoute", "WebSocketSession"]
File without changes
File without changes
File without changes
File without changes