This commit is contained in:
2025-08-04 20:43:47 +03:00
parent d5ed160746
commit 18b13fdb57
5 changed files with 188 additions and 3 deletions

33
src/api/accounts.py Normal file
View File

@ -0,0 +1,33 @@
from typing import Annotated
from fastapi import APIRouter, Depends, HTTPException, status
from psycopg2._psycopg import connection
import db.accounts as db
import settings.settings as settings
from api.utils import get_password_hash
from db.internal import get_db_connection
accounts_router = APIRouter(prefix="/api/accounts", tags=["anon"])
@accounts_router.post("/add/user")
async def add_account(
platform: str,
login: str,
password: str,
metadata: dict,
conn: Annotated[connection, Depends(get_db_connection)]
):
if not settings.settings.allow_create_users:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Not allowed",
)
if db.check_account_existence(conn, platform, login, password):
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Account already exists",
)
hashed_password = get_password_hash(password)
return db.create_user(conn, username, hashed_password, "user")

View File

@ -3,6 +3,9 @@ from typing import Annotated
import bcrypt
import jwt
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from jwt.exceptions import InvalidTokenError
@ -17,6 +20,19 @@ from db.internal import get_db_connection
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
def encrypt_str(string, key_hex):
key = bytes.fromhex(key_hex)
cipher = AES.new(key, AES.MODE_ECB) # Простейший режим (небезопасно для больших данных!)
encrypted_string = cipher.encrypt(pad(string.encode(), AES.block_size))
return encrypted_string
def decrypt_str(encrypted_string, key_hex):
key = bytes.fromhex(key_hex)
cipher = AES.new(key, AES.MODE_ECB)
string = unpad(cipher.decrypt(encrypted_string), AES.block_size)
return string.decode()
def verify_password(plain_password: str, hashed_password: str):
return bcrypt.checkpw(plain_password.encode("utf-8"), hashed_password.encode("utf-8"))

128
src/db/accounts.py Normal file
View File

@ -0,0 +1,128 @@
import json
import psycopg2.extras
from psycopg2._psycopg import connection
# account create and delete
def create_account(
conn: connection,
platform: str,
login: str,
password: int,
metadata: dict
):
with conn.cursor() as cur:
cur.execute(
"""
insert into picrinth.accounts
(platform, login, password,
metadata, created_at)
values (%s, %s, %s, %s, now())
returning id
""",
(platform, login, password, json.dumps(metadata)),
)
conn.commit()
return cur.rowcount > 0
def delete_account(
conn: connection,
account_id: str
):
with conn.cursor() as cur:
cur.execute(
"""
delete from picrinth.accounts
where account_id = %s
""",
(account_id),
)
conn.commit()
return cur.rowcount > 0
# account checks
def check_account_existence_by_id(
conn: connection,
account_id: str
):
with conn.cursor() as cur:
cur.execute(
"""
select exists(
select 1
from picrinth.accounts
where account_id = %s
);
""",
(account_id),
)
return cur.fetchone()[0] # type: ignore
def check_account_existence(
conn: connection,
platform: str,
login: str,
password: str
):
with conn.cursor() as cur:
cur.execute(
"""
select exists(
select 1
from picrinth.accounts
where platform = %s, login = %s, password = %s
);
""",
(platform, login, password),
)
return cur.fetchone()[0] # type: ignore
# account update
def update_account(
conn: connection,
account_id: str,
platform: str,
login: str,
password: int,
metadata: dict
):
with conn.cursor() as cur:
cur.execute(
"""
update picrinth.accounts
SET platform = %s,
login = %s,
password = %s,
metadata = %s
where account_id = %s
""",
(platform, login, password, json.dumps(metadata), account_id),
)
conn.commit()
return cur.rowcount > 0
# account receiving
def get_account(
conn: connection,
account_id: str
):
with conn.cursor(cursor_factory=psycopg2.extras.DictCursor) as cur:
cur.execute(
"""
select username,
account_id, platform, login,
password, metadata, created_at
from picrinth.accounts
where account_id = %s
""",
(account_id),
)
return cur.fetchone()

View File

@ -1,3 +1,4 @@
from fastapi import HTTPException, status
from psycopg2._psycopg import connection
import db.pictures as db
@ -26,6 +27,12 @@ def generate_feed(
pixiv()
case "gelbooru":
gelbooru()
case _:
return HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Platform is not supported",
)
# TODO: remove mock results
pictures_ids = db.get_all_pictures_ids(conn)
return pictures_ids