XML::canonicalizeData()   B
last analyzed

Complexity

Conditions 11
Paths 10

Size

Total Lines 43
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
eloc 23
c 3
b 1
f 0
dl 0
loc 43
rs 7.3166
cc 11
nc 10
nop 4

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\Exception\CanonicalizationFailedException;
10
use SimpleSAML\XMLSecurity\XML\ds\Transforms;
11
use SimpleSAML\XPath\Constants as XPATH_C;
12
13
use function array_map;
14
use function is_null;
15
16
/**
17
 * Class with utility methods for XML manipulation.
18
 *
19
 * @package simplesamlphp/xml-security
20
 */
21
class XML
22
{
23
    /**
24
     * Canonicalize any given node.
25
     *
26
     * @param \DOMElement $element The DOM element that needs canonicalization.
27
     * @param string $c14nMethod The identifier of the canonicalization algorithm to use.
28
     *   See \SimpleSAML\XMLSecurity\Constants.
29
     * @param string[]|null $xpaths An array of xpaths to filter the nodes by. Defaults to null (no filters).
30
     * @param string[]|null $prefixes An array of namespace prefixes to filter the nodes by.
31
     *   Defaults to null (no filters).
32
     *
33
     * @return string The canonical representation of the given DOM node, according to the algorithm requested.
34
     */
35
    public static function canonicalizeData(
36
        DOMElement $element,
37
        string $c14nMethod,
38
        ?array $xpaths = null,
39
        ?array $prefixes = null,
40
    ): string {
41
        $withComments = match ($c14nMethod) {
42
            C::C14N_EXCLUSIVE_WITH_COMMENTS, C::C14N_INCLUSIVE_WITH_COMMENTS => true,
43
            default => false,
44
        };
45
        $exclusive = match ($c14nMethod) {
46
            C::C14N_EXCLUSIVE_WITH_COMMENTS, C::C14N_EXCLUSIVE_WITHOUT_COMMENTS => true,
47
            default => false,
48
        };
49
50
        if (
51
            is_null($xpaths)
52
            && ($element->ownerDocument !== null)
53
            && ($element->ownerDocument->documentElement !== null)
54
            && $element->isSameNode($element->ownerDocument->documentElement)
55
        ) {
56
            // check for any PI or comments as they would have been excluded
57
            $current = $element;
58
            for ($refNode = $current->previousSibling; $refNode !== null; $current = $refNode) {
0 ignored issues
show
Unused Code introduced by
The assignment to $current is dead and can be removed.
Loading history...
59
                if (
60
                    (($refNode->nodeType === XML_COMMENT_NODE) && $withComments)
61
                    || $refNode->nodeType === XML_PI_NODE
62
                ) {
63
                    break;
64
                }
65
            }
66
67
            if ($refNode === null) {
68
                $element = $element->ownerDocument;
69
            }
70
        }
71
72
        $ret = $element->C14N($exclusive, $withComments, $xpaths, $prefixes);
73
        if ($ret === false) {
74
            // GHSA-h25p-2wxc-6584
75
            throw new CanonicalizationFailedException();
76
        }
77
        return $ret;
78
    }
79
80
81
    /**
82
     * Process all transforms specified by a given Reference element.
83
     *
84
     * @param \SimpleSAML\XMLSecurity\XML\ds\Transforms $transforms The transforms to apply.
85
     * @param \DOMElement $data The data referenced.
86
     *
87
     * @return string The canonicalized data after applying all transforms specified by $ref.
88
     *
89
     * @see http://www.w3.org/TR/xmldsig-core/#sec-ReferenceProcessingModel
90
     */
91
    public static function processTransforms(
92
        Transforms $transforms,
93
        DOMElement $data,
94
    ): string {
95
        $canonicalMethod = C::C14N_EXCLUSIVE_WITHOUT_COMMENTS;
96
        $arXPath = null;
97
        $prefixList = null;
98
        foreach ($transforms->getTransform() as $transform) {
99
            $canonicalMethod = $transform->getAlgorithm()->getValue();
100
            switch ($canonicalMethod) {
101
                case C::C14N_EXCLUSIVE_WITHOUT_COMMENTS:
102
                case C::C14N_EXCLUSIVE_WITH_COMMENTS:
103
                    $inclusiveNamespaces = $transform->getInclusiveNamespaces();
104
                    if ($inclusiveNamespaces !== null) {
105
                        $prefixes = $inclusiveNamespaces->getPrefixes();
106
                        if ($prefixes !== null) {
107
                            $prefixList = array_map('strval', $prefixes->toArray());
108
                        }
109
                    }
110
                    break;
111
                case XPATH_C::XPATH10_URI:
112
                    $xpath = $transform->getXPath();
113
                    if ($xpath !== null) {
114
                        $arXPath = [];
115
                        $arXPath['query'] = '(.//. | .//@* | .//namespace::*)[' . $xpath->getExpression() . ']';
116
//                        $arXpath['namespaces'] = $xpath->getNamespaces();
117
                        // TODO: review if $nsnode->localName is equivalent to the keys in getNamespaces()
118
//                        $nslist = $xp->query('./namespace::*', $node);
119
//                        foreach ($nslist as $nsnode) {
120
//                            if ($nsnode->localName != "xml") {
121
//                                $arXPath['namespaces'][$nsnode->localName] = $nsnode->nodeValue;
122
//                            }
123
//                        }
124
                    }
125
                    break;
126
            }
127
        }
128
129
        return self::canonicalizeData($data, $canonicalMethod, $arXPath, $prefixList);
130
    }
131
}
132