77 lines
2.5 KiB
Python
77 lines
2.5 KiB
Python
"""
|
|
models/db.py — DBfrontend: encrypted message store.
|
|
"""
|
|
|
|
import time
|
|
from cryptography.fernet import Fernet
|
|
from cryptography.hazmat.primitives import hashes
|
|
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
|
import base64
|
|
from sqlalchemy.orm import sessionmaker
|
|
|
|
from .base import make_engine, Messages
|
|
|
|
|
|
class DBfrontend:
|
|
def __init__(self, db_cfg, secret: bytes, salt: bytes):
|
|
self.engine = make_engine(db_cfg)
|
|
self.Session = sessionmaker(bind=self.engine)
|
|
self.cipher = self._get_cipher(secret, salt)
|
|
|
|
@staticmethod
|
|
def _get_cipher(secret: bytes, salt: bytes) -> Fernet:
|
|
kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100_000)
|
|
key = base64.urlsafe_b64encode(kdf.derive(secret))
|
|
return Fernet(key)
|
|
|
|
def _encrypt(self, message: str) -> str:
|
|
return self.cipher.encrypt(message.encode()).decode()
|
|
|
|
def _decrypt(self, encrypted: str) -> str:
|
|
try:
|
|
return self.cipher.decrypt(encrypted.encode()).decode()
|
|
except Exception:
|
|
return "[Decryption failed]"
|
|
|
|
def add_message(self, channel: str, ip: str, content: str) -> int:
|
|
with self.Session() as session:
|
|
msg = Messages(
|
|
channel=channel,
|
|
ip=ip,
|
|
content=self._encrypt(content),
|
|
timestamp=int(time.time() * 1000),
|
|
)
|
|
session.add(msg)
|
|
session.commit()
|
|
return msg.id
|
|
|
|
def get_messages(self, channel: str = "general", limit: int = 50) -> list:
|
|
with self.Session() as session:
|
|
q = (
|
|
session.query(Messages)
|
|
.filter(Messages.channel == channel)
|
|
.order_by(Messages.id.desc())
|
|
.limit(limit)
|
|
)
|
|
result = []
|
|
for msg in reversed(q.all()):
|
|
result.append(
|
|
{
|
|
"id": msg.id,
|
|
"channel": msg.channel,
|
|
"ip": msg.ip,
|
|
"content": self._decrypt(msg.content),
|
|
"timestamp": msg.timestamp,
|
|
}
|
|
)
|
|
return result
|
|
|
|
def delete_message(self, msg_id: int) -> bool:
|
|
with self.Session() as session:
|
|
msg = session.get(Messages, msg_id)
|
|
if msg:
|
|
session.delete(msg)
|
|
session.commit()
|
|
return True
|
|
return False
|