refactor: dynamically generate website
Some checks failed
Build Docker images / docker (push) Failing after 13m58s

This commit is contained in:
DevMiner 2023-12-01 14:25:05 +01:00
parent 5e9ed59e25
commit 56baffb242
Signed by: DevMiner
GPG key ID: 251708456D625398
13 changed files with 241 additions and 40 deletions

12
.editorconfig Normal file
View file

@ -0,0 +1,12 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

View file

@ -12,7 +12,7 @@ on:
env:
REGISTRY: ghcr.io
IMAGE_NAME: "thedevminertv/ca-list"
IMAGE_NAME: "thedevminertv/ca-cert-list"
jobs:
docker:

1
.gitignore vendored
View file

@ -1 +0,0 @@
*.override.yml

View file

@ -1,4 +1,8 @@
FROM ghcr.io/thedevminertv/gostatic:1.2.3
FROM ghcr.io/thedevminertv/gostatic:1.2.5
CMD ["-compress-level", "2"]
COPY ./public /static
RUN apk add --no-cache openssl coreutils
COPY --chown=app:app ./entrypoint.sh /entrypoint.sh
COPY --chown=app:app ./generate.sh /generate.sh
COPY ./public /static

18
LICENSE Normal file
View file

@ -0,0 +1,18 @@
Copyright 2023 DevMiner <devminer@devminer.xyz>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the “Software”), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

35
README.md Normal file
View file

@ -0,0 +1,35 @@
# CA-Cert List
> This application provides a simple list to download your own root CA certificates. Useful for people that self-sign their own certificates.
![Screenshot](./_docs/Example-Page.png)
## Usage
Create your own Dockerfile which derives from `ghcr.io/thedevminertv/ca-cert-list:latest` and add your own certificates to `/certs`.
The application will bind to port 80.
The application expects the `/certs` folder to contain the following files:
- `<Certificate name>` [Folder]
- `cert.crt` [File]: Your certificate
- `description.txt`: A description of your certificate
Example Dockerfile:
```dockerfile
FROM ghcr.io/thedevminertv/ca-cert-list:latest
COPY ./certs /certs
```
Build and run the container:
```bash
docker build -t my-ca-cert-list .
docker run -d -p 80:80 my-ca-cert-list
```
## License
This project is licensed under the MIT License. See [LICENSE](./LICENSE) for more information.

BIN
_docs/Example-Page.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View file

@ -1,10 +0,0 @@
version: '3'
services:
certs:
build: .
labels:
- "traefik.enable=true"
- "traefik.http.services.certs.loadbalancer.server.port=80"
- "traefik.http.routers.certs.rule=Host(`certs.i.devminer.xyz`)"
- "traefik.http.routers.certs.service=certs"

9
entrypoint.sh Normal file
View file

@ -0,0 +1,9 @@
#!/bin/sh
set -e
./generate.sh
chown -R app:app /static
su app -c "/bin/gostatic --files /static --addr :80 $*"

84
generate.sh Normal file
View file

@ -0,0 +1,84 @@
#!/bin/sh
mkdir -p /static/certificates
CERT_HTML=$(
cat <<EOF
<li>
<a href="/certificates/{{FILENAME}}" download>
<h2>{{NAME}}</h2>
<span>{{DESCRIPTION}}</span>
<div class="chips">
<div class="chip">
<span>
<span>Expiry</span>
</span>
<span class="local-date-time" data-timestamp="{{EXPIRY_TIMESTAMP}}">{{EXPIRY}}</span>
</div>
<div class="chip">
<span>
<span>SHA256</span>
</span>
<span>
<code>{{SHA256}}</code>
</span>
</div>
<div class="chip">
<span>
<span>SHA1</span>
</span>
<span>
<code>{{SHA1}}</code>
</span>
</div>
<div class="chip">
<span>
<span>MD5</span>
</span>
<span>
<code>{{MD5}}</code>
</span>
</div>
</div>
</a>
</li>
EOF
)
set -e
HTML=""
for CERT in /certs/*; do
file="$CERT/cert.crt"
certname=$(basename "$CERT")
description=$(cat "$CERT/description.txt")
expire_time=$(openssl x509 -enddate -noout -in "$file" | cut -d= -f2)
expire_epoch=$(date -d "$expire_time" +%s)
sha256=$(openssl x509 -in "$file" -noout -sha256 -fingerprint | cut -d= -f2)
sha1=$(openssl x509 -in "$file" -noout -sha1 -fingerprint | cut -d= -f2)
md5=$(openssl x509 -in "$file" -noout -md5 -fingerprint | cut -d= -f2)
component=$(
echo $CERT_HTML |
sed "s|{{NAME}}|$certname|g" |
sed "s|{{FILENAME}}|${certname}.crt|g" |
sed "s|{{DESCRIPTION}}|$description|g" |
sed "s|{{EXPIRY_TIMESTAMP}}|$expire_epoch|g" |
sed "s|{{EXPIRY}}|$expire_time|g" |
sed "s|{{SHA256}}|$sha256|g" |
sed "s|{{SHA1}}|$sha1|g" |
sed "s|{{MD5}}|$md5|g"
)
HTML="$HTML$component"
cp "$file" "/static/certificates/$certname.crt"
done
# replace html
sed -i "s|{{HTML}}|$HTML|g" /static/index.html

Binary file not shown.

Binary file not shown.

View file

@ -6,6 +6,13 @@
<title>Certificates / Zertifikate</title>
<style>
@font-face {
font-family: "Monaspace Neon";
src: url(/MonaspaceNeon-Light.woff) format("woff"),
url(/MonaspaceNeon-Light.otf) format("opentype");
font-weight: 300;
}
* {
margin: 0;
padding: 0;
@ -27,8 +34,19 @@
margin: 2rem;
}
code {
font-family: "Monaspace Neon", "Courier New", Courier, monospace;
line-height: 1;
font-size: 13px;
}
span:has(code) {
display: flex;
align-items: center;
}
body {
max-width: 768px;
max-width: 840px;
margin: 0 auto;
}
@ -38,13 +56,13 @@
}
ul > li > a {
padding: 1.25rem 1.25rem;
padding: 1rem 1.25rem 1.25rem 1.25rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
color: #ff00ff;
color: #eee;
text-decoration: none;
border: #272727 1px solid;
@ -52,46 +70,78 @@
transition: border 0.2s ease-in-out;
}
.chip {
display: inline-block;
color: #eee;
ul > li > a:hover {
border: #ff00ff 1px solid;
}
.chip > span:first-child {
padding: 0.125rem 0.5rem;
ul > li > a > :first-child {
color: #ff00ff;
font-size: 1.25rem;
font-weight: bold;
}
.chips {
display: flex;
flex-wrap: wrap;
gap: 0.25rem;
}
.chip {
display: inline-flex;
align-items: center;
color: #eee;
max-width: 100%;
overflow: hidden;
overflow-wrap: anywhere;
pointer-events: stroke;
}
.chip > * {
align-self: stretch;
display: flex;
padding: 0.25rem 0.5rem;
}
.chip > :first-child {
min-width: fit-content;
background-color: #353535;
border-radius: 0.25rem 0 0 0.25rem;
}
.chip > span:last-child {
padding: 0.125rem 0.5rem;
.chip > :first-child > * {
margin: auto;
line-height: 1;
}
.chip > :last-child {
line-height: 1;
background-color: #222222;
border-radius: 0 0.25rem 0.25rem 0;
}
ul > li > a:hover {
border: #ff00ff 1px solid;
}
</style>
</head>
<body>
<h1>Certificates / Zertifikate</h1>
<h1>Certificates</h1>
<ul>
<li>
<a href="/certificates/root.crt" download>
<span> Root CA / Wurzel-Zertifizierungsstelle </span>
<div class="chip">
<span>Expiry date / Auslaufdatum</span><span>27.09.2033</span>
</div>
</a>
</li>
{{HTML}}
</ul>
<script>
(() => {
const els = document.querySelectorAll(".local-date-time");
for (const el of els) {
try {
el.innerText = new Date(
+el.dataset.timestamp * 1000
).toLocaleDateString();
} catch {}
}
})();
</script>
</body>
</html>