mirror of
https://git.pleroma.social/pleroma/relay.git
synced 2024-11-09 18:08:00 +00:00
Compare commits
3 commits
b8b6dda131
...
a6f1738b73
Author | SHA1 | Date | |
---|---|---|---|
a6f1738b73 | |||
ea0658e2ea | |||
5c210dc20f |
|
@ -35,6 +35,21 @@ if typing.TYPE_CHECKING:
|
|||
from .misc import Message, Response
|
||||
|
||||
|
||||
def get_csp(request: web.Request) -> str:
|
||||
data = [
|
||||
"default-src 'none'",
|
||||
f"script-src 'nonce-{request['hash']}'",
|
||||
f"style-src 'self' 'nonce-{request['hash']}'",
|
||||
"form-action 'self'",
|
||||
"connect-src 'self'",
|
||||
"img-src 'self'",
|
||||
"object-src 'none'",
|
||||
"frame-ancestors 'none'"
|
||||
]
|
||||
|
||||
return '; '.join(data) + ';'
|
||||
|
||||
|
||||
class Application(web.Application):
|
||||
DEFAULT: Application | None = None
|
||||
|
||||
|
@ -127,21 +142,6 @@ class Application(web.Application):
|
|||
return timedelta(seconds=uptime.seconds)
|
||||
|
||||
|
||||
def get_csp(self, request: Request) -> str:
|
||||
data = [
|
||||
"default-src 'none'",
|
||||
f"script-src 'nonce-{request['hash']}'",
|
||||
f"style-src 'self' 'nonce-{request['hash']}'",
|
||||
"form-action 'self'",
|
||||
"connect-src 'self'",
|
||||
"img-src 'self'",
|
||||
"object-src 'none'",
|
||||
"frame-ancestors 'none'"
|
||||
]
|
||||
|
||||
return '; '.join(data) + ';'
|
||||
|
||||
|
||||
def push_message(self, inbox: str, message: Message, instance: Row) -> None:
|
||||
self['push_queue'].put((inbox, message, instance))
|
||||
|
||||
|
@ -240,7 +240,7 @@ class CachedStaticResource(StaticResource):
|
|||
def __init__(self, prefix: str, path: Path):
|
||||
StaticResource.__init__(self, prefix, path)
|
||||
|
||||
self.cache: dict[Path, bytes] = {}
|
||||
self.cache: dict[str, bytes] = {}
|
||||
|
||||
for filename in path.rglob('*'):
|
||||
if filename.is_dir():
|
||||
|
@ -333,8 +333,8 @@ async def handle_response_headers(request: web.Request, handler: Callable) -> Re
|
|||
resp.headers['Server'] = 'ActivityRelay'
|
||||
|
||||
# Still have to figure out how csp headers work
|
||||
if resp.content_type == 'text/html':
|
||||
resp.headers['Content-Security-Policy'] = Application.DEFAULT.get_csp(request)
|
||||
if resp.content_type == 'text/html' and not request.path.startswith("/api"):
|
||||
resp.headers['Content-Security-Policy'] = get_csp(request)
|
||||
|
||||
if not request.app['dev'] and request.path.endswith(('.css', '.js')):
|
||||
# cache for 2 weeks
|
||||
|
|
|
@ -192,26 +192,29 @@ class Connection(SqlConnection):
|
|||
|
||||
def put_user(self, username: str, password: str | None, handle: str | None = None) -> Row:
|
||||
if self.get_user(username):
|
||||
data = {
|
||||
'username': username
|
||||
}
|
||||
data: dict[str, str] = {}
|
||||
|
||||
if password:
|
||||
data['password'] = password
|
||||
data['hash'] = self.hasher.hash(password)
|
||||
|
||||
if handle:
|
||||
data['handler'] = handle
|
||||
data['handle'] = handle
|
||||
|
||||
else:
|
||||
if password is None:
|
||||
raise ValueError('Password cannot be empty')
|
||||
stmt = Update("users", data)
|
||||
stmt.set_where("username", username)
|
||||
|
||||
data = {
|
||||
'username': username,
|
||||
'hash': self.hasher.hash(password),
|
||||
'handle': handle,
|
||||
'created': datetime.now(tz = timezone.utc)
|
||||
}
|
||||
with self.query(stmt) as cur:
|
||||
return cur.one()
|
||||
|
||||
if password is None:
|
||||
raise ValueError('Password cannot be empty')
|
||||
|
||||
data = {
|
||||
'username': username,
|
||||
'hash': self.hasher.hash(password),
|
||||
'handle': handle,
|
||||
'created': datetime.now(tz = timezone.utc)
|
||||
}
|
||||
|
||||
with self.run('put-user', data) as cur:
|
||||
return cur.one() # type: ignore
|
||||
|
|
10
relay/dev.py
10
relay/dev.py
|
@ -100,8 +100,8 @@ def cli_run(dev: bool):
|
|||
|
||||
try:
|
||||
while True:
|
||||
handler.proc.stdin.write(sys.stdin.read().encode('UTF-8'))
|
||||
handler.proc.stdin.flush()
|
||||
handler.proc.stdin.write(sys.stdin.read().encode('UTF-8')) # type: ignore
|
||||
handler.proc.stdin.flush() # type: ignore
|
||||
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
@ -121,12 +121,12 @@ class WatchHandler(PatternMatchingEventHandler):
|
|||
PatternMatchingEventHandler.__init__(self)
|
||||
|
||||
self.dev: bool = dev
|
||||
self.proc = None
|
||||
self.last_restart = None
|
||||
self.proc: subprocess.Popen | None = None
|
||||
self.last_restart: datetime | None = None
|
||||
|
||||
|
||||
def kill_proc(self):
|
||||
if self.proc.poll() is not None:
|
||||
if not self.proc or self.proc.poll() is not None:
|
||||
return
|
||||
|
||||
logging.info(f'Terminating process {self.proc.pid}')
|
||||
|
|
|
@ -15,6 +15,7 @@ from ..misc import Message, Response, boolean, get_app
|
|||
if typing.TYPE_CHECKING:
|
||||
from aiohttp.web import Request
|
||||
from collections.abc import Callable, Sequence
|
||||
from typing import Any
|
||||
|
||||
|
||||
PUBLIC_API_PATHS: Sequence[tuple[str, str]] = (
|
||||
|
@ -149,7 +150,7 @@ class Config(View):
|
|||
if isinstance(data, Response):
|
||||
return data
|
||||
|
||||
data['key'] = data['key'].replace('-', '_');
|
||||
data['key'] = data['key'].replace('-', '_')
|
||||
|
||||
if data['key'] not in ConfigData.USER_KEYS():
|
||||
return Response.new_error(400, 'Invalid key', 'json')
|
||||
|
@ -255,7 +256,7 @@ class RequestView(View):
|
|||
|
||||
|
||||
async def post(self, request: Request) -> Response:
|
||||
data = await self.get_api_data(['domain', 'accept'], [])
|
||||
data: dict[str, Any] | Response = await self.get_api_data(['domain', 'accept'], [])
|
||||
data['accept'] = boolean(data['accept'])
|
||||
|
||||
try:
|
||||
|
@ -430,7 +431,7 @@ class User(View):
|
|||
|
||||
|
||||
async def patch(self, request: Request) -> Response:
|
||||
data = await self.get_api_data(['username'], ['password', ['handle']])
|
||||
data = await self.get_api_data(['username'], ['password', 'handle'])
|
||||
|
||||
if isinstance(data, Response):
|
||||
return data
|
||||
|
|
|
@ -126,7 +126,7 @@ class View(AbstractView):
|
|||
return Response.new_error(400, 'Invalid JSON data', 'json')
|
||||
|
||||
else:
|
||||
post_data = convert_data(self.request.query) # type: ignore
|
||||
post_data = convert_data(self.request.query)
|
||||
|
||||
data = {}
|
||||
|
||||
|
|
|
@ -3,14 +3,12 @@ from __future__ import annotations
|
|||
import typing
|
||||
|
||||
from aiohttp import web
|
||||
from argon2.exceptions import VerifyMismatchError
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from .base import View, register_route
|
||||
|
||||
from ..database import THEMES, ConfigData
|
||||
from ..database import THEMES
|
||||
from ..logger import LogLevel
|
||||
from ..misc import ACTOR_FORMATS, Message, Response, get_app
|
||||
from ..misc import Response, get_app
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from aiohttp.web import Request
|
||||
|
@ -40,9 +38,9 @@ async def handle_frontend_path(request: web.Request, handler: Callable) -> Respo
|
|||
return Response.new('', 302, {'Location': '/'})
|
||||
|
||||
if not request['user'] and request.path.startswith('/admin'):
|
||||
response = Response.new('', 302, {'Location': f'/login?redir={request.path}'})
|
||||
response.del_cookie('user-token')
|
||||
return response
|
||||
response = Response.new('', 302, {'Location': f'/login?redir={request.path}'})
|
||||
response.del_cookie('user-token')
|
||||
return response
|
||||
|
||||
response = await handler(request)
|
||||
|
||||
|
|
Loading…
Reference in a new issue