Compare commits

...

14 Commits

Author SHA1 Message Date
Developer 02
519df50404 Add culture-specific formatting for SQL parameters
Updated ParamsExtensions to include System.Globalization for
culture-invariant formatting of double values. This change
ensures proper SQL parameterization by avoiding issues with
decimal separators across different cultures.
2025-05-07 15:35:14 +02:00
Developer 02
9a71d2b805 Enhance SQL handling in EnvelopeReceiverController
- Added using directive for EnvelopeGenerator.Application.SQL.
- Updated SQL command formatting to use ToSqlParam() for improved security against SQL injection.
- Modified history creation SQL command to use string interpolation for parameters.
- Removed explicit parameter addition, streamlining SQL parameter handling.
2025-05-07 15:09:00 +02:00
Developer 02
5f8e8deb5b Refactor SQL parameter handling in EnvelopeReceiverController
Updated the SQL command execution in `EnvelopeReceiverController.cs` to use a formatted SQL string with `string.Format` instead of parameterized commands. This change simplifies command preparation but may increase the risk of SQL injection if input values are not properly sanitized.
2025-05-07 15:03:27 +02:00
Developer 02
645153113c Update SQL parameters in DocumentCreateReadSQL class
Modified the parameters for the stored procedure `[dbo].[PRSIG_API_ADD_DOC]` in the `DocumentCreateReadSQL` class. Replaced `@BYTE_DATA` with `@BYTE_DATA1`, repositioned `@ENV_UID`, and ensured `@OUT_DOCID` is explicitly marked as an output parameter.
2025-05-07 14:33:07 +02:00
Developer 02
2ba7f41a21 Remove SQL command string from DocumentCreateReadSQL
This commit removes a SQL command string from the `Raw` property in the `DocumentCreateReadSQL` class. The changes include the deletion of a `USE` statement for the `[DD_ECM]` database, variable declarations, and the execution of a stored procedure. This alters the structure and execution of SQL commands within the class.
2025-05-07 14:27:09 +02:00
Developer 02
c8f21be905 Rename recipient properties for consistency
Updated `CreateEnvelopeReceiverResponse` and `EnvelopeReceiverController` to rename `SentRecipients` to `SentReceiver` and `UnsentRecipients` to `UnsentReceivers`. Adjusted corresponding lists and mappings to ensure uniformity in naming conventions across the codebase.
2025-05-07 14:26:50 +02:00
Developer 02
1875acb7b5 Refactor SQL queries and data mappings
- Updated SQL query in `EnvelopeReceiverAddReadSQL.cs` to select specific columns (`ENVELOPE_ID` and `RECEIVER_ID`) for improved performance and clarity.
- Changed mapping of `SentRecipients` in `EnvelopeReceiverController.cs` to expect a single `ReceiverReadDto` instead of a collection, reflecting a change in data handling.
- Modified `QueryAsync` in `EnvelopeReceiverExecutor.cs` to remove the generic type parameter, allowing for more flexible data handling.
2025-05-07 14:10:20 +02:00
Developer 02
6bdf0d5220 Enhance SQL parameter handling in CreateDocumentAsync
Updated the CreateDocumentAsync method in the DocumentExecutor class to use ToSqlParam() for formatting SQL query parameters. This change improves security by preventing potential SQL injection vulnerabilities associated with direct variable insertion into the SQL string.
2025-05-07 13:28:06 +02:00
Developer 02
ad855b77cd Refactor SQL execution in DocumentCreateReadSQL
Changed namespace for DocumentCreateReadSQL and updated SQL command to use formatted strings for parameters. Simplified DocumentExecutor to directly use the formatted SQL, enhancing clarity and reducing complexity in parameter handling.
2025-05-07 13:21:17 +02:00
Developer 02
a781440252 Refactor EnvelopeReceiverExecutor dependencies
Added the namespace `EnvelopeGenerator.Application.Contracts.Repositories` and removed the unused `Microsoft.Extensions.Logging` import in `EnvelopeReceiverExecutor.cs` to streamline code dependencies.
2025-05-07 13:15:15 +02:00
Developer 02
5fc689ee4d Refactor SQL query execution in AddEnvelopeReceiverAsync
Updated the SQL query execution in the EnvelopeReceiverExecutor class to use a formatted SQL string directly with parameters instead of a parameterized query method. This change simplifies the execution but may introduce SQL injection risks and affect performance.
2025-05-07 13:14:40 +02:00
Developer 02
38d05850e3 Refactor CreateEnvelopeAsync to use string formatting
Updated the `CreateEnvelopeAsync` method in the `EnvelopeExecutor` class to handle SQL parameters by directly formatting the SQL string with `string.Format`, replacing the previous parameterized query approach. This change enhances readability but may introduce potential SQL injection risks if not managed carefully.
2025-05-07 13:11:52 +02:00
Developer 02
06d25b6f5b Refactor SQL handling in EnvelopeGenerator application
- Added `System.Data` using directive in `EnvelopeCreateReadSQL.cs`.
- Updated SQL command strings to use parameter placeholders.
- Corrected method name from `CreateParmas` to `CreateParams` and added output parameter `@OutUid`.
- Made similar updates in `EnvelopeReceiverAddReadSQL.cs`.
- Introduced `ParamsExtensions` class with `ToSqlParam` method for converting .NET objects to SQL-safe parameter strings.
2025-05-07 13:09:59 +02:00
Developer 02
55b01cf396 Refactor command records and simplify document handling
- Updated `ReceiverGetOrCreateCommand` to include a required `IEnumerable<Signature>`.
- Modified `DocumentCreateCommand` to remove `DataAsByte` and enforce a required `DataAsBase64` property with immutability.
- Cleaned up SQL command formatting in `EnvelopeReceiverAddReadSQL`.
- Simplified document validation logic in `EnvelopeReceiverController` by removing redundant checks.
- Changed hardcoded connection string to a variable `_cnnStr` for improved security and flexibility.
2025-05-07 12:04:01 +02:00
11 changed files with 91 additions and 84 deletions

View File

@@ -60,8 +60,8 @@ public class CreateEnvelopeReceiverCommandHandler : IRequestHandler<CreateEnvelo
}
var res = _mapper.Map<CreateEnvelopeReceiverResponse>(envelope);
res.UnsentRecipients = unsentRecipients;
res.SentRecipients = _mapper.Map<IEnumerable<ReceiverReadDto>>(sentRecipients);
res.UnsentReceivers = unsentRecipients;
res.SentReceiver = _mapper.Map<IEnumerable<ReceiverReadDto>>(sentRecipients);
return res;
}
}

View File

@@ -36,14 +36,12 @@ public record ReceiverGetOrCreateCommand([Required] IEnumerable<Signature> Signa
/// <summary>
/// DTO zum Erstellen eines Dokuments.
/// </summary>
/// <param name="DataAsByte">
/// Die Dokumentdaten im Byte-Array-Format. Wird verwendet, wenn das Dokument als Roh-Binärdaten bereitgestellt wird.
/// </param>
public record DocumentCreateCommand(byte[]? DataAsByte = null)
public record DocumentCreateCommand()
{
/// <summary>
/// Die Dokumentdaten im Base64-String-Format. Wird verwendet, wenn das Dokument als Base64-codierter String bereitgestellt wird.
/// </summary>
public string? DataAsBase64 { get; set; }
[Required]
public required string DataAsBase64 { get; init; }
};
#endregion

View File

@@ -30,10 +30,10 @@ public record CreateEnvelopeReceiverResponse : CreateEnvelopeResponse
/// <summary>
///
/// </summary>
public IEnumerable<ReceiverReadDto> SentRecipients { get; set; } = new List<ReceiverReadDto>();
public IEnumerable<ReceiverReadDto> SentReceiver { get; set; } = new List<ReceiverReadDto>();
/// <summary>
///
/// </summary>
public IEnumerable<ReceiverGetOrCreateCommand> UnsentRecipients { get; set; } = new List<ReceiverGetOrCreateCommand>();
public IEnumerable<ReceiverGetOrCreateCommand> UnsentReceivers { get; set; } = new List<ReceiverGetOrCreateCommand>();
}

View File

@@ -10,19 +10,17 @@ namespace EnvelopeGenerator.Application.SQL;
public class DocumentCreateReadSQL : ISQL<EnvelopeDocument>
{
/// <summary>
///
/// Base64, OUT_UID
/// </summary>
public string Raw => @"
USE [DD_ECM]
DECLARE @BYTE_DATA1 as VARBINARY(MAX)
SET @BYTE_DATA1 = CONVERT(VARBINARY(MAX),'@Base64')
SET @BYTE_DATA1 = CONVERT(VARBINARY(MAX),{0})
DECLARE @OUT_DOCID int
EXEC [dbo].[PRSIG_API_ADD_DOC]
@ENV_UID = @OUT_UID,
@BYTE_DATA = @BYTE_DATA1,
@OUT_DOCID = @OUT_DOCID OUTPUT
{1},
@BYTE_DATA1,
@OUT_DOCID OUTPUT
SELECT TOP(1) *
FROM [dbo].[TBSIG_ENVELOPE_DOCUMENT]

View File

@@ -1,6 +1,7 @@
using Dapper;
using EnvelopeGenerator.Application.Contracts.SQLExecutor;
using EnvelopeGenerator.Domain.Entities;
using System.Data;
namespace EnvelopeGenerator.Application.SQL;
@@ -10,18 +11,17 @@ namespace EnvelopeGenerator.Application.SQL;
public class EnvelopeCreateReadSQL : ISQL<Envelope>
{
/// <summary>
///
/// USER_ID, TITLE, TFAEnabled, MESSAGE
/// </summary>
public string Raw => @"
USE [DD_ECM];
DECLARE @OUT_UID varchar(36);
EXEC [dbo].[PRSIG_API_CREATE_ENVELOPE]
@USER_ID = @UserId,
@TITLE = @Title,
@TFAEnabled = @TfaEnabled,
@MESSAGE = @Message,
@OUT_UID = @OUT_UID OUTPUT;
{0},
{1},
{2},
{3},
@OUT_UID OUTPUT;
SELECT TOP(1) *
FROM [dbo].[TBSIG_ENVELOPE]
@@ -36,13 +36,14 @@ public class EnvelopeCreateReadSQL : ISQL<Envelope>
/// <param name="message"></param>
/// <param name="tfaEnabled"></param>
/// <returns></returns>
public static DynamicParameters CreateParmas(int userId, string title = "", string message = "", bool tfaEnabled = false)
public static DynamicParameters CreateParams(int userId, string title = "", string message = "", bool tfaEnabled = false)
{
var parameters = new DynamicParameters();
parameters.Add("@UserId", userId);
parameters.Add("@Title", title);
parameters.Add("@TfaEnabled", tfaEnabled ? 1 : 0);
parameters.Add("@Message", message);
parameters.Add("@OutUid", dbType: DbType.String, size: 36, direction: ParameterDirection.Output);
return parameters;
}
}

View File

@@ -10,21 +10,20 @@ namespace EnvelopeGenerator.Application.SQL;
public class EnvelopeReceiverAddReadSQL : ISQL<Envelope>
{
/// <summary>
///
/// ENV_UID, EMAIL_ADRESS, SALUTATION, PHONE,
/// </summary>
public string Raw => @"
USE [DD_ECM]
DECLARE @OUT_RECEIVER_ID int
EXEC [dbo].[PRSIG_API_CREATE_RECEIVER]
@ENV_UID = @ENV_UID,
@EMAIL_ADRESS = @EMAIL_ADRESS,
@SALUTATION = @SALUTATION,
@PHONE = @PHONE,
@OUT_RECEIVER_ID = @OUT_RECEIVER_ID OUTPUT
{0},
{1},
{2},
{3},
@OUT_RECEIVER_ID OUTPUT
SELECT TOP(1) *
FROM TBSIG_ENVELOPE_RECEIVER
SELECT TOP(1) [ENVELOPE_ID] As EnvelopeId, [RECEIVER_ID] As ReceiverId
FROM [dbo].[TBSIG_ENVELOPE_RECEIVER]
WHERE [GUID] = @OUT_RECEIVER_ID;
";

View File

@@ -0,0 +1,30 @@
using System.Globalization;
namespace EnvelopeGenerator.Application.SQL;
/// <summary>
/// Extension method for converting objects to SQL parameter strings.
/// </summary>
public static class ParamsExtensions
{
/// <summary>
/// Converts a .NET object to its corresponding SQL-safe parameter string.
/// </summary>
/// <param name="obj">The object to convert.</param>
/// <returns>A string representing the SQL parameter.</returns>
public static string ToSqlParam(this object? obj)
{
if (obj is null)
return "NULL";
else if (obj is string strVal)
return $"'{strVal}'";
else if (obj is bool boolVal)
return boolVal ? "1" : "0";
else if (obj is double doubleVal)
return $"'{doubleVal.ToString(CultureInfo.InvariantCulture)}'";
else if (obj is int intVal)
return intVal.ToString();
else
throw new NotSupportedException($"Type '{obj.GetType().FullName}' is not supported for SQL parameter conversion.");
}
}

View File

@@ -6,6 +6,7 @@ using EnvelopeGenerator.Application.DTOs.Receiver;
using EnvelopeGenerator.Application.EnvelopeReceivers.Commands.Create;
using EnvelopeGenerator.Application.EnvelopeReceivers.Queries.Read;
using EnvelopeGenerator.Application.Envelopes.Queries.ReceiverName;
using EnvelopeGenerator.Application.SQL;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.GeneratorAPI.Models;
using MediatR;
@@ -202,35 +203,25 @@ public class EnvelopeReceiverController : ControllerBase
#endregion
#region Add receivers
List<EnvelopeReceiver> sentRecipients = new();
List<ReceiverGetOrCreateCommand> unsentRecipients = new();
List<EnvelopeReceiver> sentReceivers = new();
List<ReceiverGetOrCreateCommand> unsentReceivers = new();
foreach (var receiver in request.Receivers)
{
var envelopeReceiver = await _erExecutor.AddEnvelopeReceiverAsync(envelope.Uuid, receiver.EmailAddress, receiver.Salution, receiver.PhoneNumber, cancel);
if (envelopeReceiver is null)
unsentRecipients.Add(receiver);
unsentReceivers.Add(receiver);
else
sentRecipients.Add(envelopeReceiver);
sentReceivers.Add(envelopeReceiver);
}
var res = _mapper.Map<CreateEnvelopeReceiverResponse>(envelope);
res.UnsentRecipients = unsentRecipients;
res.SentRecipients = _mapper.Map<IEnumerable<ReceiverReadDto>>(sentRecipients);
res.UnsentReceivers = unsentReceivers;
res.SentReceiver = _mapper.Map<List<ReceiverReadDto>>(sentReceivers.Select(er => er.Receiver));
#endregion
#region Add document
if(request.Document.DataAsBase64 is null)
if (request.Document.DataAsByte is null)
return BadRequest("No document data is found");
else
request.Document.DataAsBase64 = Convert.ToBase64String(request.Document.DataAsByte);
else if (request.Document.DataAsByte is not null)
return BadRequest("Document data cannot be assigned as both byte data and base64 string.");
else if (!IsBase64String(request.Document.DataAsBase64))
return BadRequest("Document data is not a base64 string");
var document = await _documentExecutor.CreateDocumentAsync(request.Document.DataAsBase64, envelope.Uuid, cancel);
if(document is null)
@@ -238,36 +229,31 @@ public class EnvelopeReceiverController : ControllerBase
#endregion
#region Add document element
// @DOC_ID, @RECEIVER_ID, @POSITION_X, @POSITION_Y, @PAGE
string sql = @"
USE [DD_ECM]
DECLARE @OUT_SUCCESS bit;
EXEC [dbo].[PRSIG_API_ADD_DOC_RECEIVER_ELEM]
@DOC_ID = @DOC_ID,
@RECEIVER_ID = @RECEIVER_ID,
@POSITION_X = @POSITION_X,
@POSITION_Y = @POSITION_Y,
@PAGE = @PAGE,
@OUT_SUCCESS = @OUT_SUCCESS OUTPUT;
{0},
{1},
{2},
{3},
{4},
@OUT_SUCCESS OUTPUT;
SELECT @OUT_SUCCESS as [@OUT_SUCCESS];";
foreach(var rcv in res.SentRecipients)
foreach(var rcv in res.SentReceiver)
foreach(var sign in request.Receivers.Where(r => r.EmailAddress == rcv.EmailAddress).FirstOrDefault()?.Signatures ?? Array.Empty<Signature>())
{
using (SqlConnection conn = new(_cnnStr))
{
conn.Open();
using SqlCommand cmd = new SqlCommand(sql, conn);
cmd.CommandType = CommandType.Text;
var formattedSQL = string.Format(sql, document.Id.ToSqlParam(), rcv.Id.ToSqlParam(), sign.X.ToSqlParam(), sign.Y.ToSqlParam(), sign.Page.ToSqlParam());
cmd.Parameters.AddWithValue("@DOC_ID", document.Id);
cmd.Parameters.AddWithValue("@RECEIVER_ID", rcv.Id);
cmd.Parameters.AddWithValue("@POSITION_X", sign.X.ToString());
cmd.Parameters.AddWithValue("@POSITION_Y", sign.Y.ToString());
cmd.Parameters.AddWithValue("@PAGE", sign.Page.ToString());
using SqlCommand cmd = new SqlCommand(formattedSQL, conn);
cmd.CommandType = CommandType.Text;
using SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
@@ -279,33 +265,28 @@ public class EnvelopeReceiverController : ControllerBase
#endregion
#region Create history
string connectionString = "Server=YOUR_SERVER;Database=YOUR_DATABASE;Trusted_Connection=True;";
// ENV_UID, STATUS_ID, USER_ID,
string sql_hist = @"
USE [DD_ECM]
DECLARE @OUT_SUCCESS bit;
EXEC [dbo].[PRSIG_API_ADD_HISTORY_STATE]
@ENV_UID = @ENV_UID,
@STATUS_ID = @STATUS_ID,
@USER_ID = @USER_ID,
@OUT_SUCCESS = @OUT_SUCCESS OUTPUT;
{0},
{1},
{2},
@OUT_SUCCESS OUTPUT;
SELECT @OUT_SUCCESS as [@OUT_SUCCESS];";
using (SqlConnection conn = new(connectionString))
using (SqlConnection conn = new(_cnnStr))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(sql_hist, conn))
var formattedSQL_hist = string.Format(sql_hist, envelope.Uuid.ToSqlParam(), 1003.ToSqlParam(), userId.ToSqlParam());
using (SqlCommand cmd = new SqlCommand(formattedSQL_hist, conn))
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("@ENV_UID", envelope.Uuid);
cmd.Parameters.AddWithValue("@STATUS_ID", 1003);
cmd.Parameters.AddWithValue("@USER_ID", userId);
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())

View File

@@ -18,9 +18,9 @@ public class DocumentExecutor : SQLExecutor, IDocumentExecutor
{
using var connection = new SqlConnection(Params.ConnectionString);
var sql = Provider.GetRequiredService<DocumentCreateReadSQL>();
var formattedSql = string.Format(sql.Raw, base64.ToSqlParam(), envelope_uuid.ToSqlParam());
await connection.OpenAsync(cancellation);
var parameters = DocumentCreateReadSQL.CreateParmas(base64, envelope_uuid);
var documents = await connection.QueryAsync<EnvelopeDocument>(sql.Raw, parameters);
var documents = await connection.QueryAsync<EnvelopeDocument>(formattedSql);
return documents.FirstOrDefault()
?? throw new InvalidOperationException($"Document creation failed. Parameters:" +
$"base64={base64}, envelope_uuid='{envelope_uuid}'.");

View File

@@ -23,9 +23,9 @@ public class EnvelopeExecutor : SQLExecutor, IEnvelopeExecutor
{
using var connection = new SqlConnection(Params.ConnectionString);
var sql = Provider.GetRequiredService<EnvelopeCreateReadSQL>();
var formattedSql = string.Format(sql.Raw, userId.ToSqlParam(), title.ToSqlParam(), tfaEnabled.ToSqlParam(), message.ToSqlParam());
await connection.OpenAsync(cancellation);
var parameters = EnvelopeCreateReadSQL.CreateParmas(userId, title, message, tfaEnabled);
var envelopes = await connection.QueryAsync<Envelope>(sql.Raw, parameters);
var envelopes = await connection.QueryAsync<Envelope>(formattedSql);
var envelope = envelopes.FirstOrDefault()
?? throw new InvalidOperationException($"Envelope creation failed. Parameters:" +
$"userId={userId}, title='{title}', message='{message}', tfaEnabled={tfaEnabled}."); ;

View File

@@ -5,7 +5,6 @@ using EnvelopeGenerator.Application.SQL;
using EnvelopeGenerator.Domain.Entities;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace EnvelopeGenerator.Infrastructure.Executor;
@@ -23,8 +22,9 @@ public class EnvelopeReceiverExecutor: SQLExecutor, IEnvelopeReceiverExecutor
{
using var connection = new SqlConnection(Params.ConnectionString);
var sql = Provider.GetRequiredService<EnvelopeReceiverAddReadSQL>();
var formattedSql = string.Format(sql.Raw, envelope_uuid.ToSqlParam(), emailAddress.ToSqlParam(), salutation.ToSqlParam(), phone.ToSqlParam());
await connection.OpenAsync(cancellation);
var envelopeReceivers = await connection.QueryAsync<EnvelopeReceiver>(sql.Raw, EnvelopeReceiverAddReadSQL.CreateParameters(envelope_uuid, emailAddress, salutation, phone));
var envelopeReceivers = await connection.QueryAsync(formattedSql);
var er = envelopeReceivers.FirstOrDefault();
if (er is null)