mirror of
https://git.pleroma.social/pleroma/relay.git
synced 2024-11-09 18:08:00 +00:00
Compare commits
2 commits
a6f1738b73
...
6112734b2f
Author | SHA1 | Date | |
---|---|---|---|
6112734b2f | |||
491f19a9cb |
|
@ -98,6 +98,8 @@ class Connection(SqlConnection):
|
||||||
with self.run('put-config', params):
|
with self.run('put-config', params):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
return data.get(key)
|
||||||
|
|
||||||
|
|
||||||
def get_inbox(self, value: str) -> Row:
|
def get_inbox(self, value: str) -> Row:
|
||||||
with self.run('get-inbox', {'value': value}) as cur:
|
with self.run('get-inbox', {'value': value}) as cur:
|
||||||
|
@ -192,7 +194,7 @@ class Connection(SqlConnection):
|
||||||
|
|
||||||
def put_user(self, username: str, password: str | None, handle: str | None = None) -> Row:
|
def put_user(self, username: str, password: str | None, handle: str | None = None) -> Row:
|
||||||
if self.get_user(username):
|
if self.get_user(username):
|
||||||
data: dict[str, str] = {}
|
data: dict[str, str | datetime | None] = {}
|
||||||
|
|
||||||
if password:
|
if password:
|
||||||
data['hash'] = self.hasher.hash(password)
|
data['hash'] = self.hasher.hash(password)
|
||||||
|
@ -204,7 +206,7 @@ class Connection(SqlConnection):
|
||||||
stmt.set_where("username", username)
|
stmt.set_where("username", username)
|
||||||
|
|
||||||
with self.query(stmt) as cur:
|
with self.query(stmt) as cur:
|
||||||
return cur.one()
|
return cur.one() # type: ignore
|
||||||
|
|
||||||
if password is None:
|
if password is None:
|
||||||
raise ValueError('Password cannot be empty')
|
raise ValueError('Password cannot be empty')
|
||||||
|
|
|
@ -149,7 +149,12 @@ class HttpClient:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
async def get(self, url: str, sign_headers: bool, cls: type[T], force: bool = False) -> T | None:
|
async def get(self,
|
||||||
|
url: str,
|
||||||
|
sign_headers: bool,
|
||||||
|
cls: type[T],
|
||||||
|
force: bool = False) -> T | None:
|
||||||
|
|
||||||
if not issubclass(cls, JsonBase):
|
if not issubclass(cls, JsonBase):
|
||||||
raise TypeError('cls must be a sub-class of "aputils.JsonBase"')
|
raise TypeError('cls must be a sub-class of "aputils.JsonBase"')
|
||||||
|
|
||||||
|
@ -174,12 +179,12 @@ class HttpClient:
|
||||||
headers.update(get_app().signer.sign_headers('POST', url, message, algorithm=algorithm))
|
headers.update(get_app().signer.sign_headers('POST', url, message, algorithm=algorithm))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logging.verbose('Sending "%s" to %s', message.type, url)
|
logging.verbose('Sending "%s" to %s', message.type.value, url)
|
||||||
|
|
||||||
async with self._session.post(url, headers = headers, data = message.to_json()) as resp:
|
async with self._session.post(url, headers = headers, data = message.to_json()) as resp:
|
||||||
# Not expecting a response, so just return
|
# Not expecting a response, so just return
|
||||||
if resp.status in {200, 202}:
|
if resp.status in {200, 202}:
|
||||||
logging.verbose('Successfully sent "%s" to %s', message.type, url)
|
logging.verbose('Successfully sent "%s" to %s', message.type.value, url)
|
||||||
return
|
return
|
||||||
|
|
||||||
logging.verbose('Received error when pushing to %s: %i', url, resp.status)
|
logging.verbose('Received error when pushing to %s: %i', url, resp.status)
|
||||||
|
|
|
@ -63,10 +63,10 @@ def set_level(level: LogLevel | str) -> None:
|
||||||
|
|
||||||
|
|
||||||
def verbose(message: str, *args: Any, **kwargs: Any) -> None:
|
def verbose(message: str, *args: Any, **kwargs: Any) -> None:
|
||||||
if not logging.root.isEnabledFor(LogLevel['VERBOSE']):
|
if not logging.root.isEnabledFor(LogLevel.VERBOSE):
|
||||||
return
|
return
|
||||||
|
|
||||||
logging.log(LogLevel['VERBOSE'], message, *args, **kwargs)
|
logging.log(LogLevel.VERBOSE, message, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
debug: Callable = logging.debug
|
debug: Callable = logging.debug
|
||||||
|
@ -76,8 +76,6 @@ error: Callable = logging.error
|
||||||
critical: Callable = logging.critical
|
critical: Callable = logging.critical
|
||||||
|
|
||||||
|
|
||||||
env_log_level: Path | str | None = os.environ.get('LOG_LEVEL', 'INFO').upper()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
env_log_file: Path | None = Path(os.environ['LOG_FILE']).expanduser().resolve()
|
env_log_file: Path | None = Path(os.environ['LOG_FILE']).expanduser().resolve()
|
||||||
|
|
||||||
|
@ -89,10 +87,16 @@ handlers: list[Any] = [logging.StreamHandler()]
|
||||||
if env_log_file:
|
if env_log_file:
|
||||||
handlers.append(logging.FileHandler(env_log_file))
|
handlers.append(logging.FileHandler(env_log_file))
|
||||||
|
|
||||||
logging.addLevelName(LogLevel['VERBOSE'], 'VERBOSE')
|
if os.environ.get('INVOCATION_ID'):
|
||||||
|
logging_format = '%(levelname)s: %(message)s'
|
||||||
|
|
||||||
|
else:
|
||||||
|
logging_format = '[%(asctime)s] %(levelname)s: %(message)s'
|
||||||
|
|
||||||
|
logging.addLevelName(LogLevel.VERBOSE, 'VERBOSE')
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level = LogLevel.INFO,
|
level = LogLevel.INFO,
|
||||||
format = '[%(asctime)s] %(levelname)s: %(message)s',
|
format = logging_format,
|
||||||
datefmt = '%Y-%m-%d %H:%M:%S',
|
datefmt = '%Y-%m-%d %H:%M:%S',
|
||||||
handlers = handlers
|
handlers = handlers
|
||||||
)
|
)
|
||||||
|
|
|
@ -130,10 +130,8 @@ class Message(aputils.Message):
|
||||||
description: str | None = None,
|
description: str | None = None,
|
||||||
approves: bool = False) -> Self:
|
approves: bool = False) -> Self:
|
||||||
|
|
||||||
return cls({
|
return cls.new(aputils.ObjectType.APPLICATION, {
|
||||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
||||||
'id': f'https://{host}/actor',
|
'id': f'https://{host}/actor',
|
||||||
'type': 'Application',
|
|
||||||
'preferredUsername': 'relay',
|
'preferredUsername': 'relay',
|
||||||
'name': 'ActivityRelay',
|
'name': 'ActivityRelay',
|
||||||
'summary': description or 'ActivityRelay bot',
|
'summary': description or 'ActivityRelay bot',
|
||||||
|
@ -155,10 +153,8 @@ class Message(aputils.Message):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def new_announce(cls: type[Self], host: str, obj: str | dict[str, Any]) -> Self:
|
def new_announce(cls: type[Self], host: str, obj: str | dict[str, Any]) -> Self:
|
||||||
return cls({
|
return cls.new(aputils.ObjectType.ANNOUNCE, {
|
||||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
||||||
'id': f'https://{host}/activities/{uuid4()}',
|
'id': f'https://{host}/activities/{uuid4()}',
|
||||||
'type': 'Announce',
|
|
||||||
'to': [f'https://{host}/followers'],
|
'to': [f'https://{host}/followers'],
|
||||||
'actor': f'https://{host}/actor',
|
'actor': f'https://{host}/actor',
|
||||||
'object': obj
|
'object': obj
|
||||||
|
@ -167,22 +163,18 @@ class Message(aputils.Message):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def new_follow(cls: type[Self], host: str, actor: str) -> Self:
|
def new_follow(cls: type[Self], host: str, actor: str) -> Self:
|
||||||
return cls({
|
return cls.new(aputils.ObjectType.FOLLOW, {
|
||||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
'id': f'https://{host}/activities/{uuid4()}',
|
||||||
'type': 'Follow',
|
|
||||||
'to': [actor],
|
'to': [actor],
|
||||||
'object': actor,
|
'object': actor,
|
||||||
'id': f'https://{host}/activities/{uuid4()}',
|
|
||||||
'actor': f'https://{host}/actor'
|
'actor': f'https://{host}/actor'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def new_unfollow(cls: type[Self], host: str, actor: str, follow: dict[str, str]) -> Self:
|
def new_unfollow(cls: type[Self], host: str, actor: str, follow: dict[str, str]) -> Self:
|
||||||
return cls({
|
return cls.new(aputils.ObjectType.UNDO, {
|
||||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
||||||
'id': f'https://{host}/activities/{uuid4()}',
|
'id': f'https://{host}/activities/{uuid4()}',
|
||||||
'type': 'Undo',
|
|
||||||
'to': [actor],
|
'to': [actor],
|
||||||
'actor': f'https://{host}/actor',
|
'actor': f'https://{host}/actor',
|
||||||
'object': follow
|
'object': follow
|
||||||
|
@ -191,10 +183,8 @@ class Message(aputils.Message):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def new_response(cls: type[Self], host: str, actor: str, followid: str, accept: bool) -> Self:
|
def new_response(cls: type[Self], host: str, actor: str, followid: str, accept: bool) -> Self:
|
||||||
return cls({
|
return cls.new(aputils.ObjectType.ACCEPT if accept else aputils.ObjectType.REJECT, {
|
||||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
|
||||||
'id': f'https://{host}/activities/{uuid4()}',
|
'id': f'https://{host}/activities/{uuid4()}',
|
||||||
'type': 'Accept' if accept else 'Reject',
|
|
||||||
'to': [actor],
|
'to': [actor],
|
||||||
'actor': f'https://{host}/actor',
|
'actor': f'https://{host}/actor',
|
||||||
'object': {
|
'object': {
|
||||||
|
|
|
@ -136,20 +136,20 @@ class ActorView(View):
|
||||||
if not digest.validate(body):
|
if not digest.validate(body):
|
||||||
raise aputils.SignatureFailureError("Body digest does not match")
|
raise aputils.SignatureFailureError("Body digest does not match")
|
||||||
|
|
||||||
if self.signature.algorithm_type == "hs2019":
|
if self.signature.algorithm_type == aputils.AlgorithmType.HS2019:
|
||||||
if "(created)" not in self.signature.headers:
|
if self.signature.created is None or self.signature.expires is None:
|
||||||
raise aputils.SignatureFailureError("'(created)' header not used")
|
raise aputils.SignatureFailureError("Missing 'created' or 'expireds' parameter")
|
||||||
|
|
||||||
current_timestamp = aputils.HttpDate.new_utc().timestamp()
|
current_timestamp = aputils.HttpDate.new_utc().timestamp()
|
||||||
|
|
||||||
if self.signature.created > current_timestamp:
|
if self.signature.created > current_timestamp:
|
||||||
raise aputils.SignatureFailureError("Creation date after current date")
|
raise aputils.SignatureFailureError("Creation date after current date")
|
||||||
|
|
||||||
if current_timestamp > self.signature.expires:
|
if self.signature.expires < current_timestamp:
|
||||||
raise aputils.SignatureFailureError("Expiration date before current date")
|
raise aputils.SignatureFailureError("Signature has expired")
|
||||||
|
|
||||||
headers["(created)"] = self.signature.created
|
headers["(created)"] = str(self.signature.created)
|
||||||
headers["(expires)"] = self.signature.expires
|
headers["(expires)"] = str(self.signature.expires)
|
||||||
|
|
||||||
if not self.signer._validate_signature(headers, self.signature):
|
if not self.signer._validate_signature(headers, self.signature):
|
||||||
raise aputils.SignatureFailureError("Signature does not match")
|
raise aputils.SignatureFailureError("Signature does not match")
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
activitypub-utils == 0.1.9
|
||||||
aiohttp >= 3.9.1
|
aiohttp >= 3.9.1
|
||||||
aiohttp-swagger[performance] == 1.0.16
|
aiohttp-swagger[performance] == 1.0.16
|
||||||
aputils @ https://git.barkshark.xyz/barkshark/aputils/archive/0.1.7.tar.gz
|
|
||||||
argon2-cffi == 23.1.0
|
argon2-cffi == 23.1.0
|
||||||
barkshark-sql @ https://git.barkshark.xyz/barkshark/bsql/archive/0.1.2.tar.gz
|
barkshark-sql @ https://git.barkshark.xyz/barkshark/bsql/archive/0.1.2.tar.gz
|
||||||
click >= 8.1.2
|
click >= 8.1.2
|
||||||
|
|
Loading…
Reference in a new issue