gerd.members-area: adds member website on <domain>/members
This commit is contained in:
parent
0ca49ba790
commit
23faf44b39
4 changed files with 153 additions and 6 deletions
|
@ -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
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -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!
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
116
machines/gerd/services/member-website/app.py
Executable file
116
machines/gerd/services/member-website/app.py
Executable 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)
|
27
machines/gerd/services/member-website/default.nix
Normal file
27
machines/gerd/services/member-website/default.nix
Normal 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}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue