Compare commits

...

10 commits

12 changed files with 121 additions and 218 deletions

View file

@ -115,7 +115,7 @@ class NewSnapshotView(ApiMixing):
text = "fail: It is not possible to parse snapshot"
return JsonResponse({'status': text}, status=500)
property = SystemProperty.objects.filter(
prop = SystemProperty.objects.filter(
uuid=ev_uuid,
# TODO this is hardcoded, it should select the user preferred algorithm
key="hidalgo1",
@ -123,7 +123,7 @@ class NewSnapshotView(ApiMixing):
).first()
if not property:
if not prop:
logger.error("Error: No property for uuid: %s", ev_uuid)
return JsonResponse({'status': 'fail'}, status=500)

View file

@ -52,7 +52,7 @@
}
</style>
<!-- Custom styles for this template -->
<link href="{% static "/css/dashboard.css" %}" rel="stylesheet">
{% endblock %}
@ -82,23 +82,23 @@
<ul class="nav flex-column">
{% if user.is_admin %}
<li class="nav-item">
<a class="admin {% if path in 'panel users states_panel' %}active {% endif %}nav-link fw-bold" data-bs-toggle="collapse" data-bs-target="#ul_admin" aria-expanded="false" aria-controls="ul_admin" href="javascript:void()">
<a class="admin {% if path in 'panel users states_panel edit_user delete_user new_user institution' %}active {% endif %}nav-link fw-bold" data-bs-toggle="collapse" data-bs-target="#ul_admin" aria-expanded="false" aria-controls="ul_admin" href="javascript:void()">
<i class="bi bi-person-fill-gear icon_sidebar"></i>
{% trans 'Admin' %}
</a>
<ul class="flex-column mb-2 ul_sidebar accordion-collapse {% if path in 'panel users' %}expanded{% else %}collapse{% endif %}" id="ul_admin" data-bs-parent="#sidebarMenu">
<ul class="flex-column mb-2 ul_sidebar accordion-collapse {% if path in 'panel institution users edit_user new_user delete_user states_panel' %}expanded{% else %}collapse{% endif %}" id="ul_admin" data-bs-parent="#sidebarMenu">
<li class="nav-item">
<a class="nav-link{% if path == 'panel' %} active2{% endif %}" href="{% url 'admin:panel' %}">
<a class="nav-link{% if path in 'panel institution' %} active2{% endif %}" href="{% url 'admin:panel' %}">
{% trans 'Panel' %}
</a>
</li>
<li class="nav-item">
<a class="nav-link{% if path == 'users' %} active2{% endif %}" href="{% url 'admin:users' %}">
<a class="nav-link{% if path in 'users edit_user new_user delete_user' %} active2{% endif %}" href="{% url 'admin:users' %}">
{% trans 'Users' %}
</a>
</li>
<li class="nav-item">
<a class="nav-link{% if path == 'states' %} active2{% endif %}" href="{% url 'admin:states_panel' %}">
<a class="nav-link{% if path == 'states_panel' %} active2{% endif %}" href="{% url 'admin:states_panel' %}">
{% trans 'States' %}
</a>
</li>
@ -188,10 +188,10 @@
{% if help_text %}
<span class="ms-1" data-bs-toggle="tooltip" data-bs-placement="right" title="{{ help_text }}">
<i class="fas fa-question-circle text-secondary h6 align-top"></i>
</span>
</span>
{% endif %}
</h1>
<form method="post" action="{% url 'dashboard:search' %}">
{% csrf_token %}
<div class="input-group rounded">
@ -201,9 +201,9 @@
</span>
</div>
</form>
</div>
<div class="row border-bottom mb-3">
<div class="col">
<small style="color:#899bbd"><i>{{ breadcrumb }}</i></small>
@ -235,7 +235,7 @@
</body>
<script>
//If help_text is passed to the view as context, a hover-able help icon is displayed
//If help_text is passed to the view as context, a hover-able help icon is displayed
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);

View file

@ -75,12 +75,12 @@ class Device:
if not self.uuids:
self.get_uuids()
properties = UserProperty.objects.filter(
user_properties = UserProperty.objects.filter(
uuid__in=self.uuids,
owner=self.owner,
type=UserProperty.Type.DOCUMENT
)
return properties
return user_properties
def get_uuids(self):
for a in self.get_properties():
@ -113,9 +113,9 @@ class Device:
properties = self.get_properties()
if not properties.count():
return
property = properties.first()
prop = properties.first()
self.last_evidence = Evidence(property.uuid)
self.last_evidence = Evidence(prop.uuid)
def is_eraseserver(self):
if not self.uuids:
@ -123,13 +123,13 @@ class Device:
if not self.uuids:
return False
property = UserProperty.objects.filter(
prop = UserProperty.objects.filter(
uuid__in=self.uuids,
owner=self.owner,
type=UserProperty.Type.ERASE_SERVER
).first()
if property:
if prop:
return True
return False

View file

@ -4,7 +4,7 @@
{% block content %}
<div class="position-fixed" style="bottom: 2rem; right: 2rem; z-index: 9999; display: flex; gap: 0.5rem;">
<button class="btn btn-warning d-flex align-items-center shadow" type="button"
<button class="btn btn-yellow d-flex align-items-center shadow" type="button"
data-bs-toggle="offcanvas" data-bs-target="#notesOffcanvas" aria-controls="notesOffcanvas"
data-bs-toggle="tooltip" data-bs-placement="left" title="{% trans 'View recent notes' %}">
<i class="bi bi-journal-text me-1"></i>
@ -18,29 +18,29 @@
<div class="offcanvas-header">
<h5 id="notesOffcanvasLabel">{% trans "Latest Notes" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
</div>
<div class="offcanvas-body" style="margin-bottom: 5rem;">
{% for note in device_notes|slice:":4" %}
<div class="card mb-3 shadow-sm">
<div class="card-body">
<div class="card-body">
<div>
<small class="text-muted">
{{ note.date|timesince }} {% trans "ago" %}
</small>
{% if user == note.user or user.is_admin %}
<span class="badge bg-warning text-dark ms-2">{% trans "Editable" %}</span>
<span class="badge bg-yellow text-dark ms-2">{% trans "Editable" %}</span>
</div>
<blockquote
class="blockquote mt-2 p-2 bg-light fst-italic"
contenteditable="true"
style="font-size: 1em!important"
style="font-size: 1.2em!important"
data-note-id="{{ note.id }}"
title="{% trans 'Click to edit this note' %}"
oninput="toggleSaveLink(this)">
{% else %}
</div>
<blockquote style="font-size: 1em!important" class="blockquote mt-2 p-2 fst-italic">
<blockquote style="font-size: 1.2em!important" class="blockquote mt-2 p-2 fst-italic">
{% endif %}
<p data-note-id="{{ note.id }}">
{{ note.description }}
@ -49,7 +49,7 @@
<small>{{ note.user.get_full_name|default:note.user.username }}</small>
</footer>
</blockquote>
{% if user == note.user or user.is_admin %}
<div class="d-flex justify-content-end align-items-center">
@ -70,10 +70,10 @@
title="{% trans 'Save changes' %}"
onclick="submitUpdatedNote('{{ note.id }}'); return false;"
>
<i class="fas fa-save"></i>
<i class="fas fa-save px-1"></i>
</a>
</form>
<!-- delete note button -->
<button type="button" class="btn btn-link btn-outline-danger btn-sm text-danger" id="deleteIcon{{ note.id }}" title="{% trans 'Delete note' %}" data-bs-toggle="collapse" data-bs-target="#confirmDelete{{ note.id }}">
<i class="bi bi-trash"></i>
@ -95,7 +95,7 @@
</div>
</form>
{% endif %}
</div>
</div>
{% empty %}
@ -119,7 +119,9 @@
{% trans "Change state" %}
{% if device_states %}
({{ device_states.0.state }})
{% endif %}
{% else %}
( {% trans "None" %} )
{% endif %}
</a>
<ul class="dropdown-menu" aria-labelledby="addStateDropdown" style="width: 100%;">
{% for state in state_definitions %}
@ -148,7 +150,7 @@
</button>
{% endif %}
<!-- Add note button -->
<button class="btn btn-warning ms-2" type="button" data-bs-toggle="modal" data-bs-target="#addNoteModal">
<button class="btn btn-yellow ms-2" type="button" data-bs-toggle="modal" data-bs-target="#addNoteModal">
<i class="bi bi-sticky"></i> {% trans "Add a note" %}
</button>
@ -204,6 +206,8 @@
{% include 'tabs/lots.html' %}
{% include 'tabs/components.html' %}
{% include 'tabs/evidences.html' %}
<!-- Add a note popup -->
@ -259,8 +263,8 @@
saveLink.classList.remove("disabled", "text-muted", "border-light");
saveLink.classList.add("text-success", "border-success");
saveLink.style.pointerEvents = "auto";
saveLink.style.pointerEvents = "auto";
}
//updates note-update-form with new value from blockquote
function submitUpdatedNote(noteId) {

View file

@ -53,6 +53,13 @@
</div>
</div>
<div class="row mb-3">
<div class="col-sm-4 text-muted fw-bold">
{% trans 'Version' %}
</div>
<div class="col-sm-8">{{ object.version|default:'' }}</div>
</div>
<div class="row mb-3">
<div class="col-sm-4 text-muted fw-bold">{% trans 'Serial Number' %}
</div>

View file

@ -117,12 +117,15 @@ class DetailsView(DashboardView, TemplateView):
)
last_evidence= self.object.get_last_evidence(),
uuid=self.object.last_uuid()
state_definitions = StateDefinition.objects.filter(
institution=self.request.user.institution
).order_by('order')
context.update({
'object': self.object,
'snapshot': last_evidence,
'lot_tags': lot_tags,
'dpps': dpps,
"state_definitions": StateDefinition.objects.filter(institution=self.request.user.institution).order_by('order'),
"state_definitions": state_definitions,
"device_states": State.objects.filter(snapshot_uuid=uuid).order_by('-date'),
"device_logs": DeviceLog.objects.filter(snapshot_uuid=uuid).order_by('-date'),
"device_notes": Note.objects.filter(snapshot_uuid=uuid).order_by('-date'),

View file

@ -10,6 +10,7 @@ from device.models import Device
from evidence.parse import Build
from evidence.models import SystemProperty, UserProperty
from utils.save_snapshots import move_json, save_in_disk
from action.models import DeviceLog
class UploadForm(forms.Form):
@ -71,6 +72,7 @@ class UserTagForm(forms.Form):
self.pk = None
self.uuid = kwargs.pop('uuid', None)
self.user = kwargs.pop('user')
instance = SystemProperty.objects.filter(
uuid=self.uuid,
key='CUSTOM_ID',
@ -88,6 +90,7 @@ class UserTagForm(forms.Form):
if not data:
return False
self.tag = data
self.instance = SystemProperty.objects.filter(
uuid=self.uuid,
key='CUSTOM_ID',
@ -101,19 +104,35 @@ class UserTagForm(forms.Form):
return
if self.instance:
old_value = self.instance.value
if not self.tag:
message = _("<Deleted> Evidence Tag. Old Value: '{}'").format(
old_value
)
self.instance.delete()
self.instance.value = self.tag
self.instance.save()
return
else:
self.instance.value = self.tag
self.instance.save()
if old_value != self.tag:
msg = "<Updated> Evidence Tag. Old Value: '{}'. New Value: '{}'"
message=_(msg).format(old_value, self.tag)
else:
message = _("<Created> Evidence Tag. Value: '{}'").format(self.tag)
SystemProperty.objects.create(
uuid=self.uuid,
key='CUSTOM_ID',
value=self.tag,
owner=self.user.institution,
user=self.user
)
DeviceLog.objects.create(
snapshot_uuid=self.uuid,
event= message,
user=self.user,
institution=self.user.institution
)
SystemProperty.objects.create(
uuid=self.uuid,
key='CUSTOM_ID',
value=self.tag,
owner=self.user.institution,
user=self.user
)
class ImportForm(forms.Form):
@ -164,8 +183,8 @@ class ImportForm(forms.Form):
table = []
for row in self.rows:
doc = create_doc(row)
property = create_property(doc, self.user)
table.append((doc, property))
prop = create_property(doc, self.user)
table.append((doc, prop))
if commit:
for doc, cred in table:

View file

@ -65,23 +65,21 @@ class Build:
index(self.user.institution, self.uuid, snap)
def create_annotations(self):
annotation = Annotation.objects.filter(
prop = SystemProperty.objects.filter(
uuid=self.uuid,
owner=self.user.institution,
type=Annotation.Type.SYSTEM,
)
if annotation:
txt = "Warning: Snapshot %s already registered (annotation exists)"
if prop:
txt = "Warning: Snapshot %s already registered (property exists)"
logger.warning(txt, self.uuid)
return
for k, v in self.build.algorithms.items():
Annotation.objects.create(
SystemProperty.objects.create(
uuid=self.uuid,
owner=self.user.institution,
user=self.user,
type=Annotation.Type.SYSTEM,
key=k,
value=self.sign(v)
)
@ -95,163 +93,3 @@ class Build:
phid = self.sign(json.dumps(self.build.get_doc()))
register_device_dlt(chid, phid, self.uuid, self.user)
register_passport_dlt(chid, phid, self.uuid, self.user)
class Build2:
def __init__(self, evidence_json, user, check=False):
if evidence_json.get("data",{}).get("lshw"):
if evidence_json.get("software") == "workbench-script":
return legacy_parse.Build(evidence_json, user, check=check)
self.evidence = evidence_json.copy()
self.json = evidence_json.copy()
if evidence_json.get("credentialSubject"):
self.json.update(evidence_json["credentialSubject"])
if evidence_json.get("evidence"):
self.json["data"] = {}
for ev in evidence_json["evidence"]:
k = ev.get("operation")
if not k:
continue
self.json["data"][k] = ev.get("output")
self.uuid = self.json['uuid']
self.user = user
self.hid = None
self.chid = None
self.phid = self.get_signature(self.json)
self.generate_chids()
if check:
return
self.index()
self.create_properties()
if settings.DPP:
self.register_device_dlt()
def index(self):
snap = json.dumps(self.evidence)
index(self.user.institution, self.uuid, snap)
def generate_chids(self):
self.algorithms = {
'hidalgo1': self.get_hid_14(),
'legacy_dpp': self.get_chid_dpp(),
}
def get_hid_14(self):
if self.json.get("software") == "workbench-script":
hid = self.get_hid(self.json)
else:
device = self.json['device']
manufacturer = device.get("manufacturer", '')
model = device.get("model", '')
chassis = device.get("chassis", '')
serial_number = device.get("serialNumber", '')
sku = device.get("sku", '')
hid = f"{manufacturer}{model}{chassis}{serial_number}{sku}"
self.chid = hashlib.sha3_256(hid.encode()).hexdigest()
return self.chid
def get_chid_dpp(self):
if self.json.get("software") == "workbench-script":
device = ParseSnapshot(self.json).device
else:
device = self.json['device']
hid = self.get_id_hw_dpp(device)
self.chid = hashlib.sha3_256(hid.encode("utf-8")).hexdigest()
return self.chid
def get_id_hw_dpp(self, d):
manufacturer = d.get("manufacturer", '')
model = d.get("model", '')
chassis = d.get("chassis", '')
serial_number = d.get("serialNumber", '')
sku = d.get("sku", '')
typ = d.get("type", '')
version = d.get("version", '')
return f"{manufacturer}{model}{chassis}{serial_number}{sku}{typ}{version}"
def get_phid(self):
if self.json.get("software") == "workbench-script":
data = ParseSnapshot(self.json)
self.device = data.device
self.components = data.components
else:
self.device = self.json.get("device")
self.components = self.json.get("components", [])
self.device.pop("actions", None)
for c in self.components:
c.pop("actions", None)
device = self.get_id_hw_dpp(self.device)
components = sorted(self.components, key=lambda x: x.get("type"))
doc = [("computer", device)]
for c in components:
doc.append((c.get("type"), self.get_id_hw_dpp(c)))
return doc
def create_properties(self):
property = SystemProperty.objects.filter(
uuid=self.uuid,
owner=self.user.institution,
)
if property:
txt = "Warning: Snapshot %s already registered (property exists)"
logger.warning(txt, self.uuid)
return
for k, v in self.algorithms.items():
SystemProperty.objects.create(
uuid=self.uuid,
owner=self.user.institution,
user=self.user,
key=k,
value=v
)
def get_hid(self, snapshot):
try:
self.inxi = self.json["data"]["inxi"]
if isinstance(self.inxi, str):
self.inxi = json.loads(self.inxi)
except Exception:
logger.error("No inxi in snapshot %s", self.uuid)
return ""
machine = get_inxi_key(self.inxi, 'Machine')
for m in machine:
system = get_inxi(m, "System")
if system:
manufacturer = system
model = get_inxi(m, "product")
serial_number = get_inxi(m, "serial")
chassis = get_inxi(m, "Type")
else:
sku = get_inxi(m, "part-nu")
mac = get_mac(self.inxi) or ""
if not mac:
txt = "Could not retrieve MAC address in snapshot %s"
logger.warning(txt, snapshot['uuid'])
return f"{manufacturer}{model}{chassis}{serial_number}{sku}"
return f"{manufacturer}{model}{chassis}{serial_number}{sku}{mac}"
def get_signature(self, doc):
return hashlib.sha3_256(json.dumps(doc).encode()).hexdigest()
def register_device_dlt(self):
chid = self.algorithms.get('legacy_dpp')
phid = self.get_signature(self.get_phid())
register_device_dlt(chid, phid, self.uuid, self.user)
register_passport_dlt(chid, phid, self.uuid, self.user)

View file

@ -47,7 +47,6 @@
</thead>
{% for snap in object.properties %}
<tbody>
{% if snap.type == 0 %}
<tr>
<td>
{{ snap.key }}
@ -63,7 +62,6 @@
</small>
</td>
</tr>
{% endif %}
</tbody>
{% endfor %}
</table>
@ -94,7 +92,7 @@
</div>
{% if form.tag.value %}
<div class="col-1">
<a class="btn btn-yellow" href="{% url 'device:delete_user_property' form.pk %}">{% translate "Delete" %}</a>
<a class="btn btn-yellow" href="{% url 'evidence:delete_tag' form.pk %}">{% translate "Delete" %}</a>
</div>
{% endif %}
</div>

View file

@ -20,4 +20,5 @@ urlpatterns = [
path("<uuid:pk>", views.EvidenceView.as_view(), name="details"),
path("<uuid:pk>/eraseserver", views.EraseServerView.as_view(), name="erase_server"),
path("<uuid:pk>/download", views.DownloadEvidenceView.as_view(), name="download"),
path("tag/<str:pk>/delete", views.DeleteEvidenceTagView.as_view(), name="delete_tag"),
]

View file

@ -12,6 +12,7 @@ from django.views.generic.edit import (
FormView,
)
from action.models import DeviceLog
from dashboard.mixins import DashboardView, Http403
from evidence.models import SystemProperty, UserProperty, Evidence
from evidence.forms import (
@ -184,3 +185,35 @@ class EraseServerView(DashboardView, FormView):
def get_success_url(self):
success_url = reverse_lazy('evidence:details', args=[self.pk])
return success_url
class DeleteEvidenceTagView(DashboardView, DeleteView):
model = SystemProperty
def get_queryset(self):
# only those with 'CUSTOM_ID'
return SystemProperty.objects.filter(owner=self.request.user.institution, key='CUSTOM_ID')
def get(self, request, *args, **kwargs):
self.object = self.get_object()
message = _("<Deleted> Evidence Tag: {}").format(self.object.value)
DeviceLog.objects.create(
snapshot_uuid=self.object.uuid,
event=message,
user=self.request.user,
institution=self.request.user.institution
)
self.object.delete()
messages.info(self.request, _("Evicende Tag deleted successfully."))
return self.handle_success()
def handle_success(self):
return redirect(self.get_success_url())
def get_success_url(self):
return self.request.META.get(
'HTTP_REFERER',
reverse_lazy('evidence:details', args=[self.object.uuid])
)

View file

@ -80,15 +80,15 @@ def create_property(doc, user, commit=False):
'value': doc['CUSTOMER_ID'],
}
if commit:
property = SystemProperty.objects.filter(
prop = SystemProperty.objects.filter(
uuid=doc["uuid"],
owner=user.institution,
)
if property:
if prop:
txt = "Warning: Snapshot %s already registered (system property exists)"
logger.warning(txt, doc["uuid"])
return property
return prop
return SystemProperty.objects.create(**data)