Compare commits

..

2 commits

Author SHA1 Message Date
Izalia Mae 6112734b2f update aputils to 0.1.9 2024-03-22 03:24:23 -04:00
Izalia Mae 491f19a9cb don't include date in logging when running via systemd 2024-03-21 22:50:22 -04:00
6 changed files with 36 additions and 35 deletions

View file

@ -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')

View file

@ -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)

View file

@ -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
) )

View file

@ -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': {

View file

@ -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")

View file

@ -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