backend/source/services/admin.ts

163 lines
3.6 KiB
TypeScript

/*
Espe | Ein schlichtes Werkzeug zur Mitglieder-Verwaltung | Backend
Copyright (C) 2024 Christian Fraß
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see
<https://www.gnu.org/licenses/>.
*/
namespace _espe.service.admin
{
/**
*/
export type type_value = {
id : _espe.type.admin_id;
object : _espe.type.admin_object;
};
/**
*/
export async function add(
name : string,
email_address : (null | string),
password : string
) : Promise<_espe.type.admin_id>
{
const admin_object : _espe.type.admin_object = {
"name": name,
"email_address": email_address,
"password_image": (await _espe.helpers.bcrypt_compute(password)),
"password_fail_count": 0,
};
return _espe.repository.admin.create(admin_object);
}
/**
*/
async function get(
name : string
) : Promise<(null | type_value)>
{
const hits : Array<
{
id : _espe.type.admin_id;
preview : _espe.type.admin_object;
}
> = await _espe.repository.admin.list(name);
return Promise.resolve<(null | type_value)>(
(hits.length === 1)
?
{"id": hits[0].id, "object": hits[0].preview}
:
null
);
}
/**
*/
async function check_password(
value : type_value,
password_given : string
) : Promise<boolean>
{
return _espe.helpers.bcrypt_compare(value.object.password_image, password_given);
}
/**
*/
export async function login(
name : string,
password : string
) : Promise<(null | type_value)>
{
const value : (null | type_value) = await get(name);
if (value === null) {
return null;
}
else {
/**
* @todo outsource fail count threshold?
*/
const password_fail_threshold : int = 3;
if (value.object.password_fail_count >= password_fail_threshold) {
lib_plankton.log.notice(
"admin_password_fail_threshold_exceeded",
{
"id": value.id,
"name": value.object.name,
"password_fail_count": (value.object.password_fail_count + 1)
}
);
await _espe.repository.admin.update(
value.id,
{
"name": value.object.name,
"email_address": value.object.email_address,
"password_image": value.object.password_image,
"password_fail_count": (value.object.password_fail_count + 1),
}
);
return null;
}
else {
if (! (await check_password(value, password))) {
await _espe.repository.admin.update(
value.id,
{
"name": value.object.name,
"email_address": value.object.email_address,
"password_image": value.object.password_image,
"password_fail_count": (value.object.password_fail_count + 1),
}
);
return null;
}
else {
return value;
}
}
}
}
/**
*/
export async function email_addresses(
) : Promise<Array<string>>
{
return (
(
(await _espe.repository.admin.list(null))
.map(hit => hit.preview["email_address"])
.filter(x => (x !== null))
) as Array<string>
);
}
/**
*/
export async function notify_all(
subject : string,
body : string
) : Promise<void>
{
return _espe.helpers.email_send(
await email_addresses(),
subject,
body
);
}
}