Coverage for src/paperap/auth.py: 93%
30 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-18 12:26 -0400
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-18 12:26 -0400
1"""
2----------------------------------------------------------------------------
4 METADATA:
6 File: auth.py
7 Project: paperap
8 Created: 2025-03-04
9 Version: 0.0.7
10 Author: Jess Mann
11 Email: jess@jmann.me
12 Copyright (c) 2025 Jess Mann
14----------------------------------------------------------------------------
16 LAST MODIFIED:
18 2025-03-04 By Jess Mann
20"""
22from __future__ import annotations
24from abc import ABC, abstractmethod
25from typing import Annotated, Any, override
27import pydantic
28from pydantic import ConfigDict, Field
31class AuthBase(pydantic.BaseModel):
32 """Base authentication class."""
34 model_config = ConfigDict(
35 str_strip_whitespace=True,
36 validate_default=True,
37 validate_assignment=True,
38 )
40 @abstractmethod
41 def get_auth_headers(self) -> dict[str, str]:
42 """Get authentication headers."""
43 raise NotImplementedError("get_auth_headers must be implemented by subclasses")
45 @abstractmethod
46 def get_auth_params(self) -> dict[str, Any]:
47 """Get authentication parameters for requests."""
48 raise NotImplementedError("get_auth_params must be implemented by subclasses")
51class TokenAuth(AuthBase):
52 """Authentication using a token."""
54 # token length appears to be 40. Set to 30 just in case (will still catch egregious errors)
55 token: Annotated[str, Field(min_length=30, max_length=75, pattern=r"^[a-zA-Z0-9]+$")]
57 @override
58 def get_auth_headers(self) -> dict[str, str]:
59 """Get the authorization headers."""
60 return {"Authorization": f"Token {self.token}"}
62 @override
63 def get_auth_params(self) -> dict[str, Any]:
64 """Get authentication parameters for requests."""
65 return {}
68class BasicAuth(AuthBase):
69 """Authentication using username and password."""
71 username: str
72 password: str
74 @override
75 def get_auth_headers(self) -> dict[str, str]:
76 """
77 Get headers for basic auth.
79 Basic auth is handled by the requests library, so no headers are needed here.
80 """
81 return {}
83 @override
84 def get_auth_params(self) -> dict[str, Any]:
85 """Get authentication parameters for requests."""
86 return {"auth": (self.username, self.password)}