parent 80a38f0d50
author DomySh <me@domysh.com> 1656456810 +0200 committer DomySh <me@domysh.com> 1656457473 +0200 Small Fixes (Stable only with 1 worker!)
This commit is contained in:
100
backend/app.py
100
backend/app.py
@@ -1,10 +1,7 @@
|
|||||||
from base64 import b64decode
|
from base64 import b64decode
|
||||||
from datetime import datetime, timedelta
|
|
||||||
import sqlite3, uvicorn, sys, secrets, re, os, asyncio, httpx, urllib, websockets
|
import sqlite3, uvicorn, sys, secrets, re, os, asyncio, httpx, urllib, websockets
|
||||||
from tabnanny import check
|
from fastapi import FastAPI, HTTPException, WebSocket, Depends
|
||||||
from typing import Union
|
from pydantic import BaseModel, BaseSettings
|
||||||
from fastapi import FastAPI, Request, HTTPException, WebSocket, Depends
|
|
||||||
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 fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
||||||
@@ -20,16 +17,22 @@ 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)
|
class Settings(BaseSettings):
|
||||||
APP_STATUS = "init"
|
JWT_ALGORITHM: str = "HS256"
|
||||||
REACT_BUILD_DIR = "../frontend/build/" if not ON_DOCKER else "frontend/"
|
REACT_BUILD_DIR: str = "../frontend/build/" if not ON_DOCKER else "frontend/"
|
||||||
REACT_HTML_PATH = os.path.join(REACT_BUILD_DIR,"index.html")
|
REACT_HTML_PATH: str = os.path.join(REACT_BUILD_DIR,"index.html")
|
||||||
|
|
||||||
|
|
||||||
|
settings = Settings()
|
||||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/login", auto_error=False)
|
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/login", auto_error=False)
|
||||||
crypto = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
crypto = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||||
|
|
||||||
app = FastAPI(debug=DEBUG)
|
app = FastAPI(debug=DEBUG)
|
||||||
|
|
||||||
|
def APP_STATUS(): return "init" if conf.get("password") is None else "run"
|
||||||
|
def JWT_SECRET(): return conf.get("secret")
|
||||||
|
|
||||||
@app.on_event("shutdown")
|
@app.on_event("shutdown")
|
||||||
async def shutdown_event():
|
async def shutdown_event():
|
||||||
await firewall.close()
|
await firewall.close()
|
||||||
@@ -37,50 +40,21 @@ async def shutdown_event():
|
|||||||
|
|
||||||
@app.on_event("startup")
|
@app.on_event("startup")
|
||||||
async def startup_event():
|
async def startup_event():
|
||||||
global APP_STATUS
|
db.init()
|
||||||
db.connect()
|
if not JWT_SECRET(): conf.put("secret", secrets.token_hex(32))
|
||||||
db.create_schema({
|
|
||||||
'services': {
|
|
||||||
'status': 'VARCHAR(100) NOT NULL',
|
|
||||||
'service_id': 'VARCHAR(100) PRIMARY KEY',
|
|
||||||
'internal_port': 'INT NOT NULL CHECK(internal_port > 0 and internal_port < 65536) UNIQUE',
|
|
||||||
'public_port': 'INT NOT NULL CHECK(internal_port > 0 and internal_port < 65536) UNIQUE',
|
|
||||||
'name': 'VARCHAR(100) NOT NULL'
|
|
||||||
},
|
|
||||||
'regexes': {
|
|
||||||
'regex': 'TEXT NOT NULL',
|
|
||||||
'mode': 'VARCHAR(1) NOT NULL',
|
|
||||||
'service_id': 'VARCHAR(100) NOT NULL',
|
|
||||||
'is_blacklist': 'BOOLEAN NOT NULL CHECK (is_blacklist IN (0, 1))',
|
|
||||||
'blocked_packets': 'INTEGER UNSIGNED NOT NULL DEFAULT 0',
|
|
||||||
'regex_id': 'INTEGER PRIMARY KEY',
|
|
||||||
'is_case_sensitive' : 'BOOLEAN NOT NULL CHECK (is_case_sensitive IN (0, 1))',
|
|
||||||
'FOREIGN KEY (service_id)':'REFERENCES services (service_id)',
|
|
||||||
},
|
|
||||||
'keys_values': {
|
|
||||||
'key': 'VARCHAR(100) PRIMARY KEY',
|
|
||||||
'value': 'VARCHAR(100) NOT NULL',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
db.query("CREATE UNIQUE INDEX IF NOT EXISTS unique_regex_service ON regexes (regex,service_id,is_blacklist,mode,is_case_sensitive);")
|
|
||||||
|
|
||||||
if not conf.get("password") is None:
|
|
||||||
APP_STATUS = "run"
|
|
||||||
|
|
||||||
await firewall.reload()
|
await firewall.reload()
|
||||||
|
|
||||||
|
|
||||||
def create_access_token(data: dict):
|
def create_access_token(data: dict):
|
||||||
global JWT_SECRET
|
|
||||||
to_encode = data.copy()
|
to_encode = data.copy()
|
||||||
encoded_jwt = jwt.encode(to_encode, JWT_SECRET, algorithm=JWT_ALGORITHM)
|
encoded_jwt = jwt.encode(to_encode, JWT_SECRET(), algorithm=settings.JWT_ALGORITHM)
|
||||||
return encoded_jwt
|
return encoded_jwt
|
||||||
|
|
||||||
async def check_login(token: str = Depends(oauth2_scheme)):
|
async def check_login(token: str = Depends(oauth2_scheme)):
|
||||||
global JWT_SECRET
|
|
||||||
if not token:
|
if not token:
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
|
payload = jwt.decode(token, JWT_SECRET(), algorithms=[settings.JWT_ALGORITHM])
|
||||||
logged_in: bool = payload.get("logged_in")
|
logged_in: bool = payload.get("logged_in")
|
||||||
except JWTError:
|
except JWTError:
|
||||||
return False
|
return False
|
||||||
@@ -97,9 +71,8 @@ async def is_loggined(auth: bool = Depends(check_login)):
|
|||||||
|
|
||||||
@app.get("/api/status")
|
@app.get("/api/status")
|
||||||
async def get_status(auth: bool = Depends(check_login)):
|
async def get_status(auth: bool = Depends(check_login)):
|
||||||
global APP_STATUS
|
|
||||||
return {
|
return {
|
||||||
"status":APP_STATUS,
|
"status": APP_STATUS(),
|
||||||
"loggined": auth
|
"loggined": auth
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,29 +85,23 @@ class PasswordChangeForm(BaseModel):
|
|||||||
|
|
||||||
@app.post("/api/login")
|
@app.post("/api/login")
|
||||||
async def login_api(form: OAuth2PasswordRequestForm = Depends()):
|
async def login_api(form: OAuth2PasswordRequestForm = Depends()):
|
||||||
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")):
|
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"}
|
return {"access_token": create_access_token({"logged_in": True}), "token_type": "bearer"}
|
||||||
raise HTTPException(406,"Wrong password!")
|
raise HTTPException(406,"Wrong password!")
|
||||||
|
|
||||||
|
|
||||||
@app.post('/api/change-password')
|
@app.post('/api/change-password')
|
||||||
async def change_password(form: PasswordChangeForm, auth: bool = Depends(is_loggined)):
|
async def change_password(form: PasswordChangeForm, auth: bool = Depends(is_loggined)):
|
||||||
|
if APP_STATUS() != "run": raise HTTPException(status_code=400)
|
||||||
global APP_STATUS, JWT_SECRET
|
|
||||||
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:
|
||||||
JWT_SECRET = secrets.token_hex(32)
|
conf.put("secret", secrets.token_hex(32))
|
||||||
|
|
||||||
hash_psw = crypto.hash(form.password)
|
hash_psw = crypto.hash(form.password)
|
||||||
conf.put("password",hash_psw)
|
conf.put("password",hash_psw)
|
||||||
@@ -143,14 +110,11 @@ async def change_password(form: PasswordChangeForm, auth: bool = Depends(is_logg
|
|||||||
|
|
||||||
@app.post('/api/set-password')
|
@app.post('/api/set-password')
|
||||||
async def set_password(form: PasswordForm):
|
async def set_password(form: PasswordForm):
|
||||||
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 = crypto.hash(form.password)
|
hash_psw = crypto.hash(form.password)
|
||||||
conf.put("password",hash_psw)
|
conf.put("password",hash_psw)
|
||||||
APP_STATUS = "run"
|
|
||||||
return {"status":"ok", "access_token": create_access_token({"logged_in": True})}
|
return {"status":"ok", "access_token": create_access_token({"logged_in": True})}
|
||||||
|
|
||||||
@app.get('/api/general-stats')
|
@app.get('/api/general-stats')
|
||||||
@@ -165,7 +129,6 @@ async def get_general_stats(auth: bool = Depends(is_loggined)):
|
|||||||
|
|
||||||
@app.get('/api/services')
|
@app.get('/api/services')
|
||||||
async def get_services(auth: bool = Depends(is_loggined)):
|
async def get_services(auth: bool = Depends(is_loggined)):
|
||||||
|
|
||||||
return db.query("""
|
return db.query("""
|
||||||
SELECT
|
SELECT
|
||||||
s.service_id `id`,
|
s.service_id `id`,
|
||||||
@@ -199,25 +162,21 @@ async def get_service(service_id: str, auth: bool = Depends(is_loggined)):
|
|||||||
|
|
||||||
@app.get('/api/service/{service_id}/stop')
|
@app.get('/api/service/{service_id}/stop')
|
||||||
async def get_service_stop(service_id: str, auth: bool = Depends(is_loggined)):
|
async def get_service_stop(service_id: str, auth: bool = Depends(is_loggined)):
|
||||||
|
|
||||||
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(service_id: str, auth: bool = Depends(is_loggined)):
|
async def get_service_pause(service_id: str, auth: bool = Depends(is_loggined)):
|
||||||
|
|
||||||
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(service_id: str, auth: bool = Depends(is_loggined)):
|
async def get_service_start(service_id: str, auth: bool = Depends(is_loggined)):
|
||||||
|
|
||||||
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(service_id: str, auth: bool = Depends(is_loggined)):
|
async def get_service_delete(service_id: str, auth: bool = Depends(is_loggined)):
|
||||||
|
|
||||||
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)
|
||||||
@@ -226,7 +185,6 @@ async def get_service_delete(service_id: str, auth: bool = Depends(is_loggined))
|
|||||||
|
|
||||||
@app.get('/api/service/{service_id}/regen-port')
|
@app.get('/api/service/{service_id}/regen-port')
|
||||||
async def get_regen_port(service_id: str, auth: bool = Depends(is_loggined)):
|
async def get_regen_port(service_id: str, auth: bool = Depends(is_loggined)):
|
||||||
|
|
||||||
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'}
|
||||||
@@ -234,7 +192,6 @@ async def get_regen_port(service_id: str, auth: bool = Depends(is_loggined)):
|
|||||||
|
|
||||||
@app.get('/api/service/{service_id}/regexes')
|
@app.get('/api/service/{service_id}/regexes')
|
||||||
async def get_service_regexes(service_id: str, auth: bool = Depends(is_loggined)):
|
async def get_service_regexes(service_id: str, auth: bool = Depends(is_loggined)):
|
||||||
|
|
||||||
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,
|
||||||
@@ -244,7 +201,6 @@ async def get_service_regexes(service_id: str, auth: bool = Depends(is_loggined)
|
|||||||
|
|
||||||
@app.get('/api/regex/{regex_id}')
|
@app.get('/api/regex/{regex_id}')
|
||||||
async def get_regex_id(regex_id: int, auth: bool = Depends(is_loggined)):
|
async def get_regex_id(regex_id: int, auth: bool = Depends(is_loggined)):
|
||||||
|
|
||||||
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,
|
||||||
@@ -256,9 +212,7 @@ async def get_regex_id(regex_id: int, auth: bool = Depends(is_loggined)):
|
|||||||
|
|
||||||
@app.get('/api/regex/{regex_id}/delete')
|
@app.get('/api/regex/{regex_id}/delete')
|
||||||
async def get_regex_delete(regex_id: int, auth: bool = Depends(is_loggined)):
|
async def get_regex_delete(regex_id: int, auth: bool = Depends(is_loggined)):
|
||||||
|
|
||||||
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:
|
||||||
db.query('DELETE FROM regexes WHERE regex_id = ?;', regex_id)
|
db.query('DELETE FROM regexes WHERE regex_id = ?;', regex_id)
|
||||||
await firewall.get(res[0]["service_id"]).update_filters()
|
await firewall.get(res[0]["service_id"]).update_filters()
|
||||||
@@ -274,7 +228,6 @@ class RegexAddForm(BaseModel):
|
|||||||
|
|
||||||
@app.post('/api/regexes/add')
|
@app.post('/api/regexes/add')
|
||||||
async def post_regexes_add(form: RegexAddForm, auth: bool = Depends(is_loggined)):
|
async def post_regexes_add(form: RegexAddForm, auth: bool = Depends(is_loggined)):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
re.compile(b64decode(form.regex))
|
re.compile(b64decode(form.regex))
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -294,7 +247,6 @@ class ServiceAddForm(BaseModel):
|
|||||||
|
|
||||||
@app.post('/api/services/add')
|
@app.post('/api/services/add')
|
||||||
async def post_services_add(form: ServiceAddForm, auth: bool = Depends(is_loggined)):
|
async def post_services_add(form: ServiceAddForm, auth: bool = Depends(is_loggined)):
|
||||||
|
|
||||||
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 (?, ?, ?, ?, ?)",
|
||||||
@@ -312,9 +264,9 @@ async def frontend_debug_proxy(path):
|
|||||||
return StreamingResponse(resp.aiter_bytes(),status_code=resp.status_code)
|
return StreamingResponse(resp.aiter_bytes(),status_code=resp.status_code)
|
||||||
|
|
||||||
async def react_deploy(path):
|
async def react_deploy(path):
|
||||||
file_request = os.path.join(REACT_BUILD_DIR, path)
|
file_request = os.path.join(settings.REACT_BUILD_DIR, path)
|
||||||
if not os.path.isfile(file_request):
|
if not os.path.isfile(file_request):
|
||||||
return FileResponse(REACT_HTML_PATH, media_type='text/html')
|
return FileResponse(settings.REACT_HTML_PATH, media_type='text/html')
|
||||||
else:
|
else:
|
||||||
return FileResponse(file_request)
|
return FileResponse(file_request)
|
||||||
|
|
||||||
@@ -356,5 +308,5 @@ if __name__ == '__main__':
|
|||||||
port=int(os.getenv("PORT","4444")),
|
port=int(os.getenv("PORT","4444")),
|
||||||
reload=DEBUG,
|
reload=DEBUG,
|
||||||
access_log=DEBUG,
|
access_log=DEBUG,
|
||||||
workers=2
|
workers=1
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ class Proxy:
|
|||||||
async with self.status_change:
|
async with self.status_change:
|
||||||
if self.isactive():
|
if self.isactive():
|
||||||
self.process.kill()
|
self.process.kill()
|
||||||
self.process = None
|
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -92,9 +91,7 @@ class Proxy:
|
|||||||
await self.update_config(filters_codes)
|
await self.update_config(filters_codes)
|
||||||
|
|
||||||
def isactive(self):
|
def isactive(self):
|
||||||
if self.process and not self.process.returncode is None:
|
return self.process and self.process.returncode is None
|
||||||
self.process = None
|
|
||||||
return True if self.process else False
|
|
||||||
|
|
||||||
async def pause(self):
|
async def pause(self):
|
||||||
if self.isactive():
|
if self.isactive():
|
||||||
|
|||||||
@@ -443,7 +443,6 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
if (argc < 5)
|
if (argc < 5)
|
||||||
|
|||||||
@@ -47,6 +47,33 @@ class SQLite():
|
|||||||
try: self.conn.commit()
|
try: self.conn.commit()
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
self.connect()
|
||||||
|
self.create_schema({
|
||||||
|
'services': {
|
||||||
|
'status': 'VARCHAR(100) NOT NULL',
|
||||||
|
'service_id': 'VARCHAR(100) PRIMARY KEY',
|
||||||
|
'internal_port': 'INT NOT NULL CHECK(internal_port > 0 and internal_port < 65536) UNIQUE',
|
||||||
|
'public_port': 'INT NOT NULL CHECK(internal_port > 0 and internal_port < 65536) UNIQUE',
|
||||||
|
'name': 'VARCHAR(100) NOT NULL'
|
||||||
|
},
|
||||||
|
'regexes': {
|
||||||
|
'regex': 'TEXT NOT NULL',
|
||||||
|
'mode': 'VARCHAR(1) NOT NULL',
|
||||||
|
'service_id': 'VARCHAR(100) NOT NULL',
|
||||||
|
'is_blacklist': 'BOOLEAN NOT NULL CHECK (is_blacklist IN (0, 1))',
|
||||||
|
'blocked_packets': 'INTEGER UNSIGNED NOT NULL DEFAULT 0',
|
||||||
|
'regex_id': 'INTEGER PRIMARY KEY',
|
||||||
|
'is_case_sensitive' : 'BOOLEAN NOT NULL CHECK (is_case_sensitive IN (0, 1))',
|
||||||
|
'FOREIGN KEY (service_id)':'REFERENCES services (service_id)',
|
||||||
|
},
|
||||||
|
'keys_values': {
|
||||||
|
'key': 'VARCHAR(100) PRIMARY KEY',
|
||||||
|
'value': 'VARCHAR(100) NOT NULL',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
self.query("CREATE UNIQUE INDEX IF NOT EXISTS unique_regex_service ON regexes (regex,service_id,is_blacklist,mode,is_case_sensitive);")
|
||||||
|
|
||||||
class KeyValueStorage:
|
class KeyValueStorage:
|
||||||
def __init__(self, db):
|
def __init__(self, db):
|
||||||
self.db = db
|
self.db = db
|
||||||
@@ -70,8 +97,7 @@ class STATUS:
|
|||||||
PAUSE = "pause"
|
PAUSE = "pause"
|
||||||
ACTIVE = "active"
|
ACTIVE = "active"
|
||||||
|
|
||||||
class ServiceNotFoundException(Exception):
|
class ServiceNotFoundException(Exception): pass
|
||||||
pass
|
|
||||||
|
|
||||||
class ServiceManager:
|
class ServiceManager:
|
||||||
def __init__(self, id, db):
|
def __init__(self, id, db):
|
||||||
@@ -83,7 +109,8 @@ class ServiceManager:
|
|||||||
)
|
)
|
||||||
self.status = STATUS.STOP
|
self.status = STATUS.STOP
|
||||||
self.filters = {}
|
self.filters = {}
|
||||||
self._proxy_update()
|
self._update_port_from_db()
|
||||||
|
self._update_filters_from_db()
|
||||||
self.lock = asyncio.Lock()
|
self.lock = asyncio.Lock()
|
||||||
self.starter = None
|
self.starter = None
|
||||||
|
|
||||||
@@ -98,10 +125,6 @@ class ServiceManager:
|
|||||||
self.proxy.internal_port = res[0]["internal_port"]
|
self.proxy.internal_port = res[0]["internal_port"]
|
||||||
self.proxy.public_port = res[0]["public_port"]
|
self.proxy.public_port = res[0]["public_port"]
|
||||||
|
|
||||||
def _proxy_update(self):
|
|
||||||
self._update_port_from_db()
|
|
||||||
self._update_filters_from_db()
|
|
||||||
|
|
||||||
def _update_filters_from_db(self):
|
def _update_filters_from_db(self):
|
||||||
res = self.db.query("""
|
res = self.db.query("""
|
||||||
SELECT
|
SELECT
|
||||||
@@ -133,8 +156,8 @@ class ServiceManager:
|
|||||||
)
|
)
|
||||||
self.proxy.filters = list(self.filters.values())
|
self.proxy.filters = list(self.filters.values())
|
||||||
|
|
||||||
def __update_status_db(self, id, status):
|
def __update_status_db(self, status):
|
||||||
self.db.query("UPDATE services SET status = ? WHERE service_id = ?;", status, id)
|
self.db.query("UPDATE services SET status = ? WHERE service_id = ?;", status, self.id)
|
||||||
|
|
||||||
async def next(self,to):
|
async def next(self,to):
|
||||||
async with self.lock:
|
async with self.lock:
|
||||||
@@ -171,7 +194,7 @@ class ServiceManager:
|
|||||||
|
|
||||||
def _set_status(self,status):
|
def _set_status(self,status):
|
||||||
self.status = status
|
self.status = status
|
||||||
self.__update_status_db(self.id,status)
|
self.__update_status_db(status)
|
||||||
|
|
||||||
|
|
||||||
async def update_filters(self):
|
async def update_filters(self):
|
||||||
@@ -222,7 +245,10 @@ class ProxyManager:
|
|||||||
await self.proxy_table[srv_id].next(req_status)
|
await self.proxy_table[srv_id].next(req_status)
|
||||||
|
|
||||||
def get(self,id):
|
def get(self,id):
|
||||||
return self.proxy_table[id]
|
if id in self.proxy_table:
|
||||||
|
return self.proxy_table[id]
|
||||||
|
else:
|
||||||
|
raise ServiceNotFoundException()
|
||||||
|
|
||||||
def check_port_is_open(port):
|
def check_port_is_open(port):
|
||||||
try:
|
try:
|
||||||
|
|||||||
12
frontend/build/asset-manifest.json
Normal file → Executable file
12
frontend/build/asset-manifest.json
Normal file → Executable file
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"files": {
|
"files": {
|
||||||
"main.css": "/static/css/main.0efd334b.css",
|
"main.css": "/static/css/main.c375ae17.css",
|
||||||
"main.js": "/static/js/main.dbb30aee.js",
|
"main.js": "/static/js/main.e6c85636.js",
|
||||||
"index.html": "/index.html",
|
"index.html": "/index.html",
|
||||||
"main.0efd334b.css.map": "/static/css/main.0efd334b.css.map",
|
"main.c375ae17.css.map": "/static/css/main.c375ae17.css.map",
|
||||||
"main.dbb30aee.js.map": "/static/js/main.dbb30aee.js.map"
|
"main.e6c85636.js.map": "/static/js/main.e6c85636.js.map"
|
||||||
},
|
},
|
||||||
"entrypoints": [
|
"entrypoints": [
|
||||||
"static/css/main.0efd334b.css",
|
"static/css/main.c375ae17.css",
|
||||||
"static/js/main.dbb30aee.js"
|
"static/js/main.e6c85636.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
2
frontend/build/index.html
Normal file → Executable file
2
frontend/build/index.html
Normal file → Executable file
@@ -1 +1 @@
|
|||||||
<!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.dbb30aee.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>
|
<!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.e6c85636.js"></script><link href="/static/css/main.c375ae17.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||||
@@ -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*/
|
|
||||||
2
frontend/build/static/css/main.c375ae17.css
Executable file
2
frontend/build/static/css/main.c375ae17.css
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
@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__yo4XA,.Footer_center-flex__uvxL9,.Footer_footer__S9pCA{align-items:center;display:flex;justify-content:center}.Footer_center-flex-row__yo4XA{flex-direction:column}.Footer_flex-spacer__VEUAB{flex-grow:1}.Footer_footer__S9pCA{background-color:#242a33;height:150px;margin-top:50px}.Header_header__Ri4em{align-items:center;background-color:#242a33;display:flex;height:140px;justify-content:center;width:100%}.Header_logo__3Bvhn{height:70%;margin-left:40px;width:200px}body{font-family:Lato,sans-serif;margin:0}.ServiceRow_center-flex-row__E5vBK,.ServiceRow_center-flex__hmJif,.ServiceRow_row__-A-i2{align-items:center;display:flex;justify-content:center}.ServiceRow_center-flex-row__E5vBK{flex-direction:column}.ServiceRow_flex-spacer__vmC0u{flex-grow:1}::-webkit-scrollbar{background:#333;cursor:pointer;margin:3px;width:12px}::-webkit-scrollbar-thumb{background:#757575;border-radius:8px}.ServiceRow_row__-A-i2{border-radius:20px;margin:10px;padding:30px 0;width:95%}.ServiceRow_name__6f1O6{color:#fff;font-size:2.3em;font-weight:bolder;margin-bottom:13px;margin-right:10px}.RegexView_box__g-S5R{margin:5px;padding:30px}.RegexView_regex_text__Fy5MY{background-color:#25262b;border-radius:15px;padding:10px}
|
||||||
|
/*# sourceMappingURL=main.c375ae17.css.map*/
|
||||||
2
frontend/build/static/css/main.0efd334b.css.map → frontend/build/static/css/main.c375ae17.css.map
Normal file → Executable file
2
frontend/build/static/css/main.0efd334b.css.map → frontend/build/static/css/main.c375ae17.css.map
Normal file → Executable file
@@ -1 +1 @@
|
|||||||
{"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":""}
|
{"version":3,"file":"static/css/main.c375ae17.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,wBAKI,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":""}
|
||||||
6
frontend/build/static/js/main.dbb30aee.js → frontend/build/static/js/main.e6c85636.js
Normal file → Executable file
6
frontend/build/static/js/main.dbb30aee.js → frontend/build/static/js/main.e6c85636.js
Normal file → Executable file
File diff suppressed because one or more lines are too long
0
frontend/build/static/js/main.dbb30aee.js.LICENSE.txt → frontend/build/static/js/main.e6c85636.js.LICENSE.txt
Normal file → Executable file
0
frontend/build/static/js/main.dbb30aee.js.LICENSE.txt → frontend/build/static/js/main.e6c85636.js.LICENSE.txt
Normal file → Executable file
2
frontend/build/static/js/main.dbb30aee.js.map → frontend/build/static/js/main.e6c85636.js.map
Normal file → Executable file
2
frontend/build/static/js/main.dbb30aee.js.map → frontend/build/static/js/main.e6c85636.js.map
Normal file → Executable file
File diff suppressed because one or more lines are too long
@@ -48,27 +48,6 @@ export async function postapi(path:string,data:any,is_form:boolean=false):Promis
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function postform(path:string,data:any):Promise<any>{
|
|
||||||
return await new Promise((resolve, reject) => {
|
|
||||||
fetch(`/api/${path}`, {
|
|
||||||
method: 'POST',
|
|
||||||
credentials: "same-origin",
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify(data)
|
|
||||||
}).then(res => {
|
|
||||||
if(res.status === 401) window.location.reload()
|
|
||||||
if(!res.ok) reject(res.statusText)
|
|
||||||
res.json().then( res => resolve(res) ).catch( err => reject(err))
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
reject(err)
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fireUpdateRequest(){
|
export function fireUpdateRequest(){
|
||||||
window.dispatchEvent(new Event(eventUpdateName))
|
window.dispatchEvent(new Event(eventUpdateName))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user