diff --git a/README.md b/README.md index 144cbf8..2bb7266 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ Marknl Iodef Library ==================== [![Build Status](https://travis-ci.org/marknl/iodef.svg?branch=master)](https://travis-ci.org/marknl/iodef) [![Latest Stable Version](https://poser.pugx.org/marknl/iodef/v/stable)](https://packagist.org/packages/marknl/iodef) -[![Latest Unstable Version](https://poser.pugx.org/marknl/iodef/v/unstable)](https://packagist.org/packages/marknl/iodef) [![Total Downloads](https://poser.pugx.org/marknl/iodef/downloads)](https://packagist.org/packages/marknl/iodef) [![License](https://poser.pugx.org/marknl/iodef/license)](https://packagist.org/packages/marknl/iodef) diff --git a/composer.json b/composer.json index 79c1982..939a3cd 100644 --- a/composer.json +++ b/composer.json @@ -5,32 +5,35 @@ "homepage": "http://e-rave.nl/iodef", "type": "library", "license": "GPL-2.0", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, "authors": [ - { - "name": "Mark Stunnenberg", - "email": "mark@e-rave.nl", - "homepage": "http://e-rave.nl/", - "role": "Lead" - } - ], + { + "name": "Mark Stunnenberg", + "email": "mark@e-rave.nl", + "homepage": "http://e-rave.nl/", + "role": "Lead" + } + ], "support": { "issues": "https://github.com/marknl/iodef/issues", "source": "https://github.com/marknl/iodef" }, "require": { "php": ">=5.5.0", - "sabre/xml": "1.5.*", - "sabre/uri": "1.2.*", + "sabre/xml": "1.5.*", + "sabre/uri": "1.2.*", "vlucas/valitron": "1.3.*" }, "autoload": { "psr-4": { "Marknl\\Iodef\\": "src/" + }, + "psr-0": { + "src/": "" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" } } } diff --git a/phpunit.xml b/phpunit.xml index 856dbdb..3ebe3c1 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,5 +1,7 @@ -elements = [ - 'IncidentID' => 'REQUIRED_MULTI', + 'IncidentID' => parent::REQUIRED_MULTI, ]; } diff --git a/src/Elements/Application.php b/src/Elements/Application.php index fbc10ba..ac9e3a2 100644 --- a/src/Elements/Application.php +++ b/src/Elements/Application.php @@ -19,7 +19,7 @@ public function __construct() ]; $this->elements = [ - 'URL' => 'OPTIONAL', + 'URL' => parent::OPTIONAL, ]; } diff --git a/src/Elements/Assessment.php b/src/Elements/Assessment.php index 81c44f0..43c661f 100644 --- a/src/Elements/Assessment.php +++ b/src/Elements/Assessment.php @@ -14,12 +14,12 @@ public function __construct() ]; $this->elements = [ - 'Impact' => 'OPTIONAL_MULTI', - 'TimeImpact' => 'OPTIONAL_MULTI', - 'MonetaryImpact' => 'OPTIONAL_MULTI', - 'Counter' => 'OPTIONAL_MULTI', - 'Confidence' => 'OPTIONAL', - 'AdditionalData' => 'OPTIONAL_MULTI', + 'Impact' => parent::OPTIONAL_MULTI, + 'TimeImpact' => parent::OPTIONAL_MULTI, + 'MonetaryImpact' => parent::OPTIONAL_MULTI, + 'Counter' => parent::OPTIONAL_MULTI, + 'Confidence' => parent::OPTIONAL, + 'AdditionalData' => parent::OPTIONAL_MULTI, ]; } diff --git a/src/Elements/Contact.php b/src/Elements/Contact.php index 896add9..bba312a 100644 --- a/src/Elements/Contact.php +++ b/src/Elements/Contact.php @@ -17,16 +17,16 @@ public function __construct() ]; $this->elements = [ - 'ContactName' => 'OPTIONAL', - 'Description' => 'OPTIONAL_MULTI', - 'RegistryHandle' => 'OPTIONAL_MULTI', - 'PostalAddress' => 'OPTIONAL', - 'Email' => 'OPTIONAL_MULTI', - 'Telephone' => 'OPTIONAL_MULTI', - 'Fax' => 'OPTIONAL', - 'Timezone' => 'OPTIONAL', - 'Contact' => 'OPTIONAL_MULTI', - 'AdditionalData' => 'OPTIONAL_MULTI', + 'ContactName' => parent::OPTIONAL, + 'Description' => parent::OPTIONAL_MULTI, + 'RegistryHandle' => parent::OPTIONAL_MULTI, + 'PostalAddress' => parent::OPTIONAL, + 'Email' => parent::OPTIONAL_MULTI, + 'Telephone' => parent::OPTIONAL_MULTI, + 'Fax' => parent::OPTIONAL, + 'Timezone' => parent::OPTIONAL, + 'Contact' => parent::OPTIONAL_MULTI, + 'AdditionalData' => parent::OPTIONAL_MULTI, ]; } diff --git a/src/Elements/EventData.php b/src/Elements/EventData.php index 36d9e05..f5f26d5 100644 --- a/src/Elements/EventData.php +++ b/src/Elements/EventData.php @@ -13,17 +13,17 @@ public function __construct() ]; $this->elements = [ - 'Description' => 'OPTIONAL_MULTI', - 'DetectTime' => 'OPTIONAL', - 'StartTime' => 'OPTIONAL', - 'Contact' => 'OPTIONAL_MULTI', - 'Assessment' => 'OPTIONAL', - 'Method' => 'OPTIONAL_MULTI', - 'Flow' => 'OPTIONAL_MULTI', - 'Expectation' => 'OPTIONAL_MULTI', - 'Record' => 'OPTIONAL', - 'EventData' => 'OPTIONAL_MULTI', - 'AdditionalData' => 'OPTIONAL_MULTI', + 'Description' => parent::OPTIONAL_MULTI, + 'DetectTime' => parent::OPTIONAL, + 'StartTime' => parent::OPTIONAL, + 'Contact' => parent::OPTIONAL_MULTI, + 'Assessment' => parent::OPTIONAL, + 'Method' => parent::OPTIONAL_MULTI, + 'Flow' => parent::OPTIONAL_MULTI, + 'Expectation' => parent::OPTIONAL_MULTI, + 'Record' => parent::OPTIONAL, + 'EventData' => parent::OPTIONAL_MULTI, + 'AdditionalData' => parent::OPTIONAL_MULTI, ]; } diff --git a/src/Elements/Expectation.php b/src/Elements/Expectation.php index 2390921..9aa6dcf 100644 --- a/src/Elements/Expectation.php +++ b/src/Elements/Expectation.php @@ -16,10 +16,10 @@ public function __construct() ]; $this->elements = [ - 'Description' => 'OPTIONAL_MULTI', - 'StartTime' => 'OPTIONAL', - 'EndTime' => 'OPTIONAL', - 'Contact' => 'OPTIONAL', + 'Description' => parent::OPTIONAL_MULTI, + 'StartTime' => parent::OPTIONAL, + 'EndTime' => parent::OPTIONAL, + 'Contact' => parent::OPTIONAL, ]; } diff --git a/src/Elements/Flow.php b/src/Elements/Flow.php index cfb4d65..09a70dd 100644 --- a/src/Elements/Flow.php +++ b/src/Elements/Flow.php @@ -9,7 +9,7 @@ class Flow extends IodefElement public function __construct() { $this->elements = [ - 'System' => 'REQUIRED_MULTI', + 'System' => parent::REQUIRED_MULTI, ]; } } diff --git a/src/Elements/History.php b/src/Elements/History.php index b2b80af..8e58ea2 100644 --- a/src/Elements/History.php +++ b/src/Elements/History.php @@ -13,7 +13,7 @@ public function __construct() ]; $this->elements = [ - 'HistoryItem' => 'REQUIRED_MULTI', + 'HistoryItem' => parent::REQUIRED_MULTI, ]; } diff --git a/src/Elements/HistoryItem.php b/src/Elements/HistoryItem.php index e74514d..723d96a 100644 --- a/src/Elements/HistoryItem.php +++ b/src/Elements/HistoryItem.php @@ -15,11 +15,11 @@ public function __construct() ]; $this->elements = [ - 'DateTime' => 'REQUIRED', - 'IncidentId' => 'OPTIONAL', - 'Contact' => 'OPTIONAL', - 'Description' => 'OPTIONAL_MULTI', - 'AdditionalData' => 'OPTIONAL_MULTI', + 'DateTime' => parent::REQUIRED, + 'IncidentId' => parent::OPTIONAL, + 'Contact' => parent::OPTIONAL, + 'Description' => parent::OPTIONAL_MULTI, + 'AdditionalData' => parent::OPTIONAL_MULTI, ]; } diff --git a/src/Elements/IODEFDocument.php b/src/Elements/IODEFDocument.php index 3394ea5..35f274d 100644 --- a/src/Elements/IODEFDocument.php +++ b/src/Elements/IODEFDocument.php @@ -21,7 +21,7 @@ public function __construct() ]; $this->elements = [ - 'Incident' => 'REQUIRED_MULTI', + 'Incident' => parent::REQUIRED_MULTI, ]; } diff --git a/src/Elements/Incident.php b/src/Elements/Incident.php index 514a49b..90de2fe 100644 --- a/src/Elements/Incident.php +++ b/src/Elements/Incident.php @@ -16,20 +16,20 @@ public function __construct() ]; $this->elements = [ - 'IncidentID' => 'REQUIRED', - 'AlternativeID' => 'OPTIONAL', - 'RelatedActivity' => 'OPTIONAL', - 'DetectTime' => 'OPTIONAL', - 'StartTime' => 'OPTIONAL', - 'EndTime' => 'OPTIONAL', - 'ReportTime' => 'REQUIRED', - 'Description' => 'OPTIONAL_MULTI', - 'Assessment' => 'REQUIRED_MULTI', - 'Method' => 'OPTIONAL_MULTI', - 'Contact' => 'REQUIRED_MULTI', - 'EventData' => 'OPTIONAL_MULTI', - 'History' => 'OPTIONAL', - 'AdditionalData' => 'OPTIONAL_MULTI', + 'IncidentID' => parent::REQUIRED, + 'AlternativeID' => parent::OPTIONAL, + 'RelatedActivity' => parent::OPTIONAL, + 'DetectTime' => parent::OPTIONAL, + 'StartTime' => parent::OPTIONAL, + 'EndTime' => parent::OPTIONAL, + 'ReportTime' => parent::REQUIRED, + 'Description' => parent::OPTIONAL_MULTI, + 'Assessment' => parent::REQUIRED_MULTI, + 'Method' => parent::OPTIONAL_MULTI, + 'Contact' => parent::REQUIRED_MULTI, + 'EventData' => parent::OPTIONAL_MULTI, + 'History' => parent::OPTIONAL, + 'AdditionalData' => parent::OPTIONAL_MULTI, ]; } diff --git a/src/Elements/Method.php b/src/Elements/Method.php index 25384f9..6fe022e 100644 --- a/src/Elements/Method.php +++ b/src/Elements/Method.php @@ -13,9 +13,9 @@ public function __construct() ]; $this->elements = [ - 'Reference' => 'OPTIONAL_MULTI', - 'Description' => 'OPTIONAL_MULTI', - 'AdditionalData' => 'OPTIONAL_MULTI', + 'Reference' => parent::OPTIONAL_MULTI, + 'Description' => parent::OPTIONAL_MULTI, + 'AdditionalData' => parent::OPTIONAL_MULTI, ]; } diff --git a/src/Elements/Node.php b/src/Elements/Node.php index 812c90d..4a70f9c 100644 --- a/src/Elements/Node.php +++ b/src/Elements/Node.php @@ -9,12 +9,12 @@ class Node extends IodefElement public function __construct() { $this->elements = [ - 'NodeName' => 'OPTIONAL_MULTI', - 'Address' => 'OPTIONAL_MULTI', - 'Location' => 'OPTIONAL', - 'DateTime' => 'OPTIONAL', - 'NodeRole' => 'OPTIONAL_MULTI', - 'Counter' => 'OPTIONAL_MULTI', + 'NodeName' => parent::OPTIONAL_MULTI, + 'Address' => parent::OPTIONAL_MULTI, + 'Location' => parent::OPTIONAL, + 'DateTime' => parent::OPTIONAL, + 'NodeRole' => parent::OPTIONAL_MULTI, + 'Counter' => parent::OPTIONAL_MULTI, ]; } } diff --git a/src/Elements/OperatingSystem.php b/src/Elements/OperatingSystem.php index b6ed0bb..83eeaa1 100644 --- a/src/Elements/OperatingSystem.php +++ b/src/Elements/OperatingSystem.php @@ -19,7 +19,7 @@ public function __construct() ]; $this->elements = [ - 'URL' => 'OPTIONAL', + 'URL' => parent::OPTIONAL, ]; } diff --git a/src/Elements/Record.php b/src/Elements/Record.php index da9bf57..d1bc13b 100644 --- a/src/Elements/Record.php +++ b/src/Elements/Record.php @@ -13,7 +13,7 @@ public function __construct() ]; $this->elements = [ - 'RecordData' => 'REQUIRED_MULTI', + 'RecordData' => parent::REQUIRED_MULTI, ]; } diff --git a/src/Elements/RecordData.php b/src/Elements/RecordData.php index f9b2533..9109ce5 100644 --- a/src/Elements/RecordData.php +++ b/src/Elements/RecordData.php @@ -13,12 +13,12 @@ public function __construct() ]; $this->elements = [ - 'DateTime' => 'OPTIONAL', - 'Description' => 'OPTIONAL_MULTI', - 'Application' => 'OPTIONAL', - 'RecordPattern' => 'OPTIONAL_MULTI', - 'RecordItem' => 'REQUIRED_MULTI', - 'AdditionalData' => 'OPTIONAL_MULTI', + 'DateTime' => parent::OPTIONAL, + 'Description' => parent::OPTIONAL_MULTI, + 'Application' => parent::OPTIONAL, + 'RecordPattern' => parent::OPTIONAL_MULTI, + 'RecordItem' => parent::REQUIRED_MULTI, + 'AdditionalData' => parent::OPTIONAL_MULTI, ]; } diff --git a/src/Elements/Reference.php b/src/Elements/Reference.php index 2d74502..52ab441 100644 --- a/src/Elements/Reference.php +++ b/src/Elements/Reference.php @@ -9,9 +9,9 @@ class Reference extends IodefElement public function __construct() { $this->elements = [ - 'ReferenceName' => 'REQUIRED', - 'URL' => 'OPTIONAL_MULTI', - 'Description' => 'OPTIONAL_MULTI', + 'ReferenceName' => parent::REQUIRED, + 'URL' => parent::OPTIONAL_MULTI, + 'Description' => parent::OPTIONAL_MULTI, ]; } } diff --git a/src/Elements/RelatedActivity.php b/src/Elements/RelatedActivity.php index c54728e..1f456b7 100644 --- a/src/Elements/RelatedActivity.php +++ b/src/Elements/RelatedActivity.php @@ -13,8 +13,8 @@ public function __construct() ]; $this->elements = [ - 'IncidentID' => 'OPTIONAL_MULTI', - 'URL' => 'OPTIONAL_MULTI', + 'IncidentID' => parent::OPTIONAL_MULTI, + 'URL' => parent::OPTIONAL_MULTI, ]; } diff --git a/src/Elements/Service.php b/src/Elements/Service.php index 575492a..18a8e81 100644 --- a/src/Elements/Service.php +++ b/src/Elements/Service.php @@ -13,12 +13,12 @@ public function __construct() ]; $this->elements = [ - 'Port' => 'OPTIONAL', - 'Portlist' => 'OPTIONAL', - 'ProtoCode' => 'OPTIONAL', - 'ProtoType' => 'OPTIONAL', - 'ProtoFlags' => 'OPTIONAL', - 'Application' => 'OPTIONAL', + 'Port' => parent::OPTIONAL, + 'Portlist' => parent::OPTIONAL, + 'ProtoCode' => parent::OPTIONAL, + 'ProtoType' => parent::OPTIONAL, + 'ProtoFlags' => parent::OPTIONAL, + 'Application' => parent::OPTIONAL, ]; } diff --git a/src/Elements/System.php b/src/Elements/System.php index f333840..033013a 100644 --- a/src/Elements/System.php +++ b/src/Elements/System.php @@ -16,12 +16,12 @@ public function __construct() 'spoofed' => 'unknown', ]; $this->elements = [ - 'Node' => 'REQUIRED', - 'Service' => 'OPTIONAL_MULTI', - 'OperatingSystem' => 'OPTIONAL_MULTI', - 'Counter' => 'OPTIONAL_MULTI', - 'Description' => 'OPTIONAL_MULTI', - 'AdditionalData' => 'OPTIONAL_MULTI', + 'Node' => parent::REQUIRED, + 'Service' => parent::OPTIONAL_MULTI, + 'OperatingSystem' => parent::OPTIONAL_MULTI, + 'Counter' => parent::OPTIONAL_MULTI, + 'Description' => parent::OPTIONAL_MULTI, + 'AdditionalData' => parent::OPTIONAL_MULTI, ]; } diff --git a/src/IodefElement.php b/src/IodefElement.php index e1767fb..d39c147 100644 --- a/src/IodefElement.php +++ b/src/IodefElement.php @@ -11,14 +11,15 @@ * IODEF Element Class. * Provides a blueprint for all IODEF Element Types. * - * @copyright Copyright (C) 2015-2016 Marknl (www.e-rave.nl) + * @copyright Copyright (C) 2015-2017 Marknl (www.e-rave.nl) * @author Mark Stunnenberg * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ abstract class IodefElement implements SabreElement { /** - * The IODEF namespace as described in rfc-5070 + * The IODEF namespace as described in rfc-5070. + * For more info: https://www.ietf.org/rfc/rfc5070.txt * @var string */ protected $ns = '{urn:ietf:params:xml:ns:iodef-1.0}'; @@ -38,9 +39,33 @@ abstract class IodefElement implements SabreElement protected $elements = []; /** - * Get the ShortName of the given IodefObject - * @param iodefElement $class - * @return string + * Constant for required element + * @var integer + */ + const REQUIRED = 0b00; + + /** + * Constant for required array element + * @var integer + */ + const REQUIRED_MULTI = 0b01; + + /** + * Constant for optional element + * @var integer + */ + const OPTIONAL = 0b10; + + /** + * Constant for optional array element + * @var integer + */ + const OPTIONAL_MULTI = 0b11; + + /** + * Get the short name of the given IodefObject. + * @param iodefElement $class An instance of IodefElement. + * @return string Class name */ public function getShortName($class = null) { @@ -55,8 +80,8 @@ public function getShortName($class = null) /** * Add an attribute. - * @param string $name - * @param string $value + * @param array $attributes Array contists of standard name/value pair. + * @return void */ public function setAttributes(array $attributes) { @@ -66,8 +91,8 @@ public function setAttributes(array $attributes) } /** - * Get the attributes - * @return array + * Get the attributes. + * @return array List of attributes. */ public function getAttributes() { @@ -76,7 +101,7 @@ public function getAttributes() /** * Set the value of the element - * @param mixed $value + * @param mixed $value Value to be set. * @return void */ public function value($value) @@ -92,20 +117,24 @@ public function value($value) public function addChild($child) { $class = $this->getShortName($child); + + // Only add child if it's an known element. if (array_key_exists($class, $this->elements)) { - if (substr($this->elements[$class], -6) == '_MULTI') { + // If we can expect more, add it to an array. + //if (substr($this->elements[$class], -6) == '_MULTI') { + if (in_array($this->elements[$class], [self::REQUIRED_MULTI, self::OPTIONAL_MULTI])) { $this->{$class}[] = $child; } else { $this->{$class} = $child; } } else { - die($this->getShortName(get_called_class()) .": {$class} is not allowed as child a element."); + die($this->getShortName(get_called_class()) .": {$class} is not allowed as a child element."); } } /** - * [getChildren description] - * @return void + * Get all chilren of the current IodefElement. + * @return array List of child elements. */ protected function getChildren() { @@ -114,6 +143,7 @@ protected function getChildren() foreach ($this->elements as $element => $occurrence) { switch ($occurrence) { case 'REQUIRED': + case self::REQUIRED: if (property_exists($this, $element)) { $retArray[] = [ 'name' => $this->ns.$element, @@ -127,6 +157,7 @@ protected function getChildren() } break; case 'OPTIONAL': + case self::OPTIONAL: if (property_exists($this, $element)) { $retArray[] = [ 'name' => $this->ns.$element, @@ -136,6 +167,7 @@ protected function getChildren() } break; case 'REQUIRED_MULTI': + case self::REQUIRED_MULTI: if (property_exists($this, $element)) { foreach ($this->$element as $child) { $retArray[] = [ @@ -151,6 +183,7 @@ protected function getChildren() } break; case 'OPTIONAL_MULTI': + case self::OPTIONAL_MULTI: if (property_exists($this, $element)) { foreach ($this->$element as $child) { $retArray[] = [ @@ -174,7 +207,7 @@ protected function getChildren() /** * Convert XML Elements to IodefElement Objects - * @param SabreReader $reader [description] + * @param SabreReader $reader * @return IodefElement */ public static function xmlDeserialize(SabreReader $reader) @@ -190,8 +223,9 @@ public static function xmlDeserialize(SabreReader $reader) // This should always and only by of type 'object'. if (gettype($child['value']) == 'object') { $className = $child['value']->getShortName(); - - if (substr($IodefElement->elements[$className], -6) == '_MULTI') { + // We can expect multiple entries here, so add it to an array. + //if (substr($IodefElement->elements[$className], -6) == '_MULTI') { + if (in_array($IodefElement->elements[$className], [self::REQUIRED_MULTI, self::OPTIONAL_MULTI])) { $IodefElement->{$className}[] = $child['value']; } else { $IodefElement->{$className} = $child['value']; @@ -225,7 +259,7 @@ public function xmlSerialize(SabreWriter $writer) $writer->write($this->getChildren()); } } else { - die($this->getShortName(). ": Validation failed, see details above."); + die("\nValidation on element <".$this->getShortName()."> failed, see details above.\n"); } } @@ -264,12 +298,12 @@ protected function validate() // Validation failed to succeeed, show errors if (!$validate_value->validate()) { - echo 'The value failed to pass the validator:'; + echo "The 'value' failed to pass the validator:"; foreach ($validate_value->errors() as $message) { if (is_array($message)) { - $message = implode(',', $message); + $message = implode(',', $message); } - echo ' '. $message; + echo ' '. strtolower($message); } return false; } diff --git a/src/Reader.php b/src/Reader.php index 05d8064..c7dc283 100644 --- a/src/Reader.php +++ b/src/Reader.php @@ -13,6 +13,10 @@ */ class Reader extends SabreReader { + /** + * Constructor + * @param string $xml XML formatted string + */ public function __construct($xml) { $this->elementMap = [ diff --git a/src/Writer.php b/src/Writer.php index ded0499..d0d16c7 100644 --- a/src/Writer.php +++ b/src/Writer.php @@ -19,6 +19,9 @@ class Writer extends SabreWriter */ public $formatOutput = false; + /** + * Contructor + */ public function __construct() { $this->openMemory(); @@ -31,8 +34,7 @@ public function __construct() } /** - * Overwrite the original method, so we can add some output - * formatting for the XML. + * Overwrite the original method, so we can add some output formatting for the XML. * @param boolval $flush Flush memory after * @return string */ diff --git a/tests/WriterTest.php b/tests/WriterTest.php index 4130749..af9030c 100644 --- a/tests/WriterTest.php +++ b/tests/WriterTest.php @@ -145,6 +145,12 @@ public function testWriter() $Incident->addChild($EventData); + $AdditionalData = new Marknl\Iodef\Elements\AdditionalData(); + $AdditionalData->setAttributes(['dtype' => 'string', 'meaning' => 'IODEF Test']); + $AdditionalData->value('Some additional data'); + + $Incident->addChild($AdditionalData); + $Document->addChild($Incident); $iodef = new Marknl\Iodef\Writer(); diff --git a/tests/iodef.xml b/tests/iodef.xml index 8b88f62..e9ec076 100644 --- a/tests/iodef.xml +++ b/tests/iodef.xml @@ -46,5 +46,6 @@ Confirm the source and take machines off-line and remediate + Some additional data