diff --git a/EnvelopeGenerator.Application/Key.cs b/EnvelopeGenerator.Application/Key.cs deleted file mode 100644 index aa44a367..00000000 --- a/EnvelopeGenerator.Application/Key.cs +++ /dev/null @@ -1,82 +0,0 @@ -namespace EnvelopeGenerator.Application; - -/// -/// -/// -public static class Key -{ - /// - /// - /// - public static readonly string InnerServiceError = nameof(InnerServiceError); - - /// - /// - /// - public static readonly string EnvelopeNotFound = nameof(EnvelopeNotFound); - - /// - /// - /// - public static readonly string EnvelopeReceiverNotFound = nameof(EnvelopeReceiverNotFound); - - /// - /// - /// - public static readonly string AccessCodeNull = nameof(AccessCodeNull); - - /// - /// - /// - public static readonly string WrongAccessCode = nameof(WrongAccessCode); - - /// - /// - /// - public static readonly string DataIntegrityIssue = nameof(DataIntegrityIssue); - - /// - /// - /// - public static readonly string SecurityBreachOrDataIntegrity = nameof(SecurityBreachOrDataIntegrity); - - /// - /// - /// - public static readonly string PossibleDataIntegrityIssue = nameof(PossibleDataIntegrityIssue); - - /// - /// - /// - public static readonly string SecurityBreach = nameof(SecurityBreach); - - /// - /// - /// - public static readonly string PossibleSecurityBreach = nameof(PossibleSecurityBreach); - - /// - /// - /// - public static readonly string WrongEnvelopeReceiverId = nameof(WrongEnvelopeReceiverId); - - /// - /// - /// - public static readonly string EnvelopeOrReceiverNonexists = nameof(EnvelopeOrReceiverNonexists); - - /// - /// - /// - public static readonly string PhoneNumberNonexists = nameof(PhoneNumberNonexists); - - /// - /// - /// - public static readonly string Default = nameof(Default); - - /// - /// - /// - public static readonly string DbMigrationTest = nameof(DbMigrationTest); -} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Resources/Resource.cs b/EnvelopeGenerator.Application/Resources/Resource.cs index 8b7e50aa..d8b51c1b 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.cs +++ b/EnvelopeGenerator.Application/Resources/Resource.cs @@ -1,9 +1,137 @@ -namespace EnvelopeGenerator.Application.Resources +using Microsoft.Extensions.Localization; +using System.Runtime.CompilerServices; + +namespace EnvelopeGenerator.Application.Resources; + +/// +/// The place holder class for Resource.*.resx +/// +public class Resource +{ +} + +//TODO: use code generator +/// +/// +/// +public static class Extensions { /// - /// The place holder class for Resource.*.resx + /// /// - public class Resource - { - } -} + /// + /// + public static string InnerServiceError(this IStringLocalizer localizer) => localizer[nameof(InnerServiceError)]; + + /// + /// + /// + /// + /// + public static string EnvelopeNotFound(this IStringLocalizer localizer) => localizer[nameof(EnvelopeNotFound)]; + + /// + /// + /// + /// + /// + public static string EnvelopeReceiverNotFound(this IStringLocalizer localizer) => localizer[nameof(EnvelopeReceiverNotFound)]; + + /// + /// + /// + /// + /// + public static string AccessCodeNull(this IStringLocalizer localizer) => localizer[nameof(AccessCodeNull)]; + + /// + /// + /// + /// + /// + public static string WrongAccessCode(this IStringLocalizer localizer) => localizer[nameof(WrongAccessCode)]; + + /// + /// + /// + /// + /// + public static string DataIntegrityIssue(this IStringLocalizer localizer) => localizer[nameof(DataIntegrityIssue)]; + + /// + /// + /// + /// + /// + public static string SecurityBreachOrDataIntegrity(this IStringLocalizer localizer) => localizer[nameof(SecurityBreachOrDataIntegrity)]; + + /// + /// + /// + /// + /// + public static string PossibleDataIntegrityIssue(this IStringLocalizer localizer) => localizer[nameof(PossibleDataIntegrityIssue)]; + + /// + /// + /// + /// + /// + public static string SecurityBreach(this IStringLocalizer localizer) => localizer[nameof(SecurityBreach)]; + + /// + /// + /// + /// + /// + public static string PossibleSecurityBreach(this IStringLocalizer localizer) => localizer[nameof(PossibleSecurityBreach)]; + + /// + /// + /// + /// + /// + public static string WrongEnvelopeReceiverId(this IStringLocalizer localizer) => localizer[nameof(WrongEnvelopeReceiverId)]; + + /// + /// + /// + /// + /// + public static string EnvelopeOrReceiverNonexists(this IStringLocalizer localizer) => localizer[nameof(EnvelopeOrReceiverNonexists)]; + + /// + /// + /// + /// + /// + public static string PhoneNumberNonexists(this IStringLocalizer localizer) => localizer[nameof(PhoneNumberNonexists)]; + + /// + /// + /// + /// + /// + public static string Default(this IStringLocalizer localizer) => localizer[nameof(Default)]; + + /// + /// + /// + /// + /// + public static string DbMigrationTest(this IStringLocalizer localizer) => localizer[nameof(DbMigrationTest)]; + + /// + /// + /// + /// + /// + public static string Culture(this IStringLocalizer localizer) => localizer[nameof(Culture)]; + + /// + /// + /// + /// + /// + public static string FiClass(this IStringLocalizer localizer) => localizer[nameof(FiClass)]; +} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx b/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx index ca8a6a7d..2fe7b8d8 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx +++ b/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx @@ -129,6 +129,9 @@ Bestätigung + + de-DE + Deutch @@ -150,6 +153,9 @@ Erstellt am {0} von {1}. Sie können den Absender über <span class="highlight highlight-envelope-info-2"><a class="mail-link" href="mailto:{2}?subject={3}&body=Sehr%20geehrter%20{4}%20{5},%0A%0A%0A">{6}</a></span> kontaktieren. + + fi-de + Abschließen diff --git a/EnvelopeGenerator.Application/Resources/Resource.en-US.resx b/EnvelopeGenerator.Application/Resources/Resource.en-US.resx index c2a8658c..d0e8d116 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.en-US.resx +++ b/EnvelopeGenerator.Application/Resources/Resource.en-US.resx @@ -129,6 +129,9 @@ Confirmation + + en-US + German @@ -150,6 +153,9 @@ Created on {0} by {1}. You can contact the sender via <span class="highlight highlight-envelope-info-2"><a class="mail-link" href="mailto:{2}?subject={3}&body=Dear%20{4}%20{5},%0A%0A%0A">{6}</a></span>. + + fi-us + Finalize diff --git a/EnvelopeGenerator.Application/Services/EmailTemplateService.cs b/EnvelopeGenerator.Application/Services/EmailTemplateService.cs index bb628376..97aaa752 100644 --- a/EnvelopeGenerator.Application/Services/EmailTemplateService.cs +++ b/EnvelopeGenerator.Application/Services/EmailTemplateService.cs @@ -36,7 +36,7 @@ public class EmailTemplateService : BasicCRUDService() - .Message(Key.InnerServiceError) + .Message("InnerServiceError") .Notice(LogLevel.Error, Flag.DataIntegrityIssue, $"EmailTemplateType '{type}' is not found in DB. Please, define required e-mail template.") : Result.Success(_mapper.Map(temp)); } diff --git a/EnvelopeGenerator.Application/Services/EnvelopeReceiverService.cs b/EnvelopeGenerator.Application/Services/EnvelopeReceiverService.cs index c13c0ac9..c845dec6 100644 --- a/EnvelopeGenerator.Application/Services/EnvelopeReceiverService.cs +++ b/EnvelopeGenerator.Application/Services/EnvelopeReceiverService.cs @@ -82,7 +82,7 @@ public class EnvelopeReceiverService : BasicCRUDService>() - .Message(_localizer[Key.EnvelopeReceiverNotFound]); + .Message(_localizer.EnvelopeReceiverNotFound()); return Result.Success(env_rcvs.Select(er => er.AccessCode) ?? Enumerable.Empty()); } @@ -100,7 +100,7 @@ public class EnvelopeReceiverService : BasicCRUDService() - .Message(Key.EnvelopeReceiverNotFound); + .Message("EnvelopeReceiverNotFound"); return Result.Success(_mapper.Map(env_rcv)); } @@ -119,7 +119,7 @@ public class EnvelopeReceiverService : BasicCRUDService() - .Message(Key.EnvelopeReceiverNotFound); + .Message("EnvelopeReceiverNotFound"); return Result.Success(_mapper.Map(env_rcv)); } @@ -138,7 +138,7 @@ public class EnvelopeReceiverService : BasicCRUDService() - .Message(_localizer[Key.WrongEnvelopeReceiverId]) + .Message(_localizer.WrongEnvelopeReceiverId()) .Notice(LogLevel.Warning, (uuid, signature).ToTitle()) .Notice(LogLevel.Warning, EnvelopeFlag.WrongEnvelopeReceiverId) .Notice(LogLevel.Warning, Flag.PossibleSecurityBreach); @@ -159,7 +159,7 @@ public class EnvelopeReceiverService : BasicCRUDService() - .Message(_localizer[Key.EnvelopeOrReceiverNonexists]) + .Message(_localizer.EnvelopeOrReceiverNonexists()) .Notice(LogLevel.Warning, (uuid, signature).ToTitle()) .Notice(LogLevel.Warning, EnvelopeFlag.EnvelopeOrReceiverNonexists) .Notice(LogLevel.Warning, Flag.PossibleDataIntegrityIssue); @@ -168,13 +168,13 @@ public class EnvelopeReceiverService : BasicCRUDService() - .Message(_localizer[Key.AccessCodeNull]) + .Message(_localizer.AccessCodeNull()) .Notice(LogLevel.Critical, (uuid, signature).ToTitle()) .Notice(LogLevel.Critical, EnvelopeFlag.AccessCodeNull) .Notice(LogLevel.Critical, Flag.DataIntegrityIssue); else if (accessCode != actualAccessCode) - return Result.Success(false).Message(_localizer[Key.WrongAccessCode]); + return Result.Success(false).Message(_localizer.WrongAccessCode()); else return Result.Success(true); } @@ -191,7 +191,7 @@ public class EnvelopeReceiverService : BasicCRUDService() - .Message(Key.WrongEnvelopeReceiverId) + .Message("WrongEnvelopeReceiverId") .Notice(LogLevel.Critical, EnvelopeFlag.WrongEnvelopeReceiverId) .Notice(LogLevel.Critical, Flag.SecurityBreach) .Notice(LogLevel.Critical, "Attempt to verify access code detected. Such actions are generally not initiated by well-intentioned users. Potential security breach suspected. Immediate investigation required."); @@ -287,7 +287,7 @@ public class EnvelopeReceiverService : BasicCRUDService() - .Message(_localizer[Key.WrongEnvelopeReceiverId]) + .Message(_localizer.WrongEnvelopeReceiverId()) .Notice(LogLevel.Warning, (uuid, signature).ToTitle()) .Notice(LogLevel.Warning, EnvelopeFlag.WrongEnvelopeReceiverId) .Notice(LogLevel.Warning, Flag.PossibleSecurityBreach); @@ -295,11 +295,11 @@ public class EnvelopeReceiverService : BasicCRUDService() - .Message(Key.EnvelopeReceiverNotFound); + .Message("EnvelopeReceiverNotFound"); if (env_rcv.PhoneNumber is null) return Result.Fail() - .Message(Key.PhoneNumberNonexists) + .Message("PhoneNumberNonexists") .Notice(LogLevel.Error, Flag.NotFound, $"An attempt was made to send sms to the user whose phone number is null. Envelope recipient ID is {envelopeReceiverId}, UUID is {uuid} and signature is {signature}."); var res = await _smsSender.SendSmsAsync(recipient: env_rcv.PhoneNumber, message: message); diff --git a/EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs b/EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs index 4e095c09..0a18c0e0 100644 --- a/EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs +++ b/EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs @@ -1,7 +1,8 @@ using EnvelopeGenerator.Application.Dto.EnvelopeReceiver; using EnvelopeGenerator.Web.Models; -using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.Mvc; using System.Security.Claims; @@ -55,6 +56,25 @@ namespace EnvelopeGenerator.Web.Controllers } #endregion + #region Cookie + public static string? GetCulture(this IRequestCookieCollection cookies) + => cookies[CookieRequestCultureProvider.DefaultCookieName]; + + public static void SetCulture(this IResponseCookies cookies, string culture) + { + var cookieOptions = new CookieOptions + { + Secure = false, + SameSite = SameSiteMode.Strict, + HttpOnly = true + }; + cookies.Append( + CookieRequestCultureProvider.DefaultCookieName, + CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)), + cookieOptions); + } + #endregion + #region View error //TODO: integrate localizer for ready-to-use views //TODO: integrate to global exception handler middleware diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index 48ffec29..9a5d42f5 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -58,8 +58,6 @@ public class HomeController : ViewControllerBase [HttpGet("/")] public IActionResult Main() { - ViewData["UserCulture"] = _cultures[UserLanguage]; - return View(new MainViewModel() { Title = _configuration["MainPageTitle"] @@ -118,8 +116,6 @@ public class HomeController : ViewControllerBase { try { - ViewData["UserCulture"] = _cultures[UserLanguage]; - return await _envRcvService.ReadByEnvelopeReceiverIdAsync(envelopeReceiverId: envelopeReceiverId).ThenAsync( SuccessAsync: async er => { if (User.IsInRole(ReceiverRole.FullyAuth)) @@ -151,7 +147,6 @@ public class HomeController : ViewControllerBase { try { - ViewData["UserCulture"] = _cultures[UserLanguage]; ViewData["EnvelopeKey"] = envelopeReceiverId; envelopeReceiverId = _sanitizer.Sanitize(envelopeReceiverId); @@ -310,7 +305,6 @@ public class HomeController : ViewControllerBase { try { - ViewData["UserCulture"] = _cultures[UserLanguage]; ViewData["EnvelopeKey"] = envelopeReceiverId; envelopeReceiverId = _sanitizer.Sanitize(envelopeReceiverId); @@ -398,7 +392,6 @@ public class HomeController : ViewControllerBase return base.Redirect($"/EnvelopeKey/{envelopeReceiverId}/Locked"); await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); - ViewData["UserCulture"] = _cultures[UserLanguage]; ViewData["EnvelopeKey"] = envelopeReceiverId; return base.View(); }), @@ -428,8 +421,6 @@ public class HomeController : ViewControllerBase return await _envRcvService.ReadByEnvelopeReceiverIdAsync(envelopeReceiverId).ThenAsync( SuccessAsync: async (er) => { - ViewData["UserCulture"] = _cultures[UserLanguage]; - ViewData["UserCulture"] = _cultures[UserLanguage]; return await _historyService.IsRejected(envelopeId: er.EnvelopeId) ? View(er) : Redirect($"/EnvelopeKey/{envelopeReceiverId}/Locked"); @@ -454,8 +445,6 @@ public class HomeController : ViewControllerBase { try { - ViewData["UserCulture"] = _cultures[UserLanguage]; - readOnlyKey = _sanitizer.Sanitize(readOnlyKey); // check if the readOnlyId is valid @@ -530,26 +519,15 @@ public class HomeController : ViewControllerBase return Ok(new { EnvelopeUuid = envelopeUuid, ReceiverSignature = receiverSignature }); } - [HttpPost("lang/{language}")] - public IActionResult SetLanguage([FromRoute] string language) + [HttpPost("lang/{culture}")] + public IActionResult SetLanguage([FromRoute] string culture) { try { - language = _sanitizer.Sanitize(language); - if (!_cultures.Languages.Contains(language)) + if (!_cultures.Languages.Contains(culture)) return BadRequest(); - var cookieOptions = new CookieOptions() - { - Secure = false, - SameSite = SameSiteMode.Strict, - HttpOnly = true - }; - - Response.Cookies.Append( - CookieRequestCultureProvider.DefaultCookieName, - CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(language)), - cookieOptions); + Response.Cookies.SetCulture(culture); return Redirect(Request.Headers["Referer"].ToString()); } @@ -563,7 +541,5 @@ public class HomeController : ViewControllerBase [HttpGet("lang")] public IActionResult GetLanguages() => Ok(_cultures.Languages); - private string? UserLanguage => Request.Cookies[CookieRequestCultureProvider.DefaultCookieName]; - public IActionResult Error404() => this.ViewError404(); } \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Middleware/CultureMiddleware.cs b/EnvelopeGenerator.Web/Middleware/CultureMiddleware.cs index 170fa44d..51243878 100644 --- a/EnvelopeGenerator.Web/Middleware/CultureMiddleware.cs +++ b/EnvelopeGenerator.Web/Middleware/CultureMiddleware.cs @@ -1,4 +1,5 @@ -using EnvelopeGenerator.Web.Models; +using EnvelopeGenerator.Web.Controllers; +using EnvelopeGenerator.Web.Models; using Microsoft.AspNetCore.Localization; using Microsoft.Extensions.Options; using System.Globalization; @@ -23,20 +24,7 @@ public class CultureMiddleware if (string.IsNullOrEmpty(cookieValue)) { - var culture = new RequestCulture(_cultures.Default.Language); - - var cookieOptions = new CookieOptions - { - Secure = false, - SameSite = SameSiteMode.Strict, - HttpOnly = true - }; - - context.Response.Cookies.Append( - cookieName, - CookieRequestCultureProvider.MakeCookieValue(culture), - cookieOptions); - + context.Response.Cookies.SetCulture(_cultures.Default.Language); CultureInfo.CurrentCulture = new CultureInfo(_cultures.Default.Language); CultureInfo.CurrentUICulture = new CultureInfo(_cultures.Default.Language); } diff --git a/EnvelopeGenerator.Web/Program.cs b/EnvelopeGenerator.Web/Program.cs index 6ee88eb6..64df0616 100644 --- a/EnvelopeGenerator.Web/Program.cs +++ b/EnvelopeGenerator.Web/Program.cs @@ -90,7 +90,7 @@ try //AddEF Core dbcontext var useDbMigration = Environment.GetEnvironmentVariable("MIGRATION_TEST_MODE") == true.ToString() || config.GetValue("UseDbMigration"); - var cnnStrName = useDbMigration ? Key.DbMigrationTest : Key.Default; + var cnnStrName = useDbMigration ? "DbMigrationTest" : "Default"; var connStr = config.GetConnectionString(cnnStrName) ?? throw new InvalidOperationException($"Connection string '{cnnStrName}' is missing in the application configuration."); diff --git a/EnvelopeGenerator.Web/Services/DatabaseService.cs b/EnvelopeGenerator.Web/Services/DatabaseService.cs index 98674029..9ec03ae0 100644 --- a/EnvelopeGenerator.Web/Services/DatabaseService.cs +++ b/EnvelopeGenerator.Web/Services/DatabaseService.cs @@ -57,7 +57,7 @@ namespace EnvelopeGenerator.Web.Services _logger = logger; _logger.LogInformation("Establishing MSSQL Database connection.."); - MSSQL = new MSSQLServer(logConfig, config.GetConnectionString(Key.Default)); + MSSQL = new MSSQLServer(logConfig, config.GetConnectionString("Default")); if (MSSQL.DBInitialized == true) { diff --git a/EnvelopeGenerator.Web/Views/Home/EnvelopeLocked.cshtml b/EnvelopeGenerator.Web/Views/Home/EnvelopeLocked.cshtml index e28dae1b..c182dce6 100644 --- a/EnvelopeGenerator.Web/Views/Home/EnvelopeLocked.cshtml +++ b/EnvelopeGenerator.Web/Views/Home/EnvelopeLocked.cshtml @@ -6,7 +6,6 @@ var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string; var cImg = _cImgOpt.Value; ViewData["Title"] = _localizer[WebKey.DocProtected]; - var userCulture = ViewData["UserCulture"] as Culture; string codeType = ViewData["CodeType"] is string _codeType ? _codeType : "accessCode"; string codeKeyName = (char.ToUpper(codeType[0]) + codeType.Substring(1)).Replace("Code", ""); bool viaSms = codeType == "smsCode"; diff --git a/EnvelopeGenerator.Web/Views/Home/EnvelopeRejected.cshtml b/EnvelopeGenerator.Web/Views/Home/EnvelopeRejected.cshtml index 6e4e8e37..467073ba 100644 --- a/EnvelopeGenerator.Web/Views/Home/EnvelopeRejected.cshtml +++ b/EnvelopeGenerator.Web/Views/Home/EnvelopeRejected.cshtml @@ -10,7 +10,6 @@ @using Newtonsoft.Json.Serialization @model EnvelopeReceiverDto; @{ - var userCulture = ViewData["UserCulture"] as Culture; var envelope = Model.Envelope; var document = Model.Envelope?.Documents?.FirstOrDefault(); var sender = Model.Envelope?.User; diff --git a/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml b/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml index 97f17d75..ce954b26 100644 --- a/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml +++ b/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml @@ -3,9 +3,6 @@ @using Newtonsoft.Json.Serialization @{ var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string; - var userCulture = ViewData["UserCulture"] as Culture; - //TODO: instead of default assignment add a middleware for culture - userCulture ??= _cultures.Default; var isReadOnly = false; if (ViewData["IsReadOnly"] is bool isReadOnly_bool) isReadOnly = isReadOnly_bool; @@ -83,7 +80,7 @@ © SignFlow 2023-2024 Digital Data GmbH
- @_localizer[WebKey.Privacy] + @_localizer[WebKey.Privacy] \ No newline at end of file