oauth2 on fastapi

This commit is contained in:
nik012003
2022-06-28 21:49:03 +02:00
parent 4971281f5a
commit e0a881abdb
14 changed files with 159 additions and 189 deletions

View File

@@ -1,10 +1,15 @@
from base64 import b64decode from base64 import b64decode
import sqlite3, uvicorn, sys, bcrypt, secrets, re, os, asyncio, httpx, urllib, websockets from datetime import datetime, timedelta
from fastapi import FastAPI, Request, HTTPException, WebSocket import sqlite3, uvicorn, sys, secrets, re, os, asyncio, httpx, urllib, websockets
from starlette.middleware.sessions import SessionMiddleware from tabnanny import check
from typing import Union
from fastapi import FastAPI, Request, HTTPException, WebSocket, Depends
from pydantic import BaseModel from pydantic import BaseModel
from fastapi.responses import FileResponse, StreamingResponse from fastapi.responses import FileResponse, StreamingResponse
from utils import SQLite, KeyValueStorage, gen_internal_port, ProxyManager, from_name_get_id, STATUS from utils import SQLite, KeyValueStorage, gen_internal_port, ProxyManager, from_name_get_id, STATUS
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
ON_DOCKER = len(sys.argv) > 1 and sys.argv[1] == "DOCKER" ON_DOCKER = len(sys.argv) > 1 and sys.argv[1] == "DOCKER"
DEBUG = len(sys.argv) > 1 and sys.argv[1] == "DEBUG" DEBUG = len(sys.argv) > 1 and sys.argv[1] == "DEBUG"
@@ -15,6 +20,14 @@ db = SQLite('db/firegex.db')
conf = KeyValueStorage(db) conf = KeyValueStorage(db)
firewall = ProxyManager(db) firewall = ProxyManager(db)
JWT_ALGORITHM="HS256"
JWT_SECRET = secrets.token_hex(32)
APP_STATUS = "init"
REACT_BUILD_DIR = "../frontend/build/" if not ON_DOCKER else "frontend/"
REACT_HTML_PATH = os.path.join(REACT_BUILD_DIR,"index.html")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/login", auto_error=False)
crypto = CryptContext(schemes=["bcrypt"], deprecated="auto")
app = FastAPI(debug=DEBUG) app = FastAPI(debug=DEBUG)
@app.on_event("shutdown") @app.on_event("shutdown")
@@ -56,28 +69,38 @@ async def startup_event():
await firewall.reload() await firewall.reload()
app.add_middleware(SessionMiddleware, secret_key=os.urandom(32)) def create_access_token(data: dict):
SESSION_TOKEN = secrets.token_hex(8) global JWT_SECRET
APP_STATUS = "init" to_encode = data.copy()
REACT_BUILD_DIR = "../frontend/build/" if not ON_DOCKER else "frontend/" encoded_jwt = jwt.encode(to_encode, JWT_SECRET, algorithm=JWT_ALGORITHM)
REACT_HTML_PATH = os.path.join(REACT_BUILD_DIR,"index.html") return encoded_jwt
async def check_login(token: str = Depends(oauth2_scheme)):
global JWT_SECRET
if not token:
return False
try:
payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
logged_in: bool = payload.get("logged_in")
except JWTError:
return False
return logged_in
async def is_loggined(auth: bool = Depends(check_login)):
def is_loggined(request: Request): if not auth:
global SESSION_TOKEN raise HTTPException(
return request.session.get("token", "") == SESSION_TOKEN status_code=401,
detail="Could not validate credentials",
def login_check(request: Request): headers={"WWW-Authenticate": "Bearer"},
if is_loggined(request): return True )
raise HTTPException(status_code=401, detail="Invalid login session!") return True
@app.get("/api/status") @app.get("/api/status")
async def get_status(request: Request): async def get_status(auth: bool = Depends(check_login)):
global APP_STATUS global APP_STATUS
return { return {
"status":APP_STATUS, "status":APP_STATUS,
"loggined": is_loggined(request) "loggined": auth
} }
class PasswordForm(BaseModel): class PasswordForm(BaseModel):
@@ -88,58 +111,51 @@ class PasswordChangeForm(BaseModel):
expire: bool expire: bool
@app.post("/api/login") @app.post("/api/login")
async def login_api(request: Request, form: PasswordForm): async def login_api(form: OAuth2PasswordRequestForm = Depends()):
global APP_STATUS, SESSION_TOKEN global APP_STATUS, JWT_SECRET
if APP_STATUS != "run": raise HTTPException(status_code=400) if APP_STATUS != "run": raise HTTPException(status_code=400)
if form.password == "": if form.password == "":
return {"status":"Cannot insert an empty password!"} return {"status":"Cannot insert an empty password!"}
await asyncio.sleep(0.3) # No bruteforce :) await asyncio.sleep(0.3) # No bruteforce :)
if crypto.verify(form.password, conf.get("password")):
print("access granted, good job")
return {"access_token": create_access_token({"logged_in": True}), "token_type": "bearer"}
raise HTTPException(406,"Wrong password!")
if bcrypt.checkpw(form.password.encode(), conf.get("password").encode()):
request.session["token"] = SESSION_TOKEN
return { "status":"ok" }
return {"status":"Wrong password!"}
@app.get("/api/logout")
async def logout(request: Request):
request.session["token"] = False
return { "status":"ok" }
@app.post('/api/change-password') @app.post('/api/change-password')
async def change_password(request: Request, form: PasswordChangeForm): async def change_password(form: PasswordChangeForm, auth: bool = Depends(is_loggined)):
login_check(request)
global APP_STATUS, SESSION_TOKEN global APP_STATUS, JWT_SECRET
if APP_STATUS != "run": raise HTTPException(status_code=400) if APP_STATUS != "run": raise HTTPException(status_code=400)
if form.password == "": if form.password == "":
return {"status":"Cannot insert an empty password!"} return {"status":"Cannot insert an empty password!"}
if form.expire: if form.expire:
SESSION_TOKEN = secrets.token_hex(8) JWT_SECRET = secrets.token_hex(32)
request.session["token"] = SESSION_TOKEN
hash_psw = bcrypt.hashpw(form.password.encode(), bcrypt.gensalt()) hash_psw = crypto.hash(form.password)
conf.put("password",hash_psw.decode()) conf.put("password",hash_psw)
return {"status":"ok"} return {"status":"ok", "access_token": create_access_token({"logged_in": True})}
@app.post('/api/set-password') @app.post('/api/set-password')
async def set_password(request: Request, form: PasswordForm): async def set_password(form: PasswordForm):
global APP_STATUS, SESSION_TOKEN global APP_STATUS, JWT_SECRET
if APP_STATUS != "init": raise HTTPException(status_code=400) if APP_STATUS != "init": raise HTTPException(status_code=400)
if form.password == "": if form.password == "":
return {"status":"Cannot insert an empty password!"} return {"status":"Cannot insert an empty password!"}
hash_psw = bcrypt.hashpw(form.password.encode(), bcrypt.gensalt()) hash_psw = crypto.hash(form.password)
conf.put("password",hash_psw.decode()) conf.put("password",hash_psw)
APP_STATUS = "run" APP_STATUS = "run"
request.session["token"] = SESSION_TOKEN return {"status":"ok", "access_token": create_access_token({"logged_in": True})}
return {"status":"ok"}
@app.get('/api/general-stats') @app.get('/api/general-stats')
async def get_general_stats(request: Request): async def get_general_stats(auth: bool = Depends(is_loggined)):
login_check(request)
return db.query(""" return db.query("""
SELECT SELECT
(SELECT COALESCE(SUM(blocked_packets),0) FROM regexes) closed, (SELECT COALESCE(SUM(blocked_packets),0) FROM regexes) closed,
@@ -148,8 +164,8 @@ async def get_general_stats(request: Request):
""")[0] """)[0]
@app.get('/api/services') @app.get('/api/services')
async def get_services(request: Request): async def get_services(auth: bool = Depends(is_loggined)):
login_check(request)
return db.query(""" return db.query("""
SELECT SELECT
s.service_id `id`, s.service_id `id`,
@@ -164,8 +180,8 @@ async def get_services(request: Request):
""") """)
@app.get('/api/service/{service_id}') @app.get('/api/service/{service_id}')
async def get_service(request: Request, service_id: str): async def get_service(service_id: str, auth: bool = Depends(is_loggined)):
login_check(request)
res = db.query(""" res = db.query("""
SELECT SELECT
s.service_id `id`, s.service_id `id`,
@@ -182,26 +198,26 @@ async def get_service(request: Request, service_id: str):
return res[0] return res[0]
@app.get('/api/service/{service_id}/stop') @app.get('/api/service/{service_id}/stop')
async def get_service_stop(request: Request, service_id: str): async def get_service_stop(service_id: str, auth: bool = Depends(is_loggined)):
login_check(request)
await firewall.get(service_id).next(STATUS.STOP) await firewall.get(service_id).next(STATUS.STOP)
return {'status': 'ok'} return {'status': 'ok'}
@app.get('/api/service/{service_id}/pause') @app.get('/api/service/{service_id}/pause')
async def get_service_pause(request: Request, service_id: str): async def get_service_pause(service_id: str, auth: bool = Depends(is_loggined)):
login_check(request)
await firewall.get(service_id).next(STATUS.PAUSE) await firewall.get(service_id).next(STATUS.PAUSE)
return {'status': 'ok'} return {'status': 'ok'}
@app.get('/api/service/{service_id}/start') @app.get('/api/service/{service_id}/start')
async def get_service_start(request: Request, service_id: str): async def get_service_start(service_id: str, auth: bool = Depends(is_loggined)):
login_check(request)
await firewall.get(service_id).next(STATUS.ACTIVE) await firewall.get(service_id).next(STATUS.ACTIVE)
return {'status': 'ok'} return {'status': 'ok'}
@app.get('/api/service/{service_id}/delete') @app.get('/api/service/{service_id}/delete')
async def get_service_delete(request: Request, service_id: str): async def get_service_delete(service_id: str, auth: bool = Depends(is_loggined)):
login_check(request)
db.query('DELETE FROM services WHERE service_id = ?;', service_id) db.query('DELETE FROM services WHERE service_id = ?;', service_id)
db.query('DELETE FROM regexes WHERE service_id = ?;', service_id) db.query('DELETE FROM regexes WHERE service_id = ?;', service_id)
await firewall.remove(service_id) await firewall.remove(service_id)
@@ -209,16 +225,16 @@ async def get_service_delete(request: Request, service_id: str):
@app.get('/api/service/{service_id}/regen-port') @app.get('/api/service/{service_id}/regen-port')
async def get_regen_port(request: Request, service_id: str): async def get_regen_port(service_id: str, auth: bool = Depends(is_loggined)):
login_check(request)
db.query('UPDATE services SET internal_port = ? WHERE service_id = ?;', gen_internal_port(db), service_id) db.query('UPDATE services SET internal_port = ? WHERE service_id = ?;', gen_internal_port(db), service_id)
await firewall.get(service_id).update_port() await firewall.get(service_id).update_port()
return {'status': 'ok'} return {'status': 'ok'}
@app.get('/api/service/{service_id}/regexes') @app.get('/api/service/{service_id}/regexes')
async def get_service_regexes(request: Request, service_id: str): async def get_service_regexes(service_id: str, auth: bool = Depends(is_loggined)):
login_check(request)
return db.query(""" return db.query("""
SELECT SELECT
regex, mode, regex_id `id`, service_id, is_blacklist, regex, mode, regex_id `id`, service_id, is_blacklist,
@@ -227,8 +243,8 @@ async def get_service_regexes(request: Request, service_id: str):
""", service_id) """, service_id)
@app.get('/api/regex/{regex_id}') @app.get('/api/regex/{regex_id}')
async def get_regex_id(request: Request, regex_id: int): async def get_regex_id(regex_id: int, auth: bool = Depends(is_loggined)):
login_check(request)
res = db.query(""" res = db.query("""
SELECT SELECT
regex, mode, regex_id `id`, service_id, is_blacklist, regex, mode, regex_id `id`, service_id, is_blacklist,
@@ -239,8 +255,8 @@ async def get_regex_id(request: Request, regex_id: int):
return res[0] return res[0]
@app.get('/api/regex/{regex_id}/delete') @app.get('/api/regex/{regex_id}/delete')
async def get_regex_delete(request: Request, regex_id: int): async def get_regex_delete(regex_id: int, auth: bool = Depends(is_loggined)):
login_check(request)
res = db.query('SELECT * FROM regexes WHERE regex_id = ?;', regex_id) res = db.query('SELECT * FROM regexes WHERE regex_id = ?;', regex_id)
if len(res) != 0: if len(res) != 0:
@@ -257,8 +273,8 @@ class RegexAddForm(BaseModel):
is_case_sensitive: bool is_case_sensitive: bool
@app.post('/api/regexes/add') @app.post('/api/regexes/add')
async def post_regexes_add(request: Request, form: RegexAddForm): async def post_regexes_add(form: RegexAddForm, auth: bool = Depends(is_loggined)):
login_check(request)
try: try:
re.compile(b64decode(form.regex)) re.compile(b64decode(form.regex))
except Exception: except Exception:
@@ -277,8 +293,8 @@ class ServiceAddForm(BaseModel):
port: int port: int
@app.post('/api/services/add') @app.post('/api/services/add')
async def post_services_add(request: Request, form: ServiceAddForm): async def post_services_add(form: ServiceAddForm, auth: bool = Depends(is_loggined)):
login_check(request)
serv_id = from_name_get_id(form.name) serv_id = from_name_get_id(form.name)
try: try:
db.query("INSERT INTO services (name, service_id, internal_port, public_port, status) VALUES (?, ?, ?, ?, ?)", db.query("INSERT INTO services (name, service_id, internal_port, public_port, status) VALUES (?, ?, ?, ?, ?)",
@@ -323,7 +339,7 @@ if DEBUG:
await asyncio.gather(fwd_task, rev_task) await asyncio.gather(fwd_task, rev_task)
@app.get("/{full_path:path}") @app.get("/{full_path:path}")
async def catch_all(request: Request, full_path:str): async def catch_all(full_path:str):
if DEBUG: if DEBUG:
try: try:
return await frontend_debug_proxy(full_path) return await frontend_debug_proxy(full_path)
@@ -339,5 +355,6 @@ if __name__ == '__main__':
host="0.0.0.0", host="0.0.0.0",
port=int(os.getenv("PORT","4444")), port=int(os.getenv("PORT","4444")),
reload=DEBUG, reload=DEBUG,
access_log=DEBUG access_log=DEBUG,
workers=2
) )

View File

@@ -1,6 +1,4 @@
import subprocess, re, os, asyncio import re, os, asyncio
#c++ -o proxy proxy.cpp
class Filter: class Filter:
def __init__(self, regex, is_case_sensitive=True, is_blacklist=True, c_to_s=False, s_to_c=False, blocked_packets=0, code=None): def __init__(self, regex, is_case_sensitive=True, is_blacklist=True, c_to_s=False, s_to_c=False, blocked_packets=0, code=None):

View File

@@ -1,5 +1,5 @@
fastapi[all] fastapi[all]
httpx httpx
uvicorn[standard] uvicorn[standard]
bcrypt passlib[bcrypt]
kthread python-jose[cryptography]

View File

@@ -182,14 +182,17 @@ class ServiceManager:
def __proxy_starter(self,to): def __proxy_starter(self,to):
async def func(): async def func():
while True: try:
if check_port_is_open(self.proxy.public_port): while True:
self._set_status(to) if check_port_is_open(self.proxy.public_port):
await self.proxy.start(in_pause=(to==STATUS.PAUSE)) self._set_status(to)
self._set_status(STATUS.STOP) await self.proxy.start(in_pause=(to==STATUS.PAUSE))
return self._set_status(STATUS.STOP)
else: return
await asyncio.sleep(.5) else:
await asyncio.sleep(.5)
except Exception:
await self.proxy.stop()
self.starter = asyncio.create_task(func()) self.starter = asyncio.create_task(func())
class ProxyManager: class ProxyManager:

View File

@@ -1,13 +0,0 @@
{
"files": {
"main.css": "/static/css/main.0efd334b.css",
"main.js": "/static/js/main.f153478b.js",
"index.html": "/index.html",
"main.0efd334b.css.map": "/static/css/main.0efd334b.css.map",
"main.f153478b.js.map": "/static/js/main.f153478b.js.map"
},
"entrypoints": [
"static/css/main.0efd334b.css",
"static/js/main.f153478b.js"
]
}

View File

@@ -1 +0,0 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="manifest" href="/site.webmanifest"><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#FFFFFFFF"/><meta name="description" content="Firegex by Pwnzer0tt1"/><title>Firegex</title><script defer="defer" src="/static/js/main.f153478b.js"></script><link href="/static/css/main.0efd334b.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

View File

@@ -1,2 +0,0 @@
@import url(https://fonts.googleapis.com/css2?family=Lato&display=swap);.center-flex,.center-flex-row{align-items:center;display:flex;justify-content:center}.center-flex-row{flex-direction:column}.flex-spacer{flex-grow:1}.Footer_center-flex-row__EeEEN,.Footer_center-flex__vCncJ,.Footer_footer__PxxIj{align-items:center;display:flex;justify-content:center}.Footer_center-flex-row__EeEEN{flex-direction:column}.Footer_flex-spacer__MHTsy{flex-grow:1}.Footer_footer__PxxIj{background-color:#242a33;height:150px;margin-top:50px}.Header_header__OKWO7{align-items:center;background-color:#242a33;display:flex;height:140px;justify-content:center;width:100%}.Header_logo__shVBB{height:70%;margin-left:40px;width:200px}body{font-family:Lato,sans-serif;margin:0}.ServiceRow_center-flex-row__g7ljt,.ServiceRow_center-flex__BYani,.ServiceRow_row__X48wF{align-items:center;display:flex;justify-content:center}.ServiceRow_center-flex-row__g7ljt{flex-direction:column}.ServiceRow_flex-spacer__zolmX{flex-grow:1}::-webkit-scrollbar{background:#333;cursor:pointer;margin:3px;width:12px}::-webkit-scrollbar-thumb{background:#757575;border-radius:8px}.ServiceRow_row__X48wF{border-radius:20px;margin:10px;padding:30px 0;width:95%}.ServiceRow_name__fL\+Lz{color:#fff;font-size:2.3em;font-weight:bolder;margin-bottom:13px;margin-right:10px}.RegexView_box__PVbdO{margin:5px;padding:30px}.RegexView_regex_text__rxij9{background-color:#25262b;border-radius:15px;padding:10px}
/*# sourceMappingURL=main.0efd334b.css.map*/

View File

@@ -1 +0,0 @@
{"version":3,"file":"static/css/main.0efd334b.css","mappings":"wEAUA,8BAGE,mBAFA,aACA,sBACA,CAGF,iBAEE,sBAGF,aACE,YAZF,gFAGE,mBAFA,aACA,sBACA,CAGF,+BAEE,sBAGF,2BACE,YCnBF,sBAGI,yBAFA,aACA,eCJY,CCEhB,sBAKI,mBAFA,wBDLY,CCMZ,aAFA,aAIA,uBALA,UAKA,CAGJ,oBAGI,WADA,iBADA,WAEA,CHVJ,KAEE,4BADA,QACA,CAGF,yFAGE,mBAFA,aACA,sBACA,CAGF,mCAEE,sBAGF,+BACE,YAGF,oBAGE,gBACA,eAFA,UAAU,CADV,UAGA,CAEF,0BACE,mBACA,kBI9BF,uBAGI,mBACA,YAFA,eADA,SAGA,CAIJ,yBAKI,WAJA,gBACA,mBAEA,mBADA,iBAEA,CCbJ,sBAEI,UAAS,CADT,YACU,CAGd,6BAEI,wBHPS,CGQT,mBAFA,YAEA","sources":["index.scss","components/Footer/Footer.module.scss","_vars.scss","components/Header/Header.module.scss","components/ServiceRow/ServiceRow.module.scss","components/RegexView/RegexView.module.scss"],"sourcesContent":["\n@use \"vars\" as *;\n\n@import url('https://fonts.googleapis.com/css2?family=Lato&display=swap');\n\nbody {\n margin: 0;\n font-family: 'Lato', sans-serif;\n}\n\n.center-flex{\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n.center-flex-row{\n @extend .center-flex;\n flex-direction: column;\n}\n\n.flex-spacer{\n flex-grow: 1;\n}\n\n::-webkit-scrollbar {\n width: 12px;\n margin:3px;\n background: #333;\n cursor: pointer;\n}\n::-webkit-scrollbar-thumb {\n background: #757575;\n border-radius: 8px;\n}","@use \"../../vars\" as *;\r\n@use \"../../index.scss\" as *;\r\n\r\n.footer{\r\n height: 150px;\r\n margin-top: 50px;\r\n background-color: $primary_color;\r\n @extend .center-flex;\r\n}","\r\n$primary_color: #242a33;\r\n$second_color: #1A1B1E;\r\n$third_color:#25262b;\r\n","\r\n@use \"../../vars\" as *;\r\n\r\n.header{\r\n width: 100%;\r\n height: 140px;\r\n background-color: $primary_color;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.logo{\r\n width: 200px;\r\n margin-left: 40px;\r\n height: 70%;\r\n}","\r\n@use \"../../index.scss\" as *;\r\n\r\n.row{\r\n width: 95%;\r\n padding: 30px 0px;\r\n border-radius: 20px;\r\n margin: 10px;\r\n @extend .center-flex;\r\n}\r\n\r\n.name{\r\n font-size: 2.3em;\r\n font-weight: bolder;\r\n margin-right: 10px;\r\n margin-bottom: 13px;\r\n color:#FFF;\r\n}","\r\n@use \"../../vars\" as *;\r\n\r\n.box{\r\n padding:30px;\r\n margin:5px;\r\n}\r\n\r\n.regex_text{\r\n padding: 10px;\r\n background-color: $third_color;\r\n border-radius: 15px;\r\n}"],"names":[],"sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -1,70 +0,0 @@
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* React Router v6.3.0
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/
/** @license React v16.13.1
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

File diff suppressed because one or more lines are too long

View File

@@ -98,7 +98,7 @@ function App() {
if(!res){ if(!res){
setSystemStatus({...systemStatus, loggined:true}) setSystemStatus({...systemStatus, loggined:true})
}else{ }else{
setError(res) setError("Login failed")
} }
}).catch( err => setError(err.toString())) }).catch( err => setError(err.toString()))
setLoadingBtn(false) setLoadingBtn(false)

View File

@@ -23,13 +23,24 @@ export type ServerResponse = {
status:string status:string
} }
export type ServerResponseToken = {
status:string,
access_token?:string
}
export type LoginResponse = {
status?:string,
access_token:string,
token_type:string
}
export type ServerStatusResponse = { export type ServerStatusResponse = {
status:string, status:string,
loggined:boolean loggined:boolean
} }
export type PasswordSend = { export type PasswordSend = {
password:string password:string,
} }
export type ChangePassword = { export type ChangePassword = {

View File

@@ -1,7 +1,7 @@
import { showNotification } from "@mantine/notifications"; import { showNotification } from "@mantine/notifications";
import { ImCross } from "react-icons/im"; import { ImCross } from "react-icons/im";
import { TiTick } from "react-icons/ti" import { TiTick } from "react-icons/ti"
import { GeneralStats, Service, ServiceAddForm, ServerResponse, RegexFilter, RegexAddForm, ServerStatusResponse, PasswordSend, ChangePassword } from "./models"; import { GeneralStats, Service, ServiceAddForm, ServerResponse, RegexFilter, RegexAddForm, ServerStatusResponse, PasswordSend, ChangePassword, LoginResponse, ServerResponseToken } from "./models";
var Buffer = require('buffer').Buffer var Buffer = require('buffer').Buffer
@@ -9,9 +9,12 @@ export const eventUpdateName = "update-info"
export async function getapi(path:string):Promise<any>{ export async function getapi(path:string):Promise<any>{
return await new Promise((resolve, reject) => { return await new Promise((resolve, reject) => {
fetch(`/api/${path}`,{credentials: "same-origin"}) fetch(`/api/${path}`,{
.then(res => { credentials: "same-origin",
headers: { "Authorization" : "Bearer " + window.localStorage.getItem("access_token")}
}).then(res => {
if(res.status === 401) window.location.reload() if(res.status === 401) window.location.reload()
if(!res.ok) reject(res.statusText) if(!res.ok) reject(res.statusText)
res.json().then( res => resolve(res) ).catch( err => reject(err)) res.json().then( res => resolve(res) ).catch( err => reject(err))
@@ -22,7 +25,30 @@ export async function getapi(path:string):Promise<any>{
}); });
} }
export async function postapi(path:string,data:any):Promise<any>{ export async function postapi(path:string,data:any,is_form:boolean=false):Promise<any>{
return await new Promise((resolve, reject) => {
fetch(`/api/${path}`, {
method: 'POST',
credentials: "same-origin",
cache: 'no-cache',
headers: {
'Content-Type': is_form ? 'application/x-www-form-urlencoded' : 'application/json',
"Authorization" : "Bearer " + window.localStorage.getItem("access_token")
},
body: is_form ? data : JSON.stringify(data)
}).then(res => {
if(res.status === 401) window.location.reload()
if(res.status === 406) resolve({status:"Wrong Password"})
if(!res.ok) reject(res.statusText)
res.json().then( res => resolve(res) ).catch( err => reject(err))
})
.catch(err => {
reject(err)
})
});
}
export async function postform(path:string,data:any):Promise<any>{
return await new Promise((resolve, reject) => { return await new Promise((resolve, reject) => {
fetch(`/api/${path}`, { fetch(`/api/${path}`, {
method: 'POST', method: 'POST',
@@ -64,23 +90,29 @@ export async function serviceinfo(service_id:string){
} }
export async function logout(){ export async function logout(){
const { status } = await getapi(`logout`) as ServerResponse; window.localStorage.removeItem("access_token")
return status === "ok"?undefined:status
} }
export async function setpassword(data:PasswordSend) { export async function setpassword(data:PasswordSend) {
const { status } = await postapi("set-password",data) as ServerResponse; const { status, access_token } = await postapi("set-password",data) as ServerResponseToken;
if (access_token)
window.localStorage.setItem("access_token", access_token);
return status === "ok"?undefined:status return status === "ok"?undefined:status
} }
export async function changepassword(data:ChangePassword) { export async function changepassword(data:ChangePassword) {
const { status } = await postapi("change-password",data) as ServerResponse; const { status, access_token } = await postapi("change-password",data) as ServerResponseToken;
return status === "ok"?undefined:status console.log(access_token)
if (access_token)
window.localStorage.setItem("access_token", access_token);
return status === "ok"?undefined:status
} }
export async function login(data:PasswordSend) { export async function login(data:PasswordSend) {
const { status } = await postapi("login",data) as ServerResponse; const from = "username=login&password=" + encodeURI(data.password);
return status === "ok"?undefined:status const { status, access_token } = await postapi("login",from,true) as LoginResponse;
window.localStorage.setItem("access_token", access_token);
return status;
} }
export async function deleteregex(regex_id:number){ export async function deleteregex(regex_id:number){