From 045330759bc3d4d69d8f37f96b95b628e24e934e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Wed, 21 Aug 2024 15:07:27 +0200 Subject: [PATCH] [mod] main --- source/main.ts | 247 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 167 insertions(+), 80 deletions(-) diff --git a/source/main.ts b/source/main.ts index bd68486..ee0515b 100644 --- a/source/main.ts +++ b/source/main.ts @@ -3,6 +3,7 @@ */ type type_conf = { server : { + host : string; port : int; }; authentication : { @@ -20,31 +21,35 @@ type type_conf = { type type_user_list_sparse = ( null | - Record< - string, - { - disabled ?: boolean; - displayname ?: string; - email ?: string; - groups ?: Array; - password : string; - } - > + { + users : Record< + string, + { + disabled ?: boolean; + displayname ?: string; + email ?: string; + groups ?: Array; + password : string; + } + >; + } ); /** */ -type type_user_list_complete = Record< - string, - { - disabled : boolean; - displayname : string; - email : string; - groups : Array; - password : string; - } ->; +type type_user_list_complete = { + users : Record< + string, + { + disabled : boolean; + displayname : string; + email : string; + groups : Array; + password : string; + } + >; +}; /** @@ -54,41 +59,65 @@ async function conf_get( ) : Promise { const raw : any = lib_plankton.json.decode(await lib_plankton.file.read(path));; - return { - "server": { - "port": ((raw["server"] ?? {})["port"] ?? 4466), - }, - "authentication": { - "timestamp_tolerance": (raw["authentication"]["timestamp_tolerance"] ?? 2.0), - "hash_salt": raw["authentication"]["hash_salt"], // required - }, - "authelia": { - "usersfile_path": ((raw["authelia"] ?? {})["usersfile_path"] ?? "/var/authelia/users.yaml"), - }, - }; + const version_fallback : int = 1; + if (! ("version" in raw)) { + lib_plankton.log.warning( + "conf_version_unspecified", + { + "assumed_version": version_fallback, + } + ); + } + else { + // do nothing + } + const version : int = (raw["version"] ?? version_fallback); + switch (version) { + default: { + throw (new Error("invalid version: " + version.toFixed(0))); + break; + } + case 1: { + return { + "server": { + "host": ((raw["server"] ?? {})["host"] ?? "::"), + "port": ((raw["server"] ?? {})["port"] ?? 7463), + }, + "authentication": { + "timestamp_tolerance": (raw["authentication"]["timestamp_tolerance"] ?? 2.0), + "hash_salt": raw["authentication"]["hash_salt"], // required + }, + "authelia": { + "usersfile_path": ((raw["authelia"] ?? {})["usersfile_path"] ?? "/var/authelia/users.yaml"), + }, + }; + break; + } + } } /** */ function encode_user_list( - user_list : type_user_list_sparse + user_list : (null | type_user_list_sparse) ) : string { let output : string = ""; - Object.entries(user_list ?? {}).forEach( + output += "users:\n"; + Object.entries((user_list === null) ? {} : user_list.users).forEach( ([key, value]) => { - output += (key + ":\n"); - output += (" " + "disabled: " + ((value.disabled ?? false) ? "true" : "false") + "\n"); - output += (" " + "displayname: " + (value.displayname ?? key) + "\n"); + output += (" " + key + ":\n"); + output += (" " + "disabled: " + ((value.disabled ?? false) ? "true" : "false") + "\n"); + output += (" " + "displayname: " + (value.displayname ?? key) + "\n"); if ("email" in value) { - output += (" " + "email: " + value.email + "\n"); + output += (" " + "email: " + value.email + "\n"); } else { // do nothing } - output += (" " + "groups: " + JSON.stringify(value.groups ?? []) + "\n"); - output += (" " + "password: " + value.password + "\n"); + output += (" " + "groups: " + JSON.stringify(value.groups ?? []) + "\n"); + output += (" " + "password: " + value.password + "\n"); } ); return output; @@ -228,42 +257,52 @@ async function main( "input_schema": () => ({ "nullable": true, "type": "object", - "additionalProperties": { - "nullable": false, - "type": "object", - "additionalProperties": false, - "properties": { - "disabled": { + "additionalProperties": false, + "properties": { + "users": { + "nullable": true, + "type": "object", + "additionalProperties": { "nullable": false, - "type": "boolean", + "type": "object", + "additionalProperties": false, + "properties": { + "disabled": { + "nullable": false, + "type": "boolean", + }, + "displayname": { + "nullable": false, + "type": "string", + }, + "email": { + "nullable": false, + "type": "string", + }, + "groups": { + "nullable": false, + "type": "array", + "items": { + "nullable": false, + "type": "string" + } + }, + "password": { + "nullable": false, + "type": "string", + }, + }, + "required": [ + "password", + ] }, - "displayname": { - "nullable": false, - "type": "string", - }, - "email": { - "nullable": false, - "type": "string", - }, - "groups": { - "nullable": false, - "type": "array", - "items": { - "nullable": false, - "type": "string" - } - }, - "password": { - "nullable": false, - "type": "string", - }, - }, - "required": [ - "password", - ] + "properties": {}, + "required": [], + } }, - "properties": {}, - "required": [], + "required": [ + "users" + ] }), "output_schema": () => ({ "nullable": true, @@ -272,6 +311,13 @@ async function main( const timestamp_local : float = lib_plankton.base.get_current_timestamp(); const timestamp_remote : float = parseFloat(stuff.query_parameters["timestamp"]); if (Math.abs(timestamp_local - timestamp_remote) > conf.authentication.timestamp_tolerance) { + lib_plankton.log.notice( + "restriction_access_denied_due_to_invalid_timestamp", + { + "timestamp_local": timestamp_local, + "timestamp_remote": timestamp_remote, + } + ); return false; } else { @@ -280,6 +326,14 @@ async function main( timestamp_remote.toFixed(0) + conf.authentication.hash_salt ); if (authhash_is !== authhash_shall) { + lib_plankton.log.notice( + "restriction_access_denied_due_to_mismatching_hashes", + { + "timestamp": timestamp_remote, + "authhash_is": authhash_is, + "authhash_shall": authhash_shall, + } + ); return false; } else { @@ -292,6 +346,11 @@ async function main( conf.authelia.usersfile_path, encode_user_list(stuff.input) ); + lib_plankton.log.notice( + "userdata_updated", + { + } + ); return Promise.resolve({ "status_code": 200, "data": null @@ -302,15 +361,43 @@ async function main( } const server : lib_plankton.server.type_subject = lib_plankton.server.make( - conf.server.port, async (input, metadata) => { - const http_request : lib_plankton.http.type_request = lib_plankton.http.decode_request(input); - const http_response : lib_plankton.http.type_response = await lib_plankton.rest.call( - rest_subject, - http_request + const http_request : lib_plankton.http.type_request = lib_plankton.http.decode_request(input.toString()); + return ( + lib_plankton.rest.call( + rest_subject, + http_request + ) + .catch( + (error) => { + lib_plankton.log.error( + "server_request_processing_failed", + { + "error": String(error), + } + ); + return Promise.resolve( + { + "version": "HTTP/1.1", + "status_code": 500, + "headers": {}, + // @ts-ignore + "body": Buffer.from(""), + } + ); + } + ) + .then( + (http_response) => { + const output : string = lib_plankton.http.encode_response(http_response); + return Promise.resolve(output); + } + ) ); - const output : string = lib_plankton.http.encode_response(http_response); - return output; + }, + { + "host": conf.server.host, + "port": conf.server.port, } );