gerd.members-area: adds member website on <domain>/members

This commit is contained in:
eyjhb 2024-08-13 13:47:14 +02:00
parent 0ca49ba790
commit 23faf44b39
No known key found for this signature in database
GPG key ID: 609F508E3239F920
4 changed files with 153 additions and 6 deletions

View file

@ -14,6 +14,8 @@
./gerd/services/murmur.nix ./gerd/services/murmur.nix
./gerd/services/hedgedoc.nix ./gerd/services/hedgedoc.nix
./gerd/services/member-website
# ./gerd/services/owncast.nix # ./gerd/services/owncast.nix
]; ];

View file

@ -76,20 +76,22 @@ let
error_page 401 =302 https://auth.fricloud.dk/?rd=$target_url; error_page 401 =302 https://auth.fricloud.dk/?rd=$target_url;
''; '';
in { in {
mine.shared.lib.authelia.mkProtectedWebsite = virtualHostConfig: lib.recursiveUpdate { mine.shared.lib.authelia.mkProtectedWebsite = { vhostConfig, endpoint ? "/" }: lib.recursiveUpdate {
forceSSL = true; forceSSL = true;
enableACME = true; enableACME = true;
extraConfig = "include ${autheliaLocation};"; extraConfig = "include ${autheliaLocation};";
locations."/" = { locations."${endpoint}" = {
extraConfig = "include ${autheliaRequest};"; extraConfig = "include ${autheliaRequest};";
}; };
} virtualHostConfig; } vhostConfig;
services.nginx.virtualHosts."test.fricloud.dk" = config.mine.shared.lib.authelia.mkProtectedWebsite { services.nginx.virtualHosts."test.fricloud.dk" = config.mine.shared.lib.authelia.mkProtectedWebsite {
vhostConfig = {
locations."/".root = pkgs.writeTextDir "index.html" '' locations."/".root = pkgs.writeTextDir "index.html" ''
ACCESS GRANTED! ACCESS GRANTED!
''; '';
}; };
};
} }

View file

@ -0,0 +1,116 @@
#!/usr/bin/env nix-shell
#!nix-shell --pure -i python3 -p "python3.withPackages (ps: with ps; [ flask ])"
from typing import Any
from flask import Flask, request
from flask import render_template, render_template_string
import argparse
import logging
import json
import sys
logging.basicConfig()
logger = logging.getLogger(__name__)
app = Flask(__name__)
services_data: dict[str, Any] = {}
tmpl_index = """
<!doctype html>
<title>Members Area</title>
<b>Welcome to the members area {% if user.name %} {{ user.name }} {% else %} {{ user.username }} {% endif %}!</b>
<h1>Services</h1>
{% for name, info in services.items() %}
<h3>{{ info.name }}</h3>
{{ info.description }}
<br>
<a href="{{ info.url }}">{{ info.url }}</a>
<pre>
Package name: {{ info.package.name }}
Package version: {{ info.package.version }}
Package homepage: {{ info.package.meta.homepage }}
License: <a href="{{ info.package.meta.license.url }}">{{ info.package.meta.license.spdxId }} ({{ info.package.meta.license.shortName }})</a>
Unfree: {{ info.package.meta.unfree }}
<pre>
<hr>
{% endfor %}
"""
def extract_secrets() -> dict[str, str]:
new_args = {}
# read all secrets
for service in services_data.values():
for k, v in service.get("secrets", {}).items():
try:
fcontent = open(v, "r").read()
except Exception as e:
logger.exception("unable to open secret file", e)
continue
isEnv: bool = False
if v.endswith("env"):
isEnv = True
if not isEnv:
new_args[k.upper()] = fcontent
continue
# parse env file
for line in fcontent.splitlines():
line = line.strip()
if not line:
continue
envkey, envvalue = line.split("=", maxsplit=1)
if envvalue[0] == '"' or envvalue[1] == "'":
envvalue = envvalue[1:-1]
new_args[envkey.upper()] = envvalue
return new_args
@app.route("/")
def index():
# extract user information
user_info = {
"username": request.headers.get("Remote-User"),
"name": request.headers.get("Remote-Name"),
"groups": request.headers.get("Remote-Groups"),
"email": request.headers.get("Remote-Email"),
}
tmpl_firstpass = render_template_string(
tmpl_index,
services=services_data,
user=user_info,
)
return render_template_string(
tmpl_firstpass,
user=user_info,
secrets=extract_secrets(),
)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"--debug",
type=bool,
action=argparse.BooleanOptionalAction,
default=False,
)
parser.add_argument("--listen", type=str, default="127.0.0.1")
parser.add_argument("--port", type=int, default=5000)
parser.add_argument("--meta-json", type=str, required=True)
args = parser.parse_args()
if args.debug:
logger.setLevel(logging.DEBUG)
services_data = json.loads(open(args.meta_json, "r").read())
app.run(host=args.listen, port=args.port, debug=args.debug)

View file

@ -0,0 +1,27 @@
{ config, pkgs, ... }:
let
urlpath = "/members";
metaJSONFile = (pkgs.formats.json {}).generate "meta-service-info.json" config.mine.shared.meta;
port = 5050;
in {
systemd.services.website-member = {
description = "members area website";
wantedBy = [ "multi-user.target" ];
after = [ "networking.target" ];
serviceConfig = {
ExecStart = let
pythonEnv = pkgs.python3.withPackages(ps: with ps; [ flask ]);
in "${pythonEnv}/bin/python ${./app.py} --port ${builtins.toString port} --meta-json ${metaJSONFile}";
Restart = "always";
};
};
services.nginx.virtualHosts."${config.mine.shared.settings.domain}" = config.mine.shared.lib.authelia.mkProtectedWebsite {
endpoint = urlpath;
vhostConfig.locations."${urlpath}" = {
extraConfig = "rewrite ^${urlpath}(.*)$ /$1 break;";
proxyPass = "http://localhost:${builtins.toString port}";
};
};
}