Passed
Pull Request — master (#2)
by Jaime Pérez
02:18
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
use function count;
13
use function is_null;
14
15
/**
16
 * Class with utility methods for XML manipulation.
17
 *
18
 * @package simplesamlphp/xml-security
19
 */
20
class XML
21
{
22
    /**
23
     * Canonicalize any given node.
24
     *
25
     * @param \DOMElement $element The DOM element that needs canonicalization.
26
     * @param string $c14nMethod The identifier of the canonicalization algorithm to use.
27
     * See \SimpleSAML\XMLSecurity\Constants.
28
     * @param array|null $xpaths An array of xpaths to filter the nodes by. Defaults to null (no filters).
29
     * @param array|null $prefixes An array of namespace prefixes to filter the nodes by. Defaults to null (no filters).
30
     *
31
     * @return string The canonical representation of the given DOM node, according to the algorithm requested.
32
     */
33
    public static function canonicalizeData(
34
        DOMElement $element,
35
        string $c14nMethod,
36
        array $xpaths = null,
37
        array $prefixes = null
38
    ): string {
39
        $exclusive = false;
40
        $withComments = false;
41
        switch ($c14nMethod) {
42
            case C::C14N_EXCLUSIVE_WITH_COMMENTS:
43
            case C::C14N_INCLUSIVE_WITH_COMMENTS:
44
                $withComments = true;
45
        }
46
        switch ($c14nMethod) {
47
            case C::C14N_EXCLUSIVE_WITH_COMMENTS:
48
            case C::C14N_EXCLUSIVE_WITHOUT_COMMENTS:
49
                $exclusive = true;
50
        }
51
52
        if (
53
            is_null($xpaths)
54
            && ($element->ownerDocument !== null)
55
            && $element->isSameNode($element->ownerDocument->documentElement)
56
        ) {
57
            // check for any PI or comments as they would have been excluded
58
            $current = $element;
59
            while ($refNode = $current->previousSibling) {
60
                if (
61
                    (($refNode->nodeType === XML_COMMENT_NODE) && $withComments)
62
                    || $refNode->nodeType === XML_PI_NODE
63
                ) {
64
                    break;
65
                }
66
                $current = $refNode;
67
            }
68
            if ($refNode == null) {
69
                $element = $element->ownerDocument;
70
            }
71
        }
72
73
        return $element->C14N($exclusive, $withComments, $xpaths, $prefixes);
74
    }
75
76
77
    /**
78
     * Process all transforms specified by a given Reference element.
79
     *
80
     * @param \SimpleSAML\XMLSecurity\XML\ds\Transforms $transforms The transforms to apply.
81
     * @param \DOMElement $data The data referenced.
82
     * @param bool $includeCommentNodes Whether to allow canonicalization with comments or not.
83
     *
84
     * @return string The canonicalized data after applying all transforms specified by $ref.
85
     *
86
     * @see http://www.w3.org/TR/xmldsig-core/#sec-ReferenceProcessingModel
87
     */
88
    public static function processTransforms(
89
        Transforms $transforms,
90
        DOMElement $data,
91
        bool $includeCommentNodes = false
92
    ): string {
93
        $canonicalMethod = C::C14N_EXCLUSIVE_WITHOUT_COMMENTS;
94
        $arXPath = null;
95
        $prefixList = null;
96
        foreach ($transforms as $transform) {
97
            /** @var Transform $transform */
98
            $algorithm = $transform->getAlgorithm();
99
            switch ($algorithm) {
100
                case C::C14N_EXCLUSIVE_WITHOUT_COMMENTS:
101
                case C::C14N_EXCLUSIVE_WITH_COMMENTS:
102
                    if (!$includeCommentNodes) {
103
                        // remove comment nodes by forcing it to use a canonicalization without comments
104
                        $canonicalMethod = C::C14N_EXCLUSIVE_WITHOUT_COMMENTS;
105
                    } else {
106
                        $canonicalMethod = $algorithm;
107
                    }
108
109
                    $inclusiveNamespaces = $transform->getInclusiveNamespaces();
110
                    if ($inclusiveNamespaces !== null) {
111
                        $prefixes = $inclusiveNamespaces->getPrefixes();
112
                        if (count($prefixes) > 0) {
113
                            $prefixList = $prefixes;
114
                        }
115
                    }
116
                    break;
117
                case C::C14N_INCLUSIVE_WITHOUT_COMMENTS:
118
                case C::C14N_INCLUSIVE_WITH_COMMENTS:
119
                    if (!$includeCommentNodes) {
120
                        // remove comment nodes by forcing it to use a canonicalization without comments
121
                        $canonicalMethod = C::C14N_INCLUSIVE_WITHOUT_COMMENTS;
122
                    } else {
123
                        $canonicalMethod = $algorithm;
124
                    }
125
126
                    break;
127
                case C::XPATH_URI:
128
                    $xpath = $transform->getXPath();
129
                    if ($xpath !== null) {
130
                        $arXPath = [];
131
                        $arXPath['query'] = '(.//. | .//@* | .//namespace::*)[' . $xpath->getExpression() . ']';
132
                        $arXpath['namespaces'] = $xpath->getNamespaces();
133
                        // TODO: review if $nsnode->localName is equivalent to the keys in getNamespaces()
134
//                        $nslist = $xp->query('./namespace::*', $node);
135
//                        foreach ($nslist as $nsnode) {
136
//                            if ($nsnode->localName != "xml") {
137
//                                $arXPath['namespaces'][$nsnode->localName] = $nsnode->nodeValue;
138
//                            }
139
//                        }
140
                    }
141
                    break;
142
            }
143
        }
144
145
        return self::canonicalizeData($data, $canonicalMethod, $arXPath, $prefixList);
146
    }
147
}
148