Passed
Pull Request — master (#2)
by Jaime Pérez
02:47
created

XML::canonicalizeData()   C

Complexity

Conditions 13
Paths 45

Size

Total Lines 41
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 13
eloc 24
nc 45
nop 4
dl 0
loc 41
rs 6.6166
c 1
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\XMLSecurity\Utils;
6
7
use DOMElement;
8
use SimpleSAML\XMLSecurity\Constants as C;
9
use SimpleSAML\XMLSecurity\XML\ds\Transform;
10
use SimpleSAML\XMLSecurity\XML\ds\Transforms;
11
12
/**
13
 * Class with utility methods for XML manipulation.
14
 *
15
 * @package simplesamlphp/xml-security
16
 */
17
class XML
18
{
19
    /**
20
     * Canonicalize any given node.
21
     *
22
     * @param \DOMElement $element The DOM element that needs canonicalization.
23
     * @param string $c14nMethod The identifier of the canonicalization algorithm to use.
24
     * See \SimpleSAML\XMLSecurity\Constants.
25
     * @param array|null $xpaths An array of xpaths to filter the nodes by. Defaults to null (no filters).
26
     * @param array|null $prefixes An array of namespace prefixes to filter the nodes by. Defaults to null (no filters).
27
     *
28
     * @return string The canonical representation of the given DOM node, according to the algorithm requested.
29
     */
30
    public static function canonicalizeData(
31
        DOMElement $element,
32
        string $c14nMethod,
33
        array $xpaths = null,
34
        array $prefixes = null
35
    ): string {
36
        $exclusive = false;
37
        $withComments = false;
38
        switch ($c14nMethod) {
39
            case C::C14N_EXCLUSIVE_WITH_COMMENTS:
40
            case C::C14N_INCLUSIVE_WITH_COMMENTS:
41
                $withComments = true;
42
        }
43
        switch ($c14nMethod) {
44
            case C::C14N_EXCLUSIVE_WITH_COMMENTS:
45
            case C::C14N_EXCLUSIVE_WITHOUT_COMMENTS:
46
                $exclusive = true;
47
        }
48
49
        if (
50
            is_null($xpaths)
51
            && ($element->ownerDocument !== null)
52
            && $element->isSameNode($element->ownerDocument->documentElement)
53
        ) {
54
            // check for any PI or comments as they would have been excluded
55
            $current = $element;
56
            while ($refNode = $current->previousSibling) {
57
                if (
58
                    (($refNode->nodeType === XML_COMMENT_NODE) && $withComments)
59
                    || $refNode->nodeType === XML_PI_NODE
60
                ) {
61
                    break;
62
                }
63
                $current = $refNode;
64
            }
65
            if ($refNode == null) {
66
                $element = $element->ownerDocument;
67
            }
68
        }
69
70
        return $element->C14N($exclusive, $withComments, $xpaths, $prefixes);
71
    }
72
73
74
    /**
75
     * Process all transforms specified by a given Reference element.
76
     *
77
     * @param \SimpleSAML\XMLSecurity\XML\ds\Transforms $transforms The transforms to apply.
78
     * @param \DOMElement $data The data referenced.
79
     * @param bool $includeCommentNodes Whether to allow canonicalization with comments or not.
80
     *
81
     * @return string The canonicalized data after applying all transforms specified by $ref.
82
     *
83
     * @see http://www.w3.org/TR/xmldsig-core/#sec-ReferenceProcessingModel
84
     */
85
    public static function processTransforms(
86
        Transforms $transforms,
87
        DOMElement $data,
88
        bool $includeCommentNodes = false
89
    ): string {
90
        $canonicalMethod = C::C14N_EXCLUSIVE_WITHOUT_COMMENTS;
91
        $arXPath = null;
92
        $prefixList = null;
93
        foreach ($transforms as $transform) {
94
            /** @var Transform $transform */
95
            $algorithm = $transform->getAlgorithm();
96
            switch ($algorithm) {
97
                case C::C14N_EXCLUSIVE_WITHOUT_COMMENTS:
98
                case C::C14N_EXCLUSIVE_WITH_COMMENTS:
99
                    if (!$includeCommentNodes) {
100
                        // remove comment nodes by forcing it to use a canonicalization without comments
101
                        $canonicalMethod = C::C14N_EXCLUSIVE_WITHOUT_COMMENTS;
102
                    } else {
103
                        $canonicalMethod = $algorithm;
104
                    }
105
106
                    $inclusiveNamespaces = $transform->getInclusiveNamespaces();
107
                    if ($inclusiveNamespaces !== null) {
108
                        $prefixes = $inclusiveNamespaces->getPrefixes();
109
                        if (count($prefixes > 0)) {
0 ignored issues
show
Bug introduced by
$prefixes > 0 of type boolean is incompatible with the type Countable|array expected by parameter $value of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

109
                        if (count(/** @scrutinizer ignore-type */ $prefixes > 0)) {
Loading history...
110
                            $prefixList = $prefixes;
111
                        }
112
                    }
113
                    break;
114
                case C::C14N_INCLUSIVE_WITHOUT_COMMENTS:
115
                case C::C14N_INCLUSIVE_WITH_COMMENTS:
116
                    if (!$includeCommentNodes) {
117
                        // remove comment nodes by forcing it to use a canonicalization without comments
118
                        $canonicalMethod = C::C14N_INCLUSIVE_WITHOUT_COMMENTS;
119
                    } else {
120
                        $canonicalMethod = $algorithm;
121
                    }
122
123
                    break;
124
                case C::XPATH_URI:
125
                    $xpath = $transform->getXPath();
126
                    if ($xpath !== null) {
127
                        $arXPath = [];
128
                        $arXPath['query'] = '(.//. | .//@* | .//namespace::*)[' . $xpath->getExpression() . ']';
129
                        $arXpath['namespaces'] = $xpath->getNamespaces();
130
                        // TODO: review if $nsnode->localName is equivalent to the keys in getNamespaces()
131
//                        $nslist = $xp->query('./namespace::*', $node);
132
//                        foreach ($nslist as $nsnode) {
133
//                            if ($nsnode->localName != "xml") {
134
//                                $arXPath['namespaces'][$nsnode->localName] = $nsnode->nodeValue;
135
//                            }
136
//                        }
137
                    }
138
                    break;
139
            }
140
        }
141
142
        return self::canonicalizeData($data, $canonicalMethod, $arXPath, $prefixList);
143
    }
144
}