fastlifeweb 0.7.0__tar.gz → 0.7.2__tar.gz
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.
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/PKG-INFO +1 -1
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/pyproject.toml +1 -1
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/configurator/configurator.py +9 -3
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/configurator/route_handler.py +3 -4
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/configurator/settings.py +5 -1
- fastlifeweb-0.7.2/src/fastlife/middlewares/__init__.py +7 -0
- fastlifeweb-0.7.2/src/fastlife/middlewares/reverse_proxy/__init__.py +10 -0
- fastlifeweb-0.7.2/src/fastlife/middlewares/reverse_proxy/x_forwarded.py +50 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/testing/testclient.py +1 -1
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/LICENSE +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/README.md +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/__init__.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/configurator/__init__.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/configurator/base.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/configurator/registry.py +0 -0
- {fastlifeweb-0.7.0/src/fastlife → fastlifeweb-0.7.2/src/fastlife/middlewares}/session/__init__.py +0 -0
- {fastlifeweb-0.7.0/src/fastlife → fastlifeweb-0.7.2/src/fastlife/middlewares}/session/middleware.py +0 -0
- {fastlifeweb-0.7.0/src/fastlife → fastlifeweb-0.7.2/src/fastlife/middlewares}/session/serializer.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/py.typed +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/request/__init__.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/request/form_data.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/request/model_result.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/routing/__init__.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/routing/router.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/security/__init__.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/security/csrf.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/security/policy.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/shared_utils/__init__.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/shared_utils/infer.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/shared_utils/resolver.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/A.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/Button.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/Checkbox.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/CsrfToken.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/Form.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/H1.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/H2.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/H3.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/H4.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/H5.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/H6.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/Hidden.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/Input.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/Label.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/Option.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/P.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/Radio.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/Select.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/__init__.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/pydantic_form/Boolean.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/pydantic_form/Checklist.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/pydantic_form/Dropdown.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/pydantic_form/Error.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/pydantic_form/Hidden.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/pydantic_form/Hint.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/pydantic_form/Model.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/pydantic_form/Sequence.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/pydantic_form/Text.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/pydantic_form/Union.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/pydantic_form/Widget.jinja +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/__init__.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/binding.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/__init__.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/abstract.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/jinjax.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/widgets/__init__.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/widgets/base.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/widgets/boolean.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/widgets/checklist.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/widgets/dropdown.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/widgets/factory.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/widgets/hidden.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/widgets/model.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/widgets/sequence.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/widgets/text.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/widgets/union.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/testing/__init__.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/views/__init__.py +0 -0
- {fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/views/pydantic_form.py +0 -0
@@ -22,7 +22,7 @@ from typing import (
|
|
22
22
|
)
|
23
23
|
|
24
24
|
import venusian # type: ignore
|
25
|
-
from fastapi import Depends, FastAPI, Response
|
25
|
+
from fastapi import Depends, FastAPI, Request, Response
|
26
26
|
from fastapi.params import Depends as DependsType
|
27
27
|
from fastapi.staticfiles import StaticFiles
|
28
28
|
|
@@ -30,6 +30,7 @@ from fastlife.configurator.base import AbstractMiddleware
|
|
30
30
|
from fastlife.configurator.route_handler import FastlifeRoute
|
31
31
|
from fastlife.security.csrf import check_csrf
|
32
32
|
|
33
|
+
from .route_handler import FastlifeRequest
|
33
34
|
from .settings import Settings
|
34
35
|
|
35
36
|
if TYPE_CHECKING:
|
@@ -63,7 +64,7 @@ class Configurator:
|
|
63
64
|
self._app.router.route_class = FastlifeRoute
|
64
65
|
self.scanner = venusian.Scanner(fastlife=self)
|
65
66
|
self.include("fastlife.views")
|
66
|
-
self.include("fastlife.
|
67
|
+
self.include("fastlife.middlewares")
|
67
68
|
|
68
69
|
def get_app(self) -> FastAPI:
|
69
70
|
"""
|
@@ -193,7 +194,12 @@ class Configurator:
|
|
193
194
|
self, status_code_or_exc: int | Type[Exception], handler: Any
|
194
195
|
) -> "Configurator":
|
195
196
|
"""Add an exception handler the application."""
|
196
|
-
|
197
|
+
|
198
|
+
def exception_handler(request: Request, exc: Exception) -> Any:
|
199
|
+
req = FastlifeRequest(self.registry, request)
|
200
|
+
return handler(req, exc)
|
201
|
+
|
202
|
+
self._app.add_exception_handler(status_code_or_exc, exception_handler)
|
197
203
|
return self
|
198
204
|
|
199
205
|
|
@@ -3,15 +3,14 @@ from typing import TYPE_CHECKING, Any, Callable, Coroutine
|
|
3
3
|
from fastapi import Request as BaseRequest
|
4
4
|
from fastapi.routing import APIRoute
|
5
5
|
from starlette.responses import Response
|
6
|
-
from starlette.types import Receive, Scope
|
7
6
|
|
8
7
|
if TYPE_CHECKING:
|
9
8
|
from .registry import AppRegistry # coverage: ignore
|
10
9
|
|
11
10
|
|
12
11
|
class FastlifeRequest(BaseRequest):
|
13
|
-
def __init__(self, registry: "AppRegistry",
|
14
|
-
super().__init__(scope, receive)
|
12
|
+
def __init__(self, registry: "AppRegistry", request: BaseRequest) -> None:
|
13
|
+
super().__init__(request.scope, request.receive)
|
15
14
|
self.registry = registry
|
16
15
|
|
17
16
|
|
@@ -24,7 +23,7 @@ class FastlifeRoute(APIRoute):
|
|
24
23
|
orig_route_handler = super().get_route_handler()
|
25
24
|
|
26
25
|
async def route_handler(request: BaseRequest) -> FastlifeRequest:
|
27
|
-
req = FastlifeRequest(self.registry, request
|
26
|
+
req = FastlifeRequest(self.registry, request)
|
28
27
|
return await orig_route_handler(req) # type: ignore
|
29
28
|
|
30
29
|
return route_handler # type: ignore
|
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Settings for the fastlife."""
|
2
|
+
|
2
3
|
from datetime import timedelta
|
3
4
|
from typing import Literal
|
4
5
|
|
@@ -77,7 +78,7 @@ class Settings(BaseSettings):
|
|
77
78
|
should be true while using https on production.
|
78
79
|
"""
|
79
80
|
session_serializer: str = Field(
|
80
|
-
default="fastlife.session.serializer:SignedSessionSerializer"
|
81
|
+
default="fastlife.middlewares.session.serializer:SignedSessionSerializer"
|
81
82
|
)
|
82
83
|
"""Cookie serializer for the session cookie."""
|
83
84
|
|
@@ -86,3 +87,6 @@ class Settings(BaseSettings):
|
|
86
87
|
|
87
88
|
check_permission: str = Field(default="fastlife.security.policy:check_permission")
|
88
89
|
"""Handler for checking permission set on any views using the configurator."""
|
90
|
+
|
91
|
+
decode_reverse_proxy_headers: bool = Field(default=True)
|
92
|
+
"""Ensure that the request object has information based on http proxy headers."""
|
@@ -0,0 +1,10 @@
|
|
1
|
+
from fastlife import Configurator, configure
|
2
|
+
|
3
|
+
from .x_forwarded import XForwardedStar
|
4
|
+
|
5
|
+
|
6
|
+
@configure
|
7
|
+
def includeme(config: Configurator) -> None:
|
8
|
+
settings = config.registry.settings
|
9
|
+
if settings.decode_reverse_proxy_headers:
|
10
|
+
config.add_middleware(XForwardedStar)
|
@@ -0,0 +1,50 @@
|
|
1
|
+
"""
|
2
|
+
A middleware that update the request scope for https behind a proxy.
|
3
|
+
|
4
|
+
The attempt of this middleware is to fix Starlette behavior that use client and scheme
|
5
|
+
header based on the header x-forwarded-* headers and the x-real-ip.
|
6
|
+
|
7
|
+
the x-forwarded-for header is not parsed to find the appropriate value,
|
8
|
+
the x-real-ip is used.
|
9
|
+
notethat the x-forwarded-port header is not used.
|
10
|
+
|
11
|
+
Note that uvicorn or hypercorn offer the same kind middleware.
|
12
|
+
"""
|
13
|
+
|
14
|
+
import logging
|
15
|
+
from typing import Optional, Sequence, Tuple
|
16
|
+
|
17
|
+
from starlette.types import ASGIApp, Receive, Scope, Send
|
18
|
+
|
19
|
+
from fastlife.configurator.base import AbstractMiddleware
|
20
|
+
|
21
|
+
|
22
|
+
log = logging.getLogger(__name__)
|
23
|
+
|
24
|
+
|
25
|
+
def get_header(headers: Sequence[Tuple[bytes, bytes]], key: bytes) -> Optional[str]:
|
26
|
+
for hdr in headers:
|
27
|
+
if hdr[0].lower() == key:
|
28
|
+
return hdr[1].decode("latin1")
|
29
|
+
return None
|
30
|
+
|
31
|
+
|
32
|
+
class XForwardedStar(AbstractMiddleware):
|
33
|
+
def __init__(
|
34
|
+
self,
|
35
|
+
app: ASGIApp,
|
36
|
+
) -> None:
|
37
|
+
self.app = app
|
38
|
+
|
39
|
+
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
|
40
|
+
if scope["type"] in ("http", "websocket"):
|
41
|
+
|
42
|
+
headers = scope["headers"]
|
43
|
+
new_vals = {
|
44
|
+
"client": get_header(headers, b"x-real-ip"),
|
45
|
+
"host": get_header(headers, b"x-forwarded-host"),
|
46
|
+
"scheme": get_header(headers, b"x-forwarded-proto"),
|
47
|
+
}
|
48
|
+
scope.update({key: val for key, val in new_vals.items() if val is not None})
|
49
|
+
|
50
|
+
await self.app(scope, receive, send)
|
@@ -14,7 +14,7 @@ from multidict import MultiDict
|
|
14
14
|
from starlette.types import ASGIApp
|
15
15
|
|
16
16
|
from fastlife.configurator.settings import Settings
|
17
|
-
from fastlife.session.serializer import AbsractSessionSerializer
|
17
|
+
from fastlife.middlewares.session.serializer import AbsractSessionSerializer
|
18
18
|
from fastlife.shared_utils.resolver import resolve
|
19
19
|
|
20
20
|
CookieTypes = httpx._types.CookieTypes # type: ignore
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{fastlifeweb-0.7.0/src/fastlife → fastlifeweb-0.7.2/src/fastlife/middlewares}/session/__init__.py
RENAMED
File without changes
|
{fastlifeweb-0.7.0/src/fastlife → fastlifeweb-0.7.2/src/fastlife/middlewares}/session/middleware.py
RENAMED
File without changes
|
{fastlifeweb-0.7.0/src/fastlife → fastlifeweb-0.7.2/src/fastlife/middlewares}/session/serializer.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templates/pydantic_form/Checklist.jinja
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/widgets/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/widgets/checklist.py
RENAMED
File without changes
|
{fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/widgets/dropdown.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{fastlifeweb-0.7.0 → fastlifeweb-0.7.2}/src/fastlife/templating/renderer/widgets/sequence.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|