diff --git a/.gitignore b/.gitignore index 3119c0e..6ef70a4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,90 @@ # Created by .ignore support plugin (hsz.mobi) -### Java template +### Gradle template +.gradle/ +/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/ + + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Kotlin template # Compiled class file +*.class # Log file *.log @@ -14,6 +98,7 @@ # Package Files # *.jar *.war +*.nar *.ear *.zip *.tar.gz @@ -22,33 +107,15 @@ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* -target/ -pom.xml.tag -pom.xml.releaseBackup -pom.xml.versionsBackup -pom.xml.next -release.properties -dependency-reduced-pom.xml -buildNumber.properties -.mvn/timing.properties - -.settings -bin/ -build-reports/ - -# Eclipse -.classpath -.factorypath -.project -.settings/ - -# Intellij -.idea/ -*.iws -*.iml - -# Mac -.DS_Store - -# Maven -log/ \ No newline at end of file +### Java template +# Compiled class file + +# Log file + +# BlueJ files + +# Mobile Tools for Java (J2ME) + +# Package Files # + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100755 index fa4f7b4..0000000 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,110 +0,0 @@ -/* -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. -*/ - -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = - "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: : " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties deleted file mode 100755 index 00d32aa..0000000 --- a/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 68c7c6e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: java - -jdk: - - oraclejdk8 - - openjdk8 - -sudo: false -install: true - -cache: - directories: - - $HOME/.m2 \ No newline at end of file diff --git a/README.md b/README.md index eb83603..25ccdc8 100644 --- a/README.md +++ b/README.md @@ -1,683 +1,92 @@ -# STIX 2.x Java library +# STIX-JAVA-KOTLIN -[![Build Status](https://travis-ci.org/StephenOTT/STIX-Java.svg?branch=master)](https://travis-ci.org/StephenOTT/STIX-Java) +A STIX 2.1 library built in Kotlin with targets of Kotlin and Java. -The library aims to provide a flexible full implementation of [STIX 2.x](https://oasis-open.github.io/cti-documentation/resources#stix-20-specification). -This means that a default implementation is provided that meets the STIX JSON specification and the core objects -and properties are provided in such a way as you can easily override and extend any implementation detail to meet your -variation of the specification. +## Concepts -De/Serilization is provided with Jackson. +The entire STIX 2.1 spec covered in interfaces and implementations. +This allows for anyone to build new implementations from the common interfaces that map out the entire STIX 2.1 spec. +All business rules can be found in the interfaces such as supported relationships, supported extensions, and field level controls. -Current Spec Target: **2.0** +The interfaces maintain the hierarchy of the STIX spec: +1. Stix Content + 1.1 Stix Object + 1.1.1 Stix Core Object + 1.1.1.1 Stix Domain Object (SDO) + 1.1.1.2 Stix Relationship Object (SRO) + 1.1.1.3 Stix Cyber Observable Object (SCO) + 1.1.2 Stix Meta Object + 1.1.2.1 Data Marking + 1.1.2.2 Language Content Object + 1.2. Stix Bundle + +### Technical design details -## Other Implementations +1. All Stix Content is immutable. +1. Stix Content can be created using the default spec as its configuration, but using the `Stix` instance you can transform th object to using the `Stix` instance's configuration. + + +## `Sitx` instance -### TAXII-springboot-bpmn +A `Stix` class instance provides the ability to create instance of a Stix spec configuration. +A Stix spec configuration provides the ability to configure the rules and configurations for the specific trust group. -Taxii server based on springboot and backed by bpmn automation. -This taxii server implements the this STIX-Java library. +Example: A system you are developing only accepts the Indicator SDO. When creating a `Stix` instance you can disable +all other objects except for the Indicator SDO. When you generate a JSON content mapper and attempt to pass another object +other than the Indicator SDO, the parser will throw an error. The default JSON content mapper that this library provides, +allows you to create a JSON content mapper from the `Stix` instance. -https://github.com/StephenOTT/TAXII-springboot-bpmn - -### stix2 (Gson based implementation) - -If you are looking for a gson based implementation, [CS-AWARE](https://cs-aware.eu) provides a [gson based implementation of the Stix2 library](https://github.com/cs-aware/stix2). - - -## Sub-Second Precision Support - -STIX-Java supports zero to 9 digit nanosecond precision with any date that is parsed by STIX-Java. -This means that while a date that was sourced/generated by the STIX-Java library will be at sub-second precision of 3 digits, -if you are parsing JSON with greater precision, or you supply a custom Instant with greater precision for a specific field, -STIX-Java will support this and store the extra precision. - -General rules to understand: - -1. By default, timestamps generated natively by the STIX-Java library will be be with 3 digits of sub-second precision (millisecond precision). -1. Sub-second precision from 0 to 9 digits (9 digits its nano second precision: `hh:mm:ss.999999999`) is supported. This means you can omit sub-seconds if you choose. -1. The StixInstant.class supports a `toString()` method that will generate a STIX Spec Date with the original precision preserved -1. Json parsing of JSON strings will support all of the above rules. - - ------ - -## Java Usage - -Example unit test showing usage. - -```groovy -import io.digitalstate.stix.bundle.Bundle -import io.digitalstate.stix.bundle.BundleObject -import io.digitalstate.stix.bundle.BundleableObject -import io.digitalstate.stix.common.StixParsers -import io.digitalstate.stix.sdo.objects.AttackPattern -import io.digitalstate.stix.sdo.objects.Malware -import io.digitalstate.stix.sro.objects.Relationship -import spock.lang.Specification - -import java.time.Instant - -class BundleSpec extends Specification { - - def "Basic 'uses' Relationship object and addition to bundle"(){ - when: "Create a Relationship with Attack Pattern and Malware" - - Relationship usesRel = Relationship.builder() - .relationshipType("uses") - .created(Instant.now()) - .sourceRef(AttackPattern.builder() - .name("Some Attack Pattern 1") - .build()) - .targetRef(Malware.builder() - .name("dog") - .addLabels("worm") - .build()) - .build() - - then: "print the JSON string version of the created relationship object" - println usesRel.toJsonString() - - then: "parse the string back into a relationship object" - BundleableObject parsedRelationship = StixParsers.parseObject(usesRel.toJsonString()) - assert parsedRelationship instanceof Relationship - - Relationship typedRelation = (Relationship)parsedRelationship - - and: "print the parsed relation" - println typedRelation - - then: "ensure the original JSON matches the new JSON" - assert usesRel.toJsonString() == typedRelation.toJsonString() - - then: "add the relationship into a bundle" - Bundle bundle = Bundle.builder() - .addObjects(usesRel) - .build() - - and: "print the bundle json" - println bundle.toJsonString() - - then: "parse json bundle back into object" - BundleObject parsedBundle = StixParsers.parseBundle(bundle.toJsonString()) - assert parsedBundle instanceof Bundle - Bundle typedBundle = (Bundle)parsedBundle - - then: "ensure original bundle and parsed bundles match in their json forms" - assert bundle.toJsonString() == typedBundle.toJsonString() - - } - - def "bundleable object parsing"(){ - when: "setup parser and object" - String attackPatternString = AttackPattern.builder() - .name("Some Attack Pattern 1") - .build().toJsonString() - - then: "can parse the json back into a attack Pattern" - BundleableObject parsedAttackPatternBo = StixParsers.parseObject(attackPatternString) - assert parsedAttackPatternBo instanceof AttackPattern - - AttackPattern parsedAttackPattern = (AttackPattern)StixParsers.parseObject(attackPatternString) - println parsedAttackPattern.toJsonString() - } -} -``` - - -## JSON - -1. All objects (Bundles, SDO, SRO, and Marking Definitions; anything that is a "bundleable object" + bundle) are able -to be individually converted into their json equivalent. - -1. All objects (Bundles, SDO, SRO, and Marking Definitions; anything that is a "bundleable object" + bundle) can be -individually parsed from Json into a object. - -1. Object references within out objects (for example a "object_markings" property), will create "dehydrated" objects -when parsing from json into objects. This means that the object will detect the "type" based on the Id value, -extract the type, and create a object of the specified type with the "hydrated" attribute marked as false. - - - -## STIX Marking Definitions and Granular Markings Data Redaction - -This library implements a redaction feature to support JSON redaction during serialization. -This feature allows the execution of Marking Definitions (`object_marking_refs`) and Granular Markings (`granular_marking_refs`). - -Current execution rules: - -1. Object Markings Refs are executed as a "Entire Object" rule. -1. Granular Markings are executed as "property value masks" and "property removal". -1. Properties that are "required" (Minimum properties needed to init the specific object) are Redacted using a mask. -1. Properties that are "optional" (Properties that are not required to init the specific object) are Redacted using property removal. -1. UNDER REVIEW: Nested objects cannot be redacted within the nested object. They must be redacted at the parent object level using the property in the parent that holds the child object. - -Marking Definitions and Granular Markings are enforced through a "Subject" security pattern: A Subject is defined at the -time of serialization of a Bundle or bundleable object. -A subject is characteristics about a subject that define the security rules. In STIX's most basic form a subject has a -list of "Object Markings" (TLP and Statements). This markings are used as the Subject's context to define what markings -the subject "has" at the time of serialization. - -When serialization occurs a the Subject's context -(a set of object markings) are passed into the serialization process. For each item in `object_marking_refs` and -`granular_marking_refs`, the Subject's context is used for evaluation. If the subject does not have all of the required -Object Markings, then redaction is actioned. - -`object_marking_refs` are executed first, and if the subject is denied, -then granular markings will be ignored, and the entire object will be redacted (removed and returned as `{}`). -In the case of a serialization of a Bundle, a redacted object would result in it be omitted from the -Bundle's `objects` array. - -If the subject passes all `object_marking_refs` validation, then `granular_marking_refs` are validated. -For each Granular Marking object, the Object Marking is validated, and if denied, the Granular Marking's Selectors -are actioned for redaction. Once all `granular_marking_refs` objects have been processed, then resulting object is returned. - - -Consider the following example: - -```groovy -Tlp tlp = Tlp.builder().tlp("red").build() -MarkingDefinition markingDefinition = MarkingDefinition.builder() - .definition(tlp) - .definitionType("tlp") - .build() - -GranularMarking granularMarking = GranularMarking.builder() - .markingRef(markingDefinition) - .addSelectors("granular_markings", "created_by_ref") - .addSelectors("created") - .build() - -AttackPattern attackPattern = AttackPattern.builder() - .name("some Attack Pattern") - .addGranularMarkings(granularMarking) - .createdByRef(Identity.builder() - .name("some Identity") - .identityClass("individual") - .build()) - .build() -``` +`Stix` instances are applied to object creation. There is a default `Stix` instance available as a static object that represents a spec matching configuration. -The above serialized with a Subject context that only contains a TLP=White Object Marking would result in the following JSON: +A `Stix` instance provides a `create(...)` method that takes a StixContent value. This value will be shallow copied and have the business rules validation run against the calling `Stix` instance. -```json -{ - "type": "bundle", - "id": "bundle--3d6bdcdd-2137-4e97-a8a4-8020dd30bc8d", - "spec_version": "2.0", - "objects": [ - { - "type": "attack-pattern", - "id": "attack-pattern--0f4d3058-f4de-4743-ae4c-988645309d92", - "created_by_ref": "identity--__REDACTED__", - "created": "██REDACTED██", - "modified": "2018-12-19T20:49:06.403Z", - "revoked": false, - "name": "some Attack Pattern" - } - ] -} -``` - -The internal implementation is configured as follows: - -```java -class SomeClass { -//... - @JsonProperty("created_by_ref") @JsonInclude(value = NON_EMPTY, content = NON_EMPTY) - @JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="id") - @JsonIdentityReference(alwaysAsId=true) - @JsonDeserialize(converter = DomainObjectOptionalConverter.class) - @Redactable(useMask = true, redactionMask = "identity--__REDACTED__") - Optional getCreatedByRef(); - - @NotNull - @JsonProperty("created") - @Value.Default - @Redactable(useMask = true) - default Instant getCreated(){ - return Instant.now(); - } - - @NotNull - @JsonProperty("granular_markings") @JsonInclude(NON_EMPTY) - @Redactable - Set getGranularMarkings(); -//... -} -``` - -Notice the varying usage of the `@Redactable` annotation. - -If `object_marking_refs` were used and a bundle was generated with the Attack Pattern, the resulting bundle would contain: -```json -{ - "type": "bundle", - "id": "bundle--3d6bdcdd-2137-4e97-a8a4-8020dd30bc8d", - "spec_version": "2.0", - "objects": [] -} -``` - -`objects` is empty because the Attack Pattern would have been redacted at the object level. - - -Future Improvements: - -1. Customizable redactions passed in based on the toJsonString() method and the Subject's context -1. Config for Throwing errors when redactions cannot be processed -1. Config for Ignoring errors when redactions cannot be process - - -# STIX Graph Support / Network Graph - -This feature is currently a active work in progress, and is subject to change. - -This library provides the ability to generate cytoscape.js compliant json that can be imported into a cytoscape instance, and visualized. - -![stix-graph-example1](./docs/images/stix-graph-example1.png) - -The above image shows a web-app that consumes a STIX Bundle, passes it to the STIX-Java libary through a HTTP-request, -and the request returns the Cytoscape compliant json for Network graph rendering. - -## Example json output - -This library will consume a STIX Bundle, and convert it into Cytoscape.js nodes/edges json, such as: - -Output was generated from the [BundleGraphSpec](./src/test/groovy/stix/bundle/BundleGraphSpec.groovy) - -```json -[ - { - "data": { - "id": "ref-89093428-585b-4754-8a6d-8cb0e6ca0a60", - "type": "ref", - "source": "observed-data--14ab5c4d-a696-483d-8792-f5686d61b2b4", - "target": "7ac69a4d-a984-4c19-a54b-13e3dd1d80e8--60cddb5b-9ea2-4855-82b7-f54eca297214", - "label": "ipv4-addr", - "ref_type": "cyber_observable" - } - }, - { - "data": { - "id": "ref-8dca6278-645f-4737-9a56-f56c8cbb44a2", - "type": "ref", - "source": "observed-data--14ab5c4d-a696-483d-8792-f5686d61b2b4", - "target": "95a14320-0d63-4d97-9173-1994c2ed7b77--a3456ae7-cddb-45de-b366-d5b56b0c3ee0", - "label": "ipv4-addr", - "ref_type": "cyber_observable" - } - }, - { - "data": { - "id": "ref-a076819b-1e6e-4d3d-822c-96f215444f23", - "type": "ref", - "source": "sighting--16103a5c-22e9-46ec-91bc-0ae521c60206", - "target": "attack-pattern--4acfe66e-587f-42e4-8daa-4d9da233f7c9", - "label": "sighting-of", - "ref_type": "sighting_of_ref" - } - }, - { - "data": { - "id": "ref-2f53e5f1-9897-45cd-a1ca-12671419a021", - "type": "ref", - "source": "observed-data--14ab5c4d-a696-483d-8792-f5686d61b2b4", - "target": "1366d1a7-ffef-4155-af4e-18cef6517502--c427ea06-8615-49ed-9701-d9e7c04c7aea", - "label": "ipv4-addr", - "ref_type": "cyber_observable" - } - }, - { - "data": { - "id": "c0bedd31-6d9f-48b7-afe5-762c13da69a3--8bbe16e2-8128-4cde-973f-15ac7d32aaa2", - "type": "coo-domain-name", - "stix": { - "type": "domain-name", - "value": "http://google.com" - } - } - }, - { - "data": { - "id": "ref-3901a3de-a38a-4bea-b784-3a08caef4c5f", - "type": "ref", - "source": "observed-data--14ab5c4d-a696-483d-8792-f5686d61b2b4", - "target": "f8647fdf-9011-4f7b-a240-462a20c1a29d--5f13f5fd-19f8-4e04-a53a-fd03dd54a1a2", - "label": "ipv4-addr", - "ref_type": "cyber_observable" - } - }, - { - "data": { - "id": "attack-pattern--cd482a80-3e47-4eed-9542-bbcf69da9405", - "type": "attack-pattern", - "stix": { - "type": "attack-pattern", - "id": "attack-pattern--cd482a80-3e47-4eed-9542-bbcf69da9405", - "created": "2019-06-05T22:49:29.813Z", - "modified": "2019-06-05T22:49:29.813Z", - "name": "attk2" - } - } - }, - { - "data": { - "id": "sighting--16103a5c-22e9-46ec-91bc-0ae521c60206", - "type": "sighting", - "stix": { - "type": "sighting", - "id": "sighting--16103a5c-22e9-46ec-91bc-0ae521c60206", - "created": "2019-06-05T22:49:30.798Z", - "modified": "2019-06-05T22:49:30.798Z", - "first_seen": "2019-06-05T22:49:30.76Z", - "last_seen": "2019-06-05T22:49:30.788Z", - "count": 1, - "sighting_of_ref": "attack-pattern--4acfe66e-587f-42e4-8daa-4d9da233f7c9", - "observed_data_refs": [ - "observed-data--14ab5c4d-a696-483d-8792-f5686d61b2b4" - ] - } - } - }, - { - "data": { - "id": "1366d1a7-ffef-4155-af4e-18cef6517502--c427ea06-8615-49ed-9701-d9e7c04c7aea", - "type": "coo-ipv4-addr", - "stix": { - "type": "ipv4-addr", - "value": "10.10.10.14" - } - } - }, - { - "data": { - "id": "ref-6b0818cf-9edf-4073-ade4-827df72de27a", - "type": "ref", - "source": "observed-data--14ab5c4d-a696-483d-8792-f5686d61b2b4", - "target": "c31c8cbf-7bd3-4865-8e89-7bbe1962d9af--34337862-99fd-46e0-a8c3-3fc7a774114e", - "label": "ipv4-addr", - "ref_type": "cyber_observable" - } - }, - { - "data": { - "id": "f8647fdf-9011-4f7b-a240-462a20c1a29d--5f13f5fd-19f8-4e04-a53a-fd03dd54a1a2", - "type": "coo-ipv4-addr", - "stix": { - "type": "ipv4-addr", - "value": "10.10.10.15" - } - } - }, - { - "data": { - "id": "attack-pattern--4acfe66e-587f-42e4-8daa-4d9da233f7c9", - "type": "attack-pattern", - "stix": { - "id": "attack-pattern--4acfe66e-587f-42e4-8daa-4d9da233f7c9", - "type": "attack-pattern", - "created": "2019-06-05T22:49:28.455Z", - "modified": "2019-06-05T22:49:28.455Z", - "name": "attk1" - } - } - }, - { - "data": { - "id": "relationship--70fca22d-4385-4194-a093-3a7cdb1a2a85", - "type": "relationship", - "source": "attack-pattern--4acfe66e-587f-42e4-8daa-4d9da233f7c9", - "target": "attack-pattern--cd482a80-3e47-4eed-9542-bbcf69da9405", - "stix": { - "type": "relationship", - "id": "relationship--70fca22d-4385-4194-a093-3a7cdb1a2a85", - "created": "2019-06-05T22:49:29.897Z", - "modified": "2019-06-05T22:49:29.897Z", - "relationship_type": "related-to", - "source_ref": "attack-pattern--4acfe66e-587f-42e4-8daa-4d9da233f7c9", - "target_ref": "attack-pattern--cd482a80-3e47-4eed-9542-bbcf69da9405" - }, - "label": "related-to", - "relationship_type": "related-to" - } - }, - { - "data": { - "id": "95a14320-0d63-4d97-9173-1994c2ed7b77--a3456ae7-cddb-45de-b366-d5b56b0c3ee0", - "type": "coo-ipv4-addr", - "stix": { - "type": "ipv4-addr", - "value": "10.10.10.11" - } - } - }, - { - "data": { - "id": "observed-data--14ab5c4d-a696-483d-8792-f5686d61b2b4", - "type": "observed-data", - "stix": { - "id": "observed-data--14ab5c4d-a696-483d-8792-f5686d61b2b4", - "type": "observed-data", - "created": "2019-06-05T22:49:30.479Z", - "modified": "2019-06-05T22:49:30.479Z", - "first_observed": "2019-06-05T22:49:30.47Z", - "last_observed": "2019-06-05T22:49:30.472Z", - "number_observed": 2, - "objects": { - "c0bedd31-6d9f-48b7-afe5-762c13da69a3": { - "type": "domain-name", - "value": "http://google.com" - }, - "7ac69a4d-a984-4c19-a54b-13e3dd1d80e8": { - "type": "ipv4-addr", - "value": "10.10.10.10" - }, - "95a14320-0d63-4d97-9173-1994c2ed7b77": { - "type": "ipv4-addr", - "value": "10.10.10.11" - }, - "c31c8cbf-7bd3-4865-8e89-7bbe1962d9af": { - "type": "ipv4-addr", - "value": "10.10.10.12" - }, - "59d133cc-d29c-4056-aeeb-6791842c0b75": { - "type": "ipv4-addr", - "value": "10.10.10.13" - }, - "1366d1a7-ffef-4155-af4e-18cef6517502": { - "type": "ipv4-addr", - "value": "10.10.10.14" - }, - "f8647fdf-9011-4f7b-a240-462a20c1a29d": { - "type": "ipv4-addr", - "value": "10.10.10.15" - } - } - } - } - }, - { - "data": { - "id": "59d133cc-d29c-4056-aeeb-6791842c0b75--c1efba8b-7ef4-4b12-a768-4b1d99d82eb7", - "type": "coo-ipv4-addr", - "stix": { - "type": "ipv4-addr", - "value": "10.10.10.13" - } - } - }, - { - "data": { - "id": "ref-029c8857-f9e0-49c6-bdaf-d3391acfbd61", - "type": "ref", - "source": "observed-data--14ab5c4d-a696-483d-8792-f5686d61b2b4", - "target": "59d133cc-d29c-4056-aeeb-6791842c0b75--c1efba8b-7ef4-4b12-a768-4b1d99d82eb7", - "label": "ipv4-addr", - "ref_type": "cyber_observable" - } - }, - { - "data": { - "id": "7ac69a4d-a984-4c19-a54b-13e3dd1d80e8--60cddb5b-9ea2-4855-82b7-f54eca297214", - "type": "coo-ipv4-addr", - "stix": { - "type": "ipv4-addr", - "value": "10.10.10.10" - } - } - }, - { - "data": { - "id": "c31c8cbf-7bd3-4865-8e89-7bbe1962d9af--34337862-99fd-46e0-a8c3-3fc7a774114e", - "type": "coo-ipv4-addr", - "stix": { - "type": "ipv4-addr", - "value": "10.10.10.12" - } - } - }, - { - "data": { - "id": "ref-a8cfe6f7-6d73-4e38-9199-0919fd6c3b74", - "type": "ref", - "source": "sighting--16103a5c-22e9-46ec-91bc-0ae521c60206", - "target": "observed-data--14ab5c4d-a696-483d-8792-f5686d61b2b4", - "label": "observed-data", - "ref_type": "observed_data" - } - }, - { - "data": { - "id": "ref-0ef21e43-1451-4b0a-8f8e-866e01b91eb0", - "type": "ref", - "source": "observed-data--14ab5c4d-a696-483d-8792-f5686d61b2b4", - "target": "c0bedd31-6d9f-48b7-afe5-762c13da69a3--8bbe16e2-8128-4cde-973f-15ac7d32aaa2", - "label": "domain-name", - "ref_type": "cyber_observable" - } - } -] -``` - - - - -# Charon Data Flow +## JSON Serialization -![Charon data flow](./docs/Diagrams/Generic-Data-Flow.png) +Example: -# Workflow / BPM / BPMN +```kotlin +val stix1 = Stix() -## Example Process Usage +val ap = AttackPattern(name = "124", confidence = StixConfidence(33)) -![course of action processing 1](./docs/BPMN/course_of_action_1.png) +val ap1: AttackPattern = stix1.create(AttackPattern(name = "124")) -![taxii collection updates](./docs/BPMN/taxii_collection_propagation.png) +val ap2: AttackPattern = stix1.create(AttackPattern(name = "124")) -![process example 1](./docs/BPMN/sample_processes_1.png) +val mapper = stix1.toJsonMapper() +// val mapper = StixJsonContentMapper.fromStixInstance(stix1) -![Report Review Process 1](./docs/BPMN/report_review.png) - -![Translation Process](./docs/BPMN/stix_data_translation.png) - -![Cyber Observable Processing](./docs/BPMN/cyber-observable-processing-1.png) - ------ - -# Raw notes - -This project is a packaging of multiple components that will be split into individual projects at some point. - -1. A full [CTI STIX](https://oasis-open.github.io/cti-documentation/) (Structured Threat Information Expression Language) Java8 implementation. (`io.digitalstate.stix`). The goal is for flexibility and reuse by other Java projects. -1. Charon Application ("Charon Server"): - 1. A SpringBoot based instance of [Camunda BPM](https://docs.camunda.org/manual/7.9/) - 1. Possible: A [TAXII](https://oasis-open.github.io/cti-documentation/taxii/intro) server implemented in SpringBoot, tied to the Camunda BPM SpringBoot instance. - 1. A bridge of CTI STIX with Camunda BPM BPMN Java-Delegates and Scripting Usage. - 1. Possible: Mongo Spring Data Mapping from the STIX Java8 implementation to Mongo Documents. - 1. Possible: Additional REST APIs in addition to the TAXII API that provide missing functionality that is available from using Camunda. - 1. Monitoring of BPMN and STIX data usage with [Prometheus Camunda Plugin](https://github.com/StephenOTT/camunda-prometheus-process-engine-plugin) - - -**Overall Concept:** Enable organizations working with CTI and STIX to have the "application" -(Charon) easily adapt to the organizations internal or standardized security processes. -An organization should not have to change their security models for a "vendor". - -Further Notes: - -By Using STIX as a common language for CTI, automated and manual workflows can be created for multi-system use: -Where each CTI system can generate STIX data and the downstream workflows can process the CTI for whatever purpose -without the need to understand the upstream CTI system (whether it be new and shinny, old and legacy, or -some customized CTI DB that has little understanding outside of the specific domain-usage). - -Leverage CTI's Who, Why, Where, How, What data to process data into meaningful automation and iterate as needed with the Charon engine. -When you need manual intervention, with human eyes and hands, you can continue to leverage Charon to process those human tasks. - - - Process Information - - Detection - - Artifact storage and processing - - Analyze - - Respond - - - Share CTI across the CTI network with the common exchange format, and enrich the data with STIX Data Enrichment from downstream enrichment processes. +// Note that any of the object implementations or any of the interfaces in the hierarchy can be used. +// The parser will use the polymorphic support to detect what is the proper class to return. - "Automation Engine" with OSS. - - Initiate Translation Services through the automation: When translation of CTI is required, it can be packaged as a - STIX bundle and processed into a workflow for processing: automatically or with human intervention. - - -Share Workflows (Shareable Workflows) across organizations and within the organization. Allowing standardization regardless of the specific engine being used. - -Monitor and Track real-time events from your upstream incident response system, and process those events in STIX for -downstream CTI event processing by actors that may not have access or want access to the upstream incident response system. - -Integration ML and AI at any point within the automation. Do not tightly couple the ML and AI into the workflows: -This allows easy swapping of ML and AI technologies, products, and innovations as a underlying capability / -force multiplier without having to integration "a whole other system". - -Enable third-party organizations to deploy the same engine within your network, collect data, -and stream it upstream to central CTI processors. Enable the third-parties to implement their specific CTI processing -processes directly in the engine without the need to "conform to how the upstream system wants to do things". -Then when the upstream system receives the STIX CTI, it can be processed based on your knowledge of that third-party -systems processes: to which you can have transparency into with reviewing their "processes" defined in the engine. +mapper.parseJson(mapper.toJson(ap1)) // You can use the mapper to convert a object to json +mapper.parseJson(mapper.toJson(ap1)) +mapper.parseJson(ap1.toJson(mapper)) // A extension provides StixContent and StixBundle will a toJson(mapper) method +mapper.parseJson(ap1.toJson(mapper)) +mapper.parseJson(ap1.toJson(mapper)) +mapper.parseJson(ap1.toJson(mapper)) +mapper.parseJson(ap1.toJson(mapper)) + + +val rel = Relationship( + relationshipType = RelationshipType("duplicate-of"), + sourceRef = ap1, + targetRef = ap2 +) +mapper.parseJson(rel.toJson(mapper)) +mapper.parseJson(rel.toJson(mapper)) +mapper.parseJson(rel.toJson(mapper)) +mapper.parseJson(rel.toJson(mapper)) +mapper.parseJson(rel.toJson(mapper)) +mapper.parseJson(rel.toJson(mapper)) -Implement organization HR conditions into the workflows: If someone does not response or review in X time, if someone is on holidays, etc -Push out IOCs and Attack patterns to downstream consumers: Consumers can establish business rules that outline their -systems and networks, and as IOCs and APs are pushed, they can be evaluated automatically (and/or manually) -by the downstream consumer system. -Same can be applied to Abnormal Behaviour reporting or Pattern awareness. - -Data Interruption reporting: Reporting in standard formats for org, and having to consume into STIX. - -Use the same engine to automate CTI testing and python scripts. Engine can be wrapped up into a single JAR, including DB. -Can be used as a CLI tool as well. - -Measure the impacts of CTI and the various STIX data being received. - -Use the STIX stream as auditing trail capability: being able to collect STIX events and cross those -events based on aggregation, counts over period of time, etc. Then generate a Request for review based on the conditions. - -Very easy to tie in ML for Event data: Such as Kibana xPack reviewing the various types of -data and detecting new patterns such as counts and increases in periods or locations. +``` -Remove the problem of "Lack of Time to implement processes" (reported as 43% of the time). -Champions can create common processes to be easily and quickly adopted by downstream groups. +## Object Validation +All Stix Content has a "stixValidateOnConstruction" parameter used to indicate if business rule validation should be executed during object creation. -Example Use Cases: -1. STIX Bureaucracy Management using Charon. -1. Security Approvals and Revocations for STIX data exposed through TAXII. -1. Managing TAXII "Hubs" / Central Databases and the review, adjustements, and approvals of submissions of data into the Charon / STIX DB. -1. Life-cycling STIX data through BPMN. -1. Managing TAXII / STIX data access requests, apply-and-removal of STIXX markings. -1. Multi-Department STIX Data Isolation with STIX data submission to UpStream STIX datasource. -1. Execute automated and manual workflows based on STIX data events (CRUD events in STIX data). -1. Concept of "Shareable Workflows": - 1. Ability to share common business and technical workflows across a single organization and across many organiztions. - 1. Ability to create Executable Workflows based on data events within STIX data. - \ No newline at end of file +When you use `stixInstance.create(...)` it will force business rule validation. \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..7e804c6 --- /dev/null +++ b/build.gradle @@ -0,0 +1,49 @@ +buildscript { + ext.kotlin_version = '1.3.50' + + repositories { + mavenCentral() + jcenter() + } + + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +apply plugin: 'java' +apply plugin: 'kotlin' +apply plugin: 'kotlin-kapt' + +apply plugin: 'application' + +sourceCompatibility = 1.8 + +compileKotlin { + kotlinOptions.jvmTarget = "1.8" +} +compileTestKotlin { + kotlinOptions.jvmTarget = "1.8" +} + +repositories { + mavenCentral() +} + + +test { + useJUnitPlatform() +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + implementation "org.jetbrains.kotlin:kotlin-reflect" + + implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.10.0" + implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.0" +// implementation "com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.10.0" +// implementation "com.fasterxml.jackson.module:jackson-module-parameter-names:2.10.0" + + testImplementation "org.jetbrains.kotlin:kotlin-test" + testImplementation "org.jetbrains.kotlin:kotlin-test-junit" +} \ No newline at end of file diff --git a/docs/BPMN/course_of_action_1.bpmn b/docs/BPMN/course_of_action_1.bpmn deleted file mode 100644 index be645d8..0000000 --- a/docs/BPMN/course_of_action_1.bpmn +++ /dev/null @@ -1,553 +0,0 @@ - - - - - SequenceFlow_0vgp55e - - - - - SequenceFlow_0vgp55e - SequenceFlow_0nbiopv - - - - - SequenceFlow_0nbiopv - SequenceFlow_0cphuti - - - DataStoreReference_1b7r9pa - Property_1xlm23y - - - DataStoreReference_1b7r9pa - - - - SequenceFlow_0cphuti - SequenceFlow_1nwrl1b - SequenceFlow_1kix2ig - - - - SequenceFlow_1nwrl1b - - - - SequenceFlow_1kix2ig - SequenceFlow_1x7glqv - - - SequenceFlow_0l4dcef - - - - SequenceFlow_02alnfr - - - - SequenceFlow_00rsegg - SequenceFlow_0tvr883 - - - SequenceFlow_0tvr883 - SequenceFlow_02alnfr - - - SequenceFlow_03vgqmo - SequenceFlow_00rsegg - SequenceFlow_1696x16 - SequenceFlow_1dorylw - SequenceFlow_1fg2lh4 - - - - - - SequenceFlow_1696x16 - SequenceFlow_0f2a997 - - - - SequenceFlow_1dorylw - SequenceFlow_1ghzfx7 - SequenceFlow_0ai75gz - - - SequenceFlow_0ai75gz - - - - SequenceFlow_0f2a997 - SequenceFlow_10ipd63 - SequenceFlow_1ghzfx7 - SequenceFlow_0jdo4py - - - - SequenceFlow_10ipd63 - - - - - SequenceFlow_0gmuasx - - - - SequenceFlow_1fg2lh4 - - - - - SequenceFlow_0l4dcef - SequenceFlow_03vgqmo - - - - SequenceFlow_0jdo4py - SequenceFlow_0gmuasx - - - Assigned based on Reviewer of CoA - - - - Custom business rules based on CoA requirements specific to cyber unit and network admins - - - - - - - SequenceFlow_1x7glqv - SequenceFlow_1hnq4c0 - - - - SequenceFlow_0tt02di - - - - - SequenceFlow_0tt02di - SequenceFlow_0r2zpdf - - - SequenceFlow_16jbxgr - SequenceFlow_16qnt0p - - - - - SequenceFlow_0r2zpdf - SequenceFlow_16jbxgr - - DataStoreReference_1qa6l9t - - - - - SequenceFlow_16qnt0p - - - - - SequenceFlow_1hnq4c0 - - - - - Notify all relevant parties that CoA was completed - - - - Relevant Parties must confirm review of CoA status Update. (Email link, login and review and press accept, etc) - - - - CoA log is updated with CoA Status Review Confirmations as they are received - - - - This will execute multiple times as the "confirmations" come in as parallel activity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/BPMN/course_of_action_1.png b/docs/BPMN/course_of_action_1.png deleted file mode 100644 index 648bd78..0000000 Binary files a/docs/BPMN/course_of_action_1.png and /dev/null differ diff --git a/docs/BPMN/cyber-observable-processing-1.bpmn b/docs/BPMN/cyber-observable-processing-1.bpmn deleted file mode 100644 index 768ece3..0000000 --- a/docs/BPMN/cyber-observable-processing-1.bpmn +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - SequenceFlow_1ubr2qc - SequenceFlow_1wii5nr - SequenceFlow_0yi02pi - - - - SequenceFlow_1qlas1i - SequenceFlow_1ubr2qc - - - SequenceFlow_02uk7kg - - - - - SequenceFlow_0yi02pi - - - - SequenceFlow_1qlas1i - - - SequenceFlow_1wii5nr - SequenceFlow_02uk7kg - - - Cyber Observable is returned to parent process - - - - Cyber Observable is modified / cleaned based on human decisions - - - - Data cleanup processors - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/BPMN/cyber-observable-processing-1.png b/docs/BPMN/cyber-observable-processing-1.png deleted file mode 100644 index a7fd710..0000000 Binary files a/docs/BPMN/cyber-observable-processing-1.png and /dev/null differ diff --git a/docs/BPMN/report_review.bpmn b/docs/BPMN/report_review.bpmn deleted file mode 100644 index 72d4be7..0000000 --- a/docs/BPMN/report_review.bpmn +++ /dev/null @@ -1,392 +0,0 @@ - - - - - - - - SequenceFlow_1cusqkf - SequenceFlow_1qkxa3p - - - SequenceFlow_1qkxa3p - SequenceFlow_0mfl44j - SequenceFlow_0ndbj3u - - - SequenceFlow_09yygo3 - - - SequenceFlow_1cusqkf - - - - SequenceFlow_0ndbj3u - SequenceFlow_09yygo3 - - - SequenceFlow_10i4zjb - - - - - - SequenceFlow_1f2lams - - - - SequenceFlow_1req4v4 - SequenceFlow_1f2lams - - - SequenceFlow_10i4zjb - SequenceFlow_0kbpron - SequenceFlow_1req4v4 - - - SequenceFlow_0kbpron - SequenceFlow_1r209mg - - - SequenceFlow_1r209mg - SequenceFlow_0u56fa7 - SequenceFlow_0ogug1j - - - - - SequenceFlow_0u56fa7 - SequenceFlow_082xzw0 - - - SequenceFlow_082xzw0 - - - - - SequenceFlow_0ogug1j - SequenceFlow_1u4s8kp - - DataStoreReference_13v4nfr - - - - - SequenceFlow_1u4s8kp - - - - Notifications are conditionally sent based on internal rules - - - - Assigned to Group.  Anyone From Group can review the information, but only 1 user can perform completion of task - - - - BPMN is determined dynamically based on the "Next Action" supplied by the person who completes the "Review Report" task.  Each "Group" can manage their own in-house processes or use enterprise processes or any combination of each. - - - - - - - - - - - SequenceFlow_0kiqpxs - - - SequenceFlow_0mfl44j - SequenceFlow_0kiqpxs - - DataStoreReference_13f61u4 - - - - - Mapping is managed in Dynamic mapping allowing real time changes through web UI - - - Mapping of Points of Interest with Groups that are interested in those POIs - - - POIs can by any indicator of interest that can be logically determined: From a Identity, with keywords, RegEx, Date Range, GeoLocation, Threat Actor, Cyber Observable Event Types, Data Marking Classification / Security Classifcations, etc - - - - - - - Receives the STIX JSON or STIX Java Object, and processes into Java Object for System Enrichment of Data - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/BPMN/report_review.png b/docs/BPMN/report_review.png deleted file mode 100644 index 2386e57..0000000 Binary files a/docs/BPMN/report_review.png and /dev/null differ diff --git a/docs/BPMN/sample_processes_1.bpmn b/docs/BPMN/sample_processes_1.bpmn deleted file mode 100644 index b2a898c..0000000 --- a/docs/BPMN/sample_processes_1.bpmn +++ /dev/null @@ -1,402 +0,0 @@ - - - - - - - - - SequenceFlow_09mh75s - - - - SequenceFlow_09mh75s - SequenceFlow_18ii8oi - - - SequenceFlow_18ii8oi - SequenceFlow_1fqe9af - SequenceFlow_076tslj - - - SequenceFlow_1fqe9af - SequenceFlow_04sm98b - - - SequenceFlow_1hmhlwg - - - SequenceFlow_0zvlit2 - SequenceFlow_076tslj - SequenceFlow_1hmhlwg - - DataStoreReference_0c3yt00 - - - - SequenceFlow_04sm98b - SequenceFlow_0zvlit2 - - - - - - - - - - - - Eval markings and various business rules - - - Based on content of Bundle, eval business rules to determine which parts of organization need to review - - - Each group determined by business rule will review the bundle contents - - - Each group can have their own managed process for STIX review (automated and manual) - - - - - - - - - SequenceFlow_0uuopg6 - SequenceFlow_0n98l6r - - - DataStoreReference_0g41h67 - Property_1sk77we - - - - SequenceFlow_0uuopg6 - - - - SequenceFlow_0n98l6r - SequenceFlow_0enf3pf - - - SequenceFlow_0krxv0m - - - - SequenceFlow_00gksn5 - SequenceFlow_1b382fh - SequenceFlow_0jscl1q - - - - - - SequenceFlow_0jscl1q - SequenceFlow_1spcf8e - - DataStoreReference_0nf65c4 - - - - SequenceFlow_1b382fh - SequenceFlow_1ob26vg - - DataStoreReference_0nf65c4 - - - - SequenceFlow_1ob26vg - - - - SequenceFlow_1spcf8e - - - - - SequenceFlow_0krxv0m - SequenceFlow_00gksn5 - - - - - - SequenceFlow_0enf3pf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/BPMN/sample_processes_1.png b/docs/BPMN/sample_processes_1.png deleted file mode 100644 index e3a3d87..0000000 Binary files a/docs/BPMN/sample_processes_1.png and /dev/null differ diff --git a/docs/BPMN/stix_data_translation.bpmn b/docs/BPMN/stix_data_translation.bpmn deleted file mode 100644 index c9918b8..0000000 --- a/docs/BPMN/stix_data_translation.bpmn +++ /dev/null @@ -1,383 +0,0 @@ - - - - - - - - SequenceFlow_0unhs0w - SequenceFlow_1f3ny23 - - - SequenceFlow_0unhs0w - - - - SequenceFlow_1k6bv0d - - - SequenceFlow_0gsryrb - SequenceFlow_1k6bv0d - - DataStoreReference_005s97h - - - - - SequenceFlow_1f3ny23 - SequenceFlow_0gsryrb - - SequenceFlow_0sqxg8t - - - - SequenceFlow_0sqxg8t - SequenceFlow_0kzpq0e - - - SequenceFlow_0kzpq0e - SequenceFlow_12kjyte - SequenceFlow_18yxhaf - - - - SequenceFlow_12kjyte - - - - - - - SequenceFlow_1mx5bdz - SequenceFlow_0ywnm5v - - - SequenceFlow_0ywnm5v - - - - SequenceFlow_0x0ey5x - SequenceFlow_0yf96lt - - - SequenceFlow_0m2l4gs - SequenceFlow_1mx5bdz - - - SequenceFlow_1dx7vq5 - - - - - SequenceFlow_064m5el - - - - SequenceFlow_1dx7vq5 - SequenceFlow_064m5el - - - - SequenceFlow_18yxhaf - SequenceFlow_0x0ey5x - SequenceFlow_1sedtuc - - - - SequenceFlow_1sedtuc - SequenceFlow_02kn65m - - - - - SequenceFlow_0yf96lt - SequenceFlow_02kn65m - SequenceFlow_0m2l4gs - - - Translator or Translator group is determined based on Business rule execution in "Determine Translator" task - - - - Task Priority determined by "Determine Priority" Tasks - - - - Dynamic rules based on Rules business configs - - - - Dynamic rules based on Rules business configs - - - - Notify's by Email or configured channle - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/BPMN/stix_data_translation.png b/docs/BPMN/stix_data_translation.png deleted file mode 100644 index c024180..0000000 Binary files a/docs/BPMN/stix_data_translation.png and /dev/null differ diff --git a/docs/BPMN/taxii_collection_propagation.bpmn b/docs/BPMN/taxii_collection_propagation.bpmn deleted file mode 100644 index 2e90051..0000000 --- a/docs/BPMN/taxii_collection_propagation.bpmn +++ /dev/null @@ -1,397 +0,0 @@ - - - - - SequenceFlow_1gyqzll - - - - SequenceFlow_1muo31v - - - - SequenceFlow_1muo31v - SequenceFlow_1gyqzll - SequenceFlow_14gbzsl - - SequenceFlow_1c11d9n - - - - - - SequenceFlow_1c11d9n - SequenceFlow_12gdemf - - - SequenceFlow_12gdemf - SequenceFlow_1ujirty - - - SequenceFlow_1h37jpi - SequenceFlow_1ilhrdk - SequenceFlow_07ye9pf - - DataStoreReference_0ejwxjg - - - - SequenceFlow_07ye9pf - - - - - - SequenceFlow_1ujirty - SequenceFlow_1h37jpi - SequenceFlow_1dq8flp - - - - SequenceFlow_1fy9sih - SequenceFlow_1tmolyu - - - - SequenceFlow_1dq8flp - SequenceFlow_1fy9sih - - - SequenceFlow_1tmolyu - SequenceFlow_1ilhrdk - SequenceFlow_0bh4w4z - - - - - SequenceFlow_0z223gd - - - - - SequenceFlow_0bh4w4z - SequenceFlow_0z223gd - - DataStoreReference_00pr4pe - - - - - SequenceFlow_1fqthuu - - - - - SequenceFlow_1fqthuu - - - - Assigned to group/person specific to the special collection in question - - - - - Reminder is configured based on the Special Collection Reviewer's Group configuration and the sensitivity of Special Collection and Object - - - - - - - SequenceFlow_1iaiz0e - SequenceFlow_11u1xxz - - - - SequenceFlow_14gbzsl - SequenceFlow_1iaiz0e - SequenceFlow_0weeqkh - - - - - SequenceFlow_0weeqkh - SequenceFlow_11u1xxz - - - - - For each defined notification hook, they will be notified when processing of the object or bundle has been completed.  Can be used by System to System, and Human notification hooks. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/BPMN/taxii_collection_propagation.png b/docs/BPMN/taxii_collection_propagation.png deleted file mode 100644 index 3bbda07..0000000 Binary files a/docs/BPMN/taxii_collection_propagation.png and /dev/null differ diff --git a/docs/Common_Code_Snippets.md b/docs/Common_Code_Snippets.md deleted file mode 100644 index 421d6a0..0000000 --- a/docs/Common_Code_Snippets.md +++ /dev/null @@ -1,8 +0,0 @@ - -#Hashes - -```java - @JsonProperty("hashes") @JsonInclude(NON_EMPTY) - @Size(min = 1, message = "Must have at least 1 hash value") - Map<@Length(min = 3, max = 256) @HashingVocab(HashingAlgorithms.class) String, String> getHashes(); -``` \ No newline at end of file diff --git a/docs/Diagrams/Generic-Data-Flow.png b/docs/Diagrams/Generic-Data-Flow.png deleted file mode 100644 index dde4403..0000000 Binary files a/docs/Diagrams/Generic-Data-Flow.png and /dev/null differ diff --git a/docs/images/stix-graph-example1.png b/docs/images/stix-graph-example1.png deleted file mode 100644 index 2d555ce..0000000 Binary files a/docs/images/stix-graph-example1.png and /dev/null differ diff --git a/docs/stix-java-notes.md b/docs/stix-java-notes.md deleted file mode 100644 index c2eaeb2..0000000 --- a/docs/stix-java-notes.md +++ /dev/null @@ -1,35 +0,0 @@ -# STIX Java library Notes - -# Relation.class - -The _Relation_ class is a wrapper class for _Stix Relationships Objects_ (SROs) (Relationship.class and Sighting.class). - -Relation.class allows the wrapping of a String Id or a Bundleable Object. This means SDOs, SROs, and Data Markings -(Marking Definitions). - -When a object is converted into a JSON string, any relationships that are within the Java object -(attributes that link to another object, whether a list of 1-1) are converted to a String ID. -When a JSON string is parsed back into a Java Object, there is no guarantee that the parsed object will contain -the other objects to complete the relationship chain. Therefore the Relation.class wrapper is used. - -When any Object is converted into JSON String, it will convert all attributes that are relations into the String ID -of the related object. - -When any object is parsed from JSON into a Java object, all relation fields will be parsed into a Relation -object that contains only the ID. -If you wish to "hydrate" the objects' relations with the pointers to the actual Objects, and thus make them navigable, -you can use the "hydrate" method helpers found in each object. - -# Object Hydration - -The process of providing a list of bundleable objects (``) to which the object to whihc you call -the hydration method on, will search through the list and create pointers to the real object and update the -Relation Wrapper from being String ID to using the actual Object. -... - -# Bundle Auto Population - -The process of a bundle performing a recursive search on all objects in the bundle, and finding any nested objects -that should be added into the bundle as "Bundle Objects". This allows someone to generate STIX objects in a fluent -and nested fashion, and not have to worry about remembering to add all objects into the bundle. -... \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..7873e26 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sat Sep 28 14:45:46 EDT 2019 +distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..af6708f --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..0f8d593 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/mvnw b/mvnw deleted file mode 100755 index 5551fde..0000000 --- a/mvnw +++ /dev/null @@ -1,286 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - wget "$jarUrl" -O "$wrapperJarPath" - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - curl -o "$wrapperJarPath" "$jarUrl" - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd deleted file mode 100755 index 48363fa..0000000 --- a/mvnw.cmd +++ /dev/null @@ -1,161 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" -FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - echo Found %WRAPPER_JAR% -) else ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" - echo Finished downloading %WRAPPER_JAR% -) -@REM End of extension - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml deleted file mode 100644 index c284203..0000000 --- a/pom.xml +++ /dev/null @@ -1,199 +0,0 @@ - - - 4.0.0 - - io.digitalstate.stix - stix - v0.10.0 - jar - - STIX 2 - STIX Java Library - - - UTF-8 - UTF-8 - 1.8 - 1.8 - 1.8 - 2.9.9 - - - - - jcenter - https://jcenter.bintray.com/ - - - - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.verion} - compile - - - com.fasterxml.jackson.module - jackson-module-parameter-names - ${jackson.verion} - compile - - - com.fasterxml.jackson.datatype - jackson-datatype-jdk8 - ${jackson.verion} - compile - - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - ${jackson.verion} - compile - - - com.fasterxml.jackson.datatype - jackson-datatype-guava - ${jackson.verion} - compile - - - - com.jayway.jsonpath - json-path - 2.4.0 - compile - - - - org.hibernate.validator - hibernate-validator - 6.0.13.Final - compile - - - org.glassfish - javax.el - 3.0.1-b09 - compile - - - - org.apache.commons - commons-lang3 - 3.8.1 - compile - - - - org.springframework - spring-expression - 5.1.4.RELEASE - compile - - - - - org.immutables - value - 2.7.3 - provided - - - org.immutables - annotate - 2.7.3 - provided - - - org.immutables - serial - 2.7.3 - provided - - - - - - org.spockframework - spock-core - 1.2-groovy-2.4 - test - - - - org.codehaus.groovy - groovy-all - 2.4.15 - test - - - net.bytebuddy - byte-buddy - 1.8.21 - test - - - org.objenesis - objenesis - 2.6 - test - - - org.hamcrest - hamcrest-core - 1.3 - test - - - - - net.andreinc.mockneat - mockneat - 0.3.2 - test - - - - org.skyscreamer - jsonassert - 1.5.0 - test - - - - - - - - - org.codehaus.gmavenplus - gmavenplus-plugin - 1.6 - - - - - compileTests - - - - - - - - maven-surefire-plugin - 2.20.1 - - false - - **/*Test.java - **/*Spec.java - - - - - - \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..4fe0a93 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'STIX-Java-Kotlin' \ No newline at end of file diff --git a/src/main/java/io/digitalstate/stix/bundle/BundleObject.java b/src/main/java/io/digitalstate/stix/bundle/BundleObject.java deleted file mode 100644 index 15229b8..0000000 --- a/src/main/java/io/digitalstate/stix/bundle/BundleObject.java +++ /dev/null @@ -1,97 +0,0 @@ -package io.digitalstate.stix.bundle; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; -import io.digitalstate.stix.common.Stix; -import io.digitalstate.stix.common.StixCustomProperties; -import io.digitalstate.stix.helpers.StixSpecVersion; -import io.digitalstate.stix.json.StixParsers; -import io.digitalstate.stix.validation.GenericValidation; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; -import java.io.IOException; -import java.io.Serializable; -import java.util.Set; - -/** - * bundle - *

- * A Bundle is a collection of arbitrary STIX Objects and Marking Definitions grouped together in a single container. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "bundle", groups = {DefaultValuesProcessor.class}) -@JsonTypeName("bundle") -@Value.Style(typeImmutable = "Bundle", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = Bundle.class) @JsonDeserialize(builder = Bundle.Builder.class) -@JsonPropertyOrder({"type", "id", "spec_version", "objects"}) -public interface BundleObject extends GenericValidation, Serializable, StixCustomProperties, Stix { - - @NotBlank - @JsonProperty("type") - @JsonPropertyDescription("The type property identifies the type of STIX Object (SDO, Relationship Object, etc). The value of the type field MUST be one of the types defined by a STIX Object (e.g., indicator).") - @Pattern(regexp = "^\\-?[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\\-?$") - @Size(min = 3, max = 250) - String getType(); - - @NotBlank - @JsonProperty("id") - @JsonPropertyDescription("Represents identifiers across the CTI specifications. The format consists of the name of the top-level object being identified, followed by two dashes (--), followed by a UUIDv4.") - @Pattern(regexp = "^[a-z][a-z-]+[a-z]--[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$") - String getId(); - - @NotBlank - @JsonProperty("spec_version") - @JsonPropertyDescription("The version of the STIX specification used to represent the content in this bundle.") - @Value.Default - default String getSpecVersion() { - return StixSpecVersion.SPECVERSION; - } - - @Size(min = 1, message = "Must have at least 1 object in bundle") - @JsonProperty(value = "objects", access = JsonProperty.Access.WRITE_ONLY) - @JsonPropertyDescription("Specifies a set of one or more STIX Objects.") - Set getObjects(); - - @JsonIgnore - @Value.Lazy - default String toJsonString() { - JsonNode response = StixParsers.getJsonMapper().valueToTree(this); - ObjectNode responseNode = (ObjectNode) response; - //@TODO Refactor as this is causing custom properties to come before the Objects prop: - responseNode.putArray("objects"); - ArrayNode objects = (ArrayNode) response.get("objects"); - - getObjects().forEach(o -> { - String redactedJson = o.toJsonString(); - try { - //@TODO refactor so the double JSON parsing does not need to happen - JsonNode redactedJsonNode = StixParsers.getJsonMapper().readTree(redactedJson); - ObjectNode redactedObjectNode = (ObjectNode) redactedJsonNode; - if (!redactedObjectNode.isNull() && redactedObjectNode.size() > 0) { - objects.add(redactedObjectNode); - } - } catch (IOException e) { - throw new IllegalStateException("Failed to Parse Object within bundle JSON"); - } - }); - - try { - return StixParsers.getJsonMapper().writeValueAsString(response); - } catch (JsonProcessingException e) { - throw new IllegalStateException("Failed to Parse Bundle JSON"); - } - - } -} diff --git a/src/main/java/io/digitalstate/stix/bundle/BundleableObject.java b/src/main/java/io/digitalstate/stix/bundle/BundleableObject.java deleted file mode 100644 index 12ec141..0000000 --- a/src/main/java/io/digitalstate/stix/bundle/BundleableObject.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.digitalstate.stix.bundle; - -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import io.digitalstate.stix.common.Stix; -import io.digitalstate.stix.custom.objects.CustomObject; -import io.digitalstate.stix.datamarkings.GranularMarkingDm; -import io.digitalstate.stix.datamarkings.MarkingDefinitionDm; - -import java.io.Serializable; -import java.util.Set; - -/** - * This interface is typically inherited by other interfaces that are considered "objects" that are part of a Bundle. - * Thus the name "BundleableObject". A Bundleable Object by STIX standard is: SDO, SRO, and Marking Definition. - * The Type field is used to determine the sub-types as registered in the {@link io.digitalstate.stix.json.StixParsers} - */ -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", include = JsonTypeInfo.As.EXISTING_PROPERTY, visible = true, defaultImpl = CustomObject.class) -public interface BundleableObject extends Serializable, Stix { - - String getType(); - String getId(); - Set getObjectMarkingRefs(); - Set getGranularMarkings(); - boolean getHydrated(); - String toJsonString(); - -} diff --git a/src/main/java/io/digitalstate/stix/common/Stix.java b/src/main/java/io/digitalstate/stix/common/Stix.java deleted file mode 100644 index dfedfea..0000000 --- a/src/main/java/io/digitalstate/stix/common/Stix.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.digitalstate.stix.common; - -/** - * Base generic interface used for indentifying that a object is a Stix based object (a Bundle or Bundleable object) - * Used mainly for generics and parsing. - * May be used in the future as a entry point for STIX instance creation - */ -public interface Stix { -} diff --git a/src/main/java/io/digitalstate/stix/common/StixBoolean.java b/src/main/java/io/digitalstate/stix/common/StixBoolean.java deleted file mode 100644 index c873461..0000000 --- a/src/main/java/io/digitalstate/stix/common/StixBoolean.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.digitalstate.stix.common; - -/** - * Wrapper for boolean that is used in Stix to track if the boolean value was User provided. - * Custom class is used instead of a Boolean in order to provide a more robust api - */ -public class StixBoolean { - - private boolean stixBooleanValue; - private boolean isDefinedValue; - - public StixBoolean(boolean stixBooleanValue) { - this.stixBooleanValue = stixBooleanValue; - this.isDefinedValue = true; - } - - public StixBoolean(boolean stixBooleanValue, boolean isDefinedValue) { - this.stixBooleanValue = stixBooleanValue; - this.isDefinedValue = isDefinedValue; - } - - /** - * Defaults to StixBoolean value to false. Sets isDefinedValue to false - */ - public StixBoolean() { - this.stixBooleanValue = false; - isDefinedValue = false; - } - - public StixBoolean(String booleanString){ - this.stixBooleanValue = Boolean.valueOf(booleanString); - this.isDefinedValue = true; - } - - public boolean getStixBooleanValue() { - return stixBooleanValue; - } - - /** - * Indicates that the boolean value was explicitly defined, even if the value was false, - * and the original object's property defaults to false if no value is provided. - * @return boolean indicating if the value was defined. - */ - public boolean isdefinedValue() { - return isDefinedValue; - } - - @Override - public String toString() { - return String.valueOf(getStixBooleanValue()); - } - -} diff --git a/src/main/java/io/digitalstate/stix/common/StixCommonProperties.java b/src/main/java/io/digitalstate/stix/common/StixCommonProperties.java deleted file mode 100644 index 2d19593..0000000 --- a/src/main/java/io/digitalstate/stix/common/StixCommonProperties.java +++ /dev/null @@ -1,122 +0,0 @@ -package io.digitalstate.stix.common; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import io.digitalstate.stix.bundle.BundleableObject; -import io.digitalstate.stix.datamarkings.GranularMarkingDm; -import io.digitalstate.stix.datamarkings.MarkingDefinitionDm; -import io.digitalstate.stix.json.StixParsers; -import io.digitalstate.stix.json.converters.dehydrated.DomainObjectOptionalConverter; -import io.digitalstate.stix.json.converters.dehydrated.MarkingDefinitionSetConverter; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.sdo.objects.IdentitySdo; -import io.digitalstate.stix.sdo.types.ExternalReferenceType; -import io.digitalstate.stix.validation.SdoDefaultValidator; -import io.digitalstate.stix.validation.groups.ValidateIdOnly; -import org.immutables.value.Value; - -import javax.validation.ConstraintViolationException; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; -import javax.validation.groups.Default; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * Base interface used by Immutable STIX Bundleable Objects - */ -@Value.Style(validationMethod = Value.Style.ValidationMethod.NONE) -public interface StixCommonProperties extends StixSpecVersion, SdoDefaultValidator, BundleableObject { - - /** - * Dictates if the object is hydrated. - * Hydration is defined as if the Object has only a "ID" or has been properly - * hydrated with the expected required fields - * @return boolean - */ - @NotNull - @Value.Default - @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - default boolean getHydrated(){ - return true; - } - - @JsonProperty("type") - @JsonPropertyDescription("The type property identifies the type of STIX Object (SDO, Relationship Object, etc). The value of the type field MUST be one of the types defined by a STIX Object (e.g., indicator).") - @Pattern(regexp = "^\\-?[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\\-?$") - @Size(min = 3, max = 250) - @NotBlank(groups = {Default.class, ValidateIdOnly.class}, message = "Type is required") - String getType(); - - @JsonProperty("id") - @JsonPropertyDescription("Represents identifiers across the CTI specifications. The format consists of the name of the top-level object being identified, followed by two dashes (--), followed by a UUIDv4.") - @Pattern(regexp = "^[a-z][a-z-]+[a-z]--[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$") - @NotBlank(groups = {Default.class, ValidateIdOnly.class}, message = "Id is required") - String getId(); - - @JsonProperty("created_by_ref") @JsonInclude(value = NON_EMPTY, content = NON_EMPTY) - @JsonPropertyDescription("Represents identifiers across the CTI specifications. The format consists of the name of the top-level object being identified, followed by two dashes (--), followed by a UUIDv4.") - @JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="id") - @JsonIdentityReference(alwaysAsId=true) - @JsonDeserialize(converter = DomainObjectOptionalConverter.class) - @Redactable(useMask = true, redactionMask = "identity--__REDACTED__") - Optional getCreatedByRef(); - - @NotNull - @JsonProperty("created") - @JsonPropertyDescription("The created property represents the time at which the first version of this object was created. The timstamp value MUST be precise to the nearest millisecond.") - @Value.Default - @Redactable(useMask = true) - default StixInstant getCreated(){ - return new StixInstant(); - } - - @NotNull - @JsonProperty("external_references") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("A list of external references which refers to non-STIX information.") - @Redactable - Set getExternalReferences(); - - @NotNull - @JsonProperty("object_marking_refs") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("The list of marking-definition objects to be applied to this object.") - @JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="id") - @JsonIdentityReference(alwaysAsId=true) - @JsonDeserialize(converter = MarkingDefinitionSetConverter.class) - @Redactable - Set getObjectMarkingRefs(); - - @NotNull - @JsonProperty("granular_markings") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("The set of granular markings that apply to this object.") - @Redactable - Set getGranularMarkings(); - - @JsonIgnore - @Value.Lazy - @Value.Auxiliary - default String toJsonString() { - try { - String jsonString = StixParsers.getJsonMapper().writeValueAsString(this); -// return BundleableObjectRedactionProcessor.processObject(this, jsonString, new HashSet<>(Arrays.asList())); - return jsonString; - } catch (JsonProcessingException e) { - throw new IllegalStateException("Cannot process JSON", e); - } - } - - @Value.Check - default void checkHydrationValidation() throws ConstraintViolationException { - if (getHydrated()){ - this.validate(); - } else { - this.validateOnlyId(); - } - } - -} diff --git a/src/main/java/io/digitalstate/stix/common/StixCustomObjectId.java b/src/main/java/io/digitalstate/stix/common/StixCustomObjectId.java deleted file mode 100644 index 7a7d1ed..0000000 --- a/src/main/java/io/digitalstate/stix/common/StixCustomObjectId.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.digitalstate.stix.common; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyDescription; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.validation.contraints.startswith.StartsWith; -import io.digitalstate.stix.validation.groups.ValidateIdOnly; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.groups.Default; - -/** - * - */ -@Value.Style(validationMethod = Value.Style.ValidationMethod.NONE) -public interface StixCustomObjectId { - - @JsonProperty("id") - @JsonPropertyDescription("Represents identifiers across the CTI specifications. The format consists of the name of the top-level object being identified, followed by two dashes (--), followed by a UUIDv4.") - @Pattern(regexp = "^[a-z][a-z-]+[a-z]--[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$") - @NotBlank(groups = {Default.class, ValidateIdOnly.class}, message = "Id is required") - @StartsWith("x-") - String getId(); - -} diff --git a/src/main/java/io/digitalstate/stix/common/StixCustomObjectType.java b/src/main/java/io/digitalstate/stix/common/StixCustomObjectType.java deleted file mode 100644 index 04c6ffb..0000000 --- a/src/main/java/io/digitalstate/stix/common/StixCustomObjectType.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.digitalstate.stix.common; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyDescription; -import io.digitalstate.stix.validation.contraints.startswith.StartsWith; -import io.digitalstate.stix.validation.groups.ValidateIdOnly; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; -import javax.validation.groups.Default; - -/** - * - */ -@Value.Style(validationMethod = Value.Style.ValidationMethod.NONE) -public interface StixCustomObjectType { - - @JsonProperty("type") - @JsonPropertyDescription("The type property identifies the type of STIX Object (SDO, Relationship Object, etc). The value of the type field MUST be one of the types defined by a STIX Object (e.g., indicator).") - @Pattern(regexp = "^\\-?[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\\-?$") - @Size(min = 3, max = 250) - @NotBlank(groups = {Default.class, ValidateIdOnly.class}, message = "Type is required1") - @StartsWith("x-") - String getType(); - -} diff --git a/src/main/java/io/digitalstate/stix/common/StixCustomProperties.java b/src/main/java/io/digitalstate/stix/common/StixCustomProperties.java deleted file mode 100644 index c8481a2..0000000 --- a/src/main/java/io/digitalstate/stix/common/StixCustomProperties.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.digitalstate.stix.common; - -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import io.digitalstate.stix.validation.contraints.startswith.StartsWith; -import org.hibernate.validator.constraints.Length; - -import java.util.Map; - -/** - * Stix Custom Properties - */ -public interface StixCustomProperties { - - /** - * Custom Properties for STIX Objects. - * Any object that supports custom properties will have a validation of the custom property prefix (typically "x_"). - * If the additional property in the JSON does not meet the StartsWith condition, then the JSON will be rejected. - * @return Map of custom properties {@code Map} - */ - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - @JsonUnwrapped @JsonAnyGetter - Map<@StartsWith() @Length(min = 3, max = 250, message = "STIX Custom Properties must have a min key length of 3 and max of 250") String, Object> getCustomProperties(); - -} diff --git a/src/main/java/io/digitalstate/stix/common/StixInstant.java b/src/main/java/io/digitalstate/stix/common/StixInstant.java deleted file mode 100644 index d2f7bf1..0000000 --- a/src/main/java/io/digitalstate/stix/common/StixInstant.java +++ /dev/null @@ -1,105 +0,0 @@ -package io.digitalstate.stix.common; - -import io.digitalstate.stix.helpers.StixDataFormats; - -import java.time.Instant; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Stores a Java.time Instant and stores the original sub-second precision digital count. - * SubSecond precision count means that the number of digits (even if all zeros / trailing zeros) are remembered. - * Use toString() to get the Stix string format for the datetime. - */ -public class StixInstant { - - public static final Pattern REGEX_SUBSECOND = Pattern.compile("(?\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(.(?[0-9]+))?Z)"); - - private final Instant instant; - private final int originalSubSecondPrecisionDigitCount; - - /** - * Generates a Instant.now() - * Defaults to 3 digits of sub second precision (milliseconds) - */ - public StixInstant() { - Instant now = Instant.now(); - this.instant = now; - this.originalSubSecondPrecisionDigitCount = 3; - } - - public StixInstant(Instant instant, int subSecondPrecision) { - Objects.requireNonNull(instant); - if (subSecondPrecision < 0 || subSecondPrecision > 9){ - throw new IllegalStateException("Subsecond precision must be between 0 and 9"); - } - - this.instant = instant; - this.originalSubSecondPrecisionDigitCount = subSecondPrecision; - } - - /** - * Defaults with parsed Instant's Nano second precision digit count. - * Note that trailing zeros would have been stripped. - * If you need to keep exact precision, including the trailing zeros, use {@link StixInstant#StixInstant(Instant, int)} - * @param instant - */ - public StixInstant(Instant instant) { - this(instant, String.valueOf(instant.getNano()).length()); - } - - /** - * Get the underlying Instant value. If you need the Stix Date with the Stix Precision then use {@link StixInstant#toString()} - * getInstant() should only be used in special cases where you need access to perform temporal work. - * @return - */ - public Instant getInstant() { - return instant; - } - - public int getOriginalSubSecondPrecisionDigitCount() { - return originalSubSecondPrecisionDigitCount; - } - - /** - * Generates a STIX Spec String of DateTime. - * Uses {@link StixDataFormats#getWriterStixDateTimeFormatter(int)} - * @return - */ - @Override - public String toString() { - return StixDataFormats.getWriterStixDateTimeFormatter(originalSubSecondPrecisionDigitCount) - .format(this.instant); - } - - public String toString(int subSecondPrecision) { - return StixDataFormats.getWriterStixDateTimeFormatter(subSecondPrecision) - .format(this.instant); - } - - public static StixInstant parse(String dateString){ - Objects.requireNonNull(dateString); - - Instant instant = Instant.from(StixDataFormats.getReaderStixDateTimeFormatter().parse(dateString)); - int subSecondPrecision = getSubSecondDigitCount(dateString); - - return new StixInstant(instant, subSecondPrecision); - } - - private static int getSubSecondDigitCount(String dateString){ - Matcher matcher = REGEX_SUBSECOND.matcher(dateString); - if (matcher.find()){ - String subSeconds = matcher.group("subSecond"); - // If no sub seconds were provided then return 0 as the precision - if (subSeconds == null){ - return 0; - } else { - return subSeconds.length(); - } - - } else { - throw new IllegalStateException("Unable to parse date"); - } - } -} diff --git a/src/main/java/io/digitalstate/stix/common/StixLabels.java b/src/main/java/io/digitalstate/stix/common/StixLabels.java deleted file mode 100644 index 7f9dbc8..0000000 --- a/src/main/java/io/digitalstate/stix/common/StixLabels.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.digitalstate.stix.common; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyDescription; -import io.digitalstate.stix.redaction.Redactable; -import org.hibernate.validator.constraints.Length; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * - */ -@Value.Style(validationMethod = Value.Style.ValidationMethod.NONE) -public interface StixLabels { - - @NotNull - @JsonProperty("labels") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("The labels property specifies a set of classifications.") - @Redactable - Set<@Length(min = 1) String> getLabels(); - -} diff --git a/src/main/java/io/digitalstate/stix/common/StixModified.java b/src/main/java/io/digitalstate/stix/common/StixModified.java deleted file mode 100644 index bfe1b09..0000000 --- a/src/main/java/io/digitalstate/stix/common/StixModified.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.digitalstate.stix.common; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyDescription; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.json.StixInstantDeserializer; -import io.digitalstate.stix.json.StixInstantSerializer; -import io.digitalstate.stix.redaction.Redactable; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import java.time.Instant; - -/** - * - */ -@Value.Style(validationMethod = Value.Style.ValidationMethod.NONE) -public interface StixModified { - - @NotNull - @JsonProperty("modified") - @JsonPropertyDescription("The modified property represents the time that this particular version of the object was created. The timstamp value MUST be precise to the nearest millisecond.") - @Value.Default - @Redactable - default StixInstant getModified(){ - return new StixInstant(); - } -} diff --git a/src/main/java/io/digitalstate/stix/common/StixRevoked.java b/src/main/java/io/digitalstate/stix/common/StixRevoked.java deleted file mode 100644 index a8f8e9a..0000000 --- a/src/main/java/io/digitalstate/stix/common/StixRevoked.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.digitalstate.stix.common; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyDescription; -import io.digitalstate.stix.redaction.Redactable; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * - */ -@Value.Style(validationMethod = Value.Style.ValidationMethod.NONE) -public interface StixRevoked { - - @NotNull - @JsonProperty("revoked") - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("The revoked property indicates whether the object has been revoked.") - @Value.Default - @Redactable - default StixBoolean getRevoked(){ - return new StixBoolean(); - } - -} diff --git a/src/main/java/io/digitalstate/stix/common/StixSpecVersion.java b/src/main/java/io/digitalstate/stix/common/StixSpecVersion.java deleted file mode 100644 index 8bd5fa1..0000000 --- a/src/main/java/io/digitalstate/stix/common/StixSpecVersion.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.digitalstate.stix.common; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; - -public interface StixSpecVersion { - - /** - * Helper attribute to track the STIX Spec Version that was used for this object. - * @return String of STIX Spec Version, example: "2.0" - */ - @NotBlank - @JsonIgnore - @Value.Lazy - default String getSpecVersion(){ - return io.digitalstate.stix.helpers.StixSpecVersion.SPECVERSION; - } - -} diff --git a/src/main/java/io/digitalstate/stix/coo/CyberObservableObject.java b/src/main/java/io/digitalstate/stix/coo/CyberObservableObject.java deleted file mode 100644 index 1e8304a..0000000 --- a/src/main/java/io/digitalstate/stix/coo/CyberObservableObject.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.digitalstate.stix.coo; - -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import io.digitalstate.stix.common.StixCustomProperties; -import io.digitalstate.stix.validation.contraints.coo.allowedparents.ValidateExtensions; - -import java.io.Serializable; - -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", include = JsonTypeInfo.As.EXISTING_PROPERTY) -@ValidateExtensions -public interface CyberObservableObject extends Serializable, - CyberObservableObjectCommonProperties, - StixCustomProperties { - -} diff --git a/src/main/java/io/digitalstate/stix/coo/CyberObservableObjectCommonProperties.java b/src/main/java/io/digitalstate/stix/coo/CyberObservableObjectCommonProperties.java deleted file mode 100644 index 8bce213..0000000 --- a/src/main/java/io/digitalstate/stix/coo/CyberObservableObjectCommonProperties.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.digitalstate.stix.coo; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyDescription; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; -import io.digitalstate.stix.coo.json.extension.CyberObservableExtensionsFieldDeserializer; -import io.digitalstate.stix.coo.json.extension.CyberObservableExtensionsFieldSerializer; -import io.digitalstate.stix.sdo.objects.ObservedDataSdo; -import io.digitalstate.stix.validation.GenericValidation; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; -import java.util.Set; -import java.util.UUID; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -public interface CyberObservableObjectCommonProperties extends GenericValidation { - - @NotBlank - @JsonProperty("type") - @JsonPropertyDescription("Indicates that this object is an Observable Object. The value of this property MUST be a valid Observable Object type name, but to allow for custom objects this has been removed from the schema.") - @Pattern(regexp = "^\\-?[a-z0-9]+(-[a-z0-9]+)*\\-?$") - @Size(min = 3, max = 250) - String getType(); - - /** - * Multiple extensions can be added, but only 1 instance of a specific extension can be added. - * @return - */ - // @TODO Add validation to ensure that only 1 instance of each extension is applied as per the spec - @JsonProperty("extensions") - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("Specifies any extensions of the object, as a dictionary.") - @JsonSerialize(using = CyberObservableExtensionsFieldSerializer.class) - @JsonDeserialize(using = CyberObservableExtensionsFieldDeserializer.class) - Set getExtensions(); - - /** - * Used for generation of Map Keys by {@link ObservedDataSdo#getObjects()} - * Manually set this value if you want to control key names. Otherwise UUIDs will be used. - * @return - */ - @JsonProperty(value = "observable_object_key", access = JsonProperty.Access.WRITE_ONLY) - @Value.Default - default String getObservableObjectKey(){ - return UUID.randomUUID().toString(); - } - -} diff --git a/src/main/java/io/digitalstate/stix/coo/extension/CyberObservableExtension.java b/src/main/java/io/digitalstate/stix/coo/extension/CyberObservableExtension.java deleted file mode 100644 index c08c5c7..0000000 --- a/src/main/java/io/digitalstate/stix/coo/extension/CyberObservableExtension.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.digitalstate.stix.coo.extension; - -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import io.digitalstate.stix.common.StixCustomProperties; -import io.digitalstate.stix.validation.GenericValidation; - - -/** - * Interface to tag Cyber Observable Extension classes - * - */ -@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", include = JsonTypeInfo.As.EXISTING_PROPERTY) -public interface CyberObservableExtension extends - CyberObservableExtensionCommonProperties, - GenericValidation, - StixCustomProperties { - -} diff --git a/src/main/java/io/digitalstate/stix/coo/extension/CyberObservableExtensionCommonProperties.java b/src/main/java/io/digitalstate/stix/coo/extension/CyberObservableExtensionCommonProperties.java deleted file mode 100644 index 65fa007..0000000 --- a/src/main/java/io/digitalstate/stix/coo/extension/CyberObservableExtensionCommonProperties.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.digitalstate.stix.coo.extension; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Size; - -@Value.Style(validationMethod = Value.Style.ValidationMethod.NONE) -public interface CyberObservableExtensionCommonProperties { - - /** - * This property is used for generation of the dictionary during serialization, and used as the "Type" mapping value for polymorphic when deserializing. - * @return - */ - @NotBlank - @JsonIgnore - @JsonProperty("type") - @Size(min = 3, max = 250) - String getType(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/extension/types/ArchiveFileExtensionExt.java b/src/main/java/io/digitalstate/stix/coo/extension/types/ArchiveFileExtensionExt.java deleted file mode 100644 index 3981d2c..0000000 --- a/src/main/java/io/digitalstate/stix/coo/extension/types/ArchiveFileExtensionExt.java +++ /dev/null @@ -1,48 +0,0 @@ -package io.digitalstate.stix.coo.extension.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; -import io.digitalstate.stix.coo.objects.FileCoo; -import io.digitalstate.stix.validation.contraints.coo.allowedparents.AllowedParents; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * The Archive File extension specifies a default extension for capturing - * properties specific to archive files. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "archive-ext", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Ext", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, passAnnotations = {AllowedParents.class}, depluralize = true) -@JsonSerialize(as = ArchiveFileExtension.class) @JsonDeserialize(builder = ArchiveFileExtension.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "contains_refs", "version", "comment" }) -@JsonTypeName("archive-ext") -@AllowedParents({FileCoo.class}) -public interface ArchiveFileExtensionExt extends CyberObservableExtension { - - @JsonProperty("contains_refs") - @JsonPropertyDescription("Specifies the files contained in the archive, as a reference to one or more other File Objects. The objects referenced in this list MUST be of type file-object.") - @NotNull - Set getContainsRefs(); - - @JsonProperty("version") - @JsonPropertyDescription("Specifies the version of the archive type used in the archive file.") - Optional getVersion(); - - @JsonProperty("comment") - @JsonPropertyDescription("Specifies a comment included as part of the archive file.") - Optional getComment(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/extension/types/HttpRequestExtensionExt.java b/src/main/java/io/digitalstate/stix/coo/extension/types/HttpRequestExtensionExt.java deleted file mode 100644 index bd1ca8d..0000000 --- a/src/main/java/io/digitalstate/stix/coo/extension/types/HttpRequestExtensionExt.java +++ /dev/null @@ -1,72 +0,0 @@ -package io.digitalstate.stix.coo.extension.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; -import io.digitalstate.stix.coo.objects.NetworkTrafficCoo; -import io.digitalstate.stix.validation.contraints.coo.allowedparents.AllowedParents; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import java.util.Map; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * http-request-ext - *

- * The HTTP request extension specifies a default extension for capturing - * network traffic properties specific to HTTP requests. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "http-request-ext", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Ext", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, passAnnotations = {AllowedParents.class}, depluralize = true) -@JsonSerialize(as = HttpRequestExtension.class) @JsonDeserialize(builder = HttpRequestExtension.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "request_method", "request_value", "request_version", "request_header", "message_body_length", - "message_body_data_ref" }) -@JsonTypeName("http-request-ext") -@AllowedParents({NetworkTrafficCoo.class}) -public interface HttpRequestExtensionExt extends CyberObservableExtension { - - @JsonProperty("request_method") - @JsonPropertyDescription("Specifies the HTTP method portion of the HTTP request line, as a lowercase string.") - @NotNull - String getRequestMethod(); - - @JsonProperty("request_value") - @JsonPropertyDescription("Specifies the value (typically a resource path) portion of the HTTP request line.") - @NotNull - String getRequestValue(); - - @JsonProperty("request_version") - @JsonPropertyDescription("Specifies the HTTP version portion of the HTTP request line, as a lowercase string.") - Optional getRequestVersion(); - - /** - * Currently only supports non-duplicate keys: https://github.com/oasis-tcs/cti-stix2/issues/137 - * @return - */ - @JsonProperty("request_header") - @JsonPropertyDescription("Specifies all of the HTTP header fields that may be found in the HTTP client request, as a dictionary.") - Map getRequestHeader(); - - //@TODO Review if this should be a long - @JsonProperty("message_body_length") - @JsonPropertyDescription("Specifies the length of the HTTP message body, if included, in bytes.") - Optional getMessageBodyLength(); - - /* - * Must be of type artifact - */ - @JsonProperty("message_body_data_ref") - @JsonPropertyDescription("Specifies the data contained in the HTTP message body, if included.") - Optional getMessageBodyDataRef(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/extension/types/IcmpExtensionExt.java b/src/main/java/io/digitalstate/stix/coo/extension/types/IcmpExtensionExt.java deleted file mode 100644 index 90fdae3..0000000 --- a/src/main/java/io/digitalstate/stix/coo/extension/types/IcmpExtensionExt.java +++ /dev/null @@ -1,48 +0,0 @@ -package io.digitalstate.stix.coo.extension.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; -import io.digitalstate.stix.coo.objects.NetworkTrafficCoo; -import io.digitalstate.stix.validation.contraints.coo.allowedparents.AllowedParents; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * icmp-ext - *

- * The ICMP extension specifies a default extension for capturing network - * traffic properties specific to ICMP. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "icmp-ext", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Ext", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, passAnnotations = {AllowedParents.class}, depluralize = true) -@JsonSerialize(as = IcmpExtension.class) @JsonDeserialize(builder = IcmpExtension.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "icmp_type_hex", "icmp_code_hex" }) -@JsonTypeName("icmp-ext") -@AllowedParents({NetworkTrafficCoo.class}) -public interface IcmpExtensionExt extends CyberObservableExtension { - - @JsonProperty("icmp_type_hex") - @JsonPropertyDescription("Specifies the ICMP type byte.") - @Pattern(regexp = "^([a-fA-F0-9]{2})+$") - @NotNull - String getOcmpTypeHex(); - - @JsonProperty("icmp_code_hex") - @JsonPropertyDescription("Specifies the ICMP code byte.") - @Pattern(regexp = "^([a-fA-F0-9]{2})+$") - @NotNull - String getIcmpCodeHex(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/extension/types/NetworkSocketExtensionExt.java b/src/main/java/io/digitalstate/stix/coo/extension/types/NetworkSocketExtensionExt.java deleted file mode 100644 index 7c90ada..0000000 --- a/src/main/java/io/digitalstate/stix/coo/extension/types/NetworkSocketExtensionExt.java +++ /dev/null @@ -1,80 +0,0 @@ -package io.digitalstate.stix.coo.extension.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; -import io.digitalstate.stix.coo.objects.NetworkTrafficCoo; -import io.digitalstate.stix.validation.contraints.coo.allowedparents.AllowedParents; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.contraints.vocab.Vocab; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import io.digitalstate.stix.vocabulary.vocabularies.NetworkSocketAddressFamilies; -import io.digitalstate.stix.vocabulary.vocabularies.NetworkSocketProtocolFamilies; -import io.digitalstate.stix.vocabulary.vocabularies.NetworkSocketTypes; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.PositiveOrZero; -import java.util.Map; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * socket-ext - *

- * The Network Socket extension specifies a default extension for capturing - * network traffic properties associated with network sockets. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "socket-ext", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Ext", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, passAnnotations = {AllowedParents.class}, depluralize = true) -@JsonSerialize(as = NetworkSocketExtension.class) @JsonDeserialize(builder = NetworkSocketExtension.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({"address_family", "is_blocking", "is_listening", "protocol_family", "options", "socket_type", - "socket_descriptor", "socket_handle" }) -@JsonTypeName("socket-ext") -@AllowedParents({NetworkTrafficCoo.class}) -public interface NetworkSocketExtensionExt extends CyberObservableExtension { - - @JsonProperty("address_family") - @JsonPropertyDescription("Specifies the address family (AF_*) that the socket is configured for.") - @NotNull - @Vocab(NetworkSocketAddressFamilies.class) - String getAddressFamily(); - - @JsonProperty("is_blocking") - @JsonPropertyDescription("Specifies whether the socket is in blocking mode.") - @NotNull - Optional getBlocking(); - - @JsonProperty("is_listening") - @JsonPropertyDescription("Specifies whether the socket is in listening mode.") - @NotNull - Optional getListening(); - - @JsonProperty("protocol_family") - @JsonPropertyDescription("Specifies the protocol family (PF_*) that the socket is configured for.") - Optional<@Vocab(NetworkSocketProtocolFamilies.class) String> getProtocolFamily(); - - //@TODO Should this enforce SO_* ? - @JsonProperty("options") - @JsonPropertyDescription("Specifies any options (SO_*) that may be used by the socket, as a dictionary.") - Map getOptions(); - - @JsonProperty("socket_type") - @JsonPropertyDescription("Specifies the type of the socket.") - Optional<@Vocab(NetworkSocketTypes.class) String> getSocketType(); - - @JsonProperty("socket_descriptor") - @JsonPropertyDescription("Specifies the socket file descriptor value associated with the socket, as a non-negative integer.") - Optional<@PositiveOrZero Long> getSocketDescriptor(); - - @JsonProperty("socket_handle") - @JsonPropertyDescription("Specifies the handle or inode value associated with the socket.") - Optional getSocketHandle(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/extension/types/NtfsFileExtenstionExt.java b/src/main/java/io/digitalstate/stix/coo/extension/types/NtfsFileExtenstionExt.java deleted file mode 100644 index 6a6cd95..0000000 --- a/src/main/java/io/digitalstate/stix/coo/extension/types/NtfsFileExtenstionExt.java +++ /dev/null @@ -1,44 +0,0 @@ -package io.digitalstate.stix.coo.extension.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; -import io.digitalstate.stix.coo.objects.FileCoo; -import io.digitalstate.stix.coo.types.NtfsAlternateDataStreamObj; -import io.digitalstate.stix.validation.contraints.businessrule.BusinessRule; -import io.digitalstate.stix.validation.contraints.coo.allowedparents.AllowedParents; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * The NTFS file extension specifies a default extension for capturing properties specific to the storage of the file on the NTFS file system. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "ntfs-ext", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Ext", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, passAnnotations = {AllowedParents.class}, depluralize = true) -@JsonSerialize(as = NtfsFileExtenstion.class) @JsonDeserialize(builder = NtfsFileExtenstion.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "sid", "alternate_data_streams" }) -@JsonTypeName("ntfs-ext") -@AllowedParents({FileCoo.class}) -@BusinessRule(ifExp = "true", thenExp = "getSid().isPresent() == true || getAlternateDataStreams().isEmpty() == false", errorMessage = "NTFS File Extension MUST contain at least one property from this extension") -public interface NtfsFileExtenstionExt extends CyberObservableExtension { - - @JsonProperty("sid") - @JsonPropertyDescription("Specifies the security ID (SID) value assigned to the file.") - Optional getSid(); - - @JsonProperty("alternate_data_streams") - @JsonPropertyDescription("Specifies a list of NTFS alternate data streams that exist for the file.") - Set getAlternateDataStreams(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/extension/types/PdfFileExtensionExt.java b/src/main/java/io/digitalstate/stix/coo/extension/types/PdfFileExtensionExt.java deleted file mode 100644 index 7018b21..0000000 --- a/src/main/java/io/digitalstate/stix/coo/extension/types/PdfFileExtensionExt.java +++ /dev/null @@ -1,58 +0,0 @@ -package io.digitalstate.stix.coo.extension.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; -import io.digitalstate.stix.coo.objects.FileCoo; -import io.digitalstate.stix.validation.contraints.businessrule.BusinessRule; -import io.digitalstate.stix.validation.contraints.coo.allowedparents.AllowedParents; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import java.util.Map; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; -/** - * The PDF file extension specifies a default extension for capturing properties - * specific to PDF files. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "pdf-ext", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Ext", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, passAnnotations = {AllowedParents.class}, depluralize = true) -@JsonSerialize(as = PdfFileExtension.class) @JsonDeserialize(builder = PdfFileExtension.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "version", "is_optimized", "document_info_dict", "pdfid0", "pdfid1" }) -@JsonTypeName("pdf-ext") -@AllowedParents({FileCoo.class}) -//@TODO review creating a simple method that will do a "at least 1 field is used" so it can be used within the annotation rather than managing duplicate of all field names: -@BusinessRule(ifExp = "true", thenExp = "getVersion().isPresent() == true || isOptimized().isPresent() == true || getDocumentInfoDict().isEmpty() == false || getPdfId0().isPresent() == true || getPdfId1().isPresent() == true", errorMessage = "At least 1 field must be used in PDF Extension.") -public interface PdfFileExtensionExt extends CyberObservableExtension { - - @JsonProperty("version") - @JsonPropertyDescription("Specifies the decimal version number of the Optional from the PDF header that specifies the version of the PDF specification to which the PDF file conforms. E.g., '1.4'.") - Optional getVersion(); - - @JsonProperty("is_optimized") - @JsonPropertyDescription("Specifies whether the PDF file has been optimized.") - @NotNull - Optional isOptimized(); - - @JsonProperty("document_info_dict") - @JsonPropertyDescription("Specifies details of the PDF document information dictionary (DID), which includes properties like the document creation data and producer, as a dictionary.") - Map getDocumentInfoDict(); - - @JsonProperty("pdfid0") - @JsonPropertyDescription("Specifies the first file identifier found for the PDF file.") - Optional getPdfId0(); - - @JsonProperty("pdfid1") - @JsonPropertyDescription("Specifies the second file identifier found for the PDF file.") - Optional getPdfId1(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/extension/types/RasterImageFileExtensionExt.java b/src/main/java/io/digitalstate/stix/coo/extension/types/RasterImageFileExtensionExt.java deleted file mode 100644 index 7b465ae..0000000 --- a/src/main/java/io/digitalstate/stix/coo/extension/types/RasterImageFileExtensionExt.java +++ /dev/null @@ -1,58 +0,0 @@ -package io.digitalstate.stix.coo.extension.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; -import io.digitalstate.stix.coo.objects.FileCoo; -import io.digitalstate.stix.validation.contraints.businessrule.BusinessRule; -import io.digitalstate.stix.validation.contraints.coo.allowedparents.AllowedParents; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import java.util.Map; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * The Raster Image file extension specifies a default extension for capturing - * properties specific to image files. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "raster-image-ext", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Ext", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, passAnnotations = {AllowedParents.class}, depluralize = true) -@JsonSerialize(as = RasterImageFileExtension.class) @JsonDeserialize(builder = RasterImageFileExtension.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "image_height", "image_width", "bits_per_pixel", "image_compression_algorithm", "exif_tags" }) -@JsonTypeName("raster-image-ext") -@AllowedParents({FileCoo.class}) -@BusinessRule(ifExp = "true", thenExp = "getImageHeight().isPresent() == true || getImageWidth().isPresent() == true || getBitsPerPixel().isPresent() == false || getImageCompressionAlgorithm().isPresent() == true || getExifTags().isEmpty() == true", errorMessage = "At least 1 field must be used in Raster Image File Extension.") -public interface RasterImageFileExtensionExt extends CyberObservableExtension { - - //@TODO Spec is missing direction about limits: Value likely needs to be MUST be positive - @JsonProperty("image_height") - @JsonPropertyDescription("Specifies the height of the image in the image file, in pixels.") - Optional getImageHeight(); - - //@TODO Spec is missing direction about limits: Value likely needs to be MUST be positive - @JsonProperty("image_width") - @JsonPropertyDescription("Specifies the width of the image in the image file, in pixels.") - Optional getImageWidth(); - - @JsonProperty("bits_per_pixel") - @JsonPropertyDescription("Specifies the sum of bits used for each color channel in the image in the image file, and thus the total number of pixels used for expressing the color depth of the image.") - Optional getBitsPerPixel(); - - @JsonProperty("image_compression_algorithm") - @JsonPropertyDescription("Specifies the name of the compression algorithm used to compress the image in the image file, if applicable.") - Optional getImageCompressionAlgorithm(); - - @JsonProperty("exif_tags") - @JsonPropertyDescription("Specifies the set of EXIF tags found in the image file, as a dictionary. Each key/value pair in the dictionary represents the name/value of a single EXIF tag.") - Map getExifTags(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/extension/types/TcpExtensionExt.java b/src/main/java/io/digitalstate/stix/coo/extension/types/TcpExtensionExt.java deleted file mode 100644 index f7073a0..0000000 --- a/src/main/java/io/digitalstate/stix/coo/extension/types/TcpExtensionExt.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.digitalstate.stix.coo.extension.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; -import io.digitalstate.stix.coo.objects.NetworkTrafficCoo; -import io.digitalstate.stix.validation.contraints.businessrule.BusinessRule; -import io.digitalstate.stix.validation.contraints.coo.allowedparents.AllowedParents; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.Pattern; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * tcp-ext - *

- * The TCP extension specifies a default extension for capturing network traffic - * properties specific to TCP. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "tcp-ext", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Ext", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, passAnnotations = {AllowedParents.class}, depluralize = true) -@JsonSerialize(as = TcpExtension.class) @JsonDeserialize(builder = TcpExtension.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "src_flags_hex", "dst_flags_hex" }) -@JsonTypeName("tcp-ext") -@AllowedParents({NetworkTrafficCoo.class}) -@BusinessRule(ifExp = "true", thenExp = "getSrcFlagsHex().isPresent() == true || getDstFlagsHex().isPresent() == true", errorMessage = "TCP Extension MUST contain at least one property from this extension") -public interface TcpExtensionExt extends CyberObservableExtension { - - /** - * Specifies the source TCP flags, as the union of all TCP flags observed - * between the start of the traffic (as defined by the start property) and - * the end of the traffic (as defined by the end property). - * - */ - @JsonProperty("src_flags_hex") - @JsonPropertyDescription("Specifies the source TCP flags, as the union of all TCP flags observed between the start of the traffic (as defined by the start property) and the end of the traffic (as defined by the end property). ") - Optional<@Pattern(regexp = "^([a-fA-F0-9]{2})+$") - String> getSrcFlagsHex(); - - /** - * Specifies the destination TCP flags, as the union of all TCP flags - * observed between the start of the traffic (as defined by the start - * property) and the end of the traffic (as defined by the end property). - * - */ - @JsonProperty("dst_flags_hex") - @JsonPropertyDescription("Specifies the destination TCP flags, as the union of all TCP flags observed between the start of the traffic (as defined by the start property) and the end of the traffic (as defined by the end property).") - Optional<@Pattern(regexp = "^([a-fA-F0-9]{2})+$") - String> getDstFlagsHex(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/extension/types/UnixAccountExtensionExt.java b/src/main/java/io/digitalstate/stix/coo/extension/types/UnixAccountExtensionExt.java deleted file mode 100644 index d92fa01..0000000 --- a/src/main/java/io/digitalstate/stix/coo/extension/types/UnixAccountExtensionExt.java +++ /dev/null @@ -1,54 +0,0 @@ -package io.digitalstate.stix.coo.extension.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; -import io.digitalstate.stix.coo.objects.UserAccountCoo; -import io.digitalstate.stix.validation.contraints.businessrule.BusinessRule; -import io.digitalstate.stix.validation.contraints.coo.allowedparents.AllowedParents; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * unix-account-ext - *

- * The UNIX account extension specifies a default extension for capturing the additional information - * for an account on a UNIX system. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "unix-account-ext", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Ext", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, passAnnotations = {AllowedParents.class}, depluralize = true) -@JsonSerialize(as = UnixAccountExtension.class) @JsonDeserialize(builder = UnixAccountExtension.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "gid", "groups", "home_dir", "shell" }) -@JsonTypeName("unix-account-ext") -@AllowedParents({UserAccountCoo.class}) -@BusinessRule(ifExp = "true", thenExp = "getGid().isPresent() == true || getGroups().isEmpty() == false || getHomeDir().isPresent() == true || getShell().isPresent() == true", errorMessage = "At least one field must be provided for Unix Account Extension") -public interface UnixAccountExtensionExt extends CyberObservableExtension { - - @JsonProperty("gid") - @JsonPropertyDescription("Specifies the primary group ID of the account.") - Optional getGid(); - - @JsonProperty("groups") - @JsonPropertyDescription("Specifies a list of names of groups that the account is a member of.") - Set getGroups(); - - @JsonProperty("home_dir") - @JsonPropertyDescription("Specifies the home directory of the account.") - Optional getHomeDir(); - - @JsonProperty("shell") - @JsonPropertyDescription("Specifies the account\u2019s command shell.") - Optional getShell(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/extension/types/WindowsPeBinaryFileExtensionExt.java b/src/main/java/io/digitalstate/stix/coo/extension/types/WindowsPeBinaryFileExtensionExt.java deleted file mode 100644 index d7eb470..0000000 --- a/src/main/java/io/digitalstate/stix/coo/extension/types/WindowsPeBinaryFileExtensionExt.java +++ /dev/null @@ -1,99 +0,0 @@ -package io.digitalstate.stix.coo.extension.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; -import io.digitalstate.stix.coo.objects.FileCoo; -import io.digitalstate.stix.coo.types.WindowsPeOptionalHeaderObj; -import io.digitalstate.stix.coo.types.WindowsPeSectionObj; -import io.digitalstate.stix.validation.contraints.coo.allowedparents.AllowedParents; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.contraints.hashingvocab.HashingVocab; -import io.digitalstate.stix.validation.contraints.vocab.Vocab; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import io.digitalstate.stix.vocabulary.vocabularies.HashingAlgorithms; -import io.digitalstate.stix.vocabulary.vocabularies.WindowsPeBinaryTypes; -import org.hibernate.validator.constraints.Length; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.PositiveOrZero; -import java.time.Instant; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * The Windows PE Binary File extension specifies a default extension for - * capturing properties specific to Windows portable executable (PE) files. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "windows-pebinary-ext", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Ext", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, passAnnotations = {AllowedParents.class}, depluralize = true, depluralizeDictionary = {"hash:hashes"}) -@JsonSerialize(as = WindowsPeBinaryFileExtension.class) @JsonDeserialize(builder = WindowsPeBinaryFileExtension.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "pe_type", "imphash", "machine_hex", "number_of_sections", "time_date_stamp", - "pointer_to_symbol_table_hex", "number_of_symbols", "size_of_optional_header", "characteristics_hex", - "file_header_hashes", "optional_header", "sections", "required" }) -@JsonTypeName("windows-pebinary-ext") -@AllowedParents({FileCoo.class}) -public interface WindowsPeBinaryFileExtensionExt extends CyberObservableExtension { - - @JsonProperty("pe_type") - @JsonPropertyDescription("Specifies the type of the PE binary. Open Vocabulary - windows-pebinary-type-ov") - @NotNull - @Vocab(WindowsPeBinaryTypes.class) - String getPeType(); - - @JsonProperty("imphash") - @JsonPropertyDescription("Specifies the special import hash, or 'imphash', calculated for the PE Binary based on its imported libraries and functions.") - Optional getImphash(); - - @JsonProperty("machine_hex") - @JsonPropertyDescription("Specifies the type of target machine.") - Optional<@Pattern(regexp = "^([a-fA-F0-9]{2})+$") String> getMachineHex(); - - @JsonProperty("number_of_sections") - @JsonPropertyDescription("Specifies the number of sections in the PE binary, as a non-negative integer.") - Optional getNumberOfSections(); - - @JsonProperty("time_date_stamp") - @JsonPropertyDescription("Specifies the time when the PE binary was created. The timestamp value MUST BE precise to the second.") - Optional getTimeDateStamp(); - - @JsonProperty("pointer_to_symbol_table_hex") - @JsonPropertyDescription("Specifies the file offset of the COFF symbol table.") - Optional<@Pattern(regexp = "^([a-fA-F0-9]{2})+$") String> getPointerToSymbolTableHex(); - - @JsonProperty("number_of_symbols") - @JsonPropertyDescription("Specifies the number of entries in the symbol table of the PE binary, as a non-negative integer.") - Optional getNumberOfSymbols(); - - @JsonProperty("size_of_optional_header") - @JsonPropertyDescription("Specifies the size of the optional header of the PE binary.") - Optional<@PositiveOrZero Long> getSizeOfOptionalHeader(); - - @JsonProperty("characteristics_hex") - @JsonPropertyDescription("Specifies the flags that indicate the file\u2019s characteristics.") - Optional<@Pattern(regexp = "^([a-fA-F0-9]{2})+$") String> getCharacteristicsHex(); - - @JsonProperty("file_header_hashes") - @JsonPropertyDescription("Specifies any hashes that were computed for the file header.") - Map<@Length(min = 3, max = 256) @HashingVocab(HashingAlgorithms.class) String, String> getFileHeaderHashes(); - - @JsonProperty("optional_header") - @JsonPropertyDescription("Specifies the PE optional header of the PE binary.") - Optional getOptionalHeader(); - - @JsonProperty("sections") - @JsonPropertyDescription("Specifies metadata about the sections in the PE file.") - Set getSections(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/extension/types/WindowsProcessExtensionExt.java b/src/main/java/io/digitalstate/stix/coo/extension/types/WindowsProcessExtensionExt.java deleted file mode 100644 index d88551e..0000000 --- a/src/main/java/io/digitalstate/stix/coo/extension/types/WindowsProcessExtensionExt.java +++ /dev/null @@ -1,64 +0,0 @@ -package io.digitalstate.stix.coo.extension.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; -import io.digitalstate.stix.coo.objects.ProcessCoo; -import io.digitalstate.stix.validation.contraints.businessrule.BusinessRule; -import io.digitalstate.stix.validation.contraints.coo.allowedparents.AllowedParents; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import java.util.Map; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * The Windows Process extension specifies a default extension for capturing properties specific to Windows processes. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "windows-process-ext", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Ext", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, passAnnotations = {AllowedParents.class}, depluralize = true) -@JsonSerialize(as = WindowsProcessExtension.class) @JsonDeserialize(builder = WindowsProcessExtension.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "aslr_enabled", "dep_enabled", "priority", "owner_sid", "window_title", "startup_info" }) -@JsonTypeName("windows-process-ext") -@AllowedParents({ProcessCoo.class}) -@BusinessRule(ifExp = "isAslrEnabled().orElse(false) == true || isDepEnabled().orElse(false) == true", thenExp = "isDepEnabled().orElse(false) == false || isAslrEnabled().orElse(false) == false", errorMessage = "Dep and ASLR cannot both be enabled") -public interface WindowsProcessExtensionExt extends CyberObservableExtension { - - //@TODO Add business rule for having at least 1 property - - @JsonProperty("aslr_enabled") - @JsonPropertyDescription("Specifies whether Address Space Layout Randomization (ASLR) is enabled for the process.") - @NotNull - Optional isAslrEnabled(); - - @JsonProperty("dep_enabled") - @JsonPropertyDescription("Specifies whether Data Execution Prevention (DEP) is enabled for the process.") - @NotNull - Optional isDepEnabled(); - - @JsonProperty("priority") - @JsonPropertyDescription("Specifies the current priority class of the process in Windows.") - Optional getPriority(); - - @JsonProperty("owner_sid") - @JsonPropertyDescription("Specifies the Security ID (SID) value of the owner of the process.") - Optional getOwnerSid(); - - @JsonProperty("window_title") - @JsonPropertyDescription("Specifies the title of the main window of the process.") - Optional getWindowTitle(); - - @JsonProperty("startup_info") - @JsonPropertyDescription("Specifies the STARTUP_INFO struct used by the process, as a dictionary.") - Map getStartupInfo(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/extension/types/WindowsServiceExtensionExt.java b/src/main/java/io/digitalstate/stix/coo/extension/types/WindowsServiceExtensionExt.java deleted file mode 100644 index ade77b8..0000000 --- a/src/main/java/io/digitalstate/stix/coo/extension/types/WindowsServiceExtensionExt.java +++ /dev/null @@ -1,75 +0,0 @@ -package io.digitalstate.stix.coo.extension.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; -import io.digitalstate.stix.coo.objects.ProcessCoo; -import io.digitalstate.stix.validation.contraints.coo.allowedparents.AllowedParents; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.contraints.vocab.Vocab; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import io.digitalstate.stix.vocabulary.vocabularies.WindowsServiceStartTypes; -import io.digitalstate.stix.vocabulary.vocabularies.WindowsServiceStatuses; -import io.digitalstate.stix.vocabulary.vocabularies.WindowsServiceTypes; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * windows-service-ext - *

- * The Windows Service extension specifies a default extension for capturing - * properties specific to Windows services. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "windows-service-ext", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Ext", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, passAnnotations = {AllowedParents.class}, depluralize = true) -@JsonSerialize(as = WindowsServiceExtension.class) @JsonDeserialize(builder = WindowsServiceExtension.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "service_name", "descriptions", "display_name", "group_name", "start_type", "service_dll_refs", - "service_type", "service_status" }) -@JsonTypeName("windows-service-ext") -@AllowedParents({ProcessCoo.class}) -public interface WindowsServiceExtensionExt extends CyberObservableExtension { - - @JsonProperty("service_name") - @JsonPropertyDescription("Specifies the name of the service.") - @NotBlank - String getServiceName(); - - @JsonProperty("descriptions") - @JsonPropertyDescription("Specifies the descriptions defined for the service.") - Set getDescriptions(); - - @JsonProperty("display_name") - @JsonPropertyDescription("Specifies the displayed name of the service in Windows GUI controls.") - Optional getDisplayName(); - - @JsonProperty("group_name") - @JsonPropertyDescription("Specifies the name of the load ordering group of which the service is a member.") - Optional getGroupName(); - - @JsonProperty("start_type") - @JsonPropertyDescription("Specifies the start options defined for the service. windows-service-start-enum") - Optional<@Vocab(WindowsServiceStartTypes.class) String> getServiceStartType(); - - @JsonProperty("service_dll_refs") - @JsonPropertyDescription("Specifies the DLLs loaded by the service, as a reference to one or more File Objects.") - Set getServiceDllRefs(); - - @JsonProperty("service_type") - @JsonPropertyDescription("Specifies the type of the service. windows-service-enum") - Optional<@Vocab(WindowsServiceTypes.class) String> getServiceType(); - - @JsonProperty("service_status") - @JsonPropertyDescription("Specifies the current status of the service. windows-service-status-enum") - Optional<@Vocab(WindowsServiceStatuses.class) String> getServiceStatus(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/json/extension/CyberObservableExtensionsFieldDeserializer.java b/src/main/java/io/digitalstate/stix/coo/json/extension/CyberObservableExtensionsFieldDeserializer.java deleted file mode 100644 index 9472d7a..0000000 --- a/src/main/java/io/digitalstate/stix/coo/json/extension/CyberObservableExtensionsFieldDeserializer.java +++ /dev/null @@ -1,44 +0,0 @@ -package io.digitalstate.stix.coo.json.extension; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.TreeNode; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import com.fasterxml.jackson.databind.node.ObjectNode; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; - -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; - -public class CyberObservableExtensionsFieldDeserializer extends StdDeserializer> { - - public CyberObservableExtensionsFieldDeserializer() { - this(null); - } - - protected CyberObservableExtensionsFieldDeserializer(Class vc) { - super(vc); - } - - @Override - public Set deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { - Set extensions = new HashSet<>(); - - TreeNode tree = p.readValueAsTree(); - - tree.fieldNames().forEachRemaining(f -> { - ObjectNode node = (ObjectNode) tree.get(f); - node.put("type", f); - try { - CyberObservableExtension extension = node.traverse(p.getCodec()).readValueAs(CyberObservableExtension.class); - extensions.add(extension); - } catch (IOException e) { - throw new IllegalStateException("Cannot deserialize COO extension: ", e); - } - }); - - return extensions; - } -} diff --git a/src/main/java/io/digitalstate/stix/coo/json/extension/CyberObservableExtensionsFieldSerializer.java b/src/main/java/io/digitalstate/stix/coo/json/extension/CyberObservableExtensionsFieldSerializer.java deleted file mode 100644 index adad3c0..0000000 --- a/src/main/java/io/digitalstate/stix/coo/json/extension/CyberObservableExtensionsFieldSerializer.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.digitalstate.stix.coo.json.extension; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; - -import java.io.IOException; -import java.util.Set; - -public class CyberObservableExtensionsFieldSerializer extends StdSerializer> { - - public CyberObservableExtensionsFieldSerializer() { - this(null); - } - - protected CyberObservableExtensionsFieldSerializer(Class> t) { - super(t); - } - - @Override - public boolean isEmpty(SerializerProvider provider, Set value) { - return value.isEmpty(); - } - - @Override - public void serialize(Set value, JsonGenerator gen, SerializerProvider provider) throws IOException { - gen.writeStartObject(); - value.forEach(ext -> { - try { - gen.writeObjectField(ext.getType(), ext); - } catch (IOException e) { - throw new IllegalStateException("Unable to serialize COO Extension:", e); - } - }); - gen.writeEndObject(); - } -} diff --git a/src/main/java/io/digitalstate/stix/coo/json/observables/CyberObservableSetFieldDeserializer.java b/src/main/java/io/digitalstate/stix/coo/json/observables/CyberObservableSetFieldDeserializer.java deleted file mode 100644 index 4f0f1b1..0000000 --- a/src/main/java/io/digitalstate/stix/coo/json/observables/CyberObservableSetFieldDeserializer.java +++ /dev/null @@ -1,46 +0,0 @@ -package io.digitalstate.stix.coo.json.observables; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.TreeNode; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import com.fasterxml.jackson.databind.node.ObjectNode; -import io.digitalstate.stix.coo.CyberObservableObject; - -import java.io.IOException; -import java.util.HashSet; -import java.util.Set; - -public class CyberObservableSetFieldDeserializer extends StdDeserializer> { - - public CyberObservableSetFieldDeserializer() { - this(null); - } - - protected CyberObservableSetFieldDeserializer(Class vc) { - super(vc); - } - - @Override - public Set deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { - Set objects = new HashSet<>(); - TreeNode tree = p.readValueAsTree(); - - tree.fieldNames().forEachRemaining(f->{ - ObjectNode node = (ObjectNode)tree.get(f); - node.put("observable_object_key", f); -// System.out.println(Node.toString()); - try { - CyberObservableObject object = node.traverse(p.getCodec()) - .readValueAs(CyberObservableObject.class); - objects.add(object); - - } catch (IOException e) { - throw new IllegalStateException("Unable to deserialize cyber observable object", e); - } - }); - - return objects; - } -} diff --git a/src/main/java/io/digitalstate/stix/coo/json/observables/CyberObservableSetFieldSerializer.java b/src/main/java/io/digitalstate/stix/coo/json/observables/CyberObservableSetFieldSerializer.java deleted file mode 100644 index 3634d3f..0000000 --- a/src/main/java/io/digitalstate/stix/coo/json/observables/CyberObservableSetFieldSerializer.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.digitalstate.stix.coo.json.observables; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import io.digitalstate.stix.coo.CyberObservableObject; - -import java.io.IOException; -import java.util.Set; - -public class CyberObservableSetFieldSerializer extends StdSerializer> { - - public CyberObservableSetFieldSerializer() { - this(null); - } - - protected CyberObservableSetFieldSerializer(Class> t) { - super(t); - } - - @Override - public boolean isEmpty(SerializerProvider provider, Set value) { - return value.isEmpty(); - } - - @Override - public void serialize(Set values, JsonGenerator gen, SerializerProvider provider) throws IOException { - gen.writeStartObject(); - values.forEach(observableObject -> { - try { - gen.writeObjectField(observableObject.getObservableObjectKey(), observableObject); - } catch (IOException e) { - throw new IllegalStateException("Unable to serialize object", e); - } - }); - gen.writeEndObject(); - } -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/ArtifactCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/ArtifactCoo.java deleted file mode 100644 index 67faac9..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/ArtifactCoo.java +++ /dev/null @@ -1,76 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.validation.contraints.businessrule.BusinessRule; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.contraints.hashingvocab.HashingVocab; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import io.digitalstate.stix.vocabulary.vocabularies.HashingAlgorithms; -import org.hibernate.validator.constraints.Length; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.Pattern; -import java.util.Map; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * artifact - *

- * The Artifact Object permits capturing an array of bytes (8-bits), as a base64-encoded string string, or linking to a file-like payload. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "artifact", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true, depluralizeDictionary = {"hash:hashes"}) -@JsonTypeName("artifact") -@JsonSerialize(as = Artifact.class) @JsonDeserialize(builder = Artifact.Builder.class) -@JsonPropertyOrder({"type", "extensions", "mime_type", "payload_bin", "url", "hashes"}) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@BusinessRule(ifExp = "getUrl().isPresent() == true", thenExp = "getHashes().isEmpty() == false && getPayloadBin().isPresent() == false", errorMessage = "When Url is used, Hashes have at least 1 value, and payload_bin cannot be used.") -@BusinessRule(ifExp = "getPayloadBin().isPresent() == true", thenExp = "getUrl().isPresent() == false && getHashes().isEmpty() == true", errorMessage = "When payload_bin is used, Url and hashes cannot be used.") -public interface ArtifactCoo extends CyberObservableObject { - - /** - * The value of this property MUST be a valid MIME type as specified in the IANA Media Types registry. - * - */ - @JsonProperty("mime_type") - @JsonPropertyDescription("The value of this property MUST be a valid MIME type as specified in the IANA Media Types registry.") - Optional<@Pattern(regexp = "^(application|audio|font|image|message|model|multipart|text|video)/[a-zA-Z0-9.+_-]+") - String> getMimeType(); - - @JsonProperty("payload_bin") - @JsonPropertyDescription("Specifies the binary data contained in the artifact as a base64-encoded string.") - //Removed the @pattern from within the optional until it is clear on the usage and expectation. - //@Pattern(regexp = "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$") - Optional getPayloadBin(); - - /** - * url-regex - *

- * Matches the elements of a URL using a regular expression. Uses Diego Perini's regex from https://gist.github.com/dperini/729294. - * - */ - @JsonProperty("url") - @JsonPropertyDescription("The value of this property MUST be a valid URL that resolves to the unencoded content.") - //@TODO review if the @Url constraint can be used instead. - Optional<@Pattern(regexp = "^(?:(?:https?|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\\.(?:[a-z\u00a1-\uffff]{2,}))\\.?)(?::\\d{2,5})?(?:[/?#]\\S*)?$") - String> getUrl(); - - //@TODO review logic requirements for Redactable on Hash values - /** - * hashes - *

- * This MUST be provided when the url property is present. Optional if payload_bin is present. - */ - @JsonProperty("hashes") - @JsonPropertyDescription("Specifies a dictionary of hashes for the contents of the url or the payload_bin.") - Map<@Length(min = 3, max = 256) @HashingVocab(HashingAlgorithms.class) String, String> getHashes(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/AutonomousSystemCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/AutonomousSystemCoo.java deleted file mode 100644 index e337d43..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/AutonomousSystemCoo.java +++ /dev/null @@ -1,43 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * autonomous-system - *

- * The AS object represents the properties of an Autonomous Systems (AS). - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "autonomous-system", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonTypeName("autonomous-system") -@JsonSerialize(as = AutonomousSystem.class) @JsonDeserialize(builder = AutonomousSystem.Builder.class) -@JsonPropertyOrder({"type", "extensions", "number", "name", "rir"}) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -public interface AutonomousSystemCoo extends CyberObservableObject { - - @JsonProperty("number") - @JsonPropertyDescription("Specifies the number assigned to the AS. Such assignments are typically performed by a Regional Internet Registries (RIR)") - Long getNumber(); - - @JsonProperty("name") - @JsonPropertyDescription("Specifies the name of the AS.") - Optional getName(); - - @JsonProperty("rir") - @JsonPropertyDescription("Specifies the name of the Regional Internet Registry (RIR) that assigned the number to the AS.") - Optional getRir(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/DirectoryCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/DirectoryCoo.java deleted file mode 100644 index 4eaccee..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/DirectoryCoo.java +++ /dev/null @@ -1,64 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.Pattern; -import java.time.Instant; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * directory - *

- * The Directory Object represents the properties common to a file system directory. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "directory", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonTypeName("directory") -@JsonSerialize(as = Directory.class) @JsonDeserialize(builder = Directory.Builder.class) -@JsonPropertyOrder({"type", "extensions", "path", "path_enc", "created", "modified", "accessed", "contains_refs"}) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -public interface DirectoryCoo extends CyberObservableObject { - - @JsonProperty("path") - @JsonPropertyDescription("Specifies the path, as originally observed, to the directory on the file system.") - String getPath(); - - /** - * This value MUST be specified using the corresponding name from the 2013-12-20 revision of the IANA character set registry. - */ - @JsonProperty("path_enc") - @JsonPropertyDescription("Specifies the observed encoding for the path.") - Optional<@Pattern(regexp = "^[a-zA-Z0-9/\\.+_:-]{2,250}$") - String> getPathEnc(); - - @JsonProperty("created") - @JsonPropertyDescription("Specifies the date/time the directory was created.") - Optional getCreated(); - - @JsonProperty("modified") - @JsonPropertyDescription("Specifies the date/time the directory was last written to/modified.") - Optional getModified(); - - @JsonProperty("accessed") - @JsonPropertyDescription("Specifies the date/time the directory was last accessed.") - Optional getAccessed(); - - //@TODO add proper support for contains refs. Must be Set of File or Directory types - @JsonProperty("contains_refs") - @JsonPropertyDescription("Specifies a list of references to other File and/or Directory Objects contained within the directory.") - Set getContainsRefs(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/DomainNameCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/DomainNameCoo.java deleted file mode 100644 index 151881f..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/DomainNameCoo.java +++ /dev/null @@ -1,40 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * domain-name - *

- * The Domain Name represents the properties of a network domain name. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "domain-name", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonTypeName("domain-name") -@JsonSerialize(as = DomainName.class) @JsonDeserialize(builder = DomainName.Builder.class) -@JsonPropertyOrder({"type", "extensions", "value", "resolves_to_refs"}) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -public interface DomainNameCoo extends CyberObservableObject { - - @JsonProperty("value") - @JsonPropertyDescription("Specifies the value of the domain name.") - @NotNull - String getValue(); - - @JsonProperty("resolves_to_refs") - @JsonPropertyDescription("Specifies a list of references to one or more IP addresses or domain names that the domain name resolves to.") - Set getResolvesToRefs(); -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/EmailAddressCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/EmailAddressCoo.java deleted file mode 100644 index 91e9a85..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/EmailAddressCoo.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * email-addr - *

- * The Email Address Object represents a single email address. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "email-addr", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonTypeName("email-addr") -@JsonSerialize(as = EmailAddress.class) @JsonDeserialize(builder = EmailAddress.Builder.class) -@JsonPropertyOrder({"type", "extensions", "value", "display_name", "belongs_to_ref"}) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -public interface EmailAddressCoo extends CyberObservableObject { - - @JsonProperty("value") - @JsonPropertyDescription("Specifies a single email address. This MUST not include the display name.") - @Pattern(regexp="(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$)") - @NotNull - String getValue(); - - @JsonProperty("display_name") - @JsonPropertyDescription("Specifies a single email display name, i.e., the name that is displayed to the human user of a mail application.") - Optional getDisplayName(); - - @JsonProperty("belongs_to_ref") - @JsonPropertyDescription("Specifies the user account that the email address belongs to, as a reference to a User Account Object.") - Optional getBelongsToRef(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/EmailMessageCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/EmailMessageCoo.java deleted file mode 100644 index e6c7a30..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/EmailMessageCoo.java +++ /dev/null @@ -1,98 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.coo.types.MimePartTypeObj; -import io.digitalstate.stix.validation.contraints.businessrule.BusinessRule; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import java.time.Instant; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * The Email Message Object represents an instance of an email message. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "email-message", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonTypeName("email-message") -@JsonSerialize(as = EmailMessage.class) @JsonDeserialize(builder = EmailMessage.Builder.class) -@JsonPropertyOrder({ "type", "extensions", "is_multipart", "date", "content_type", "from_ref", "sender_ref", "to_refs", "cc_refs", "bcc_refs", "subject", - "received_lines", "additional_header_fields", "body", "body_multipart", "raw_email_ref" }) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@BusinessRule(ifExp = "isMultipart() == true", thenExp = "getBody().isPresent() == false", errorMessage = "Body cannot be used if isMultipart equals true") -@BusinessRule(ifExp = "isMultipart() == false", thenExp = "getBodyMultipart().isEmpty() == true", errorMessage = "Body_Multipart cannot be used if isMultipart equals false") -public interface EmailMessageCoo extends CyberObservableObject { - - @JsonProperty("is_multipart") - @JsonPropertyDescription("Indicates whether the email body contains multiple MIME parts.") - @NotNull - Boolean isMultipart(); - - @JsonProperty("date") - @JsonPropertyDescription("Specifies the date/time that the email message was sent.") - Optional getDate(); - - @JsonProperty("content_type") - @JsonPropertyDescription("Specifies the value of the 'Content-Type' header of the email message.") - Optional getContentType(); - - @JsonProperty("from_ref") - @JsonPropertyDescription("Specifies the value of the 'From:' header of the email message.") - Optional getFromRef(); - - @JsonProperty("sender_ref") - @JsonPropertyDescription("Specifies the value of the 'From' field of the email message") - Optional getSenderRef(); - - @JsonProperty("to_refs") - @JsonPropertyDescription("Specifies the mailboxes that are 'To:' recipients of the email message") - Set getToRefs(); - - @JsonProperty("cc_refs") - @JsonPropertyDescription("Specifies the mailboxes that are 'CC:' recipients of the email message") - Set getCcRefs(); - - @JsonProperty("bcc_refs") - @JsonPropertyDescription("Specifies the mailboxes that are 'BCC:' recipients of the email message.") - Set getBccRefs(); - - @JsonProperty("subject") - @JsonPropertyDescription("Specifies the subject of the email message.") - Optional getSubject(); - - @JsonProperty("received_lines") - @JsonPropertyDescription("Specifies one or more Received header fields that may be included in the email headers.") - Set getReceivedLines(); - - //@TODO Should become a Multi-Map in the future https://github.com/oasis-tcs/cti-stix2/issues/138 - @JsonProperty("additional_header_fields") - @JsonPropertyDescription("Specifies any other header fields (except for date, received_lines, content_type, from_ref, sender_ref, to_refs, cc_refs, bcc_refs, and subject) found in the email message, as a dictionary.") - Map getAdditionalHeaderFields(); - - @JsonProperty("body") - @JsonPropertyDescription("Specifies a string containing the email body.") - Optional getBody(); - - @JsonProperty("body_multipart") - @JsonPropertyDescription("Specifies a list of the MIME parts that make up the email body.") - Set getBodyMultipart(); - - @JsonProperty("raw_email_ref") - @JsonPropertyDescription("Specifies the raw binary contents of the email message, including both the headers and body, as a reference to an Artifact Object.") - Optional getRawEmailRef(); - - -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/FileCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/FileCoo.java deleted file mode 100644 index defe256..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/FileCoo.java +++ /dev/null @@ -1,111 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.validation.contraints.businessrule.BusinessRule; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.contraints.hashingvocab.HashingVocab; -import io.digitalstate.stix.validation.contraints.vocab.Vocab; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import io.digitalstate.stix.vocabulary.vocabularies.EncryptionAlgorithms; -import io.digitalstate.stix.vocabulary.vocabularies.HashingAlgorithms; -import org.hibernate.validator.constraints.Length; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Positive; -import java.time.Instant; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * file - *

- * The File Object represents the properties of a file. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "file", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true, depluralizeDictionary = {"hash:hashes"}) -@JsonTypeName("file") -@JsonSerialize(as = File.class) @JsonDeserialize(builder = File.Builder.class) -@JsonPropertyOrder({ "type", "extensions", "hashes", "size", "name", "name_enc", "magic_number_hex", "mime_type", "created", "modified", - "accessed", "parent_directory_ref", "is_encrypted", "encryption_algorithm", "decryption_key" , "contains_refs", "content_ref", }) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@BusinessRule(ifExp = "isEncrypted().orElse(false) == false", thenExp = "getEncryptionAlgorithm().isPresent() == false && getDecryptionKey().isPresent() == false", errorMessage = "Encryption Algorithm and Description Key cannot be used if Encrypted equals false.") -public interface FileCoo extends CyberObservableObject { - - @JsonProperty("hashes") - @JsonPropertyDescription("Specifies a dictionary of hashes for the contents of the file.") - Map<@Length(min = 3, max = 256) @HashingVocab(HashingAlgorithms.class) String, String> getHashes(); - - @JsonProperty("size") - @JsonPropertyDescription("Specifies the size of the file, in bytes, as a non-negative integer.") - Optional<@Positive Long> getSize(); - - @JsonProperty("name") - @JsonPropertyDescription("Specifies the name of the file.") - Optional getName(); - - @JsonProperty("name_enc") - @JsonPropertyDescription("Specifies the observed encoding for the name of the file.") - Optional<@Pattern(regexp = "^[a-zA-Z0-9/\\.+_:-]{2,250}$") - String> getNameEnc(); - - @JsonProperty("magic_number_hex") - @JsonPropertyDescription("Specifies the hexadecimal constant ('magic number') associated with a specific file format that corresponds to the file, if applicable.") - Optional<@Pattern(regexp = "^([a-fA-F0-9]{2})+$") - String> getMagicNumberHex(); - - //@TODO Convert this to a Vocab Validation - @JsonProperty("mime_type") - @JsonPropertyDescription("Specifies the MIME type name specified for the file, e.g., 'application/msword'.") - Optional<@Pattern(regexp = "^(application|audio|font|image|message|model|multipart|text|video)/[a-zA-Z0-9.+_-]+") - String> getMimeType(); - - @JsonProperty("created") - @JsonPropertyDescription("Specifies the date/time the file was created.") - Optional getCreated(); - - @JsonProperty("modified") - @JsonPropertyDescription("Specifies the date/time the file was last written to/modified.") - Optional getModified(); - - @JsonProperty("accessed") - @JsonPropertyDescription("Specifies the date/time the file was last accessed.") - Optional getAccessed(); - - @JsonProperty("parent_directory_ref") - @JsonPropertyDescription("Specifies the parent directory of the file, as a reference to a Directory Object.") - Optional getParentDirectoryRef(); - - @JsonProperty("is_encrypted") - @JsonPropertyDescription("Specifies whether the file is encrypted.") - @NotNull - Optional isEncrypted(); - - @JsonProperty("encryption_algorithm") - @JsonPropertyDescription("Specifies the name of the encryption algorithm used to encrypt the file. Open Vocabulary - encryption-algorithm-ov") - Optional<@Vocab(EncryptionAlgorithms.class) String> getEncryptionAlgorithm(); - - @JsonProperty("decryption_key") - @JsonPropertyDescription("Specifies the decryption key used to decrypt the archive file.") - Optional getDecryptionKey(); - - @JsonProperty("contains_refs") - @JsonPropertyDescription("Specifies a list of references to other Observable Objects contained within the file.") - Set getContainsRefs(); - - @JsonProperty("content_ref") - @JsonPropertyDescription("Specifies the content of the file, represented as an Artifact Object.") - Optional getContentRef(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/Ipv4AddressCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/Ipv4AddressCoo.java deleted file mode 100644 index 45d8a52..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/Ipv4AddressCoo.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * ipv4-addr - *

- * The IPv4 Address Object represents one or more IPv4 addresses expressed using CIDR notation. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "ipv4-addr", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonTypeName("ipv4-addr") -@JsonSerialize(as = Ipv4Address.class) @JsonDeserialize(builder = Ipv4Address.Builder.class) -@JsonPropertyOrder({"type", "extensions", "value", "resolves_to_refs", "belongs_to_refs"}) -public interface Ipv4AddressCoo extends CyberObservableObject { - // TODO Consider using regexp to validate: - // http://blog.markhatton.co.uk/2011/03/15/regular-expressions-for-ip-addresses-cidr-ranges-and-hostnames/ - - /** - * If a given IPv4 Address Object represents a single IPv4 address, the CIDR /32 suffix MAY be omitted. - * (Required) - * - */ - @JsonProperty("value") - @JsonPropertyDescription("Specifies one or more IPv4 addresses expressed using CIDR notation.") - @NotNull - String getValue(); - - /** - * The objects referenced in this list MUST be of type mac-addr. - * - */ - @JsonProperty("resolves_to_refs") - @JsonPropertyDescription("Specifies a list of references to one or more Layer 2 Media Access Control (MAC) addresses that the IPv4 address resolves to.") - Set getResolvesToRefs(); - - /** - * The objects referenced in this list MUST be of type autonomous-system. - * - */ - @JsonProperty("belongs_to_refs") - @JsonPropertyDescription("Specifies a reference to one or more autonomous systems (AS) that the IPv4 address belongs to.") - Set getBelongsToRefs(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/Ipv6AddressCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/Ipv6AddressCoo.java deleted file mode 100644 index 9b5022d..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/Ipv6AddressCoo.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * ipv6-addr - *

- * The IPv6 Address Object represents one or more IPv6 addresses expressed using CIDR notation. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "ipv6-addr", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonTypeName("ipv6-addr") -@JsonSerialize(as = Ipv6Address.class) @JsonDeserialize(builder = Ipv6Address.Builder.class) -@JsonPropertyOrder({"type", "extensions", "value", "resolves_to_refs", "belongs_to_refs"}) -public interface Ipv6AddressCoo extends CyberObservableObject { - // TODO Consider using regexp to validate: - // http://blog.markhatton.co.uk/2011/03/15/regular-expressions-for-ip-addresses-cidr-ranges-and-hostnames/ - - /** - * If a given IPv6 Address Object represents a single IPv6 address, the CIDR /128 suffix MAY be omitted. - * (Required) - * - */ - @JsonProperty("value") - @JsonPropertyDescription("Specifies one or more IPv6 addresses expressed using CIDR notation.") - @NotNull - String getValue(); - - /** - * The objects referenced in this list MUST be of type mac-addr. - * - */ - @JsonProperty("resolves_to_refs") - @JsonPropertyDescription("Specifies a list of references to one or more Layer 2 Media Access Control (MAC) addresses that the IPv4 address resolves to.") - Set getResolvesToRefs(); - - /** - * The objects referenced in this list MUST be of type autonomous-system. - * - */ - @JsonProperty("belongs_to_refs") - @JsonPropertyDescription("Specifies a reference to one or more autonomous systems (AS) that the IPv4 address belongs to.") - Set getBelongsToRefs(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/MacAddressCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/MacAddressCoo.java deleted file mode 100644 index 50816f5..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/MacAddressCoo.java +++ /dev/null @@ -1,44 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * mac-addr - *

- * The MAC Address Object represents a single Media Access Control (MAC) address. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "mac-addr", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonTypeName("mac-addr") -@JsonSerialize(as = MacAddress.class) @JsonDeserialize(builder = MacAddress.Builder.class) -@JsonPropertyOrder({"type", "extensions", "value"}) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -public interface MacAddressCoo extends CyberObservableObject { - - /** - * The MAC address value MUST be represented as a single colon-delimited, lowercase MAC-48 address, - * which MUST include leading zeros for each octet. - * (Required) - * - */ - @JsonProperty("value") - @JsonPropertyDescription("Specifies one or more mac addresses expressed using CIDR notation.") - @Pattern(regexp="^([0-9a-f]{2}[:]){5}([0-9a-f]{2})$") - @NotNull - String getValue(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/MutexCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/MutexCoo.java deleted file mode 100644 index 10f0df0..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/MutexCoo.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * mutex - *

- * The Mutex Object represents the properties of a mutual exclusion (mutex) object. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "mutex", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonTypeName("mutex") -@JsonSerialize(as = Mutex.class) @JsonDeserialize(builder = Mutex.Builder.class) -@JsonPropertyOrder({"type", "extensions", "name"}) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -public interface MutexCoo extends CyberObservableObject { - - @JsonProperty("name") - @JsonPropertyDescription("Specifies the name of the mutex object.") - @NotNull - String getName(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/NetworkTrafficCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/NetworkTrafficCoo.java deleted file mode 100644 index d283a0d..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/NetworkTrafficCoo.java +++ /dev/null @@ -1,140 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.hibernate.validator.constraints.Range; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import java.time.Instant; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - - -/** - * network-traffic - *

- * The Network Traffic Object represents arbitrary network traffic that - * originates from a source and is addressed to a destination. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "network-traffic", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = NetworkTraffic.class) @JsonDeserialize(builder = NetworkTraffic.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonTypeName("network-traffic") -@JsonPropertyOrder({ "type", "extensions", "start", "end", "src_ref", "dst_ref", "src_port", "dst_port", "protocols", "src_byte_count", - "dst_byte_count", "src_packets", "dst_packets", "ipfix", "src_payload_ref", "dst_payload_ref", - "encapsulates_refs", "encapsulated_by_ref" }) -public interface NetworkTrafficCoo extends CyberObservableObject { - - @JsonProperty("start") - @JsonPropertyDescription("Specifies the date/time the network traffic was initiated, if known.") - Optional getStart(); - - @JsonProperty("end") - @JsonPropertyDescription("Specifies the date/time the network traffic ended, if known.") - Optional getEnd(); - - @JsonProperty("is_active") - @JsonPropertyDescription("Indicates whether the network traffic is still ongoing.") - @NotNull - Optional isActive(); - - /* - * Must be of type ipv4-addr, ipv6-addr, mac-addr, or domain-name - */ - @JsonProperty("src_ref") - @JsonPropertyDescription("Specifies the source of the network traffic, as a reference to one or more Observable Objects.") - Optional getSrcRef(); - - /* - * Must be of type ipv4-addr, ipv6-addr, mac-addr, or domain-name - */ - @JsonProperty("dst_ref") - @JsonPropertyDescription("Specifies the destination of the network traffic, as a reference to one or more Observable Objects.") - Optional getDstRef(); - - @JsonProperty("src_port") - @JsonPropertyDescription("Specifies the source port used in the network traffic, as an integer. The port value MUST be in the range of 0 - 65535.") - Optional<@Range(min = 0, max = 65535 ) Integer> getSrcPort(); - - @JsonProperty("dst_port") - @JsonPropertyDescription("Specifies the destination port used in the network traffic, as an integer. The port value MUST be in the range of 0 - 65535.") - Optional<@Range(min = 0, max = 65535) Integer> getDstPort(); - - /* - * Specifies the protocols observed in the network traffic, along with their - * corresponding state. Protocols MUST be listed in low to high order, from outer to inner in terms of packet encapsulation. - * That is, the protocols in the outer level of the packet, such as IP, MUST be listed first. - * The protocol names SHOULD come from the service names defined in the Service Name column of th - * IANA Service Name and Port Number Registry - * - */ - @JsonProperty("protocols") - @JsonPropertyDescription("Specifies the protocols observed in the network traffic, along with their corresponding state.") - @NotNull - Set getProtocols(); - - @JsonProperty("src_byte_count") - @JsonPropertyDescription("Specifies the number of bytes sent from the source to the destination.") - Optional getSrcByteCount(); - - @JsonProperty("dst_byte_count") - @JsonPropertyDescription("Specifies the number of bytes sent from the destination to the source.") - Optional getDstByteCount(); - - @JsonProperty("src_packets") - @JsonPropertyDescription("Specifies the number of packets sent from the source to the destination.") - Optional getSrcPackets(); - - @JsonProperty("dst_packets") - @JsonPropertyDescription("Specifies the number of packets sent destination to the source.") - Optional getDstPackets(); - - /* - * Objects much be Integers or Strings - */ - @JsonProperty("ipfix") - @JsonPropertyDescription("Specifies any IP Flow Information Export [IPFIX] data for the traffic, as a dictionary.") - Map getIpFix(); - - /* - * Must be of type artifact - */ - @JsonProperty("src_payload_ref") - @JsonPropertyDescription("Specifies the bytes sent from the source to the destination.") - Optional getSrcPayloadRef(); - - /* - * Must be of type artifact - */ - @JsonProperty("dst_payload_ref") - @JsonPropertyDescription("Specifies the bytes sent from the source to the destination.") - Optional getDstPayloadRef(); - - /* - * Must be of type network-traffic - */ - @JsonProperty("encapsulates_refs") - @JsonPropertyDescription("Links to other network-traffic objects encapsulated by a network-traffic.") - Set getEncapsulatesRefs(); - - /* - * Must be of type network-traffic - */ - @JsonProperty("encapsulated_by_ref") - @JsonPropertyDescription("Links to another network-traffic object which encapsulates this object.") - Optional getEncapsulatedByRef(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/ProcessCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/ProcessCoo.java deleted file mode 100644 index ec81bcd..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/ProcessCoo.java +++ /dev/null @@ -1,96 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.validation.contraints.businessrule.BusinessRule; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import java.time.Instant; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * process - *

- * The Process Object represents common properties of an instance of a computer - * program as executed on an operating system. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "process", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = Process.class) @JsonDeserialize(builder = Process.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonTypeName("process") -@JsonPropertyOrder({ "type", "extensions", "is_hidden", "pid", "name", "created", "cwd", "arguments", "command_line", - "environment_variables", "opened_connection_refs", "creator_user_ref", "binary_ref", "parent_ref", - "child_refs" }) -@BusinessRule(ifExp = "true", thenExp = "getExtensions().isEmpty() == false || isHidden().isPresent() == true || getPid().isPresent() == true || getName().isPresent() == true || getCreated().isPresent() == true || getCwd().isPresent() == true || getArguments().isEmpty() == false || getCommandLine().isPresent() == true || getEnvironmentVariables().isEmpty() == false || getOpenedConnectionRefs().isEmpty() == false || getCreatorUserRef().isPresent() == true || getBinaryRef().isPresent() == true || getParentRef().isPresent() == true || getChildRefs().isEmpty() == false", errorMessage = "A Process Object MUST contain at least one property (other than type) from this object (or one of its extensions).") -public interface ProcessCoo extends CyberObservableObject { - - @JsonProperty("is_hidden") - @JsonPropertyDescription("Specifies whether the process is hidden.") - @NotNull - Optional isHidden(); - - @JsonProperty("pid") - @JsonPropertyDescription("Specifies the Process ID, or PID, of the process.") - Optional getPid(); - - @JsonProperty("name") - @JsonPropertyDescription("Specifies the name of the process.") - Optional getName(); - - @JsonProperty("created") - @JsonPropertyDescription("Specifies the date/time at which the process was created.") - Optional getCreated(); - - @JsonProperty("cwd") - @JsonPropertyDescription("Specifies the current working directory of the process.") - Optional getCwd(); - - //@TODO need better clarification in the STIX SPEC about if this should be a SET or LIST. Are duplicate arguments allowed? - @JsonProperty("arguments") - @JsonPropertyDescription("Specifies the list of arguments used in executing the process.") - List getArguments(); - - @JsonProperty("command_line") - @JsonPropertyDescription("Specifies the full command line used in executing the process, including the process name (depending on the operating system).") - Optional getCommandLine(); - - @JsonProperty("environment_variables") - @JsonPropertyDescription("Specifies the list of environment variables associated with the process as a dictionary.") - Map getEnvironmentVariables(); - - @JsonProperty("opened_connection_refs") - @JsonPropertyDescription("Specifies the list of network connections opened by the process, as a reference to one or more Network Traffic Objects.") - Set getOpenedConnectionRefs(); - - @JsonProperty("creator_user_ref") - @JsonPropertyDescription("Specifies the user that created the process, as a reference to a User Account Object.") - Optional getCreatorUserRef(); - - @JsonProperty("binary_ref") - @JsonPropertyDescription("Specifies the executable binary that was executed as the process, as a reference to a File Object.") - Optional getBinaryRef(); - - @JsonProperty("parent_ref") - @JsonPropertyDescription("Specifies the other process that spawned (i.e. is the parent of) this one, as represented by a Process Object.") - Optional getParentRef(); - - @JsonProperty("child_refs") - @JsonPropertyDescription("Specifies the other processes that were spawned by (i.e. children of) this process, as a reference to one or more other Process Objects.") - Set getChildRefs(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/SoftwareCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/SoftwareCoo.java deleted file mode 100644 index 6936b75..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/SoftwareCoo.java +++ /dev/null @@ -1,65 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * software - *

- * The Software Object represents high-level properties associated with software, including software products. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "software", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = Software.class) @JsonDeserialize(builder = Software.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonTypeName("software") -@JsonPropertyOrder({ - "type", "extensions", "cpe", "languages", "vendor", "version" }) -public interface SoftwareCoo extends CyberObservableObject { - - @JsonProperty("name") - @JsonPropertyDescription("Specifies the name of the software.") - @NotNull - String getName(); - - /** - * TODO The value for this property MUST be a CPE v2.3 entry from the official NVD CPE Dictionary. - * regex pattern = "^cpe:2\\.3:[aho](?::(?:[a-zA-Z0-9!\"#$%&'()*+,\\\\-_.\/();<=>?@\\[\\]^`{|}~]|\\:)+){10}$" - * Is not valid for the @Pattern annotation (invalid escape chars) - * Remove @Pattern(regexp="^cpe:2\\.3:[aho]") until working solution is provided - */ - @JsonProperty("cpe") - @JsonPropertyDescription("Specifies the Common Platform Enumeration (CPE) entry for the software, if available.") - Optional getCpe(); - - /** - * TODO The value of each list member MUST be an ISO 639-2 language code. - */ - @JsonProperty("languages") - @JsonPropertyDescription("Specifies the languages supported by the software.") - Set<@Pattern(regexp="^[a-z]{3}$") String> getLanguages(); - - @JsonProperty("vendor") - @JsonPropertyDescription("Specifies the name of the vendor of the software.") - Optional getVendor(); - - @JsonProperty("version") - @JsonPropertyDescription("Specifies the version of the software.") - Optional getVersion(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/UrlCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/UrlCoo.java deleted file mode 100644 index 3be6fdc..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/UrlCoo.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * url - *

- * The URL Object represents the properties of a uniform resource locator (URL). - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "url", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonTypeName("url") -@JsonSerialize(as = Url.class) @JsonDeserialize(builder = Url.Builder.class) -@JsonPropertyOrder({"type", "extensions", "value"}) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -public interface UrlCoo extends CyberObservableObject { - - /** - * The value of this property MUST conform to [RFC3986], more specifically section 1.1.3 - * with reference to the definition for "Uniform Resource Locator" - * (Required) - * - */ - //@TODO can this be changed from @Pattern to @URL? - @JsonProperty("value") - @JsonPropertyDescription("Specifies the value of the URL.") - @Pattern(regexp="^([a-zA-Z][a-zA-Z0-9+.-]*):(?:\\/\\/((?:(?=((?:[a-zA-Z0-9-._~!$&'()*+,;=:]|%[0-9a-fA-F]{2})*))(\\3)@)?(?=((?:\\[?(?:::[a-fA-F0-9]+(?::[a-fA-F0-9]+)?|(?:[a-fA-F0-9]+:)+(?::[a-fA-F0-9]+)+|(?:[a-fA-F0-9]+:)+(?::|(?:[a-fA-F0-9]+:?)*))\\]?)|(?:[a-zA-Z0-9-._~!$&'()*+,;=]|%[0-9a-fA-F]{2})*))\\5(?::(?=(\\d*))\\6)?)(\\/(?=((?:[a-zA-Z0-9-._~!$&'()*+,;=:@\\/]|%[0-9a-fA-F]{2})*))\\8)?|(\\/?(?!\\/)(?=((?:[a-zA-Z0-9-._~!$&'()*+,;=:@\\/]|%[0-9a-fA-F]{2})*))\\10)?)(?:\\?(?=((?:[a-zA-Z0-9-._~!$&'()*+,;=:@\\/?]|%[0-9a-fA-F]{2})*))\\11)?(?:#(?=((?:[a-zA-Z0-9-._~!$&'()*+,;=:@\\/?]|%[0-9a-fA-F]{2})*))\\12)?$") - @NotNull - String getValue(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/UserAccountCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/UserAccountCoo.java deleted file mode 100644 index 5586cde..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/UserAccountCoo.java +++ /dev/null @@ -1,97 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.contraints.vocab.Vocab; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import io.digitalstate.stix.vocabulary.vocabularies.AccountTypes; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import java.time.Instant; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * user-account - *

- * The User Account Object represents an instance of any type of user account, - * including but not limited to operating system, device, messaging service, and - * social media platform accounts. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "user-account", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = UserAccount.class) @JsonDeserialize(builder = UserAccount.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonTypeName("user-account") -@JsonPropertyOrder({ "type", "extensions","user_id", "account_login", "account_type", "display_name", - "is_service_account", "is_privileged", "can_escalate_privs", "is_disabled", "account_created", - "account_expires", "password_last_changed", "account_first_login", "account_last_login" }) -public interface UserAccountCoo extends CyberObservableObject { - - @JsonProperty("user_id") - @JsonPropertyDescription("Specifies the identifier of the account.") - @NotNull - String getUserId(); - - @JsonProperty("account_login") - @JsonPropertyDescription("Specifies the account login string, used in cases where the user_id property specifies something other than what a user would type when they login.") - Optional getAccountLogin(); - - @JsonProperty("account_type") - @JsonPropertyDescription("Specifies the type of the account. This is an open vocabulary and values SHOULD come from the account-type-ov vocabulary.") - Optional<@Vocab(AccountTypes.class) String> getAccountType(); - - @JsonProperty("display_name") - @JsonPropertyDescription("Specifies the display name of the account, to be shown in user interfaces, if applicable.") - Optional getDisplayName(); - - @JsonProperty("is_service_account") - @JsonPropertyDescription("Indicates that the account is associated with a network service or system process (daemon), not a specific individual.") - @NotNull - Optional isServiceAccount(); - - @JsonProperty("is_privileged") - @JsonPropertyDescription("Specifies that the account has elevated privileges (i.e., in the case of root on Unix or the Windows Administrator account).") - @NotNull - Optional isPrivileged(); - - @JsonProperty("can_escalate_privs") - @JsonPropertyDescription("Specifies that the account has the ability to escalate privileges (i.e., in the case of sudo on Unix or a Windows Domain Admin account).") - @NotNull - Optional isCanEscalatePrivs(); - - @JsonProperty("is_disabled") - @JsonPropertyDescription("Specifies if the account is disabled.") - @NotNull - Optional isDisabled(); - - @JsonProperty("account_created") - @JsonPropertyDescription("Specifies when the account was created.") - Optional getAccountCreated(); - - @JsonProperty("account_expires") - @JsonPropertyDescription("Specifies the expiration date of the account.") - Optional getAccountExpires(); - - @JsonProperty("password_last_changed") - @JsonPropertyDescription("Specifies when the account password was last changed.") - Optional getPasswordLastChanged(); - - @JsonProperty("account_first_login") - @JsonPropertyDescription("Specifies when the account was first accessed.") - Optional getAccountFirstLogin(); - - @JsonProperty("account_last_login") - @JsonPropertyDescription("Specifies when the account was last accessed.") - Optional getAccountLastLogin(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/WindowsRegistryKeyCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/WindowsRegistryKeyCoo.java deleted file mode 100644 index 49017a9..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/WindowsRegistryKeyCoo.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.coo.types.WindowsRegistryValueObj; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import java.time.Instant; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * windows-registry-key - *

- * The Registry Key Object represents the properties of a Windows registry key. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "windows-registry-key", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = WindowsRegistryKey.class) @JsonDeserialize(builder = WindowsRegistryKey.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "type", "key", "values", "modified", "creator_user_ref", "number_of_subkeys", "extensions" }) -@JsonTypeName("windows-registry-key") -public interface WindowsRegistryKeyCoo extends CyberObservableObject { - - @JsonProperty("key") - @JsonPropertyDescription("Specifies the full registry key including the hive.") - @Pattern(regexp = "^HKEY_LOCAL_MACHINE|hkey_local_machine|HKEY_CURRENT_USER|hkey_current_user|HKEY_CLASSES_ROOT|hkey_classes_root|HKEY_CURRENT_CONFIG|hkey_current_config|HKEY_PERFORMANCE_DATA|hkey_performance_data|HKEY_USERS|hkey_users|HKEY_DYN_DATA") - @NotNull - String getKey(); - - @JsonProperty("values") - @JsonPropertyDescription("Specifies the values found under the registry key.") - Set getValues(); - - @JsonProperty("modified") - @JsonPropertyDescription("Specifies the last date/time that the registry key was modified.") - Optional getModified(); - - //@TODO Must be of type user-account - @JsonProperty("creator_user_ref") - @JsonPropertyDescription("Specifies a reference to a user account, represented as a User Account Object, that created the registry key.") - Optional getCreatorUserRef(); - - @JsonProperty("number_of_subkeys") - @JsonPropertyDescription("Specifies the number of subkeys contained under the registry key.") - Optional getNumberOfSubkeys(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/objects/X509CertificateCoo.java b/src/main/java/io/digitalstate/stix/coo/objects/X509CertificateCoo.java deleted file mode 100644 index ed9672c..0000000 --- a/src/main/java/io/digitalstate/stix/coo/objects/X509CertificateCoo.java +++ /dev/null @@ -1,97 +0,0 @@ -package io.digitalstate.stix.coo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.coo.types.X509v3ExtensionsObj; -import io.digitalstate.stix.validation.contraints.businessrule.BusinessRule; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.contraints.hashingvocab.HashingVocab; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import io.digitalstate.stix.vocabulary.vocabularies.HashingAlgorithms; -import org.hibernate.validator.constraints.Length; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import java.time.Instant; -import java.util.Map; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * x509-certificate - *

- * The X509 Certificate Object represents the properties of an X.509 certificate. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "x509-certificate", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Coo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true, depluralizeDictionary = {"hash:hashes"}) -@JsonTypeName("x509-certificate") -@JsonSerialize(as = X509Certificate.class) @JsonDeserialize(builder = X509Certificate.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "type", "extensions", "is_self_signed", "hashes", "version", "serial_number", - "signature_algorithm", "issuer", "validity_not_before", "validity_not_after", - "subject", "subject_public_key_algorithm", "subject_public_key_modulus", - "subject_public_key_exponent", "x509_v3_extensions" -}) -//@TODO refactor BusinessRule annotation with custom emthod that looks up every field and does a check if there is a value -@BusinessRule(ifExp = "true", thenExp = "isSelfSigned().isPresent() == true || getHashes().isEmpty() == false || getVersion().isPresent() == true || getSerialNumber().isPresent() == true || getSignatureAlgorithm().isPresent() == true || getIssuer().isPresent() == true || getValidityNotBefore().isPresent() == true || getValidityNotAfter().isPresent() == true || getSubject().isPresent() == true || getSubjectPublicKeyAlgorithm().isPresent() == true || getSubjectPublicKeyModulus().isPresent() == true || getSubjectPublicKeyExponent().isPresent() == true || getX509V3Extensions().isPresent() == true", errorMessage = "At least 1 property must be provided") -public interface X509CertificateCoo extends CyberObservableObject { - - @JsonProperty("is_self_signed") - @JsonPropertyDescription("Specifies whether the certificate is self-signed, i.e., whether it is signed by the same entity whose identity it certifies.") - Optional isSelfSigned(); - - @JsonProperty("hashes") - @JsonPropertyDescription("Specifies any hashes that were calculated for the entire contents of the certificate.") - Map<@Length(min = 3, max = 256) @HashingVocab(HashingAlgorithms.class) String, String> getHashes(); - - @JsonProperty("version") - @JsonPropertyDescription("Specifies the version of the encoded certificate.") - Optional getVersion(); - - @JsonProperty("serial_number") - @JsonPropertyDescription("Specifies the unique identifier for the certificate, as issued by a specific Certificate Authority.") - Optional getSerialNumber(); - - @JsonProperty("signature_algorithm") - @JsonPropertyDescription("Specifies the name of the algorithm used to sign the certificate.") - Optional getSignatureAlgorithm(); - - @JsonProperty("issuer") - @JsonPropertyDescription("Specifies the name of the Certificate Authority that issued the certificate.") - Optional getIssuer(); - - @JsonProperty("validity_not_before") - @JsonPropertyDescription("Specifies the date on which the certificate validity period begins.") - Optional getValidityNotBefore(); - - @JsonProperty("validity_not_after") - @JsonPropertyDescription("Specifies the date on which the certificate validity period ends.") - Optional getValidityNotAfter(); - - @JsonProperty("subject") - @JsonPropertyDescription("Specifies the name of the entity associated with the public key stored in the subject public key field of the certificate.") - Optional getSubject(); - - @JsonProperty("subject_public_key_algorithm") - @JsonPropertyDescription("Specifies the name of the algorithm with which to encrypt data being sent to the subject.") - Optional getSubjectPublicKeyAlgorithm(); - - @JsonProperty("subject_public_key_modulus") - @JsonPropertyDescription("Specifies the modulus portion of the subject\u2019s public RSA key.") - Optional getSubjectPublicKeyModulus(); - - @JsonProperty("subject_public_key_exponent") - @JsonPropertyDescription("Specifies the exponent portion of the subject\u2019s public RSA key, as an integer.") - Optional getSubjectPublicKeyExponent(); - - @JsonProperty("x509_v3_extensions") - @JsonPropertyDescription("Specifies any standard X.509 v3 extensions that may be used in the certificate.") - Optional getX509V3Extensions(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/types/MimePartTypeObj.java b/src/main/java/io/digitalstate/stix/coo/types/MimePartTypeObj.java deleted file mode 100644 index 085f7ca..0000000 --- a/src/main/java/io/digitalstate/stix/coo/types/MimePartTypeObj.java +++ /dev/null @@ -1,56 +0,0 @@ -package io.digitalstate.stix.coo.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixCustomProperties; -import io.digitalstate.stix.validation.GenericValidation; -import io.digitalstate.stix.validation.contraints.businessrule.BusinessRule; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import java.io.Serializable; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * Specifies a component of a multi-part email body. - * - */ -@Value.Immutable @Serial.Version(1L) -@Value.Style(typeAbstract="*Obj", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = MimePartType.class) @JsonDeserialize(builder = MimePartType.Builder.class) -@JsonPropertyOrder({"body", "body_raw_ref", "content_type", "content_disposition"}) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@BusinessRule(ifExp = "true", thenExp = "getBody().isPresent() == true || getBodyRawRef().isPresent() == true", errorMessage = "One of body OR body_raw_ref MUST be included.") -public interface MimePartTypeObj extends GenericValidation, StixCustomProperties, Serializable { - - /** - * Contents of body MUST be decoded to Unicode. - */ - @JsonProperty("body") - @JsonPropertyDescription("Specifies the contents of the MIME part if the content_type is not provided OR starts with text/") - Optional getBody(); - - /** - * The object referenced in this property MUST be of type artifact or file. - * For use cases where conveying the actual data contained in the MIME part is of primary importance, artifact SHOULD be used. - * Otherwise, for use cases where conveying metadata about the file-like properties of the MIME part is of primary importance, file SHOULD be used. - */ - @JsonProperty("body_raw_ref") - @JsonPropertyDescription("Specifies the contents of non-textual MIME parts, that is those whose content_type does not start with text/") - Optional getBodyRawRef(); - - /** - * Any additional “Content-Type” header field parameters such as charset SHOULD be included in this property. - */ - @JsonProperty("content_type") - @JsonPropertyDescription("Specifies the value of the 'Content-Type' header field of the MIME part.") - Optional getContentType(); - - @JsonProperty("content_disposition") - @JsonPropertyDescription("Specifies the value of the 'Content-Disposition' header field of the MIME part.") - Optional getContentDisposition(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/types/NtfsAlternateDataStreamObj.java b/src/main/java/io/digitalstate/stix/coo/types/NtfsAlternateDataStreamObj.java deleted file mode 100644 index fbb3894..0000000 --- a/src/main/java/io/digitalstate/stix/coo/types/NtfsAlternateDataStreamObj.java +++ /dev/null @@ -1,48 +0,0 @@ -package io.digitalstate.stix.coo.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixCustomProperties; -import io.digitalstate.stix.validation.GenericValidation; -import io.digitalstate.stix.validation.contraints.hashingvocab.HashingVocab; -import io.digitalstate.stix.vocabulary.vocabularies.HashingAlgorithms; -import org.hibernate.validator.constraints.Length; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.PositiveOrZero; -import java.io.Serializable; -import java.util.Map; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * The Alternate Data Stream type represents an NTFS alternate data stream. - * - */ -@Value.Immutable @Serial.Version(1L) -//@DefaultTypeValue(value = "alternate-data-stream-type", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Obj", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true, depluralizeDictionary = {"hash:hashes"}) -@JsonSerialize(as = NtfsAlternateDataStream.class) @JsonDeserialize(builder = NtfsAlternateDataStream.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "name", "hashes", "size" }) -//@JsonTypeName("alternate-data-stream-type") -public interface NtfsAlternateDataStreamObj extends GenericValidation, StixCustomProperties, Serializable { - - @JsonProperty("name") - @JsonPropertyDescription("Specifies the name of the alternate data stream.") - @NotNull - String getName(); - - @JsonProperty("hashes") - @JsonPropertyDescription("Specifies a dictionary of hashes for the data contained in the alternate data stream.") - Map<@Length(min = 3, max = 256) @HashingVocab(HashingAlgorithms.class) String, String> getHashes(); - - @JsonProperty("size") - @JsonPropertyDescription("Specifies the size of the alternate data stream, in bytes, as a non-negative integer.") - Optional<@PositiveOrZero Long> getSize(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/types/WindowsPeOptionalHeaderObj.java b/src/main/java/io/digitalstate/stix/coo/types/WindowsPeOptionalHeaderObj.java deleted file mode 100644 index 3ecc6f7..0000000 --- a/src/main/java/io/digitalstate/stix/coo/types/WindowsPeOptionalHeaderObj.java +++ /dev/null @@ -1,170 +0,0 @@ -package io.digitalstate.stix.coo.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixCustomProperties; -import io.digitalstate.stix.validation.GenericValidation; -import io.digitalstate.stix.validation.contraints.businessrule.BusinessRule; -import io.digitalstate.stix.validation.contraints.hashingvocab.HashingVocab; -import io.digitalstate.stix.vocabulary.vocabularies.HashingAlgorithms; -import org.hibernate.validator.constraints.Length; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.Pattern; -import javax.validation.constraints.PositiveOrZero; -import java.io.Serializable; -import java.util.Map; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - - -/** - * The Windows PE Optional Header type represents the properties of the PE - * optional header. - * - */ -@Value.Immutable @Serial.Version(1L) -//@DefaultTypeValue(value = "windows-pe-optional-header-type", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Obj", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true, depluralizeDictionary = {"hash:hashes"}) -@JsonSerialize(as = WindowsPeOptionalHeader.class) @JsonDeserialize(builder = WindowsPeOptionalHeader.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "magic_hex", "major_linker_version", "minor_linker_version", "size_of_code", - "size_of_initialized_data", "size_of_uninitialized_data", "address_of_entry_point", "base_of_code", - "base_of_data", "image_base", "section_alignment", "file_alignment", "major_os_version", "minor_os_version", - "major_image_version", "minor_image_version", "major_subsystem_version", "minor_subsystem_version", - "win32_version_value_hex", "size_of_image", "size_of_headers", "checksum_hex", "subsystem_hex", - "dll_characteristics_hex", "size_of_stack_reserve", "size_of_stack_commit", "size_of_heap_reserve", - "size_of_heap_commit", "loader_flags_hex", "number_of_rva_and_sizes", "hashes" }) -//@JsonTypeName("windows-pe-optional-header-type") -@BusinessRule(ifExp = "true", thenExp = "getMagicHex().isPresent() == true || getMajorLinkerVersion().isPresent() == true || getMinorLinkerVersion().isPresent() == true || getSizeOfCode().isPresent() == true || getSizeOfInitializedData().isPresent() == true || getSizeOfUninitializedData().isPresent() == true || getAddressOfEntryPoint().isPresent() == true || getBaseOfCode().isPresent() == true || getBaseOfData().isPresent() == true || getImageBase().isPresent() == true || getSectionAlignment().isPresent() == true || getFileAlignment().isPresent() == true || getMajorOsVersion().isPresent() == true || getMinorOsVersion().isPresent() == true || getMajorImageVersion().isPresent() == true || getMinorImageVersion().isPresent() == true || getMajorSubsystemVersion().isPresent() == true || getMinorSubsystemVersion().isPresent() == true || getWin32VersionValueHex().isPresent() == true || getSizeOfImage().isPresent() == true || getSizeOfHeaders().isPresent() == true || getChecksumHex().isPresent() == true || getSubsystemHex().isPresent() == true || getDllCharacteristicsHex().isPresent() == true || getSizeOfStackReserve().isPresent() == true || getSizeOfStackCommit().isPresent() == true || getSizeOfHeapReserve().isPresent() == true || getSizeOfHeapCommit().isPresent() == true || getLoaderFlagsHex().isPresent() == true || getNumberOfRvaAndSizes().isPresent() == true || getHashes().isEmpty() == true", errorMessage = "At least 1 field must be used in Windows Pe Extension Optional Header Object.") -public interface WindowsPeOptionalHeaderObj extends GenericValidation, StixCustomProperties, Serializable { -//@TODO Add GITHUB issue that says the requirement for atleast 1 field to be present - - @JsonProperty("magic_hex") - @JsonPropertyDescription("Specifies the unsigned Optional that indicates the type of the PE binary.") - Optional<@Pattern(regexp = "^([a-fA-F0-9]{2})+$") String> getMagicHex(); - - @JsonProperty("major_linker_version") - @JsonPropertyDescription("Specifies the linker major version number.") - Optional getMajorLinkerVersion(); - - @JsonProperty("minor_linker_version") - @JsonPropertyDescription("Specifies the linker minor version number.") - Optional getMinorLinkerVersion(); - - @JsonProperty("size_of_code") - @JsonPropertyDescription("Specifies the size of the code (text) section. If there are multiple such sections, this refers to the sum of the sizes of each section.") - Optional<@PositiveOrZero Long> getSizeOfCode(); - - @JsonProperty("size_of_initialized_data") - @JsonPropertyDescription("Specifies the size of the initialized data section. If there are multiple such sections, this refers to the sum of the sizes of each section.") - Optional<@PositiveOrZero Long> getSizeOfInitializedData(); - - @JsonProperty("size_of_uninitialized_data") - @JsonPropertyDescription("Specifies the size of the uninitialized data section. If there are multiple such sections, this refers to the sum of the sizes of each section.") - Optional<@PositiveOrZero Long> getSizeOfUninitializedData(); - - @JsonProperty("address_of_entry_point") - @JsonPropertyDescription("Specifies the address of the entry point relative to the image base when the executable is loaded into memory.") - Optional getAddressOfEntryPoint(); - - @JsonProperty("base_of_code") - @JsonPropertyDescription("Specifies the address that is relative to the image base of the beginning-of-code section when it is loaded into memory.") - Optional getBaseOfCode(); - - @JsonProperty("base_of_data") - @JsonPropertyDescription("Specifies the address that is relative to the image base of the beginning-of-data section when it is loaded into memory.") - Optional getBaseOfData(); - - @JsonProperty("image_base") - @JsonPropertyDescription("Specifies the preferred address of the first byte of the image when loaded into memory.") - Optional getImageBase(); - - @JsonProperty("section_alignment") - @JsonPropertyDescription("Specifies the alignment (in bytes) of PE sections when they are loaded into memory.") - Optional getSectionAlignment(); - - @JsonProperty("file_alignment") - @JsonPropertyDescription("Specifies the factor (in bytes) that is used to align the raw data of sections in the image file.") - Optional getFileAlignment(); - - @JsonProperty("major_os_version") - @JsonPropertyDescription("Specifies the major version number of the required operating system.") - Optional getMajorOsVersion(); - - @JsonProperty("minor_os_version") - @JsonPropertyDescription("Specifies the minor version number of the required operating system.") - Optional getMinorOsVersion(); - - @JsonProperty("major_image_version") - @JsonPropertyDescription("Specifies the major version number of the image.") - Optional getMajorImageVersion(); - - @JsonProperty("minor_image_version") - @JsonPropertyDescription("Specifies the minor version number of the image.") - Optional getMinorImageVersion(); - - @JsonProperty("major_subsystem_version") - @JsonPropertyDescription("Specifies the major version number of the subsystem.") - Optional getMajorSubsystemVersion(); - - @JsonProperty("minor_subsystem_version") - @JsonPropertyDescription("Specifies the minor version number of the subsystem.") - Optional getMinorSubsystemVersion(); - - @JsonProperty("win32_version_value_hex") - @JsonPropertyDescription("Specifies the reserved win32 version value.") - Optional<@Pattern(regexp = "^([a-fA-F0-9]{2})+$") String> getWin32VersionValueHex(); - - @JsonProperty("size_of_image") - @JsonPropertyDescription("Specifies the size, in bytes, of the image, including all headers, as the image is loaded in memory.") - Optional<@PositiveOrZero Long> getSizeOfImage(); - - @JsonProperty("size_of_headers") - @JsonPropertyDescription("Specifies the combined size of the MS-DOS, PE header, and section headers, rounded up a multiple of the value specified in the file_alignment header.") - Optional<@PositiveOrZero Long> getSizeOfHeaders(); - - @JsonProperty("checksum_hex") - @JsonPropertyDescription("Specifies the checksum of the PE binary.") - Optional<@Pattern(regexp = "^([a-fA-F0-9]{2})+$") String> getChecksumHex(); - - @JsonProperty("subsystem_hex") - @JsonPropertyDescription("Specifies the subsystem (e.g., GUI, device driver, etc.) that is required to run this image.") - Optional<@Pattern(regexp = "^([a-fA-F0-9]{2})+$") String> getSubsystemHex(); - - @JsonProperty("dll_characteristics_hex") - @JsonPropertyDescription("Specifies the flags that characterize the PE binary.") - Optional<@Pattern(regexp = "^([a-fA-F0-9]{2})+$") String> getDllCharacteristicsHex(); - - @JsonProperty("size_of_stack_reserve") - @JsonPropertyDescription("Specifies the size of the stack to reserve") - Optional<@PositiveOrZero Long> getSizeOfStackReserve(); - - @JsonProperty("size_of_stack_commit") - @JsonPropertyDescription("Specifies the size of the stack to commit.") - Optional<@PositiveOrZero Long> getSizeOfStackCommit(); - - @JsonProperty("size_of_heap_reserve") - @JsonPropertyDescription("Specifies the size of the local heap space to reserve.") - Optional<@PositiveOrZero Long> getSizeOfHeapReserve(); - - @JsonProperty("size_of_heap_commit") - @JsonPropertyDescription("Specifies the size of the local heap space to commit.") - Optional<@PositiveOrZero Long> getSizeOfHeapCommit(); - - @JsonProperty("loader_flags_hex") - @JsonPropertyDescription("Specifies the reserved loader flags.") - Optional<@Pattern(regexp = "^([a-fA-F0-9]{2})+$") String> getLoaderFlagsHex(); - - @JsonProperty("number_of_rva_and_sizes") - @JsonPropertyDescription("Specifies the number of data-directory entries in the remainder of the optional header.") - Optional getNumberOfRvaAndSizes(); - - @JsonProperty("hashes") - @JsonPropertyDescription("Specifies any hashes that were computed for the optional header.") - Map<@Length(min = 3, max = 256) @HashingVocab(HashingAlgorithms.class) String, String> getHashes(); - -} \ No newline at end of file diff --git a/src/main/java/io/digitalstate/stix/coo/types/WindowsPeSectionObj.java b/src/main/java/io/digitalstate/stix/coo/types/WindowsPeSectionObj.java deleted file mode 100644 index 74ebe74..0000000 --- a/src/main/java/io/digitalstate/stix/coo/types/WindowsPeSectionObj.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.digitalstate.stix.coo.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixCustomProperties; -import io.digitalstate.stix.validation.GenericValidation; -import io.digitalstate.stix.validation.contraints.hashingvocab.HashingVocab; -import io.digitalstate.stix.vocabulary.vocabularies.HashingAlgorithms; -import org.hibernate.validator.constraints.Length; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.PositiveOrZero; -import java.io.Serializable; -import java.util.Map; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * The PE Section type specifies metadata about a PE file section. - * - */ -@Value.Immutable @Serial.Version(1L) -//@DefaultTypeValue(value = "windows-pe-section-type", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Obj", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true, depluralizeDictionary = {"hash:hashes"}) -@JsonSerialize(as = WindowsPeSection.class) @JsonDeserialize(builder = WindowsPeSection.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "name", "size", "entropy", "hashes" }) -//@JsonTypeName("windows-pe-section-type") -public interface WindowsPeSectionObj extends GenericValidation, StixCustomProperties, Serializable { - - //@TODO Check and then add issue to GITHUB about missing spec docs about min required fields - //@TODO Add business rule with check for at least 1 required field. - - @JsonProperty("name") - @JsonPropertyDescription("Specifies the name of the section.") - @NotNull - Optional getName(); - - @JsonProperty("size") - @JsonPropertyDescription("Specifies the size of the section, in bytes.") - Optional<@PositiveOrZero Long> getSize(); - - @JsonProperty("entropy") - @JsonPropertyDescription("Specifies the calculated entropy for the section, as calculated using the Shannon algorithm.") - Optional getEntropy(); - - @JsonProperty("hashes") - @JsonPropertyDescription("Specifies any hashes computed over the section.") - Map<@Length(min = 3, max = 256) @HashingVocab(HashingAlgorithms.class) String, String> getHashes(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/types/WindowsRegistryValueObj.java b/src/main/java/io/digitalstate/stix/coo/types/WindowsRegistryValueObj.java deleted file mode 100644 index 326057a..0000000 --- a/src/main/java/io/digitalstate/stix/coo/types/WindowsRegistryValueObj.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.digitalstate.stix.coo.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixCustomProperties; -import io.digitalstate.stix.validation.GenericValidation; -import io.digitalstate.stix.validation.contraints.vocab.Vocab; -import io.digitalstate.stix.vocabulary.vocabularies.WindowsRegistryValueDataTypes; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import java.io.Serializable; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - - -/** - * The Windows Registry Value type captures the properties of a Windows Registry Key Value. - */ -@Value.Immutable @Serial.Version(1L) -//@DefaultTypeValue(value = "windows-registry-value-type", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Obj", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = WindowsRegistryValue.class) @JsonDeserialize(builder = WindowsRegistryValue.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "name", "data", "data_type" }) -//@JsonTypeName("windows-registry-value-type") -public interface WindowsRegistryValueObj extends GenericValidation, StixCustomProperties, Serializable { - - @JsonProperty("name") - @JsonPropertyDescription("Specifies the name of the registry value. For specifying the default value in a registry key, an empty string MUST be used.") - @NotNull - String getName(); - - @JsonProperty("data") - @JsonPropertyDescription("Specifies the data contained in the registry value.") - Optional getData(); - - @JsonProperty("data_type") - @JsonPropertyDescription("Specifies the registry (REG_*) data type used in the registry value.") - Optional<@Vocab(WindowsRegistryValueDataTypes.class) String> getDataType(); - -} diff --git a/src/main/java/io/digitalstate/stix/coo/types/X509v3ExtensionsObj.java b/src/main/java/io/digitalstate/stix/coo/types/X509v3ExtensionsObj.java deleted file mode 100644 index 0a4d382..0000000 --- a/src/main/java/io/digitalstate/stix/coo/types/X509v3ExtensionsObj.java +++ /dev/null @@ -1,105 +0,0 @@ -package io.digitalstate.stix.coo.types; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixCustomProperties; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.validation.GenericValidation; -import io.digitalstate.stix.validation.contraints.businessrule.BusinessRule; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import java.io.Serializable; -import java.time.Instant; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * x509-certificate - *

- * The X509 Certificate Object represents the properties of an X.509 certificate. - * Note that the X.509 v3 Extensions type is not a STIX Cyber Observables extension, - * it is a type that describes X.509 extensions. - * - */ -@Value.Immutable @Serial.Version(1L) -//@DefaultTypeValue(value = "x509-v3-extensions-type", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Obj", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = X509v3Extensions.class) @JsonDeserialize(builder = X509v3Extensions.Builder.class) -@JsonInclude(value = NON_EMPTY, content= NON_EMPTY) -@JsonPropertyOrder({ "basic_constraints", "name_constraints", "policy_constraints", "key_usage", "extended_key_usage", - "subject_key_identifier", "authority_key_identifier", "subject_alternative_name", "issuer_alternative_name", - "subject_directory_attributes", "crl_distribution_points", "inhibit_any_policy", - "private_key_usage_period_not_before", "private_key_usage_period_not_after", "certificate_policies", - "policy_mappings" }) -//@JsonTypeName("x509-v3-extensions-type") -@BusinessRule(ifExp = "true", thenExp = "getBasicConstraints().isPresent() == true || getNameConstraints().isPresent() == true || getPolicyConstraints().isPresent() == true || getKeyUsage().isPresent() == true || getExtendedKeyUsage().isPresent() == true || getSubjectKeyIdentifier().isPresent() == true || getAuthorityKeyIdentifier().isPresent() == true || getSubjectAlternativeName().isPresent() == true || getIssuerAlternativeName().isPresent() == true || getSubjectDirectoryAttributes().isPresent() == true || getCrlDistributionPoints().isPresent() == true || getInhibitAnyPolicy().isPresent() == true || getPrivateKeyUsagePeriodNotBefore().isPresent() == true || getPrivateKeyUsagePeriodNotAfter().isPresent() == true || getCertificatePolicies().isPresent() == true || getPolicyMappings().isPresent() == true", errorMessage = "At least 1 property must be provided") -public interface X509v3ExtensionsObj extends GenericValidation, StixCustomProperties, Serializable { - - @JsonProperty("basic_constraints") - @JsonPropertyDescription("Specifies a multi-valued extension which indicates whether a certificate is a CA certificate.") - Optional getBasicConstraints(); - - @JsonProperty("name_constraints") - @JsonPropertyDescription("Specifies a namespace within which all subject names in subsequent certificates in a certification path MUST be located.") - Optional getNameConstraints(); - - @JsonProperty("policy_constraints") - @JsonPropertyDescription("Specifies any constraints on path validation for certificates issued to CAs.") - Optional getPolicyConstraints(); - - @JsonProperty("key_usage") - @JsonPropertyDescription("Specifies a multi-valued extension consisting of a list of names of the permitted key usages.") - Optional getKeyUsage(); - - @JsonProperty("extended_key_usage") - @JsonPropertyDescription("Specifies a list of usages indicating purposes for which the certificate public key can be used for.") - Optional getExtendedKeyUsage(); - - @JsonProperty("subject_key_identifier") - @JsonPropertyDescription("Specifies the identifier that provides a means of identifying certificates that contain a particular public key.") - Optional getSubjectKeyIdentifier(); - - @JsonProperty("authority_key_identifier") - @JsonPropertyDescription("Specifies the identifier that provides a means of identifying the public key corresponding to the key used to sign a certificate.") - Optional getAuthorityKeyIdentifier(); - - @JsonProperty("subject_alternative_name") - @JsonPropertyDescription("Specifies the additional identities to be bound to the subject of the certificate.") - Optional getSubjectAlternativeName(); - - @JsonProperty("issuer_alternative_name") - @JsonPropertyDescription("Specifies the additional identities to be bound to the issuer of the certificate.") - Optional getIssuerAlternativeName(); - - @JsonProperty("subject_directory_attributes") - @JsonPropertyDescription("Specifies the identification attributes (e.g., nationality) of the subject.") - Optional getSubjectDirectoryAttributes(); - - @JsonProperty("crl_distribution_points") - @JsonPropertyDescription("Specifies how CRL information is obtained.") - Optional getCrlDistributionPoints(); - - @JsonProperty("inhibit_any_policy") - @JsonPropertyDescription("Specifies the number of additional certificates that may appear in the path before anyPolicy is no longer permitted.") - Optional getInhibitAnyPolicy(); - - @JsonProperty("private_key_usage_period_not_before") - @JsonPropertyDescription("Specifies the date on which the validity period begins for the key, if it is different from the validity period of the certificate.") - Optional getPrivateKeyUsagePeriodNotBefore(); - - @JsonProperty("private_key_usage_period_not_after") - @JsonPropertyDescription("Specifies the date on which the validity period ends for the key, if it is different from the validity period of the certificate.") - Optional getPrivateKeyUsagePeriodNotAfter(); - - @JsonProperty("certificate_policies") - @JsonPropertyDescription("Specifies a sequence of one or more policy information terms, each of which consists of an object identifier (OID) and optional qualifiers.") - Optional getCertificatePolicies(); - - @JsonProperty("policy_mappings") - @JsonPropertyDescription("Specifies one or more pairs of OIDs(); each pair includes an issuerDomainPolicy and a subjectDomainPolicy") - Optional getPolicyMappings(); - -} diff --git a/src/main/java/io/digitalstate/stix/custom/StixCustomObject.java b/src/main/java/io/digitalstate/stix/custom/StixCustomObject.java deleted file mode 100644 index 9d477d2..0000000 --- a/src/main/java/io/digitalstate/stix/custom/StixCustomObject.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.digitalstate.stix.custom; - -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonUnwrapped; -import io.digitalstate.stix.common.*; -import io.digitalstate.stix.validation.contraints.startswith.StartsWith; -import org.hibernate.validator.constraints.Length; - -import java.util.Map; - -/** - * Provides a Generic STIX Custom Object to use for Bundleable objects when the object is not included in the mappings. - * Note: Custom properties (x_) are included in the CustomObjectProperties - */ -public interface StixCustomObject extends - StixCommonProperties, - StixLabels, - StixModified, - StixRevoked{ - - @Override - @StartsWith("x-") - String getType(); - - @Override - @StartsWith("x-") - String getId(); - - //@TODO Future enhancement to create a custom deserializer that will support the difference between x_ props and the CustomObjectProperties() - @JsonProperty(access = JsonProperty.Access.READ_ONLY) - @JsonUnwrapped @JsonAnyGetter - Map<@Length(min = 3, - max = 250, - message = "STIX Custom Properties must have a min key length of 3 and max of 250") - String, Object> getCustomObjectProperties(); - -} diff --git a/src/main/java/io/digitalstate/stix/custom/objects/GenericCustomObject.java b/src/main/java/io/digitalstate/stix/custom/objects/GenericCustomObject.java deleted file mode 100644 index ff35c98..0000000 --- a/src/main/java/io/digitalstate/stix/custom/objects/GenericCustomObject.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.digitalstate.stix.custom.objects; - -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import com.fasterxml.jackson.annotation.JsonTypeName; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.bundle.BundleableObject; -import io.digitalstate.stix.custom.StixCustomObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - - -@Value.Immutable @Serial.Version(1L) -//@DefaultTypeValue(value = "", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="Generic*", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = CustomObject.class) @JsonDeserialize(builder = CustomObject.Builder.class) -@JsonPropertyOrder({"type", "id", "created_by_ref", "created", - "modified", "revoked", "labels", "external_references", - "object_marking_refs", "granular_markings"}) -public interface GenericCustomObject extends StixCustomObject { - - -} diff --git a/src/main/java/io/digitalstate/stix/datamarkings/GranularMarkingDm.java b/src/main/java/io/digitalstate/stix/datamarkings/GranularMarkingDm.java deleted file mode 100644 index 7fdf907..0000000 --- a/src/main/java/io/digitalstate/stix/datamarkings/GranularMarkingDm.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.digitalstate.stix.datamarkings; - -import com.fasterxml.jackson.annotation.JsonIdentityInfo; -import com.fasterxml.jackson.annotation.JsonIdentityReference; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.ObjectIdGenerators; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixCustomProperties; -import io.digitalstate.stix.json.converters.dehydrated.MarkingDefinitionConverter; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.validation.SdoDefaultValidator; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.io.Serializable; -import java.util.Set; - -@Value.Immutable @Serial.Version(1L) -@Value.Style(typeAbstract="*Dm", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, depluralize = true) -@JsonSerialize(as = GranularMarking.class) @JsonDeserialize(builder = GranularMarking.Builder.class) -@Redactable -public interface GranularMarkingDm extends StixCustomProperties, SdoDefaultValidator, Serializable { - - @NotNull - @JsonProperty("marking_ref") - @JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="id") - @JsonIdentityReference(alwaysAsId=true) - @JsonDeserialize(converter = MarkingDefinitionConverter.class) - MarkingDefinitionDm getMarkingRef(); - - @Size(min = 1, message = "Must have as least 1 selector") - @JsonProperty("selectors") - Set getSelectors(); - -} diff --git a/src/main/java/io/digitalstate/stix/datamarkings/MarkingDefinitionDm.java b/src/main/java/io/digitalstate/stix/datamarkings/MarkingDefinitionDm.java deleted file mode 100644 index 23a8adb..0000000 --- a/src/main/java/io/digitalstate/stix/datamarkings/MarkingDefinitionDm.java +++ /dev/null @@ -1,52 +0,0 @@ -package io.digitalstate.stix.datamarkings; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.annotation.JsonTypeName; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixCommonProperties; -import io.digitalstate.stix.common.StixCustomProperties; -import io.digitalstate.stix.datamarkings.objects.StatementMarkingObject; -import io.digitalstate.stix.datamarkings.objects.TlpMarkingObject; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.contraints.markingdefinitiontype.MarkingDefinitionTypeLimit; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; - -/** - *

Builder Required Fields:

- *
    - *
  1. {@link MarkingDefinition#getDefinitionType()} - (A helper is in-place for this field that will pre-populate the value based on the specific Marking Object, which makes this field essentially optional).
  2. - *
  3. {@link MarkingDefinition#getDefinition()} - the Marking Object. Two objects are currently supported: {@link Tlp} and {@link Statement}.
  4. - *
- */ -@Value.Immutable @Serial.Version(1L) -@JsonTypeName("marking-definition") -@DefaultTypeValue(value = "marking-definition", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Dm", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = MarkingDefinition.class) @JsonDeserialize(builder = MarkingDefinition.Builder.class) -@JsonPropertyOrder({"type", "id", "created_by_ref", "created", - "external_references", "object_marking_refs", "granular_markings", "definition_type", - "definition"}) -@MarkingDefinitionTypeLimit(markingObject = TlpMarkingObject.class, markingDefinitionType = "tlp", groups = {DefaultValuesProcessor.class}) -@MarkingDefinitionTypeLimit(markingObject = StatementMarkingObject.class, markingDefinitionType = "statement", groups = {DefaultValuesProcessor.class}) -@Redactable -public interface MarkingDefinitionDm extends StixCommonProperties, StixCustomProperties { - - @NotBlank - @JsonProperty("definition_type") - String getDefinitionType(); - - @NotNull - @JsonProperty("definition") - @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "definition_type", include = JsonTypeInfo.As.EXTERNAL_PROPERTY) - StixMarkingObject getDefinition(); - -} diff --git a/src/main/java/io/digitalstate/stix/datamarkings/StixMarkingObject.java b/src/main/java/io/digitalstate/stix/datamarkings/StixMarkingObject.java deleted file mode 100644 index e2fe31c..0000000 --- a/src/main/java/io/digitalstate/stix/datamarkings/StixMarkingObject.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.digitalstate.stix.datamarkings; - -import io.digitalstate.stix.common.StixCustomProperties; - -import java.io.Serializable; - -public interface StixMarkingObject extends StixCustomProperties, Serializable { - -} diff --git a/src/main/java/io/digitalstate/stix/datamarkings/objects/StatementMarkingObject.java b/src/main/java/io/digitalstate/stix/datamarkings/objects/StatementMarkingObject.java deleted file mode 100644 index d76d2f6..0000000 --- a/src/main/java/io/digitalstate/stix/datamarkings/objects/StatementMarkingObject.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.digitalstate.stix.datamarkings.objects; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonTypeName; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.datamarkings.StixMarkingObject; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.validation.GenericValidation; -import org.hibernate.validator.constraints.Length; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; - -@Value.Immutable @Serial.Version(1L) -@Value.Style(typeImmutable = "Statement", additionalJsonAnnotations = {JsonTypeName.class}, validationMethod = Value.Style.ValidationMethod.NONE, depluralize = true) -@JsonSerialize(as = Statement.class) @JsonDeserialize(builder = Statement.Builder.class) -@Redactable -@JsonTypeName("statement") -public interface StatementMarkingObject extends GenericValidation, StixMarkingObject { - - @NotBlank - @JsonProperty("statement") - @Length(min = 1) String getStatement(); - -} diff --git a/src/main/java/io/digitalstate/stix/datamarkings/objects/TlpMarkingObject.java b/src/main/java/io/digitalstate/stix/datamarkings/objects/TlpMarkingObject.java deleted file mode 100644 index 993a099..0000000 --- a/src/main/java/io/digitalstate/stix/datamarkings/objects/TlpMarkingObject.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.digitalstate.stix.datamarkings.objects; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonTypeName; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.datamarkings.StixMarkingObject; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.validation.GenericValidation; -import io.digitalstate.stix.validation.contraints.vocab.Vocab; -import io.digitalstate.stix.vocabulary.vocabularies.TlpLevels; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; - -@Value.Immutable @Serial.Version(1L) -@Value.Style(typeImmutable = "Tlp", additionalJsonAnnotations = {JsonTypeName.class}, validationMethod = Value.Style.ValidationMethod.NONE, depluralize = true) -@JsonSerialize(as = Tlp.class) @JsonDeserialize(builder = Tlp.Builder.class) -@Redactable -@JsonTypeName("tlp") -public interface TlpMarkingObject extends GenericValidation, StixMarkingObject { - - @NotNull - @JsonProperty("tlp") - @Vocab(TlpLevels.class) - String getTlp(); - -} diff --git a/src/main/java/io/digitalstate/stix/graph/GraphGenerator.java b/src/main/java/io/digitalstate/stix/graph/GraphGenerator.java deleted file mode 100644 index 08e11d7..0000000 --- a/src/main/java/io/digitalstate/stix/graph/GraphGenerator.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.digitalstate.stix.graph; - -import io.digitalstate.stix.graph.elements.GraphElement; - -import java.util.Set; - -public interface GraphGenerator { - - Set process(); -} diff --git a/src/main/java/io/digitalstate/stix/graph/StixGraphGenerator.java b/src/main/java/io/digitalstate/stix/graph/StixGraphGenerator.java deleted file mode 100644 index 686ba50..0000000 --- a/src/main/java/io/digitalstate/stix/graph/StixGraphGenerator.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.digitalstate.stix.graph; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.digitalstate.stix.bundle.BundleObject; -import io.digitalstate.stix.graph.bundle.BundleObjectGraphGenerator; -import io.digitalstate.stix.graph.elements.GraphElement; -import io.digitalstate.stix.json.StixParsers; - -import java.util.HashSet; -import java.util.Set; - -public class StixGraphGenerator implements GraphGenerator { - - private BundleObject bundle; - private ObjectMapper jsonMapper = StixParsers.getJsonMapper(); - - public StixGraphGenerator(BundleObject bundle) { - this.bundle = bundle; - } - - @Override - public Set process(){ - Set elements = new HashSet<>(); - - elements.addAll(new BundleObjectGraphGenerator(bundle).process()); - - return elements; - } - - public String toJson(){ - try { - return jsonMapper.writeValueAsString(process()); - } catch (JsonProcessingException e) { - throw new IllegalStateException(e); - } - } -} diff --git a/src/main/java/io/digitalstate/stix/graph/bundle/BundleObjectGraphGenerator.java b/src/main/java/io/digitalstate/stix/graph/bundle/BundleObjectGraphGenerator.java deleted file mode 100644 index dcdb77a..0000000 --- a/src/main/java/io/digitalstate/stix/graph/bundle/BundleObjectGraphGenerator.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.digitalstate.stix.graph.bundle; - -import io.digitalstate.stix.bundle.BundleObject; -import io.digitalstate.stix.graph.GraphGenerator; -import io.digitalstate.stix.graph.elements.GraphElement; - -import java.util.HashSet; -import java.util.Set; - -public class BundleObjectGraphGenerator implements GraphGenerator { - - private BundleObject object; - - public BundleObjectGraphGenerator(BundleObject object) { - this.object = object; - } - - public BundleObject getObject() { - return object; - } - - public Set process(){ - Set items = new HashSet<>(); - - object.getObjects().forEach(o->{ - items.addAll(new BundleableObjectGraphGenerator(o).process()); - }); - return items; - } - -} diff --git a/src/main/java/io/digitalstate/stix/graph/bundle/BundleableObjectGraphGenerator.java b/src/main/java/io/digitalstate/stix/graph/bundle/BundleableObjectGraphGenerator.java deleted file mode 100644 index 5ef5133..0000000 --- a/src/main/java/io/digitalstate/stix/graph/bundle/BundleableObjectGraphGenerator.java +++ /dev/null @@ -1,48 +0,0 @@ -package io.digitalstate.stix.graph.bundle; - -import io.digitalstate.stix.bundle.BundleableObject; -import io.digitalstate.stix.graph.sdo.DomainObjectGraphGenerator; -import io.digitalstate.stix.graph.GraphGenerator; -import io.digitalstate.stix.graph.sro.RelationshipSroGraphGenerator; -import io.digitalstate.stix.graph.sro.SightingSroGraphGenerator; -import io.digitalstate.stix.graph.elements.GraphElement; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.sro.objects.RelationshipSro; -import io.digitalstate.stix.sro.objects.SightingSro; - -import java.util.HashSet; -import java.util.Set; - -public class BundleableObjectGraphGenerator implements GraphGenerator { - - private BundleableObject object; - - public BundleableObjectGraphGenerator(BundleableObject object) { - this.object = object; - } - - public BundleableObject getObject() { - return object; - } - - public Set process(){ - Set items = new HashSet<>(); - - Class objectClass = object.getClass(); - - if (DomainObject.class.isAssignableFrom(objectClass)){ - items.addAll(new DomainObjectGraphGenerator((DomainObject)object).process()); - - } else if (RelationshipSro.class.isAssignableFrom(objectClass)){ - items.addAll(new RelationshipSroGraphGenerator((RelationshipSro)object).process()); - - } else if (SightingSro.class.isAssignableFrom(objectClass)){ - items.addAll( - new SightingSroGraphGenerator((SightingSro) object).process() - ); - } - - return items; - } - -} diff --git a/src/main/java/io/digitalstate/stix/graph/coo/CyberObservableGraphGenerator.java b/src/main/java/io/digitalstate/stix/graph/coo/CyberObservableGraphGenerator.java deleted file mode 100644 index e07cb0e..0000000 --- a/src/main/java/io/digitalstate/stix/graph/coo/CyberObservableGraphGenerator.java +++ /dev/null @@ -1,50 +0,0 @@ -package io.digitalstate.stix.graph.coo; - -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.graph.GraphGenerator; -import io.digitalstate.stix.graph.elements.GraphElement; -import io.digitalstate.stix.graph.elements.Node; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - -/** - * Generally used by the Observed Data SDO Graph Generator - */ -public class CyberObservableGraphGenerator implements GraphGenerator { - - private CyberObservableObject object; - private String observedDataObjectId; - - public CyberObservableGraphGenerator(String observedDataObjectId, CyberObservableObject object) { - this.object = object; - this.observedDataObjectId = observedDataObjectId; - } - - public CyberObservableObject getObject() { - return object; - } - - public String getObservedDataObjectId() { - return observedDataObjectId; - } - - public Set process(){ - Set elements = new HashSet<>(); - elements.add(generateNode()); - - return elements; - } - - // Is public to support custom usage by Observed Data Graph Generator - public Node generateNode(){ - String uuid = object.getObservableObjectKey() + "--" + UUID.randomUUID().toString(); - String type = "coo-" + object.getType(); - - return new Node(uuid, type, null, object); - //@TODO Refactor to support the parent node prob for sub graph node support -// return new Node(uuid, type, observedDataObjectId, object); - } - -} diff --git a/src/main/java/io/digitalstate/stix/graph/datamarkings/MarkingDefinitionGraphGenerator.java b/src/main/java/io/digitalstate/stix/graph/datamarkings/MarkingDefinitionGraphGenerator.java deleted file mode 100644 index 57a9a1f..0000000 --- a/src/main/java/io/digitalstate/stix/graph/datamarkings/MarkingDefinitionGraphGenerator.java +++ /dev/null @@ -1,44 +0,0 @@ -package io.digitalstate.stix.graph.datamarkings; - -import io.digitalstate.stix.datamarkings.MarkingDefinitionDm; -import io.digitalstate.stix.graph.GraphGenerator; -import io.digitalstate.stix.graph.elements.GraphElement; -import io.digitalstate.stix.graph.elements.Node; - -import java.util.HashSet; -import java.util.Set; - -public class MarkingDefinitionGraphGenerator implements GraphGenerator{ - - private MarkingDefinitionDm object; - - public MarkingDefinitionGraphGenerator(MarkingDefinitionDm object) { - this.object = object; - } - - public MarkingDefinitionDm getObject() { - return object; - } - - public Set process(){ - Set elements = new HashSet<>(); - - elements.add(generateNode()); -// elements.addAll(generateEdges()); - - return elements; - } - - private Node generateNode(){ - return new Node(object.getId(), object.getType(), null, object); - } - -// private Set generateEdges() { -// Set edges = new HashSet<>(); -// -// edges.addAll(generateObjectMarkingRefEdges(object.getObjectMarkingRefs())); -// -// return edges; -// } - -} diff --git a/src/main/java/io/digitalstate/stix/graph/elements/Edge.java b/src/main/java/io/digitalstate/stix/graph/elements/Edge.java deleted file mode 100644 index c9bddc6..0000000 --- a/src/main/java/io/digitalstate/stix/graph/elements/Edge.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.digitalstate.stix.graph.elements; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import javax.validation.constraints.NotNull; - -public class Edge implements GraphElement { - - private EdgeData data; - - public Edge(@NotNull String id, String type, String source, String target, Object jsonData) { - this.data = new EdgeData(id, type, source, target, jsonData); - } - - @JsonProperty("data") - public EdgeData getData() { - return data; - } - - public void setData(EdgeData data) { - this.data = data; - } -} - - diff --git a/src/main/java/io/digitalstate/stix/graph/elements/EdgeData.java b/src/main/java/io/digitalstate/stix/graph/elements/EdgeData.java deleted file mode 100644 index df06cb5..0000000 --- a/src/main/java/io/digitalstate/stix/graph/elements/EdgeData.java +++ /dev/null @@ -1,96 +0,0 @@ -package io.digitalstate.stix.graph.elements; - -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonUnwrapped; - -import java.util.HashMap; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -public class EdgeData { - - private String id; - private String type; - private String source; - private String target; - private Object jsonData; - private String edgeLabel; - private HashMap additionalProperties = new HashMap<>(); - - public EdgeData(String id, String type, String source, String target, Object jsonData) { - this.id = id; - this.type = type; - this.source = source; - this.target = target; - this.jsonData = jsonData; - } - - @JsonProperty("id") - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - @JsonProperty("type") - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - @JsonProperty("source") - public String getSource() { - return source; - } - - public void setSource(String source) { - this.source = source; - } - - @JsonProperty("target") - public String getTarget() { - return target; - } - - public void setTarget(String target) { - this.target = target; - } - - @JsonProperty("stix") - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - public Object getJsonData() { - return jsonData; - } - - public void setJsonData(Object jsonData) { - this.jsonData = jsonData; - } - - @JsonProperty("label") - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - public String getEdgeLabel() { - return edgeLabel; - } - - public void setEdgeLabel(String edgeLabel) { - this.edgeLabel = edgeLabel; - } - - @JsonUnwrapped - @JsonAnyGetter - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - public HashMap getAdditionalProperties() { - return additionalProperties; - } - - public void setAdditionalProperties(HashMap additionalProperties) { - this.additionalProperties = additionalProperties; - } -} diff --git a/src/main/java/io/digitalstate/stix/graph/elements/GraphElement.java b/src/main/java/io/digitalstate/stix/graph/elements/GraphElement.java deleted file mode 100644 index 0e391a8..0000000 --- a/src/main/java/io/digitalstate/stix/graph/elements/GraphElement.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.digitalstate.stix.graph.elements; - -import java.util.Set; - -public interface GraphElement { - -} diff --git a/src/main/java/io/digitalstate/stix/graph/elements/Node.java b/src/main/java/io/digitalstate/stix/graph/elements/Node.java deleted file mode 100644 index fac83fc..0000000 --- a/src/main/java/io/digitalstate/stix/graph/elements/Node.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.digitalstate.stix.graph.elements; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import javax.validation.constraints.NotNull; - -public class Node implements GraphElement { - - private NodeData data; - - public Node(@NotNull String id, String type, String parent, Object jsonData) { - this.data = new NodeData(id, type, parent, jsonData); - } - - @JsonProperty("data") - public NodeData getData() { - return data; - } - - public void setData(NodeData data) { - this.data = data; - } -} diff --git a/src/main/java/io/digitalstate/stix/graph/elements/NodeData.java b/src/main/java/io/digitalstate/stix/graph/elements/NodeData.java deleted file mode 100644 index 5fcdc4e..0000000 --- a/src/main/java/io/digitalstate/stix/graph/elements/NodeData.java +++ /dev/null @@ -1,75 +0,0 @@ -package io.digitalstate.stix.graph.elements; - -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonUnwrapped; - -import java.util.HashMap; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -public class NodeData { - - private String id; - private String type; - private String parent; - private Object jsonData; - private HashMap additionalProperties = new HashMap<>(); - - public NodeData(String id, String type, String parent, Object jsonData) { - this.id = id; - this.type = type; - this.parent = parent; - this.jsonData = jsonData; - } - - @JsonProperty("id") - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - @JsonProperty("type") - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - @JsonProperty("parent") - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - public String getParent() { - return parent; - } - - public void setParent(String parent) { - this.parent = parent; - } - - @JsonProperty("stix") - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - public Object getJsonData() { - return jsonData; - } - - public void setJsonData(Object jsonData) { - this.jsonData = jsonData; - } - - @JsonUnwrapped - @JsonAnyGetter - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - public HashMap getAdditionalProperties() { - return additionalProperties; - } - - public void setAdditionalProperties(HashMap additionalProperties) { - this.additionalProperties = additionalProperties; - } -} diff --git a/src/main/java/io/digitalstate/stix/graph/sdo/DomainObjectGraphGenerator.java b/src/main/java/io/digitalstate/stix/graph/sdo/DomainObjectGraphGenerator.java deleted file mode 100644 index 61e7185..0000000 --- a/src/main/java/io/digitalstate/stix/graph/sdo/DomainObjectGraphGenerator.java +++ /dev/null @@ -1,46 +0,0 @@ -package io.digitalstate.stix.graph.sdo; - -import io.digitalstate.stix.graph.GraphGenerator; -import io.digitalstate.stix.graph.elements.GraphElement; -import io.digitalstate.stix.graph.elements.Node; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.sdo.objects.ObservedDataSdo; - -import java.util.HashSet; -import java.util.Set; - -public class DomainObjectGraphGenerator implements GraphGenerator { - - private DomainObject object; - - public DomainObjectGraphGenerator(DomainObject object) { - this.object = object; - } - - @Override - public Set process() { - Set elements = new HashSet<>(); - - if (ObservedDataSdo.class.isAssignableFrom(object.getClass())){ - elements.addAll(generateObservedDataGraphElements((ObservedDataSdo)object)); - } else { - //@TODO Add various support for the other SDOs - elements.add(generateNode()); - } - - return elements; - } - - public DomainObject getObject() { - return object; - } - - private Node generateNode() { - return new Node(object.getId(), object.getType(), null, object); - } - - private Set generateObservedDataGraphElements(ObservedDataSdo observedDataSdo){ - return new ObservedDataGraphGenerator(observedDataSdo).process(); - } - -} diff --git a/src/main/java/io/digitalstate/stix/graph/sdo/ObservedDataGraphGenerator.java b/src/main/java/io/digitalstate/stix/graph/sdo/ObservedDataGraphGenerator.java deleted file mode 100644 index 8639e91..0000000 --- a/src/main/java/io/digitalstate/stix/graph/sdo/ObservedDataGraphGenerator.java +++ /dev/null @@ -1,65 +0,0 @@ -package io.digitalstate.stix.graph.sdo; - -import io.digitalstate.stix.graph.GraphGenerator; -import io.digitalstate.stix.graph.coo.CyberObservableGraphGenerator; -import io.digitalstate.stix.graph.elements.Edge; -import io.digitalstate.stix.graph.elements.GraphElement; -import io.digitalstate.stix.graph.elements.Node; -import io.digitalstate.stix.sdo.objects.ObservedDataSdo; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - -public class ObservedDataGraphGenerator implements GraphGenerator { - - private ObservedDataSdo object; - - public ObservedDataGraphGenerator(ObservedDataSdo object) { - this.object = object; - } - - @Override - public Set process() { - Set elements = new HashSet<>(); - - elements.add(generateNode()); - elements.addAll(generateCooElements()); - - return elements; - } - - private Node generateNode() { - return new Node(object.getId(), object.getType(), null, object); - } - - public ObservedDataSdo getObject() { - return object; - } - - private Set generateCooElements(){ - Set elements = new HashSet<>(); - - String observedDataId = object.getId(); - - object.getObjects().forEach(coo -> { - - // Generate the Cyber Observable node - Node cooGraphNode = new CyberObservableGraphGenerator(observedDataId, coo).generateNode(); - elements.add(cooGraphNode); - - String uuidPrefix = "ref"; - String uuid = uuidPrefix + "-" + UUID.randomUUID().toString(); - // Use the Cyber Observable node's ID as the target: - Edge edge = new Edge(uuid, uuidPrefix, observedDataId, cooGraphNode.getData().getId(), null); - - edge.getData().setEdgeLabel(coo.getType()); - edge.getData().getAdditionalProperties().put("ref_type", "cyber_observable"); - - elements.add(edge); - }); - - return elements; - } - -} diff --git a/src/main/java/io/digitalstate/stix/graph/sro/RelationshipSroGraphGenerator.java b/src/main/java/io/digitalstate/stix/graph/sro/RelationshipSroGraphGenerator.java deleted file mode 100644 index 1ae0f3d..0000000 --- a/src/main/java/io/digitalstate/stix/graph/sro/RelationshipSroGraphGenerator.java +++ /dev/null @@ -1,46 +0,0 @@ -package io.digitalstate.stix.graph.sro; - -import io.digitalstate.stix.graph.GraphGenerator; -import io.digitalstate.stix.graph.elements.Edge; -import io.digitalstate.stix.graph.elements.GraphElement; -import io.digitalstate.stix.sro.objects.RelationshipSro; - -import java.util.HashSet; -import java.util.Set; - -public class RelationshipSroGraphGenerator implements GraphGenerator { - - private RelationshipSro object; - - public RelationshipSroGraphGenerator(RelationshipSro object) { - this.object = object; - } - - public RelationshipSro getObject() { - return object; - } - - @Override - public Set process() { - Set elements = new HashSet<>(); - elements.add(generateEdge()); - return elements; - } - - private Edge generateEdge() { - Edge edge = new Edge(object.getId(), - object.getType(), - object.getSourceRef().getId(), - object.getTargetRef().getId(), - object); - - edge.getData().setEdgeLabel(object.getRelationshipType()); - - edge.getData() - .getAdditionalProperties() - .put("relationship_type", object.getRelationshipType()); - - return edge; - } - -} diff --git a/src/main/java/io/digitalstate/stix/graph/sro/SightingSroGraphGenerator.java b/src/main/java/io/digitalstate/stix/graph/sro/SightingSroGraphGenerator.java deleted file mode 100644 index 4cb20d2..0000000 --- a/src/main/java/io/digitalstate/stix/graph/sro/SightingSroGraphGenerator.java +++ /dev/null @@ -1,85 +0,0 @@ -package io.digitalstate.stix.graph.sro; - -import io.digitalstate.stix.graph.GraphGenerator; -import io.digitalstate.stix.graph.elements.Edge; -import io.digitalstate.stix.graph.elements.GraphElement; -import io.digitalstate.stix.graph.elements.Node; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.sdo.objects.ObservedDataSdo; -import io.digitalstate.stix.sro.objects.SightingSro; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - -public class SightingSroGraphGenerator implements GraphGenerator { - - private SightingSro object; - - public SightingSroGraphGenerator(SightingSro object) { - this.object = object; - } - - public SightingSro getObject() { - return object; - } - - public Set process(){ - Set elements = new HashSet<>(); - - elements.add(generateNode()); - elements.addAll(generateEdges()); - - return elements; - } - - private Node generateNode(){ - return new Node(object.getId(), object.getType(), null, object); - } - - private Set generateEdges() { - Set edges = new HashSet<>(); - - edges.add(generateSightingOfRefEdge(object.getSightingOfRef())); - - edges.addAll(generateObservedDataEdges(object.getId(), object.getObservedDataRefs())); - - return edges; - } - - private Edge generateSightingOfRefEdge(DomainObject sightingOfRefDomainObject){ - String uuidPrefix = "ref"; - - DomainObject sor = object.getSightingOfRef(); - - String sorUuid = uuidPrefix + "-" + UUID.randomUUID().toString(); - - Edge edge = new Edge(sorUuid, uuidPrefix, object.getId(), sor.getId(), null); - - edge.getData().setEdgeLabel("sighting-of"); - - edge.getData().getAdditionalProperties().put("ref_type", "sighting_of_ref"); - - return edge; - } - - private Set generateObservedDataEdges(String sourceId, Set observedDataSdoSet){ - Set edges = new HashSet<>(); - - observedDataSdoSet.forEach(od -> { - String uuidPrefix = "ref"; - String odUuid = uuidPrefix + "-" + UUID.randomUUID().toString(); - - Edge edge = new Edge(odUuid, uuidPrefix, sourceId, od.getId(), null); - - edge.getData().setEdgeLabel("observed-data"); - - edge.getData().getAdditionalProperties().put("ref_type", "observed_data"); - - edges.add(edge); - }); - - return edges; - } - -} diff --git a/src/main/java/io/digitalstate/stix/helpers/StixCustomPropertiesConfig.java b/src/main/java/io/digitalstate/stix/helpers/StixCustomPropertiesConfig.java deleted file mode 100644 index 961a67a..0000000 --- a/src/main/java/io/digitalstate/stix/helpers/StixCustomPropertiesConfig.java +++ /dev/null @@ -1,41 +0,0 @@ -package io.digitalstate.stix.helpers; - -import java.util.HashSet; -import java.util.Set; - -/** - * STIX Custom properties configuration - */ -public class StixCustomPropertiesConfig { - - /** - * Default Custom Property Prefix: {@code x_ }. - */ - public static final String DEFAULT_CUSTOM_PROPERTY_PREFIX = "x_"; - - private static Set additionalPropertyPrefixes = new HashSet<>(); - - /** - * Get Additional STIX Custom Property prefixes. - */ - public static Set getAdditionalPropertyPrefixes() { - return additionalPropertyPrefixes; - } - - /** - * Set Additional STIX Custom Property prefixes. - */ - public static void setAdditionalPropertyPrefixes(Set additionalPropertyPrefixes) { - StixCustomPropertiesConfig.additionalPropertyPrefixes = additionalPropertyPrefixes; - } - - /** - * Returns a aggregate of The Default Custom Property Prefix and any defined additional customer property prefixes. - * @return Set of allowed custom property prefixes - */ - public static Set getAllCustomPropertyPrefixes(){ - Set allPrefixes = new HashSet<>(getAdditionalPropertyPrefixes()); - allPrefixes.add(DEFAULT_CUSTOM_PROPERTY_PREFIX); - return allPrefixes; - } -} diff --git a/src/main/java/io/digitalstate/stix/helpers/StixDataFormats.java b/src/main/java/io/digitalstate/stix/helpers/StixDataFormats.java deleted file mode 100644 index 4a72cd7..0000000 --- a/src/main/java/io/digitalstate/stix/helpers/StixDataFormats.java +++ /dev/null @@ -1,52 +0,0 @@ -package io.digitalstate.stix.helpers; - -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; -import java.time.temporal.ChronoField; - -public class StixDataFormats { - - /** - * Default pattern for deserialization of date/times into a STIX compliant timestamp. - */ - public static final String TIMESTAMP_PATTERN = "yyyy-MM-dd'T'HH:mm:ss[.SSS][.SS][.S]X"; - - /** - * Default Timezone used for Serialization and Deserialization. - */ - public static final String TIMEZONE = "UTC"; - - /** - * Supports 0-9 digits of Sub-Second precision storage. (Nano Second Support) - * @return - */ - public static DateTimeFormatter getReaderStixDateTimeFormatter() { - DateTimeFormatterBuilder formatterBuilder = new DateTimeFormatterBuilder() - .appendPattern("yyyy-MM-dd'T'HH:mm:ss") - .optionalStart() - .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true) - .optionalEnd() - .appendPattern("X"); - - return formatterBuilder.toFormatter().withZone(ZoneId.of("UTC")); - } - - public static DateTimeFormatter getWriterStixDateTimeFormatter(int subSecondPrecision) { - if (subSecondPrecision > 9){ - throw new IllegalArgumentException("Sub-Second Precision can only be from 0 to 9 digits"); - } - DateTimeFormatterBuilder formatterBuilder = new DateTimeFormatterBuilder(); - - formatterBuilder.appendPattern("yyyy-MM-dd'T'HH:mm:ss"); - - if (subSecondPrecision > 0){ - formatterBuilder.appendFraction(ChronoField.NANO_OF_SECOND,subSecondPrecision, subSecondPrecision, true); - } - - formatterBuilder.appendPattern("X"); - - return formatterBuilder.toFormatter().withZone(ZoneId.of("UTC")); - } - -} diff --git a/src/main/java/io/digitalstate/stix/helpers/StixSpecVersion.java b/src/main/java/io/digitalstate/stix/helpers/StixSpecVersion.java deleted file mode 100644 index 93b5030..0000000 --- a/src/main/java/io/digitalstate/stix/helpers/StixSpecVersion.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.digitalstate.stix.helpers; - - -public class StixSpecVersion { - - /** - * STIX spec version number - */ - public static final String SPECVERSION = "2.0"; -} diff --git a/src/main/java/io/digitalstate/stix/json/StixBooleanDeserializer.java b/src/main/java/io/digitalstate/stix/json/StixBooleanDeserializer.java deleted file mode 100644 index f29157c..0000000 --- a/src/main/java/io/digitalstate/stix/json/StixBooleanDeserializer.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.digitalstate.stix.json; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.digitalstate.stix.common.StixBoolean; - -import java.io.IOException; - -public class StixBooleanDeserializer extends StdDeserializer { - - public StixBooleanDeserializer(){ - this(null); - } - - public StixBooleanDeserializer(Class vc) { - super(vc); - } - - @Override - public StixBoolean deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { - return new StixBoolean(p.getBooleanValue()); - } -} diff --git a/src/main/java/io/digitalstate/stix/json/StixBooleanSerializer.java b/src/main/java/io/digitalstate/stix/json/StixBooleanSerializer.java deleted file mode 100644 index f8e7940..0000000 --- a/src/main/java/io/digitalstate/stix/json/StixBooleanSerializer.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.digitalstate.stix.json; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import io.digitalstate.stix.common.StixBoolean; - -import java.io.IOException; - -public class StixBooleanSerializer extends StdSerializer { - - public StixBooleanSerializer() { - this(null); - } - - public StixBooleanSerializer(Class t) { - super(t); - } - - @Override - public boolean isEmpty(SerializerProvider provider, StixBoolean value) { - return !value.isdefinedValue(); - //@TODO Future enhancement: Make this a configuration so the impl can decide if non defined values should still be serialized as their default values - } - - @Override - public void serialize(final StixBoolean value, JsonGenerator gen, SerializerProvider provider) throws IOException { - gen.writeBoolean(value.getStixBooleanValue()); - } -} diff --git a/src/main/java/io/digitalstate/stix/json/StixInstantDeserializer.java b/src/main/java/io/digitalstate/stix/json/StixInstantDeserializer.java deleted file mode 100644 index 75c7f5f..0000000 --- a/src/main/java/io/digitalstate/stix/json/StixInstantDeserializer.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.digitalstate.stix.json; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import io.digitalstate.stix.common.StixInstant; - -import java.io.IOException; - -public class StixInstantDeserializer extends StdDeserializer { - - public StixInstantDeserializer(){ - this(null); - } - - public StixInstantDeserializer(Class vc) { - super(vc); - } - - @Override - public StixInstant deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { - return StixInstant.parse(p.getText()); - } -} diff --git a/src/main/java/io/digitalstate/stix/json/StixInstantSerializer.java b/src/main/java/io/digitalstate/stix/json/StixInstantSerializer.java deleted file mode 100644 index 4751998..0000000 --- a/src/main/java/io/digitalstate/stix/json/StixInstantSerializer.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.digitalstate.stix.json; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import io.digitalstate.stix.common.StixInstant; - -import java.io.IOException; - -public class StixInstantSerializer extends StdSerializer { - - public StixInstantSerializer() { - this(null); - } - - public StixInstantSerializer(Class t) { - super(t); - } - - @Override - public void serialize(final StixInstant value, JsonGenerator gen, SerializerProvider provider) throws IOException { - gen.writeString(value.toString()); - } -} diff --git a/src/main/java/io/digitalstate/stix/json/StixParserValidationException.java b/src/main/java/io/digitalstate/stix/json/StixParserValidationException.java deleted file mode 100644 index c46ff17..0000000 --- a/src/main/java/io/digitalstate/stix/json/StixParserValidationException.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.digitalstate.stix.json; - -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; -import javax.validation.ValidationException; -import java.util.Collections; -import java.util.Set; - -public class StixParserValidationException extends RuntimeException { - - public StixParserValidationException(ValidationException exceptionCause) { - super(exceptionCause); - } - - /** - * If Cause is ${@link ConstraintViolationException}, - * then returns the set of constraint validations, or else returns null. - * @return Set of Constraint Violations - */ - public Set> getConstraintValidations() { - if (getCause().getClass().equals(ConstraintViolationException.class)) { - return ((ConstraintViolationException) getCause()).getConstraintViolations(); - } else { - return Collections.emptySet(); - } - } - } diff --git a/src/main/java/io/digitalstate/stix/json/StixParsers.java b/src/main/java/io/digitalstate/stix/json/StixParsers.java deleted file mode 100644 index a1a2f5e..0000000 --- a/src/main/java/io/digitalstate/stix/json/StixParsers.java +++ /dev/null @@ -1,157 +0,0 @@ -package io.digitalstate.stix.json; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.datatype.guava.GuavaModule; -import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import com.fasterxml.jackson.module.paramnames.ParameterNamesModule; -import io.digitalstate.stix.bundle.Bundle; -import io.digitalstate.stix.bundle.BundleObject; -import io.digitalstate.stix.bundle.BundleableObject; -import io.digitalstate.stix.common.Stix; -import io.digitalstate.stix.common.StixBoolean; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.coo.extension.types.*; -import io.digitalstate.stix.coo.objects.*; -import io.digitalstate.stix.coo.objects.Process; -import io.digitalstate.stix.datamarkings.MarkingDefinition; -import io.digitalstate.stix.datamarkings.objects.Statement; -import io.digitalstate.stix.datamarkings.objects.Tlp; -import io.digitalstate.stix.sdo.objects.*; -import io.digitalstate.stix.sro.objects.Relationship; -import io.digitalstate.stix.sro.objects.Sighting; - -import javax.validation.ValidationException; -import java.io.IOException; - -/** - * Default JSON Mapper is configured with JsonMapperBase configs + StixSubTypesModule + StixInstantModule - */ -public class StixParsers { - - private static ObjectMapper jsonMapper = new ObjectMapper() - .registerModule(new ParameterNamesModule()) - .registerModule(new Jdk8Module()) - .registerModule(new JavaTimeModule()) - .registerModule(new GuavaModule()) - .registerModule(generateStixSubTypesModule()) - .registerModule(generateStixInstantModule()) - .registerModule(generateStixBooleanModule()); - - /** - * Generates a Base Object Mapper with some generic modules. - * - * @return - */ - public static ObjectMapper generateJsonMapperBase() { - return new ObjectMapper() - .registerModule(new ParameterNamesModule()) - .registerModule(new Jdk8Module()) - .registerModule(new JavaTimeModule()) - .registerModule(new GuavaModule()); - } - - public static ObjectMapper getJsonMapper() { - return jsonMapper; - } - - /** - * Override for setting a custom configured ObjectMapper - * - * @param objectMapper - */ - public static void setJsonMapper(ObjectMapper objectMapper) { - jsonMapper = objectMapper; - } - - /** - * Generate a Jackson module for all STIX objects (SDOs, SROs, Markings, bundle, observables, and observable extensions) - * - * @return - */ - public static SimpleModule generateStixSubTypesModule() { - SimpleModule module = new SimpleModule(); - - Class[] sdoClasses = {AttackPattern.class, Campaign.class, CourseOfAction.class, - Identity.class, Indicator.class, IntrusionSet.class, Malware.class, ObservedData.class, - Report.class, ThreatActor.class, Tool.class, Vulnerability.class}; - - Class[] sroClasses = {Relationship.class, Sighting.class}; - - Class[] dataMarkingClasses = {MarkingDefinition.class, Statement.class, Tlp.class}; - - Class[] bundleClasses = {Bundle.class}; - - Class[] cyberObservableClasses = {Artifact.class, AutonomousSystem.class, Directory.class, - DomainName.class, EmailAddress.class, EmailMessage.class, File.class, Ipv4Address.class, Ipv6Address.class, - MacAddress.class, Mutex.class, NetworkTraffic.class, Process.class, Software.class, Url.class, - UserAccount.class, WindowsRegistryKey.class, X509Certificate.class}; - - Class[] cyberObservableExtensionClasses = {ArchiveFileExtension.class, HttpRequestExtension.class, IcmpExtension.class, - NetworkSocketExtension.class, NtfsFileExtenstion.class, PdfFileExtension.class, RasterImageFileExtension.class, - TcpExtension.class, UnixAccountExtension.class, WindowsPeBinaryFileExtension.class, WindowsProcessExtension.class, - WindowsServiceExtension.class}; - - module.registerSubtypes(sdoClasses); - module.registerSubtypes(sroClasses); - module.registerSubtypes(dataMarkingClasses); - module.registerSubtypes(bundleClasses); - module.registerSubtypes(cyberObservableClasses); - module.registerSubtypes(cyberObservableExtensionClasses); - - return module; - } - - public static SimpleModule generateStixInstantModule() { - SimpleModule module = new SimpleModule(); - module.addSerializer(StixInstant.class, new StixInstantSerializer()); - module.addDeserializer(StixInstant.class, new StixInstantDeserializer()); - return module; - } - - public static SimpleModule generateStixBooleanModule() { - SimpleModule module = new SimpleModule(); - module.addSerializer(StixBoolean.class, new StixBooleanSerializer()); - module.addDeserializer(StixBoolean.class, new StixBooleanDeserializer()); - return module; - } - - public static BundleObject parseBundle(String bundleJsonString) throws IOException, StixParserValidationException { - try { - return getJsonMapper().readValue(bundleJsonString, BundleObject.class); - } catch (IOException ex) { - if (ValidationException.class.isAssignableFrom(ex.getCause().getClass())) { - throw new StixParserValidationException((ValidationException) ex.getCause()); - } else { - throw ex; - } - } - } - - public static BundleableObject parseObject(String objectJsonString) throws IOException, StixParserValidationException { - try { - return getJsonMapper().readValue(objectJsonString, BundleableObject.class); - } catch (IOException ex) { - if (ValidationException.class.isAssignableFrom(ex.getCause().getClass())) { - throw new StixParserValidationException((ValidationException) ex.getCause()); - } else { - throw ex; - } - } - } - - public static T parse(String bundleJsonString, Class stixClass) throws IOException, StixParserValidationException { - try { - return getJsonMapper().readValue(bundleJsonString, stixClass); - } catch (IOException ex) { - if (ValidationException.class.isAssignableFrom(ex.getCause().getClass())) { - throw new StixParserValidationException((ValidationException) ex.getCause()); - } else { - throw ex; - } - } - } -} diff --git a/src/main/java/io/digitalstate/stix/json/converters/dehydrated/BundleableObjectConverter.java b/src/main/java/io/digitalstate/stix/json/converters/dehydrated/BundleableObjectConverter.java deleted file mode 100644 index d320502..0000000 --- a/src/main/java/io/digitalstate/stix/json/converters/dehydrated/BundleableObjectConverter.java +++ /dev/null @@ -1,42 +0,0 @@ -package io.digitalstate.stix.json.converters.dehydrated; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.util.StdConverter; -import io.digitalstate.stix.bundle.BundleableObject; -import io.digitalstate.stix.json.StixParsers; - -/** - * Generates a Dehydrated Bundleable Object based on a ID. - */ -public class BundleableObjectConverter extends StdConverter { - - @Override - public BundleableObject convert(String value) { - String[] parsedValue = value.split("--"); - - if (parsedValue.length == 2){ - ObjectMapper mapper = StixParsers.getJsonMapper(); - ObjectNode node = mapper.createObjectNode(); - - node.put("type", parsedValue[0]); - node.put("id", value); - node.put("hydrated", false); - - - try { - BundleableObject bundleableObject = mapper.treeToValue(node, BundleableObject.class); - //@TODO add more logic - return bundleableObject; - - } catch (JsonProcessingException e) { - e.printStackTrace(); - throw new IllegalArgumentException("Cannot Parse Json: " + e.getMessage()); - } - - } else { - throw new IllegalArgumentException("Id is not valid format, Cannot Parse Value: " + value); - } - } -} \ No newline at end of file diff --git a/src/main/java/io/digitalstate/stix/json/converters/dehydrated/BundleableObjectSetConverter.java b/src/main/java/io/digitalstate/stix/json/converters/dehydrated/BundleableObjectSetConverter.java deleted file mode 100644 index 7b650c9..0000000 --- a/src/main/java/io/digitalstate/stix/json/converters/dehydrated/BundleableObjectSetConverter.java +++ /dev/null @@ -1,49 +0,0 @@ -package io.digitalstate.stix.json.converters.dehydrated; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.util.StdConverter; -import io.digitalstate.stix.bundle.BundleableObject; -import io.digitalstate.stix.json.StixParsers; - -import java.util.HashSet; -import java.util.Set; - -/** - * Generates a Dehydrated Bundleable Object based on a ID from a Set of BundleableObjects. - */ -public class BundleableObjectSetConverter extends StdConverter, Set> { - - @Override - public Set convert(Set values) { - Set bundleableObjectSet = new HashSet<>(); - values.forEach(v -> { - String[] parsedValue = v.split("--"); - - if (parsedValue.length == 2) { - ObjectMapper mapper = StixParsers.getJsonMapper(); - ObjectNode node = mapper.createObjectNode(); - - node.put("type", parsedValue[0]); - node.put("id", v); - node.put("hydrated", false); - - - try { - BundleableObject bundleableObject = mapper.treeToValue(node, BundleableObject.class); - //@TODO add more logic - bundleableObjectSet.add(bundleableObject); - - } catch (JsonProcessingException e) { - e.printStackTrace(); - throw new IllegalArgumentException("Cannot Parse Json: " + e.getMessage()); - } - - } else { - throw new IllegalArgumentException("Id is not valid format, Cannot Parse Value: " + v); - } - }); - return bundleableObjectSet; - } -} \ No newline at end of file diff --git a/src/main/java/io/digitalstate/stix/json/converters/dehydrated/DomainObjectConverter.java b/src/main/java/io/digitalstate/stix/json/converters/dehydrated/DomainObjectConverter.java deleted file mode 100644 index 453f13b..0000000 --- a/src/main/java/io/digitalstate/stix/json/converters/dehydrated/DomainObjectConverter.java +++ /dev/null @@ -1,42 +0,0 @@ -package io.digitalstate.stix.json.converters.dehydrated; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.util.StdConverter; -import io.digitalstate.stix.json.StixParsers; -import io.digitalstate.stix.sdo.DomainObject; - -/** - * Generates a Dehydrated Domain Object based on a ID. - */ -public class DomainObjectConverter extends StdConverter { - - @Override - public DomainObject convert(String value) { - String[] parsedValue = value.split("--"); - - if (parsedValue.length == 2){ - ObjectMapper mapper = StixParsers.getJsonMapper(); - ObjectNode node = mapper.createObjectNode(); - - node.put("type", parsedValue[0]); - node.put("id", value); - node.put("hydrated", false); - - - try { - DomainObject domainObject = mapper.treeToValue(node, DomainObject.class); - //@TODO add more logic - return domainObject; - - } catch (JsonProcessingException e) { - e.printStackTrace(); - throw new IllegalArgumentException("Cannot Parse Json: " + e.getMessage()); - } - - } else { - throw new IllegalArgumentException("Id is not valid format, Cannot Parse Value: " + value); - } - } -} \ No newline at end of file diff --git a/src/main/java/io/digitalstate/stix/json/converters/dehydrated/DomainObjectOptionalConverter.java b/src/main/java/io/digitalstate/stix/json/converters/dehydrated/DomainObjectOptionalConverter.java deleted file mode 100644 index 6840819..0000000 --- a/src/main/java/io/digitalstate/stix/json/converters/dehydrated/DomainObjectOptionalConverter.java +++ /dev/null @@ -1,43 +0,0 @@ -package io.digitalstate.stix.json.converters.dehydrated; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.util.StdConverter; -import io.digitalstate.stix.json.StixParsers; -import io.digitalstate.stix.sdo.DomainObject; - -import java.util.Optional; - -/** - * Generates a Dehydrated Domain Object based on a ID. - */ -public class DomainObjectOptionalConverter extends StdConverter> { - - @Override - public Optional convert(String value) { - String[] parsedValue = value.split("--"); - - if (parsedValue.length == 2){ - ObjectMapper mapper = StixParsers.getJsonMapper(); - ObjectNode node = mapper.createObjectNode(); - - node.put("type", parsedValue[0]); - node.put("id", value); - node.put("hydrated", false); - - - try { - return Optional.ofNullable(mapper.treeToValue(node, DomainObject.class)); - //@TODO add more logic - - } catch (JsonProcessingException e) { - e.printStackTrace(); - throw new IllegalArgumentException("Cannot Parse Json: " + e.getMessage()); - } - - } else { - throw new IllegalArgumentException("Id is not valid format, Cannot Parse Value: " + value); - } - } -} \ No newline at end of file diff --git a/src/main/java/io/digitalstate/stix/json/converters/dehydrated/MarkingDefinitionConverter.java b/src/main/java/io/digitalstate/stix/json/converters/dehydrated/MarkingDefinitionConverter.java deleted file mode 100644 index 702907d..0000000 --- a/src/main/java/io/digitalstate/stix/json/converters/dehydrated/MarkingDefinitionConverter.java +++ /dev/null @@ -1,42 +0,0 @@ -package io.digitalstate.stix.json.converters.dehydrated; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.util.StdConverter; -import io.digitalstate.stix.datamarkings.MarkingDefinitionDm; -import io.digitalstate.stix.json.StixParsers; - -/** - * Generates a Dehydrated Domain Object based on a ID. - */ -public class MarkingDefinitionConverter extends StdConverter { - - @Override - public MarkingDefinitionDm convert(String value) { - String[] parsedValue = value.split("--"); - - if (parsedValue.length == 2){ - ObjectMapper mapper = StixParsers.getJsonMapper(); - ObjectNode node = mapper.createObjectNode(); - - node.put("type", parsedValue[0]); - node.put("id", value); - node.put("hydrated", false); - - - try { - MarkingDefinitionDm domainObject = mapper.treeToValue(node, MarkingDefinitionDm.class); - //@TODO add more logic - return domainObject; - - } catch (JsonProcessingException e) { - e.printStackTrace(); - throw new IllegalArgumentException("Cannot Parse Json: " + e.getMessage()); - } - - } else { - throw new IllegalArgumentException("Id is not valid format, Cannot Parse Value: " + value); - } - } -} \ No newline at end of file diff --git a/src/main/java/io/digitalstate/stix/json/converters/dehydrated/MarkingDefinitionSetConverter.java b/src/main/java/io/digitalstate/stix/json/converters/dehydrated/MarkingDefinitionSetConverter.java deleted file mode 100644 index ba7b66e..0000000 --- a/src/main/java/io/digitalstate/stix/json/converters/dehydrated/MarkingDefinitionSetConverter.java +++ /dev/null @@ -1,48 +0,0 @@ -package io.digitalstate.stix.json.converters.dehydrated; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.util.StdConverter; -import io.digitalstate.stix.datamarkings.MarkingDefinitionDm; -import io.digitalstate.stix.json.StixParsers; - -import java.util.HashSet; -import java.util.Set; - -/** - * Generates a Dehydrated Marking Definition Set used for Deserialization - */ -public class MarkingDefinitionSetConverter extends StdConverter, Set> { - - @Override - public Set convert(Set values) { - Set markDefSet = new HashSet<>(); - values.forEach(v -> { - String[] parsedValue = v.split("--"); - - if (parsedValue.length == 2) { - ObjectMapper mapper = StixParsers.getJsonMapper(); - ObjectNode node = mapper.createObjectNode(); - - node.put("type", parsedValue[0]); - node.put("id", v); - node.put("hydrated", false); - - try { - MarkingDefinitionDm markingDef = mapper.treeToValue(node, MarkingDefinitionDm.class); - //@TODO add more logic - markDefSet.add(markingDef); - - } catch (JsonProcessingException e) { - e.printStackTrace(); - throw new IllegalArgumentException("Cannot Parse Json: " + e.getMessage()); - } - - } else { - throw new IllegalArgumentException("Id is not valid format, Cannot Parse Value: " + v); - } - }); - return markDefSet; - } -} \ No newline at end of file diff --git a/src/main/java/io/digitalstate/stix/redaction/Redactable.java b/src/main/java/io/digitalstate/stix/redaction/Redactable.java deleted file mode 100644 index dd47a50..0000000 --- a/src/main/java/io/digitalstate/stix/redaction/Redactable.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.digitalstate.stix.redaction; - -import org.immutables.annotate.InjectAnnotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.*; - -/** - * Marker to indicate which classes and methods are Redactable. - * Redaction is the modification of JSON properties or removal of properties and - * entire objects during serialization based on STIX Marking Definitions and Granular Markings. - */ -@Documented -@Target( { ANNOTATION_TYPE, TYPE, METHOD }) -@Retention(RetentionPolicy.RUNTIME) -@InjectAnnotation(target = {InjectAnnotation.Where.ACCESSOR, InjectAnnotation.Where.IMMUTABLE_TYPE}, code = "([[*]])", type = Redactable.class) -public @interface Redactable { - - boolean useMask() default false; - String redactionMask() default ""+ ((char)0x2588) + ((char)0x2588) + "REDACTED" + ((char)0x2588) + ((char)0x2588); - - //@TODO: - // Add Masking config - // Add Conditional - // Add object Refs -} diff --git a/src/main/java/io/digitalstate/stix/redaction/processors/BundleableObjectRedactionProcessor.java b/src/main/java/io/digitalstate/stix/redaction/processors/BundleableObjectRedactionProcessor.java deleted file mode 100644 index aa2894d..0000000 --- a/src/main/java/io/digitalstate/stix/redaction/processors/BundleableObjectRedactionProcessor.java +++ /dev/null @@ -1,117 +0,0 @@ -package io.digitalstate.stix.redaction.processors; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.jayway.jsonpath.Configuration; -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import com.jayway.jsonpath.Option; -import io.digitalstate.stix.bundle.BundleableObject; -import io.digitalstate.stix.datamarkings.GranularMarkingDm; -import io.digitalstate.stix.datamarkings.MarkingDefinitionDm; -import io.digitalstate.stix.datamarkings.StixMarkingObject; -import io.digitalstate.stix.redaction.Redactable; - -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -public class BundleableObjectRedactionProcessor { - - public static String processObject(BundleableObject bundleableObject, String jsonString, Set subjectsMarkingObjects) { - - String block = Character.toString((char) 0x2588); - String redactedMaskValue = block + block + "REDACTED" + block + block; - - Set markingDefinitionsSet = bundleableObject.getObjectMarkingRefs(); - - if (!markingDefinitionsSet.isEmpty()) { - // @TODO look into how to allow injection of annotaiton in multiple locations -// Redactable classRedactable = Optional.ofNullable(bundleableObject.getClass().getDeclaredAnnotation(Redactable.class)) -// .orElseThrow(IllegalStateException::new); - - Set objectMarkings = markingDefinitionsSet.stream() - .filter(md -> md.getDefinitionType().equals("tlp")) - .map(MarkingDefinitionDm::getDefinition) - .collect(Collectors.toSet()); - - if (!subjectsMarkingObjects.containsAll(objectMarkings)) { - return "{}"; - } - } - - - Set granularMarkingDms = bundleableObject.getGranularMarkings(); - - if (!granularMarkingDms.isEmpty()) { - Configuration conf = Configuration.builder() - .options(Option.AS_PATH_LIST).build(); - DocumentContext doc = JsonPath.using(conf).parse(jsonString); - - Set getMethods = Arrays.stream(bundleableObject.getClass().getDeclaredMethods()) - .filter(m -> m.getAnnotation(JsonProperty.class) != null) - .filter(m -> m.getName().startsWith("get")) - .collect(Collectors.toSet()); - System.out.println("getMethods: " + getMethods.toString()); - - granularMarkingDms.forEach(gm -> { - MarkingDefinitionDm markingDefinition = gm.getMarkingRef(); - StixMarkingObject markingObject = gm.getMarkingRef().getDefinition(); - Set selectors = gm.getSelectors(); - - if (markingDefinition.getDefinitionType().equals("tlp") && !subjectsMarkingObjects.contains(markingObject)) { - selectors.forEach(s -> { - - // Parse the selectors into JsonPath - List pathLists = doc.read("$." + s); - System.out.println("Parsed Selector Matches: " + pathLists.toString()); - - - final String regex = "\\$\\['(.*?)'\\]"; - final Pattern pattern = Pattern.compile(regex); - - pathLists.forEach(path -> { - // @TODO refactor to support multiple levels of inner object redaction - - Matcher jsonPathPropertyNameMatcher = pattern.matcher(path); - boolean matcherResult = jsonPathPropertyNameMatcher.find(); - if (!matcherResult) { - throw new IllegalStateException("Cannot make a match / cannot parse the json path pattern"); - } else if (jsonPathPropertyNameMatcher.groupCount() > 1) { - throw new IllegalStateException("Cannot make a match / Multiple Matches found"); - } - String jsonPathPropertyName = jsonPathPropertyNameMatcher.group(1); - - - Method methodForPath = getMethods.stream() - .filter(m -> m.getDeclaredAnnotation(JsonProperty.class).value().equals(jsonPathPropertyName)) - .findFirst().orElseThrow(IllegalStateException::new); - String jacksonPropertyName = methodForPath.getAnnotation(JsonProperty.class).value(); - - System.out.println("jsonPathName: " + jsonPathPropertyName); - System.out.println("JacksonPathname: " + jacksonPropertyName); - - Redactable redactableAnn = Optional - .ofNullable(methodForPath.getDeclaredAnnotation(Redactable.class)) - .orElseThrow(IllegalStateException::new); - - // Redaction Logic: - if (redactableAnn.useMask()) { - doc.set(path, redactableAnn.redactionMask()); - } else { - doc.delete(path); - } - - }); - }); - } - }); - return doc.jsonString(); - } - return jsonString; - } -} diff --git a/src/main/java/io/digitalstate/stix/sdo/DomainObject.java b/src/main/java/io/digitalstate/stix/sdo/DomainObject.java deleted file mode 100644 index 32ab918..0000000 --- a/src/main/java/io/digitalstate/stix/sdo/DomainObject.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.digitalstate.stix.sdo; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import io.digitalstate.stix.common.*; -import io.digitalstate.stix.sro.objects.RelationshipSro; - -import javax.validation.constraints.NotNull; -import java.io.Serializable; -import java.util.Set; - -/** - * Base interface used by Immutable STIX Domain Objects - */ -public interface DomainObject extends Serializable, - StixCommonProperties, - StixCustomProperties, - StixLabels, - StixModified, - StixRevoked{ - - /** - * This is used with the SROs. The SRO interface enforces what relationships can be created. The Relationships can then be stored in the Domain object if they choose. - * Otherwise you would typically add these Relationship SROs that are specific to SDOs, can be grabbed during bundle creation. - * @return Set of Relationship SROs - */ - @NotNull - @JsonIgnore - Set getRelationships(); - -} diff --git a/src/main/java/io/digitalstate/stix/sdo/objects/AttackPatternSdo.java b/src/main/java/io/digitalstate/stix/sdo/objects/AttackPatternSdo.java deleted file mode 100644 index 40d7fe9..0000000 --- a/src/main/java/io/digitalstate/stix/sdo/objects/AttackPatternSdo.java +++ /dev/null @@ -1,56 +0,0 @@ -package io.digitalstate.stix.sdo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.sdo.types.KillChainPhaseType; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * attack-pattern - *

- * Attack Patterns are a type of TTP that describe ways that adversaries attempt to compromise targets. - * - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "attack-pattern", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Sdo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonTypeName("attack-pattern") -@JsonSerialize(as = AttackPattern.class) @JsonDeserialize(builder = AttackPattern.Builder.class) -@JsonPropertyOrder({"type", "id", "created_by_ref", "created", - "modified", "revoked", "labels", "external_references", - "object_marking_refs", "granular_markings", - "name", "description", "kill_chain_phases"}) -@Redactable -public interface AttackPatternSdo extends DomainObject { - - @NotBlank - @JsonProperty("name") - @JsonPropertyDescription("The name used to identify the Attack Pattern.") - @Redactable(useMask = true) - String getName(); - - @JsonProperty("description") - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("A description that provides more details and context about the Attack Pattern, potentially including its purpose and its key characteristics.") - @Redactable - Optional getDescription(); - - @JsonProperty("kill_chain_phases") - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("The list of kill chain phases for which this attack pattern is used.") - @Redactable - Set getKillChainPhases(); - -} \ No newline at end of file diff --git a/src/main/java/io/digitalstate/stix/sdo/objects/CampaignSdo.java b/src/main/java/io/digitalstate/stix/sdo/objects/CampaignSdo.java deleted file mode 100644 index 5a63ee1..0000000 --- a/src/main/java/io/digitalstate/stix/sdo/objects/CampaignSdo.java +++ /dev/null @@ -1,76 +0,0 @@ -package io.digitalstate.stix.sdo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import java.time.Instant; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * campaign - *

- * A Campaign is a grouping of adversary behavior that describes a set of malicious activities or attacks that occur over a period of time against a specific set of targets. - * - */ -@Value.Immutable @Serial.Version(1L) -@JsonTypeName("campaign") -@DefaultTypeValue(value = "campaign", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Sdo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = Campaign.class) @JsonDeserialize(builder = Campaign.Builder.class) -@JsonPropertyOrder({"type", "id", "created_by_ref", "created", - "modified", "revoked", "labels", "external_references", - "object_marking_refs", "granular_markings", "name", "description", - "aliases", "first_seen", "last_seen", "objective"}) -@Redactable -public interface CampaignSdo extends DomainObject { - - @NotBlank - @JsonProperty("name") - @JsonPropertyDescription("The name used to identify the Campaign.") - @Redactable(useMask = true) - String getName(); - - @JsonProperty("description") - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("A description that provides more details and context about the Campaign, potentially including its purpose and its key characteristics.") - @Redactable - Optional getDescription(); - - @NotNull - @JsonProperty("aliases") - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("Alternative names used to identify this campaign.") - @Redactable - Set getAliases(); - - @JsonProperty("first_seen") - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("The time that this Campaign was first seen.") - @Redactable - Optional getFirstSeen(); - - //@TODO add support to ensure that Last Seen is AFTER the First Seen value - @JsonProperty("last_seen") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("The time that this Campaign was last seen.") - @Redactable - Optional getLastSeen(); - - @JsonProperty("objective") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("This field defines the Campaign’s primary goal, objective, desired outcome, or intended effect.") - @Redactable - Optional getObjective(); - -} diff --git a/src/main/java/io/digitalstate/stix/sdo/objects/CourseOfActionSdo.java b/src/main/java/io/digitalstate/stix/sdo/objects/CourseOfActionSdo.java deleted file mode 100644 index 0d4d67e..0000000 --- a/src/main/java/io/digitalstate/stix/sdo/objects/CourseOfActionSdo.java +++ /dev/null @@ -1,57 +0,0 @@ -package io.digitalstate.stix.sdo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * course-of-action - *

- * A Course of Action is an action taken either to prevent an attack or to respond to an attack that is in progress. - * - */ -@Value.Immutable @Serial.Version(1L) -@JsonTypeName("course-of-action") -@DefaultTypeValue(value = "course-of-action", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Sdo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = CourseOfAction.class) @JsonDeserialize(builder = CourseOfAction.Builder.class) -@JsonPropertyOrder({"type", "id", "created_by_ref", "created", - "modified", "revoked", "labels", "external_references", - "object_marking_refs", "granular_markings", "name", - "description", "action"}) -@Redactable -public interface CourseOfActionSdo extends DomainObject { - - @NotBlank - @JsonProperty("name") - @JsonPropertyDescription("The name used to identify the Course of Action.") - @Redactable(useMask = true) - String getName(); - - @JsonProperty("description") - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("A description that provides more details and context about the Course of Action, potentially including its purpose and its key characteristics.") - @Redactable - Optional getDescription(); - - @NotNull - @JsonProperty("action") - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("RESERVED – To capture structured/automated courses of action.") - @Redactable(useMask = true) - Set getAction(); - -} diff --git a/src/main/java/io/digitalstate/stix/sdo/objects/IdentitySdo.java b/src/main/java/io/digitalstate/stix/sdo/objects/IdentitySdo.java deleted file mode 100644 index 33396f9..0000000 --- a/src/main/java/io/digitalstate/stix/sdo/objects/IdentitySdo.java +++ /dev/null @@ -1,76 +0,0 @@ -package io.digitalstate.stix.sdo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.contraints.vocab.Vocab; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import io.digitalstate.stix.vocabulary.vocabularies.IdentityClasses; -import io.digitalstate.stix.vocabulary.vocabularies.IndustrySectors; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * identity - *

- * Identities can represent actual individuals, organizations, or groups (e.g., ACME, Inc.) as well as classes of individuals, organizations, or groups. - * - */ -@Value.Immutable @Serial.Version(1L) -@JsonTypeName("identity") -@DefaultTypeValue(value = "identity", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Sdo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = Identity.class) @JsonDeserialize(builder = Identity.Builder.class) -@JsonPropertyOrder({"type", "id", "created_by_ref", "created", - "modified", "revoked", "labels", "external_references", - "object_marking_refs", "granular_markings", "name", "description", - "identity_class", "sectors", "contact_information"}) -@Redactable -public interface IdentitySdo extends DomainObject { - - // Note for the labels attribute: - // The list of roles that this Identity performs (e.g., CEO, Domain Administrators, Doctors, Hospital, or Retailer). No open vocabulary is yet defined for this property. - - @NotBlank - @JsonProperty("name") - @JsonPropertyDescription("The name of this Identity.") - @Redactable(useMask = true) - String getName(); - - @JsonProperty("description") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("A description that provides more details and context about the Identity.") - @Redactable - Optional getDescription(); - - @NotBlank - @Vocab(IdentityClasses.class) - @JsonProperty("identity_class") - @JsonPropertyDescription("The type of entity that this Identity describes, e.g., an individual or organization. Open Vocab - identity-class-ov") - @Redactable(useMask = true) - String getIdentityClass(); - - @NotNull - @Vocab(IndustrySectors.class) - @JsonProperty("sectors") - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("The list of sectors that this Identity belongs to. Open Vocab - industry-sector-ov") - @Redactable - Set getSectors(); - - @JsonProperty("contact_information") - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("The contact information (e-mail, phone number, etc.) for this Identity.") - @Redactable - Optional getContactInformation(); - -} diff --git a/src/main/java/io/digitalstate/stix/sdo/objects/IndicatorSdo.java b/src/main/java/io/digitalstate/stix/sdo/objects/IndicatorSdo.java deleted file mode 100644 index 5493156..0000000 --- a/src/main/java/io/digitalstate/stix/sdo/objects/IndicatorSdo.java +++ /dev/null @@ -1,86 +0,0 @@ -package io.digitalstate.stix.sdo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.sdo.types.KillChainPhaseType; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.contraints.vocab.Vocab; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import io.digitalstate.stix.vocabulary.vocabularies.IndicatorLabels; -import org.hibernate.validator.constraints.Length; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.time.Instant; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * indicator - *

- * Indicators contain a pattern that can be used to detect suspicious or malicious cyber activity. - * - */ -@Value.Immutable @Serial.Version(1L) -@JsonTypeName("indicator") -@DefaultTypeValue(value = "indicator", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Sdo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = Indicator.class) @JsonDeserialize(builder = Indicator.Builder.class) -@JsonPropertyOrder({"type", "id", "created_by_ref", "created", - "modified", "revoked", "labels", "external_references", - "object_marking_refs", "granular_markings", "name", - "description", "pattern", "valid_from", "valid_until", - "kill_chain_phases"}) -@Redactable -public interface IndicatorSdo extends DomainObject { - - @Override - @NotNull @Size(min = 1) - @Vocab(IndicatorLabels.class) - @JsonPropertyDescription("This field is an Open Vocabulary that specifies the type of indicator. Open vocab - indicator-label-ov") - @Redactable(useMask = true) - Set<@Length(min = 1) String> getLabels(); - - @JsonProperty("name") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("The name used to identify the Indicator.") - @Redactable - Optional getName(); - - @JsonProperty("description") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("A description that provides more details and context about this Indicator, potentially including its purpose and its key characteristics.") - @Redactable - Optional getDescription(); - - @NotBlank - @JsonProperty("pattern") - @JsonPropertyDescription("The detection pattern for this indicator. The default language is STIX Patterning.") - @Redactable(useMask = true) - String getPattern(); - - @NotNull - @JsonProperty("valid_from") - @JsonPropertyDescription("The time from which this indicator should be considered valuable intelligence.") - @Redactable(useMask = true) - StixInstant getValidFrom(); - - @JsonProperty("valid_until") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("The time at which this indicator should no longer be considered valuable intelligence.") - @Redactable - Optional getValidUntil(); - - @NotNull - @JsonProperty("kill_chain_phases") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("The list of kill chain phases for which this attack pattern is used.") - @Redactable - Set getKillChainPhases(); - -} diff --git a/src/main/java/io/digitalstate/stix/sdo/objects/IntrusionSetSdo.java b/src/main/java/io/digitalstate/stix/sdo/objects/IntrusionSetSdo.java deleted file mode 100644 index 41ac603..0000000 --- a/src/main/java/io/digitalstate/stix/sdo/objects/IntrusionSetSdo.java +++ /dev/null @@ -1,94 +0,0 @@ -package io.digitalstate.stix.sdo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.contraints.vocab.Vocab; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import io.digitalstate.stix.vocabulary.vocabularies.AttackMotivations; -import io.digitalstate.stix.vocabulary.vocabularies.AttackResourceLevels; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import java.time.Instant; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * intrusion-set - *

- * An Intrusion Set is a grouped set of adversary behavior and resources with common properties that is believed to be orchestrated by a single organization. - * - */ -@Value.Immutable @Serial.Version(1L) -@JsonTypeName("intrusion-set") -@DefaultTypeValue(value = "intrusion-set", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Sdo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = IntrusionSet.class) @JsonDeserialize(builder = IntrusionSet.Builder.class) -@JsonPropertyOrder({"type", "id", "created_by_ref", "created", - "modified", "revoked", "labels", "external_references", - "object_marking_refs", "granular_markings", "name", "description", "aliases", - "first_seen", "last_seen", "goals", "resource_level", - "primary_motivation", "secondary_motivation"}) -@Redactable -public interface IntrusionSetSdo extends DomainObject { - - @NotBlank - @JsonProperty("name") - @JsonPropertyDescription("The name used to identify the Intrusion Set.") - @Redactable(useMask = true) - String getName(); - - @JsonProperty("description") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("Provides more context and details about the Intrusion Set object.") - @Redactable - Optional getDescription(); - - @NotNull - @JsonProperty("aliases") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("Alternative names used to identify this Intrusion Set.") - @Redactable - Set getAliases(); - - @JsonProperty("first_seen") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("The time that this Intrusion Set was first seen.") - @Redactable - Optional getFirstSeen(); - - @JsonProperty("last_seen") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("The time that this Intrusion Set was last seen.") - @Redactable - Optional getLastSeen(); - - @NotNull - @JsonProperty("goals") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("The high level goals of this Intrusion Set, namely, what are they trying to do.") - @Redactable - Set getGoals(); - - @JsonProperty("resource_level") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("This defines the organizational level at which this Intrusion Set typically works. Open Vocab - attack-resource-level-ov") - @Redactable - Optional<@Vocab(AttackResourceLevels.class) String> getResourceLevel(); - - @JsonProperty("primary_motivation") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("The primary reason, motivation, or purpose behind this Intrusion Set. Open Vocab - attack-motivation-ov") - @Redactable - Optional<@Vocab(AttackMotivations.class) String> getPrimaryMotivation(); - - @NotNull - @Vocab(AttackMotivations.class) - @JsonProperty("secondary_motivations") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("The secondary reasons, motivations, or purposes behind this Intrusion Set. Open Vocab - attack-motivation-ov") - @Redactable - Set getSecondaryMotivations(); - -} diff --git a/src/main/java/io/digitalstate/stix/sdo/objects/MalwareSdo.java b/src/main/java/io/digitalstate/stix/sdo/objects/MalwareSdo.java deleted file mode 100644 index c3672d8..0000000 --- a/src/main/java/io/digitalstate/stix/sdo/objects/MalwareSdo.java +++ /dev/null @@ -1,69 +0,0 @@ -package io.digitalstate.stix.sdo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.sdo.types.KillChainPhaseType; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.contraints.vocab.Vocab; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import io.digitalstate.stix.vocabulary.vocabularies.MalwareLabels; -import org.hibernate.validator.constraints.Length; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - - -/** - * malware - *

- * Malware is a type of TTP that is also known as malicious code and malicious software, refers to a program that is inserted into a system, - * usually covertly, with the intent of compromising the confidentiality, integrity, or availability of the victim's data, applications, - * or operating system (OS) or of otherwise annoying or disrupting the victim. - */ -@Value.Immutable @Serial.Version(1L) -@DefaultTypeValue(value = "malware", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Sdo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonTypeName("malware") -@JsonSerialize(as = Malware.class) @JsonDeserialize(builder = Malware.Builder.class) -@JsonPropertyOrder({"type", "id", "created_by_ref", "created", - "modified", "revoked", "labels", "external_references", - "object_marking_refs", "granular_markings", "name", "description", - "kill_chain_phases"}) -@Redactable -public interface MalwareSdo extends DomainObject { - - @Override - @Vocab(MalwareLabels.class) - @JsonPropertyDescription("The type of malware being described. Open Vocab - malware-label-ov") - @NotNull @Size(min = 1, message = "At least one label from malware-label-ov must be used") - @Redactable(useMask = true) - Set<@Length(min = 1) String> getLabels(); - - @NotBlank - @JsonProperty("name") - @JsonPropertyDescription("The name used to identify the Malware.") - @Redactable(useMask = true) - String getName(); - - @JsonProperty("description") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("Provides more context and details about the Malware object.") - @Redactable - Optional getDescription(); - - @NotNull - @JsonProperty("kill_chain_phases") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("The list of kill chain phases for which this Malware instance can be used.") - @Redactable - Set getKillChainPhases(); - -} diff --git a/src/main/java/io/digitalstate/stix/sdo/objects/ObservedDataSdo.java b/src/main/java/io/digitalstate/stix/sdo/objects/ObservedDataSdo.java deleted file mode 100644 index 1a3169d..0000000 --- a/src/main/java/io/digitalstate/stix/sdo/objects/ObservedDataSdo.java +++ /dev/null @@ -1,73 +0,0 @@ -package io.digitalstate.stix.sdo.objects; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyDescription; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import com.fasterxml.jackson.annotation.JsonTypeName; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.coo.json.observables.CyberObservableSetFieldDeserializer; -import io.digitalstate.stix.coo.json.observables.CyberObservableSetFieldSerializer; -import io.digitalstate.stix.json.StixInstantDeserializer; -import io.digitalstate.stix.json.StixInstantSerializer; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.hibernate.validator.constraints.Range; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Positive; -import javax.validation.constraints.Size; -import java.time.Instant; -import java.util.Set; -/** - * observed-data - *

- * Observed data conveys information that was observed on systems and networks, such as log data or network traffic, using the Cyber Observable specification. - * - */ -@Value.Immutable @Serial.Version(1L) -@JsonTypeName("observed-data") -@DefaultTypeValue(value = "observed-data", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Sdo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = ObservedData.class) @JsonDeserialize(builder = ObservedData.Builder.class) -@JsonPropertyOrder({"type", "id", "created_by_ref", "created", - "modified", "revoked", "labels", "external_references", - "object_marking_refs", "granular_markings", "first_observed", "last_observed", - "number_observed", "objects"}) -@Redactable -public interface ObservedDataSdo extends DomainObject { - - @NotNull - @JsonProperty("first_observed") - @JsonPropertyDescription("The beginning of the time window that the data was observed during.") - @Redactable(useMask = true) - StixInstant getFirstObserved(); - - @NotNull - @JsonProperty("last_observed") - @JsonPropertyDescription("The end of the time window that the data was observed during.") - @Redactable(useMask = true) - StixInstant getLastObserved(); - - @NotNull @Positive - @JsonProperty("number_observed") - @JsonPropertyDescription("The number of times the data represented in the objects property was observed. This MUST be an integer between 1 and 999,999,999 inclusive.") - @Redactable(useMask = true) - @Range(min = 1, max = 999999999) - Integer getNumberObserved(); - - @NotNull @Size(min = 1, message = "At least one Cyber Observable Reference must be provided") - @JsonProperty("objects") - @JsonPropertyDescription("A dictionary of Cyber Observable Objects that describes the single 'fact' that was observed.") - @Redactable(useMask = true) - @JsonSerialize(using = CyberObservableSetFieldSerializer.class) - @JsonDeserialize(using = CyberObservableSetFieldDeserializer.class) - Set getObjects(); - -} diff --git a/src/main/java/io/digitalstate/stix/sdo/objects/ReportSdo.java b/src/main/java/io/digitalstate/stix/sdo/objects/ReportSdo.java deleted file mode 100644 index 4edf9a5..0000000 --- a/src/main/java/io/digitalstate/stix/sdo/objects/ReportSdo.java +++ /dev/null @@ -1,81 +0,0 @@ -package io.digitalstate.stix.sdo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.bundle.BundleableObject; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.json.StixInstantDeserializer; -import io.digitalstate.stix.json.StixInstantSerializer; -import io.digitalstate.stix.json.converters.dehydrated.BundleableObjectSetConverter; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.contraints.vocab.Vocab; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import io.digitalstate.stix.vocabulary.vocabularies.ReportLabels; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.time.Instant; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * report - *

- * Reports are collections of threat intelligence focused on one or more topics, such as a - * description of a threat actor, malware, or attack technique, including context and related details. - * - */ -@Value.Immutable @Serial.Version(1L) -@JsonTypeName("report") -@DefaultTypeValue(value = "report", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Sdo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = Report.class) @JsonDeserialize(builder = Report.Builder.class) -@JsonPropertyOrder({"type", "id", "created_by_ref", "created", - "modified", "revoked", "labels", "external_references", - "object_marking_refs", "granular_markings", "name", "description", - "published", "object_refs"}) -@Redactable -public interface ReportSdo extends DomainObject { - - @Override - @NotNull - @JsonPropertyDescription("This field is an Open Vocabulary that specifies the primary subject of this report. The suggested values for this field are in report-label-ov.") - @Redactable(useMask = true) - @Size(min = 1) - Set<@Vocab(ReportLabels.class) String> getLabels(); - - @NotBlank - @JsonProperty("name") - @JsonPropertyDescription("A description that provides more details and context about Report.") - @Redactable(useMask = true) - String getName(); - - @JsonProperty("description") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("A description that provides more details and context about Report.") - @Redactable - Optional getDescription(); - - @NotNull - @JsonProperty("published") - @JsonPropertyDescription("The date that this report object was officially published by the creator of this report.") - @Redactable(useMask = true) - StixInstant getPublished(); - - @NotNull @Size(min = 1, message = "Must have at least one Report object reference") - @JsonProperty("object_refs") - @JsonPropertyDescription("Specifies the STIX Objects that are referred to by this Report.") - @JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="id") - @JsonIdentityReference(alwaysAsId=true) - @JsonDeserialize( converter = BundleableObjectSetConverter.class) - @Redactable(useMask = true) - Set getObjectRefs(); - -} diff --git a/src/main/java/io/digitalstate/stix/sdo/objects/ThreatActorSdo.java b/src/main/java/io/digitalstate/stix/sdo/objects/ThreatActorSdo.java deleted file mode 100644 index 8109b0e..0000000 --- a/src/main/java/io/digitalstate/stix/sdo/objects/ThreatActorSdo.java +++ /dev/null @@ -1,109 +0,0 @@ -package io.digitalstate.stix.sdo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.contraints.vocab.Vocab; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import io.digitalstate.stix.vocabulary.vocabularies.*; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * threat-actor - *

- * Threat Actors are actual individuals, groups, or organizations believed to be operating with malicious intent. - * - */ -@Value.Immutable @Serial.Version(1L) -@Value.Style(typeAbstract="*Sdo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true, depluralizeDictionary = {"alias:aliases"}) -@JsonTypeName("threat-actor") -@DefaultTypeValue(value = "threat-actor", groups = {DefaultValuesProcessor.class}) -@JsonSerialize(as = ThreatActor.class) @JsonDeserialize(builder = ThreatActor.Builder.class) -@JsonPropertyOrder({"type", "id", "created_by_ref", "created", - "modified", "revoked", "labels", "external_references", - "object_marking_refs", "granular_markings", "uses", "name", - "description", "aliases", "roles", "goals", "sophistication", - "resource_level", "primary_motivation", "secondary_motivation", "personal_motivations"}) -@Redactable -public interface ThreatActorSdo extends DomainObject { - - @Override - @NotNull @Size(min = 1, message = "Must have at least one value from threat-actor-label-ov") - @Vocab(ThreatActorLabels.class) - @JsonPropertyDescription("This field specifies the type of threat actor. Open Vocab - threat-actor-label-ov") - @Redactable(useMask = true) - Set<@Size(min = 1) String> getLabels(); - - @NotBlank - @JsonProperty("name") - @JsonPropertyDescription("A name used to identify this Threat Actor or Threat Actor group.") - @Redactable(useMask = true) - String getName(); - - @JsonProperty("description") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("A description that provides more details and context about the Threat Actor.") - @Redactable - Optional getDescription(); - - @NotNull - @JsonProperty("aliases") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("A list of other names that this Threat Actor is believed to use.") - @Redactable - Set getAliases(); - - @NotNull - @Vocab(ThreatActorRoles.class) - @JsonProperty("roles") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("This is a list of roles the Threat Actor plays. Open Vocab - threat-actor-role-ov") - @Redactable - Set getRoles(); - - @NotNull - @JsonProperty("goals") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("The high level goals of this Threat Actor, namely, what are they trying to do.") - @Redactable - Set<@Size(min = 1) String> getGoals(); - - @NotNull - @JsonProperty("sophistication") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("The skill, specific knowledge, special training, or expertise a Threat Actor must have to perform the attack. Open Vocab - threat-actor-sophistication-ov") - @Redactable - Optional<@Vocab(ThreatActorSophistication.class) String> getSophistication(); - - @JsonProperty("resource_level") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("This defines the organizational level at which this Threat Actor typically works. Open Vocab - attack-resource-level-ov") - @Redactable - Optional<@Vocab(AttackResourceLevels.class) String> getResourceLevel(); - - @JsonProperty("primary_motivation") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("The primary reason, motivation, or purpose behind this Threat Actor. Open Vocab - attack-motivation-ov") - @Redactable - Optional<@Vocab(AttackMotivations.class) String> getPrimaryMotivation(); - - @NotNull - @Vocab(AttackMotivations.class) - @JsonProperty("secondary_motivations") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("The secondary reasons, motivations, or purposes behind this Threat Actor. Open Vocab - attack-motivation-ov") - @Redactable - Set getSecondaryMotivations(); - - @NotNull - @Vocab(AttackMotivations.class) - @JsonProperty("personal_motivations") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("The personal reasons, motivations, or purposes of the Threat Actor regardless of organizational goals. Open Vocab - attack-motivation-ov") - @Redactable - Set getPersonalMotivations(); - -} diff --git a/src/main/java/io/digitalstate/stix/sdo/objects/ToolSdo.java b/src/main/java/io/digitalstate/stix/sdo/objects/ToolSdo.java deleted file mode 100644 index 4866d36..0000000 --- a/src/main/java/io/digitalstate/stix/sdo/objects/ToolSdo.java +++ /dev/null @@ -1,73 +0,0 @@ -package io.digitalstate.stix.sdo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.sdo.types.KillChainPhaseType; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.contraints.vocab.Vocab; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import io.digitalstate.stix.vocabulary.vocabularies.ToolLabels; -import org.hibernate.validator.constraints.Length; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * tool - *

- * Tools are legitimate software that can be used by threat actors to perform attacks. - * This SDO MUST NOT be used to characterize malware. - * Further, Tool MUST NOT be used to characterise tools used as part of a course of action in response to an attack. - * - */ -@Value.Immutable @Serial.Version(1L) -@JsonTypeName("tool") -@DefaultTypeValue(value = "tool", groups = {DefaultValuesProcessor.class}) -@Value.Style(typeAbstract="*Sdo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonSerialize(as = Tool.class) @JsonDeserialize(builder = Tool.Builder.class) -@JsonPropertyOrder({"type", "id", "created_by_ref", "created", - "modified", "revoked", "labels", "external_references", - "object_marking_refs", "granular_markings", "name", - "description", "kill_chain_phases", "tool_version"}) -@Redactable -public interface ToolSdo extends DomainObject { - - @Override - @NotNull - @Vocab(ToolLabels.class) - @JsonPropertyDescription("The kind(s) of tool(s) being described. Open Vocab - tool-label-ov") - @Redactable(useMask = true) - Set<@Length(min = 1) String> getLabels(); - - @NotBlank - @JsonProperty("name") - @JsonPropertyDescription("The name used to identify the Tool.") - @Redactable(useMask = true) - String getName(); - - @JsonProperty("description") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("Provides more context and details about the Tool object.") - @Redactable - Optional getDescription(); - - @NotNull - @JsonProperty("kill_chain_phases") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("The list of kill chain phases for which this Tool instance can be used.") - @Redactable - Set getKillChainPhases(); - - @JsonProperty("tool_version") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("The version identifier associated with the tool.") - @Redactable - Optional getToolVersion(); - -} diff --git a/src/main/java/io/digitalstate/stix/sdo/objects/VulnerabilitySdo.java b/src/main/java/io/digitalstate/stix/sdo/objects/VulnerabilitySdo.java deleted file mode 100644 index 7e4b507..0000000 --- a/src/main/java/io/digitalstate/stix/sdo/objects/VulnerabilitySdo.java +++ /dev/null @@ -1,46 +0,0 @@ -package io.digitalstate.stix.sdo.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * vulnerability - *

- * A Vulnerability is a mistake in software that can be directly used by a hacker to gain access to a system or network. - * - */ -@Value.Immutable @Serial.Version(1L) -@Value.Style(typeAbstract="*Sdo", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@JsonTypeName("vulnerability") -@DefaultTypeValue(value = "vulnerability", groups = {DefaultValuesProcessor.class}) -@JsonSerialize(as = Vulnerability.class) @JsonDeserialize(builder = Vulnerability.Builder.class) -@JsonPropertyOrder({"type", "id", "created_by_ref", "created", - "modified", "revoked", "labels", "external_references", - "object_marking_refs", "granular_markings", "name", "description"}) -@Redactable -public interface VulnerabilitySdo extends DomainObject { - - @NotBlank - @JsonProperty("name") - @JsonPropertyDescription("The name used to identify the Vulnerability.") - @Redactable(useMask = true) - String getName(); - - @JsonProperty("description") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("Provides more context and details about the Vulnerability.") - @Redactable - Optional getDescription(); - -} diff --git a/src/main/java/io/digitalstate/stix/sdo/types/ExternalReferenceType.java b/src/main/java/io/digitalstate/stix/sdo/types/ExternalReferenceType.java deleted file mode 100644 index c505f2e..0000000 --- a/src/main/java/io/digitalstate/stix/sdo/types/ExternalReferenceType.java +++ /dev/null @@ -1,63 +0,0 @@ -package io.digitalstate.stix.sdo.types; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyDescription; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixCustomProperties; -import io.digitalstate.stix.validation.GenericValidation; -import io.digitalstate.stix.validation.contraints.hashingvocab.HashingVocab; -import io.digitalstate.stix.vocabulary.vocabularies.HashingAlgorithms; -import org.hibernate.validator.constraints.Length; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import java.io.Serializable; -import java.util.Map; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * external-reference - *

- * External references are used to describe pointers to information represented outside of STIX. - * - */ -@Value.Immutable @Serial.Version(1L) -@Value.Style(typeAbstract="*Type", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, depluralize = true, depluralizeDictionary = {"hash:hashes"}) -@JsonSerialize(as = ExternalReference.class) @JsonDeserialize(builder = ExternalReference.Builder.class) -@JsonPropertyOrder({ - "source_name", - "description", - "url", - "hashes", - "external_id" -}) -public interface ExternalReferenceType extends GenericValidation, StixCustomProperties, Serializable { - - @NotBlank - @JsonProperty("source_name") - @JsonPropertyDescription("The source within which the external-reference is defined (system, registry, organization, etc.)") - String getSourceName(); - - @JsonProperty("description") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("A human readable description") - Optional getDescription(); - - @JsonProperty("url") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("Matches the elements of a URL using a regular expression. Uses Diego Perini's regex from https://gist.github.com/dperini/729294.") - Optional getUrl(); - - @JsonProperty("hashes") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("Specifies a dictionary of hashes for the file.") - Map<@Length(min = 3, max = 256) @HashingVocab(HashingAlgorithms.class) String, String> getHashes(); - - @JsonProperty("external_id") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("An identifier for the external reference content") - Optional getExternalId(); - -} diff --git a/src/main/java/io/digitalstate/stix/sdo/types/KillChainPhaseType.java b/src/main/java/io/digitalstate/stix/sdo/types/KillChainPhaseType.java deleted file mode 100644 index 9e56221..0000000 --- a/src/main/java/io/digitalstate/stix/sdo/types/KillChainPhaseType.java +++ /dev/null @@ -1,70 +0,0 @@ -package io.digitalstate.stix.sdo.types; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyDescription; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import com.fasterxml.jackson.annotation.JsonValue; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixCustomProperties; -import io.digitalstate.stix.validation.GenericValidation; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import java.io.Serializable; - -/** - * kill-chain-phase - *

- * The kill-chain-phase represents a phase in a kill chain. - */ -@Value.Immutable @Serial.Version(1L) -@Value.Style(typeAbstract="*Type", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, depluralize = true) -@JsonSerialize(as = KillChainPhase.class) @JsonDeserialize(builder = KillChainPhase.Builder.class) -@JsonPropertyOrder({ - "kill_chain_name", - "phase_name" -}) -public interface KillChainPhaseType extends GenericValidation, StixCustomProperties, Serializable { - - @NotBlank - @JsonProperty("kill_chain_name") - @JsonPropertyDescription("The name of the kill chain.") - String killChainName(); - - @NotBlank - @JsonProperty("phase_name") - @JsonPropertyDescription("The name of the phase in the kill chain.") - String phaseName(); - - - /** - * Create an Enumeration of the most common one: Lockheed-Martin - */ - //@TODO Convert to Vocab pattern - public enum LockheedMartinKillChain { - RECONNAISSANCE("reconnaissance"), - WEAPONIZATION("weaponization"), - DELIVERY("delivery"), - EXPLOITATION("exploitation"), - INSTALLATION("installation"), - COMMAND_AND_CONTROL("command-and-control"), - ACTIONS_ON_OBJECTIVE("actions-on-objective"); - - public static final String killChainName = "lockheed-martin-cyber-kill-chain"; - - String phase; - - LockheedMartinKillChain(String val) { - this.phase = val; - } - - @Override - public String toString() {return phase;} - - @JsonValue - public String getPhase() { return phase; } - } - -} diff --git a/src/main/java/io/digitalstate/stix/sro/RelationshipObject.java b/src/main/java/io/digitalstate/stix/sro/RelationshipObject.java deleted file mode 100644 index aad7aa4..0000000 --- a/src/main/java/io/digitalstate/stix/sro/RelationshipObject.java +++ /dev/null @@ -1,14 +0,0 @@ -package io.digitalstate.stix.sro; - -import io.digitalstate.stix.common.*; - -import java.io.Serializable; - -public interface RelationshipObject extends Serializable, - StixCommonProperties, - StixCustomProperties, - StixLabels, - StixModified, - StixRevoked { - -} diff --git a/src/main/java/io/digitalstate/stix/sro/objects/RelationshipSro.java b/src/main/java/io/digitalstate/stix/sro/objects/RelationshipSro.java deleted file mode 100644 index 1280359..0000000 --- a/src/main/java/io/digitalstate/stix/sro/objects/RelationshipSro.java +++ /dev/null @@ -1,105 +0,0 @@ -package io.digitalstate.stix.sro.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.json.converters.dehydrated.DomainObjectConverter; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.sdo.objects.*; -import io.digitalstate.stix.sro.RelationshipObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.contraints.relationship.RelationshipLimit; -import io.digitalstate.stix.validation.contraints.relationship.RelationshipTypeLimit; -import io.digitalstate.stix.validation.contraints.vocab.Vocab; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import io.digitalstate.stix.vocabulary.vocabularies.RelationshipTypes; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import java.util.Optional; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * relationship - *

- * The Relationship object is used to link together two SDOs in order to describe how they are related to each other. - * - */ -@Value.Immutable @Serial.Version(1L) -@Value.Style(typeAbstract="*Sro", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@DefaultTypeValue(value = "relationship", groups = {DefaultValuesProcessor.class}) -@JsonTypeName("relationship") -@JsonSerialize(as = Relationship.class) @JsonDeserialize(builder = Relationship.Builder.class) -@JsonPropertyOrder({"type", "id", "created_by_ref", "created", - "modified", "revoked", "labels", "external_references", - "object_marking_refs", "granular_markings", "relationship_type", "description", - "source_ref", "target_ref"}) -@Redactable -//@TODO Refactor RelationshipTypeLimit and RelationshipLimit as they are partially redundant -@RelationshipTypeLimit(source = AttackPatternSdo.class, relationshipTypes = {"targets", "uses"}) -@RelationshipTypeLimit(source = CampaignSdo.class, relationshipTypes = {"attributed-to", "targets", "uses"}) -@RelationshipTypeLimit(source = CourseOfActionSdo.class, relationshipTypes = {"mitigates"}) -@RelationshipTypeLimit(source = IdentitySdo.class, relationshipTypes = {"targets", "attributed-to", "impersonates"}) -@RelationshipTypeLimit(source = IndicatorSdo.class, relationshipTypes = {"indicates"}) -@RelationshipTypeLimit(source = IntrusionSetSdo.class, relationshipTypes = {"attributed-to", "targets", "uses"}) -@RelationshipTypeLimit(source = MalwareSdo.class, relationshipTypes = {"targets", "uses", "variant-of"}) -@RelationshipTypeLimit(source = ThreatActorSdo.class, relationshipTypes = {"attributed-to", "impersonates", "targets", "uses"}) -@RelationshipTypeLimit(source = ToolSdo.class, relationshipTypes = {"targets"}) -@RelationshipLimit(source = DomainObject.class, relationshipType = "derived-from", target = {DomainObject.class}, classEquality = true) -@RelationshipLimit(source = DomainObject.class, relationshipType = "duplicate-of", target = {DomainObject.class}, classEquality = true) -@RelationshipLimit(source = DomainObject.class, relationshipType = "related-to", target = {DomainObject.class}) -@RelationshipLimit(source = AttackPatternSdo.class, relationshipType = "targets", target = {IdentitySdo.class, VulnerabilitySdo.class}) -@RelationshipLimit(source = AttackPatternSdo.class, relationshipType = "uses", target = {MalwareSdo.class, ToolSdo.class}) -@RelationshipLimit(source = CampaignSdo.class, relationshipType = "attributed-to", target = {IntrusionSetSdo.class, ThreatActorSdo.class}) -@RelationshipLimit(source = CampaignSdo.class, relationshipType = "targets", target = {IdentitySdo.class, VulnerabilitySdo.class}) -@RelationshipLimit(source = CampaignSdo.class, relationshipType = "uses", target = {AttackPatternSdo.class, MalwareSdo.class, ToolSdo.class}) -@RelationshipLimit(source = CourseOfActionSdo.class, relationshipType = "mitigates", target = {AttackPatternSdo.class, MalwareSdo.class, ToolSdo.class, VulnerabilitySdo.class}) -@RelationshipLimit(source = IndicatorSdo.class, relationshipType = "indicates", target = {AttackPatternSdo.class, CampaignSdo.class, IntrusionSetSdo.class, MalwareSdo.class, ThreatActorSdo.class, ToolSdo.class}) -@RelationshipLimit(source = IntrusionSetSdo.class, relationshipType = "attributed-to", target = {ThreatActorSdo.class}) -@RelationshipLimit(source = IntrusionSetSdo.class, relationshipType = "targets", target = {IdentitySdo.class, VulnerabilitySdo.class}) -@RelationshipLimit(source = IntrusionSetSdo.class, relationshipType = "uses", target = {AttackPatternSdo.class, MalwareSdo.class, ToolSdo.class}) -@RelationshipLimit(source = MalwareSdo.class, relationshipType = "targets", target = {IdentitySdo.class, VulnerabilitySdo.class}) -@RelationshipLimit(source = MalwareSdo.class, relationshipType = "uses", target = {ToolSdo.class}) -@RelationshipLimit(source = MalwareSdo.class, relationshipType = "variant-of", target = {MalwareSdo.class}) -@RelationshipLimit(source = ThreatActorSdo.class, relationshipType = "attributed-to", target = {IdentitySdo.class}) -@RelationshipLimit(source = ThreatActorSdo.class, relationshipType = "impersonates", target = {IdentitySdo.class}) -@RelationshipLimit(source = ThreatActorSdo.class, relationshipType = "targets", target = {IdentitySdo.class, VulnerabilitySdo.class}) -@RelationshipLimit(source = ThreatActorSdo.class, relationshipType = "uses", target = {AttackPatternSdo.class, MalwareSdo.class, ToolSdo.class}) -@RelationshipLimit(source = ToolSdo.class, relationshipType = "targets", target = {IdentitySdo.class, VulnerabilitySdo.class}) -public interface RelationshipSro extends RelationshipObject { - - @NotBlank - @Vocab(RelationshipTypes.class) - @JsonProperty("relationship_type") - @JsonPropertyDescription("The name used to identify the type of relationship.") - @Redactable(useMask = true) - String getRelationshipType(); - - @JsonProperty("description") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("A description that helps provide context about the relationship.") - @Redactable - Optional getDescription(); - - @NotNull - @JsonProperty("source_ref") - @JsonPropertyDescription("The ID of the source (from) object.") - @JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="id") - @JsonIdentityReference(alwaysAsId=true) - @JsonDeserialize(converter = DomainObjectConverter.class) - @Redactable(useMask = true) - DomainObject getSourceRef(); - - @NotNull - @JsonProperty("target_ref") - @JsonPropertyDescription("The ID of the target (to) object.") - @JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="id") - @JsonIdentityReference(alwaysAsId=true) - @JsonDeserialize(converter = DomainObjectConverter.class) - @Redactable(useMask = true) - DomainObject getTargetRef(); - -} diff --git a/src/main/java/io/digitalstate/stix/sro/objects/SightingSro.java b/src/main/java/io/digitalstate/stix/sro/objects/SightingSro.java deleted file mode 100644 index 20aac6a..0000000 --- a/src/main/java/io/digitalstate/stix/sro/objects/SightingSro.java +++ /dev/null @@ -1,95 +0,0 @@ -package io.digitalstate.stix.sro.objects; - -import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import io.digitalstate.stix.common.StixBoolean; -import io.digitalstate.stix.common.StixInstant; -import io.digitalstate.stix.json.converters.dehydrated.DomainObjectConverter; -import io.digitalstate.stix.redaction.Redactable; -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.sdo.objects.IdentitySdo; -import io.digitalstate.stix.sdo.objects.ObservedDataSdo; -import io.digitalstate.stix.sro.RelationshipObject; -import io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue; -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import org.hibernate.validator.constraints.Range; -import org.immutables.serial.Serial; -import org.immutables.value.Value; - -import javax.validation.constraints.NotNull; -import java.time.Instant; -import java.util.Optional; -import java.util.Set; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -/** - * sighting - *

- * A Sighting denotes the belief that something in CTI (e.g., an indicator, malware, tool, threat actor, etc.) was seen. - * - */ -@Value.Immutable @Serial.Version(1L) -@Value.Style(typeAbstract="*Sro", typeImmutable="*", validationMethod = Value.Style.ValidationMethod.NONE, additionalJsonAnnotations = {JsonTypeName.class}, depluralize = true) -@DefaultTypeValue(value = "sighting", groups = {DefaultValuesProcessor.class}) -@JsonTypeName("sighting") -@JsonSerialize(as = Sighting.class) @JsonDeserialize(builder = Sighting.Builder.class) -@JsonPropertyOrder({"type", "id", "created_by_ref", "created", - "modified", "revoked", "labels", "external_references", - "object_marking_refs", "granular_markings", "first_seen", "last_seen", - "count", "sighting_of_ref", "observed_data_refs", "where_sighted_refs", - "summary"}) -@Redactable -public interface SightingSro extends RelationshipObject { - - @JsonProperty("first_seen") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("The beginning of the time window during which the SDO referenced by the sighting_of_ref property was sighted.") - @Redactable - Optional getFirstSeen(); - - @JsonProperty("last_seen") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("The end of the time window during which the SDO referenced by the sighting_of_ref property was sighted.") - @Redactable - Optional getLastSeen(); - - @JsonProperty("count") @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("This is an integer between 0 and 999,999,999 inclusive and represents the number of times the object was sighted.") - @Redactable - Optional<@Range(min = 0, max = 999999999) Integer> getCount(); - - @JsonProperty("sighting_of_ref") - @JsonPropertyDescription("An ID reference to the object that has been sighted.") - @JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="id") - @JsonIdentityReference(alwaysAsId=true) - @JsonDeserialize(converter = DomainObjectConverter.class) - @Redactable(useMask = true) - DomainObject getSightingOfRef(); - - @JsonProperty("observed_data_refs") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("A list of ID references to the Observed Data objects that contain the raw cyber data for this Sighting.") - @JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="id") - @JsonIdentityReference(alwaysAsId=true) - @JsonDeserialize(contentConverter = DomainObjectConverter.class) - @Redactable - Set getObservedDataRefs(); - - @JsonProperty("where_sighted_refs") @JsonInclude(NON_EMPTY) - @JsonPropertyDescription("The ID of the Victim Target objects of the entities that saw the sighting.") - @JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="id") - @JsonIdentityReference(alwaysAsId=true) - @JsonDeserialize(contentConverter = DomainObjectConverter.class) - @Redactable - Set getWhereSightedRefs(); - - @NotNull - @JsonProperty("summary") - @JsonInclude(value = NON_EMPTY, content= NON_EMPTY) - @JsonPropertyDescription("The summary property indicates whether the Sighting should be considered summary data.") - @Redactable - @Value.Default - default StixBoolean isSummary(){ - return new StixBoolean(); - } - -} diff --git a/src/main/java/io/digitalstate/stix/validation/GenericValidation.java b/src/main/java/io/digitalstate/stix/validation/GenericValidation.java deleted file mode 100644 index daff30b..0000000 --- a/src/main/java/io/digitalstate/stix/validation/GenericValidation.java +++ /dev/null @@ -1,12 +0,0 @@ -package io.digitalstate.stix.validation; - -import org.immutables.value.Value; - -public interface GenericValidation extends SdoDefaultValidator { - - @Value.Check - default public void validateEntity(){ - this.validate(); - } - -} diff --git a/src/main/java/io/digitalstate/stix/validation/SdoDefaultValidator.java b/src/main/java/io/digitalstate/stix/validation/SdoDefaultValidator.java deleted file mode 100644 index c067fc0..0000000 --- a/src/main/java/io/digitalstate/stix/validation/SdoDefaultValidator.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.digitalstate.stix.validation; - -import io.digitalstate.stix.validation.sequences.SequenceDefault; -import io.digitalstate.stix.validation.sequences.SequenceValidationIdOnly; - -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; -import javax.validation.Validation; -import javax.validation.Validator; -import java.util.Set; - -public interface SdoDefaultValidator { - - Validator VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator(); - - default void validate() throws ConstraintViolationException{ - Set> violations = VALIDATOR.validate(this, SequenceDefault.class); - if (!violations.isEmpty()) { - throw new ConstraintViolationException(violations); - } - } - - default void validateOnlyId() throws ConstraintViolationException{ - Set> violations = VALIDATOR.validate(this, SequenceValidationIdOnly.class); - if (!violations.isEmpty()) { - throw new ConstraintViolationException(violations); - } - } -} - - - - diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/businessrule/BusinessRule.java b/src/main/java/io/digitalstate/stix/validation/contraints/businessrule/BusinessRule.java deleted file mode 100644 index 1271f6c..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/businessrule/BusinessRule.java +++ /dev/null @@ -1,84 +0,0 @@ -package io.digitalstate.stix.validation.contraints.businessrule; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.*; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.TYPE; - -/** - * The interface Business rule. - */ -@Documented -@Constraint(validatedBy = {StixValidateBusinessRuleValidator.class}) -@Target( { ANNOTATION_TYPE, TYPE }) -@Retention(RetentionPolicy.RUNTIME) -@Repeatable(BusinessRule.List.class) -public @interface BusinessRule { - - /** - * Message string. Not Used. The Error Message is used instead. - * - * @return the string - */ - String message() default "An business rule failed to validate"; - - /** - * Groups class [ ]. - * - * @return the class [ ] - */ - Class[] groups() default {}; - - /** - * Payload class [ ]. - * - * @return the class [ ] - */ - Class[] payload() default {}; - - /** - * If exp string. - * - * @return the string - */ - String ifExp(); - - /** - * Then exp string. - * - * @return the string - */ -//@TODO look into making the thenExp param into a array. So you can provide multiple independent conditions that all must result in the ExpectedResult value - String thenExp(); - - /** - * Error message string. - * - * @return the string - */ - String errorMessage(); - - /** - * Expected result boolean. - * - * @return the boolean - */ - boolean expectedResult() default true; - - /** - * The interface List. - */ - @Documented - @Retention(RetentionPolicy.RUNTIME) - @Target( { ANNOTATION_TYPE, TYPE }) - @interface List { - /** - * Value business rule [ ]. - * - * @return the business rule [ ] - */ - BusinessRule[] value(); - } -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/businessrule/StixValidateBusinessRuleValidator.java b/src/main/java/io/digitalstate/stix/validation/contraints/businessrule/StixValidateBusinessRuleValidator.java deleted file mode 100644 index 9f36204..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/businessrule/StixValidateBusinessRuleValidator.java +++ /dev/null @@ -1,65 +0,0 @@ -package io.digitalstate.stix.validation.contraints.businessrule; - -import org.springframework.expression.Expression; -import org.springframework.expression.ExpressionParser; -import org.springframework.expression.spel.SpelCompilerMode; -import org.springframework.expression.spel.SpelParserConfiguration; -import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.expression.spel.support.StandardEvaluationContext; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.util.Optional; - - -public class StixValidateBusinessRuleValidator implements ConstraintValidator { - - private String ifExp; - private String thenExp; - private String errorMessage; - private boolean expectedResult; - - //@TODO review compilation settings and how to optimize this - private SpelParserConfiguration spelConfig = new SpelParserConfiguration(SpelCompilerMode.MIXED, Thread.currentThread().getContextClassLoader()); - private ExpressionParser parser = new SpelExpressionParser(spelConfig); - - @Override - public void initialize(BusinessRule constraintAnnotation) { - ifExp = constraintAnnotation.ifExp(); - thenExp = constraintAnnotation.thenExp(); - errorMessage = constraintAnnotation.errorMessage(); - expectedResult = constraintAnnotation.expectedResult(); - } - - @Override - public boolean isValid(Object value, ConstraintValidatorContext cxt) { - - StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); - evaluationContext.setRootObject(value); - - Expression evalIf = parser.parseExpression(ifExp); - boolean evalIfResult = Optional.ofNullable(evalIf.getValue(evaluationContext, Boolean.class)) - .orElseThrow(() -> new IllegalArgumentException("Unable to parse business rule's ifExp")); - - if (!evalIfResult) { - // If the if statement is false then no further eval is required as the rule does not apply - return true; - - } else { - // If the business rule applies then: - Expression evalThen = parser.parseExpression(thenExp); - boolean evalThenResult = Optional.ofNullable(evalThen.getValue(evaluationContext, Boolean.class)) - .orElseThrow(() -> new IllegalArgumentException("Unable to parse business rule's thenExp")); - - if (evalThenResult == expectedResult) { - return true; - - } else { - String violationMessage = errorMessage; - cxt.disableDefaultConstraintViolation(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - return false; - } - } - } -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/coo/allowedparents/AllowedParents.java b/src/main/java/io/digitalstate/stix/validation/contraints/coo/allowedparents/AllowedParents.java deleted file mode 100644 index 966ad14..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/coo/allowedparents/AllowedParents.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.digitalstate.stix.validation.contraints.coo.allowedparents; - -import io.digitalstate.stix.coo.CyberObservableObject; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.TYPE; - -/** - * Values must be Array of Cyber Observable Object Interfaces!. - */ -@Documented -@Target( { ANNOTATION_TYPE, TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface AllowedParents { - Class[] value(); -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/coo/allowedparents/StixValidateParentCooValidator.java b/src/main/java/io/digitalstate/stix/validation/contraints/coo/allowedparents/StixValidateParentCooValidator.java deleted file mode 100644 index 539ea27..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/coo/allowedparents/StixValidateParentCooValidator.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.digitalstate.stix.validation.contraints.coo.allowedparents; - -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.util.Arrays; -import java.util.Optional; - -public class StixValidateParentCooValidator implements ConstraintValidator { - - //@TODO ADD LOGGING!!! - @Override - public boolean isValid(CyberObservableObject cyberObservableObject, ConstraintValidatorContext cxt) { - if (cyberObservableObject.getExtensions().size() >= 1) { - for (CyberObservableExtension ext : cyberObservableObject.getExtensions()) { - Optional annotation = Optional.ofNullable(ext.getClass().getDeclaredAnnotation(AllowedParents.class)); - - if (annotation.isPresent()) { -// System.out.println("FOUND"); - Class[] values = annotation.get().value(); - - if (values.length >= 1) { - boolean hasAllowedParent = Arrays.stream(values).anyMatch(i-> - i.isAssignableFrom(cyberObservableObject.getClass())); - - if (hasAllowedParent){ -// System.out.println("Class is assignable from Allowed-Parents interface list"); - return true; - } else { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Class attempting to use extension is not part of allowedParents interface list found on the Extension. Calling Cyber Observable Class: " + - ext.getClass().getCanonicalName() + " and Extension only supports interfaces: " + Arrays.toString(values); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - return false; - } - - } else { -// System.out.println("No classes defined"); - return true; - } - } else { -// System.out.println("NOT FOUND"); - return true; - } - } - } else { -// System.out.println("No Extensions"); - return true; - } -// System.out.println("nothing to do"); - return true; - } -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/coo/allowedparents/ValidateExtensions.java b/src/main/java/io/digitalstate/stix/validation/contraints/coo/allowedparents/ValidateExtensions.java deleted file mode 100644 index 04598c5..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/coo/allowedparents/ValidateExtensions.java +++ /dev/null @@ -1,25 +0,0 @@ -package io.digitalstate.stix.validation.contraints.coo.allowedparents; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.TYPE; - -/** - * Used to Validation Cyber Observable Extensions - * Should only be placed on Cyber Observable Object classes. - */ -@Documented -@Constraint(validatedBy = {StixValidateParentCooValidator.class}) -@Target( { ANNOTATION_TYPE, TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface ValidateExtensions { - String message() default "{io.digitalstate.stix.validation.contraints.coo.allowedparents.ValidateReferences}"; - Class[] groups() default {}; - Class[] payload() default {}; -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/coo/validateextensions/StixValidateParentCooValidator.java b/src/main/java/io/digitalstate/stix/validation/contraints/coo/validateextensions/StixValidateParentCooValidator.java deleted file mode 100644 index 3be91c3..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/coo/validateextensions/StixValidateParentCooValidator.java +++ /dev/null @@ -1,56 +0,0 @@ -package io.digitalstate.stix.validation.contraints.coo.validateextensions; - -import io.digitalstate.stix.coo.CyberObservableObject; -import io.digitalstate.stix.coo.extension.CyberObservableExtension; -import io.digitalstate.stix.validation.contraints.coo.allowedparents.AllowedParents; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.util.Arrays; -import java.util.Optional; - -public class StixValidateParentCooValidator implements ConstraintValidator { - - //@TODO ADD LOGGING!!! - @Override - public boolean isValid(CyberObservableObject cyberObservableObject, ConstraintValidatorContext cxt) { - if (cyberObservableObject.getExtensions().size() >= 1) { - for (CyberObservableExtension ext : cyberObservableObject.getExtensions()) { - Optional annotation = Optional.ofNullable(ext.getClass().getDeclaredAnnotation(AllowedParents.class)); - - if (annotation.isPresent()) { -// System.out.println("FOUND"); - Class[] values = annotation.get().value(); - - if (values.length >= 1) { - boolean hasAllowedParent = Arrays.stream(values).anyMatch(i-> - i.isAssignableFrom(cyberObservableObject.getClass())); - - if (hasAllowedParent){ -// System.out.println("Class is assignable from Allowed-Parents interface list"); - return true; - } else { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Class attempting to use extension is not part of allowedParents interface list found on the Extension. Calling Cyber Observable Class: " + - ext.getClass().getCanonicalName() + " and Extension only supports interfaces: " + Arrays.toString(values); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - return false; - } - - } else { -// System.out.println("No classes defined"); - return true; - } - } else { -// System.out.println("NOT FOUND"); - return true; - } - } - } else { -// System.out.println("No Extensions"); - return true; - } -// System.out.println("nothing to do"); - return true; - } -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/coo/validateextensions/ValidateReferences.java b/src/main/java/io/digitalstate/stix/validation/contraints/coo/validateextensions/ValidateReferences.java deleted file mode 100644 index 5aa610b..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/coo/validateextensions/ValidateReferences.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.digitalstate.stix.validation.contraints.coo.validateextensions; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.TYPE; - -/** - * Used to Validation Cyber Observable Extensions - * Should only be placed on Cyber Observable Object classes. - * This annotation will ensure that the extension is only used on the classes that implement {@link io.digitalstate.stix.validation.contraints.coo.allowedparents.AllowedParents} with the proper configuration. - */ -@Documented -@Constraint(validatedBy = {StixValidateParentCooValidator.class}) -@Target( { ANNOTATION_TYPE, TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface ValidateReferences { - String message() default "{io.digitalstate.stix.validation.contraints.coo.allowedparents.ValidateReferences}"; - Class[] groups() default {}; - Class[] payload() default {}; -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/defaulttypevalue/DefaultTypeValue.java b/src/main/java/io/digitalstate/stix/validation/contraints/defaulttypevalue/DefaultTypeValue.java deleted file mode 100644 index d66daff..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/defaulttypevalue/DefaultTypeValue.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.digitalstate.stix.validation.contraints.defaulttypevalue; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.TYPE; - - -/** - *

Sets the default value of the {@code type} field for a Bundleable object. - * This annotation must only be applied on a Class level of a class that extends from Bundleable object - * (Typically SDOs, SROs, COOs, COO-Extensions, and Marking Definitions).

- *
- *

This annotation will also validate a manually set {@code type} attribute. - * If the {@code type} attribute does not equal the value set in this annotation, then validation will fail.

- */ -@Documented -@Constraint(validatedBy = {StixDefaultTypeValueBundleableValidator.class, StixDefaultTypeValueBundleObjectValidator.class, StixDefaultTypeValueCyberObservableValidator.class, StixDefaultTypeValueCyberObservableExtensionValidator.class}) -@Target( { ANNOTATION_TYPE, TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface DefaultTypeValue { - String message() default "{io.digitalstate.stix.validation.contraints.defaulttypevalue.DefaultTypeValue}"; - Class[] groups() default {}; - Class[] payload() default {}; - - String value(); - -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/defaulttypevalue/StixDefaultTypeValueBundleObjectValidator.java b/src/main/java/io/digitalstate/stix/validation/contraints/defaulttypevalue/StixDefaultTypeValueBundleObjectValidator.java deleted file mode 100644 index 13e667d..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/defaulttypevalue/StixDefaultTypeValueBundleObjectValidator.java +++ /dev/null @@ -1,91 +0,0 @@ -package io.digitalstate.stix.validation.contraints.defaulttypevalue; - -import io.digitalstate.stix.bundle.BundleObject; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.lang.reflect.Field; -import java.util.UUID; - -/** - * This is used solely for a STIX Bundle. - */ -public class StixDefaultTypeValueBundleObjectValidator implements ConstraintValidator { - - private String defaultTypeValue; - - @Override - public void initialize(DefaultTypeValue relationshipTypeLimitConstraint) { - defaultTypeValue = relationshipTypeLimitConstraint.value(); - } - - @Override - public boolean isValid(BundleObject bundleObject, - ConstraintValidatorContext cxt) { - - String type = bundleObject.getType(); - if (type == null || type.isEmpty()){ - try { - Field typeField = bundleObject.getClass().getDeclaredField("type"); - typeField.setAccessible(true); - typeField.set(bundleObject, defaultTypeValue); - } catch (NoSuchFieldException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Cant find Field: 'type' for: " + bundleObject.getClass(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - - } catch (IllegalAccessException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Illegal Access Exception for: 'type' for: " + bundleObject.getClass(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - } - } else { - if (bundleObject.getType().equals(defaultTypeValue)){ - return true; - } else{ - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Field 'type' must have value of " + defaultTypeValue + "for class " + bundleObject.getClass().getCanonicalName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - return false; - } - } - - String id = bundleObject.getId(); - if (id == null || id.isEmpty()){ - try { - Field idField = bundleObject.getClass().getDeclaredField("id"); - idField.setAccessible(true); - String idValue = String.join("--", defaultTypeValue, UUID.randomUUID().toString()); - idField.set(bundleObject, idValue); - - } catch (IllegalAccessException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Illegal Access Exception for: 'id' for: " + bundleObject.getClass(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - - } catch (NoSuchFieldException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Cant find Field: 'id' for: " + bundleObject.getClass(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - } - } else { - boolean idStartsWithType = id.startsWith(defaultTypeValue + "--"); - if (!idStartsWithType){ - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Id does not start with the proper type value(Looking for '" + defaultTypeValue + "--' : provided 'id' value was: " + id; - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - return false; - } - } - return true; - } -} - diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/defaulttypevalue/StixDefaultTypeValueBundleableValidator.java b/src/main/java/io/digitalstate/stix/validation/contraints/defaulttypevalue/StixDefaultTypeValueBundleableValidator.java deleted file mode 100644 index a984f41..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/defaulttypevalue/StixDefaultTypeValueBundleableValidator.java +++ /dev/null @@ -1,94 +0,0 @@ -package io.digitalstate.stix.validation.contraints.defaulttypevalue; - -import io.digitalstate.stix.bundle.BundleableObject; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.lang.reflect.Field; -import java.util.UUID; - -/** - * This is used on any class that implements BundleableObject. - */ -public class StixDefaultTypeValueBundleableValidator implements ConstraintValidator { - - private String defaultTypeValue; - - @Override - public void initialize(DefaultTypeValue relationshipTypeLimitConstraint) { - defaultTypeValue = relationshipTypeLimitConstraint.value(); - } - - @Override - public boolean isValid(BundleableObject bundleableObject, - ConstraintValidatorContext cxt) { - - String type = bundleableObject.getType(); - if (type == null || type.isEmpty()){ - try { - Field typeField = bundleableObject.getClass().getDeclaredField("type"); - typeField.setAccessible(true); - typeField.set(bundleableObject, defaultTypeValue); - } catch (NoSuchFieldException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Cant find Field: 'type' for: " + bundleableObject.getClass(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - - } catch (IllegalAccessException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Illegal Access Exception for: 'type' for: " + bundleableObject.getClass(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - } - } else { - if (bundleableObject.getType().equals(defaultTypeValue)){ - return true; - } else{ - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Field 'type' must have value of " + defaultTypeValue + "for class " + bundleableObject.getClass().getCanonicalName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - return false; - } - } - - // Validate the ID attribute - String id = bundleableObject.getId(); - if (id == null || id.isEmpty()){ - try { - Field idField = bundleableObject.getClass().getDeclaredField("id"); - idField.setAccessible(true); - String idValue = String.join("--", defaultTypeValue, UUID.randomUUID().toString()); - idField.set(bundleableObject, idValue); - - } catch (IllegalAccessException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Illegal Access Exception for: 'id' for: " + bundleableObject.getClass(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - - } catch (NoSuchFieldException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Cant find Field: 'id' for: " + bundleableObject.getClass(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - } - } else { - boolean idStartsWithType = id.startsWith(defaultTypeValue + "--"); - if (!idStartsWithType){ - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Id does not start with the proper type value(Looking for '" + defaultTypeValue + "--' : provided 'id' value was: " + id; - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - return false; - } - //@TODO add optional logic to enforce a style of UUID - } - - return true; - } -} - diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/defaulttypevalue/StixDefaultTypeValueCyberObservableExtensionValidator.java b/src/main/java/io/digitalstate/stix/validation/contraints/defaulttypevalue/StixDefaultTypeValueCyberObservableExtensionValidator.java deleted file mode 100644 index 2e5eff7..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/defaulttypevalue/StixDefaultTypeValueCyberObservableExtensionValidator.java +++ /dev/null @@ -1,59 +0,0 @@ -package io.digitalstate.stix.validation.contraints.defaulttypevalue; - -import io.digitalstate.stix.coo.extension.CyberObservableExtension; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.lang.reflect.Field; - -/** - * This is used on any class that implements CyberObservableObject. - */ -public class StixDefaultTypeValueCyberObservableExtensionValidator implements ConstraintValidator { - - private String defaultTypeValue; - - @Override - public void initialize(DefaultTypeValue relationshipTypeLimitConstraint) { - defaultTypeValue = relationshipTypeLimitConstraint.value(); - } - - @Override - public boolean isValid(CyberObservableExtension cyberObservableExtension, - ConstraintValidatorContext cxt) { - - String type = cyberObservableExtension.getType(); - if (type == null || type.isEmpty()){ - try { - Field typeField = cyberObservableExtension.getClass().getDeclaredField("type"); - typeField.setAccessible(true); - typeField.set(cyberObservableExtension, defaultTypeValue); - } catch (NoSuchFieldException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Cant find Field: 'type' for: " + cyberObservableExtension.getClass(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - - } catch (IllegalAccessException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Illegal Access Exception for: 'type' for: " + cyberObservableExtension.getClass(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - } - } else { - if (cyberObservableExtension.getType().equals(defaultTypeValue)){ - return true; - } else{ - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Field 'type' must have value of " + defaultTypeValue + "for class " + cyberObservableExtension.getClass().getCanonicalName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - return false; - } - } - - return true; - } -} - diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/defaulttypevalue/StixDefaultTypeValueCyberObservableValidator.java b/src/main/java/io/digitalstate/stix/validation/contraints/defaulttypevalue/StixDefaultTypeValueCyberObservableValidator.java deleted file mode 100644 index 4e47d90..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/defaulttypevalue/StixDefaultTypeValueCyberObservableValidator.java +++ /dev/null @@ -1,57 +0,0 @@ -package io.digitalstate.stix.validation.contraints.defaulttypevalue; - -import io.digitalstate.stix.coo.CyberObservableObject; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.lang.reflect.Field; - -/** - * This is used on any class that implements CyberObservableObject. - */ -public class StixDefaultTypeValueCyberObservableValidator implements ConstraintValidator { - - private String defaultTypeValue; - - @Override - public void initialize(DefaultTypeValue relationshipTypeLimitConstraint) { - defaultTypeValue = relationshipTypeLimitConstraint.value(); - } - - @Override - public boolean isValid(CyberObservableObject cyberObservableObject, - ConstraintValidatorContext cxt) { - String type = cyberObservableObject.getType(); - if (type == null || type.isEmpty()){ - try { - Field typeField = cyberObservableObject.getClass().getDeclaredField("type"); - typeField.setAccessible(true); - typeField.set(cyberObservableObject, defaultTypeValue); - } catch (NoSuchFieldException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Cant find Field: 'type' for: " + cyberObservableObject.getClass(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - - } catch (IllegalAccessException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Illegal Access Exception for: 'type' for: " + cyberObservableObject.getClass(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - } - } else { - if (cyberObservableObject.getType().equals(defaultTypeValue)){ - return true; - } else{ - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Field 'type' must have value of " + defaultTypeValue + "for class " + cyberObservableObject.getClass().getCanonicalName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - return false; - } - } - return true; - } -} - diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/hashingvocab/HashingVocab.java b/src/main/java/io/digitalstate/stix/validation/contraints/hashingvocab/HashingVocab.java deleted file mode 100644 index ca1b0af..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/hashingvocab/HashingVocab.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.digitalstate.stix.validation.contraints.hashingvocab; - -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.TYPE_USE; - -/** - *

A modified version of the @StartsWith annotation, where this modified version - * provides a parameter level control over Map keys, that meet the Hashes spec, - * and allows x_ key names in addition

- */ -@Documented -@Constraint(validatedBy = {StixHashingVocabValidatorString.class}) -@Target( { ANNOTATION_TYPE, TYPE_USE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface HashingVocab { - String message() default "{io.digitalstate.stix.validation.contraints.hashingvocab}"; - Class[] groups() default {}; - Class[] payload() default {}; - - Class value(); - -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/hashingvocab/StixHashingVocabValidatorString.java b/src/main/java/io/digitalstate/stix/validation/contraints/hashingvocab/StixHashingVocabValidatorString.java deleted file mode 100644 index 9eb227e..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/hashingvocab/StixHashingVocabValidatorString.java +++ /dev/null @@ -1,57 +0,0 @@ -package io.digitalstate.stix.validation.contraints.hashingvocab; - -import com.google.common.collect.Sets; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -public class StixHashingVocabValidatorString implements ConstraintValidator { - - private Class vocabulary; - - @Override - public void initialize(HashingVocab hashingVocabConstraint) { - vocabulary = hashingVocabConstraint.value(); - } - - @Override - public boolean isValid(String vocab, - ConstraintValidatorContext cxt) { - if (vocab.startsWith("x_")) { - return true; - } else { - try { - Set vocabTerms = vocabulary.newInstance().getAllTerms(); - boolean evalContains = vocabTerms.contains(vocab); - if (!evalContains) { - Sets.SetView difference = Sets.difference(new HashSet<>(Arrays.asList(vocab)), vocabTerms); - - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Item: " + difference.toString() + " is not found in class " + vocabulary.getCanonicalName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - return false; - } else { - return true; - } - - } catch (InstantiationException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "InstantiationException from " + vocabulary.getSimpleName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - - } catch (IllegalAccessException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "IllegalAccessException from " + vocabulary.getSimpleName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - } - } - } -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/markingdefinitiontype/MarkingDefinitionTypeLimit.java b/src/main/java/io/digitalstate/stix/validation/contraints/markingdefinitiontype/MarkingDefinitionTypeLimit.java deleted file mode 100644 index 7aa3ee4..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/markingdefinitiontype/MarkingDefinitionTypeLimit.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.digitalstate.stix.validation.contraints.markingdefinitiontype; - -import io.digitalstate.stix.datamarkings.StixMarkingObject; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.*; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.TYPE; - -/** - * To only be used on STIX MarkingDefinition class. - * The annotation provides a Javax Validation that enforces Marking Definition Types based on the actual definition being used. - * This annotation enforces the STIX Relationship Type restrictions for each SDO. - */ -@Documented -@Constraint(validatedBy = {StixMarkingDefinitionTypeLimitValidator.class}) -@Target( { ANNOTATION_TYPE, TYPE }) -@Retention(RetentionPolicy.RUNTIME) -@Repeatable(MarkingDefinitionTypeLimit.List.class) -public @interface MarkingDefinitionTypeLimit { - String message() default "{io.digitalstate.stix.validation.contraints.markingdefinitiontype.MarkingDefinitionTypeLimit}"; - Class[] groups() default {}; - Class[] payload() default {}; - - Class markingObject(); - String markingDefinitionType(); - - @Documented - @Retention(RetentionPolicy.RUNTIME) - @Target( { ANNOTATION_TYPE, TYPE }) - @interface List { - MarkingDefinitionTypeLimit[] value(); - } -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/markingdefinitiontype/StixMarkingDefinitionTypeLimitValidator.java b/src/main/java/io/digitalstate/stix/validation/contraints/markingdefinitiontype/StixMarkingDefinitionTypeLimitValidator.java deleted file mode 100644 index 4fc8084..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/markingdefinitiontype/StixMarkingDefinitionTypeLimitValidator.java +++ /dev/null @@ -1,78 +0,0 @@ -package io.digitalstate.stix.validation.contraints.markingdefinitiontype; - -import io.digitalstate.stix.datamarkings.MarkingDefinitionDm; -import io.digitalstate.stix.datamarkings.StixMarkingObject; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.lang.reflect.Field; - -public class StixMarkingDefinitionTypeLimitValidator implements ConstraintValidator { - - private Class markingObject; - private String markingDefinitionType; - - @Override - public void initialize(MarkingDefinitionTypeLimit markingDefinitionTypeLimitConstraint) { - markingObject = markingDefinitionTypeLimitConstraint.markingObject(); - markingDefinitionType = markingDefinitionTypeLimitConstraint.markingDefinitionType(); - } - - @Override - public boolean isValid(MarkingDefinitionDm markingDefinitionDm, - ConstraintValidatorContext cxt) { - - if (markingDefinitionDm.getHydrated()) { - // Throws error is the definition property is null. - // This is semi duplication of the notNull annotation on the attribute - if (markingDefinitionDm.getDefinition() == null) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Definition attribute of a Marking Definition cannot be null"; - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - return false; - - // Default Value helper to populate the definition_type attribute based on the definition attribute's class - } else if (markingDefinitionDm.getDefinitionType() == null) { - if (markingObject.isAssignableFrom(markingDefinitionDm.getDefinition().getClass())) { - try { - Field typeField = markingDefinitionDm.getClass().getDeclaredField("definitionType"); - typeField.setAccessible(true); - typeField.set(markingDefinitionDm, markingDefinitionType); - - } catch (NoSuchFieldException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Cant find Field: 'definitionType' for: " + markingObject; - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - - } catch (IllegalAccessException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Illegal Access Exception for: 'definitionType' for: " + markingObject; - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - } - } - } - - // Checks if the definition and the definition type match as per the spec and class requirements - // Requirements are stated in the class level(type) of the Marking Definition. - if (markingObject.isAssignableFrom(markingDefinitionDm.getDefinition().getClass())) { - if (markingDefinitionDm.getDefinitionType().equals(markingDefinitionType)) { - return true; - } else { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Marking Definition Type is incorrect for Marking Object"; - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - return false; - } - } else { - return true; - } - } else { - // If the object is not hydrated, then this logic does not matter - return true; - } - } -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/relationship/RelationshipLimit.java b/src/main/java/io/digitalstate/stix/validation/contraints/relationship/RelationshipLimit.java deleted file mode 100644 index 9d58746..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/relationship/RelationshipLimit.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.digitalstate.stix.validation.contraints.relationship; - -import io.digitalstate.stix.sdo.DomainObject; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.*; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.TYPE; - -@Documented -@Constraint(validatedBy = {StixRelationshipLimitValidator.class}) -@Target( { ANNOTATION_TYPE, TYPE }) -@Retention(RetentionPolicy.RUNTIME) -@Repeatable(RelationshipLimit.List.class) -public @interface RelationshipLimit { - String message() default "{io.digitalstate.stix.validation.contraints.relationship.RelationshipLimit}"; - Class[] groups() default {}; - Class[] payload() default {}; - - Class source(); - String relationshipType(); - Class[] target(); - boolean classEquality() default false; - - @Documented - @Retention(RetentionPolicy.RUNTIME) - @Target( { ANNOTATION_TYPE, TYPE }) - @interface List { - RelationshipLimit[] value(); - } - -} \ No newline at end of file diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/relationship/RelationshipTypeLimit.java b/src/main/java/io/digitalstate/stix/validation/contraints/relationship/RelationshipTypeLimit.java deleted file mode 100644 index 4788142..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/relationship/RelationshipTypeLimit.java +++ /dev/null @@ -1,39 +0,0 @@ -package io.digitalstate.stix.validation.contraints.relationship; - -import io.digitalstate.stix.sdo.DomainObject; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.*; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.TYPE; - -/** - * To only be used on STIX Relationship class. - * The annotation provides a Javax Validation that looks at the RelationshipType being used. - * This annotation enforces the STIX Relationship Type restrictions for each SDO. - */ -@Documented -@Constraint(validatedBy = {StixRelationshipTypeLimitValidator.class}) -@Target( { ANNOTATION_TYPE, TYPE }) -@Retention(RetentionPolicy.RUNTIME) -@Repeatable(RelationshipTypeLimit.List.class) -public @interface RelationshipTypeLimit { - String message() default "{io.digitalstate.stix.validation.contraints.relationship.DefaultTypeValue}"; - Class[] groups() default {}; - Class[] payload() default {}; - - boolean enforceCommonRelationshipTypes() default true; - // @TODO look to use reflection to populate the Common Relationship Types default values. - String[] commonRelationshipTypes() default {"duplicate-of", "derived-from", "related-to"}; - Class source(); - String[] relationshipTypes(); - - @Documented - @Retention(RetentionPolicy.RUNTIME) - @Target( { ANNOTATION_TYPE, TYPE }) - @interface List { - RelationshipTypeLimit[] value(); - } -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/relationship/StixRelationshipLimitValidator.java b/src/main/java/io/digitalstate/stix/validation/contraints/relationship/StixRelationshipLimitValidator.java deleted file mode 100644 index e23212f..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/relationship/StixRelationshipLimitValidator.java +++ /dev/null @@ -1,68 +0,0 @@ -package io.digitalstate.stix.validation.contraints.relationship; - -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.sro.objects.RelationshipSro; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.util.Arrays; -import java.util.stream.Collectors; - -public class StixRelationshipLimitValidator implements ConstraintValidator { - - private Class source; - private String relationshipType; - private Class[] target; - private boolean classEquality; - - @Override - public void initialize(RelationshipLimit relationshipLimit) { - source = relationshipLimit.source(); - target = relationshipLimit.target(); - relationshipType = relationshipLimit.relationshipType(); - classEquality = relationshipLimit.classEquality(); - } - - @Override - public boolean isValid(RelationshipSro object, - ConstraintValidatorContext cxt) { - - if (object.getRelationshipType().equals(relationshipType)){ - if (classEquality){ - if (!object.getSourceRef().getClass().equals(object.getTargetRef().getClass())){ - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Class Equality mismatch: Source: " + - source.getCanonicalName() + " does not match Target: " + object.getTargetRef().getClass().getCanonicalName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - return false; - } - } - //@TODO write detail docs about the logic and how to eval this for debugging - // The use of isAssignableFrom is typically confusing from basic logic between the interfaces and the Immutable class - if (source.isAssignableFrom(object.getSourceRef().getClass())){ - boolean hasInstance = Arrays.stream(target).anyMatch(t-> t.isAssignableFrom(object.getTargetRef().getClass())); - if (classEquality && object.getTargetRef().getClass().equals(object.getSourceRef().getClass())){ - return true; - - } else if (hasInstance){ - return true; - - }else { - cxt.disableDefaultConstraintViolation(); - String targetClasses = Arrays.stream(target).map(Class::getCanonicalName).collect(Collectors.toList()).toString(); - String violationMessage = "Source/Target/RelationshipType Mismatch: Source: " + - source.getCanonicalName() + " with Relationship-Type '" + relationshipType + - "' is only supported for Target(s): " + targetClasses; - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - return false; - } - - } else { - return true; - } - - } else { - return true; - } - } -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/relationship/StixRelationshipTypeLimitValidator.java b/src/main/java/io/digitalstate/stix/validation/contraints/relationship/StixRelationshipTypeLimitValidator.java deleted file mode 100644 index 92e7894..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/relationship/StixRelationshipTypeLimitValidator.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.digitalstate.stix.validation.contraints.relationship; - -import io.digitalstate.stix.sdo.DomainObject; -import io.digitalstate.stix.sro.objects.RelationshipSro; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.util.Arrays; -import java.util.List; - -public class StixRelationshipTypeLimitValidator implements ConstraintValidator { - - private Class source; - private String[] relationshipTypes; - private String[] commonRelationshipsTypes; - private boolean enforceCommonRelationshipTypes; - - @Override - public void initialize(RelationshipTypeLimit relationshipTypeLimitConstraint) { - source = relationshipTypeLimitConstraint.source(); - relationshipTypes = relationshipTypeLimitConstraint.relationshipTypes(); - commonRelationshipsTypes = relationshipTypeLimitConstraint.commonRelationshipTypes(); - enforceCommonRelationshipTypes = relationshipTypeLimitConstraint.enforceCommonRelationshipTypes(); - } - - @Override - public boolean isValid(RelationshipSro relationshipSro, - ConstraintValidatorContext cxt) { - if (source.isAssignableFrom(relationshipSro.getSourceRef().getClass())){ - List typesList = Arrays.asList(relationshipTypes); - List commonTypesList = Arrays.asList(commonRelationshipsTypes); - if (typesList.contains(relationshipSro.getRelationshipType())){ - return true; - } else if (enforceCommonRelationshipTypes && commonTypesList.contains(relationshipSro.getRelationshipType())){ - return true; - }else { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Relationship Type: '" + relationshipSro.getRelationshipType() + - "' is not supported with class " + relationshipSro.getClass().getCanonicalName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - return false; - } - } else { - return true; - } - } -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/startswith/StartsWith.java b/src/main/java/io/digitalstate/stix/validation/contraints/startswith/StartsWith.java deleted file mode 100644 index 96f4c52..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/startswith/StartsWith.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.digitalstate.stix.validation.contraints.startswith; - -import io.digitalstate.stix.helpers.StixCustomPropertiesConfig; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.TYPE_USE; - -/** - *

Provides a Starts With validator of String values.

- *
- *

Defaults to {@link StixCustomPropertiesConfig#DEFAULT_CUSTOM_PROPERTY_PREFIX}

- */ -@Documented -@Constraint(validatedBy = {StixStartsWithValidatorString.class}) -@Target( { ANNOTATION_TYPE, TYPE_USE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface StartsWith { - String message() default "{io.digitalstate.stix.validation.contraints.startswith.StartsWith}"; - Class[] groups() default {}; - Class[] payload() default {}; - - String value() default StixCustomPropertiesConfig.DEFAULT_CUSTOM_PROPERTY_PREFIX; - -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/startswith/StixStartsWithValidatorString.java b/src/main/java/io/digitalstate/stix/validation/contraints/startswith/StixStartsWithValidatorString.java deleted file mode 100644 index f022454..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/startswith/StixStartsWithValidatorString.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.digitalstate.stix.validation.contraints.startswith; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; - -public class StixStartsWithValidatorString implements ConstraintValidator { - - private String prefix; - - @Override - public void initialize(StartsWith startsWithConstraint) { - prefix = startsWithConstraint.value(); - } - - @Override - public boolean isValid(String value, ConstraintValidatorContext cxt) { - if (value.startsWith(prefix)){ - return true; - } else{ - cxt.disableDefaultConstraintViolation(); - String violationMessage = "StartsWith violation: string must start with value: " - + prefix + ", but provided value: " + value; - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - return false; - } - } -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/vocab/StixVocabValidatorCollection.java b/src/main/java/io/digitalstate/stix/validation/contraints/vocab/StixVocabValidatorCollection.java deleted file mode 100644 index 05c433b..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/vocab/StixVocabValidatorCollection.java +++ /dev/null @@ -1,51 +0,0 @@ -package io.digitalstate.stix.validation.contraints.vocab; - -import com.google.common.collect.Sets; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.util.HashSet; -import java.util.Set; - -public class StixVocabValidatorCollection implements ConstraintValidator> { - - private Class vocabulary; - - @Override - public void initialize(Vocab vocabConstraint) { - vocabulary = vocabConstraint.value(); - } - - @Override - public boolean isValid(Set vocab, - ConstraintValidatorContext cxt) { - try { - Set vocabTerms = vocabulary.newInstance().getAllTerms(); - boolean evalContains = vocabTerms.containsAll(vocab); - if (!evalContains){ - cxt.disableDefaultConstraintViolation(); - Sets.SetView difference = Sets.difference(new HashSet<>(vocab), vocabTerms); - - String violationMessage = "Items: " + difference.toString() + " are not found in class " + vocabulary.getCanonicalName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - } - - return evalContains; - - } catch (InstantiationException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "InstantiationException from " + vocabulary.getSimpleName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - - } catch (IllegalAccessException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "IllegalAccessException from " + vocabulary.getSimpleName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - } - } -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/vocab/StixVocabValidatorOptionalString.java b/src/main/java/io/digitalstate/stix/validation/contraints/vocab/StixVocabValidatorOptionalString.java deleted file mode 100644 index 28f37d1..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/vocab/StixVocabValidatorOptionalString.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.digitalstate.stix.validation.contraints.vocab; - -import com.google.common.collect.Sets; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; - -public class StixVocabValidatorOptionalString implements ConstraintValidator> { - - private Class vocabulary; - - @Override - public void initialize(Vocab vocabConstraint) { - vocabulary = vocabConstraint.value(); - } - - @Override - public boolean isValid(Optional vocab, ConstraintValidatorContext cxt) { - if (vocab.isPresent()) { - try { - Set vocabTerms = vocabulary.newInstance().getAllTerms(); - boolean evalContains = vocabTerms.contains(vocab.get()); - if (!evalContains) { - Sets.SetView difference = Sets.difference(new HashSet<>(Arrays.asList(vocab.get())), vocabTerms); - cxt.disableDefaultConstraintViolation(); - String violationMessage = "Item: " + difference.toString() + " is not found in class " + vocabulary.getCanonicalName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - } - - return evalContains; - - } catch (InstantiationException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "InstantiationException from " + vocabulary.getSimpleName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - - } catch (IllegalAccessException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "IllegalAccessException from " + vocabulary.getSimpleName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - } - } else { - return true; - } - } -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/vocab/StixVocabValidatorString.java b/src/main/java/io/digitalstate/stix/validation/contraints/vocab/StixVocabValidatorString.java deleted file mode 100644 index f62f776..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/vocab/StixVocabValidatorString.java +++ /dev/null @@ -1,56 +0,0 @@ -package io.digitalstate.stix.validation.contraints.vocab; - -import com.google.common.collect.Sets; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -public class StixVocabValidatorString implements ConstraintValidator { - - private Class vocabulary; - - @Override - public void initialize(Vocab vocabConstraint) { - vocabulary = vocabConstraint.value(); - } - - @Override - public boolean isValid(String vocab, ConstraintValidatorContext cxt) { - if (vocab == null) { - return true; - - } else { - try { - Set vocabTerms = vocabulary.newInstance().getAllTerms(); - boolean evalContains = vocabTerms.contains(vocab); - if (!evalContains) { - cxt.disableDefaultConstraintViolation(); - Sets.SetView difference = Sets.difference(new HashSet<>(Arrays.asList(vocab)), vocabTerms); - - String violationMessage = "Item: " + difference.toString() + " is not found in class " + vocabulary.getCanonicalName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - } - - return evalContains; - - } catch (InstantiationException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "InstantiationException from " + vocabulary.getSimpleName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - - } catch (IllegalAccessException e) { - cxt.disableDefaultConstraintViolation(); - String violationMessage = "IllegalAccessException from " + vocabulary.getSimpleName(); - cxt.buildConstraintViolationWithTemplate(violationMessage).addConstraintViolation(); - e.printStackTrace(); - return false; - } - } - } -} diff --git a/src/main/java/io/digitalstate/stix/validation/contraints/vocab/Vocab.java b/src/main/java/io/digitalstate/stix/validation/contraints/vocab/Vocab.java deleted file mode 100644 index 68bb70c..0000000 --- a/src/main/java/io/digitalstate/stix/validation/contraints/vocab/Vocab.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.digitalstate.stix.validation.contraints.vocab; - -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.*; - -/** - *

Provides STIX Vocabulary validation for {@code String} and {@code Set} fields.

- *
- *

Value is the vocabulary class to be used for validation. - * The class must implement {@link StixVocabulary} interface.

- *
- *

Example usage: {@code @HashingVocab(AttackMotivations.class)}

- */ -@Documented -@Constraint(validatedBy = { - StixVocabValidatorString.class, - StixVocabValidatorCollection.class -}) -@Target( { METHOD, FIELD, TYPE_USE, ANNOTATION_TYPE, PARAMETER }) -@Retention(RetentionPolicy.RUNTIME) -public @interface Vocab { - String message() default "{io.digitalstate.stix.validation.contraints.VocabContains}"; - Class[] groups() default {}; - Class[] payload() default {}; - - Class value(); - -} diff --git a/src/main/java/io/digitalstate/stix/validation/groups/DefaultValuesProcessor.java b/src/main/java/io/digitalstate/stix/validation/groups/DefaultValuesProcessor.java deleted file mode 100644 index 92c91cb..0000000 --- a/src/main/java/io/digitalstate/stix/validation/groups/DefaultValuesProcessor.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.digitalstate.stix.validation.groups; - -public interface DefaultValuesProcessor { -} diff --git a/src/main/java/io/digitalstate/stix/validation/groups/NoValidation.java b/src/main/java/io/digitalstate/stix/validation/groups/NoValidation.java deleted file mode 100644 index 3849ad6..0000000 --- a/src/main/java/io/digitalstate/stix/validation/groups/NoValidation.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.digitalstate.stix.validation.groups; - -public interface NoValidation { -} diff --git a/src/main/java/io/digitalstate/stix/validation/groups/ValidateIdOnly.java b/src/main/java/io/digitalstate/stix/validation/groups/ValidateIdOnly.java deleted file mode 100644 index ccec271..0000000 --- a/src/main/java/io/digitalstate/stix/validation/groups/ValidateIdOnly.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.digitalstate.stix.validation.groups; - -/** - * Validate ID Only Group used by javax.validation - */ - -public interface ValidateIdOnly { -} diff --git a/src/main/java/io/digitalstate/stix/validation/sequences/SequenceDefault.java b/src/main/java/io/digitalstate/stix/validation/sequences/SequenceDefault.java deleted file mode 100644 index cc899b9..0000000 --- a/src/main/java/io/digitalstate/stix/validation/sequences/SequenceDefault.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.digitalstate.stix.validation.sequences; - -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; - -import javax.validation.GroupSequence; -import javax.validation.groups.Default; - -@GroupSequence({DefaultValuesProcessor.class, Default.class}) -public interface SequenceDefault { -} diff --git a/src/main/java/io/digitalstate/stix/validation/sequences/SequenceValidationIdOnly.java b/src/main/java/io/digitalstate/stix/validation/sequences/SequenceValidationIdOnly.java deleted file mode 100644 index 7920858..0000000 --- a/src/main/java/io/digitalstate/stix/validation/sequences/SequenceValidationIdOnly.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.digitalstate.stix.validation.sequences; - -import io.digitalstate.stix.validation.groups.DefaultValuesProcessor; -import io.digitalstate.stix.validation.groups.ValidateIdOnly; - -import javax.validation.GroupSequence; - -@GroupSequence({DefaultValuesProcessor.class, ValidateIdOnly.class}) -public interface SequenceValidationIdOnly { -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/StixVocabulary.java b/src/main/java/io/digitalstate/stix/vocabulary/StixVocabulary.java deleted file mode 100644 index c6c412e..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/StixVocabulary.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.digitalstate.stix.vocabulary; - -import java.util.Set; - -public interface StixVocabulary { - - /** - * Get all default terms - * @return - */ - Set getAllTerms(); - - /** - * Get all default terms and append some additional terms - * @param terms - * @return - */ - Set getAllTermsWithAdditional(String[] terms); -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/AccountTypes.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/AccountTypes.java deleted file mode 100644 index 0d65fa5..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/AccountTypes.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class AccountTypes implements StixVocabulary { - @JsonProperty("account-type-ov") - private Set terms = new HashSet<>(Arrays.asList( - "unix", "windows local", "windows domain", "ldap", "tacacs", "radius", - "nis", "openid", "facebook", "skype", "twitter", "kavi" - )); - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } - - -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/AttackMotivations.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/AttackMotivations.java deleted file mode 100644 index b6c155e..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/AttackMotivations.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class AttackMotivations implements StixVocabulary { - - @JsonProperty("attack_motivations_vocabulary") - private Set terms = new HashSet<>(Arrays.asList( - "accidental", "coercion", "dominance", - "ideology", "notoriety", "organizational-gain", - "personal-gain", "personal-satisfaction", "revenge", - "unpredictable")); - - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } - -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/AttackResourceLevels.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/AttackResourceLevels.java deleted file mode 100644 index ec2a6ff..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/AttackResourceLevels.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class AttackResourceLevels implements StixVocabulary { - - @JsonProperty("attack_resource_levels_vocabulary") - private Set terms = new HashSet<>(Arrays.asList( - "individual", "club", "content", - "team", "organization", "government")); - - // - // Getters and Setters - // - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/EncryptionAlgorithms.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/EncryptionAlgorithms.java deleted file mode 100644 index 6cb0f49..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/EncryptionAlgorithms.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class EncryptionAlgorithms implements StixVocabulary { - - @JsonProperty("encryption-algo-ov") - private Set terms = new HashSet<>(Arrays.asList( - "AES128-ECB", "AES128-CBC", "AES128-CFB", "AES128-COFB", - "AES128-CTR", "AES128-XTS", "AES128-GCM", - "Salsa20", "Salsa8B", "ChaCha20-Poly1305", "ChaCha20", - "DES-CBC", "3DES-CBC", "DES-EBC", "3DES-EBC", - "CAST128-CBC", "CAST256-CBC", "RSA", "DSA" - )); - - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } - -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/HashingAlgorithms.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/HashingAlgorithms.java deleted file mode 100644 index 5e8a1c2..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/HashingAlgorithms.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class HashingAlgorithms implements StixVocabulary { - - @JsonProperty("hashing_algorithms_vocabulary") - private Set terms = new HashSet<>(Arrays.asList( - "MD5", "MD6", "RIPEMD-160", "SHA-1", - "SHA-224", "SHA-256", "SHA-384", "SHA-512", - "SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512", - "SSDEEP", "WHIRLPOOL")); - - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } - -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/IdentityClasses.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/IdentityClasses.java deleted file mode 100644 index 143731f..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/IdentityClasses.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class IdentityClasses implements StixVocabulary { - - @JsonProperty("identity_classes_vocabulary") - private Set terms = new HashSet<>(Arrays.asList( - "individual", "group", "organization", - "class", "unknown")); - - // - // Getters and Setters - // - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/IndicatorLabels.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/IndicatorLabels.java deleted file mode 100644 index 20539e9..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/IndicatorLabels.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class IndicatorLabels implements StixVocabulary { - - @JsonProperty("indicator_labels_vocabulary") - private Set terms = new HashSet<>(Arrays.asList( - "anomalous-activity", "anonymization", "benign", - "compromised", "malicious-activity", "attribution")); - - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/IndustrySectors.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/IndustrySectors.java deleted file mode 100644 index 59f4c5b..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/IndustrySectors.java +++ /dev/null @@ -1,40 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class IndustrySectors implements StixVocabulary { - - @JsonProperty("industry_sectors_vocabulary") - private Set terms = new HashSet<>(Arrays.asList( - "agriculture", "aerospace", "automotive", - "communications", "construction", "defence", - "education", "energy", "entertainment", - "financial-services", "government-national", "government-regional", - "government-local", "government-public-services", "healthcare", - "hospitality-leisure", "infrastructure", "insurance", - "manufacturing", "mining", "non-profit", - "pharmaceuticals", "retail", "technology", - "telecommunications", "transportation", "utilities")); - - // - // Getters and Setters - // - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/MalwareLabels.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/MalwareLabels.java deleted file mode 100644 index 300f43c..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/MalwareLabels.java +++ /dev/null @@ -1,37 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class MalwareLabels implements StixVocabulary { - - @JsonProperty("malware_labels_vocabulary") - private Set terms = new HashSet<>(Arrays.asList( - "adware", "backdoor", "bot", - "ddos", "dropper", "exploit-kit", - "keylogger", "ransomware", "remote-access-trojan", - "resource-exploitation", "rogue-security-software", "rootkit", - "screen-capture", "spyware", "trojan", - "virus", "worm")); - - // - // Getters and Setters - // - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/NetworkSocketAddressFamilies.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/NetworkSocketAddressFamilies.java deleted file mode 100644 index 9e50430..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/NetworkSocketAddressFamilies.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class NetworkSocketAddressFamilies implements StixVocabulary { - - @JsonProperty("network-socket-address-family-enum") - private Set terms = new HashSet<>(Arrays.asList( - "AF_UNSPEC", "AF_INET", "AF_IPX", "AF_APPLETALK", - "AF_NETBIOS", "AF_INET_6", "AF_IRDA", "AF_BTH" - )); - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } - -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/NetworkSocketProtocolFamilies.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/NetworkSocketProtocolFamilies.java deleted file mode 100644 index a5d800c..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/NetworkSocketProtocolFamilies.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class NetworkSocketProtocolFamilies implements StixVocabulary { - - @JsonProperty("network-socket-protocol-family-enum") - private Set terms = new HashSet<>(Arrays.asList( - "PF_INET", "PF_AX25", "PF_IPX", "PF_INET_6", - "PF_APPLETALK", "PF_NETROM", "PF_BRIDGE", "PF_ATMPVC", - "PF_X25", "PF_ROSE", "PF_DECNET", "PF_NETBEUI", - "PF_SECURITY", "PF_KEY", "PF_NETLINK", "PF_ROUTE", - "PF_PACKET", "PF_ASH", "PF_ECONET", "PF_ATMSVC", - "PF_SNA", "PF_IRDA", "PF_PPPOX", "PF_WANPIPE", - "PF_BLUETOOTH" - )); - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } - -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/NetworkSocketTypes.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/NetworkSocketTypes.java deleted file mode 100644 index 9b08a5e..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/NetworkSocketTypes.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class NetworkSocketTypes implements StixVocabulary { - - @JsonProperty("network-socket-type-enum") - private Set terms = new HashSet<>(Arrays.asList( - "SOCK_STREAM", "SOCK_DGRAM", - "SOCK_RAW", "SOCK_RDM", - "SOCK_SEQPACKET" - )); - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } - -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/RelationshipTypes.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/RelationshipTypes.java deleted file mode 100644 index ea21fe4..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/RelationshipTypes.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class RelationshipTypes implements StixVocabulary { - - private static Set terms = new HashSet<>(Arrays.asList( - "targets", - "uses", - "attributed-to", - "mitigates", - "indicates", - "variant-of", - "impersonates")); - - private static Set commonTerms = new HashSet<>(Arrays.asList( - "duplicate-of", - "derived-from", - "related-to")); - - @Override - public Set getAllTerms() { - return Stream.concat(terms.stream(), commonTerms.stream()) - .collect(Collectors.toCollection(HashSet::new)); - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/ReportLabels.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/ReportLabels.java deleted file mode 100644 index 4364e99..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/ReportLabels.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class ReportLabels implements StixVocabulary { - - @JsonProperty("report_labels_vocabulary") - private Set terms = new HashSet<>(Arrays.asList( - "threat-report", "attack-pattern", "campaign", - "identity", "indicator", "malware", - "observed-data", "threat-actor", "tool", - "vulnerability")); - - // - // Getters and Setters - // - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/ThreatActorLabels.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/ThreatActorLabels.java deleted file mode 100644 index 1164f63..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/ThreatActorLabels.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class ThreatActorLabels implements StixVocabulary { - - @JsonProperty("threat_actor_labels_vocabulary") - private Set terms = new HashSet<>(Arrays.asList( - "activist", "competitor", "crime-syndicate", - "criminal", "hacker", "insider-accidental", - "insider-disgruntled", "nation-state", "sensationalist", - "spy", "terrorist")); - - // - // Getters and Setters - // - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/ThreatActorRoles.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/ThreatActorRoles.java deleted file mode 100644 index 872cdf0..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/ThreatActorRoles.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class ThreatActorRoles implements StixVocabulary { - - @JsonProperty("threat_actor_roles_vocabulary") - private Set terms = new HashSet<>(Arrays.asList( - "agent", "director", "independent", - "infrastructure-architect", "infrastructure-operator", "malware-author", - "sponsor")); - - // - // Getters and Setters - // - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/ThreatActorSophistication.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/ThreatActorSophistication.java deleted file mode 100644 index fc5f979..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/ThreatActorSophistication.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class ThreatActorSophistication implements StixVocabulary { - - @JsonProperty("threat_actor_sophistication_vocabulary") - private Set terms = new HashSet<>(Arrays.asList( - "none", "minimal", "intermediate", - "advanced", "expert", "innovator", - "strategic")); - - // - // Getters and Setters - // - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/TlpLevels.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/TlpLevels.java deleted file mode 100644 index 8c68577..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/TlpLevels.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class TlpLevels implements StixVocabulary { - - @JsonProperty("tlp_levels_vocabulary") - private Set terms = new HashSet<>(Arrays.asList( - "white", "green", "amber", "red")); - - // - // Getters and Setters - // - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/ToolLabels.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/ToolLabels.java deleted file mode 100644 index 657e574..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/ToolLabels.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class ToolLabels implements StixVocabulary { - - @JsonProperty("tool_labels_vocabulary") - private Set terms = new HashSet<>(Arrays.asList( - "denial-of-service", "exploitation", "information-gathering", - "network-capture", "credential-exploitation", "remote-access", - "vulnerability-scanning")); - - // - // Getters and Setters - // - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/WindowsPeBinaryTypes.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/WindowsPeBinaryTypes.java deleted file mode 100644 index ee404b2..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/WindowsPeBinaryTypes.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class WindowsPeBinaryTypes implements StixVocabulary { - - @JsonProperty("windows-pebinary-type-ov") - private Set terms = new HashSet<>(Arrays.asList( - "exe", "dll", "sys" - )); - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } - -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/WindowsRegistryValueDataTypes.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/WindowsRegistryValueDataTypes.java deleted file mode 100644 index eae3783..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/WindowsRegistryValueDataTypes.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class WindowsRegistryValueDataTypes implements StixVocabulary { - - @JsonProperty("data-types") - private Set terms = new HashSet<>(Arrays.asList( - "REG_NONE", "REG_SZ", "REG_EXPAND_SZ", - "REG_BINARY", "REG_DWORD", "REG_DWORD_BIG_ENDIAN", - "REG_LINK", "REG_MULTI_SZ", "REG_RESOURCE_LIST", - "REG_FULL_RESOURCE_DESCRIPTION", "REG_RESOURCE_REQUIREMENTS_LIST", "REG_QWORD", - "REG_INVALID_TYPE" - )); - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } - -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/WindowsServiceStartTypes.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/WindowsServiceStartTypes.java deleted file mode 100644 index c5584e6..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/WindowsServiceStartTypes.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class WindowsServiceStartTypes implements StixVocabulary { - - @JsonProperty("windows-service-start-type-enum") - private Set terms = new HashSet<>(Arrays.asList( - "SERVICE_AUTO_START", "SERVICE_BOOT_START", "SERVICE_DEMAND_START", - "SERVICE_DISABLED", "SERVICE_SYSTEM_ALERT" - )); - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } - -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/WindowsServiceStatuses.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/WindowsServiceStatuses.java deleted file mode 100644 index ed2ede1..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/WindowsServiceStatuses.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class WindowsServiceStatuses implements StixVocabulary { - - @JsonProperty("windows-service-status-enum") - private Set terms = new HashSet<>(Arrays.asList( - "SERVICE_CONTINUE_PENDING", "SERVICE_PAUSE_PENDING", "SERVICE_PAUSED", - "SERVICE_RUNNING", "SERVICE_START_PENDING", "SERVICE_STOP_PENDING", - "SERVICE_STOPPED" - )); - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } - -} diff --git a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/WindowsServiceTypes.java b/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/WindowsServiceTypes.java deleted file mode 100644 index 6be021a..0000000 --- a/src/main/java/io/digitalstate/stix/vocabulary/vocabularies/WindowsServiceTypes.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.digitalstate.stix.vocabulary.vocabularies; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.digitalstate.stix.vocabulary.StixVocabulary; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class WindowsServiceTypes implements StixVocabulary { - - @JsonProperty("windows-service-type-enum") - private Set terms = new HashSet<>(Arrays.asList( - "SERVICE_KERNEL_DRIVER", "SERVICE_FILE_SYSTEM_DRIVER", - "SERVICE_WIN32_OWN_PROCESS", "SERVICE_WIN32_SHARE_PROCESS" - )); - - @Override - public Set getAllTerms() { - return terms; - } - - @Override - public Set getAllTermsWithAdditional(String[] terms) { - return Stream.concat(getAllTerms().stream(), Arrays.stream(terms)) - .collect(Collectors.toCollection(HashSet::new)); - } - -} diff --git a/src/main/kotlin/com/stephenott/stix/Bundle.kt b/src/main/kotlin/com/stephenott/stix/Bundle.kt new file mode 100644 index 0000000..0f7e90e --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/Bundle.kt @@ -0,0 +1,2 @@ +package com.stephenott.stix + diff --git a/src/main/kotlin/com/stephenott/stix/MainRunner.kt b/src/main/kotlin/com/stephenott/stix/MainRunner.kt new file mode 100644 index 0000000..71d5a6c --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/MainRunner.kt @@ -0,0 +1,96 @@ +package com.stephenott.stix + +import com.stephenott.stix.objects.StixObject +import com.stephenott.stix.objects.core.StixCoreObject +import com.stephenott.stix.objects.core.sco.objects.NetworkTraffic +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sdo.objects.AttackPattern +import com.stephenott.stix.objects.core.sdo.objects.AttackPatternSdo +import com.stephenott.stix.objects.core.sro.StixRelationshipObject +import com.stephenott.stix.objects.core.sro.objects.Relationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.objects.core.sro.objects.Sighting +import com.stephenott.stix.objects.meta.datamarking.MarkingDefinition +import com.stephenott.stix.objects.meta.datamarking.objects.Statement +import com.stephenott.stix.objects.meta.datamarking.objects.Tlp +import com.stephenott.stix.serialization.json.StixJsonContentMapper +import com.stephenott.stix.serialization.json.jsonMapper +import com.stephenott.stix.serialization.json.toJson +import com.stephenott.stix.serialization.json.toJsonMapper +import com.stephenott.stix.type.* +import com.stephenott.stix.type.vocab.MarkingDefinitionTypeOv + +object MainRunner { + + @JvmStatic + fun main(args: Array) { + + // Create a Stix instance (used to provide configurations of supported objects + val stix1 = Stix() + + // generation of a Attack Pattern using the default configs + val ap = AttackPattern(name = "124", + confidence = StixConfidence(33)) + + // Generation of a Attack Pattern using the stix1 instance ("trust group") + // This is used to force a specific stix instance to be used: this would be used to + // validate/transfer objects between trust groups, ensuring that content is valid + val ap1: AttackPattern = stix1.create(AttackPattern(name = "124", + confidence = StixConfidence(33))) + + val ap2: AttackPattern = stix1.create(AttackPattern(name = "124", + confidence = StixConfidence(33))) + + val sighting1 = Sighting(sightingOfRef = ap1.id) + val net1 = NetworkTraffic(isActive = StixBoolean(true), protocols = StixStringList(listOf("http"))) + + val mapper = stix1.toJsonMapper() +// val mapper = StixJsonContentMapper.fromStixInstance(stix1) + println(ap1.toJson(mapper)) + println(mapper.parseJson(mapper.toJson(ap1))) + println(mapper.parseJson(ap1.toJson(mapper))) + println(mapper.parseJson(ap1.toJson(mapper))) + println(mapper.parseJson(ap1.toJson(mapper))) + println(mapper.parseJson(ap1.toJson(mapper))) + + println(net1.toJson(mapper)) + println(mapper.parseJson(net1.toJson(mapper))) + + val jsonString: String = ap1.toJson(mapper) + println(jsonString) + + println(mapper.parseJson(jsonString)) + println(mapper.parseJson(jsonString)) + println(mapper.parseJson(jsonString)) + println(mapper.parseJson(jsonString)) + println(mapper.parseJson(jsonString)) + println(mapper.parseJson(jsonString)) + + + val rel = Relationship( + relationshipType = RelationshipType("duplicate-of"), + sourceRef = ap1, + targetRef = ap2 + ) + println(mapper.parseJson(rel.toJson(mapper))) + println(mapper.parseJson(rel.toJson(mapper))) + println(mapper.parseJson(rel.toJson(mapper))) + println(mapper.parseJson(rel.toJson(mapper))) + println(mapper.parseJson(rel.toJson(mapper))) + println(mapper.parseJson(rel.toJson(mapper))) + + println(mapper.parseJson(sighting1.toJson(mapper))) + + val markDef1 = MarkingDefinition("test", MarkingDefinitionTypeOv("tlp"), + Tlp("white") + ) + println(mapper.parseJson(markDef1.toJson(mapper))) + println(markDef1.toJson(mapper)) + + val markDef2 = MarkingDefinition("test2", MarkingDefinitionTypeOv("statement"), + Statement("white-statement") + ) + println(mapper.parseJson(markDef2.toJson(mapper))) + println(markDef2.toJson(mapper)) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/Stix.kt b/src/main/kotlin/com/stephenott/stix/Stix.kt new file mode 100644 index 0000000..9925858 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/Stix.kt @@ -0,0 +1,40 @@ +package com.stephenott.stix + +import com.stephenott.stix.common.StixMarkingObjectRegistry +import com.stephenott.stix.common.StixObjectRegistry +import com.stephenott.stix.common.StixObjectRelationshipRegistry +import com.sun.org.apache.xpath.internal.operations.Bool +import kotlin.reflect.full.createInstance +import kotlin.reflect.full.instanceParameter +import kotlin.reflect.full.memberFunctions + +data class Stix( + val registries: StixRegistries = StixRegistries() +) { + + //@TODO future place that common configurations will go. + + companion object { + val defaultRegistries: StixRegistries = StixRegistries() + + var defaultValidateOnConstruction: Boolean = true + + val defaultStixInstance: Stix = Stix(defaultRegistries) + } + + + inline fun create(stixContent: T): T{ + val copy = stixContent::class.memberFunctions.first { it.name == "copy" } + val instanceParam = copy.instanceParameter!! + val validateParam = copy.parameters.first { it.name == StixContent::stixValidateOnConstruction.name } + val stixInstanceParam = copy.parameters.first { it.name == StixContent::stixInstance.name } + return copy.callBy(mapOf(instanceParam to stixContent, validateParam to true, stixInstanceParam to this)) as T + } + +} + +data class StixRegistries( + val objectRegistry: StixObjectRegistry = StixObjectRegistry(), + val relationshipRegistry: StixObjectRelationshipRegistry = StixObjectRelationshipRegistry(), + val markingObjectRegistry: StixMarkingObjectRegistry = StixMarkingObjectRegistry() +) {} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/StixBundle.kt b/src/main/kotlin/com/stephenott/stix/StixBundle.kt new file mode 100644 index 0000000..9809f0c --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/StixBundle.kt @@ -0,0 +1,36 @@ +package com.stephenott.stix + +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.objects.StixObject +import com.stephenott.stix.type.StixIdentifier +import com.stephenott.stix.type.StixType + +interface StixBundle : StixContent { + val objects: LinkedHashSet + + companion object : + CompanionStixType, + BusinessRulesValidator { + + override val stixType = StixType("bundle") + + override fun objectValidationRules(obj: StixBundle, stixInstance: Stix) { + //@TODO + } + } +} + + +data class Bundle(override val type: StixType = StixBundle.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val objects: LinkedHashSet, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : StixBundle { + + init { + StixBundle.objectValidationRules(this, stixInstance) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/StixContent.kt b/src/main/kotlin/com/stephenott/stix/StixContent.kt new file mode 100644 index 0000000..a20edd0 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/StixContent.kt @@ -0,0 +1,16 @@ +package com.stephenott.stix + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.stephenott.stix.common.StixIdentifierProp +import com.stephenott.stix.common.StixTypeProp + +interface StixContent : + StixTypeProp, + StixIdentifierProp { + + val stixInstance: Stix + val stixValidateOnConstruction: Boolean + + companion object{} + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/common/CommonProperties.kt b/src/main/kotlin/com/stephenott/stix/common/CommonProperties.kt new file mode 100644 index 0000000..b7d262f --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/common/CommonProperties.kt @@ -0,0 +1,72 @@ +package com.stephenott.stix.common + +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixConfidence +import com.stephenott.stix.type.StixLabels +import com.stephenott.stix.type.StixLang + +interface StixTypeProp{ + val type: StixType +} + +interface StixIdentifierProp{ + val id: StixIdentifier +} + +interface StixCreatedByRef{ + val createdByRef: String? +} + +interface StixCreatedProp{ + val created: StixTimestamp +} + +interface StixExternalReferencesProp{ + val externalReferences: ExternalReferences? +} + +interface StixObjectMarkingsRefsProp{ + val objectMarkingsRefs: String? +} + +interface StixGranularMarkingsProp{ + val granularMarkings: String? +} + +interface StixSpecVersionProp{ + val specVersion: StixSpecVersion +} + +interface StixLabelsProp { + val labels: StixLabels? +} + +interface StixModifiedProp { + val modified: StixTimestamp +} + +interface StixRevokedProp { + val revoked: StixBoolean +} + +interface StixConfidenceProp { + val confidence: StixConfidence? +} + +interface StixLangProp { + val lang: StixLang? +} + +/** + * Only used on SCO + */ +interface StixExtensionsProp { + val extensions: Extensions? +} + +/** + * Only used on SCO + */ +interface StixDefangedProp { + val defanged: StixBoolean +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/common/CommonValidations.kt b/src/main/kotlin/com/stephenott/stix/common/CommonValidations.kt new file mode 100644 index 0000000..f940ae0 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/common/CommonValidations.kt @@ -0,0 +1,9 @@ +package com.stephenott.stix.common + +import com.stephenott.stix.StixContent +import com.stephenott.stix.type.StixType + +fun requireStixType(type: StixType, obj: StixContent){ + require(obj.type == type, + lazyMessage = {"Object has incorrect type value. Value was: ${obj.type}, but expected type value was $type"}) +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/common/StixDataFormats.kt b/src/main/kotlin/com/stephenott/stix/common/StixDataFormats.kt new file mode 100644 index 0000000..43d7c37 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/common/StixDataFormats.kt @@ -0,0 +1,51 @@ +package com.stephenott.stix.common + +import java.time.ZoneId +import java.time.format.DateTimeFormatter +import java.time.format.DateTimeFormatterBuilder +import java.time.temporal.ChronoField + +object StixDataFormats { + + /** + * Default pattern for deserialization of date/times into a STIX compliant timestamp. + */ + val TIMESTAMP_PATTERN = "yyyy-MM-dd'T'HH:mm:ss[.SSS][.SS][.S]X" + + /** + * Default Timezone used for Serialization and Deserialization. + */ + val TIMEZONE = "UTC" + + /** + * Supports 0-9 digits of Sub-Second precision storage. (Nano Second Support) + * @return + */ + val readerStixDateTimeFormatter: DateTimeFormatter + get() { + val formatterBuilder = DateTimeFormatterBuilder() + .appendPattern("yyyy-MM-dd'T'HH:mm:ss") + .optionalStart() + .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true) + .optionalEnd() + .appendPattern("X") + + return formatterBuilder.toFormatter().withZone(ZoneId.of("UTC")) + } + + fun getWriterStixDateTimeFormatter(subSecondPrecision: Int): DateTimeFormatter { + require(subSecondPrecision <= 9) { "Sub-Second Precision can only be from 0 to 9 digits" } + val formatterBuilder = DateTimeFormatterBuilder() + + formatterBuilder.appendPattern("yyyy-MM-dd'T'HH:mm:ss") + + if (subSecondPrecision > 0) { + formatterBuilder.appendFraction(ChronoField.NANO_OF_SECOND, subSecondPrecision, subSecondPrecision, true) + } + + formatterBuilder.appendPattern("X") + + return formatterBuilder.toFormatter().withZone(ZoneId.of("UTC")) + } + +} diff --git a/src/main/kotlin/com/stephenott/stix/common/StixMarkingObjectRegistry.kt b/src/main/kotlin/com/stephenott/stix/common/StixMarkingObjectRegistry.kt new file mode 100644 index 0000000..413bd88 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/common/StixMarkingObjectRegistry.kt @@ -0,0 +1,15 @@ +package com.stephenott.stix.common + +import com.stephenott.stix.objects.meta.datamarking.MarkingObject +import com.stephenott.stix.objects.meta.datamarking.objects.Statement +import com.stephenott.stix.objects.meta.datamarking.objects.Tlp +import com.stephenott.stix.type.vocab.MarkingDefinitionTypeOv +import kotlin.reflect.KClass + +class StixMarkingObjectRegistry() { + + val registry: MutableMap> = mutableMapOf( + Pair(MarkingDefinitionTypeOv("statement"), Statement::class), + Pair(MarkingDefinitionTypeOv("tlp"), Tlp::class) + ) +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/common/StixObjectRegistry.kt b/src/main/kotlin/com/stephenott/stix/common/StixObjectRegistry.kt new file mode 100644 index 0000000..7e295b8 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/common/StixObjectRegistry.kt @@ -0,0 +1,154 @@ +package com.stephenott.stix.common + +import com.stephenott.stix.objects.StixObject +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.objects.* +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sdo.objects.* +import com.stephenott.stix.objects.core.sro.StixRelationshipObject +import com.stephenott.stix.objects.core.sro.objects.Relationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.objects.core.sro.objects.Sighting +import com.stephenott.stix.objects.core.sro.objects.SightingSro +import com.stephenott.stix.objects.meta.StixMetaObject +import com.stephenott.stix.objects.meta.datamarking.MarkingDefinition +import com.stephenott.stix.objects.meta.datamarking.MarkingDefinitionDm +import com.stephenott.stix.objects.meta.datamarking.MarkingObject +import com.stephenott.stix.objects.meta.datamarking.objects.Statement +import com.stephenott.stix.objects.meta.datamarking.objects.StatementMo +import com.stephenott.stix.objects.meta.datamarking.objects.Tlp +import com.stephenott.stix.objects.meta.datamarking.objects.TlpMo +import com.stephenott.stix.objects.meta.lco.objects.LanguageContent +import com.stephenott.stix.objects.meta.lco.objects.LanguageContentLco +import com.stephenott.stix.type.StixType +import com.stephenott.stix.type.vocab.MarkingDefinitionTypeOv +import kotlin.reflect.KClass + +data class StixObjectRegistry( + val customSdoRegistry: Map> = mapOf(), + val customScoRegistry: Map> = mapOf(), + val customSroRegistry: Map> = mapOf(), + val customMetaObjectRegistry: Map> = mapOf(), + val customMarkingObjectRegistry: Map> = mapOf() +) { + + // STIX OBJECT Registry: + + val sdoRegistry: Map> = mapOf( + Pair(AttackPatternSdo.stixType, AttackPattern::class), + Pair(CampaignSdo.stixType, Campaign::class), + Pair(CourseOfActionSdo.stixType, CourseOfAction::class), + Pair(GroupingSdo.stixType, Grouping::class), + Pair(IdentitySdo.stixType, Identity::class), + Pair(IndicatorSdo.stixType, Indicator::class), + Pair(InfrastructureSdo.stixType, Infrastructure::class), + Pair(IntrusionSetSdo.stixType, IntrusionSet::class), + Pair(LocationSdo.stixType, Location::class), + Pair(MalwareSdo.stixType, Malware::class), + Pair(MalwareAnalysisSdo.stixType, MalwareAnalysis::class), + Pair(NoteSdo.stixType, Note::class), + Pair(ObservedDataSdo.stixType, ObservedData::class), + Pair(OpinionSdo.stixType, Opinion::class), + Pair(ReportSdo.stixType, Report::class), + Pair(ThreatActorSdo.stixType, ThreatActor::class), + Pair(VulnerabilitySdo.stixType, Vulnerability::class) + ) + + val scoRegistry: Map> = mapOf( + Pair(ArtifactSco.stixType, Artifact::class), + Pair(AutonomousSystemSco.stixType, AutonomousSystem::class), + Pair(DirectorySco.stixType, Directory::class), + Pair(DomainNameSco.stixType, DomainName::class), + Pair(EmailAddressSco.stixType, EmailAddress::class), + Pair(EmailMessageSco.stixType, EmailMessage::class), + Pair(FileSco.stixType, File::class), + Pair(IPv4AddressSco.stixType, IPv4Address::class), + Pair(IPv6AddressSco.stixType, IPv6Address::class), + Pair(MacAddressSco.stixType, MacAddress::class), + Pair(MutexSco.stixType, Mutex::class), + Pair(NetworkTrafficSco.stixType, NetworkTraffic::class), + Pair(ProcessSco.stixType, Process::class), + Pair(SoftwareSco.stixType, Software::class), + Pair(UrlSco.stixType, Url::class), + Pair(UserAccountSco.stixType, UserAccount::class), + Pair(WindowsRegistryKeySco.stixType, WindowsRegistryKey::class), + Pair(X509CertificateSco.stixType, X509Certificate::class) + ) + + val sroRegistry: Map> = mapOf( + Pair(RelationshipSro.stixType, Relationship::class), + Pair(SightingSro.stixType, Sighting::class) + ) + + val metaObjectRegistry: Map> = mapOf( + Pair(MarkingDefinitionDm.stixType, MarkingDefinition::class), + Pair(LanguageContentLco.stixType, LanguageContent::class) + ) + + /** + * Aggregate of the Stix Objects (spec defined and custom) + */ + private fun aggregateObjects(): Map> { + val objects = mutableMapOf>() + objects.plusAssign(sdoRegistry) + objects.plusAssign(scoRegistry) + objects.plusAssign(sroRegistry) + objects.plusAssign(metaObjectRegistry) + objects.plusAssign(customSdoRegistry) + objects.plusAssign(customScoRegistry) + objects.plusAssign(customSroRegistry) + objects.plusAssign(customMetaObjectRegistry) + return objects + } + + private var registryAggregate: Map> = aggregateObjects() + + /** + * Refreshes the Stix Object registry / regenerates the aggregated map of StixType and KClasses. + * When you add new objects to the specific registries (SDO, SRO, Custom, etc) + * you need to refresh for the values to become available. + * + * Typically used for polymorphic serialization/deserialization. + * + * The Refresh allows new objects to be added at runtime. + */ + fun refreshRegistry(){ + registryAggregate = aggregateObjects() + } + + /** + * Master repository of all objects that are considered Stix Objects (Bundleable Objects) / tier 1 objects in a bundle. + */ + val registry: Map> = registryAggregate + + + + // MARKING OBJECT REGISTRY: + + val markingObjectRegistry: Map> = mapOf( + Pair(TlpMo.definitionType, Tlp::class), + Pair(StatementMo.definitionType, Statement::class) + ) + + private fun aggregateMarkingObjects(): Map> { + val objects = mutableMapOf>() + objects.plusAssign(markingObjectRegistry) + objects.plusAssign(customMarkingObjectRegistry) + + return objects + } + + private var markingObjectRegistryAggregate: Map> = aggregateMarkingObjects() + + /** + * Refreshes the Marking Object registry + * + * Typically used for polymorphic serialization/deserialization. + * + * The Refresh allows new objects to be added at runtime. + */ + fun refreshMarkingObjectRegistry(){ + markingObjectRegistryAggregate = aggregateMarkingObjects() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/common/StixObjectRelationshipRegistry.kt b/src/main/kotlin/com/stephenott/stix/common/StixObjectRelationshipRegistry.kt new file mode 100644 index 0000000..66af8e6 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/common/StixObjectRelationshipRegistry.kt @@ -0,0 +1,30 @@ +package com.stephenott.stix.common + +import com.stephenott.stix.objects.core.sdo.objects.* +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro + +class StixObjectRelationshipRegistry() { + + var registry: List = + RelationshipSro.allowedCommonRelationships + + AttackPatternSdo.allowedRelationships + + CampaignSdo.allowedRelationships + + CourseOfActionSdo.allowedRelationships + + GroupingSdo.allowedRelationships + + IdentitySdo.allowedRelationships + + IndicatorSdo.allowedRelationships + + InfrastructureSdo.allowedRelationships + + IntrusionSetSdo.allowedRelationships + + LocationSdo.allowedRelationships + + MalwareSdo.allowedRelationships + + MalwareAnalysisSdo.allowedRelationships + + NoteSdo.allowedRelationships + + ObservedDataSdo.allowedRelationships + + OpinionSdo.allowedRelationships + + ReportSdo.allowedRelationships + + ThreatActorSdo.allowedRelationships + + ToolSdo.allowedRelationships + + VulnerabilitySdo.allowedRelationships + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/common/ValidatorManager.kt b/src/main/kotlin/com/stephenott/stix/common/ValidatorManager.kt new file mode 100644 index 0000000..a3e9dcb --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/common/ValidatorManager.kt @@ -0,0 +1,36 @@ +package com.stephenott.stix.common + +import com.stephenott.stix.Stix +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.StixType +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface BusinessRulesValidator{ + fun objectValidationRules(obj: T, stixInstance: Stix) +} + +interface BusinessRulesExtensionValidator{ + fun objectValidationRules(obj: T) +} + +interface CompanionStixType{ + val stixType: StixType +} + +interface CompanionExtensionType{ + val extensionType: String +} + +interface CompanionIdContributingProperties{ + val idContributingProperties: List> +} + +interface CompanionAllowedRelationships{ + val allowedRelationships: List +} + +interface CompanionAllowedExtensions{ + val allowedExtensions: List> +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/StixObject.kt b/src/main/kotlin/com/stephenott/stix/objects/StixObject.kt new file mode 100644 index 0000000..01eb74b --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/StixObject.kt @@ -0,0 +1,14 @@ +package com.stephenott.stix.objects + +import com.stephenott.stix.StixContent +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship + +/** + * Parent object for all STIX objects: SDO, SCO, SRO, Metadata + */ +interface StixObject : + StixContent { + + fun allowedRelationships(): List + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/StixCoreObject.kt b/src/main/kotlin/com/stephenott/stix/objects/core/StixCoreObject.kt new file mode 100644 index 0000000..96af30e --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/StixCoreObject.kt @@ -0,0 +1,6 @@ +package com.stephenott.stix.objects.core + +import com.stephenott.stix.objects.StixObject + +interface StixCoreObject: StixObject { +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/StixCyberObservableObject.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/StixCyberObservableObject.kt new file mode 100644 index 0000000..c91ea8d --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/StixCyberObservableObject.kt @@ -0,0 +1,13 @@ +package com.stephenott.stix.objects.core.sco + +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.StixObject +import com.stephenott.stix.objects.core.StixCoreObject + +interface StixCyberObservableObject : + StixCoreObject, + StixSpecVersionProp, + StixObjectMarkingsRefsProp, + StixGranularMarkingsProp, + StixDefangedProp, + StixExtensionsProp {} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/ScoExtension.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/ScoExtension.kt new file mode 100644 index 0000000..fbcebf5 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/ScoExtension.kt @@ -0,0 +1,3 @@ +package com.stephenott.stix.objects.core.sco.extension + +interface ScoExtension diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/ArchiveFileExtension.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/ArchiveFileExtension.kt new file mode 100644 index 0000000..c5e97c2 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/ArchiveFileExtension.kt @@ -0,0 +1,35 @@ +package com.stephenott.stix.objects.core.sco.extension.objects + +import com.stephenott.stix.common.BusinessRulesExtensionValidator +import com.stephenott.stix.common.CompanionExtensionType +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sco.objects.DirectorySco +import com.stephenott.stix.objects.core.sco.objects.FileSco +import com.stephenott.stix.type.StixIdentifiers + +interface ArchiveFileExtensionExt : ScoExtension { + val containsRefs: StixIdentifiers + val comment: String? + + companion object : + CompanionExtensionType, + BusinessRulesExtensionValidator { + + override val extensionType: String = "archive-ext" + + override fun objectValidationRules(obj: ArchiveFileExtensionExt) { + require(obj.containsRefs.all { it.type in listOf(FileSco.stixType, DirectorySco.stixType) }, + lazyMessage = { "contains_refs can only contain references to File and Directory SCOs." }) + } + } +} + +data class ArchiveFileExtension( + override val containsRefs: StixIdentifiers, + override val comment: String? = null +) : ArchiveFileExtensionExt { + + init { + ArchiveFileExtensionExt.objectValidationRules(this) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/HttpRequestExtension.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/HttpRequestExtension.kt new file mode 100644 index 0000000..026fa4a --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/HttpRequestExtension.kt @@ -0,0 +1,43 @@ +package com.stephenott.stix.objects.core.sco.extension.objects + +import com.stephenott.stix.common.BusinessRulesExtensionValidator +import com.stephenott.stix.common.CompanionExtensionType +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sco.objects.ArtifactSco +import com.stephenott.stix.type.HttpRequestHeaderDictionary +import com.stephenott.stix.type.StixIdentifier +import com.stephenott.stix.type.StixInteger + +interface HttpRequestExtensionExt : ScoExtension { + val requestMethod: String + val requestValue: String + val requestVersion: String? + val requestHeader: HttpRequestHeaderDictionary? + val messageBodyLength: StixInteger? + val messageBodyDataRef: StixIdentifier? + + companion object : + CompanionExtensionType, + BusinessRulesExtensionValidator { + + override val extensionType: String = "http-request-ext" + + override fun objectValidationRules(obj: HttpRequestExtensionExt) { + require(obj.messageBodyDataRef?.type == ArtifactSco.stixType) + } + } +} + +data class HttpRequestExtension( + override val requestMethod: String, + override val requestValue: String, + override val requestVersion: String? = null, + override val requestHeader: HttpRequestHeaderDictionary? = null, + override val messageBodyLength: StixInteger? = null, + override val messageBodyDataRef: StixIdentifier? = null +) : HttpRequestExtensionExt { + + init { + HttpRequestExtensionExt.objectValidationRules(this) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/IcmpExtension.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/IcmpExtension.kt new file mode 100644 index 0000000..022b9a0 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/IcmpExtension.kt @@ -0,0 +1,34 @@ +package com.stephenott.stix.objects.core.sco.extension.objects + +import com.stephenott.stix.common.BusinessRulesExtensionValidator +import com.stephenott.stix.common.CompanionExtensionType +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.type.StixHex + +interface IcmpExtensionExt: ScoExtension{ + + val icmpTypeHex: StixHex + val icmpCodeHex: StixHex + + companion object: + CompanionExtensionType, + BusinessRulesExtensionValidator { + + override val extensionType: String = "icmp-ext" + + override fun objectValidationRules(obj: IcmpExtensionExt) { + + } + } +} + +data class IcmpExtension( + override val icmpTypeHex: StixHex, + override val icmpCodeHex: StixHex + +): IcmpExtensionExt { + + init { + IcmpExtensionExt.objectValidationRules(this) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/NetworkSocketExtension.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/NetworkSocketExtension.kt new file mode 100644 index 0000000..c87d589 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/NetworkSocketExtension.kt @@ -0,0 +1,47 @@ +package com.stephenott.stix.objects.core.sco.extension.objects + +import com.stephenott.stix.common.BusinessRulesExtensionValidator +import com.stephenott.stix.common.CompanionExtensionType +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.type.StixBoolean +import com.stephenott.stix.type.StixInteger +import com.stephenott.stix.type.vocab.NetworkSocketAddressFamilyEnum +import com.stephenott.stix.type.vocab.NetworkSocketTypeEnum + +interface NetworkSocketExtensionExt: ScoExtension{ + + val addressFamily: NetworkSocketAddressFamilyEnum + val isBlocking: StixBoolean? + val isListening: StixBoolean? + val options: LinkedHashMap? //@TODO *** Refactor: https://github.com/oasis-tcs/cti-stix2/issues/185 + val socketType: NetworkSocketTypeEnum? + val socketDescriptor: StixInteger? + val socketHandle: StixInteger? + + companion object: + CompanionExtensionType, + BusinessRulesExtensionValidator { + + override val extensionType: String = "socket-ext" + + override fun objectValidationRules(obj: NetworkSocketExtensionExt) { + + } + } +} + +data class NetworkSocketExtension( + override val addressFamily: NetworkSocketAddressFamilyEnum, + override val isBlocking: StixBoolean? = null, + override val isListening: StixBoolean? = null, + override val options: LinkedHashMap? = null, + override val socketType: NetworkSocketTypeEnum? = null, + override val socketDescriptor: StixInteger? = null, + override val socketHandle: StixInteger? = null + +): NetworkSocketExtensionExt { + + init { + NetworkSocketExtensionExt.objectValidationRules(this) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/NtfsFileExtension.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/NtfsFileExtension.kt new file mode 100644 index 0000000..9b9dbf5 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/NtfsFileExtension.kt @@ -0,0 +1,33 @@ +package com.stephenott.stix.objects.core.sco.extension.objects + +import com.stephenott.stix.common.BusinessRulesExtensionValidator +import com.stephenott.stix.common.CompanionExtensionType +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.type.AlternateDataStreams + +interface NtfsFileExtensionExt: ScoExtension{ + val sid: String? + val alternateDataStreams: AlternateDataStreams? + + companion object: + CompanionExtensionType, + BusinessRulesExtensionValidator { + + override val extensionType: String = "ntfs-ext" + + override fun objectValidationRules(obj: NtfsFileExtensionExt) { + require(obj.sid != null || obj.alternateDataStreams != null, + lazyMessage = {"At least 1 property must be provided in the ntfs-ext extension."}) + } + } +} + +data class NtfsFileExtension( + override val sid: String? = null, + override val alternateDataStreams: AlternateDataStreams? = null +): NtfsFileExtensionExt { + + init { + NtfsFileExtensionExt.objectValidationRules(this) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/PdfFileExtension.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/PdfFileExtension.kt new file mode 100644 index 0000000..538ab81 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/PdfFileExtension.kt @@ -0,0 +1,44 @@ +package com.stephenott.stix.objects.core.sco.extension.objects + +import com.stephenott.stix.common.BusinessRulesExtensionValidator +import com.stephenott.stix.common.CompanionExtensionType +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.type.StixBoolean + +interface PdfFileExtensionExt: ScoExtension{ + + val version: String? + val isOptimized: StixBoolean? + val documentInfoDict: LinkedHashMap? + val pdfid0: String? + val pdfid1: String? + + companion object: + CompanionExtensionType, + BusinessRulesExtensionValidator { + + override val extensionType: String = "pdf-ext" + + override fun objectValidationRules(obj: PdfFileExtensionExt) { + require(obj.version != null || + obj.isOptimized != null || + obj.documentInfoDict != null || + obj.pdfid0 != null || + obj.pdfid1 != null, + lazyMessage = {"PDF File Extension must have at least one property provided."}) + } + } +} + +data class PdfFileExtension( + override val version: String? = null, + override val isOptimized: StixBoolean? = null, + override val documentInfoDict: LinkedHashMap? = null, + override val pdfid0: String? = null, + override val pdfid1: String? = null +): PdfFileExtensionExt { + + init { + PdfFileExtensionExt.objectValidationRules(this) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/RasterImageFileExtension.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/RasterImageFileExtension.kt new file mode 100644 index 0000000..0cd5de1 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/RasterImageFileExtension.kt @@ -0,0 +1,42 @@ +package com.stephenott.stix.objects.core.sco.extension.objects + +import com.stephenott.stix.common.BusinessRulesExtensionValidator +import com.stephenott.stix.common.CompanionExtensionType +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.type.ExifTagsDictionary +import com.stephenott.stix.type.StixInteger + +interface RasterImageFileExtensionExt: ScoExtension{ + + val imageHeight: StixInteger? + val imageWidth: StixInteger? + val bitsPerPixel: StixInteger? + val exifTags: ExifTagsDictionary? + + companion object: + CompanionExtensionType, + BusinessRulesExtensionValidator { + + override val extensionType: String = "raster-image-ext" + + override fun objectValidationRules(obj: RasterImageFileExtensionExt) { + require(obj.imageHeight != null || + obj.imageWidth != null || + obj.bitsPerPixel != null || + obj.exifTags != null, + lazyMessage = {"At least 1 property must be provided for RasterImage File Extension"}) + } + } +} + +data class RasterImageFileExtension( + override val imageHeight: StixInteger? = null, + override val imageWidth: StixInteger? = null, + override val bitsPerPixel: StixInteger? = null, + override val exifTags: ExifTagsDictionary? = null +): RasterImageFileExtensionExt { + + init { + RasterImageFileExtensionExt.objectValidationRules(this) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/TcpExtension.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/TcpExtension.kt new file mode 100644 index 0000000..2b250e9 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/TcpExtension.kt @@ -0,0 +1,35 @@ +package com.stephenott.stix.objects.core.sco.extension.objects + +import com.stephenott.stix.common.BusinessRulesExtensionValidator +import com.stephenott.stix.common.CompanionExtensionType +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.type.StixHex + +interface TcpExtensionExt : ScoExtension { + + val srcFlagsHex: StixHex? + val dstFlagsHex: StixHex? + + companion object : + CompanionExtensionType, + BusinessRulesExtensionValidator { + + override val extensionType: String = "tcp-ext" + + override fun objectValidationRules(obj: TcpExtensionExt) { + require(obj.srcFlagsHex != null || + obj.dstFlagsHex != null, + lazyMessage = { "At least one property must be provided for tcp-ext" }) + } + } +} + +data class TcpExtension( + override val srcFlagsHex: StixHex? = null, + override val dstFlagsHex: StixHex? = null +) : TcpExtensionExt { + + init { + TcpExtensionExt.objectValidationRules(this) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/UnixAccountExtension.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/UnixAccountExtension.kt new file mode 100644 index 0000000..ed1ee31 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/UnixAccountExtension.kt @@ -0,0 +1,39 @@ +package com.stephenott.stix.objects.core.sco.extension.objects + +import com.stephenott.stix.common.BusinessRulesExtensionValidator +import com.stephenott.stix.common.CompanionExtensionType +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.type.StixInteger +import com.stephenott.stix.type.StixStringList + +interface UnixAccountExtensionExt : ScoExtension { + + val gid: StixInteger? + val groups: StixStringList? + val homeDir: String? + val shell: String? + + companion object : + CompanionExtensionType, + BusinessRulesExtensionValidator { + + override val extensionType: String = "unix-account-ext" + + override fun objectValidationRules(obj: UnixAccountExtensionExt) { + require(listOf(obj.gid, obj.groups, obj.homeDir, obj.shell).any { it != null }, + lazyMessage = {"unix-account-ext must have at least one property provided/is not null."}) + } + } +} + +data class UnixAccountExtension( + override val gid: StixInteger? = null, + override val groups: StixStringList? = null, + override val homeDir: String? = null, + override val shell: String? = null +) : UnixAccountExtensionExt { + + init { + UnixAccountExtensionExt.objectValidationRules(this) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/WindowsPeBinaryFileExtension.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/WindowsPeBinaryFileExtension.kt new file mode 100644 index 0000000..279d938 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/WindowsPeBinaryFileExtension.kt @@ -0,0 +1,65 @@ +package com.stephenott.stix.objects.core.sco.extension.objects + +import com.stephenott.stix.common.BusinessRulesExtensionValidator +import com.stephenott.stix.common.CompanionExtensionType +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.type.* +import com.stephenott.stix.type.vocab.WindowsPebinaryTypeOv +import kotlin.reflect.KVisibility +import kotlin.reflect.full.memberProperties + +interface WindowsPeBinaryFileExtensionExt : ScoExtension { + + val peType: WindowsPebinaryTypeOv + val imphash: String? + val machineHex: StixHex? + val numberOfSections: StixInteger? + val timeDateStamp: StixTimestamp? + val pointerToSymbolTableHex: StixHex? + val numberOfSymbols: StixInteger? + val sizeOfOptionalHeader: StixInteger? + val characteristicsHex: StixHex? + val fileHeaderHashes: HashesDictionary? + val optionalHeader: WindowsPeOptionalHeaderType? + val sections: WindowsPeSectionTypes? + + companion object : + CompanionExtensionType, + BusinessRulesExtensionValidator { + + override val extensionType: String = "windows-pebinary-ext" + + override fun objectValidationRules(obj: WindowsPeBinaryFileExtensionExt) { + require(obj.timeDateStamp?.subSecondPrecision == 0, + lazyMessage = {"time_date_stamp cannot have sub-second precision"}) + require(obj.sizeOfOptionalHeader?.value!! >= 0, + lazyMessage = {"size_of_optional_header must not be negative."}) + require(obj::class.memberProperties + .filter { + it.visibility == KVisibility.PUBLIC && it.name != obj::peType.name + }.any { it.getter.call() != null }, + lazyMessage = { "At least one property other than pe_type must be provided/be not null." }) + } + } +} + +data class WindowsPeBinaryFileExtension( + override val peType: WindowsPebinaryTypeOv, + override val imphash: String? = null, + override val machineHex: StixHex? = null, + override val numberOfSections: StixInteger? = null, + override val timeDateStamp: StixTimestamp? = null, + override val pointerToSymbolTableHex: StixHex? = null, + override val numberOfSymbols: StixInteger? = null, + override val sizeOfOptionalHeader: StixInteger? = null, + override val characteristicsHex: StixHex? = null, + override val fileHeaderHashes: HashesDictionary? = null, + override val optionalHeader: WindowsPeOptionalHeaderType? = null, + override val sections: WindowsPeSectionTypes? = null + +) : WindowsPeBinaryFileExtensionExt { + + init { + WindowsPeBinaryFileExtensionExt.objectValidationRules(this) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/WindowsProcessExtension.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/WindowsProcessExtension.kt new file mode 100644 index 0000000..232e8d2 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/WindowsProcessExtension.kt @@ -0,0 +1,65 @@ +package com.stephenott.stix.objects.core.sco.extension.objects + +import com.stephenott.stix.common.BusinessRulesExtensionValidator +import com.stephenott.stix.common.CompanionExtensionType +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.type.StixBoolean +import com.stephenott.stix.type.vocab.WindowsIntegrityLevelEnum +import kotlin.reflect.KVisibility +import kotlin.reflect.full.memberProperties + +interface WindowsProcessExtensionExt : ScoExtension { + + val aslrEnabled: StixBoolean? + val depEnabled: StixBoolean? + val priority: WindowsProcessExtensionPriority? + val ownerSid: String? + val windowTitle: String? + val startupInfo: LinkedHashMap? //@TODO refactor with https://github.com/oasis-tcs/cti-stix2/issues/185#issuecomment-543309219 + val integrityLevel: WindowsIntegrityLevelEnum? + + companion object : + CompanionExtensionType, + BusinessRulesExtensionValidator { + + override val extensionType: String = "windows-process-ext" + + override fun objectValidationRules(obj: WindowsProcessExtensionExt) { + require(obj::class.memberProperties + .filter {it.visibility == KVisibility.PUBLIC} + .any { it.getter.call() != null }, + lazyMessage = {"At least one property must be provided/not null."}) + } + } +} + +data class WindowsProcessExtensionPriority( + val priority: String, + val enforceSuffixRule: Boolean = WindowsProcessExtensionPriority.enforceSuffixRuleDefault +): CharSequence by priority { + + companion object{ + var enforceSuffixRuleDefault: Boolean = true + } + + init { + if (enforceSuffixRule){ + require(priority.endsWith("_CLASS")) + } + } +} + +data class WindowsProcessExtension( + override val aslrEnabled: StixBoolean? = null, + override val depEnabled: StixBoolean? = null, + override val priority: WindowsProcessExtensionPriority? = null, + override val ownerSid: String? = null, + override val windowTitle: String? = null, + override val startupInfo: LinkedHashMap? = null, + override val integrityLevel: WindowsIntegrityLevelEnum? = null +) : WindowsProcessExtensionExt { + + init { + WindowsProcessExtensionExt.objectValidationRules(this) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/WindowsServiceExtension.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/WindowsServiceExtension.kt new file mode 100644 index 0000000..53b5073 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/extension/objects/WindowsServiceExtension.kt @@ -0,0 +1,55 @@ +package com.stephenott.stix.objects.core.sco.extension.objects + +import com.stephenott.stix.common.BusinessRulesExtensionValidator +import com.stephenott.stix.common.CompanionExtensionType +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.type.StixIdentifiers +import com.stephenott.stix.type.StixStringList +import com.stephenott.stix.type.vocab.WindowsServiceStartTypeEnum +import com.stephenott.stix.type.vocab.WindowsServiceStatusEnum +import com.stephenott.stix.type.vocab.WindowsServiceTypeEnum +import kotlin.reflect.KVisibility +import kotlin.reflect.full.memberProperties + +interface WindowsServiceExtensionExt : ScoExtension { + + val serviceName: String? + val descriptions: StixStringList? + val displayName: String? + val groupName: String? + val startType: WindowsServiceStartTypeEnum? + val serviceDllRefs: StixIdentifiers? + val serviceType: WindowsServiceTypeEnum? + val serviceStatus: WindowsServiceStatusEnum? + + companion object : + CompanionExtensionType, + BusinessRulesExtensionValidator { + + override val extensionType: String = "windows-service-ext" + + override fun objectValidationRules(obj: WindowsServiceExtensionExt) { + require(this::class.memberProperties + .filter {it.visibility == KVisibility.PUBLIC} + .any { it.getter.call() != null }, + lazyMessage = {"windows-service-extension requires at least one property must be provided/not null."}) + } + } +} + +data class WindowsServiceExtension( + override val serviceName: String? = null, + override val descriptions: StixStringList? = null, + override val displayName: String? = null, + override val groupName: String? = null, + override val startType: WindowsServiceStartTypeEnum? = null, + override val serviceDllRefs: StixIdentifiers? = null, + override val serviceType: WindowsServiceTypeEnum? = null, + override val serviceStatus: WindowsServiceStatusEnum? = null + +) : WindowsServiceExtensionExt { + + init { + WindowsServiceExtensionExt.objectValidationRules(this) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Artifact.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Artifact.kt new file mode 100644 index 0000000..f93f3ff --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Artifact.kt @@ -0,0 +1,93 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import com.stephenott.stix.type.vocab.EncryptionAlgorithmEnum +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface ArtifactSco : StixCyberObservableObject { + + val mimeType: String? + val payloadBin: StixBinary? + val url: String? + val hashes: HashesDictionary? + val encryptionAlgorithm: EncryptionAlgorithmEnum? + val decryptionKey: String? + + companion object : + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val allowedExtensions: List> = listOf() + + override val stixType = StixType("artifact") + + override val idContributingProperties: List> = listOf( + ArtifactSco::hashes, + ArtifactSco::payloadBin + ) + + override val allowedRelationships: List = listOf( + + ) + + override fun objectValidationRules(obj: ArtifactSco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + if (obj.url != null) { + require(obj.payloadBin == null, lazyMessage = { "payload_bin must not be present if url is provided." }) + } + if (obj.payloadBin != null) { + require(obj.url == null, lazyMessage = { "url must not be present if payload_bin is provided." }) + } + if (obj.url != null) { + require(obj.hashes != null, lazyMessage = { "hashes must be present when url property is present" }) + } + if (obj.encryptionAlgorithm == null) { + require( + obj.decryptionKey == null, + lazyMessage = { "decryption_key must not be present when encryption_algorithm is absent." }) + } + } + + } +} + +data class Artifact( + override val mimeType: String? = null, + override val payloadBin: StixBinary? = null, + override val url: String? = null, + override val hashes: HashesDictionary? = null, + override val encryptionAlgorithm: EncryptionAlgorithmEnum? = null, + override val decryptionKey: String? = null, + override val type: StixType = StixType(ArtifactSco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : ArtifactSco { + + init { + if (this.stixValidateOnConstruction) { + ArtifactSco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/AutonomousSystem.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/AutonomousSystem.kt new file mode 100644 index 0000000..d21274c --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/AutonomousSystem.kt @@ -0,0 +1,70 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface AutonomousSystemSco : StixCyberObservableObject { + + val number: StixInteger + val name: String? + val rir: String? + + companion object: + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val allowedExtensions: List> = listOf() + + override val stixType = StixType("autonomous-system") + + override val idContributingProperties: List> = listOf( + AutonomousSystemSco::number + ) + + override val allowedRelationships: List = listOf( + + ) + + override fun objectValidationRules(obj: AutonomousSystemSco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + } + + } +} + +data class AutonomousSystem( + override val number: StixInteger, + override val name: String? = null, + override val rir: String? = null, + override val type: StixType = StixType(AutonomousSystemSco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : AutonomousSystemSco { + + init { + if (this.stixValidateOnConstruction) { + AutonomousSystemSco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Directory.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Directory.kt new file mode 100644 index 0000000..db2e860 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Directory.kt @@ -0,0 +1,81 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface DirectorySco : StixCyberObservableObject { + + val path: String + val pathEnc: String? //@TODO add validation + val ctime: StixTimestamp? + val mtime: StixTimestamp? + val atime: StixTimestamp? + val containsRefs: StixIdentifiers? + + companion object : + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val allowedExtensions: List> = listOf() + + override val stixType = StixType("directory") + + override val idContributingProperties: List> = listOf( + DirectorySco::path + ) + + override val allowedRelationships: List = listOf( + + ) + + override fun objectValidationRules(obj: DirectorySco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + obj.containsRefs?.let { + require(it.all { id -> id.type == stixType || id.type == FileSco.stixType }, + lazyMessage = { "contains_refs must only contain SCOs of type Directory and File." } + ) + } + } + } +} + +data class Directory( + override val path: String, + override val pathEnc: String? = null, + override val ctime: StixTimestamp? = null, + override val mtime: StixTimestamp? = null, + override val atime: StixTimestamp? = null, + override val containsRefs: StixIdentifiers?, + override val type: StixType = StixType(DirectorySco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : DirectorySco { + + init { + if (this.stixValidateOnConstruction) { + DirectorySco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/DomainName.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/DomainName.kt new file mode 100644 index 0000000..2cd6f0a --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/DomainName.kt @@ -0,0 +1,82 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface DomainNameSco : StixCyberObservableObject { + + val value: String //@TODO add validation + //@TODO deprecated resolves_to_refs, add elevator code to create relationships from the 2.1 objects + + companion object: + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val allowedExtensions: List> = listOf() + + override val stixType = StixType("domain-name") + + override val idContributingProperties: List> = listOf( + DomainNameSco::value + ) + + override val allowedRelationships: List = listOf( + AllowedRelationship( + DomainNameSco::class, + RelationshipType("resolves-to"), + DomainNameSco::class + ), + AllowedRelationship( + DomainNameSco::class, + RelationshipType("resolves-to"), + DomainNameSco::class // @TODO IPV4-addr + ), + AllowedRelationship( + DomainNameSco::class, + RelationshipType("resolves-to"), + DomainNameSco::class // @TODO IPV6-addr + ) + ) + + override fun objectValidationRules(obj: DomainNameSco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + } + + } +} + +data class DomainName( + override val value: String, + override val type: StixType = StixType(DomainNameSco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : DomainNameSco { + + init { + if (this.stixValidateOnConstruction) { + DomainNameSco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/EmailAddress.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/EmailAddress.kt new file mode 100644 index 0000000..0f5f4e6 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/EmailAddress.kt @@ -0,0 +1,75 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface EmailAddressSco : StixCyberObservableObject { + + val value: String //@TODO add validation + val displayName: String? //@TODO add validation + val belongsToRef: StixIdentifier? + + companion object : + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val allowedExtensions: List> = listOf() + + override val stixType = StixType("email-addr") + + override val idContributingProperties: List> = listOf( + EmailAddressSco::value + ) + + override val allowedRelationships: List = listOf( + + ) + + override fun objectValidationRules(obj: EmailAddressSco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + obj.belongsToRef?.let { + require(it.type == UserAccountSco.stixType, + lazyMessage = { "belongs_to_ref must reference a user-account SCO." } + ) + } + } + } +} + +data class EmailAddress( + override val value: String, + override val displayName: String? = null, + override val belongsToRef: StixIdentifier? = null, + override val type: StixType = StixType(EmailAddressSco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : EmailAddressSco { + + init { + if (this.stixValidateOnConstruction) { + EmailAddressSco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/EmailMessage.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/EmailMessage.kt new file mode 100644 index 0000000..31676ce --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/EmailMessage.kt @@ -0,0 +1,124 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface EmailMessageSco : StixCyberObservableObject { + + val isMultipart: StixBoolean + val date: StixTimestamp? + val contentType: String? + val fromRef: StixIdentifier? + val senderRef: StixIdentifier? + val toRefs: StixIdentifiers? + val ccRefs: StixIdentifiers? + val bccRefs: StixIdentifiers? + val messageId: String? + val subject: String? + val receivedLines: StixStringList? + val additionalHeaderFields: AdditionalHeaderFieldsDictionary? + val body: String? + val bodyMultipart: MimePartTypes? + val rawEmailRef: StixIdentifier? + + companion object : + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val allowedExtensions: List> = listOf() + + override val stixType = StixType("email-message") + + override val idContributingProperties: List> = listOf( + EmailMessageSco::fromRef, + EmailMessageSco::subject, + EmailMessageSco::body + ) + + override val allowedRelationships: List = listOf( + + ) + + override fun objectValidationRules(obj: EmailMessageSco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + obj.fromRef?.let { + require(it.type == EmailAddressSco.stixType, + lazyMessage = { "from_ref must be references to email-address SCO" }) + } + obj.senderRef?.let { + require(it.type == EmailAddressSco.stixType, + lazyMessage = { "sender_ref must be references to email-address SCO" }) + } + obj.toRefs?.let { + require(it.all { id -> id.type == EmailAddressSco.stixType }, + lazyMessage = { "to_refs must be references to email-address SCO" }) + } + obj.ccRefs?.let { + require(it.all { id -> id.type == EmailAddressSco.stixType }, + lazyMessage = { "cc_refs must be references to email-address SCO" }) + } + obj.bccRefs?.let { + require(it.all { id -> id.type == EmailAddressSco.stixType }, + lazyMessage = { "bcc_refs must be references to email-address SCO" }) + } + + if (obj.isMultipart.value) { + require(obj.body == null, + lazyMessage = { "body cannot be used when is_multipart is true" }) + } else { + require(obj.bodyMultipart == null, + lazyMessage = { "body_multipart cannot be used when is_multipart is false" }) + } + } + } +} + +data class EmailMessage( + override val isMultipart: StixBoolean, + override val date: StixTimestamp? = null, + override val contentType: String? = null, + override val fromRef: StixIdentifier? = null, + override val senderRef: StixIdentifier? = null, + override val toRefs: StixIdentifiers? = null, + override val ccRefs: StixIdentifiers? = null, + override val bccRefs: StixIdentifiers? = null, + override val messageId: String? = null, + override val subject: String? = null, + override val receivedLines: StixStringList? = null, + override val additionalHeaderFields: AdditionalHeaderFieldsDictionary? = null, + override val body: String? = null, + override val bodyMultipart: MimePartTypes? = null, + override val rawEmailRef: StixIdentifier? = null, + override val type: StixType = StixType(EmailMessageSco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : EmailMessageSco { + + init { + if (this.stixValidateOnConstruction) { + EmailMessageSco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/File.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/File.kt new file mode 100644 index 0000000..9327b72 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/File.kt @@ -0,0 +1,114 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sco.extension.objects.* +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.isSubclassOf + +interface FileSco : StixCyberObservableObject { + + val hashes: HashesDictionary? + val size: StixInteger? + val name: String? + val nameEnc: String? + val magicNumberHex: StixHex? + val mimeType: String? + val cTime: StixTimestamp? + val mTime: StixTimestamp? + val aTime: StixTimestamp? + val parentDirectoryRef: StixIdentifier? + val containsRefs: StixIdentifiers? + val contentRef: StixIdentifier? + + companion object : + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val stixType = StixType("file") + + override val idContributingProperties: List> = listOf( + FileSco::hashes, + FileSco::name, + FileSco::extensions + ) + + override val allowedRelationships: List = listOf( + + ) + + override val allowedExtensions: List> = listOf( + NtfsFileExtensionExt::class, + RasterImageFileExtensionExt::class, + PdfFileExtensionExt::class, + ArchiveFileExtensionExt::class, + WindowsPeBinaryFileExtensionExt::class + ) + + override fun objectValidationRules(obj: FileSco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + obj.size?.let { + require(it.value >= 0, + lazyMessage = { "size must not be a negative number." }) + } + obj.parentDirectoryRef?.let { + require(it.type == DirectorySco.stixType, + lazyMessage = { "parent_directory_ref must only contain a reference to a Directory object SCO." }) + } + obj.containsRefs?.let { + require(it.all { id -> stixInstance.registries.objectRegistry.registry.getValue(id.type).isSubclassOf(StixCyberObservableObject::class) }, + lazyMessage = { "contains_refs can only contain references to SCOs." }) + } + obj.contentRef?.let { + require(it.type == ArtifactSco.stixType, + lazyMessage = { "content_ref must only contain a reference to a Artifact SCO." }) + } + } + } +} + +data class File( + override val hashes: HashesDictionary? = null, + override val size: StixInteger? = null, + override val name: String? = null, + override val nameEnc: String? = null, + override val magicNumberHex: StixHex? = null, + override val mimeType: String? = null, + override val cTime: StixTimestamp? = null, + override val mTime: StixTimestamp? = null, + override val aTime: StixTimestamp? = null, + override val parentDirectoryRef: StixIdentifier? = null, + override val containsRefs: StixIdentifiers? = null, + override val contentRef: StixIdentifier? = null, + override val type: StixType = StixType(FileSco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : FileSco { + + init { + if (this.stixValidateOnConstruction) { + FileSco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/IPv4Address.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/IPv4Address.kt new file mode 100644 index 0000000..ece9446 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/IPv4Address.kt @@ -0,0 +1,76 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface IPv4AddressSco : StixCyberObservableObject { + + val value: String +// val resolvesToRefs: StixIdentifiers //@TODO DEPRECATED add elevator +// val belongsToRefs: StixIdentifiers //@TODO DEPRECATED add elevator + + companion object: + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val allowedExtensions: List> = listOf() + + override val stixType = StixType("ipv4-addr") + + override val idContributingProperties: List> = listOf( + IPv4AddressSco::value + ) + + override val allowedRelationships: List = listOf( + AllowedRelationship( + IPv4AddressSco::class, + RelationshipType("resolves-to"), + DomainNameSco::class //@TODO mac-addr + ), + AllowedRelationship( + IPv4AddressSco::class, + RelationshipType("belongs-to"), + AutonomousSystemSco::class + ) + ) + + override fun objectValidationRules(obj: IPv4AddressSco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + } + } +} + +data class IPv4Address( + override val value: String, + override val type: StixType = StixType(IPv4AddressSco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : IPv4AddressSco { + + init { + if (this.stixValidateOnConstruction) { + IPv4AddressSco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/IPv6Address.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/IPv6Address.kt new file mode 100644 index 0000000..363ee78 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/IPv6Address.kt @@ -0,0 +1,77 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface IPv6AddressSco : StixCyberObservableObject { + + val value: String +// val resolvesToRefs: StixIdentifiers //@TODO DEPRECATED add elevator +// val belongsToRefs: StixIdentifiers //@TODO DEPRECATED add elevator + + companion object : + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val allowedExtensions: List> = listOf() + + override val stixType = StixType("ipv6-addr") + + override val idContributingProperties: List> = listOf( + IPv6AddressSco::value + ) + + override val allowedRelationships: List = listOf( + AllowedRelationship( + IPv6AddressSco::class, + RelationshipType("resolves-to"), + DomainNameSco::class //@TODO mac-addr + ), + AllowedRelationship( + IPv6AddressSco::class, + RelationshipType("belongs-to"), + AutonomousSystemSco::class + ) + ) + + override fun objectValidationRules(obj: IPv6AddressSco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + } + + } +} + +data class IPv6Address( + override val value: String, + override val type: StixType = StixType(IPv6AddressSco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : IPv6AddressSco { + + init { + if (this.stixValidateOnConstruction) { + IPv6AddressSco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/MacAddress.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/MacAddress.kt new file mode 100644 index 0000000..bedd38d --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/MacAddress.kt @@ -0,0 +1,68 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface MacAddressSco : StixCyberObservableObject { + + val value: String + + companion object : + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val allowedExtensions: List> = listOf() + + override val stixType = StixType("mac-addr") + + override val idContributingProperties: List> = listOf( + MacAddressSco::value + ) + + override val allowedRelationships: List = listOf( + + ) + + override fun objectValidationRules(obj: MacAddressSco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + //@TODO The MAC address value ​MUST​ be represented as a single colon-delimited, lowercase MAC-48 address, which ​MUST​ include leading zeros for each octet. + } + + } +} + +data class MacAddress( + override val value: String, + override val type: StixType = StixType(MacAddressSco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : MacAddressSco { + + init { + if (this.stixValidateOnConstruction) { + MacAddressSco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Mutex.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Mutex.kt new file mode 100644 index 0000000..6ed3f16 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Mutex.kt @@ -0,0 +1,67 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface MutexSco : StixCyberObservableObject { + + val name: String + + companion object : + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val allowedExtensions: List> = listOf() + + override val stixType = StixType("mutex") + + override val idContributingProperties: List> = listOf( + MutexSco::name + ) + + override val allowedRelationships: List = listOf( + + ) + + override fun objectValidationRules(obj: MutexSco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + } + + } +} + +data class Mutex( + override val name: String, + override val type: StixType = StixType(MutexSco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : MutexSco { + + init { + if (this.stixValidateOnConstruction) { + MutexSco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/NetworkTraffic.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/NetworkTraffic.kt new file mode 100644 index 0000000..b2eec67 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/NetworkTraffic.kt @@ -0,0 +1,168 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sco.extension.objects.* +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface NetworkTrafficSco : StixCyberObservableObject { + + val start: StixTimestamp? + val end: StixTimestamp? + val isActive: StixBoolean? + val srcRef: StixIdentifier? + val dstRef: StixIdentifier? + val srcPort: StixInteger? + val dstPort: StixInteger? + val protocols: StixStringList + val srcByteCount: StixInteger? + val dstByteCount: StixInteger? + val srcPackets: StixInteger? + val dstPackets: StixInteger? + val ipfix: IpfixDictionary? + val srcPayloadRef: StixIdentifier? + val dstPayloadRef: StixIdentifier? + val encapsulatesRefs: StixIdentifiers? + val encapsulatedByRef: StixIdentifier? + + companion object : + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val stixType = StixType("network-traffic") + + override val idContributingProperties: List> = listOf( + NetworkTrafficSco::start, + NetworkTrafficSco::srcRef, + NetworkTrafficSco::dstRef, + NetworkTrafficSco::srcPort, + NetworkTrafficSco::dstPort, + NetworkTrafficSco::protocols + ) + + override val allowedRelationships: List = listOf( + + ) + + override val allowedExtensions: List> = listOf( + HttpRequestExtensionExt::class, + TcpExtensionExt::class, + IcmpExtensionExt::class, + NetworkSocketExtensionExt::class + ) + + override fun objectValidationRules(obj: NetworkTrafficSco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + obj.isActive?.let { + if (it.value) { + require(obj.end == null, + lazyMessage = { "If is_active is true then end must not be included." }) + } + } + if (obj.start != null && obj.end != null) { + require(obj.end?.instant!!.isAfter(obj.start?.instant), + lazyMessage = { "if start and end are both defined then end must be later than start." }) + } + obj.end?.let { + require(obj.isActive != null && + !obj.isActive!!.value && + obj.isActive!!.isDefinedValue, + lazyMessage = { "If end is provided then is_active must be provided and have a value of false." }) + } + obj.srcRef?.let { + require(it.type in listOf( + IPv4AddressSco.stixType, + IPv6AddressSco.stixType, + MacAddressSco.stixType, + DomainNameSco.stixType + ), + lazyMessage = { "src_ref must be a reference to one of: ipv4-addr, ipv6-addr, mac-addr, domain-name." }) + } + obj.dstRef?.let { + require(it.type in listOf( + IPv4AddressSco.stixType, + IPv6AddressSco.stixType, + MacAddressSco.stixType, + DomainNameSco.stixType + ), + lazyMessage = { "dst_ref must be a reference to one of: ipv4-addr, ipv6-addr, mac-addr, domain-name." }) + } + obj.srcPort?.let { + require(it.value in 0..65535, + lazyMessage = { "src_port must be in range 0 to 65535" }) + } + obj.dstPort?.let { + require(it.value in 0..65535, + lazyMessage = { "dst_port must be in range 0 to 65535" }) + } + obj.srcPayloadRef?.let { + require(it.type == ArtifactSco.stixType, + lazyMessage = { "src_payload_ref must only reference type artifact" }) + } + obj.dstPayloadRef?.let { + require(it.type == ArtifactSco.stixType, + lazyMessage = { "dst_payload_ref must only reference type artifact" }) + } + obj.encapsulatesRefs?.let { + require(it.all { id -> id.type == NetworkTrafficSco.stixType }, + lazyMessage = { "encapsulates_refs values must only reference type network-traffic" }) + } + obj.encapsulatedByRef?.let { + require(it.type == NetworkTrafficSco.stixType, + lazyMessage = { "encapsulated_by_ref must only reference type network-traffic" }) + } + } + + } +} + +data class NetworkTraffic( + override val start: StixTimestamp? = null, + override val end: StixTimestamp? = null, + override val isActive: StixBoolean? = null, + override val srcRef: StixIdentifier? = null, + override val dstRef: StixIdentifier? = null, + override val srcPort: StixInteger? = null, + override val dstPort: StixInteger? = null, + override val protocols: StixStringList, + override val srcByteCount: StixInteger? = null, + override val dstByteCount: StixInteger? = null, + override val srcPackets: StixInteger? = null, + override val dstPackets: StixInteger? = null, + override val ipfix: IpfixDictionary? = null, + override val srcPayloadRef: StixIdentifier? = null, + override val dstPayloadRef: StixIdentifier? = null, + override val encapsulatesRefs: StixIdentifiers? = null, + override val encapsulatedByRef: StixIdentifier? = null, + override val type: StixType = StixType(NetworkTrafficSco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : NetworkTrafficSco { + + init { + if (this.stixValidateOnConstruction) { + NetworkTrafficSco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Process.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Process.kt new file mode 100644 index 0000000..fcec321 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Process.kt @@ -0,0 +1,106 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sco.extension.objects.WindowsProcessExtensionExt +import com.stephenott.stix.objects.core.sco.extension.objects.WindowsServiceExtensionExt +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface ProcessSco : StixCyberObservableObject { + + val isHidden: StixBoolean? + val pid: StixInteger? + val createdTime: StixTimestamp? + val cwd: String? + val commandLine: String? + val environmentVariables: LinkedHashMap? //@TODO Refactor: https://github.com/oasis-tcs/cti-stix2/issues/185#issuecomment-543299610 + val openedConnectionRef: StixIdentifier? + val creatorUserRef: StixIdentifier? + val imageRef: StixIdentifier? + val parentRef: StixIdentifier? + val childRefs: StixIdentifiers? + + companion object : + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val stixType = StixType("process") + + override val idContributingProperties: List> = listOf( + //@TODO review as there are no ID contributing props as per current spec + ) + + override val allowedRelationships: List = listOf( + + ) + + override val allowedExtensions: List> = listOf( + WindowsProcessExtensionExt::class, + WindowsServiceExtensionExt::class + ) + + override fun objectValidationRules(obj: ProcessSco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + require(obj.openedConnectionRef?.type == NetworkTrafficSco.stixType, + lazyMessage = { "opened_connection_ref must only reference network-traffic SCO." }) + + require(obj.creatorUserRef?.type == UserAccountSco.stixType, + lazyMessage = { "creator_user_ref must only reference user-account SCO." }) + + require(obj.imageRef?.type == FileSco.stixType, + lazyMessage = { "image_ref must only reference file SCO." }) + + require(obj.parentRef?.type == ProcessSco.stixType, + lazyMessage = { "parent_ref must only reference process SCO." }) + + require(obj.childRefs?.all { it.type == ProcessSco.stixType }!!, + lazyMessage = { "child_refs must only have values that reference process SCO." }) + } + + } +} + +data class Process( + override val isHidden: StixBoolean? = null, + override val pid: StixInteger? = null, + override val createdTime: StixTimestamp? = null, + override val cwd: String? = null, + override val commandLine: String? = null, + override val environmentVariables: LinkedHashMap? = null, + override val openedConnectionRef: StixIdentifier? = null, + override val creatorUserRef: StixIdentifier? = null, + override val imageRef: StixIdentifier? = null, + override val parentRef: StixIdentifier? = null, + override val childRefs: StixIdentifiers? = null, + override val type: StixType = StixType(ProcessSco.stixType), + override val id: StixIdentifier = StixIdentifier(type), //@TODO review as spec currently says that a Process SCO uses a UUID v4 + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : ProcessSco { + + init { + if (this.stixValidateOnConstruction) { + ProcessSco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Software.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Software.kt new file mode 100644 index 0000000..fccea54 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Software.kt @@ -0,0 +1,79 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import com.stephenott.stix.type.vocab.LanguageCodes +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface SoftwareSco : StixCyberObservableObject { + + val name: String + val cpe: String? + val languages: LanguageCodes? + val vendor: String? + val version: String? + + companion object : + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val allowedExtensions: List> = listOf() + + override val stixType = StixType("software") + + override val idContributingProperties: List> = listOf( + SoftwareSco::name, + SoftwareSco::cpe, + SoftwareSco::vendor, + SoftwareSco::version + ) + + override val allowedRelationships: List = listOf( + + ) + + override fun objectValidationRules(obj: SoftwareSco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + } + + } +} + +data class Software( + override val name: String, + override val cpe: String? = null, + override val languages: LanguageCodes? = null, + override val vendor: String? = null, + override val version: String? = null, + override val type: StixType = StixType(SoftwareSco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : SoftwareSco { + + init { + if (this.stixValidateOnConstruction) { + SoftwareSco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Url.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Url.kt new file mode 100644 index 0000000..4bb946e --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/Url.kt @@ -0,0 +1,66 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface UrlSco : StixCyberObservableObject { + + val value: String + + companion object : + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val allowedExtensions: List> = listOf() + + override val stixType = StixType("url") + + override val idContributingProperties: List> = listOf( + UrlSco::value + ) + + override val allowedRelationships: List = listOf( + + ) + + override fun objectValidationRules(obj: UrlSco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + } + + } +} + +data class Url( + override val value: String, + override val type: StixType = StixType(UrlSco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : UrlSco { + + init { + if (this.stixValidateOnConstruction) { + UrlSco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/UserAccount.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/UserAccount.kt new file mode 100644 index 0000000..7cae06a --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/UserAccount.kt @@ -0,0 +1,98 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sco.extension.objects.UnixAccountExtensionExt +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import com.stephenott.stix.type.vocab.AccountType +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface UserAccountSco : StixCyberObservableObject { + + val userId: String? + val credential: String? + val accountLogin: String? + val accountType: AccountType? + val displayName: String? + val isServiceAccount: StixBoolean? + val isPrivilege: StixBoolean? + val canEscalatePrivs: StixBoolean? + val isDisabled: StixBoolean? + val accountCreated: StixTimestamp? + val accountExpires: StixTimestamp? + val credentialLastChanged: StixTimestamp? + val accountFirstLogin: StixTimestamp? + val accountLastLogin: StixTimestamp? + + companion object : + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val stixType = StixType("user-account") + + override val idContributingProperties: List> = listOf( + UserAccountSco::accountType, + UserAccountSco::userId, + UserAccountSco::accountLogin + ) + + override val allowedRelationships: List = listOf( + + ) + + override val allowedExtensions: List> = listOf( + UnixAccountExtensionExt::class + ) + + override fun objectValidationRules(obj: UserAccountSco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + } + + } +} + +data class UserAccount( + override val userId: String? = null, + override val credential: String? = null, + override val accountLogin: String? = null, + override val accountType: AccountType? = null, + override val displayName: String? = null, + override val isServiceAccount: StixBoolean? = null, + override val isPrivilege: StixBoolean? = null, + override val canEscalatePrivs: StixBoolean? = null, + override val isDisabled: StixBoolean? = null, + override val accountCreated: StixTimestamp? = null, + override val accountExpires: StixTimestamp? = null, + override val credentialLastChanged: StixTimestamp? = null, + override val accountFirstLogin: StixTimestamp? = null, + override val accountLastLogin: StixTimestamp? = null, + override val type: StixType = StixType(UserAccountSco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : UserAccountSco { + + init { + if (this.stixValidateOnConstruction) { + UserAccountSco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/WindowsRegistryKey.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/WindowsRegistryKey.kt new file mode 100644 index 0000000..ff3040f --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/WindowsRegistryKey.kt @@ -0,0 +1,82 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface WindowsRegistryKeySco : StixCyberObservableObject { + + val key: String? + val values: WindowsRegistryValueTypes? + val modifiedTimed: StixTimestamp? + val creatorUserRef: StixIdentifier? + val numberOfSubkeys: StixInteger? + + companion object : + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val stixType = StixType("windows-registry-key") + + override val idContributingProperties: List> = listOf( + WindowsRegistryKeySco::key, + WindowsRegistryKeySco::values // @TODO ** There is another pattern like this where only 1 value from this prop should be used in the ID. Should look to standardize on this to make the code simpler + ) + + override val allowedRelationships: List = listOf() + + override val allowedExtensions: List> = listOf() + + override fun objectValidationRules(obj: WindowsRegistryKeySco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + require( + listOf(obj.key, obj.values, obj.modifiedTimed, obj.creatorUserRef, obj.numberOfSubkeys) + .any { it != null }, + lazyMessage = { "windows-registry-key requires at least one property must be included." } + ) + + require(obj.creatorUserRef?.type == UserAccountSco.stixType, + lazyMessage = { "creator_user_ref must only reference a user-account SCO" } + ) + } + + } +} + +data class WindowsRegistryKey( + override val key: String? = null, + override val values: WindowsRegistryValueTypes? = null, + override val modifiedTimed: StixTimestamp? = null, + override val creatorUserRef: StixIdentifier? = null, + override val numberOfSubkeys: StixInteger? = null, + override val type: StixType = StixType(WindowsRegistryKeySco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : WindowsRegistryKeySco { + + init { + if (this.stixValidateOnConstruction) { + WindowsRegistryKeySco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/X509Certificate.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/X509Certificate.kt new file mode 100644 index 0000000..675f375 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sco/objects/X509Certificate.kt @@ -0,0 +1,104 @@ +package com.stephenott.stix.objects.core.sco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.extension.ScoExtension +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.StixSpecVersion.Companion.StixVersions +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 + +interface X509CertificateSco : StixCyberObservableObject { + + val isSelfSigned: StixBoolean? + val hashes: HashesDictionary? + val version: String? + val serialNumber: String? + val signatureAlgorithm: String? + val issuer: String? + val validityNotBefore: StixTimestamp? + val validityNotAfter: StixTimestamp? + val subject: String? + val subjectPublicKeyAlgorithm: String? + val subjectPublicKeyModulus: String? + val subjectPublicKeyExponent: StixInteger? + val x509v3Extensions: X509v3ExtensionsTypes? + + companion object : + CompanionStixType, + BusinessRulesValidator, + CompanionIdContributingProperties, + CompanionAllowedRelationships, + CompanionAllowedExtensions { + + override val stixType = StixType("x509-certificate") + + override val idContributingProperties: List> = listOf( + X509CertificateSco::hashes, //@TODO If the ​hashes​ property is present, include only one hash. The selected hash ​SHOULD​ come from this ordered list (based on the following order of preference) [ MD5, SHA-1, SHA-256, SHA-512 ]. + X509CertificateSco::serialNumber + ) + + override val allowedRelationships: List = listOf() + + override val allowedExtensions: List> = listOf() + + override fun objectValidationRules(obj: X509CertificateSco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + require(listOf( //@TODO review against Stix 2 Issues against 182 + obj.isSelfSigned, + obj.hashes, + obj.version, + obj.serialNumber, + obj.signatureAlgorithm, + obj.issuer, + obj.validityNotBefore, + obj.validityNotAfter, + obj.subject, + obj.subjectPublicKeyAlgorithm, + obj.subjectPublicKeyModulus, + obj.subjectPublicKeyExponent, + obj.x509v3Extensions + ).any { it != null }, + lazyMessage = { "X509-Certificate must contain at least one property (other than " }) + } + } +} + +data class X509Certificate( + override val isSelfSigned: StixBoolean? = null, + override val hashes: HashesDictionary? = null, + override val version: String? = null, + override val serialNumber: String? = null, + override val signatureAlgorithm: String? = null, + override val issuer: String? = null, + override val validityNotBefore: StixTimestamp? = null, + override val validityNotAfter: StixTimestamp? = null, + override val subject: String? = null, + override val subjectPublicKeyAlgorithm: String? = null, + override val subjectPublicKeyModulus: String? = null, + override val subjectPublicKeyExponent: StixInteger? = null, + override val x509v3Extensions: X509v3ExtensionsTypes? = null, + override val type: StixType = StixType(X509CertificateSco.stixType), + override val id: StixIdentifier = StixIdentifier(type), + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(StixVersions.TWO_DOT_ONE, false), + override val extensions: Extensions? = null, + override val defanged: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : X509CertificateSco { + + init { + if (this.stixValidateOnConstruction) { + X509CertificateSco.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/StixDomainObject.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/StixDomainObject.kt new file mode 100644 index 0000000..942de27 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/StixDomainObject.kt @@ -0,0 +1,19 @@ +package com.stephenott.stix.objects.core.sdo + +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.StixObject +import com.stephenott.stix.objects.core.StixCoreObject + +interface StixDomainObject : + StixCoreObject, + StixCreatedByRef, + StixCreatedProp, + StixExternalReferencesProp, + StixObjectMarkingsRefsProp, + StixGranularMarkingsProp, + StixSpecVersionProp, + StixModifiedProp, + StixLabelsProp, + StixRevokedProp, + StixLangProp, + StixConfidenceProp {} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/AttackPattern.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/AttackPattern.kt new file mode 100644 index 0000000..e04744e --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/AttackPattern.kt @@ -0,0 +1,98 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* +import com.stephenott.stix.type.KillChainPhases + +interface AttackPatternSdo : StixDomainObject { + val name: String + val description: String? + val killChainPhases: KillChainPhases? //@TODO + + companion object: CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("attack-pattern") + + override fun objectValidationRules(obj: AttackPatternSdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + } + + override val allowedRelationships: List = listOf( + AllowedRelationship( + AttackPatternSdo::class, + RelationshipType("delivers"), + MalwareSdo::class + ), + + AllowedRelationship( + AttackPatternSdo::class, + RelationshipType("targets"), + IdentitySdo::class + ), + AllowedRelationship( + AttackPatternSdo::class, + RelationshipType("targets"), + LocationSdo::class + ), + AllowedRelationship( + AttackPatternSdo::class, + RelationshipType("targets"), + VulnerabilitySdo::class + ), + + AllowedRelationship( + AttackPatternSdo::class, + RelationshipType("uses"), + MalwareSdo::class + ), + AllowedRelationship( + AttackPatternSdo::class, + RelationshipType("uses"), + ToolSdo::class + ) + ) + + } + +} + +data class AttackPattern( + override val name: String, + override val description: String? = null, + override val killChainPhases: KillChainPhases? = null, + override val type: StixType = AttackPatternSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : AttackPatternSdo { + + init { + if (this.stixValidateOnConstruction) { + AttackPatternSdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return AttackPatternSdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Campaign.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Campaign.kt new file mode 100644 index 0000000..a588cb7 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Campaign.kt @@ -0,0 +1,133 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* + +interface CampaignSdo : StixDomainObject { + val name: String + val description: String? + val aliases: String? + val firstSeen: StixTimestamp? + val lastSeen: StixTimestamp? + val objective: String? + + companion object: CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override fun objectValidationRules(obj: CampaignSdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + if (obj.firstSeen != null){ + require(obj.lastSeen?.instant!!.isAfter(obj.firstSeen!!.instant)) + } + } + + override val stixType = StixType("campaign") + + override val allowedRelationships: List = listOf( + AllowedRelationship( + CampaignSdo::class, + RelationshipType("attributed-to"), + IntrusionSetSdo::class + ), + AllowedRelationship( + CampaignSdo::class, + RelationshipType("attributed-to"), + ThreatActorSdo::class + ), + + AllowedRelationship( + CampaignSdo::class, + RelationshipType("compromises"), + InfrastructureSdo::class + ), + + AllowedRelationship( + CampaignSdo::class, + RelationshipType("originates-from"), + LocationSdo::class + ), + + AllowedRelationship( + CampaignSdo::class, + RelationshipType("targets"), + IdentitySdo::class + ), + AllowedRelationship( + CampaignSdo::class, + RelationshipType("targets"), + LocationSdo::class + ), + AllowedRelationship( + CampaignSdo::class, + RelationshipType("targets"), + VulnerabilitySdo::class + ), + + AllowedRelationship( + CampaignSdo::class, + RelationshipType("uses"), + AttackPatternSdo::class + ), + AllowedRelationship( + CampaignSdo::class, + RelationshipType("uses"), + InfrastructureSdo::class + ), + AllowedRelationship( + CampaignSdo::class, + RelationshipType("uses"), + MalwareSdo::class + ), + AllowedRelationship( + CampaignSdo::class, + RelationshipType("uses"), + ToolSdo::class + ) + ) + } + +} + +data class Campaign ( + override val name: String, + override val description: String? = null, + override val aliases: String? = null, + override val firstSeen: StixTimestamp? = null, + override val lastSeen: StixTimestamp? = null, + override val objective: String? = null, + override val type: StixType = CampaignSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : CampaignSdo { + + init { + if (this.stixValidateOnConstruction) { + CampaignSdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return CampaignSdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/CourseOfAction.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/CourseOfAction.kt new file mode 100644 index 0000000..faa21e9 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/CourseOfAction.kt @@ -0,0 +1,124 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* +import com.stephenott.stix.type.vocab.CourseOfActionTypeOv + +interface CourseOfActionSdo : StixDomainObject { + val name: String + val description: String? + val actionType: CourseOfActionTypeOv? //@TODO add option to override type value as the spec says it's a "should" + val osExecutionEnvs: OsExecutionEnvs? + val actionBin: StixBinary? + val actionReference: ExternalReference? + + companion object: CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("course-of-action") + + override fun objectValidationRules(obj: CourseOfActionSdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + if (obj.actionReference != null){ + require(obj.actionBin == null, + lazyMessage = {"action_bin must not be present if action_reference is provided."}) + } + if (obj.actionBin != null){ + require(obj.actionReference == null, + lazyMessage = {"action_reference must not be present if action_bin is provided."}) + } + } + + override val allowedRelationships: List = listOf( + AllowedRelationship( + CourseOfActionSdo::class, + RelationshipType("investigates"), + IndicatorSdo::class + ), + + AllowedRelationship( + CourseOfActionSdo::class, + RelationshipType("mitigates"), + AttackPatternSdo::class + ), + AllowedRelationship( + CourseOfActionSdo::class, + RelationshipType("mitigates"), + IndicatorSdo::class + ), + AllowedRelationship( + CourseOfActionSdo::class, + RelationshipType("mitigates"), + MalwareSdo::class + ), + AllowedRelationship( + CourseOfActionSdo::class, + RelationshipType("mitigates"), + ToolSdo::class + ), + AllowedRelationship( + CourseOfActionSdo::class, + RelationshipType("mitigates"), + VulnerabilitySdo::class + ), + + AllowedRelationship( + CourseOfActionSdo::class, + RelationshipType("remediates"), + MalwareSdo::class + ), + AllowedRelationship( + CourseOfActionSdo::class, + RelationshipType("remediates"), + VulnerabilitySdo::class + ) + ) + } + + +} + +data class CourseOfAction( + override val name: String, + override val description: String? = null, + override val actionType: CourseOfActionTypeOv? = null, + override val osExecutionEnvs: OsExecutionEnvs? = null, + override val actionBin: StixBinary? = null, + override val actionReference: ExternalReference? = null, + override val type: StixType = CourseOfActionSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : CourseOfActionSdo { + + init { + if (this.stixValidateOnConstruction) { + CourseOfActionSdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return CourseOfActionSdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Grouping.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Grouping.kt new file mode 100644 index 0000000..0610d1f --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Grouping.kt @@ -0,0 +1,66 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* +import com.stephenott.stix.type.vocab.GroupingContextOv + +interface GroupingSdo : StixDomainObject { + val name: String? + val description: String? + val context: GroupingContextOv + val objectRefs: StixIdentifiers + + companion object : CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("grouping") + + override fun objectValidationRules(obj: GroupingSdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + } + + override val allowedRelationships: List = listOf() + } +} + +data class Grouping( + override val name: String? = null, + override val description: String? = null, + override val context: GroupingContextOv, + override val objectRefs: StixIdentifiers, + override val type: StixType = GroupingSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : GroupingSdo { + + init { + if (this.stixValidateOnConstruction) { + GroupingSdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return GroupingSdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Identity.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Identity.kt new file mode 100644 index 0000000..2007684 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Identity.kt @@ -0,0 +1,78 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* +import com.stephenott.stix.type.vocab.IdentityClass +import com.stephenott.stix.type.vocab.IdentityRoles +import com.stephenott.stix.type.vocab.IndustrySectors + +interface IdentitySdo : StixDomainObject { + val name: String + val description: String? + val roles: IdentityRoles? + val identityClass: IdentityClass? + val sectors: IndustrySectors? + val contactInformation: String? + + companion object : CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("identity") + + override fun objectValidationRules(obj: IdentitySdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + } + + override val allowedRelationships: List = listOf( + AllowedRelationship( + IdentitySdo::class, + RelationshipType("located-at"), + LocationSdo::class + ) + ) + } +} + +data class Identity( + override val name: String, + override val description: String? = null, + override val roles: IdentityRoles? = null, + override val identityClass: IdentityClass? = null, + override val sectors: IndustrySectors? = null, + override val contactInformation: String? = null, + override val type: StixType = IdentitySdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : IdentitySdo { + + init { + if (this.stixValidateOnConstruction) { + IdentitySdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return IdentitySdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } + +} diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Indicator.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Indicator.kt new file mode 100644 index 0000000..85b573e --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Indicator.kt @@ -0,0 +1,122 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* +import com.stephenott.stix.type.vocab.IndicatorTypes +import com.stephenott.stix.type.KillChainPhases +import com.stephenott.stix.type.vocab.PatternType + +interface IndicatorSdo : StixDomainObject { + val name: String? + val description: String? + val indicatorTypes: IndicatorTypes + val pattern: StixPattern + val patternType: PatternType + val patternVersion: String? + val validFrom: StixTimestamp + val validUntil: StixTimestamp? + val killChainPhases: KillChainPhases? + + companion object : CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("indicator") + + override fun objectValidationRules(obj: IndicatorSdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + require(obj.validUntil?.instant!!.isAfter(obj.validFrom.instant), + lazyMessage = {"valid_until must come after valid_from."}) + } + + override val allowedRelationships: List = listOf( + AllowedRelationship( + IndicatorSdo::class, + RelationshipType("indicates"), + AttackPatternSdo::class + ), + AllowedRelationship( + IndicatorSdo::class, + RelationshipType("indicates"), + CampaignSdo::class + ), + AllowedRelationship( + IndicatorSdo::class, + RelationshipType("indicates"), + InfrastructureSdo::class + ), + AllowedRelationship( + IndicatorSdo::class, + RelationshipType("indicates"), + IntrusionSetSdo::class + ), + AllowedRelationship( + IndicatorSdo::class, + RelationshipType("indicates"), + MalwareSdo::class + ), + AllowedRelationship( + IndicatorSdo::class, + RelationshipType("indicates"), + ThreatActorSdo::class + ), + AllowedRelationship( + IndicatorSdo::class, + RelationshipType("indicates"), + ToolSdo::class + ), + + AllowedRelationship( + IndicatorSdo::class, + RelationshipType("based-on"), + ObservedDataSdo::class + ) + ) + } +} + +data class Indicator( + override val name: String? = null, + override val description: String? = null, + override val indicatorTypes: IndicatorTypes, + override val pattern: StixPattern, + override val patternType: PatternType, + override val patternVersion: String? = null, + override val validFrom: StixTimestamp, + override val validUntil: StixTimestamp?, + override val killChainPhases: KillChainPhases?, + override val type: StixType = IndicatorSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : IndicatorSdo { + + init { + if (this.stixValidateOnConstruction) { + IndicatorSdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return IndicatorSdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Infrastructure.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Infrastructure.kt new file mode 100644 index 0000000..38695d2 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Infrastructure.kt @@ -0,0 +1,164 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sco.StixCyberObservableObject +import com.stephenott.stix.objects.core.sco.objects.DomainNameSco +import com.stephenott.stix.objects.core.sco.objects.IPv4AddressSco +import com.stephenott.stix.objects.core.sco.objects.IPv6AddressSco +import com.stephenott.stix.objects.core.sco.objects.UrlSco +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* +import com.stephenott.stix.type.vocab.InfrastructureTypes +import com.stephenott.stix.type.KillChainPhases + +interface InfrastructureSdo : StixDomainObject { + val name: String + val description: String? + val infrastructureTypes: InfrastructureTypes + val aliases: StixStringList? + val killChainPhases: KillChainPhases? + val firstSeen: StixTimestamp? + val lastSeen: StixTimestamp? + + companion object : CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("infrastructure") + + override fun objectValidationRules(obj: InfrastructureSdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + if (obj.firstSeen != null && obj.lastSeen != null){ + require(obj.lastSeen!!.instant >= obj.firstSeen!!.instant) + } + } + + override val allowedRelationships: List = listOf( + AllowedRelationship( + InfrastructureSdo::class, + RelationshipType("communicates-with"), + InfrastructureSdo::class + ), + AllowedRelationship( + InfrastructureSdo::class, + RelationshipType("communicates-with"), + IPv4AddressSco::class + ), + AllowedRelationship( + InfrastructureSdo::class, + RelationshipType("communicates-with"), + IPv6AddressSco::class + ), + AllowedRelationship( + InfrastructureSdo::class, + RelationshipType("communicates-with"), + DomainNameSco::class + ), + AllowedRelationship( + InfrastructureSdo::class, + RelationshipType("communicates-with"), + UrlSco::class + ), + AllowedRelationship( + InfrastructureSdo::class, + RelationshipType("consists-of"), + InfrastructureSdo::class + ), + AllowedRelationship( + InfrastructureSdo::class, + RelationshipType("consists-of"), + ObservedDataSdo::class + ), + AllowedRelationship( + InfrastructureSdo::class, + RelationshipType("consists-of"), + StixCyberObservableObject::class + ), + AllowedRelationship( + InfrastructureSdo::class, + RelationshipType("controls"), + InfrastructureSdo::class + ), + AllowedRelationship( + InfrastructureSdo::class, + RelationshipType("controls"), + MalwareSdo::class + ), + AllowedRelationship( + InfrastructureSdo::class, + RelationshipType("delivers"), + MalwareSdo::class + ), + AllowedRelationship( + InfrastructureSdo::class, + RelationshipType("has"), + VulnerabilitySdo::class + ), + AllowedRelationship( + InfrastructureSdo::class, + RelationshipType("hosts"), + ToolSdo::class + ), + AllowedRelationship( + InfrastructureSdo::class, + RelationshipType("hosts"), + MalwareSdo::class + ), + AllowedRelationship( + InfrastructureSdo::class, + RelationshipType("located-at"), + LocationSdo::class + ), + AllowedRelationship( + InfrastructureSdo::class, + RelationshipType("uses"), + InfrastructureSdo::class + ) + ) + } + +} + +data class Infrastructure( + override val name: String, + override val description: String? = null, + override val infrastructureTypes: InfrastructureTypes, + override val aliases: StixStringList? = null, + override val killChainPhases: KillChainPhases? = null, + override val firstSeen: StixTimestamp? = null, + override val lastSeen: StixTimestamp? = null, + override val type: StixType = InfrastructureSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : InfrastructureSdo { + + init { + if (this.stixValidateOnConstruction) { + InfrastructureSdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return InfrastructureSdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/IntrusionSet.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/IntrusionSet.kt new file mode 100644 index 0000000..885e135 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/IntrusionSet.kt @@ -0,0 +1,142 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* +import com.stephenott.stix.type.vocab.* + +interface IntrusionSetSdo : StixDomainObject { + val name: String + val description: String? + val aliases: StixStringList? + val firstSeen: StixTimestamp? + val lastSeen: StixTimestamp? + val goals: StixStringList? + val resourceLevel: AttackResourceLevelOv? + val primaryMotivation: AttackMotivationOv? + val secondaryMotivations: AttackMotivations? + + companion object : CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("intrusion-set") + + override fun objectValidationRules(obj: IntrusionSetSdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + if (obj.firstSeen != null && obj.lastSeen != null){ + require(obj.lastSeen!!.instant >= obj.firstSeen!!.instant, + lazyMessage = {"last_seen must be equal or greater than first_seen."}) + } + } + + override val allowedRelationships: List = listOf( + AllowedRelationship( + IntrusionSetSdo::class, + RelationshipType("attributed-to"), + ThreatActorSdo::class + ), + AllowedRelationship( + IntrusionSetSdo::class, + RelationshipType("compromises"), + InfrastructureSdo::class + ), + AllowedRelationship( + IntrusionSetSdo::class, + RelationshipType("hosts"), + InfrastructureSdo::class + ), + AllowedRelationship( + IntrusionSetSdo::class, + RelationshipType("owns"), + InfrastructureSdo::class + ), + AllowedRelationship( + IntrusionSetSdo::class, + RelationshipType("originates-from"), + LocationSdo::class + ), + AllowedRelationship( + IntrusionSetSdo::class, + RelationshipType("targets"), + IdentitySdo::class + ), + AllowedRelationship( + IntrusionSetSdo::class, + RelationshipType("targets"), + LocationSdo::class + ), + AllowedRelationship( + IntrusionSetSdo::class, + RelationshipType("targets"), + VulnerabilitySdo::class + ), + AllowedRelationship( + IntrusionSetSdo::class, + RelationshipType("uses"), + AttackPatternSdo::class + ), + AllowedRelationship( + IntrusionSetSdo::class, + RelationshipType("uses"), + InfrastructureSdo::class + ), + AllowedRelationship( + IntrusionSetSdo::class, + RelationshipType("uses"), + MalwareSdo::class + ), + AllowedRelationship( + IntrusionSetSdo::class, + RelationshipType("uses"), + ToolSdo::class + ) + ) + } +} + +data class IntrusionSet( + override val name: String, + override val description: String? = null, + override val aliases: StixStringList? = null, + override val firstSeen: StixTimestamp? = null, + override val lastSeen: StixTimestamp? = null, + override val goals: StixStringList? = null, + override val resourceLevel: AttackResourceLevelOv? = null, + override val primaryMotivation: AttackMotivationOv? = null, + override val secondaryMotivations: AttackMotivations? = null, + override val type: StixType = IntrusionSetSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : IntrusionSetSdo { + + init { + if (this.stixValidateOnConstruction) { + IntrusionSetSdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return IntrusionSetSdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Location.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Location.kt new file mode 100644 index 0000000..f5c2427 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Location.kt @@ -0,0 +1,89 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* +import com.stephenott.stix.type.vocab.AdministrativeArea +import com.stephenott.stix.type.vocab.City +import com.stephenott.stix.type.vocab.RegionOv + +interface LocationSdo : StixDomainObject { + val name: String + val description: String? + val latitude: Latitude? + val longitude: Longitude? + val precision: LatLongPrecision? + val region: RegionOv? + val administrativeArea: AdministrativeArea? + val city: City? + val streetAddress: StreetAddress? + val postalCode: PostalCode? + + companion object : CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("location") + + override fun objectValidationRules(obj: LocationSdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + if (obj.latitude != null) require(obj.longitude != null, + lazyMessage = { "longitude must be provided when latitude is used." }) + if (obj.longitude != null) require(obj.latitude != null, + lazyMessage = { "latitude must be provided when longitude is used." }) + if (obj.precision != null) require(obj.latitude != null && obj.longitude != null, + lazyMessage = { "latitude and longitude must be provided when precision is used." }) + } + + override val allowedRelationships: List = listOf( + + ) + } +} + +data class Location( + override val name: String, + override val description: String? = null, + override val latitude: Latitude? = null, + override val longitude: Longitude? = null, + override val precision: LatLongPrecision? = null, + override val region: RegionOv? = null, + override val administrativeArea: AdministrativeArea?, + override val city: City? = null, + override val streetAddress: StreetAddress? = null, + override val postalCode: PostalCode? = null, + override val type: StixType = LocationSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : LocationSdo { + + init { + if (this.stixValidateOnConstruction) { + LocationSdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return LocationSdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Malware.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Malware.kt new file mode 100644 index 0000000..5700d73 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Malware.kt @@ -0,0 +1,223 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sco.objects.* +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* +import com.stephenott.stix.type.vocab.* + +interface MalwareSdo : StixDomainObject { + val name: String? + val description: String? + val malwareTypes: MalwareTypes + val isFamily: StixBoolean + val aliases: StixStringList? + val killChainPhases: KillChainPhases? + val firstSeen: StixTimestamp? + val lastSeen: StixTimestamp? + val osExecutionEnvs: OsExecutionEnvs? + val architectureExecutionEnvs: ProcessorArchitectures? + val implementationLanguage: ImplementationLanguages? + val capabilities: MalwareCapabilities? + val sampleRefs: StixIdentifiers? + + companion object : CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("malware") + + override fun objectValidationRules(obj: MalwareSdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + if (obj.firstSeen != null && obj.lastSeen != null) { + require(obj.lastSeen!!.instant >= obj.firstSeen!!.instant, + lazyMessage = { "last_seen must greater than or equal to first_seen." }) + } + } + + override val allowedRelationships: List = listOf( + //@TODO convert allowedrelationship to a Kotlin DSL + AllowedRelationship( + MalwareSdo::class, + RelationshipType("authored-by"), + ThreatActorSdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("authored-by"), + IntrusionSetSdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("beacons-to"), + InfrastructureSdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("exfiltrates-to"), + InfrastructureSdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("communicates-with"), + IPv4AddressSco::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("communicates-with"), + IPv6AddressSco::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("communicates-with"), + DomainNameSco::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("communicates-with"), + UrlSco::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("controls"), + MalwareSdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("downloads"), + MalwareSdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("downloads"), + ToolSdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("downloads"), + FileSco::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("drops"), + MalwareSdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("drops"), + ToolSdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("drops"), + FileSco::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("exploits"), + VulnerabilitySdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("originates-from"), + LocationSdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("targets"), + IdentitySdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("targets"), + InfrastructureSdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("targets"), + LocationSdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("targets"), + VulnerabilitySdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("uses"), + AttackPatternSdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("uses"), + InfrastructureSdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("uses"), + MalwareSdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("uses"), + ToolSdo::class + ), + AllowedRelationship( + MalwareSdo::class, + RelationshipType("variant-of"), + MalwareSdo::class + ) + ) + } +} + +data class Malware + ( + override val name: String, + override val description: String? = null, + override val malwareTypes: MalwareTypes, + override val isFamily: StixBoolean, + override val aliases: StixStringList? = null, + override val killChainPhases: KillChainPhases? = null, + override val firstSeen: StixTimestamp? = null, + override val lastSeen: StixTimestamp? = null, + override val osExecutionEnvs: OsExecutionEnvs? = null, + override val architectureExecutionEnvs: ProcessorArchitectures? = null, + override val implementationLanguage: ImplementationLanguages? = null, + override val capabilities: MalwareCapabilities? = null, + override val sampleRefs: StixIdentifiers? = null, + override val type: StixType = MalwareSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : MalwareSdo { + + init { + if (this.stixValidateOnConstruction) { + MalwareSdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return MalwareSdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/MalwareAnalysis.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/MalwareAnalysis.kt new file mode 100644 index 0000000..6b14bb3 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/MalwareAnalysis.kt @@ -0,0 +1,119 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sco.objects.SoftwareSco +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* +import com.stephenott.stix.type.vocab.MalwareAvResult + +interface MalwareAnalysisSdo : StixDomainObject { + val product: Product + val version: String? + val hostVmRef: StixIdentifier? + val operatingSystemRef: StixIdentifier? + val installedSystemRefs: StixIdentifiers? + val configurationVersion: String? + val modules: StixStringList? + val analysisEngineVersion: String? + val analysisDefinitionVersion: String? + val submitted: StixTimestamp? + val analysisStarted: StixTimestamp? + val analysisEnded: StixTimestamp? + val avResult: MalwareAvResult? + val analysisScoRefs: StixIdentifiers? + + companion object : CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("malware-analysis") + + override fun objectValidationRules(obj: MalwareAnalysisSdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + //@TODO Product Name Validation enhancement: The name of the analysis engine or product that was used. Product names ​SHOULD​ be all lowercase with words separated by a dash "-". For cases where the name of a product cannot be specified, a value of "anonymized" MUST ​be used. + + require(obj.hostVmRef?.type == SoftwareSco.stixType, + lazyMessage = {"host_vm_ref must only reference a software SCO."}) + + require(obj.operatingSystemRef?.type == SoftwareSco.stixType, + lazyMessage = {"operating_system_ref must only reference a software SCO."}) + + require(obj.installedSystemRefs?.all { it.type == SoftwareSco.stixType }!!, + lazyMessage = {"installed_system_refs must only have values that reference a software SCO."}) + } + + override val allowedRelationships: List = listOf( + AllowedRelationship( + MalwareAnalysisSdo::class, + RelationshipType("characterizes"), + MalwareSdo::class + ), + AllowedRelationship( + MalwareAnalysisSdo::class, + RelationshipType("av-analysis-of"), + MalwareSdo::class + ), + AllowedRelationship( + MalwareAnalysisSdo::class, + RelationshipType("static-analysis-of"), + MalwareSdo::class + ), + AllowedRelationship( + MalwareAnalysisSdo::class, + RelationshipType("dynamic-analysis-of"), + MalwareSdo::class + ) + ) + } +} + +data class MalwareAnalysis + ( + override val product: Product, + override val version: String? = null, + override val hostVmRef: StixIdentifier? = null, + override val operatingSystemRef: StixIdentifier? = null, + override val installedSystemRefs: StixIdentifiers? = null, + override val configurationVersion: String? = null, + override val modules: StixStringList? = null, + override val analysisEngineVersion: String? = null, + override val analysisDefinitionVersion: String? = null, + override val submitted: StixTimestamp? = null, + override val analysisStarted: StixTimestamp? = null, + override val analysisEnded: StixTimestamp? = null, + override val avResult: MalwareAvResult? = null, + override val analysisScoRefs: StixIdentifiers? = null, + override val type: StixType = MalwareAnalysisSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : MalwareAnalysisSdo { + + init { + if (this.stixValidateOnConstruction) { + MalwareAnalysisSdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return MalwareAnalysisSdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Note.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Note.kt new file mode 100644 index 0000000..a38b35a --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Note.kt @@ -0,0 +1,66 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* + +interface NoteSdo : StixDomainObject { + val abstract: String? + val content: String + val authors: StixStringList? + val objectRefs: StixIdentifiers + + companion object : CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("note") + + override fun objectValidationRules(obj: NoteSdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + } + + override val allowedRelationships: List = listOf() + } + +} + +data class Note( + override val abstract: String? = null, + override val content: String, + override val authors: StixStringList? = null, + override val objectRefs: StixIdentifiers, + override val type: StixType = NoteSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : NoteSdo { + + init { + if (this.stixValidateOnConstruction) { + NoteSdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return NoteSdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/ObservedData.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/ObservedData.kt new file mode 100644 index 0000000..9568010 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/ObservedData.kt @@ -0,0 +1,71 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* + +interface ObservedDataSdo : StixDomainObject { + val firstObserved: StixTimestamp + val lastObserved: StixTimestamp + val numberObserved: StixInteger + val objectRefs: StixIdentifiers + + companion object : CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("observed-data") + + override fun objectValidationRules(obj: ObservedDataSdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + require(obj.lastObserved.instant >= obj.firstObserved.instant, + lazyMessage = { "last_observed must be greater than or equal to first_observed." }) + + require(obj.numberObserved.value in 1..999999999, + lazyMessage = { "number_observed must be between 1 and 999,999,999." }) + + require(obj.objectRefs.any { it.type in stixInstance.registries.objectRegistry.scoRegistry.keys }, + lazyMessage = { "object_refs must contain at least one SCO." }) + } + + override val allowedRelationships: List = listOf() + } +} + +data class ObservedData( + override val firstObserved: StixTimestamp, + override val lastObserved: StixTimestamp, + override val numberObserved: StixInteger, + override val objectRefs: StixIdentifiers, + override val type: StixType = ObservedDataSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : ObservedDataSdo { + + init { + if (this.stixValidateOnConstruction) { + ObservedDataSdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return ObservedDataSdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Opinion.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Opinion.kt new file mode 100644 index 0000000..b7e1440 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Opinion.kt @@ -0,0 +1,69 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* +import com.stephenott.stix.type.vocab.OpinionEnum + +interface OpinionSdo : StixDomainObject { + val explanation: String? + val authors: StixStringList? + val opinion: OpinionEnum + val objectRefs: StixIdentifiers + + companion object : CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("opinion") + + override fun objectValidationRules(obj: OpinionSdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + } + + override val allowedRelationships: List = listOf( + + ) + } +} + +data class Opinion( + override val explanation: String? = null, + override val authors: StixStringList? = null, + override val opinion: OpinionEnum, + override val objectRefs: StixIdentifiers, + override val type: StixType = OpinionSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : OpinionSdo { + + init { + if (this.stixValidateOnConstruction) { + OpinionSdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return OpinionSdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Report.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Report.kt new file mode 100644 index 0000000..92442de --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Report.kt @@ -0,0 +1,68 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* +import com.stephenott.stix.type.vocab.ReportTypes + +interface ReportSdo : StixDomainObject { + val name: String + val description: String? + val reportTypes: ReportTypes + val published: StixTimestamp + val objectRefs: StixIdentifiers + + companion object : CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("report") + + override fun objectValidationRules(obj: ReportSdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + } + + override val allowedRelationships: List = listOf() + } +} + +data class Report( + override val name: String, + override val description: String? = null, + override val reportTypes: ReportTypes, + override val published: StixTimestamp, + override val objectRefs: StixIdentifiers, + override val type: StixType = ReportSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : ReportSdo { + + init { + if (this.stixValidateOnConstruction) { + ReportSdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return ReportSdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/ThreatActor.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/ThreatActor.kt new file mode 100644 index 0000000..3288a30 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/ThreatActor.kt @@ -0,0 +1,155 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* +import com.stephenott.stix.type.vocab.* + +interface ThreatActorSdo : StixDomainObject { + val name: String + val description: String? + val threatActorTypes: ThreatActorTypes + val aliases: StixStringList? + val firstSeen: StixTimestamp? + val lastSeen: StixTimestamp? + val roles: ThreatActorRoles? + val goals: StixStringList? + val sophistication: ThreatActorSophisticationOv? + val resourceLevel: AttackResourceLevelOv? + val primaryMotivation: AttackMotivationOv? + val secondaryMotivation: AttackMotivationOv? + val personalMotivations: AttackMotivations? + + companion object : CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("threat-actor") + + override fun objectValidationRules(obj: ThreatActorSdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + if (obj.firstSeen != null && obj.lastSeen != null){ + require(obj.lastSeen!!.instant >= obj.firstSeen!!.instant, + lazyMessage = {"last_seen must be greater than or equal to first_Seen."}) + } + } + + override val allowedRelationships: List = listOf( + AllowedRelationship( + ThreatActorSdo::class, + RelationshipType("attributed-to"), + IdentitySdo::class + ), + AllowedRelationship( + ThreatActorSdo::class, + RelationshipType("compromises"), + InfrastructureSdo::class + ), + AllowedRelationship( + ThreatActorSdo::class, + RelationshipType("hosts"), + InfrastructureSdo::class + ), + AllowedRelationship( + ThreatActorSdo::class, + RelationshipType("owns"), + InfrastructureSdo::class + ), + AllowedRelationship( + ThreatActorSdo::class, + RelationshipType("impersonates"), + IdentitySdo::class + ), + AllowedRelationship( + ThreatActorSdo::class, + RelationshipType("located-at"), + LocationSdo::class + ), + AllowedRelationship( + ThreatActorSdo::class, + RelationshipType("targets"), + IdentitySdo::class + ), + AllowedRelationship( + ThreatActorSdo::class, + RelationshipType("targets"), + LocationSdo::class + ), + AllowedRelationship( + ThreatActorSdo::class, + RelationshipType("targets"), + VulnerabilitySdo::class + ), + AllowedRelationship( + ThreatActorSdo::class, + RelationshipType("uses"), + AttackPatternSdo::class + ), + AllowedRelationship( + ThreatActorSdo::class, + RelationshipType("uses"), + InfrastructureSdo::class + ), + AllowedRelationship( + ThreatActorSdo::class, + RelationshipType("uses"), + MalwareSdo::class + ), + AllowedRelationship( + ThreatActorSdo::class, + RelationshipType("uses"), + ToolSdo::class + ) + ) + } +} + +data class ThreatActor( + override val name: String, + override val description: String? = null, + override val threatActorTypes: ThreatActorTypes, + override val aliases: StixStringList? = null, + override val firstSeen: StixTimestamp? = null, + override val lastSeen: StixTimestamp? = null, + override val roles: ThreatActorRoles? = null, + override val goals: StixStringList? = null, + override val sophistication: ThreatActorSophisticationOv? = null, + override val resourceLevel: AttackResourceLevelOv? = null, + override val primaryMotivation: AttackMotivationOv? = null, + override val secondaryMotivation: AttackMotivationOv? = null, + override val personalMotivations: AttackMotivations? = null, + override val type: StixType = ThreatActorSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : ThreatActorSdo { + + init { + if (this.stixValidateOnConstruction) { + ThreatActorSdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return ThreatActorSdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Tool.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Tool.kt new file mode 100644 index 0000000..435a07d --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Tool.kt @@ -0,0 +1,112 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* +import com.stephenott.stix.type.KillChainPhases +import com.stephenott.stix.type.vocab.ToolTypes + +interface ToolSdo : StixDomainObject { + val name: String + val description: String? + val toolTypes: ToolTypes + val aliases: StixStringList? + val killChainPhases: KillChainPhases? + val toolVersion: String? + + companion object : CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("tool") + + override fun objectValidationRules(obj: ToolSdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + } + + override val allowedRelationships: List = listOf( + AllowedRelationship( + ToolSdo::class, + RelationshipType("delivers"), + MalwareSdo::class + ), + AllowedRelationship( + ToolSdo::class, + RelationshipType("drops"), + MalwareSdo::class + ), + AllowedRelationship( + ToolSdo::class, + RelationshipType("has"), + VulnerabilitySdo::class + ), + AllowedRelationship( + ToolSdo::class, + RelationshipType("targets"), + IdentitySdo::class + ), + AllowedRelationship( + ToolSdo::class, + RelationshipType("targets"), + InfrastructureSdo::class + ), + AllowedRelationship( + ToolSdo::class, + RelationshipType("targets"), + LocationSdo::class + ), + AllowedRelationship( + ToolSdo::class, + RelationshipType("targets"), + VulnerabilitySdo::class + ), + AllowedRelationship( + ToolSdo::class, + RelationshipType("uses"), + InfrastructureSdo::class + ) + ) + } +} + +data class Tool( + override val name: String, + override val description: String? = null, + override val toolTypes: ToolTypes, + override val aliases: StixStringList? = null, + override val killChainPhases: KillChainPhases? = null, + override val toolVersion: String? = null, + override val type: StixType = ToolSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : ToolSdo { + + init { + if (this.stixValidateOnConstruction) { + ToolSdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return ToolSdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Vulnerability.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Vulnerability.kt new file mode 100644 index 0000000..5284ba5 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sdo/objects/Vulnerability.kt @@ -0,0 +1,61 @@ +package com.stephenott.stix.objects.core.sdo.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sdo.StixDomainObject +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.core.sro.objects.RelationshipSro +import com.stephenott.stix.type.* + +interface VulnerabilitySdo : StixDomainObject { + val name: String + val description: String? + + companion object : CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + override val stixType = StixType("vulnerability") + + override fun objectValidationRules(obj: VulnerabilitySdo, stixInstance: Stix) { + requireStixType(this.stixType, obj) + } + + override val allowedRelationships: List = listOf() + } +} + +data class Vulnerability( + override val name: String, + override val description: String? = null, + override val type: StixType = VulnerabilitySdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val lang: StixLang? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : VulnerabilitySdo { + + init { + if (this.stixValidateOnConstruction) { + VulnerabilitySdo.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + return VulnerabilitySdo.allowedRelationships + RelationshipSro.allowedCommonRelationships + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sro/StixRelationshipObject.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sro/StixRelationshipObject.kt new file mode 100644 index 0000000..53ac3a4 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sro/StixRelationshipObject.kt @@ -0,0 +1,19 @@ +package com.stephenott.stix.objects.core.sro + +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.StixObject +import com.stephenott.stix.objects.core.StixCoreObject + +interface StixRelationshipObject: + StixCoreObject, + StixCreatedByRef, + StixCreatedProp, + StixExternalReferencesProp, + StixObjectMarkingsRefsProp, + StixGranularMarkingsProp, + StixSpecVersionProp, + StixModifiedProp, + StixLabelsProp, + StixRevokedProp { + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sro/objects/Relationship.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sro/objects/Relationship.kt new file mode 100644 index 0000000..dda5a80 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sro/objects/Relationship.kt @@ -0,0 +1,160 @@ +package com.stephenott.stix.objects.core.sro.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.* +import com.stephenott.stix.objects.StixObject +import com.stephenott.stix.objects.core.sro.StixRelationshipObject +import com.stephenott.stix.type.* +import java.lang.IllegalStateException +import kotlin.reflect.KClass +import kotlin.reflect.full.isSubclassOf + +interface RelationshipSro : StixRelationshipObject { + val relationshipType: RelationshipType + val description: String? + val sourceRef: StixIdentifier + val targetRef: StixIdentifier + val startTime: StixTimestamp? + val stopTime: StixTimestamp? + + companion object : CompanionStixType, + BusinessRulesValidator { + + override val stixType = StixType("relationship") + + override fun objectValidationRules(obj: RelationshipSro, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + } + + val allowedCommonRelationships: List = listOf( + AllowedRelationship( + StixObject::class, + RelationshipType("duplicate-of"), + StixObject::class, + RelationshipRule { obj -> + require(obj.sourceRef.type == obj.targetRef.type, + lazyMessage = { "duplicate-of relationship (${obj.id}) requires source(${obj.sourceRef}) and target(${obj.targetRef}) must be same type" }) + } + ), + AllowedRelationship( + StixObject::class, + RelationshipType("derived-from"), + StixObject::class, + RelationshipRule { obj -> + require(obj.sourceRef.type == obj.targetRef.type, + lazyMessage = { "derived-from relationship (${obj.id}) requires source(${obj.sourceRef}) and target(${obj.targetRef}) must be same type" }) + } + ), + AllowedRelationship( + StixObject::class, + RelationshipType("related-to"), + StixObject::class + ) + ) + } +} + +data class RelationshipRule(private val rule: (relObj: RelationshipSro) -> Unit) { + fun execute(relObj: RelationshipSro) { + rule(relObj) + } +} + +data class AllowedRelationship( + val from: KClass, + val type: RelationshipType, + val to: KClass, + val rule: RelationshipRule? = null +) {} + +data class Relationship( + override val relationshipType: RelationshipType, + override val description: String? = null, + override val sourceRef: StixIdentifier, + override val targetRef: StixIdentifier, + override val startTime: StixTimestamp? = null, + override val stopTime: StixTimestamp? = null, + override val type: StixType = RelationshipSro.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : RelationshipSro { + + /** + * No Relationships are supported for RelationshipSro + */ + override fun allowedRelationships(): List { + return listOf() + } + + constructor( + relationshipType: RelationshipType, + description: String? = null, + sourceRef: StixObject, + targetRef: StixObject, + startTime: StixTimestamp? = null, + stopTime: StixTimestamp? = null, + type: StixType = RelationshipSro.stixType, + id: StixIdentifier = StixIdentifier(type), + createdByRef: String? = null, + created: StixTimestamp = StixTimestamp(), + externalReferences: ExternalReferences? = null, + objectMarkingsRefs: String? = null, + granularMarkings: String? = null, + specVersion: StixSpecVersion = StixSpecVersion(), + labels: StixLabels? = null, + modified: StixTimestamp = StixTimestamp(created), + revoked: StixBoolean = StixBoolean() + ) : this( + relationshipType, description, sourceRef.id, + targetRef.id, startTime, stopTime, + type, id, createdByRef, + created, externalReferences, objectMarkingsRefs, + granularMarkings, specVersion, labels, + modified, revoked + ) + + + init { + if (this.stixValidateOnConstruction) { + val sourceClass: KClass = this.stixInstance.registries.objectRegistry.registry[sourceRef.type] + ?: throw IllegalStateException("Unable to find sourceRef in Object Registry") + + val targetClass: KClass = this.stixInstance.registries.objectRegistry.registry[targetRef.type] + ?: throw IllegalStateException("Unable to find targetRef in Object Registry") + + + //@TODO add support for x- custom objects + val allowedRelationships: List = this.stixInstance.registries.relationshipRegistry + .registry.filter { + sourceClass.isSubclassOf(it.from) && + it.type == this.relationshipType && + targetClass.isSubclassOf(it.to) + } + + if (allowedRelationships.size > 1) { + println("Duplicate relationships found: $allowedRelationships") + //@TODO add some logging for a warning to indicate multiple duplication objects are registered + } + + require(allowedRelationships.isNotEmpty(), + lazyMessage = { "${this.id} is not a valid relationship for a ${this.sourceRef.type}" } + ) + + //@TODO To a deeper test of this functionality + allowedRelationships[0].rule?.execute(this) +// allowedRelationships[0].rule?.execute(this) + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/core/sro/objects/Sighting.kt b/src/main/kotlin/com/stephenott/stix/objects/core/sro/objects/Sighting.kt new file mode 100644 index 0000000..6fbac84 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/core/sro/objects/Sighting.kt @@ -0,0 +1,91 @@ +package com.stephenott.stix.objects.core.sro.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sdo.objects.IdentitySdo +import com.stephenott.stix.objects.core.sdo.objects.LocationSdo +import com.stephenott.stix.objects.core.sdo.objects.ObservedDataSdo +import com.stephenott.stix.objects.core.sro.StixRelationshipObject +import com.stephenott.stix.type.* + +interface SightingSro : StixRelationshipObject { + val description: String? + val firstSeen: StixTimestamp? + val lastSeen: StixTimestamp? //@TODO *** REVIEW SPEC: Says must be after first seen. But does not say "equals + val count: StixInteger? + val sightingOfRef: StixIdentifier + val observedDataRefs: StixIdentifiers? + val whereSightedRefs: StixIdentifiers? + val summary: StixBoolean + + companion object : CompanionStixType, + BusinessRulesValidator { + + override val stixType: StixType = StixType("sighting") + + override fun objectValidationRules(obj: SightingSro, stixInstance: Stix) { + requireStixType(this.stixType, obj) + + if (obj.firstSeen != null && obj.lastSeen != null) { + require(obj.lastSeen!!.instant.isAfter(obj.firstSeen!!.instant), + lazyMessage = { "last_seen must be later than first_seen." }) + } + + obj.count?.let { + require(it.value in 0..999999999, + lazyMessage = { "count must be between 0 and 999,999,999." }) + } + + require(obj.sightingOfRef.type in stixInstance.registries.objectRegistry.sdoRegistry.keys, + lazyMessage = { "sighting_of_ref must reference only a SDO." }) // @TODO should also support custom objects + + obj.observedDataRefs?.let { + require(it.all { id -> id.type == ObservedDataSdo.stixType }, + lazyMessage = { "observed_data_refs must only have values that are references to Observed Data SDO." }) + } + + obj.whereSightedRefs?.let { + require(it.all { id -> id.type in listOf(IdentitySdo.stixType, LocationSdo.stixType) }, + lazyMessage = { "where_sighted_refs must only have values that reference Identity or Location SDO." }) + } + } + } +} + +data class Sighting( + override val description: String? = null, + override val firstSeen: StixTimestamp? = null, + override val lastSeen: StixTimestamp? = null, + override val count: StixInteger? = null, + override val sightingOfRef: StixIdentifier, + override val observedDataRefs: StixIdentifiers? = null, + override val whereSightedRefs: StixIdentifiers? = null, + override val summary: StixBoolean = StixBoolean(), + override val type: StixType = SightingSro.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : SightingSro { + + init { + if (this.stixValidateOnConstruction) { + SightingSro.objectValidationRules(this, stixInstance) + } + } + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/meta/StixMetaObject.kt b/src/main/kotlin/com/stephenott/stix/objects/meta/StixMetaObject.kt new file mode 100644 index 0000000..b9cb6c8 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/meta/StixMetaObject.kt @@ -0,0 +1,7 @@ +package com.stephenott.stix.objects.meta + +import com.stephenott.stix.objects.StixObject + + +interface StixMetaObject: + StixObject {} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/DataMarking.kt b/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/DataMarking.kt new file mode 100644 index 0000000..4974be0 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/DataMarking.kt @@ -0,0 +1,13 @@ +package com.stephenott.stix.objects.meta.datamarking + +import com.stephenott.stix.objects.meta.StixMetaObject +import com.stephenott.stix.common.* + +interface DataMarking: StixMetaObject, + StixCreatedByRef, + StixCreatedProp, + StixExternalReferencesProp, + StixObjectMarkingsRefsProp, + StixGranularMarkingsProp, + StixSpecVersionProp{ +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/GranularMarking.kt b/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/GranularMarking.kt new file mode 100644 index 0000000..1889ab2 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/GranularMarking.kt @@ -0,0 +1,32 @@ +package com.stephenott.stix.objects.meta.datamarking + +import com.stephenott.stix.type.StixIdentifier +import com.stephenott.stix.type.StixLang +import com.stephenott.stix.type.StixStringList + +interface GranularMarkingGm{ + val lang: StixLang? + val markingRef: StixIdentifier? + val selectors: StixStringList +} + +data class GranularMarking( + override val lang: StixLang?, + override val markingRef: StixIdentifier?, + override val selectors: StixStringList +): GranularMarkingGm { + + init { + if (lang == null){ + require(markingRef != null) + require(markingRef.type == MarkingDefinitionDm.stixType) + } else { + require(markingRef == null) + } + + + } + + constructor(lang: StixLang, selectors: StixStringList): this(lang, null, selectors) + constructor(markingRef: StixIdentifier, selectors: StixStringList): this(null, markingRef, selectors) +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/MarkingDefinition.kt b/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/MarkingDefinition.kt new file mode 100644 index 0000000..1df4749 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/MarkingDefinition.kt @@ -0,0 +1,63 @@ +package com.stephenott.stix.objects.meta.datamarking + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.type.* +import com.stephenott.stix.type.vocab.MarkingDefinitionTypeOv + +interface MarkingDefinitionDm: DataMarking{ + val name: String? + val definitionType: MarkingDefinitionTypeOv + val definition: MarkingObject + + companion object: CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + + const val definitionPolymorphicFieldName: String = "definition_type" + + override val stixType = StixType("marking-definition") + + override val allowedRelationships: List = listOf( + //@TODO review if this is needed for this object + ) + + override fun objectValidationRules(obj: MarkingDefinitionDm, stixInstance: Stix) { + requireStixType(this.stixType, obj) + } + + } +} + +data class MarkingDefinition( + override val name: String? = null, + override val definitionType: MarkingDefinitionTypeOv, + override val definition: MarkingObject, + override val type: StixType = MarkingDefinitionDm.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +): MarkingDefinitionDm { + + init { + if (this.stixValidateOnConstruction) { + MarkingDefinitionDm.objectValidationRules(this, stixInstance) + } + } + + + override fun allowedRelationships(): List { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/MarkingObject.kt b/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/MarkingObject.kt new file mode 100644 index 0000000..2de3953 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/MarkingObject.kt @@ -0,0 +1,12 @@ +package com.stephenott.stix.objects.meta.datamarking + +import com.stephenott.stix.type.vocab.MarkingDefinitionTypeOv + +interface MarkingObject { + +} + +interface MarkingObjectCompanionDefType{ + val definitionType: MarkingDefinitionTypeOv +} + diff --git a/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/objects/Statement.kt b/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/objects/Statement.kt new file mode 100644 index 0000000..dd61866 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/objects/Statement.kt @@ -0,0 +1,18 @@ +package com.stephenott.stix.objects.meta.datamarking.objects + +import com.stephenott.stix.objects.meta.datamarking.MarkingObject +import com.stephenott.stix.objects.meta.datamarking.MarkingObjectCompanionDefType +import com.stephenott.stix.type.vocab.MarkingDefinitionTypeOv + +interface StatementMo : MarkingObject { + companion object: MarkingObjectCompanionDefType { + override val definitionType: MarkingDefinitionTypeOv = MarkingDefinitionTypeOv("statement") + } + + val statement: String + +} + +data class Statement( + override val statement: String +): StatementMo \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/objects/Tlp.kt b/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/objects/Tlp.kt new file mode 100644 index 0000000..f7bc398 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/meta/datamarking/objects/Tlp.kt @@ -0,0 +1,19 @@ +package com.stephenott.stix.objects.meta.datamarking.objects + +import com.stephenott.stix.objects.meta.datamarking.MarkingObject +import com.stephenott.stix.objects.meta.datamarking.MarkingObjectCompanionDefType +import com.stephenott.stix.type.vocab.MarkingDefinitionTypeOv + + +interface TlpMo : MarkingObject { + companion object: MarkingObjectCompanionDefType{ + override val definitionType: MarkingDefinitionTypeOv = MarkingDefinitionTypeOv("tlp") + } + + val tlp: String +} + +data class Tlp( + override val tlp: String + +): TlpMo \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/meta/lco/LanguageContentObject.kt b/src/main/kotlin/com/stephenott/stix/objects/meta/lco/LanguageContentObject.kt new file mode 100644 index 0000000..4e47f10 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/meta/lco/LanguageContentObject.kt @@ -0,0 +1,20 @@ +package com.stephenott.stix.objects.meta.lco + +import com.stephenott.stix.objects.meta.StixMetaObject +import com.stephenott.stix.common.* + +/** + * Built to support future custom language handling classes + */ +interface LanguageContentObject: StixMetaObject, + StixCreatedByRef, + StixCreatedProp, + StixExternalReferencesProp, + StixObjectMarkingsRefsProp, + StixGranularMarkingsProp, + StixSpecVersionProp, + StixModifiedProp, + StixLabelsProp, + StixRevokedProp, + StixConfidenceProp { +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/objects/meta/lco/objects/LanguageContent.kt b/src/main/kotlin/com/stephenott/stix/objects/meta/lco/objects/LanguageContent.kt new file mode 100644 index 0000000..81a7d99 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/objects/meta/lco/objects/LanguageContent.kt @@ -0,0 +1,61 @@ +package com.stephenott.stix.objects.meta.lco.objects + +import com.stephenott.stix.Stix +import com.stephenott.stix.common.BusinessRulesValidator +import com.stephenott.stix.common.CompanionAllowedRelationships +import com.stephenott.stix.common.CompanionStixType +import com.stephenott.stix.common.requireStixType +import com.stephenott.stix.objects.core.sdo.objects.AttackPatternSdo +import com.stephenott.stix.objects.core.sro.objects.AllowedRelationship +import com.stephenott.stix.objects.meta.lco.LanguageContentObject +import com.stephenott.stix.type.* + +interface LanguageContentLco : LanguageContentObject { + val objectRef: StixIdentifier + val objectModified: StixTimestamp? + val contents: LanguageContentDictionary + + companion object: CompanionStixType, + BusinessRulesValidator, + CompanionAllowedRelationships { + override fun objectValidationRules(obj: LanguageContentLco, stixInstance: Stix) { + requireStixType(this.stixType, obj) + } + + override val stixType = StixType("language-content") + + override val allowedRelationships: List = listOf( + ) + + } +} + +data class LanguageContent( + override val objectRef: StixIdentifier, + override val objectModified: StixTimestamp? = null, + override val contents: LanguageContentDictionary, + override val type: StixType = AttackPatternSdo.stixType, + override val id: StixIdentifier = StixIdentifier(type), + override val createdByRef: String? = null, + override val created: StixTimestamp = StixTimestamp(), + override val externalReferences: ExternalReferences? = null, + override val objectMarkingsRefs: String? = null, + override val granularMarkings: String? = null, + override val specVersion: StixSpecVersion = StixSpecVersion(), + override val labels: StixLabels? = null, + override val modified: StixTimestamp = StixTimestamp(created), + override val revoked: StixBoolean = StixBoolean(), + override val confidence: StixConfidence? = null, + override val stixInstance: Stix = Stix.defaultStixInstance, + override val stixValidateOnConstruction: Boolean = Stix.defaultValidateOnConstruction +) : LanguageContentLco { + + init { + LanguageContentLco.objectValidationRules(this, stixInstance) + } + + override fun allowedRelationships(): List { + return LanguageContentLco.allowedRelationships + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/serialization/StixContentMapper.kt b/src/main/kotlin/com/stephenott/stix/serialization/StixContentMapper.kt new file mode 100644 index 0000000..35163bf --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/serialization/StixContentMapper.kt @@ -0,0 +1,10 @@ +package com.stephenott.stix.serialization + +import com.stephenott.stix.StixRegistries + +interface StixContentMapper { + val mapper: Any + + val stixRegistries: StixRegistries +} + diff --git a/src/main/kotlin/com/stephenott/stix/serialization/json/JsonExtensions.kt b/src/main/kotlin/com/stephenott/stix/serialization/json/JsonExtensions.kt new file mode 100644 index 0000000..c0f88df --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/serialization/json/JsonExtensions.kt @@ -0,0 +1,87 @@ +package com.stephenott.stix.serialization.json + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.databind.DeserializationFeature +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.PropertyNamingStrategy +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule +import com.stephenott.stix.StixBundle +import com.stephenott.stix.StixContent +import com.stephenott.stix.StixRegistries +import com.stephenott.stix.serialization.StixContentMapper +import com.fasterxml.jackson.module.kotlin.* +import com.stephenott.stix.Stix + +class StixJsonContentMapper( + override val stixRegistries: StixRegistries = StixRegistries(), + override val mapper: ObjectMapper = createStixJsonObjectMapper(stixRegistries) +) : StixContentMapper { + + /** + * Parse a json string into any kind of Stix Content (SDO, SCO, SRO, Relationships, etc) + */ + inline fun parseJson(json: String): T { + try { + return mapper.readValue(json) + } catch (e: Exception) { + throw IllegalArgumentException("Unable to parse json.", e) + } + } + + fun toJson(value: StixContent): String { + return this.mapper.writeValueAsString(value) + } + + fun toJson(value: StixBundle): String { + return this.mapper.writeValueAsString(value) + } + + companion object { + + fun fromStixInstance(instance: Stix): StixJsonContentMapper { + return StixJsonContentMapper(instance.registries) + } + + fun createStixJsonObjectMapper(stixRegistries: StixRegistries): ObjectMapper { + return ObjectMapper() + .registerModule(KotlinModule()) //@TODO see jackson kotlin module issue #87. Waiting for fix. Currently if a subtype does not exist then it fails to provide a meaningful error. + .registerModule(JavaTimeModule()) + .setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE) + .setSerializationInclusion(JsonInclude.Include.NON_EMPTY) + .configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, true) + .configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true) + .registerModule(createStixTimestampSerializationModule()) + .registerModule(createStixIdentifierSerializationModule()) + .registerModule(createStixTypeSerializationModule()) + .registerModule(createStixSpecVersionSerializationModule()) + .registerModule(createStixBooleanSerializationModule()) + .registerModule(createStixContentSerializationModule(stixRegistries.objectRegistry)) + .registerModule(createRelationshipTypeSerializationModule()) + .registerModule(createStixIntegerSerializationModule()) + .registerModule(createStixConfidenceSerializationModule()) + .registerModule(createStixOpenVocabSerializationModule()) + .registerModule(createStixMarkingObjectSerializationModule(stixRegistries.markingObjectRegistry)) + } + } +} + +/** + * Creates a StixJsonContentMapper based on the Stix instance + */ +fun Stix.toJsonMapper(): StixJsonContentMapper { + return StixJsonContentMapper(this.registries) +} + +/** + * Convert StixContent to a json string. + */ +fun StixContent.toJson(mapper: StixJsonContentMapper): String { + return mapper.mapper.writeValueAsString(this) +} + +/** + * Convert a StixBundle to a json string. + */ +fun StixBundle.toJson(mapper: StixJsonContentMapper): String { + return mapper.mapper.writeValueAsString(this) +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/serialization/json/RelationshipTypeSerialization.kt b/src/main/kotlin/com/stephenott/stix/serialization/json/RelationshipTypeSerialization.kt new file mode 100644 index 0000000..72c8984 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/serialization/json/RelationshipTypeSerialization.kt @@ -0,0 +1,29 @@ +package com.stephenott.stix.serialization.json + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import com.stephenott.stix.type.RelationshipType + + +fun createRelationshipTypeSerializationModule(): SimpleModule{ + return SimpleModule() + .addSerializer(RelationshipType::class.java, RelationshipTypeSerializer()) + .addDeserializer(RelationshipType::class.java, RelationshipTypeDeserializer()) +} + +class RelationshipTypeSerializer() : StdSerializer(RelationshipType::class.java) { + override fun serialize(value: RelationshipType?, gen: JsonGenerator?, provider: SerializerProvider?) { + gen!!.writeString(value.toString()) + } +} + +class RelationshipTypeDeserializer() : StdDeserializer(RelationshipType::class.java) { + override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): RelationshipType { + return RelationshipType(p!!.text) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/serialization/json/StixBooleanSerialization.kt b/src/main/kotlin/com/stephenott/stix/serialization/json/StixBooleanSerialization.kt new file mode 100644 index 0000000..b8f484f --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/serialization/json/StixBooleanSerialization.kt @@ -0,0 +1,39 @@ +package com.stephenott.stix.serialization.json + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import com.stephenott.stix.type.StixBoolean +import kotlin.IllegalArgumentException + + +fun createStixBooleanSerializationModule(): SimpleModule{ + return SimpleModule() + .addSerializer(StixBoolean::class.java, StixBooleanSerializer()) + .addDeserializer(StixBoolean::class.java, StixBooleanDeserializer()) +} + +class StixBooleanSerializer() : StdSerializer(StixBoolean::class.java) { + + override fun isEmpty(provider: SerializerProvider?, value: StixBoolean?): Boolean { + return value == null || !value.isDefinedValue + } + + override fun serialize(value: StixBoolean?, gen: JsonGenerator?, provider: SerializerProvider?) { + gen!!.writeBoolean(value!!.value) + } +} + +class StixBooleanDeserializer() : StdDeserializer(StixBoolean::class.java) { + override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): StixBoolean { + try { + return StixBoolean.parse(p!!.text) + } catch (e: Exception){ + throw IllegalArgumentException("Unable to parse boolean.", e) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/serialization/json/StixConfidenceSerialization.kt b/src/main/kotlin/com/stephenott/stix/serialization/json/StixConfidenceSerialization.kt new file mode 100644 index 0000000..cfb3b0e --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/serialization/json/StixConfidenceSerialization.kt @@ -0,0 +1,38 @@ +package com.stephenott.stix.serialization.json + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import com.stephenott.stix.type.StixConfidence +import com.stephenott.stix.type.StixType + + +fun createStixConfidenceSerializationModule(): SimpleModule{ + return SimpleModule() + .addSerializer(StixConfidence::class.java, StixConfidenceSerializer()) + .addDeserializer(StixConfidence::class.java, StixConfidenceDeserializer()) +} + +class StixConfidenceSerializer() : StdSerializer(StixConfidence::class.java) { + override fun isEmpty(provider: SerializerProvider?, value: StixConfidence?): Boolean { + return value == null || value.stixValue == null + } + + override fun serialize(value: StixConfidence?, gen: JsonGenerator?, provider: SerializerProvider?) { + gen!!.writeNumber(value!!.getConfidence()) + } +} + +class StixConfidenceDeserializer() : StdDeserializer(StixConfidence::class.java) { + override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): StixConfidence { + if (p!!.numberType == JsonParser.NumberType.INT){ + return StixConfidence(p.intValue) + } else { + throw IllegalArgumentException("Invalid confidence value.") + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/serialization/json/StixContentSerialization.kt b/src/main/kotlin/com/stephenott/stix/serialization/json/StixContentSerialization.kt new file mode 100644 index 0000000..59a00b2 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/serialization/json/StixContentSerialization.kt @@ -0,0 +1,37 @@ +package com.stephenott.stix.serialization.json + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonTypeInfo +import com.fasterxml.jackson.databind.jsontype.NamedType +import com.fasterxml.jackson.databind.module.SimpleModule +import com.stephenott.stix.Stix +import com.stephenott.stix.StixContent +import com.stephenott.stix.StixRegistries +import com.stephenott.stix.common.StixObjectRegistry + + +fun createStixContentSerializationModule(objectRegistry: StixObjectRegistry): SimpleModule { + val module: SimpleModule = SimpleModule() + + objectRegistry.registry.forEach { (type, clazz) -> + module.registerSubtypes(NamedType(clazz.java, type.toString())) + } + + module.setMixInAnnotation(StixContent::class.java, StixContentTypeMixin::class.java) + + return module +} + +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.EXISTING_PROPERTY, + visible = true, + property = "type" +) +interface StixContentTypeMixin{ + @get:JsonIgnore //@TODO Review for need of a 'set:' + val stixInstance: Stix + + @get:JsonIgnore + val stixValidateOnConstruction: Boolean +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/serialization/json/StixIdentifierSerialization.kt b/src/main/kotlin/com/stephenott/stix/serialization/json/StixIdentifierSerialization.kt new file mode 100644 index 0000000..63f2820 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/serialization/json/StixIdentifierSerialization.kt @@ -0,0 +1,34 @@ +package com.stephenott.stix.serialization.json + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import com.stephenott.stix.type.StixIdentifier + + +fun createStixIdentifierSerializationModule(): SimpleModule{ + return SimpleModule() + .addSerializer(StixIdentifier::class.java, StixIdentifierSerializer()) + .addDeserializer(StixIdentifier::class.java, StixIdentifierDeserializer()) +} + +class StixIdentifierSerializer() : StdSerializer(StixIdentifier::class.java) { + override fun serialize(value: StixIdentifier?, gen: JsonGenerator?, provider: SerializerProvider?) { + gen!!.writeString(value!!.toString()) + } +} + +class StixIdentifierDeserializer() : StdDeserializer(StixIdentifier::class.java) { + override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): StixIdentifier { + try { + return StixIdentifier.parse(p!!.text) + } catch (e: Exception) { + throw IllegalArgumentException("Unable to parse identifier", e) + } + + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/serialization/json/StixIntegerSerialization.kt b/src/main/kotlin/com/stephenott/stix/serialization/json/StixIntegerSerialization.kt new file mode 100644 index 0000000..3a52bbe --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/serialization/json/StixIntegerSerialization.kt @@ -0,0 +1,33 @@ +package com.stephenott.stix.serialization.json + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import com.stephenott.stix.type.StixInteger + + +fun createStixIntegerSerializationModule(): SimpleModule { + return SimpleModule() + .addSerializer(StixInteger::class.java, StixIntegerSerializer()) + .addDeserializer(StixInteger::class.java, StixIntegerDeserializer()) +} + +class StixIntegerSerializer() : StdSerializer(StixInteger::class.java) { + override fun serialize(value: StixInteger?, gen: JsonGenerator?, provider: SerializerProvider?) { + gen!!.writeNumber(value!!.value) + } +} + +class StixIntegerDeserializer() : StdDeserializer(StixInteger::class.java) { + override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): StixInteger { + if (p!!.numberType == JsonParser.NumberType.INT) { + return StixInteger(p.intValue) + } else { + throw IllegalArgumentException("value is not expected integer format.") + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/serialization/json/StixMarkingObjectSerialization.kt b/src/main/kotlin/com/stephenott/stix/serialization/json/StixMarkingObjectSerialization.kt new file mode 100644 index 0000000..7a2a5c2 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/serialization/json/StixMarkingObjectSerialization.kt @@ -0,0 +1,37 @@ +package com.stephenott.stix.serialization.json + +import com.fasterxml.jackson.annotation.JsonTypeInfo +import com.fasterxml.jackson.databind.jsontype.NamedType +import com.fasterxml.jackson.databind.module.SimpleModule +import com.stephenott.stix.common.StixMarkingObjectRegistry +import com.stephenott.stix.common.StixObjectRegistry +import com.stephenott.stix.objects.meta.datamarking.MarkingDefinition +import com.stephenott.stix.objects.meta.datamarking.MarkingDefinitionDm +import com.stephenott.stix.objects.meta.datamarking.MarkingObject +import com.stephenott.stix.objects.meta.datamarking.objects.Statement +import com.stephenott.stix.objects.meta.datamarking.objects.Tlp + +fun createStixMarkingObjectSerializationModule(markingObjectRegistry: StixMarkingObjectRegistry): SimpleModule { + + val module = SimpleModule() + + // Registers each markingObject that is located in the MarkingObjectRegistry + //@TODO review implications for race event where these will not be loaded when create the StixMapper class. Likely will want to pass the data into the function. + markingObjectRegistry.registry.forEach { (typeOv, clazz) -> + module.registerSubtypes(NamedType(clazz.java, typeOv.getValue())) + } + + module.setMixInAnnotation(MarkingDefinition::class.java, MarkingObjectDefinitionTypeMixin::class.java) + + return module +} + +abstract class MarkingObjectDefinitionTypeMixin { + + @get:JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.EXTERNAL_PROPERTY, + property = MarkingDefinitionDm.definitionPolymorphicFieldName + ) + abstract val definition: MarkingObject +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/serialization/json/StixOpenVocabSerialization.kt b/src/main/kotlin/com/stephenott/stix/serialization/json/StixOpenVocabSerialization.kt new file mode 100644 index 0000000..90fe8be --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/serialization/json/StixOpenVocabSerialization.kt @@ -0,0 +1,32 @@ +package com.stephenott.stix.serialization.json + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.* +import com.fasterxml.jackson.databind.deser.ContextualDeserializer +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import com.stephenott.stix.type.vocab.OpenVocab + + +fun createStixOpenVocabSerializationModule(): SimpleModule { + return SimpleModule() + .addSerializer(OpenVocab::class.java, StixOpenVocabSerializer()) + .addDeserializer(OpenVocab::class.java, StixOpenVocabDeserializer()) +} + +class StixOpenVocabSerializer() : StdSerializer(OpenVocab::class.java) { + override fun serialize(value: OpenVocab?, gen: JsonGenerator?, provider: SerializerProvider?) { + gen!!.writeString(value!!.getValue()) + } +} + +class StixOpenVocabDeserializer() : StdDeserializer(OpenVocab::class.java) { + + override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): OpenVocab { + println(ctxt!!.contextualType) + + return p!!.readValueAs(ctxt.contextualType.rawClass) as OpenVocab + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/serialization/json/StixSpecVersionSerialization.kt b/src/main/kotlin/com/stephenott/stix/serialization/json/StixSpecVersionSerialization.kt new file mode 100644 index 0000000..8768414 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/serialization/json/StixSpecVersionSerialization.kt @@ -0,0 +1,37 @@ +package com.stephenott.stix.serialization.json + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import com.stephenott.stix.type.StixSpecVersion + + +fun createStixSpecVersionSerializationModule(): SimpleModule{ + return SimpleModule() + .addSerializer(StixSpecVersion::class.java, StixSpecVersionSerializer()) + .addDeserializer(StixSpecVersion::class.java, StixSpecVersionDeserializer()) +} + +class StixSpecVersionSerializer() : StdSerializer(StixSpecVersion::class.java) { + override fun isEmpty(provider: SerializerProvider?, value: StixSpecVersion?): Boolean { + return value == null || !value.isDefinedValue + } + + override fun serialize(value: StixSpecVersion?, gen: JsonGenerator?, provider: SerializerProvider?) { + gen!!.writeString(value.toString()) + } +} + +class StixSpecVersionDeserializer() : StdDeserializer(StixSpecVersion::class.java) { + override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): StixSpecVersion { + try { + return StixSpecVersion.parse(p!!.text) + } catch (e: Exception){ + throw IllegalArgumentException("Unable to parse spec_version.", e) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/serialization/json/StixTimestampSerialization.kt b/src/main/kotlin/com/stephenott/stix/serialization/json/StixTimestampSerialization.kt new file mode 100644 index 0000000..b9f638a --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/serialization/json/StixTimestampSerialization.kt @@ -0,0 +1,34 @@ +package com.stephenott.stix.serialization.json + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import com.stephenott.stix.type.StixTimestamp + + +fun createStixTimestampSerializationModule(): SimpleModule{ + return SimpleModule() + .addSerializer(StixTimestamp::class.java, StixTimestampSerializer()) + .addDeserializer(StixTimestamp::class.java, StixTimestampDeserializer()) +} + +class StixTimestampSerializer() : StdSerializer(StixTimestamp::class.java) { + override fun serialize(value: StixTimestamp, gen: JsonGenerator, provider: SerializerProvider) { + gen.writeString(value.toString()) + } +} + +class StixTimestampDeserializer() : StdDeserializer(StixTimestamp::class.java) { + override fun deserialize(p: JsonParser, ctxt: DeserializationContext): StixTimestamp { + try { + return StixTimestamp.parse(p.text) + } catch (e: Exception){ + throw IllegalArgumentException("Unable to parse timestamp.", e) + } + + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/serialization/json/StixTypeSerialization.kt b/src/main/kotlin/com/stephenott/stix/serialization/json/StixTypeSerialization.kt new file mode 100644 index 0000000..9798de1 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/serialization/json/StixTypeSerialization.kt @@ -0,0 +1,45 @@ +package com.stephenott.stix.serialization.json + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.JsonParser +import com.fasterxml.jackson.databind.DeserializationContext +import com.fasterxml.jackson.databind.KeyDeserializer +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.deser.std.StdDeserializer +import com.fasterxml.jackson.databind.module.SimpleModule +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import com.stephenott.stix.type.StixType + +fun createStixTypeSerializationModule(): SimpleModule{ + return SimpleModule() + .addSerializer(StixType::class.java, StixTypeSerializer()) + .addDeserializer(StixType::class.java, StixTypeDeserializer()) + .addKeyDeserializer(StixType::class.java, StixTypeKeyDeserializer()) +} + +class StixTypeSerializer() : StdSerializer(StixType::class.java) { + + override fun serialize(value: StixType?, gen: JsonGenerator?, provider: SerializerProvider?) { + gen!!.writeString(value!!.toString()) + } +} + + +class StixTypeKeyDeserializer() : KeyDeserializer(){ + //@TODO *** why this was needed. Was getting a key map error from jackson when not inlcuded. + // It started to occur for a unknown reason + //This should not be required + override fun deserializeKey(key: String?, ctxt: DeserializationContext?): Any { + return key!! + } +} + +class StixTypeDeserializer() : StdDeserializer(StixType::class.java) { + override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): StixType { + try { + return StixType.parse(p!!.text) + } catch (e: Exception){ + throw IllegalArgumentException("Unable to parse type property.", e) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/AdditionalHeaderFieldsDictionary.kt b/src/main/kotlin/com/stephenott/stix/type/AdditionalHeaderFieldsDictionary.kt new file mode 100644 index 0000000..475438f --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/AdditionalHeaderFieldsDictionary.kt @@ -0,0 +1,16 @@ +package com.stephenott.stix.type + +class AdditionalHeaderFieldsDictionary(private val fields: Map>): + Map> by fields { + + init { + require(unallowedFields.any { it in fields.keys }) + } + + companion object{ + val unallowedFields: List = listOf( + "date","received_lines", "content_type", + "from_ref", "sender_ref", "to_refs", + "cc_refs", "bcc_refs", "subject") + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/AlternateDataStreams.kt b/src/main/kotlin/com/stephenott/stix/type/AlternateDataStreams.kt new file mode 100644 index 0000000..3c2600a --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/AlternateDataStreams.kt @@ -0,0 +1,18 @@ +package com.stephenott.stix.type + +class AlternateDataStreams(private val streams: List): + List by streams{ + + init { + //@TODO + } +} + +data class AlternateDataStreamType( + val name: String, + val hashes: HashesDictionary, + val size: StixInteger){ + init { + require(size.value >= 0, lazyMessage = {"size must not be negative."}) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/ExifTagsDictionary.kt b/src/main/kotlin/com/stephenott/stix/type/ExifTagsDictionary.kt new file mode 100644 index 0000000..b459112 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/ExifTagsDictionary.kt @@ -0,0 +1,20 @@ +package com.stephenott.stix.type + +class ExifTagsDictionary(private val dictionary: LinkedHashMap): + Map by dictionary { + + init { + //@TODO + + //@TODO Add a JsonCreator constructor for the Map + + } +} + +interface ExifTag{ + val value: Any +} + +data class ExifTagStringValue(override val value: String): ExifTag + +data class ExifTagIntegerValue(override val value: StixInteger): ExifTag \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/Extensions.kt b/src/main/kotlin/com/stephenott/stix/type/Extensions.kt new file mode 100644 index 0000000..6d717d9 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/Extensions.kt @@ -0,0 +1,5 @@ +package com.stephenott.stix.type + +import com.stephenott.stix.objects.core.sco.extension.ScoExtension + +class Extensions(private val dictionary: Set): Set by dictionary {} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/ExternalReferences.kt b/src/main/kotlin/com/stephenott/stix/type/ExternalReferences.kt new file mode 100644 index 0000000..42ea023 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/ExternalReferences.kt @@ -0,0 +1,16 @@ +package com.stephenott.stix.type + +class ExternalReferences(private val references: LinkedHashSet): + Set by references + +data class ExternalReference( + val sourceName: String, + val description: String?, + val url: String?, + val hashes: HashesDictionary?, + val externalId: String? +) { + init { + //@TODO add biz logic for what fields can be populated + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/HashesDictionary.kt b/src/main/kotlin/com/stephenott/stix/type/HashesDictionary.kt new file mode 100644 index 0000000..9742fb8 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/HashesDictionary.kt @@ -0,0 +1,31 @@ +package com.stephenott.stix.type + +import com.stephenott.stix.type.vocab.OpenVocab + +class HashesDictionary(private val immutableDictionary: LinkedHashMap = linkedMapOf()): + Map by immutableDictionary { +} + +class HashingAlgorithm(private val algorithm: String): OpenVocab { + override fun getValue(): String { + return algorithm + } + + companion object{ + const val vocabName: String = "hash-algorithm-ov​" + + var vocab: LinkedHashSet = linkedSetOf( + "MD5", "MD6", "RIPEMD-160", "SHA-1", + "SHA-224", "SHA-256", "SHA-384", "SHA-512", + "SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512", + "SSDEEP", "WHIRLPOOL") + set(value) { + require(value.all { it.length in 3..256 }) + field = value + } + } + + init { + require(this.algorithm in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/HttpRequestHeaderDictionary.kt b/src/main/kotlin/com/stephenott/stix/type/HttpRequestHeaderDictionary.kt new file mode 100644 index 0000000..9c3959f --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/HttpRequestHeaderDictionary.kt @@ -0,0 +1,9 @@ +package com.stephenott.stix.type + +class HttpRequestHeaderDictionary(private val headers: Map>): + Map> by headers { + + init { + //note that this dictionary allows for a value in the List to be a empty non-null string such as "". + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/IpfixDictionary.kt b/src/main/kotlin/com/stephenott/stix/type/IpfixDictionary.kt new file mode 100644 index 0000000..cfc7c7b --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/IpfixDictionary.kt @@ -0,0 +1,20 @@ +package com.stephenott.stix.type + +class IpfixDictionary(private val dictionary: LinkedHashMap): + Map by dictionary { + + init { + //@TODO + + //@TODO Add a JsonCreator constructor for the Map + + } +} + +interface IpFixElement{ + val value: Any +} + +data class IpfixElementStringValue(override val value: String): IpFixElement + +data class IpfixElementIntegerValue(override val value: StixInteger): IpFixElement \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/KillChainPhases.kt b/src/main/kotlin/com/stephenott/stix/type/KillChainPhases.kt new file mode 100644 index 0000000..75f7722 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/KillChainPhases.kt @@ -0,0 +1,25 @@ +package com.stephenott.stix.type + +class KillChainPhases(private val phases: LinkedHashSet) : Set by phases { + + init { + require(phases.size >0) + } +} + +data class KillChainPhase(val killChainName: String, val phaseName: String) {} + +object CommonKillChainPhases { + + val lockheedMartinKillChainName = "lockheed-martin-cyber-kill-chain" + enum class LockheedMartinKillChainPhases(val phaseName: String) { + RECONNAISSANCE("reconnaissance"), + WEAPONIZATION("weaponization"), + DELIVERY("delivery"), + EXPLOITATION("exploitation"), + INSTALLATION("installation"), + COMMAND_AND_CONTROL("command-and-control"), + ACTIONS_ON_OBJECTIVE("actions-on-objective"); + } +} + diff --git a/src/main/kotlin/com/stephenott/stix/type/LanguageContentDictionary.kt b/src/main/kotlin/com/stephenott/stix/type/LanguageContentDictionary.kt new file mode 100644 index 0000000..b6ace7b --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/LanguageContentDictionary.kt @@ -0,0 +1,21 @@ +package com.stephenott.stix.type + +class LanguageContentDictionary(private val languages: Set = linkedSetOf()): + Map by languages.associateBy({it.languageCode}){ + + init { + //@TODO + + //@TODO Add a JsonCreator constructor for the Map + + } +} + +data class LanguageContent(val languageCode: String, val content: Map) { + + init { + //@TODO add language code validation + //@TODO add better type handler for the content Map + //@TODO add support for untranslated content + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/LocationData.kt b/src/main/kotlin/com/stephenott/stix/type/LocationData.kt new file mode 100644 index 0000000..263c526 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/LocationData.kt @@ -0,0 +1,16 @@ +package com.stephenott.stix.type + +class Latitude(val value: Float){ + init { + require(value in -90.0..90.0) + } +} + +class Longitude(val value: Float){ + init { + require(value in -180.0..180.0) + } +} + +class LatLongPrecision(val value: Float){ +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/MimePartTypes.kt b/src/main/kotlin/com/stephenott/stix/type/MimePartTypes.kt new file mode 100644 index 0000000..062ca29 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/MimePartTypes.kt @@ -0,0 +1,31 @@ +package com.stephenott.stix.type + +import com.stephenott.stix.objects.core.sco.objects.ArtifactSco +import com.stephenott.stix.objects.core.sco.objects.FileSco + +class MimePartTypes(private val parts: List): List by parts{ + init { + //@TODO + } +} + +data class MimePartType( + val body: String?, + val bodyRawRef: StixIdentifier?, + val ContentType: String?, + val contentDisposition: String? +) { + + init { + if (body != null) { + require(bodyRawRef == null, lazyMessage = { "Only one of body or body_raw_ref must be included." }) + } + if (bodyRawRef != null) { + require(body == null, lazyMessage = { "Only one of body or body_raw_ref must be included." }) + require(bodyRawRef.type == ArtifactSco.stixType || + bodyRawRef.type == FileSco.stixType, + lazyMessage = { "body_raw_ref must be a SCO of type artifact or file." }) + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/OsExecutionEnvs.kt b/src/main/kotlin/com/stephenott/stix/type/OsExecutionEnvs.kt new file mode 100644 index 0000000..8c5abd9 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/OsExecutionEnvs.kt @@ -0,0 +1,7 @@ +package com.stephenott.stix.type + +class OsExecutionEnvs(private val envs: LinkedHashSet): + Set by envs{ +} + +data class OsExecutionEnv(val env: String){} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/Product.kt b/src/main/kotlin/com/stephenott/stix/type/Product.kt new file mode 100644 index 0000000..67f857b --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/Product.kt @@ -0,0 +1,11 @@ +package com.stephenott.stix.type + +data class Product(private val product: String){ + init { + require(product.none { it.isWhitespace() && it.isUpperCase() }) + } + + override fun toString(): String { + return product + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/RelationshipType.kt b/src/main/kotlin/com/stephenott/stix/type/RelationshipType.kt new file mode 100644 index 0000000..99790c2 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/RelationshipType.kt @@ -0,0 +1,12 @@ +package com.stephenott.stix.type + +data class RelationshipType(val type: String) { + init { + //@TODO + //The value of this property MUST be in ASCII and is limited to characters a–z (lowercase ASCII), 0–9, and hyphen (-). + } + + override fun toString(): String { + return type + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/StixBinary.kt b/src/main/kotlin/com/stephenott/stix/type/StixBinary.kt new file mode 100644 index 0000000..bc3d20e --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/StixBinary.kt @@ -0,0 +1,7 @@ +package com.stephenott.stix.type + +data class StixBinary(val binary: String){ + init { + //@TODO base 64 + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/StixBoolean.kt b/src/main/kotlin/com/stephenott/stix/type/StixBoolean.kt new file mode 100644 index 0000000..40e792f --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/StixBoolean.kt @@ -0,0 +1,29 @@ +package com.stephenott.stix.type + +data class StixBoolean( + val value: Boolean = false, + val isDefinedValue: Boolean = false +) { + + /** + * Defaults to StixBoolean value to false. Sets isDefinedValue to false. + * Essentially if the no arg constructor was used, we assume that its a default boolean value rather than explicitly being provided. + * This mainly has implications for JSON processing. + */ + constructor() : this(false, false) + + constructor(value: Boolean) : this(value, true) + + constructor(stixBoolean: StixBoolean) : this(stixBoolean.value, stixBoolean.isDefinedValue) + + companion object { + fun parse(booleanString: String): StixBoolean { + return StixBoolean(booleanString.toBoolean(), true) + } + } + + override fun toString(): String { + return this.value.toString() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/StixConfidence.kt b/src/main/kotlin/com/stephenott/stix/type/StixConfidence.kt new file mode 100644 index 0000000..852246c --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/StixConfidence.kt @@ -0,0 +1,124 @@ +package com.stephenott.stix.type + +import java.lang.IllegalArgumentException +import java.lang.IllegalStateException + +/** + * stixValue must be provided to be considered a valid StixConfidence. + * + */ +data class StixConfidence(val realValue: Int?, val stixValue: Int?, val scaleValue: String?) { + + constructor(confidence: Int): this(null, confidence, null) + + init { + realValue?.let { + require(stixValue != null) + } + stixValue?.let { + require(stixValue in 0..100) + } + scaleValue?.let { + require(it.isNotEmpty()) + } + + require(realValue != null || stixValue != null || scaleValue != null) + } + + fun getConfidence(): Int{ + if (stixValue != null){ + return stixValue + } else { + throw IllegalStateException("Unable to determine confidence value because it is null.") + } + } + + companion object { + //@TODO Interop Comment for Github: Review the use of Null for the confidence values, as null is usually only used for "not provided". Confirm on GH issues. + fun noneLowMedHighScale(realValue: Int?): StixConfidence { + return when (realValue) { + null -> StixConfidence(null, null, "Not Specified") + 0 -> StixConfidence(realValue, 0, "None") + in 1..29 -> StixConfidence(realValue, 15, "Low") + in 30..69 -> StixConfidence(realValue, 50, "Med") + in 70..100 -> StixConfidence(realValue, 85, "High") + else -> { + throw IllegalArgumentException("Invalid value.") + } + } + } + + fun zeroToTenScale(realValue: Int?): StixConfidence { + return when (realValue) { + null -> StixConfidence(null, null, "Not Specified") + in 0..4 -> StixConfidence(realValue, 0, "0") + in 5..14 -> StixConfidence(realValue, 10, "1") + in 15..24 -> StixConfidence(realValue, 20, "2") + in 25..34 -> StixConfidence(realValue, 30, "3") + in 35..44 -> StixConfidence(realValue, 40, "4") + in 45..54 -> StixConfidence(realValue, 50, "5") + in 55..64 -> StixConfidence(realValue, 60, "6") + in 65..74 -> StixConfidence(realValue, 70, "7") + in 75..84 -> StixConfidence(realValue, 80, "8") + in 85..94 -> StixConfidence(realValue, 90, "9") + in 95..100 -> StixConfidence(realValue, 100, "10") + else -> { + throw IllegalArgumentException("Invalid value.") + } + } + } + + fun admiraltyCredibility(realValue: Int?): StixConfidence { + return when (realValue) { + null -> StixConfidence(null, null, "6 - Truth cannot be judged") + in 0..19 -> StixConfidence(realValue, 10, "5 - Improbable") + in 20..39 -> StixConfidence(realValue, 30, "4 - Doubtful") + in 40..59 -> StixConfidence(realValue, 50, "3 - Possibly True") + in 60..79 -> StixConfidence(realValue, 70, "2 - Probably True") + in 80..100 -> StixConfidence(realValue, 90, "1 - Confirmed by other sources") + else -> { + throw IllegalArgumentException("Invalid value.") + } + } + } + + /** + * Words of Estimative Probability (WEP) + */ + fun wepScale(realValue: Int?): StixConfidence { + //@TODO Review the scaleValues in the 2.1 Docs for typos: Inconsistencies in the capitalization + return when (realValue) { + null -> StixConfidence(null, null, "Not Specified") + 0 -> StixConfidence(realValue, 0, "Impossible") + in 1..19 -> StixConfidence(realValue, 10, "Highly Unlikely/Almost Certainly Not") + in 20..39 -> StixConfidence(realValue, 30, "Unlikely/Probably Not") + in 40..59 -> StixConfidence(realValue, 50, "Even Chance") + in 60..79 -> StixConfidence(realValue, 70, "Likely/Probable") + in 80..99 -> StixConfidence(realValue, 90, "Highly likely/Almost Certain") + 100 -> StixConfidence(realValue, 100, "Certain") + else -> { + throw IllegalArgumentException("Invalid value.") + } + } + } + + /** + * DNI Scale: ICD 203 + */ + fun dniScale(realValue: Int?): StixConfidence { + return when (realValue) { + null -> StixConfidence(null, null, "Not Specified") + in 0..9 -> StixConfidence(realValue, 5, "Almost No Chance / Remote") + in 10..19 -> StixConfidence(realValue, 15, "Very Unlikely / Highly Improbable") + in 20..39 -> StixConfidence(realValue, 30, "Unlikely/Improbable") + in 40..59 -> StixConfidence(realValue, 50, "Rough Even Chance / Roughly Even Odds") + in 60..79 -> StixConfidence(realValue, 70, "Likely / Probable") + in 80..89 -> StixConfidence(realValue, 85, "Very Likely / Highly Probable") + in 90..100 -> StixConfidence(realValue, 95, "Almost Certain / Nearly Certain") + else -> { + throw IllegalArgumentException("Invalid value.") + } + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/StixFloat.kt b/src/main/kotlin/com/stephenott/stix/type/StixFloat.kt new file mode 100644 index 0000000..7d1376e --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/StixFloat.kt @@ -0,0 +1,3 @@ +package com.stephenott.stix.type + +data class StixFloat (val value: Float) {} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/StixHex.kt b/src/main/kotlin/com/stephenott/stix/type/StixHex.kt new file mode 100644 index 0000000..6343e4f --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/StixHex.kt @@ -0,0 +1,7 @@ +package com.stephenott.stix.type + +data class StixHex (val value: String) { + init { + //@TODO add hex validation + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/StixIdentifier.kt b/src/main/kotlin/com/stephenott/stix/type/StixIdentifier.kt new file mode 100644 index 0000000..880c506 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/StixIdentifier.kt @@ -0,0 +1,40 @@ +package com.stephenott.stix.type + +import java.util.* +import kotlin.collections.LinkedHashSet + +class StixIdentifiers(private val identifiers: LinkedHashSet) : + Set by identifiers { + + //@TODO add limits on which Identifiers can be added for specific implementations +} + +data class StixIdentifier( + val type: StixType, + val uuid: String = generateUUIDv4() +) { + + constructor(type: String) : this(StixType(type)) + + //@TODO Add deterministic ID generation + + companion object { + fun generateUUIDv4(): String = UUID.randomUUID().toString() + const val typeUUIDSpacer = "--" + + fun parse(stringIdentifier: String): StixIdentifier{ + val type: String = stringIdentifier.substringBefore(typeUUIDSpacer) + val uuid: String = stringIdentifier.substringAfter(typeUUIDSpacer) + return StixIdentifier(StixType(type), uuid) + } + + } + + fun getIdentifier(): String { + return type.toString() + typeUUIDSpacer + uuid + } + + override fun toString(): String { + return getIdentifier() + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/StixInteger.kt b/src/main/kotlin/com/stephenott/stix/type/StixInteger.kt new file mode 100644 index 0000000..211a710 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/StixInteger.kt @@ -0,0 +1,3 @@ +package com.stephenott.stix.type + +data class StixInteger (val value: Int) {} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/StixLabels.kt b/src/main/kotlin/com/stephenott/stix/type/StixLabels.kt new file mode 100644 index 0000000..192ac9e --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/StixLabels.kt @@ -0,0 +1,7 @@ +package com.stephenott.stix.type + +class StixLabels(private val labels: LinkedHashSet): Set by labels { + init { + labels.all { it.isNotEmpty() } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/StixLang.kt b/src/main/kotlin/com/stephenott/stix/type/StixLang.kt new file mode 100644 index 0000000..80aff22 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/StixLang.kt @@ -0,0 +1,15 @@ +package com.stephenott.stix.type + +data class StixLang (val lang: String, val isDefinedValue: Boolean){ + init { + //@TODO add RFC5646 language code validation + } + + constructor(): this(DEFAULT_LANG, false) + + constructor(lang: String): this(lang, true) + + companion object{ + const val DEFAULT_LANG = "en" + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/StixPattern.kt b/src/main/kotlin/com/stephenott/stix/type/StixPattern.kt new file mode 100644 index 0000000..75dfea7 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/StixPattern.kt @@ -0,0 +1,9 @@ +package com.stephenott.stix.type + +class StixPattern(private val pattern: String): + CharSequence by pattern { + + init { + pattern.isNotEmpty() + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/StixSpecVersion.kt b/src/main/kotlin/com/stephenott/stix/type/StixSpecVersion.kt new file mode 100644 index 0000000..aea6553 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/StixSpecVersion.kt @@ -0,0 +1,29 @@ +package com.stephenott.stix.type + +import java.lang.IllegalArgumentException + +data class StixSpecVersion(private val versionEnum: StixVersions, val isDefinedValue: Boolean) { + + companion object{ + enum class StixVersions(val version: String) { +// TWO_DOT_ZERO("2.0"), //@TODO review this + TWO_DOT_ONE("2.1") + } + + fun parse(versionString: String): StixSpecVersion{ + try { + return StixSpecVersion(StixVersions.values().first { it.version == versionString }, true) + } catch (e: Exception){ + throw IllegalArgumentException("Unable to parse spec version. Note that only spec version 2.1 is supported. Use an elevator to pre-convert 2.0 to 2.1", e) + } + + } + } + + //@TODO Review if this is the correct default + constructor() : this(StixVersions.TWO_DOT_ONE, true) + + override fun toString(): String { + return versionEnum.version + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/StixStringList.kt b/src/main/kotlin/com/stephenott/stix/type/StixStringList.kt new file mode 100644 index 0000000..260adb9 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/StixStringList.kt @@ -0,0 +1,9 @@ +package com.stephenott.stix.type + + +//@TODO refactor to generic +class StixStringList(private val list: List): List by list{ + init { + require(list.isNotEmpty(), lazyMessage = {"STIX Spec does not allow empty lists."}) // https://github.com/oasis-tcs/cti-stix2/issues/144#issuecomment-481370524 + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/StixTimestamp.kt b/src/main/kotlin/com/stephenott/stix/type/StixTimestamp.kt new file mode 100644 index 0000000..ede4c37 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/StixTimestamp.kt @@ -0,0 +1,54 @@ +package com.stephenott.stix.type + +import com.stephenott.stix.common.StixDataFormats +import java.time.Instant +import java.util.regex.Pattern + +data class StixTimestamp( + val instant: Instant, + val subSecondPrecision: Int) { + + init { + //@TODO how to detect what parameters were used + require(!(subSecondPrecision < 0 || subSecondPrecision > 9)) { "Sub-second precision must be between 0 and 9" } + } + + companion object { + var defaultSubSecondPrecision = 3 + var REGEX_SUBSECOND: Pattern = + Pattern.compile("(?\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(.(?[0-9]+))?Z)") + + fun parse(dateString: String): StixTimestamp { + val instant = Instant.from(StixDataFormats.readerStixDateTimeFormatter.parse(dateString)) + val subSecondPrecision = getSubSecondDigitCount(dateString) + + return StixTimestamp(instant, subSecondPrecision) + } + + private fun getSubSecondDigitCount(dateString: String): Int { + val matcher = REGEX_SUBSECOND.matcher(dateString) + if (matcher.find()) { + val subSeconds: String? = matcher.group("subSecond") + // If no sub seconds were provided then return 0 as the precision + return subSeconds?.length ?: 0 + + } else { + throw IllegalStateException("Unable to parse date") + } + } + } + + constructor(stixTimestamp: StixTimestamp) : this(stixTimestamp.instant, stixTimestamp.subSecondPrecision) + + constructor() : this(Instant.now(), defaultSubSecondPrecision){} + + constructor(instant: Instant) : this(instant, instant.nano.toString().length) + + override fun toString(): String { + return StixDataFormats.getWriterStixDateTimeFormatter(subSecondPrecision).format(this.instant) + } + + fun toString(subSecondPrecision: Int): String { + return StixDataFormats.getWriterStixDateTimeFormatter(subSecondPrecision).format(this.instant) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/StixType.kt b/src/main/kotlin/com/stephenott/stix/type/StixType.kt new file mode 100644 index 0000000..28586d9 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/StixType.kt @@ -0,0 +1,38 @@ +package com.stephenott.stix.type + +data class StixType( + val type: String, + val isCustomType: Boolean = false) +{ + + init { + require(type.length in IntRange(3, 250)) + require(Regex("^\\-?[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\\-?$").matches(type)) + } + + companion object{ + var customObjectPrefix: String = "x-" //@TODO refactor to lazy init and a outside factory + + fun parse(typeString: String): StixType{ + val isCustomObject: Boolean = typeString.startsWith(customObjectPrefix) + val type: String = if (isCustomObject){ + typeString.substringAfter(customObjectPrefix) + } else { + typeString + } + + return StixType(type, isCustomObject) + } + + } + + constructor(stixType: StixType): this(stixType.type, stixType.isCustomType) + + override fun toString(): String { + return if (isCustomType){ + customObjectPrefix + type + } else { + type + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/StreetAddress.kt b/src/main/kotlin/com/stephenott/stix/type/StreetAddress.kt new file mode 100644 index 0000000..6427673 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/StreetAddress.kt @@ -0,0 +1,16 @@ +package com.stephenott.stix.type + +data class StreetAddress(val address: String){ + + + override fun toString(): String { + return super.toString() + } +} + +data class PostalCode(val postalCode: String){ + + override fun toString(): String { + return super.toString() + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/WindowsPeOptionalHeaderType.kt b/src/main/kotlin/com/stephenott/stix/type/WindowsPeOptionalHeaderType.kt new file mode 100644 index 0000000..bd8a950 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/WindowsPeOptionalHeaderType.kt @@ -0,0 +1,60 @@ +package com.stephenott.stix.type + +import kotlin.reflect.KVisibility +import kotlin.reflect.full.* + + +data class WindowsPeOptionalHeaderType( + val magicHex: StixHex? = null, + val majorLinkerVersion: StixInteger? = null, + val minorLinkerVersion: StixInteger? = null, + val sizeOfCode: StixInteger? = null, + val sizeOfInitializedData: StixInteger? = null, + val sizeOfUninitializedData: StixInteger? = null, + val addressOfEntryPoint: StixInteger? = null, + val baseOfCode: StixInteger? = null, + val baseOfData: StixInteger? = null, + val imageBase: StixInteger? = null, + val sectionAlignment: StixInteger? = null, + val fileAlignment: StixInteger? = null, + val majorOsVersion: StixInteger? = null, + val minorOsVersion: StixInteger? = null, + val majorImageVersion: StixInteger? = null, + val minorImageVersion: StixInteger? = null, + val majorSubsystemVersion: StixInteger? = null, + val minorSubsystemVersion: StixInteger? = null, + val win32VersionValueHex: StixHex? = null, + val sizeOfImage: StixInteger? = null, + val sizeOfHeaders: StixInteger? = null, + val checksumHex: StixHex? = null, + val subsystemHex: StixHex? = null, + val dllCharacteristics: StixHex? = null, + val sizeOfStackReserve: StixInteger? = null, + val sizeOfStackCommit: StixInteger? = null, + val sizeOfHeapReserve: StixInteger? = null, + val sizeOfHeapCommit: StixInteger? = null, + val loaderFlagsHex: StixHex? = null, + val numberOfRvaAndSizes: StixInteger? = null, + val hashes: HashesDictionary? = null + +) { + + init { + + require(this::class.memberProperties + .filter {it.visibility == KVisibility.PUBLIC} + .any { it.getter.call() != null }, + lazyMessage = {"At least one property must be provided/be not null."}) + + require(sizeOfCode?.value!! >= 0) + require(sizeOfInitializedData?.value!! >= 0) + require(sizeOfUninitializedData?.value!! >= 0) + require(sizeOfImage?.value!! >= 0) + require(sizeOfHeaders?.value!! >= 0) + require(sizeOfStackReserve?.value!! >= 0) + require(sizeOfStackCommit?.value!! >= 0) + require(sizeOfHeapReserve?.value!! >= 0) + require(sizeOfHeapCommit?.value!! >= 0) + } + + } \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/WindowsPeSectionType.kt b/src/main/kotlin/com/stephenott/stix/type/WindowsPeSectionType.kt new file mode 100644 index 0000000..78ed133 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/WindowsPeSectionType.kt @@ -0,0 +1,18 @@ +package com.stephenott.stix.type + +class WindowsPeSectionTypes(private val types: List): List by types{ + +} + +data class WindowsPeSectionType( + val name: String, + val size: StixInteger?, + val entropy: StixFloat?, + val hashes: HashesDictionary? +) { + + init { + require(size?.value!! >= 0) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/WindowsRegistryValueType.kt b/src/main/kotlin/com/stephenott/stix/type/WindowsRegistryValueType.kt new file mode 100644 index 0000000..d7e3680 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/WindowsRegistryValueType.kt @@ -0,0 +1,21 @@ +package com.stephenott.stix.type + +import com.stephenott.stix.type.vocab.WindowsRegistryDataTypeEnum + +class WindowsRegistryValueTypes(private val types: List): List by types{ + + init { + //@TODO + } + +} + +data class WindowsRegistryValueType( + val name: String?, + val data: String?, + val dataType: WindowsRegistryDataTypeEnum? +) { + init { + require(listOf(name, data, dataType).any { it != null }) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/X509v3ExtensionsTypes.kt b/src/main/kotlin/com/stephenott/stix/type/X509v3ExtensionsTypes.kt new file mode 100644 index 0000000..9d83ee0 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/X509v3ExtensionsTypes.kt @@ -0,0 +1,38 @@ +package com.stephenott.stix.type + +import kotlin.reflect.KVisibility +import kotlin.reflect.full.memberProperties + +class X509v3ExtensionsTypes(private val types: List): List by types{ + init { + require(types.isNotEmpty()) + } +} + +data class X509v3ExtensionsType( + val basicConstraints: String?, + val nameConstraints: String?, + val policyConstraints: String?, + val keyUsage: String?, + val extendedKeyUsage: String?, + val subjectKeyIdentifier: String?, + val authorityKeyIdentifier: String?, + val subjectAlternativeName: String?, + val issuerAlternativeName: String?, + val subjectDirectoryAttributes: String?, + val crlDistributionPoints: String?, + val inhibitAnyPolicy: String?, + val privateKeyUsagePeriodNotBefore: StixTimestamp?, + val privateKeyUsagePeriodNotAfter: StixTimestamp?, + val certificatePolicies: String?, + val policyMappings: String? +) { + + init { + require(this::class.memberProperties + .filter {it.visibility == KVisibility.PUBLIC} + .any { it.getter.call() != null }, + lazyMessage = {"At least one property must be provided/not null."}) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/AccountTypeOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/AccountTypeOv.kt new file mode 100644 index 0000000..692f5e2 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/AccountTypeOv.kt @@ -0,0 +1,27 @@ +package com.stephenott.stix.type.vocab + +class AccountType(private val type: String) : OpenVocab, CharSequence by type { + override fun getValue(): String { + return type + } + + companion object { + + const val vocabName = "account-type-ov" + + var vocab: LinkedHashSet = linkedSetOf( + "facebook", "ldap", "nis", + "openid", "radius", "skype", + "tacacs", "twitter", "unix", + "windows-local", "windows-domain" + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.type in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/AdministrativeAreas.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/AdministrativeAreas.kt new file mode 100644 index 0000000..8a4d8c5 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/AdministrativeAreas.kt @@ -0,0 +1,36 @@ +package com.stephenott.stix.type.vocab + +class AdministrativeAreas(private val areas: LinkedHashSet = linkedSetOf(), enforceVocab: Boolean = false) : + Set by areas { + + init { + if (enforceVocab) { + areas.all { AdministrativeArea.vocab.contains(it.toString()) } + } + } +} + +class AdministrativeArea(private val area: String, enforceVocab: Boolean = false) : OpenVocab { + + override fun getValue(): String { + return area + } + + init { + if (enforceVocab) { + require(vocab.contains(area)) + } + } + + companion object { + + const val vocabName = "administrative-areas" + + var vocab: LinkedHashSet = linkedSetOf( + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/AttackMotivationOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/AttackMotivationOv.kt new file mode 100644 index 0000000..90f3c64 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/AttackMotivationOv.kt @@ -0,0 +1,26 @@ +package com.stephenott.stix.type.vocab + +class AttackMotivations(private val motivations: LinkedHashSet = linkedSetOf()) : + Set by motivations { +} + +class AttackMotivationOv(private val motivation: String) : OpenVocab { + override fun getValue(): String { + return motivation + } + + companion object { + const val vocabName = "attack-motivation-ov" + + val vocab: LinkedHashSet = linkedSetOf( + "accidental", "coercion", "dominance", + "ideology", "notoriety", "organizational-gain", + "personal-gain", "personal-satisfaction", + "revenge", "unpredictable" + ) + } + + init { + require(this.motivation in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/AttackResourceLevelOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/AttackResourceLevelOv.kt new file mode 100644 index 0000000..b997d1b --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/AttackResourceLevelOv.kt @@ -0,0 +1,21 @@ +package com.stephenott.stix.type.vocab + +class AttackResourceLevelOv(private val level: String) : OpenVocab, CharSequence by level { + + override fun getValue(): String { + return level + } + + companion object { + const val vocabName = "attack-resource-level-ov" + + val vocab: LinkedHashSet = linkedSetOf( + "individual", "club", "contest", + "team", "organization", "government" + ) + } + + init { + require(this.level in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/Cities.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/Cities.kt new file mode 100644 index 0000000..2ef7e00 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/Cities.kt @@ -0,0 +1,36 @@ +package com.stephenott.stix.type.vocab + +class Cities(private val cities: LinkedHashSet = linkedSetOf(), enforceVocab: Boolean = false) : + Set by cities { + + init { + if (enforceVocab) { + cities.all { City.vocab.contains(it.toString()) } + } + } +} + +class City(private val city: String, enforceVocab: Boolean = false) : OpenVocab, CharSequence by city { + + override fun getValue(): String { + return city + } + + init { + if (enforceVocab) { + require(vocab.contains(city)) + } + } + + companion object { + + const val vocabName = "cities" + + var vocab: LinkedHashSet = linkedSetOf( + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/ClosedVocab.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/ClosedVocab.kt new file mode 100644 index 0000000..eaf831b --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/ClosedVocab.kt @@ -0,0 +1,7 @@ +package com.stephenott.stix.type.vocab + +interface ClosedVocab { + + fun getValue(): String + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/CourseOfActionTypeOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/CourseOfActionTypeOv.kt new file mode 100644 index 0000000..4c52740 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/CourseOfActionTypeOv.kt @@ -0,0 +1,21 @@ +package com.stephenott.stix.type.vocab + +class CourseOfActionTypeOv(private val type: String) : ClosedVocab { + + override fun getValue(): String { + return type + } + + companion object { + const val vocabName = "course-of-action-type-ov" + + val vocab: LinkedHashSet = linkedSetOf( + "textual:text/plain", "textual:text/html", "textual:text/md", + "textual:pdf" + ) + } + + init { + require(this.type in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/EncryptionAlgorithmEnum.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/EncryptionAlgorithmEnum.kt new file mode 100644 index 0000000..bc9c5a5 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/EncryptionAlgorithmEnum.kt @@ -0,0 +1,20 @@ +package com.stephenott.stix.type.vocab + +class EncryptionAlgorithmEnum(private val algorithm: String) : OpenVocab { + + override fun getValue(): String { + return algorithm + } + + companion object { + const val vocabName = "encryption-algorithm-enum" + + val vocab: LinkedHashSet = linkedSetOf( + "AES-256-GCM​", "ChaCha20-Poly1305", "mime-type-indicated" + ) + } + + init { + require(this.algorithm in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/GroupingContextOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/GroupingContextOv.kt new file mode 100644 index 0000000..912a9e9 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/GroupingContextOv.kt @@ -0,0 +1,20 @@ +package com.stephenott.stix.type.vocab + +class GroupingContextOv(private val groupingContext: String) : OpenVocab { + + override fun getValue(): String { + return groupingContext + } + + companion object { + const val vocabName = "grouping-context-ov" + + val vocab: LinkedHashSet = linkedSetOf( + "suspicious-activity", "malware-analysis", "unspecified" + ) + } + + init { + require(this.groupingContext in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/IdentityClassOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/IdentityClassOv.kt new file mode 100644 index 0000000..39b7d7e --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/IdentityClassOv.kt @@ -0,0 +1,25 @@ +package com.stephenott.stix.type.vocab + +class IdentityClass(private val identityClass: String): OpenVocab { + + override fun getValue(): String { + return identityClass + } + + companion object{ + + const val vocabName = "identity-class-ov" + + var vocab: LinkedHashSet = linkedSetOf( + "individual", "group", "system", + "organization", "class", "unspecified") + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.identityClass in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/IdentityRoles.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/IdentityRoles.kt new file mode 100644 index 0000000..28c79af --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/IdentityRoles.kt @@ -0,0 +1,36 @@ +package com.stephenott.stix.type.vocab + +class IdentityRoles(private val roles: LinkedHashSet = linkedSetOf(), enforceVocab: Boolean = false) : + Set by roles { + + init { + if (enforceVocab) { + roles.all { IdentityRole.vocab.contains(it.toString()) } + } + } +} + +class IdentityRole(private val role: String, enforceVocab: Boolean = false) : OpenVocab { + + override fun getValue(): String { + return role + } + + init { + if (enforceVocab) { + require(vocab.contains(role)) + } + } + + companion object { + + val vocabName = "identity-roles" + + var vocab: LinkedHashSet = linkedSetOf( + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/ImplementationLanguageOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/ImplementationLanguageOv.kt new file mode 100644 index 0000000..3964314 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/ImplementationLanguageOv.kt @@ -0,0 +1,35 @@ +package com.stephenott.stix.type.vocab + +class ImplementationLanguages(private val languages: LinkedHashSet = linkedSetOf()) : + Set by languages { +} + +class ImplementationLanguage(private val language: String) : OpenVocab { + + override fun getValue(): String { + return language + } + + companion object { + + const val vocabName = "implementation-language-ov" + + var vocab: LinkedHashSet = linkedSetOf( + "applescript", "bash", "c", + "c++", "c#,", "go", + "java", "javascript", "lua", + "objective-c", "perl", "php", + "powershell", "python", "ruby", + "scala", "swift", "typescript", + "visual-basic", "x86-32", "x86-64" + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.language in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/IndicatorTypeOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/IndicatorTypeOv.kt new file mode 100644 index 0000000..8540f8a --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/IndicatorTypeOv.kt @@ -0,0 +1,34 @@ +package com.stephenott.stix.type.vocab + +class IndicatorTypes(private val types: LinkedHashSet) : + Set by types { + + init { + require(types.size > 0) + } +} + +class IndicatorType(private val type: String) : OpenVocab { + override fun getValue(): String { + return type + } + + companion object { + + const val vocabName = "indicator-type-ov" + + var vocab: LinkedHashSet = linkedSetOf( + "anomalous-activity", "anonymization", "benign", + "compromised", "malicious-activity", "attribution", + "unknown" + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.type in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/IndustrySectorOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/IndustrySectorOv.kt new file mode 100644 index 0000000..068fbea --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/IndustrySectorOv.kt @@ -0,0 +1,37 @@ +package com.stephenott.stix.type.vocab + +class IndustrySectors(private val sectors: LinkedHashSet = linkedSetOf()) : + Set by sectors { +} + +class IndustrySector(private val sector: String) : OpenVocab { + + override fun getValue(): String { + return sector + } + + companion object { + + const val vocabName = "industry-sector-ov" + + var vocab: LinkedHashSet = linkedSetOf( + "agriculture", "aerospace", "automotive", + "communications", "construction", "defence", + "education", "energy", "entertainment", + "financial-services", "government-national", "government-regional", + "government-local", "government-public-services", "healthcare", + "hospitality-leisure", "infrastructure", "insurance", + "manufacturing", "mining", "non-profit", + "pharmaceuticals", "retail", "technology", + "telecommunications", "transportation", "utilities" + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.sector in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/InfrastructureTypeOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/InfrastructureTypeOv.kt new file mode 100644 index 0000000..80bf22b --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/InfrastructureTypeOv.kt @@ -0,0 +1,32 @@ +package com.stephenott.stix.type.vocab + +class InfrastructureTypes(private val types: LinkedHashSet = linkedSetOf()) : + Set by types { +} + +class InfrastructureType(private val type: String) : OpenVocab { + + override fun getValue(): String { + return type + } + + companion object { + + const val vocabName = "infrastructure-type-ov" + + var vocab: LinkedHashSet = linkedSetOf( + "amplification", "anonymization", "botnet", + "command-and-control", "exfiltration", "hosting-malware", + "hosting-target-lists", "phishing", "reconnaissance", + "staging", "undefined" + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.type in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/LanguageCodes.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/LanguageCodes.kt new file mode 100644 index 0000000..20189d8 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/LanguageCodes.kt @@ -0,0 +1,27 @@ +package com.stephenott.stix.type.vocab + +class LanguageCodes(private val codes: LinkedHashSet = linkedSetOf()) : + Set by codes { + + init { + //@TODO + } +} + +data class LanguageCode(private val code: String) : ClosedVocab { + override fun getValue(): String { + return code + } + + init { + require(LanguageCode.vocab.contains(code)) + } + + companion object { + const val vocabName = "iso-639-2-language-codes" + + val vocab: LinkedHashSet = linkedSetOf( + "en" //@TODO add rest of language codes + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/MalwareAvResultOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/MalwareAvResultOv.kt new file mode 100644 index 0000000..08e4821 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/MalwareAvResultOv.kt @@ -0,0 +1,28 @@ +package com.stephenott.stix.type.vocab + +class MalwareAvResults(private val results: LinkedHashSet = linkedSetOf()) : + Set by results { +} + +class MalwareAvResult(private val result: String) : OpenVocab { + override fun getValue(): String { + return result + } + + companion object { + const val vocabName = "malware-av-result-ov" + + var vocab: LinkedHashSet = linkedSetOf( + "malicious", "suspicious", "benign", + "unknown" + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.result in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/MalwareCapabilitiesOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/MalwareCapabilitiesOv.kt new file mode 100644 index 0000000..31d18a9 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/MalwareCapabilitiesOv.kt @@ -0,0 +1,41 @@ +package com.stephenott.stix.type.vocab + +class MalwareCapabilities(private val capabilities: LinkedHashSet = linkedSetOf()) : + Set by capabilities { +} + +class MalwareCapability(private val capability: String) : OpenVocab { + + override fun getValue(): String { + return capability + } + + companion object { + + const val vocabName = "malware-capabilities-ov" + + var vocab: LinkedHashSet = linkedSetOf( + "accesses-remote-machines", "anti-debugging", "anti-disassembly", + "anti-emulation", "anti-memory-forensics", "anti-sandbox", + "anti-vm", "captures-input-peripherals", "captures-output-peripherals", + "captures-system-state-data", "cleans-traces-of-infection", "commits-fraud", + "communicates-with-c2", "compromises-data-availability", "compromises-data-integrity", + "compromises-system-availability", "controls-local-machine", "degrades-security-software", + "degrades-system-updates", "determines-c2-server", "emails-spam", + "escalates-privileges", "evades-av", "exfiltrates-data", + "fingerprints-host", "hides-artifacts", "hides-executing-code", + "infects-files", "infects-remote-machines", "installs-other-components", + "persists-after-system-reboot", "prevents-artifact-access", "prevents-artifact-deletion", + "probes-network-environment", "self-modifies", "steals-authentication-credentials", + "violates-system-operational-integrity" + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.capability in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/MalwareTypeOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/MalwareTypeOv.kt new file mode 100644 index 0000000..b4db5a1 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/MalwareTypeOv.kt @@ -0,0 +1,36 @@ +package com.stephenott.stix.type.vocab + +class MalwareTypes(private val types: LinkedHashSet = linkedSetOf()) : + Set by types { +} + +class MalwareType(private val type: String) : OpenVocab { + + override fun getValue(): String { + return type + } + + companion object { + + const val vocabName = "malware-type-ov" + + var vocab: LinkedHashSet = linkedSetOf( + "adware", "backdoor", "bot", + "bootkit", "ddos", "downloader", + "dropper", "exploit-kit", "keylogger", + "ransomware", "remote-access-trojan", "resource-exploitation", + "rogue-security-software", "rootkit", "screen-capture", + "spyware", "trojan", "unknown", + "virus", "webshell", "wiper", + "worm" + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.type in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/MarkingDefinitionTypeOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/MarkingDefinitionTypeOv.kt new file mode 100644 index 0000000..2ad1886 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/MarkingDefinitionTypeOv.kt @@ -0,0 +1,23 @@ +package com.stephenott.stix.type.vocab + +data class MarkingDefinitionTypeOv(private val definitionType: String): OpenVocab { + override fun getValue(): String { + return definitionType + } + + companion object{ + + const val vocabName = "marking-definition-type-ov" + + var vocab: LinkedHashSet = linkedSetOf( + "statement", "tlp") + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.definitionType in vocab, lazyMessage = {"Marking Definition is using a unsupported definition_type"}) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/NetworkSocketAddressFamilyEnum.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/NetworkSocketAddressFamilyEnum.kt new file mode 100644 index 0000000..8cf6ce5 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/NetworkSocketAddressFamilyEnum.kt @@ -0,0 +1,22 @@ +package com.stephenott.stix.type.vocab + +class NetworkSocketAddressFamilyEnum(private val addressFamily: String) : ClosedVocab { + + override fun getValue(): String { + return addressFamily + } + + companion object { + const val vocabName = "network-socket-address-family-enum" + + val vocab: LinkedHashSet = linkedSetOf( + "AF_UNSPEC", "AF_INET", "AF_IPX", + "AF_APPLETALK", "AF_NETBIOS", "AF_INET6", + "AF_IRDA", "AF_BTH" + ) + } + + init { + require(this.addressFamily in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/NetworkSocketTypeEnum.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/NetworkSocketTypeEnum.kt new file mode 100644 index 0000000..b43b6af --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/NetworkSocketTypeEnum.kt @@ -0,0 +1,21 @@ +package com.stephenott.stix.type.vocab + +class NetworkSocketTypeEnum(private val type: String) : ClosedVocab { + + override fun getValue(): String { + return type + } + + companion object { + const val vocabName = "network-socket-type-enum" + + val vocab: LinkedHashSet = linkedSetOf( + "SOCK_STREAM", "AF_ISOCK_DGRAMNET", "SOCK_RAW", + "SOCK_RDM", "SOCK_SEQPACKET" + ) + } + + init { + require(this.type in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/OpenVocab.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/OpenVocab.kt new file mode 100644 index 0000000..94c1cad --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/OpenVocab.kt @@ -0,0 +1,6 @@ +package com.stephenott.stix.type.vocab + +interface OpenVocab { + fun getValue(): String + +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/OpinionEnum.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/OpinionEnum.kt new file mode 100644 index 0000000..73e9469 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/OpinionEnum.kt @@ -0,0 +1,25 @@ +package com.stephenott.stix.type.vocab + +class OpinionEnum(private val opinion: String) : ClosedVocab { + override fun getValue(): String { + return opinion + } + + companion object { + + const val vocabName = "opinion-enum" + + var vocab: LinkedHashSet = linkedSetOf( + "strongly-disagree", "disagree", + "neutral", "agree", "strongly-agree" + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.opinion in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/PatternTypes.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/PatternTypes.kt new file mode 100644 index 0000000..03a18cc --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/PatternTypes.kt @@ -0,0 +1,21 @@ +package com.stephenott.stix.type.vocab + +class PatternType(private val type: String) : ClosedVocab { + + override fun getValue(): String { + return type + } + + companion object { + + const val vocabName = "pattern-type" //@TODO + + val vocab: LinkedHashSet = linkedSetOf( + "stix", "snort", "yara" + ) + } + + init { + require(this.type in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/ProcessorArchitectureOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/ProcessorArchitectureOv.kt new file mode 100644 index 0000000..001d701 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/ProcessorArchitectureOv.kt @@ -0,0 +1,31 @@ +package com.stephenott.stix.type.vocab + +class ProcessorArchitectures(private val architectures: LinkedHashSet = linkedSetOf()) : + Set by architectures { +} + +class ProcessorArchitecture(private val architecture: String) : OpenVocab { + + override fun getValue(): String { + return architecture + } + + companion object { + + const val vocabName = "processor-architecture-ov" + + var vocab: LinkedHashSet = linkedSetOf( + "alpha", "arm", "ia-64", + "mips", "powerpc", "sparc", + "x86", "x86-64" + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.architecture in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/RegionOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/RegionOv.kt new file mode 100644 index 0000000..119aaed --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/RegionOv.kt @@ -0,0 +1,28 @@ +package com.stephenott.stix.type.vocab + +class RegionOv(private val region: String) : ClosedVocab { + + override fun getValue(): String { + return region + } + + companion object { + const val vocabName = "region-ov" + + val vocab: LinkedHashSet = linkedSetOf( + "africa", "eastern-africa", "middle-africa", + "northern-africa", "southern-africa", "western-africa", + "americas", "latin-america-caribbean", "south-america", + "caribbean", "central-america", "northern-america", + "asia", "central-asia", "eastern-asia", + "southern-asia", "western-asia", "europe", + "eastern-europe", "northern-europe", "southern-europe", + "western-europe", "oceania", "australia-new-zealand", + "melanesia", "micronesia", "polynesia", "antarctica" + ) + } + + init { + require(this.region in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/ReportTypeOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/ReportTypeOv.kt new file mode 100644 index 0000000..40a32b8 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/ReportTypeOv.kt @@ -0,0 +1,31 @@ +package com.stephenott.stix.type.vocab + +class ReportTypes(private val types: LinkedHashSet = linkedSetOf()) : + Set by types { +} + +class ReportType(private val type: String) : OpenVocab { + override fun getValue(): String { + return type + } + + companion object { + + const val vocabName = "report-type-ov" + + var vocab: LinkedHashSet = linkedSetOf( + "attack-pattern", "campaign", "identity", + "indicator", "intrusion-set", "malware", + "observed-data", "threat-actor", "threat-report", + "tool", "vulnerability" + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.type in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/ThreatActorRoleOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/ThreatActorRoleOv.kt new file mode 100644 index 0000000..706a60b --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/ThreatActorRoleOv.kt @@ -0,0 +1,31 @@ +package com.stephenott.stix.type.vocab + +class ThreatActorRoles(private val roles: LinkedHashSet = linkedSetOf()) : + Set by roles { +} + +class ThreatActorRole(private val role: String) : OpenVocab { + + override fun getValue(): String { + return role + } + + companion object { + + const val vocabName = "threat-actor-role-ov" + + var vocab: LinkedHashSet = linkedSetOf( + "agent", "director", "independent", + "infrastructure-architect", "infrastructure-operator", "malware-author", + "sponsor" + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.role in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/ThreatActorSophisticationOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/ThreatActorSophisticationOv.kt new file mode 100644 index 0000000..d4c74cd --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/ThreatActorSophisticationOv.kt @@ -0,0 +1,27 @@ +package com.stephenott.stix.type.vocab + +class ThreatActorSophisticationOv(private val sophistication: String) : OpenVocab { + + override fun getValue(): String { + return sophistication + } + + companion object { + + const val vocabName = "threat-actor-sophistication" + + var vocab: LinkedHashSet = linkedSetOf( + "none", "minimal", "intermediate", + "advanced", "expert", "innovator", + "strategic" + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.sophistication in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/ThreatActorTypeOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/ThreatActorTypeOv.kt new file mode 100644 index 0000000..7ebb991 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/ThreatActorTypeOv.kt @@ -0,0 +1,32 @@ +package com.stephenott.stix.type.vocab + +class ThreatActorTypes(private val types: LinkedHashSet = linkedSetOf()) : + Set by types { +} + +class ThreatActorType(private val type: String) : OpenVocab { + + override fun getValue(): String { + return type + } + + companion object { + + const val vocabName = "threat-actor-type-ov" + + var vocab: LinkedHashSet = linkedSetOf( + "activist", "competitor", "crime-syndicate", + "criminal", "hacker", "insider-accidental", + "insider-disgruntled", "nation-state", "sensationalist", + "spy", "terrorist", "unknown" + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.type in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/ToolTypeOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/ToolTypeOv.kt new file mode 100644 index 0000000..3e343e5 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/ToolTypeOv.kt @@ -0,0 +1,28 @@ +package com.stephenott.stix.type.vocab + +class ToolTypes(private val types: LinkedHashSet = linkedSetOf()) : + Set by types { +} + +class ToolType(private val type: String) : OpenVocab { + + override fun getValue(): String { + return type + } + + companion object { + var vocab: LinkedHashSet = linkedSetOf( + "denial-of-service", "exploitation", "information-gathering", + "network-capture", "credential-exploitation", "remote-access", + "vulnerability-scanning", "unknown" + ) + set(value) { + require(value.isNotEmpty()) + field = value + } + } + + init { + require(this.type in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsIntegrityLevelEnum.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsIntegrityLevelEnum.kt new file mode 100644 index 0000000..5a6afc0 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsIntegrityLevelEnum.kt @@ -0,0 +1,20 @@ +package com.stephenott.stix.type.vocab + +class WindowsIntegrityLevelEnum(private val level: String) : ClosedVocab { + override fun getValue(): String { + return level + } + + companion object { + const val vocabName = "windows-integrity-level-enum" + + val vocab: LinkedHashSet = linkedSetOf( + "low", "medium", "high", + "system" + ) + } + + init { + require(this.level in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsPebinaryTypeOv.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsPebinaryTypeOv.kt new file mode 100644 index 0000000..e539cc1 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsPebinaryTypeOv.kt @@ -0,0 +1,20 @@ +package com.stephenott.stix.type.vocab + +class WindowsPebinaryTypeOv(private val type: String) : ClosedVocab { + + override fun getValue(): String { + return type + } + + companion object { + const val vocabName = "windows-pebinary-type-ov" + + val vocab: LinkedHashSet = linkedSetOf( + "dll", "exe", "sys" + ) + } + + init { + require(this.type in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsRegistryDataTypeEnum.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsRegistryDataTypeEnum.kt new file mode 100644 index 0000000..300bb45 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsRegistryDataTypeEnum.kt @@ -0,0 +1,24 @@ +package com.stephenott.stix.type.vocab + +class WindowsRegistryDataTypeEnum(private val datatype: String) : ClosedVocab { + + override fun getValue(): String { + return datatype + } + + companion object { + const val vocabName = "windows-registry-datatype-enum" + + val vocab: LinkedHashSet = linkedSetOf( + "REG_NONE", "REG_SZ", "REG_EXPAND_SZ", + "REG_BINARY", "REG_DWORD", "REG_DWORD_BIG_ENDIAN", + "REG_DWORD_LITTLE_ENDIAN", "REG_LINK", "REG_MULTI_SZ", + "REG_RESOURCE_LIST", "REG_FULL_RESOURCE_DESCRIPTION", "REG_RESOURCE_REQUIREMENTS_LIST", + "REG_QWORD", "REG_INVALID_TYPE" + ) + } + + init { + require(this.datatype in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsServiceStartTypeEnum.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsServiceStartTypeEnum.kt new file mode 100644 index 0000000..8ee9190 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsServiceStartTypeEnum.kt @@ -0,0 +1,21 @@ +package com.stephenott.stix.type.vocab + +class WindowsServiceStartTypeEnum(private val type: String) : ClosedVocab { + + override fun getValue(): String { + return type + } + + companion object { + const val vocabName = "windows-service-start-type-enum" + + val vocab: LinkedHashSet = linkedSetOf( + "SERVICE_AUTO_START", "SERVICE_BOOT_START", "SERVICE_DEMAND_START", + "SERVICE_DISABLED", "SERVICE_SYSTEM_ALERT" + ) + } + + init { + require(this.type in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsServiceStatusEnum.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsServiceStatusEnum.kt new file mode 100644 index 0000000..a4b4138 --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsServiceStatusEnum.kt @@ -0,0 +1,22 @@ +package com.stephenott.stix.type.vocab + +class WindowsServiceStatusEnum(private val status: String) : ClosedVocab { + + override fun getValue(): String { + return status + } + + companion object { + const val vocabName = "windows-service-status-enum" + + val vocab: LinkedHashSet = linkedSetOf( + "SERVICE_CONTINUE_PENDING", "SERVICE_PAUSE_PENDING", "SERVICE_PAUSED", + "SERVICE_RUNNING", "SERVICE_START_PENDING", "SERVICE_STOP_PENDING", + "SERVICE_STOPPED" + ) + } + + init { + require(this.status in vocab) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsServiceTypeEnum.kt b/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsServiceTypeEnum.kt new file mode 100644 index 0000000..06ee28b --- /dev/null +++ b/src/main/kotlin/com/stephenott/stix/type/vocab/WindowsServiceTypeEnum.kt @@ -0,0 +1,21 @@ +package com.stephenott.stix.type.vocab + +class WindowsServiceTypeEnum(private val type: String) : ClosedVocab { + + override fun getValue(): String { + return type + } + + companion object { + const val vocabName = "windows-service-type-enum" + + val vocab: LinkedHashSet = linkedSetOf( + "SERVICE_KERNEL_DRIVER", "SERVICE_FILE_SYSTEM_DRIVER", "SERVICE_WIN32_OWN_PROCESS", + "SERVICE_WIN32_SHARE_PROCESS" + ) + } + + init { + require(this.type in vocab) + } +} \ No newline at end of file diff --git a/src/test/groovy/faker/StixMockDataGenerator.groovy b/src/test/groovy/faker/StixMockDataGenerator.groovy deleted file mode 100644 index d4a90d4..0000000 --- a/src/test/groovy/faker/StixMockDataGenerator.groovy +++ /dev/null @@ -1,2983 +0,0 @@ -package faker - -import faker.configs.ObservedDataGeneratorConfig -import io.digitalstate.stix.bundle.Bundle -import io.digitalstate.stix.bundle.BundleableObject -import io.digitalstate.stix.common.StixBoolean -import io.digitalstate.stix.common.StixInstant -import io.digitalstate.stix.coo.extension.types.* -import io.digitalstate.stix.coo.objects.* -import io.digitalstate.stix.coo.types.* -import io.digitalstate.stix.datamarkings.GranularMarking -import io.digitalstate.stix.datamarkings.MarkingDefinition -import io.digitalstate.stix.datamarkings.objects.Statement -import io.digitalstate.stix.datamarkings.objects.Tlp -import io.digitalstate.stix.sdo.DomainObject -import io.digitalstate.stix.sdo.objects.* -import io.digitalstate.stix.sdo.types.* -import io.digitalstate.stix.sro.objects.* -import io.digitalstate.stix.vocabulary.vocabularies.* -import net.andreinc.mockneat.MockNeat - -import java.time.Instant -import java.time.LocalDate -import java.util.concurrent.ThreadLocalRandom - -public class StixMockDataGenerator { - - // MockNeat object - MockNeat mock = MockNeat.threadLocal() - - - Instant commonLowerDate = Instant.ofEpochMilli(LocalDate.of(2000, 1, 1).toEpochDay()) - - Instant generateRandomDate(Instant lower, Instant upper){ - return Instant.ofEpochMilli(ThreadLocalRandom.current() - .longs(lower.toEpochMilli(), upper.toEpochMilli()) - .findAny() - .getAsLong()) - } - - // - // Mocks and Generators: - // - - /** - * Generates a random set of single word labels - * @return - */ - Set generateRandomLabels() { - Set labels = new HashSet<>() - - mock.ints().range(1, 20).get().times { - labels.add(mock.words().get()) - } - return labels - } - - /** - * Generate a random Map of Custom Properties - * @return - */ - Map generateCustomProperties() { - - Map customProperties = new HashMap<>() - - mock.ints().range(0, 20).get().times { - String key = mock.words().prepend("x_").get() - switch (mock.ints().range(0, 5).get()) { - case 0: - customProperties.put(key, mock.words().get()) - break - case 1: - customProperties.put(key, mock.words().accumulate(mock.ints().range(1, 100).get(), " ").get()) - break - case 2: - customProperties.put(key, mock.ints().range(0, 999999).get()) - break - case 3: - customProperties.put(key, mock.doubles().range(0.0, 999999.0).get()) - break - case 4: - customProperties.put(key, mock.bools().probability(50).get()) - break - case 5: - HashMap map1 = new HashMap<>() - mock.ints().range(1, 30).get().times { - map1.put(mock.words().get(), mock.words().accumulate(mock.ints().range(1, 10).get(), " ").get()) - } - customProperties.put(key, map1) - break - } - } - return customProperties - } - - - /** - * Generate a random KillChain Phase - * @return - */ - KillChainPhase mockKillChainPhase() { - return KillChainPhase.builder() - .killChainName(mock.words().accumulate(mock.ints().range(1, 5).get(), "-").get()) - .phaseName(mock.words().accumulate(mock.ints().range(1, 5).get(), " ").get()) - .build() - } - - /** - * Generate a random External Reference - * @return - */ - ExternalReference mockExternalReference() { - ExternalReference.Builder builder = ExternalReference.builder() - .sourceName(mock.words().get()) - - if (mock.bools().probability(50).get()) { - builder.description(mock.words().accumulate(mock.ints().range(1, 100).get(), " ").get()) - } - - if (mock.bools().probability(50).get()) { - builder.url(mock.urls().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("MD5", mock.hashes().md5().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-256", mock.hashes().sha256().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-512", mock.hashes().sha512().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-1", mock.hashes().sha1().get()) - } - - if (mock.bools().probability(50).get()) { - builder.externalId(mock.uuids().get()) - } - - return builder.build() - } - - /** - * Generate a random Attack pattern - * @return - */ - AttackPattern mockAttackPattern() { - AttackPattern.Builder builder = AttackPattern.builder() - .name(mock.words().accumulate(mock.ints().range(1, 5).get(), " ").get()) - - Instant objectCreated = generateRandomDate(commonLowerDate, Instant.now()) - builder.created(new StixInstant(objectCreated)) - - if (mock.bools().probability(50).get()) { - builder.modified(new StixInstant(generateRandomDate(commonLowerDate, objectCreated))) - } - - if (mock.bools().probability(50).get()) { - builder.description(mock.words().accumulate(mock.ints().range(1, 50).get(), " ").get()) - } - - if (mock.bools().probability(50).get()) { - builder.description(mock.words().accumulate(mock.ints().range(1, 50).get(), " ").get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 15).get().times { - builder.addKillChainPhase(mockKillChainPhase()) - } - } - - if (mock.bools().probability(50).get()) { - builder.addAllLabels(generateRandomLabels()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 10).get().times { - builder.addExternalReferences(mockExternalReference()) - } - } - - if (mock.bools().probability(50).get()) { - builder.revoked(new StixBoolean(true)) - } - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - if (mock.bools().probability(50).get()) { - builder.createdByRef(mockIdentity()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addObjectMarkingRef(mockMarkingDefinition()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addGranularMarking(mockGranularMarking()) - } - } - - return builder.build() - } - - /** - * Generate a random Campaign - * @return - */ - Campaign mockCampaign() { - Campaign.Builder builder = Campaign.builder() - .name(mock.words().accumulate(mock.ints().range(1, 5).get(), "-").get()) - - Instant objectCreated = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.created(new StixInstant(objectCreated)) - if (mock.bools().probability(50).get()) { - builder.modified(new StixInstant(generateRandomDate(objectCreated, Instant.now()))) - } - } - - if (mock.bools().probability(50).get()) { - builder.description(mock.words().accumulate(mock.ints().range(1, 50).get(), " ").get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 5).get().times { - builder.addAliase(mock.words().accumulate(mock.ints().range(1, 5).get(), "-").get()) - } - } - - Instant firstSeen = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.firstSeen(new StixInstant(firstSeen)) - } - - if (mock.bools().probability(50).get()) { - builder.lastSeen(new StixInstant(generateRandomDate(firstSeen, Instant.now()))) - } - - if (mock.bools().probability(50).get()) { - builder.objective(mock.words().accumulate(mock.ints().range(1, 50).get(), " ").get()) - } - - if (mock.bools().probability(50).get()) { - builder.addAllLabels(generateRandomLabels()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 10).get().times { - builder.addExternalReferences(mockExternalReference()) - } - } - - if (mock.bools().probability(50).get()) { - builder.revoked(new StixBoolean(true)) - } - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - if (mock.bools().probability(50).get()) { - builder.createdByRef(mockIdentity()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addObjectMarkingRef(mockMarkingDefinition()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addGranularMarking(mockGranularMarking()) - } - } - - return builder.build() - } - - /** - * Generate a random Course of Action - * @return - */ - CourseOfAction mockCourseOfAction() { - CourseOfAction.Builder builder = CourseOfAction.builder() - .name(mock.words().accumulate(mock.ints().range(1, 5).get(), "-").get()) - - Instant objectCreated = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.created(new StixInstant(objectCreated)) - if (mock.bools().probability(50).get()) { - builder.modified(new StixInstant(generateRandomDate(objectCreated, Instant.now()))) - } - } - - if (mock.bools().probability(50).get()) { - builder.description(mock.words().accumulate(mock.ints().range(1, 50).get(), " ").get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 10).get().times { - builder.addAction(mock.words().accumulate(mock.ints().range(1, 30).get(), " ").get()) - } - } - - if (mock.bools().probability(50).get()) { - builder.addAllLabels(generateRandomLabels()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 10).get().times { - builder.addExternalReferences(mockExternalReference()) - } - } - - if (mock.bools().probability(50).get()) { - builder.revoked(new StixBoolean(true)) - } - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - if (mock.bools().probability(50).get()) { - builder.createdByRef(mockIdentity()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addObjectMarkingRef(mockMarkingDefinition()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addGranularMarking(mockGranularMarking()) - } - } - - return builder.build() - } - - /** - * Generate a random Identity - * @return - */ - Identity mockIdentity() { - Identity.Builder builder = Identity.builder() - .name(mock.names().full(33.33).get()) - - Instant objectCreated = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.created(new StixInstant(objectCreated)) - if (mock.bools().probability(50).get()) { - builder.modified(new StixInstant(generateRandomDate(objectCreated, Instant.now()))) - } - } - - if (mock.bools().probability(50).get()) { - builder.description(mock.words().accumulate(mock.ints().range(1, 50).get(), " ").get()) - } - - builder.identityClass(mock.fromStrings(new IdentityClasses().getAllTerms().toList()).get()) - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addSector(mock.fromStrings(new IndustrySectors().getAllTerms().toList()).get()) - } - } - - if (mock.bools().probability(50).get()) { - builder.contactInformation("${mock.emails().get()} ${mock.departments().get()}") - } - - if (mock.bools().probability(50).get()) { - builder.addAllLabels(generateRandomLabels()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 10).get().times { - builder.addExternalReferences(mockExternalReference()) - } - } - - if (mock.bools().probability(50).get()) { - builder.revoked(new StixBoolean(true)) - } - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addObjectMarkingRef(mockMarkingDefinition()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addGranularMarking(mockGranularMarking()) - } - } - - //Note does not test against .createdByRef() to prevent possible recursion - - return builder.build() - } - - Indicator mockIndicator() { - Indicator.Builder builder = Indicator.builder() - - Instant objectCreated = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.created(new StixInstant(objectCreated)) - if (mock.bools().probability(50).get()) { - builder.modified(new StixInstant(generateRandomDate(objectCreated, Instant.now()))) - } - } - - builder.addLabel(mock.fromStrings(new IndicatorLabels().getAllTerms().toList()).get()) - - if (mock.bools().probability(50).get()) { - builder.name(mock.words().accumulate(mock.ints().range(1, 5).get(), "-").get()) - } - - if (mock.bools().probability(50).get()) { - builder.description(mock.words().accumulate(mock.ints().range(1, 50).get(), " ").get()) - } - - builder.pattern("SOME PATTERN GOES HERE") - - Instant validFrom = generateRandomDate(commonLowerDate, Instant.now()) - builder.validFrom(new StixInstant(validFrom)) - - if (mock.bools().probability(50).get()) { - builder.validUntil(new StixInstant(generateRandomDate(validFrom, Instant.now()))) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 15).get().times { - builder.addKillChainPhase(mockKillChainPhase()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 10).get().times { - builder.addExternalReferences(mockExternalReference()) - } - } - - if (mock.bools().probability(50).get()) { - builder.revoked(new StixBoolean(true)) - } - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - if (mock.bools().probability(50).get()) { - builder.createdByRef(mockIdentity()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addObjectMarkingRef(mockMarkingDefinition()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addGranularMarking(mockGranularMarking()) - } - } - - return builder.build() - } - - IntrusionSet mockIntrusionSet() { - IntrusionSet.Builder builder = IntrusionSet.builder() - - Instant objectCreated = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.created(new StixInstant(objectCreated)) - if (mock.bools().probability(50).get()) { - builder.modified(new StixInstant(generateRandomDate(objectCreated, Instant.now()))) - } - } - - builder.name(mock.words().accumulate(mock.ints().range(1, 5).get(), "-").get()) - - if (mock.bools().probability(50).get()) { - builder.description(mock.words().accumulate(mock.ints().range(1, 50).get(), " ").get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 5).get().times { - builder.addAliase(mock.words().accumulate(mock.ints().range(1, 5).get(), "-").get()) - } - } - - Instant firstSeen = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.firstSeen(new StixInstant(firstSeen)) - } - - if (mock.bools().probability(50).get()) { - builder.lastSeen(new StixInstant(generateRandomDate(firstSeen, Instant.now()))) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 15).get().times { - builder.addGoal(mock.words().accumulate(mock.ints().range(1, 10).get(), " ").get()) - } - } - - if (mock.bools().probability(50).get()) { - builder.resourceLevel(mock.fromStrings(new AttackResourceLevels().getAllTerms().toList()).get()) - } - - if (mock.bools().probability(50).get()) { - builder.primaryMotivation(mock.fromStrings(new AttackMotivations().getAllTerms().toList()).get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addSecondaryMotivation(mock.fromStrings(new AttackMotivations().getAllTerms().toList()).get()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 10).get().times { - builder.addExternalReferences(mockExternalReference()) - } - } - - if (mock.bools().probability(50).get()) { - builder.revoked(new StixBoolean(true)) - } - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - if (mock.bools().probability(50).get()) { - builder.createdByRef(mockIdentity()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addObjectMarkingRef(mockMarkingDefinition()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addGranularMarking(mockGranularMarking()) - } - } - - return builder.build() - } - - Malware mockMalware() { - Malware.Builder builder = Malware.builder() - - Instant objectCreated = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.created(new StixInstant(objectCreated)) - if (mock.bools().probability(50).get()) { - builder.modified(new StixInstant(generateRandomDate(objectCreated, Instant.now()))) - } - } - - builder.addLabel(mock.fromStrings(new MalwareLabels().getAllTerms().toList()).get()) - - builder.name(mock.words().accumulate(mock.ints().range(1, 5).get(), "-").get()) - - if (mock.bools().probability(50).get()) { - builder.description(mock.words().accumulate(mock.ints().range(1, 50).get(), " ").get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 15).get().times { - builder.addKillChainPhase(mockKillChainPhase()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 10).get().times { - builder.addExternalReferences(mockExternalReference()) - } - } - - if (mock.bools().probability(50).get()) { - builder.revoked(new StixBoolean(true)) - } - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - if (mock.bools().probability(50).get()) { - builder.createdByRef(mockIdentity()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addObjectMarkingRef(mockMarkingDefinition()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addGranularMarking(mockGranularMarking()) - } - } - - return builder.build() - } - - ObservedData mockObservedData(ObservedDataGeneratorConfig config = new ObservedDataGeneratorConfig()) { - ObservedData.Builder builder = ObservedData.builder() - - Instant objectCreated = generateRandomDate(config.propCreatedLowerDate, config.propCreatedUpperDate) - if (mock.bools().probability(config.propCreatedProbability).get()) { - builder.created(new StixInstant(objectCreated, config.propCreatedDateSubsecondPrecision)) - if (mock.bools().probability(config.propModifiedProbability).get()) { - builder.modified(new StixInstant(generateRandomDate(objectCreated, config.propModifiedUpperDate), config.propModifiedSubsecondPrecision)) - } - } - - Instant firstObserved = generateRandomDate(config.propFirstObservedLowerDate, config.propFirstObservedUpperDate) - builder.firstObserved(new StixInstant(firstObserved, config.propFirstObservedSubsecondPrecision)) - - builder.lastObserved(new StixInstant(generateRandomDate(firstObserved, config.propLastObservedUpperDate), config.propLastObservedSubsecondPrecision)) - - builder.numberObserved(mock.ints().range(config.propNumberObservedLowerCount, config.propNumberObservedUpperCount).get()) - - - if (mock.bools().probability(config.artifactCoo.occurrence_probability).get()) { - mock.ints().range(config.artifactCoo.occurs_count_lower, config.artifactCoo.occurs_count_upper).get().times { - builder.addObject(mockArtifactCoo()) - } - } - - if (mock.bools().probability(config.autonomousSystemCoo.occurrence_probability).get()) { - mock.ints().range(config.autonomousSystemCoo.occurs_count_lower, config.autonomousSystemCoo.occurs_count_upper).get().times { - builder.addObject(mockAutonomousSystemCoo()) - } - } - - if (mock.bools().probability(config.directoryCoo.occurrence_probability).get()) { - mock.ints().range(config.directoryCoo.occurs_count_lower, config.directoryCoo.occurs_count_upper).get().times { - builder.addObject(mockDirectoryCoo()) - } - } - - if (mock.bools().probability(config.domainNameCoo.occurrence_probability).get()) { - mock.ints().range(config.domainNameCoo.occurs_count_lower, config.domainNameCoo.occurs_count_upper).get().times { - builder.addObject(mockDomainNameCoo()) - } - } - - if (mock.bools().probability(config.emailAddressCoo.occurrence_probability).get()) { - mock.ints().range(config.emailAddressCoo.occurs_count_lower, config.emailAddressCoo.occurs_count_upper).get().times { - builder.addObject(mockEmailAddressCoo()) - } - } - - //@TODO Refactor to pass in Email address objects and artifacts - if (mock.bools().probability(config.emailMessageCoo.occurrence_probability).get()) { - mock.ints().range(config.emailMessageCoo.occurs_count_lower, config.emailMessageCoo.occurs_count_upper).get().times { - builder.addObject(mockEmailMessageCoo()) - } - } - - if (mock.bools().probability(config.fileCoo.occurrence_probability).get()) { - mock.ints().range(config.fileCoo.occurs_count_lower, config.fileCoo.occurs_count_upper).get().times { - builder.addObject(mockFileCoo()) - } - } - - if (mock.bools().probability(config.ipv4AddressCoo.occurrence_probability).get()) { - mock.ints().range(config.ipv4AddressCoo.occurs_count_lower, config.ipv4AddressCoo.occurs_count_upper).get().times { - builder.addObject(mockIpv4AddressCoo()) - } - } - - if (mock.bools().probability(config.ipv6AddressCoo.occurrence_probability).get()) { - mock.ints().range(config.ipv6AddressCoo.occurs_count_lower, config.ipv6AddressCoo.occurs_count_upper).get().times { - builder.addObject(mockIpv6AddressCoo()) - } - } - - if (mock.bools().probability(config.macAddressCoo.occurrence_probability).get()) { - mock.ints().range(config.macAddressCoo.occurs_count_lower, config.macAddressCoo.occurs_count_upper).get().times { - builder.addObject(mockMacAddress()) - } - } - - if (mock.bools().probability(config.mutexCoo.occurrence_probability).get()) { - mock.ints().range(config.mutexCoo.occurs_count_lower, config.mutexCoo.occurs_count_upper).get().times { - builder.addObject(mockMutexCoo()) - } - } - - if (mock.bools().probability(config.networkTrafficCoo.occurrence_probability).get()) { - mock.ints().range(config.networkTrafficCoo.occurs_count_lower, config.networkTrafficCoo.occurs_count_upper).get().times { - builder.addObject(mockNetworkTrafficCoo()) - } - } - - if (mock.bools().probability(config.processCoo.occurrence_probability).get()) { - mock.ints().range(config.processCoo.occurs_count_lower, config.processCoo.occurs_count_upper).get().times { - builder.addObject(mockProcessCoo()) - } - } - - if (mock.bools().probability(config.softwareCoo.occurrence_probability).get()) { - mock.ints().range(config.softwareCoo.occurs_count_lower, config.softwareCoo.occurs_count_upper).get().times { - builder.addObject(mockSoftwareCoo()) - } - } - - if (mock.bools().probability(config.urlCoo.occurrence_probability).get()) { - mock.ints().range(config.urlCoo.occurs_count_lower, config.urlCoo.occurs_count_upper).get().times { - builder.addObject(mockUrlCoo()) - } - } - - if (mock.bools().probability(config.userAccountCoo.occurrence_probability).get()) { - mock.ints().range(config.userAccountCoo.occurs_count_lower, config.userAccountCoo.occurs_count_upper).get().times { - builder.addObject(mockUserAccountCoo()) - } - } - - if (mock.bools().probability(config.windowsRegisteryKeyCoo.occurrence_probability).get()) { - mock.ints().range(config.windowsRegisteryKeyCoo.occurs_count_lower, config.windowsRegisteryKeyCoo.occurs_count_upper).get().times { - builder.addObject(mockWindowsRegistryKeyCoo()) - } - } - - if (mock.bools().probability(config.x509CertificateCoo.occurrence_probability).get()) { - mock.ints().range(config.x509CertificateCoo.occurs_count_lower, config.x509CertificateCoo.occurs_count_upper).get().times { - builder.addObject(mockX509CertificateCoo()) - } - } - - - if (mock.bools().probability(config.externalReferences.occurrence_probability).get()) { - mock.ints().range(config.externalReferences.occurs_count_lower, config.externalReferences.occurs_count_upper).get().times { - builder.addExternalReferences(mockExternalReference()) - } - } - - if (mock.bools().probability(config.propRevokedProbability).get()) { - builder.revoked(new StixBoolean(true)) - } - - if (mock.bools().probability(config.propCustomPropsProbability).get()) { - builder.customProperties(generateCustomProperties()) - } - - if (mock.bools().probability(config.propCreatedByRefProbability).get()) { - builder.createdByRef(mockIdentity()) - } - - if (mock.bools().probability(config.objectMarkings.occurrence_probability).get()) { - mock.ints().range(config.objectMarkings.occurs_count_lower, config.objectMarkings.occurs_count_upper).get().times { - builder.addObjectMarkingRef(mockMarkingDefinition()) - } - } - - if (mock.bools().probability(config.granularMarkings.occurrence_probability).get()) { - mock.ints().range(config.granularMarkings.occurs_count_lower, config.granularMarkings.occurs_count_upper).get().times { - builder.addGranularMarking(mockGranularMarking()) - } - } - - if (mock.bools().probability(config.labelsOccurrenceProbability).get()) { - builder.labels(generateRandomLabels()) - } - - return builder.build() - } - - // Cyber Observables - - Artifact mockArtifactCoo() { - Artifact.Builder builder = Artifact.builder() - - if (mock.bools().probability(50).get()) { - builder.mimeType(mock.mimes().get()) - } - - if (mock.bools().probability(50).get()) { - builder.payloadBin(mock.words().accumulate(mock.ints().range(1, 5).get(), " ").get()) - } else { - builder.url(mock.urls().get()) - builder.putHash("SHA-256", mock.hashes().sha256().get()) - - if (mock.bools().probability(33.33).get()) { - builder.putHash("SHA-1", mock.hashes().sha1().get()) - } - - if (mock.bools().probability(33.33).get()) { - builder.putHash("MD5", mock.hashes().md5().get()) - } - } - - return builder.build() - } - - AutonomousSystem mockAutonomousSystemCoo() { - AutonomousSystem.Builder builder = AutonomousSystem.builder() - - builder.number(mock.longs().get()) - - if (mock.bools().probability(50).get()) { - builder.name(mock.words().accumulate(mock.ints().range(1, 5).get(), "-").get()) - } - - if (mock.bools().probability(50).get()) { - builder.rir(mock.words().accumulate(mock.ints().range(1, 5).get(), "-").get()) - } - - return builder.build() - } - - Directory mockDirectoryCoo() { - Directory.Builder builder = Directory.builder() - - builder.path(mock.words().accumulate(mock.ints().range(1, 5).get(), "/").get()) - - if (mock.bools().probability(50).get()) { - builder.pathEnc("csASCII") - } - - Instant created = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.created(new StixInstant(created)) - } - - Instant modified = generateRandomDate(created, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.modified(new StixInstant(modified)) - } - - if (mock.bools().probability(50).get()) { - builder.accessed(new StixInstant(generateRandomDate(created, Instant.now()))) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - if (mock.bools().probability(50).get()) { - builder.addContainsRef(mockFileCoo().getObservableObjectKey()) - } else { - //@TODO add support for contains_refs with directories - // This will require that Creating a Directory COO has a param to - // set where other Contains refs are generated so a endless cannot happen. - } - } - } - - return builder.build() - } - - DomainName mockDomainNameCoo() { - DomainName.Builder builder = DomainName.builder() - - builder.value(mock.domains().get()) - - //@TODO Add resolves_to_refs mocking - - return builder.build() - } - - EmailAddress mockEmailAddressCoo() { - EmailAddress.Builder builder = EmailAddress.builder() - - builder.value(mock.emails().get()) - - if (mock.bools().probability(50).get()) { - builder.displayName(mock.names().full(33.33).get()) - } - - //@TODO Add belongs_to_ref mocking - - return builder.build() - } - - EmailMessage mockEmailMessageCoo() { - EmailMessage.Builder builder = EmailMessage.builder() - - if (mock.bools().probability(50).get()) { - builder.isMultipart(true) - mock.ints().range(1, 5).get().times { - builder.addBodyMultipart(mockMimePartTypeCooType()) - } - } else { - builder.isMultipart(false) - builder.body(mock.words().accumulate(mock.ints().range(1, 100).get(), " ").get()) - } - - if (mock.bools().probability(50).get()) { - builder.date(new StixInstant(generateRandomDate(commonLowerDate, Instant.now()))) - } - - if (mock.bools().probability(50).get()) { - builder.contentType(mock.mimes().get()) - } - - if (mock.bools().probability(50).get()) { - builder.fromRef(mockEmailAddressCoo().getObservableObjectKey()) - } - - if (mock.bools().probability(50).get()) { - builder.senderRef(mockEmailAddressCoo().getObservableObjectKey()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - builder.addToRef(mockEmailAddressCoo().getObservableObjectKey()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - builder.addCcRef(mockEmailAddressCoo().getObservableObjectKey()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - builder.addBccRef(mockEmailAddressCoo().getObservableObjectKey()) - } - } - - if (mock.bools().probability(50).get()) { - builder.subject(mock.words().accumulate(mock.ints().range(1, 10).get(), " ").get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - builder.addReceivedLine(mock.words().accumulate(mock.ints().range(1, 50).get(), " ").get()) - } - } - - if (mock.bools().probability(50).get()) { - builder.rawEmailRef(mockArtifactCoo().getObservableObjectKey()) - } - - return builder.build() - } - - MimePartType mockMimePartTypeCooType() { - MimePartType.Builder builder = MimePartType.builder() - - if (mock.bools().probability(50).get()) { - builder.body(mock.words().accumulate(mock.ints().range(1, 50).get(), " ").get()) - } else { - if (mock.bools().probability(50).get()) { - builder.bodyRawRef(mockArtifactCoo().getObservableObjectKey()) - } else { - builder.bodyRawRef(mockFileCoo().getObservableObjectKey()) - } - } - - if (mock.bools().probability(50).get()) { - builder.contentType(mock.mimes().get()) - } - - if (mock.bools().probability(50).get()) { - builder.contentDisposition(mock.words().get()) - } - - return builder.build() - } - - File mockFileCoo() { - File.Builder builder = File.builder() - - if (mock.bools().probability(50).get()) { - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addExtension(mockNtfsFileExtensionCooExt()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addExtension(mockRasterImageFileExtensionCooExt()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addExtension(mockPdfFileExtensionCooExt()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addExtension(mockArchiveFileExtensionCooExt()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addExtension(mockWindowsPeBinaryFileExtensionCooExt()) - } - } - } - - if (mock.bools().probability(50).get()) { - if (mock.bools().probability(20).get()) { - builder.putHash("MD5", mock.hashes().md5().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-256", mock.hashes().sha256().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-512", mock.hashes().sha512().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-1", mock.hashes().sha1().get()) - } - } - - if (mock.bools().probability(50).get()) { - builder.size(mock.longs().range(0, 999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.name(mock.words().accumulate(mock.ints().range(1, 5).get(), "-").get()) - } - - if (mock.bools().probability(50).get()) { - builder.nameEnc(mock.words().get()) - } - - //@TODO hardcoded the hex value until a proper generator can be built. - if (mock.bools().probability(50).get()) { - builder.magicNumberHex("F9") - } - - if (mock.bools().probability(50).get()) { - builder.mimeType(mock.mimes().get()) - } - - Instant created = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.created(new StixInstant(created)) - } - - if (mock.bools().probability(50).get()) { - builder.modified(new StixInstant(generateRandomDate(created, Instant.now()))) - } - - if (mock.bools().probability(50).get()) { - builder.accessed(new StixInstant(generateRandomDate(created, Instant.now()))) - } - - if (mock.bools().probability(50).get()) { - builder.parentDirectoryRef(mockDirectoryCoo().getObservableObjectKey()) - } - - if (mock.bools().probability(50).get()) { - builder.isEncrypted(true) - - if (mock.bools().probability(50).get()) { - builder.encryptionAlgorithm(mock.fromStrings(new EncryptionAlgorithms().getAllTerms().toList()).get()) - } - - if (mock.bools().probability(50).get()) { - builder.decryptionKey(mock.words().accumulate(mock.ints().range(1, 20).get(), "").get()) - } - } - - //@TODO come up with a simple use case that does not cause recursion for the "contains_refs" field - - return builder.build() - } - - Ipv4Address mockIpv4AddressCoo() { - Ipv4Address.Builder builder = Ipv4Address.builder() - - builder.value(mock.ipv4s().get()) - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - builder.addResolvesToRef(mockMacAddress().getObservableObjectKey()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - builder.addBelongsToRef(mockAutonomousSystemCoo().getObservableObjectKey()) - } - } - - return builder.build() - } - - Ipv6Address mockIpv6AddressCoo() { - Ipv6Address.Builder builder = Ipv6Address.builder() - - builder.value(mock.iPv6s().get()) - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - builder.addResolvesToRef(mockMacAddress().getObservableObjectKey()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - builder.addBelongsToRef(mockAutonomousSystemCoo().getObservableObjectKey()) - } - } - - return builder.build() - } - - MacAddress mockMacAddress() { - MacAddress.Builder builder = MacAddress.builder() - - builder.value(mock.macs().get()) - - return builder.build() - } - - Mutex mockMutexCoo() { - Mutex.Builder builder = Mutex.builder() - - builder.name(mock.words().get()) - - return builder.build() - } - - NetworkTraffic mockNetworkTrafficCoo() { - NetworkTraffic.Builder builder = NetworkTraffic.builder() - - if (mock.bools().probability(50).get()) { - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addExtension(mockHttpRequestExtensionCooExt()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addExtension(mockTcpExtensionCooExt()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addExtension(mockIcmpExtensionCooExt()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addExtension(mockNetworkSocketExtensionCooExt()) - } - } - } - - Instant start = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.start(new StixInstant(start)) - } - - if (mock.bools().probability(50).get()) { - builder.end(new StixInstant(generateRandomDate(start, Instant.now()))) - } - - // 33% true, 33% false, 33% never set / null: - if (mock.bools().probability(33).get()) { - builder.isActive(true) - } - - if (mock.bools().probability(33).get()) { - builder.isActive(false) - } - - if (mock.bools().probability(50).get()) { - switch (mock.ints().range(0, 3).get()) { - case 0: - builder.srcRef(mockIpv4AddressCoo().getObservableObjectKey()) - break - case 1: - builder.srcRef(mockIpv6AddressCoo().getObservableObjectKey()) - break - case 2: - builder.srcRef(mockMacAddress().getObservableObjectKey()) - break - case 3: - builder.srcRef(mockDomainNameCoo().getObservableObjectKey()) - break - } - } - - if (mock.bools().probability(50).get()) { - switch (mock.ints().range(0, 3).get()) { - case 0: - builder.dstRef(mockIpv4AddressCoo().getObservableObjectKey()) - break - case 1: - builder.dstRef(mockIpv6AddressCoo().getObservableObjectKey()) - break - case 2: - builder.dstRef(mockMacAddress().getObservableObjectKey()) - break - case 3: - builder.dstRef(mockDomainNameCoo().getObservableObjectKey()) - break - } - } - - if (mock.bools().probability(50).get()) { - builder.srcPort(mock.ints().range(0, 65535).get()) - } - - if (mock.bools().probability(50).get()) { - builder.dstPort(mock.ints().range(0, 65535).get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - builder.addProtocol(mock.fromStrings("ipv4", "tcp", "http", "udp", "ipv6", "ssl", "https").get()) - } - } - - if (mock.bools().probability(50).get()) { - builder.srcByteCount(mock.longs().range(0, 999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.dstByteCount(mock.longs().range(0, 999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.srcPackets(mock.longs().range(0, 999999999).get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - String key = mock.uuids().get() - if (mock.bools().probability(50).get()) { - builder.putIpFix(key, mock.words().get()) - } else { - builder.putIpFix(key, mock.ints().range(0, 999999999).get()) - } - } - } - - if (mock.bools().probability(50).get()) { - builder.srcPayloadRef(mockArtifactCoo().getObservableObjectKey()) - } - - //@TODO encapsulates_refs (List) - - //@TODO encapsulated_by_ref - - return builder.build() - } - - Process mockProcessCoo() { - Process.Builder builder = Process.builder() - - if (mock.bools().probability(50).get()) { - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addExtension(mockWindowsProcessExtensionCooExt()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addExtension(mockWindowsServiceExtensionCooExt()) - } - } - } - - if (mock.bools().probability(33).get()) { - builder.isHidden(true) - } else { - builder.isHidden(false) - } - - if (mock.bools().probability(50).get()) { - builder.pid(mock.longs().range(0, 999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.name(mock.words().accumulate(mock.ints().range(1, 5).get(), "-").get()) - } - - if (mock.bools().probability(50).get()) { - builder.created(new StixInstant(generateRandomDate(commonLowerDate, Instant.now()))) - } - - if (mock.bools().probability(50).get()) { - builder.cwd(mock.words().accumulate(mock.ints().range(1, 5).get(), "/").prepend("/").get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - builder.addArgument(mock.uuids().get()) - } - } - - if (mock.bools().probability(50).get()) { - builder.commandLine("${mock.words().get()} ${mock.words().accumulate(mock.ints().range(1, 5).get(), " ").get()}") - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 20).get().times { - builder.putEnvironmentVariable(mock.uuids().get(), mock.words().get()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - builder.addOpenedConnectionRef(mockNetworkTrafficCoo().getObservableObjectKey()) - } - } - - if (mock.bools().probability(50).get()) { - builder.creatorUserRef(mockUserAccountCoo().getObservableObjectKey()) - } - - if (mock.bools().probability(50).get()) { - builder.binaryRef(mockFileCoo().getObservableObjectKey()) - } - - - //@TODO parent_ref - - //@TODO child_refs - - - return builder.build() - } - - Software mockSoftwareCoo() { - Software.Builder builder = Software.builder() - - builder.name(mock.words().get()) - - if (mock.bools().probability(50).get()) { - builder.cpe("cpe:2.3:${mock.words().get()}") - } - - //@TODO add better language dictionary support - if (mock.bools().probability(50).get()) { - builder.addLanguage("eng") - if (mock.bools().probability(50).get()) { - builder.addLanguage("fre") - } - } - - if (mock.bools().probability(50).get()) { - builder.vendor(mock.words().get()) - } - - if (mock.bools().probability(50).get()) { - builder.version("${mock.ints().range(0, 5).get()}.${mock.ints().range(0, 5).get()}.${mock.ints().range(0, 5).get()}") - } - - return builder.build() - } - - Url mockUrlCoo() { - Url.Builder builder = Url.builder() - - builder.value(mock.urls().get()) - - return builder.build() - } - - UserAccount mockUserAccountCoo() { - UserAccount.Builder builder = UserAccount.builder() - - if (mock.bools().probability(50).get()) { - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addExtension(mockUnixAccountExtensionCooExt()) - } - } - } - - builder.userId(mock.uuids().get()) - - if (mock.bools().probability(50).get()) { - builder.accountLogin(mock.names().last().get()) - } - - if (mock.bools().probability(50).get()) { - builder.accountType(mock.fromStrings(new AccountTypes().getAllTerms().toList()).get()) - } - - if (mock.bools().probability(50).get()) { - builder.displayName(mock.words().get()) - } - - if (mock.bools().probability(33).get()) { - builder.isServiceAccount(true) - } - - if (mock.bools().probability(33).get()) { - builder.isServiceAccount(false) - } - - if (mock.bools().probability(33).get()) { - builder.isPrivileged(true) - } - - if (mock.bools().probability(33).get()) { - builder.isPrivileged(false) - } - - if (mock.bools().probability(33).get()) { - builder.isCanEscalatePrivs(true) - } - - if (mock.bools().probability(33).get()) { - builder.isCanEscalatePrivs(false) - } - - if (mock.bools().probability(33).get()) { - builder.isDisabled(true) - } - - if (mock.bools().probability(33).get()) { - builder.isDisabled(false) - } - - Instant accountCreated = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.accountCreated(new StixInstant(accountCreated)) - } - - if (mock.bools().probability(50).get()) { - builder.accountExpires(new StixInstant(generateRandomDate(accountCreated, Instant.now().plusMillis(1000000)))) - } - - if (mock.bools().probability(50).get()) { - builder.passwordLastChanged(new StixInstant(generateRandomDate(accountCreated, Instant.now()))) - } - - Instant firstLogin = generateRandomDate(accountCreated, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.accountFirstLogin(new StixInstant(firstLogin)) - } - - if (mock.bools().probability(50).get()) { - builder.accountLastLogin(new StixInstant(generateRandomDate(firstLogin, Instant.now()))) - } - - return builder.build() - } - - WindowsRegistryKey mockWindowsRegistryKeyCoo() { - WindowsRegistryKey.Builder builder = WindowsRegistryKey.builder() - - builder.key(mock.fromStrings("HKEY_LOCAL_MACHINE", "hkey_local_machine", "HKEY_CURRENT_USER", "hkey_current_user", "HKEY_CLASSES_ROOT", "hkey_classes_root", "HKEY_CURRENT_CONFIG", "hkey_current_config", "HKEY_PERFORMANCE_DATA", "hkey_performance_data", "HKEY_USERS", "hkey_users", "HKEY_DYN_DATA").get()) - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - builder.addValue(mockWindowsRegistryValue()) - } - } - - if (mock.bools().probability(50).get()) { - builder.modified(new StixInstant(generateRandomDate(commonLowerDate, Instant.now()))) - } - - if (mock.bools().probability(50).get()) { - builder.creatorUserRef(mockUserAccountCoo().getObservableObjectKey()) - } - - if (mock.bools().probability(50).get()) { - builder.numberOfSubkeys(mock.longs().range(0, 999999999).get()) - } - - return builder.build() - } - - WindowsRegistryValue mockWindowsRegistryValue() { - WindowsRegistryValue.Builder builder = WindowsRegistryValue.builder() - - builder.name(mock.words().get()) - - if (mock.bools().probability(50).get()) { - builder.data(mock.words().get()) - } - - if (mock.bools().probability(50).get()) { - builder.dataType(mock.fromStrings(new WindowsRegistryValueDataTypes().getAllTerms().toList()).get()) - } - - return builder.build() - } - - X509Certificate mockX509CertificateCoo() { - X509Certificate.Builder builder = X509Certificate.builder() - - if (mock.bools().probability(33).get()) { - builder.isSelfSigned(true) - } else { - builder.isSelfSigned(false) - } - - if (mock.bools().probability(50).get()) { - if (mock.bools().probability(20).get()) { - builder.putHash("MD5", mock.hashes().md5().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-256", mock.hashes().sha256().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-512", mock.hashes().sha512().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-1", mock.hashes().sha1().get()) - } - } - - if (mock.bools().probability(50).get()) { - builder.version("${mock.ints().range(0, 5).get()}.${mock.ints().range(0, 5).get()}.${mock.ints().range(0, 5).get()}") - } - - if (mock.bools().probability(50).get()) { - builder.serialNumber(mock.ints().range(1, 9999999).get().toString()) - } - - if (mock.bools().probability(50).get()) { - builder.signatureAlgorithm(mock.words().get()) - } - - if (mock.bools().probability(50).get()) { - builder.issuer(mock.words().get()) - } - - Instant validityNotBefore = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.validityNotBefore(new StixInstant(validityNotBefore)) - } - - if (mock.bools().probability(50).get()) { - builder.validityNotAfter(new StixInstant(generateRandomDate(validityNotBefore, Instant.now().plusMillis(1000000)))) - } - - if (mock.bools().probability(50).get()) { - builder.subject(mock.words().get()) - } - - if (mock.bools().probability(50).get()) { - builder.subjectPublicKeyAlgorithm(mock.words().get()) - } - - if (mock.bools().probability(50).get()) { - builder.subjectPublicKeyModulus(mock.words().get()) - } - - if (mock.bools().probability(50).get()) { - builder.subjectPublicKeyExponent(mock.longs().get()) - } - - //@TODO x509_v3_extensions property - - return builder.build() - } - - Report mockReport() { - Report.Builder builder = Report.builder() - - Instant objectCreated = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.created(new StixInstant(objectCreated)) - if (mock.bools().probability(50).get()) { - builder.modified(new StixInstant(generateRandomDate(objectCreated, Instant.now()))) - } - } - - mock.ints().range(1, 5).get().times { - builder.addLabel(mock.fromStrings(new ReportLabels().getAllTerms().toList()).get()) - } - - builder.name(mock.words().accumulate(mock.ints().range(1, 8).get(), " ").get()) - - if (mock.bools().probability(50).get()) { - builder.description(mock.words().accumulate(mock.ints().range(1, 50).get(), " ").get()) - } - - builder.published(new StixInstant(generateRandomDate(commonLowerDate, Instant.now()))) - - mock.ints().range(1, 50).get().times { - switch (mock.ints().range(1, 14).get()) { - case 1: - builder.addObjectRef(mockAttackPattern()) - break - case 2: - builder.addObjectRef(mockCampaign()) - break - case 3: - builder.addObjectRef(mockCourseOfAction()) - break - case 4: - builder.addObjectRef(mockIdentity()) - break - case 5: - builder.addObjectRef(mockIndicator()) - break - case 6: - builder.addObjectRef(mockIntrusionSet()) - break - case 7: - builder.addObjectRef(mockMalware()) - break - case 8: - builder.addObjectRef(mockObservedData()) - break - case 9: - builder.addObjectRef(mockThreatActor()) - break - case 10: - builder.addObjectRef(mockTool()) - break - case 11: - builder.addObjectRef(mockVulnerability()) - break - case 12: - builder.addObjectRef(mockMarkingDefinition()) - break - case 13: - builder.addObjectRef(mockRelationship()) - break - case 14: - builder.addObjectRef(mockSighting()) - break - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 10).get().times { - builder.addExternalReferences(mockExternalReference()) - } - } - - if (mock.bools().probability(50).get()) { - builder.revoked(new StixBoolean(true)) - } - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - if (mock.bools().probability(50).get()) { - builder.createdByRef(mockIdentity()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addObjectMarkingRef(mockMarkingDefinition()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addGranularMarking(mockGranularMarking()) - } - } - - return builder.build() - } - - ThreatActor mockThreatActor() { - ThreatActor.Builder builder = ThreatActor.builder() - - Instant objectCreated = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.created(new StixInstant(objectCreated)) - if (mock.bools().probability(50).get()) { - builder.modified(new StixInstant(generateRandomDate(objectCreated, Instant.now()))) - } - } - - mock.ints().range(1, 5).get().times { - builder.addLabel(mock.fromStrings(new ThreatActorLabels().getAllTerms().toList()).get()) - } - - builder.name(mock.names().get()) - - if (mock.bools().probability(50).get()) { - builder.description(mock.words().accumulate(mock.ints().range(1, 50).get(), " ").get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addAlias(mock.names().get()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addRole(mock.fromStrings(new ThreatActorRoles().getAllTerms().toList()).get()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addGoal(mock.words().accumulate(mock.ints().range(1, 10).get(), " ").get()) - } - } - - if (mock.bools().probability(50).get()) { - builder.sophistication(mock.fromStrings(new ThreatActorSophistication().getAllTerms().toList()).get()) - } - - if (mock.bools().probability(50).get()) { - builder.resourceLevel(mock.fromStrings(new AttackResourceLevels().getAllTerms().toList()).get()) - } - - if (mock.bools().probability(50).get()) { - builder.primaryMotivation(mock.fromStrings(new AttackMotivations().getAllTerms().toList()).get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addSecondaryMotivation(mock.fromStrings(new AttackMotivations().getAllTerms().toList()).get()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addPersonalMotivation(mock.fromStrings(new AttackMotivations().getAllTerms().toList()).get()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 10).get().times { - builder.addExternalReferences(mockExternalReference()) - } - } - - if (mock.bools().probability(50).get()) { - builder.revoked(new StixBoolean(true)) - } - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - if (mock.bools().probability(50).get()) { - builder.createdByRef(mockIdentity()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addObjectMarkingRef(mockMarkingDefinition()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addGranularMarking(mockGranularMarking()) - } - } - - return builder.build() - } - - Tool mockTool() { - Tool.Builder builder = Tool.builder() - - Instant objectCreated = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.created(new StixInstant(objectCreated)) - if (mock.bools().probability(50).get()) { - builder.modified(new StixInstant(generateRandomDate(objectCreated, Instant.now()))) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addLabel(mock.fromStrings(new ToolLabels().getAllTerms().toList()).get()) - } - } - - builder.name(mock.words().get()) - - if (mock.bools().probability(50).get()) { - builder.description(mock.words().accumulate(mock.ints().range(1, 50).get(), " ").get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 15).get().times { - builder.addKillChainPhase(mockKillChainPhase()) - } - } - - if (mock.bools().probability(50).get()) { - builder.toolVersion("${mock.ints().range(0, 5).get()}.${mock.ints().range(0, 5).get()}.${mock.ints().range(0, 5).get()}") - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 10).get().times { - builder.addExternalReferences(mockExternalReference()) - } - } - - if (mock.bools().probability(50).get()) { - builder.revoked(new StixBoolean(true)) - } - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - if (mock.bools().probability(50).get()) { - builder.createdByRef(mockIdentity()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addObjectMarkingRef(mockMarkingDefinition()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addGranularMarking(mockGranularMarking()) - } - } - - return builder.build() - } - - Vulnerability mockVulnerability() { - Vulnerability.Builder builder = Vulnerability.builder() - - Instant objectCreated = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.created(new StixInstant(objectCreated)) - if (mock.bools().probability(50).get()) { - builder.modified(new StixInstant(generateRandomDate(objectCreated, Instant.now()))) - } - } - - builder.name(mock.words().get()) - - if (mock.bools().probability(50).get()) { - builder.description(mock.words().accumulate(mock.ints().range(1, 50).get(), " ").get()) - } - - if (mock.bools().probability(50).get()) { - builder.labels(generateRandomLabels()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 10).get().times { - builder.addExternalReferences(mockExternalReference()) - } - } - - if (mock.bools().probability(50).get()) { - builder.revoked(new StixBoolean(true)) - } - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - if (mock.bools().probability(50).get()) { - builder.createdByRef(mockIdentity()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addObjectMarkingRef(mockMarkingDefinition()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addGranularMarking(mockGranularMarking()) - } - } - - return builder.build() - } - - BundleableObject generateRandomBundleableObject(){ - switch (mock.ints().range(1, 14).get()) { - case 1: - return mockAttackPattern() - break - case 2: - return mockCampaign() - break - case 3: - return mockCourseOfAction() - break - case 4: - return mockIdentity() - break - case 5: - return mockIndicator() - break - case 6: - return mockIntrusionSet() - break - case 7: - return mockMalware() - break - case 8: - return mockObservedData() - break - case 9: - return mockThreatActor() - break - case 10: - return mockTool() - break - case 11: - return mockVulnerability() - break - case 12: - return mockMarkingDefinition() - break - case 13: - return mockRelationship() - break - case 14: - return mockSighting() - break - default: - throw new IllegalArgumentException("Unknown Bundleable Object was attempted to be generated") - break - } - } - - Bundle mockBundle(int bundleCountLowerValue = 1, int bundleCountUpperValue = 100) { - Bundle.Builder builder = Bundle.builder() - - mock.ints().range(bundleCountLowerValue, bundleCountUpperValue).get().times { - builder.addObject(generateRandomBundleableObject()) - } - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - return builder.build() - } - - MarkingDefinition mockMarkingDefinition() { - MarkingDefinition.Builder builder = MarkingDefinition.builder() - - Instant objectCreated = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.created(new StixInstant(objectCreated)) - } - - String type = mock.fromStrings("tlp", "statement").get() - - builder.definitionType(type) - - switch (type) { - case "tlp": - builder.definition(mockTlpMakingObject()) - break - case "statement": - builder.definition(mockStatementMarkingObject()) - break - } - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - builder.build() - } - - Statement mockStatementMarkingObject() { - Statement.Builder builder = Statement.builder() - - builder.statement(mock.words().accumulate(mock.ints().range(1, 30).get(), " ").get()) - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - return builder.build() - } - - Tlp mockTlpMakingObject() { - Tlp.Builder builder = Tlp.builder() - - builder.tlp(mock.fromStrings(new TlpLevels().getAllTerms().toList()).get()) - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - return builder.build() - } - - GranularMarking mockGranularMarking() { - GranularMarking.Builder builder = GranularMarking.builder() - - builder.markingRef(mockMarkingDefinition()) - - mock.ints().range(1, 10).get().times { - builder.addSelector(mock.words().get()) - } - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - return builder.build() - } - - Relationship mockRelationship() { - Relationship.Builder builder = Relationship.builder() - - Instant objectCreated = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.created(new StixInstant(objectCreated)) - if (mock.bools().probability(50).get()) { - builder.modified(new StixInstant(generateRandomDate(objectCreated, Instant.now()))) - } - } - - switch (mock.ints().range(1, 11).get()) { - case 1: - builder.sourceRef(mockAttackPattern()) - - switch (mock.ints().range(1, 2).get()) { - case 1: - builder.relationshipType("targets") - if (mock.bools().probability(50).get()) { - builder.targetRef(mockIdentity()) - } else { - builder.targetRef(mockVulnerability()) - } - break - case 2: - builder.relationshipType("uses") - if (mock.bools().probability(50).get()) { - builder.targetRef(mockMalware()) - } else { - builder.targetRef(mockTool()) - } - break - } - - break - - case 2: - builder.sourceRef(mockCampaign()) - - switch (mock.ints().range(1, 3).get()) { - case 1: - builder.relationshipType("attributed-to") - if (mock.bools().probability(50).get()) { - builder.targetRef(mockIntrusionSet()) - } else { - builder.targetRef(mockThreatActor()) - } - break - case 2: - builder.relationshipType("targets") - if (mock.bools().probability(50).get()) { - builder.targetRef(mockIdentity()) - } else { - builder.targetRef(mockVulnerability()) - } - break - case 3: - builder.relationshipType("uses") - switch (mock.ints().range(1, 3).get()) { - case 1: - builder.targetRef(mockAttackPattern()) - break - case 2: - builder.targetRef(mockMalware()) - break - case 3: - builder.targetRef(mockTool()) - break - } - break - } - break - - case 3: - builder.sourceRef(mockCourseOfAction()) - builder.relationshipType("mitigates") - - switch (mock.ints().range(1, 4).get()) { - case 1: - builder.targetRef(mockAttackPattern()) - break - case 2: - builder.targetRef(mockMalware()) - break - case 3: - builder.targetRef(mockTool()) - break - case 4: - builder.targetRef(mockVulnerability()) - break - } - break - - case 4: - builder.sourceRef(mockIndicator()) - builder.relationshipType("indicates") - - switch (mock.ints().range(1, 6).get()) { - case 1: - builder.targetRef(mockAttackPattern()) - break - case 2: - builder.targetRef(mockCampaign()) - break - case 3: - builder.targetRef(mockIntrusionSet()) - break - case 4: - builder.targetRef(mockMalware()) - break - case 5: - builder.targetRef(mockThreatActor()) - break - case 6: - builder.targetRef(mockTool()) - break - } - break - - case 5: - builder.sourceRef(mockIntrusionSet()) - - switch (mock.ints().range(1, 3).get()) { - case 1: - builder.relationshipType("attributed-to") - builder.targetRef(mockThreatActor()) - break - case 2: - builder.relationshipType("targets") - if (mock.bools().probability(50).get()) { - builder.targetRef(mockIdentity()) - } else { - builder.targetRef(mockVulnerability()) - } - break - case 3: - builder.relationshipType("uses") - switch (mock.ints().range(1, 3).get()) { - case 1: - builder.targetRef(mockAttackPattern()) - break - case 2: - builder.targetRef(mockMalware()) - break - case 3: - builder.targetRef(mockTool()) - break - } - break - } - break - - case 6: - builder.sourceRef(mockMalware()) - - switch (mock.ints().range(1, 3).get()) { - case 1: - builder.relationshipType("targets") - if (mock.bools().probability(50).get()) { - builder.targetRef(mockIdentity()) - } else { - builder.targetRef(mockVulnerability()) - } - break - case 2: - builder.relationshipType("uses") - builder.targetRef(mockTool()) - break - case 3: - builder.relationshipType("variant-of") - builder.targetRef(mockMalware()) - break - } - break - - case 7: - builder.sourceRef(mockThreatActor()) - - switch (mock.ints().range(1, 4).get()) { - case 1: - builder.relationshipType("attributed-to") - builder.targetRef(mockIdentity()) - break - case 2: - builder.relationshipType("impersonates") - builder.targetRef(mockIdentity()) - break - case 3: - builder.relationshipType("targets") - if (mock.bools().probability(50).get()) { - builder.targetRef(mockIdentity()) - } else { - builder.targetRef(mockVulnerability()) - } - break - case 4: - builder.relationshipType("uses") - switch (mock.ints().range(1, 3).get()) { - case 1: - builder.targetRef(mockAttackPattern()) - break - case 2: - builder.targetRef(mockMalware()) - break - case 3: - builder.targetRef(mockTool()) - break - } - break - } - break - case 8: - builder.sourceRef(mockTool()) - - builder.relationshipType("targets") - switch (mock.ints().range(1, 2).get()) { - case 1: - builder.targetRef(mockIdentity()) - break - case 2: - builder.targetRef(mockVulnerability()) - break - } - break - - case 9: - DomainObject object = mockRandomDomainObject() - - builder.sourceRef(object) - - builder.relationshipType("derived-from") - - builder.targetRef(mockRandomDomainObject(object.getType())) - - break - - case 10: - DomainObject object = mockRandomDomainObject() - - builder.sourceRef(object) - - builder.relationshipType("duplicate-of") - - builder.targetRef(mockRandomDomainObject(object.getType())) - - break - - case 11: - DomainObject object = mockRandomDomainObject() - - builder.sourceRef(object) - - builder.relationshipType("related-to") - - builder.targetRef(mockRandomDomainObject()) - - break - } - - // Extra details - - if (mock.bools().probability(50).get()) { - builder.description(mock.words().accumulate(mock.ints().range(1, 50).get(), " ").get()) - } - - if (mock.bools().probability(50).get()) { - builder.labels(generateRandomLabels()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(0, 10).get().times { - builder.addExternalReferences(mockExternalReference()) - } - } - - if (mock.bools().probability(50).get()) { - builder.revoked(new StixBoolean(true)) - } - - if (mock.bools().probability(50).get()) { - builder.customProperties(generateCustomProperties()) - } - - if (mock.bools().probability(50).get()) { - builder.createdByRef(mockIdentity()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addObjectMarkingRef(mockMarkingDefinition()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addGranularMarking(mockGranularMarking()) - } - } - - return builder.build() - } - - Sighting mockSighting() { - Sighting.Builder builder = Sighting.builder() - - Instant objectCreated = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.created(new StixInstant(objectCreated)) - if (mock.bools().probability(50).get()) { - builder.modified(new StixInstant(generateRandomDate(objectCreated, Instant.now()))) - } - } - - Instant firstSeen = generateRandomDate(commonLowerDate, Instant.now()) - if (mock.bools().probability(50).get()) { - builder.firstSeen(new StixInstant(firstSeen)) - } - - //@TODO This data will fail tests in the future as it create dates that are BEFORE the firstSeen. Not currently enforced - if (mock.bools().probability(50).get()) { - builder.lastSeen(new StixInstant(generateRandomDate(firstSeen, Instant.now()))) - } - - if (mock.bools().probability(50).get()) { - builder.count(mock.ints().range(0, 999999999).get()) - } - - builder.sightingOfRef(mockRandomDomainObject()) - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 30).get().times { - builder.addObservedDataRef(mockObservedData()) - } - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 30).get().times { - builder.addWhereSightedRef(mockIdentity()) - } - } - - if (mock.bools().probability(20).get()) { - builder.isSummary(new StixBoolean(true)) - } - - return builder.build() - } - - DomainObject mockRandomDomainObject(String manualType) { - - String[] types = ["attack-pattern", "campaign", - "course-of-action", "identity", - "indicator", "intrusion-set", - "malware", "observed-data", - "threat-actor", "tool", - "vulnerability"] - - if (manualType == null) { - manualType = mock.fromStrings(types).get() - } else { - if (!types.contains(manualType)) { - throw new IllegalArgumentException("invalid manualType") - } - } - - switch (manualType) { - case "attack-pattern": - return mockAttackPattern() - case "campaign": - return mockCampaign() - case "course-of-action": - return mockCourseOfAction() - case "identity": - return mockIdentity() - case "indicator": - return mockIndicator() - case "intrusion-set": - return mockIntrusionSet() - case "malware": - return mockMalware() - case "observed-data": - return mockObservedData() - case "threat-actor": - return mockThreatActor() - case "tool": - return mockTool() - case "vulnerability": - return mockVulnerability() - } - } - - ArchiveFileExtension mockArchiveFileExtensionCooExt() { - ArchiveFileExtension.Builder builder = ArchiveFileExtension.builder() - - if (mock.bools().probability(33).get()) { - mock.ints().range(1, 2).get().times { - builder.addContainsRef(mockFileCoo().getObservableObjectKey()) - } - } - - if (mock.bools().probability(50).get()) { - builder.version("${mock.ints().range(0, 5).get()}.${mock.ints().range(0, 5).get()}.${mock.ints().range(0, 5).get()}") - } - - if (mock.bools().probability(50).get()) { - builder.comment(mock.words().accumulate(mock.ints().range(1, 20).get(), " ").get()) - } - - return builder.build() - } - - HttpRequestExtension mockHttpRequestExtensionCooExt() { - HttpRequestExtension.Builder builder = HttpRequestExtension.builder() - - builder.requestMethod(mock.fromStrings("GET", "PUT", "POST", "PATCH", "DELETE").get()) - - builder.requestValue(mock.words().accumulate(mock.ints().range(1, 30).get(), " ").get().toString()) - - builder.requestVersion(mock.fromStrings("1.0", "1.1", "2.0").get()) - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - String key = mock.words().accumulate(mock.ints().range(2, 3).get(), "").get() - String value = mock.words().accumulate(mock.ints().range(1, 5).get(), "-").get() - builder.putRequestHeader(key, value) - } - } - - if (mock.bools().probability(50).get()) { - builder.messageBodyLength(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.messageBodyDataRef(mockArtifactCoo().getObservableObjectKey()) - } - - return builder.build() - } - - IcmpExtension mockIcmpExtensionCooExt() { - IcmpExtension.Builder builder = IcmpExtension.builder() - - builder.icmpCodeHex(mock.chars().hex().get().toString() + mock.chars().hex().get().toString()) - - builder.ocmpTypeHex(mock.chars().hex().get().toString() + mock.chars().hex().get().toString()) - - return builder.build() - } - - - NetworkSocketExtension mockNetworkSocketExtensionCooExt() { - NetworkSocketExtension.Builder builder = NetworkSocketExtension.builder() - - builder.addressFamily(mock.fromStrings(new NetworkSocketAddressFamilies().getAllTerms().toList()).get()) - - if (mock.bools().probability(50).get()) { - builder.blocking(true) - } - - if (mock.bools().probability(50).get()) { - builder.listening(true) - } - - if (mock.bools().probability(50).get()) { - builder.protocolFamily(mock.fromStrings(new NetworkSocketProtocolFamilies().getAllTerms().toList()).get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - String key = mock.words().accumulate(mock.ints().range(2, 3).get(), "").get() - String value = mock.words().accumulate(mock.ints().range(1, 5).get(), "-").get() - builder.putOption("SO_${key}", value) - } - } - - if (mock.bools().probability(50).get()) { - builder.socketType(mock.fromStrings(new NetworkSocketTypes().getAllTerms().toList()).get()) - } - - if (mock.bools().probability(50).get()) { - builder.socketDescriptor(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.socketHandle(mock.longs().range(0, 999999999999).get()) - } - - return builder.build() - } - - NtfsFileExtenstion mockNtfsFileExtensionCooExt() { - NtfsFileExtenstion.Builder builder = NtfsFileExtenstion.builder() - - if (mock.bools().probability(50).get()) { - builder.sid(mock.words().get()) - } else { - if (mock.bools().probability(50).get()) { - builder.sid(mock.words().get()) - } - mock.ints().range(1, 5).get().times { - builder.addAlternateDataStream(mockNtfsAlternateDataStreamCooExtObj()) - } - } - return builder.build() - } - - NtfsAlternateDataStream mockNtfsAlternateDataStreamCooExtObj() { - NtfsAlternateDataStream.Builder builder = NtfsAlternateDataStream.builder() - - builder.name(mock.words().get()) - - if (mock.bools().probability(50).get()) { - if (mock.bools().probability(20).get()) { - builder.putHash("MD5", mock.hashes().md5().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-256", mock.hashes().sha256().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-512", mock.hashes().sha512().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-1", mock.hashes().sha1().get()) - } - } - - if (mock.bools().probability(50).get()) { - builder.size(mock.longs().range(0, 999999999999).get()) - } - - return builder.build() - } - - PdfFileExtension mockPdfFileExtensionCooExt() { - PdfFileExtension.Builder builder = PdfFileExtension.builder() - - if (mock.bools().probability(50).get()) { - builder.version("${mock.ints().range(0, 5).get()}.${mock.ints().range(0, 5).get()}.${mock.ints().range(0, 5).get()}") - } - - builder.isOptimized(mock.bools().probability(50).get()) - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - String key = mock.words().accumulate(mock.ints().range(2, 3).get(), "").get() - String value = mock.words().accumulate(mock.ints().range(1, 5).get(), " ").get() - builder.putDocumentInfoDict(key, value) - } - } - - if (mock.bools().probability(50).get()) { - builder.pdfId0(mock.words().accumulate(mock.ints().range(1, 2).get(), "-").get()) - } - - if (mock.bools().probability(50).get()) { - builder.pdfId1(mock.words().accumulate(mock.ints().range(1, 2).get(), "-").get()) - } - - return builder.build() - } - - RasterImageFileExtension mockRasterImageFileExtensionCooExt() { - RasterImageFileExtension.Builder builder = RasterImageFileExtension.builder() - - builder.imageHeight(mock.longs().range(0, 999999999999).get()) - - if (mock.bools().probability(50).get()) { - builder.imageWidth(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.bitsPerPixel(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.imageCompressionAlgorithm(mock.words().accumulate(mock.ints().range(1, 2).get(), "-").get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - String key = mock.words().accumulate(mock.ints().range(2, 3).get(), "-").get() - String value = mock.words().accumulate(mock.ints().range(1, 5).get(), " ").get() - builder.putExifTag(key, value) - } - } - - return builder.build() - } - - TcpExtension mockTcpExtensionCooExt() { - TcpExtension.Builder builder = TcpExtension.builder() - - builder.srcFlagsHex(mock.chars().hex().get().toString() + mock.chars().hex().get().toString()) - - builder.dstFlagsHex(mock.chars().hex().get().toString() + mock.chars().hex().get().toString()) - - return builder.build() - } - - UnixAccountExtension mockUnixAccountExtensionCooExt() { - UnixAccountExtension.Builder builder = UnixAccountExtension.builder() - - builder.gid(mock.longs().range(0, 999999999999).get()) - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addGroup(mock.words().get()) - } - } - - if (mock.bools().probability(50).get()) { - builder.homeDir("./${mock.words().accumulate(mock.ints().range(1, 5).get(), "/").get()}") - } - - if (mock.bools().probability(50).get()) { - builder.shell("${mock.words().get()} ${mock.words().accumulate(mock.ints().range(1, 5).get(), " ").get()}") - } - - return builder.build() - } - - WindowsPeBinaryFileExtension mockWindowsPeBinaryFileExtensionCooExt() { - WindowsPeBinaryFileExtension.Builder builder = WindowsPeBinaryFileExtension.builder() - - builder.peType(mock.fromStrings(new WindowsPeBinaryTypes().getAllTerms().toList()).get()) - - if (mock.bools().probability(50).get()) { - builder.imphash(mock.hashes().md5().get()) - } - - if (mock.bools().probability(50).get()) { - builder.machineHex(mock.chars().hex().get().toString() + mock.chars().hex().get().toString()) - } - - if (mock.bools().probability(50).get()) { - builder.numberOfSections(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.timeDateStamp(new StixInstant(generateRandomDate(commonLowerDate, Instant.now()))) - } - - if (mock.bools().probability(50).get()) { - builder.pointerToSymbolTableHex(mock.chars().hex().get().toString() + mock.chars().hex().get().toString()) - } - - if (mock.bools().probability(50).get()) { - builder.numberOfSymbols(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.sizeOfOptionalHeader(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.characteristicsHex(mock.chars().hex().get().toString() + mock.chars().hex().get().toString()) - } - - if (mock.bools().probability(50).get()) { - if (mock.bools().probability(20).get()) { - builder.putFileHeaderHash("MD5", mock.hashes().md5().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putFileHeaderHash("SHA-256", mock.hashes().sha256().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putFileHeaderHash("SHA-512", mock.hashes().sha512().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putFileHeaderHash("SHA-1", mock.hashes().sha1().get()) - } - } - - if (mock.bools().probability(50).get()) { - builder.optionalHeader(mockWindowsPeOptionalHeaderCooExtObj()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addSection(mockWindowsPeSectionCooExtObj()) - } - } - - return builder.build() - } - - WindowsPeOptionalHeader mockWindowsPeOptionalHeaderCooExtObj() { - WindowsPeOptionalHeader.Builder builder = WindowsPeOptionalHeader.builder() - - builder.magicHex(mock.chars().hex().get().toString() + mock.chars().hex().get().toString()) - - if (mock.bools().probability(50).get()) { - builder.majorLinkerVersion(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.minorLinkerVersion(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.sizeOfCode(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.sizeOfInitializedData(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.addressOfEntryPoint(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.baseOfCode(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.baseOfData(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.imageBase(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.sectionAlignment(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.fileAlignment(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.majorOsVersion(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.minorOsVersion(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.majorImageVersion(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.minorImageVersion(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.majorSubsystemVersion(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.minorSubsystemVersion(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.win32VersionValueHex(mock.chars().hex().get().toString() + mock.chars().hex().get().toString()) - } - - if (mock.bools().probability(50).get()) { - builder.sizeOfImage(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.sizeOfHeaders(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.checksumHex(mock.chars().hex().get().toString() + mock.chars().hex().get().toString()) - } - - if (mock.bools().probability(50).get()) { - builder.subsystemHex(mock.chars().hex().get().toString() + mock.chars().hex().get().toString()) - } - - if (mock.bools().probability(50).get()) { - builder.dllCharacteristicsHex(mock.chars().hex().get().toString() + mock.chars().hex().get().toString()) - } - - if (mock.bools().probability(50).get()) { - builder.sizeOfStackReserve(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.sizeOfStackCommit(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.sizeOfHeapReserve(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.sizeOfHeapCommit(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.loaderFlagsHex(mock.chars().hex().get().toString() + mock.chars().hex().get().toString()) - } - - if (mock.bools().probability(50).get()) { - builder.numberOfRvaAndSizes(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - if (mock.bools().probability(20).get()) { - builder.putHash("MD5", mock.hashes().md5().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-256", mock.hashes().sha256().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-512", mock.hashes().sha512().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-1", mock.hashes().sha1().get()) - } - } - - return builder.build() - } - - WindowsPeSection mockWindowsPeSectionCooExtObj() { - WindowsPeSection.Builder builder = WindowsPeSection.builder() - - if (mock.bools().probability(50).get()) { - builder.name(mock.words().accumulate(mock.ints().range(1, 5).get(), "-").get()) - } - - if (mock.bools().probability(50).get()) { - builder.size(mock.longs().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - builder.entropy(mock.floats().range(0, 999999999999).get()) - } - - if (mock.bools().probability(50).get()) { - if (mock.bools().probability(20).get()) { - builder.putHash("MD5", mock.hashes().md5().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-256", mock.hashes().sha256().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-512", mock.hashes().sha512().get()) - } - - if (mock.bools().probability(20).get()) { - builder.putHash("SHA-1", mock.hashes().sha1().get()) - } - } - - return builder.build() - } - - WindowsProcessExtension mockWindowsProcessExtensionCooExt() { - WindowsProcessExtension.Builder builder = WindowsProcessExtension.builder() - - if (mock.bools().probability(50).get()) { - builder.isAslrEnabled(true) - } else { - builder.isAslrEnabled(false) - builder.isDepEnabled(mock.bools().probability(50).get()) - } - - if (mock.bools().probability(50).get()) { - builder.priority(mock.words().accumulate(mock.ints().range(1, 3).get(), "_").get()) - } - - if (mock.bools().probability(50).get()) { - builder.ownerSid(mock.ints().range(1, 999999).get().toString()) - } - - if (mock.bools().probability(50).get()) { - builder.windowTitle(mock.words().accumulate(mock.ints().range(1, 5).get(), " ").get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - String key = mock.words().accumulate(mock.ints().range(2, 3).get(), "-").get() - String value = mock.words().accumulate(mock.ints().range(1, 5).get(), " ").get() - builder.putStartupInfo(key, value) - } - } - - return builder.build() - } - - WindowsServiceExtension mockWindowsServiceExtensionCooExt() { - WindowsServiceExtension.Builder builder = WindowsServiceExtension.builder() - - builder.serviceName(mock.words().accumulate(mock.ints().range(1, 3).get(), "-").get()) - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 5).get().times { - builder.addDescription(mock.words().accumulate(mock.ints().range(1, 10).get(), " ").get()) - } - } - - if (mock.bools().probability(50).get()) { - builder.displayName(mock.words().accumulate(mock.ints().range(1, 2).get(), "-").get()) - } - - if (mock.bools().probability(50).get()) { - builder.groupName(mock.words().accumulate(mock.ints().range(1, 2).get(), "-").get()) - } - - if (mock.bools().probability(50).get()) { - builder.serviceStartType(mock.fromStrings(new WindowsServiceStartTypes().getAllTerms().toList()).get()) - } - - if (mock.bools().probability(50).get()) { - mock.ints().range(1, 10).get().times { - builder.addServiceDllRef(mock.words().accumulate(mock.ints().range(1, 3).get(), "-").get()) - } - } - - if (mock.bools().probability(50).get()) { - builder.serviceType(mock.fromStrings(new WindowsServiceTypes().getAllTerms().toList()).get()) - } - - if (mock.bools().probability(50).get()) { - builder.serviceStatus(mock.fromStrings(new WindowsServiceStatuses().getAllTerms().toList()).get()) - } - - return builder.build() - } -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/ObservedDataGeneratorConfig.groovy b/src/test/groovy/faker/configs/ObservedDataGeneratorConfig.groovy deleted file mode 100644 index c144e15..0000000 --- a/src/test/groovy/faker/configs/ObservedDataGeneratorConfig.groovy +++ /dev/null @@ -1,87 +0,0 @@ -package faker.configs - -import faker.configs.sdo.observeddata.ObservedData_ArtifactCooConfig -import faker.configs.sdo.observeddata.ObservedData_AutonomousSystemCooConfig -import faker.configs.sdo.observeddata.ObservedData_DirectoryCooConfig -import faker.configs.sdo.observeddata.ObservedData_DomainNameCooConfig -import faker.configs.sdo.observeddata.ObservedData_EmailAddressCooConfig -import faker.configs.sdo.observeddata.ObservedData_EmailMessageCooConfig -import faker.configs.sdo.observeddata.ObservedData_ExternalReferencesConfig -import faker.configs.sdo.observeddata.ObservedData_FileCooConfig -import faker.configs.sdo.observeddata.ObservedData_GranularMarkingConfig -import faker.configs.sdo.observeddata.ObservedData_Ipv4AddressCooConfig -import faker.configs.sdo.observeddata.ObservedData_Ipv6AddressCooConfig -import faker.configs.sdo.observeddata.ObservedData_MacAddressCooConfig -import faker.configs.sdo.observeddata.ObservedData_MutexCooConfig -import faker.configs.sdo.observeddata.ObservedData_NetworkTrafficCooConfig -import faker.configs.sdo.observeddata.ObservedData_ObjectMarkingsConfig -import faker.configs.sdo.observeddata.ObservedData_ProcessCooConfig -import faker.configs.sdo.observeddata.ObservedData_SoftwareCooConfig -import faker.configs.sdo.observeddata.ObservedData_UrlCooConfig -import faker.configs.sdo.observeddata.ObservedData_UserAccountCooConfig -import faker.configs.sdo.observeddata.ObservedData_WindowsRegistryKeyCooConfig -import faker.configs.sdo.observeddata.ObservedData_X509CertificateCooConfig - -import java.time.Instant -import java.time.LocalDate - -class ObservedDataGeneratorConfig { - - private Instant DEFAULT_LOWER_DATE = Instant.ofEpochMilli(LocalDate.of(2000, 1, 1).toEpochDay()) - private Instant DEFAULT_UPPER_DATE = Instant.now() - private int DEFAULT_DATE_SUBSECOND_PRECISION = 3 - - int propCreatedProbability = 50 - Instant propCreatedLowerDate = DEFAULT_LOWER_DATE - Instant propCreatedUpperDate = DEFAULT_UPPER_DATE - int propCreatedDateSubsecondPrecision = DEFAULT_DATE_SUBSECOND_PRECISION - - int propModifiedProbability = 50 - Instant propModifiedUpperDate = DEFAULT_UPPER_DATE - int propModifiedSubsecondPrecision = DEFAULT_DATE_SUBSECOND_PRECISION - - int propRevokedProbability = 50 - - int propCreatedByRefProbability = 50 - - int propCustomPropsProbability = 50 - - Instant propFirstObservedLowerDate = DEFAULT_LOWER_DATE - Instant propFirstObservedUpperDate = DEFAULT_UPPER_DATE - int propFirstObservedSubsecondPrecision = DEFAULT_DATE_SUBSECOND_PRECISION - - Instant propLastObservedUpperDate = DEFAULT_UPPER_DATE - int propLastObservedSubsecondPrecision = DEFAULT_DATE_SUBSECOND_PRECISION - - int propNumberObservedUpperCount = 999999999 - int propNumberObservedLowerCount = 1 - - ObservedData_ArtifactCooConfig artifactCoo = new ObservedData_ArtifactCooConfig() - ObservedData_AutonomousSystemCooConfig autonomousSystemCoo = new ObservedData_AutonomousSystemCooConfig() - ObservedData_DirectoryCooConfig directoryCoo = new ObservedData_DirectoryCooConfig() - ObservedData_DomainNameCooConfig domainNameCoo = new ObservedData_DomainNameCooConfig() - ObservedData_EmailAddressCooConfig emailAddressCoo = new ObservedData_EmailAddressCooConfig() - ObservedData_EmailMessageCooConfig emailMessageCoo = new ObservedData_EmailMessageCooConfig() - ObservedData_FileCooConfig fileCoo = new ObservedData_FileCooConfig() - ObservedData_Ipv4AddressCooConfig ipv4AddressCoo = new ObservedData_Ipv4AddressCooConfig() - ObservedData_Ipv6AddressCooConfig ipv6AddressCoo = new ObservedData_Ipv6AddressCooConfig() - ObservedData_MacAddressCooConfig macAddressCoo = new ObservedData_MacAddressCooConfig() - ObservedData_MutexCooConfig mutexCoo = new ObservedData_MutexCooConfig() - ObservedData_NetworkTrafficCooConfig networkTrafficCoo = new ObservedData_NetworkTrafficCooConfig() - ObservedData_ProcessCooConfig processCoo = new ObservedData_ProcessCooConfig() - ObservedData_SoftwareCooConfig softwareCoo = new ObservedData_SoftwareCooConfig() - ObservedData_UrlCooConfig urlCoo = new ObservedData_UrlCooConfig() - ObservedData_UserAccountCooConfig userAccountCoo = new ObservedData_UserAccountCooConfig() - ObservedData_WindowsRegistryKeyCooConfig windowsRegisteryKeyCoo = new ObservedData_WindowsRegistryKeyCooConfig() - ObservedData_X509CertificateCooConfig x509CertificateCoo = new ObservedData_X509CertificateCooConfig() - - - ObservedData_ExternalReferencesConfig externalReferences = new ObservedData_ExternalReferencesConfig() - - ObservedData_GranularMarkingConfig granularMarkings = new ObservedData_GranularMarkingConfig() - - ObservedData_ObjectMarkingsConfig objectMarkings = new ObservedData_ObjectMarkingsConfig() - - int labelsOccurrenceProbability = 30 - -} diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_ArtifactCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_ArtifactCooConfig.groovy deleted file mode 100644 index 802790d..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_ArtifactCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_ArtifactCooConfig{ - int occurrence_probability = 100 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_AutonomousSystemCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_AutonomousSystemCooConfig.groovy deleted file mode 100644 index 1403b1a..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_AutonomousSystemCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_AutonomousSystemCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_DirectoryCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_DirectoryCooConfig.groovy deleted file mode 100644 index 1a964c3..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_DirectoryCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_DirectoryCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_DomainNameCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_DomainNameCooConfig.groovy deleted file mode 100644 index 30c2ea1..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_DomainNameCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_DomainNameCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_EmailAddressCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_EmailAddressCooConfig.groovy deleted file mode 100644 index f073e1f..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_EmailAddressCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_EmailAddressCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_EmailMessageCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_EmailMessageCooConfig.groovy deleted file mode 100644 index 41cae8d..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_EmailMessageCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_EmailMessageCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_ExternalReferencesConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_ExternalReferencesConfig.groovy deleted file mode 100644 index f65c832..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_ExternalReferencesConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_ExternalReferencesConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_FileCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_FileCooConfig.groovy deleted file mode 100644 index 466a7cd..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_FileCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_FileCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_GranularMarkingConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_GranularMarkingConfig.groovy deleted file mode 100644 index ca50fc4..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_GranularMarkingConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_GranularMarkingConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_Ipv4AddressCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_Ipv4AddressCooConfig.groovy deleted file mode 100644 index fe5bbd3..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_Ipv4AddressCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_Ipv4AddressCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_Ipv6AddressCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_Ipv6AddressCooConfig.groovy deleted file mode 100644 index 6c9a2d1..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_Ipv6AddressCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_Ipv6AddressCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_MacAddressCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_MacAddressCooConfig.groovy deleted file mode 100644 index ce49157..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_MacAddressCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_MacAddressCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_MutexCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_MutexCooConfig.groovy deleted file mode 100644 index 75751f5..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_MutexCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_MutexCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_NetworkTrafficCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_NetworkTrafficCooConfig.groovy deleted file mode 100644 index 4f1dfe9..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_NetworkTrafficCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_NetworkTrafficCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_ObjectMarkingsConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_ObjectMarkingsConfig.groovy deleted file mode 100644 index 258959d..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_ObjectMarkingsConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_ObjectMarkingsConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_ProcessCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_ProcessCooConfig.groovy deleted file mode 100644 index 26a6f3b..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_ProcessCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_ProcessCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_SoftwareCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_SoftwareCooConfig.groovy deleted file mode 100644 index 70a6030..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_SoftwareCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_SoftwareCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_UrlCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_UrlCooConfig.groovy deleted file mode 100644 index de26ceb..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_UrlCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_UrlCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_UserAccountCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_UserAccountCooConfig.groovy deleted file mode 100644 index 653876f..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_UserAccountCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_UserAccountCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_WindowsRegistryKeyCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_WindowsRegistryKeyCooConfig.groovy deleted file mode 100644 index b2b183c..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_WindowsRegistryKeyCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_WindowsRegistryKeyCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_X509CertificateCooConfig.groovy b/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_X509CertificateCooConfig.groovy deleted file mode 100644 index ca82ab9..0000000 --- a/src/test/groovy/faker/configs/sdo/observeddata/ObservedData_X509CertificateCooConfig.groovy +++ /dev/null @@ -1,7 +0,0 @@ -package faker.configs.sdo.observeddata - -class ObservedData_X509CertificateCooConfig { - int occurrence_probability = 10 - int occurs_count_lower = 1 - int occurs_count_upper = 5 -} \ No newline at end of file diff --git a/src/test/groovy/stix/bundle/BundleGraphSpec.groovy b/src/test/groovy/stix/bundle/BundleGraphSpec.groovy deleted file mode 100644 index abccfb3..0000000 --- a/src/test/groovy/stix/bundle/BundleGraphSpec.groovy +++ /dev/null @@ -1,69 +0,0 @@ -package stix.bundle - -import io.digitalstate.stix.bundle.Bundle -import io.digitalstate.stix.common.StixInstant -import io.digitalstate.stix.coo.objects.DomainName -import io.digitalstate.stix.coo.objects.Ipv4Address -import io.digitalstate.stix.graph.StixGraphGenerator -import io.digitalstate.stix.sdo.objects.AttackPattern -import io.digitalstate.stix.sdo.objects.ObservedData -import io.digitalstate.stix.sro.objects.Relationship -import io.digitalstate.stix.sro.objects.Sighting -import spock.lang.Specification - -class BundleGraphSpec extends Specification { - - def "Generate a Simple Graph of STIX data"() { - when: "Create Objects" - AttackPattern attackPattern1 = AttackPattern.builder().name("attk1").build() - AttackPattern attackPattern2 = AttackPattern.builder().name("attk2").build() - - Relationship relationship1 = Relationship.builder() - .sourceRef(attackPattern1) - .targetRef(attackPattern2) - .relationshipType("related-to") - .build() - - DomainName domainName1 = DomainName.builder() - .value("http://google.com") - .build() - Ipv4Address ip1 = Ipv4Address.builder().value("10.10.10.10").build() - Ipv4Address ip2 = Ipv4Address.builder().value("10.10.10.11").build() - Ipv4Address ip3 = Ipv4Address.builder().value("10.10.10.12").build() - Ipv4Address ip4 = Ipv4Address.builder().value("10.10.10.13").build() - Ipv4Address ip5 = Ipv4Address.builder().value("10.10.10.14").build() - Ipv4Address ip6 = Ipv4Address.builder().value("10.10.10.15").build() - - ObservedData observedData1 = ObservedData.builder() - .addObjects(domainName1, ip1, ip2, ip3, ip4, ip5, ip6) - .firstObserved(new StixInstant()) - .lastObserved(new StixInstant()) - .numberObserved(2) - .build() - - Sighting sighting1 = Sighting.builder() - .firstSeen(new StixInstant()) - .lastSeen(new StixInstant()) - .count(1) - .sightingOfRef(attackPattern1) - .addObservedDataRef(observedData1) - .build() - - then: "build bundle" - - Bundle bundle = Bundle.builder() - .addObjects(attackPattern1, attackPattern2, relationship1, observedData1, sighting1) - .build() - - println bundle.toString() - - then: "generate graph json" - - StixGraphGenerator graph = new StixGraphGenerator(bundle) - - println graph.process().toString() - - println graph.toJson() - - } -} diff --git a/src/test/groovy/stix/bundle/BundleSpec.groovy b/src/test/groovy/stix/bundle/BundleSpec.groovy deleted file mode 100644 index 0562338..0000000 --- a/src/test/groovy/stix/bundle/BundleSpec.groovy +++ /dev/null @@ -1,125 +0,0 @@ -package stix.bundle - -import com.fasterxml.jackson.core.JsonGenerator -import com.fasterxml.jackson.core.JsonParser -import com.fasterxml.jackson.core.TreeNode -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.node.ArrayNode -import io.digitalstate.stix.bundle.Bundle -import io.digitalstate.stix.bundle.BundleableObject -import io.digitalstate.stix.json.StixParsers -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import spock.lang.Ignore -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import faker.StixMockDataGenerator - -class BundleSpec extends Specification { - - @Shared - ObjectMapper mapper = new ObjectMapper() - @Shared - StixMockDataGenerator stixMockDataGenerator = new StixMockDataGenerator() - - @Unroll - def "Generate Bundle Data: Run: '#i'"() { - when: "Generating Bundle Data" - Bundle originalBundle = stixMockDataGenerator.mockBundle(1, 2) - - JsonNode originalJson = mapper.readTree(originalBundle.toJsonString()) - String originalJsonString = mapper.writeValueAsString(originalJson) -// println "Original Json: ${originalJsonString}" - - then: "Parse Json back into Bundle Object" - Bundle parsedBundle = (Bundle) StixParsers.parseBundle(originalJsonString) - Bundle parsedBundleGeneric = StixParsers.parse(originalJsonString, Bundle.class) -// println "Parsed Object: ${parsedBundle}" - - //@TODO needs to be setup to handle dehydrated object comparison - then: "Parsed object should match Original object" -// assert originalAttackPattern == parsedAttackPattern - - then: "Convert Parsed Bundle back to into Json" - JsonNode newJson = mapper.readTree(parsedBundle.toJsonString()) - String newJsonString = mapper.writeValueAsString(newJson) -// println "New Json: ${newJsonString}" - - then: "New Json should match Original Json" - JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) - - where: - i << (1..100) // More tests are run because of the large variation of probabilities and number of combinations - } - - def "Parse Indicator Bundle"() { - - when: "setup file access to bundle" - - String bundleJson = getClass() - .getResource("/stix/baseline/json/sdo/indicator/indicators.json").getText("UTF-8") - - then: "Parse json into bundle" - Bundle bundle = (Bundle) StixParsers.parseBundle(bundleJson) -// println bundle.toJsonString() - - and: "the original bundle json matches the parsed object that was converted back to json" - assert mapper.readTree(bundle.toJsonString()) == mapper.readTree(bundleJson) - } - - @Ignore - def "Generate File of a large Bundle"() { - when: "Generating Bundle Data" - Bundle originalBundle = stixMockDataGenerator.mockBundle(1, 2) - - then: "Convert Bundle to Json" - FileWriter fileWriter = new FileWriter(new File("./bundle-large.json")) - - JsonGenerator jg = StixParsers.getJsonMapper() - .getFactory() - .createGenerator(fileWriter) - - // Change this value to generate different sizes - int objectCount = 50000 - - jg.writeStartObject() - - jg.writeStringField("id", originalBundle.getId()) - jg.writeStringField("type", originalBundle.getType()) - jg.writeStringField("spec_version", originalBundle.getSpecVersion()) - - jg.writeArrayFieldStart("objects") - objectCount.times({ o -> - jg.writeObject(stixMockDataGenerator.generateRandomBundleableObject()) - }) - jg.writeEndArray() - - jg.writeEndObject() - - jg.close() - fileWriter.close() - } - - @Ignore - def "Parse Large Bundle"() { - when: - File file = new File("./bundle-large.json") - - then: - JsonParser parser = StixParsers.getJsonMapper().getFactory().createParser(file) - - then: - TreeNode tree = parser.readValueAsTree() - TreeNode objectsArray = tree.get("objects") - if (objectsArray.isArray()){ - ((ArrayNode)objectsArray).each {o -> - BundleableObject bundleableObject = o.traverse(parser.getCodec()) - .readValueAs(BundleableObject.class) - - println bundleableObject - } - } - } -} diff --git a/src/test/groovy/stix/custom/CustomObjectSpec.groovy b/src/test/groovy/stix/custom/CustomObjectSpec.groovy deleted file mode 100644 index 49d4927..0000000 --- a/src/test/groovy/stix/custom/CustomObjectSpec.groovy +++ /dev/null @@ -1,30 +0,0 @@ -package stix.custom - -import com.fasterxml.jackson.databind.ObjectMapper -import io.digitalstate.stix.bundle.BundleableObject -import io.digitalstate.stix.custom.StixCustomObject -import io.digitalstate.stix.custom.objects.CustomObject -import io.digitalstate.stix.json.StixParsers -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll - -class CustomObjectSpec extends Specification { - - @Shared ObjectMapper mapper = new ObjectMapper() - - @Unroll - def "Generic Object Test 1"() { - when: "Attempt to Parse a custom object" - String jsonString = getClass().getResource("/stix/custom/custom_object_1.json").getText("UTF-8") - - then: - StixCustomObject originalObject = (StixCustomObject)StixParsers.parseObject(jsonString) - StixCustomObject originalObjectGeneric = StixParsers.parse(jsonString, CustomObject.class) - BundleableObject bundleableObject = StixParsers.parse(jsonString, BundleableObject.class) -// println originalObject -// println originalObjectGeneric -// println bundleableObject -// println "********" - } -} diff --git a/src/test/groovy/stix/datamarkings/MarkingDefinitionSpec.groovy b/src/test/groovy/stix/datamarkings/MarkingDefinitionSpec.groovy deleted file mode 100644 index 4603a67..0000000 --- a/src/test/groovy/stix/datamarkings/MarkingDefinitionSpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package stix.datamarkings - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import io.digitalstate.stix.datamarkings.MarkingDefinition -import io.digitalstate.stix.json.StixParsers -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import faker.StixMockDataGenerator - -class MarkingDefinitionSpec extends Specification{ - - @Shared ObjectMapper mapper = new ObjectMapper() - @Shared StixMockDataGenerator stixMockDataGenerator = new StixMockDataGenerator() - - @Unroll - def "Generate Marking Definition Data: Run: '#i'"() { - when: "Generating Marking Definition Data" - MarkingDefinition originalMarkingDefinition = stixMockDataGenerator.mockMarkingDefinition() -// println "Original Object: ${originalMarkingDefinition.toString()}" - - then: "Convert Marking Definition to Json" - JsonNode originalJson = mapper.readTree(originalMarkingDefinition.toJsonString()) - String originalJsonString = mapper.writeValueAsString(originalJson) -// println "Original Json: ${originalJsonString}" - - then: "Parse Json back into Marking Definition Object" - MarkingDefinition parsedMarkingDefinition = (MarkingDefinition)StixParsers.parseObject(originalJsonString) - MarkingDefinition parsedMarkingDefinitionGeneric = StixParsers.parse(originalJsonString, MarkingDefinition.class) -// println "Parsed Object: ${parsedMarkingDefinition}" - - //@TODO needs to be setup to handle dehydrated object comparison -// then: "Parsed object should match Original object" -// assert originalMarkingDefinition == parsedMarkingDefinition - - then: "Convert Parsed Marking Definition Object back to into Json" - JsonNode newJson = mapper.readTree(parsedMarkingDefinition.toJsonString()) - String newJsonString = mapper.writeValueAsString(newJson) -// println "New Json: ${newJsonString}" - - then: "New Json should match Original Json" - JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) - - where: - i << (1..100) - } -} diff --git a/src/test/groovy/stix/sdo/AttackPatternSpec.groovy b/src/test/groovy/stix/sdo/AttackPatternSpec.groovy deleted file mode 100644 index bec51f0..0000000 --- a/src/test/groovy/stix/sdo/AttackPatternSpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package stix.sdo - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import io.digitalstate.stix.json.StixParsers -import io.digitalstate.stix.sdo.objects.AttackPattern -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import faker.StixMockDataGenerator - -class AttackPatternSpec extends Specification { - - @Shared ObjectMapper mapper = new ObjectMapper() - @Shared StixMockDataGenerator stixMockDataGenerator = new StixMockDataGenerator() - - @Unroll - def "Generate Attack Pattern Data: Run: '#i'"() { - when: "Generating Attack Pattern Data" - AttackPattern originalAttackPattern = stixMockDataGenerator.mockAttackPattern() -// println "Original Object: ${originalAttackPattern.toString()}" - - then: "Convert Attack Pattern to Json" - JsonNode originalJson = mapper.readTree(originalAttackPattern.toJsonString()) - String originalJsonString = mapper.writeValueAsString(originalJson) -// println "Original Json: ${originalJsonString}" - - then: "Parse Json back into Attack Pattern Object" - AttackPattern parsedAttackPattern = (AttackPattern)StixParsers.parseObject(originalJsonString) - AttackPattern parsedAttackPatternGeneric = StixParsers.parse(originalJsonString, AttackPattern.class) -// println "Parsed Object: ${parsedAttackPattern}" - - //@TODO needs to be setup to handle dehydrated object comparison -// then: "Parsed object should match Original object" -// assert originalAttackPattern == parsedAttackPattern - - then: "Convert Parsed Attack Pattern Object back to into Json" - JsonNode newJson = mapper.readTree(parsedAttackPattern.toJsonString()) - String newJsonString = mapper.writeValueAsString(newJson) -// println "New Json: ${newJsonString}" - - then: "New Json should match Original Json" - JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) - - where: - i << (1..100) - } -} diff --git a/src/test/groovy/stix/sdo/CampaignSpec.groovy b/src/test/groovy/stix/sdo/CampaignSpec.groovy deleted file mode 100644 index e84bb4b..0000000 --- a/src/test/groovy/stix/sdo/CampaignSpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package stix.sdo - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import io.digitalstate.stix.json.StixParsers -import io.digitalstate.stix.sdo.objects.Campaign -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import faker.StixMockDataGenerator - -class CampaignSpec extends Specification { - - @Shared ObjectMapper mapper = new ObjectMapper() - @Shared StixMockDataGenerator stixMockDataGenerator = new StixMockDataGenerator() - - @Unroll - def "Generate Campaign Data: Run: '#i'"() { - when: "Generating Campaign Data" - Campaign originalCampaign = stixMockDataGenerator.mockCampaign() -// println "Original Object: ${originalCampaign.toString()}" - - then: "Convert Campaign to Json" - JsonNode originalJson = mapper.readTree(originalCampaign.toJsonString()) - String originalJsonString = mapper.writeValueAsString(originalJson) -// println "Original Json: ${originalJsonString}" - - then: "Parse Json back into Campaign Object" - Campaign parsedCampaign = (Campaign)StixParsers.parseObject(originalJsonString) - Campaign parsedCampaignGeneric = StixParsers.parse(originalJsonString, Campaign.class) -// println "Parsed Object: ${parsedCampaign}" - - //@TODO needs to be setup to handle dehydrated object comparison -// then: "Parsed object should match Original object" -// assert originalAttackPattern == parsedAttackPattern - - then: "Convert Parsed Identity Object back to into Json" - JsonNode newJson = mapper.readTree(parsedCampaign.toJsonString()) - String newJsonString = mapper.writeValueAsString(newJson) -// println "New Json: ${newJsonString}" - - then: "New Json should match Original Json" - JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) - - where: - i << (1..100) - } -} diff --git a/src/test/groovy/stix/sdo/CourseOfActionSpec.groovy b/src/test/groovy/stix/sdo/CourseOfActionSpec.groovy deleted file mode 100644 index 6d11b4a..0000000 --- a/src/test/groovy/stix/sdo/CourseOfActionSpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package stix.sdo - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import io.digitalstate.stix.json.StixParsers -import io.digitalstate.stix.sdo.objects.CourseOfAction -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import faker.StixMockDataGenerator - -class CourseOfActionSpec extends Specification { - - @Shared ObjectMapper mapper = new ObjectMapper() - @Shared StixMockDataGenerator stixMockDataGenerator = new StixMockDataGenerator() - - @Unroll - def "Generate Course of Action Data: Run: '#i'"() { - when: "Generating Identity Data" - CourseOfAction originalCourseOfAction = stixMockDataGenerator.mockCourseOfAction() -// println "Original Object: ${originalCourseOfAction.toString()}" - - then: "Convert Course of Action to Json" - JsonNode originalJson = mapper.readTree(originalCourseOfAction.toJsonString()) - String originalJsonString = mapper.writeValueAsString(originalJson) -// println "Original Json: ${originalJsonString}" - - then: "Parse Json back into Course of Action Object" - CourseOfAction parsedCourseOfAction = (CourseOfAction)StixParsers.parseObject(originalJsonString) - CourseOfAction parsedCourseOfActionGeneric = StixParsers.parse(originalJsonString, CourseOfAction.class) -// println "Parsed Object: ${parsedCourseOfAction}" - - //@TODO needs to be setup to handle dehydrated object comparison -// then: "Parsed object should match Original object" -// assert originalAttackPattern == parsedAttackPattern - - then: "Convert Parsed Identity Object back to into Json" - JsonNode newJson = mapper.readTree(parsedCourseOfAction.toJsonString()) - String newJsonString = mapper.writeValueAsString(newJson) -// println "New Json: ${newJsonString}" - - then: "New Json should match Original Json" - JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) - - where: - i << (1..100) - } -} diff --git a/src/test/groovy/stix/sdo/IdentitySpec.groovy b/src/test/groovy/stix/sdo/IdentitySpec.groovy deleted file mode 100644 index a95359e..0000000 --- a/src/test/groovy/stix/sdo/IdentitySpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package stix.sdo - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import io.digitalstate.stix.json.StixParsers -import io.digitalstate.stix.sdo.objects.Identity -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import faker.StixMockDataGenerator - -class IdentitySpec extends Specification { - - @Shared ObjectMapper mapper = new ObjectMapper() - @Shared StixMockDataGenerator stixMockDataGenerator = new StixMockDataGenerator() - - @Unroll - def "Generate Identity Data: Run: '#i'"() { - when: "Generating Identity Data" - Identity originalIdentity = stixMockDataGenerator.mockIdentity() -// println "Original Object: ${originalIdentity.toString()}" - - then: "Convert Identity to Json" - JsonNode originalJson = mapper.readTree(originalIdentity.toJsonString()) - String originalJsonString = mapper.writeValueAsString(originalJson) -// println "Original Json: ${originalJsonString}" - - then: "Parse Json back into Attack Pattern Object" - Identity parsedIdentity = (Identity)StixParsers.parseObject(originalJsonString) - Identity parsedIdentityGeneric = StixParsers.parse(originalJsonString, Identity.class) -// println "Parsed Object: ${parsedIdentity}" - - //@TODO needs to be setup to handle dehydrated object comparison -// then: "Parsed object should match Original object" -// assert originalAttackPattern == parsedAttackPattern - - then: "Convert Parsed Identity Object back to into Json" - JsonNode newJson = mapper.readTree(parsedIdentity.toJsonString()) - String newJsonString = mapper.writeValueAsString(newJson) -// println "New Json: ${newJsonString}" - - then: "New Json should match Original Json" - JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) - - where: - i << (1..100) - } -} diff --git a/src/test/groovy/stix/sdo/IndicatorSpec.groovy b/src/test/groovy/stix/sdo/IndicatorSpec.groovy deleted file mode 100644 index 8580dbc..0000000 --- a/src/test/groovy/stix/sdo/IndicatorSpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package stix.sdo - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import io.digitalstate.stix.json.StixParsers -import io.digitalstate.stix.sdo.objects.Indicator -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import faker.StixMockDataGenerator - -class IndicatorSpec extends Specification { - - @Shared ObjectMapper mapper = new ObjectMapper() - @Shared StixMockDataGenerator stixMockDataGenerator = new StixMockDataGenerator() - - @Unroll - def "Generate Indicator Data: Run: '#i'"() { - when: "Generating Indicator Data" - Indicator originalIndicator = stixMockDataGenerator.mockIndicator() -// println "Original Object: ${originalIndicator.toString()}" - - then: "Convert Indicator to Json" - JsonNode originalJson = mapper.readTree(originalIndicator.toJsonString()) - String originalJsonString = mapper.writeValueAsString(originalJson) -// println "Original Json: ${originalJsonString}" - - then: "Parse Json back into Indicator Object" - Indicator parsedIndicator = (Indicator)StixParsers.parseObject(originalJsonString) - Indicator parsedIndicatorGeneric = StixParsers.parse(originalJsonString, Indicator.class) -// println "Parsed Object: ${parsedIndicator}" - - //@TODO needs to be setup to handle dehydrated object comparison -// then: "Parsed object should match Original object" -// assert originalAttackPattern == parsedAttackPattern - - then: "Convert Parsed Indicator back to into Json" - JsonNode newJson = mapper.readTree(parsedIndicator.toJsonString()) - String newJsonString = mapper.writeValueAsString(newJson) -// println "New Json: ${newJsonString}" - - then: "New Json should match Original Json" - JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) - - where: - i << (1..100) - } -} diff --git a/src/test/groovy/stix/sdo/IntrusionSetSpec.groovy b/src/test/groovy/stix/sdo/IntrusionSetSpec.groovy deleted file mode 100644 index 4c18fe1..0000000 --- a/src/test/groovy/stix/sdo/IntrusionSetSpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package stix.sdo - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import io.digitalstate.stix.json.StixParsers -import io.digitalstate.stix.sdo.objects.IntrusionSet -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import faker.StixMockDataGenerator - -class IntrusionSetSpec extends Specification { - - @Shared ObjectMapper mapper = new ObjectMapper() - @Shared StixMockDataGenerator stixMockDataGenerator = new StixMockDataGenerator() - - @Unroll - def "Generate Intrusion Set Data: Run: '#i'"() { - when: "Generating Intrusion Set Data" - IntrusionSet originalIntrusionSet = stixMockDataGenerator.mockIntrusionSet() -// println "Original Object: ${originalIntrusionSet.toString()}" - - then: "Convert Intrusion Set to Json" - JsonNode originalJson = mapper.readTree(originalIntrusionSet.toJsonString()) - String originalJsonString = mapper.writeValueAsString(originalJson) -// println "Original Json: ${originalJsonString}" - - then: "Parse Json back into Intrusion Set Object" - IntrusionSet parsedIntrusionSet = (IntrusionSet)StixParsers.parseObject(originalJsonString) - IntrusionSet parsedIntrusionSetGeneric = StixParsers.parse(originalJsonString, IntrusionSet.class) -// println "Parsed Object: ${parsedIntrusionSet}" - - //@TODO needs to be setup to handle dehydrated object comparison -// then: "Parsed object should match Original object" -// assert originalAttackPattern == parsedAttackPattern - - then: "Convert Parsed Intrusion Set back to into Json" - JsonNode newJson = mapper.readTree(parsedIntrusionSet.toJsonString()) - String newJsonString = mapper.writeValueAsString(newJson) -// println "New Json: ${newJsonString}" - - then: "New Json should match Original Json" - JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) - - where: - i << (1..100) - } -} diff --git a/src/test/groovy/stix/sdo/MalwareSpec.groovy b/src/test/groovy/stix/sdo/MalwareSpec.groovy deleted file mode 100644 index b047e9b..0000000 --- a/src/test/groovy/stix/sdo/MalwareSpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package stix.sdo - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import io.digitalstate.stix.json.StixParsers -import io.digitalstate.stix.sdo.objects.Malware -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import faker.StixMockDataGenerator - -class MalwareSpec extends Specification { - - @Shared ObjectMapper mapper = new ObjectMapper() - @Shared StixMockDataGenerator stixMockDataGenerator = new StixMockDataGenerator() - - @Unroll - def "Generate Malware Data: Run: '#i'"() { - when: "Generating Malware Data" - Malware originalMalware = stixMockDataGenerator.mockMalware() -// println "Original Object: ${originalMalware.toString()}" - - then: "Convert Malware to Json" - JsonNode originalJson = mapper.readTree(originalMalware.toJsonString()) - String originalJsonString = mapper.writeValueAsString(originalJson) -// println "Original Json: ${originalJsonString}" - - then: "Parse Json back into Malware Object" - Malware parsedMalware = (Malware)StixParsers.parseObject(originalJsonString) - Malware parsedMalwareGeneric = StixParsers.parse(originalJsonString, Malware.class) -// println "Parsed Object: ${parsedMalware}" - - //@TODO needs to be setup to handle dehydrated object comparison -// then: "Parsed object should match Original object" -// assert originalAttackPattern == parsedAttackPattern - - then: "Convert Parsed Malware back to into Json" - JsonNode newJson = mapper.readTree(parsedMalware.toJsonString()) - String newJsonString = mapper.writeValueAsString(newJson) -// println "New Json: ${newJsonString}" - - then: "New Json should match Original Json" - JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) - - where: - i << (1..100) - } -} diff --git a/src/test/groovy/stix/sdo/ObservedDataSpec.groovy b/src/test/groovy/stix/sdo/ObservedDataSpec.groovy deleted file mode 100644 index f83d202..0000000 --- a/src/test/groovy/stix/sdo/ObservedDataSpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package stix.sdo - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import io.digitalstate.stix.json.StixParsers -import io.digitalstate.stix.sdo.objects.ObservedData -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import faker.StixMockDataGenerator - -class ObservedDataSpec extends Specification { - - @Shared ObjectMapper mapper = new ObjectMapper() - @Shared StixMockDataGenerator stixMockDataGenerator = new StixMockDataGenerator() - - @Unroll - def "Generate Observed-Data Data: Run: '#i'"() { - when: "Generating Observed-Data Data" - ObservedData originalObservedData = stixMockDataGenerator.mockObservedData() -// println "Original Object: ${originalObservedData.toString()}" - - then: "Convert Observed-Data to Json" - JsonNode originalJson = mapper.readTree(originalObservedData.toJsonString()) - String originalJsonString = mapper.writeValueAsString(originalJson) -// println "Original Json: ${originalJsonString}" - - then: "Parse Json back into Observed-Data Object" - ObservedData parsedObservedData = (ObservedData)StixParsers.parseObject(originalJsonString) - ObservedData parsedObservedDataGeneric = StixParsers.parse(originalJsonString, ObservedData.class) -// println "Parsed Object: ${parsedObservedData}" - - //@TODO needs to be setup to handle dehydrated object comparison -// then: "Parsed object should match Original object" -// assert originalAttackPattern == parsedAttackPattern - - then: "Convert Parsed Observed-Data back to into Json" - JsonNode newJson = mapper.readTree(parsedObservedData.toJsonString()) - String newJsonString = mapper.writeValueAsString(newJson) -// println "New Json: ${newJsonString}" - - then: "New Json should match Original Json" - JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) - - where: - i << (1..5000) // More tests are run because of the large variation of probabilities and number of combinations - } -} diff --git a/src/test/groovy/stix/sdo/ReportSpec.groovy b/src/test/groovy/stix/sdo/ReportSpec.groovy deleted file mode 100644 index f14288e..0000000 --- a/src/test/groovy/stix/sdo/ReportSpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package stix.sdo - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import io.digitalstate.stix.json.StixParsers -import io.digitalstate.stix.sdo.objects.Report -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import faker.StixMockDataGenerator - -class ReportSpec extends Specification { - - @Shared ObjectMapper mapper = new ObjectMapper() - @Shared StixMockDataGenerator stixMockDataGenerator = new StixMockDataGenerator() - - @Unroll - def "Generate Report Data: Run: '#i'"() { - when: "Generating Report Data" - Report originalReport = stixMockDataGenerator.mockReport() -// println "Original Object: ${originalReport.toString()}" - - then: "Convert Report to Json" - JsonNode originalJson = mapper.readTree(originalReport.toJsonString()) - String originalJsonString = mapper.writeValueAsString(originalJson) -// println "Original Json: ${originalJsonString}" - - then: "Parse Json back into Report Object" - Report parsedReport = (Report)StixParsers.parseObject(originalJsonString) - Report parsedReportGeneric = StixParsers.parse(originalJsonString, Report.class) -// println "Parsed Object: ${parsedReport}" - - //@TODO needs to be setup to handle dehydrated object comparison -// then: "Parsed object should match Original object" -// assert originalAttackPattern == parsedAttackPattern - - then: "Convert Parsed Report back to into Json" - JsonNode newJson = mapper.readTree(parsedReport.toJsonString()) - String newJsonString = mapper.writeValueAsString(newJson) -// println "New Json: ${newJsonString}" - - then: "New Json should match Original Json" - JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) - - where: - i << (1..500) // More tests are run because of the large variation of probabilities and number of combinations - } -} diff --git a/src/test/groovy/stix/sdo/ThreatActorSpec.groovy b/src/test/groovy/stix/sdo/ThreatActorSpec.groovy deleted file mode 100644 index 6bf5023..0000000 --- a/src/test/groovy/stix/sdo/ThreatActorSpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package stix.sdo - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import io.digitalstate.stix.json.StixParsers -import io.digitalstate.stix.sdo.objects.ThreatActor -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import faker.StixMockDataGenerator - -class ThreatActorSpec extends Specification { - - @Shared ObjectMapper mapper = new ObjectMapper() - @Shared StixMockDataGenerator stixMockDataGenerator = new StixMockDataGenerator() - - @Unroll - def "Generate Threat Actor Data: Run: '#i'"() { - when: "Generating Threat Actor Data" - ThreatActor originalThreatActor = stixMockDataGenerator.mockThreatActor() -// println "Original Object: ${originalThreatActor.toString()}" - - then: "Convert Threat Actor to Json" - JsonNode originalJson = mapper.readTree(originalThreatActor.toJsonString()) - String originalJsonString = mapper.writeValueAsString(originalJson) -// println "Original Json: ${originalJsonString}" - - then: "Parse Json back into Threat Actor Object" - ThreatActor parsedThreatActor = (ThreatActor)StixParsers.parseObject(originalJsonString) - ThreatActor parsedThreatActorGeneric = StixParsers.parse(originalJsonString, ThreatActor.class) -// println "Parsed Object: ${parsedThreatActor}" - - //@TODO needs to be setup to handle dehydrated object comparison -// then: "Parsed object should match Original object" -// assert originalAttackPattern == parsedAttackPattern - - then: "Convert Parsed Threat Actor back to into Json" - JsonNode newJson = mapper.readTree(parsedThreatActor.toJsonString()) - String newJsonString = mapper.writeValueAsString(newJson) -// println "New Json: ${newJsonString}" - - then: "New Json should match Original Json" - JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) - - where: - i << (1..100) // More tests are run because of the large variation of probabilities and number of combinations - } -} diff --git a/src/test/groovy/stix/sdo/ToolSpec.groovy b/src/test/groovy/stix/sdo/ToolSpec.groovy deleted file mode 100644 index 13e1b00..0000000 --- a/src/test/groovy/stix/sdo/ToolSpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package stix.sdo - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import io.digitalstate.stix.json.StixParsers -import io.digitalstate.stix.sdo.objects.Tool -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import faker.StixMockDataGenerator - -class ToolSpec extends Specification { - - @Shared ObjectMapper mapper = new ObjectMapper() - @Shared StixMockDataGenerator stixMockDataGenerator = new StixMockDataGenerator() - - @Unroll - def "Generate Tool Data: Run: '#i'"() { - when: "Generating Tool Data" - Tool originalTool = stixMockDataGenerator.mockTool() -// println "Original Object: ${originalTool.toString()}" - - then: "Convert Tool to Json" - JsonNode originalJson = mapper.readTree(originalTool.toJsonString()) - String originalJsonString = mapper.writeValueAsString(originalJson) -// println "Original Json: ${originalJsonString}" - - then: "Parse Json back into Tool Object" - Tool parsedTool = (Tool)StixParsers.parseObject(originalJsonString) - Tool parsedToolGeneric = StixParsers.parse(originalJsonString, Tool.class) -// println "Parsed Object: ${parsedTool}" - - //@TODO needs to be setup to handle dehydrated object comparison -// then: "Parsed object should match Original object" -// assert originalAttackPattern == parsedAttackPattern - - then: "Convert Parsed Tool back to into Json" - JsonNode newJson = mapper.readTree(parsedTool.toJsonString()) - String newJsonString = mapper.writeValueAsString(newJson) -// println "New Json: ${newJsonString}" - - then: "New Json should match Original Json" - JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) - - where: - i << (1..100) // More tests are run because of the large variation of probabilities and number of combinations - } -} diff --git a/src/test/groovy/stix/sdo/VulnerabilitySpec.groovy b/src/test/groovy/stix/sdo/VulnerabilitySpec.groovy deleted file mode 100644 index b09d2ad..0000000 --- a/src/test/groovy/stix/sdo/VulnerabilitySpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package stix.sdo - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import io.digitalstate.stix.json.StixParsers -import io.digitalstate.stix.sdo.objects.Vulnerability -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import faker.StixMockDataGenerator - -class VulnerabilitySpec extends Specification { - - @Shared ObjectMapper mapper = new ObjectMapper() - @Shared StixMockDataGenerator stixMockDataGenerator = new StixMockDataGenerator() - - @Unroll - def "Generate Vulnerability Data: Run: '#i'"() { - when: "Generating Vulnerability Data" - Vulnerability originalVulnerability = stixMockDataGenerator.mockVulnerability() -// println "Original Object: ${originalVulnerability.toString()}" - - then: "Convert Vulnerability to Json" - JsonNode originalJson = mapper.readTree(originalVulnerability.toJsonString()) - String originalJsonString = mapper.writeValueAsString(originalJson) -// println "Original Json: ${originalJsonString}" - - then: "Parse Json back into Vulnerability Object" - Vulnerability parsedVulnerability = (Vulnerability)StixParsers.parseObject(originalJsonString) - Vulnerability parsedVulnerabilityGeneric = StixParsers.parse(originalJsonString, Vulnerability.class) -// println "Parsed Object: ${parsedVulnerability}" - - //@TODO needs to be setup to handle dehydrated object comparison -// then: "Parsed object should match Original object" -// assert originalAttackPattern == parsedAttackPattern - - then: "Convert Parsed Vulnerability back to into Json" - JsonNode newJson = mapper.readTree(parsedVulnerability.toJsonString()) - String newJsonString = mapper.writeValueAsString(newJson) -// println "New Json: ${newJsonString}" - - then: "New Json should match Original Json" - JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) - - where: - i << (1..100) // More tests are run because of the large variation of probabilities and number of combinations - } -} diff --git a/src/test/groovy/stix/sro/RelationshipSpec.groovy b/src/test/groovy/stix/sro/RelationshipSpec.groovy deleted file mode 100644 index fa6b38d..0000000 --- a/src/test/groovy/stix/sro/RelationshipSpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package stix.sro - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import io.digitalstate.stix.json.StixParsers -import io.digitalstate.stix.sro.objects.Relationship -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import faker.StixMockDataGenerator - -class RelationshipSpec extends Specification { - - @Shared ObjectMapper mapper = new ObjectMapper() - @Shared StixMockDataGenerator stixMockDataGenerator = new StixMockDataGenerator() - - @Unroll - def "Generate Relationship SRO Data: Run: '#i'"() { - when: "Generating Relationship SRO Data" - Relationship originalRelationship = stixMockDataGenerator.mockRelationship() -// println "Original Object: ${originalRelationship.toString()}" - - then: "Convert Relationship to Json" - JsonNode originalJson = mapper.readTree(originalRelationship.toJsonString()) - String originalJsonString = mapper.writeValueAsString(originalJson) -// println "Original Json: ${originalJsonString}" - - then: "Parse Json back into Relationship Object" - Relationship parsedRelationship = (Relationship)StixParsers.parseObject(originalJsonString) - Relationship parsedRelationshipGeneric = StixParsers.parse(originalJsonString, Relationship.class) -// println "Parsed Object: ${parsedRelationship}" - - //@TODO needs to be setup to handle dehydrated object comparison -// then: "Parsed object should match Original object" -// assert originalRelationship == parsedMarkingDefinition - - then: "Convert Parsed Relationship Object back to into Json" - JsonNode newJson = mapper.readTree(parsedRelationship.toJsonString()) - String newJsonString = mapper.writeValueAsString(newJson) -// println "New Json: ${newJsonString}" - - then: "New Json should match Original Json" - JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) - - where: - i << (1..100) - } -} diff --git a/src/test/groovy/stix/sro/SightingSpec.groovy b/src/test/groovy/stix/sro/SightingSpec.groovy deleted file mode 100644 index 9edca11..0000000 --- a/src/test/groovy/stix/sro/SightingSpec.groovy +++ /dev/null @@ -1,50 +0,0 @@ -package stix.sro - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import io.digitalstate.stix.json.StixParsers -import io.digitalstate.stix.sro.objects.Sighting -import org.skyscreamer.jsonassert.JSONAssert -import org.skyscreamer.jsonassert.JSONCompareMode -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll -import faker.StixMockDataGenerator - -class SightingSpec extends Specification { - - @Shared ObjectMapper mapper = new ObjectMapper() - @Shared StixMockDataGenerator stixMockDataGenerator = new StixMockDataGenerator() - - @Unroll - def "Generate Sighting SRO Data: Run: '#i'"() { - when: "Generating Sighting SRO Data" - Sighting originalSighting = stixMockDataGenerator.mockSighting() -// println "Original Object: ${originalSighting.toString()}" - - then: "Convert Sighting to Json" - JsonNode originalJson = mapper.readTree(originalSighting.toJsonString()) - String originalJsonString = mapper.writeValueAsString(originalJson) -// println "Original Json: ${originalJsonString}" - - then: "Parse Json back into Sighting Object" - Sighting parsedSighting = (Sighting)StixParsers.parseObject(originalJsonString) - Sighting parsedSightingGeneric = StixParsers.parse(originalJsonString, Sighting.class) -// println "Parsed Object: ${parsedSighting}" - - //@TODO needs to be setup to handle dehydrated object comparison -// then: "Parsed object should match Original object" -// assert originalSighting == parsedMarkingDefinition - - then: "Convert Parsed Sighting Object back to into Json" - JsonNode newJson = mapper.readTree(parsedSighting.toJsonString()) - String newJsonString = mapper.writeValueAsString(newJson) -// println "New Json: ${newJsonString}" - - then: "New Json should match Original Json" - JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) - - where: - i << (1..100) - } -} diff --git a/src/test/groovy/stix/stixinstant/StixInstantSpec.groovy b/src/test/groovy/stix/stixinstant/StixInstantSpec.groovy deleted file mode 100644 index b08b810..0000000 --- a/src/test/groovy/stix/stixinstant/StixInstantSpec.groovy +++ /dev/null @@ -1,37 +0,0 @@ -package stix.stixinstant - -import io.digitalstate.stix.json.StixParsers -import io.digitalstate.stix.sdo.objects.Campaign -import spock.lang.Specification - -class StixInstantSpec extends Specification { - - def "time test to ensure Instant Precisions are maintained"(){ - when: - Campaign campaignCreatedNoSubSec = StixParsers.parseObject("{\"type\":\"campaign\",\"id\":\"campaign--854ae5bf-e07b-4853-95f8-0f85027af1ea\",\"created_by_ref\":\"identity--5eb4619f-b1b6-4b7b-9504-bd3b4d05ce8a\",\"created\":\"2019-04-26T21:14:11Z\",\"modified\":\"2019-04-26T21:14:11.851Z\",\"revoked\":false,\"labels\":[\"interspersed\",\"yep\",\"contemners\",\"spurts\",\"aft\",\"aldose\"],\"granular_markings\":[{\"marking_ref\":\"marking-definition--980dffe6-2006-45bc-86c7-9885c986fdaa\",\"selectors\":[\"broch\",\"lipped\"],\"x_delimitates\":\"thick\",\"x_chocolaty\":380412,\"x_disarmingly\":\"cataplexy eyeleted poss belike told reformism neglect grillage purer justiciars boosts about haste compulsive over reinvolve blackly obliterate gamy here suffused triaxial tuatara circlers fianchetto aforementioned viverrine drowsily ties screeds fun larvicidal wuthering condyloma epistolize intwines loins ditto litho bluish straightaway restaged\",\"x_dryer\":327849,\"x_unblushingly\":false},{\"marking_ref\":\"marking-definition--f82c9f27-edb4-496b-9eca-58080db5d16d\",\"selectors\":[\"bootleg\",\"muclucs\",\"eild\",\"vandalises\",\"sardiuses\",\"astray\",\"exhaustively\",\"pyrogallic\"]}],\"name\":\"disastrously\"}") - Campaign campaignCreated9SubSec = StixParsers.parseObject("{\"type\":\"campaign\",\"id\":\"campaign--854ae5bf-e07b-4853-95f8-0f85027af1ea\",\"created_by_ref\":\"identity--5eb4619f-b1b6-4b7b-9504-bd3b4d05ce8a\",\"created\":\"2019-04-26T21:14:11.999999999Z\",\"modified\":\"2019-04-26T21:14:11.851Z\",\"revoked\":false,\"labels\":[\"interspersed\",\"yep\",\"contemners\",\"spurts\",\"aft\",\"aldose\"],\"granular_markings\":[{\"marking_ref\":\"marking-definition--980dffe6-2006-45bc-86c7-9885c986fdaa\",\"selectors\":[\"broch\",\"lipped\"],\"x_delimitates\":\"thick\",\"x_chocolaty\":380412,\"x_disarmingly\":\"cataplexy eyeleted poss belike told reformism neglect grillage purer justiciars boosts about haste compulsive over reinvolve blackly obliterate gamy here suffused triaxial tuatara circlers fianchetto aforementioned viverrine drowsily ties screeds fun larvicidal wuthering condyloma epistolize intwines loins ditto litho bluish straightaway restaged\",\"x_dryer\":327849,\"x_unblushingly\":false},{\"marking_ref\":\"marking-definition--f82c9f27-edb4-496b-9eca-58080db5d16d\",\"selectors\":[\"bootleg\",\"muclucs\",\"eild\",\"vandalises\",\"sardiuses\",\"astray\",\"exhaustively\",\"pyrogallic\"]}],\"name\":\"disastrously\"}") - Campaign campaignCreatedZerosSubSec = StixParsers.parseObject("{\"type\":\"campaign\",\"id\":\"campaign--854ae5bf-e07b-4853-95f8-0f85027af1ea\",\"created_by_ref\":\"identity--5eb4619f-b1b6-4b7b-9504-bd3b4d05ce8a\",\"created\":\"2019-04-26T21:14:11.000000000Z\",\"modified\":\"2019-04-26T21:14:11.851Z\",\"revoked\":false,\"labels\":[\"interspersed\",\"yep\",\"contemners\",\"spurts\",\"aft\",\"aldose\"],\"granular_markings\":[{\"marking_ref\":\"marking-definition--980dffe6-2006-45bc-86c7-9885c986fdaa\",\"selectors\":[\"broch\",\"lipped\"],\"x_delimitates\":\"thick\",\"x_chocolaty\":380412,\"x_disarmingly\":\"cataplexy eyeleted poss belike told reformism neglect grillage purer justiciars boosts about haste compulsive over reinvolve blackly obliterate gamy here suffused triaxial tuatara circlers fianchetto aforementioned viverrine drowsily ties screeds fun larvicidal wuthering condyloma epistolize intwines loins ditto litho bluish straightaway restaged\",\"x_dryer\":327849,\"x_unblushingly\":false},{\"marking_ref\":\"marking-definition--f82c9f27-edb4-496b-9eca-58080db5d16d\",\"selectors\":[\"bootleg\",\"muclucs\",\"eild\",\"vandalises\",\"sardiuses\",\"astray\",\"exhaustively\",\"pyrogallic\"]}],\"name\":\"disastrously\"}") - Campaign campaignCreated3ZerosSubSec = StixParsers.parseObject("{\"type\":\"campaign\",\"id\":\"campaign--854ae5bf-e07b-4853-95f8-0f85027af1ea\",\"created_by_ref\":\"identity--5eb4619f-b1b6-4b7b-9504-bd3b4d05ce8a\",\"created\":\"2019-04-26T21:14:11.000Z\",\"modified\":\"2019-04-26T21:14:11.851Z\",\"revoked\":false,\"labels\":[\"interspersed\",\"yep\",\"contemners\",\"spurts\",\"aft\",\"aldose\"],\"granular_markings\":[{\"marking_ref\":\"marking-definition--980dffe6-2006-45bc-86c7-9885c986fdaa\",\"selectors\":[\"broch\",\"lipped\"],\"x_delimitates\":\"thick\",\"x_chocolaty\":380412,\"x_disarmingly\":\"cataplexy eyeleted poss belike told reformism neglect grillage purer justiciars boosts about haste compulsive over reinvolve blackly obliterate gamy here suffused triaxial tuatara circlers fianchetto aforementioned viverrine drowsily ties screeds fun larvicidal wuthering condyloma epistolize intwines loins ditto litho bluish straightaway restaged\",\"x_dryer\":327849,\"x_unblushingly\":false},{\"marking_ref\":\"marking-definition--f82c9f27-edb4-496b-9eca-58080db5d16d\",\"selectors\":[\"bootleg\",\"muclucs\",\"eild\",\"vandalises\",\"sardiuses\",\"astray\",\"exhaustively\",\"pyrogallic\"]}],\"name\":\"disastrously\"}") - Campaign campaignCreated3DigitsWithTrailingZerosSubSec = StixParsers.parseObject("{\"type\":\"campaign\",\"id\":\"campaign--854ae5bf-e07b-4853-95f8-0f85027af1ea\",\"created_by_ref\":\"identity--5eb4619f-b1b6-4b7b-9504-bd3b4d05ce8a\",\"created\":\"2019-04-26T21:14:11.111000000Z\",\"modified\":\"2019-04-26T21:14:11.851Z\",\"revoked\":false,\"labels\":[\"interspersed\",\"yep\",\"contemners\",\"spurts\",\"aft\",\"aldose\"],\"granular_markings\":[{\"marking_ref\":\"marking-definition--980dffe6-2006-45bc-86c7-9885c986fdaa\",\"selectors\":[\"broch\",\"lipped\"],\"x_delimitates\":\"thick\",\"x_chocolaty\":380412,\"x_disarmingly\":\"cataplexy eyeleted poss belike told reformism neglect grillage purer justiciars boosts about haste compulsive over reinvolve blackly obliterate gamy here suffused triaxial tuatara circlers fianchetto aforementioned viverrine drowsily ties screeds fun larvicidal wuthering condyloma epistolize intwines loins ditto litho bluish straightaway restaged\",\"x_dryer\":327849,\"x_unblushingly\":false},{\"marking_ref\":\"marking-definition--f82c9f27-edb4-496b-9eca-58080db5d16d\",\"selectors\":[\"bootleg\",\"muclucs\",\"eild\",\"vandalises\",\"sardiuses\",\"astray\",\"exhaustively\",\"pyrogallic\"]}],\"name\":\"disastrously\"}") - - then: - assert campaignCreatedNoSubSec.getCreated().toString() == "2019-04-26T21:14:11Z" - assert campaignCreatedNoSubSec.getCreated().getInstant().toString() == "2019-04-26T21:14:11Z" - - then: - assert campaignCreated9SubSec.getCreated().toString() == "2019-04-26T21:14:11.999999999Z" - assert campaignCreated9SubSec.getCreated().getInstant().toString() == "2019-04-26T21:14:11.999999999Z" - - then: - assert campaignCreatedZerosSubSec.getCreated().toString() == "2019-04-26T21:14:11.000000000Z" - assert campaignCreatedZerosSubSec.getCreated().getInstant().toString() == "2019-04-26T21:14:11Z" - - then: - assert campaignCreated3ZerosSubSec.getCreated().toString() == "2019-04-26T21:14:11.000Z" - assert campaignCreated3ZerosSubSec.getCreated().getInstant().toString() == "2019-04-26T21:14:11Z" - - then: - assert campaignCreated3DigitsWithTrailingZerosSubSec.getCreated().toString() == "2019-04-26T21:14:11.111000000Z" - assert campaignCreated3DigitsWithTrailingZerosSubSec.getCreated().getInstant().toString() == "2019-04-26T21:14:11.111Z" - } -} diff --git a/src/test/groovy/stix/validation/AttackPatternValidationSpec.groovy b/src/test/groovy/stix/validation/AttackPatternValidationSpec.groovy deleted file mode 100644 index 0da30c6..0000000 --- a/src/test/groovy/stix/validation/AttackPatternValidationSpec.groovy +++ /dev/null @@ -1,95 +0,0 @@ -package stix.validation - -import io.digitalstate.stix.json.StixParserValidationException -import io.digitalstate.stix.json.StixParsers -import spock.lang.Specification - -class AttackPatternValidationSpec extends Specification { - - def "Validate invalid Attack-Pattern JSON"() { - when: "Parsing invalid Attack-Pattern JSON " - String json = ''' - { - "type": "attack-pattern", - "id": "attack-pattern--17e6110c-0f51-4d91-8c1c-417d3f886bda", - "created_by_ref": "identity--826cf0f0-2105-4cf3-a56a-06998d17b1ec", - "created": "2019-03-13T21:41:01.373Z", - "modified": "2019-03-13T21:41:01.374Z", - "revoked": true, - "labels": [ - "111", - "crabbing", - "metricized", - "potentates", - "cresylic", - "ultrasonic" - ], - "object_marking_refs": [ - "marking-definition--4805e1e6-f9c8-476c-bae3-1fa8b3a89197", - "marking-definition--3966fea2-f4a3-4eac-8cb8-c37be13e7fe5", - "marking-definition--2301e050-08c1-4d68-abe1-372a9c9bf0af" - ], - "granular_markings": [ - { - "marking_ref": "marking-definition--a4cb9815-d20e-41d7-a729-e2f3d432144f", - "selectors": [ - "tithe" - ] - }, - { - "marking_ref": "marking-definition--d15d48de-abc7-4c3e-a3ba-bad2198478c4", - "selectors": [ - "cozily", - "atremble", - "twaddle", - "moreish", - "cruciferous", - "recommence", - "bluntly", - "scudded", - "quiescent" - ] - }, - { - "marking_ref": "marking-definition--1a6676db-d3f9-403f-8975-3ba1f8f983a6", - "selectors": [ - "adagio", - "teff", - "eburnation", - "sousaphones", - "whisks" - ] - }, - { - "marking_ref": "marking-definition--ad10add9-9008-45c7-b40b-0ccb27bb9c27", - "selectors": [ - "neuk", - "reuses", - "squat" - ] - } - ], - "name": "dog", - "description": "quicksilver nobbut lame subahs heathfowl slightly bountifulness vitellines creepies custom both boldly darkly unwooded", - "x_breakfasts": 848823, - "xx_gats": "respondent persistently trephining anodizes washiest untimely jibe" - } - ''' - - then: "Should have 1 error" - try { - StixParsers.parseObject(json) - } catch (StixParserValidationException ex) { - assert ex.getConstraintValidations().size() == 1 -// ex.getConstraintValidations().each { x -> -// println "------" -// println "Type: ${x.getRootBean().getClass().getSimpleName()}" -// println "Message: ${x.getMessage()}" -// println "path: ${x.getPropertyPath()}" -// println "invalid_value: ${x.getInvalidValue().toString()}" -// println "------" -// } - } - } - -} diff --git a/src/test/groovy/stix/validation/BundleValidationSpec.groovy b/src/test/groovy/stix/validation/BundleValidationSpec.groovy deleted file mode 100644 index a00617c..0000000 --- a/src/test/groovy/stix/validation/BundleValidationSpec.groovy +++ /dev/null @@ -1,203 +0,0 @@ -package stix.validation - -import io.digitalstate.stix.json.StixParserValidationException -import io.digitalstate.stix.json.StixParsers -import spock.lang.Specification - -class BundleValidationSpec extends Specification { - - def "Validate invalid Bundle JSON"() { - when: "Parsing invalid Bundle JSON " - String json = ''' - { - "type": "bundle", - "id": "bundle--830d3023-6c2d-4d91-b1dc-b594959b8d48", - "spec_version": "2.0", - "x_indolently": 232355.30549115842, - "x_signora": "girts", - "x_cementitious": "teetotally expansionism impudently loams solonchak hooligans awry yale snappingly blamed refutably natation schoolgirlish reshapes bought jots protectively waur whimsically pailfuls reddle deprivation quite bituminised thin falls mailman amie hugely crousely summarises saintliest faithfully gap flam eighth perdie choicely phut pears bifilar impetrative specialises yeah vainly religieuse pistole flown flail unplaced spicate repossesses trindles fidge cattishly limbed sural frits generousness hoppings palpitating stultifies topes intercity mat now mews slay bistouries instigating secretively rebuttable legitimate unslung compatibly rayless summarily reassure fresh canny shiftily inarm vernalizing crimp repopulates landscaping fumier abnegations hippophiles chastely bight unbrotherly coldly archaizes", - "x_simular": 940778.1190796582, - "x_orchestrates": 800790, - "x_else": true, - "x_scrumptiously": 189963.7126364522, - "x_entraps": true, - "x_pentathlons": "illustrious coequally forte seditiously topee geotropic undress bumpily dinars admeasure sham pruriently antiquations grate unsayable playable fey courteously lineally highlands stains barbarous euphonized intonate quickly insulators adumbrated wield telly girt acromion remorselessly discrete perigee truculently ducks subzero umpire sapindaceous lieve treats germane snecked clot uncordial lint mow gaiety perplexity starchily polyploidy stopless ablins flongs tongued weans chotts", - "x_ghastfully": 947223, - "x_repurifies": 348826, - "x_lengthways": "precess", - "x_altruistic": "scabious dissipating transmutably malefactors scatophagy ban disimpassioned ought negotiates deign vividly puddocks upstair equalising lampoonist monogenic acrogens nightmarishly dominances fishily lubricous pronely unknightly sass sport frogged clause backwater glumes suffumigates scag nomadic plaguy casket proud connectedly umbonate forbidder derestrict yare outtelling yodelling logicises poulterers breakaways prod fricassees divinizing days devitalize burglarises chomps lalangs entwining medalling interspacing xerography lochia outdoors sighs obnoxious moochers deceptively leadless revocably salving larch hairiest stomatitis outdares indiscreet tenth doomwatchers decretive socialistic manifold counterpoises cornier flaunts ninth confessedly recountal fruitions savorous toothed gorgonise keyless commensurate loads instructor", - "x_tairas": "icier", - "x_mumms": 410175, - "x_marigold": 471065.5268547859, - "x_annex": "overlive publicize sepulcher days kerchiefed objectivist quire whisk posh unsurfaced brooms chalk thrice lysing trichologist mair interplants transmigrated catacumbal when multipurpose bloated days clues strung reinstated bucktooth soppiest reinterring rimming picked charged strop licht dupes why pedicellate detribalized molto constructs obumbrates eradicate ruinable retail vivo throngs myall unnoticed concussive ever sugarless bleeds diffusedly hithermost cleverish crummier whiles fun monadelphous embowelling buoyancy linoleum alway arranges fasciate unbalances malingerers feal deputation federally lamellibranch reconquer beefeaters shill swith expressively mickles rhodic disport cauterized adhibit coves pencils dern likely inflaming neatly", - "objects": [ - { - "id": "vulnerability--f5c62801-f9b0-42a7-983e-78ed03560b2b", - "type": "vulnerability", - "created_by_ref": "identity--44fda38a-2010-4510-bd69-3e176224abe3", - "created": "2019-03-21T20:51:39.872Z", - "modified": "2019-03-21T20:51:39.872Z", - "revoked": false, - "labels": [ - "amphibrachic", - "longly", - "lode", - "forehanded", - "daglock", - "yes", - "unimportuned", - "garotting", - "loaf", - "ferroconcrete", - "downstairs" - ], - "granular_markings": [ - { - "marking_ref": "marking-definition--2ad5b13d-c9c7-4bea-9dfa-5b1e5a2194b7", - "selectors": [ - "perisarc", - "landslide", - "thorps", - "sonnets", - "dryer", - "skimmings" - ], - "x_wifeless": "befitting prescriptivism slums lucubrated paynims mattresses thwacks welts quattrocento videodisk fraudful runed chugs moodier splodges psts swerve slink abloom incages filthily there overrates buss unaccounted promotive sisterliness alleviates wit bloodily smiles influent smut farawayness interbreedings massacres what geophagous scrimps sized inlets pocks melilots verifiers chirper docs inveigh forsooth quadrifid hybridizes doctoral aught whiles stoop around tidily worst choppy stridulous smash heap unsustaining untouchable doggone phut mischarging spasms attributing gratifiers interchanges militating invincibly dytiscid overselling prompt windmills slanderously counsellable" - }, - { - "marking_ref": "marking-definition--893f95c0-ea68-4c58-ba83-84c99e6a6eb3", - "selectors": [ - "trailingly", - "redesigns", - "amounts", - "hipped", - "metaphrase", - "meanwhile", - "deeply" - ], - "x_squirrelly": true, - "x_nominated": true, - "x_toothed": "loads goads quells wipes vagarious lampads sometimes proems flatter distastefully dotard monochromes brief luculent blithely basidial wastes", - "x_cloying": 325664, - "x_loath": "eructations", - "x_lambkin": false, - "x_pauperized": "sordid", - "x_romantics": 831690, - "x_conciliar": "yesterevening brought atomises", - "x_doabs": "consistently", - "x_tierced": false - }, - { - "marking_ref": "marking-definition--3697dbf5-c4d0-4c99-ba83-797dcb183387", - "selectors": [ - "vivacities" - ], - "x_dully": 509046, - "x_fends": "byzants retting tight slap thig golfs robustly setts dentexes grout snide tight epos ways unhorsing ayahs microtones miters explorations chalkpits cuttles tight unchastely systematized surely restructure vixen uptearing clearly overplied floodlighted riverlike worse skirts unconstant unbespoken dent respirable", - "x_bilk": "jargonises", - "x_spang": 533218.6108306068, - "x_smoulders": 193127.38563754444, - "x_otherwhere": 500157, - "x_compactedly": true, - "x_reactively": "distinguish hues flops here maims undiminished condemnable casually engrossments unhusk loads copulating heliograph citruses succulently clam communizing cheesing weighs candelabrum cauld embedments", - "x_explicitly": "swearings maliciously insolubly roaringly laggingly blamed griping undeserving aecidium sorobans transnational assai produces depresses tenderized fumed dutiable dismally carburizing course lest aestivate sump killikinick quintan clomb tinkling thin redips caracol tracklessness worst pitifully demagnetize yet crack unreproved pegh draftiness crawfishes romaines overcloud desiccate caustically pluckily thick rehearsed dyeable regulate entresol flawier wittingly imperium mistiest stannaries lucubrate ditto scorched patting incurs inward cholent stingingly expects screams mercilessly havocs ruffians bead pitched promises gurge hafts glumaceous chartists tressed since seriatim halest gainless imprisons between cognitions", - "x_secretly": true, - "x_banderilla": "pepino", - "x_rewash": 315436.90735046, - "x_convulsively": false, - "x_daftly": "preannounce", - "x_far": 444089.75319646124, - "x_trichinized": true, - "x_counteract": false, - "x_mighty": 404750, - "x_mauve": 123931 - } - ], - "namee": "megaliths", - "description": "towered left away symphysial cronk artier pocks unobtained tsarist could endarch revengingly nocuously could disquietly" - }, - { - "id": "vulnerability--f36853bb-7745-403f-af15-b3c324c057c7", - "type": "vulnerability", - "created_by_ref": "identity--c39f93f0-072f-4c97-a2e4-ec9358ecb093", - "created": "2019-03-21T20:51:39.878Z", - "modified": "2019-03-21T20:51:39.878Z", - "revoked": true, - "external_references": [ - { - "source_name": "cognizes", - "description": "smash barbeques shoehorn spang jade", - "url": "http://www.chayscaprice.org", - "hashes": { - "SHA-512": "db39af5838979105222d43fbbd08f7ae8ee064e103c9a9523d8819f395bb2cdd56ecb0af54b4db3569497868556f8642277129280faf031e2dba369bbd5d950c" - }, - "external_id": "1c5c3cb8-62b5-4a9b-a920-e3405235cb9a" - }, - { - "source_name": "vocative", - "hashes": { - "SHA-256": "e0ccc55e8669f4c6470de2f36553d377096136cebb0752566a4e644c1b79d3ad" - } - } - ], - "object_marking_refs": [ - "marking-definition--c631a64f-df15-4be2-ad76-4350a4adb4e7" - ], - "granular_markings": [ - { - "marking_ref": "marking-definition--fe9ff6b4-8548-41d4-b6c5-9c304658581c", - "selectors": [ - "discourages", - "quaveringly", - "goad", - "evaded", - "scores", - "wrest", - "lest", - "historicism" - ] - }, - { - "marking_ref": "marking-definition--60900ddb-a0e2-4508-8d3d-f1122f644856", - "selectors": [ - "boot", - "newsier" - ] - }, - { - "marking_ref": "marking-definition--f941ff40-a304-4f8b-93c0-7cc7bf708540", - "selectors": [ - "unovercome", - "pewter", - "cheesing", - "cruelly" - ], - "x_obtrusively": false, - "x_motorises": true - } - ], - "namee": "beefcakes", - "description": "sober fossilize hypostyle proprietors miscellanists deviceful keloidal fowls mesenteric scotomatous suburbanize nights undiscording inverter pinfolds dang redeems avail underdrawing reallotted segments arytenoid evaded lowering resiliently hereto excessively theologised demonstrative quads seaplanes lushy quirt equipoised typing reground dryer shoreward" - } - ] - } - ''' - - then: "Should have 1 error" - try { - StixParsers.parseBundle(json) - } catch (StixParserValidationException ex) { - assert ex.getConstraintValidations().size() == 2 -// ex.getConstraintValidations().each { x -> -// println "------" -// println "Type: ${x.getRootBean().getClass().getSimpleName()}" -// println "Object Id: ${x.getRootBean().asType(BundleableObject).getId()}" -// println "Message: ${x.getMessage()}" -// println "path: ${x.getPropertyPath()}" -// println "invalid_value: ${x.getInvalidValue().toString()}" -// println "------" -// } - } - } - -} diff --git a/src/test/resources/stix/baseline/README.md b/src/test/resources/stix/baseline/README.md deleted file mode 100644 index bc2769e..0000000 --- a/src/test/resources/stix/baseline/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Baseline JSON file - -This package contains a set of baseline JSON files that contain "happy state"/valid STIX data. - -The goal is to have a consistent set of files that represent basic valid json for each of the STIX related objects. - -This JSON files are used in tests to validate serialization capabilities. \ No newline at end of file diff --git a/src/test/resources/stix/baseline/json/sdo/indicator/indicators.json b/src/test/resources/stix/baseline/json/sdo/indicator/indicators.json deleted file mode 100644 index bd2ab32..0000000 --- a/src/test/resources/stix/baseline/json/sdo/indicator/indicators.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "bundle", - "id": "bundle--6fab341c-36c5-4a7f-be29-0a6e3b85e7b0", - "spec_version": "2.0", - "objects": [ - { - "type": "indicator", - "id": "indicator--59ccb738-921a-4941-8ab2-33da522bd4e1", - "created": "2019-04-08T22:59:50.0Z", - "modified": "2019-04-08T22:59:50.00Z", - "revoked": false, - "labels": [ - "malicious-activity" - ], - "name": "128.0.0.1", - "pattern": "[ipv4-addr:value = '128.0.0.1']", - "valid_from": "2019-04-08T22:59:50.000Z" - } - ] -} \ No newline at end of file diff --git a/src/test/resources/stix/baseline/json/sdo/threatreport/apt1.json b/src/test/resources/stix/baseline/json/sdo/threatreport/apt1.json deleted file mode 100644 index b0cde43..0000000 --- a/src/test/resources/stix/baseline/json/sdo/threatreport/apt1.json +++ /dev/null @@ -1,1101 +0,0 @@ -{ - "type": "bundle", - "id": "bundle--cf20f99b-3ed2-4a9f-b4f1-d660a7fc8241", - "spec_version": "2.0", - "objects": [ - { - "type": "intrusion-set", - "id": "intrusion-set--da1065ce-972c-4605-8755-9cd1074e3b5a", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "APT1", - "description": "APT1 is a single organization of operators that has conducted a cyber espionage campaign against a broad range of victims since at least 2006.", - "first_seen": "2006-06-01T18:13:15.684Z", - "resource_level": "government", - "primary_motivation": "organizational-gain", - "aliases": [ - "Comment Crew", - "Comment Group", - "Shady Rat" - ] - }, - { - "type": "threat-actor", - "id": "threat-actor--6d179234-61fc-40c4-ae86-3d53308d8e65", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Ugly Gorilla", - "labels": [ - "nation-state", - "spy" - ], - "roles": [ - "malware-author", - "agent", - "infrastructure-operator" - ], - "resource_level": "government", - "aliases": [ - "Greenfield", - "JackWang", - "Wang Dong" - ], - "primary_motivation": "organizational-gain" - }, - { - "type": "threat-actor", - "id": "threat-actor--d84cf283-93be-4ca7-890d-76c63eff3636", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "DOTA", - "labels": [ - "nation-state", - "spy" - ], - "aliases": [ - "dota", - "Rodney", - "Raith" - ], - "resource_level": "government", - "roles": [ - "agent", - "infrastructure-operator" - ], - "primary_motivation": "organizational-gain" - }, - { - "type": "threat-actor", - "id": "threat-actor--02e7c48f-0301-4c23-b3e4-02e5a0114c21", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "SuperHard", - "labels": [ - "nation-state" - ], - "sophistication": "expert", - "aliases": [ - "dota", - "Rodney", - "Raith" - ], - "resource_level": "government", - "roles": [ - "malware-author" - ], - "primary_motivation": "organizational-gain" - }, - { - "type": "threat-actor", - "id": "threat-actor--d5b62b58-df7c-46b1-a435-4d01945fe21d", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Communist Party of China", - "description": " The CPC is the ultimate authority in Mainland China and tasks the PLA to commit cyber espionage and data theft against organizations around the world.", - "labels": [ - "nation-state" - ], - "resource_level": "government", - "roles": [ - "sponsor", - "director" - ], - "aliases": [ - "CPC" - ], - "primary_motivation": "organizational-gain" - }, - { - "type": "threat-actor", - "id": "threat-actor--94624865-2709-443f-9b4c-2891985fd69b", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Unit 61398", - "description": "Unit 61398 functions as the Third Department's premier entity targeting the United States and Canada, most likely focusing on political, economic, and military-related intelligence.", - "labels": [ - "nation-state" - ], - "resource_level": "government", - "roles": [ - "agent" - ], - "aliases": [ - "PLA GSD's 3rd Department, 2nd Bureau", - "Military Unit Cover Designator (MUCD) 61398" - ], - "primary_motivation": "organizational-gain" - }, - { - "type": "identity", - "id": "identity--a9119a87-6576-46af-bfd7-4fbe55926671", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "JackWang", - "identity_class": "individual", - "sectors": [ - "government-national" - ], - "contact_information": "uglygorilla@163.com" - }, - { - "type": "identity", - "id": "identity--e88ab115-7768-4630-baa3-3d49a7d946ea", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Wang Dong", - "identity_class": "individual", - "sectors": [ - "government-national" - ], - "contact_information": "uglygorilla@163.com" - }, - { - "type": "identity", - "id": "identity--0e9d20d9-fb11-42e3-94bc-b89fb5b007ca", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "dota", - "identity_class": "individual", - "sectors": [ - "government-national" - ], - "contact_information": "dota.d013@gmail.com" - }, - { - "type": "identity", - "id": "identity--ecf1c7de-d96c-41c6-a510-b9c65cdc9e3b", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Mei Qiang", - "identity_class": "individual", - "sectors": [ - "government-national" - ], - "contact_information": "mei_qiang_82@sohu.com" - }, - { - "type": "indicator", - "id": "indicator--031778a4-057f-48e6-9db9-c8d72b81ccd5", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "HTRAN Hop Point Accessor", - "pattern": "[ipv4-addr:value = '223.166.0.0/15']", - "labels": [ - "malicious-activity" - ], - "valid_from": "2015-05-15T09:12:16.432678Z", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "establish-foothold" - } - ] - }, - { - "type": "indicator", - "id": "indicator--da1d061b-2bc9-467a-b16f-8d14f468e1f0", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "HTRAN Hop Point Accessor", - "pattern": "[ipv4-addr:value = '58.246.0.0/15']", - "labels": [ - "malicious-activity" - ], - "valid_from": "2015-05-15T09:12:16.432678Z", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "establish-foothold" - } - ] - }, - { - "type": "indicator", - "id": "indicator--2173d108-5714-42fd-8213-4f3790259fda", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "HTRAN Hop Point Accessor", - "pattern": "[ipv4-addr:value = '112.64.0.0/15']", - "labels": [ - "malicious-activity" - ], - "valid_from": "2015-05-15T09:12:16.432678Z", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "establish-foothold" - } - ] - }, - { - "type": "indicator", - "id": "indicator--8ce03314-dfea-4498-ac9b-136e41ab00e4", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "HTRAN Hop Point Accessor", - "pattern": "[ipv4-addr:value = '139.226.0.0/15']", - "labels": [ - "malicious-activity" - ], - "valid_from": "2015-05-15T09:12:16.432678Z", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "establish-foothold" - } - ] - }, - { - "type": "indicator", - "id": "indicator--3f3ff9f1-bb4e-4392-89e5-1991179042ba", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "FQDN hugesoft.org", - "pattern": "[domain-name:value = 'hugesoft.org']", - "labels": [ - "malicious-activity" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--8390fd29-24ed-45d4-84d7-c5e5feaf195d", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "FQDN arrowservice.net", - "pattern": "[domain-name:value = 'arrowservice.net']", - "labels": [ - "malicious-activity" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--1002c58e-cbde-4930-b5ee-490037fd4f7e", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "FQDN msnhome.org", - "pattern": "[domain-name:value = 'msnhome.org']", - "labels": [ - "malicious-activity" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--8d12f44f-8ac0-4b12-8b4a-3699ca8c9691", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Appendix E MD5 hash '001dd76872d80801692ff942308c64e6'", - "pattern": "[file:hashes.md5 = '001dd76872d80801692ff942308c64e6']", - "labels": [ - "malicious-activity" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--745e1537-b4f3-49da-9f64-df6b1b5df190", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Appendix E MD5 hash '002325a0a67fded0381b5648d7fe9b8e'", - "pattern": "[file:hashes.md5 = '002325a0a67fded0381b5648d7fe9b8e']", - "labels": [ - "malicious-activity" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--1dbe6ed0-c305-458f-9cce-f83c678f5afd", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Appendix E MD5 hash '00dbb9e1c09dbdafb360f3163ba5a3de'", - "pattern": "[file:hashes.md5 = '00dbb9e1c09dbdafb360f3163ba5a3de']", - "labels": [ - "malicious-activity" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--b3b6b540-d838-11e2-853b-005056c00008", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Appendix F SSL Certificate for serial number '(Negative)4c:0b:1d:19:74:86:a7:66:b4:1a:bf:40:27:21:76:28'", - "pattern": "[x509-certificate:issuer = 'CN=WEBMAIL' AND x509-certificate:serial_number = '4c:0b:1d:19:74:86:a7:66:b4:1a:bf:40:27:21:76:28']", - "labels": [ - "malicious-activity" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--b3b7035e-d838-11e2-8d38-005056c00008", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Appendix F SSL Certificate for serial number '0e:97:88:1c:6c:a1:37:96:42:03:bc:45:42:24:75:6c'", - "pattern": "[x509-certificate:issuer = 'CN=LM-68AB71FBD8F5' AND x509-certificate:serial_number = '0e:97:88:1c:6c:a1:37:96:42:03:bc:45:42:24:75:6c']", - "labels": [ - "malicious-activity" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "malware", - "id": "malware--2485b844-4efe-4343-84c8-eb33312dd56f", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "MANITSME", - "labels": [ - "backdoor", - "dropper", - "remote-access-trojan" - ], - "description": "This malware will beacon out at random intervals to the remote attacker. The attacker can run programs, execute arbitrary commands, and easily upload and download files." - }, - { - "type": "malware", - "id": "malware--c0217091-9d3d-42a1-8952-ccc12d4ad8d0", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "WEBC2-UGX", - "labels": [ - "backdoor", - "remote-access-trojan" - ], - "description": "A WEBC2 backdoor is designed to retrieve a Web page from a C2 server. It expects the page to contain special HTML tags; the backdoor will attempt to interpret the data between the tags as commands." - }, - { - "type": "malware", - "id": "malware--0f01c5a3-f516-4450-9381-4dd9f2279411", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "WEBC2 Backdoor", - "labels": [ - "backdoor", - "remote-access-trojan" - ], - "description": "A WEBC2 backdoor is designed to retrieve a Web page from a C2 server. It expects the page to contain special HTML tags; the backdoor will attempt to interpret the data between the tags as commands.", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "establish-foothold" - } - ] - }, - { - "type": "malware", - "id": "malware--33159b98-3264-4e10-a968-d67975b6272f", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "HUC Packet Transmit Tool (HTRAN)", - "labels": [ - "backdoor", - "remote-access-trojan" - ], - "description": "When APT1 attackers are not using WEBC2, they require a “command and control” (C2) user interface so they can issue commands to the backdoor. This interface sometimes runs on their personal attack system, which is typically in Shanghai. In these instances, when a victim backdoor makes contact with a hop, the communications need to be forwarded from the hop to the intruder’s Shanghai system so the backdoor can talk to the C2 server software. We have observed 767 separate instances in which APT1 intruders used the publicly available “HUC Packet Transmit Tool” or HTRAN on a hopThe HTRAN utility is merely a middle-man, facilitating connections between the victim and the attacker who is using the hop point.", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "establish-foothold" - } - ] - }, - { - "type": "malware", - "id": "malware--fb490cdb-6760-41eb-a79b-0b930a50c017", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "AURIGA", - "labels": [ - "backdoor", - "keylogger" - ], - "description": "Malware family that contains functionality for keystroke logging, creating and killing processes, performing file system and registry modifications, etc." - }, - { - "type": "malware", - "id": "malware--ea50ecb7-2cd4-4895-bd08-31cd591ed0ca", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "BANGAT", - "labels": [ - "backdoor", - "keylogger" - ], - "description": "Malware family that contains functionality for keylogging, creating and killing processes, performing filesystem and registry modifications, etc." - }, - { - "type": "tool", - "id": "tool--ce45f721-af14-4fc0-938c-000c16186418", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "cachedump", - "labels": [ - "credential-exploitation" - ], - "description": "This program extracts cached password hashes from a system’s registry.", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "escalate-privileges" - } - ] - }, - { - "type": "tool", - "id": "tool--e9778c42-bc2f-4eda-9fb4-6a931834f68c", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "fgdump", - "labels": [ - "credential-exploitation" - ], - "description": "Windows password hash dumper", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "escalate-privileges" - } - ], - "external_references": [ - { - "source_name": "fgdump", - "url": "http://www.foofus.net/fizzgig/fgdump/" - } - ] - }, - { - "type": "tool", - "id": "tool--1cf6a3b8-be43-4c1a-b042-546a890c31b2", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "gsecdump", - "labels": [ - "credential-exploitation" - ], - "description": "Obtains password hashes from the Windows registry, including the SAM file, cached domain credentials, and LSA secrets", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "escalate-privileges" - } - ], - "external_references": [ - { - "source_name": "gsecdump", - "url": "http://www.truesec.se" - } - ] - }, - { - "type": "tool", - "id": "tool--4d82bd3e-24a3-4f9d-b8f3-b57267fe06a9", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "lslsass", - "labels": [ - "credential-exploitation" - ], - "description": "Dump active logon session password hashes from the lsass process", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "escalate-privileges" - } - ], - "external_references": [ - { - "source_name": "lslsass", - "url": "http://www.truesec.se" - } - ] - }, - { - "type": "tool", - "id": "tool--7de5dfcc-6809-4772-9f11-cf26c2be53aa", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "mimikatz", - "labels": [ - "credential-exploitation" - ], - "description": "A utility primarily used for dumping password hashes", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "escalate-privileges" - } - ], - "external_references": [ - { - "source_name": "mimikatz", - "url": "http://blog.gentilkiwi.com/mimikatz" - } - ] - }, - { - "type": "tool", - "id": "tool--266b12f2-aa16-4607-809e-f2d33eebb52e", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "pass-the-hash toolkit", - "labels": [ - "credential-exploitation" - ], - "description": "Allows an intruder to “pass” a password hash (without knowing the original password) to log in to systems", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "escalate-privileges" - } - ], - "external_references": [ - { - "source_name": "pass-the-hash toolkit", - "url": "http://oss.coresecurity.com/projects/pshtoolkit.htm" - } - ] - }, - { - "type": "tool", - "id": "tool--98fd8dc1-6cc7-4908-899f-07473f55149a", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "pwdump7", - "labels": [ - "credential-exploitation" - ], - "description": "Dumps password hashes from the Windows registry", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "escalate-privileges" - } - ], - "external_references": [ - { - "source_name": "pwdump7", - "url": "http://www.tarasco.org/security/pwdump_7/" - } - ] - }, - { - "type": "tool", - "id": "tool--4215b0e5-928e-4b2a-9b5f-64819f287f48", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "pwdumpX", - "labels": [ - "credential-exploitation" - ], - "description": "Dumps password hashes from the Windows registry", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "escalate-privileges" - } - ] - }, - { - "type": "tool", - "id": "tool--a6dd62d0-9683-48bf-a9cd-61e7eceae57e", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "GETMAIL", - "labels": [ - "information-gathering" - ], - "description": "GETMAIL was designed specifically to extract email messages, attachments, and folders from within Microsoft Outlook archive (“PST”) files.", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "complete-mission" - } - ] - }, - { - "type": "tool", - "id": "tool--806a8f83-4913-4216-bb19-02b48ae25da5", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "MAPIGET", - "labels": [ - "information-gathering" - ], - "description": "MAPIGET was designed specifically to steal email that has not yet been archived and still resides on a Microsoft Exchange Server.", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "complete-mission" - } - ] - }, - { - "type": "attack-pattern", - "id": "attack-pattern--3098c57b-d623-4c11-92f4-5905da66658b", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Initial Compromise", - "description": "As with most other APT groups, spear phishing is APT1’s most commonly used technique. The spear phishing emails contain either a malicious attachment or a hyperlink to a malicious file. The subject line and the text in the email body are usually relevant to the recipient. APT1 also creates webmail accounts using real peoples’ names — names that are familiar to the recipient, such as a colleague, a company executive, an IT department employee, or company counsel. The files they use contain malicious executables that install a custom APT1 backdoor that we call WEBC2-TABLE.", - "external_references": [ - { - "source_name": "capec", - "description": "spear phishing", - "external_id": "CAPEC-163" - } - ], - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "initial-compromise" - } - ] - }, - { - "type": "attack-pattern", - "id": "attack-pattern--1e2c4237-d469-4144-9c0b-9e5c0c513c49", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Establishing a Foothold", - "description": "APT1 establishes a foothold once email recipients open a malicious file and a backdoor is subsequently installed. In almost every case, APT backdoors initiate outbound connections to the intruder’s 'command and control' (C2) server. While APT1 intruders occasionally use publicly available backdoors such as Poison Ivy and Gh0st RAT, the vast majority of the time they use what appear to be their own custom backdoors. APT1’s backdoors are in two categories: 'Beachhead Backdoors' and 'Standard Backdoors.' Beachhead Backdoors offer the attacker a toe-hold to perform simple tasks like retrieve files, gather basic system information and trigger the execution of other more significant capabilities such as a standard backdoor. APT1’s beachhead backdoors are usually what we call WEBC2 backdoors. WEBC2 backdoors are probably the most well-known kind of APT1 backdoor, and are the reason why some security companies refer to APT1 as the Comment Crew. A WEBC2 backdoor is designed to retrieve a webpage from a C2 server. It expects the webpage to contain special HTML tags; the backdoor will attempt to interpret the data between the tags as commands. WEBC2 backdoors are often packaged with spear phishing emails. Once installed, APT1 intruders have the option to tell victim systems to download and execute additional malicious software of their choice. The standard, non-WEBC2 APT1 backdoor typically communicates using the HTTP protocol (to blend in with legitimate web traffic) or a custom protocol that the malware authors designed themselves. The BISCUIT backdoor (so named for the command “bdkzt”) is an illustrative example of the range of commands that APT1 has built into its “standard” backdoors. APT1 has used and steadily modified BISCUIT since as early as 2007 and continues to use it presently. Some APT backdoors attempt to mimic legitimate Internet traffic other than the HTTP protocol. When network defenders see the communications between these backdoors and their C2 servers, they might easily dismiss them as legitimate network traffic. Additionally, many of APT1’s backdoors use SSL encryption so that communications are hidden in an encrypted SSL tunnel.", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "establish-foothold" - } - ] - }, - { - "type": "attack-pattern", - "id": "attack-pattern--e13f3e6d-4f9c-4265-b1cf-f997a1bf7827", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Privilege Escalation", - "description": "Escalating privileges involves acquiring items (most often usernames and passwords) that will allow access to more resources within the network. APT1 predominantly uses publicly available tools to dump password hashes from victim systems in order to obtain legitimate user credentials.", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "escalate-privileges" - } - ] - }, - { - "type": "attack-pattern", - "id": "attack-pattern--5728f45b-2eca-4942-a7f6-bc4267c1ab8d", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Internal Reconnaisance", - "description": "In the Internal Reconnaissance stage, the intruder collects information about the victim environment. Like most APT (and non-APT) intruders, APT1 primarily uses built-in operating system commands to explore a compromised system and its networked environment. Although they usually simply type these commands into a command shell, sometimes intruders may use batch scripts to speed up the process.", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "internal-recon" - } - ] - }, - { - "type": "attack-pattern", - "id": "attack-pattern--0bea2358-c244-4905-a664-a5cdce7bb767", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Lateral Movement", - "description": "Once an APT intruder has a foothold inside the network and a set of legitimate credentials, it is simple for the intruder to move around the network undetected. They can connect to shared resources on other systems. They can execute commands on other systems using the publicly available 'psexec' tool from Microsoft Sysinternals or the built-in Windows Task Scheduler ('at.exe').", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "move-laterally" - } - ] - }, - { - "type": "attack-pattern", - "id": "attack-pattern--7151c6d0-7e97-47ce-9290-087315ea3db7", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Maintain Presence", - "description": "In this stage, the intruder takes actions to ensure continued, long-term control over key systems in the network environment from outside of the network. APT1 does this in three ways: Install new backdoors on multiple systems, use legitimate VPN credentials, and log in to web portals.", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "maintain-presence" - } - ] - }, - { - "type": "attack-pattern", - "id": "attack-pattern--0781fe70-4c94-4300-8865-4b08b98611b4", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Completing the Mission", - "description": "Similar to other APT groups we track, once APT1 finds files of interest they pack them into archive files before stealing them. APT intruders most commonly use the RAR archiving utility for this task and ensure that the archives are password protected. Sometimes APT1 intruders use batch scripts to assist them in the process. After creating files compressed via RAR, the APT1 attackers will transfer files out of the network in ways that are consistent with other APT groups, including using the File Transfer Protocol (FTP) or their existing backdoors. Many times their RAR files are so large that the attacker splits them into chunks before transferring them. Unlike most other APT groups we track, APT1 uses two email-stealing utilities that we believe are unique to APT1. The first, GETMAIL, was designed specifically to extract email messages, attachments, and folders from within Microsoft Outlook archive ('PST') files. The GETMAIL utility allows APT1 intruders the flexibility to take only the emails between dates of their choice. In one case, we observed an APT1 intruder return to a compromised system once a week for four weeks in a row to steal only the past week’s emails. Whereas GETMAIL steals email in Outlook archive files, the second utility, MAPIGET, was designed specifically to steal email that has not yet been archived and still resides on a Microsoft Exchange Server. In order to operate successfully, MAPIGET requires username/password combinations that the Exchange server will accept. MAPIGET extracts email from specified accounts into text files (for the email body) and separate attachments, if there are any.", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "complete-mission" - } - ] - }, - { - "type": "report", - "id": "report--e33ffe07-2f4c-48d8-b0af-ee2619d765cf", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "APT1: Exposing One of China's Cyber Espionage Units", - "labels": [ - "threat-report", - "threat-actor" - ], - "published": "2013-02-19T00:00:00.000000Z", - "description": "Since 2004, Mandiant has investigated computer security breaches at hundreds of organizations around the world. The majority of these security breaches are attributed to advanced threat actors referred to as the 'Advanced Persistent Threat' (APT). We first published details about the APT in our January 2010 M-Trends report. As we stated in the report, our position was that 'The Chinese government may authorize this activity, but theres no way to determine the\textent of its involvement.' Now, three years later, we have the evidence required to change our assessment. The details\twe have analyzed during hundreds of investigations convince us that the groups conducting these activities are based primarily in China and that the Chinese Government is aware of them. Mandiant continues to track dozens of APT groups around the world; however, this report is focused on the most prolific of these groups. We refer to this group as 'APT1' and it is one of more than 20 APT groups with origins in China. APT1 is a single organization of operators that has conducted a cyber espionage campaign against a broad range of victims since at least 2006. From our observations, it is one of the most prolific cyber espionage groups in terms of the sheer quantity of information stolen. The scale and impact of APT1's operations compelled us to write this report. The activity we have directly observed likely represents only a small fraction of the cyber espionage that APT1 has conducted. Though our visibility of APT1's activities is incomplete, we have analyzed the group's intrusions against nearly 150 victims over seven years. From our unique vantage point responding to victims, we tracked APT1 back to four large networks in Shanghai, two of which are allocated directly to the Pudong New Area. We uncovered a substantial amount of APT1's attack infrastructure, command and control, and modus operandi (tools, tactics, and procedures). In an effort to underscore there are actual individuals behind the keyboard, Mandiant is revealing three personas we have attributed to APT1. These operators, like soldiers, may merely be following orders given to them by others. Our analysis has led us to conclude that APT1 is likely government-sponsored and one of the most persistent of China's cyber threat actors. We believe that APT1 is able to wage such a long-running and extensive cyber espionage campaign in large part because it receives direct government support. In seeking to identify the organization behind this activity, our research found that People's Liberation Army (PLA's) Unit 61398 is similar to APT1 in its mission, capabilities, and resources. PLA Unit 61398 is also located in precisely the same area from which APT1 activity appears to originate.", - "object_refs": [ - "attack-pattern--3098c57b-d623-4c11-92f4-5905da66658b", - "attack-pattern--1e2c4237-d469-4144-9c0b-9e5c0c513c49", - "attack-pattern--e13f3e6d-4f9c-4265-b1cf-f997a1bf7827", - "attack-pattern--5728f45b-2eca-4942-a7f6-bc4267c1ab8d", - "attack-pattern--0bea2358-c244-4905-a664-a5cdce7bb767", - "attack-pattern--7151c6d0-7e97-47ce-9290-087315ea3db7", - "attack-pattern--0781fe70-4c94-4300-8865-4b08b98611b4", - "identity--a9119a87-6576-46af-bfd7-4fbe55926671", - "identity--e88ab115-7768-4630-baa3-3d49a7d946ea", - "identity--0e9d20d9-fb11-42e3-94bc-b89fb5b007ca", - "identity--ecf1c7de-d96c-41c6-a510-b9c65cdc9e3b", - "indicator--031778a4-057f-48e6-9db9-c8d72b81ccd5", - "indicator--da1d061b-2bc9-467a-b16f-8d14f468e1f0", - "indicator--2173d108-5714-42fd-8213-4f3790259fda", - "indicator--8ce03314-dfea-4498-ac9b-136e41ab00e4", - "indicator--3f3ff9f1-bb4e-4392-89e5-1991179042ba", - "indicator--8390fd29-24ed-45d4-84d7-c5e5feaf195d", - "indicator--1002c58e-cbde-4930-b5ee-490037fd4f7e", - "indicator--8d12f44f-8ac0-4b12-8b4a-3699ca8c9691", - "indicator--745e1537-b4f3-49da-9f64-df6b1b5df190", - "indicator--1dbe6ed0-c305-458f-9cce-f83c678f5afd", - "indicator--b3b6b540-d838-11e2-853b-005056c00008", - "indicator--b3b7035e-d838-11e2-8d38-005056c00008", - "intrusion-set--da1065ce-972c-4605-8755-9cd1074e3b5a", - "malware--2485b844-4efe-4343-84c8-eb33312dd56f", - "malware--c0217091-9d3d-42a1-8952-ccc12d4ad8d0", - "malware--0f01c5a3-f516-4450-9381-4dd9f2279411", - "malware--33159b98-3264-4e10-a968-d67975b6272f", - "malware--fb490cdb-6760-41eb-a79b-0b930a50c017", - "malware--ea50ecb7-2cd4-4895-bd08-31cd591ed0ca", - "threat-actor--6d179234-61fc-40c4-ae86-3d53308d8e65", - "threat-actor--d84cf283-93be-4ca7-890d-76c63eff3636", - "threat-actor--02e7c48f-0301-4c23-b3e4-02e5a0114c21", - "threat-actor--d5b62b58-df7c-46b1-a435-4d01945fe21d", - "threat-actor--94624865-2709-443f-9b4c-2891985fd69b", - "tool--ce45f721-af14-4fc0-938c-000c16186418", - "tool--e9778c42-bc2f-4eda-9fb4-6a931834f68c", - "tool--1cf6a3b8-be43-4c1a-b042-546a890c31b2", - "tool--4d82bd3e-24a3-4f9d-b8f3-b57267fe06a9", - "tool--7de5dfcc-6809-4772-9f11-cf26c2be53aa", - "tool--266b12f2-aa16-4607-809e-f2d33eebb52e", - "tool--4215b0e5-928e-4b2a-9b5f-64819f287f48", - "tool--a6dd62d0-9683-48bf-a9cd-61e7eceae57e", - "tool--806a8f83-4913-4216-bb19-02b48ae25da5", - "tool--98fd8dc1-6cc7-4908-899f-07473f55149a", - "relationship--6598bf44-1c10-4218-af9f-75b5b71c23a7", - "relationship--35f7a2bb-e4e2-4e56-8693-665bbb64162c", - "relationship--fd5cda8b-f45f-43bd-a9da-e521ddd7126e", - "relationship--a20b8626-a15e-41f0-bcb1-c05321e126f0", - "relationship--d84cf283-93be-4ca7-890d-76c63eff3636", - "relationship--71e6832f-17ee-42fd-938d-c7f881be2028", - "relationship--9dd881a7-6e9b-4c35-bef5-7a777bca65d3", - "relationship--306ce398-f708-47f9-88a1-38aa5b9985fc", - "relationship--8668d82a-1c97-4bea-a367-e391b025e00e", - "relationship--e0ca2caa-7fa0-4f36-ad19-96f107eb6023", - "relationship--765815fb-d993-4a1d-959f-7f7bcc4a5eb3", - "relationship--85b2a834-e4b5-4299-9a6b-bf2ac26dde7b", - "relationship--61f4fd3b-f581-4497-9149-e624c317287b", - "relationship--7cede760-b866-490e-ad5b-1df34bc14f8d", - "relationship--b2806dec-6f20-4a0d-ae9a-d4b1f7be71e3", - "relationship--3921b161-5872-4c21-8ab0-b5b84233f3dc", - "relationship--81827b05-8c20-4247-b5d8-674295a1c611", - "relationship--066593e1-49a4-4a3d-a5bb-2e0b4ce1a63c", - "relationship--b385d984-ba8a-4180-8e0e-af7b9987bcb8", - "relationship--6ffbec81-fa01-4b98-8726-c9d9fb2ef6b6", - "relationship--25586f60-bc27-47d6-9a8e-d1c6456c2f28", - "relationship--d080c1ea-1dd7-4da9-b64b-e68bb1c5887e", - "relationship--c9c66478-c9cf-49cd-bca2-66ce34a9c56d", - "relationship--44686fda-311c-4cdb-abef-80e922e7a3fb", - "relationship--340cb676-79ff-49e9-b6ba-cd27e06772c4", - "relationship--9908520f-b25d-44a8-900b-d4e0825dcd0d", - "relationship--1fbd9a8d-4c14-431c-9520-3ccc50b748c1", - "relationship--389a8dcd-8663-4f18-8584-d69a77bd71aa", - "relationship--b345f1d0-09c5-4a71-bfc6-a52bd5923a01", - "relationship--912b31d0-09c5-4a71-bfc6-a52bd5989a1b" - ] - }, - { - "type": "relationship", - "id": "relationship--6598bf44-1c10-4218-af9f-75b5b71c23a7", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "threat-actor--6d179234-61fc-40c4-ae86-3d53308d8e65", - "target_ref": "malware--2485b844-4efe-4343-84c8-eb33312dd56f" - }, - { - "type": "relationship", - "id": "relationship--35f7a2bb-e4e2-4e56-8693-665bbb64162c", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "threat-actor--6d179234-61fc-40c4-ae86-3d53308d8e65", - "target_ref": "malware--c0217091-9d3d-42a1-8952-ccc12d4ad8d0" - }, - { - "type": "relationship", - "id": "relationship--fd5cda8b-f45f-43bd-a9da-e521ddd7126e", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "attributed-to", - "source_ref": "threat-actor--6d179234-61fc-40c4-ae86-3d53308d8e65", - "target_ref": "identity--a9119a87-6576-46af-bfd7-4fbe55926671" - }, - { - "type": "relationship", - "id": "relationship--a20b8626-a15e-41f0-bcb1-c05321e126f0", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "attributed-to", - "source_ref": "threat-actor--6d179234-61fc-40c4-ae86-3d53308d8e65", - "target_ref": "identity--e88ab115-7768-4630-baa3-3d49a7d946ea" - }, - { - "type": "relationship", - "id": "relationship--d84cf283-93be-4ca7-890d-76c63eff3636", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "attributed-to", - "source_ref": "threat-actor--d84cf283-93be-4ca7-890d-76c63eff3636", - "target_ref": "identity--0e9d20d9-fb11-42e3-94bc-b89fb5b007ca" - }, - { - "type": "relationship", - "id": "relationship--71e6832f-17ee-42fd-938d-c7f881be2028", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "attributed-to", - "source_ref": "threat-actor--02e7c48f-0301-4c23-b3e4-02e5a0114c21", - "target_ref": "identity--ecf1c7de-d96c-41c6-a510-b9c65cdc9e3b" - }, - { - "type": "relationship", - "id": "relationship--9dd881a7-6e9b-4c35-bef5-7a777bca65d3", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "threat-actor--02e7c48f-0301-4c23-b3e4-02e5a0114c21", - "target_ref": "malware--fb490cdb-6760-41eb-a79b-0b930a50c017" - }, - { - "type": "relationship", - "id": "relationship--306ce398-f708-47f9-88a1-38aa5b9985fc", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "threat-actor--02e7c48f-0301-4c23-b3e4-02e5a0114c21", - "target_ref": "malware--ea50ecb7-2cd4-4895-bd08-31cd591ed0ca" - }, - { - "type": "relationship", - "id": "relationship--8668d82a-1c97-4bea-a367-e391b025e00e", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "attributed-to", - "source_ref": "intrusion-set--da1065ce-972c-4605-8755-9cd1074e3b5a", - "target_ref": "threat-actor--94624865-2709-443f-9b4c-2891985fd69b" - }, - { - "type": "relationship", - "id": "relationship--e0ca2caa-7fa0-4f36-ad19-96f107eb6023", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "attributed-to", - "source_ref": "intrusion-set--da1065ce-972c-4605-8755-9cd1074e3b5a", - "target_ref": "threat-actor--d5b62b58-df7c-46b1-a435-4d01945fe21d" - }, - { - "type": "relationship", - "id": "relationship--765815fb-d993-4a1d-959f-7f7bcc4a5eb3", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "attributed-to", - "source_ref": "intrusion-set--da1065ce-972c-4605-8755-9cd1074e3b5a", - "target_ref": "threat-actor--6d179234-61fc-40c4-ae86-3d53308d8e65" - }, - { - "type": "relationship", - "id": "relationship--85b2a834-e4b5-4299-9a6b-bf2ac26dde7b", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "attack-pattern--1e2c4237-d469-4144-9c0b-9e5c0c513c49", - "target_ref": "malware--0f01c5a3-f516-4450-9381-4dd9f2279411" - }, - { - "type": "relationship", - "id": "relationship--61f4fd3b-f581-4497-9149-e624c317287b", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "attack-pattern--1e2c4237-d469-4144-9c0b-9e5c0c513c49", - "target_ref": "malware--33159b98-3264-4e10-a968-d67975b6272f" - }, - { - "type": "relationship", - "id": "relationship--7cede760-b866-490e-ad5b-1df34bc14f8d", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--031778a4-057f-48e6-9db9-c8d72b81ccd5", - "target_ref": "malware--33159b98-3264-4e10-a968-d67975b6272f" - }, - { - "type": "relationship", - "id": "relationship--b2806dec-6f20-4a0d-ae9a-d4b1f7be71e3", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--da1d061b-2bc9-467a-b16f-8d14f468e1f0", - "target_ref": "malware--33159b98-3264-4e10-a968-d67975b6272f" - }, - { - "type": "relationship", - "id": "relationship--3921b161-5872-4c21-8ab0-b5b84233f3dc", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--2173d108-5714-42fd-8213-4f3790259fda", - "target_ref": "malware--33159b98-3264-4e10-a968-d67975b6272f" - }, - { - "type": "relationship", - "id": "relationship--81827b05-8c20-4247-b5d8-674295a1c611", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--8ce03314-dfea-4498-ac9b-136e41ab00e4", - "target_ref": "malware--33159b98-3264-4e10-a968-d67975b6272f" - }, - { - "type": "relationship", - "id": "relationship--066593e1-49a4-4a3d-a5bb-2e0b4ce1a63c", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "attack-pattern--e13f3e6d-4f9c-4265-b1cf-f997a1bf7827", - "target_ref": "tool--ce45f721-af14-4fc0-938c-000c16186418" - }, - { - "type": "relationship", - "id": "relationship--b385d984-ba8a-4180-8e0e-af7b9987bcb8", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "attack-pattern--e13f3e6d-4f9c-4265-b1cf-f997a1bf7827", - "target_ref": "tool--e9778c42-bc2f-4eda-9fb4-6a931834f68c" - }, - { - "type": "relationship", - "id": "relationship--6ffbec81-fa01-4b98-8726-c9d9fb2ef6b6", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "attack-pattern--e13f3e6d-4f9c-4265-b1cf-f997a1bf7827", - "target_ref": "tool--1cf6a3b8-be43-4c1a-b042-546a890c31b2" - }, - { - "type": "relationship", - "id": "relationship--25586f60-bc27-47d6-9a8e-d1c6456c2f28", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "attack-pattern--e13f3e6d-4f9c-4265-b1cf-f997a1bf7827", - "target_ref": "tool--4d82bd3e-24a3-4f9d-b8f3-b57267fe06a9" - }, - { - "type": "relationship", - "id": "relationship--d080c1ea-1dd7-4da9-b64b-e68bb1c5887e", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "attack-pattern--e13f3e6d-4f9c-4265-b1cf-f997a1bf7827", - "target_ref": "tool--7de5dfcc-6809-4772-9f11-cf26c2be53aa" - }, - { - "type": "relationship", - "id": "relationship--c9c66478-c9cf-49cd-bca2-66ce34a9c56d", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "attack-pattern--e13f3e6d-4f9c-4265-b1cf-f997a1bf7827", - "target_ref": "tool--266b12f2-aa16-4607-809e-f2d33eebb52e" - }, - { - "type": "relationship", - "id": "relationship--44686fda-311c-4cdb-abef-80e922e7a3fb", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "attack-pattern--e13f3e6d-4f9c-4265-b1cf-f997a1bf7827", - "target_ref": "tool--98fd8dc1-6cc7-4908-899f-07473f55149a" - }, - { - "type": "relationship", - "id": "relationship--340cb676-79ff-49e9-b6ba-cd27e06772c4", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "attack-pattern--e13f3e6d-4f9c-4265-b1cf-f997a1bf7827", - "target_ref": "tool--4215b0e5-928e-4b2a-9b5f-64819f287f48" - }, - { - "type": "relationship", - "id": "relationship--9908520f-b25d-44a8-900b-d4e0825dcd0d", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "attack-pattern--0781fe70-4c94-4300-8865-4b08b98611b4", - "target_ref": "tool--a6dd62d0-9683-48bf-a9cd-61e7eceae57e" - }, - { - "type": "relationship", - "id": "relationship--1fbd9a8d-4c14-431c-9520-3ccc50b748c1", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "attack-pattern--0781fe70-4c94-4300-8865-4b08b98611b4", - "target_ref": "tool--806a8f83-4913-4216-bb19-02b48ae25da5" - }, - { - "type": "relationship", - "id": "relationship--389a8dcd-8663-4f18-8584-d69a77bd71aa", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--3f3ff9f1-bb4e-4392-89e5-1991179042ba", - "target_ref": "threat-actor--6d179234-61fc-40c4-ae86-3d53308d8e65" - }, - { - "type": "relationship", - "id": "relationship--b345f1d0-09c5-4a71-bfc6-a52bd5923a01", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--8390fd29-24ed-45d4-84d7-c5e5feaf195d", - "target_ref": "threat-actor--6d179234-61fc-40c4-ae86-3d53308d8e65" - }, - { - "type": "relationship", - "id": "relationship--912b31d0-09c5-4a71-bfc6-a52bd5989a1b", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--1002c58e-cbde-4930-b5ee-490037fd4f7e", - "target_ref": "threat-actor--6d179234-61fc-40c4-ae86-3d53308d8e65" - } - ] -} diff --git a/src/test/resources/stix/baseline/json/sdo/threatreport/poisonivy.json b/src/test/resources/stix/baseline/json/sdo/threatreport/poisonivy.json deleted file mode 100644 index 5ca55b2..0000000 --- a/src/test/resources/stix/baseline/json/sdo/threatreport/poisonivy.json +++ /dev/null @@ -1,1810 +0,0 @@ -{ - "type": "bundle", - "id": "bundle--ac946f1d-6a0e-4a9d-bc83-3f1f3bfda6ba", - "spec_version": "2.0", - "objects": [ - { - "type": "malware", - "id": "malware--591f0cb7-d66f-4e14-a8e6-5927b597f920", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Poison Ivy", - "description": "Poison Ivy is a remote access tool, first released in 2005 but unchanged since 2008. It includes features common to most Windows-based RATs, including key logging, screen capturing, video capturing, file transfers, system administration, password theft, and traffic relaying.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "identity", - "id": "identity--81cade27-7df8-4730-836b-62d880e6d9d3", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "FireEye, Inc.", - "identity_class": "organization", - "sectors": [ - "technology" - ] - }, - { - "type": "campaign", - "id": "campaign--752c225d-d6f6-4456-9130-d9580fd4007b", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "admin@338", - "description": "Active since 2008, this campaign mostly targets the financial services industry, though we have also seen activity in the telecom, government, and defense sectors.", - "first_seen": "2008-01-07T00:00:00.000000Z" - }, - { - "type": "campaign", - "id": "campaign--d02a1560-ff69-49f4-ac34-919b8aa4b91e", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "th3bug", - "description": "This ongoing campaign targets a number of industries but appears to prefer targets in higher education and the healthcare sectors.", - "first_seen": "2009-10-26T00:00:00.000000Z" - }, - { - "type": "campaign", - "id": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "menuPass", - "description": "The threat actor behind menuPass prefers to target U.S. and foreign defense contractors.", - "first_seen": "2009-12-14T00:00:00.000000Z" - }, - { - "type": "attack-pattern", - "id": "attack-pattern--19da6e1c-69a8-4c2f-886d-d620d09d3b5a", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "external_references": [ - { - "source_name": "capec", - "description": "spear phishing", - "external_id": "CAPEC-163" - } - ], - "name": "Spear Phishing Attack Pattern used by admin@338", - "description": "The preferred attack vector used by admin@338 is spear-phishing emails. Using content that is relevant to the target, these emails are designed to entice the target to open an attachment that contains the malicious PIVY server code.", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "initial-compromise" - } - ] - }, - { - "type": "attack-pattern", - "id": "attack-pattern--ea2c747d-4aa3-4573-8853-37b7159bc180", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Strategic Web Compromise Attack Pattern used by th3bug", - "description": "Attacks attributed to th3bug use a strategic Web compromise to infect targets. This approach is more indiscriminate, which probably accounts for the more disparate range of targets.", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "initial-compromise" - } - ] - }, - { - "type": "attack-pattern", - "id": "attack-pattern--fb6aa549-c94a-4e45-b4fd-7e32602dad85", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "external_references": [ - { - "source_name": "capec", - "description": "spear phishing", - "external_id": "CAPEC-163" - } - ], - "name": "Spear Phishing Attack Pattern used by menuPass", - "description": "menuPass appears to favor spear phishing to deliver payloads to the intended targets. While the attackers behind menuPass have used other RATs in their campaign, it appears that they use PIVY as their primary persistence mechanism.", - "kill_chain_phases": [ - { - "kill_chain_name": "mandiant-attack-lifecycle-model", - "phase_name": "initial-compromise" - } - ] - }, - { - "type": "course-of-action", - "id": "course-of-action--70b3d5f6-374b-4488-8688-729b6eedac5b", - "created_by_ref": "identity--81cade27-7df8-4730-836b-62d880e6d9d3", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Analyze with FireEye Calamine Toolset", - "description": "Calamine is a set of free tools to help organizations detect and examine Poison Ivy infections on their systems. The package includes these components: PIVY callback-decoding tool (ChopShop Module) and PIVY memory-decoding tool (PIVY PyCommand Script).", - "external_references": [ - { - "source_name": "Calamine ChopShop Module", - "description": "The FireEye Poison Ivy decoder checks the beginning of each TCP session for possible PIVY challengeresponse sequences. If found, the module will try to validate the response using one or more passwords supplied as arguments.", - "url": "https://github.com/fireeye/chopshop" - }, - { - "source_name": "Calamine PyCommand Script", - "description": "Helps locate the PIVY password.", - "url": "https://github.com/fireeye/pycommands" - } - ] - }, - { - "type": "malware", - "id": "malware--61a62a6a-9a18-4758-8e52-622431c4b8ae", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (808e21d6efa2884811fbd0adf67fda78)", - "description": "The key@123 sample (password for admin@338), 808e21d6efa2884811fbd0adf67fda78, connects directly to 219.76.208.163", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--30ea087f-7d2b-496b-9ed1-5f000c8b7695", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (8010cae3e8431bb11ed6dc9acabb93b7,)", - "description": "Two CnC domain names from the admin@338 sample 8010cae3e8431bb11ed6dc9acabb93b7, connect to www.webserver.dynssl.com and www.webserver.freetcp.com and resolve to 219.76.208.163. It also connects to the CnC domain www.webserver.fartit.com.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--4de25c38-5826-4ee7-b84d-878064de87ad", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (0323de551aa10ca6221368c4a73732e6,)", - "description": "The gwx@123 sample 0323de551aa10ca6221368c4a73732e6 connects to the CnC domain names microsofta.byinter.net, microsoftb.byinter.net, microsoftc.byinter. net, and microsofte.byinter.net.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--dc669921-4a1a-470d-bfae-694e740ce181", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (8002debc47e04d534b45f7bb7dfcab4d)", - "description": "The sample 8002debc47e04d534b45f7bb7dfcab4d connected to kr.iphone.qpoe.com with the PIVY password admin.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--f86febd3-609b-4d2e-9fec-aa805cb498bf", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (55a3b2656ceac2ba6257b6e39f4a5b5a)", - "description": "The sample 55a3b2656ceac2ba6257b6e39f4a5b5a connected to ct.toh.info domain with the PIVY password th3bug.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--80c260d9-a075-4148-9301-ebe4af27f449", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (b08694e14a9b966d8033b42b58ab727d)", - "description": "This sample (b08694e14a9b966d8033b42b58ab727d) for menuPass connected to a control server at js001.3322.org with a password xiaoxiaohuli (Chinese translation: 'little little fox')", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--3ed0364f-62c8-4ebc-b136-deaf6966880b", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (d8c00fed6625e5f8d0b8188a5caac115)", - "description": "The sample d8c00fed6625e5f8d0b8188a5caac115 connected to apple.cmdnetview.com with the password XGstone.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--17099f03-5ec8-456d-a2de-968aebaafc78", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (b1deff736b6d12b8d98b485e20d318ea)", - "description": "The sample b1deff736b6d12b8d98b485e20d318ea connected to autuo.xicp.net with the password keaidestone.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--e14b6476-40b5-4b0b-bde7-0e856ab00b6c", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (08709f35581e0958d1ca4e50b7d86dba)", - "description": "The sample 08709f35581e0958d1ca4e50b7d86dba has a compile time of July 20. 2012 and connected to tw.2012yearleft.com with the password keaidestone. This sample also used the CBricksDoc launcher.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--feaf146d-ea67-4eb1-946a-6f352ff79a81", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (e84853c0484b02b7518dd683787d04f)", - "description": "The sample e84853c0484b02b7518dd6837 87d04fc connected to dedydns.ns01.us with the password smallfish and used the CBricksDoc launcher.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--13791e02-6621-45fb-8c10-f6b72e1bf553", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (cf8094c07c15aa394dddd4eca4aa8c8b)", - "description": "The sample cf8094c07c15aa394dddd4eca4aa8c8b connected to maofajapa.3322.org with the password happyyongzi.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--703a15a7-eb85-475d-a27a-77d8fcf8f7b9", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (410eeaa18dbec01a27c5b41753b3c7ed )", - "description": "The sample 410eeaa18dbec01a27c5b41753b3c7ed connected to send.have8000.com with the password of suzuki.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--fade08cb-fa57-485e-97f8-fab5a1bd4460", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (b2dc98caa647e64a2a8105c298218462)", - "description": "The sample b2dc98caa647e64a2a8105c298218462 connected to apple.cmdnetview.com with the password XGstone.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--3050937d-6330-44c7-83ba-8821e1f7e7bd", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (68fec995a13762184a2616bda86757f8)", - "description": "68fec995a13762184a2616bda86757f8 had a compile time of March 25, 2012 and connected to fbi.zyns.com with the password menuPass. This sample also used the CBricksDoc launcher.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--9d995717-edc3-4bd8-8554-aecf773bdecc", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (39a59411e7b12236c0b4351168fb47ce)", - "description": "The sample 39a59411e7b12236c0b4351168fb47ce had a compile time of April 2, 2010 and connected to weile3322b.3322.org with the password keaidestone. This sample used a launcher of CPiShellPutDoc.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--40e15fa5-df8d-4771-a682-21dab0a024fd", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (f5315fb4a654087d30c69c768d80f826)", - "description": "The sample f5315fb4a654087d30c69c768d80f826 had a compile time of May 21, 2010 and connected to ngcc.8800.org with the password menuPass. This sample also used a launcher of CPiShellPutDoc.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--69101c2f-da92-47af-b402-7c60a39a982f", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (e6ca06e9b000933567a8604300094a85)", - "description": "The sample e6ca06e9b000933567a8604300094a85 connected to the domain sh.chromeenter.com with the password happyyongzi.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--1601b8c2-5e6f-4a18-a413-10527e5d90b7", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (56cff0d0e0ce486aa0b9e4bc0bf2a141)", - "description": "The sample 56cff0d0e0ce486aa0b9e4bc0bf2a141 was compiled on 2011-08-31 and connected to mf.ddns.info with the password menuPass.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--626badcc-4257-4222-946c-6d6e889836ea", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (60963553335fa5877bd5f9be9d8b23a6 )", - "description": "The sample 60963553335fa5877bd5f9be9d8b23a6 was compiled on June 9, 2012 and connected to av.ddns.us with the password of admin", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--3b275ed1-9c2e-4443-b1dd-5cfb51eaef2e", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (6d989302166ba1709d66f90066c2fd59)", - "description": "A number of menuPass and admin samples also shared the same CBricksDoc launcher including but not limited to 6d989302166ba1709d66f90066c2fd59.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--f138b6e0-9a7d-4cd9-a904-08a7df2eabb1", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (4bc6cab128f623f34bb97194da21d7b6)", - "description": "A number of menuPass and admin samples also shared the same CBricksDoc launcher including but not limited to 4bc6cab128f623f34bb97194da21d7b6.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--302ac5b5-486c-4c99-8cad-4426aeaf47b6", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (4e84b1448cf96fabe88c623b222057c4)", - "description": "The sample 4e84b1448cf96fabe88c623b222057c4 connected to jj.mysecondarydns.com with the password menuPass", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--e1c02dca-d3fe-48f1-bb4b-3cacd2bc3619", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (494e65cf21ad559fccf3dacdd69acc94)", - "description": "The sample 494e65cf21ad559fccf3dacdd69acc94 connected to mongoles.3322.org with the password fishplay. It also connects to CBricksDoc.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "malware", - "id": "malware--a4f315bd-e159-4bfb-8439-0d5a8330fc70", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "PIVY Variant (a5965b750997dbecec61358d41ac93c7)", - "description": "The sample a5965b750997dbecec61358d41ac93c7 connected to 3q.wubangtu.info with the password menuPass. It also connects to CBricksDoc.", - "labels": [ - "remote-access-trojan" - ] - }, - { - "type": "indicator", - "id": "indicator--e8094b09-7df4-4b13-b207-1e27af3c4bde", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "IP address: 219.76.208.163", - "description": "IP address for key@123 sample 808e21d6efa2884811fbd0adf67fda78", - "pattern": "[ipv4-addr:value = '219.76.208.163']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--329ae6e9-25bd-49e8-89d1-aae4ca52e4a7", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "www.webserver.dynssl.com", - "description": "www.webserver.dynssl.com resolved to 113.10.246.30, 219.90.112.203, 219.90.112.203, 75.126.95.138, 219.90.112.197, and 202.65.222.45, which overlap with the gwx@123 IP addresses.", - "pattern": "[domain-name:value = 'www.webserver.dynssl.com' OR ipv4-addr:value = '113.10.246.30' OR ipv4-addr:value = '219.90.112.203' OR ipv4-addr:value = '75.126.95.138' OR ipv4-addr:value = '219.90.112.197' OR ipv4-addr:value = '202.65.222.45']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--54e1e351-fec0-41a4-b62c-d7f86101e241", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "www.webserver.freetcp.com", - "description": "www.webserver.freetcp.com resolved to 113.10.246.30, 219.90.112.203, 202.65.220.64, 75.126.95.138, 219.90.112.197, and 202.65.222.45, which overlap with the gwx@123 IP addresses.", - "pattern": "[domain-name:value = 'www.webserver.freetcp.com' OR ipv4-addr:value = '113.10.246.30' OR ipv4-addr:value = '219.90.112.203' OR ipv4-addr:value = '202.65.220.64' OR ipv4-addr:value = '75.126.95.138' OR ipv4-addr:value = '219.90.112.197' OR ipv4-addr:value = '202.65.222.45']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--2e59f00b-0986-437e-9ebd-e0d61900d688", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "www.webserver.fartit.com", - "description": "www.webserver.fartit.com resolved to 113.10.246.30, 219.90.112.203, 202.65.220.64, and 75.126.95.138, which overlap with the gwx@123 IP addresses.", - "pattern": "[domain-name:value = 'www.webserver.fartit.com' OR ipv4-addr:value = '113.10.246.30' OR ipv4-addr:value = '219.90.112.203' OR ipv4-addr:value = '202.65.220.64' OR ipv4-addr:value = '75.126.95.138']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--8da68996-f175-4ae0-bd74-aad4913873b8", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "microsoft.byinter.net", - "description": "The gwx@123 sample 0323de551aa10ca6221368c4a73732e6 connects to the CnC domain names microsofta.byinter.net, microsoftb.byinter.net, microsoftc.byinter.net, and microsofte.byinter.net. These domain names resolved to 113.10.246.30, 219.90.112.203, 202.65.220.64, 75.126.95.138, 219.90.112.197, 202.65.222.45, and 98.126.148.114.", - "pattern": "[domain-name:value = 'microsofta.byinter.net' OR domain-name:value = 'microsoftb.byinter.net' OR domain-name:value = 'microsoftc.byinter.net' OR domain-name:value = 'microsofte.byinter.net' OR ipv4-addr:value = '113.10.246.30' OR ipv4-addr:value = '219.90.112.203' OR ipv4-addr:value = '202.65.220.64' OR ipv4-addr:value = '75.126.95.138' OR ipv4-addr:value = '219.90.112.197' OR ipv4-addr:value = '202.65.222.45' OR ipv4-addr:value = '98.126.148.114']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--4e11b23f-732b-418e-b786-4dbf65459d50", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "nkr.iphone.qpoe.com", - "description": "th3bug used domain name: nkr.iphone.qpoe.com. The domain nkr.iphone.qpoe.com resolved to 180.210.206.96 on January 12, 2012 and also 101.78.151.179 on December 23, 2011.", - "pattern": "[domain-name:value = 'nkr.iphone.qpoe.com' OR ipv4-addr:value = '180.210.206.96' OR ipv4-addr:value = '101.78.151.179']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--b7fa7e73-e645-4813-9723-161bbd8dda62", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "e.ct.toh.info", - "description": "th3bug used domain name: e.ct.toh.info. The domain e.ct.toh.info resolved to 101.78.151.179 on June 12, 2012. The sample 55a3b2656ceac2ba6257b6e39f4a5b5a connected to ct.toh.info domain with the PIVY password th3bug.", - "pattern": "[domain-name:value = 'e.ct.toh.info' OR ipv4-addr:value = '101.78.151.179']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--b2f09ce0-2db4-480f-bd2f-073ddb3a0c87", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "js001.3322.org", - "description": "menuPass used control server: js001.3322.org. The sample (b08694e14a9b966d8033b42b58ab727d) connected to a control server at js001.3322.org with a password xiaoxiaohuli (Chinese translation: 'little little fox')", - "pattern": "[domain-name:value = 'js001.3322.org' OR ipv4-addr:value = '101.78.151.179']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--9842a3b9-fc5b-44c4-bb48-578cf6f728d9", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "apple.cmdnetview.com", - "description": "menuPass used domain: apple.cmdnetview.com. The sample d8c00fed6625e5f8d0b8188a5caac115 connected to apple.cmdnetview.com with the password XGstone. IP 60.10.1.120 hosted this domain.", - "pattern": "[domain-name:value = 'apple.cmdnetview.com' OR ipv4-addr:value = '60.10.1.120']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--4e4c4ad7-4909-456a-b6fa-e24a6f682a40", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "autuo.xicp.net", - "description": "menuPass used domain: autuo.xicp.net. The sample b1deff736b6d12b8d98b485e20d318ea connected to autuo.xicp.net with the password keaidestone. IP 60.10.1.115 hosted this domain.", - "pattern": "[domain-name:value = 'domain autuo.xicp.net' OR ipv4-addr:value = '60.10.1.115']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--137acf67-cedc-4a07-8719-72759174de3a", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "CBricksDoc", - "description": "menuPass uses Microsoft Foundation Class Library class name CBricksDoc as a launcher for PIVY.", - "pattern": "[file:name = 'CBricksDoc']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--9695dc2f-d92a-4f2b-8b16-b0e21d7c631d", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "tw.2012yearleft.com", - "description": "08709f35581e0958d1ca4e50b7d86dba has a compile time of July 20. 2012 and connected to tw.2012yearleft.com with the password keaidestone. 2012yearleft.com was registered on February 13, 2012 by zhengyanbin8@gmail.com.", - "pattern": "[domain-name:value = 'tw.2012yearleft.com' OR ipv4-addr:value = '60.10.1.114' OR ipv4-addr:value = '60.1.1.114']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--7fd865ed-93e9-481f-953b-82ab386190ae", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "dedydns.ns01.us", - "description": "The domain dedydns.ns01.us resolved to 60.10.1.121. The sample e84853c0484b02b7518dd6837 87d04fc connected to dedydns.ns01.us with the password smallfish and used the CBricksDoc launcher.", - "pattern": "[domain-name:value = 'dedydns.ns01.us' OR ipv4-addr:value = '60.10.1.121']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--e5bc6507-d052-447f-93c7-db7ef32211da", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "maofajapa.3322.org", - "description": "The domain maofajapa.3322.org resolved to 60.10.1.121. The sample cf8094c07c15aa394dddd4eca4aa8c8b connected to maofajapa.3322.org with the password happyyongzi.", - "pattern": "[domain-name:value = 'maofajapa.3322.org' OR ipv4-addr:value = '60.10.1.121']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--fead5c52-9533-405c-b822-a034092a1ba8", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "send.have8000.com", - "description": "The sample 410eeaa18dbec01a27c5b41753b3c7ed connected to send.have8000.com with the password of suzuki. The domain have8000.com was registered on 2012-02-13 via the email zhengyanbin8@ gmail.com.", - "pattern": "[domain-name:value = 'send.have8000.com']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--405ff732-2c35-4f46-9f78-2a632ce36e03", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "fbi.zyns.com", - "description": "The domain fbi.zyns.com resolved to 60.10.1.118 on August 21, 2012. 68fec995a13762184a2616bda86757f8 had a compile time of March 25, 2012 and connected to fbi.zyns.com with the password menuPass.", - "pattern": "[domain-name:value = 'fbi.zyns.com' OR ipv4-addr:value = '60.10.1.118']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--4d58096e-b5c9-47d8-af9a-1af5f4762d6b", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "weile3322b.3322.org", - "description": "The sample 39a59411e7b12236c0b4351168fb47ce had a compile time of April 2, 2010 and connected to weile3322b.3322.org with the password keaidestone.", - "pattern": "[domain-name:value = 'weile3322b.3322.org']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--9c725598-a160-4e91-8b93-ed0956709892", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "ngcc.8800.org", - "description": "The sample f5315fb4a654087d30c69c768d80f826 had a compile time of May 21, 2010 and connected to ngcc.8800.org with the password menuPass", - "pattern": "[domain-name:value = 'ngcc.8800.org']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--2efe7c62-1b96-4568-81ee-c85b840bde39", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "sh.chromeenter.com", - "description": "The sample e6ca06e9b000933567a8604300094a85 connected to the domain sh.chromeenter.com with the password happyyongzi. The domain sh.chromeenter.com previously resolved to the IP 60.2.148.167.", - "pattern": "[domain-name:value = 'sh.chromeenter.com' OR ipv4-addr:value = '60.2.148.167']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--b8322c9b-8031-4fb3-9cbc-8a1ea0fe3cfa", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "mf.ddns.info", - "description": "The sample 56cff0d0e0ce486aa0b9e4bc0bf2a141 was compiled on 2011-08-31 and connected to mf.ddns.info with the password menuPass. The domain mf.ddns.info resolved to 54.241.8.84 on November 22, 2012. This same IP also hosted the domain av.ddns.us on the same date.", - "pattern": "[domain-name:value = 'mf.ddns.info' OR ipv4-addr:value = '60.2.148.167']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--b08f9631-dd94-4d99-a96c-32b42af2ea81", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "av.ddns.us", - "description": "The sample 60963553335fa5877bd5f9be9d8b23a6 was compiled on June 9, 2012 and connected to av.ddns.us with the password of admin.", - "pattern": "[domain-name:value = 'av.ddns.us' OR ipv4-addr:value = '60.2.148.167']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--950c01b8-c647-4cc8-b0c1-3612fa780108", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "jj.mysecondarydns.com", - "description": "The sample 4e84b1448cf96fabe88c623b222057c4 connected to jj.mysecondarydns.com with the password menuPass. The domain jj.mysecondarydns.com also resolved to 60.2.148.167.", - "pattern": "[domain-name:value = 'jj.mysecondarydns.com' OR ipv4-addr:value = '60.2.148.167']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--ae29faa6-5f70-4eb8-981b-30818433a52e", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "mongoles.3322.org", - "description": "The sample 494e65cf21ad559fccf3dacdd69acc94 connected to mongoles.3322.org with the password fishplay.", - "pattern": "[domain-name:value = 'mongoles.3322.org' OR ipv4-addr:value = '123.183.210.28']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--b6cc482d-89db-4e6b-a592-723070f6d22d", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "3q.wubangtu.info", - "description": "The sample a5965b750997dbecec61358d41ac93c7 connected to 3q.wubangtu.info with the password menuPass. The domain wubangtu.info also resolved to 123.183.210.28.", - "pattern": "[domain-name:value = '3q.wubangtu.info' OR ipv4-addr:value = '123.183.210.28']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "indicator", - "id": "indicator--0b71628d-31dd-4eb8-baee-39f19c0a14b0", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "CPiShellPutDoc", - "description": "menuPass uses CPiShellPutDoc as a launcher for PIVY.", - "pattern": "[file:name = 'CPiShellPutDoc']", - "labels": [ - "malicious-activity", - "attribution" - ], - "valid_from": "2015-05-15T09:12:16.432678Z" - }, - { - "type": "vulnerability", - "id": "vulnerability--c7cab3fb-0822-43a5-b1ba-c9bab34361a2", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "CVE-2012-0158", - "description": "Weaponized Microsoft Word document used by admin@338", - "external_references": [ - { - "source_name": "cve", - "external_id": "CVE-2012-0158" - } - ] - }, - { - "type": "vulnerability", - "id": "vulnerability--6a2eab9c-9789-4437-812b-d74323fa3bca", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "CVE-2009-4324", - "description": "Adobe acrobat PDF's used by admin@338", - "external_references": [ - { - "source_name": "cve", - "external_id": "CVE-2009-4324" - } - ] - }, - { - "type": "vulnerability", - "id": "vulnerability--2b7f00d8-b133-4a92-9118-46ce5f8b2531", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "CVE-2013-0422", - "description": "Java 7 vulnerability exploited by th3bug", - "external_references": [ - { - "source_name": "cve", - "external_id": "CVE-2013-0422" - } - ] - }, - { - "type": "vulnerability", - "id": "vulnerability--4d7dc9cb-983f-40b4-b597-d7a38b2d9a4b", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "CVE-2013-1347", - "description": "Microsoft Internet Explorer 8 vulnerability exploited by th3bug", - "external_references": [ - { - "source_name": "cve", - "external_id": "CVE-2013-1347" - } - ] - }, - { - "type": "vulnerability", - "id": "vulnerability--8323404c-1fdd-4272-822b-829f85556c53", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "CVE-2011-3544", - "description": "JRE vulnerability exploited by th3bug", - "external_references": [ - { - "source_name": "cve", - "external_id": "CVE-2011-3544" - } - ] - }, - { - "type": "vulnerability", - "id": "vulnerability--717cb1c9-eab3-4330-8340-e4858055aa80", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "CVE-2010-3333", - "description": "menuPass campaign using weaponized Microsoft Word documents, exploiting this vulnerability", - "external_references": [ - { - "source_name": "cve", - "external_id": "CVE-2010-3333" - } - ] - }, - { - "type": "report", - "id": "report--f2b63e80-b523-4747-a069-35c002c690db", - "created_by_ref": "identity--81cade27-7df8-4730-836b-62d880e6d9d3", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "name": "Poison Ivy: Assessing Damage and Extracting Intelligence", - "labels": [ - "threat-report", - "malware" - ], - "published": "2013-08-21T00:00:00.000000Z", - "description": "This report spotlights Poison Ivy (PIVY), a RAT that remains popular and effective a full eight years after its release, despite its age and familiarity in IT security circles. Poison Ivy is a remote access tool that is freely available for download from its official web site at www.poisonivy-rat.com. First released in 2005, the tool has gone unchanged since 2008 with version 2.3.2. Poison Ivy includes features common to most Windows-based RATs, including key logging, screen capturing, video capturing, file transfers, system administration, password theft, and traffic relaying. Poison Ivy's wide availability and easy-to-use features make it a popular choice for all kinds of criminals. But it is probably most notable for its role in many high profile, targeted APT attacks. These APTs pursue specific targets, using RATs to maintain a persistent presence within the target's network. They move laterally and escalate system privileges to extract sensitive information-whenever the attacker wants to do so. Because some RATs used in targeted attacks are widely available, determining whether an attack is part of a broader APT campaign can be difficult. Equally challenging is identifying malicious traffic to determine the attacker's post-compromise activities and assess overall damage - these RATs often encrypt their network communications after the initial exploit. In 2011, three years after the most recent release of PIVY, attackers used the RAT to compromise security firm RSA and steal data about its SecureID authentication system. That data was subsequently used in other attacks. The RSA attack was linked to Chinese threat actors and described at the time as extremely sophisticated. Exploiting a zero-day vulnerability, the attack delivered PIVY as the payload. It was not an isolated incident. The campaign appears to have started in 2010, with many other companies compromised. PIVY also played a key role in the 2011 campaign known as Nitro that targeted chemical makers, government agencies, defense contractors, and human rights groups. Still active a year later, the Nitro attackers used a zero-day vulnerability in Java to deploy PIVY in 2012. Just recently, PIVY was the payload of a zero-day exploit in Internet Explorer used in what is known as a 'strategic web compromise' attack against visitors to a U.S. government website and a variety of others. RATs require live, direct, real-time human interaction by the APT attacker. This characteristic is distinctly different from crimeware (malware focused on cybercrime), where the criminal can issue commands to their botnet of compromised endpoints whenever they please and set them to work on a common goal such as a spam relay. In contrast, RATs are much more personal and may indicate that you are dealing with a dedicated threat actor that is interested in your organization specifically.", - "object_refs": [ - "malware--591f0cb7-d66f-4e14-a8e6-5927b597f920", - "malware--61a62a6a-9a18-4758-8e52-622431c4b8ae", - "malware--30ea087f-7d2b-496b-9ed1-5f000c8b7695", - "malware--4de25c38-5826-4ee7-b84d-878064de87ad", - "malware--dc669921-4a1a-470d-bfae-694e740ce181", - "malware--f86febd3-609b-4d2e-9fec-aa805cb498bf", - "malware--80c260d9-a075-4148-9301-ebe4af27f449", - "malware--3ed0364f-62c8-4ebc-b136-deaf6966880b", - "malware--17099f03-5ec8-456d-a2de-968aebaafc78", - "malware--feaf146d-ea67-4eb1-946a-6f352ff79a81", - "malware--13791e02-6621-45fb-8c10-f6b72e1bf553", - "malware--703a15a7-eb85-475d-a27a-77d8fcf8f7b9", - "malware--fade08cb-fa57-485e-97f8-fab5a1bd4460", - "malware--3050937d-6330-44c7-83ba-8821e1f7e7bd", - "malware--9d995717-edc3-4bd8-8554-aecf773bdecc", - "malware--40e15fa5-df8d-4771-a682-21dab0a024fd", - "malware--69101c2f-da92-47af-b402-7c60a39a982f", - "malware--1601b8c2-5e6f-4a18-a413-10527e5d90b7", - "malware--626badcc-4257-4222-946c-6d6e889836ea", - "malware--3b275ed1-9c2e-4443-b1dd-5cfb51eaef2e", - "malware--f138b6e0-9a7d-4cd9-a904-08a7df2eabb1", - "malware--302ac5b5-486c-4c99-8cad-4426aeaf47b6", - "malware--e1c02dca-d3fe-48f1-bb4b-3cacd2bc3619", - "malware--a4f315bd-e159-4bfb-8439-0d5a8330fc70", - "identity--81cade27-7df8-4730-836b-62d880e6d9d3", - "campaign--752c225d-d6f6-4456-9130-d9580fd4007b", - "campaign--d02a1560-ff69-49f4-ac34-919b8aa4b91e", - "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "attack-pattern--19da6e1c-69a8-4c2f-886d-d620d09d3b5a", - "attack-pattern--ea2c747d-4aa3-4573-8853-37b7159bc180", - "attack-pattern--fb6aa549-c94a-4e45-b4fd-7e32602dad85", - "course-of-action--70b3d5f6-374b-4488-8688-729b6eedac5b", - "indicator--e8094b09-7df4-4b13-b207-1e27af3c4bde", - "indicator--329ae6e9-25bd-49e8-89d1-aae4ca52e4a7", - "indicator--54e1e351-fec0-41a4-b62c-d7f86101e241", - "indicator--2e59f00b-0986-437e-9ebd-e0d61900d688", - "indicator--8da68996-f175-4ae0-bd74-aad4913873b8", - "indicator--4e11b23f-732b-418e-b786-4dbf65459d50", - "indicator--b7fa7e73-e645-4813-9723-161bbd8dda62", - "indicator--b2f09ce0-2db4-480f-bd2f-073ddb3a0c87", - "indicator--9842a3b9-fc5b-44c4-bb48-578cf6f728d9", - "indicator--4e4c4ad7-4909-456a-b6fa-e24a6f682a40", - "indicator--137acf67-cedc-4a07-8719-72759174de3a", - "indicator--9695dc2f-d92a-4f2b-8b16-b0e21d7c631d", - "indicator--7fd865ed-93e9-481f-953b-82ab386190ae", - "indicator--e5bc6507-d052-447f-93c7-db7ef32211da", - "indicator--fead5c52-9533-405c-b822-a034092a1ba8", - "indicator--405ff732-2c35-4f46-9f78-2a632ce36e03", - "indicator--4d58096e-b5c9-47d8-af9a-1af5f4762d6b", - "indicator--9c725598-a160-4e91-8b93-ed0956709892", - "indicator--2efe7c62-1b96-4568-81ee-c85b840bde39", - "indicator--b8322c9b-8031-4fb3-9cbc-8a1ea0fe3cfa", - "indicator--b08f9631-dd94-4d99-a96c-32b42af2ea81", - "indicator--950c01b8-c647-4cc8-b0c1-3612fa780108", - "indicator--ae29faa6-5f70-4eb8-981b-30818433a52e", - "indicator--b6cc482d-89db-4e6b-a592-723070f6d22d", - "indicator--0b71628d-31dd-4eb8-baee-39f19c0a14b0", - "vulnerability--c7cab3fb-0822-43a5-b1ba-c9bab34361a2", - "vulnerability--6a2eab9c-9789-4437-812b-d74323fa3bca", - "vulnerability--2b7f00d8-b133-4a92-9118-46ce5f8b2531", - "vulnerability--4d7dc9cb-983f-40b4-b597-d7a38b2d9a4b", - "vulnerability--8323404c-1fdd-4272-822b-829f85556c53", - "vulnerability--717cb1c9-eab3-4330-8340-e4858055aa80", - "relationship--26c5311c-9d9b-4b9b-b3b5-bac10e16a7a3", - "relationship--e794befc-3270-4050-b560-b6b080ab0418", - "relationship--77a4c40e-3c33-43dc-8c78-04992ebcabf2", - "relationship--a91f3d5c-ceac-44cf-b92b-efb819241606", - "relationship--134c393e-cbe0-433c-9a7a-95263ed8578f", - "relationship--900b11dc-bfa7-4dea-adb6-0e8d726b4ded", - "relationship--8076ec7c-f6f6-4dca-a239-8bb6b5ad0c10", - "relationship--0dd66a71-c45b-4786-bd7b-92cf952afdc1", - "relationship--dc37f2bb-1a45-48b1-864e-c34dcde75d1d", - "relationship--670ae011-1649-44e2-a63e-ead0b4a4cffd", - "relationship--1a2a3630-5764-4d6e-a3c3-cb4ca27ff5f5", - "relationship--b5046891-d2c0-4497-a167-594f778517f8", - "relationship--253dbb93-c6f9-4839-8ce9-026c7b0a81e1", - "relationship--d70ebcc3-5640-423d-b9b0-7158c532c040", - "relationship--3bb540a4-c3be-478e-85e2-2a6c294c3dbd", - "relationship--4e726ced-0207-4196-8a14-4400c09b039e", - "relationship--b9736cd3-9482-4094-9178-1cde2b273aff", - "relationship--70205e3e-195d-4bd5-a208-ada6cdf143e3", - "relationship--6bb5a995-b874-4e17-88eb-38e00c8e5740", - "relationship--d4247377-5302-4ede-a0f2-579f7db67bb6", - "relationship--b8617e55-00c0-4066-8222-927846edcafe", - "relationship--f34d9e2e-715f-4baf-8226-40abfcb91012", - "relationship--937f310a-396a-403f-bb6f-400ad8920018", - "relationship--14a06709-3c0b-4e72-ad49-dd0f6d775e65", - "relationship--5f6c6509-ca0c-43db-8c0e-8e138f6d913c", - "relationship--ca99fa83-0d1b-4ddd-88c8-0dee38856a88", - "relationship--38a52125-130f-4ce7-9b38-f234553ba83d", - "relationship--e13b17d0-1fef-4f98-a4a8-895c3e4cf1e2", - "relationship--262a8234-d7e2-477a-baeb-ed65b639e33a", - "relationship--f4ceabc6-9302-4dc5-9cc1-4d40ef43503c", - "relationship--56b1023c-9e28-4449-8b4f-bc2adde45e1a", - "relationship--8997440e-00f5-48e1-8b56-69d3b6f9f1fd", - "relationship--80ac0601-0660-4057-b3b0-dca0fe35a6b4", - "relationship--2583921a-2f02-42c5-bd25-0f37eb2e6ef9", - "relationship--7231e729-42e3-4f29-ae6f-6d80192c4bd1", - "relationship--201ee2d5-74f4-4beb-b13a-34d948854655", - "relationship--afee4dc4-7d0e-450d-9164-4429649ab386", - "relationship--ed403d0d-b55d-4e78-94d3-4e035a045c39", - "relationship--4303ebf2-9590-4ec0-a702-e7bfff64bc5f", - "relationship--54f845bb-0967-4c0f-ac8a-8ad4785cbbe6", - "relationship--0bd19ca0-2bbb-4df0-92ec-59a4e9169c64", - "relationship--89ddeb74-ea26-44f9-bb6d-3f17c9d4efaa", - "relationship--eb400750-c866-47c3-89a2-fa6d1a90e9e7", - "relationship--7450856e-051f-4d49-953c-ad24f170af0e", - "relationship--1d6b0425-603d-4217-948a-fabb2a398450", - "relationship--1895dd86-dc46-4505-ba62-5724a1df2362", - "relationship--a4e0751d-8d59-4447-96ea-3799fecf66d7", - "relationship--258796f6-e46a-421a-b3f5-7db6114fb2bc", - "relationship--9431d9f9-6d8b-4373-b42c-172a663391b3", - "relationship--07d2f213-1794-483e-b95b-03761826c052", - "relationship--aa430e5b-0519-4e94-bc2c-8836d196acd7", - "relationship--c0786bd4-9c15-48ee-a19e-a9d6aba25d67", - "relationship--498b9f3b-488b-40d5-aaaf-e67b93c1d92b", - "relationship--d875538e-cc47-4353-a572-2dae27ef0a44", - "relationship--313d56c4-eef9-417e-952d-073690c20ee4", - "relationship--6b091c0f-a700-4f3e-9d98-0b8abf9a306b", - "relationship--5aff864a-1789-4df2-87fa-03ec43cf4fdd", - "relationship--325ebcb6-723c-4f50-8a32-aca18809e6eb", - "relationship--0cb9c725-3d55-4165-b2a9-9414d7933987", - "relationship--640a0454-57eb-408f-aa13-b5732b4d0b6f", - "relationship--41550302-6e95-4cf6-8d7c-d417a99d98dc", - "relationship--911dcbb0-96f4-4995-9961-5ea4b2fa7ce2", - "relationship--7b6ba584-fa87-4a6f-8c21-8123fa88db74", - "relationship--69101c2f-da92-47af-b402-7c60a39a982f", - "relationship--25055108-a2ae-4855-bd5f-6ab396aacbc5", - "relationship--44c80cab-73ce-4b17-a4cb-9a36e2585403", - "relationship--32655cb3-7455-4761-b1f2-0b82153a0540", - "relationship--fe963c8c-65a4-49ea-910b-e1cf3c80f1b4", - "relationship--4b0abf75-6f05-4bd5-8ac5-19778b245274", - "relationship--154049a5-731d-4e50-af13-f0f2c9b71f91", - "relationship--db55db06-499d-4867-9ab9-3ed4331eedb2", - "relationship--cc802697-7677-4bd7-a8b9-e728788ac783", - "relationship--a371be18-8ca5-4453-80f5-ae52d982c21b", - "relationship--9a3bd620-01b5-4764-beb0-f085417ed8f3", - "relationship--48906405-9980-4583-8559-2085c111bf89", - "relationship--13222c71-d8fa-4688-adae-c3f8ca43a41b", - "relationship--73c4529e-560e-4831-8497-a0db72f7dfd8", - "relationship--8d3e1ed6-7d9c-4aa5-b121-f4eb193312cf", - "relationship--2c11dcc0-7968-4c07-bdde-791a8f5e2e37", - "relationship--fd97d0ef-370e-4b6f-b2d3-8fb881aadc3f", - "relationship--c05d2410-848c-47e5-a94f-c64510e2b08d", - "relationship--92a21b52-2961-42aa-8b01-54ea294d9d73", - "relationship--76a9283a-b844-47a5-a5d0-b31859115f88", - "relationship--bbd3ba5c-2a75-4902-bd42-1215a2bc320e", - "relationship--4f784f2f-7d8e-4f12-9ddd-b685055f8076", - "relationship--263e38f4-8ecb-414f-b3c4-0f045d1be5ed", - "relationship--a56e8582-fc6e-4be8-bf35-7e939269d65e", - "relationship--d7d9952c-4443-4711-a48c-7009a0f0f8ea", - "relationship--78f110e6-2cd6-442e-971f-a2ff40c3b843", - "relationship--b2fb88f2-5ad7-4c07-b4b2-61986decb477" - ] - }, - { - "type": "relationship", - "id": "relationship--26c5311c-9d9b-4b9b-b3b5-bac10e16a7a3", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--752c225d-d6f6-4456-9130-d9580fd4007b", - "target_ref": "attack-pattern--19da6e1c-69a8-4c2f-886d-d620d09d3b5a" - }, - { - "type": "relationship", - "id": "relationship--e794befc-3270-4050-b560-b6b080ab0418", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--d02a1560-ff69-49f4-ac34-919b8aa4b91e", - "target_ref": "attack-pattern--ea2c747d-4aa3-4573-8853-37b7159bc180" - }, - { - "type": "relationship", - "id": "relationship--77a4c40e-3c33-43dc-8c78-04992ebcabf2", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "attack-pattern--fb6aa549-c94a-4e45-b4fd-7e32602dad85" - }, - { - "type": "relationship", - "id": "relationship--134c393e-cbe0-433c-9a7a-95263ed8578f", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "mitigates", - "source_ref": "course-of-action--70b3d5f6-374b-4488-8688-729b6eedac5b", - "target_ref": "malware--591f0cb7-d66f-4e14-a8e6-5927b597f920" - }, - { - "type": "relationship", - "id": "relationship--a91f3d5c-ceac-44cf-b92b-efb819241606", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--752c225d-d6f6-4456-9130-d9580fd4007b", - "target_ref": "malware--61a62a6a-9a18-4758-8e52-622431c4b8ae" - }, - { - "type": "relationship", - "id": "relationship--900b11dc-bfa7-4dea-adb6-0e8d726b4ded", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--e8094b09-7df4-4b13-b207-1e27af3c4bde", - "target_ref": "malware--61a62a6a-9a18-4758-8e52-622431c4b8ae" - }, - { - "type": "relationship", - "id": "relationship--8076ec7c-f6f6-4dca-a239-8bb6b5ad0c10", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--e8094b09-7df4-4b13-b207-1e27af3c4bde", - "target_ref": "campaign--752c225d-d6f6-4456-9130-d9580fd4007b" - }, - { - "type": "relationship", - "id": "relationship--0dd66a71-c45b-4786-bd7b-92cf952afdc1", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--329ae6e9-25bd-49e8-89d1-aae4ca52e4a7", - "target_ref": "campaign--752c225d-d6f6-4456-9130-d9580fd4007b" - }, - { - "type": "relationship", - "id": "relationship--dc37f2bb-1a45-48b1-864e-c34dcde75d1d", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--329ae6e9-25bd-49e8-89d1-aae4ca52e4a7", - "target_ref": "malware--30ea087f-7d2b-496b-9ed1-5f000c8b7695" - }, - { - "type": "relationship", - "id": "relationship--670ae011-1649-44e2-a63e-ead0b4a4cffd", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--8da68996-f175-4ae0-bd74-aad4913873b8", - "target_ref": "campaign--752c225d-d6f6-4456-9130-d9580fd4007b" - }, - { - "type": "relationship", - "id": "relationship--1a2a3630-5764-4d6e-a3c3-cb4ca27ff5f5", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--8da68996-f175-4ae0-bd74-aad4913873b8", - "target_ref": "malware--4de25c38-5826-4ee7-b84d-878064de87ad" - }, - { - "type": "relationship", - "id": "relationship--b5046891-d2c0-4497-a167-594f778517f8", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--2e59f00b-0986-437e-9ebd-e0d61900d688", - "target_ref": "campaign--752c225d-d6f6-4456-9130-d9580fd4007b" - }, - { - "type": "relationship", - "id": "relationship--253dbb93-c6f9-4839-8ce9-026c7b0a81e1", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--2e59f00b-0986-437e-9ebd-e0d61900d688", - "target_ref": "malware--30ea087f-7d2b-496b-9ed1-5f000c8b7695" - }, - { - "type": "relationship", - "id": "relationship--d70ebcc3-5640-423d-b9b0-7158c532c040", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "targets", - "source_ref": "campaign--752c225d-d6f6-4456-9130-d9580fd4007b", - "target_ref": "vulnerability--c7cab3fb-0822-43a5-b1ba-c9bab34361a2" - }, - { - "type": "relationship", - "id": "relationship--3bb540a4-c3be-478e-85e2-2a6c294c3dbd", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "targets", - "source_ref": "campaign--752c225d-d6f6-4456-9130-d9580fd4007b", - "target_ref": "vulnerability--6a2eab9c-9789-4437-812b-d74323fa3bca" - }, - { - "type": "relationship", - "id": "relationship--4e726ced-0207-4196-8a14-4400c09b039e", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "targets", - "source_ref": "attack-pattern--19da6e1c-69a8-4c2f-886d-d620d09d3b5a", - "target_ref": "vulnerability--c7cab3fb-0822-43a5-b1ba-c9bab34361a2" - }, - { - "type": "relationship", - "id": "relationship--b9736cd3-9482-4094-9178-1cde2b273aff", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "targets", - "source_ref": "attack-pattern--19da6e1c-69a8-4c2f-886d-d620d09d3b5a", - "target_ref": "vulnerability--6a2eab9c-9789-4437-812b-d74323fa3bca" - }, - { - "type": "relationship", - "id": "relationship--70205e3e-195d-4bd5-a208-ada6cdf143e3", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "targets", - "source_ref": "campaign--d02a1560-ff69-49f4-ac34-919b8aa4b91e", - "target_ref": "vulnerability--2b7f00d8-b133-4a92-9118-46ce5f8b2531" - }, - { - "type": "relationship", - "id": "relationship--6bb5a995-b874-4e17-88eb-38e00c8e5740", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "targets", - "source_ref": "campaign--d02a1560-ff69-49f4-ac34-919b8aa4b91e", - "target_ref": "vulnerability--4d7dc9cb-983f-40b4-b597-d7a38b2d9a4b" - }, - { - "type": "relationship", - "id": "relationship--d4247377-5302-4ede-a0f2-579f7db67bb6", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "targets", - "source_ref": "campaign--d02a1560-ff69-49f4-ac34-919b8aa4b91e", - "target_ref": "vulnerability--8323404c-1fdd-4272-822b-829f85556c53" - }, - { - "type": "relationship", - "id": "relationship--b8617e55-00c0-4066-8222-927846edcafe", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--d02a1560-ff69-49f4-ac34-919b8aa4b91e", - "target_ref": "malware--dc669921-4a1a-470d-bfae-694e740ce181" - }, - { - "type": "relationship", - "id": "relationship--f34d9e2e-715f-4baf-8226-40abfcb91012", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--d02a1560-ff69-49f4-ac34-919b8aa4b91e", - "target_ref": "malware--f86febd3-609b-4d2e-9fec-aa805cb498bf" - }, - { - "type": "relationship", - "id": "relationship--937f310a-396a-403f-bb6f-400ad8920018", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--4e11b23f-732b-418e-b786-4dbf65459d50", - "target_ref": "campaign--d02a1560-ff69-49f4-ac34-919b8aa4b91e" - }, - { - "type": "relationship", - "id": "relationship--14a06709-3c0b-4e72-ad49-dd0f6d775e65", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--4e11b23f-732b-418e-b786-4dbf65459d50", - "target_ref": "malware--dc669921-4a1a-470d-bfae-694e740ce181" - }, - { - "type": "relationship", - "id": "relationship--5f6c6509-ca0c-43db-8c0e-8e138f6d913c", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--b7fa7e73-e645-4813-9723-161bbd8dda62", - "target_ref": "campaign--d02a1560-ff69-49f4-ac34-919b8aa4b91e" - }, - { - "type": "relationship", - "id": "relationship--ca99fa83-0d1b-4ddd-88c8-0dee38856a88", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--b7fa7e73-e645-4813-9723-161bbd8dda62", - "target_ref": "malware--f86febd3-609b-4d2e-9fec-aa805cb498bf" - }, - { - "type": "relationship", - "id": "relationship--38a52125-130f-4ce7-9b38-f234553ba83d", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--80c260d9-a075-4148-9301-ebe4af27f449" - }, - { - "type": "relationship", - "id": "relationship--e13b17d0-1fef-4f98-a4a8-895c3e4cf1e2", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--b2f09ce0-2db4-480f-bd2f-073ddb3a0c87", - "target_ref": "malware--80c260d9-a075-4148-9301-ebe4af27f449" - }, - { - "type": "relationship", - "id": "relationship--262a8234-d7e2-477a-baeb-ed65b639e33a", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--b2f09ce0-2db4-480f-bd2f-073ddb3a0c87", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--f4ceabc6-9302-4dc5-9cc1-4d40ef43503c", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "targets", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "vulnerability--717cb1c9-eab3-4330-8340-e4858055aa80" - }, - { - "type": "relationship", - "id": "relationship--56b1023c-9e28-4449-8b4f-bc2adde45e1a", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "targets", - "source_ref": "attack-pattern--fb6aa549-c94a-4e45-b4fd-7e32602dad85", - "target_ref": "vulnerability--717cb1c9-eab3-4330-8340-e4858055aa80" - }, - { - "type": "relationship", - "id": "relationship--8997440e-00f5-48e1-8b56-69d3b6f9f1fd", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--9842a3b9-fc5b-44c4-bb48-578cf6f728d9", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--80ac0601-0660-4057-b3b0-dca0fe35a6b4", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--9842a3b9-fc5b-44c4-bb48-578cf6f728d9", - "target_ref": "malware--3ed0364f-62c8-4ebc-b136-deaf6966880b" - }, - { - "type": "relationship", - "id": "relationship--2583921a-2f02-42c5-bd25-0f37eb2e6ef9", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--3ed0364f-62c8-4ebc-b136-deaf6966880b" - }, - { - "type": "relationship", - "id": "relationship--7231e729-42e3-4f29-ae6f-6d80192c4bd1", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--4e4c4ad7-4909-456a-b6fa-e24a6f682a40", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--201ee2d5-74f4-4beb-b13a-34d948854655", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--9842a3b9-fc5b-44c4-bb48-578cf6f728d9", - "target_ref": "malware--17099f03-5ec8-456d-a2de-968aebaafc78" - }, - { - "type": "relationship", - "id": "relationship--afee4dc4-7d0e-450d-9164-4429649ab386", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--17099f03-5ec8-456d-a2de-968aebaafc78" - }, - { - "type": "relationship", - "id": "relationship--ed403d0d-b55d-4e78-94d3-4e035a045c39", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--137acf67-cedc-4a07-8719-72759174de3a", - "target_ref": "malware--17099f03-5ec8-456d-a2de-968aebaafc78" - }, - { - "type": "relationship", - "id": "relationship--4303ebf2-9590-4ec0-a702-e7bfff64bc5f", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--137acf67-cedc-4a07-8719-72759174de3a", - "target_ref": "malware--3ed0364f-62c8-4ebc-b136-deaf6966880b" - }, - { - "type": "relationship", - "id": "relationship--54f845bb-0967-4c0f-ac8a-8ad4785cbbe6", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--137acf67-cedc-4a07-8719-72759174de3a", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--0bd19ca0-2bbb-4df0-92ec-59a4e9169c64", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--137acf67-cedc-4a07-8719-72759174de3a", - "target_ref": "malware--e14b6476-40b5-4b0b-bde7-0e856ab00b6c" - }, - { - "type": "relationship", - "id": "relationship--89ddeb74-ea26-44f9-bb6d-3f17c9d4efaa", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--9695dc2f-d92a-4f2b-8b16-b0e21d7c631d", - "target_ref": "malware--e14b6476-40b5-4b0b-bde7-0e856ab00b6c" - }, - { - "type": "relationship", - "id": "relationship--eb400750-c866-47c3-89a2-fa6d1a90e9e7", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--9695dc2f-d92a-4f2b-8b16-b0e21d7c631d", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--7450856e-051f-4d49-953c-ad24f170af0e", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--e14b6476-40b5-4b0b-bde7-0e856ab00b6c" - }, - { - "type": "relationship", - "id": "relationship--1d6b0425-603d-4217-948a-fabb2a398450", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--7fd865ed-93e9-481f-953b-82ab386190ae", - "target_ref": "malware--feaf146d-ea67-4eb1-946a-6f352ff79a81" - }, - { - "type": "relationship", - "id": "relationship--1895dd86-dc46-4505-ba62-5724a1df2362", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--7fd865ed-93e9-481f-953b-82ab386190ae", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--a4e0751d-8d59-4447-96ea-3799fecf66d7", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--feaf146d-ea67-4eb1-946a-6f352ff79a81" - }, - { - "type": "relationship", - "id": "relationship--258796f6-e46a-421a-b3f5-7db6114fb2bc", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--e5bc6507-d052-447f-93c7-db7ef32211da", - "target_ref": "malware--13791e02-6621-45fb-8c10-f6b72e1bf553" - }, - { - "type": "relationship", - "id": "relationship--9431d9f9-6d8b-4373-b42c-172a663391b3", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--e5bc6507-d052-447f-93c7-db7ef32211da", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--07d2f213-1794-483e-b95b-03761826c052", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--13791e02-6621-45fb-8c10-f6b72e1bf553" - }, - { - "type": "relationship", - "id": "relationship--aa430e5b-0519-4e94-bc2c-8836d196acd7", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--fead5c52-9533-405c-b822-a034092a1ba8", - "target_ref": "malware--703a15a7-eb85-475d-a27a-77d8fcf8f7b9" - }, - { - "type": "relationship", - "id": "relationship--c0786bd4-9c15-48ee-a19e-a9d6aba25d67", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--fead5c52-9533-405c-b822-a034092a1ba8", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--498b9f3b-488b-40d5-aaaf-e67b93c1d92b", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--703a15a7-eb85-475d-a27a-77d8fcf8f7b9" - }, - { - "type": "relationship", - "id": "relationship--d875538e-cc47-4353-a572-2dae27ef0a44", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--9842a3b9-fc5b-44c4-bb48-578cf6f728d9", - "target_ref": "malware--fade08cb-fa57-485e-97f8-fab5a1bd4460" - }, - { - "type": "relationship", - "id": "relationship--313d56c4-eef9-417e-952d-073690c20ee4", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--fade08cb-fa57-485e-97f8-fab5a1bd4460" - }, - { - "type": "relationship", - "id": "relationship--6b091c0f-a700-4f3e-9d98-0b8abf9a306b", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--405ff732-2c35-4f46-9f78-2a632ce36e03", - "target_ref": "malware--3050937d-6330-44c7-83ba-8821e1f7e7bd" - }, - { - "type": "relationship", - "id": "relationship--5aff864a-1789-4df2-87fa-03ec43cf4fdd", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--405ff732-2c35-4f46-9f78-2a632ce36e03", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--325ebcb6-723c-4f50-8a32-aca18809e6eb", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--3050937d-6330-44c7-83ba-8821e1f7e7bd" - }, - { - "type": "relationship", - "id": "relationship--0cb9c725-3d55-4165-b2a9-9414d7933987", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--4d58096e-b5c9-47d8-af9a-1af5f4762d6b", - "target_ref": "malware--9d995717-edc3-4bd8-8554-aecf773bdecc" - }, - { - "type": "relationship", - "id": "relationship--640a0454-57eb-408f-aa13-b5732b4d0b6f", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--4d58096e-b5c9-47d8-af9a-1af5f4762d6b", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--41550302-6e95-4cf6-8d7c-d417a99d98dc", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--9d995717-edc3-4bd8-8554-aecf773bdecc" - }, - { - "type": "relationship", - "id": "relationship--911dcbb0-96f4-4995-9961-5ea4b2fa7ce2", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--9c725598-a160-4e91-8b93-ed0956709892", - "target_ref": "malware--40e15fa5-df8d-4771-a682-21dab0a024fd" - }, - { - "type": "relationship", - "id": "relationship--7b6ba584-fa87-4a6f-8c21-8123fa88db74", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--9c725598-a160-4e91-8b93-ed0956709892", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--69101c2f-da92-47af-b402-7c60a39a982f", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--40e15fa5-df8d-4771-a682-21dab0a024fd" - }, - { - "type": "relationship", - "id": "relationship--25055108-a2ae-4855-bd5f-6ab396aacbc5", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--2efe7c62-1b96-4568-81ee-c85b840bde39", - "target_ref": "malware--69101c2f-da92-47af-b402-7c60a39a982f" - }, - { - "type": "relationship", - "id": "relationship--44c80cab-73ce-4b17-a4cb-9a36e2585403", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--2efe7c62-1b96-4568-81ee-c85b840bde39", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--32655cb3-7455-4761-b1f2-0b82153a0540", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--69101c2f-da92-47af-b402-7c60a39a982f" - }, - { - "type": "relationship", - "id": "relationship--fe963c8c-65a4-49ea-910b-e1cf3c80f1b4", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--b8322c9b-8031-4fb3-9cbc-8a1ea0fe3cfa", - "target_ref": "malware--1601b8c2-5e6f-4a18-a413-10527e5d90b7" - }, - { - "type": "relationship", - "id": "relationship--4b0abf75-6f05-4bd5-8ac5-19778b245274", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--b8322c9b-8031-4fb3-9cbc-8a1ea0fe3cfa", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--154049a5-731d-4e50-af13-f0f2c9b71f91", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--1601b8c2-5e6f-4a18-a413-10527e5d90b7" - }, - { - "type": "relationship", - "id": "relationship--db55db06-499d-4867-9ab9-3ed4331eedb2", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--b08f9631-dd94-4d99-a96c-32b42af2ea81", - "target_ref": "malware--626badcc-4257-4222-946c-6d6e889836ea" - }, - { - "type": "relationship", - "id": "relationship--cc802697-7677-4bd7-a8b9-e728788ac783", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--b08f9631-dd94-4d99-a96c-32b42af2ea81", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--a371be18-8ca5-4453-80f5-ae52d982c21b", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--626badcc-4257-4222-946c-6d6e889836ea" - }, - { - "type": "relationship", - "id": "relationship--9a3bd620-01b5-4764-beb0-f085417ed8f3", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--137acf67-cedc-4a07-8719-72759174de3a", - "target_ref": "malware--3b275ed1-9c2e-4443-b1dd-5cfb51eaef2e" - }, - { - "type": "relationship", - "id": "relationship--48906405-9980-4583-8559-2085c111bf89", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--3b275ed1-9c2e-4443-b1dd-5cfb51eaef2e" - }, - { - "type": "relationship", - "id": "relationship--13222c71-d8fa-4688-adae-c3f8ca43a41b", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--137acf67-cedc-4a07-8719-72759174de3a", - "target_ref": "malware--f138b6e0-9a7d-4cd9-a904-08a7df2eabb1" - }, - { - "type": "relationship", - "id": "relationship--73c4529e-560e-4831-8497-a0db72f7dfd8", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--f138b6e0-9a7d-4cd9-a904-08a7df2eabb1" - }, - { - "type": "relationship", - "id": "relationship--8d3e1ed6-7d9c-4aa5-b121-f4eb193312cf", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--950c01b8-c647-4cc8-b0c1-3612fa780108", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--2c11dcc0-7968-4c07-bdde-791a8f5e2e37", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--302ac5b5-486c-4c99-8cad-4426aeaf47b6" - }, - { - "type": "relationship", - "id": "relationship--fd97d0ef-370e-4b6f-b2d3-8fb881aadc3f", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--950c01b8-c647-4cc8-b0c1-3612fa780108", - "target_ref": "malware--302ac5b5-486c-4c99-8cad-4426aeaf47b6" - }, - { - "type": "relationship", - "id": "relationship--c05d2410-848c-47e5-a94f-c64510e2b08d", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--ae29faa6-5f70-4eb8-981b-30818433a52e", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--92a21b52-2961-42aa-8b01-54ea294d9d73", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--e1c02dca-d3fe-48f1-bb4b-3cacd2bc3619" - }, - { - "type": "relationship", - "id": "relationship--76a9283a-b844-47a5-a5d0-b31859115f88", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--ae29faa6-5f70-4eb8-981b-30818433a52e", - "target_ref": "malware--e1c02dca-d3fe-48f1-bb4b-3cacd2bc3619" - }, - { - "type": "relationship", - "id": "relationship--bbd3ba5c-2a75-4902-bd42-1215a2bc320e", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--137acf67-cedc-4a07-8719-72759174de3a", - "target_ref": "malware--e1c02dca-d3fe-48f1-bb4b-3cacd2bc3619" - }, - { - "type": "relationship", - "id": "relationship--4f784f2f-7d8e-4f12-9ddd-b685055f8076", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--b6cc482d-89db-4e6b-a592-723070f6d22d", - "target_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05" - }, - { - "type": "relationship", - "id": "relationship--263e38f4-8ecb-414f-b3c4-0f045d1be5ed", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "uses", - "source_ref": "campaign--721976f9-56d7-4749-8c69-b3ac7c315f05", - "target_ref": "malware--a4f315bd-e159-4bfb-8439-0d5a8330fc70" - }, - { - "type": "relationship", - "id": "relationship--a56e8582-fc6e-4be8-bf35-7e939269d65e", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--b6cc482d-89db-4e6b-a592-723070f6d22d", - "target_ref": "malware--a4f315bd-e159-4bfb-8439-0d5a8330fc70" - }, - { - "type": "relationship", - "id": "relationship--d7d9952c-4443-4711-a48c-7009a0f0f8ea", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--137acf67-cedc-4a07-8719-72759174de3a", - "target_ref": "malware--a4f315bd-e159-4bfb-8439-0d5a8330fc70" - }, - { - "type": "relationship", - "id": "relationship--78f110e6-2cd6-442e-971f-a2ff40c3b843", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--0b71628d-31dd-4eb8-baee-39f19c0a14b0", - "target_ref": "malware--40e15fa5-df8d-4771-a682-21dab0a024fd" - }, - { - "type": "relationship", - "id": "relationship--b2fb88f2-5ad7-4c07-b4b2-61986decb477", - "created": "2015-05-15T09:12:16.432Z", - "modified": "2015-05-15T09:12:16.432Z", - "relationship_type": "indicates", - "source_ref": "indicator--0b71628d-31dd-4eb8-baee-39f19c0a14b0", - "target_ref": "malware--69101c2f-da92-47af-b402-7c60a39a982f" - } - ] -} diff --git a/src/test/resources/stix/custom/custom_object_1.json b/src/test/resources/stix/custom/custom_object_1.json deleted file mode 100644 index 946db44..0000000 --- a/src/test/resources/stix/custom/custom_object_1.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "external_references": [ - { - "external_id": "TA0006", - "source_name": "mitre-attack", - "url": "https://attack.mitre.org/tactics/TA0006" - } - ], - "id": "x-mitre-tactic--2558fd61-8c75-4730-94c4-11926db2a263", - "name": "Credential Access", - "created": "2018-10-17T00:14:20.652Z", - "modified": "2018-10-17T00:14:20.652Z", - "type": "x-mitre-tactic", - "description": "Credential access represents techniques resulting in access to or control over system, domain, or service credentials that are used within an enterprise environment. Adversaries will likely attempt to obtain legitimate credentials from users or administrator accounts (local system administrator or domain users with administrator access) to use within the network. This allows the adversary to assume the identity of the account, with all of that account's permissions on the system and network, and makes it harder for defenders to detect the adversary. With sufficient access within a network, an adversary can create accounts for later use within the environment.", - "x_mitre_shortname": "credential-access" -} \ No newline at end of file