From 8d628e4826bcd58f1b1a2e18c53d1474715c4bb5 Mon Sep 17 00:00:00 2001 From: Project_IO Date: Tue, 10 Sep 2024 14:20:11 +0900 Subject: [PATCH] feat: middle save --- Makefile | 1 + app.py | 6 ++-- generate.py | 19 +++++++++++- routes/auth.py | 8 ++++++ routes/balance.py | 31 ++++++++++++++++---- service/auth_service.py | 54 ++++++++++++++++++++++++++++++++++ service/balance_service.py | 59 ++++++++++++++++++++++++-------------- util/auth_lib.py | 12 ++++++++ 8 files changed, 160 insertions(+), 30 deletions(-) create mode 100644 Makefile create mode 100644 routes/auth.py create mode 100644 service/auth_service.py create mode 100644 util/auth_lib.py diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Makefile @@ -0,0 +1 @@ + diff --git a/app.py b/app.py index 4e2eb1b..84055fa 100644 --- a/app.py +++ b/app.py @@ -1,5 +1,6 @@ -from routes.balance import router from fastapi import FastAPI, Response +from routes.auth import router as auth +from routes.balance import router as balance app = FastAPI() @@ -8,4 +9,5 @@ def index(resp: Response): resp.headers.setdefault("Content-Type", "text") return "Hello, World!" -app.include_router(router=router) +app.include_router(router=auth) +app.include_router(router=balance) diff --git a/generate.py b/generate.py index 846c8a3..bf12fc2 100644 --- a/generate.py +++ b/generate.py @@ -5,14 +5,31 @@ def __main__(): conn = psycopg2.connect(conn_param) cur = conn.cursor() + cur.execute( + """ + create table account( + name varchar(25), + username varchar(25) primary key, + password varchar(50) not null, + salt varchar(50) + unique(username) + ); + """ + ) + cur.execute( """ create table balset( id serial primary key, + uid varchar(25) not null, name varchar(50), date bigint, price bigint, - memo varchar(300) + memo varchar(300), + constraint FK_Account_ID + foreign key (uid) + references account(username) + on delete CASCADE ); """ ) diff --git a/routes/auth.py b/routes/auth.py new file mode 100644 index 0000000..dca351c --- /dev/null +++ b/routes/auth.py @@ -0,0 +1,8 @@ +from fastapi import APIRouter +from service.auth_service import Credential + +router = APIRouter() + +@router.post("/auth/login") +def login(auth: Credential): + return {"ok": 1, "token": "Basic {}"} diff --git a/routes/balance.py b/routes/balance.py index 945f595..1a9bfce 100644 --- a/routes/balance.py +++ b/routes/balance.py @@ -5,14 +5,20 @@ from service.balance_service import Balance, BalanceService, UpdateForm router = APIRouter() @router.post("/balance", status_code=201) -def insert(balance: Balance): +def insert(balance: Balance, resp: Response): started = datetime.now().microsecond / 1000 service = BalanceService() - name = service.create(balance=balance) + ok = service.create(balance=balance) + if not ok == 1: + resp.status_code = 500 + return { + "ok": 0, + "errno": "error occurred to running transaction" + } return { "ok": 1, - "name": name, + "name": balance.name, "respond_time": "{}ms".format(round((datetime.now().microsecond / 1000) - started)) } @@ -63,7 +69,7 @@ def update(action, id, balance: UpdateForm, resp: Response): "errno": "memo value size is too long: (maximum size: 300 bytes, your size: {} bytes)".format(len(balance.memo)) } - service.update( + ok = service.update( int(id), action, { "name": balance.name, @@ -73,6 +79,13 @@ def update(action, id, balance: UpdateForm, resp: Response): } ) + if not ok == 1: + resp.status_code = 500 + return { + "ok": 0, + "errno": "error occurred to running transaction" + } + return { "ok": 1, "id": int(id), @@ -80,10 +93,16 @@ def update(action, id, balance: UpdateForm, resp: Response): } @router.delete("/balance/{id}") -def delete(id): +def delete(id, resp: Response): started = datetime.now().microsecond / 1000 service = BalanceService() - service.delete(int(id)) + ok = service.delete(int(id)) + if not ok == 1: + resp.status_code = 500 + return { + "ok": 0, + "errno": "error occurred to running transaction" + } return { "ok": 1, diff --git a/service/auth_service.py b/service/auth_service.py new file mode 100644 index 0000000..dbe37ff --- /dev/null +++ b/service/auth_service.py @@ -0,0 +1,54 @@ +import base64, psycopg2 +from fastapi import Request +from pydantic import BaseModel +from util.config import conn_param + +class AuthData: + name: str + username: str + password: str + salt: str + +class Register: + name: str + username: str + password: str + +class Credential(BaseModel): + username: str + password: str + +class AuthService: + def __init__(self): + self._conn = psycopg2.connect(conn_param) + + def read(self, username: str): + cur = self._conn.cursor() + + cur.execute("select * from account where username = %s;", (username)) + data = cur.fetchone() + if data == None: + return None + + cur.close() + self._conn.close() + + return AuthData( + name = data[0], + username = data[1], + password = data[2], + salt = data[3] + ) + + def check_auth(self, req: Request) -> bool: + raw = req.headers.get("Authorization") + raw_token = raw.removeprefix("Basic ").encode("ascii") + + token = base64.b64decode(raw_token) + data = token.decode("utf-8").split(":") + + acc = self.read(data[0]) + if acc.username == data[0] and acc.password == data[1]: + return True + + return False diff --git a/service/balance_service.py b/service/balance_service.py index 6fb3f6f..d6d25e1 100644 --- a/service/balance_service.py +++ b/service/balance_service.py @@ -18,19 +18,24 @@ class BalanceService: def __init__(self): self._conn = psycopg2.connect(conn_param) - def create(self, balance: Balance) -> str: + def create(self, balance: Balance): + ok = True cur = self._conn.cursor() - cur.execute( - "insert into balset(name, date, price, memo) values (%s, %s, %s, %s);", - (balance.name, balance.date, balance.price, balance.memo) - ) + try: + cur.execute( + "insert into balset(name, date, price, memo) values (%s, %s, %s, %s);", + (balance.name, balance.date, balance.price, balance.memo) + ) - self._conn.commit() - - cur.close() - self._conn.close() + self._conn.commit() + except: + self._conn.rollback() + ok = False + finally: + cur.close() + self._conn.close() - return balance.name + return ok def read(self, id: int): cur = self._conn.cursor() @@ -53,19 +58,31 @@ class BalanceService: } def update(self, id: int, act: str, balance: UpdateForm): + ok = True cur = self._conn.cursor() - cur.execute(f"update balset set {act} = %s where id = %s;", (balance[act], id)) + try: + cur.execute(f"update balset set {act} = %s where id = %s;", (balance[act], id)) + self._conn.commit() + except: + self._conn.rollback() + ok = False + finally: + cur.close() + self._conn.close() - self._conn.commit() - - cur.close() - self._conn.close() + return ok def delete(self, id: int): + ok = True cur = self._conn.cursor() - cur.execute("delete from balset where id = %s;", (id)) - - self._conn.commit() - - cur.close() - self._conn.close() + try: + cur.execute("delete from balset where id = %s;", (id)) + self._conn.commit() + except: + self._conn.rollback() + ok = False + finally: + cur.close() + self._conn.close() + + return ok diff --git a/util/auth_lib.py b/util/auth_lib.py new file mode 100644 index 0000000..5f24356 --- /dev/null +++ b/util/auth_lib.py @@ -0,0 +1,12 @@ +import base64 +from hashlib import sha256 + +def hash(password: str, salt: str): + return sha256("{}:{}".format(password, salt)) + +def gen_token(username: str, hashed_password: str): + raw = ("{}:{}".format(username, hashed_password)).encode("utf-8") + raw_token = base64.b64encode(raw) + + token = raw_token.decode("ascii") + return token