99from django .template .defaultfilters import slugify
1010import stix2 , json
1111from txt2detection .models import TAG_PATTERN
12+ from dogesec_commons .utils .serializers import JSONSchemaSerializer
1213
1314
1415def validate_model (model ):
@@ -86,8 +87,8 @@ def __init__(self, *args, **kwargs):
8687 super ().__init__ (* args , ** kwargs )
8788
8889 def to_internal_value (self , data ):
89- if isinstance (data , (str , Mapping )) or not hasattr (data , ' __iter__' ):
90- self .fail (' not_a_list' , input_type = type (data ).__name__ )
90+ if isinstance (data , (str , Mapping )) or not hasattr (data , " __iter__" ):
91+ self .fail (" not_a_list" , input_type = type (data ).__name__ )
9192 retval = []
9293 if hasattr (self .parent , "skip_csv" ):
9394 retval = data
@@ -110,7 +111,7 @@ class FileSerializer(serializers.ModelSerializer):
110111 help_text = "Full path to the file to be converted. The mimetype of the file uploaded must match that expected by the `mode` selected. This is a file2txt setting." ,
111112 )
112113 mode = serializers .ChoiceField (
113- choices = list (f2t_core . BaseParser . PARSERS . keys () ),
114+ choices = list ([ "txt" , "html" , "html_article" , "word" , "pdf" , "md" ] ),
114115 help_text = "How the File should be processed. This is a file2txt setting." ,
115116 )
116117 report_id = ReportIDField (
@@ -181,6 +182,7 @@ class Meta:
181182 exclude = ["markdown_file" , "status" , "level" ]
182183 read_only_fields = ["id" ]
183184
185+
184186class FileDocumentSerializer (FileSerializer ):
185187 type_label = "siemrules.file"
186188 ai_provider = serializers .CharField (
@@ -305,8 +307,6 @@ class RuleCloneSerializer(serializers.Serializer):
305307 description = serializers .CharField (required = False )
306308
307309
308-
309-
310310class HealthCheckChoices (StrEnum ):
311311 AUTHORIZED = auto ()
312312 UNAUTHORIZED = auto ()
@@ -315,19 +315,109 @@ class HealthCheckChoices(StrEnum):
315315 UNKNOWN = auto ()
316316 OFFLINE = auto ()
317317
318+
318319class HealthCheckChoiceField (serializers .ChoiceField ):
319320 def __init__ (self , ** kwargs ):
320321 choices = [m .value for m in HealthCheckChoices ]
321322 super ().__init__ (choices , ** kwargs )
322-
323+
324+
323325class HealthCheckLLMs (serializers .Serializer ):
324326 openai = HealthCheckChoiceField ()
325327 deepseek = HealthCheckChoiceField ()
326328 anthropic = HealthCheckChoiceField ()
327329 gemini = HealthCheckChoiceField ()
328330 openrouter = HealthCheckChoiceField ()
329331
332+
330333class HealthCheckSerializer (serializers .Serializer ):
331334 ctibutler = HealthCheckChoiceField ()
332335 vulmatch = HealthCheckChoiceField ()
333- llms = HealthCheckLLMs ()
336+ llms = HealthCheckLLMs ()
337+
338+
339+ class AttackNavigatorDomainSerializer (JSONSchemaSerializer ):
340+ json_schema = {
341+ "$schema" : "http://json-schema.org/draft-07/schema#" ,
342+ "title" : "MITRE ATT&CK Navigator Layer v4.5" ,
343+ "type" : "object" ,
344+ "required" : ["versions" , "name" , "domain" , "techniques" ],
345+ "properties" : {
346+ "versions" : {
347+ "type" : "object" ,
348+ "properties" : {
349+ "layer" : {"type" : "string" , "example" : "4.5" },
350+ "attack" : {"type" : "string" , "example" : "17.0" },
351+ "navigator" : {"type" : "string" , "example" : "5.1.0" },
352+ },
353+ "required" : ["layer" , "attack" , "navigator" ],
354+ "additionalProperties" : False ,
355+ },
356+ "name" : {"type" : "string" },
357+ "domain" : {
358+ "type" : "string" ,
359+ "enum" : ["enterprise-attack" , "mobile-attack" , "ics-attack" ],
360+ },
361+ "description" : {"type" : "string" },
362+ "gradient" : {
363+ "type" : "object" ,
364+ "required" : ["colors" , "minValue" , "maxValue" ],
365+ "properties" : {
366+ "colors" : {
367+ "type" : "array" ,
368+ "items" : {"type" : "string" , "pattern" : "^#[0-9A-Fa-f]{6}$" },
369+ },
370+ "minValue" : {"type" : "number" },
371+ "maxValue" : {"type" : "number" },
372+ },
373+ },
374+ "legendItems" : {
375+ "type" : "array" ,
376+ "items" : {
377+ "type" : "object" ,
378+ "properties" : {
379+ "label" : {"type" : "string" },
380+ "color" : {"type" : "string" , "pattern" : "^#[0-9A-Fa-f]{6}$" },
381+ "value" : {"type" : "number" },
382+ },
383+ },
384+ },
385+ "showTacticsRowBackground" : {"type" : "boolean" },
386+ "techniques" : {
387+ "type" : "array" ,
388+ "items" : {
389+ "type" : "object" ,
390+ "required" : ["techniqueID" ],
391+ "properties" : {
392+ "techniqueID" : {"type" : "string" },
393+ "tactic" : {"type" : "string" },
394+ "score" : {"type" : ["number" , "null" ]},
395+ "color" : {"type" : "string" , "pattern" : "^#[0-9A-Fa-f]{6}$" },
396+ "comment" : {"type" : "string" },
397+ "enabled" : {"type" : "boolean" },
398+ "links" : {
399+ "type" : "array" ,
400+ "items" : {
401+ "type" : "object" ,
402+ "properties" : {
403+ "href" : {"type" : "string" , "format" : "uri" },
404+ "text" : {"type" : "string" },
405+ },
406+ "required" : ["href" , "text" ],
407+ },
408+ },
409+ },
410+ "additionalProperties" : True ,
411+ },
412+ },
413+ "tacticUseIds" : {"type" : "array" , "items" : {"type" : "string" }},
414+ "filters" : {
415+ "type" : "object" ,
416+ "properties" : {
417+ "includeSubtechniques" : {"type" : "boolean" },
418+ "showOnlyVisibleTechniques" : {"type" : "boolean" },
419+ },
420+ },
421+ },
422+ "additionalProperties" : True ,
423+ }
0 commit comments