XML::processTransforms()   B
last analyzed

Complexity

Conditions 8
Paths 10

Size

Total Lines 39
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 8
eloc 21
c 2
b 0
f 0
nc 10
nop 2
dl 0
loc 39
rs 8.4444
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\Transforms;
10
use SimpleSAML\XPath\Constants as XPATH_C;
11
12
use function array_map;
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 string[]|null $xpaths An array of xpaths to filter the nodes by. Defaults to null (no filters).
29
     * @param string[]|null $prefixes An array of namespace prefixes to filter the nodes by.
30
     *   Defaults to null (no filters).
31
     *
32
     * @return string The canonical representation of the given DOM node, according to the algorithm requested.
33
     */
34
    public static function canonicalizeData(
35
        DOMElement $element,
36
        string $c14nMethod,
37
        ?array $xpaths = null,
38
        ?array $prefixes = null,
39
    ): string {
40
        $withComments = match ($c14nMethod) {
41
            C::C14N_EXCLUSIVE_WITH_COMMENTS, C::C14N_INCLUSIVE_WITH_COMMENTS => true,
42
            default => false,
43
        };
44
        $exclusive = match ($c14nMethod) {
45
            C::C14N_EXCLUSIVE_WITH_COMMENTS, C::C14N_EXCLUSIVE_WITHOUT_COMMENTS => true,
46
            default => false,
47
        };
48
49
        if (
50
            is_null($xpaths)
51
            && ($element->ownerDocument !== null)
52
            && ($element->ownerDocument->documentElement !== null)
53
            && $element->isSameNode($element->ownerDocument->documentElement)
54
        ) {
55
            // check for any PI or comments as they would have been excluded
56
            $current = $element;
57
            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...
58
                if (
59
                    (($refNode->nodeType === XML_COMMENT_NODE) && $withComments)
60
                    || $refNode->nodeType === XML_PI_NODE
61
                ) {
62
                    break;
63
                }
64
            }
65
66
            if ($refNode === null) {
67
                $element = $element->ownerDocument;
68
            }
69
        }
70
71
        return $element->C14N($exclusive, $withComments, $xpaths, $prefixes);
72
    }
73
74
75
    /**
76
     * Process all transforms specified by a given Reference element.
77
     *
78
     * @param \SimpleSAML\XMLSecurity\XML\ds\Transforms $transforms The transforms to apply.
79
     * @param \DOMElement $data The data referenced.
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
    ): string {
89
        $canonicalMethod = C::C14N_EXCLUSIVE_WITHOUT_COMMENTS;
90
        $arXPath = null;
91
        $prefixList = null;
92
        foreach ($transforms->getTransform() as $transform) {
93
            $canonicalMethod = $transform->getAlgorithm()->getValue();
94
            switch ($canonicalMethod) {
95
                case C::C14N_EXCLUSIVE_WITHOUT_COMMENTS:
96
                case C::C14N_EXCLUSIVE_WITH_COMMENTS:
97
                    $inclusiveNamespaces = $transform->getInclusiveNamespaces();
98
                    if ($inclusiveNamespaces !== null) {
99
                        $prefixes = $inclusiveNamespaces->getPrefixes();
100
                        if ($prefixes !== null) {
101
                            $prefixList = array_map('strval', $prefixes->toArray());
102
                        }
103
                    }
104
                    break;
105
                case XPATH_C::XPATH10_URI:
106
                    $xpath = $transform->getXPath();
107
                    if ($xpath !== null) {
108
                        $arXPath = [];
109
                        $arXPath['query'] = '(.//. | .//@* | .//namespace::*)[' . $xpath->getExpression() . ']';
110
//                        $arXpath['namespaces'] = $xpath->getNamespaces();
111
                        // TODO: review if $nsnode->localName is equivalent to the keys in getNamespaces()
112
//                        $nslist = $xp->query('./namespace::*', $node);
113
//                        foreach ($nslist as $nsnode) {
114
//                            if ($nsnode->localName != "xml") {
115
//                                $arXPath['namespaces'][$nsnode->localName] = $nsnode->nodeValue;
116
//                            }
117
//                        }
118
                    }
119
                    break;
120
            }
121
        }
122
123
        return self::canonicalizeData($data, $canonicalMethod, $arXPath, $prefixList);
124
    }
125
}
126