419 lines
11 KiB
TypeScript
419 lines
11 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/>.
|
|
*/
|
|
|
|
|
|
/**
|
|
*/
|
|
async function main(
|
|
args_raw : Array<string>
|
|
) : Promise<void>
|
|
{
|
|
// init
|
|
lib_plankton.log.conf_push(
|
|
[
|
|
lib_plankton.log.channel_make(
|
|
{
|
|
"kind": "stdout",
|
|
"data": {
|
|
"threshold": "notice",
|
|
// "format": "human_readable",
|
|
}
|
|
}
|
|
),
|
|
]
|
|
);
|
|
const language_codes : Array<string> = [
|
|
"deu",
|
|
"eng",
|
|
];
|
|
await (
|
|
Promise.all(
|
|
language_codes
|
|
.map(
|
|
language_code => (
|
|
lib_plankton.file.read(
|
|
lib_plankton.string.coin(
|
|
"data/localization/{{language_code}}.loc.json",
|
|
{
|
|
"language_code": language_code,
|
|
}
|
|
)
|
|
)
|
|
.then<any>(
|
|
content => (new Promise<any>(
|
|
(resolve, reject) => {
|
|
try {
|
|
resolve(JSON.parse(content));
|
|
}
|
|
catch (error) {
|
|
reject(error);
|
|
}
|
|
}
|
|
))
|
|
)
|
|
)
|
|
)
|
|
)
|
|
.then(
|
|
packages => lib_plankton.translate.initialize(
|
|
{
|
|
"verbosity": 1,
|
|
"packages": packages,
|
|
"order": language_codes,
|
|
"autopromote": false,
|
|
}
|
|
)
|
|
)
|
|
);
|
|
|
|
// args
|
|
const arg_handler : lib_plankton.args.class_handler = new lib_plankton.args.class_handler({
|
|
"action": lib_plankton.args.class_argument.positional({
|
|
"index": 0,
|
|
"type": lib_plankton.args.enum_type.string,
|
|
"mode": lib_plankton.args.enum_mode.replace,
|
|
"default": "serve",
|
|
"name": "action",
|
|
"info": lib_plankton.string.coin(
|
|
"{{description}}:\n{{options}}\n\t\t",
|
|
{
|
|
"description": lib_plankton.translate.get("help.args.action.options.serve"),
|
|
"options": (
|
|
[
|
|
{
|
|
"name": "serve",
|
|
"description": lib_plankton.translate.get("help.args.action.options.serve"),
|
|
},
|
|
{
|
|
"name": "api-doc",
|
|
"description": lib_plankton.translate.get("help.args.action.options.api_doc")
|
|
},
|
|
{
|
|
"name": "email-test",
|
|
"description": lib_plankton.translate.get("help.args.action.options.email_test")
|
|
},
|
|
{
|
|
"name": "expose-conf",
|
|
"description": lib_plankton.translate.get("help.args.action.options.expose_conf")
|
|
},
|
|
{
|
|
"name": "password-image",
|
|
"description": lib_plankton.translate.get("help.args.action.options.password_image")
|
|
},
|
|
{
|
|
"name": "export-authelia",
|
|
"description": lib_plankton.translate.get("help.args.action.options.export_authelia")
|
|
},
|
|
{
|
|
"name": "help",
|
|
"description": lib_plankton.translate.get("help.args.action.options.help")
|
|
},
|
|
]
|
|
.map(
|
|
entry => lib_plankton.string.coin(
|
|
"\t\t- {{name}}\n\t\t\t{{description}}\n",
|
|
{
|
|
"name": entry.name,
|
|
"description": entry.description,
|
|
}
|
|
)
|
|
)
|
|
.join("")
|
|
),
|
|
}
|
|
),
|
|
}),
|
|
"arg1": lib_plankton.args.class_argument.positional({
|
|
"index": 1,
|
|
"type": lib_plankton.args.enum_type.string,
|
|
"mode": lib_plankton.args.enum_mode.replace,
|
|
"default": null,
|
|
// "info": null,
|
|
"name": "arg1",
|
|
"hidden": true,
|
|
}),
|
|
"arg2": lib_plankton.args.class_argument.positional({
|
|
"index": 2,
|
|
"type": lib_plankton.args.enum_type.string,
|
|
"mode": lib_plankton.args.enum_mode.replace,
|
|
"default": null,
|
|
// "info": null,
|
|
"name": "arg2",
|
|
"hidden": true,
|
|
}),
|
|
"conf_path": lib_plankton.args.class_argument.volatile({
|
|
"indicators_long": ["conf_path"],
|
|
"indicators_short": ["c"],
|
|
"type": lib_plankton.args.enum_type.string,
|
|
"mode": lib_plankton.args.enum_mode.replace,
|
|
"default": "conf.json",
|
|
"info": lib_plankton.translate.get("help.args.conf_path.description"),
|
|
"name": "conf-path",
|
|
}),
|
|
"help": lib_plankton.args.class_argument.volatile({
|
|
"indicators_long": ["help"],
|
|
"indicators_short": ["h"],
|
|
"type": lib_plankton.args.enum_type.boolean,
|
|
"mode": lib_plankton.args.enum_mode.replace,
|
|
"default": false,
|
|
"info": lib_plankton.translate.get("help.args.help.description"),
|
|
"name": "help",
|
|
}),
|
|
});
|
|
const args : Record<string, any> = arg_handler.read(lib_plankton.args.enum_environment.cli, args_raw.join(" "));
|
|
|
|
// init
|
|
await _espe.conf.load(args["conf_path"]);
|
|
{
|
|
const language : (null | string) = _espe.conf.get().general.language;
|
|
if (language === null) {
|
|
// do nothing
|
|
}
|
|
else {
|
|
lib_plankton.translate.promote(language);
|
|
}
|
|
}
|
|
lib_plankton.log.conf_push(
|
|
_espe.conf.get().log.map(
|
|
log_output => lib_plankton.log.channel_make(
|
|
{
|
|
"kind": log_output.kind,
|
|
"data": log_output.data
|
|
}
|
|
)
|
|
)
|
|
);
|
|
|
|
// exec
|
|
if (args["help"] || (args["action"] === "help")) {
|
|
process.stdout.write(
|
|
arg_handler.generate_help(
|
|
{
|
|
"programname": "espe",
|
|
"description": "Espe | Backend",
|
|
"executable": "espe",
|
|
}
|
|
)
|
|
+
|
|
"\n"
|
|
);
|
|
}
|
|
else {
|
|
switch (args["action"]) {
|
|
default: {
|
|
process.stderr.write("invalid action: " + args["action"] + "\n");
|
|
break;
|
|
}
|
|
case "password-image": {
|
|
const input : (null | string) = args["arg1"];
|
|
if (input === null) {
|
|
throw (new Error("SYNTAX: password-image <password>"));
|
|
}
|
|
else {
|
|
const result : string = await _espe.helpers.bcrypt_compute(input);
|
|
process.stdout.write(result + "\n")
|
|
}
|
|
break;
|
|
}
|
|
case "expose-conf": {
|
|
process.stdout.write(
|
|
JSON.stringify(
|
|
_espe.conf.get(),
|
|
undefined,
|
|
"\t"
|
|
)
|
|
+
|
|
"\n"
|
|
);
|
|
break;
|
|
}
|
|
case "api-doc": {
|
|
lib_plankton.log.conf_push([]);
|
|
const rest_subject : lib_plankton.rest.type_rest = _espe.api.make();
|
|
lib_plankton.log.conf_pop();
|
|
process.stdout.write(
|
|
JSON.stringify(
|
|
lib_plankton.rest.to_oas(rest_subject),
|
|
undefined,
|
|
"\t"
|
|
)
|
|
);
|
|
break;
|
|
}
|
|
case "email-test": {
|
|
await _espe.helpers.email_send(
|
|
(
|
|
(args["arg1"] !== null)
|
|
? [args["arg1"]]
|
|
: (
|
|
(
|
|
_espe.conf.get().admins
|
|
.map(admin => admin.email_address)
|
|
.filter(x => (x !== null))
|
|
) as Array<string>
|
|
)
|
|
),
|
|
lib_plankton.string.coin(
|
|
"{{head}} | Test",
|
|
{
|
|
"head": _espe.conf.get().settings.organisation.name,
|
|
}
|
|
),
|
|
"This is a test e-mail"
|
|
);
|
|
break;
|
|
}
|
|
case "serve": {
|
|
// prepare database
|
|
await _espe.database.check();
|
|
|
|
await lib_plankton.session.setup(
|
|
{
|
|
"data_chest": (
|
|
_espe.conf.get().session_management.in_memory
|
|
? lib_plankton.storage.memory.implementation_chest<lib_plankton.session.type_session>({})
|
|
: lib_plankton.call.convey(
|
|
lib_plankton.storage.sql_table_common.chest(
|
|
{
|
|
"database_implementation": _espe.helpers.database_implementation(),
|
|
"table_name": "sessions",
|
|
"key_names": ["key"],
|
|
}
|
|
),
|
|
[
|
|
(core) => ({
|
|
"setup": (input) => core.setup(undefined),
|
|
"clear": () => core.clear(),
|
|
"write": (key, value) => core.write([key], {"data": JSON.stringify(value)}),
|
|
"delete": (key) => core.delete([key]),
|
|
"read": (key) => core.read([key]).then(row => JSON.parse(row["data"])),
|
|
// "search": (term) => core.search(term).then(() => []),
|
|
"search": (term) => Promise.reject(new Error("not implemented")),
|
|
}),
|
|
]
|
|
)
|
|
),
|
|
"default_lifetime": _espe.conf.get().session_management.lifetime,
|
|
}
|
|
);
|
|
|
|
// outputs
|
|
_espe.service.member.listen_change(
|
|
() => {
|
|
lib_plankton.log.info(
|
|
"member_change",
|
|
{
|
|
}
|
|
);
|
|
_espe.conf.get().outputs.forEach(
|
|
output_description => {
|
|
const procedure : (() => Promise<void>) = (
|
|
(() => {
|
|
switch (output_description.kind) {
|
|
default: {
|
|
lib_plankton.log.warning(
|
|
"output_kind_unhandled",
|
|
{
|
|
"description": output_description,
|
|
}
|
|
);
|
|
return (() => Promise.resolve<void>(undefined));
|
|
break;
|
|
}
|
|
case "authelia_file": {
|
|
return (() => _espe.service.member.output_authelia_file(output_description.data));
|
|
break;
|
|
}
|
|
case "http": {
|
|
return (() => _espe.service.member.output_http(output_description.data));
|
|
break;
|
|
}
|
|
case "arc": {
|
|
return (() => _espe.service.member.output_arc(output_description.data));
|
|
break;
|
|
}
|
|
}
|
|
}) ()
|
|
);
|
|
(
|
|
procedure()
|
|
.then(
|
|
() => {
|
|
}
|
|
)
|
|
.catch(
|
|
(error) => {
|
|
lib_plankton.log.warning(
|
|
"output_procedure_failed",
|
|
{
|
|
"error": String(error),
|
|
}
|
|
);
|
|
}
|
|
)
|
|
);
|
|
}
|
|
);
|
|
}
|
|
);
|
|
|
|
const rest_subject : lib_plankton.rest.type_rest = _espe.api.make();
|
|
const server : lib_plankton.server.type_subject = lib_plankton.server.make(
|
|
async (input, metadata) => {
|
|
const http_request : lib_plankton.http.type_request = lib_plankton.http.decode_request(input.toString());
|
|
const http_response : lib_plankton.http.type_response = await lib_plankton.rest.call(
|
|
rest_subject,
|
|
http_request,
|
|
{
|
|
"checklevel_restriction": lib_plankton.api.enum_checklevel.hard,
|
|
// "checklevel_input": lib_plankton.api.enum_checklevel.soft,
|
|
// "checklevel_output": lib_plankton.api.enum_checklevel.soft,
|
|
}
|
|
);
|
|
const output : string = lib_plankton.http.encode_response(http_response);
|
|
return output;
|
|
},
|
|
{
|
|
"host": _espe.conf.get().server.host,
|
|
"port": _espe.conf.get().server.port,
|
|
// DANGER! DANGER!
|
|
"threshold": 0.125,
|
|
}
|
|
);
|
|
|
|
lib_plankton.server.start(server);
|
|
break;
|
|
}
|
|
case "export-authelia": {
|
|
process.stdout.write(await _espe.service.member.export_authelia_user_file() + "\n");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
(
|
|
main(process.argv.slice(2))
|
|
.then(
|
|
() => {
|
|
}
|
|
)
|
|
.catch(
|
|
(error) => {
|
|
process.stderr.write(String(error) + "\n");
|
|
}
|
|
)
|
|
);
|