Forked from an inaccessible project.
-
Olivér FACKLAM authoredOlivér FACKLAM authored
user.ts 9.87 KiB
/**
* @file Ce fichier contient la classe de l'API du LDAP qui gère les opérations sur les groupes. Elle est destinée à être exportée pour être utilisée par les resolvers.
* @author hawkspar
*/
import { ldapConfig, userData, categories } from '../internal/config';
import {Basics} from '../internal/basics';
import {Tools} from '../internal/tools';
import ldapEscape from 'ldap-escape';
//------------------------------------------------------------------------------------------------------------------------
// Classes à exporter TBT
//------------------------------------------------------------------------------------------------------------------------
export {userData};
export class User {
/**
* @memberof LDAP
* @class User
* @classdesc Cette classe est une des deux classes exportables permettant de faire des opérations sur les utilisateurs.
* @summary Constructeur vide.
*/
constructor() {}
/**
* @memberof LDAP
* @summary Fonction qui renvoit les infos de base relatives à un utilisateur particulier.
* @desc Cette fonction utilise {@link Tools.peek} avec l'interface {@link userData}.
* @arg {string} uid - Identifiant de l'utilisateur, supposé valide.
* @return {Promise(userData)} Informations recueillies au format {@link userData}.
* @static
* @async
*/
static async peek(uid: string) : Promise<userData> {
try {
let data : userData = await Tools.peek<userData>("user", uid, userData);
// Reconstruction des groupes dont un utilisateur est membre
for (let cat of categories) {
let dn = ldapConfig.user.uid + "=" + ldapEscape.filter("${txt}", { txt: uid }) + "," + ldapConfig.dn.user;
data[cat] = await Basics.searchSingle("group", ldapConfig.group.gid, null, ldapConfig.group[cat] + "=" + dn);
}
return data;
}
catch(err) {
throw "Error while peeking a user.";
}
}
/**
* @memberof LDAP
* @summary Fonction qui retrouve les uid des paxs validant les critères de recherche. Utiliser {@link User.peek} au cas par cas après pour obtenir les vraies infos.
* @desc Cette fonction utilise {@link Tools.search}.
* @arg {userData} data - Dictionnaire contenant les données nécessaires à la recherche. Les valeurs sont celles entrées par l'utilisateur et sont par hypothèse
* comme des sous-parties compactes des valeurs renvoyées. Tous les champs ci-dessous peuvent être indifféremment des listes (par exemple pour chercher un membre
* de plusieurs groupes) ou des éléments isolés. Si un champ n'est pas pertinent, le mettre à '' ou undefined.
* @return {Promise(string[])} gids des profils qui "match" les critères proposés.
* @static
* @async
*/
static async search(data: userData) : Promise<string[]> {
try {
return Tools.search("user", data);
}
catch(err) {
throw "Erreur lors de la recherche approximative d'un utilisateur.";
}
}
/**
* @memberof LDAP
* @summary Fonction qui créé un nouvel utilisateur dans le LDAP.
* @desc Appelle {@link LDAP.add} bien sûr, mais aussi {@link Tools.add} pour gérer les groupes du nouvel utilisateur.
* @arg {userData} data - Dictionnaire des informations utilisateurs. Des erreurs peuvent apparaître si tous les champs ne sont pas remplis.
* Cette application permet de rejoindre des groupes en masse pour toute catégorie, à la fois façon Sigma et CAS.
* @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
* @async
* @static
*/
static async create(data: userData): Promise<boolean> {
// Calcul d'un dictionnaire d'ajout
let vals = {};
// uid de base généré à partir de nom et prénom, plus potentiellement promo et un offset
// MEF mélange de Promise et de fonction standard
try {
Tools.generateUid("user",data['givenName'],data['lastName'],data['birthdate']).then(id => { vals[ldapConfig.user.uid]=id; } );
}
catch(err) {
throw "Erreur lors de la génération d'un hruid pour un nouvel utilisateur.";
}
let uid : string = vals[ldapConfig.user.uid];
// Génère une erreur si un champ n'est pas rempli
for (let key_att of ["givenName","lastName","nickname","gender","photo","phone","adress","mail","birthdate","nationality"]) {
// Ecriture de toutes les valeurs uniques
if (data[key_att] != undefined) vals[ldapConfig.user[key_att]]=data[key_att];
}
// Appel à la fonction de base
if (!await Basics.add("user", vals)) throw "Erreur de l'ajout de la feuille à l'arbre utilisateur.";
// Certains champs nécessitent de petits calculs
let vals3={};
// ldapConfiguration du mot de passe utilisateur
// Le préfixe {CRYPT} signifie que le mdp est hashé dans OpenLDAP voir : https://www.openldap.org/doc/admin24/security.html
vals3[ldapConfig.user['password']] = "{CRYPT}"+data['password'];
// Ecriture d'un surnom s'il y a lieu
if ((data['nickname']!=undefined) && (data['nickname']!='')) vals3[ldapConfig.user['nickname']]=data['nickname'];
try {
// Génération id aléatoire unique
vals3[ldapConfig.user['id']]= await Tools.generateId(ldapConfig.user['id'], "user");
}
catch(err) {
throw "Erreur lors de la génération d'un id numérique pour un nouvel utilisateur.";
}
// Code root
vals3[ldapConfig.user['cleanFullName']]=data['fullName'].replace(':', ';').toLowerCase().normalize('UFD');
// Inscription des valeurs calculées
if (!await Basics.change("user", uid, "add", vals3)) throw "Erreur lors de l'ajout des valeurs calculées à la feuille du nouvel utilisateur.";
["posixAccount", "shadowAccount", "brUser"].forEach(cst => {
let val3={};
vals3[ldapConfig.user['class']]=cst;
Basics.change("user", uid, "add", vals3).then(res => {
if (!res) throw "Erreur lors de l'ajout d'une valeur constante à la feuille du nouvel utilisateur.";
});
});
function DFS(uid, gid, cat) {
let to_visit = [gid];
let tmp = ldapConfig.user[cat];
while (to_visit.length > 0) {
let cur_gid = to_visit.pop();
Basics.change("user", uid, "add", { tmp: cur_gid});
if (cat == "admins") var rel = "childs";
to_visit.concat(Basics.searchSingle("group", ldapConfig.group[rel], cur_gid));
}
}
// Ajout dans les groupes à la catégorie voulue
for (let cat of categories) {
for (let gid of data[cat]) Tools.add(uid, gid, cat).then(res => {
if (!res) throw "Erreur de l'ajout d'un membre au nouveau groupe.";
});
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------
// Fonctions de suppression TBT
//------------------------------------------------------------------------------------------------------------------------
/**
* @memberof LDAP
* @summary Fonction qui supprime un utilisateur du LDAP.
* @desc Cette fonction commence par gérer les groupes du membre puis le supprime entièrement.
* Appelle {@link LDAP.clear} bien sûr, mais aussi {@link Tools.remove} pour gérer les groupes de l'utilisateur sortant.
* @arg {string} uid - uid de la victime
* @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
* @async
* @static
*/
static async delete(uid: string): Promise<boolean> {
try {
// Gestion des groupes d'abord
let profil = await User.peek(uid);
for (let cat of categories) {
profil[ldapConfig.user[cat]].forEach(async function (gid: string) {
// Enlever de la liste des membres
let lm = await Tools.get(gid, "group", cat);
if (lm.includes(uid)) {
// Supprime tous les membres
if (!await Basics.change("group", gid, "del", ldapConfig.group[cat])) {
throw "Erreur lors de la suppression de tous les membres du groupe.";
}
// Les rajoute un par un, sauf pour le supprimé
lm.forEach(id => {
if (id!=uid) {
Tools.add(id, gid, cat).then(res => {
if (!res) throw "Erreur lors du ré-ajout d'un autre membre";
});
}
});
}
});
}
}
catch(err) {
throw "Erreur lors de l'obtention des informations de l'utilisateur à supprimer.";
}
// Elimination
if (!Basics.clear("user", uid)) throw "Erreur lors de la suppression de l'utilisateur.";
return true;
}
/**
* @memberof LDAP
* @summary Fonction qui édite un utilisateur existant dans le LDAP.
* @desc Appelle simplement {@link Tools.edit}. Sans effet sur les groupes de l'utilisateur concerné.
* @arg {userData} data - Dictionnaire des informations utilisateurs
* @return {Promise(boolean)} `true` si la modification s'est bien déroulée, false sinon
* @async
* @static
*/
static async edit(data : userData) : Promise<boolean> {
try {
return Tools.edit("user",data);
}
catch(err) {
throw "Erreur lors de la modification d'un utilisateur.";
}
}
}