Add create new API key from api v2

This commit is contained in:
amcmanu3 2023-09-03 23:30:26 -04:00
parent cd4bd681d9
commit 6a4a9f77d9
4 changed files with 223 additions and 234 deletions

View File

@ -1525,139 +1525,7 @@ class PanelHandler(BaseHandler):
role = self.controller.roles.get_role(r)
exec_user_role.add(role["role_name"])
if page == "edit_user":
if bleach.clean(self.get_argument("username", None)).lower() == "system":
self.redirect(
"/panel/error?error=Unauthorized access: "
"system user is not editable"
)
user_id = bleach.clean(self.get_argument("id", None))
user = self.controller.users.get_user_by_id(user_id)
username = bleach.clean(self.get_argument("username", None).lower())
theme = bleach.clean(self.get_argument("theme", "default"))
if (
username != self.controller.users.get_user_by_id(user_id)["username"]
and username in self.controller.users.get_all_usernames()
):
self.redirect(
"/panel/error?error=Duplicate User: Useranme already exists."
)
password0 = bleach.clean(self.get_argument("password0", None))
password1 = bleach.clean(self.get_argument("password1", None))
email = bleach.clean(self.get_argument("email", "default@example.com"))
enabled = int(float(self.get_argument("enabled", "0")))
try:
hints = int(bleach.clean(self.get_argument("hints")))
hints = True
except:
hints = False
lang = bleach.clean(
self.get_argument("language"), self.helper.get_setting("language")
)
if superuser:
# Checks if user is trying to change super user status of self.
# We don't want that. Automatically make them stay super user
# since we know they are.
if str(exec_user["user_id"]) != str(user_id):
superuser = int(bleach.clean(self.get_argument("superuser", "0")))
else:
superuser = 1
else:
superuser = 0
if exec_user["superuser"]:
manager = self.get_argument("manager")
if manager == "":
manager = None
else:
manager = int(manager)
else:
manager = user["manager"]
if (
not exec_user["superuser"]
and int(exec_user["user_id"]) != user["manager"]
):
if username is None or username == "":
self.redirect("/panel/error?error=Invalid username")
return
if user_id is None:
self.redirect("/panel/error?error=Invalid User ID")
return
if (
EnumPermissionsCrafty.USER_CONFIG
not in exec_user_crafty_permissions
):
if str(user_id) != str(exec_user["user_id"]):
self.redirect(
"/panel/error?error=Unauthorized access: not a user editor"
)
return
user_data = {
"username": username,
"password": password0,
"email": email,
"lang": lang,
"hints": hints,
"theme": theme,
}
self.controller.users.update_user(user_id, user_data=user_data)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
f"Edited user {username} (UID:{user_id}) password",
server_id=0,
source_ip=self.get_remote_ip(),
)
self.redirect("/panel/panel_config")
return
# does this user id exist?
if not self.controller.users.user_id_exists(user_id):
self.redirect("/panel/error?error=Invalid User ID")
return
else:
if password0 != password1:
self.redirect("/panel/error?error=Passwords must match")
return
roles = self.get_user_role_memberships()
permissions_mask, server_quantity = self.get_perms_quantity()
# if email is None or "":
# email = "default@example.com"
user_data = {
"username": username,
"manager": manager,
"password": password0,
"email": email,
"enabled": enabled,
"roles": roles,
"lang": lang,
"superuser": superuser,
"hints": hints,
"theme": theme,
}
user_crafty_data = {
"permissions_mask": permissions_mask,
"server_quantity": server_quantity,
}
self.controller.users.update_user(
user_id, user_data=user_data, user_crafty_data=user_crafty_data
)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
f"Edited user {username} (UID:{user_id}) with roles {roles} "
f"and permissions {permissions_mask}",
server_id=0,
source_ip=self.get_remote_ip(),
)
self.redirect("/panel/panel_config")
elif page == "edit_user_apikeys":
if page == "edit_user_apikeys":
user_id = self.get_argument("id", None)
name = self.get_argument("name", None)
superuser = self.get_argument("superuser", None) == "1"
@ -1737,100 +1605,6 @@ class PanelHandler(BaseHandler):
)
self.finish()
elif page == "add_user":
username = bleach.clean(self.get_argument("username", None).lower())
if username.lower() == "system":
self.redirect(
"/panel/error?error=Unauthorized access: "
"username system is reserved for the Crafty system."
" Please choose a different username."
)
return
password0 = bleach.clean(self.get_argument("password0", None))
password1 = bleach.clean(self.get_argument("password1", None))
email = bleach.clean(self.get_argument("email", "default@example.com"))
enabled = int(float(self.get_argument("enabled", "0")))
theme = bleach.clean(self.get_argument("theme"), "default")
hints = True
lang = bleach.clean(
self.get_argument("lang", self.helper.get_setting("language"))
)
# We don't want a non-super user to be able to create a super user.
if superuser:
new_superuser = int(bleach.clean(self.get_argument("superuser", "0")))
else:
new_superuser = 0
if EnumPermissionsCrafty.USER_CONFIG not in exec_user_crafty_permissions:
self.redirect(
"/panel/error?error=Unauthorized access: not a user editor"
)
return
if (
not self.controller.crafty_perms.can_add_user(exec_user["user_id"])
and not exec_user["superuser"]
):
self.redirect(
"/panel/error?error=Unauthorized access: quantity limit reached"
)
return
if username is None or username == "":
self.redirect("/panel/error?error=Invalid username")
return
if exec_user["superuser"]:
manager = self.get_argument("manager")
if manager == "":
manager = None
else:
manager = int(manager)
else:
manager = int(exec_user["user_id"])
# does this user id exist?
if self.controller.users.get_id_by_name(username) is not None:
self.redirect("/panel/error?error=User exists")
return
if password0 != password1:
self.redirect("/panel/error?error=Passwords must match")
return
roles = self.get_user_role_memberships()
permissions_mask, server_quantity = self.get_perms_quantity()
user_id = self.controller.users.add_user(
username,
manager=manager,
password=password0,
email=email,
enabled=enabled,
superuser=new_superuser,
theme=theme,
)
user_data = {"roles": roles, "lang": lang, "hints": True}
user_crafty_data = {
"permissions_mask": permissions_mask,
"server_quantity": server_quantity,
}
self.controller.users.update_user(
user_id, user_data=user_data, user_crafty_data=user_crafty_data
)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
f"Added user {username} (UID:{user_id})",
server_id=0,
source_ip=self.get_remote_ip(),
)
self.controller.management.add_to_audit_log(
exec_user["user_id"],
f"Edited user {username} (UID:{user_id}) with roles {roles}",
server_id=0,
source_ip=self.get_remote_ip(),
)
self.redirect("/panel/panel_config")
else:
self.set_status(404)
page_data = {

View File

@ -49,6 +49,7 @@ from app.classes.web.routes.api.users.user.index import ApiUsersUserIndexHandler
from app.classes.web.routes.api.users.user.permissions import (
ApiUsersUserPermissionsHandler,
)
from app.classes.web.routes.api.users.user.api import ApiUsersUserKeyHandler
from app.classes.web.routes.api.users.user.pfp import ApiUsersUserPfpHandler
from app.classes.web.routes.api.users.user.public import ApiUsersUserPublicHandler
from app.classes.web.routes.api.crafty.config.index import ApiCraftyConfigIndexHandler
@ -90,6 +91,11 @@ def api_handlers(handler_args):
ApiUsersIndexHandler,
handler_args,
),
(
r"/api/v2/users/([0-9]+)/key/?",
ApiUsersUserKeyHandler,
handler_args,
),
(
r"/api/v2/users/([0-9]+)/?",
ApiUsersUserIndexHandler,

View File

@ -0,0 +1,146 @@
import json
import logging
from jsonschema import ValidationError, validate
from app.classes.web.base_api_handler import BaseApiHandler
logger = logging.getLogger(__name__)
class ApiUsersUserKeyHandler(BaseApiHandler):
def get(self, _user_id: str, key_id: int):
auth_data = self.authenticate_user()
if not auth_data:
return
(
_,
_exec_user_crafty_permissions,
_,
_,
_user,
) = auth_data
key = self.controller.users.get_user_api_key(key_id)
# does this user id exist?
if key is None:
self.redirect("/panel/error?error=Invalid Key ID")
return
if (
str(key.user_id) != str(auth_data[4]["user_id"])
and not auth_data[4]["superuser"]
):
self.redirect(
"/panel/error?error=You are not authorized to access this key."
)
return
self.controller.management.add_to_audit_log(
auth_data[4]["user_id"],
f"Generated a new API token for the key {key.name} "
f"from user with UID: {key.user_id}",
server_id=0,
source_ip=self.get_remote_ip(),
)
self.finish_json(
{
"status": "ok",
"data": self.controller.authentication.generate(
key.user_id_id, {"token_id": key.token_id}
),
}
)
def patch(self, user_id: str):
user_key_schema = {
"type": "object",
"properties": {
"name": {"type": "string", "minLength": 3},
"server_permissions_mask": {
"type": "string",
"pattern": "^[01]{8}$", # 8 bits, see EnumPermissionsServer
},
"crafty_permissions_mask": {
"type": "string",
"pattern": "^[01]{3}$", # 8 bits, see EnumPermissionsCrafty
},
"superuser": {"type": "boolean"},
},
"additionalProperties": False,
"minProperties": 1,
}
auth_data = self.authenticate_user()
if not auth_data:
return
(
_,
_exec_user_crafty_permissions,
_,
_superuser,
user,
) = auth_data
try:
data = json.loads(self.request.body)
except json.decoder.JSONDecodeError as e:
return self.finish_json(
400, {"status": "error", "error": "INVALID_JSON", "error_data": str(e)}
)
try:
validate(data, user_key_schema)
except ValidationError as e:
return self.finish_json(
400,
{
"status": "error",
"error": "INVALID_JSON_SCHEMA",
"error_data": str(e),
},
)
if user_id == "@me":
user_id = user["user_id"]
# does this user id exist?
if not self.controller.users.user_id_exists(user_id):
return self.finish_json(
400,
{
"status": "error",
"error": "USER NOT FOUND",
"error_data": "USER_NOT_FOUND",
},
)
if (
str(user_id) != str(auth_data[4]["user_id"])
and not auth_data[4]["superuser"]
):
return self.finish_json(
400,
{
"status": "error",
"error": "NOT AUTHORIZED",
"error_data": "TRIED TO EDIT KEY WIHTOUT AUTH",
},
)
key_id = self.controller.users.add_user_api_key(
data["name"],
user_id,
data["superuser"],
data["server_permissions_mask"],
data["crafty_permissions_mask"],
)
self.controller.management.add_to_audit_log(
auth_data[4]["user_id"],
f"Added API key {data['name']} with crafty permissions "
f"{data['crafty_permissions_mask']}"
f" and {data['server_permissions_mask']} for user with UID: {user_id}",
server_id=0,
source_ip=self.get_remote_ip(),
)
self.finish_json(200, {"status": "ok", "data": {"id": key_id}})

View File

@ -115,10 +115,7 @@
'createNew', data['lang']) }}</h4>
</div>
<div class="card-body">
<form id="user_form" class="forms-sample" method="post"
action="/panel/edit_user_apikeys">
{% raw xsrf_form_html() %}
<input type="hidden" name="id" value="{{ data['user']['user_id'] }}">
<form id="user_api_form" class="forms-sample">
<div class="form-group">
<label class="form-label" for="username">{{ translate('apiKeys', 'name',
@ -142,7 +139,7 @@
}}</label>
</td>
<td>
<input type="checkbox" class=""
<input type="checkbox" class="server_perm"
id="permission_{{ permission.name }}"
name="permission_{{ permission.name }}" value="1">
</td>
@ -154,7 +151,7 @@
}}</label>
</td>
<td>
<input type="checkbox" class=""
<input type="checkbox" class="crafty_perm"
id="permission_{{ permission.name }}"
name="permission_{{ permission.name }}" value="1">
</td>
@ -201,8 +198,74 @@
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
}
const userId = new URLSearchParams(document.location.search).get('id')
$(document).ready(function () {
$("#user_api_form").on("submit", async function (e) {
e.preventDefault();
var token = getCookie("_xsrf")
let apiForm = document.getElementById("user_api_form");
let formData = new FormData(apiForm);
//Create an object from the form data entries
let formDataObject = Object.fromEntries(formData.entries());
//We need to make sure these are sent regardless of whether or not they're checked
formDataObject.disabled_language_files = $('#lang_select').val();
$('#user_api_form input[type="checkbox"]:checked').each(function () {
if ($(this).val() == 'True') {
formDataObject[this.name] = true;
} else {
formDataObject[this.name] = false;
}
});
let server_permissions = $('.server_perm').map(function () {
if (this.checked) {
return "1";
} else {
return "0"
}
}).get();
server_permissions = server_permissions.join("");
let crafty_permissions = $('.crafty_perm').map(function () {
if (this.checked) {
return "1";
} else {
return "0"
}
}).get();
crafty_permissions = crafty_permissions.join("");
console.log(server_permissions);
console.log(crafty_permissions);
console.log(formDataObject);
// Format the plain form data as JSON
let formDataJsonString = JSON.stringify({
"name": formDataObject.name,
"server_permissions_mask": server_permissions,
"crafty_permissions_mask": crafty_permissions,
"superuser": $("#superuser").prop('checked'),
});
console.log(formDataJsonString);
let res = await fetch(`/api/v2/users/${userId}/key/`, {
method: 'PATCH',
headers: {
'X-XSRFToken': token
},
body: formDataJsonString,
});
let responseData = await res.json();
if (responseData.status === "ok") {
location.reload();
} else {
bootbox.alert({
title: responseData.error,
message: responseData.error_data
});
}
});
console.log("ready!");
$('.delete-api-key').click(function () {
var keyId = $(this).data("key-id");