333 lines
7.1 KiB
TypeScript
333 lines
7.1 KiB
TypeScript
|
|
||
|
/**
|
||
|
*/
|
||
|
type type_conf = {
|
||
|
server : {
|
||
|
port : int;
|
||
|
};
|
||
|
authentication : {
|
||
|
timestamp_tolerance : float;
|
||
|
hash_salt : string;
|
||
|
};
|
||
|
authelia : {
|
||
|
usersfile_path : string;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
type type_user_list_sparse = (
|
||
|
null
|
||
|
|
|
||
|
Record<
|
||
|
string,
|
||
|
{
|
||
|
disabled ?: boolean;
|
||
|
displayname ?: string;
|
||
|
email ?: string;
|
||
|
groups ?: Array<string>;
|
||
|
password : string;
|
||
|
}
|
||
|
>
|
||
|
);
|
||
|
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
type type_user_list_complete = Record<
|
||
|
string,
|
||
|
{
|
||
|
disabled : boolean;
|
||
|
displayname : string;
|
||
|
email : string;
|
||
|
groups : Array<string>;
|
||
|
password : string;
|
||
|
}
|
||
|
>;
|
||
|
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
async function conf_get(
|
||
|
path : string
|
||
|
) : Promise<type_conf>
|
||
|
{
|
||
|
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"),
|
||
|
},
|
||
|
};
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
function encode_user_list(
|
||
|
user_list : type_user_list_sparse
|
||
|
) : string
|
||
|
{
|
||
|
let output : string = "";
|
||
|
Object.entries(user_list ?? {}).forEach(
|
||
|
([key, value]) => {
|
||
|
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");
|
||
|
}
|
||
|
else {
|
||
|
// do nothing
|
||
|
}
|
||
|
output += (" " + "groups: " + JSON.stringify(value.groups ?? []) + "\n");
|
||
|
output += (" " + "password: " + value.password + "\n");
|
||
|
}
|
||
|
);
|
||
|
return output;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
*/
|
||
|
async function main(
|
||
|
args_raw : Array<string>
|
||
|
) : Promise<void>
|
||
|
{
|
||
|
lib_plankton.log.conf_push(
|
||
|
[
|
||
|
lib_plankton.log.channel_make(
|
||
|
{
|
||
|
"kind": "stdout",
|
||
|
"data": {
|
||
|
"threshold": "info",
|
||
|
// "format": "human_readable",
|
||
|
}
|
||
|
}
|
||
|
),
|
||
|
]
|
||
|
);
|
||
|
|
||
|
// args
|
||
|
const arg_handler : lib_plankton.args.class_handler = new lib_plankton.args.class_handler({
|
||
|
"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": "path to conf file",
|
||
|
"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": "only show help and exit",
|
||
|
"name": "help",
|
||
|
}),
|
||
|
});
|
||
|
const args : Record<string, any> = arg_handler.read(lib_plankton.args.enum_environment.cli, args_raw.join(" "));
|
||
|
|
||
|
const conf : type_conf = await conf_get(args.conf_path);
|
||
|
|
||
|
// exec
|
||
|
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"}
|
||
|
},
|
||
|
}
|
||
|
);
|
||
|
{
|
||
|
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",
|
||
|
},
|
||
|
{
|
||
|
"name": "auth",
|
||
|
"required": true,
|
||
|
"description": "authorization string",
|
||
|
},
|
||
|
],
|
||
|
"input_schema": () => ({
|
||
|
"nullable": true,
|
||
|
"type": "object",
|
||
|
"additionalProperties": {
|
||
|
"nullable": false,
|
||
|
"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",
|
||
|
]
|
||
|
},
|
||
|
"properties": {},
|
||
|
"required": [],
|
||
|
}),
|
||
|
"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) {
|
||
|
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) {
|
||
|
return false;
|
||
|
}
|
||
|
else {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"execution": async (stuff) => {
|
||
|
await lib_plankton.file.write(
|
||
|
conf.authelia.usersfile_path,
|
||
|
encode_user_list(stuff.input)
|
||
|
);
|
||
|
return Promise.resolve({
|
||
|
"status_code": 200,
|
||
|
"data": null
|
||
|
});
|
||
|
},
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
|
||
|
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 output : string = lib_plankton.http.encode_response(http_response);
|
||
|
return output;
|
||
|
}
|
||
|
);
|
||
|
|
||
|
lib_plankton.server.start(server);
|
||
|
|
||
|
return Promise.resolve<void>(undefined);
|
||
|
}
|
||
|
|
||
|
|
||
|
(
|
||
|
main(process.argv.slice(2))
|
||
|
.then(
|
||
|
() => {}
|
||
|
)
|
||
|
.catch(
|
||
|
(error) => {process.stderr.write(String(error));}
|
||
|
)
|
||
|
);
|
||
|
|