backend/source/conf.ts
2024-08-28 06:15:01 +02:00

565 lines
13 KiB
TypeScript

/*
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
Copyright (C) 2024 Christian Fraß
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see
<https://www.gnu.org/licenses/>.
*/
namespace _espe.conf
{
/**
*/
type type_log_threshold = (
"debug"
|
"info"
|
"notice"
|
"warning"
|
"error"
);
/**
*/
type type_log_format = (
"jsonl"
|
"human_readable"
);
/**
*/
export type type_conf = {
general : {
language : (null | string);
verification_secret : (null | string);
};
log : Array<
{
kind : "stdout";
data : {
threshold : type_log_threshold;
};
}
|
{
kind : "file";
data : {
threshold : type_log_threshold;
path : string;
};
}
|
{
kind : "email";
data : {
threshold : type_log_threshold;
smtp_credentials : {
host : string;
port : int;
username : string;
password : string;
};
sender : string;
receivers : Array<string>;
};
}
>;
server : {
host : string;
port : int;
path_base : string;
};
database : (
{
kind : "sqlite";
data : {
path : string;
};
}
|
{
kind : "postgresql";
data : {
host : string;
port ?: int;
username : string;
password : string;
schema : string;
};
}
);
email_sending : (
{
kind : "regular";
data : {
smtp_credentials : _espe.helpers.type_smtp_credentials;
sender : string;
};
}
|
{
kind : "redirect";
data : {
smtp_credentials : _espe.helpers.type_smtp_credentials;
sender : string;
target : string;
};
}
|
{
kind : "console";
data : {
};
}
|
{
kind : "drop";
data : {
};
}
);
session_management : {
in_memory : boolean;
drop_all_at_start : boolean;
lifetime : int;
};
settings : {
organisation : {
name : string;
domain : string;
};
misc : {
prefix_for_veiled_email_addresses : string;
facultative_membership_number : boolean;
auto_register : boolean;
};
summon_email : {
remark : string;
};
password_policy : {
minimum_length : (null | int);
maximum_length : (null | int);
must_contain_letter : boolean;
must_contain_number : boolean;
must_contain_special_character : boolean;
};
password_change : {
cooldown_time : int;
};
name_index : {
veil : boolean;
salt : (null | string);
};
connections : {
frontend_url_base : (null | string);
login_url : (null | string);
};
};
// TODO: evtl. in Datenbank verlagern
admins : Array<
{
name : string;
password_image : string;
email_address : (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<string,string>;
};
}
|
{
kind : "arc";
data : {
http_scheme : ("http" | "https");
http_host : string;
http_port : int;
hash_salt : string;
}
}
>;
};
/**
*/
var _data : (null | type_conf) = null;
/**
*/
export function inject(
conf_raw : any
) : void
{
const version : int = (conf_raw["version"] ?? 4);
_data = {
"general": (
((node_general) => ({
"language": (node_general["language"] ?? null),
"verification_secret": (node_general["verification_secret"] ?? null),
})) (conf_raw["general"] ?? {})
),
"log": (
(() => {
switch (version) {
case 1: {
return [
{
"kind": "stdout",
"data": {
"threshold": ((conf_raw["general"] ?? {})["verbosity"] ?? "notice"),
}
},
];
break;
}
case 2:
case 3:
case 4: {
const node_log = (
conf_raw["log"]
??
[
{
"kind": "stdout",
"data": {
}
},
]
);
return (
node_log.map(
(node_log_entry : any) => ({
"kind": node_log_entry["kind"],
"data": Object.assign(
{
"format": "human_readable",
"threshold": "notice",
},
(node_log_entry["data"] ?? {})
)
})
)
);
break;
}
}
}) ()
),
"server": (
((node_server) => ({
"host": (() => {
switch (version) {
case 1:
case 2:
case 3: {
return "::";
break;
}
case 4: {
return (node_server["host"] ?? "::");
break
}
}
}) (),
"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": (() => {
switch (version) {
case 1:
case 2: {
const node_output = (conf_raw["output"] ?? {});
return (
("authelia" in node_output)
?
[
{
"kind": "authelia_file",
"data": {
"path": node_output["authelia"],
}
}
]
:
[
]
);
break;
}
case 3: {
return (conf_raw["outputs"] ?? []);
break;
}
case 4: {
const node_outputs = (conf_raw["outputs"] ?? []);
return node_outputs.map(
(output_description : {kind : string; data : any;}) => {
const kind : string = output_description["kind"];
const node_options_data_raw = (output_description["data"] ?? {});
switch (kind) {
case "authelia_file": {
return {
"kind": kind,
"data": {
"path": (node_options_data_raw["path"] ?? "/var/authelia/users.yaml"),
}
};
break;
}
case "http": {
return {
"kind": kind,
"data": {
"scheme": (node_options_data_raw["scheme"] ?? "http"),
"host": (node_options_data_raw["host"] ?? "localhost"),
"path": (node_options_data_raw["path"] ?? ""),
"method": (node_options_data_raw["method"] ?? "post"),
"query": (node_options_data_raw["query"] ?? null),
"headers": (node_options_data_raw["headers"] ?? {"Content-Type": "application/json"}),
},
};
break;
}
case "arc": {
return {
"kind": kind,
"data": {
"http_scheme": (node_options_data_raw["scheme"] ?? "http"),
"http_host": (node_options_data_raw["http_host"] ?? "localhost"),
"http_port": (node_options_data_raw["http_port"] ?? 7463),
"hash_salt": node_options_data_raw["hash_salt"],
}
};
break;
}
default: {
throw (new Error("unhandled"));
break;
}
}
}
);
break;
}
}
}) (),
};
}
/**
* @todo mandatory fields
*/
export async function load(
path : string
) : Promise<void>
{
let conf_raw : any;
if (! (await lib_plankton.file.exists(path))) {
// return Promise.reject<void>(new Error("configuration file not found: " + path + "; using fallback"));
conf_raw = {};
}
else {
try {
conf_raw = lib_plankton.json.decode(await lib_plankton.file.read(path));
}
catch (error) {
conf_raw = null;
}
}
if (conf_raw === null) {
return Promise.reject<void>("configuration file could not be read");
}
else {
inject(conf_raw);
// process.stderr.write(JSON.stringify(_data, undefined, "\t"));
return Promise.resolve<void>(undefined);
}
}
/**
*/
export function get(
) : type_conf
{
if (_data === null) {
throw (new Error("conf not loaded yet"));
}
else {
return _data;
}
}
}