/** * @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); for (let cat of categories) { let dn = ldapConfig.user.uid + "=" + ldapEscape.filter("${txt}", { txt: uid }) + "," + ldapConfig.dn.user; console.log(ldapConfig.group[cat] + "=" + dn); data[cat] = await Basics.searchSingle("group", ldapConfig.group.gid, null, ldapConfig.group[cat] + "=" + dn); console.log(data[cat]); } 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. * @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 = vals[ldapConfig.user.uid]; // Génère une erreur si un champ n'est pas rempli for (let key_att in data) { // Ecriture de toutes les valeurs uniques if (!Array.isArray(data[key_att])) { 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."; } for (let key_att in data) { // Modifications multiples pour avoir plusieurs champs de même type ; boucle sur les attributs multiples if (Array.isArray(data[key_att])) { // On rajoute chaque valeur en entrée data[key_att].forEach(val => { let vals2 = {}; vals2[ldapConfig.user[key_att]]=val; Basics.change("user", uid, "add", vals2).then(res => { if (!res) { throw "Erreur lors de l'ajout d'une valeur pour un champ à valeurs multiples à la feuille du nouvel 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."; } }); }); // Ajout dans les groupes à la catégorie voulue for (let cat of categories) { for (let gid of data[cat]) { Tools.add(uid, gid, cat); } } 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."; } } }