First Commit

This commit is contained in:
Jorge Luis caudillo esparza
2026-05-09 16:36:57 -07:00
parent 96ad4c0d3e
commit d0c284d9c0
131 changed files with 4009 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
namespace ADS.Apis.Gps.Infrastructure.Crypto;
public sealed class LegacyCryptoOptions
{
public string Mode { get; set; } = "AES"; // "DES" o "AES"
public string Key { get; set; } = "";
public string IV { get; set; } = ""; // Base64
}

View File

@@ -0,0 +1,69 @@
using System.Security.Cryptography;
using System.Text;
using ADS.Apis.Gps.Application.Common.Crypto;
using Microsoft.Extensions.Options;
namespace ADS.Apis.Gps.Infrastructure.Crypto;
public sealed class LegacyPasswordEncryptor : ILegacyPasswordEncryptor
{
private readonly LegacyCryptoOptions _opt;
public LegacyPasswordEncryptor(IOptions<LegacyCryptoOptions> opt)
=> _opt = opt.Value;
public string Encrypt(string plainText)
{
if (string.IsNullOrEmpty(plainText)) return string.Empty;
var mode = (_opt.Mode ?? "AES").Trim().ToUpperInvariant();
var iv = Convert.FromBase64String(_opt.IV ?? "");
return mode switch
{
"DES" => EncryptDesBase64(plainText, _opt.Key, iv),
"AES" => EncryptAesBase64(plainText, _opt.Key, iv),
_ => throw new InvalidOperationException($"Unsupported LegacyCrypto.Mode: {_opt.Mode}")
};
}
private static string EncryptDesBase64(string plainText, string keySource, byte[] iv8)
{
if (iv8.Length != 8) throw new ArgumentException("DES IV must be 8 bytes.", nameof(iv8));
var key8 = Encoding.UTF8.GetBytes((keySource ?? string.Empty).PadRight(8).Substring(0, 8));
using var des = new DESCryptoServiceProvider
{
Mode = CipherMode.CBC,
Padding = PaddingMode.PKCS7,
Key = key8,
IV = iv8
};
var input = Encoding.UTF8.GetBytes(plainText);
using var encryptor = des.CreateEncryptor(des.Key, des.IV);
var cipher = encryptor.TransformFinalBlock(input, 0, input.Length);
return Convert.ToBase64String(cipher);
}
private static string EncryptAesBase64(string plainText, string keySource, byte[] iv16)
{
if (iv16.Length != 16) throw new ArgumentException("AES IV must be 16 bytes.", nameof(iv16));
var key32 = Encoding.UTF8.GetBytes((keySource ?? string.Empty).PadRight(32).Substring(0, 32));
using var aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = key32;
aes.IV = iv16;
var input = Encoding.UTF8.GetBytes(plainText);
using var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
var cipher = encryptor.TransformFinalBlock(input, 0, input.Length);
return Convert.ToBase64String(cipher);
}
}

View File

@@ -0,0 +1,57 @@
using System.Data;
using System.Threading;
using System.Threading.Tasks;
using ADS.Apis.Gps.Domain.Models.Sicrep;
using ADS.Apis.Gps.Domain.Ports.Sicrep;
using ADS.Helpers.Data.Abstractions;
using ADS.Helpers.MultiTenant.Abstractions;
using ADS.Helpers.MultiTenant.Context;
using Dapper;
namespace ADS.Apis.Gps.Infrastructure.Data.Dapper;
public sealed class DapperSicrepUserValidationRepository : ISicrepUserValidationRepository
{
private readonly ITenantDbConnectionFactory _connFactory;
private readonly ITenantContextAccessor _tenantAccessor;
public DapperSicrepUserValidationRepository(
ITenantDbConnectionFactory connFactory,
ITenantContextAccessor tenantAccessor)
{
_connFactory = connFactory;
_tenantAccessor = tenantAccessor;
}
public async Task<SicrepUserValidationResult?> ValidateUserAsync(
string usuario,
string contrasena32,
int cveEmpresa,
string? ip,
string? mac,
string? grupoEmpresa,
CancellationToken ct = default)
{
var tenant = _tenantAccessor.Current
?? throw new UnauthorizedAccessException("TenantContext not available.");
// USAMOS TU MÉTODO REAL
using var conn = _connFactory.Create();//tenant.Database.ConnectionString);
var p = new DynamicParameters();
p.Add("@Usuario", usuario, DbType.String, size: 32);
p.Add("@Contraseña", contrasena32, DbType.String, size: 32);
p.Add("@CveEmpresa", cveEmpresa, DbType.Int32);
p.Add("@IP", ip ?? string.Empty, DbType.String, size: 20);
p.Add("@MAC", mac ?? string.Empty, DbType.String, size: 50);
p.Add("@GrupoEmpresa", grupoEmpresa ?? string.Empty, DbType.String, size: 100);
const string sp = "[dbo].[PA_Sis_UsuarioValidacionGet]";
var result = await conn.QueryFirstOrDefaultAsync<SicrepUserValidationResult>(
sp,
p,
commandType: CommandType.StoredProcedure);
return result;
}
}

View File

@@ -0,0 +1,34 @@
using ADS.Apis.Gps.Application.Abstractions.Security;
using ADS.Apis.Gps.Application.Common.Crypto;
using ADS.Apis.Gps.Application.Contracts.Auth;
using ADS.Apis.Gps.Application.UseCases.Auth;
using ADS.Apis.Gps.Domain.Ports.Sicrep;
using ADS.Apis.Gps.Infrastructure.Crypto;
using ADS.Apis.Gps.Infrastructure.Data.Dapper;
using ADS.Apis.Gps.Infrastructure.Security;
using Microsoft.Extensions.DependencyInjection;
namespace ADS.Apis.Gps.Infrastructure.DependencyInjection;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddGpsSicrepAuth(this IServiceCollection services)
{
services.AddScoped<IAdsUserCredentialValidator, AdsUserCredentialValidator>();
services.AddScoped<IAdsClientCredentialValidator, AdsClientCredentialValidator>();
// Domain Ports -> Infrastructure
services.AddScoped<ISicrepUserValidationRepository, DapperSicrepUserValidationRepository>();
// Application
services.AddScoped<ISicrepAuthService, SicrepAuthService>();
return services;
}
public static IServiceCollection AddGpsInfrastructure(this IServiceCollection services, IConfiguration configuration)
{
services.Configure<LegacyCryptoOptions>(configuration.GetSection("LegacyCrypto"));
services.AddSingleton<ILegacyPasswordEncryptor, LegacyPasswordEncryptor>();
return services;
}
}

View File

@@ -0,0 +1,45 @@
using System.Data;
using Dapper;
using ADS.Apis.Gps.Application.Abstractions.Security;
using ADS.Helpers.Data.Abstractions;
namespace ADS.Apis.Gps.Infrastructure.Security;
public sealed class AdsClientCredentialValidator : IAdsClientCredentialValidator
{
private readonly ITenantDbConnectionFactory _db;
public AdsClientCredentialValidator(ITenantDbConnectionFactory db)
{
_db = db;
}
public async Task<AdsClientCredentialResult> ValidateAsync(string clientId, string clientSecret, CancellationToken ct = default)
{
// using var conn = await _db.OpenAsync(ct);
// var p = new DynamicParameters();
// p.Add("@ClientId", clientId, DbType.String);
// p.Add("@ClientSecret", clientSecret, DbType.String);
// var row = await conn.QueryFirstOrDefaultAsync<ClientRow>(
// sql: "PA_Sicrep_ValidateClient",
// param: p,
// commandType: CommandType.StoredProcedure
// );
// if (row is null || row.IsValid == 0)
// return new AdsClientCredentialResult(false, null, null, null);
// return new AdsClientCredentialResult(true, row.ClientId, row.ClientKey, row.ClientName);
return null;
}
private sealed class ClientRow
{
public int IsValid { get; init; }
public int ClientId { get; init; }
public string ClientKey { get; init; } = string.Empty;
public string ClientName { get; init; } = string.Empty;
}
}

View File

@@ -0,0 +1,47 @@
using System.Data;
using Dapper;
using ADS.Apis.Gps.Application.Abstractions.Security;
using ADS.Helpers.Data.Abstractions;
namespace ADS.Apis.Gps.Infrastructure.Security;
public sealed class AdsUserCredentialValidator : IAdsUserCredentialValidator
{
private readonly ITenantDbConnectionFactory _db;
public AdsUserCredentialValidator(ITenantDbConnectionFactory db)
{
_db = db;
}
public async Task<AdsUserCredentialResult> ValidateAsync(string username, string password, CancellationToken ct = default)
{
// using var conn = await _db.OpenAsync(ct);
// // EJEMPLO: si validas con SP
// // Cambia el nombre del SP y los nombres de parámetros a tus reales.
// var p = new DynamicParameters();
// p.Add("@Usuario", username, DbType.String);
// p.Add("@Password", password, DbType.String);
// var row = await conn.QueryFirstOrDefaultAsync<UserRow>(
// sql: "PA_Sicrep_ValidateUser",
// param: p,
// commandType: CommandType.StoredProcedure
// );
// if (row is null || row.IsValid == 0)
// return new AdsUserCredentialResult(false, null, null, null);
// return new AdsUserCredentialResult(true, row.UserId, row.Username, row.DisplayName);
return null;
}
private sealed class UserRow
{
public int IsValid { get; init; }
public int UserId { get; init; }
public string Username { get; init; } = string.Empty;
public string DisplayName { get; init; } = string.Empty;
}
}

View File

@@ -0,0 +1,60 @@
using System.Data;
using ADS.Apis.Gps.Application.Units;
using ADS.Helpers.Data;
using ADS.Helpers.Data.Abstractions;
using Dapper;
namespace ADS.Apis.Gps.Infrastructure.Units;
public sealed class UnitLocationQueryService : IUnitLocationQueryService
{
private readonly ITenantDbConnectionFactory _connectionFactory;
public UnitLocationQueryService(ITenantDbConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}
public async Task<UnitLastLocationResponse?> GetLastLocationByNoEconomicoAsync(
int cveUsuario,
string noEconomico,
CancellationToken ct = default)
{
using var connection = _connectionFactory.Create();
var command = new CommandDefinition(
commandText: "dbo.PA_GPS_DispositovoUbicacionByNoEconomicoGet",
parameters: new
{
CveUsuario = cveUsuario,
NoEconomico = noEconomico
},
commandType: CommandType.StoredProcedure,
cancellationToken: ct
);
return await connection.QueryFirstOrDefaultAsync<UnitLastLocationResponse>(command);
}
public async Task<IReadOnlyList<UnitClientLocationResponse>> GetLocationsByClientAsync(
int cveUsuario,
int cveCliente,
CancellationToken ct = default)
{
using var connection = _connectionFactory.Create();
var command = new CommandDefinition(
commandText: "dbo.PA_GPS_DispositovoUbicacionPorClienteGet",
parameters: new
{
CveUsuario = cveUsuario,
CveCliente = cveCliente
},
commandType: CommandType.StoredProcedure,
cancellationToken: ct
);
var result = await connection.QueryAsync<UnitClientLocationResponse>(command);
return result.AsList();
}
}