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>;
|
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 {
|
declare namespace lib_plankton.log {
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
|
@ -996,10 +1006,40 @@ declare namespace lib_plankton.log {
|
||||||
* the path of the log file
|
* the path of the log file
|
||||||
*/
|
*/
|
||||||
private path;
|
private path;
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
private human_readable;
|
||||||
/**
|
/**
|
||||||
* [constructor]
|
* [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;
|
add(entry: type_entry): void;
|
||||||
|
|
|
@ -2173,6 +2173,100 @@ var lib_plankton;
|
||||||
file.delete_ = delete_;
|
file.delete_ = delete_;
|
||||||
})(file = lib_plankton.file || (lib_plankton.file = {}));
|
})(file = lib_plankton.file || (lib_plankton.file = {}));
|
||||||
})(lib_plankton || (lib_plankton = {}));
|
})(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 __extends = (this && this.__extends) || (function () {
|
||||||
var extendStatics = function (d, b) {
|
var extendStatics = function (d, b) {
|
||||||
extendStatics = Object.setPrototypeOf ||
|
extendStatics = Object.setPrototypeOf ||
|
||||||
|
@ -2445,9 +2539,10 @@ var lib_plankton;
|
||||||
/**
|
/**
|
||||||
* [constructor]
|
* [constructor]
|
||||||
*/
|
*/
|
||||||
function class_channel_file(path) {
|
function class_channel_file(path, human_readable) {
|
||||||
var _this = _super.call(this) || this;
|
var _this = _super.call(this) || this;
|
||||||
_this.path = path;
|
_this.path = path;
|
||||||
|
_this.human_readable = human_readable;
|
||||||
return _this;
|
return _this;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -2455,24 +2550,40 @@ var lib_plankton;
|
||||||
class_channel_file.prototype.add = function (entry) {
|
class_channel_file.prototype.add = function (entry) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
var nm_fs = require("fs");
|
var nm_fs = require("fs");
|
||||||
nm_fs.writeFile(this.path, {
|
var line = (this.human_readable
|
||||||
|
? (("<" + (new Date(Date.now())).toISOString().slice(0, 19) + ">")
|
||||||
|
+
|
||||||
|
" "
|
||||||
|
+
|
||||||
|
("[" + log.level_show(entry.level) + "]")
|
||||||
|
+
|
||||||
|
" "
|
||||||
|
+
|
||||||
|
("" + entry.incident + "")
|
||||||
|
+
|
||||||
|
": "
|
||||||
|
+
|
||||||
|
JSON.stringify(entry.details, undefined, " ")
|
||||||
|
+
|
||||||
|
"\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+"
|
"flag": "a+"
|
||||||
}, (("<" + (new Date(Date.now())).toISOString().slice(0, 19) + ">")
|
}, function (error) {
|
||||||
+
|
if (error !== null) {
|
||||||
" "
|
process.stderr.write('-- [plankton] could not add log entry to file ' + _this.path + "\n");
|
||||||
+
|
}
|
||||||
("[" + log.level_show(entry.level) + "]")
|
else {
|
||||||
+
|
// do nothing
|
||||||
" "
|
}
|
||||||
+
|
|
||||||
("" + entry.incident + "")
|
|
||||||
+
|
|
||||||
": "
|
|
||||||
+
|
|
||||||
JSON.stringify(entry.details, undefined, " ")
|
|
||||||
+
|
|
||||||
"\n"), function (error) {
|
|
||||||
process.stderr.write('-- [plankton] could not add log entry to file ' + _this.path + "\n");
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
return class_channel_file;
|
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
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU Lesser General Public License for more details.
|
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
|
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/>.
|
along with »bacterio-plankton:log«. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
@ -2635,7 +2798,7 @@ var lib_plankton;
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
function channel_make(description) {
|
function channel_make(description) {
|
||||||
var _a, _b, _c, _d;
|
var _a, _b, _c, _d, _e;
|
||||||
switch (description.kind) {
|
switch (description.kind) {
|
||||||
default: {
|
default: {
|
||||||
throw (new Error("unhandled log channel kind: " + description.kind));
|
throw (new Error("unhandled log channel kind: " + description.kind));
|
||||||
|
@ -2646,11 +2809,15 @@ var lib_plankton;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "file": {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case "notify": {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10453,7 +10620,7 @@ var lib_plankton;
|
||||||
// "input_shape": options.input_type,
|
// "input_shape": options.input_type,
|
||||||
// "output_shape": options.output_type,
|
// "output_shape": options.output_type,
|
||||||
});
|
});
|
||||||
lib_plankton.log.info("rest_route_added", {
|
lib_plankton.log.debug("rest_route_added", {
|
||||||
"http_method": http_method,
|
"http_method": http_method,
|
||||||
"path": path,
|
"path": path,
|
||||||
// "routetree": rest.routetree,
|
// "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
|
rest_subject : lib_plankton.rest.type_rest
|
||||||
) : void
|
) : void
|
||||||
{
|
{
|
||||||
register<_espe.service.member.type_value, null>(
|
register<null, null>(
|
||||||
rest_subject,
|
rest_subject,
|
||||||
lib_plankton.http.enum_method.delete,
|
lib_plankton.http.enum_method.delete,
|
||||||
"/member/:id",
|
"/member/delete/:id",
|
||||||
{
|
{
|
||||||
"description": "löscht ein vorhandenes Mitglied",
|
"description": "löscht ein vorhandenes Mitglied",
|
||||||
"restriction": restriction_logged_in,
|
"restriction": restriction_logged_in,
|
||||||
"execution": async ({"path_parameters": path_parameters}) => {
|
"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);
|
await _espe.service.member.remove(member_id);
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
"status_code": 200,
|
"status_code": 200,
|
||||||
|
|
|
@ -27,6 +27,7 @@ namespace _espe.api
|
||||||
membership_number : (null | string);
|
membership_number : (null | string);
|
||||||
name_real_value : string;
|
name_real_value : string;
|
||||||
email_address_private : (null | string);
|
email_address_private : (null | string);
|
||||||
|
notification_target_url_template ?: (null | string);
|
||||||
},
|
},
|
||||||
(
|
(
|
||||||
string
|
string
|
||||||
|
@ -59,6 +60,11 @@ namespace _espe.api
|
||||||
"nullable": true,
|
"nullable": true,
|
||||||
"description": "private E-Mail-Adresse"
|
"description": "private E-Mail-Adresse"
|
||||||
},
|
},
|
||||||
|
"notification_target_url_template": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"description": "Platz-Halter: id"
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"membership_number",
|
"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({
|
return Promise.resolve({
|
||||||
"status_code": 201,
|
"status_code": 201,
|
||||||
"data": member_id
|
"data": member_id
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace _espe.api
|
||||||
_espe.api.register_member_list(rest_subject);
|
_espe.api.register_member_list(rest_subject);
|
||||||
_espe.api.register_member_read(rest_subject);
|
_espe.api.register_member_read(rest_subject);
|
||||||
_espe.api.register_member_modify(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
|
// password_change
|
||||||
{
|
{
|
||||||
_espe.api.register_member_password_change_initialize(rest_subject);
|
_espe.api.register_member_password_change_initialize(rest_subject);
|
||||||
|
|
571
source/conf.ts
571
source/conf.ts
|
@ -16,26 +16,68 @@ You should have received a copy of the GNU General Public License along with thi
|
||||||
namespace _espe.conf
|
namespace _espe.conf
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
type type_log_threshold = (
|
||||||
|
"debug"
|
||||||
|
|
|
||||||
|
"info"
|
||||||
|
|
|
||||||
|
"notice"
|
||||||
|
|
|
||||||
|
"warning"
|
||||||
|
|
|
||||||
|
"error"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
type type_log_format = (
|
||||||
|
"jsonl"
|
||||||
|
|
|
||||||
|
"human_readable"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
export type type_conf = {
|
export type type_conf = {
|
||||||
general : {
|
general : {
|
||||||
language : (null | string);
|
language : (null | string);
|
||||||
verbosity : (
|
|
||||||
"none"
|
|
||||||
|
|
|
||||||
"debug"
|
|
||||||
|
|
|
||||||
"notice"
|
|
||||||
|
|
|
||||||
"info"
|
|
||||||
|
|
|
||||||
"warning"
|
|
||||||
|
|
|
||||||
"error"
|
|
||||||
);
|
|
||||||
verification_secret : (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 : {
|
server : {
|
||||||
port : int;
|
port : int;
|
||||||
path_base : string;
|
path_base : string;
|
||||||
|
@ -102,6 +144,7 @@ namespace _espe.conf
|
||||||
misc : {
|
misc : {
|
||||||
prefix_for_veiled_email_addresses : string;
|
prefix_for_veiled_email_addresses : string;
|
||||||
facultative_membership_number : boolean;
|
facultative_membership_number : boolean;
|
||||||
|
auto_register : boolean;
|
||||||
};
|
};
|
||||||
summon_email : {
|
summon_email : {
|
||||||
remark : string;
|
remark : string;
|
||||||
|
@ -150,164 +193,366 @@ namespace _espe.conf
|
||||||
conf_raw : any
|
conf_raw : any
|
||||||
) : void
|
) : void
|
||||||
{
|
{
|
||||||
_data = {
|
switch (conf_raw["version"]) {
|
||||||
"general": (
|
case 1: {
|
||||||
((node_general) => ({
|
_data = {
|
||||||
"language": (node_general["language"] ?? null),
|
"general": (
|
||||||
"verbosity": (node_general["verbosity"] ?? "notice"),
|
((node_general) => ({
|
||||||
"verification_secret": (node_general["verification_secret"] ?? null),
|
"language": (node_general["language"] ?? null),
|
||||||
})) (conf_raw["general"] ?? {})
|
"verification_secret": (node_general["verification_secret"] ?? null),
|
||||||
),
|
})) (conf_raw["general"] ?? {})
|
||||||
"server": (
|
|
||||||
((node_server) => ({
|
|
||||||
"port": (node_server["port"] ?? 3593),
|
|
||||||
"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"] ?? "regular");
|
|
||||||
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),
|
|
||||||
})) (node_settings["misc"] ?? {})
|
|
||||||
),
|
),
|
||||||
"summon_email": (
|
"log": [
|
||||||
((node_settings_summon_email) => ({
|
{
|
||||||
"remark": (node_settings_summon_email["remark"] ?? null),
|
"kind": "stdout",
|
||||||
})) (node_settings["summon_email"] ?? {})
|
"data": {
|
||||||
|
"threshold": ((conf_raw["general"] ?? {})["verbosity"] ?? "notice"),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"server": (
|
||||||
|
((node_server) => ({
|
||||||
|
"port": (node_server["port"] ?? 4916),
|
||||||
|
"path_base": (node_server["path_base"] ?? ""),
|
||||||
|
})) (conf_raw["server"] ?? {})
|
||||||
),
|
),
|
||||||
"password_policy": (
|
"database": (
|
||||||
((node_settings_password_policy) => ({
|
((node_database) => {
|
||||||
"minimum_length": (
|
const kind : string = (node_database["kind"] ?? "sqlite");
|
||||||
("minimum_length" in node_settings_password_policy)
|
const node_database_data_raw = (node_database["data"] ?? {});
|
||||||
? node_settings_password_policy["minimum_length"]
|
switch (kind) {
|
||||||
: 8
|
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"] ?? {})
|
||||||
),
|
),
|
||||||
"maximum_length": (
|
"summon_email": (
|
||||||
("maximum_length" in node_settings_password_policy)
|
((node_settings_summon_email) => ({
|
||||||
? node_settings_password_policy["maximum_length"]
|
"remark": (node_settings_summon_email["remark"] ?? null),
|
||||||
: 240
|
})) (node_settings["summon_email"] ?? {})
|
||||||
),
|
),
|
||||||
"must_contain_letter": (node_settings_password_policy["must_contain_letter"] ?? true),
|
"password_policy": (
|
||||||
"must_contain_number": (node_settings_password_policy["must_contain_number"] ?? true),
|
((node_settings_password_policy) => ({
|
||||||
"must_contain_special_character": (node_settings_password_policy["must_contain_special_character"] ?? true),
|
"minimum_length": (
|
||||||
})) (node_settings["password_policy"] ?? {})
|
("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"] ?? {})
|
||||||
),
|
),
|
||||||
"password_change": (
|
"admins": (conf_raw["admins"] ?? []),
|
||||||
((node_settings_password_change) => ({
|
"output": (
|
||||||
"cooldown_time": (node_settings_password_change["cooldown_time"] ?? 86400),
|
((node_session_output) => ({
|
||||||
})) (node_settings["password_change"] ?? {})
|
"authelia": (node_session_output["authelia"] ?? null),
|
||||||
|
})) (conf_raw["output"] ?? {})
|
||||||
),
|
),
|
||||||
"name_index": (
|
};
|
||||||
((node_settings_password_policy) => ({
|
break;
|
||||||
"veil": (node_settings_password_policy["veil"] ?? false),
|
}
|
||||||
"salt": (node_settings_password_policy["salt"] ?? null),
|
case 2: {
|
||||||
})) (node_settings["name_index"] ?? {})
|
_data = {
|
||||||
|
"general": (
|
||||||
|
((node_general) => ({
|
||||||
|
"language": (node_general["language"] ?? null),
|
||||||
|
"verification_secret": (node_general["verification_secret"] ?? null),
|
||||||
|
})) (conf_raw["general"] ?? {})
|
||||||
),
|
),
|
||||||
"connections": (
|
"log": (
|
||||||
((node_settings_connections) => ({
|
((node_log) => node_log.map(
|
||||||
"frontend_url_base": (node_settings_connections["frontend_url_base"] ?? null),
|
(node_log_entry : any) => ({
|
||||||
"login_url": (node_settings_connections["login_url"] ?? null),
|
"kind": node_log_entry["kind"],
|
||||||
})) (node_settings["connections"] ?? {})
|
"data": Object.assign(
|
||||||
|
{
|
||||||
|
"format": "human_readable",
|
||||||
|
"threshold": "notice",
|
||||||
|
},
|
||||||
|
(node_log_entry["data"] ?? {})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)) (
|
||||||
|
conf_raw["log"]
|
||||||
|
??
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"kind": "console",
|
||||||
|
"data": {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
),
|
),
|
||||||
})) (conf_raw["settings"] ?? {})
|
"server": (
|
||||||
),
|
((node_server) => ({
|
||||||
"admins": (conf_raw["admins"] ?? []),
|
"port": (node_server["port"] ?? 4916),
|
||||||
"output": (
|
"path_base": (node_server["path_base"] ?? ""),
|
||||||
((node_session_output) => ({
|
})) (conf_raw["server"] ?? {})
|
||||||
"authelia": (node_session_output["authelia"] ?? null),
|
),
|
||||||
})) (conf_raw["output"] ?? {})
|
"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.subject": "Registrierung erfolgt",
|
||||||
"email.registration.body": "Das Mitglied '{{name_display}}' hat sich soeben registriert:\n\n{{url}}",
|
"email.registration.body": "Das Mitglied '{{name_display}}' hat sich soeben registriert:\n\n{{url}}",
|
||||||
"email.activation.subject": "Freischaltung erfolgt",
|
"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.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.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",
|
"email.password_change.execution.subject": "Passwort-Änderung abgeschlossen",
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
"email.registration.subject": "Registration received",
|
"email.registration.subject": "Registration received",
|
||||||
"email.registration.body": "The member '{{name_display}}' just registered:\n\n{{url}}",
|
"email.registration.body": "The member '{{name_display}}' just registered:\n\n{{url}}",
|
||||||
"email.activation.subject": "Activated",
|
"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.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.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",
|
"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(
|
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'!");
|
return Promise.reject<void>("no smtp credentials specified; add in conf as 'email_sending.data.smtp_credentials'!");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return email_send_real(
|
return lib_plankton.email.send(
|
||||||
parameters.smtp_credentials,
|
parameters.smtp_credentials,
|
||||||
|
parameters.sender,
|
||||||
receivers,
|
receivers,
|
||||||
subject,
|
subject,
|
||||||
content,
|
content
|
||||||
{
|
|
||||||
"sender": parameters.sender,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
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'!");
|
return Promise.reject<void>("no smtp credentials specified; add in conf as 'email_sending.data.smtp_credentials'!");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return email_send_real(
|
return lib_plankton.email.send(
|
||||||
parameters.smtp_credentials,
|
parameters.smtp_credentials,
|
||||||
|
parameters.sender,
|
||||||
[parameters.target],
|
[parameters.target],
|
||||||
lib_plankton.string.coin(
|
lib_plankton.string.coin(
|
||||||
"[REDIRECTION] {{receivers}} | {{original_subject}}",
|
"[REDIRECTION] {{receivers}} | {{original_subject}}",
|
||||||
|
@ -240,10 +184,7 @@ namespace _espe.helpers
|
||||||
"original_subject": subject
|
"original_subject": subject
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
content,
|
content
|
||||||
{
|
|
||||||
"sender": parameters.sender,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -21,16 +21,61 @@ async function main(
|
||||||
) : Promise<void>
|
) : Promise<void>
|
||||||
{
|
{
|
||||||
// init
|
// init
|
||||||
await lib_plankton.translate.initialize(
|
lib_plankton.log.conf_push(
|
||||||
{
|
[
|
||||||
"verbosity": 1,
|
lib_plankton.log.channel_make(
|
||||||
"packages": [
|
{
|
||||||
JSON.parse(await lib_plankton.file.read("data/localization/deu.loc.json")),
|
"kind": "stdout",
|
||||||
JSON.parse(await lib_plankton.file.read("data/localization/eng.loc.json")),
|
"data": {
|
||||||
],
|
"threshold": "notice",
|
||||||
"order": ["deu", "eng"],
|
// "format": "human_readable",
|
||||||
"autopromote": false,
|
}
|
||||||
}
|
}
|
||||||
|
),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
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
|
// args
|
||||||
|
@ -138,19 +183,14 @@ async function main(
|
||||||
lib_plankton.translate.promote(_espe.conf.get().general.language);
|
lib_plankton.translate.promote(_espe.conf.get().general.language);
|
||||||
}
|
}
|
||||||
lib_plankton.log.conf_push(
|
lib_plankton.log.conf_push(
|
||||||
[
|
_espe.conf.get().log.map(
|
||||||
new lib_plankton.log.class_channel_minlevel(
|
log_output => lib_plankton.log.channel_make(
|
||||||
new lib_plankton.log.class_channel_stdout(),
|
|
||||||
{
|
{
|
||||||
"none": lib_plankton.log.enum_level.error,
|
"kind": log_output.kind,
|
||||||
"error": lib_plankton.log.enum_level.error,
|
"data": log_output.data
|
||||||
"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]
|
|
||||||
),
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// exec
|
// exec
|
||||||
|
|
|
@ -191,9 +191,18 @@ namespace _espe.service.member
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
async function send_activation_email(
|
async function send_activation_email(
|
||||||
member_object : _espe.type.member_object
|
member_object : _espe.type.member_object,
|
||||||
|
options : {
|
||||||
|
password ?: (null | string);
|
||||||
|
} = {}
|
||||||
) : Promise<void>
|
) : Promise<void>
|
||||||
{
|
{
|
||||||
|
options = Object.assign(
|
||||||
|
{
|
||||||
|
"password": null,
|
||||||
|
},
|
||||||
|
options
|
||||||
|
);
|
||||||
if (! member_object.enabled) {
|
if (! member_object.enabled) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
@ -219,6 +228,20 @@ namespace _espe.service.member
|
||||||
"name_display": name_display(member_object),
|
"name_display": name_display(member_object),
|
||||||
"name_login": name_login(member_object),
|
"name_login": name_login(member_object),
|
||||||
"url": (_espe.conf.get().settings.connections.login_url ?? "--"),
|
"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);
|
const member_object : _espe.type.member_object = await get(member_id);
|
||||||
|
|
||||||
let flaws : Array<{incident : string; details : Record<string, any>;}> = [];
|
let flaws : Array<{incident : string; details : Record<string, any>;}> = [];
|
||||||
const password_set : boolean = (
|
let password_value : string;
|
||||||
(data.password !== null)
|
let password_generated : boolean;
|
||||||
&&
|
|
||||||
(data.password !== "")
|
|
||||||
);
|
|
||||||
if (member_object.registered) {
|
if (member_object.registered) {
|
||||||
flaws.push({"incident": "already_registered", "details": {}});
|
flaws.push({"incident": "already_registered", "details": {}});
|
||||||
|
password_value = "";
|
||||||
|
password_generated = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (
|
if (
|
||||||
password_set
|
|
||||||
&&
|
|
||||||
(data.password !== null)
|
(data.password !== null)
|
||||||
|
&&
|
||||||
|
(data.password !== "")
|
||||||
) {
|
) {
|
||||||
flaws = flaws.concat(
|
flaws = flaws.concat(
|
||||||
validate_password(data.password)
|
validate_password(data.password)
|
||||||
.map(flaw => ({"incident": ("password_" + flaw.incident), "details": flaw.details}))
|
.map(flaw => ({"incident": ("password_" + flaw.incident), "details": flaw.details}))
|
||||||
);
|
);
|
||||||
|
password_value = data.password;
|
||||||
|
password_generated = false;
|
||||||
}
|
}
|
||||||
else {
|
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_veiled_address = data.email_use_veiled_address;
|
||||||
member_object.email_use_nominal_address = data.email_use_nominal_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.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;
|
member_object.registered = true;
|
||||||
await _espe.repository.member.update(member_id, member_object);
|
await _espe.repository.member.update(member_id, member_object);
|
||||||
signal_change();
|
signal_change();
|
||||||
|
@ -475,29 +501,24 @@ namespace _espe.service.member
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if (url === null) {
|
/*await*/ _espe.helpers.notify_admins(
|
||||||
// do nothing
|
lib_plankton.string.coin(
|
||||||
}
|
"{{head}} | {{core}}",
|
||||||
else {
|
{
|
||||||
/*await*/ _espe.helpers.notify_admins(
|
"head": _espe.conf.get().settings.organisation.name,
|
||||||
lib_plankton.string.coin(
|
"core": lib_plankton.translate.get("email.registration.subject"),
|
||||||
"{{head}} | {{core}}",
|
}
|
||||||
{
|
),
|
||||||
"head": _espe.conf.get().settings.organisation.name,
|
lib_plankton.string.coin(
|
||||||
"core": lib_plankton.translate.get("email.registration.subject"),
|
lib_plankton.translate.get("email.registration.body"),
|
||||||
}
|
{
|
||||||
),
|
"name_display": name_display(member_object),
|
||||||
lib_plankton.string.coin(
|
"url": (url ?? "?"),
|
||||||
lib_plankton.translate.get("email.registration.body"),
|
}
|
||||||
{
|
)
|
||||||
"name_display": name_display(member_object),
|
);
|
||||||
"url": url,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/*await*/ send_activation_email(member_object);
|
/*await*/ send_activation_email(member_object, {"password": password_generated ? password_value : null});
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve(flaws);
|
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
|
* 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)
|
* @todo check validity (e.g. username characters)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -46,6 +46,7 @@ def main():
|
||||||
"--update",
|
"--update",
|
||||||
"--verbose",
|
"--verbose",
|
||||||
"--exclude='conf.json'",
|
"--exclude='conf.json'",
|
||||||
|
"--exclude='data.sqlite'",
|
||||||
("%s/" % args.build_directory),
|
("%s/" % args.build_directory),
|
||||||
(
|
(
|
||||||
("%s" % args.target_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_list.ts \
|
||||||
${dir_source}/api/actions/member_read.ts \
|
${dir_source}/api/actions/member_read.ts \
|
||||||
${dir_source}/api/actions/member_modify.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_initialize.ts \
|
||||||
${dir_source}/api/actions/member_password_change_execute.ts \
|
${dir_source}/api/actions/member_password_change_execute.ts \
|
||||||
${dir_source}/api/functions.ts \
|
${dir_source}/api/functions.ts \
|
||||||
|
|
|
@ -19,6 +19,7 @@ modules="${modules} api"
|
||||||
modules="${modules} rest"
|
modules="${modules} rest"
|
||||||
modules="${modules} http"
|
modules="${modules} http"
|
||||||
modules="${modules} server"
|
modules="${modules} server"
|
||||||
|
modules="${modules} email"
|
||||||
modules="${modules} args"
|
modules="${modules} args"
|
||||||
modules="${modules} translate"
|
modules="${modules} translate"
|
||||||
modules="${modules} log"
|
modules="${modules} log"
|
||||||
|
|
Loading…
Add table
Reference in a new issue