From f690787f75913e996e0e1f0ee25c433a44416e57 Mon Sep 17 00:00:00 2001 From: saravahdatipour Date: Thu, 9 Jan 2025 17:30:10 +0100 Subject: [PATCH 1/9] multi-stage dockerfile --- Dockerfile | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/Dockerfile b/Dockerfile index ac94edd..6850c1f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,31 +1,31 @@ -FROM python:3.9-slim - -WORKDIR / - -RUN apt-get update && \ - apt-get install -y curl apache2 && \ - curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \ - apt-get install -y nodejs && \ - npm install -g yarn && \ - pip install Jinja2 && \ - pip install requests +# Stage 1: download and build the webpages +FROM python:3.9-slim AS python-build +COPY . . +RUN pip install Jinja2 requests \ + && python3 download_repos.py \ + && python3 -u update.py +# Stage 2: install dependencies and build assets +FROM node:18 AS node-build ENV NODE_OPTIONS=--openssl-legacy-provider - COPY . . -RUN python3 download_repos.py && \ - python3 -u update.py && \ - test -f index.json && \ - yarn && yarn build && \ - mkdir -p /var/www/html && \ - cp -r /en /var/www/html/ && \ - cp -r /nl /var/www/html/ && \ - cp -r /repos /var/www/html/ && \ - cp style.css /var/www/html/ && \ - cp logo.svg /var/www/html/ && \ - cp script.js /var/www/html/ && \ - cp index.json /var/www/html/ +RUN yarn && yarn build +# Stage 3: host +FROM debian:bullseye-slim +RUN apt-get update && \ + apt-get install -y apache2 && \ + rm -rf /var/lib/apt/lists/* && \ + echo 'Alias /en /var/www/html/en' >> /etc/apache2/apache2.conf && \ + echo 'Alias /nl /var/www/html/nl' >> /etc/apache2/apache2.conf && \ + echo '' >> /etc/apache2/apache2.conf && \ + echo ' Require all denied' >> /etc/apache2/apache2.conf && \ + echo '' >> /etc/apache2/apache2.conf +COPY --from=python-build /en/ /var/www/html/en/ +COPY --from=python-build /nl/ /var/www/html/nl/ +COPY --from=python-build /repos/ /var/www/html/repos/ +COPY --from=python-build index.json /var/www/html/ +COPY --from=node-build /script.js /var/www/html/ +COPY style.css logo.svg /var/www/html/ EXPOSE 80 - -CMD ["apache2ctl", "-D", "FOREGROUND"] +CMD ["apache2ctl", "-D", "FOREGROUND"] \ No newline at end of file From 7067fe2cf36d2d69c225c8d4c789d2b8e6dc7935 Mon Sep 17 00:00:00 2001 From: saravahdatipour Date: Mon, 13 Jan 2025 10:25:00 +0100 Subject: [PATCH 2/9] multi-stage dockerfile and fix docker image bugs --- Dockerfile | 68 +++++++++++++++++++++++++++------------------ README.markdown | 7 ++--- docker-compose.yaml | 12 ++++++++ nginx.conf | 15 ++++++++++ 4 files changed, 70 insertions(+), 32 deletions(-) create mode 100644 docker-compose.yaml create mode 100644 nginx.conf diff --git a/Dockerfile b/Dockerfile index 6850c1f..440e281 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,31 +1,45 @@ -# Stage 1: download and build the webpages -FROM python:3.9-slim AS python-build -COPY . . -RUN pip install Jinja2 requests \ - && python3 download_repos.py \ - && python3 -u update.py +# --- Stage 1 Node build +FROM node:18-slim AS node-build + +WORKDIR /app + +COPY src ./ +COPY webpack.config.js yarn.lock package.json ./ -# Stage 2: install dependencies and build assets -FROM node:18 AS node-build -ENV NODE_OPTIONS=--openssl-legacy-provider +RUN yarn install --frozen-lockfile + +ENV NODE_OPTIONS="--openssl-legacy-provider" COPY . . -RUN yarn && yarn build - -# Stage 3: host -FROM debian:bullseye-slim -RUN apt-get update && \ - apt-get install -y apache2 && \ - rm -rf /var/lib/apt/lists/* && \ - echo 'Alias /en /var/www/html/en' >> /etc/apache2/apache2.conf && \ - echo 'Alias /nl /var/www/html/nl' >> /etc/apache2/apache2.conf && \ - echo '' >> /etc/apache2/apache2.conf && \ - echo ' Require all denied' >> /etc/apache2/apache2.conf && \ - echo '' >> /etc/apache2/apache2.conf -COPY --from=python-build /en/ /var/www/html/en/ -COPY --from=python-build /nl/ /var/www/html/nl/ -COPY --from=python-build /repos/ /var/www/html/repos/ -COPY --from=python-build index.json /var/www/html/ -COPY --from=node-build /script.js /var/www/html/ +RUN yarn build + +# --- Stage 2 Python build +FROM python:3.9-slim AS python-build + +WORKDIR /app +COPY --from=node-build /app ./ + +COPY download_repos.py update.py config.json ./ +RUN ls -l /app + +RUN pip install --no-cache-dir Jinja2 requests && \ + python3 download_repos.py && \ + python3 -u update.py + +# --- Stage 3: Final nginx stage +FROM nginx:stable + +COPY nginx.conf /etc/nginx/conf.d/default.conf + +COPY --from=python-build /app/en/ /var/www/html/en/ +COPY --from=python-build /app/nl/ /var/www/html/nl/ +COPY --from=python-build /app/repos/ /var/www/html/repos/ +COPY --from=python-build /app/index.json /var/www/html/ +COPY --from=node-build /app/script.js /var/www/html/ COPY style.css logo.svg /var/www/html/ + +RUN chown -R nginx:nginx /var/www/html && \ + chmod -R 755 /var/www/html + EXPOSE 80 -CMD ["apache2ctl", "-D", "FOREGROUND"] \ No newline at end of file + +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/README.markdown b/README.markdown index 9249cbf..9f94f1b 100644 --- a/README.markdown +++ b/README.markdown @@ -31,12 +31,9 @@ To generate the JavaScript handling issuance sessions of demo credentials, run: ## Running with Docker -To build and run the Docker container, build and run the docker image via the following: +To build and run the Docker container, you can use docker compose file - docker build -t attribute-index . - docker run -p 80:80 attribute-index - -## Using untrusted scheme managers + docker compose up Currently, scheme managers are considered trusted. Generating an attribute index for an untrusted scheme manager has at least the following problems at the diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..944a863 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,12 @@ +version: '3.8' + +services: + attribute-index: + build: + context: . + dockerfile: Dockerfile + ports: + - "80:80" + environment: + - NODE_OPTIONS=--openssl-legacy-provider + restart: unless-stopped diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..12663a8 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,15 @@ +server { + listen 80; + server_name 127.0.0.1; + root /var/www/html; + index index.html; + charset utf-8; + + location / { + if ($uri = /) { + return 301 /en; + } + try_files $uri $uri/ =404; + add_header Content-Type "text/html; charset=utf-8"; + } +} \ No newline at end of file From 3288a6420e86bea0684a7a23178337ded9ed0346 Mon Sep 17 00:00:00 2001 From: saravahdatipour Date: Mon, 13 Jan 2025 10:36:49 +0100 Subject: [PATCH 3/9] fix the bug in navigator preselecting issuer --- templates/credential-navigator.html | 69 +++++++++++++++-------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/templates/credential-navigator.html b/templates/credential-navigator.html index a457ccf..ebe2d29 100644 --- a/templates/credential-navigator.html +++ b/templates/credential-navigator.html @@ -35,27 +35,13 @@

Issuing Demo Credentials

- - {% if organized_data %} - {% for issuer in organized_data[0].issuers %} - - {% endfor %} - {% endif %}
- - {% if organized_data and organized_data[0].issuers %} - {% for credential in organized_data[0].issuers[0].credentials %} - - {% endfor %} - {% endif %}
@@ -65,29 +51,46 @@

Issuing Demo Credentials

function updateIssuers(schemeId) { const issuerSelect = document.getElementById('issuer'); - const scheme = organizedData.find(s => s.identifier === schemeId); - + const credentialSelect = document.getElementById('credential'); + issuerSelect.innerHTML = ''; - if (scheme) { - scheme.issuers.forEach(issuer => { - const option = new Option(issuer.name[{{LANG|tojson|safe}}], issuer.identifier); - issuerSelect.add(option); - }); + credentialSelect.innerHTML = ''; + credentialSelect.disabled = true; + + if (schemeId) { + const scheme = organizedData.find(s => s.identifier === schemeId); + if (scheme) { + scheme.issuers.forEach(issuer => { + const option = new Option(issuer.name[{{LANG|tojson|safe}}], issuer.identifier); + issuerSelect.add(option); + }); + issuerSelect.disabled = false; + } else { + issuerSelect.disabled = true; + } + } else { + issuerSelect.disabled = true; } - updateCredentials('', ''); } function updateCredentials(schemeId, issuerId) { const credentialSelect = document.getElementById('credential'); - const scheme = organizedData.find(s => s.identifier === schemeId); - const issuer = scheme?.issuers.find(i => i.identifier === issuerId); - + credentialSelect.innerHTML = ''; - if (issuer) { - issuer.credentials.forEach(cred => { - const option = new Option(cred.name[{{LANG|tojson|safe}}], cred.identifier); - credentialSelect.add(option); - }); + if (schemeId && issuerId) { + const scheme = organizedData.find(s => s.identifier === schemeId); + const issuer = scheme?.issuers.find(i => i.identifier === issuerId); + if (issuer) { + issuer.credentials.forEach(cred => { + const option = new Option(cred.name[{{LANG|tojson|safe}}], cred.identifier); + credentialSelect.add(option); + }); + credentialSelect.disabled = false; + } else { + credentialSelect.disabled = true; + } + } else { + credentialSelect.disabled = true; } } @@ -107,4 +110,4 @@

Issuing Demo Credentials

}); -{% endblock main %} \ No newline at end of file +{% endblock main %} From 4110bf652f42711be6aa71a881d297b53e7c0289 Mon Sep 17 00:00:00 2001 From: saravahdatipour Date: Mon, 13 Jan 2025 10:39:17 +0100 Subject: [PATCH 4/9] small edit --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 9f94f1b..b68cfa2 100644 --- a/README.markdown +++ b/README.markdown @@ -31,7 +31,7 @@ To generate the JavaScript handling issuance sessions of demo credentials, run: ## Running with Docker -To build and run the Docker container, you can use docker compose file +To build and run the Docker container, you can use docker compose: docker compose up From 6bbe49150f9ff1b574e1d4ce15af332c31867282 Mon Sep 17 00:00:00 2001 From: saravahdatipour Date: Mon, 13 Jan 2025 11:03:24 +0100 Subject: [PATCH 5/9] Some improvements to readability --- Dockerfile | 4 +- README.markdown | 12 +-- generate-index.py | 238 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 245 insertions(+), 9 deletions(-) create mode 100755 generate-index.py diff --git a/Dockerfile b/Dockerfile index 440e281..3141a39 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,12 +18,12 @@ FROM python:3.9-slim AS python-build WORKDIR /app COPY --from=node-build /app ./ -COPY download_repos.py update.py config.json ./ +COPY download_repos.py generate-index.py config.json ./ RUN ls -l /app RUN pip install --no-cache-dir Jinja2 requests && \ python3 download_repos.py && \ - python3 -u update.py + python3 -u generate-index.py # --- Stage 3: Final nginx stage FROM nginx:stable diff --git a/README.markdown b/README.markdown index b68cfa2..e7a3faa 100644 --- a/README.markdown +++ b/README.markdown @@ -1,6 +1,6 @@ # Attribute index -Generate documentation for the IRMA scheme manager. You can browse a live +Generate documentation for the Yivi scheme manager. You can browse a live version [over here](https://privacybydesign.foundation/attribute-index/en/). ## Installing @@ -12,17 +12,15 @@ Dependencies: * [Jinja2](http://jinja.pocoo.org/) (Debian package: `python3-jinja2`) * yarn -Before generating content, download the scheme managers by running `download_repos.py`. -To add a scheme, configure the schemes config in `config.json`. ## Running -To generate the HTML for the attribute index, run the script: +Before you run the script to generate Yivi index pages run the `download_repos.py` script. This downloalds +most recent version of the schemes. If new schemes are added, you can modify the `config.json` file to add them. - python3 update.py + python3 download_repos.py + python3 generate-index.py -If you want to have an up-to-date attribute index, it is recommended to update -the scheme managers regularly and run the update script afterwards. To generate the JavaScript handling issuance sessions of demo credentials, run: diff --git a/generate-index.py b/generate-index.py new file mode 100755 index 0000000..b13c586 --- /dev/null +++ b/generate-index.py @@ -0,0 +1,238 @@ +#!/usr/bin/python3 + +import json +from xml.dom import minidom +import os +import jinja2 # Debian: python3-jinja2 +from datetime import datetime + +BOOL = { + 'true': True, + 'false': False, +} + +def filter_active(highlightpath, currentpath): + if highlightpath == currentpath: + return 'active' + else: + return '' + +def render(out, template_name, **kwargs): + env = jinja2.Environment( + loader=jinja2.FileSystemLoader('templates'), + autoescape=True) + env.filters['active'] = filter_active + template = env.get_template(template_name) + html = template.render(base='.', assets='..', **kwargs) + open(out, 'w', encoding='utf-8').write(html) + + +def getText(element): + strings = [] + for node in element.childNodes: + if node.nodeType == node.TEXT_NODE: + strings.append(node.data) + return ''.join(strings) + +def getTime(element): + return format(datetime.fromtimestamp(int(getText(element))), '%Y-%m-%d %H:%M:%S') + +def translated(element): + strings = {} + for child in element.childNodes: + if child.nodeType != child.ELEMENT_NODE: + continue + strings[child.nodeName] = getText(child) + return strings + +def readAttribute(xml, credential): + name = xml.getElementsByTagName('Name') + desc = xml.getElementsByTagName('Description') + attribute = { + 'id': xml.getAttribute('id'), + 'optional': len(xml.getAttribute('optional')) > 0, + 'revocation': len(xml.getAttribute('revocation')) > 0, + 'randomblind': len(xml.getAttribute('randomblind')) > 0, + 'name': translated(name[0]) if len(name) > 0 else None, + 'description': translated(desc[0]) if len(desc) > 0 else None, + } + attribute['identifier'] = '%s.%s' % (credential['identifier'], attribute['id']) + return attribute + +def readCredential(path): + xml = minidom.parse(path + '/description.xml') + deprecated = xml.getElementsByTagName('DeprecatedSince') + credential = { + 'schememgr': getText(xml.getElementsByTagName('SchemeManager')[0]), + 'issuer': getText(xml.getElementsByTagName('IssuerID')[0]), + 'id': getText(xml.getElementsByTagName('CredentialID')[0]), + 'name': translated(xml.getElementsByTagName('Name')[0]), + 'shortName': translated(xml.getElementsByTagName('ShortName')[0]), + 'description': translated(xml.getElementsByTagName('Description')[0]), + 'revocation': xml.getElementsByTagName('RevocationServers').length > 0, + 'deprecated': getTime(deprecated[0]) if len(deprecated) > 0 else None, + 'logo': path + '/logo.png', + 'shouldBeSingleton': False, + 'attributes': [], + } + credential['identifier'] = '%s.%s.%s' % (credential['schememgr'], credential['issuer'], credential['id']) + + singletonElements = xml.getElementsByTagName('ShouldBeSingleton') + if singletonElements: + # Not all credential descriptions have a ShouldBeSingleton element. + credential['shouldBeSingleton'] = BOOL[getText(singletonElements[0])] + + for attribute in xml.getElementsByTagName('Attributes')[0].childNodes: + if attribute.nodeType != attribute.ELEMENT_NODE: + continue + credentialAttr = readAttribute(attribute, credential) + if credentialAttr['revocation']: + continue + credential['attributes'].append(credentialAttr) + + return credential + +def readIssuer(path): + xml = minidom.parse(path + '/description.xml') + issuer = { + 'id': getText(xml.getElementsByTagName('ID')[0]), + 'schememgr': getText(xml.getElementsByTagName('SchemeManager')[0]), + 'shortName': translated(xml.getElementsByTagName('ShortName')[0]), + 'name': translated(xml.getElementsByTagName('Name')[0]), + 'contactEmail': getText(xml.getElementsByTagName('ContactEMail')[0]), + 'logo': path + '/logo.png', + 'credentials': {}, + } + issuer['identifier'] = '%s.%s' % (issuer['schememgr'], issuer['id']) + + for fn in sorted(os.listdir(path + '/Issues')): + issuer['credentials'][fn] = readCredential(path + '/Issues/' + fn) + + return issuer + +def readSchemeManager(path): + schememgr = {} + + xml = minidom.parse(path + '/description.xml') + schememgr = { + 'id': getText(xml.getElementsByTagName('Id')[0]), + 'name': translated(xml.getElementsByTagName('Name')[0]), + 'description': translated(xml.getElementsByTagName('Description')[0]), + 'url': getText(xml.getElementsByTagName('Url')[0]), + 'contact': getText(xml.getElementsByTagName('Contact')[0]), + 'keyshareServer': None, + 'keyshareWebsite': None, + 'keyshareAttribute': None, + 'issuers': {}, + } + schememgr['identifier'] = schememgr['id'] # for consistency + schememgr['test'] = bool(os.path.exists(path + '/sk.pem')) + + keyshareServerElements = xml.getElementsByTagName('KeyshareServer') + if keyshareServerElements: + schememgr['keyshareServer'] = getText(keyshareServerElements[0]) + + keyshareWebsiteElements = xml.getElementsByTagName('KeyshareWebsite') + if keyshareWebsiteElements: + schememgr['keyshareWebsite'] = getText(keyshareWebsiteElements[0]) + + keyshareAttributeElements = xml.getElementsByTagName('KeyshareAttribute') + if keyshareAttributeElements: + schememgr['keyshareAttribute'] = getText(keyshareAttributeElements[0]) + + for fn in sorted(os.listdir(path)): + issuerPath = path + '/' + fn + if os.path.exists(issuerPath + '/description.xml'): + schememgr['issuers'][fn] = readIssuer(issuerPath) + + return schememgr + +def generateHTML(index, out, lang): + os.makedirs(out, exist_ok=True) + + render(out + '/index.html', 'about.html', + index=index, + LANG=lang, + identifier='') + + render(out + '/glossary.html', 'glossary.html', + index=index, + LANG=lang, + identifier='glossary') + + + + organized_data = [] + for schememgr in index: + scheme_data = { + 'identifier': schememgr['identifier'], + 'name': schememgr['name'], + 'issuers': [] + } + + for issuerId, issuer in sorted(schememgr['issuers'].items()): + issuer_data = { + 'identifier': issuer['identifier'], + 'name': issuer['name'], + 'credentials': [] + } + + for credentialId, credential in sorted(issuer['credentials'].items()): + issuer_data['credentials'].append({ + 'identifier': credential['identifier'], + 'name': credential['name'] + }) + + scheme_data['issuers'].append(issuer_data) + + organized_data.append(scheme_data) + + for schememgr in index: + render(out + '/' + schememgr['identifier'] + '.html', 'schememgr.html', + index=index, + schememgr=schememgr, + LANG=lang, + identifier=schememgr['identifier']) + for issuerId, issuer in sorted(schememgr['issuers'].items()): + render(out + '/' + issuer['identifier'] + '.html', 'issuer.html', + index=index, + schememgr=schememgr, + issuer=issuer, + LANG=lang, + identifier=issuer['identifier']) + for credentialId, credential in sorted(issuer['credentials'].items()): + render(out + '/' + credential['identifier'] + '.html', 'credential.html', + index=index, + schememgr=schememgr, + issuer=issuer, + credential=credential, + LANG=lang, + identifier=credential['identifier']) + + + + render(out + '/credential-navigator.html', 'credential-navigator.html', + index=index, + organized_data=organized_data, + LANG=lang, + identifier='credential-navigator') + +if __name__ == '__main__': + config_file = 'config.json' + if os.path.exists(config_file): + with open(config_file) as f: + schememanagers = json.load(f) + try: + index = [] + for info in schememanagers: + index.append(readSchemeManager(info['PATH'])) + + with open('index.json', 'w') as json_file: + json.dump(index, json_file) + print("JSON file generated: index.json") + + generateHTML(index, 'en', 'en') + generateHTML(index, 'nl', 'nl') + + except Exception as e: + print(f"An error occurred: {e}") \ No newline at end of file From 219f97b50a5791fe4c0ff8a80e54f6666e53af20 Mon Sep 17 00:00:00 2001 From: saravahdatipour Date: Mon, 13 Jan 2025 11:03:51 +0100 Subject: [PATCH 6/9] Rename the script for readability --- update.py | 238 ------------------------------------------------------ 1 file changed, 238 deletions(-) delete mode 100755 update.py diff --git a/update.py b/update.py deleted file mode 100755 index b13c586..0000000 --- a/update.py +++ /dev/null @@ -1,238 +0,0 @@ -#!/usr/bin/python3 - -import json -from xml.dom import minidom -import os -import jinja2 # Debian: python3-jinja2 -from datetime import datetime - -BOOL = { - 'true': True, - 'false': False, -} - -def filter_active(highlightpath, currentpath): - if highlightpath == currentpath: - return 'active' - else: - return '' - -def render(out, template_name, **kwargs): - env = jinja2.Environment( - loader=jinja2.FileSystemLoader('templates'), - autoescape=True) - env.filters['active'] = filter_active - template = env.get_template(template_name) - html = template.render(base='.', assets='..', **kwargs) - open(out, 'w', encoding='utf-8').write(html) - - -def getText(element): - strings = [] - for node in element.childNodes: - if node.nodeType == node.TEXT_NODE: - strings.append(node.data) - return ''.join(strings) - -def getTime(element): - return format(datetime.fromtimestamp(int(getText(element))), '%Y-%m-%d %H:%M:%S') - -def translated(element): - strings = {} - for child in element.childNodes: - if child.nodeType != child.ELEMENT_NODE: - continue - strings[child.nodeName] = getText(child) - return strings - -def readAttribute(xml, credential): - name = xml.getElementsByTagName('Name') - desc = xml.getElementsByTagName('Description') - attribute = { - 'id': xml.getAttribute('id'), - 'optional': len(xml.getAttribute('optional')) > 0, - 'revocation': len(xml.getAttribute('revocation')) > 0, - 'randomblind': len(xml.getAttribute('randomblind')) > 0, - 'name': translated(name[0]) if len(name) > 0 else None, - 'description': translated(desc[0]) if len(desc) > 0 else None, - } - attribute['identifier'] = '%s.%s' % (credential['identifier'], attribute['id']) - return attribute - -def readCredential(path): - xml = minidom.parse(path + '/description.xml') - deprecated = xml.getElementsByTagName('DeprecatedSince') - credential = { - 'schememgr': getText(xml.getElementsByTagName('SchemeManager')[0]), - 'issuer': getText(xml.getElementsByTagName('IssuerID')[0]), - 'id': getText(xml.getElementsByTagName('CredentialID')[0]), - 'name': translated(xml.getElementsByTagName('Name')[0]), - 'shortName': translated(xml.getElementsByTagName('ShortName')[0]), - 'description': translated(xml.getElementsByTagName('Description')[0]), - 'revocation': xml.getElementsByTagName('RevocationServers').length > 0, - 'deprecated': getTime(deprecated[0]) if len(deprecated) > 0 else None, - 'logo': path + '/logo.png', - 'shouldBeSingleton': False, - 'attributes': [], - } - credential['identifier'] = '%s.%s.%s' % (credential['schememgr'], credential['issuer'], credential['id']) - - singletonElements = xml.getElementsByTagName('ShouldBeSingleton') - if singletonElements: - # Not all credential descriptions have a ShouldBeSingleton element. - credential['shouldBeSingleton'] = BOOL[getText(singletonElements[0])] - - for attribute in xml.getElementsByTagName('Attributes')[0].childNodes: - if attribute.nodeType != attribute.ELEMENT_NODE: - continue - credentialAttr = readAttribute(attribute, credential) - if credentialAttr['revocation']: - continue - credential['attributes'].append(credentialAttr) - - return credential - -def readIssuer(path): - xml = minidom.parse(path + '/description.xml') - issuer = { - 'id': getText(xml.getElementsByTagName('ID')[0]), - 'schememgr': getText(xml.getElementsByTagName('SchemeManager')[0]), - 'shortName': translated(xml.getElementsByTagName('ShortName')[0]), - 'name': translated(xml.getElementsByTagName('Name')[0]), - 'contactEmail': getText(xml.getElementsByTagName('ContactEMail')[0]), - 'logo': path + '/logo.png', - 'credentials': {}, - } - issuer['identifier'] = '%s.%s' % (issuer['schememgr'], issuer['id']) - - for fn in sorted(os.listdir(path + '/Issues')): - issuer['credentials'][fn] = readCredential(path + '/Issues/' + fn) - - return issuer - -def readSchemeManager(path): - schememgr = {} - - xml = minidom.parse(path + '/description.xml') - schememgr = { - 'id': getText(xml.getElementsByTagName('Id')[0]), - 'name': translated(xml.getElementsByTagName('Name')[0]), - 'description': translated(xml.getElementsByTagName('Description')[0]), - 'url': getText(xml.getElementsByTagName('Url')[0]), - 'contact': getText(xml.getElementsByTagName('Contact')[0]), - 'keyshareServer': None, - 'keyshareWebsite': None, - 'keyshareAttribute': None, - 'issuers': {}, - } - schememgr['identifier'] = schememgr['id'] # for consistency - schememgr['test'] = bool(os.path.exists(path + '/sk.pem')) - - keyshareServerElements = xml.getElementsByTagName('KeyshareServer') - if keyshareServerElements: - schememgr['keyshareServer'] = getText(keyshareServerElements[0]) - - keyshareWebsiteElements = xml.getElementsByTagName('KeyshareWebsite') - if keyshareWebsiteElements: - schememgr['keyshareWebsite'] = getText(keyshareWebsiteElements[0]) - - keyshareAttributeElements = xml.getElementsByTagName('KeyshareAttribute') - if keyshareAttributeElements: - schememgr['keyshareAttribute'] = getText(keyshareAttributeElements[0]) - - for fn in sorted(os.listdir(path)): - issuerPath = path + '/' + fn - if os.path.exists(issuerPath + '/description.xml'): - schememgr['issuers'][fn] = readIssuer(issuerPath) - - return schememgr - -def generateHTML(index, out, lang): - os.makedirs(out, exist_ok=True) - - render(out + '/index.html', 'about.html', - index=index, - LANG=lang, - identifier='') - - render(out + '/glossary.html', 'glossary.html', - index=index, - LANG=lang, - identifier='glossary') - - - - organized_data = [] - for schememgr in index: - scheme_data = { - 'identifier': schememgr['identifier'], - 'name': schememgr['name'], - 'issuers': [] - } - - for issuerId, issuer in sorted(schememgr['issuers'].items()): - issuer_data = { - 'identifier': issuer['identifier'], - 'name': issuer['name'], - 'credentials': [] - } - - for credentialId, credential in sorted(issuer['credentials'].items()): - issuer_data['credentials'].append({ - 'identifier': credential['identifier'], - 'name': credential['name'] - }) - - scheme_data['issuers'].append(issuer_data) - - organized_data.append(scheme_data) - - for schememgr in index: - render(out + '/' + schememgr['identifier'] + '.html', 'schememgr.html', - index=index, - schememgr=schememgr, - LANG=lang, - identifier=schememgr['identifier']) - for issuerId, issuer in sorted(schememgr['issuers'].items()): - render(out + '/' + issuer['identifier'] + '.html', 'issuer.html', - index=index, - schememgr=schememgr, - issuer=issuer, - LANG=lang, - identifier=issuer['identifier']) - for credentialId, credential in sorted(issuer['credentials'].items()): - render(out + '/' + credential['identifier'] + '.html', 'credential.html', - index=index, - schememgr=schememgr, - issuer=issuer, - credential=credential, - LANG=lang, - identifier=credential['identifier']) - - - - render(out + '/credential-navigator.html', 'credential-navigator.html', - index=index, - organized_data=organized_data, - LANG=lang, - identifier='credential-navigator') - -if __name__ == '__main__': - config_file = 'config.json' - if os.path.exists(config_file): - with open(config_file) as f: - schememanagers = json.load(f) - try: - index = [] - for info in schememanagers: - index.append(readSchemeManager(info['PATH'])) - - with open('index.json', 'w') as json_file: - json.dump(index, json_file) - print("JSON file generated: index.json") - - generateHTML(index, 'en', 'en') - generateHTML(index, 'nl', 'nl') - - except Exception as e: - print(f"An error occurred: {e}") \ No newline at end of file From cd2d9e0cdd6ddc886f9ec2f0b4590e44f361e751 Mon Sep 17 00:00:00 2001 From: saravahdatipour Date: Mon, 13 Jan 2025 11:04:40 +0100 Subject: [PATCH 7/9] remove unused CI --- .gitlab-ci.yml | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index d87aec8..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,27 +0,0 @@ -image: privacybydesign/node_yarn_python3:latest - -stages: - - build - -before_script: - - set -euxo pipefail - - git clone https://github.com/privacybydesign/pbdf-schememanager.git - - git clone https://github.com/privacybydesign/irma-demo-schememanager.git - - yarn install --frozen-lockfile - -build: - stage: build - artifacts: - # Disabling artifact expiry is not supported yet, so make - expire_in: 100 year - paths: - - nl/ - - en/ - - pbdf-schememanager/ - - irma-demo-schememanager/ - - script.js - - style.css - - index.json - script: - - yarn run build - - python3 update.py From 8a8db9dc8106e83ccc81a54519e2b6d322be7288 Mon Sep 17 00:00:00 2001 From: saravahdatipour Date: Mon, 13 Jan 2025 11:07:32 +0100 Subject: [PATCH 8/9] Accept all server names --- nginx.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nginx.conf b/nginx.conf index 12663a8..aefec62 100644 --- a/nginx.conf +++ b/nginx.conf @@ -1,6 +1,6 @@ server { listen 80; - server_name 127.0.0.1; + server_name _; root /var/www/html; index index.html; charset utf-8; From 92027456735c631acae544cfd2203bb50cf8006a Mon Sep 17 00:00:00 2001 From: saravahdatipour Date: Mon, 13 Jan 2025 11:28:48 +0100 Subject: [PATCH 9/9] Fix mime type error blocking css and js files --- nginx.conf | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/nginx.conf b/nginx.conf index aefec62..92911a2 100644 --- a/nginx.conf +++ b/nginx.conf @@ -12,4 +12,11 @@ server { try_files $uri $uri/ =404; add_header Content-Type "text/html; charset=utf-8"; } + location ~* \.(css|js|svg|png|jpg|jpeg|gif|ico|woff|woff2|ttf|eot)$ { + root /var/www/html; + try_files $uri =404; + access_log off; + expires max; + add_header Cache-Control "public"; + } } \ No newline at end of file