From 1d24a64b46e8b4b1e648cecf409f24b3112fbc13 Mon Sep 17 00:00:00 2001
From: Thijs Kinkhorst <thijs@kinkhorst.com>
Date: Mon, 6 Sep 2021 14:38:43 +0000
Subject: [PATCH] Reimplement attribute presentation with translation and
 without HTML generation in controller

---
 modules/admin/lib/Controller/Test.php | 178 +-------------------------
 modules/admin/templates/status.twig   |  22 +++-
 2 files changed, 24 insertions(+), 176 deletions(-)

diff --git a/modules/admin/lib/Controller/Test.php b/modules/admin/lib/Controller/Test.php
index 5441a9715..bb2f9add7 100644
--- a/modules/admin/lib/Controller/Test.php
+++ b/modules/admin/lib/Controller/Test.php
@@ -146,17 +146,15 @@ class Test
 
             $httpUtils = new Utils\HTTP();
             $t = new Template($this->config, 'admin:status.twig', 'attributes');
+            $l = $t->getLocalization();
+            $l->addDomain($l->getLocaleDir(), 'attributes');
             $t->data = [
                 'attributes' => $attributes,
-                'attributesHtml' => $this->getAttributesHTML($t, $attributes, ''),
                 'authData' => $authData,
+                'remaining' => isset($authData['Expire']) ? $authData['Expire'] - time() : null,
                 'nameid' => $nameId,
                 'logouturl' => $httpUtils->getSelfURLNoQuery() . '?as=' . urlencode($as) . '&logout',
             ];
-
-            if ($nameId !== false) {
-                $t->data['nameidHtml'] = $this->getNameIDHTML($t, $nameId);
-            }
         }
 
         Module::callHooks('configpage', $t);
@@ -165,174 +163,4 @@ class Test
         $this->menu->addOption('logout', $this->authUtils->getAdminLogoutURL(), Translate::noop('Log out'));
         return $this->menu->insert($t);
     }
-
-
-    /**
-     * @param \SimpleSAML\XHTML\Template $t
-     * @param \SAML2\XML\saml\NameID $nameId
-     * @return string
-     */
-    private function getNameIDHTML(Template $t, NameID $nameId): string
-    {
-        $result = '';
-        $list = [
-            "NameId" => [$nameId->getValue()],
-        ];
-        if ($nameId->getFormat() !== null) {
-            $list['Format'] = [$nameId->getFormat()];
-        }
-        if ($nameId->getNameQualifier() !== null) {
-            $list['NameQualifier'] = [$nameId->getNameQualifier()];
-        }
-        if ($nameId->getSPNameQualifier() !== null) {
-            $list['SPNameQualifier'] = [$nameId->getSPNameQualifier()];
-        }
-        if ($nameId->getSPProvidedID() !== null) {
-            $list['SPProvidedID'] = [$nameId->getSPProvidedID()];
-        }
-        return $result . $this->getAttributesHTML($t, $list, '');
-    }
-
-
-    /**
-     * @param \SimpleSAML\XHTML\Template $t
-     * @param array $attributes
-     * @param string $nameParent
-     * @return string
-     */
-    private function getAttributesHTML(Template $t, array $attributes, string $nameParent): string
-    {
-        $alternate = ['pure-table-odd', 'pure-table-even'];
-        $i = 0;
-        $parentStr = (strlen($nameParent) > 0) ? strtolower($nameParent) . '_' : '';
-        $str = (strlen($nameParent) > 0)
-            ? '<table class="pure-table pure-table-attributes" summary="attribute overview">'
-            : '<table id="table_with_attributes" class="pure-table pure-table-attributes"'
-            . ' summary="attribute overview">';
-        foreach ($attributes as $name => $value) {
-            $nameraw = $name;
-            $name = Translate::noop($parentStr . $nameraw);
-            if (preg_match('/^child_/', $nameraw)) {
-                $parentName = preg_replace('/^child_/', '', $nameraw);
-                foreach ($value as $child) {
-                    $str .= '<tr class="odd"><td colspan="2" style="padding: 2em">' .
-                        $this->getAttributesHTML($t, $child, $parentName) . '</td></tr>';
-                }
-            } else {
-                if (sizeof($value) > 1) {
-                    $str .= '<tr class="' . $alternate[($i++ % 2)] . '"><td class="attrname">';
-                    if ($nameraw !== $name) {
-                        $str .= htmlspecialchars($name) . '<br/>';
-                    }
-                    $str .= '<code>' . htmlspecialchars($nameraw) . '</code>';
-                    $str .= '</td><td class="attrvalue"><ul>';
-                    foreach ($value as $listitem) {
-                        if ($nameraw === 'jpegPhoto') {
-                            $str .= '<li><img src="data:image/jpeg;base64,' . htmlspecialchars($listitem) . '" /></li>';
-                        } else {
-                            $str .= '<li>' . $this->presentAssoc($listitem) . '</li>';
-                        }
-                    }
-                    $str .= '</ul></td></tr>';
-                } elseif (isset($value[0])) {
-                    $str .= '<tr class="' . $alternate[($i++ % 2)] . '"><td class="attrname">';
-                    if ($nameraw !== $name) {
-                        $str .= htmlspecialchars($name) . '<br/>';
-                    }
-                    $str .= '<code>' . htmlspecialchars($nameraw) . '</code>';
-                    $str .= '</td>';
-                    if ($nameraw === 'jpegPhoto') {
-                        $str .= '<td class="attrvalue"><img src="data:image/jpeg;base64,' . htmlspecialchars($value[0])
-                            . '" /></td></tr>';
-                    } elseif (is_a($value[0], 'DOMNodeList')) {
-                        // try to see if we have a NameID here
-                        /** @var \DOMNodeList $value[0] */
-                        $n = $value[0]->length;
-                        for ($idx = 0; $idx < $n; $idx++) {
-                            $elem = $value[0]->item($idx);
-                            /* @var \DOMElement $elem */
-                            if (!($elem->localName === 'NameID' && $elem->namespaceURI === Constants::NS_SAML)) {
-                                continue;
-                            }
-                            $str .= $this->presentEptid($t->getTranslator(), new NameID($elem));
-                            break; // we only support one NameID here
-                        }
-                        $str .= '</td></tr>';
-                    } elseif (is_a($value[0], '\SAML2\XML\saml\NameID')) {
-                        $str .= $this->presentEptid($t->getTranslator(), $value[0]);
-                        $str .= '</td></tr>';
-                    } else {
-                        $str .= '<td class="attrvalue">' . htmlspecialchars($value[0]) . '</td></tr>';
-                    }
-                }
-            }
-            $str .= "\n";
-        }
-        $str .= '</table>';
-        return $str;
-    }
-
-
-    /**
-     * @param array|string $attr
-     * @return string
-     */
-    private function presentList($attr): string
-    {
-        if (is_array($attr) && count($attr) > 1) {
-            $str = '<ul>';
-            foreach ($attr as $value) {
-                $str .= '<li>' . htmlspecialchars(strval($attr)) . '</li>';
-            }
-            $str .= '</ul>';
-            return $str;
-        } else {
-            return htmlspecialchars($attr[0]);
-        }
-    }
-
-
-    /**
-     * @param array|string $attr
-     * @return string
-     */
-    private function presentAssoc($attr): string
-    {
-        if (is_array($attr)) {
-            $str = '<dl>';
-            foreach ($attr as $key => $value) {
-                $str .= "\n" . '<dt>' . htmlspecialchars($key) . '</dt><dd>' . $this->presentList($value) . '</dd>';
-            }
-            $str .= '</dl>';
-            return $str;
-        } else {
-            return htmlspecialchars($attr);
-        }
-    }
-
-
-    /**
-     * @param \SimpleSAML\Locale\Translate $t
-     * @param \SAML2\XML\saml\NameID $nameID
-     * @return string
-     */
-    private function presentEptid(Translate $t, NameID $nameID): string
-    {
-        $eptid = [
-            'NameID' => [$nameID->getValue()],
-        ];
-        if ($nameID->getFormat() !== null) {
-            $eptid['Format'] = [$nameID->getFormat()];
-        }
-        if ($nameID->getNameQualifier() !== null) {
-            $eptid['NameQualifier'] = [$nameID->getNameQualifier()];
-        }
-        if ($nameID->getSPNameQualifier() !== null) {
-            $eptid['SPNameQualifier'] = [$nameID->getSPNameQualifier()];
-        }
-        if ($nameID->getSPProvidedID() !== null) {
-            $eptid['SPProvidedID'] = [$nameID->getSPProvidedID()];
-        }
-        return '<td class="attrvalue">' . $this->presentAssoc($eptid);
-    }
 }
diff --git a/modules/admin/templates/status.twig b/modules/admin/templates/status.twig
index 44c87ccd2..38fc86399 100644
--- a/modules/admin/templates/status.twig
+++ b/modules/admin/templates/status.twig
@@ -8,9 +8,29 @@
     <p>{% trans %}Hi, this is the status page of SimpleSAMLphp. Here you can see if your session is timed out, how long
      it lasts until it times out and all the attributes that are attached to your session.{% endtrans %}</p>
 
+    {% if remaining %}
+        <p>{% trans %}Your session is valid for {{ remaining }} seconds from now.{% endtrans %}</p>
+    {% endif %}
+
     <h2>{{ '{status:attributes_header}'|trans }}</h2>
 
-    {{ attributesHtml|raw }}
+    {% set items = attributes %}
+
+{% embed '_table.twig' -%}
+
+    {% block namecol -%}
+    {% set translated = name|trans %}
+    <td class="attrname">{% if translated != name %} {{ translated }} <br>{% endif %} <samp>{{ name }}</samp></td>
+    {% endblock %}
+
+
+    {% block value -%}
+    {% if name =='jpegPhoto'-%}
+        <img src="data:image/jpeg;base64,{{ value }}" alt="{% trans %}Content of jpegPhoto attribute{% endtrans %}">
+    {% else %}{{ value }}{% endif -%}
+    {% endblock %}
+
+{%- endembed %}
 
     {%- if nameid or authData %}
 
-- 
GitLab