|
1 | 1 | from dataclasses import field, dataclass |
2 | 2 | from datetime import datetime, timezone |
3 | | -from typing import Optional, runtime_checkable, Protocol, TypeVar |
| 3 | +from typing import Optional |
4 | 4 |
|
| 5 | +from fastapi_api_key.domain.base import ApiKeyEntity |
5 | 6 | from fastapi_api_key.domain.errors import KeyExpired, KeyInactive |
6 | 7 | from fastapi_api_key.utils import ( |
7 | 8 | uuid_factory, |
|
10 | 11 | ) |
11 | 12 |
|
12 | 13 |
|
13 | | -@runtime_checkable |
14 | | -class ApiKeyEntity(Protocol): |
15 | | - """Protocol for an API key entity. |
16 | | -
|
17 | | - Attributes: |
18 | | - id_ (str): Unique identifier for the API key. |
19 | | - name (Optional[str]): Optional name for the API key. |
20 | | - description (Optional[str]): Optional description for the API key. |
21 | | - is_active (bool): Indicates if the API key is active. |
22 | | - expires_at (Optional[datetime]): Optional expiration datetime for the API key. |
23 | | - created_at (datetime): Datetime when the API key was created. |
24 | | - last_used_at (Optional[datetime]): Optional datetime when the API key was last used. |
25 | | - key_id (str): Public identifier part of the API key. |
26 | | - key_hash (Optional[str]): Hashed secret part of the API key. |
27 | | - key_secret_first (str): First part of the secret for display purposes. |
28 | | - key_secret_last (str): Last part of the secret for display purposes. |
29 | | - """ |
30 | | - |
31 | | - id_: str |
32 | | - name: Optional[str] |
33 | | - description: Optional[str] |
34 | | - is_active: bool |
35 | | - expires_at: Optional[datetime] |
36 | | - created_at: datetime |
37 | | - last_used_at: Optional[datetime] |
38 | | - key_id: str |
39 | | - key_hash: Optional[str] |
40 | | - _key_secret: Optional[str] |
41 | | - _key_secret_first: Optional[str] |
42 | | - _key_secret_last: Optional[str] |
43 | | - |
44 | | - @property |
45 | | - def key_secret(self) -> Optional[str]: |
46 | | - """The secret part of the API key, only available at creation time.""" |
47 | | - key_secret = self._key_secret |
48 | | - self._key_secret = None # Clear after first access |
49 | | - return key_secret |
50 | | - |
51 | | - @property |
52 | | - def key_secret_first(self) -> str: |
53 | | - """First part of the secret for display purposes/give the user a clue as to which key we are talking about.""" |
54 | | - ... |
55 | | - |
56 | | - @property |
57 | | - def key_secret_last(self) -> str: |
58 | | - """Last part of the secret for display purposes/give the user a clue as to which key we are talking about.""" |
59 | | - ... |
60 | | - |
61 | | - def full_key_secret( |
62 | | - self, |
63 | | - global_prefix: str, |
64 | | - separator: str, |
65 | | - key_secret: str, |
66 | | - ) -> str: |
67 | | - """Construct the full API key string to be given to the user.""" |
68 | | - ... |
69 | | - |
70 | | - def disable(self) -> None: |
71 | | - """Disable the API key so it cannot be used for authentication.""" |
72 | | - ... |
73 | | - |
74 | | - def enable(self) -> None: |
75 | | - """Enable the API key so it can be used for authentication.""" |
76 | | - ... |
77 | | - |
78 | | - def touch(self) -> None: |
79 | | - """Mark the key as used now. Trigger for each ensured authentication.""" |
80 | | - ... |
81 | | - |
82 | | - def ensure_can_authenticate(self) -> None: |
83 | | - """Raise domain errors if this key cannot be used for authentication. |
84 | | -
|
85 | | - Raises: |
86 | | - ApiKeyDisabledError: If the key is disabled. |
87 | | - ApiKeyExpiredError: If the key is expired. |
88 | | - """ |
89 | | - ... |
90 | | - |
91 | | - |
92 | | -D = TypeVar("D", bound=ApiKeyEntity) |
93 | | - |
94 | | - |
95 | 14 | def _normalize_datetime(value: Optional[datetime]) -> Optional[datetime]: |
96 | 15 | """Ensure datetimes are timezone-aware (UTC).""" |
97 | 16 | if value is None: |
|
0 commit comments