From 2135dfff1f369c5ca5db37bc7617e8be96cdca1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Sun, 18 Aug 2024 13:54:58 +0200 Subject: [PATCH] [int] --- source/conf.ts | 249 ++++++++++++++++++++++++++++++++++++-- source/main.ts | 39 ++++-- source/services/member.ts | 150 ++++++++++++++++++++++- tools/build | 1 + 4 files changed, 409 insertions(+), 30 deletions(-) diff --git a/source/conf.ts b/source/conf.ts index cab001d..26520c6 100644 --- a/source/conf.ts +++ b/source/conf.ts @@ -176,9 +176,35 @@ namespace _espe.conf email_address : (null | string); } >; - output : { - authelia : (null | string); - }; + outputs : Array< + { + kind : "authelia_file"; + data : { + path : string; + } + } + | + { + kind : "http"; + data : { + scheme : ("http" | "https"); + host : string; + path : string; + method : ("get" | "post" | "put" | "patch" | "delete" | "head" | "options"); + query : (null | string); + headers : Record; + }; + } + | + { + kind : "authelia_call"; + data : { + http_scheme : ("http" | "https"); + http_host : string; + hash_salt : string; + } + } + >; }; @@ -355,10 +381,20 @@ namespace _espe.conf })) (conf_raw["settings"] ?? {}) ), "admins": (conf_raw["admins"] ?? []), - "output": ( - ((node_session_output) => ({ - "authelia": (node_session_output["authelia"] ?? null), - })) (conf_raw["output"] ?? {}) + "outputs": ( + ((node_output) => ( + ("authelia" in node_output) + ? [ + { + "kind": "authelia_file", + "data": { + "path": node_output["authelia"], + } + } + ] + : [ + ] + )) (conf_raw["output"] ?? {}) ), }; break; @@ -540,14 +576,205 @@ namespace _espe.conf })) (conf_raw["settings"] ?? {}) ), "admins": (conf_raw["admins"] ?? []), - "output": ( - ((node_session_output) => ({ - "authelia": (node_session_output["authelia"] ?? null), - })) (conf_raw["output"] ?? {}) + "outputs": ( + ((node_output) => ( + ("authelia" in node_output) + ? [ + { + "kind": "authelia_file", + "data": { + "path": node_output["authelia"], + } + } + ] + : [ + ] + )) (conf_raw["output"] ?? {}) ), }; break; } + case 3: { + _data = { + "general": ( + ((node_general) => ({ + "language": (node_general["language"] ?? null), + "verification_secret": (node_general["verification_secret"] ?? null), + })) (conf_raw["general"] ?? {}) + ), + "log": ( + ((node_log) => node_log.map( + (node_log_entry : any) => ({ + "kind": node_log_entry["kind"], + "data": Object.assign( + { + "format": "human_readable", + "threshold": "notice", + }, + (node_log_entry["data"] ?? {}) + ) + }) + )) ( + conf_raw["log"] + ?? + [ + { + "kind": "console", + "data": { + } + }, + ] + ) + ), + "server": ( + ((node_server) => ({ + "port": (node_server["port"] ?? 4916), + "path_base": (node_server["path_base"] ?? ""), + })) (conf_raw["server"] ?? {}) + ), + "database": ( + ((node_database) => { + const kind : string = (node_database["kind"] ?? "sqlite"); + const node_database_data_raw = (node_database["data"] ?? {}); + switch (kind) { + case "sqlite": { + return { + "kind": kind, + "data": { + "path": (node_database_data_raw["path"] ?? "data.sqlite"), + } + }; + break; + } + case "postgresql": { + return { + "kind": kind, + "data": node_database_data_raw, + }; + break; + } + default: { + throw (new Error("unhandled")); + break; + } + } + }) (conf_raw["database"] ?? {}) + ), + "email_sending": ( + ((node_email_sending) => { + const kind : string = (node_email_sending["kind"] ?? "console"); + const data_raw = (node_email_sending["data"] ?? {}); + switch (kind) { + case "regular": { + return { + "kind": kind, + "data": { + "smtp_credentials": (data_raw["smtp_credentials"] ?? null), + "sender": data_raw["sender"], + } + }; + break; + } + case "redirect": { + return { + "kind": kind, + "data": { + "smtp_credentials": (data_raw["smtp_credentials"] ?? null), + "sender": data_raw["sender"], + "target": data_raw["target"], + } + }; + break; + } + case "console": { + return { + "kind": kind, + "data": { + } + }; + break; + } + case "drop": { + return { + "kind": kind, + "data": { + } + }; + break; + } + default: { + throw (new Error("unhandled")); + break; + } + } + }) (conf_raw["email_sending"] ?? {}) + ), + "session_management": ( + ((node_session_management) => ({ + "in_memory": (node_session_management["in_memory"] ?? true), + "drop_all_at_start": (node_session_management["drop_all_at_start"] ?? true), + "lifetime": (node_session_management["lifetime"] ?? 900), + })) (conf_raw["session_management"] ?? {}) + ), + "settings": ( + ((node_settings) => ({ + "organisation": { + "name": ((node_settings["organisation"] ?? {})["name"] ?? "Example Orginsation"), // TODO: mandatory? + "domain": ((node_settings["organisation"] ?? {})["domain"] ?? "example.org"), // TODO: mandatory? + }, + "misc": ( + ((node_settings_misc) => ({ + "prefix_for_veiled_email_addresses": (node_settings_misc["prefix_for_veiled_email_addresses"] ?? "member-"), + "facultative_membership_number": (node_settings_misc["facultative_membership_number"] ?? false), + "auto_register": (node_settings_misc["auto_register"] ?? false), + })) (node_settings["misc"] ?? {}) + ), + "summon_email": ( + ((node_settings_summon_email) => ({ + "remark": (node_settings_summon_email["remark"] ?? null), + })) (node_settings["summon_email"] ?? {}) + ), + "password_policy": ( + ((node_settings_password_policy) => ({ + "minimum_length": ( + ("minimum_length" in node_settings_password_policy) + ? node_settings_password_policy["minimum_length"] + : 8 + ), + "maximum_length": ( + ("maximum_length" in node_settings_password_policy) + ? node_settings_password_policy["maximum_length"] + : 240 + ), + "must_contain_letter": (node_settings_password_policy["must_contain_letter"] ?? true), + "must_contain_number": (node_settings_password_policy["must_contain_number"] ?? true), + "must_contain_special_character": (node_settings_password_policy["must_contain_special_character"] ?? true), + })) (node_settings["password_policy"] ?? {}) + ), + "password_change": ( + ((node_settings_password_change) => ({ + "cooldown_time": (node_settings_password_change["cooldown_time"] ?? 86400), + })) (node_settings["password_change"] ?? {}) + ), + "name_index": ( + ((node_settings_password_policy) => ({ + "veil": (node_settings_password_policy["veil"] ?? true), + "salt": (node_settings_password_policy["salt"] ?? ""), + })) (node_settings["name_index"] ?? {}) + ), + "connections": ( + ((node_settings_connections) => ({ + "frontend_url_base": (node_settings_connections["frontend_url_base"] ?? null), + "login_url": (node_settings_connections["login_url"] ?? null), + })) (node_settings["connections"] ?? {}) + ), + })) (conf_raw["settings"] ?? {}) + ), + "admins": (conf_raw["admins"] ?? []), + "outputs": (conf_raw["outputs"] ?? []), + }; + break; + } default: { throw (new Error("invalid conf version: " + conf_raw["version"])); break; diff --git a/source/main.ts b/source/main.ts index 898d7b1..52cbf95 100644 --- a/source/main.ts +++ b/source/main.ts @@ -317,20 +317,33 @@ async function main( ); // outputs { - if (_espe.conf.get().output.authelia === null) { - // do nothing - } - else { - _espe.service.member.listen_change( - async () => { - const authelia_export : string = await _espe.service.member.export_authelia_user_file(); - lib_plankton.file.write( - _espe.conf.get().output.authelia, - authelia_export - ); + _espe.conf.get().outputs.forEach( + output_description => { + switch (output_description.kind) { + default: { + lib_plankton.log.warning( + "output_kind_unhandled", + { + "description": output_description, + } + ); + break; + } + case "authelia_file": { + _espe.service.member.output_authelia_file(output_description.data); + break; + } + case "http": { + _espe.service.member.output_http(output_description.data); + break; + } + case "authelia_call": { + _espe.service.member.output_authelia_call(output_description.data); + break; + } } - ); - } + } + ); } const rest_subject : lib_plankton.rest.type_rest = _espe.api.make(); diff --git a/source/services/member.ts b/source/services/member.ts index 15b5354..1e272c8 100644 --- a/source/services/member.ts +++ b/source/services/member.ts @@ -253,7 +253,7 @@ namespace _espe.service.member /** * gibt die vollständigen Daten aller Mitglieder aus */ - async function dump( + export async function dump( ) : Promise< Array< { @@ -776,11 +776,11 @@ namespace _espe.service.member /** * @todo check validity (e.g. username characters) */ - export async function export_authelia_user_file( + export async function export_authelia_user_data( options : { custom_data ?: (null | Array<_espe.type.member_object>); } = {} - ) : Promise + ) : Promise { options = Object.assign( { @@ -789,8 +789,6 @@ namespace _espe.service.member options ); - const nm_yaml = require("yaml"); - type type_entry = { disabled : boolean; displayname : string; @@ -842,10 +840,150 @@ namespace _espe.service.member ), Object.fromEntries, (x : Record) => ({"users": x}), - (x : {users : Record}) => nm_yaml.stringify(x), ] ); } + + /** + */ + export async function export_authelia_user_file( + options : { + custom_data ?: (null | Array<_espe.type.member_object>); + } = {} + ) : Promise + { + options = Object.assign( + { + "custom_data": null, + }, + options + ); + + const nm_yaml = require("yaml"); + return nm_yaml.stringify(await export_authelia_user_data(options)); + } + + + /** + */ + export async function output_authelia_file( + output_parameters : { + path : string; + } + ) : Promise + { + await lib_plankton.file.write( + output_parameters.path, + await _espe.service.member.export_authelia_user_file() + ); + } + + + /** + */ + export async function output_http( + output_parameters : { + scheme : ("http" | "https"); + host : string; + path : string; + method : ("get" | "post" | "put" | "patch" | "delete" | "head" | "options"); + query : (null | string); + headers : Record; + } + ) : Promise + { + const http_request : lib_plankton.http.type_request = { + "scheme": output_parameters.scheme, + "host": output_parameters.host, + "path": output_parameters.path, + "version": "HTTP/1.1", + "method": ( + ( + { + "get": lib_plankton.http.enum_method.get, + "post": lib_plankton.http.enum_method.post, + "put": lib_plankton.http.enum_method.put, + "patch": lib_plankton.http.enum_method.patch, + "delete": lib_plankton.http.enum_method.delete, + "head": lib_plankton.http.enum_method.head, + "options": lib_plankton.http.enum_method.options, + }[output_parameters.method] + ) + ?? + lib_plankton.http.enum_method.post + ), + "query": output_parameters.query, + "headers": output_parameters.headers, + "body": lib_plankton.json.encode(await _espe.service.member.dump()), + }; + const http_response : lib_plankton.http.type_response = await lib_plankton.http.call( + http_request + ); + if (! ((http_response.status_code >= 200) && (http_response.status_code < 400))) { + lib_plankton.log.warning( + "output_http_failed", + { + "http_request": http_request, + "http_response_status_code": http_response.status_code, + } + ); + } + else { + // do nothing + } + } + + + /** + */ + export async function output_authelia_call( + output_parameters : { + http_scheme : ("http" | "https"); + http_host : string; + hash_salt : string; + } + ) : Promise + { + const timestamp : float = lib_plankton.base.get_current_timestamp(); + const auth : string = lib_plankton.sha256.get( + timestamp.toFixed(0) + + + output_parameters.hash_salt + ); + const http_request : lib_plankton.http.type_request = { + "scheme": output_parameters.http_scheme, + "host": output_parameters.http_host, + "path": "/users/set", + "version": "HTTP/1.1", + "method": lib_plankton.http.enum_method.put, + "query": lib_plankton.string.coin( + "?timestamp={{timestamp}}&auth={{auth}}", + { + "timestamp": timestamp.toFixed(0), + "auth": auth, + } + ), + "headers": { + "Content-Type": "application/json", + }, + "body": lib_plankton.json.encode(await _espe.service.member.export_authelia_user_data()), + }; + const http_response : lib_plankton.http.type_response = await lib_plankton.http.call( + http_request + ); + if (http_response.status_code !== 200) { + lib_plankton.log.warning( + "output_authelia_callback_failed", + { + "http_response_status_code": http_response.status_code, + } + ); + } + else { + // do nothing + } + } + } diff --git a/tools/build b/tools/build index 95fe086..bbb646b 100755 --- a/tools/build +++ b/tools/build @@ -52,3 +52,4 @@ def main(): main() +