Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Davide Arcuri committed Oct 24, 2024
1 parent fb6d942 commit fe84e69
Show file tree
Hide file tree
Showing 9 changed files with 346 additions and 184 deletions.
57 changes: 54 additions & 3 deletions examples/local_api.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@
"dumps = session.get(f\"{url}/api/dumps/\", verify=False).json()\n",
"print(f\"{len(dumps)} dumps found\")\n",
"if dumps: \n",
" pprint(dumps[0])"
" pprint(dumps[0])\n",
" dump_pk = dumps[0]['index']"
]
},
{
Expand Down Expand Up @@ -173,6 +174,7 @@
"if res.status_code == 200:\n",
" if example := res.json():\n",
" print(example[0])\n",
" plugin_pk = example[0]\n",
"else:\n",
" print(res.status_code, res.text) "
]
Expand All @@ -190,11 +192,13 @@
"metadata": {},
"outputs": [],
"source": [
"\"\"\" TODO\n",
"res = session.get(f\"{url}/api/dumps/{dump_pk}/plugins/{plugin_pk}/\", verify=False)\n",
"if res.status_code == 200:\n",
" pprint(res.json())\n",
" result_pk = [x['pk'] for x in res.json() if x['plugin'] == 'linux.pslist.PsList'][0]\n",
" print(res.status_code)\n"
" print(res.status_code)\n",
"\"\"\""
]
},
{
Expand Down Expand Up @@ -287,6 +291,53 @@
"walker = pyg.walk(df)\n",
"\"\"\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# EDIT DUMP"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"data = {\n",
" \"name\": \"string\",\n",
" \"folder\": {\n",
" \"name\": \"string\"\n",
" },\n",
" \"color\": \"#7218EE\",\n",
" \"status\": \"1\",\n",
" \"comment\": \"stringghjny\"\n",
"}\n",
"res = session.patch(f\"{url}/api/dumps/{dump_pk}\", json=data, cookies=first.cookies, headers=headers, verify=False)\n",
"if res.status_code == 200:\n",
" pprint(res.json())\n",
" dump_pk = res.json()[\"index\"]\n",
"else:\n",
" print(res.status_code, res.text)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# DELETE DUMP"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"res = session.delete(f\"{url}/api/dumps/{dump_pk}\", cookies=first.cookies, headers=headers, verify=False)\n",
"print(res.status_code, res.text) "
]
}
],
"metadata": {
Expand All @@ -305,7 +356,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.8"
"version": "3.10.15"
}
},
"nbformat": 4,
Expand Down
9 changes: 9 additions & 0 deletions orochi/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,15 @@ class Meta:
]


class DumpEditIn(ModelSchema):
folder: Optional[FolderSchema] = None
authorized_users: Optional[List[int]] = None

class Meta:
model = Dump
fields = ["comment", "name", "color", "status"]


class DumpSchema(ModelSchema):
folder: Optional[FolderSchema] = None
author: UserOutSchema = None
Expand Down
127 changes: 124 additions & 3 deletions orochi/api/routers/dumps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,24 @@
from uuid import UUID, uuid1

from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import transaction
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from guardian.shortcuts import get_objects_for_user
from ninja import File, Query, Router, UploadedFile
from guardian.shortcuts import assign_perm, get_objects_for_user, get_perms, remove_perm
from ninja import File, PatchDict, Query, Router, UploadedFile
from ninja.security import django_auth

from orochi.api.filters import DumpFilters, OperatingSytemFilters
from orochi.api.models import DumpIn, DumpInfoSchema, DumpSchema, ResultSmallOutSchema
from orochi.api.models import (
DumpEditIn,
DumpIn,
DumpInfoSchema,
DumpSchema,
ErrorsOut,
ResultSmallOutSchema,
SuccessResponse,
)
from orochi.website.defaults import RESULT_STATUS_NOT_STARTED, RESULT_STATUS_RUNNING
from orochi.website.models import Dump, Folder, Result, UserPlugin
from orochi.website.views import index_f_and_f
Expand Down Expand Up @@ -46,6 +55,44 @@ def list_dumps(request, filters: Query[OperatingSytemFilters]):
return dumps


@router.delete(
"/{pk}",
auth=django_auth,
url_name="delete_dump",
response={200: SuccessResponse, 400: ErrorsOut},
)
def delete_dump(request, pk: UUID):
"""
Deletes a dump identified by its primary key (pk). This function ensures that the user has permission to delete the dump before proceeding with the deletion.
Args:
request: The HTTP request object.
pk (UUID): The primary key of the dump to be deleted.
Returns:
SuccessResponse: A response indicating the successful deletion of the dump.
Raises:
Http404: If the dump with the specified primary key does not exist.
ErrorsOut: If the user does not have permission to delete the dump.
Examples:
DELETE /dumps/{pk}
"""
try:
dump = get_object_or_404(Dump, index=pk)
name = dump.name
if dump not in get_objects_for_user(request.user, "website.can_see"):
return 400, {"errors": "Error during index deletion."}
dump.delete()
shutil.rmtree(f"{settings.MEDIA_ROOT}/{dump.index}")
return 200, {"message": f"Index {name} has been deleted successfully."}
except Exception as excp:
return 400, {
"errors": str(excp) if excp else "Generic error during dump deletion"
}


@router.get("/{pk}", response=DumpInfoSchema, auth=django_auth)
def get_dump_info(request, pk: UUID):
"""
Expand Down Expand Up @@ -152,6 +199,65 @@ def create_dump(request, payload: DumpIn, upload: Optional[UploadedFile] = File(
return HttpResponse(f"Bad Request ({excp})", status=400)


@router.patch("/{pk}", url_name="edit_index", response=DumpSchema, auth=django_auth)
def edit_dump(request, pk: UUID, payload: PatchDict[DumpEditIn]):
"""
Edits an existing dump based on the provided payload. This function updates the dump's attributes and manages user permissions for accessing the dump.
Args:
request: The HTTP request object.
payload (PatchDict[DumpEditIn]): The data containing the updates to be applied to the dump.
Returns:
DumpSchema: The updated dump object.
Raises:
Http404: If the dump with the specified index does not exist.
HttpResponse: If there is an error during the update process.
Examples:
PATCH /dumps/{pk}
"""

try:
dump = get_object_or_404(Dump, index=pk)
if dump not in get_objects_for_user(request.user, "website.can_see"):
return 403, {"message": "Unauthorized"}

auth_users = [
user.pk
for user in get_user_model().objects.all()
if "can_see" in get_perms(user, dump) and user != request.user
]

if payload["folder"]:
folder, _ = Folder.objects.get_or_create(
name=payload["folder"]["name"], user=request.user
)
dump.folder = folder

for attr, value in payload.items():
if attr not in ["authorized_users", "folder"]:
setattr(dump, attr, value)
else:
for user_pk in payload.get("authorized_users", []):
user = get_user_model().objects.get(pk=user_pk)
if user.pk not in auth_users:
assign_perm(
"can_see",
user,
dump,
)
for user_pk in auth_users:
if user_pk not in payload.get("authorized_users", []):
user = get_user_model().objects.get(pk=user_pk)
remove_perm("can_see", user, dump)
dump.save()
return dump
except Exception as excp:
return HttpResponse(f"Bad Request ({excp})", status=400)


@router.get(
"/{idxs:pks}/plugins",
url_name="dumps_plugins",
Expand Down Expand Up @@ -188,3 +294,18 @@ def get_dump_plugins(request, pks: List[UUID], filters: Query[DumpFilters] = Non
if filters and filters.result:
res = res.filter(result=filters.result)
return res


@router.get(
"/{idxs:pks}/plugin/{str:plugin_name}",
url_name="dumps_plugin_status",
auth=django_auth,
)
def get_dump_plugin_status(request, pks: List[UUID], plugin_name: int):
dumps_ok = get_objects_for_user(request.user, "website.can_see")
dumps = [
dump.index for dump in Dump.objects.filter(index__in=pks) if dump in dumps_ok
]
return Result.objects.select_related("dump", "plugin").filter(
dump__index__in=dumps, plugin__name=plugin_name
)
64 changes: 47 additions & 17 deletions orochi/templates/website/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -846,21 +846,47 @@ <h5 class="offcanvas-title" id="leftNoteLabel">History Log</h5>
$(document).on("submit", "#edit-index", function (e) {
e.preventDefault();
var form = $(this);
let formData = form.serializeArray();
let obj = {};
formData.forEach(item => {
if (['csrfmiddlewaretoken', 'folder'].indexOf(item.name) == -1) {
obj[item.name] = item.value;
}else if(item.name == 'folder'){
if(item.value != null && item.value != ''){
obj['folder'] = {'name': $("#id_folder").find(":selected").text()}
}
}
});
$.ajaxSetup({
headers: { 'X-CSRFToken': $('input[name="csrfmiddlewaretoken"]').val() }
});

$.ajax({
url: form.attr("action"),
data: form.serialize(),
data: JSON.stringify(obj),
contentType: "application/json",
type: form.attr("method"),
dataType: 'json',
success: function (data) {
if (data.form_is_valid) {
$("#index-list").html(data.dumps);
$("#modal-update").modal('hide');
selected_plugin = null;
update_sidebar();
} else {
$("#modal-update .modal-content").html(data.html_form);
}
}
success: function () {
$("#modal-update").modal('hide');
selected_plugin = null;
update_sidebar();
$.toast({
title: 'Index updated!',
content: 'Index updated successfully!',
type: 'success',
delay: 5000
});
},
error: function () {
$("#modal-update").modal('hide');
$.toast({
title: 'Index delete!',
content: 'Error in index update!',
type: 'error',
delay: 5000
});
},
});
});

Expand All @@ -870,10 +896,14 @@ <h5 class="offcanvas-title" id="leftNoteLabel">History Log</h5>
var index = btn.data('index');
bootbox.confirm("Are you sure??", function (result) {
if (result === true) {

$.ajaxSetup({
headers: { 'X-CSRFToken': $('input[name="csrfmiddlewaretoken"]').val() }
});

$.ajax({
url: "{% url 'website:index_delete' %}",
data: { 'index': index },
method: 'get',
url: "{% url 'api:delete_dump' pk=111111111122222222223333333333444444 %}".replace(/111111111122222222223333333333444444/, index),
method: 'delete',
dataType: 'json',
success: function (data) {
btn.parent().parent().parent().remove();
Expand All @@ -885,15 +915,15 @@ <h5 class="offcanvas-title" id="leftNoteLabel">History Log</h5>
update_sidebar();
$.toast({
title: 'Index delete!',
content: 'Index has been deleted successfully.',
content: data.message,
type: 'success',
delay: 5000
});
},
error: function () {
error: function (data) {
$.toast({
title: 'Index delete!',
content: 'Error during index deletion.',
content: data.errors,
type: 'error',
delay: 5000
});
Expand Down
2 changes: 1 addition & 1 deletion orochi/templates/website/partial_index_edit.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% load widget_tweaks %}

<form method="post" action="{% url 'website:index_edit' %}" id="edit-index">
<form method="patch" action="{% url 'api:edit_index' pk=index %}" id="edit-index">
{{ form.media }}
{% csrf_token %}
<div class="modal-header">
Expand Down
Loading

0 comments on commit fe84e69

Please sign in to comment.