crypticorn 2.17.0rc7__py3-none-any.whl → 2.18.0__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 (78) hide show
  1. crypticorn/auth/client/api/admin_api.py +2 -0
  2. crypticorn/auth/client/api/auth_api.py +1417 -545
  3. crypticorn/auth/client/api/service_api.py +4 -0
  4. crypticorn/auth/client/api/user_api.py +4 -0
  5. crypticorn/auth/client/api/wallet_api.py +4 -0
  6. crypticorn/auth/client/api_client.py +5 -0
  7. crypticorn/auth/client/configuration.py +2 -2
  8. crypticorn/auth/client/models/add_wallet_request.py +1 -1
  9. crypticorn/auth/client/models/authorize_user_request.py +1 -1
  10. crypticorn/auth/client/models/create_api_key_request.py +3 -3
  11. crypticorn/auth/client/models/create_user_request.py +1 -1
  12. crypticorn/auth/client/models/get_api_keys200_response_inner.py +3 -3
  13. crypticorn/auth/client/models/list_wallets200_response_balances_inner_sale_round.py +1 -1
  14. crypticorn/auth/client/models/list_wallets200_response_balances_inner_wallet.py +1 -1
  15. crypticorn/auth/client/models/list_wallets200_response_balances_inner_wallet_vesting_wallets_inner.py +1 -1
  16. crypticorn/auth/client/models/list_wallets200_response_data_inner.py +1 -1
  17. crypticorn/auth/client/models/logout_default_response.py +1 -1
  18. crypticorn/auth/client/models/oauth_callback200_response_user.py +1 -1
  19. crypticorn/auth/client/models/refresh_token_info200_response_user_session.py +1 -1
  20. crypticorn/auth/client/models/rotate_tokens200_response.py +1 -1
  21. crypticorn/auth/client/models/token_info200_response.py +1 -1
  22. crypticorn/auth/client/models/update_user_request.py +1 -1
  23. crypticorn/auth/client/models/user_by_username200_response.py +1 -1
  24. crypticorn/auth/client/models/verify200_response.py +1 -1
  25. crypticorn/auth/client/models/verify_email200_response_auth.py +1 -1
  26. crypticorn/auth/client/models/verify_email200_response_auth_auth.py +1 -1
  27. crypticorn/auth/client/models/whoami200_response.py +1 -1
  28. crypticorn/common/__init__.py +11 -11
  29. crypticorn/common/auth.py +109 -57
  30. crypticorn/common/decorators.py +1 -1
  31. crypticorn/common/enums.py +1 -0
  32. crypticorn/common/errors.py +7 -21
  33. crypticorn/common/exceptions.py +33 -17
  34. crypticorn/common/logging.py +5 -4
  35. crypticorn/common/metrics.py +17 -5
  36. crypticorn/common/middleware.py +61 -12
  37. crypticorn/common/mixins.py +2 -1
  38. crypticorn/common/pagination.py +3 -2
  39. crypticorn/common/router/admin_router.py +17 -6
  40. crypticorn/common/router/status_router.py +3 -26
  41. crypticorn/common/utils.py +6 -6
  42. crypticorn/common/warnings.py +1 -0
  43. crypticorn/dex/client/api/admin_api.py +3 -0
  44. crypticorn/dex/client/api/signals_api.py +27 -23
  45. crypticorn/dex/client/api/status_api.py +3 -0
  46. crypticorn/dex/client/api_client.py +5 -0
  47. crypticorn/dex/client/configuration.py +2 -2
  48. crypticorn/dex/client/models/exception_detail.py +1 -1
  49. crypticorn/dex/client/models/paginated_response_signal_with_token.py +1 -1
  50. crypticorn/dex/client/models/signal_overview_stats.py +4 -2
  51. crypticorn/dex/client/models/signal_volume.py +4 -4
  52. crypticorn/dex/client/models/signal_with_token.py +2 -2
  53. crypticorn/dex/client/models/token_detail.py +1 -1
  54. crypticorn/klines/main.py +1 -1
  55. crypticorn/metrics/main.py +1 -1
  56. crypticorn/trade/client/__init__.py +1 -7
  57. crypticorn/trade/client/api/admin_api.py +0 -402
  58. crypticorn/trade/client/api/trading_actions_api.py +86 -315
  59. crypticorn/trade/client/models/__init__.py +1 -7
  60. crypticorn/trade/client/models/actions_count.py +88 -0
  61. crypticorn/trade/client/models/api_error_identifier.py +1 -0
  62. crypticorn/trade/client/models/exchange_key.py +1 -1
  63. crypticorn/trade/client/models/exchange_key_balance.py +1 -1
  64. crypticorn/trade/client/models/execution_ids.py +1 -1
  65. crypticorn/trade/client/models/notification_create.py +1 -1
  66. crypticorn/trade/client/models/post_futures_action.py +1 -1
  67. crypticorn/trade/client/models/spot_balance.py +6 -7
  68. crypticorn/trade/client/models/tpsl.py +4 -19
  69. crypticorn/trade/client/models/tpsl_create.py +6 -19
  70. {crypticorn-2.17.0rc7.dist-info → crypticorn-2.18.0.dist-info}/METADATA +1 -1
  71. {crypticorn-2.17.0rc7.dist-info → crypticorn-2.18.0.dist-info}/RECORD +75 -77
  72. crypticorn/trade/client/models/paginated_response_union_futures_trading_action_spot_trading_action.py +0 -141
  73. crypticorn/trade/client/models/paginated_response_union_futures_trading_action_spot_trading_action_data_inner.py +0 -165
  74. crypticorn/trade/client/models/spot_trading_action.py +0 -207
  75. {crypticorn-2.17.0rc7.dist-info → crypticorn-2.18.0.dist-info}/WHEEL +0 -0
  76. {crypticorn-2.17.0rc7.dist-info → crypticorn-2.18.0.dist-info}/entry_points.txt +0 -0
  77. {crypticorn-2.17.0rc7.dist-info → crypticorn-2.18.0.dist-info}/licenses/LICENSE +0 -0
  78. {crypticorn-2.17.0rc7.dist-info → crypticorn-2.18.0.dist-info}/top_level.txt +0 -0
@@ -11,10 +11,14 @@ Generated by OpenAPI Generator (https://openapi-generator.tech)
11
11
  Do not edit the class manually.
12
12
  """ # noqa: E501
13
13
 
14
+ import warnings
14
15
  from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt
15
16
  from typing import Any, Dict, List, Optional, Tuple, Union
16
17
  from typing_extensions import Annotated
17
18
 
19
+ from pydantic import Field, StrictStr
20
+ from typing import Optional
21
+ from typing_extensions import Annotated
18
22
  from crypticorn.auth.client.models.list_wallets200_response_user_value import (
19
23
  ListWallets200ResponseUserValue,
20
24
  )
@@ -11,10 +11,14 @@ Generated by OpenAPI Generator (https://openapi-generator.tech)
11
11
  Do not edit the class manually.
12
12
  """ # noqa: E501
13
13
 
14
+ import warnings
14
15
  from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt
15
16
  from typing import Any, Dict, List, Optional, Tuple, Union
16
17
  from typing_extensions import Annotated
17
18
 
19
+ from pydantic import Field, StrictStr
20
+ from typing import Any, Optional
21
+ from typing_extensions import Annotated
18
22
  from crypticorn.auth.client.models.create_user_request import CreateUserRequest
19
23
  from crypticorn.auth.client.models.resend_verification_email_request import (
20
24
  ResendVerificationEmailRequest,
@@ -11,10 +11,14 @@ Generated by OpenAPI Generator (https://openapi-generator.tech)
11
11
  Do not edit the class manually.
12
12
  """ # noqa: E501
13
13
 
14
+ import warnings
14
15
  from pydantic import validate_call, Field, StrictFloat, StrictStr, StrictInt
15
16
  from typing import Any, Dict, List, Optional, Tuple, Union
16
17
  from typing_extensions import Annotated
17
18
 
19
+ from pydantic import Field, StrictFloat, StrictInt, StrictStr
20
+ from typing import Any, Optional, Union
21
+ from typing_extensions import Annotated
18
22
  from crypticorn.auth.client.models.add_wallet200_response import AddWallet200Response
19
23
  from crypticorn.auth.client.models.add_wallet_request import AddWalletRequest
20
24
  from crypticorn.auth.client.models.list_wallets200_response import (
@@ -33,6 +33,11 @@ from crypticorn.auth.client import rest
33
33
  from crypticorn.auth.client.exceptions import (
34
34
  ApiValueError,
35
35
  ApiException,
36
+ BadRequestException,
37
+ UnauthorizedException,
38
+ ForbiddenException,
39
+ NotFoundException,
40
+ ServiceException,
36
41
  )
37
42
 
38
43
  RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]]
@@ -195,7 +195,7 @@ class Configuration:
195
195
  debug: Optional[bool] = None,
196
196
  ) -> None:
197
197
  """Constructor"""
198
- self._base_path = "https://api.crypticorn.dev/v1/auth" if host is None else host
198
+ self._base_path = "http://localhost/v1/auth" if host is None else host
199
199
  """Default Base url
200
200
  """
201
201
  self.server_index = 0 if server_index is None and host is None else server_index
@@ -528,7 +528,7 @@ class Configuration:
528
528
  """
529
529
  return [
530
530
  {
531
- "url": "https://api.crypticorn.dev/v1/auth",
531
+ "url": "http://localhost/v1/auth",
532
532
  "description": "No description provided",
533
533
  }
534
534
  ]
@@ -19,7 +19,7 @@ import json
19
19
 
20
20
  from pydantic import BaseModel, ConfigDict, Field, StrictFloat, StrictInt, StrictStr
21
21
  from typing import Any, ClassVar, Dict, List, Optional, Union
22
- from typing import Set
22
+ from typing import Optional, Set
23
23
  from typing_extensions import Self
24
24
 
25
25
 
@@ -20,7 +20,7 @@ import json
20
20
  from pydantic import BaseModel, ConfigDict, Field, StrictBool
21
21
  from typing import Any, ClassVar, Dict, List, Optional
22
22
  from typing_extensions import Annotated
23
- from typing import Set
23
+ from typing import Optional, Set
24
24
  from typing_extensions import Self
25
25
 
26
26
 
@@ -21,7 +21,7 @@ from datetime import datetime
21
21
  from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator
22
22
  from typing import Any, ClassVar, Dict, List, Optional
23
23
  from typing_extensions import Annotated
24
- from typing import Set
24
+ from typing import Optional, Set
25
25
  from typing_extensions import Self
26
26
 
27
27
 
@@ -50,7 +50,7 @@ class CreateApiKeyRequest(BaseModel):
50
50
  if i not in set(
51
51
  [
52
52
  "read:predictions",
53
- "read:dexsignals",
53
+ "read:dex:signals",
54
54
  "read:hive:model",
55
55
  "read:hive:data",
56
56
  "write:hive:model",
@@ -85,7 +85,7 @@ class CreateApiKeyRequest(BaseModel):
85
85
  ]
86
86
  ):
87
87
  raise ValueError(
88
- "each list item must be one of ('read:predictions', 'read:dexsignals', 'read:hive:model', 'read:hive:data', 'write:hive:model', 'read:trade:bots', 'write:trade:bots', 'read:trade:exchangekeys', 'write:trade:exchangekeys', 'read:trade:orders', 'read:trade:actions', 'write:trade:actions', 'read:trade:exchanges', 'read:trade:futures', 'write:trade:futures', 'read:trade:notifications', 'write:trade:notifications', 'read:trade:strategies', 'write:trade:strategies', 'read:pay:payments', 'read:pay:products', 'write:pay:products', 'read:pay:now', 'write:pay:now', 'read:metrics:marketcap', 'read:metrics:indicators', 'read:metrics:exchanges', 'read:metrics:tokens', 'read:metrics:markets', 'read:sentiment', 'read:klines', 'read:admin', 'write:admin')"
88
+ "each list item must be one of ('read:predictions', 'read:dex:signals', 'read:hive:model', 'read:hive:data', 'write:hive:model', 'read:trade:bots', 'write:trade:bots', 'read:trade:exchangekeys', 'write:trade:exchangekeys', 'read:trade:orders', 'read:trade:actions', 'write:trade:actions', 'read:trade:exchanges', 'read:trade:futures', 'write:trade:futures', 'read:trade:notifications', 'write:trade:notifications', 'read:trade:strategies', 'write:trade:strategies', 'read:pay:payments', 'read:pay:products', 'write:pay:products', 'read:pay:now', 'write:pay:now', 'read:metrics:marketcap', 'read:metrics:indicators', 'read:metrics:exchanges', 'read:metrics:tokens', 'read:metrics:markets', 'read:sentiment', 'read:klines', 'read:admin', 'write:admin')"
89
89
  )
90
90
  return value
91
91
 
@@ -20,7 +20,7 @@ import json
20
20
  from pydantic import BaseModel, ConfigDict, Field, StrictStr
21
21
  from typing import Any, ClassVar, Dict, List, Optional
22
22
  from typing_extensions import Annotated
23
- from typing import Set
23
+ from typing import Optional, Set
24
24
  from typing_extensions import Self
25
25
 
26
26
 
@@ -20,7 +20,7 @@ import json
20
20
  from datetime import datetime
21
21
  from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator
22
22
  from typing import Any, ClassVar, Dict, List, Optional
23
- from typing import Set
23
+ from typing import Optional, Set
24
24
  from typing_extensions import Self
25
25
 
26
26
 
@@ -58,7 +58,7 @@ class GetApiKeys200ResponseInner(BaseModel):
58
58
  if i not in set(
59
59
  [
60
60
  "read:predictions",
61
- "read:dexsignals",
61
+ "read:dex:signals",
62
62
  "read:hive:model",
63
63
  "read:hive:data",
64
64
  "write:hive:model",
@@ -93,7 +93,7 @@ class GetApiKeys200ResponseInner(BaseModel):
93
93
  ]
94
94
  ):
95
95
  raise ValueError(
96
- "each list item must be one of ('read:predictions', 'read:dexsignals', 'read:hive:model', 'read:hive:data', 'write:hive:model', 'read:trade:bots', 'write:trade:bots', 'read:trade:exchangekeys', 'write:trade:exchangekeys', 'read:trade:orders', 'read:trade:actions', 'write:trade:actions', 'read:trade:exchanges', 'read:trade:futures', 'write:trade:futures', 'read:trade:notifications', 'write:trade:notifications', 'read:trade:strategies', 'write:trade:strategies', 'read:pay:payments', 'read:pay:products', 'write:pay:products', 'read:pay:now', 'write:pay:now', 'read:metrics:marketcap', 'read:metrics:indicators', 'read:metrics:exchanges', 'read:metrics:tokens', 'read:metrics:markets', 'read:sentiment', 'read:klines', 'read:admin', 'write:admin')"
96
+ "each list item must be one of ('read:predictions', 'read:dex:signals', 'read:hive:model', 'read:hive:data', 'write:hive:model', 'read:trade:bots', 'write:trade:bots', 'read:trade:exchangekeys', 'write:trade:exchangekeys', 'read:trade:orders', 'read:trade:actions', 'write:trade:actions', 'read:trade:exchanges', 'read:trade:futures', 'write:trade:futures', 'read:trade:notifications', 'write:trade:notifications', 'read:trade:strategies', 'write:trade:strategies', 'read:pay:payments', 'read:pay:products', 'write:pay:products', 'read:pay:now', 'write:pay:now', 'read:metrics:marketcap', 'read:metrics:indicators', 'read:metrics:exchanges', 'read:metrics:tokens', 'read:metrics:markets', 'read:sentiment', 'read:klines', 'read:admin', 'write:admin')"
97
97
  )
98
98
  return value
99
99
 
@@ -20,7 +20,7 @@ import json
20
20
  from datetime import datetime
21
21
  from pydantic import BaseModel, ConfigDict, Field, StrictFloat, StrictInt, StrictStr
22
22
  from typing import Any, ClassVar, Dict, List, Optional, Union
23
- from typing import Set
23
+ from typing import Optional, Set
24
24
  from typing_extensions import Self
25
25
 
26
26
 
@@ -22,7 +22,7 @@ from typing import Any, ClassVar, Dict, List, Optional, Union
22
22
  from crypticorn.auth.client.models.list_wallets200_response_balances_inner_wallet_vesting_wallets_inner import (
23
23
  ListWallets200ResponseBalancesInnerWalletVestingWalletsInner,
24
24
  )
25
- from typing import Set
25
+ from typing import Optional, Set
26
26
  from typing_extensions import Self
27
27
 
28
28
 
@@ -27,7 +27,7 @@ from pydantic import (
27
27
  StrictStr,
28
28
  )
29
29
  from typing import Any, ClassVar, Dict, List, Optional, Union
30
- from typing import Set
30
+ from typing import Optional, Set
31
31
  from typing_extensions import Self
32
32
 
33
33
 
@@ -20,7 +20,7 @@ import json
20
20
  from datetime import datetime
21
21
  from pydantic import BaseModel, ConfigDict, StrictStr
22
22
  from typing import Any, ClassVar, Dict, List, Optional
23
- from typing import Set
23
+ from typing import Optional, Set
24
24
  from typing_extensions import Self
25
25
 
26
26
 
@@ -22,7 +22,7 @@ from typing import Any, ClassVar, Dict, List, Optional
22
22
  from crypticorn.auth.client.models.logout_default_response_issues_inner import (
23
23
  LogoutDefaultResponseIssuesInner,
24
24
  )
25
- from typing import Set
25
+ from typing import Optional, Set
26
26
  from typing_extensions import Self
27
27
 
28
28
 
@@ -19,7 +19,7 @@ import json
19
19
 
20
20
  from pydantic import BaseModel, ConfigDict, StrictStr
21
21
  from typing import Any, ClassVar, Dict, List, Optional
22
- from typing import Set
22
+ from typing import Optional, Set
23
23
  from typing_extensions import Self
24
24
 
25
25
 
@@ -20,7 +20,7 @@ import json
20
20
  from datetime import datetime
21
21
  from pydantic import BaseModel, ConfigDict, Field, StrictStr
22
22
  from typing import Any, ClassVar, Dict, List, Optional
23
- from typing import Set
23
+ from typing import Optional, Set
24
24
  from typing_extensions import Self
25
25
 
26
26
 
@@ -22,7 +22,7 @@ from typing import Any, ClassVar, Dict, List, Optional, Union
22
22
  from crypticorn.auth.client.models.verify_email200_response_auth_auth import (
23
23
  VerifyEmail200ResponseAuthAuth,
24
24
  )
25
- from typing import Set
25
+ from typing import Optional, Set
26
26
  from typing_extensions import Self
27
27
 
28
28
 
@@ -22,7 +22,7 @@ from typing import Any, ClassVar, Dict, List, Optional
22
22
  from crypticorn.auth.client.models.verify_email200_response_auth_auth import (
23
23
  VerifyEmail200ResponseAuthAuth,
24
24
  )
25
- from typing import Set
25
+ from typing import Optional, Set
26
26
  from typing_extensions import Self
27
27
 
28
28
 
@@ -19,7 +19,7 @@ import json
19
19
 
20
20
  from pydantic import BaseModel, ConfigDict, StrictStr
21
21
  from typing import Any, ClassVar, Dict, List, Optional
22
- from typing import Set
22
+ from typing import Optional, Set
23
23
  from typing_extensions import Self
24
24
 
25
25
 
@@ -19,7 +19,7 @@ import json
19
19
 
20
20
  from pydantic import BaseModel, ConfigDict, Field, StrictStr
21
21
  from typing import Any, ClassVar, Dict, List, Optional
22
- from typing import Set
22
+ from typing import Optional, Set
23
23
  from typing_extensions import Self
24
24
 
25
25
 
@@ -27,7 +27,7 @@ from pydantic import (
27
27
  StrictStr,
28
28
  )
29
29
  from typing import Any, ClassVar, Dict, List, Optional, Union
30
- from typing import Set
30
+ from typing import Optional, Set
31
31
  from typing_extensions import Self
32
32
 
33
33
 
@@ -22,7 +22,7 @@ from typing import Any, ClassVar, Dict, List, Optional
22
22
  from crypticorn.auth.client.models.verify_email200_response_auth_auth import (
23
23
  VerifyEmail200ResponseAuthAuth,
24
24
  )
25
- from typing import Set
25
+ from typing import Optional, Set
26
26
  from typing_extensions import Self
27
27
 
28
28
 
@@ -27,7 +27,7 @@ from pydantic import (
27
27
  StrictStr,
28
28
  )
29
29
  from typing import Any, ClassVar, Dict, List, Optional, Union
30
- from typing import Set
30
+ from typing import Optional, Set
31
31
  from typing_extensions import Self
32
32
 
33
33
 
@@ -19,7 +19,7 @@ import json
19
19
 
20
20
  from pydantic import BaseModel, ConfigDict, Field, StrictBool, StrictStr
21
21
  from typing import Any, ClassVar, Dict, List, Optional
22
- from typing import Set
22
+ from typing import Optional, Set
23
23
  from typing_extensions import Self
24
24
 
25
25
 
@@ -1,18 +1,18 @@
1
- from crypticorn.common.errors import *
2
- from crypticorn.common.scopes import *
3
- from crypticorn.common.urls import *
4
- from crypticorn.common.decorators import *
5
- from crypticorn.common.mixins import *
1
+ from crypticorn.common.ansi_colors import *
6
2
  from crypticorn.common.auth import *
3
+ from crypticorn.common.decorators import *
7
4
  from crypticorn.common.enums import *
8
- from crypticorn.common.utils import *
5
+ from crypticorn.common.errors import *
9
6
  from crypticorn.common.exceptions import *
10
- from crypticorn.common.pagination import *
11
7
  from crypticorn.common.logging import *
12
- from crypticorn.common.ansi_colors import *
8
+ from crypticorn.common.metrics import *
13
9
  from crypticorn.common.middleware import *
14
- from crypticorn.common.warnings import *
10
+ from crypticorn.common.mixins import *
15
11
  from crypticorn.common.openapi import *
16
- from crypticorn.common.metrics import *
17
- from crypticorn.common.router.status_router import router as status_router
12
+ from crypticorn.common.pagination import *
18
13
  from crypticorn.common.router.admin_router import router as admin_router
14
+ from crypticorn.common.router.status_router import router as status_router
15
+ from crypticorn.common.scopes import *
16
+ from crypticorn.common.urls import *
17
+ from crypticorn.common.utils import *
18
+ from crypticorn.common.warnings import *
crypticorn/common/auth.py CHANGED
@@ -1,25 +1,30 @@
1
1
  import json
2
+ from typing import Union
2
3
 
3
- from crypticorn.auth import Verify200Response, AuthClient, Configuration
4
+ from crypticorn.auth import AuthClient, Configuration, Verify200Response
4
5
  from crypticorn.auth.client.exceptions import ApiException
5
- from crypticorn.common.scopes import Scope
6
6
  from crypticorn.common.exceptions import (
7
7
  ApiError,
8
- HTTPException,
9
8
  ExceptionContent,
9
+ HTTPException,
10
10
  )
11
- from crypticorn.common.urls import BaseUrl, Service, ApiVersion
11
+ from crypticorn.common.scopes import Scope
12
+ from crypticorn.common.urls import ApiVersion, BaseUrl, Service
12
13
  from fastapi import Depends, Query
13
14
  from fastapi.security import (
14
- HTTPAuthorizationCredentials,
15
- SecurityScopes,
16
- HTTPBearer,
17
15
  APIKeyHeader,
16
+ HTTPAuthorizationCredentials,
18
17
  HTTPBasic,
18
+ HTTPBasicCredentials,
19
+ HTTPBearer,
20
+ SecurityScopes,
19
21
  )
20
22
  from typing_extensions import Annotated
21
- from typing import Union
22
- from fastapi.security import HTTPBasicCredentials
23
+
24
+ AUTHENTICATE_HEADER = "WWW-Authenticate"
25
+ BEARER_AUTH_SCHEME = "Bearer"
26
+ APIKEY_AUTH_SCHEME = "X-API-Key"
27
+ BASIC_AUTH_SCHEME = "Basic"
23
28
 
24
29
  # Auth Schemes
25
30
  http_bearer = HTTPBearer(
@@ -29,15 +34,15 @@ http_bearer = HTTPBearer(
29
34
  )
30
35
 
31
36
  apikey_header = APIKeyHeader(
32
- name="X-API-Key",
37
+ name=APIKEY_AUTH_SCHEME,
33
38
  auto_error=False,
34
39
  description="The API key to use for authentication.",
35
40
  )
36
41
 
37
- basic_auth = HTTPBasic(
38
- scheme_name="Basic",
42
+ http_basic = HTTPBasic(
43
+ scheme_name=BASIC_AUTH_SCHEME,
39
44
  auto_error=False,
40
- description="The username and password to use for authentication. Only used in /admin/metrics",
45
+ description="The username and password to use for authentication.",
41
46
  )
42
47
 
43
48
 
@@ -55,7 +60,7 @@ class AuthHandler:
55
60
  base_url: BaseUrl = BaseUrl.PROD,
56
61
  ):
57
62
  self.url = f"{base_url}/{ApiVersion.V1}/{Service.AUTH}"
58
- self.client = AuthClient(Configuration(host=self.url))
63
+ self.client = AuthClient(Configuration(host=self.url), is_sync=False)
59
64
 
60
65
  async def _verify_api_key(self, api_key: str) -> Verify200Response:
61
66
  """
@@ -73,6 +78,12 @@ class AuthHandler:
73
78
  self.client.config.access_token = bearer.credentials
74
79
  return await self.client.login.verify()
75
80
 
81
+ async def _verify_basic(self, basic: HTTPBasicCredentials) -> Verify200Response:
82
+ """
83
+ Verifies the basic authentication credentials.
84
+ """
85
+ return await self.client.login.verify_basic_auth(basic.username, basic.password)
86
+
76
87
  async def _validate_scopes(
77
88
  self, api_scopes: list[Scope], user_scopes: list[Scope]
78
89
  ) -> bool:
@@ -118,6 +129,8 @@ class AuthHandler:
118
129
  error = ApiError.EXPIRED_API_KEY
119
130
  elif message == "jwt expired":
120
131
  error = ApiError.EXPIRED_BEARER
132
+ elif message == "Invalid basic authentication credentials":
133
+ error = ApiError.INVALID_BASIC_AUTH
121
134
  else:
122
135
  message = "Invalid bearer token"
123
136
  error = (
@@ -150,17 +163,17 @@ class AuthHandler:
150
163
  This function is used for HTTP connections.
151
164
  """
152
165
  try:
153
- return await self.combined_auth(bearer=None, api_key=api_key, sec=sec)
166
+ return await self.full_auth(
167
+ bearer=None, api_key=api_key, basic=None, sec=sec
168
+ )
154
169
  except HTTPException as e:
155
- if e.detail.get("code") == ApiError.NO_CREDENTIALS.identifier:
156
- raise HTTPException(
157
- content=ExceptionContent(
158
- error=ApiError.NO_API_KEY,
159
- message="No credentials provided. API key is required",
160
- ),
161
- headers={"WWW-Authenticate": "X-API-Key"},
162
- )
163
- raise e
170
+ raise HTTPException(
171
+ content=ExceptionContent(
172
+ error=ApiError.from_json(e.detail),
173
+ message=e.detail.get("message"),
174
+ ),
175
+ headers={AUTHENTICATE_HEADER: APIKEY_AUTH_SCHEME},
176
+ )
164
177
 
165
178
  async def bearer_auth(
166
179
  self,
@@ -176,17 +189,37 @@ class AuthHandler:
176
189
  This function is used for HTTP connections.
177
190
  """
178
191
  try:
179
- return await self.combined_auth(bearer=bearer, api_key=None, sec=sec)
192
+ return await self.full_auth(
193
+ bearer=bearer, api_key=None, basic=None, sec=sec
194
+ )
195
+ except HTTPException as e:
196
+ raise HTTPException(
197
+ content=ExceptionContent(
198
+ error=ApiError.from_json(e.detail),
199
+ message=e.detail.get("message"),
200
+ ),
201
+ headers={AUTHENTICATE_HEADER: BEARER_AUTH_SCHEME},
202
+ )
203
+
204
+ async def basic_auth(
205
+ self,
206
+ credentials: Annotated[Union[HTTPBasicCredentials, None], Depends(http_basic)],
207
+ ) -> Verify200Response:
208
+ """
209
+ Verifies the basic authentication credentials. This authentication method should just be used for special cases like /admin/metrics, where JWT and API key authentication are not desired or not possible.
210
+ """
211
+ try:
212
+ return await self.full_auth(
213
+ basic=credentials, bearer=None, api_key=None, sec=None
214
+ )
180
215
  except HTTPException as e:
181
- if e.detail.get("code") == ApiError.NO_CREDENTIALS.identifier:
182
- raise HTTPException(
183
- content=ExceptionContent(
184
- error=ApiError.NO_BEARER,
185
- message="No credentials provided. Bearer token is required",
186
- ),
187
- headers={"WWW-Authenticate": "Bearer"},
188
- )
189
- raise e
216
+ raise HTTPException(
217
+ content=ExceptionContent(
218
+ error=ApiError.from_json(e.detail),
219
+ message=e.detail.get("message"),
220
+ ),
221
+ headers={AUTHENTICATE_HEADER: BASIC_AUTH_SCHEME},
222
+ )
190
223
 
191
224
  async def combined_auth(
192
225
  self,
@@ -202,8 +235,38 @@ class AuthHandler:
202
235
  Use this function if you want to allow access via either the bearer token or the API key.
203
236
  This function is used for HTTP connections.
204
237
  """
205
- tokens = [bearer, api_key]
238
+ try:
239
+ return await self.full_auth(
240
+ basic=None, bearer=bearer, api_key=api_key, sec=sec
241
+ )
242
+ except HTTPException as e:
243
+ raise HTTPException(
244
+ content=ExceptionContent(
245
+ error=ApiError.from_json(e.detail),
246
+ message=e.detail.get("message"),
247
+ ),
248
+ headers={
249
+ AUTHENTICATE_HEADER: f"{BEARER_AUTH_SCHEME}, {APIKEY_AUTH_SCHEME}"
250
+ },
251
+ )
206
252
 
253
+ async def full_auth(
254
+ self,
255
+ basic: Annotated[Union[HTTPBasicCredentials, None], Depends(http_basic)] = None,
256
+ bearer: Annotated[
257
+ Union[HTTPAuthorizationCredentials, None], Depends(http_bearer)
258
+ ] = None,
259
+ api_key: Annotated[Union[str, None], Depends(apikey_header)] = None,
260
+ sec: SecurityScopes = SecurityScopes(),
261
+ ) -> Verify200Response:
262
+ """
263
+ IMPORTANT: combined_auth is sufficient for most use cases. This function adds basic auth to the mix, which is needed for external services like prometheus, but is not recommended for internal use.
264
+ Verifies the bearer token, API key and basic authentication credentials and checks the scopes.
265
+ Returns early on the first successful verification, otherwise tries all available tokens.
266
+ Use this function if you want to allow access via either the bearer token, the API key or the basic authentication credentials.
267
+ This function is used for HTTP connections.
268
+ """
269
+ tokens = [bearer, api_key, basic]
207
270
  last_error = None
208
271
  for token in tokens:
209
272
  try:
@@ -214,6 +277,8 @@ class AuthHandler:
214
277
  res = await self._verify_api_key(token)
215
278
  elif isinstance(token, HTTPAuthorizationCredentials):
216
279
  res = await self._verify_bearer(token)
280
+ elif isinstance(token, HTTPBasicCredentials):
281
+ res = await self._verify_basic(token)
217
282
  if res is None:
218
283
  continue
219
284
  if sec:
@@ -230,9 +295,11 @@ class AuthHandler:
230
295
  raise HTTPException(
231
296
  content=ExceptionContent(
232
297
  error=ApiError.NO_CREDENTIALS,
233
- message="No credentials provided. Either API key or bearer token is required.",
298
+ message="No credentials provided. Check the WWW-Authenticate header for the available authentication methods.",
234
299
  ),
235
- headers={"WWW-Authenticate": "Bearer, X-API-Key"},
300
+ headers={
301
+ AUTHENTICATE_HEADER: f"{BEARER_AUTH_SCHEME}, {APIKEY_AUTH_SCHEME}, {BASIC_AUTH_SCHEME}"
302
+ },
236
303
  )
237
304
 
238
305
  async def ws_api_key_auth(
@@ -257,7 +324,11 @@ class AuthHandler:
257
324
  Use this function if you only want to allow access via the bearer token.
258
325
  This function is used for WebSocket connections.
259
326
  """
260
- credentials = HTTPAuthorizationCredentials(scheme="Bearer", credentials=bearer)
327
+ credentials = (
328
+ HTTPAuthorizationCredentials(scheme="Bearer", credentials=bearer)
329
+ if bearer
330
+ else None
331
+ )
261
332
  return await self.bearer_auth(bearer=credentials, sec=sec)
262
333
 
263
334
  async def ws_combined_auth(
@@ -277,22 +348,3 @@ class AuthHandler:
277
348
  else None
278
349
  )
279
350
  return await self.combined_auth(bearer=credentials, api_key=api_key, sec=sec)
280
-
281
- async def basic_auth(
282
- self,
283
- credentials: Annotated[HTTPBasicCredentials, Depends(basic_auth)],
284
- ):
285
- """
286
- Verifies the basic authentication credentials. This authentication method should just be used for special cases like /admin/metrics, where JWT and API key authentication are not desired or not possible.
287
- """
288
- try:
289
- await self.client.login.verify_basic_auth(credentials.username, credentials.password)
290
- except ApiException as e:
291
- raise HTTPException(
292
- content=ExceptionContent(
293
- error=ApiError.INVALID_BASIC_AUTH,
294
- message="Invalid basic authentication credentials",
295
- ),
296
- headers={"WWW-Authenticate": "Basic"},
297
- )
298
- return credentials.username
@@ -1,5 +1,5 @@
1
- from typing import Optional, Type, Any, Tuple
2
1
  from copy import deepcopy
2
+ from typing import Any, Optional, Tuple, Type
3
3
 
4
4
  from pydantic import BaseModel, create_model
5
5
  from pydantic.fields import FieldInfo
@@ -6,6 +6,7 @@ except ImportError:
6
6
  from strenum import StrEnum
7
7
 
8
8
  import warnings
9
+
9
10
  from crypticorn.common.mixins import ValidateEnumMixin
10
11
  from crypticorn.common.warnings import CrypticornDeprecatedSince215
11
12