From c1f0fcde3f4ccfe1116cd45eed29f6244dab32bb Mon Sep 17 00:00:00 2001
From: Marco Malavolti <marco.malavolti@garr.it>
Date: Sun, 30 Jul 2023 04:18:41 +0200
Subject: [PATCH] Update Docker implementation. Missing CRON

---
 Dockerfile-dev      | 59 +++++++++++++++++------------
 eccs_properties.py  | 92 ++++++++++++++++++++++++++++++++++++++-------
 get-sps-metadata.sh |  4 +-
 setup-eccs-dev.sh   |  2 +-
 start.sh            |  4 +-
 supervisord.conf    | 49 ++++++++++++++++++++----
 web/index.php       |  8 ++--
 7 files changed, 166 insertions(+), 52 deletions(-)

diff --git a/Dockerfile-dev b/Dockerfile-dev
index a712a79..c881d1a 100644
--- a/Dockerfile-dev
+++ b/Dockerfile-dev
@@ -3,31 +3,34 @@ LABEL Authors="Marco Malavolti <marco.malavolti@garr.it>"
 
 USER root
 
-ENV ECCS_VERSION=2.1.0
 ENV XMLSECTOOL_VERSION=3.0.0
 ENV AMAZON_JDK_KEY=https://corretto.aws/downloads/resources/11.0.6.10.1/B04F24E3.pub
 
 COPY --from=hairyhenderson/gomplate:v3.11.5 /gomplate /bin/gomplate
 
 RUN apt-get update \
-    && apt-get install --no-install-recommends -y apt-utils vim git bash-completion \
-    ca-certificates curl unzip uwsgi cron gpg gpg-agent libxml2-utils supervisor \
+    && apt-get install -y apt-utils net-tools vim bash-completion \
+    ca-certificates curl unzip uwsgi uwsgi-plugin-python3 cron gpg gpg-agent libxml2-utils \
     python3 python3-pip python3-click python3-flask python3-flask-restful \
-    python3-requests python3-selenium python3-urllib3 apache2 \
-    libpcre3 libpcre3-dev libapache2-mod-proxy-uwsgi build-essential python3-dev \
+    python3-requests python3-selenium python3-urllib3 apache2 supervisor php \
+    libpcre3 libapache2-mod-proxy-uwsgi build-essential \
     && sed -i -e 's/"syntax on/syntax on/g' /etc/vim/vimrc \
     && printf "\nif [ -f /etc/bash_completion ]; then\n . /etc/bash_completion\nfi" >> /etc/profile
 
-COPY supervisord.conf /etc/supervisor/conf.d/
-
 # Get ECCS
 WORKDIR /root
-RUN curl "https://gitlab.software.geant.org/edugain/eccs/-/archive/v$ECCS_VERSION/eccs-v$ECCS_VERSION.tar.gz" --output eccs-v$ECCS_VERSION.tar.gz \
-    && tar xzf eccs-v$ECCS_VERSION.tar.gz && rm eccs-v$ECCS_VERSION.tar.gz \
-    && mv eccs-v$ECCS_VERSION eccs
 
-# Get Google Chrome & Google Chrome Driver
+RUN mkdir eccs
 WORKDIR eccs
+COPY api.py clean7daysOldFiles.sh cleanAndRunEccs.sh eccs.ini eccs.py eccs_properties.py eccs-sps-md-cron eccs-wsgi.py get-sps-metadata.sh retryFailedChecks.py runEccs.py utils.py .
+COPY html/ html/
+COPY input/ input/
+COPY logs/ logs/
+COPY output/ output/
+COPY selenium-logs/ selenium-logs/
+COPY web/ web/
+
+# Get Google Chrome & Google Chrome Driver
 RUN curl "https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb" --output google-chrome-stable_current_amd64.deb \
     && apt install -y ./google-chrome-stable_current_amd64.deb --no-install-recommends \
     && curl "https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/115.0.5790.110/linux64/chromedriver-linux64.zip" --output chromedriver_linux64.zip \
@@ -42,28 +45,36 @@ RUN wget $AMAZON_JDK_KEY -O /tmp/amazon-corretto.pub \
  && gpg --no-default-keyring --keyring /tmp/temp-keyring.gpg --export --output /etc/apt/keyrings/amazon-corretto.gpg \
  && rm /tmp/temp-keyring.gpg
 COPY amazon-corretto.list /etc/apt/sources.list.d/amazon-corretto.list
+COPY eccs-sps-md-cron /etc/cron.d/eccs_get_sps_metadata
 RUN apt-get update && apt-get install -y java-11-amazon-corretto-jdk \
     && curl "https://shibboleth.net/downloads/tools/xmlsectool/$XMLSECTOOL_VERSION/xmlsectool-$XMLSECTOOL_VERSION-bin.zip" --output xmlsectool-$XMLSECTOOL_VERSION-bin.zip \
     && unzip xmlsectool-$XMLSECTOOL_VERSION-bin.zip \
+    && mv xmlsectool-$XMLSECTOOL_VERSION xmlsectool \
+    && echo "$XMLSECTOOL_VERSION" > xmlsectool/version.txt \
     && rm xmlsectool-$XMLSECTOOL_VERSION-bin.zip \
     && curl "https://mdx.idem.garr.it/idem-mdx-service-crt.pem" --output idem-mdx-service-crt.pem
 
-COPY get-sps-metadata.sh get-sps-metadata.sh
-COPY eccs_properties.py.template eccs_properties.py
-COPY eccs-sps-md-cron /etc/cron.d/eccs_get_sps_metadata
-
 # Install ECCS API
-COPY eccs.ini eccs.ini
-COPY eccs.service eccs.service
-COPY eccs.service /etc/systemd/system/eccs.service
-
+#COPY eccs.service /etc/systemd/system/multi-user.target.wants/eccs.service
+COPY eccs.conf /etc/apache2/conf-available/eccs.conf
+RUN ln -s /etc/apache2/conf-available/eccs.conf /etc/apache2/conf-enabled/eccs.conf \
+    && ln -s /etc/apache2/mods-available/proxy.conf /etc/apache2/mods-enabled/proxy.conf \  
+    && ln -s /etc/apache2/mods-available/proxy.load /etc/apache2/mods-enabled/proxy.load \ 
+    && ln -s /etc/apache2/mods-available/proxy_uwsgi.load /etc/apache2/mods-enabled/proxy_uwsgi.load \ 
+    && chmod 755 /root
 
 EXPOSE 80
 EXPOSE 443
 
-CMD tail -f /dev/null
+#CMD tail -f /dev/null
+
+#SUPERVISOR
+COPY supervisord.conf /etc/supervisor/supervisord.conf
+RUN mkdir -p /var/log/supervisor \
+    && mkdir -p /var/run/supervisord \
+    && chmod -R 0755 /var/log/supervisor
+
+COPY start.sh /start.sh
+RUN chmod +x /start.sh
+CMD /start.sh
 
-##COPY start-dev.sh /start.sh
-#COPY start.sh /start.sh
-#RUN chmod +x /start.sh
-#CMD /start.sh
diff --git a/eccs_properties.py b/eccs_properties.py
index eb63097..c467610 100644
--- a/eccs_properties.py
+++ b/eccs_properties.py
@@ -1,8 +1,49 @@
 import os
+import random
+import string
 from datetime import date
+import xml.etree.ElementTree as ET
 
-DAY = date.today().isoformat()
+def get_real_sps():
+    sps_list = []
+
+    namespaces = {
+       'md': 'urn:oasis:names:tc:SAML:2.0:metadata',
+    }
+
+    sp_1_entityid = "https://sp-demo.idem.garr.it/shibboleth"
+    sp_2_entityid = "https://attribute-viewer.aai.switch.ch/interfederation-test/shibboleth"
+
+    tree = ET.parse(SPS_MD_PATH)
+    root = tree.getroot()
+
+    sp_1 = root.find(f"./md:EntityDescriptor[@entityID='{sp_1_entityid}']/md:SPSSODescriptor/md:AssertionConsumerService[@Binding='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST']", namespaces)
+    sp_2 = root.find(f"./md:EntityDescriptor[@entityID='{sp_2_entityid}']/md:SPSSODescriptor/md:AssertionConsumerService[@Binding='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST']", namespaces)
+
+    sp_1_http_post_acs = sp_1.get("Location")
+    sp_2_http_post_acs = sp_2.get("Location")
+
+    # SP 1
+    sps_list.append({
+       "entityID":f"{sp_1_entityid}",
+       "http_post_acs_location":f"{sp_1_http_post_acs}"
+    })
 
+    # SP 2
+    sps_list.append({
+       "entityID":f"{sp_2_entityid}",
+       "http_post_acs_location":f"{sp_2_http_post_acs}"
+    })
+
+    return sps_list
+
+def get_fake_sp_name():
+    chars = string.ascii_lowercase
+    return ''.join(random.choice(chars) for x in range(10))+'.org'
+
+# Miscellaneous
+DAY = date.today().isoformat()
+CA_BUNDLE_PATH = "/etc/ssl/certs/ca-certificates.crt"
 ECCS_DIR = f"{os.environ['HOME']}/eccs"
 PATHCHROMEDRIVER = f"{ECCS_DIR}/chromedriver"
 ECCS_PYTHON = f"{ECCS_DIR}/python/bin/python3"
@@ -19,11 +60,14 @@ ECCS_OUTPUTDIR = f"{ECCS_DIR}/output"
 ECCS_RESULTSLOG = f"eccs_{DAY}.log"
 ECCS_HTMLDIR = f"{ECCS_DIR}/html"
 
+# SPS Metadata
+SPS_MD_PATH = f"{ECCS_INPUTDIR}/sps-metadata.xml"
+
 # Selenium
 ECCS_SELENIUMDEBUG = False
 ECCS_SELENIUMLOGDIR = f"{ECCS_DIR}/selenium-logs"
-ECCS_SELENIUMPAGELOADTIMEOUT = 30 #seconds (remind to change timeout seconds also on web/eccs.js)
-ECCS_SELENIUMSCRIPTTIMEOUT = 30   #seconds
+ECCS_SELENIUMPAGELOADTIMEOUT = 60 #seconds (remind to change timeout seconds also on web/eccs.js)
+ECCS_SELENIUMSCRIPTTIMEOUT = 60   #seconds
 ECCS_REQUESTSTIMEOUT = 15   #seconds
 
 # Logs
@@ -36,22 +80,44 @@ ECCS_STDERRIDP = f"{ECCS_LOGSDIR}/stderr_idp_{DAY}.log"
 ECCS_FAILEDCMDIDP = f"{ECCS_LOGSDIR}/failed-cmd-idp.sh"
 
 # Number of processes to run in parallel
-ECCS_NUMPROCESSES = 35
+ECCS_NUMPROCESSES = 30
 
-# The 2 SPs that will be used to test each IdP
+# The 3 SPs that will be used to test each IdP
 ECCS_SPS = [
-   "https://sp-demo.idem.garr.it/Shibboleth.sso/Login?entityID=",
-   "https://attribute-viewer.aai.switch.ch/interfederation-test/Shibboleth.sso/Login?entityID="
+   { 
+     "entityID":f"{get_real_sps()[0]['entityID']}",
+     "http_post_acs_location":f"{get_real_sps()[0]['http_post_acs_location']}",
+   },
+   {
+     "entityID":f"{get_real_sps()[1]['entityID']}",
+     "http_post_acs_location":f"{get_real_sps()[1]['http_post_acs_location']}",
+   },
+   {
+     "entityID":f"https://{get_fake_sp_name()}/shibboleth",
+     "http_post_acs_location":f"https://{get_fake_sp_name()}/Shibboleth.sso/SAML2/POST",
+   }
 ]
 
 # ROBOTS.TXT
 ROBOTS_USER_AGENT = "ECCS/2.0 (+https://technical.edugain.org/eccs)"
 
 # PATTERNS
-IDPERROR = "error.occurred"
-METADATAPATTERN = "Unable.to.locate(\sissuer.in|).metadata(\sfor|)|no.metadata.found|profile.is.not.configured.for.relying.party|Cannot.locate.entity|fail.to.load.unknown.provider|does.not.recognise.the.service|unable.to.load.provider|Nous.n'avons.pas.pu.(charg|charger).le.fournisseur.de service|Metadata.not.found|application.you.have.accessed.is.not.registered.for.use.with.this.service|Message.did.not.meet.security.requirements|Unsupported.Request|Not.Authorized|METADATANOTFOUND|Unknown.login.requester|is.unspecified.or.unsupported|Unknown.service.provider|Richiesta.non.supportata|Metadati.non.trovati|untrusted.provider|Unregistered.Service|Unsupported.request|UNHANDLEDEXCEPTION|Metadata.*.expired|Could.not.find.any.*.metadata.*.for"
-PASSWORDPATTERN = '<input[\s]+[^>]*(type=\s*[\'"]password[\'"]|password)[^>]*>'
-REFUSEDPATTERN = '(^http)(.*\.png$)|(.*\.css$)|(.*\.js$)|(.*\.gif$)|(.*\.svg$)|(.*\.jpg$)'
+JAVASCRIPT = '"x-my-okta-version"'
+IDPERROR = "error\s(has\s)?occur(r)?(ed)$|Error\swhen\sprocessing\s(the\s)?authentication\srequest|The\s(server|system)\sencountered\san\s(internal\s)?error|Internal\sServer\sError|403\sForbidden|Service\sUnavailable|InvalidProfileConfiguration|Unexpected\sSystem\sError|404\s(.\s)?not\sfound|OpenAthens:\s404|On\stapahtunut\svirhe|Unhandled\sexception|Bad\sGateway|Page\sNot\sFound|Δεν\sεπιτρέπεται\sη\sπρόσβαση|tempora(ry|rily)\s(unavailable|error)+|License\serror|n'est\spas\sgérée|Invalid\sRequest|Erreur\s!|Please\sreport\sthis\serror\sto|该网站无法访问|proxy\serror|There\sis\sa\sproblem\swith\syour\saccount"
+METADATAPATTERN = "Unable\sto\slocate(\sissuer\sin|)\smetadata(\sfor|)|no\smetadata\sfound|profile\sis\snot\sconfigured\sfor\srelying\sparty|Cannot\slocate\sentity|fail\sto\sload\sunknown\sprovider|does\snot\srecognise\sthe\sservice|unable\sto\sload\sprovider|Nous\sn'avons\spas\spu\s(charg|charger)\sle\sfournisseur\sde\sservice|Metadata\snot\sfound|application\s(you\shave\saccessed\s)?is\snot\sregistered\s(for\suse\sthis\sservice)?|Message\sdid\snot\smeet\ssecurity\srequirements|unsupported\s[Rr]equest|METADATANOTFOUND|Unknown\slogin\srequester|is\sunspecified\sor\sunsupported|Unknown\sservice\sprovider|Richiesta\snon\ssupportata|Metadati\snon\strovati|untrusted\sprovider|Unregistered\sService|UNHANDLEDEXCEPTION|Metadata.*.expired|Could\snot\sfind\sany.*.metadata.*.for|不支持的请求|l'application\sn'est\spas\senregistrée|Requisição\snão\ssuportada|トされていないリクエスト|is\snot\sallowed|Authorization\sFailure|Pedido\snão\ssuportado|Nicht\sunterstützte\sAnfrage|Service\sNot\sAuthorized\sfor\sSingle\sSign-On|Your\sbrowser\ssent\sa\srequest\sthat\sthis\sserver\scould\snot\sunderstand|Application\sNot\sAuthorized\sTo\sUse\sCAS"
+XPATH_CHECK_PATTERN = '//input[@type="password"]|//input[@type="Password"]|//input[@type="email"]|//input[@type="user"]|//input[@name="name"]|//form[@action="/idp/module.php/multiauth/selectsource.php"]|//input[@type="text"]'
+#PASSWORDPATTERN = '<input[\s]+[^>]*(type=\s*[\'"]password[\'"]|password)[^>]*>'
+#PASSWORDPATTERN = '<input[\s]+[^>]*((type|name)=\s*[\'"]password|email|user|text|name[\'"]|password|email|user|text|name)[^>]*>|<form[\s]+[^>]*(action)=\s*[\'"]/idp/module.php/multiauth/selectsource.php[\'"][^>]*>'
+#PASSWORDPATTERN = '<input[\s]+[^>]*((type|name)=\s*"password|email|user|text|name"|password|email|user|text|name)[^>]*>|<form[\s]+[^>]*(action)=\s*"/idp/module.php/multiauth/selectsource.php"[^>]*>'
+#PASSWORDPATTERN = '<input[\s]+[^>]*((type=|name=)["]?(text|password|email)["]?)[\s]+[^>]*>|<form[\s]+[^>]*(action)=\s*"/idp/module.php/multiauth/selectsource.php"[^>]*>'
+PASSWORDPATTERN = '<input[\s][^>]*(type=|name=)"?(.*passw(or)?d)"?.*[^>]>$|<form[\s]+[^>]*(action)=\s*"/idp/module.php/multiauth/selectsource.php"[^>]*>'
+
+### PRODUCTION ECCS
+# PASSWORDPATTERN = '<input[\s]+[^>]*((type|name)=\s*"password|email|user|text|name"|password|email|user|text|name)[^>]*>|<form[\s]+[^>]*(action)=\s*"/idp/module.php/multiauth/selectsource.php"[^>]*>'
+### END
+
+#USERNAMEPATTERN = '<input[\s]+[^>]*((type=\s*[\'"](text|email)[\'"]|user)|(name=\s*[\'"](name)[\'"]))[^>]*>'
+#REFUSEDPATTERN = '(^http)(.*\.png$)|(.*\.css$)|(.*\.js$)|(.*\.gif$)|(.*\.svg$)|(.*\.jpg$)'
 
 # { 'reg_auth':'reason' }
 FEDS_DISABLED_DICT = {
@@ -64,7 +130,7 @@ FEDS_DISABLED_DICT = {
 IDPS_DISABLED_DICT = {
    'https://idp.eie.gr/idp/shibboleth':'Disabled on 2019-04-24 because ECCS cannot check non-standard login page',
    'https://edugain-proxy.igtf.net/simplesaml/saml2/idp/metadata.php':'Disabled on 2017-03-17 on request of federation operator',
-   'https://gn-vho.grnet.gr/idp/shibboleth':'Disabled on 2019-04-24 because basic authentication is not supported by ECCS check',
+   #'https://gn-vho.grnet.gr/idp/shibboleth':'Disabled on 2019-04-24 because basic authentication is not supported by ECCS check',
    'https://wtc.tu-chemnitz.de/shibboleth':'Disabled on 2019-02-26 because ECCS cannot check non-standard login page',
    'https://idp.fraunhofer.de/idp/shibboleth':'Disabled on 2017-11-24 on request of federation operator',
    'https://idp.dfn-cert.de/idp/shibboleth':'Disabled on 2018-04-05 on request of federation operator',
@@ -72,7 +138,7 @@ IDPS_DISABLED_DICT = {
    'https://login.lstonline.ac.uk/idp/pingfederate':'Disabled on 2017-02-08 on request of federation operator',
    'https://indiid.net/idp/shibboleth':'Disabled on 2017-10-27 on request of federation operator',
    'https://idp.nulc.ac.uk/openathens':'Disabled on 2017-10-27 on request of federation operator',
-   'https://lc-idp.lincolncollege.ac.uk/shibboleth':'Disabled on 2015-08-17 because uses HTTP Basic authentication, which cannot be checked reliably',
+#   'https://lc-idp.lincolncollege.ac.uk/shibboleth':'Disabled on 2015-08-17 because uses HTTP Basic authentication, which cannot be checked reliably',
    'https://idp.wnsc.ac.uk/idp/shibboleth':'Disabled on 2017-10-27 on request of federation operator',
 #   'https://idp.strodes.ac.uk/shibboleth':'Disabled on 2015-08-17 because uses HTTP Basic authentication, which cannot be checked reliably',
    'https://idp.uel.ac.uk/shibboleth':'Disabled on 2017-10-27 on request of federation operator',
diff --git a/get-sps-metadata.sh b/get-sps-metadata.sh
index 4aa5422..7db93e3 100755
--- a/get-sps-metadata.sh
+++ b/get-sps-metadata.sh
@@ -14,8 +14,8 @@ if [ ! -f "$sp_md_1" ] || [ ! -f "$sp_md_2" ]; then
   exit 1
 fi
 
-sp_md_1_is_valid=$(bash xmlsectool-3.0.0/xmlsectool.sh --verifySignature --certificate idem-mdx-service-crt.pem --inFile input/sp_md_1.xml | grep "XML document signature verified." | wc -l)
-sp_md_2_is_valid=$(bash xmlsectool-3.0.0/xmlsectool.sh --verifySignature --certificate idem-mdx-service-crt.pem --inFile input/sp_md_2.xml | grep "XML document signature verified." | wc -l)
+sp_md_1_is_valid=$(bash xmlsectool/xmlsectool.sh --verifySignature --certificate idem-mdx-service-crt.pem --inFile input/sp_md_1.xml | grep "XML document signature verified." | wc -l)
+sp_md_2_is_valid=$(bash xmlsectool/xmlsectool.sh --verifySignature --certificate idem-mdx-service-crt.pem --inFile input/sp_md_2.xml | grep "XML document signature verified." | wc -l)
 
 # Check the validity of both SP metadata files
 if [ $sp_md_1_is_valid -eq 0 ] || [ $sp_md_1_is_valid -eq 0 ]; then
diff --git a/setup-eccs-dev.sh b/setup-eccs-dev.sh
index dc9f153..1175436 100755
--- a/setup-eccs-dev.sh
+++ b/setup-eccs-dev.sh
@@ -38,7 +38,7 @@ docker compose up -d
 
 ECCS_IP=$(docker inspect eccs | grep "IPAddress" | grep -E -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | tail -n 1)
 
-DOMAIN_NAME="technical.edugain.org technical-test.edugain.org"
+DOMAIN_NAME="eccs.edugain.org"
 
 modify_hosts_file "remove" "$DOMAIN_NAME"
 modify_hosts_file "add" "$DOMAIN_NAME" "$ECCS_IP"
diff --git a/start.sh b/start.sh
index 995b731..ee49a1d 100644
--- a/start.sh
+++ b/start.sh
@@ -1,6 +1,8 @@
 #!/bin/bash
 
-# ...other things...
+bash /root/eccs/get-sps-metadata.sh
+
+touch /root/eccs/eccs.ini
 
 # Last command
 exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
diff --git a/supervisord.conf b/supervisord.conf
index b7ff44a..288cab2 100644
--- a/supervisord.conf
+++ b/supervisord.conf
@@ -1,17 +1,50 @@
 [supervisord]
 nodaemon=true
+pidfile=/var/run/supervisord/supervisord.pid
+user=root
+
+[unix_http_server]
+file=/var/run/supervisor.sock
+chmod=0777
+
+[supervisorctl]
+serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket
+
+[rpcinterface:supervisor]
+supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
 
 [program:cron]
 command=cron -f
+stdout_logfile=/dev/stdout
+stdout_logfile_maxbytes=0
+stderr_logfile=/dev/stderr
+stderr_logfile_maxbytes=0
+autostart=true
+autorestart=true
+
+[program:uwsgi]
+#command=uwsgi --ini /root/eccs/eccs.ini --die-on-term
+command=uwsgi --ini /root/eccs/eccs.ini --die-on-term
+stdout_logfile=/dev/stdout
+stdout_logfile_maxbytes=0
+stderr_logfile=/dev/stderr
+stderr_logfile_maxbytes=0
+autostart=true
+autorestart=true
+
+[program:apache2]
+command=/usr/sbin/apache2ctl -DFOREGROUND
+killasgroup=true
+stopasgroup=true
+stdout_logfile=/dev/stdout
+stdout_logfile_maxbytes=0
+stderr_logfile=/dev/stdout
+stderr_logfile_maxbytes=0
 autostart=true
 autorestart=true
 
-#[program:uwsgi]
-#command=uwsgi --ini /path/to/uwsgi_config.ini
-#autostart=true
-#autorestart=true
+#[program:rsyslog]
+#command=/usr/sbin/rsyslogd -n
+#stdout_logfile=/dev/stdout
+#stdout_logfile_maxbytes=0
 
-#[program:apache2]
-#command=apache2ctl -DFOREGROUND
-#autostart=true
-#autorestart=true
diff --git a/web/index.php b/web/index.php
index ae3b006..dc7720c 100644
--- a/web/index.php
+++ b/web/index.php
@@ -15,7 +15,7 @@ $data['firstDate'] = $firstDate;
 $data['lastDate'] = $lastDate;
 $data['idp'] = htmlspecialchars($_GET["idp"]);
 $data['reg_auth'] = htmlspecialchars($_GET["reg_auth"]);
-$data['date'] = (htmlspecialchars($_GET["date"]) ? htmlspecialchars($_GET["date"] : $lastDate);
+$data['date'] = (htmlspecialchars($_GET["date"]) ? htmlspecialchars($_GET["date"]) : $lastDate);
 $data['status'] = htmlspecialchars($_GET["status"]);
 $data['check_result'] = htmlspecialchars($_GET["check_result"]);
 ?>
@@ -24,6 +24,8 @@ $data['check_result'] = htmlspecialchars($_GET["check_result"]);
 <html>
    <head>
     <meta charset=utf-8 />
+    <script type="text/javascript" src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
+    <script type="text/javascript" src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js"></script>
     <script type="text/javascript" src="https://cdn.datatables.net/1.10.22/js/jquery.dataTables.min.js"></script>
     <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.22/css/jquery.dataTables.min.css"/>
     <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"/>
@@ -69,9 +71,9 @@ $data['check_result'] = htmlspecialchars($_GET["check_result"]);
           </div> <!-- END clearFix -->
           <hr>
        </div> <!-- END status -->
-       <button id="btn-show-all-children" type="button">Expand All</button>
+       <!--<button id="btn-show-all-children" type="button">Expand All</button>
        <button id="btn-hide-all-children" type="button">Collapse All</button>
-       <hr>
+       <hr>-->
        <div class="container">
           <div class="loader"></div>      
           <table id="eccstable" class="cell-border" style="width:100%">
-- 
GitLab