Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
39 changes: 39 additions & 0 deletions bazaar/core/migrations/0007_bookmark.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Generated by Django 6.0.8 on 2026-10-05 13:51

import django.db.models.deletion
import uuid
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("core", "0006_alter_yara_content_alter_yara_title"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name="Bookmark",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("sample", models.CharField(max_length=256)),
(
"owner",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
),
]
40 changes: 40 additions & 0 deletions bazaar/core/migrations/0008_comment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Generated by Django 6.0.8 on 2026-10-06 12:59

import django.db.models.deletion
import uuid
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("core", "0007_bookmark"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name="Comment",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("sample", models.CharField(max_length=256)),
("content", models.CharField(max_length=4096)),
(
"owner",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 6.0.8 on 2026-10-06 17:36

from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("core", "0008_comment"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.AddConstraint(
model_name="comment",
constraint=models.UniqueConstraint(
fields=("sample", "owner"), name="unique_comment_per_sample_per_owner"
),
),
]
40 changes: 40 additions & 0 deletions bazaar/core/migrations/0010_notification.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Generated by Django 6.0.8 on 2026-10-07 08:15

import django.db.models.deletion
import uuid
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("core", "0009_comment_unique_comment_per_sample_per_owner"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name="Notification",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
),
),
("text_content", models.CharField(max_length=128)),
("redirect_link", models.CharField(max_length=128)),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
),
]
37 changes: 35 additions & 2 deletions bazaar/core/models.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,45 @@
import uuid

import yara
from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import models
import uuid

from elasticsearch import Elasticsearch


class Notification(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
text_content = models.CharField(max_length=128)
redirect_link = models.CharField(max_length=128)


class Comment(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
sample = models.CharField(max_length=256)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
content = models.CharField(max_length=4096)

class Meta:
constraints = [
models.UniqueConstraint(
fields=["sample", "owner"],
name="unique_comment_per_sample_per_owner",
),
]


class Bookmark(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
sample = models.CharField(max_length=256)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

@staticmethod
def get_es_index(user):
es_index = f'bookmark_user_{user.id}'
return es_index


def check_yara_rule(rule):
try:
yara.compile(source=rule)
Expand Down
19 changes: 16 additions & 3 deletions bazaar/core/modules/pithus.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@
from django.conf import settings
from django.core.files.storage import default_storage
from django.utils import timezone
from django.contrib.auth import get_user_model


from elasticsearch import Elasticsearch
from elasticsearch.helpers.actions import scan

from bazaar.core.fingerprinting import ApplicationSignature
from bazaar.core.utils import strings_from_apk
from bazaar.core.models import Yara
from bazaar.core.models import Yara, Notification


es = Elasticsearch(
Expand Down Expand Up @@ -355,7 +357,12 @@ def yara_analysis(sha256, rule_id=-1):
return {'status': 'success', 'info': ''}


def retrohunt(rule_id):
def retrohunt(rule_id, user_id):

user_model = get_user_model()
if user_id is not None:
user = user_model.objects.get(pk=user_id)

rule = None
try:
rule = Yara.objects.get(id=rule_id)
Expand All @@ -367,7 +374,13 @@ def retrohunt(rule_id):
index=settings.ELASTICSEARCH_APK_INDEX,
):
_id = report.get('_source').get('sha256')
execute_single_yara_rule(rule.id, _id)
res = execute_single_yara_rule(rule.id, _id)
if user_id is not None and user is not None and user.is_authenticated and res['status'] == 'success':
Notification.objects.create(
user=user,
text_content=f"Retrohunt found sample matching [{rule.title}]",
redirect_link="/workspace"
)

del rule
gc.collect()
Expand Down
1 change: 1 addition & 0 deletions bazaar/core/services/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
from bazaar.core.services import search as SearchService # noqa: F401
from bazaar.core.services import rules as RulesService # noqa: F401
from bazaar.core.services import genom as GenomService # noqa: F401
from bazaar.core.services import notifications as NotificationsService # noqa: F401
35 changes: 35 additions & 0 deletions bazaar/core/services/notifications.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

from bazaar.core.models import Notification


def get_user_notifications(request):
if not request.user.is_authenticated:
return []

return Notification.objects.filter(user=request.user)


def add_user_notification(user, text_content, redirect_link=None):
if not user.is_authenticated:
return False

Notification.objects.create(user=user, text_content=text_content, redirect_link=redirect_link)
return True


def delete_user_notification(request, notif_id):
if not request.user.is_authenticated:
return False
notifications = Notification.objects.filter(user=request.user, id=notif_id)
for notif in notifications:
notif.delete()
return True


def delete_all_user_notifications(request):
if not request.user.is_authenticated:
return False
notifications = Notification.objects.filter(user=request.user)
for notif in notifications:
notif.delete()
return True
4 changes: 4 additions & 0 deletions bazaar/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,10 @@ def normalize(data):
return x


def transform_results(results):
return [doc['_source'] for doc in results['hits']['hits']]


def transform_hl_results(results):
ret = []
for doc in results['hits']['hits']:
Expand Down
12 changes: 12 additions & 0 deletions bazaar/front/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from django.forms import ModelForm
from bazaar.core.models import Yara
from bazaar.core.models import Comment


class SimilaritySearchForm(forms.Form):
Expand Down Expand Up @@ -51,3 +52,14 @@ class YaraCreateForm(ModelForm):
class Meta:
model = Yara
fields = ['title', 'content', 'is_private']


class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ["content"]
widgets = {
"content": forms.Textarea(attrs={
"rows": 5,
}),
}
27 changes: 18 additions & 9 deletions bazaar/front/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
from django.views.generic.base import TemplateView

from bazaar.front.view import HomeView, ReportView, basic_upload_view, similarity_search_view, export_report_view, \
download_sample_view, my_rules_view, my_rule_edit_view, my_rule_create_view, my_rule_delete_view, og_card_view, \
my_retrohunt_view, get_andgrocfg_code, get_genom, basic_url_download_view, report_status_view, instance_status
download_sample_view, my_rule_edit_view, my_rule_create_view, my_rule_delete_view, og_card_view, \
my_retrohunt_view, get_andgrocfg_code, get_genom, basic_url_download_view, report_status_view, instance_status, \
remove_bookmark_sample_view, add_bookmark_sample_view, workspace_view, add_comment_view, delete_comment_view, \
notifications_view, notification_delete_view

app_name = "front"
urlpatterns = [
Expand All @@ -15,16 +17,23 @@
path("report/<str:sha256>/card", view=og_card_view, name="og_card"),
path("report/<str:sha256>/status", view=report_status_view, name="report_status"),
path("apk/", view=basic_upload_view, name="basic_upload"),
path("url/", view=basic_url_download_view, name="basic_url_download"),
path("apk/<str:sha256>", view=download_sample_view, name="download_sample"),
path("similar/", view=similarity_search_view, name="similarity_search"),
path("similar/<str:sha256>", view=similarity_search_view, name="similarity_search"),
path("rules/", view=my_rules_view, name="my_rules"),
path("rules/new", view=my_rule_create_view, name="my_rule_create"),
path("rules/<str:uuid>/edit", view=my_rule_edit_view, name="my_rule_edit"),
path("apk/<str:sha256>/bookmark/add", view=add_bookmark_sample_view, name="add_bookmark_sample"),
path("apk/<str:sha256>/bookmark/remove", view=remove_bookmark_sample_view,
name="remove_bookmark_sample"),
path("rules/<str:uuid>/delete", view=my_rule_delete_view, name="my_rule_delete"),
path("rules/<str:uuid>/edit", view=my_rule_edit_view, name="my_rule_edit"),
path("rules/<str:uuid>/retro", view=my_retrohunt_view, name="my_rule_retro"),
path("rules/new", view=my_rule_create_view, name="my_rule_create"),
path("similar/", view=similarity_search_view, name="similarity_search"),
path("similar/<str:sha256>", view=similarity_search_view, name="similarity_search"),
path("androcfg/<str:sha256>/<path:foo>", view=get_andgrocfg_code, name="get_andgrocfg_code"),
path("androcfg/all", view=get_genom, name="get_genom"),
path("status", view=instance_status, name="instance_status")
path("status", view=instance_status, name="instance_status"),
path("url/", view=basic_url_download_view, name="basic_url_download"),
path("workspace/", view=workspace_view, name="workspace"),
path("comment/<str:sha256>/add", view=add_comment_view, name="add_comment"),
path("comment/<uuid:comment_id>/delete", view=delete_comment_view, name="delete_comment"),
path("notifications", view=notifications_view, name="notifications_url"),
path("notifications/<uuid:notif_id>/delete", view=notification_delete_view, name="notifications_url")
]
Loading
Loading