1
0
Fork 0
mirror of https://github.com/Ysurac/openmptcprouter-vps-admin.git synced 2025-03-09 15:40:05 +00:00

Fix and better code

This commit is contained in:
Ycarus 2020-03-03 13:49:23 +01:00
parent 9f69540b62
commit ae2f3b31fd

View file

@ -17,28 +17,36 @@ import socket
import re import re
import hashlib import hashlib
import time import time
from pprint import pprint
from datetime import datetime, timedelta
from tempfile import mkstemp
from typing import List, Optional
from shutil import move
from enum import Enum
import logging
import uvicorn import uvicorn
import jwt import jwt
from jwt import PyJWTError from jwt import PyJWTError
from netaddr import * from netaddr import *
from pprint import pprint
from datetime import datetime,timedelta
from tempfile import mkstemp
from typing import List
from shutil import move
from pprint import pprint
from netjsonconfig import OpenWrt from netjsonconfig import OpenWrt
from fastapi import Depends, FastAPI, HTTPException, Security, Query from fastapi import Depends, FastAPI, HTTPException, Security, Query
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm, SecurityScopes from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm, SecurityScopes, OAuth2
from passlib.context import CryptContext from passlib.context import CryptContext
from fastapi.encoders import jsonable_encoder
from fastapi.security.base import SecurityBase
from fastapi.security.utils import get_authorization_scheme_param
from fastapi.openapi.docs import get_swagger_ui_html
from fastapi.openapi.models import OAuthFlows as OAuthFlowsModel
from fastapi.openapi.utils import get_openapi
from fastapi.openapi.models import SecurityBase as SecurityBaseModel
from pydantic import BaseModel, ValidationError from pydantic import BaseModel, ValidationError
from starlette.status import HTTP_401_UNAUTHORIZED from starlette.status import HTTP_403_FORBIDDEN
from enum import Enum from starlette.responses import RedirectResponse, Response, JSONResponse
from starlette.requests import Request
import logging LOG = logging.getLogger('api')
log = logging.getLogger('api') #LOG.setLevel(logging.ERROR)
log.setLevel(logging.ERROR) LOG.setLevel(logging.DEBUG)
#log.setLevel(logging.DEBUG)
# Generate a random secret key # Generate a random secret key
SECRET_KEY = uuid.uuid4().hex SECRET_KEY = uuid.uuid4().hex
@ -48,35 +56,35 @@ ACCESS_TOKEN_EXPIRE_MINUTES = 1440
ALGORITHM = "HS256" ALGORITHM = "HS256"
# Get main net interface # Get main net interface
file = open('/etc/shorewall/params.net', "r") FILE = open('/etc/shorewall/params.net', "r")
read = file.read() READ = FILE.read()
iface = None IFACE = None
for line in read.splitlines(): for line in READ.splitlines():
if 'NET_IFACE=' in line: if 'NET_IFACE=' in line:
iface=line.split('=',1)[1] IFACE = line.split('=', 1)[1]
# Get interface rx/tx # Get interface rx/tx
def get_bytes(t, iface='eth0'): def get_bytes(t, iface='eth0'):
with open('/sys/class/net/' + iface + '/statistics/' + t + '_bytes', 'r') as f: with open('/sys/class/net/' + iface + '/statistics/' + t + '_bytes', 'r') as f:
data = f.read(); data = f.read()
return int(data) return int(data)
def get_bytes_ss(port): def get_bytes_ss(port):
ss_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM); ss_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ss_socket.settimeout(3) ss_socket.settimeout(3)
ss_socket.sendto('ping'.encode(), ("127.0.0.1",8839)); ss_socket.sendto('ping'.encode(), ("127.0.0.1", 8839))
ss_recv = ss_socket.recv(1024); ss_recv = ss_socket.recv(1024)
json_txt = ss_recv.decode("utf-8").replace('stat: ',''); json_txt = ss_recv.decode("utf-8").replace('stat: ', '')
result = json.loads(json_txt); result = json.loads(json_txt)
if str(port) in result: if str(port) in result:
return result[str(port)] return result[str(port)]
else: else:
return 0 return 0
def add_ss_user(port, key): def add_ss_user(port, key):
ss_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM); ss_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
data = 'add: {"server_port": ' + port + ', "key": "' + key + '"}' data = 'add: {"server_port": ' + port + ', "key": "' + key + '"}'
ss_socket.sendto(data.encode(), ("127.0.0.1",8839)); ss_socket.sendto(data.encode(), ("127.0.0.1", 8839))
with open('/etc/shadowsocks-libev/manager.json') as f: with open('/etc/shadowsocks-libev/manager.json') as f:
content = f.read() content = f.read()
content = re.sub(",\s*}", "}", content) content = re.sub(",\s*}", "}", content)
@ -87,9 +95,9 @@ def add_ss_user(port,key):
def remove_ss_user(port): def remove_ss_user(port):
ss_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM); ss_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
data = 'remove: {"server_port": ' + port + '}' data = 'remove: {"server_port": ' + port + '}'
ss_socket.sendto(data.encode(), ("127.0.0.1",8839)); ss_socket.sendto(data.encode(), ("127.0.0.1", 8839))
with open('/etc/shadowsocks-libev/manager.json') as f: with open('/etc/shadowsocks-libev/manager.json') as f:
content = f.read() content = f.read()
content = re.sub(",\s*}", "}", content) content = re.sub(",\s*}", "}", content)
@ -117,9 +125,11 @@ def add_glorytun_tcp(userid):
glorytun_tcp_key = secrets.token_hex(32) glorytun_tcp_key = secrets.token_hex(32)
with open('/etc/glorytun-tcp/tun' + str(userid) + '.key', 'w') as f: with open('/etc/glorytun-tcp/tun' + str(userid) + '.key', 'w') as f:
f.write(glorytun_tcp_key.upper()) f.write(glorytun_tcp_key.upper())
os.system("systemctl -q enable glorytun-tcp@tun" + str(userid))
os.system("systemctl -q restart glorytun-tcp@tun" + str(userid)) os.system("systemctl -q restart glorytun-tcp@tun" + str(userid))
def remove_glorytun_tcp(userid): def remove_glorytun_tcp(userid):
os.system("systemctl -q disable glorytun-tcp@tun" + str(userid))
os.system("systemctl -q stop glorytun-tcp@tun" + str(userid)) os.system("systemctl -q stop glorytun-tcp@tun" + str(userid))
os.remove('/etc/glorytun-tcp/tun' + str(userid) + '.key') os.remove('/etc/glorytun-tcp/tun' + str(userid) + '.key')
os.remove('/etc/glorytun-tcp/tun' + str(userid)) os.remove('/etc/glorytun-tcp/tun' + str(userid))
@ -140,13 +150,14 @@ def add_glorytun_udp(userid):
n.write("\n" + 'LOCALIP=' + str(list(network)[1]) + "\n") n.write("\n" + 'LOCALIP=' + str(list(network)[1]) + "\n")
n.write('REMOTEIP=' + str(list(network)[2]) + "\n") n.write('REMOTEIP=' + str(list(network)[2]) + "\n")
n.write('BROADCASTIP=' + str(network.broadcast) + "\n") n.write('BROADCASTIP=' + str(network.broadcast) + "\n")
glorytun_udp_key = secrets.token_hex(32)
with open('/etc/glorytun-tcp/tun' + str(userid) + '.key', 'r') as f, open('/etc/glorytun-udp/tun' + str(userid) + '.key', 'w') as n: with open('/etc/glorytun-tcp/tun' + str(userid) + '.key', 'r') as f, open('/etc/glorytun-udp/tun' + str(userid) + '.key', 'w') as n:
for line in f: for line in f:
n.write(line) n.write(line)
os.system("systemctl -q enable glorytun-udp@tun" + str(userid))
os.system("systemctl -q restart glorytun-udp@tun" + str(userid)) os.system("systemctl -q restart glorytun-udp@tun" + str(userid))
def remove_glorytun_udp(userid): def remove_glorytun_udp(userid):
os.system("systemctl -q disable glorytun-udp@tun" + str(userid))
os.system("systemctl -q stop glorytun-udp@tun" + str(userid)) os.system("systemctl -q stop glorytun-udp@tun" + str(userid))
os.remove('/etc/glorytun-udp/tun' + str(userid) + '.key') os.remove('/etc/glorytun-udp/tun' + str(userid) + '.key')
os.remove('/etc/glorytun-udp/tun' + str(userid)) os.remove('/etc/glorytun-udp/tun' + str(userid))
@ -172,9 +183,11 @@ def add_dsvpn(userid):
dsvpn_key = secrets.token_hex(32) dsvpn_key = secrets.token_hex(32)
with open('/etc/dsvpn/dsvpn' + str(userid) + '.key', 'w') as f: with open('/etc/dsvpn/dsvpn' + str(userid) + '.key', 'w') as f:
f.write(dsvpn_key.upper()) f.write(dsvpn_key.upper())
os.system("systemctl -q enable dsvpn@dsvpn" + str(userid))
os.system("systemctl -q restart dsvpn@dsvpn" + str(userid)) os.system("systemctl -q restart dsvpn@dsvpn" + str(userid))
def remove_dsvpn(userid): def remove_dsvpn(userid):
os.system("systemctl -q disable dsvpn@dsvpn" + str(userid))
os.system("systemctl -q stop dsvpn@dsvpn" + str(userid)) os.system("systemctl -q stop dsvpn@dsvpn" + str(userid))
os.remove('/etc/dsvpn/dsvpn' + str(userid)) os.remove('/etc/dsvpn/dsvpn' + str(userid))
os.remove('/etc/dsvpn/dsvpn' + str(userid) + '.key') os.remove('/etc/dsvpn/dsvpn' + str(userid) + '.key')
@ -194,7 +207,7 @@ def file_as_bytes(file):
def shorewall_add_port(user, port, proto, name, fwtype='ACCEPT'): def shorewall_add_port(user, port, proto, name, fwtype='ACCEPT'):
userid = user.userid userid = user.userid
if userid == None: if userid is None:
userid = 0 userid = 0
initial_md5 = hashlib.md5(file_as_bytes(open('/etc/shorewall/rules', 'rb'))).hexdigest() initial_md5 = hashlib.md5(file_as_bytes(open('/etc/shorewall/rules', 'rb'))).hexdigest()
fd, tmpfile = mkstemp() fd, tmpfile = mkstemp()
@ -208,12 +221,12 @@ def shorewall_add_port(user,port,proto,name,fwtype='ACCEPT'):
n.write('ACCEPT net $FW ' + proto + ' ' + port + ' # OMR ' + user.username + ' open ' + name + ' port ' + proto + "\n") n.write('ACCEPT net $FW ' + proto + ' ' + port + ' # OMR ' + user.username + ' open ' + name + ' port ' + proto + "\n")
elif fwtype == 'DNAT' and userid == 0: elif fwtype == 'DNAT' and userid == 0:
n.write('DNAT net vpn:$OMR_ADDR ' + proto + ' ' + port + ' # OMR ' + user.username + ' redirect ' + name + ' port ' + proto + "\n") n.write('DNAT net vpn:$OMR_ADDR ' + proto + ' ' + port + ' # OMR ' + user.username + ' redirect ' + name + ' port ' + proto + "\n")
elif fwtype == 'DNAT' and not userid == 0: elif fwtype == 'DNAT' and userid != 0:
n.write('DNAT net vpn:$OMR_ADDR_USER' + str(userid) + ' ' + proto + ' ' + port + ' # OMR ' + user.username + ' redirect ' + name + ' port ' + proto + "\n") n.write('DNAT net vpn:$OMR_ADDR_USER' + str(userid) + ' ' + proto + ' ' + port + ' # OMR ' + user.username + ' redirect ' + name + ' port ' + proto + "\n")
os.close(fd) os.close(fd)
move(tmpfile, '/etc/shorewall/rules') move(tmpfile, '/etc/shorewall/rules')
final_md5 = hashlib.md5(file_as_bytes(open('/etc/shorewall/rules', 'rb'))).hexdigest() final_md5 = hashlib.md5(file_as_bytes(open('/etc/shorewall/rules', 'rb'))).hexdigest()
if not initial_md5 == final_md5: if initial_md5 != final_md5:
os.system("systemctl -q reload shorewall") os.system("systemctl -q reload shorewall")
def shorewall_del_port(username, port, proto, name, fwtype='ACCEPT'): def shorewall_del_port(username, port, proto, name, fwtype='ACCEPT'):
@ -228,7 +241,7 @@ def shorewall_del_port(username,port,proto,name,fwtype='ACCEPT'):
os.close(fd) os.close(fd)
move(tmpfile, '/etc/shorewall/rules') move(tmpfile, '/etc/shorewall/rules')
final_md5 = hashlib.md5(file_as_bytes(open('/etc/shorewall/rules', 'rb'))).hexdigest() final_md5 = hashlib.md5(file_as_bytes(open('/etc/shorewall/rules', 'rb'))).hexdigest()
if not initial_md5 == final_md5: if initial_md5 != final_md5:
os.system("systemctl -q reload shorewall") os.system("systemctl -q reload shorewall")
def shorewall6_add_port(user, port, proto, name, fwtype='ACCEPT'): def shorewall6_add_port(user, port, proto, name, fwtype='ACCEPT'):
@ -247,12 +260,12 @@ def shorewall6_add_port(user,port,proto,name,fwtype='ACCEPT'):
n.write('ACCEPT net $FW ' + proto + ' ' + port + ' # OMR ' + user.username + ' open ' + name + ' port ' + proto + "\n") n.write('ACCEPT net $FW ' + proto + ' ' + port + ' # OMR ' + user.username + ' open ' + name + ' port ' + proto + "\n")
elif fwtype == 'DNAT' and userid == 0: elif fwtype == 'DNAT' and userid == 0:
n.write('DNAT net vpn:$OMR_ADDR ' + proto + ' ' + port + ' # OMR ' + user.username + ' redirect ' + name + ' port ' + proto + "\n") n.write('DNAT net vpn:$OMR_ADDR ' + proto + ' ' + port + ' # OMR ' + user.username + ' redirect ' + name + ' port ' + proto + "\n")
elif fwtype == 'DNAT' and not userid == 0: elif fwtype == 'DNAT' and userid != 0:
n.write('DNAT net vpn:$OMR_ADDR_USER' + str(userid) + ' ' + proto + ' ' + port + ' # OMR ' + user.username + ' redirect ' + name + ' port ' + proto + "\n") n.write('DNAT net vpn:$OMR_ADDR_USER' + str(userid) + ' ' + proto + ' ' + port + ' # OMR ' + user.username + ' redirect ' + name + ' port ' + proto + "\n")
os.close(fd) os.close(fd)
move(tmpfile, '/etc/shorewall6/rules') move(tmpfile, '/etc/shorewall6/rules')
final_md5 = hashlib.md5(file_as_bytes(open('/etc/shorewall6/rules', 'rb'))).hexdigest() final_md5 = hashlib.md5(file_as_bytes(open('/etc/shorewall6/rules', 'rb'))).hexdigest()
if not initial_md5 == final_md5: if initial_md5 != final_md5:
os.system("systemctl -q reload shorewall6") os.system("systemctl -q reload shorewall6")
def shorewall6_del_port(username, port, proto, name, fwtype='ACCEPT'): def shorewall6_del_port(username, port, proto, name, fwtype='ACCEPT'):
@ -267,7 +280,7 @@ def shorewall6_del_port(username,port,proto,name,fwtype='ACCEPT'):
os.close(fd) os.close(fd)
move(tmpfile, '/etc/shorewall6/rules') move(tmpfile, '/etc/shorewall6/rules')
final_md5 = hashlib.md5(file_as_bytes(open('/etc/shorewall6/rules', 'rb'))).hexdigest() final_md5 = hashlib.md5(file_as_bytes(open('/etc/shorewall6/rules', 'rb'))).hexdigest()
if not initial_md5 == final_md5: if initial_md5 != final_md5:
os.system("systemctl -q reload shorewall6") os.system("systemctl -q reload shorewall6")
def set_lastchange(sync=0): def set_lastchange(sync=0):
@ -277,7 +290,7 @@ def set_lastchange(sync = 0):
try: try:
data = json.loads(content) data = json.loads(content)
except ValueError as e: except ValueError as e:
return jsonify({'error': 'Config file not readable','route': 'lastchange'}), 200 return {'error': 'Config file not readable', 'route': 'lastchange'}
data["lastchange"] = time.time() + sync data["lastchange"] = time.time() + sync
with open('/etc/openmptcprouter-vps-admin/omr-admin-config.json', 'w') as outfile: with open('/etc/openmptcprouter-vps-admin/omr-admin-config.json', 'w') as outfile:
json.dump(data, outfile, indent=4) json.dump(data, outfile, indent=4)
@ -289,7 +302,7 @@ def set_global_param(key,value):
try: try:
data = json.loads(content) data = json.loads(content)
except ValueError as e: except ValueError as e:
return jsonify({'error': 'Config file not readable','route': 'global_param'}), 200 return {'error': 'Config file not readable', 'route': 'global_param'}
data[key] = value data[key] = value
with open('/etc/openmptcprouter-vps-admin/omr-admin-config.json', 'w') as outfile: with open('/etc/openmptcprouter-vps-admin/omr-admin-config.json', 'w') as outfile:
json.dump(data, outfile, indent=4) json.dump(data, outfile, indent=4)
@ -308,7 +321,7 @@ fake_users_db = omr_config_data['users'][0]
def verify_password(plain_password, user_password): def verify_password(plain_password, user_password):
if plain_password == user_password: if plain_password == user_password:
log.debug("password true") LOG.debug("password true")
return True return True
return False return False
@ -323,16 +336,16 @@ def get_user(db, username: str):
def authenticate_user(fake_db, username: str, password: str): def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username) user = get_user(fake_db, username)
if not user: if not user:
log.debug("user doesn't exist") LOG.debug("user doesn't exist")
return False return False
if not verify_password(password, user.user_password): if not verify_password(password, user.user_password):
log.debug("wrong password") LOG.debug("wrong password")
return False return False
return user return user
class Token(BaseModel): class Token(BaseModel):
access_token: str access_token: str = None
token_type: str token_type: str = None
class TokenData(BaseModel): class TokenData(BaseModel):
@ -352,16 +365,79 @@ class User(BaseModel):
class UserInDB(User): class UserInDB(User):
user_password: str user_password: str
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token") # Add support for auth before seeing doc
app = FastAPI(redoc_url=None) class OAuth2PasswordBearerCookie(OAuth2):
def __init__(
self,
tokenUrl: str,
scheme_name: str = None,
scopes: dict = None,
auto_error: bool = True,
):
if not scopes:
scopes = {}
flows = OAuthFlowsModel(password={"tokenUrl": tokenUrl, "scopes": scopes})
super().__init__(flows=flows, scheme_name=scheme_name, auto_error=auto_error)
async def __call__(self, request: Request) -> Optional[str]:
header_authorization: str = request.headers.get("Authorization")
cookie_authorization: str = request.cookies.get("Authorization")
header_scheme, header_param = get_authorization_scheme_param(
header_authorization
)
cookie_scheme, cookie_param = get_authorization_scheme_param(
cookie_authorization
)
if header_scheme.lower() == "bearer":
authorization = True
scheme = header_scheme
param = header_param
elif cookie_scheme.lower() == "bearer":
authorization = True
scheme = cookie_scheme
param = cookie_param
else:
authorization = False
if not authorization or scheme.lower() != "bearer":
if self.auto_error:
raise HTTPException(
status_code=HTTP_403_FORBIDDEN, detail="Not authenticated"
)
else:
return None
return param
class BasicAuth(SecurityBase):
def __init__(self, scheme_name: str = None, auto_error: bool = True):
self.scheme_name = scheme_name or self.__class__.__name__
self.model = SecurityBaseModel(type="http")
self.auto_error = auto_error
async def __call__(self, request: Request) -> Optional[str]:
authorization: str = request.headers.get("Authorization")
scheme, param = get_authorization_scheme_param(authorization)
if not authorization or scheme.lower() != "basic":
if self.auto_error:
raise HTTPException(
status_code=HTTP_403_FORBIDDEN, detail="Not authenticated"
)
else:
return None
return param
basic_auth = BasicAuth(auto_error=False)
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer( oauth2_scheme = OAuth2PasswordBearerCookie(tokenUrl="/token")
tokenUrl="/token",
scopes={"me": "Read information about the current user.", "items": "Read items."}, app = FastAPI(docs_url=None, redoc_url=None, openapi_url=None)
)
def create_access_token(*, data: dict, expires_delta: timedelta = None): def create_access_token(*, data: dict, expires_delta: timedelta = None):
to_encode = data.copy() to_encode = data.copy()
@ -375,7 +451,7 @@ def create_access_token(*, data: dict, expires_delta: timedelta = None):
async def get_current_user(token: str = Depends(oauth2_scheme)): async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException( credentials_exception = HTTPException(
status_code=HTTP_401_UNAUTHORIZED, status_code=HTTP_403_FORBIDDEN,
detail="Could not validate credentials", detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"}, headers={"WWW-Authenticate": "Bearer"},
) )
@ -383,7 +459,7 @@ async def get_current_user(token: str = Depends(oauth2_scheme)):
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub") username: str = payload.get("sub")
if username is None: if username is None:
log.debug("get_current_user: Username not found") LOG.debug("get_current_user: Username not found")
raise credentials_exception raise credentials_exception
token_data = TokenData(username=username) token_data = TokenData(username=username)
except PyJWTError: except PyJWTError:
@ -393,13 +469,23 @@ async def get_current_user(token: str = Depends(oauth2_scheme)):
raise credentials_exception raise credentials_exception
return user return user
async def get_current_active_user(current_user: User = Depends(get_current_user)):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
return current_user
# Show something at homepage
@app.get("/")
async def homepage():
return "Welcome to OpenMPTCProuter Server part"
# Provide a method to create access tokens. The create_jwt() # Provide a method to create access tokens. The create_jwt()
# function is used to actually generate the token # function is used to actually generate the token
@app.post('/token', response_model=Token) @app.post('/token', response_model=Token)
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()): async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(fake_users_db, form_data.username, form_data.password) user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user: if not user:
log.debug("Incorrect username or password") LOG.debug("Incorrect username or password")
raise HTTPException(status_code=400, detail="Incorrect username or password") raise HTTPException(status_code=400, detail="Incorrect username or password")
# Identity can be any data that is json serializable # Identity can be any data that is json serializable
@ -409,10 +495,63 @@ async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(
) )
return {"access_token": access_token, "token_type": "bearer"} return {"access_token": access_token, "token_type": "bearer"}
@app.get("/logout")
async def route_logout_and_remove_cookie():
response = RedirectResponse(url="/")
response.delete_cookie("Authorization")
return response
# Login for doc
@app.get("/login_basic")
async def login_basic(auth: BasicAuth = Depends(basic_auth)):
if not auth:
response = Response(headers={"WWW-Authenticate": "Basic"}, status_code=401)
return response
try:
decoded = base64.b64decode(auth).decode("ascii")
username, _, password = decoded.partition(":")
user = authenticate_user(fake_users_db, username, password)
if not user:
raise HTTPException(status_code=400, detail="Incorrect email or password")
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": username}, expires_delta=access_token_expires
)
token = jsonable_encoder(access_token)
response = RedirectResponse(url="/docs")
response.set_cookie(
"Authorization",
value=f"Bearer {token}",
httponly=True,
max_age=1800,
expires=1800,
)
return response
except:
response = Response(headers={"WWW-Authenticate": "Basic"}, status_code=401)
return response
@app.get("/openapi.json")
async def get_open_api_endpoint(current_user: User = Depends(get_current_active_user)):
return JSONResponse(get_openapi(title="FastAPI", version=1, routes=app.routes))
@app.get("/docs")
async def get_documentation(current_user: User = Depends(get_current_active_user)):
return get_swagger_ui_html(openapi_url="/openapi.json", title="docs")
# Get VPS status # Get VPS status
@app.get('/status') @app.get('/status')
async def status(current_user: User = Depends(get_current_user)): async def status(current_user: User = Depends(get_current_user)):
log.debug('Get status...') LOG.debug('Get status...')
vps_loadavg = os.popen("cat /proc/loadavg | awk '{print $1\" \"$2\" \"$3}'").read().rstrip() vps_loadavg = os.popen("cat /proc/loadavg | awk '{print $1\" \"$2\" \"$3}'").read().rstrip()
vps_uptime = os.popen("cat /proc/uptime | awk '{print $1}'").read().rstrip() vps_uptime = os.popen("cat /proc/uptime | awk '{print $1}'").read().rstrip()
vps_hostname = socket.gethostname() vps_hostname = socket.gethostname()
@ -420,31 +559,31 @@ async def status(current_user: User = Depends(get_current_user)):
vps_kernel = os.popen('uname -r').read().rstrip() vps_kernel = os.popen('uname -r').read().rstrip()
vps_omr_version = os.popen("grep -s 'OpenMPTCProuter VPS' /etc/* | awk '{print $4}'").read().rstrip() vps_omr_version = os.popen("grep -s 'OpenMPTCProuter VPS' /etc/* | awk '{print $4}'").read().rstrip()
mptcp_enabled = os.popen('sysctl -n net.mptcp.mptcp_enabled').read().rstrip() mptcp_enabled = os.popen('sysctl -n net.mptcp.mptcp_enabled').read().rstrip()
shadowsocks_port = current_user.shadowsocks_port #shadowsocks_port = current_user.shadowsocks_port
#if not shadowsocks_port == None: #if not shadowsocks_port == None:
# ss_traffic = get_bytes_ss(current_user.shadowsocks_port) # ss_traffic = get_bytes_ss(current_user.shadowsocks_port)
#else: #else:
ss_traffic = 0 ss_traffic = 0
log.debug('Get status: done') LOG.debug('Get status: done')
if iface: if IFACE:
return {'vps': {'time': vps_current_time,'loadavg': vps_loadavg,'uptime': vps_uptime,'mptcp': mptcp_enabled,'hostname': vps_hostname,'kernel': vps_kernel, 'omr_version': vps_omr_version}, 'network': {'tx': get_bytes('tx',iface),'rx': get_bytes('rx',iface)}, 'shadowsocks': {'traffic': ss_traffic}} return {'vps': {'time': vps_current_time, 'loadavg': vps_loadavg, 'uptime': vps_uptime, 'mptcp': mptcp_enabled, 'hostname': vps_hostname, 'kernel': vps_kernel, 'omr_version': vps_omr_version}, 'network': {'tx': get_bytes('tx', IFACE), 'rx': get_bytes('rx', IFACE)}, 'shadowsocks': {'traffic': ss_traffic}}
else: else:
return {'error': 'No iface defined', 'route': 'status'} return {'error': 'No iface defined', 'route': 'status'}
# Get VPS config # Get VPS config
@app.get('/config') @app.get('/config')
async def config(current_user: User = Depends(get_current_user)): async def config(current_user: User = Depends(get_current_user)):
log.debug('Get config...') LOG.debug('Get config...')
userid = current_user.userid userid = current_user.userid
if userid == None: if userid is None:
userid = 0 userid = 0
with open('/etc/openmptcprouter-vps-admin/omr-admin-config.json') as f: with open('/etc/openmptcprouter-vps-admin/omr-admin-config.json') as f:
try: try:
omr_config_data = json.load(f) omr_config_data = json.load(f)
except ValueError as e: except ValueError as e:
omr_config_data = {} omr_config_data = {}
log.debug('Get config... shadowsocks') LOG.debug('Get config... shadowsocks')
with open('/etc/shadowsocks-libev/manager.json') as f: with open('/etc/shadowsocks-libev/manager.json') as f:
content = f.read() content = f.read()
content = re.sub(",\s*}", "}", content) content = re.sub(",\s*}", "}", content)
@ -499,7 +638,7 @@ async def config(current_user: User = Depends(get_current_user)):
#else: #else:
ss_traffic = 0 ss_traffic = 0
log.debug('Get config... glorytun') LOG.debug('Get config... glorytun')
if os.path.isfile('/etc/glorytun-tcp/tun' + str(userid) +'.key'): if os.path.isfile('/etc/glorytun-tcp/tun' + str(userid) +'.key'):
glorytun_key = open('/etc/glorytun-tcp/tun' + str(userid) + '.key').readline().rstrip() glorytun_key = open('/etc/glorytun-tcp/tun' + str(userid) + '.key').readline().rstrip()
else: else:
@ -552,7 +691,7 @@ async def config(current_user: User = Depends(get_current_user)):
glorytun_udp_host_ip = '10.255.254.1' glorytun_udp_host_ip = '10.255.254.1'
glorytun_udp_client_ip = '10.255.254.2' glorytun_udp_client_ip = '10.255.254.2'
available_vpn = ["glorytun-tcp", "glorytun-udp"] available_vpn = ["glorytun-tcp", "glorytun-udp"]
log.debug('Get config... dsvpn') LOG.debug('Get config... dsvpn')
if os.path.isfile('/etc/dsvpn/dsvpn' + str(userid) + '.key'): if os.path.isfile('/etc/dsvpn/dsvpn' + str(userid) + '.key'):
dsvpn_key = open('/etc/dsvpn/dsvpn' + str(userid) + '.key').readline().rstrip() dsvpn_key = open('/etc/dsvpn/dsvpn' + str(userid) + '.key').readline().rstrip()
available_vpn.append("dsvpn") available_vpn.append("dsvpn")
@ -575,7 +714,7 @@ async def config(current_user: User = Depends(get_current_user)):
dsvpn_host_ip = '10.255.251.1' dsvpn_host_ip = '10.255.251.1'
dsvpn_client_ip = '10.255.251.2' dsvpn_client_ip = '10.255.251.2'
log.debug('Get config... iperf3') LOG.debug('Get config... iperf3')
if os.path.isfile('/etc/iperf3/public.pem'): if os.path.isfile('/etc/iperf3/public.pem'):
with open('/etc/iperf3/public.pem', "rb") as iperfkey_file: with open('/etc/iperf3/public.pem', "rb") as iperfkey_file:
iperf_keyb = base64.b64encode(iperfkey_file.read()) iperf_keyb = base64.b64encode(iperfkey_file.read())
@ -588,7 +727,7 @@ async def config(current_user: User = Depends(get_current_user)):
else: else:
pihole = False pihole = False
log.debug('Get config... openvpn') LOG.debug('Get config... openvpn')
#if os.path.isfile('/etc/openvpn/server/static.key'): #if os.path.isfile('/etc/openvpn/server/static.key'):
# with open('/etc/openvpn/server/static.key',"rb") as ovpnkey_file: # with open('/etc/openvpn/server/static.key',"rb") as ovpnkey_file:
# openvpn_keyb = base64.b64encode(ovpnkey_file.read()) # openvpn_keyb = base64.b64encode(ovpnkey_file.read())
@ -638,7 +777,7 @@ async def config(current_user: User = Depends(get_current_user)):
mlvpn_client_ip = '10.255.253.2' mlvpn_client_ip = '10.255.253.2'
log.debug('Get config... mptcp') LOG.debug('Get config... mptcp')
mptcp_enabled = os.popen('sysctl -n net.mptcp.mptcp_enabled').read().rstrip() mptcp_enabled = os.popen('sysctl -n net.mptcp.mptcp_enabled').read().rstrip()
mptcp_checksum = os.popen('sysctl -n net.mptcp.mptcp_checksum').read().rstrip() mptcp_checksum = os.popen('sysctl -n net.mptcp.mptcp_checksum').read().rstrip()
mptcp_path_manager = os.popen('sysctl -n net.mptcp.mptcp_path_manager').read().rstrip() mptcp_path_manager = os.popen('sysctl -n net.mptcp.mptcp_path_manager').read().rstrip()
@ -647,12 +786,12 @@ async def config(current_user: User = Depends(get_current_user)):
congestion_control = os.popen('sysctl -n net.ipv4.tcp_congestion_control').read().rstrip() congestion_control = os.popen('sysctl -n net.ipv4.tcp_congestion_control').read().rstrip()
log.debug('Get config... ipv6') LOG.debug('Get config... ipv6')
ipv6_network = os.popen('ip -6 addr show ' + iface +' | grep -oP "(?<=inet6 ).*(?= scope global)"').read().rstrip() ipv6_network = os.popen('ip -6 addr show ' + IFACE +' | grep -oP "(?<=inet6 ).*(?= scope global)"').read().rstrip()
#ipv6_addr = os.popen('wget -6 -qO- -T 2 ipv6.openmptcprouter.com').read().rstrip() #ipv6_addr = os.popen('wget -6 -qO- -T 2 ipv6.openmptcprouter.com').read().rstrip()
ipv6_addr = os.popen('ip -6 addr show ' + iface +' | grep -oP "(?<=inet6 ).*(?= scope global)" | cut -d/ -f1').read().rstrip() ipv6_addr = os.popen('ip -6 addr show ' + IFACE +' | grep -oP "(?<=inet6 ).*(?= scope global)" | cut -d/ -f1').read().rstrip()
#ipv4_addr = os.popen('wget -4 -qO- -T 1 https://ip.openmptcprouter.com').read().rstrip() #ipv4_addr = os.popen('wget -4 -qO- -T 1 https://ip.openmptcprouter.com').read().rstrip()
log.debug('get server IPv4') LOG.debug('get server IPv4')
ipv4_addr = os.popen("dig -4 TXT +timeout=2 +tries=1 +short o-o.myaddr.l.google.com @ns1.google.com | awk -F'\"' '{ print $2}'").read().rstrip() ipv4_addr = os.popen("dig -4 TXT +timeout=2 +tries=1 +short o-o.myaddr.l.google.com @ns1.google.com | awk -F'\"' '{ print $2}'").read().rstrip()
if ipv4_addr == '': if ipv4_addr == '':
ipv4_addr = os.popen('wget -4 -qO- -T 1 http://ifconfig.co').read().rstrip() ipv4_addr = os.popen('wget -4 -qO- -T 1 http://ifconfig.co').read().rstrip()
@ -668,7 +807,7 @@ async def config(current_user: User = Depends(get_current_user)):
vps_omr_version = os.popen("grep -s 'OpenMPTCProuter VPS' /etc/* | awk '{print $4}'").read().rstrip() vps_omr_version = os.popen("grep -s 'OpenMPTCProuter VPS' /etc/* | awk '{print $4}'").read().rstrip()
vps_loadavg = os.popen("cat /proc/loadavg | awk '{print $1" "$2" "$3}'").read().rstrip() vps_loadavg = os.popen("cat /proc/loadavg | awk '{print $1" "$2" "$3}'").read().rstrip()
vps_uptime = os.popen("cat /proc/uptime | awk '{print $1}'").read().rstrip() vps_uptime = os.popen("cat /proc/uptime | awk '{print $1}'").read().rstrip()
log.debug('get hostname') LOG.debug('get hostname')
vps_domain = os.popen('wget -4 -qO- -T 1 http://hostname.openmptcprouter.com').read().rstrip() vps_domain = os.popen('wget -4 -qO- -T 1 http://hostname.openmptcprouter.com').read().rstrip()
#vps_domain = os.popen('dig -4 +short +times=3 +tries=1 -x ' + ipv4_addr + " | sed 's/\.$//'").read().rstrip() #vps_domain = os.popen('dig -4 +short +times=3 +tries=1 -x ' + ipv4_addr + " | sed 's/\.$//'").read().rstrip()
user_permissions = current_user.permissions user_permissions = current_user.permissions
@ -697,7 +836,7 @@ async def config(current_user: User = Depends(get_current_user)):
alllanips = [] alllanips = []
client2client = False client2client = False
if 'client2client' in omr_config_data and omr_config_data['client2client'] == True: if 'client2client' in omr_config_data and omr_config_data['client2client']:
client2client = True client2client = True
for users in omr_config_data['users'][0]: for users in omr_config_data['users'][0]:
if 'lanips' in omr_config_data['users'][0][users] and users != current_user.username: if 'lanips' in omr_config_data['users'][0][users] and users != current_user.username:
@ -708,7 +847,7 @@ async def config(current_user: User = Depends(get_current_user)):
for line in f: for line in f:
if '#DNAT net vpn:$OMR_ADDR tcp 1-64999' in line: if '#DNAT net vpn:$OMR_ADDR tcp 1-64999' in line:
shorewall_redirect = "disable" shorewall_redirect = "disable"
log.debug('Get config: done') LOG.debug('Get config: done')
return {'vps': {'kernel': vps_kernel, 'machine': vps_machine, 'omr_version': vps_omr_version, 'loadavg': vps_loadavg, 'uptime': vps_uptime, 'aes': vps_aes}, 'shadowsocks': {'traffic': ss_traffic, 'key': shadowsocks_key, 'port': shadowsocks_port, 'method': shadowsocks_method, 'fast_open': shadowsocks_fast_open, 'reuse_port': shadowsocks_reuse_port, 'no_delay': shadowsocks_no_delay, 'mptcp': shadowsocks_mptcp, 'ebpf': shadowsocks_ebpf, 'obfs': shadowsocks_obfs, 'obfs_plugin': shadowsocks_obfs_plugin, 'obfs_type': shadowsocks_obfs_type}, 'glorytun': {'key': glorytun_key, 'udp': {'host_ip': glorytun_udp_host_ip, 'client_ip': glorytun_udp_client_ip}, 'tcp': {'host_ip': glorytun_tcp_host_ip, 'client_ip': glorytun_tcp_client_ip}, 'port': glorytun_port, 'chacha': glorytun_chacha}, 'dsvpn': {'key': dsvpn_key, 'host_ip': dsvpn_host_ip, 'client_ip': dsvpn_client_ip, 'port': dsvpn_port}, 'openvpn': {'key': openvpn_key, 'client_key': openvpn_client_key, 'client_crt': openvpn_client_crt, 'client_ca': openvpn_client_ca, 'host_ip': openvpn_host_ip, 'client_ip': openvpn_client_ip, 'port': openvpn_port}, 'mlvpn': {'key': mlvpn_key, 'host_ip': mlvpn_host_ip, 'client_ip': mlvpn_client_ip}, 'shorewall': {'redirect_ports': shorewall_redirect}, 'mptcp': {'enabled': mptcp_enabled, 'checksum': mptcp_checksum, 'path_manager': mptcp_path_manager, 'scheduler': mptcp_scheduler, 'syn_retries': mptcp_syn_retries}, 'network': {'congestion_control': congestion_control, 'ipv6_network': ipv6_network, 'ipv6': ipv6_addr, 'ipv4': ipv4_addr, 'domain': vps_domain}, 'vpn': {'available': available_vpn, 'current': vpn}, 'iperf': {'user': 'openmptcprouter', 'password': 'openmptcprouter', 'key': iperf3_key}, 'pihole': {'state': pihole}, 'user': {'name': current_user.username, 'permission': user_permissions}, '6in4': {'localip': localip6, 'remoteip': remoteip6}, 'client2client': {'enabled': client2client, 'lanips': alllanips}} return {'vps': {'kernel': vps_kernel, 'machine': vps_machine, 'omr_version': vps_omr_version, 'loadavg': vps_loadavg, 'uptime': vps_uptime, 'aes': vps_aes}, 'shadowsocks': {'traffic': ss_traffic, 'key': shadowsocks_key, 'port': shadowsocks_port, 'method': shadowsocks_method, 'fast_open': shadowsocks_fast_open, 'reuse_port': shadowsocks_reuse_port, 'no_delay': shadowsocks_no_delay, 'mptcp': shadowsocks_mptcp, 'ebpf': shadowsocks_ebpf, 'obfs': shadowsocks_obfs, 'obfs_plugin': shadowsocks_obfs_plugin, 'obfs_type': shadowsocks_obfs_type}, 'glorytun': {'key': glorytun_key, 'udp': {'host_ip': glorytun_udp_host_ip, 'client_ip': glorytun_udp_client_ip}, 'tcp': {'host_ip': glorytun_tcp_host_ip, 'client_ip': glorytun_tcp_client_ip}, 'port': glorytun_port, 'chacha': glorytun_chacha}, 'dsvpn': {'key': dsvpn_key, 'host_ip': dsvpn_host_ip, 'client_ip': dsvpn_client_ip, 'port': dsvpn_port}, 'openvpn': {'key': openvpn_key, 'client_key': openvpn_client_key, 'client_crt': openvpn_client_crt, 'client_ca': openvpn_client_ca, 'host_ip': openvpn_host_ip, 'client_ip': openvpn_client_ip, 'port': openvpn_port}, 'mlvpn': {'key': mlvpn_key, 'host_ip': mlvpn_host_ip, 'client_ip': mlvpn_client_ip}, 'shorewall': {'redirect_ports': shorewall_redirect}, 'mptcp': {'enabled': mptcp_enabled, 'checksum': mptcp_checksum, 'path_manager': mptcp_path_manager, 'scheduler': mptcp_scheduler, 'syn_retries': mptcp_syn_retries}, 'network': {'congestion_control': congestion_control, 'ipv6_network': ipv6_network, 'ipv6': ipv6_addr, 'ipv4': ipv4_addr, 'domain': vps_domain}, 'vpn': {'available': available_vpn, 'current': vpn}, 'iperf': {'user': 'openmptcprouter', 'password': 'openmptcprouter', 'key': iperf3_key}, 'pihole': {'state': pihole}, 'user': {'name': current_user.username, 'permission': user_permissions}, '6in4': {'localip': localip6, 'remoteip': remoteip6}, 'client2client': {'enabled': client2client, 'lanips': alllanips}}
# Set shadowsocks config # Set shadowsocks config
@ -729,7 +868,7 @@ def shadowsocks(*,params: ShadowsocksConfigparams,current_user: User = Depends(g
if current_user.permissions == "ro": if current_user.permissions == "ro":
set_lastchange(10) set_lastchange(10)
return {'result': 'permission', 'reason': 'Read only user', 'route': 'shadowsocks'} return {'result': 'permission', 'reason': 'Read only user', 'route': 'shadowsocks'}
ipv6_network = os.popen('ip -6 addr show ' + iface +' | grep -oP "(?<=inet6 ).*(?= scope global)"').read().rstrip() ipv6_network = os.popen('ip -6 addr show ' + IFACE +' | grep -oP "(?<=inet6 ).*(?= scope global)"').read().rstrip()
with open('/etc/shadowsocks-libev/manager.json') as f: with open('/etc/shadowsocks-libev/manager.json') as f:
content = f.read() content = f.read()
content = re.sub(",\s*}", "}", content) content = re.sub(",\s*}", "}", content)
@ -1198,7 +1337,7 @@ def vpnips(*,vpnconfig: VPNips,current_user: User = Depends(get_current_user)):
move(tmpfile, '/etc/shorewall/params.vpn') move(tmpfile, '/etc/shorewall/params.vpn')
final_md5 = hashlib.md5(file_as_bytes(open('/etc/shorewall/params.vpn', 'rb'))).hexdigest() final_md5 = hashlib.md5(file_as_bytes(open('/etc/shorewall/params.vpn', 'rb'))).hexdigest()
if not initial_md5 == final_md5: if not initial_md5 == final_md5:
os.system("systemctl -q restart shorewall") os.system("systemctl -q reload shorewall")
set_lastchange() set_lastchange()
initial_md5 = hashlib.md5(file_as_bytes(open('/etc/shorewall6/params.vpn', 'rb'))).hexdigest() initial_md5 = hashlib.md5(file_as_bytes(open('/etc/shorewall6/params.vpn', 'rb'))).hexdigest()
@ -1216,7 +1355,7 @@ def vpnips(*,vpnconfig: VPNips,current_user: User = Depends(get_current_user)):
move(tmpfile, '/etc/shorewall6/params.vpn') move(tmpfile, '/etc/shorewall6/params.vpn')
final_md5 = hashlib.md5(file_as_bytes(open('/etc/shorewall6/params.vpn', 'rb'))).hexdigest() final_md5 = hashlib.md5(file_as_bytes(open('/etc/shorewall6/params.vpn', 'rb'))).hexdigest()
if not initial_md5 == final_md5: if not initial_md5 == final_md5:
os.system("systemctl -q restart shorewall6") os.system("systemctl -q reload shorewall6")
set_lastchange() set_lastchange()
return {'result': 'done', 'reason': 'changes applied'} return {'result': 'done', 'reason': 'changes applied'}