Nexom 1.0.6__py3-none-any.whl → 1.0.8__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.
- nexom/app/auth.py +1 -2
- nexom/app/middleware.py +85 -1
- nexom/app/path.py +8 -2
- nexom/app/response.py +3 -0
- nexom/assets/app/static/style.css +1 -1
- nexom/assets/app/templates/default.html +1 -1
- nexom/assets/app/wsgi.py +1 -2
- {nexom-1.0.6.dist-info → nexom-1.0.8.dist-info}/METADATA +1 -1
- {nexom-1.0.6.dist-info → nexom-1.0.8.dist-info}/RECORD +13 -13
- {nexom-1.0.6.dist-info → nexom-1.0.8.dist-info}/WHEEL +0 -0
- {nexom-1.0.6.dist-info → nexom-1.0.8.dist-info}/entry_points.txt +0 -0
- {nexom-1.0.6.dist-info → nexom-1.0.8.dist-info}/licenses/LICENSE +0 -0
- {nexom-1.0.6.dist-info → nexom-1.0.8.dist-info}/top_level.txt +0 -0
nexom/app/auth.py
CHANGED
|
@@ -133,8 +133,7 @@ class AuthService:
|
|
|
133
133
|
def handler(self, environ: dict) -> JsonResponse:
|
|
134
134
|
req = Request(environ)
|
|
135
135
|
try:
|
|
136
|
-
|
|
137
|
-
return route.call_handler(req)
|
|
136
|
+
return self.routing.handle(req)
|
|
138
137
|
|
|
139
138
|
except NexomError as e:
|
|
140
139
|
# error code -> proper HTTP status
|
nexom/app/middleware.py
CHANGED
|
@@ -48,4 +48,88 @@ class MiddlewareChain:
|
|
|
48
48
|
|
|
49
49
|
return call_at(0, request, args)
|
|
50
50
|
|
|
51
|
-
return wrapped
|
|
51
|
+
return wrapped
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class CORSMiddleware:
|
|
55
|
+
def __init__(
|
|
56
|
+
self,
|
|
57
|
+
allowed_origins: list[str] | None = None, # None or ["*"] = allow all
|
|
58
|
+
allowed_methods: list[str] | None = None,
|
|
59
|
+
allowed_headers: list[str] | None = None,
|
|
60
|
+
access_control_allow_credentials: bool = False,
|
|
61
|
+
max_age: int | None = 600,
|
|
62
|
+
) -> None:
|
|
63
|
+
self.allowed_origins = allowed_origins or ["*"]
|
|
64
|
+
self.allowed_methods = [m.upper() for m in (allowed_methods or ["GET", "POST", "PUT", "DELETE", "OPTIONS"])]
|
|
65
|
+
self.allowed_headers = allowed_headers or ["Content-Type", "Authorization"]
|
|
66
|
+
self.allow_credentials = access_control_allow_credentials
|
|
67
|
+
self.max_age = max_age
|
|
68
|
+
|
|
69
|
+
def _is_allowed_origin(self, origin: str) -> bool:
|
|
70
|
+
return "*" in self.allowed_origins or origin in self.allowed_origins
|
|
71
|
+
|
|
72
|
+
def _append_vary_origin(self, res: Response) -> None:
|
|
73
|
+
# append_header が単純 append なので、重複しないように軽くケア
|
|
74
|
+
for k, v in getattr(res, "headers", []):
|
|
75
|
+
if k.lower() == "vary":
|
|
76
|
+
# 既に Vary があるなら Origin が含まれてるかだけチェック
|
|
77
|
+
if "origin" in [p.strip().lower() for p in v.split(",")]:
|
|
78
|
+
return
|
|
79
|
+
res.append_header("Vary", v + ", Origin")
|
|
80
|
+
return
|
|
81
|
+
res.append_header("Vary", "Origin")
|
|
82
|
+
|
|
83
|
+
def __call__(self, request: Request, args: dict[str, str | None], next_: Handler) -> Response:
|
|
84
|
+
origin = request.headers.get("origin")
|
|
85
|
+
if not origin:
|
|
86
|
+
return next_(request, args)
|
|
87
|
+
|
|
88
|
+
if not self._is_allowed_origin(origin):
|
|
89
|
+
return next_(request, args)
|
|
90
|
+
|
|
91
|
+
# preflight 判定
|
|
92
|
+
acrm = request.headers.get("access-control-request-method")
|
|
93
|
+
is_preflight = request.method == "OPTIONS" and acrm is not None
|
|
94
|
+
|
|
95
|
+
if is_preflight:
|
|
96
|
+
# 204で十分(body無し)
|
|
97
|
+
res = Response(b"", status=204)
|
|
98
|
+
else:
|
|
99
|
+
res = next_(request, args)
|
|
100
|
+
|
|
101
|
+
# Allow-Origin(単一 or *)
|
|
102
|
+
if "*" in self.allowed_origins and not self.allow_credentials:
|
|
103
|
+
res.append_header("Access-Control-Allow-Origin", "*")
|
|
104
|
+
else:
|
|
105
|
+
# credentials=True なら必ず echo(*は禁止)
|
|
106
|
+
res.append_header("Access-Control-Allow-Origin", origin)
|
|
107
|
+
self._append_vary_origin(res)
|
|
108
|
+
|
|
109
|
+
# Allow-Credentials
|
|
110
|
+
if self.allow_credentials:
|
|
111
|
+
res.append_header("Access-Control-Allow-Credentials", "true")
|
|
112
|
+
|
|
113
|
+
# Allow-Methods
|
|
114
|
+
if self.allowed_methods == ["*"]:
|
|
115
|
+
req_method = request.headers.get("access-control-request-method")
|
|
116
|
+
res.append_header("Access-Control-Allow-Methods", req_method or "GET, POST, PUT, DELETE, OPTIONS")
|
|
117
|
+
else:
|
|
118
|
+
res.append_header("Access-Control-Allow-Methods", ", ".join(self.allowed_methods))
|
|
119
|
+
|
|
120
|
+
# Allow-Headers
|
|
121
|
+
if self.allowed_headers == ["*"]:
|
|
122
|
+
req_headers = request.headers.get("access-control-request-headers")
|
|
123
|
+
# ブラウザが要求してきたヘッダをそのまま許可
|
|
124
|
+
if req_headers:
|
|
125
|
+
res.append_header("Access-Control-Allow-Headers", req_headers)
|
|
126
|
+
else:
|
|
127
|
+
res.append_header("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
|
128
|
+
else:
|
|
129
|
+
res.append_header("Access-Control-Allow-Headers", ", ".join(self.allowed_headers))
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
if self.max_age is not None:
|
|
133
|
+
res.append_header("Access-Control-Max-Age", str(self.max_age))
|
|
134
|
+
|
|
135
|
+
return res
|
nexom/app/path.py
CHANGED
|
@@ -48,7 +48,7 @@ class Path:
|
|
|
48
48
|
self.path_args[idx] = m.group(1)
|
|
49
49
|
|
|
50
50
|
if detection_index == 0:
|
|
51
|
-
detection_index = len(path_segments)
|
|
51
|
+
detection_index = 0 if path == "" else len(path_segments)
|
|
52
52
|
|
|
53
53
|
self.path: str = "/".join(path_segments[:detection_index])
|
|
54
54
|
self.detection_range: int = detection_index
|
|
@@ -192,4 +192,10 @@ class Router(list[Path]):
|
|
|
192
192
|
|
|
193
193
|
if self.raise_if_not_exist:
|
|
194
194
|
raise PathNotFoundError(request_path)
|
|
195
|
-
return None
|
|
195
|
+
return None
|
|
196
|
+
|
|
197
|
+
def handle(self, request: Request) -> Response:
|
|
198
|
+
path = self.get(request.path, method=request.method)
|
|
199
|
+
if path is None:
|
|
200
|
+
raise PathNotFoundError(request.path)
|
|
201
|
+
return path.call_handler(request, tuple(self.middlewares))
|
nexom/app/response.py
CHANGED
nexom/assets/app/wsgi.py
CHANGED
|
@@ -39,8 +39,7 @@ def app(environ: dict, start_response: Callable) -> Iterable[bytes]:
|
|
|
39
39
|
path = req.path
|
|
40
40
|
method = req.method
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
res = p.call_handler(req)
|
|
42
|
+
res = routing.handle(req)
|
|
44
43
|
|
|
45
44
|
except PathNotFoundError as e:
|
|
46
45
|
logger.warn(str(e))
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
nexom/__init__.py,sha256=wMpCghSUTLo67kGxKbaK2QnU7DpfICyfp3-XbDObLSA,367
|
|
2
2
|
nexom/__main__.py,sha256=VKT7WSe6552_mzwLwJqa55tfag5Olr28eYVhVnf9kWY,6196
|
|
3
3
|
nexom/app/__init__.py,sha256=DgKTx8GtuRJkiRwBKmLhCLlf3l19zTWwXEmeRPznzlM,1089
|
|
4
|
-
nexom/app/auth.py,sha256=
|
|
4
|
+
nexom/app/auth.py,sha256=ahLgrzV7v1-QFjoLu5bk69_VjQhto5jiibc3Dq8zh1I,13744
|
|
5
5
|
nexom/app/cookie.py,sha256=VCau9i8z6QlkaE_s8gKZXjcFtrV2bX1T4xssNtpJ5A0,2026
|
|
6
6
|
nexom/app/db.py,sha256=fl3SrNPOltTT3d5PqjISdS4u7SXEMRqLPotbJE0FXsY,3320
|
|
7
7
|
nexom/app/http_status_codes.py,sha256=R4ka3n4rijqvfahF5n5kS-Qrg8bZSsrvF8lGnpKWAgY,1934
|
|
8
|
-
nexom/app/middleware.py,sha256=
|
|
9
|
-
nexom/app/path.py,sha256=
|
|
8
|
+
nexom/app/middleware.py,sha256=PO3V76pdnPsKwVqxM9Lx02vqsTQeLEDU-bLJpZqUhvs,5017
|
|
9
|
+
nexom/app/path.py,sha256=5SJpqWYcQIIc4kuOSYgCZIBnpjzc_0CT_opSEnIg6Vc,6262
|
|
10
10
|
nexom/app/request.py,sha256=4dvcfrrS9gKzVFtoizRw5eFvP7eHRXsavh21zEHXX2U,8867
|
|
11
|
-
nexom/app/response.py,sha256=
|
|
11
|
+
nexom/app/response.py,sha256=1HznRpImlLTdnKb8r0Pd-5DAMkOK7HzoaL7qjbQ68Xo,4585
|
|
12
12
|
nexom/app/template.py,sha256=sGaO39EPrPs-K_4gUxdhtEOyjzYyEPTUzpBzJqFP-_Y,3650
|
|
13
13
|
nexom/app/user.py,sha256=6KLLsb08Ma39CnLBbq5y290o33tfxtHFWu9lu1kT0NM,623
|
|
14
14
|
nexom/assets/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
15
|
nexom/assets/app/config.py,sha256=Ltpj40PE1--s0eRPTHiJNFqG8pFA7Lb6x02C39kwoYA,765
|
|
16
16
|
nexom/assets/app/gunicorn.conf.py,sha256=0kAQ7ddfpnPpqLAZxIXqYPF6EuUzkjIC9aOTqfxn6rc,149
|
|
17
17
|
nexom/assets/app/router.py,sha256=Rnm_H6k6fIAhNaP62IP7lcSsZ0O2q_TfSyYQWd9tdh4,412
|
|
18
|
-
nexom/assets/app/wsgi.py,sha256=
|
|
18
|
+
nexom/assets/app/wsgi.py,sha256=5wk74UzxVE5lnWwtXFcbjOW7Fz9nz9NWG9lq8Q6bzbw,1698
|
|
19
19
|
nexom/assets/app/__pycache__/__init__.cpython-313.pyc,sha256=5qiNgiTI26RZcyxr09EKigB5YYYBSqRJxyq8LCVWR14,195
|
|
20
20
|
nexom/assets/app/pages/__init__.py,sha256=DlX9iwM39JaMKfzK4mbgjE2uVMX3ax0wd2mCVnpg0b4,61
|
|
21
21
|
nexom/assets/app/pages/_templates.py,sha256=1c8KUwfMHkoo7S4neFbYjs5ixK44evn-uFVAFR9Y834,213
|
|
@@ -24,9 +24,9 @@ nexom/assets/app/pages/document.py,sha256=JI9ChJ2BTXFyOiCnm4PRUnOY1xaLHeOI1ZEqHM
|
|
|
24
24
|
nexom/assets/app/pages/__pycache__/__init__.cpython-313.pyc,sha256=iQGBtjKUOXVUrrp1qQIfoj44NL_I2H_YGdL-RJ7gtC8,273
|
|
25
25
|
nexom/assets/app/static/dog.jpeg,sha256=qGEhcg48FxRLRISzbmXvw1qvfbdluC_ukM8ZrHg7_XE,6559
|
|
26
26
|
nexom/assets/app/static/github.png,sha256=DUwjX--e_sVBdKfABfwP4M4tY9NcIYmKtRSFhxETl6k,6223
|
|
27
|
-
nexom/assets/app/static/style.css,sha256=
|
|
27
|
+
nexom/assets/app/static/style.css,sha256=9LxUcxaQ8ppnHEncJPuO-Mt_DYCUFv56wzlHq5ed264,12609
|
|
28
28
|
nexom/assets/app/templates/base.html,sha256=RVW_63gA1sr7pqNkfB6Djk5an_VFpowahDIHGjfV-Wk,349
|
|
29
|
-
nexom/assets/app/templates/default.html,sha256=
|
|
29
|
+
nexom/assets/app/templates/default.html,sha256=H2C9GX0ZQJyT4wUTBOM0Zl-09nCPpGJAjJpvLA7OPkg,617
|
|
30
30
|
nexom/assets/app/templates/document.html,sha256=XzKxibNf_i5DXBN2MHwLu2_Y5KNr9hSgIYxlY5l3gT8,5694
|
|
31
31
|
nexom/assets/app/templates/footer.html,sha256=mh0mm4f1nHIGV3cjDFFi8gpYwEpgk5Jqpbjokh9DPbA,94
|
|
32
32
|
nexom/assets/app/templates/header.html,sha256=ZqtFQtL7hP8Rf5naU8jMSfE6Ce1ktA9KRb2g0PbF8Kc,341
|
|
@@ -49,9 +49,9 @@ nexom/core/log.py,sha256=q0FYz1-kkTUHvNkEBW5V1zvUv1phMYchOqwAfUXGHQI,3016
|
|
|
49
49
|
nexom/core/object_html_render.py,sha256=4yT3Aihia4oG62gr1rqZd757wEXsu78mTCCpjpVE7JM,7027
|
|
50
50
|
nexom/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
51
51
|
nexom/templates/auth.py,sha256=q-kNIpi2M1UH8fmEy7lmcnM1hCTpj9r78wHXgnW-Aak,4617
|
|
52
|
-
nexom-1.0.
|
|
53
|
-
nexom-1.0.
|
|
54
|
-
nexom-1.0.
|
|
55
|
-
nexom-1.0.
|
|
56
|
-
nexom-1.0.
|
|
57
|
-
nexom-1.0.
|
|
52
|
+
nexom-1.0.8.dist-info/licenses/LICENSE,sha256=YbcHyxYLJ5jePeMS_NXpR9yiZjP5skhn32LvcKeknJw,1066
|
|
53
|
+
nexom-1.0.8.dist-info/METADATA,sha256=sNPABMxuaMtXyZ8zfcZHVsiNIx91AThkSuEsOs1dDYo,5896
|
|
54
|
+
nexom-1.0.8.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
55
|
+
nexom-1.0.8.dist-info/entry_points.txt,sha256=0r1egKZmF1MUo25AKPt-2d55sk5Q_EIBOQwD3JC8RgI,46
|
|
56
|
+
nexom-1.0.8.dist-info/top_level.txt,sha256=mTyUruscL3rqXvYJRo8KGwDM6PWXRzgf4CamLr8LSX4,6
|
|
57
|
+
nexom-1.0.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|