[mod] rename:authelia-calls->arc
This commit is contained in:
parent
045330759b
commit
468ac9a23e
5 changed files with 267 additions and 247 deletions
29
notes.md
29
notes.md
|
@ -1,29 +0,0 @@
|
|||
- siehe `~/projekte/linke/sonstiges/authelia-callbacks`
|
||||
|
||||
- Espe macht HTTP-Request zu `callbacks.authelia.linke.sx` mit Nutzerliste als Rumpf (Authentifizierung?)
|
||||
|
||||
- submit
|
||||
- timestamp
|
||||
- userlist
|
||||
- authhash (`sha256(timestamp+secret)`)
|
||||
|
||||
|
||||
```
|
||||
type type_data = Record<
|
||||
string,
|
||||
{
|
||||
disabled : boolean;
|
||||
displayname : string;
|
||||
email : string;
|
||||
groups : Array<string>;
|
||||
password : string;
|
||||
}
|
||||
>;
|
||||
|
||||
type type_payload = {
|
||||
timestamp : int;
|
||||
authhash : string;
|
||||
data : type_data;
|
||||
}
|
||||
|
||||
```
|
34
readme.md
Normal file
34
readme.md
Normal file
|
@ -0,0 +1,34 @@
|
|||
# ARC
|
||||
|
||||
## Beschreibung
|
||||
|
||||
- ARC = **A**uthelia **R**emote **C**ontrol
|
||||
- Dienst zur Steuerung einer [Authelia](https://www.authelia.com/)-Instanz
|
||||
|
||||
|
||||
## Erstellung
|
||||
|
||||
### Voraussetzungen
|
||||
|
||||
- GNU Make
|
||||
- NodeJS
|
||||
|
||||
|
||||
### Anweisungen
|
||||
|
||||
- `tools/build` ausführen
|
||||
|
||||
|
||||
## Betrieb
|
||||
|
||||
### Voraussetzungen
|
||||
|
||||
- NodeJS
|
||||
|
||||
|
||||
### Anweisungen
|
||||
|
||||
- ins Erzeugnis-Verzeichnis wechseln
|
||||
- `./arc -h` ausführen
|
||||
- für die meisten Anwendungsfälle ist es erforderlich eine Konfigurations-Datei anzulegen
|
||||
|
439
source/main.ts
439
source/main.ts
|
@ -170,239 +170,254 @@ async function main(
|
|||
const conf : type_conf = await conf_get(args.conf_path);
|
||||
|
||||
// exec
|
||||
const rest_subject : lib_plankton.rest.type_rest = lib_plankton.rest.make(
|
||||
if (args["help"]) {
|
||||
process.stdout.write(
|
||||
arg_handler.generate_help(
|
||||
{
|
||||
"programname": "arc",
|
||||
"description": "Authelia Remote Control",
|
||||
"executable": "arc",
|
||||
}
|
||||
)
|
||||
+
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
else {
|
||||
const rest_subject : lib_plankton.rest.type_rest = lib_plankton.rest.make(
|
||||
{
|
||||
"title": "authelia-callbacks",
|
||||
"versioning_method": "header",
|
||||
"versioning_header_name": "X-Api-Version",
|
||||
"set_access_control_headers": true,
|
||||
"authentication": {
|
||||
"kind": "key_header",
|
||||
"parameters": {"name": "X-Session-Key"}
|
||||
},
|
||||
}
|
||||
);
|
||||
{
|
||||
"title": "authelia-callbacks",
|
||||
"versioning_method": "header",
|
||||
"versioning_header_name": "X-Api-Version",
|
||||
"set_access_control_headers": true,
|
||||
"authentication": {
|
||||
"kind": "key_header",
|
||||
"parameters": {"name": "X-Session-Key"}
|
||||
},
|
||||
}
|
||||
);
|
||||
{
|
||||
lib_plankton.rest.register<
|
||||
null,
|
||||
string
|
||||
>
|
||||
(
|
||||
rest_subject,
|
||||
lib_plankton.http.enum_method.get,
|
||||
"/meta/ping",
|
||||
{
|
||||
"description": "sendet ein 'pong' zurück; gedacht um die Erreichbarkeit des Backends zu prüfen",
|
||||
"input_schema": () => ({
|
||||
"nullable": true,
|
||||
}),
|
||||
"output_schema": () => ({
|
||||
"nullable": false,
|
||||
"type": "string",
|
||||
}),
|
||||
// "restriction": restriction_none,
|
||||
"execution": () => {
|
||||
return Promise.resolve({
|
||||
"status_code": 200,
|
||||
"data": "pong",
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
lib_plankton.rest.register<
|
||||
null,
|
||||
any
|
||||
>
|
||||
(
|
||||
rest_subject,
|
||||
lib_plankton.http.enum_method.get,
|
||||
"/meta/spec",
|
||||
{
|
||||
"description": "gibt die API-Spezifikation im OpenAPI-Format aus",
|
||||
"input_schema": () => ({
|
||||
"nullable": true,
|
||||
}),
|
||||
"output_schema": () => ({
|
||||
}),
|
||||
// "restriction": restriction_none,
|
||||
"execution": () => {
|
||||
return Promise.resolve({
|
||||
"status_code": 200,
|
||||
"data": lib_plankton.rest.to_oas(rest_subject),
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
lib_plankton.rest.register<
|
||||
type_user_list_sparse,
|
||||
null
|
||||
>(
|
||||
rest_subject,
|
||||
lib_plankton.http.enum_method.put,
|
||||
"/users/set",
|
||||
{
|
||||
"description": "setzt die Nutzerliste",
|
||||
"query_parameters": [
|
||||
{
|
||||
"name": "timestamp",
|
||||
"required": true,
|
||||
"description": "current UNIX timestamp",
|
||||
lib_plankton.rest.register<
|
||||
null,
|
||||
string
|
||||
>
|
||||
(
|
||||
rest_subject,
|
||||
lib_plankton.http.enum_method.get,
|
||||
"/meta/ping",
|
||||
{
|
||||
"description": "sendet ein 'pong' zurück; gedacht um die Erreichbarkeit des Backends zu prüfen",
|
||||
"input_schema": () => ({
|
||||
"nullable": true,
|
||||
}),
|
||||
"output_schema": () => ({
|
||||
"nullable": false,
|
||||
"type": "string",
|
||||
}),
|
||||
// "restriction": restriction_none,
|
||||
"execution": () => {
|
||||
return Promise.resolve({
|
||||
"status_code": 200,
|
||||
"data": "pong",
|
||||
});
|
||||
},
|
||||
{
|
||||
"name": "auth",
|
||||
"required": true,
|
||||
"description": "authorization string",
|
||||
}
|
||||
);
|
||||
lib_plankton.rest.register<
|
||||
null,
|
||||
any
|
||||
>
|
||||
(
|
||||
rest_subject,
|
||||
lib_plankton.http.enum_method.get,
|
||||
"/meta/spec",
|
||||
{
|
||||
"description": "gibt die API-Spezifikation im OpenAPI-Format aus",
|
||||
"input_schema": () => ({
|
||||
"nullable": true,
|
||||
}),
|
||||
"output_schema": () => ({
|
||||
}),
|
||||
// "restriction": restriction_none,
|
||||
"execution": () => {
|
||||
return Promise.resolve({
|
||||
"status_code": 200,
|
||||
"data": lib_plankton.rest.to_oas(rest_subject),
|
||||
});
|
||||
},
|
||||
],
|
||||
"input_schema": () => ({
|
||||
"nullable": true,
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"users": {
|
||||
"nullable": true,
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"nullable": false,
|
||||
}
|
||||
);
|
||||
lib_plankton.rest.register<
|
||||
type_user_list_sparse,
|
||||
null
|
||||
>(
|
||||
rest_subject,
|
||||
lib_plankton.http.enum_method.put,
|
||||
"/users/set",
|
||||
{
|
||||
"description": "setzt die Nutzerliste",
|
||||
"query_parameters": [
|
||||
{
|
||||
"name": "timestamp",
|
||||
"required": true,
|
||||
"description": "current UNIX timestamp",
|
||||
},
|
||||
{
|
||||
"name": "auth",
|
||||
"required": true,
|
||||
"description": "authorization string",
|
||||
},
|
||||
],
|
||||
"input_schema": () => ({
|
||||
"nullable": true,
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"users": {
|
||||
"nullable": true,
|
||||
"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": {
|
||||
"additionalProperties": {
|
||||
"nullable": false,
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"disabled": {
|
||||
"nullable": false,
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"nullable": false,
|
||||
"type": "string",
|
||||
"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",
|
||||
]
|
||||
},
|
||||
"required": [
|
||||
"password",
|
||||
]
|
||||
},
|
||||
"properties": {},
|
||||
"required": [],
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"users"
|
||||
]
|
||||
}),
|
||||
"output_schema": () => ({
|
||||
"nullable": true,
|
||||
}),
|
||||
"restriction": async (stuff) => {
|
||||
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,
|
||||
"properties": {},
|
||||
"required": [],
|
||||
}
|
||||
);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
const authhash_is : string = stuff.query_parameters["auth"];
|
||||
const authhash_shall : string = lib_plankton.sha256.get(
|
||||
timestamp_remote.toFixed(0) + conf.authentication.hash_salt
|
||||
);
|
||||
if (authhash_is !== authhash_shall) {
|
||||
},
|
||||
"required": [
|
||||
"users"
|
||||
]
|
||||
}),
|
||||
"output_schema": () => ({
|
||||
"nullable": true,
|
||||
}),
|
||||
"restriction": async (stuff) => {
|
||||
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_mismatching_hashes",
|
||||
"restriction_access_denied_due_to_invalid_timestamp",
|
||||
{
|
||||
"timestamp": timestamp_remote,
|
||||
"authhash_is": authhash_is,
|
||||
"authhash_shall": authhash_shall,
|
||||
"timestamp_local": timestamp_local,
|
||||
"timestamp_remote": timestamp_remote,
|
||||
}
|
||||
);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
const authhash_is : string = stuff.query_parameters["auth"];
|
||||
const authhash_shall : string = lib_plankton.sha256.get(
|
||||
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 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"execution": async (stuff) => {
|
||||
await lib_plankton.file.write(
|
||||
conf.authelia.usersfile_path,
|
||||
encode_user_list(stuff.input)
|
||||
);
|
||||
lib_plankton.log.notice(
|
||||
"userdata_updated",
|
||||
{
|
||||
},
|
||||
"execution": async (stuff) => {
|
||||
await lib_plankton.file.write(
|
||||
conf.authelia.usersfile_path,
|
||||
encode_user_list(stuff.input)
|
||||
);
|
||||
lib_plankton.log.notice(
|
||||
"userdata_updated",
|
||||
{
|
||||
}
|
||||
);
|
||||
return Promise.resolve({
|
||||
"status_code": 200,
|
||||
"data": null
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
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());
|
||||
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<lib_plankton.http.type_response>(
|
||||
{
|
||||
"version": "HTTP/1.1",
|
||||
"status_code": 500,
|
||||
"headers": {},
|
||||
// @ts-ignore
|
||||
"body": Buffer.from(""),
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
return Promise.resolve({
|
||||
"status_code": 200,
|
||||
"data": null
|
||||
});
|
||||
},
|
||||
)
|
||||
.then<string>(
|
||||
(http_response) => {
|
||||
const output : string = lib_plankton.http.encode_response(http_response);
|
||||
return Promise.resolve<string>(output);
|
||||
}
|
||||
)
|
||||
);
|
||||
},
|
||||
{
|
||||
"host": conf.server.host,
|
||||
"port": conf.server.port,
|
||||
}
|
||||
);
|
||||
|
||||
lib_plankton.server.start(server);
|
||||
}
|
||||
|
||||
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());
|
||||
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<lib_plankton.http.type_response>(
|
||||
{
|
||||
"version": "HTTP/1.1",
|
||||
"status_code": 500,
|
||||
"headers": {},
|
||||
// @ts-ignore
|
||||
"body": Buffer.from(""),
|
||||
}
|
||||
);
|
||||
}
|
||||
)
|
||||
.then<string>(
|
||||
(http_response) => {
|
||||
const output : string = lib_plankton.http.encode_response(http_response);
|
||||
return Promise.resolve<string>(output);
|
||||
}
|
||||
)
|
||||
);
|
||||
},
|
||||
{
|
||||
"host": conf.server.host,
|
||||
"port": conf.server.port,
|
||||
}
|
||||
);
|
||||
|
||||
lib_plankton.server.start(server);
|
||||
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ def main():
|
|||
"-o",
|
||||
"--output-directory",
|
||||
type = str,
|
||||
default = "/tmp/authelia-calls",
|
||||
default = "/tmp/arc",
|
||||
metavar = "<output-directory>",
|
||||
help = "output directory",
|
||||
)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
dir_tools := tools
|
||||
dir_lib := lib
|
||||
dir_source := source
|
||||
dir_temp := /tmp/authelia-calls-temp
|
||||
dir_temp := /tmp/arc-temp
|
||||
dir_build := build
|
||||
|
||||
|
||||
|
@ -19,18 +19,18 @@ cmd_tsc := ${dir_tools}/typescript/node_modules/.bin/tsc
|
|||
## rules
|
||||
|
||||
.PHONY: _default
|
||||
_default: ${dir_build}/authelia-calls
|
||||
_default: ${dir_build}/arc
|
||||
|
||||
${dir_temp}/authelia-calls-unlinked.js: \
|
||||
${dir_temp}/arc-unlinked.js: \
|
||||
${dir_lib}/plankton/plankton.d.ts \
|
||||
${dir_source}/main.ts
|
||||
@ ${cmd_log} "compiling …"
|
||||
@ ${cmd_tsc} --lib es2020 --strict $^ --outFile $@
|
||||
|
||||
${dir_build}/authelia-calls: \
|
||||
${dir_build}/arc: \
|
||||
${dir_source}/head.js \
|
||||
${dir_lib}/plankton/plankton.js \
|
||||
${dir_temp}/authelia-calls-unlinked.js
|
||||
${dir_temp}/arc-unlinked.js
|
||||
@ ${cmd_log} "linking …"
|
||||
@ ${cmd_mkdir} $(dir $@)
|
||||
@ ${cmd_cat} $^ > $@
|
||||
|
|
Loading…
Add table
Reference in a new issue