Merge branch 'dev-auto_register'
This commit is contained in:
commit
2b1e99d1d6
15 changed files with 874 additions and 322 deletions
42
lib/plankton/plankton.d.ts
vendored
42
lib/plankton/plankton.d.ts
vendored
|
@ -923,6 +923,16 @@ declare namespace lib_plankton.file {
|
|||
*/
|
||||
function delete_(path: string): Promise<void>;
|
||||
}
|
||||
declare namespace lib_plankton.email {
|
||||
/**
|
||||
*/
|
||||
function send(smtp_credentials: {
|
||||
host: string;
|
||||
port: int;
|
||||
username: string;
|
||||
password: string;
|
||||
}, sender: string, receivers: Array<string>, subject: string, content: string): Promise<void>;
|
||||
}
|
||||
declare namespace lib_plankton.log {
|
||||
/**
|
||||
*/
|
||||
|
@ -996,10 +1006,40 @@ declare namespace lib_plankton.log {
|
|||
* the path of the log file
|
||||
*/
|
||||
private path;
|
||||
/**
|
||||
*/
|
||||
private human_readable;
|
||||
/**
|
||||
* [constructor]
|
||||
*/
|
||||
constructor(path: string);
|
||||
constructor(path: string, human_readable: boolean);
|
||||
/**
|
||||
*/
|
||||
add(entry: type_entry): void;
|
||||
}
|
||||
}
|
||||
declare namespace lib_plankton.log {
|
||||
/**
|
||||
*/
|
||||
class class_channel_email extends class_channel {
|
||||
/**
|
||||
*/
|
||||
private smtp_credentials;
|
||||
/**
|
||||
*/
|
||||
private sender;
|
||||
/**
|
||||
*/
|
||||
private receivers;
|
||||
/**
|
||||
* [constructor]
|
||||
*/
|
||||
constructor(smtp_credentials: {
|
||||
host: string;
|
||||
port: int;
|
||||
username: string;
|
||||
password: string;
|
||||
}, sender: string, receivers: Array<string>);
|
||||
/**
|
||||
*/
|
||||
add(entry: type_entry): void;
|
||||
|
|
|
@ -2173,6 +2173,100 @@ var lib_plankton;
|
|||
file.delete_ = delete_;
|
||||
})(file = lib_plankton.file || (lib_plankton.file = {}));
|
||||
})(lib_plankton || (lib_plankton = {}));
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||
function step(op) {
|
||||
if (f) throw new TypeError("Generator is already executing.");
|
||||
while (_) try {
|
||||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||
switch (op[0]) {
|
||||
case 0: case 1: t = op; break;
|
||||
case 4: _.label++; return { value: op[1], done: false };
|
||||
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||
default:
|
||||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||
if (t[2]) _.ops.pop();
|
||||
_.trys.pop(); continue;
|
||||
}
|
||||
op = body.call(thisArg, _);
|
||||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||
}
|
||||
};
|
||||
/*
|
||||
This file is part of »bacterio-plankton:email«.
|
||||
|
||||
Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
|
||||
<info@greenscale.de>
|
||||
|
||||
»bacterio-plankton:email« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»bacterio-plankton:lang« 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »bacterio-plankton:email«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
var lib_plankton;
|
||||
(function (lib_plankton) {
|
||||
var email;
|
||||
(function (email) {
|
||||
/**
|
||||
*/
|
||||
function send(smtp_credentials, sender, receivers, subject, content) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
var nm_nodemailer, transporter, info;
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
nm_nodemailer = require("nodemailer");
|
||||
transporter = nm_nodemailer.createTransport({
|
||||
"host": smtp_credentials.host,
|
||||
"port": smtp_credentials.port,
|
||||
"secure": false,
|
||||
"auth": {
|
||||
"user": smtp_credentials.username,
|
||||
"pass": smtp_credentials.password
|
||||
},
|
||||
"debug": true
|
||||
});
|
||||
return [4 /*yield*/, transporter.sendMail({
|
||||
"from": sender,
|
||||
"to": receivers.join(", "),
|
||||
"subject": subject,
|
||||
"text": content
|
||||
})];
|
||||
case 1:
|
||||
info = _a.sent();
|
||||
return [2 /*return*/];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
email.send = send;
|
||||
})(email = lib_plankton.email || (lib_plankton.email = {}));
|
||||
})(lib_plankton || (lib_plankton = {}));
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = function (d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
|
@ -2445,9 +2539,10 @@ var lib_plankton;
|
|||
/**
|
||||
* [constructor]
|
||||
*/
|
||||
function class_channel_file(path) {
|
||||
function class_channel_file(path, human_readable) {
|
||||
var _this = _super.call(this) || this;
|
||||
_this.path = path;
|
||||
_this.human_readable = human_readable;
|
||||
return _this;
|
||||
}
|
||||
/**
|
||||
|
@ -2455,9 +2550,8 @@ var lib_plankton;
|
|||
class_channel_file.prototype.add = function (entry) {
|
||||
var _this = this;
|
||||
var nm_fs = require("fs");
|
||||
nm_fs.writeFile(this.path, {
|
||||
"flag": "a+"
|
||||
}, (("<" + (new Date(Date.now())).toISOString().slice(0, 19) + ">")
|
||||
var line = (this.human_readable
|
||||
? (("<" + (new Date(Date.now())).toISOString().slice(0, 19) + ">")
|
||||
+
|
||||
" "
|
||||
+
|
||||
|
@ -2471,8 +2565,25 @@ var lib_plankton;
|
|||
+
|
||||
JSON.stringify(entry.details, undefined, " ")
|
||||
+
|
||||
"\n"), function (error) {
|
||||
"\n")
|
||||
: (JSON.stringify({
|
||||
"timestamp": lib_plankton.base.get_current_timestamp(),
|
||||
"level_number": entry.level,
|
||||
"level_name": log.level_show(entry.level),
|
||||
"incident": entry.incident,
|
||||
"details": entry.details
|
||||
})
|
||||
+
|
||||
"\n"));
|
||||
nm_fs.writeFile(this.path, line, {
|
||||
"flag": "a+"
|
||||
}, function (error) {
|
||||
if (error !== null) {
|
||||
process.stderr.write('-- [plankton] could not add log entry to file ' + _this.path + "\n");
|
||||
}
|
||||
else {
|
||||
// do nothing
|
||||
}
|
||||
});
|
||||
};
|
||||
return class_channel_file;
|
||||
|
@ -2496,6 +2607,58 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »bacterio-plankton:log«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
var lib_plankton;
|
||||
(function (lib_plankton) {
|
||||
var log;
|
||||
(function (log) {
|
||||
/**
|
||||
*/
|
||||
var class_channel_email = /** @class */ (function (_super) {
|
||||
__extends(class_channel_email, _super);
|
||||
/**
|
||||
* [constructor]
|
||||
*/
|
||||
function class_channel_email(smtp_credentials, sender, receivers) {
|
||||
var _this = _super.call(this) || this;
|
||||
_this.smtp_credentials = smtp_credentials;
|
||||
_this.sender = sender;
|
||||
_this.receivers = receivers;
|
||||
return _this;
|
||||
}
|
||||
/**
|
||||
*/
|
||||
class_channel_email.prototype.add = function (entry) {
|
||||
var nm_fs = require("fs");
|
||||
lib_plankton.email.send(this.smtp_credentials, this.sender, this.receivers, (("[" + log.level_show(entry.level) + "]")
|
||||
+
|
||||
" "
|
||||
+
|
||||
("" + entry.incident + "")), JSON.stringify(entry.details, undefined, " "));
|
||||
};
|
||||
return class_channel_email;
|
||||
}(log.class_channel));
|
||||
log.class_channel_email = class_channel_email;
|
||||
})(log = lib_plankton.log || (lib_plankton.log = {}));
|
||||
})(lib_plankton || (lib_plankton = {}));
|
||||
/*
|
||||
This file is part of »bacterio-plankton:log«.
|
||||
|
||||
Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
|
||||
<info@greenscale.de>
|
||||
|
||||
»bacterio-plankton:log« is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
»bacterio-plankton:lang« 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 Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with »bacterio-plankton:log«. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
@ -2635,7 +2798,7 @@ var lib_plankton;
|
|||
/**
|
||||
*/
|
||||
function channel_make(description) {
|
||||
var _a, _b, _c, _d;
|
||||
var _a, _b, _c, _d, _e;
|
||||
switch (description.kind) {
|
||||
default: {
|
||||
throw (new Error("unhandled log channel kind: " + description.kind));
|
||||
|
@ -2646,11 +2809,15 @@ var lib_plankton;
|
|||
break;
|
||||
}
|
||||
case "file": {
|
||||
return (new log.class_channel_minlevel(new log.class_channel_file((_b = description.data["path"]) !== null && _b !== void 0 ? _b : "/tmp/plankton.log"), translate_level((_c = description.data["threshold"]) !== null && _c !== void 0 ? _c : "debug")));
|
||||
return (new log.class_channel_minlevel(new log.class_channel_file(((_b = description.data["path"]) !== null && _b !== void 0 ? _b : "/tmp/plankton.log"), false), translate_level((_c = description.data["threshold"]) !== null && _c !== void 0 ? _c : "debug")));
|
||||
break;
|
||||
}
|
||||
case "email": {
|
||||
return (new log.class_channel_minlevel(new log.class_channel_email(description.data["smtp_credentials"], description.data["sender"], description.data["receivers"]), translate_level((_d = description.data["threshold"]) !== null && _d !== void 0 ? _d : "debug")));
|
||||
break;
|
||||
}
|
||||
case "notify": {
|
||||
return (new log.class_channel_minlevel(new log.class_channel_notify(), translate_level((_d = description.data["threshold"]) !== null && _d !== void 0 ? _d : "debug")));
|
||||
return (new log.class_channel_minlevel(new log.class_channel_notify(), translate_level((_e = description.data["threshold"]) !== null && _e !== void 0 ? _e : "debug")));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -10453,7 +10620,7 @@ var lib_plankton;
|
|||
// "input_shape": options.input_type,
|
||||
// "output_shape": options.output_type,
|
||||
});
|
||||
lib_plankton.log.info("rest_route_added", {
|
||||
lib_plankton.log.debug("rest_route_added", {
|
||||
"http_method": http_method,
|
||||
"path": path,
|
||||
// "routetree": rest.routetree,
|
||||
|
|
69
misc/conf.example.json
Normal file
69
misc/conf.example.json
Normal file
|
@ -0,0 +1,69 @@
|
|||
{
|
||||
"general": {
|
||||
"language": null,
|
||||
"verbosity": "info",
|
||||
"verification_secret": null
|
||||
},
|
||||
"server": {
|
||||
"port": 4916,
|
||||
"path_base": ""
|
||||
},
|
||||
"database": {
|
||||
"kind": "sqlite",
|
||||
"data": {
|
||||
"path": "data.sqlite"
|
||||
}
|
||||
},
|
||||
"email_sending": {
|
||||
"kind": "console",
|
||||
"data": {
|
||||
}
|
||||
},
|
||||
"session_management": {
|
||||
"in_memory": false,
|
||||
"drop_all_at_start": false,
|
||||
"lifetime": 7200
|
||||
},
|
||||
"settings": {
|
||||
"organisation": {
|
||||
"name": "Example Orginsation",
|
||||
"domain": "example.org"
|
||||
},
|
||||
"misc": {
|
||||
"prefix_for_veiled_email_addresses": "member-",
|
||||
"facultative_membership_number": true,
|
||||
"auto_register": true
|
||||
},
|
||||
"summon_email": {
|
||||
"remark": null
|
||||
},
|
||||
"password_policy": {
|
||||
"minimum_length": 4,
|
||||
"maximum_length": 12,
|
||||
"must_contain_letter": true,
|
||||
"must_contain_number": false,
|
||||
"must_contain_special_character": false
|
||||
},
|
||||
"password_change": {
|
||||
"cooldown_time": 300
|
||||
},
|
||||
"name_index": {
|
||||
"veil": false,
|
||||
"salt": null
|
||||
},
|
||||
"connections": {
|
||||
"frontend_url_base": null,
|
||||
"login_url": null
|
||||
}
|
||||
},
|
||||
"admins": [
|
||||
{
|
||||
"name": "admin",
|
||||
"password_image": "$2b$12$xOa6iWPOMjiwJ3oIOZWDGu/w2Ca/eKLHWE7aDItkNsP/79nJk065i",
|
||||
"email_address": "espe-admin@example.org"
|
||||
}
|
||||
],
|
||||
"output": {
|
||||
"authelia": "/tmp/authelia-users.yml"
|
||||
}
|
||||
}
|
|
@ -22,15 +22,15 @@ namespace _espe.api
|
|||
rest_subject : lib_plankton.rest.type_rest
|
||||
) : void
|
||||
{
|
||||
register<_espe.service.member.type_value, null>(
|
||||
register<null, null>(
|
||||
rest_subject,
|
||||
lib_plankton.http.enum_method.delete,
|
||||
"/member/:id",
|
||||
"/member/delete/:id",
|
||||
{
|
||||
"description": "löscht ein vorhandenes Mitglied",
|
||||
"restriction": restriction_logged_in,
|
||||
"execution": async ({"path_parameters": path_parameters}) => {
|
||||
const member_id : _espe.service.member.type_id = parseInt(path_parameters["id"]);
|
||||
const member_id : _espe.type.member_id = parseInt(path_parameters["id"]);
|
||||
await _espe.service.member.remove(member_id);
|
||||
return Promise.resolve({
|
||||
"status_code": 200,
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace _espe.api
|
|||
membership_number : (null | string);
|
||||
name_real_value : string;
|
||||
email_address_private : (null | string);
|
||||
notification_target_url_template ?: (null | string);
|
||||
},
|
||||
(
|
||||
string
|
||||
|
@ -59,6 +60,11 @@ namespace _espe.api
|
|||
"nullable": true,
|
||||
"description": "private E-Mail-Adresse"
|
||||
},
|
||||
"notification_target_url_template": {
|
||||
"type": "string",
|
||||
"nullable": true,
|
||||
"description": "Platz-Halter: id"
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"membership_number",
|
||||
|
@ -105,6 +111,24 @@ namespace _espe.api
|
|||
),
|
||||
}
|
||||
);
|
||||
if (! _espe.conf.get().settings.misc.auto_register) {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
// TODO: Werte in Konfiguration auslagern
|
||||
await _espe.service.member.register(
|
||||
member_id,
|
||||
{
|
||||
"email_use_veiled_address": false,
|
||||
"email_use_nominal_address": false,
|
||||
"email_redirect_to_private_address": false,
|
||||
"password": null,
|
||||
},
|
||||
{
|
||||
"notification_target_url_template": input.notification_target_url_template,
|
||||
}
|
||||
);
|
||||
}
|
||||
return Promise.resolve({
|
||||
"status_code": 201,
|
||||
"data": member_id
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace _espe.api
|
|||
_espe.api.register_member_list(rest_subject);
|
||||
_espe.api.register_member_read(rest_subject);
|
||||
_espe.api.register_member_modify(rest_subject);
|
||||
// _espe.api.register_member_delete(rest_subject);
|
||||
_espe.api.register_member_delete(rest_subject);
|
||||
// password_change
|
||||
{
|
||||
_espe.api.register_member_password_change_initialize(rest_subject);
|
||||
|
|
271
source/conf.ts
271
source/conf.ts
|
@ -18,24 +18,66 @@ namespace _espe.conf
|
|||
|
||||
/**
|
||||
*/
|
||||
export type type_conf = {
|
||||
general : {
|
||||
language : (null | string);
|
||||
verbosity : (
|
||||
"none"
|
||||
|
|
||||
type type_log_threshold = (
|
||||
"debug"
|
||||
|
|
||||
"notice"
|
||||
|
|
||||
"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 : {
|
||||
port : int;
|
||||
path_base : string;
|
||||
|
@ -102,6 +144,7 @@ namespace _espe.conf
|
|||
misc : {
|
||||
prefix_for_veiled_email_addresses : string;
|
||||
facultative_membership_number : boolean;
|
||||
auto_register : boolean;
|
||||
};
|
||||
summon_email : {
|
||||
remark : string;
|
||||
|
@ -150,17 +193,26 @@ namespace _espe.conf
|
|||
conf_raw : any
|
||||
) : void
|
||||
{
|
||||
switch (conf_raw["version"]) {
|
||||
case 1: {
|
||||
_data = {
|
||||
"general": (
|
||||
((node_general) => ({
|
||||
"language": (node_general["language"] ?? null),
|
||||
"verbosity": (node_general["verbosity"] ?? "notice"),
|
||||
"verification_secret": (node_general["verification_secret"] ?? null),
|
||||
})) (conf_raw["general"] ?? {})
|
||||
),
|
||||
"log": [
|
||||
{
|
||||
"kind": "stdout",
|
||||
"data": {
|
||||
"threshold": ((conf_raw["general"] ?? {})["verbosity"] ?? "notice"),
|
||||
}
|
||||
},
|
||||
],
|
||||
"server": (
|
||||
((node_server) => ({
|
||||
"port": (node_server["port"] ?? 3593),
|
||||
"port": (node_server["port"] ?? 4916),
|
||||
"path_base": (node_server["path_base"] ?? ""),
|
||||
})) (conf_raw["server"] ?? {})
|
||||
),
|
||||
|
@ -194,7 +246,7 @@ namespace _espe.conf
|
|||
),
|
||||
"email_sending": (
|
||||
((node_email_sending) => {
|
||||
const kind : string = (node_email_sending["kind"] ?? "regular");
|
||||
const kind : string = (node_email_sending["kind"] ?? "console");
|
||||
const data_raw = (node_email_sending["data"] ?? {});
|
||||
switch (kind) {
|
||||
case "regular": {
|
||||
|
@ -258,6 +310,7 @@ namespace _espe.conf
|
|||
((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": (
|
||||
|
@ -289,8 +342,8 @@ namespace _espe.conf
|
|||
),
|
||||
"name_index": (
|
||||
((node_settings_password_policy) => ({
|
||||
"veil": (node_settings_password_policy["veil"] ?? false),
|
||||
"salt": (node_settings_password_policy["salt"] ?? null),
|
||||
"veil": (node_settings_password_policy["veil"] ?? true),
|
||||
"salt": (node_settings_password_policy["salt"] ?? ""),
|
||||
})) (node_settings["name_index"] ?? {})
|
||||
),
|
||||
"connections": (
|
||||
|
@ -308,6 +361,198 @@ namespace _espe.conf
|
|||
})) (conf_raw["output"] ?? {})
|
||||
),
|
||||
};
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
_data = {
|
||||
"general": (
|
||||
((node_general) => ({
|
||||
"language": (node_general["language"] ?? null),
|
||||
"verification_secret": (node_general["verification_secret"] ?? null),
|
||||
})) (conf_raw["general"] ?? {})
|
||||
),
|
||||
"log": (
|
||||
((node_log) => node_log.map(
|
||||
(node_log_entry : any) => ({
|
||||
"kind": node_log_entry["kind"],
|
||||
"data": Object.assign(
|
||||
{
|
||||
"format": "human_readable",
|
||||
"threshold": "notice",
|
||||
},
|
||||
(node_log_entry["data"] ?? {})
|
||||
)
|
||||
})
|
||||
)) (
|
||||
conf_raw["log"]
|
||||
??
|
||||
[
|
||||
{
|
||||
"kind": "console",
|
||||
"data": {
|
||||
}
|
||||
},
|
||||
]
|
||||
)
|
||||
),
|
||||
"server": (
|
||||
((node_server) => ({
|
||||
"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"] ?? []),
|
||||
"output": (
|
||||
((node_session_output) => ({
|
||||
"authelia": (node_session_output["authelia"] ?? null),
|
||||
})) (conf_raw["output"] ?? {})
|
||||
),
|
||||
};
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw (new Error("invalid conf version: " + conf_raw["version"]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
"email.registration.subject": "Registrierung erfolgt",
|
||||
"email.registration.body": "Das Mitglied '{{name_display}}' hat sich soeben registriert:\n\n{{url}}",
|
||||
"email.activation.subject": "Freischaltung erfolgt",
|
||||
"email.activation.body": "Hi, {{name_display}}\n\nDein Mitglieder-Konto wurde gerade freigeschalten. Du kannst dich nun anmelden:\n\nURL: {{url}}\nAnmelde-Name: {{name_login}}",
|
||||
"email.activation.body": "Hi, {{name_display}}\n\nDein Mitglieder-Konto wurde gerade freigeschalten. Du kannst dich nun anmelden:\n\nURL: {{url}}\nAnmelde-Name: {{name_login}}\n{{password_info}}",
|
||||
"email.activation.password_info": "Passwort: {{password}}\n\nBitte ändere dein Passwort zeitnah!",
|
||||
"email.password_change.initialization.subject": "Passwort-Änderung eingeleitet",
|
||||
"email.password_change.initialization.body": "Hi, {{name}}\n\nDie Funktion zum Ändern deines Passwortes wurde aufgerufen. Wenn du dein Passwort ändern willst, rufe folgenden Link auf:\n\n{{url}}\n",
|
||||
"email.password_change.execution.subject": "Passwort-Änderung abgeschlossen",
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
"email.registration.subject": "Registration received",
|
||||
"email.registration.body": "The member '{{name_display}}' just registered:\n\n{{url}}",
|
||||
"email.activation.subject": "Activated",
|
||||
"email.activation.body": "Hi, {{name_display}}\n\nYour account has just been activated. You may login now:\n\nURL: {{url}}\nLogin name: {{name_login}}",
|
||||
"email.activation.body": "Hi, {{name_display}}\n\nYour account has just been activated. You may login now:\n\nURL: {{url}}\nLogin name: {{name_login}}\n{{password_info}}",
|
||||
"email.activation.password_info": "Password: {{password}}\n\nPlease change your password soon!",
|
||||
"email.password_change.initialization.subject": "Password change initialized",
|
||||
"email.password_change.initialization.body": "Hi, {{name}}\n\nThe function for changing your password has been triggered. If you want to change your password, open the folloling link:\n\n{{url}}",
|
||||
"email.password_change.execution.subject": "Password change concluded",
|
||||
|
|
|
@ -124,61 +124,6 @@ namespace _espe.helpers
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo outsource?
|
||||
*/
|
||||
async function email_send_real(
|
||||
smtp_credentials : {
|
||||
host : string;
|
||||
port : int;
|
||||
username : string;
|
||||
password : string;
|
||||
},
|
||||
receivers : Array<string>,
|
||||
subject : string,
|
||||
content : string,
|
||||
options : {
|
||||
sender ?: (null | string);
|
||||
} = {}
|
||||
) : Promise<void>
|
||||
{
|
||||
options = Object.assign(
|
||||
{
|
||||
"sender": /*null*/"admin@example.org",
|
||||
},
|
||||
options
|
||||
);
|
||||
lib_plankton.log.info(
|
||||
"email_send_real",
|
||||
{
|
||||
"receivers": receivers,
|
||||
"subject": subject,
|
||||
}
|
||||
);
|
||||
const nm_nodemailer = require("nodemailer");
|
||||
const transporter = nm_nodemailer.createTransport(
|
||||
{
|
||||
"host": smtp_credentials.host,
|
||||
"port": smtp_credentials.port,
|
||||
"secure": false,
|
||||
"auth": {
|
||||
"user": smtp_credentials.username,
|
||||
"pass": smtp_credentials.password,
|
||||
},
|
||||
"debug": true,
|
||||
}
|
||||
);
|
||||
const info = await transporter.sendMail(
|
||||
{
|
||||
"from": (options.sender ?? ""),
|
||||
"to": receivers.join(", "),
|
||||
"subject": subject,
|
||||
"text": content,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function email_send(
|
||||
|
@ -207,14 +152,12 @@ namespace _espe.helpers
|
|||
return Promise.reject<void>("no smtp credentials specified; add in conf as 'email_sending.data.smtp_credentials'!");
|
||||
}
|
||||
else {
|
||||
return email_send_real(
|
||||
return lib_plankton.email.send(
|
||||
parameters.smtp_credentials,
|
||||
parameters.sender,
|
||||
receivers,
|
||||
subject,
|
||||
content,
|
||||
{
|
||||
"sender": parameters.sender,
|
||||
}
|
||||
content
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
@ -230,8 +173,9 @@ namespace _espe.helpers
|
|||
return Promise.reject<void>("no smtp credentials specified; add in conf as 'email_sending.data.smtp_credentials'!");
|
||||
}
|
||||
else {
|
||||
return email_send_real(
|
||||
return lib_plankton.email.send(
|
||||
parameters.smtp_credentials,
|
||||
parameters.sender,
|
||||
[parameters.target],
|
||||
lib_plankton.string.coin(
|
||||
"[REDIRECTION] {{receivers}} | {{original_subject}}",
|
||||
|
@ -240,10 +184,7 @@ namespace _espe.helpers
|
|||
"original_subject": subject
|
||||
}
|
||||
),
|
||||
content,
|
||||
{
|
||||
"sender": parameters.sender,
|
||||
}
|
||||
content
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -21,16 +21,61 @@ async function main(
|
|||
) : Promise<void>
|
||||
{
|
||||
// init
|
||||
await lib_plankton.translate.initialize(
|
||||
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": [
|
||||
JSON.parse(await lib_plankton.file.read("data/localization/deu.loc.json")),
|
||||
JSON.parse(await lib_plankton.file.read("data/localization/eng.loc.json")),
|
||||
],
|
||||
"order": ["deu", "eng"],
|
||||
"packages": packages,
|
||||
"order": language_codes,
|
||||
"autopromote": false,
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// args
|
||||
|
@ -138,19 +183,14 @@ async function main(
|
|||
lib_plankton.translate.promote(_espe.conf.get().general.language);
|
||||
}
|
||||
lib_plankton.log.conf_push(
|
||||
[
|
||||
new lib_plankton.log.class_channel_minlevel(
|
||||
new lib_plankton.log.class_channel_stdout(),
|
||||
_espe.conf.get().log.map(
|
||||
log_output => lib_plankton.log.channel_make(
|
||||
{
|
||||
"none": lib_plankton.log.enum_level.error,
|
||||
"error": lib_plankton.log.enum_level.error,
|
||||
"warning": lib_plankton.log.enum_level.warning,
|
||||
"notice": lib_plankton.log.enum_level.notice,
|
||||
"info": lib_plankton.log.enum_level.info,
|
||||
"debug":lib_plankton.log.enum_level.debug,
|
||||
}[_espe.conf.get().general.verbosity]
|
||||
),
|
||||
]
|
||||
"kind": log_output.kind,
|
||||
"data": log_output.data
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// exec
|
||||
|
|
|
@ -191,9 +191,18 @@ namespace _espe.service.member
|
|||
/**
|
||||
*/
|
||||
async function send_activation_email(
|
||||
member_object : _espe.type.member_object
|
||||
member_object : _espe.type.member_object,
|
||||
options : {
|
||||
password ?: (null | string);
|
||||
} = {}
|
||||
) : Promise<void>
|
||||
{
|
||||
options = Object.assign(
|
||||
{
|
||||
"password": null,
|
||||
},
|
||||
options
|
||||
);
|
||||
if (! member_object.enabled) {
|
||||
// do nothing
|
||||
}
|
||||
|
@ -219,6 +228,20 @@ namespace _espe.service.member
|
|||
"name_display": name_display(member_object),
|
||||
"name_login": name_login(member_object),
|
||||
"url": (_espe.conf.get().settings.connections.login_url ?? "--"),
|
||||
"password_info": (
|
||||
(
|
||||
(options.password === undefined)
|
||||
||
|
||||
(options.password === null)
|
||||
)
|
||||
? ""
|
||||
: lib_plankton.string.coin(
|
||||
lib_plankton.translate.get("email.activation.password_info"),
|
||||
{
|
||||
"password": options.password,
|
||||
}
|
||||
)
|
||||
),
|
||||
}
|
||||
)
|
||||
);
|
||||
|
@ -424,28 +447,31 @@ namespace _espe.service.member
|
|||
);
|
||||
|
||||
const member_object : _espe.type.member_object = await get(member_id);
|
||||
|
||||
let flaws : Array<{incident : string; details : Record<string, any>;}> = [];
|
||||
const password_set : boolean = (
|
||||
(data.password !== null)
|
||||
&&
|
||||
(data.password !== "")
|
||||
);
|
||||
let password_value : string;
|
||||
let password_generated : boolean;
|
||||
if (member_object.registered) {
|
||||
flaws.push({"incident": "already_registered", "details": {}});
|
||||
password_value = "";
|
||||
password_generated = false;
|
||||
}
|
||||
else {
|
||||
if (
|
||||
password_set
|
||||
&&
|
||||
(data.password !== null)
|
||||
&&
|
||||
(data.password !== "")
|
||||
) {
|
||||
flaws = flaws.concat(
|
||||
validate_password(data.password)
|
||||
.map(flaw => ({"incident": ("password_" + flaw.incident), "details": flaw.details}))
|
||||
);
|
||||
password_value = data.password;
|
||||
password_generated = false;
|
||||
}
|
||||
else {
|
||||
// do nothing
|
||||
password_value = generate_password();
|
||||
password_generated = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -456,7 +482,7 @@ namespace _espe.service.member
|
|||
member_object.email_use_veiled_address = data.email_use_veiled_address;
|
||||
member_object.email_use_nominal_address = data.email_use_nominal_address;
|
||||
member_object.email_redirect_to_private_address = data.email_redirect_to_private_address;
|
||||
member_object.password_image = await password_image(data.password);
|
||||
member_object.password_image = await password_image(password_value);
|
||||
member_object.registered = true;
|
||||
await _espe.repository.member.update(member_id, member_object);
|
||||
signal_change();
|
||||
|
@ -475,10 +501,6 @@ namespace _espe.service.member
|
|||
}
|
||||
)
|
||||
);
|
||||
if (url === null) {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
/*await*/ _espe.helpers.notify_admins(
|
||||
lib_plankton.string.coin(
|
||||
"{{head}} | {{core}}",
|
||||
|
@ -491,13 +513,12 @@ namespace _espe.service.member
|
|||
lib_plankton.translate.get("email.registration.body"),
|
||||
{
|
||||
"name_display": name_display(member_object),
|
||||
"url": url,
|
||||
"url": (url ?? "?"),
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
/*await*/ send_activation_email(member_object);
|
||||
/*await*/ send_activation_email(member_object, {"password": password_generated ? password_value : null});
|
||||
}
|
||||
|
||||
return Promise.resolve(flaws);
|
||||
|
@ -538,6 +559,17 @@ namespace _espe.service.member
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function remove(
|
||||
id : _espe.type.member_id
|
||||
) : Promise<void>
|
||||
{
|
||||
await _espe.repository.member.delete_(id);
|
||||
signal_change();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bereitet eine Passwort-Rücksetzung für Mitglieder vor
|
||||
*
|
||||
|
@ -741,17 +773,6 @@ namespace _espe.service.member
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
export async function remove(
|
||||
id : _espe.type.member_id
|
||||
) : Promise<void>
|
||||
{
|
||||
await _espe.repository.member.delete(id);
|
||||
signal_change();
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @todo check validity (e.g. username characters)
|
||||
*/
|
||||
|
|
|
@ -46,6 +46,7 @@ def main():
|
|||
"--update",
|
||||
"--verbose",
|
||||
"--exclude='conf.json'",
|
||||
"--exclude='data.sqlite'",
|
||||
("%s/" % args.build_directory),
|
||||
(
|
||||
("%s" % args.target_directory)
|
||||
|
|
|
@ -65,6 +65,7 @@ ${dir_temp}/espe-core.js ${dir_temp}/espe-core.d.ts: \
|
|||
${dir_source}/api/actions/member_list.ts \
|
||||
${dir_source}/api/actions/member_read.ts \
|
||||
${dir_source}/api/actions/member_modify.ts \
|
||||
${dir_source}/api/actions/member_delete.ts \
|
||||
${dir_source}/api/actions/member_password_change_initialize.ts \
|
||||
${dir_source}/api/actions/member_password_change_execute.ts \
|
||||
${dir_source}/api/functions.ts \
|
||||
|
|
|
@ -19,6 +19,7 @@ modules="${modules} api"
|
|||
modules="${modules} rest"
|
||||
modules="${modules} http"
|
||||
modules="${modules} server"
|
||||
modules="${modules} email"
|
||||
modules="${modules} args"
|
||||
modules="${modules} translate"
|
||||
modules="${modules} log"
|
||||
|
|
Loading…
Add table
Reference in a new issue