﻿unit funciones;

interface

uses
  Wincrypt;

// --- INTERFAZ PÚBLICA ---
// Lo que pongas aquí será visible para otros formularios y unidades
// que añadan 'uGestionClaves' a su cláusula 'uses'.

// Genera una contraseña aleatoria de 8 caracteres que cumple las reglas.
function GenerarContraseñaSegura: string;

// Valida si una contraseña dada cumple las reglas (8 chars, 1 mayús, 1 num, 1 especial).
function ValidarContraseña(const AContraseña: string): Boolean;
function GetNombreEquipo: string;
//function EsCertificadoDeConfianza(pCertContext: PCCERT_CONTEXT): Boolean;

implementation

// --- IMPLEMENTACIÓN PRIVADA ---
// Aquí va el código "real" y las variables o constantes
// que no necesitan ser vistas desde fuera.

uses
  Windows, System.SysUtils,  // Para Random, Length, Pos
  System.Character; // Para TCharacter, TArray<Char>

// Constantes privadas de la unidad.
// Ambas funciones usarán estas mismas constantes.
const
  cLongitud = 12;
  vMayusculas = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  vMinusculas = 'abcdefghijklmnopqrstuvwxyz';
  vNumeros    = '0123456789';
  vEspeciales = '!@#$%&*as ?';

// --- Implementación de las funciones ---

// Función que comprueba si un certificado es válido POR FECHA
{function EsCertificadoDeConfianza(pCertContext: PCCERT_CONTEXT): Boolean;
var
  pChainContext: PCCERT_CHAIN_CONTEXT;
  ChainPara: TCertChainPara;
  dwError: DWORD;
begin
  Result := False;
  pChainContext := nil;

  // Prepara los parámetros para la construcción de la cadena
  FillChar(ChainPara, SizeOf(TCertChainPara), 0);
  ChainPara.cbSize := SizeOf(TCertChainPara);

  // Intentamos construir la cadena de certificados
  if not CertGetCertificateChain(
      0,                // hChainEngine
      pCertContext,     // pCertContext
      nil,              // pTime
      nil,              // hAdditionalStore
      @ChainPara,       // pChainPara
      CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL, // dwFlags (usa caché)
      nil,              // pvReserved
      pChainContext) then
  begin
    Exit; // No se pudo construir la cadena
  end;

  try
    // Si la cadena se construyó, comprobamos su estado de error.
    // CERT_TRUST_NO_ERROR (valor 0) significa que todo está bien:
    // las fechas son correctas, la cadena es de confianza y no está revocado.
    dwError := pChainContext^.TrustStatus.dwErrorStatus;

    Result := (dwError = CERT_TRUST_NO_ERROR);

  finally
    // Siempre debemos liberar el contexto de la cadena
    if pChainContext <> nil then
      CertFreeCertificateChain(pChainContext);
  end;
end;
}
function GetNombreEquipo: string;
var
  Buffer: array[0..MAX_COMPUTERNAME_LENGTH] of Char;
  BufferSize: DWORD;
begin
  BufferSize := MAX_COMPUTERNAME_LENGTH + 1; // Prepara el tamaño del buffer

  // Llama a la función de la API de Windows
  if GetComputerName(Buffer, BufferSize) then
    Result := string(Buffer) // Convierte el buffer de Chars a un string
  else
    Result := ''; // Devuelve vacío si hubo un error
end;

function GenerarContraseñaSegura: string;
var
  CAll: string;
  i, j, L: Integer;
  Temp: Char; // En XE3, esto es WideChar
begin
  // --- Inicialización Segura ---
  // (Esto evita al 100% cualquier error de 'const nil' o caracteres corruptos)

  // 1. Crear el pool completo
  CAll := vMayusculas + vMinusculas + vNumeros + vEspeciales;

  // --- COMPROBACIÓN DE PÁNICO ---
  // Si alguna de estas cadenas es 'nil' por alguna razón corrupta, fallará aquí.
  if (Length(vMayusculas) = 0) or (Length(vNumeros) = 0) or
     (Length(vEspeciales) = 0) or (Length(CAll) = 0) then
  begin
    Result := 'ERROR'; // Devuelve esto si algo es nil
//    ShowMessage('Error: Las cadenas de caracteres están vacías o son nulas.');
    Exit;
  end;

  // 2. Construir el string base (garantizando los requisitos)
  Result := '';
  Result := Result + vMayusculas[Random(Length(vMayusculas)) + 1]; // 1. Mayúscula
  Result := Result + vNumeros[Random(Length(vNumeros)) + 1];    // 2. Número
  Result := Result + vEspeciales[Random(Length(vEspeciales)) + 1]; // 3. Especial

  // 3. Rellenar el resto (8 - 3 = 5 caracteres)
  for i := 4 to cLongitud do
  begin
    Result := Result + CAll[Random(Length(CAll)) + 1];
  end;

  // 4. Barajar (Mezclar) el string final (Algoritmo Fisher-Yates)
  //    (Los strings en Delphi son 1-based)
  L := Length(Result);
  for i := L downto 2 do
  begin
    j := Random(i - 1) + 1; // Índice aleatorio entre 1 e i-1

    // Intercambiar Result[i] y Result[j]
    Temp := Result[i];
    Result[i] := Result[j];
    Result[j] := Temp;
  end;

  // 5. Devolver el string mezclado
  // (Result ya contiene el valor)
end;
function ValidarContraseña(const AContraseña: string): Boolean;
var
  TieneMayus: Boolean;
  TieneNum: Boolean;
  TieneEspecial: Boolean;
  C: Char;
begin
  // Regla 1: Longitud exacta (usa la constante)
  if Length(AContraseña) < cLongitud then
  begin
    Result := False;
    Exit;
  end;

  // Inicializamos las banderas de comprobación
  TieneMayus := False;
  TieneNum := False;
  TieneEspecial := False;

  // Regla 2, 3 y 4: Comprobar el contenido
  for C in AContraseña do
  begin
    if TCharacter.IsUpper(C) then
      TieneMayus := True
    else if TCharacter.IsDigit(C) then
      TieneNum := True
    else if Pos(C, vEspeciales) > 0 then // Usa la constante de la unidad
      TieneEspecial := True;

    // Optimización: Si ya cumplimos todo, salimos del bucle
    if TieneMayus and TieneNum and TieneEspecial then
      Break;
  end;

  // El resultado final es verdadero SÓLO si las tres banderas son verdaderas
  Result := TieneMayus and TieneNum and TieneEspecial;
end;


// --- SECCIÓN DE INICIALIZACIÓN ---
// Este código se ejecuta UNA SOLA VEZ cuando la aplicación carga esta unidad.
initialization
  // Inicializa el generador de números aleatorios para toda la aplicación.
  // Es el lugar perfecto para ponerlo.
  Randomize;

end.
