Refaktorisierung: Absicherung von DB-Operationen und Verbesserung der Geschäftslogik

- Implementierung von LINQ-Abfragen innerhalb der Core-Bibliothek zur Minderung von SQL-Injection-Anfälligkeiten für DB-Operationen von Umschlägen und Empfängern.
- Aktualisierung der Geschäftslogik in der Service-Schicht für verbessertes Transaktionshandling.
- Erweiterung der ServiceMessage um eine neue Flag-Funktion zum Verfolgen von Cybersecurity- und Datenintegritätsproblemen.
- Hinzufügen spezifischer Benutzerverhaltensflags zur besseren Erkennung und Behandlung potenzieller Datenverletzungen.
This commit is contained in:
Developer 02 2024-04-24 13:45:03 +02:00
parent f2e718565d
commit 6338b81571
47 changed files with 644 additions and 310 deletions

View File

@ -2,10 +2,14 @@
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts;
using static EnvelopeGenerator.Common.Constants;
namespace EnvelopeGenerator.Application.Contracts
{
public interface IEnvelopeHistoryService : IBasicCRUDService<IEnvelopeHistoryRepository, EnvelopeHistoryDto, EnvelopeHistory, long>
{
Task<int> CountAsync(int? envelopeId = null, string? userReference = null, int? status = null);
Task<bool> AccessCodeAlreadyRequested(int envelopeId, string userReference);
}
}

View File

@ -7,6 +7,17 @@ namespace EnvelopeGenerator.Application.Contracts
{
public interface IEnvelopeReceiverService : IBasicCRUDService<IEnvelopeReceiverRepository, EnvelopeReceiverDto, EnvelopeReceiver, int>
{
Task<IServiceMessage> VerifyAccessCode(string envelopeUuid, string accessCode);
Task<IServiceResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUuidAsync(string uuid, bool withEnvelope = true, bool withReceiver = false);
Task<IServiceResult<IEnumerable<EnvelopeReceiverDto>>> ReadBySignatureAsync(string signature, bool withEnvelope = false, bool withReceiver = true);
Task<IServiceResult<EnvelopeReceiverDto>> ReadByUuidSignatureAsync(string uuid, string signature, bool withEnvelope = true, bool withReceiver = true);
Task<IServiceResult<EnvelopeReceiverDto>> ReadByEnvelopeReceiverIdAsync(string envelopeReceiverId, bool withEnvelope = true, bool withReceiver = true);
Task<IServiceResult<bool>> VerifyAccessCodeAsync(string uuid, string signature, string accessCode);
Task<IServiceResult<bool>> VerifyAccessCodeAsync(string envelopeReceiverId, string accessCode);
}
}

View File

@ -7,8 +7,8 @@ namespace EnvelopeGenerator.Application.Contracts
{
public interface IEnvelopeService : IBasicCRUDService<IEnvelopeRepository, EnvelopeDto, Envelope, int>
{
Task<IServiceResult<IEnumerable<EnvelopeDto>>> ReadAllWithAsync(bool documents = false, bool receivers = false, bool history = false, bool documentReceiverElement = false);
Task<IServiceResult<IEnumerable<EnvelopeDto>>> ReadAllWithAsync(bool documents = false, bool envelopeReceivers = false, bool history = false, bool documentReceiverElement = false);
Task<IServiceResult<EnvelopeDto>> ReadByUuidAsync(string uuid, string? signature = null, bool withDocuments = false, bool withReceivers = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withAll = false);
Task<IServiceResult<EnvelopeDto>> ReadByUuidAsync(string uuid, string? signature = null, bool withDocuments = false, bool withEnvelopeReceivers = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withUser = false, bool withAll = false);
}
}

View File

@ -1,4 +1,5 @@
using EnvelopeGenerator.Domain.Entities;
using DigitalData.UserManager.Domain.Entities;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.DTOs
{
@ -26,13 +27,13 @@ namespace EnvelopeGenerator.Application.DTOs
int? ExpiresWhenDays,
int? ExpiresWarningWhenDays,
bool DmzMoved,
ReceiverDto? User,
User? User,
EnvelopeType? EnvelopeType,
string? EnvelopeTypeTitle,
bool IsAlreadySent,
string? StatusTranslated,
string? ContractTypeTranslated,
IEnumerable<EnvelopeDocumentDto>? Documents,
IEnumerable<EnvelopeReceiverDto>? Receivers,
IEnumerable<EnvelopeReceiverDto>? EnvelopeReceivers,
IEnumerable<EnvelopeHistoryDto>? History);
}

View File

@ -6,10 +6,10 @@ namespace EnvelopeGenerator.Application.DTOs
int EnvelopeId,
int ReceiverId,
int Sequence,
string Name,
string JobTitle,
string CompanyName,
string PrivateMessage,
string? Name,
string? JobTitle,
string? CompanyName,
string? PrivateMessage,
DateTime AddedWhen,
DateTime? ChangedWhen,
Envelope? Envelope,

View File

@ -4,6 +4,6 @@
int Id,
string EmailAddress,
string Signature,
DateTime AddedWhen,
IEnumerable<EnvelopeReceiverDto>? EnvelopeReceivers);
DateTime AddedWhen
);
}

View File

@ -0,0 +1,7 @@
namespace EnvelopeGenerator.Application
{
public enum EnvelopeFlag
{
EnvelopeOrReceiverNonexists
}
}

View File

@ -22,6 +22,18 @@
<Reference Include="DigitalData.Core.Contracts">
<HintPath>..\..\WebCoreModules\DigitalData.Core.Application\bin\Debug\net7.0\DigitalData.Core.Contracts.dll</HintPath>
</Reference>
<Reference Include="DigitalData.Core.Infrastructure">
<HintPath>..\..\WebUserManager\DigitalData.UserManager.Application\bin\Debug\net7.0\DigitalData.Core.Infrastructure.dll</HintPath>
</Reference>
<Reference Include="DigitalData.UserManager.Application">
<HintPath>..\..\WebUserManager\DigitalData.UserManager.Application\bin\Debug\net7.0\DigitalData.UserManager.Application.dll</HintPath>
</Reference>
<Reference Include="DigitalData.UserManager.Domain">
<HintPath>..\..\WebUserManager\DigitalData.UserManager.Domain\bin\Debug\net7.0\DigitalData.UserManager.Domain.dll</HintPath>
</Reference>
<Reference Include="DigitalData.UserManager.Infrastructure">
<HintPath>..\..\WebUserManager\DigitalData.UserManager.Application\bin\Debug\net7.0\DigitalData.UserManager.Infrastructure.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@ -0,0 +1,39 @@
using EnvelopeGenerator.Application.Services;
using Microsoft.Extensions.Logging;
using System.Text;
namespace EnvelopeGenerator.Application
{
public static class EnvelopeGeneratorExtensions
{
public static void LogEnvelopeError(this ILogger logger, string receiverId, string? message, params object?[] args)
{
(string? envelopeUuid, string? receiverSignature) = receiverId.DecodeEnvelopeReceiverId();
var sb = new StringBuilder($"Envelope Uuid: {envelopeUuid}\nReceiver Signature: {receiverSignature}");
if (message is not null)
sb.AppendLine().Append(message);
logger.Log(LogLevel.Error, sb.ToString(), args);
}
public static void LogEnvelopeError(this ILogger logger, string uuid, string? signature = null, string? message = null, params object?[] args)
{
var sb = new StringBuilder($"Envelope Uuid: {uuid}");
if(signature is not null)
sb.AppendLine().Append($"Receiver Signature: {signature}");
if (message is not null)
sb.AppendLine().Append(message);
logger.Log(LogLevel.Error, sb.ToString(), args);
}
public static string ToTitle(this (string? UUID, string? Signature) envelopeReceiverTuple)
{
return $"Envelope UUID: {envelopeReceiverTuple.UUID}\n Receiver Signature: {envelopeReceiverTuple.Signature}";
}
}
}

View File

@ -0,0 +1,19 @@
namespace EnvelopeGenerator.Application
{
public enum MessageKey
{
EnvelopeNotFound,
EnvelopeReceiverNotFound,
AccessCodeNull2Client,
AccessCodeNull2Logger,
WrongAccessCode,
DataIntegrityIssue,
SecurityBreachOrDataIntegrity,
PossibleDataIntegrityIssue,
SecurityBreach,
PossibleSecurityBreach,
WrongEnvelopeReceiverId2Client, //Do not leak information about the creation of the url. For example, the envelope you are looking for does not exist
WrongEnvelopeReceiverId2Logger,
EnvelopeOrReceiverNonexists
}
}

View File

@ -5,13 +5,76 @@
/// </summary>
public static class EnvelopeGeneratorExtensions
{
/// <summary>
/// Validates whether a given string is a correctly formatted Base-64 encoded string.
/// </summary>
/// <remarks>
/// This method checks the string for proper Base-64 formatting, which includes validating
/// the length of the string (must be divisible by 4). It also checks each character to ensure
/// it belongs to the Base-64 character set (A-Z, a-z, 0-9, '+', '/', and '=' for padding).
/// The method ensures that padding characters ('=') only appear at the end of the string and
/// are in a valid configuration (either one '=' at the end if the string's length % 4 is 3,
/// or two '==' if the length % 4 is 2).
/// </remarks>
/// <param name="input">The Base-64 encoded string to validate.</param>
/// <returns>
/// <c>true</c> if the string is a valid Base-64 encoded string; otherwise, <c>false</c>.
/// </returns>
/// <example>
/// <code>
/// string testString = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnk=";
/// bool isValid = IsValidBase64String(testString);
/// Console.WriteLine(isValid); // Output: true
/// </code>
/// </example>
public static bool IsBase64String(this string input)
{
// Check if the string is null or empty
if (string.IsNullOrEmpty(input))
{
return false;
}
// Replace valid base-64 padding
input = input.Trim();
int mod4 = input.Length % 4;
if (mod4 > 0)
{
// Base-64 string lengths should be divisible by 4
return false;
}
// Check each character to ensure it is valid base-64
foreach (char c in input)
{
if (!char.IsLetterOrDigit(c) && c != '+' && c != '/' && c != '=')
{
// Invalid character detected
return false;
}
}
// Ensure no invalid padding scenarios exist
if (input.EndsWith("==") && (input.Length % 4 == 0) ||
input.EndsWith("=") && (input.Length % 4 == 3))
{
return true;
}
return input.IndexOf('=') == -1; // No padding allowed except at the end
}
/// <summary>
/// Decodes the envelope receiver ID and extracts the envelope UUID and receiver signature.
/// </summary>
/// <param name="envelopeReceiverId">The base64 encoded string containing the envelope UUID and receiver signature.</param>
/// <returns>A tuple containing the envelope UUID and receiver signature.</returns>
public static (string EnvelopeUuid, string ReceiverSignature) DecodeEnvelopeReceiverId(this string envelopeReceiverId)
public static (string? EnvelopeUuid, string? ReceiverSignature) DecodeEnvelopeReceiverId(this string envelopeReceiverId)
{
if (!envelopeReceiverId.IsBase64String())
{
return (null, null);
}
byte[] bytes = Convert.FromBase64String(envelopeReceiverId);
string decodedString = System.Text.Encoding.UTF8.GetString(bytes);
string[] parts = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);

View File

@ -5,6 +5,7 @@ using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts;
using static EnvelopeGenerator.Common.Constants;
namespace EnvelopeGenerator.Application.Services
{
@ -14,5 +15,9 @@ namespace EnvelopeGenerator.Application.Services
: base(repository, translationService, mapper)
{
}
public async Task<int> CountAsync(int? envelopeId = null, string? userReference = null, int? status = null) => await _repository.CountAsync(envelopeId: envelopeId, userReference: userReference, status: status);
public async Task<bool> AccessCodeAlreadyRequested(int envelopeId, string userReference) => await _repository.CountAsync(envelopeId: envelopeId, userReference:userReference, status: (int) EnvelopeStatus.AccessCodeRequested) > 0;
}
}

View File

@ -6,7 +6,6 @@ using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts;
using Microsoft.EntityFrameworkCore;
namespace EnvelopeGenerator.Application.Services
{
@ -17,10 +16,84 @@ namespace EnvelopeGenerator.Application.Services
{
}
public async Task<IServiceMessage> VerifyAccessCode(string envelopeUuid, string accessCode)
public async Task<IServiceResult<IEnumerable<EnvelopeReceiverDto>>> ReadBySignatureAsync(string signature, bool withEnvelope = false, bool withReceiver = true)
{
var envelopeAccessCode = await _repository.ReadAccessCodeByEnvelopeUuid(envelopeUuid);
return CreateMessage(isSuccess: accessCode == envelopeAccessCode) ;
var env_rcvs = await _repository.ReadBySignatureAsync(signature: signature, withEnvelope: withEnvelope, withReceiver: withReceiver);
return Successful(_mapper.MapOrThrow<IEnumerable<EnvelopeReceiverDto>>(env_rcvs));
}
public async Task<IServiceResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUuidAsync(string uuid, bool withEnvelope = true, bool withReceiver = false)
{
var env_rcvs = await _repository.ReadByUuidAsync(uuid: uuid, withEnvelope: withEnvelope, withReceiver: withReceiver);
return Successful(_mapper.MapOrThrow<IEnumerable<EnvelopeReceiverDto>>(env_rcvs));
}
public async Task<IServiceResult<EnvelopeReceiverDto>> ReadByUuidSignatureAsync(string uuid, string signature, bool withEnvelope = true, bool withReceiver = true)
{
var env_rcv = await _repository.ReadByUuidSignatureAsync(uuid: uuid, signature: signature, withEnvelope: withEnvelope, withReceiver: withReceiver);
if (env_rcv is null)
return Failed<EnvelopeReceiverDto>()
.WithClientMessageKey(MessageKey.EnvelopeReceiverNotFound);
return Successful(_mapper.MapOrThrow<EnvelopeReceiverDto>(env_rcv));
}
public async Task<IServiceResult<EnvelopeReceiverDto>> ReadByEnvelopeReceiverIdAsync(string envelopeReceiverId, bool withEnvelope = true, bool withReceiver = true)
{
(string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
if (uuid is null || signature is null)
return Failed<EnvelopeReceiverDto>()
.WithClientMessageKey(MessageKey.WrongEnvelopeReceiverId2Client)
.WithWarningMessage((uuid, signature).ToTitle())
.WithWarningMessageKey(MessageKey.WrongEnvelopeReceiverId2Logger)
.WithWarningMessageKey(MessageKey.PossibleSecurityBreach)
.WithFlag(Flag.PossibleSecurityBreach);
return await ReadByUuidSignatureAsync(uuid: uuid, signature: signature, withEnvelope: withEnvelope, withReceiver: withReceiver);
}
public async Task<IServiceResult<bool>> VerifyAccessCodeAsync(string uuid, string signature, string accessCode)
{
var er = await _repository.ReadByUuidSignatureAsync(uuid: uuid, signature: signature);
if (er is null)
return Failed<bool>()
.WithClientMessageKey(MessageKey.EnvelopeOrReceiverNonexists)
.WithWarningMessage((uuid, signature).ToTitle())
.WithWarningMessageKey(MessageKey.EnvelopeOrReceiverNonexists)
.WithWarningMessageKey(MessageKey.PossibleDataIntegrityIssue)
.WithFlag(MessageKey.PossibleDataIntegrityIssue);
var actualAccessCode = er.AccessCode;
if (actualAccessCode is null)
return Failed<bool>()
.WithClientMessageKey(MessageKey.AccessCodeNull2Client)
.WithCriticalMessage((uuid, signature).ToTitle())
.WithCriticalMessageKey(MessageKey.AccessCodeNull2Logger)
.WithCriticalMessageKey(MessageKey.DataIntegrityIssue)
.WithFlag(Flag.DataIntegrityIssue);
else if(accessCode != actualAccessCode)
return Successful(false).WithClientMessageKey(MessageKey.WrongAccessCode);
else
return Successful(true);
}
public async Task<IServiceResult<bool>> VerifyAccessCodeAsync(string envelopeReceiverId, string accessCode)
{
(string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
if (uuid is null || signature is null)
return Failed<bool>()
.WithClientMessageKey(MessageKey.WrongEnvelopeReceiverId2Client)
.WithCriticalMessageKey(MessageKey.WrongEnvelopeReceiverId2Logger)
.WithCriticalMessageKey(MessageKey.SecurityBreach)
.WithCriticalMessage("Attempt to verify access code detected. Such actions are generally not initiated by well-intentioned users. Potential security breach suspected. Immediate investigation required.")
.WithFlag(Flag.SecurityBreach);
return await VerifyAccessCodeAsync(uuid: uuid, signature: signature, accessCode: accessCode);
}
}
}

View File

@ -6,26 +6,29 @@ using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts;
using Microsoft.Extensions.Logging;
namespace EnvelopeGenerator.Application.Services
{
public class EnvelopeService : BasicCRUDService<IEnvelopeRepository, EnvelopeDto, Envelope, int>, IEnvelopeService
{
public EnvelopeService(IEnvelopeRepository repository, IKeyTranslationService translationService, IMapper mapper)
private readonly ILogger _logger;
public EnvelopeService(IEnvelopeRepository repository, IKeyTranslationService translationService, IMapper mapper, ILogger<EnvelopeService> logger)
: base(repository, translationService, mapper)
{
_logger = logger;
}
public async Task<IServiceResult<IEnumerable<EnvelopeDto>>> ReadAllWithAsync(bool documents = false, bool receivers = false, bool history = false, bool documentReceiverElement = false)
public async Task<IServiceResult<IEnumerable<EnvelopeDto>>> ReadAllWithAsync(bool documents = false, bool envelopeReceivers = false, bool history = false, bool documentReceiverElement = false)
{
var envelopes = await _repository.ReadAllWithAsync(documents: documents, receivers: receivers, history: history, documentReceiverElement: documentReceiverElement);
var envelopes = await _repository.ReadAllWithAsync(documents: documents, envelopeReceivers: envelopeReceivers, history: history, documentReceiverElement: documentReceiverElement);
var readDto = _mapper.MapOrThrow<IEnumerable<EnvelopeDto>>(envelopes);
return Successful(readDto);
}
public async Task<IServiceResult<EnvelopeDto>> ReadByUuidAsync(string uuid, string? signature = null, bool withDocuments = false, bool withReceivers = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withAll = false)
public async Task<IServiceResult<EnvelopeDto>> ReadByUuidAsync(string uuid, string? signature = null, bool withDocuments = false, bool withEnvelopeReceivers = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withUser = false, bool withAll = false)
{
var envelope = await _repository.ReadByUuidAsync(uuid: uuid, signature: signature, withDocuments: withDocuments, withReceivers: withReceivers, withHistory: withHistory, withDocumentReceiverElement: withDocumentReceiverElement, withAll:withAll);
var envelope = await _repository.ReadByUuidAsync(uuid: uuid, signature: signature, withDocuments: withDocuments, withEnvelopeReceivers: withEnvelopeReceivers, withHistory: withHistory, withDocumentReceiverElement: withDocumentReceiverElement, withUser:withUser, withAll:withAll);
if (envelope is null)
return Failed<EnvelopeDto>();

View File

@ -1,119 +0,0 @@
namespace EnvelopeGenerator.Domain
{
public class Constants
{
#region Status Fields
public enum EnvelopeStatus
{
Invalid = 0,
EnvelopeCreated = 1001,
EnvelopeSaved = 1002,
EnvelopeQueued = 1003,
EnvelopeSent = 1004, // Not used
EnvelopePartlySigned = 1005,
EnvelopeCompletelySigned = 1006,
EnvelopeReportCreated = 1007,
EnvelopeArchived = 1008,
EnvelopeDeleted = 1009,
AccessCodeRequested = 2001,
AccessCodeCorrect = 2002,
AccessCodeIncorrect = 2003,
DocumentOpened = 2004,
DocumentSigned = 2005,
SignatureConfirmed = 2006,
MessageInvitationSent = 3001, // Used by Trigger
MessageAccessCodeSent = 3002,
MessageConfirmationSent = 3003,
MessageDeletionSent = 3004,
MessageCompletionSent = 3005
}
public enum ElementStatus
{
Created = 0
}
public enum DocumentStatus
{
Created = 0,
Signed = 1
}
public enum ReceiverStatus
{
Unsigned = 0,
Signed = 1
}
#endregion
#region Type Fields
public enum ElementType
{
Signature = 1
}
public enum ContractType
{
Contract = 1,
ReadAndSign = 2
}
public enum ColorType
{
ReceiverColor1 = 1,
ReceiverColor2 = 2,
ReceiverColor3 = 3,
ReceiverColor4 = 4,
ReceiverColor5 = 5,
ReceiverColor6 = 6,
ReceiverColor7 = 7,
ReceiverColor8 = 8,
ReceiverColor9 = 9,
ReceiverColor10 = 10
}
public enum CertificationType
{
ElectronicSignature = 1,
QualifiedSignature = 2
}
public enum FinalEmailType
{
No = 0,
Yes = 1,
YesWithAttachment = 2
}
public enum PageOrientation
{
Portrait = 0,
Landscape = 1
}
public enum EmailTemplateType
{
DocumentReceived,
DocumentSigned,
DocumentDeleted,
DocumentCompleted,
DocumentAccessCodeReceived
}
#endregion
#region Constants
public const string DATABASE = "DATABASE";
public const string LOGCONFIG = "LOGCONFIG";
public const string GDPICTURE = "GDPICTURE";
public const string GREEN_300 = "#bbf7d0";
public const string RED_300 = "#fecaca";
public const string ORANGE_300 = "#fed7aa";
#endregion
}
}

View File

@ -1,4 +1,5 @@
using EnvelopeGenerator.Common.My.Resources;
using EnvelopeGenerator.Common;
using EnvelopeGenerator.Common.My.Resources;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@ -84,8 +85,11 @@ namespace EnvelopeGenerator.Domain.Entities
[Column("DMZ_MOVED")]
public bool DmzMoved { get; set; }
/// <summary>
/// The sender of envelope
/// </summary>
[ForeignKey("UserId")]
public Receiver? User { get; set; }
public DigitalData.UserManager.Domain.Entities.User? User { get; set; }
[ForeignKey("EnvelopeTypeId")]
public EnvelopeType? EnvelopeType { get; set; }
@ -111,7 +115,7 @@ namespace EnvelopeGenerator.Domain.Entities
public IEnumerable<EnvelopeDocument>? Documents { get; set; }
public IEnumerable<EnvelopeReceiver>? Receivers { get; set; }
public IEnumerable<EnvelopeReceiver>? EnvelopeReceivers { get; set; }
public IEnumerable<EnvelopeHistory>? History { get; set; }
}

View File

@ -19,19 +19,19 @@ namespace EnvelopeGenerator.Domain.Entities
public int Sequence { get; set; }
[Column("NAME", TypeName = "nvarchar(128)")]
public string Name { get; set; }
public string? Name { get; set; }
[Column("JOB_TITLE", TypeName = "nvarchar(128)")]
public string JobTitle { get; set; }
public string? JobTitle { get; set; }
[Column("COMPANY_NAME", TypeName = "nvarchar(128)")]
public string CompanyName { get; set; }
public string? CompanyName { get; set; }
[Column("PRIVATE_MESSAGE", TypeName = "nvarchar(max)")]
public string PrivateMessage { get; set; }
public string? PrivateMessage { get; set; }
[Column("ACCESS_CODE", TypeName = "nvarchar(64)")]
public string AccessCode { get; set; }
public string? AccessCode { get; set; }
[Required]
[Column("ADDED_WHEN", TypeName = "datetime")]

View File

@ -22,7 +22,5 @@ namespace EnvelopeGenerator.Domain.Entities
[Required]
[Column("ADDED_WHEN", TypeName = "datetime")]
public DateTime AddedWhen { get; set; }
public IEnumerable<EnvelopeReceiver>? EnvelopeReceivers { get; set; }
}
}

View File

@ -10,4 +10,10 @@
<ProjectReference Include="..\EnvelopeGenerator.Common\EnvelopeGenerator.Common.vbproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="DigitalData.UserManager.Domain">
<HintPath>..\..\WebUserManager\DigitalData.UserManager.Domain\bin\Debug\net7.0\DigitalData.UserManager.Domain.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@ -5,5 +5,6 @@ namespace EnvelopeGenerator.Infrastructure.Contracts
{
public interface IEnvelopeHistoryRepository : ICRUDRepository<EnvelopeHistory, long>
{
Task<int> CountAsync(int? envelopeId = null, string? userReference = null, int? status = null);
}
}

View File

@ -5,6 +5,12 @@ namespace EnvelopeGenerator.Infrastructure.Contracts
{
public interface IEnvelopeReceiverRepository : ICRUDRepository<EnvelopeReceiver, int>
{
Task<string?> ReadAccessCodeByEnvelopeUuid(string envelopeUuid);
Task<IEnumerable<EnvelopeReceiver>> ReadByUuidAsync(string uuid, bool withEnvelope = true, bool withReceiver = false);
Task<IEnumerable<EnvelopeReceiver>> ReadBySignatureAsync(string signature, bool withEnvelope = false, bool withReceiver = true);
Task<EnvelopeReceiver?> ReadByUuidSignatureAsync(string uuid, string signature, bool withEnvelope = true, bool withReceiver = true);
Task<string?> ReadAccessCodeAsync(string uuid, string signature);
}
}

View File

@ -5,8 +5,8 @@ namespace EnvelopeGenerator.Infrastructure.Contracts
{
public interface IEnvelopeRepository : ICRUDRepository<Envelope, int>
{
Task<IEnumerable<Envelope>> ReadAllWithAsync(bool documents = false, bool receivers = false, bool history = false, bool documentReceiverElement = true);
Task<IEnumerable<Envelope>> ReadAllWithAsync(bool documents = false, bool envelopeReceivers = false, bool history = false, bool documentReceiverElement = true);
Task<Envelope?> ReadByUuidAsync(string uuid, string? signature = null, bool withDocuments = false, bool withReceivers = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withAll = false);
Task<Envelope?> ReadByUuidAsync(string uuid, string? signature = null, bool withDocuments = false, bool withEnvelopeReceivers = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withUser = false, bool withAll = false);
}
}

View File

@ -26,6 +26,9 @@
<Reference Include="DigitalData.Core.Infrastructure">
<HintPath>..\..\WebCoreModules\DigitalData.Core.Infrastructure\bin\Debug\net7.0\DigitalData.Core.Infrastructure.dll</HintPath>
</Reference>
<Reference Include="DigitalData.UserManager.Domain">
<HintPath>..\..\WebUserManager\DigitalData.UserManager.Domain\bin\Debug\net7.0\DigitalData.UserManager.Domain.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@ -2,6 +2,7 @@
using DigitalData.UserManager.Infrastructure.Repositories;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts;
using Microsoft.EntityFrameworkCore;
namespace EnvelopeGenerator.Infrastructure.Repositories
{
@ -10,5 +11,21 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
public EnvelopeHistoryRepository(EGDbContext dbContext) : base(dbContext)
{
}
public async Task<int> CountAsync(int? envelopeId = null, string? userReference = null, int? status = null)
{
var query = _dbSet.AsQueryable();
if (envelopeId is not null)
query = query.Where(eh => eh.EnvelopeId == envelopeId);
if (userReference is not null)
query = query.Where(eh => eh.UserReference == userReference);
if (status is not null)
query = query.Where(eh => eh.Status == status);
return await query.CountAsync();
}
}
}

View File

@ -23,7 +23,7 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
query = query.Include(e => e.Documents);
if (receivers)
query = query.Include(e => e.Receivers);
query = query.Include(e => e.EnvelopeReceivers);
if (history)
query = query.Include(e => e.History);
@ -31,12 +31,12 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
return await query.ToListAsync();
}
public async Task<Envelope?> ReadByUuidAsync(string uuid, string? signature = null, bool withDocuments = false, bool withReceivers = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withAll = false)
public async Task<Envelope?> ReadByUuidAsync(string uuid, string? signature = null, bool withDocuments = false, bool withEnvelopeReceivers = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withUser = false, bool withAll = false)
{
var query = _dbSet.Where(e => e.Uuid == uuid);
if (signature is not null)
query = query.Where(e => e.Receivers != null && e.Receivers.Any(er => er.Receiver != null && er.Receiver.Signature == signature));
query = query.Where(e => e.EnvelopeReceivers != null && e.EnvelopeReceivers.Any(er => er.Receiver != null && er.Receiver.Signature == signature));
if (withAll || withDocuments)
if (withAll || withDocumentReceiverElement)
@ -44,8 +44,11 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
else
query = query.Include(e => e.Documents);
if (withAll || withReceivers)
query = query.Include(e => e.Receivers!).ThenInclude(er => er.Receiver);
if (withAll || withEnvelopeReceivers)
query = query.Include(e => e.EnvelopeReceivers!).ThenInclude(er => er.Receiver);
if (withAll || withUser)
query = query.Include(e => e.User!);
if (withAll || withHistory)
query = query.Include(e => e.History);

View File

@ -3,6 +3,7 @@ using DigitalData.UserManager.Infrastructure.Repositories;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts;
using Microsoft.EntityFrameworkCore;
using System;
namespace EnvelopeGenerator.Infrastructure.Repositories
{
@ -12,14 +13,37 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
{
}
public async Task<string?> ReadAccessCodeByEnvelopeUuid(string envelopeUuid)
private IQueryable<EnvelopeReceiver> ReadWhere(string? uuid = null, string? signature = null, bool withEnvelope = false, bool withReceiver = false)
{
var accessCode = await _dbSet
.Where(er => er.Envelope != null && er.Envelope.Uuid == envelopeUuid)
var query = _dbSet.AsQueryable();
if(uuid is not null)
query = query.Where(er => er.Envelope != null && er.Envelope.Uuid == uuid);
if (signature is not null)
query = query.Where(er => er.Receiver != null && er.Receiver.Signature == signature);
if (withEnvelope)
query = query.Include(er => er.Envelope);
if (withReceiver)
query = query.Include(er => er.Receiver);
return query;
}
public async Task<IEnumerable<EnvelopeReceiver>> ReadByUuidAsync(string uuid, bool withEnvelope = true, bool withReceiver = false)
=> await ReadWhere(uuid: uuid, withEnvelope: withEnvelope, withReceiver: withReceiver).ToListAsync();
public async Task<IEnumerable<EnvelopeReceiver>> ReadBySignatureAsync(string signature, bool withEnvelope = false, bool withReceiver = true)
=> await ReadWhere(signature: signature, withEnvelope: withEnvelope, withReceiver: withReceiver).ToListAsync();
public async Task<EnvelopeReceiver?> ReadByUuidSignatureAsync(string uuid, string signature, bool withEnvelope = true, bool withReceiver = true)
=> await ReadWhere(uuid: uuid, signature: signature, withEnvelope: withEnvelope, withReceiver: withReceiver).FirstOrDefaultAsync();
public async Task<string?> ReadAccessCodeAsync(string uuid, string signature)
=> await ReadWhere(uuid:uuid, signature:signature)
.Select(er => er.AccessCode)
.FirstOrDefaultAsync();
return accessCode;
}
}
}

View File

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="EnvelopeGenerator.Service.My.MySettings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="EnvelopeGenerator.Service.My.MySettings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

View File

@ -11,7 +11,7 @@
<AssemblyName>EnvelopeGenerator.Service</AssemblyName>
<FileAlignment>512</FileAlignment>
<MyType>Console</MyType>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
</PropertyGroup>

View File

@ -1,10 +1,10 @@
'------------------------------------------------------------------------------
' <auto-generated>
' Dieser Code wurde von einem Tool generiert.
' Laufzeitversion:4.0.30319.42000
' This code was generated by a tool.
' Runtime Version:4.0.30319.42000
'
' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
' der Code erneut generiert wird.
' Changes to this file may cause incorrect behavior and will be lost if
' the code is regenerated.
' </auto-generated>
'------------------------------------------------------------------------------

View File

@ -1,10 +1,10 @@
'------------------------------------------------------------------------------
' <auto-generated>
' Dieser Code wurde von einem Tool generiert.
' Laufzeitversion:4.0.30319.42000
' This code was generated by a tool.
' Runtime Version:4.0.30319.42000
'
' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
' der Code erneut generiert wird.
' Changes to this file may cause incorrect behavior and will be lost if
' the code is regenerated.
' </auto-generated>
'------------------------------------------------------------------------------
@ -15,12 +15,12 @@ Imports System
Namespace My.Resources
'Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert
'-Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert.
'Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
'mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu.
'This class was auto-generated by the StronglyTypedResourceBuilder
'class via a tool like ResGen or Visual Studio.
'To add or remove a member, edit your .ResX file then rerun ResGen
'with the /str option, or rebuild your VS project.
'''<summary>
''' Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
''' A strongly-typed resource class, for looking up localized strings, etc.
'''</summary>
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0"), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
@ -33,7 +33,7 @@ Namespace My.Resources
Private resourceCulture As Global.System.Globalization.CultureInfo
'''<summary>
''' Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
''' Returns the cached ResourceManager instance used by this class.
'''</summary>
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
@ -47,8 +47,8 @@ Namespace My.Resources
End Property
'''<summary>
''' Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
''' Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
''' Overrides the current thread's CurrentUICulture property for all
''' resource lookups using this strongly typed resource class.
'''</summary>
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Friend Property Culture() As Global.System.Globalization.CultureInfo

View File

@ -1,10 +1,10 @@
'------------------------------------------------------------------------------
' <auto-generated>
' Dieser Code wurde von einem Tool generiert.
' Laufzeitversion:4.0.30319.42000
' This code was generated by a tool.
' Runtime Version:4.0.30319.42000
'
' Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
' der Code erneut generiert wird.
' Changes to this file may cause incorrect behavior and will be lost if
' the code is regenerated.
' </auto-generated>
'------------------------------------------------------------------------------
@ -15,14 +15,14 @@ Option Explicit On
Namespace My
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.3.0.0"), _
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.9.0.0"), _
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
Partial Friend NotInheritable Class MySettings
Inherits Global.System.Configuration.ApplicationSettingsBase
Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings()),MySettings)
#Region "Automatische My.Settings-Speicherfunktion"
#Region "My.Settings Auto-Save Functionality"
#If _MyType = "WindowsForms" Then
Private Shared addedHandler As Boolean

View File

@ -1,8 +1,6 @@
using DigitalData.Modules.Logging;
using EnvelopeGenerator.Common;
using EnvelopeGenerator.Common;
using EnvelopeGenerator.Web.Services;
using Microsoft.AspNetCore.Mvc;
using System.Text;
namespace EnvelopeGenerator.Web.Controllers
{

View File

@ -9,6 +9,8 @@ using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using DigitalData.Core.API;
using DigitalData.Core.Application;
namespace EnvelopeGenerator.Web.Controllers
{
@ -18,63 +20,36 @@ namespace EnvelopeGenerator.Web.Controllers
private readonly IConfiguration _config;
private readonly IEnvelopeReceiverService _envRcvService;
private readonly IEnvelopeService _envelopeService;
public HomeController(DatabaseService databaseService, EnvelopeOldService envelopeOldService, ILogger<HomeController> logger, IConfiguration configuration, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeService envelopeService) : base(databaseService, logger)
private readonly IEnvelopeHistoryService _historyService;
public HomeController(DatabaseService databaseService, EnvelopeOldService envelopeOldService, ILogger<HomeController> logger, IConfiguration configuration, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeService envelopeService, IEnvelopeHistoryService historyService) : base(databaseService, logger)
{
this.envelopeOldService = envelopeOldService;
_envRcvService = envelopeReceiverService;
_envelopeService = envelopeService;
_config = configuration;
}
[HttpGet("/")]
public IActionResult Index()
{
return View();
}
[HttpPost("/")]
public IActionResult DebugEnvelopes([FromForm] string? password)
{
try
{
var passwordFromConfig = _config["Config:AdminPassword"];
if (passwordFromConfig == null)
{
ViewData["error"] = "No admin password configured!";
return View("Index");
}
if (password != passwordFromConfig)
{
ViewData["error"] = "Wrong Password!";
return View("Index");
}
List<Envelope> envelopes = envelopeOldService.LoadEnvelopes();
return View(envelopes);
}
catch(Exception ex)
{
_logger.LogError(ex, "Unexpected error");
ViewData["error"] = "Unknown error!";
return View("Index");
}
_historyService = historyService;
}
[HttpGet("/EnvelopeKey/{envelopeReceiverId}")]
public async Task<IActionResult> SendAccessCode([FromRoute] string envelopeReceiverId)
{
var envelope = await _envelopeService.ReadByUuidAsync(envelopeReceiverId.GetEnvelopeUuid());
ViewData["EnvelopeKey"] = envelopeReceiverId;
try
{
(string envelopeUuid, string receiverSignature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
var envelopeResult = await _envelopeService.ReadByUuidAsync(envelopeUuid, signature: receiverSignature, withEnvelopeReceivers:true);
var envelope = envelopeResult.Data;
var envelopeReceiver = envelope?.EnvelopeReceivers?.FirstOrDefault();
var mailAddress = envelopeReceiver?.Receiver?.EmailAddress;
var useAccessCode = envelope?.UseAccessCode;
ViewData["EnvelopeResult"] = envelopeResult;
if(envelopeResult.IsSuccess && envelope is not null && mailAddress is not null && (envelope.UseAccessCode ?? false))
{
EnvelopeResponse response = await envelopeOldService.LoadEnvelope(envelopeReceiverId);
if (response.Envelope.UseAccessCode)
{
bool accessCodeAlreadyRequested = database.Models.receiverModel.AccessCodeAlreadyRequested(response.Receiver.Email, response.Envelope.Id);
accessCodeAlreadyRequested = await _historyService.AccessCodeAlreadyRequested(envelopeId: envelope.Id, userReference: mailAddress);
if (!accessCodeAlreadyRequested)
{
// Send email with password
@ -82,36 +57,64 @@ namespace EnvelopeGenerator.Web.Controllers
bool result = database.Services.emailService.SendDocumentAccessCodeReceivedEmail(response.Envelope, response.Receiver);
}
}
return Redirect($"/EnvelopeKey/{envelopeReceiverId}/Locked");
else
{
envelopeResult.WithMessageKey(MessageKey.FailedToSendAccessCode);
_logger.LogError($"{MessageKey.FailedToSendAccessCode.ToString()}");
}
}
catch(Exception ex)
{
_logger.LogError(ex, MessageKey.UnexpectedError.ToString());
}
[HttpGet("/EnvelopeKey/{envelopeReceiverId}/Locked")]
return View("EnvelopeLocked").WithData("EnvelopeKey", envelopeReceiverId);
}
[HttpGet("EnvelopeKey/{envelopeReceiverId}/Locked")]
public IActionResult EnvelopeLocked([FromRoute] string envelopeReceiverId)
{
ViewData["EnvelopeKey"] = envelopeReceiverId;
return View();
return View().WithData("EnvelopeKey", envelopeReceiverId);
}
[HttpPost("/EnvelopeKey/{envelopeReceiverId}/Locked")]
public async Task<IActionResult> LogInEnvelope([FromRoute] string envelopeReceiverId, [FromForm] string access_code)
{
var decodedId = envelopeReceiverId.DecodeEnvelopeReceiverId();
try
{
(string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
_logger.LogInformation($"Envelope UUID: [{decodedId.EnvelopeUuid}]");
_logger.LogInformation($"Receiver Signature: [{decodedId.ReceiverSignature}]");
if(uuid is null || signature is null)
{
_logger.LogWarning($"{MessageKey.WrongEnvelopeReceiverId.ToString()}");
return BadRequest(_envelopeService.CreateMessage(false, MessageKey.WrongEnvelopeReceiverId.ToString()));
}
_logger.LogInformation($"Envelope UUID: [{uuid}]\nReceiver Signature: [{signature}]");
var verification = await _envRcvService.VerifyAccessCodeAsync(uuid: uuid, signature: signature, accessCode: access_code);
var isVerified = verification.Data;
var verification = await _envRcvService.VerifyAccessCode(decodedId.EnvelopeUuid, access_code);
EnvelopeResponse response = await envelopeOldService.LoadEnvelope(envelopeReceiverId);
if (verification.IsSuccess)
if (!verification.IsSuccess)
{
_logger.LogServiceMessage(verification);
if (verification.HasFlag(Flag.SecurityBreach))
return Forbid();
return StatusCode(StatusCodes.Status500InternalServerError, verification.ClientMessages.Join());
}
else if (isVerified)
{
if (envelopeOldService.ReceiverAlreadySigned(response.Envelope, response.Receiver.Id))
{
return Redirect("/EnvelopeKey/{envelopeReceiverId}/Success");
return Redirect($"/EnvelopeKey/{envelopeReceiverId}/Success");
}
var envelope = await _envelopeService.ReadByUuidAsync(uuid: decodedId.EnvelopeUuid, signature: decodedId.ReceiverSignature, withAll: true);
var envelope = await _envelopeService.ReadByUuidAsync(uuid: uuid, signature: signature, withAll: true);
database.Services.actionService.EnterCorrectAccessCode(response.Envelope, response.Receiver); //for history
ViewData["EnvelopeKey"] = envelopeReceiverId;
ViewData["EnvelopeResponse"] = response;
@ -127,8 +130,8 @@ namespace EnvelopeGenerator.Web.Controllers
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, decodedId.EnvelopeUuid),
new Claim(ClaimTypes.Hash, decodedId.ReceiverSignature),
new Claim(ClaimTypes.NameIdentifier, uuid),
new Claim(ClaimTypes.Hash, signature),
};
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
@ -146,10 +149,17 @@ namespace EnvelopeGenerator.Web.Controllers
else
{
database.Services.actionService.EnterIncorrectAccessCode(response.Envelope, response.Receiver); //for history
_logger.LogWarning(string.Join("\n", verification.Messages));
return Unauthorized();
}
}
catch(Exception ex)
{
_logger.LogError(ex, MessageKey.UnexpectedError.ToString());
return this.InnerServiceError(messageKey: MessageKey.UnexpectedError);
}
}
[HttpGet("/EnvelopeKey/{envelopeReceiverId}/Success")]
public async Task<IActionResult> EnvelopeSigned(string envelopeReceiverId)
@ -168,14 +178,11 @@ namespace EnvelopeGenerator.Web.Controllers
return Ok(new { EnvelopeUuid = envelopeUuid, ReceiverSignature = receiverSignature });
}
[HttpGet("Error")]
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
[Authorize]
[HttpGet("test")]
public string Test() => "Test";
}
}

View File

@ -14,13 +14,10 @@ namespace EnvelopeGenerator.Web.Controllers.Test
}
[NonAction]
public override Task<IActionResult> GetAll()
{
return base.GetAll();
}
public override Task<IActionResult> GetAll() => base.GetAll();
[HttpGet]
public virtual async Task<IActionResult> GetAll([FromQuery] string? envelopeKey = default, [FromQuery] bool withDocuments = false, [FromQuery] bool withReceivers = false, [FromQuery] bool withHistory = false, [FromQuery] bool withDocumentReceiverElement = false, [FromQuery] bool withAll = true)
public async Task<IActionResult> GetAll([FromQuery] string? envelopeKey = default, [FromQuery] bool withDocuments = false, [FromQuery] bool withEnvelopeReceivers = false, [FromQuery] bool withHistory = false, [FromQuery] bool withDocumentReceiverElement = false, [FromQuery] bool withUser = false, [FromQuery] bool withAll = true)
{
if(envelopeKey is not null)
{
@ -29,7 +26,7 @@ namespace EnvelopeGenerator.Web.Controllers.Test
var envlopeServiceResult = await _service.ReadByUuidAsync(
uuid: decoded.EnvelopeUuid,
signature: decoded.ReceiverSignature,
withDocuments: withDocuments, withReceivers: withReceivers, withHistory: withHistory, withDocumentReceiverElement:withDocumentReceiverElement, withAll:withAll);
withDocuments: withDocuments, withEnvelopeReceivers: withEnvelopeReceivers, withHistory: withHistory, withDocumentReceiverElement:withDocumentReceiverElement, withUser:withUser, withAll:withAll);
if (envlopeServiceResult.IsSuccess)
{
@ -38,7 +35,7 @@ namespace EnvelopeGenerator.Web.Controllers.Test
return NotFound();
}
var result = await _service.ReadAllWithAsync(documents: withDocuments, receivers: withReceivers, history: withHistory);
var result = await _service.ReadAllWithAsync(documents: withDocuments, envelopeReceivers: withEnvelopeReceivers, history: withHistory);
if (result.IsSuccess)
{
return Ok(result);

View File

@ -3,6 +3,7 @@ using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts;
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Web.Controllers.Test
{
@ -10,7 +11,18 @@ namespace EnvelopeGenerator.Web.Controllers.Test
{
public TestEnvelopeHistoryController(ILogger<TestEnvelopeHistoryController> logger, IEnvelopeHistoryService service) : base(logger, service)
{
}
[HttpGet("Count")]
public async Task<IActionResult> Count(int? envelopeId = null, string? userReference = null, int? status = null)
{
return Ok(await _service.CountAsync(envelopeId, userReference, status));
}
[HttpGet("is-ac-req")]
public async Task<IActionResult> AccessCodeAlreadyRequested(int envelopeId, string userReference)
{
return Ok(await _service.AccessCodeAlreadyRequested(envelopeId, userReference));
}
}
}

View File

@ -1,8 +1,11 @@
using DigitalData.Core.API;
using DigitalData.Core.Application;
using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Application.Services;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts;
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Web.Controllers.Test
{
@ -10,7 +13,38 @@ namespace EnvelopeGenerator.Web.Controllers.Test
{
public TestEnvelopeReceiverController(ILogger<TestEnvelopeReceiverController> logger, IEnvelopeReceiverService service) : base(logger, service)
{
}
[HttpGet("verify-access-code/{envelope_receiver_id}")]
public async Task<IActionResult> VerifyAccessCode([FromRoute] string envelope_receiver_id, [FromQuery] string access_code)
{
var verification = await _service.VerifyAccessCodeAsync(envelopeReceiverId:envelope_receiver_id, accessCode: access_code);
if (verification.IsSuccess)
return Ok(verification);
else if (verification.HasFlag(Flag.SecurityBreach))
return Forbid();
else if (verification.HasFlag(Flag.SecurityBreachOrDataIntegrity))
return Conflict();
else
return this.InnerServiceError(verification);
}
[HttpGet("e-r-id/{envelope_receiver_id}")]
public async Task<IActionResult> GetByEnvelopeReceiverId([FromRoute] string envelope_receiver_id)
{
var er_result = await _service.ReadByEnvelopeReceiverIdAsync(envelopeReceiverId: envelope_receiver_id);
if (er_result.IsSuccess)
return Ok(er_result);
else
return this.InnerServiceError(er_result);
}
[HttpGet("decode")]
public IActionResult DecodeEnvelopeReceiverId(string envelopeReceiverId)
{
var decoded = envelopeReceiverId.DecodeEnvelopeReceiverId();
return Ok(new { uuid = decoded.EnvelopeUuid, signature = decoded.ReceiverSignature });
}
}
}

View File

@ -0,0 +1,60 @@
using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Common;
using EnvelopeGenerator.Web.Services;
using Microsoft.AspNetCore.Mvc;
namespace EnvelopeGenerator.Web.Controllers.Test
{
public class TestViewController : BaseController
{
private readonly EnvelopeOldService envelopeOldService;
private readonly IConfiguration _config;
private readonly IEnvelopeReceiverService _envRcvService;
private readonly IEnvelopeService _envelopeService;
public TestViewController(DatabaseService databaseService, EnvelopeOldService envelopeOldService, ILogger<TestViewController> logger, IConfiguration configuration, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeService envelopeService) : base(databaseService, logger)
{
this.envelopeOldService = envelopeOldService;
_envRcvService = envelopeReceiverService;
_envelopeService = envelopeService;
_config = configuration;
}
[HttpGet("/")]
public IActionResult Index()
{
return View("Index");
}
[HttpPost("/")]
public IActionResult DebugEnvelopes([FromForm] string? password)
{
try
{
var passwordFromConfig = _config["Config:AdminPassword"];
if (passwordFromConfig == null)
{
ViewData["error"] = "No admin password configured!";
return View("Index");
}
if (password != passwordFromConfig)
{
ViewData["error"] = "Wrong Password!";
return View("Index");
}
List<Envelope> envelopes = envelopeOldService.LoadEnvelopes();
return View("DebugEnvelopes", envelopes);
}
catch(Exception ex)
{
_logger.LogError(ex, "Unexpected error");
ViewData["error"] = "Unknown error!";
return View("Index");
}
}
}
}

View File

@ -25,6 +25,9 @@
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="7.0.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
<PackageReference Include="System.DirectoryServices" Version="7.0.1" />
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="7.0.1" />
<PackageReference Include="System.DirectoryServices.Protocols" Version="7.0.1" />
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
<PackageReference Include="System.Security.Cryptography.Cng" Version="5.0.0" />
</ItemGroup>
@ -66,6 +69,15 @@
<Reference Include="DigitalData.Modules.Logging">
<HintPath>..\..\DDModules\Logging\bin\Debug\DigitalData.Modules.Logging.dll</HintPath>
</Reference>
<Reference Include="DigitalData.UserManager.Application">
<HintPath>..\..\WebUserManager\DigitalData.UserManager.Application\bin\Debug\net7.0\DigitalData.UserManager.Application.dll</HintPath>
</Reference>
<Reference Include="DigitalData.UserManager.Domain">
<HintPath>..\..\WebUserManager\DigitalData.UserManager.Application\bin\Debug\net7.0\DigitalData.UserManager.Domain.dll</HintPath>
</Reference>
<Reference Include="DigitalData.UserManager.Infrastructure">
<HintPath>..\..\WebUserManager\DigitalData.UserManager.Application\bin\Debug\net7.0\DigitalData.UserManager.Infrastructure.dll</HintPath>
</Reference>
<Reference Include="GdPicture.NET.14">
<HintPath>D:\ProgramFiles\GdPicture.NET 14\Redist\GdPicture.NET (.NET Framework 4.5)\GdPicture.NET.14.dll</HintPath>
</Reference>

View File

@ -0,0 +1,10 @@
namespace EnvelopeGenerator.Web
{
public enum MessageKey
{
UnexpectedError,
FailedToSendAccessCode,
WrongEnvelopeReceiverId, //the value should be about URL (like URL is not existing) as a part of security.
DataIntegrityError
}
}

View File

@ -13,6 +13,7 @@ using NLog.Web;
using DigitalData.Core.API;
using Microsoft.AspNetCore.Authentication.Cookies;
using DigitalData.Core.Application;
using DigitalData.UserManager.Application.MappingProfiles;
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
logger.Info("Logging initialized!");
@ -29,9 +30,10 @@ try
// Add higher order services
builder.Services.AddScoped<EnvelopeOldService>();
// Add services to the container.
// Add controllers and razor views
builder.Services.AddControllersWithViews(options =>
{
//remove option for Test*Controller
options.Conventions.Add(new RemoveIfControllerConvention()
.AndIf(c => c.ControllerName.StartsWith("Test"))
.AndIf(c => !builder.Configuration.GetValue<bool>("AddTestControllers")));
@ -86,6 +88,7 @@ try
//Auto mapping profiles
builder.Services.AddAutoMapper(typeof(BasicDtoMappingProfile).Assembly);
builder.Services.AddAutoMapper(typeof(UserMappingProfile).Assembly);
builder.Services.Configure<CookiePolicyOptions>(options =>
{

View File

@ -1,7 +1,18 @@
@{
ViewData["Title"] = "Dokument geschützt";
}
@if(ViewData["Test1"] is string test1)
{
<script>
console.log("@test1");
</script>
}
@if (ViewData["Test2"] is string test2)
{
<script>
console.log("@test2");
</script>
}
<div class="page container p-5">
<header class="text-center">
<div class="icon locked">

View File

@ -9,7 +9,8 @@
{
var envelope = Model.Data;
var document = envelope.Documents?.FirstOrDefault();
var receiver = envelope.Receivers?.FirstOrDefault();
var receiver = envelope.EnvelopeReceivers?.FirstOrDefault();
var sender = envelope.User;
var receiverName = receiver?.Name ?? string.Empty;
var pages = document?.Elements?.Select(e => e.Page) ?? Array.Empty<int>();
var stPageIndexes = string.Join(pages.Count() > 1 ? ", " : "", pages.Take(pages.Count() - 1))

View File

@ -21,21 +21,33 @@
"type": "File",
"fileName": "E:\\EnvelopeGenerator\\Logs\\${shortdate}-ECM.EnvelopeGenerator.Web-Error.log",
"maxArchiveDays": 30
},
"criticalLogs": {
"type": "File",
"fileName": "E:\\EnvelopeGenerator\\Logs\\${shortdate}-ECM.EnvelopeGenerator.Web-Critical.log",
"maxArchiveDays": 30
}
},
// Trace, Debug, Info, Warn, Error and Fatal
"rules": [
{
"logger": "*",
"minLevel": "Info",
"maxLevel": "Warn",
"writeTo": "infoLogs"
},
{
"logger": "*",
"minLevel": "Error",
"level": "Error",
"writeTo": "errorLogs"
},
{
"logger": "Namespace.Controllers.*",
"logger": "*",
"level": "Fatal",
"writeTo": "criticalLogs"
},
{
"logger": "EnvelopeGenerator.Web.Controllers.*",
"minLevel": "Error",
"writeTo": "errorLogs",
"final": true

View File

@ -35,10 +35,7 @@ class App {
// Load the document from the filestore
console.debug('Loading document from filestore')
const documentResponse = await this.Network.getDocument(
this.envelopeKey,
this.currentDocument.id
)
const documentResponse = this.documentBytes
if (documentResponse.fatal || documentResponse.error) {
console.error(documentResponse.error)