Skip to content

Commit

Permalink
add thumbnails, videos, system tags, add parents, etc
Browse files Browse the repository at this point in the history
  • Loading branch information
kheina committed Feb 15, 2025
1 parent cdd580e commit a970bca
Show file tree
Hide file tree
Showing 47 changed files with 2,677 additions and 1,706 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ credentials
db
docker
images
videos
6 changes: 4 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ RUN apt update && \
libtiff-dev \
libwebp-dev \
imagemagick \
libimage-exiftool-perl && \
rm -rf /var/lib/apt/lists/*
libimage-exiftool-perl \
ffmpeg

RUN rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY . /app
Expand Down
26 changes: 13 additions & 13 deletions authenticator/authenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from shared.caching.key_value_store import KeyValueStore
from shared.config.credentials import fetch
from shared.datetime import datetime
from shared.exceptions.http_error import BadRequest, Conflict, HttpError, InternalServerError, NotFound, Unauthorized, UnprocessableEntity
from shared.exceptions.http_error import BadRequest, Conflict, FailedLogin, HttpError, InternalServerError, NotFound, UnprocessableEntity
from shared.hashing import Hashable
from shared.models import InternalUser
from shared.models.auth import AuthState, AuthToken, KhUser, Scope, TokenMetadata
Expand Down Expand Up @@ -367,7 +367,7 @@ async def login(self, email: str, password: str, otp: Optional[str], token_data:
)

if not data :
raise Unauthorized('login failed.')
raise FailedLogin('login failed.')

user_id, pwhash, secret, handle, name, mod, otp_secret_index, otp_nonce, otp_key = data
delete_otp: Optional[Callable[[], Awaitable[None]]] = None
Expand All @@ -389,12 +389,12 @@ async def login(self, email: str, password: str, otp: Optional[str], token_data:
otp_secret: str = aeskey.decrypt(otp_nonce, otp_key, self._secrets[otp_secret_index]).decode()

if not pyotp.TOTP(otp_secret).verify(otp) :
raise Unauthorized('login failed.')
raise FailedLogin('login failed.')

password_hash = pwhash.decode()

if not self._argon2.verify(password_hash, password.encode() + self._secrets[secret]) :
raise Unauthorized('login failed.')
raise FailedLogin('login failed.')

if self._argon2.check_needs_rehash(password_hash) :
password_hash = self._argon2.hash(password.encode() + self._secrets[secret]).encode()
Expand All @@ -421,7 +421,7 @@ async def login(self, email: str, password: str, otp: Optional[str], token_data:
token: TokenResponse = await self.generate_token(user_id, token_data)

except VerifyMismatchError as e :
raise Unauthorized('login failed.', err=e)
raise FailedLogin('login failed.', err=e)

except HttpError :
raise
Expand Down Expand Up @@ -518,18 +518,18 @@ async def botLogin(self, token: str) -> LoginResponse :
)

if not data :
raise Unauthorized('bot login failed.')
raise FailedLogin('bot login failed.')

bot_type_id: int
user_id, pw, secret, bot_type_id = data
password_hash = pw.decode()
bot_type = await bot_type_map.get(bot_type_id)

if user_id != bot_login.user_id :
raise Unauthorized('login failed.')
raise FailedLogin('login failed.')

if not self._argon2.verify(password_hash, bot_login.password + self._secrets[secret]) :
raise Unauthorized('login failed.')
raise FailedLogin('login failed.')

if self._argon2.check_needs_rehash(password_hash) :
new_pw_hash = self._argon2.hash(bot_login.password + self._secrets[secret]).encode()
Expand All @@ -545,7 +545,7 @@ async def botLogin(self, token: str) -> LoginResponse :
)

except VerifyMismatchError :
raise Unauthorized('login failed.')
raise FailedLogin('login failed.')

except HttpError :
raise
Expand Down Expand Up @@ -603,19 +603,19 @@ async def changePassword(self, email: str, old_password: str, new_password: str)
)

if not data :
raise Unauthorized('password change failed.')
raise FailedLogin('password change failed.')

pwhash, secret = data
password_hash = pwhash

if not self._argon2.verify(password_hash.decode(), old_password.encode() + self._secrets[secret]) :
raise Unauthorized('password change failed.')
raise FailedLogin('password change failed.')

secret = randbelow(len(self._secrets))
new_password_hash = self._argon2.hash(new_password.encode() + self._secrets[secret]).encode()

except VerifyMismatchError :
raise Unauthorized('login failed.')
raise FailedLogin('login failed.')

except HttpError :
raise
Expand Down Expand Up @@ -810,7 +810,7 @@ async def check_recovery_code(self: Self, user_id: int, otp: str) -> Callable[[]
)

if not otp_data :
raise Unauthorized('login failed.')
raise FailedLogin('login failed.')

otp_hash: str = otp_data[0].decode()
otp_secret_index = otp_data[1]
Expand Down
14 changes: 9 additions & 5 deletions configs/configs.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime
from random import randrange
from re import Match, Pattern
from re import compile as re_compile
from typing import Dict, List, Optional, Self, Tuple, Type, Union
Expand Down Expand Up @@ -49,7 +50,7 @@ class Configs(SqlInterface) :
async def startup(self) -> bool :
Configs.Serializers = {
ConfigType.banner: (AvroSerializer(BannerStore), await repo.addSchema(convert_schema(BannerStore))),
ConfigType.costs: (AvroSerializer(CostsStore), await repo.addSchema(convert_schema(CostsStore))),
ConfigType.costs: (AvroSerializer(CostsStore), await repo.addSchema(convert_schema(CostsStore))),
}
self.UserConfigFingerprint = await repo.addSchema(convert_schema(UserConfig))
assert self.Serializers.keys() == set(ConfigType.__members__.values()), 'Did you forget to add serializers for a config?'
Expand All @@ -59,23 +60,23 @@ async def startup(self) -> bool :

@AsyncLRU(maxsize=32)
@staticmethod
async def getSchema(fingerprint: bytes) -> Schema:
async def getSchema(fingerprint: bytes) -> Schema :
return parse_avro_schema((await repo.getSchema(fingerprint)).decode())


@HttpErrorHandler('retrieving patreon campaign info')
@AerospikeCache('kheina', 'configs', 'patreon-campaign-funds', TTL_minutes=10)
async def getFunding(self) -> int :
if environment.is_local() :
return 1500
return randrange(1000, 1500)

campaign = PatreonClient.fetch_campaign()
return campaign.data()[0].attribute('campaign_pledge_sum') # type: ignore


@HttpErrorHandler('retrieving config')
@AerospikeCache('kheina', 'configs', '{config}', _kvs=KVS)
async def getConfig[T: BaseModel](self, config: ConfigType, _: Type[T]) -> T :
async def getConfig[T: BaseModel](self, config: ConfigType, type_: Type[T]) -> T :
data: Optional[tuple[bytes]] = await self.query_async("""
SELECT bytes
FROM kheina.public.configs
Expand All @@ -91,7 +92,10 @@ async def getConfig[T: BaseModel](self, config: ConfigType, _: Type[T]) -> T :
value: bytes = bytes(data[0])
assert value[:2] == AvroMarker

deserializer: AvroDeserializer = AvroDeserializer(read_model=self.SerializerTypeMap[config], write_model=await Configs.getSchema(value[2:10]))
deserializer: AvroDeserializer = AvroDeserializer(
read_model = self.SerializerTypeMap[config],
write_model = await Configs.getSchema(value[2:10]),
)
return deserializer(value[10:])


Expand Down
Loading

0 comments on commit a970bca

Please sign in to comment.