mirror of
https://github.com/netinvent/npbackup.git
synced 2025-10-09 05:01:13 +08:00
upgrade_server: Implement basic permission and multi user support
This commit is contained in:
parent
321fafa8af
commit
76f591d943
2 changed files with 80 additions and 16 deletions
|
@ -3,18 +3,23 @@
|
||||||
http_server:
|
http_server:
|
||||||
listen: 0.0.0.0
|
listen: 0.0.0.0
|
||||||
port: 8080
|
port: 8080
|
||||||
username: upgrade_client
|
users:
|
||||||
password: super_secret_password
|
- upgrade_client:
|
||||||
|
password: super_secret_password
|
||||||
|
permissions:
|
||||||
|
- audience:
|
||||||
|
- private
|
||||||
|
- public
|
||||||
|
|
||||||
upgrades:
|
upgrades:
|
||||||
# Build dir should contain the following structure
|
# Build dir should contain the following structure
|
||||||
# /VERSION
|
# /VERSION
|
||||||
# VERSION is a file containing a single line with the currently built NPBackup version, example: 2.2.0
|
# VERSION is a file containing a single line with the currently built NPBackup version, example: 2.2.0
|
||||||
# /{platform}/{arch}/{binary}
|
# /{platform}/{arch}/{binary}/{audience}
|
||||||
# Current platforms are 'windows', 'linux'
|
# Current platforms are 'windows', 'linux'
|
||||||
# Current arches are 'x64', 'x86', 'arm' and 'arm64'
|
# Current arches are 'x64', 'x86', 'arm' and 'arm64'
|
||||||
# In each folder there should be a npbackup or npbackup.exe binary depending on the platform
|
# In each folder there should be a npbackup or npbackup.exe binary depending on the platform
|
||||||
data_root: /var/www/upgrade_server/dist
|
data_root: /var/npbackup_upgrade_server/dist
|
||||||
# We'll store a CSV containing backup clients that upgrade here
|
# We'll store a CSV containing backup clients that upgrade here
|
||||||
statistics_file: /var/www/upgrade_server/stats.csv
|
statistics_file: /var/npbackup_upgrade_server/stats.csv
|
||||||
|
|
||||||
|
|
|
@ -60,17 +60,20 @@ security = HTTPBasic()
|
||||||
|
|
||||||
|
|
||||||
def get_current_username(credentials: HTTPBasicCredentials = Depends(security)):
|
def get_current_username(credentials: HTTPBasicCredentials = Depends(security)):
|
||||||
current_username_bytes = credentials.username.encode("utf8")
|
authenticated_user = None
|
||||||
correct_username_bytes = config_dict["http_server"]["username"].encode("utf-8")
|
|
||||||
is_correct_username = secrets.compare_digest(
|
|
||||||
current_username_bytes, correct_username_bytes
|
for user in config_dict["http_server"]["users"]:
|
||||||
)
|
try:
|
||||||
current_password_bytes = credentials.password.encode("utf8")
|
if secrets.compare_digsest(credentials.username.encode("utf-8"), user.encode("utf-8")):
|
||||||
correct_password_bytes = config_dict["http_server"]["password"].encode("utf-8")
|
if secrets.compare_digest(credentials.password.encode("utf-8"), config_dict["http_server"]["users"]["user"]["password"].encode("utf-8")):
|
||||||
is_correct_password = secrets.compare_digest(
|
authenticated_user = user
|
||||||
current_password_bytes, correct_password_bytes
|
break
|
||||||
)
|
except Exception as exc:
|
||||||
if not (is_correct_username and is_correct_password):
|
logger.info(f"Failed to check user: {exc}")
|
||||||
|
|
||||||
|
|
||||||
|
if authenticated_user is None:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
detail="Incorrect email or password",
|
detail="Incorrect email or password",
|
||||||
|
@ -79,6 +82,17 @@ def get_current_username(credentials: HTTPBasicCredentials = Depends(security)):
|
||||||
return credentials.username
|
return credentials.username
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_permissions(username: str):
|
||||||
|
"""
|
||||||
|
Returns a list of permissions
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return config_dict["http_server"]["users"][username]["permissions"]
|
||||||
|
except Exception as exc:
|
||||||
|
logger.error(f"Failed to get user permissions: {exc}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
async def api_root(auth=Depends(get_current_username)):
|
async def api_root(auth=Depends(get_current_username)):
|
||||||
if crud.is_enabled():
|
if crud.is_enabled():
|
||||||
|
@ -139,9 +153,18 @@ async def current_version(
|
||||||
client_ip = x_forwarded_for
|
client_ip = x_forwarded_for
|
||||||
else:
|
else:
|
||||||
client_ip = request.client.host
|
client_ip = request.client.host
|
||||||
|
|
||||||
|
try:
|
||||||
|
has_permission = True if audience.value in get_user_permissions(auth)["audience"] else False
|
||||||
|
except Exception as exc:
|
||||||
|
logger.error(f"Failed to get user permissions: {exc}")
|
||||||
|
has_permission = False
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"action": "check_version",
|
"action": "check_version",
|
||||||
"ip": client_ip,
|
"ip": client_ip,
|
||||||
|
"user": auth,
|
||||||
|
"has_permission": has_permission,
|
||||||
"auto_upgrade_host_identity": auto_upgrade_host_identity,
|
"auto_upgrade_host_identity": auto_upgrade_host_identity,
|
||||||
"installed_version": installed_version,
|
"installed_version": installed_version,
|
||||||
"group": group,
|
"group": group,
|
||||||
|
@ -156,6 +179,12 @@ async def current_version(
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.error("No statistics file set.")
|
logger.error("No statistics file set.")
|
||||||
|
|
||||||
|
if not has_permission:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=403,
|
||||||
|
detail="User does not have permission to access this resource",
|
||||||
|
)
|
||||||
|
|
||||||
if not crud.is_enabled():
|
if not crud.is_enabled():
|
||||||
return CurrentVersion(version="0.00")
|
return CurrentVersion(version="0.00")
|
||||||
|
|
||||||
|
@ -222,9 +251,18 @@ async def upgrades(
|
||||||
client_ip = x_forwarded_for
|
client_ip = x_forwarded_for
|
||||||
else:
|
else:
|
||||||
client_ip = request.client.host
|
client_ip = request.client.host
|
||||||
|
|
||||||
|
try:
|
||||||
|
has_permission = True if audience.value in get_user_permissions(auth)["audience"] else False
|
||||||
|
except Exception as exc:
|
||||||
|
logger.error(f"Failed to get user permissions: {exc}")
|
||||||
|
has_permission = False
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"action": "get_file_info",
|
"action": "get_file_info",
|
||||||
"ip": client_ip,
|
"ip": client_ip,
|
||||||
|
"user": auth,
|
||||||
|
"has_permission": has_permission,
|
||||||
"auto_upgrade_host_identity": auto_upgrade_host_identity,
|
"auto_upgrade_host_identity": auto_upgrade_host_identity,
|
||||||
"installed_version": installed_version,
|
"installed_version": installed_version,
|
||||||
"group": group,
|
"group": group,
|
||||||
|
@ -239,6 +277,12 @@ async def upgrades(
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.error("No statistics file set.")
|
logger.error("No statistics file set.")
|
||||||
|
|
||||||
|
if not has_permission:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=403,
|
||||||
|
detail="User does not have permission to access this resource",
|
||||||
|
)
|
||||||
|
|
||||||
if not crud.is_enabled():
|
if not crud.is_enabled():
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=503, detail="Service is currently disabled for maintenance"
|
status_code=503, detail="Service is currently disabled for maintenance"
|
||||||
|
@ -307,9 +351,18 @@ async def download(
|
||||||
client_ip = x_forwarded_for
|
client_ip = x_forwarded_for
|
||||||
else:
|
else:
|
||||||
client_ip = request.client.host
|
client_ip = request.client.host
|
||||||
|
|
||||||
|
try:
|
||||||
|
has_permission = True if audience.value in get_user_permissions(auth)["audience"] else False
|
||||||
|
except Exception as exc:
|
||||||
|
logger.error(f"Failed to get user permissions: {exc}")
|
||||||
|
has_permission = False
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"action": "download_upgrade",
|
"action": "download_upgrade",
|
||||||
"ip": client_ip,
|
"ip": client_ip,
|
||||||
|
"user": auth,
|
||||||
|
"has_permission": has_permission,
|
||||||
"auto_upgrade_host_identity": auto_upgrade_host_identity,
|
"auto_upgrade_host_identity": auto_upgrade_host_identity,
|
||||||
"installed_version": installed_version,
|
"installed_version": installed_version,
|
||||||
"group": group,
|
"group": group,
|
||||||
|
@ -324,6 +377,12 @@ async def download(
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.error("No statistics file set.")
|
logger.error("No statistics file set.")
|
||||||
|
|
||||||
|
if not has_permission:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=403,
|
||||||
|
detail="User does not have permission to access this resource",
|
||||||
|
)
|
||||||
|
|
||||||
if not crud.is_enabled():
|
if not crud.is_enabled():
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=503, detail="Service is currently disabled for maintenance"
|
status_code=503, detail="Service is currently disabled for maintenance"
|
||||||
|
|
Loading…
Add table
Reference in a new issue