
    <iM                        S r SSKrSSKrSSKrSSKrSSKrSSKrSSK	J
r  SSKr\" 5       r\R                   " S5      rSrSr " S S\R(                  5      r " S S	\R(                  5      rSS
 jr " S S\R                  5      rS rS rS r\R8                  \R:                  4S jrS rS r S r!S r"S r#\RH                  RJ                  4S jr&\RH                  RJ                  4S jr'\RH                  RJ                  4S jr(\RH                  RJ                  4S jr)\RH                  RJ                  4S jr* " S S\R(                  5      r+\RH                  RJ                  4S jr,g)z4Utility functions and classes for the STIX2 library.    Nz^[a-z].*z%Y-%m-%dT%H:%M:%SZz%Y-%m-%dT%H:%M:%S.%fZc                   $    \ rS rSrSrSrSrSrSrg)	Precision   z
Timestamp format precisions.
          N)	__name__
__module____qualname____firstlineno____doc__ANYSECONDMILLISECOND__static_attributes__r	       E/home/james-whalen/.local/lib/python3.13/site-packages/stix2/utils.pyr   r      s     CFKr   r   c                        \ rS rSrSrSrSrSrg)PrecisionConstraint#   z
Timestamp precision constraints.  These affect how the Precision
values are applied when formatting a timestamp.

These constraints don't really make sense with the ANY precision, so they
have no effect in that case.
r   r   r	   N)r
   r   r   r   r   EXACTMINr   r	   r   r   r   r   #   s     E
Cr   r   c                     Ub  [        X!5      (       d   e[        X5      (       dX  U c  Ub  Un U $ [        U [        5      (       a  XR                  5          n U $ [        SR	                  UR
                  U 5      5      eU $ )as  
Detect and convert strings to enums and None to a default enum.  This
allows use of strings and None in APIs, while enforcing the enum type: if
you use a string, it must name a valid enum value.  This implementation is
case-insensitive.

:param value: A value to be interpreted as an enum (string, Enum instance,
    or None).  If an Enum instance, it must be an instance of enum_type.
:param enum_type: The enum type which strings will be interpreted against
:param enum_default: The default enum to use if value is None.  Must be
    an instance of enum_type, or None.  If None, you are disallowing a
    default and requiring that value be non-None.
:return: An instance of enum_type
:raises TypeError: If value was neither an instance of enum_type, None, nor
    a string
:raises KeyError: If value was a string which couldn't be interpreted as an
    enum value from enum_type
zNot a valid {}: {})
isinstancestrupper	TypeErrorformatr
   )value	enum_typeenum_defaults      r   to_enumr#   0   s    & :l#F#FFFe''=\5 E L s##kkm,E L $++&&  Lr   c                   $    \ rS rSrSrS rS rSrg)STIXdatetimeT   z
Bundle a datetime with some format-related metadata, so that JSON
serialization has the info it needs to produce compliant timestamps.
c                     [        UR                  S[        R                  5      [        5      n[        UR                  S[        R
                  5      [        5      n[        US   [        R                  5      (       a_  US   nUR                  UR                  UR                  UR                  UR                  UR                  UR                  UR                   4n[        R                  R"                  " U /UQ70 UD6nX6l        XFl        U$ )N	precisionprecision_constraintr   )r#   popr   r   r   r   r   dtdatetimeyearmonthdayhourminutesecondmicrosecondtzinfo__new__r(   r)   )clsargskwargsr(   r)   dttmselfs          r   r5   STIXdatetime.__new__Z   s    JJ{IMM2
	  'JJ-/B/H/HI 

 d1gr{{++7D		4::txxDKKT--t{{D
 {{""3888"$8!r   c                     S[        U 5      -  $ )Nz'%s')format_datetime)r:   s    r   __repr__STIXdatetime.__repr__p   s    ---r   r(   r)   N)r
   r   r   r   r   r5   r>   r   r	   r   r   r%   r%   T   s    
,.r   r%   c                     0 nU  HA  nUR                  S5      =(       d    UR                  S5      nUc	  X!US   '   M8  X!US   U4'   MC     [        UR                  5       5      $ )aI  Deduplicate a list of STIX objects to a unique set.

Reduces a set of STIX objects to unique set by looking
at 'id' and 'modified' fields - as a unique object version
is determined by the combination of those fields

Note: Be aware, as can be seen in the implementation
of deduplicate(),that if the "stix_obj_list" argument has
multiple STIX objects of the same version, the last object
version found in the list will be the one that is returned.

Args:
    stix_obj_list (list): list of STIX objects (dicts)

Returns:
    A list with a unique set of the passed list of STIX objects.

modifiedcreatedid)getlistvalues)stix_obj_listunique_objsobjvers       r   deduplicaterL   t   sg    & Kggj!7SWWY%7;%(D	",/TC()  ""$%%r   c                  D    [         R                  [        R                  S9$ )z5Return a STIX timestamp of the current date and time.)tz)r%   nowpytzUTCr	   r   r   get_timestamprR      s    txx((r   c                    U R                   b  U R                   R                  U 5      c   [        R                  R	                  U 5      nOU R                  [        R                  5      nUR                  S5      n[        U S[        R                  5      n[        U S[        R                  5      nSnU[        R                  :X  a<  UR                  (       a*  SR                  UR                  5      R                  S5      nOU[        R                  :X  aP  U[        R                   :X  a;  UR                  (       a*  SR                  UR                  5      R                  S5      nOmU[        R                  :X  a  SR                  UR                  5      SS nO:SR                  UR                  5      R                  S5      R#                  SS5      nS	R                  UU(       a  S
OSU5      nU$ )zConvert a datetime object into a valid STIX timestamp string.

1. Convert to timezone-aware
2. Convert to UTC
3. Format in ISO format
4. Ensure correct precision
   a. Add subsecond value if warranted, according to precision settings
5. Add "Z"

Nz%Y-%m-%dT%H:%M:%Sr(   r)    z{:06d}0r   z{}{}{}Z.)r4   	utcoffsetrP   utclocalize
astimezonestrftimegetattrr   r   r   r   r3   r   rstripr   r   ljust)r9   zonedtsr(   r)   frac_seconds_strs         r   r=   r=      s    {{dkk33D9A!!$')	+	,Bk9==9I"$&9&?&? IMM!'u/@/@AHHM	i&&	&#6#:#::   #+??53D3D#EVC[ !  #6#<#<<'u/@/@A"1E  ())*q# 
 
		
R
B Ir   c           	         [        U[        5      n[        U[        5      n[        U [        R
                  5      (       aW  [        U S5      (       a  U nO[        R                  R                  U [        R                  " SS[        R                  S95      nOSU ;   a  [        O[        n [        R                  R                  X5      nUR"                  (       a   UR%                  [        R                  5      nO[        R                  R'                  U5      nU[        R(                  :X  a$  U[        R*                  :X  a  UR-                  SS9nOIU[        R.                  :X  a5  U[        R*                  :X  a!  UR0                  S-  S-  nUR-                  US9n[3        X1US9$ ! [        [         4 a    [!        S5      ef = f)	a  
Parse a value into a valid STIX timestamp object.  Also, optionally adjust
precision of fractional seconds.  This allows alignment with JSON
serialization requirements, and helps ensure we're not using extra
precision which would be lost upon JSON serialization.  The precision
info will be embedded in the returned object, so that JSON serialization
will format it correctly.

:param value: A datetime.datetime or datetime.date instance, or a string
:param precision: A precision value: either an instance of the Precision
    enum, or a string naming one of the enum values (case-insensitive)
:param precision_constraint: A precision constraint value: either an
    instance of the PrecisionConstraint enum, or a string naming one of
    the enum values (case-insensitive)
:return: A STIXdatetime instance, which is a datetime but also carries the
    precision info necessary to properly JSON-serialize it.
r0   r   )r4   rV   zUmust be a datetime object, date object, or timestamp string in a recognizable format.)r3   i  r@   )r#   r   r   r   r+   datehasattrr,   combinetimerP   rX   _TIMESTAMP_FORMAT_FRAC_TIMESTAMP_FORMATstrptimer   
ValueErrorr4   rZ   rY   r   r   replacer   r3   r%   )r    r(   r)   r`   fmtparseduss          r   parse_into_datetimero      sw   * 	9-I"#79LM%!!5&!!B $$UBGGAq,JKB ),u$:K	[[))%5F ==""488,B ""6*B I$$$#6#<#<<*B 
i++	+#6#<#<<..D(D0B+B 
6J 7 :& 	= 	s   *F$ $G c                 4   [        U 5      [        L a  U $  [        R                  " U 5      $ ! [         a     Of = f [        R
                  " U 5      $ ! [         a     Of = f [        U 5      $ ! [        [        4 a    [        S[        U 5      -  5      ef = f)zVReturn data as a dictionary.

Input can be a dictionary, string, or file-like object.
z"Cannot convert '%s' to dictionary.)	typedictjsonloadsr   loadAttributeErrorrj   r   )datas    r   	_get_dictrx     s     DzT	::d## 			99T?" 			O:I& 	OACIMNN	Os)   , 
99A 
A A $
A/ /(Bc                 z    / nU R                   R                   H  nUR                  UR                  5        M      U$ )z9Given an object, return the names of the class hierarchy.)	__class____mro__appendr
   )rJ   namesr6   s      r   get_class_hierarchy_namesr~   1  s0    E}}$$S\\" %Lr   c                 ,    U R                  SS5      S   $ )N--r   r   )split)stix_ids    r   get_type_from_idr   9  s    ==q!!$$r   c                     U S   nSU ;   a  U S   nU$ SU ;  a  SnU$ US:X  a!  [        S[        S U S    5       5      5      nU$ U[        R                  S   S	   ;   a  SnU$ SnU$ )
z
Given a dict representing a STIX object, try to detect what spec version
it is likely to comply with.

:param stix_dict: A dict with some STIX content.  Must at least have a
    "type" property.
:return: A STIX version in "X.Y" format
rq   spec_versionrD   z2.0bundlez2.1c              3   8   #    U  H  n[        U5      v   M     g 7fN)detect_spec_version).0rJ   s     r   	<genexpr>&detect_spec_version.<locals>.<genexpr>V  s      4HS#C((4Hs   objectsobservables)maxmappingsSTIX2_OBJ_MAPS)	stix_dictobj_typevs      r   r   r   =  s      H" n%, H+ 
Y	& H% 
X	  4=i4H 
 H 
X,,U3MB	B 
 H Hr   c                 j    [        U [        5      (       a  SU ;   a  [        U 5      nU$ U n U$ U S   nU$ )a  
Get a STIX type from the given value: if a STIX ID is passed, the type
prefix is extracted; if string which is not a STIX ID is passed, it is
assumed to be a STIX type and is returned; otherwise it is assumed to be a
mapping with a "type" property, and the value of that property is returned.

:param value: A mapping with a "type" property, or a STIX ID or type
    as a string
:return: A STIX type
r   rq   )r   r   r   )r    type_s     r   _stix_type_ofr   e  sG     %5=$U+E L	 E L fLr   c                     Sn[        U [        R                  R                  5      (       a  [	        U 5      nX1:w  a  SnU(       a1  [
        R                  U   n[        U 5      nXTS   ;   =(       a    US;  nU$ )ak  
Determine whether the given object, type, or ID is/is for an SDO of the
given STIX version.  If value is a type or ID, this just checks whether
the type was registered as an SDO in the given STIX version.  If a mapping,
*simple* STIX version inference is additionally done on the value, and the
result is checked against stix_version.  It does not attempt to fully
validate the value.

:param value: A mapping with a "type" property, or a STIX ID or type
    as a string
:param stix_version: A STIX version as a string
:return: True if the type of the given value is an SDO type of the given
    version; False if not
TFr   >   r   sightingrelationshiplanguage-contentmarking-definitionr   collectionsabcMappingr   r   r   r   r    stix_versionresultvalue_stix_versioncls_mapsr   s         r   is_sdor   {  sy      F%001107-F**<8e$9-- 
% @
 3

 Mr   c                     Sn[        U [        R                  R                  5      (       a  [	        U 5      nX1:w  a  SnU(       a%  [
        R                  U   n[        U 5      nXTS   ;   nU$ )ak  
Determine whether the given object, type, or ID is/is for an SCO of the
given STIX version.  If value is a type or ID, this just checks whether
the type was registered as an SCO in the given STIX version.  If a mapping,
*simple* STIX version inference is additionally done on the value, and the
result is checked against stix_version.  It does not attempt to fully
validate the value.

:param value: A mapping with a "type" property, or a STIX ID or type
    as a string
:param stix_version: A STIX version as a string
:return: True if the type of the given value is an SCO type of the given
    version; False if not
TFr   r   r   s         r   is_scor     se      F%001107-F**<8e$=11Mr   c                     Sn[        U [        R                  R                  5      (       a  [	        U 5      nX1:w  a  SnU(       a  [        U 5      nUS;   nU$ )aX  
Determine whether the given object, type, or ID is/is for an SRO of the
given STIX version.  If value is a type or ID, this just checks whether
the type is "sighting" or "relationship".  If a mapping, *simple* STIX
version inference is additionally done on the value, and the result is
checked against stix_version.  It does not attempt to fully validate the
value.

:param value: A mapping with a "type" property, or a STIX ID or type
    as a string
:param stix_version: A STIX version as a string
:return: True if the type of the given value is an SRO type of the given
    version; False if not
TF)r   r   r   r   r   r   r   r   r    r   r   r   r   s        r   is_sror     sS      F%001107-Fe$66Mr   c                     Sn[        U [        R                  R                  5      (       a  [	        U 5      nX1:w  a  SnU(       a3  [
        R                  U   n[        U 5      nXTS   ;   =(       d    XTS   ;   nU$ )a  
Determine whether an object, type, or ID is/is for any STIX object.  This
includes all SDOs, SCOs, meta-objects, and bundle.  If value is a type or
ID, this just checks whether the type was registered in the given STIX
version.  If a mapping, *simple* STIX version inference is additionally
done on the value, and the result is checked against stix_version.  It does
not attempt to fully validate the value.

:param value: A mapping with a "type" property, or a STIX ID or type
    as a string
:param stix_version: A STIX version as a string
:return: True if the type of the given value is a valid STIX type with
    respect to the given STIX version; False if not
TFr   r   r   r   s         r   	is_objectr     sz      F%001107-F**<8e$=11 ,++ 	 Mr   c                     Sn[        U [        R                  R                  5      (       a  [	        U 5      nX1:w  a  SnU(       a  [        U 5      nUS:H  nU$ )a0  
Determine whether the given object, type, or ID is/is for an marking
definition of the given STIX version.  If value is a type or ID, this just
checks whether the type is "marking-definition".  If a mapping, *simple*
STIX version inference is additionally done on the value, and the result
is checked against stix_version.  It does not attempt to fully validate the
value.

:param value: A STIX object, object ID, or type as a string.
:param stix_version: A STIX version as a string
:return: True if the value is/is for a marking definition, False otherwise.
TFr   r   r   s        r   
is_markingr     sS     F%001107-Fe$..Mr   c                   $    \ rS rSrSrSrSrSrSrg)STIXTypeClassi  z,
Represents different classes of STIX type.
r   r   r   r	   N)	r
   r   r   r   r   SDOSCOSROr   r	   r   r   r   r     s     C
C
Cr   r   c                 ,   U H  nU[         R                  L a  [        X5      nO_U[         R                  L a  [	        X5      nO@U[         R
                  L a  [        X5      nO![        U 5      nXS:H  =(       a    [        X5      nU(       d  M    U$    SnU$ )a  
Determine whether the type of the given value satisfies the given
constraints.  'types' must contain STIX types as strings, and/or the
STIXTypeClass enum values.  STIX types imply an exact match constraint;
STIXTypeClass enum values imply a more general constraint, that the object
or type be in that class of STIX type.  These constraints are implicitly
OR'd together.

:param value: A mapping with a "type" property, or a STIX ID or type
    as a string
:param stix_version: A STIX version as a string
:param types: A sequence of STIX type strings or STIXTypeClass enum values
:return: True if the object or type satisfies the constraints; False if not
F)	r   r   r   r   r   r   r   r   r   )r    r   typesr   r   r   s         r   is_stix_typer     s      M%%%E0Fm'''E0Fm'''E0F %U+H&I9U+IF6
 M' " Mr   r   )-r   collections.abcr   r,   r+   enumrs   rerP   stix2.registryregistryr   stix2.versionstix2objectNOWcompilePREFIX_21_REGEXrh   rg   Enumr   r   r#   r%   rL   rR   r=   r   r   ro   rx   r~   r   r   r   versionDEFAULT_VERSIONr   r   r   r   r   r   r   r	   r   r   <module>r      sH   :     	  ! 
 h**[)( 0 		 	$)) 	!H.2;; .@&@)
;~ ]],22@FO.%%P,  %}}<< B  %}}<< <  %}}<< < #(--"?"? > $)==#@#@ 8DII  &+]]%B%B #r   