From 87c839549ad8e6ae0ce54c5ca15440b114b47b8b Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Mon, 15 Apr 2024 17:24:27 +0200 Subject: [PATCH 1/5] =?UTF-8?q?Cookie-basierte=20automatische=20Autorisier?= =?UTF-8?q?ung=20wurde=20konfiguriert.=20Middlevare=20f=C3=BCr=20Benutzerb?= =?UTF-8?q?erechtigung=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Contracts/IJWTService.cs | 24 ++ .../EnvelopeGenerator.Application.csproj | 1 + .../Controllers/ControllerBaseExtensions.cs | 21 + .../Controllers/HomeController.cs | 67 +++- .../Controllers/Test/TestAuthController.cs | 42 ++ .../Controllers/Test/TestControllerBase.cs | 1 - .../EnvelopeGenerator.Web.csproj | 2 + EnvelopeGenerator.Web/Program.cs | 52 ++- .../Properties/launchSettings.json | 32 +- .../Views/Home/ShowEnvelope.cshtml | 1 + .../Views/Shared/_CookieConsentPartial.cshtml | 24 ++ .../Views/Shared/_Layout.cshtml | 5 +- EnvelopeGenerator.Web/appsettings.json | 27 +- EnvelopeGenerator.Web/wwwroot/css/site.css | 4 + ...bootstrap-cookie-consent-settings-main.zip | Bin 0 -> 18308 bytes .../.gitattributes | 4 + .../.gitignore | 2 + .../LICENSE | 21 + .../README.md | 121 ++++++ .../cookie-consent-content/de.json | 31 ++ .../cookie-consent-content/en.json | 31 ++ .../cookie-consent-content/oc.json | 31 ++ .../examples/cookie-banner-example.html | 79 ++++ .../examples/legal-notice.html | 17 + .../examples/privacy-policy.html | 17 + .../favicon.ico | Bin 0 -> 15406 bytes .../index.html | 34 ++ .../package-lock.json | 13 + .../package.json | 28 ++ .../Shaack/BootstrapCookieConsentSettings.php | 64 ++++ .../src/bootstrap-cookie-consent-settings.js | 359 ++++++++++++++++++ 31 files changed, 1111 insertions(+), 44 deletions(-) create mode 100644 EnvelopeGenerator.Application/Contracts/IJWTService.cs create mode 100644 EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs create mode 100644 EnvelopeGenerator.Web/Controllers/Test/TestAuthController.cs create mode 100644 EnvelopeGenerator.Web/Views/Shared/_CookieConsentPartial.cshtml create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main.zip create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitattributes create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitignore create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/LICENSE create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/README.md create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/de.json create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/en.json create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/oc.json create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/cookie-banner-example.html create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/legal-notice.html create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/privacy-policy.html create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/favicon.ico create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/index.html create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package-lock.json create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package.json create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/php/Shaack/BootstrapCookieConsentSettings.php create mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/src/bootstrap-cookie-consent-settings.js diff --git a/EnvelopeGenerator.Application/Contracts/IJWTService.cs b/EnvelopeGenerator.Application/Contracts/IJWTService.cs new file mode 100644 index 00000000..138b8643 --- /dev/null +++ b/EnvelopeGenerator.Application/Contracts/IJWTService.cs @@ -0,0 +1,24 @@ +using Microsoft.IdentityModel.Tokens; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Security.Cryptography; + +namespace EnvelopeGenerator.Application.Contracts +{ + public interface IJWTService + { + public static SymmetricSecurityKey GenerateSecurityKey(int byteSize = 32) + { + using var rng = RandomNumberGenerator.Create(); + var randomBytes = new byte[byteSize]; + rng.GetBytes(randomBytes); + var securityKey = new SymmetricSecurityKey(randomBytes); + + return securityKey; + } + + string GenerateToken(TClaimValue claimValue); + + JwtSecurityToken? ReadSecurityToken(string token); + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/EnvelopeGenerator.Application.csproj b/EnvelopeGenerator.Application/EnvelopeGenerator.Application.csproj index 65f46232..01eaa890 100644 --- a/EnvelopeGenerator.Application/EnvelopeGenerator.Application.csproj +++ b/EnvelopeGenerator.Application/EnvelopeGenerator.Application.csproj @@ -8,6 +8,7 @@ + diff --git a/EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs b/EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs new file mode 100644 index 00000000..6a203195 --- /dev/null +++ b/EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Mvc; +using System.Security.Claims; + +namespace EnvelopeGenerator.Web.Controllers +{ + public static class ControllerBaseExtensions + { + + public static (string EnvelopeUuid, string ReceiverSignature)? GetAuthenticatedEnvelopeDetails(this ControllerBase controller) + { + if(controller?.User?.Identity?.IsAuthenticated ?? false) + { + var envelopeUuid = controller.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + var receiverSignature = controller.User.FindFirst(ClaimTypes.Hash)?.Value; + if (!string.IsNullOrEmpty(envelopeUuid) && !string.IsNullOrEmpty(receiverSignature)) + return (EnvelopeUuid: envelopeUuid, ReceiverSignature: receiverSignature); + } + return null; + } + } +} diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index edb39a69..d219e671 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -1,12 +1,14 @@ using EnvelopeGenerator.Application.Contracts; -using EnvelopeGenerator.Application.DTOs; using EnvelopeGenerator.Application.Services; using EnvelopeGenerator.Common; using EnvelopeGenerator.Web.Models; using EnvelopeGenerator.Web.Services; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Primitives; using System.Diagnostics; +using System.Security.Claims; +using Microsoft.AspNetCore.Authorization; namespace EnvelopeGenerator.Web.Controllers { @@ -62,7 +64,7 @@ namespace EnvelopeGenerator.Web.Controllers } [HttpGet("/EnvelopeKey/{envelopeReceiverId}")] - public async Task ShowEnvelope([FromRoute] string envelopeReceiverId) + public async Task SendAccessCode([FromRoute] string envelopeReceiverId) { EnvelopeResponse response = await envelopeOldService.LoadEnvelope(envelopeReceiverId); @@ -76,18 +78,20 @@ namespace EnvelopeGenerator.Web.Controllers bool actionResult = database.Services.actionService.RequestAccessCode(response.Envelope, response.Receiver); bool result = database.Services.emailService.SendDocumentAccessCodeReceivedEmail(response.Envelope, response.Receiver); } - - return Redirect($"/EnvelopeKey/{envelopeReceiverId}/Locked"); - } - else - { - ViewData["EnvelopeKey"] = envelopeReceiverId; - return View(); } + + return Redirect($"/EnvelopeKey/{envelopeReceiverId}/Locked"); + } + + [HttpGet("/EnvelopeKey/{envelopeReceiverId}/Locked")] + public IActionResult EnvelopeLocked([FromRoute] string envelopeReceiverId) + { + ViewData["EnvelopeKey"] = envelopeReceiverId; + return View(); } [HttpPost("/EnvelopeKey/{envelopeReceiverId}/Locked")] - public async Task ShowEnvelope([FromRoute] string envelopeReceiverId, [FromForm] string access_code) + public async Task LogInEnvelope([FromRoute] string envelopeReceiverId, [FromForm] string access_code) { var decodedId = envelopeReceiverId.DecodeEnvelopeReceiverId(); @@ -99,16 +103,15 @@ namespace EnvelopeGenerator.Web.Controllers if (verification.IsSuccess) { - if (envelopeOldService.ReceiverAlreadySigned(response.Envelope, response.Receiver.Id) == true) + if (envelopeOldService.ReceiverAlreadySigned(response.Envelope, response.Receiver.Id)) { - return Problem(statusCode: 403); + return Redirect("/EnvelopeKey/{envelopeReceiverId}/Success"); } var envelope = await _envelopeService.ReadByUuidAsync(uuid: decodedId.EnvelopeUuid, signature: decodedId.ReceiverSignature, withAll: true); database.Services.actionService.EnterCorrectAccessCode(response.Envelope, response.Receiver); //for history ViewData["EnvelopeKey"] = envelopeReceiverId; ViewData["EnvelopeResponse"] = response; - ViewData["EnvelopeResponse"] = response; if (response.Envelope.Documents.Count() > 0) { @@ -119,6 +122,22 @@ namespace EnvelopeGenerator.Web.Controllers else ViewData["DocumentBytes"] = null; + var claims = new List + { + new Claim(ClaimTypes.NameIdentifier, decodedId.EnvelopeUuid), + new Claim(ClaimTypes.Hash, decodedId.ReceiverSignature), + }; + + var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); + var authProperties = new AuthenticationProperties + { + }; + + await HttpContext.SignInAsync( + CookieAuthenticationDefaults.AuthenticationScheme, + new ClaimsPrincipal(claimsIdentity), + authProperties); + return View("ShowEnvelope", envelope); } else @@ -129,19 +148,21 @@ namespace EnvelopeGenerator.Web.Controllers } } - [HttpGet("/EnvelopeKey/{envelopeReceiverId}/Locked")] - public async Task EnvelopeLocked([FromRoute] string envelopeReceiverId) + [HttpGet("/EnvelopeKey/{envelopeReceiverId}/Success")] + public async Task EnvelopeSigned(string envelopeReceiverId) { + await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); ViewData["EnvelopeKey"] = envelopeReceiverId; return View(); } - [HttpGet("/EnvelopeKey/{EnvelopeReceiverId}/Success")] - public IActionResult EnvelopeSigned() + [Authorize] + [HttpGet("IsAuthenticated")] + public IActionResult IsAuthenticated() { - ViewData["EnvelopeKey"] = HttpContext.Request.RouteValues["EnvelopeReceiverId"]; - - return View(); + var envelopeUuid = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + var receiverSignature = User.FindFirst(ClaimTypes.Hash)?.Value; + return Ok(new { EnvelopeUuid = envelopeUuid, ReceiverSignature = receiverSignature }); } [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] @@ -149,5 +170,9 @@ namespace EnvelopeGenerator.Web.Controllers { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } + + [Authorize] + [HttpGet("test")] + public string Test() => "Test"; } } \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Controllers/Test/TestAuthController.cs b/EnvelopeGenerator.Web/Controllers/Test/TestAuthController.cs new file mode 100644 index 00000000..07f838cf --- /dev/null +++ b/EnvelopeGenerator.Web/Controllers/Test/TestAuthController.cs @@ -0,0 +1,42 @@ +using EnvelopeGenerator.Application.Contracts; +using EnvelopeGenerator.Application.Services; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Security.Claims; + +namespace EnvelopeGenerator.Web.Controllers.Test +{ + [ApiController] + [Route("api/test/[controller]")] + public class TestAuthController : ControllerBase + { + private readonly IJWTService _authService; + + public TestAuthController(IJWTService authService) + { + _authService = authService; + } + + [HttpPost] + public IActionResult ProvideToken([FromQuery] string value) + { + var token = _authService.GenerateToken(value); + return Ok(token); + } + + [HttpGet] + public IActionResult GetSecurityToken([FromQuery] string token) + { + var sToken = _authService.ReadSecurityToken(token); + return Ok(sToken); + } + + [HttpGet("Username")] + [Authorize] + public IActionResult Getname() + { + var username = User.Claims?.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value; + return Ok(username); + } + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Controllers/Test/TestControllerBase.cs b/EnvelopeGenerator.Web/Controllers/Test/TestControllerBase.cs index e719897a..814d53a8 100644 --- a/EnvelopeGenerator.Web/Controllers/Test/TestControllerBase.cs +++ b/EnvelopeGenerator.Web/Controllers/Test/TestControllerBase.cs @@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Mvc; namespace EnvelopeGenerator.Web.Controllers.Test { - //[NonController] [ApiController] [Route("api/test/[controller]")] public class TestControllerBase : BasicCRUDControllerBase where TOriginalController : CRUDControllerBase where TCRUDService : ICRUDService where TCRUDRepository : ICRUDRepository where TDto : class where TEntity : class diff --git a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj index d168af5c..6dcbdcee 100644 --- a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj +++ b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj @@ -23,8 +23,10 @@ + + diff --git a/EnvelopeGenerator.Web/Program.cs b/EnvelopeGenerator.Web/Program.cs index fb294e56..99d3236e 100644 --- a/EnvelopeGenerator.Web/Program.cs +++ b/EnvelopeGenerator.Web/Program.cs @@ -11,6 +11,8 @@ using NLog; using Quartz; using NLog.Web; using DigitalData.Core.API; +using Microsoft.AspNetCore.Authentication.Cookies; +using DigitalData.Core.Application; var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger(); logger.Info("Logging initialized!"); @@ -49,7 +51,7 @@ try builder.Services.AddDbContext(options => options.UseSqlServer(connStr)); - //Inject CRUD Service and repositories + //Inject CRUD Service and repositoriesad builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -82,7 +84,51 @@ try //Auto mapping profiles builder.Services.AddAutoMapper(typeof(BasicDtoMappingProfile).Assembly); - + + builder.Services.Configure(options => + { + options.CheckConsentNeeded = context => + { + var consentCookie = context.Request.Cookies["cookie-consent-settings"]; + return consentCookie != "necessary=false"; + }; + + options.MinimumSameSitePolicy = SameSiteMode.Strict; + options.ConsentCookie.Name = "cookie-consent-settings"; + }); + + builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) + .AddCookie(options => + { + options.Cookie.HttpOnly = true; // Makes the cookie inaccessible to client-side scripts for security + options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; // Ensures cookies are sent over HTTPS only + options.Cookie.SameSite = SameSiteMode.Strict; // Protects against CSRF attacks by restricting how cookies are sent with requests from external sites + // Set up event handlers for dynamic login and logout paths + options.Events = new CookieAuthenticationEvents + { + OnRedirectToLogin = context => + { + // Dynamically calculate the redirection path, for example: + var envelopeReceiverId = context.HttpContext.Request.RouteValues["envelopeReceiverId"]; + context.RedirectUri = $"/EnvelopeKey/{envelopeReceiverId}/Locked"; + + context.Response.Redirect(context.RedirectUri); + return Task.CompletedTask; + }, + OnRedirectToLogout = context => + { + // Apply a similar redirection logic for logout + var envelopeReceiverId = context.HttpContext.Request.RouteValues["envelopeReceiverId"]; + context.RedirectUri = $"/EnvelopeKey/{envelopeReceiverId}/Success"; + + context.Response.Redirect(context.RedirectUri); + return Task.CompletedTask; + } + }; + }); + + builder.Services.AddCookieConsentSettings(); + var app = builder.Build(); // Configure the HTTP request pipeline. @@ -98,9 +144,11 @@ try app.UseHttpsRedirection(); app.UseStaticFiles(); + app.UseCookiePolicy(); app.UseRouting(); + app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); diff --git a/EnvelopeGenerator.Web/Properties/launchSettings.json b/EnvelopeGenerator.Web/Properties/launchSettings.json index bbb353e2..ecea07e7 100644 --- a/EnvelopeGenerator.Web/Properties/launchSettings.json +++ b/EnvelopeGenerator.Web/Properties/launchSettings.json @@ -1,21 +1,13 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:30275", - "sslPort": 44372 - } - }, +{ "profiles": { "EnvelopeGenerator.Web": { "commandName": "Project", - "dotnetRunMessages": true, "launchBrowser": true, - "applicationUrl": "https://localhost:7141;http://localhost:5282", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" - } + }, + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7141;http://localhost:5282" }, "IIS Express": { "commandName": "IISExpress", @@ -26,13 +18,21 @@ }, "swagger": { "commandName": "Project", - "dotnetRunMessages": true, "launchBrowser": true, "launchUrl": "swagger", - "applicationUrl": "https://localhost:7202;http://localhost:5009", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" - } + }, + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7202;http://localhost:5009" + } + }, + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:30275", + "sslPort": 44372 } } -} +} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Views/Home/ShowEnvelope.cshtml b/EnvelopeGenerator.Web/Views/Home/ShowEnvelope.cshtml index 247ae6f1..bc2d46ff 100644 --- a/EnvelopeGenerator.Web/Views/Home/ShowEnvelope.cshtml +++ b/EnvelopeGenerator.Web/Views/Home/ShowEnvelope.cshtml @@ -4,6 +4,7 @@ @{ ViewData["Title"] = "Dokument unterschreiben"; } + @if (Model.IsSuccess && Model.Data is not null) { var envelope = Model.Data; diff --git a/EnvelopeGenerator.Web/Views/Shared/_CookieConsentPartial.cshtml b/EnvelopeGenerator.Web/Views/Shared/_CookieConsentPartial.cshtml new file mode 100644 index 00000000..1c54ec03 --- /dev/null +++ b/EnvelopeGenerator.Web/Views/Shared/_CookieConsentPartial.cshtml @@ -0,0 +1,24 @@ +@using DigitalData.Core.Application.DTO; +@using Microsoft.AspNetCore.Http.Features +@using Newtonsoft.Json.Serialization; +@using Newtonsoft.Json; +@inject CookieConsentSettings _cookieSettings +@{ + var consentFeature = Context.Features.Get(); + var showBanner = !consentFeature?.CanTrack ?? false; + var cookieString = consentFeature?.CreateConsentCookie(); +} +@if (showBanner) +{ + +} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml b/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml index 45774e97..63e1073b 100644 --- a/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml +++ b/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml @@ -19,13 +19,12 @@ + @await RenderSectionAsync("Scripts", required: false)
+ @RenderBody()
- - - @Html.AntiForgeryToken() diff --git a/EnvelopeGenerator.Web/appsettings.json b/EnvelopeGenerator.Web/appsettings.json index 4e1b460c..2ca1852b 100644 --- a/EnvelopeGenerator.Web/appsettings.json +++ b/EnvelopeGenerator.Web/appsettings.json @@ -43,5 +43,30 @@ ] }, - "AddTestControllers": false + "AddTestControllers": true, + "Jwt": { + "Issuer": "https://localhost:7202", + "Audience": "https://localhost:7202", + "Key": "8RGnd7x0G2TYLOIW4m_qlIls7MfbAIGNrpQJzMAUIvULHOLiG723znRa_MG-Z4yw3SErusOU4hTui2rVBMcCaQ" + }, + "AuthCookieConfig": { + "HttpOnly": true, + "SecurePolicy": 1 + + }, + "CookieConsentSettings": { + "PrivacyPolicyUrl": "./", + "LegalNoticeUrl": "./", + "ContentURL": "/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content", + "ButtonAgreeClass": "btn btn-primary", + "ButtonDontAgreeClass": "btn btn-link text-decoration-none none-display", + "ButtonSaveClass": "btn btn-secondary none-display", + "Lang": "en", + "DefaultLang": "en", + "CookieName": "cookie-consent-settings", + "CookieStorageDays": 1, + "ModalId": "bootstrapCookieConsentSettingsModal", + "AlsoUseLocalStorage": false, + "Categories": [ "necessary" ] + } } \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/css/site.css b/EnvelopeGenerator.Web/wwwroot/css/site.css index a2075121..1c169b00 100644 --- a/EnvelopeGenerator.Web/wwwroot/css/site.css +++ b/EnvelopeGenerator.Web/wwwroot/css/site.css @@ -135,4 +135,8 @@ footer#page-footer a:focus { } .envelope-message { font-family: 'Roboto', sans-serif; +} + +.none-display { + display: none } \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main.zip b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main.zip new file mode 100644 index 0000000000000000000000000000000000000000..85b930f7acd238b8859e54e3865a2c04984cd130 GIT binary patch literal 18308 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 literal 0 HcmV?d00001 diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitattributes b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitattributes new file mode 100644 index 00000000..f2bc0acc --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitattributes @@ -0,0 +1,4 @@ +src/bootstrap-cookie-consent-settings.js linguist-vendored=false +index.html linguist-documentation +demo/legal-notice.html linguist-documentation +demo/privacy-policy.html linguist-documentation \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitignore b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitignore new file mode 100644 index 00000000..e0b850e0 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitignore @@ -0,0 +1,2 @@ +/.idea +/node_modules \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/LICENSE b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/LICENSE new file mode 100644 index 00000000..7bd9a202 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Stefan Haack + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/README.md b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/README.md new file mode 100644 index 00000000..e087d50b --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/README.md @@ -0,0 +1,121 @@ +# bootstrap-cookie-consent-settings + +A modal dialog (cookie banner) and framework to handle the EU law (as written by EuGH, 1.10.2019 – C-673/17) +about cookies in a website. Needs Bootstrap 5. + +- [Demo page](https://shaack.com/projekte/bootstrap-cookie-consent-settings) +- [GitHub Repository](https://github.com/shaack/bootstrap-cookie-consent-settings) +- [npm package](https://www.npmjs.com/package/bootstrap-cookie-consent-settings) + +## Usage + +### Construct + +Initialize the cookie consent framework with the constructor + +```js +var cookieSettings = new BootstrapCookieConsentSettings(props) +``` + +You should configure the framework with the `props` object, at least the properties `privacyPolicyUrl`, `legalNoticeUrl` +and `contentURL`. The default configuration is + +```js +this.props = { + privacyPolicyUrl: undefined, // the URL of your privacy policy page + legalNoticeUrl: undefined, // the URL of you legal notice page (Impressum) + contentURL: "/cookie-consent-content", // this folder must contain the language-files in the needed languages (`[lang].js`) + buttonAgreeClass: "btn btn-primary", // the "Agree to all" buttons class + buttonDontAgreeClass: "btn btn-link text-decoration-none", // the "I do not agree" buttons class + buttonSaveClass: "btn btn-secondary", // the "Save selection" buttons class + autoShowModal: true, // disable autoShowModal on the privacy policy and legal notice pages, to make these pages readable + alsoUseLocalStorage: true, // if true, the settings are stored in localStorage, too + postSelectionCallback: undefined, // callback function, called after the user has saved the settings + lang: navigator.language, // the language, in which the modal is shown + defaultLang: "en", // default language, if `lang` is not available as translation in `cookie-consent-content` + categories: ["necessary", "statistics", "marketing", "personalization"], // the categories for selection, must be contained in the language files + cookieName: "cookie-consent-settings", // the name of the cookie in which the configuration is stored as JSON + cookieStorageDays: 365, // the duration the cookie configuration is stored on the client + modalId: "bootstrapCookieConsentSettingsModal" // the id of the modal dialog element +} +``` + +### Show dialog + +On a new visit the dialog is shown automatically. + +To allow the user a reconfiguration you can show the Dialog again with + +```js +cookieSettings.showDialog() +``` + +### Read the settings in JavaScript + +Read all cookie settings with + +```js +cookieSettings.getSettings() +``` + +It should return some JSON like + +```json +{ + "necessary": true, + "statistics": true, + "marketing": true, + "personalization": true +} +``` + +or `undefined`, before the user has chosen his cookie options. + +Read a specific cookie setting with + +```js +cookieSettings.getSettings('statistics') +``` + +for the `statistics` cookie settings. Also returns `undefined`, before the user has chosen his cookie options. + +### Read the settings from the backend + +You can read the settings with all server languages, you just have to read the cookie `cookie-consent-settings`. +The content of the cookie is encoded like a http query string. + +``` +necessary=true&statistics=false&marketing=true&personalization=true +``` + +#### PHP helper class + +I provide a PHP helper class that you can use to read and write the settings from a PHP backend. + +It is located in `php/Shaack/BootstrapCookieConsentSettings.php`. + +You can use it as described in the following example. + +```PHP +$cookieSettings = new \Shaack\BootstrapCookieConsentSettings(); +// read all settings +$allSettings = $cookieSettings->getSettings(); +// read a specific setting +$statisticsAllowed = $cookieSettings->getSetting("statistics"); +// write a specific setting +$cookieSettings->setSetting("statistics", false); +``` + +### Internationalization + +You find the language files in `./cookie-consent-content`. You can add here language files or modify the existing. If +you add language files please consider a pull request to also add them in this repository. Thanks. + +## Disclaimer + +You can use this banner for your website free of charge under the [MIT-License](./LICENSE). + +The banner and framework was designed in cooperation with data protection officers and lawyers. However, we can not +guarantee whether the banner is correct for your website and assume no liability for its use. + +bootstrap-cookie-consent-settings is a project of [shaack.com](https://shaack.com). diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/de.json b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/de.json new file mode 100644 index 00000000..3da494a4 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/de.json @@ -0,0 +1,31 @@ +{ + "title": "Privatsphäre Einstellungen", + "body": "Wir nutzen Cookies und ähnliche Technologien, die zum Betrieb der Website erforderlich sind. Zusätzliche Cookies werden nur mit Ihrer Zustimmung verwendet. Es steht Ihnen frei, Ihre Zustimmung jederzeit zu geben, zu verweigern oder zurückzuziehen, indem Sie den Link \"Cookie-Einstellungen\" unten auf jeder Seite nutzen. Sie können der Verwendung von Cookies durch uns zustimmen, indem Sie auf \"Einverstanden\" klicken. Für weitere Informationen darüber, welche Daten gesammelt und wie sie an unsere Partner weitergegeben werden, lesen Sie bitte unsere --privacy-policy--.", + "privacyPolicy": "Datenschutzerklärung", + "legalNotice": "Impressum", + "mySettings": "Meine Einstellungen", + "buttonNotAgree": "Ich bin nicht einverstanden", + "buttonAgree": "Einverstanden", + "buttonSaveSelection": "Auswahl speichern", + "buttonAgreeAll": "Allen zustimmen", + "categories": { + "necessary": { + "title": "Notwendig", + "description": ["Zum Betrieb der Website erforderlich"] + }, + "statistics": { + "title": "Statistik", + "description": ["Beobachtung der Website-Nutzung und Optimierung der Benutzererfahrung"] + }, + "marketing": { + "title": "Marketing", + "description": ["Bewertung von Marketingaktionen"] + }, + "personalization": { + "title": "Personalisierung", + "description": ["Speicherung Ihrer Präferenzen aus früheren Besuchen", + "Sammeln von Benutzer-Feedback zur Verbesserung unserer Website", + "Erfassung Ihrer Interessen, um maßgeschneiderte Inhalte und Angebote anzubieten"] + } + } +} diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/en.json b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/en.json new file mode 100644 index 00000000..27d5c9a7 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/en.json @@ -0,0 +1,31 @@ +{ + "title": "Privacy Settings", + "body": "We use cookies and similar technologies that are necessary to operate the website. Additional cookies are only used with your consent. You are free to give, deny, or withdraw your consent at any time by using the \"cookie settings\" link at the bottom of each page. You can consent to our use of cookies by clicking \"Agree\". For more information about what information is collected and how it is shared with our partners, please read our --privacy-policy--.", + "privacyPolicy": "Data Protection Statement", + "legalNotice": "Legal Notice", + "mySettings": "My Settings", + "buttonNotAgree": "I do not agree", + "buttonAgree": "Agree", + "buttonSaveSelection": "Save selection", + "buttonAgreeAll": "Agree to all", + "categories": { + "necessary": { + "title": "Necessary", + "description": ["Required to run the website"] + }, + "statistics": { + "title": "Statistics", + "description": ["Monitoring website usage and optimizing the user experience"] + }, + "marketing": { + "title": "Marketing", + "description": ["Evaluation of marketing actions"] + }, + "personalization": { + "title": "Personalization", + "description": ["Storage of your preferences from previous visits", + "Collecting user feedback to improve our website", + "Recording of your interests in order to provide customised content and offers"] + } + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/oc.json b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/oc.json new file mode 100644 index 00000000..3e211f77 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/oc.json @@ -0,0 +1,31 @@ +{ + "title": "Paramètres de confidencialitat", + "body": "Utilizam de cookies e de tecnologias similaras que fan mestièr pel foncionament del site web. De cookies addicionals son sonque utilizats amb vòstre acòrd. Sètz liure de donar, refusar o tirar vòstre acòrd a tot moment en utilizant lo ligam «Paramètres de cookies» enbàs de cada pagina. Podètz consentir a nòstra utilizacion dels cookies en clicant «Acceptar». Per mai d'informacions tocant quina informacion es collectada e partejada amb nòstre socis, vejatz nòstra --privacy-policy--.", + "privacyPolicy": "declaracion de proteccion de las donadas", + "legalNotice": "Mencions legalas", + "mySettings": "Mos paramètres", + "buttonNotAgree": "Soi pas d'acòrd", + "buttonAgree": "Acceptar", + "buttonSaveSelection": "Enregistrar la seleccion", + "buttonAgreeAll": "Tot acceptar", + "categories": { + "necessary": { + "title": "Necessaris", + "description": ["Requerits pel foncionament del site"] + }, + "statistics": { + "title": "Estatisticas", + "description": ["Per susvelhar l'utilizacion del site e melhorar l'experiéncia dels utilizaires"] + }, + "marketing": { + "title": "Marketing", + "description": ["Estudi de las accions de marketing"] + }, + "personalization": { + "title": "Personalizacion", + "description": ["Gardar las preferéncias de visitas precedentas", + "Reculhir los comentaris dels utilizaire per melhorar nòstre site web", + "Enregistrar vòstres interesses per vos fornir de contenguts e publicitats personalizats<"] + } + } +} diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/cookie-banner-example.html b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/cookie-banner-example.html new file mode 100644 index 00000000..c8f40991 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/cookie-banner-example.html @@ -0,0 +1,79 @@ + + + + + + + + bootstrap-cookie-banner demo page + + +
+

bootstrap-cookie-consent-settings demo page

+

This is a modal dialog (cookie banner) and framework to handle the German and EU law (as written by EuGH, + 1.10.2019 – C-673/17) about cookies in a website. This banner requires Bootstrap.

+

Usage

+

Construct

+

Initialize the cookie consent framework with the constructor

+

var cookieSettings = new BootstrapCookieConsent()

+

Show the Dialog

+

On a new visit the dialog is shown automatically. For reconfiguration + show the Dialog again with cookieSettings.showDialog(). +

+

+ Cookie Settings +

+

Read the settings

+

Read all cookie settings with cookieSettings.getSettings()

+
+
+

+        
+
+

Read a specific cookie setting with cookieSettings.getSettings('statistics')

+
+
+

+        
+
+

The code of this banner

+
+
+
var cookieSettings = new BootstrapCookieConsentSettings({
+    contentURL: "../cookie-consent-content",
+    privacyPolicyUrl: "privacy-policy.html",
+    legalNoticeUrl: "legal-notice.html",
+    postSelectionCallback: function () {
+        location.reload() // reload after selection
+    }
+})
+
+
+

More documentation

+

Find more documentation and + the sourcecode on GitHub

+
+ + + + + + diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/legal-notice.html b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/legal-notice.html new file mode 100644 index 00000000..92e24a22 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/legal-notice.html @@ -0,0 +1,17 @@ + + + + + + + + bootstrap-cookie-banner demo page + + +
+

bootstrap-cookie-consent-settings

+

This is the legal notice dummy page.

+

You have to set the legal notice URL in your content files.

+
+ + diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/privacy-policy.html b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/privacy-policy.html new file mode 100644 index 00000000..89495da2 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/privacy-policy.html @@ -0,0 +1,17 @@ + + + + + + + + bootstrap-cookie-banner demo page + + +
+

bootstrap-cookie-consent-settings

+

This is the privacy policy dummy page.

+

You have to set the privacy policy URL in your content files.

+
+ + diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/favicon.ico b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..55786c3a245c2a851997ed222b022b1eaad89a24 GIT binary patch literal 15406 zcmeHNUuYaf7$0rbA}T3ZiN)ff#Rgm9Al}{X#*}+e1VKa$^vyhpjV-y`-K3TlJZ(W= zd{7a6Q9<7XA1nxhwt4YiZ)WeRA&Ryd9}0z5Efl3-N#Zwm`EF+?vwv=L+e_jse9X7= z{hi;;&d$s(AvcgsWMF_mnIq3{CZtFR$>rMjLt6=XAL{b?W%&bye6x*^AshZ&+sl&+7=t@|BqZ&|eCW%@#X8$}^j}%&_TV z#~yfIM?gkuOE*69;t%&BjT}0&yXDKJS6ljV_UIJK;TpTuwAruS+Lvo{w;2xm1?2m@a=*U|+Ij-$i$HwW`^%W5Pa>Js`s0|ZSgyAHVe=2nmlwo1VSMl7(?5$9_7tqu zmF<=D=zVE7n2#JE#t`hoWc$|M4WHj7Zi7C;`aduh@g3MM zBj?`;J7xUV{%(qm!E?Poi7n`)j&He*eI~@>dmC&&ma)&jk3s7A!_TpsFrHj;9AGcC zFOCeyds?(z(f_ay5A#84wH56aeWl^$_^S0!8ox1~PA-+I^_OKbsZ`vq9<97;;1Dw|MsNf`d%e<9R2|3}pSHrd&C zb6;|du<@_5kE-i_{o~^r$QePKqIgb G5%>=~3#UZ@ literal 0 HcmV?d00001 diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/index.html b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/index.html new file mode 100644 index 00000000..9363d1d4 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/index.html @@ -0,0 +1,34 @@ + + + + + + + + bootstrap-cookie-consent-settings demo page + + +
+

bootstrap-cookie-consent-settings demo page

+

This is a modal dialog (cookie banner) and framework to handle the German and EU law (as written by EuGH, + 1.10.2019 – C-673/17) about cookies in a website. This banner requires Bootstrap.

+

We also have another, smaller cookie banner, without dependencies, which + does not offer the user an advanced configuration. You can find it in GitHub as + cookie-consent-js.

+

Example

+ +

Further Information

+ +
+ + diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package-lock.json b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package-lock.json new file mode 100644 index 00000000..96d3d6fa --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "bootstrap-cookie-consent-settings", + "version": "4.1.4", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "bootstrap-cookie-consent-settings", + "version": "4.1.4", + "license": "MIT" + } + } +} diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package.json b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package.json new file mode 100644 index 00000000..e7113652 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package.json @@ -0,0 +1,28 @@ +{ + "name": "bootstrap-cookie-consent-settings", + "version": "4.1.4", + "description": "Settings dialog in Bootstrap 5 and framework to handle the EU law (may 2020) about cookies in a website", + "browser": "./src/bootstrap-cookie-banner.js", + "scripts": { + "test": "echo \"No test specified\"" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/shaack/bootstrap-cookie-banner.git" + }, + "keywords": [ + "bootstrap", + "cookie", + "consent", + "eu", + "gdpr", + "dsgvo" + ], + "author": "Stefan Haack (shaack.com)", + "license": "MIT", + "bugs": { + "url": "https://github.com/shaack/bootstrap-cookie-banner/issues" + }, + "homepage": "https://shaack.com", + "main": "src/bootstrap-cookie-consent-settings.js" +} diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/php/Shaack/BootstrapCookieConsentSettings.php b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/php/Shaack/BootstrapCookieConsentSettings.php new file mode 100644 index 00000000..6bb23fd5 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/php/Shaack/BootstrapCookieConsentSettings.php @@ -0,0 +1,64 @@ +cookieName = $cookieName; + $this->cookieStorageDays = $cookieStorageDays; + } + + /** + * Read the whole consent cookie into an array. + * @return array + */ + public function getSettings() : array { + parse_str(@$_COOKIE[$this->cookieName], $array); + return array_map(function($value) { + return $value === "true"; + }, $array); + } + + /** + * Write a value to the consent cookie. + * @param string $optionName + * @return bool + */ + public function getSetting(string $optionName) : bool { + return !!$this->getSettings()[$optionName]; + } + + /** + * Write an array of values to the consent cookie. + * @param array $settings + * @return void + */ + public function setSettings(array $settings) : void { + $settings["necessary"] = true; + $encoded = http_build_query(array_map(function($value) { + return $value ? "true" : "false"; + },$settings), "", "&"); + setrawcookie($this->cookieName, $encoded, time() + (86400 * $this->cookieStorageDays), "/"); + } + + /** + * Read a value from the consent cookie. + * @param string $optionName + * @param bool $value + * @return void + */ + public function setSetting(string $optionName, bool $value) : void { + $settings = $this->getSettings(); + $settings[$optionName] = $value; + $this->setSettings($settings); + } + +} diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/src/bootstrap-cookie-consent-settings.js b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/src/bootstrap-cookie-consent-settings.js new file mode 100644 index 00000000..e623a643 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/src/bootstrap-cookie-consent-settings.js @@ -0,0 +1,359 @@ +/** + * Author and copyright: Stefan Haack (https://shaack.com) + * Repository: https://github.com/shaack/bootstrap-cookie-consent-settings + * License: MIT, see file 'LICENSE' + */ + +"use strict" + +function BootstrapCookieConsentSettings(props) { + + const self = this + let detailedSettingsShown = false + this.props = { + privacyPolicyUrl: undefined, // the URL of your privacy policy page + legalNoticeUrl: undefined, // the URL of you legal notice page (Impressum) + contentURL: "/cookie-consent-content", // this folder must contain the language-files in the needed languages (`[lang].js`) + buttonAgreeClass: "btn btn-primary", // the "Agree to all" buttons class + buttonDontAgreeClass: "btn btn-link text-decoration-none", // the "I do not agree" buttons class + buttonSaveClass: "btn btn-secondary", // the "Save selection" buttons class + autoShowModal: true, // disable autoShowModal on the privacy policy and legal notice pages, to make these pages readable + alsoUseLocalStorage: true, // if true, the settings are stored in localStorage, too + postSelectionCallback: undefined, // callback function, called after the user has saved the settings + lang: navigator.language, // the language, in which the modal is shown + defaultLang: "en", // default language, if `lang` is not available as translation in `cookie-consent-content` + categories: ["necessary", "statistics", "marketing", "personalization"], // the categories for selection, must be contained in the language files + cookieName: "cookie-consent-settings", // the name of the cookie in which the configuration is stored as JSON + cookieStorageDays: 365, // the duration the cookie configuration is stored on the client + modalId: "bootstrapCookieConsentSettingsModal" // the id of the modal dialog element + } + if (!props.privacyPolicyUrl) { + console.error("please set `privacyPolicyUrl` in the props of BootstrapCookieConsentSettings") + } + if (!props.legalNoticeUrl) { + console.error("please set `legalNoticeUrl` in the props of BootstrapCookieConsentSettings") + } + for (const property in props) { + // noinspection JSUnfilteredForInLoop + this.props[property] = props[property] + } + this.lang = this.props.lang + if (this.lang.indexOf("-") !== -1) { + this.lang = this.lang.split("-")[0] + } + + // read the cookie, and if its content does not fit the categories, remove it + const cookieContent = getCookie(this.props.cookieName) + if (cookieContent) { + try { + for (const category of this.props.categories) { + if (cookieContent[category] === undefined) { + console.log("cookie settings changed, removing settings cookie") + removeCookie(this.props.cookieName) + break + } + } + } catch (e) { + // problems with the cookie, remove it + console.warn("cookie settings changed, removing settings cookie", e) + removeCookie(this.props.cookieName) + } + } + + /** + * Read the language file and render the modal + */ + fetchContent(self.lang, (result) => { + self.content = JSON.parse(result) + renderModal() + }) + + function renderModal() { + const _t = self.content + const linkPrivacyPolicy = '' + _t.privacyPolicy + '' + const linkLegalNotice = '' + _t.legalNotice + '' + if (self.content[self.lang] === undefined) { + self.lang = self.props.defaultLang + } + self.content.body = self.content.body.replace(/--privacy-policy--/, linkPrivacyPolicy) + let optionsHtml = "" + for (const category of self.props.categories) { + const categoryContent = self.content.categories[category] + if (!categoryContent) { + console.error("no content for category", category, "found in language file", self.lang) + } + let descriptionList = "" + for (const descriptionElement of categoryContent.description) { + descriptionList += `
  • ${descriptionElement}
  • ` + } + optionsHtml += `
    +
    + + +
    +
      + ${descriptionList} +
    +
    ` + } + self.modalContent = ` +` + if (!getCookie(self.props.cookieName) && self.props.autoShowModal) { + showDialog() + } + } + + function showDialog() { + documentReady(function () { + self.modalElement = document.getElementById(self.props.modalId) + if (!self.modalElement) { + self.modalElement = document.createElement("div") + self.modalElement.id = self.props.modalId + self.modalElement.setAttribute("class", "modal fade") + self.modalElement.setAttribute("tabindex", "-1") + self.modalElement.setAttribute("role", "dialog") + self.modalElement.setAttribute("aria-labelledby", self.props.modalId) + self.modalElement.innerHTML = self.modalContent + document.body.append(self.modalElement) + if (self.props.postSelectionCallback) { + self.modalElement.addEventListener("hidden.bs.modal", function () { + self.props.postSelectionCallback() + }) + } + self.modal = new bootstrap.Modal(self.modalElement, { + backdrop: "static", + keyboard: false + }) + self.modal.show() + self.buttonDoNotAgree = self.modalElement.querySelector("#bccs-buttonDoNotAgree") + self.buttonAgree = self.modalElement.querySelector("#bccs-buttonAgree") + self.buttonSave = self.modalElement.querySelector("#bccs-buttonSave") + self.buttonAgreeAll = self.modalElement.querySelector("#bccs-buttonAgreeAll") + updateButtons() + updateOptionsFromCookie() + self.modalElement.querySelector("#bccs-options").addEventListener("hide.bs.collapse", function () { + detailedSettingsShown = false + updateButtons() + }) + self.modalElement.querySelector("#bccs-options").addEventListener("show.bs.collapse", function () { + detailedSettingsShown = true + updateButtons() + }) + self.buttonDoNotAgree.addEventListener("click", function () { + doNotAgree() + }) + self.buttonAgree.addEventListener("click", function () { + agreeAll() + }) + self.buttonSave.addEventListener("click", function () { + saveSettings() + }) + self.buttonAgreeAll.addEventListener("click", function () { + agreeAll() + }) + } else { + self.modal.show() + } + }.bind(this)) + } + + function updateOptionsFromCookie() { + const settings = self.getSettings() + if (settings) { + for (let setting in settings) { + const checkboxElement = self.modalElement.querySelector("#bccs-checkbox-" + setting) + checkboxElement.checked = settings[setting] === "true" + } + } + const checkboxNecessary = self.modalElement.querySelector("#bccs-checkbox-necessary") + checkboxNecessary.checked = true + checkboxNecessary.disabled = true + } + + function updateButtons() { + if (detailedSettingsShown) { + self.buttonDoNotAgree.style.display = "none" + self.buttonAgree.style.display = "none" + self.buttonSave.style.removeProperty("display") + self.buttonAgreeAll.style.removeProperty("display") + } else { + self.buttonDoNotAgree.style.removeProperty("display") + self.buttonAgree.style.removeProperty("display") + self.buttonSave.style.display = "none" + self.buttonAgreeAll.style.display = "none" + } + } + + function gatherOptions(setAllTo = undefined) { + const options = {} + for (const category of self.props.categories) { + if (setAllTo === undefined) { + const checkbox = self.modalElement.querySelector("#bccs-checkbox-" + category) + if (!checkbox) { + console.error("checkbox not found for category", category) + } + options[category] = checkbox.checked + } else { + options[category] = setAllTo + } + } + options["necessary"] = true // necessary is necessary + return options + } + + function agreeAll() { + setCookie(self.props.cookieName, gatherOptions(true), self.props.cookieStorageDays) + self.modal.hide() + } + + function doNotAgree() { + setCookie(self.props.cookieName, gatherOptions(false), self.props.cookieStorageDays) + self.modal.hide() + } + + function saveSettings() { + setCookie(self.props.cookieName, gatherOptions(), self.props.cookieStorageDays) + self.modal.hide() + } + + function fetchContent(lang, callback) { + const request = new XMLHttpRequest() + request.overrideMimeType("application/json") + const url = self.props.contentURL + '/' + lang + '.json' + request.open('GET', url, true) + request.onreadystatechange = function () { + if (request.readyState === 4 && request.status === 200) { + if (request.status === 200) { + callback(request.responseText) + } else { + console.error(url, request.status) + } + } + } + request.onloadend = function () { + if (request.status === 404 && lang !== self.props.defaultLang) { + console.warn("language " + lang + " not found trying defaultLang " + self.props.defaultLang) + fetchContent(self.props.defaultLang, callback) + } + } + request.send(null) + } + + function setCookie(name, object, days) { + let expires = "" + if (days) { + const date = new Date() + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)) + expires = "; expires=" + date.toUTCString() + } + const value = new URLSearchParams(object).toString() + document.cookie = name + "=" + (value || "") + expires + "; Path=/; SameSite=Strict;" + // store value also in localStorage + localStorage.setItem(name, value) + } + + function getCookie(name) { + const nameEQ = name + "=" + const ca = document.cookie.split(';') + for (let i = 0; i < ca.length; i++) { + let c = ca[i] + while (c.charAt(0) === ' ') { + c = c.substring(1, c.length) + } + if (c.indexOf(nameEQ) === 0) { + const urlSearchParams = new URLSearchParams(c.substring(nameEQ.length, c.length)) + const result = {} + for (const [key, value] of urlSearchParams) { + result[key] = value + } + return result + } + } + // if cookie not found, try localStorage + const value = localStorage.getItem(name) + if (value) { + const urlSearchParams = new URLSearchParams(value) + const result = {} + for (const [key, value] of urlSearchParams) { + result[key] = value + } + setCookie(name, result, self.props.cookieStorageDays) + return result + } + return null + } + + function removeCookie(name) { + document.cookie = name + '=; Path=/; SameSite=Strict; Expires=Thu, 01 Jan 1970 00:00:01 GMT;' + } + + function documentReady(callback) { + if (document.readyState !== 'loading') { + callback() + } else { + document.addEventListener('DOMContentLoaded', callback) + } + } + + // API + this.showDialog = function () { + showDialog() + } + this.getSettings = function (optionName) { + const cookieContent = getCookie(self.props.cookieName) + if (cookieContent) { + if (optionName === undefined) { + return cookieContent + } else { + if (cookieContent) { + return cookieContent[optionName] + } else { + return false + } + } + } else { + return undefined + } + } + this.setSetting = function (name, value) { + let settings = self.getSettings() || {} + for (const category of this.props.categories) { + if(settings[category] === undefined) { + settings[category] = true + } + } + settings[name] = value + setCookie(self.props.cookieName, settings, self.props.cookieStorageDays) + } +} From 1c55c4aa99feb99937278de2e3637489b61408af Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Tue, 16 Apr 2024 10:32:39 +0200 Subject: [PATCH 2/5] Implementierte GDPR-konforme Cookie-Zustimmungsmechanik MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Integrierte die 'bootstrap-cookie-consent-settings' Bibliothek für Cookie-Zustimmungsdialoge - Hinzugefügt mehrsprachige Unterstützung für Cookie-Dialoge - Konfigurierte Anwendungseinstellungen in 'appsettings.json' - Erstellt Datenschutz- und Cookie-Richtlinien mit TermsFeed - Angepasste sprachbasierte Einstellungen in './wwwroot/cookie-consent-content' --- .../EnvelopeGenerator.Web.csproj | 6 + .../Views/Shared/_Layout.cshtml | 2 +- EnvelopeGenerator.Web/appsettings.json | 8 +- .../wwwroot/cookie-consent-content/de.json | 17 ++ .../wwwroot/cookie-consent-content/en.json | 17 ++ .../wwwroot/cookies-policy.en.html | 68 +++++++ ...bootstrap-cookie-consent-settings-main.zip | Bin 18308 -> 0 bytes .../.gitattributes | 4 - .../.gitignore | 2 - .../LICENSE | 21 -- .../README.md | 121 ------------ .../bootstrap-cookie-consent-settings.js | 0 .../cookie-consent-content/de.json | 31 --- .../cookie-consent-content/en.json | 31 --- .../cookie-consent-content/oc.json | 31 --- .../examples/cookie-banner-example.html | 79 -------- .../examples/legal-notice.html | 17 -- .../examples/privacy-policy.html | 17 -- .../favicon.ico | Bin 15406 -> 0 bytes .../index.html | 34 ---- .../package-lock.json | 13 -- .../package.json | 28 --- .../Shaack/BootstrapCookieConsentSettings.php | 64 ------ .../wwwroot/privacy-policy.en.html | 184 ++++++++++++++++++ 24 files changed, 297 insertions(+), 498 deletions(-) create mode 100644 EnvelopeGenerator.Web/wwwroot/cookie-consent-content/de.json create mode 100644 EnvelopeGenerator.Web/wwwroot/cookie-consent-content/en.json create mode 100644 EnvelopeGenerator.Web/wwwroot/cookies-policy.en.html delete mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main.zip delete mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitattributes delete mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitignore delete mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/LICENSE delete mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/README.md rename EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/{src => }/bootstrap-cookie-consent-settings.js (100%) delete mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/de.json delete mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/en.json delete mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/oc.json delete mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/cookie-banner-example.html delete mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/legal-notice.html delete mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/privacy-policy.html delete mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/favicon.ico delete mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/index.html delete mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package-lock.json delete mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package.json delete mode 100644 EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/php/Shaack/BootstrapCookieConsentSettings.php create mode 100644 EnvelopeGenerator.Web/wwwroot/privacy-policy.en.html diff --git a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj index 6dcbdcee..77d36604 100644 --- a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj +++ b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj @@ -75,6 +75,12 @@ Never + + Always + + + Always +
    diff --git a/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml b/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml index 63e1073b..a15a6e84 100644 --- a/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml +++ b/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml @@ -19,7 +19,7 @@ - + @await RenderSectionAsync("Scripts", required: false)
    diff --git a/EnvelopeGenerator.Web/appsettings.json b/EnvelopeGenerator.Web/appsettings.json index 2ca1852b..e761e269 100644 --- a/EnvelopeGenerator.Web/appsettings.json +++ b/EnvelopeGenerator.Web/appsettings.json @@ -55,13 +55,13 @@ }, "CookieConsentSettings": { - "PrivacyPolicyUrl": "./", - "LegalNoticeUrl": "./", - "ContentURL": "/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content", + "PrivacyPolicyUrl": "./privacy-policy.en.html", + "LegalNoticeUrl": "./cookies-policy.en.html", + "ContentURL": "/cookie-consent-content", "ButtonAgreeClass": "btn btn-primary", "ButtonDontAgreeClass": "btn btn-link text-decoration-none none-display", "ButtonSaveClass": "btn btn-secondary none-display", - "Lang": "en", + "Lang": "de", "DefaultLang": "en", "CookieName": "cookie-consent-settings", "CookieStorageDays": 1, diff --git a/EnvelopeGenerator.Web/wwwroot/cookie-consent-content/de.json b/EnvelopeGenerator.Web/wwwroot/cookie-consent-content/de.json new file mode 100644 index 00000000..de868af5 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/cookie-consent-content/de.json @@ -0,0 +1,17 @@ +{ + "title": "Cookie-Nutzung", + "body": "Unsere Webseite verwendet notwendige Cookies, um richtig funktionieren zu können. Diese Cookies sind erforderlich für die Sicherheit der Seite und die Verbesserung der Benutzererfahrung. Es ist wichtig, dass Sie unsere Cookie-Nutzung akzeptieren, um alle Funktionen unserer Webseite vollständig nutzen zu können.", + "privacyPolicy": "Datenschutzerklärung", + "legalNotice": "Details zur Cookie-Nutzung", + "mySettings": "Einstellungen", + "buttonNotAgree": "Ich bin nicht einverstanden", + "buttonAgree": "Einverstanden", + "buttonSaveSelection": "Auswahl speichern", + "buttonAgreeAll": "Einverstanden", + "categories": { + "necessary": { + "title": "Notwendig", + "description": [ "Diese Cookies sind notwendig für Funktionen wie Seitensicherheit, Sitzungsverwaltung und Schutz. Unsere Cookies umfassen technische Cookies, die für die Sitzungsverwaltung und zur Gewährleistung der Sicherheit verwendet werden." ] + } + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/cookie-consent-content/en.json b/EnvelopeGenerator.Web/wwwroot/cookie-consent-content/en.json new file mode 100644 index 00000000..66877490 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/cookie-consent-content/en.json @@ -0,0 +1,17 @@ +{ + "title": "Cookie Usage", + "body": "Our website uses essential cookies to function properly. These cookies are necessary for site security and improving user experience. It is important that you accept our cookie usage to fully benefit from all the features of our website.", + "privacyPolicy": "Data Protection Statement", + "legalNotice": "Cookie Usage Details", + "mySettings": "Settings", + "buttonNotAgree": "I do not agree", + "buttonAgree": "Agree", + "buttonSaveSelection": "Save selection", + "buttonAgreeAll": "Agree", + "categories": { + "necessary": { + "title": "Necessary", + "description": [ "These cookies are necessary for functions such as site security, session management, and protection. Our cookies include technical cookies that are used for session management and to ensure security." ] + } + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/cookies-policy.en.html b/EnvelopeGenerator.Web/wwwroot/cookies-policy.en.html new file mode 100644 index 00000000..73262fb6 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/cookies-policy.en.html @@ -0,0 +1,68 @@ +

    Cookies Policy

    +

    Last updated: April 16, 2024

    +

    This Cookies Policy explains what Cookies are and how We use them. You should read this policy so You can understand what type of cookies We use, or the information We collect using Cookies and how that information is used. This Cookies Policy has been created with the help of the Cookies Policy Generator.

    +

    Cookies do not typically contain any information that personally identifies a user, but personal information that we store about You may be linked to the information stored in and obtained from Cookies. For further information on how We use, store and keep your personal data secure, see our Privacy Policy.

    +

    We do not store sensitive personal information, such as mailing addresses, account passwords, etc. in the Cookies We use.

    +

    Interpretation and Definitions

    +

    Interpretation

    +

    The words of which the initial letter is capitalized have meanings defined under the following conditions. The following definitions shall have the same meaning regardless of whether they appear in singular or in plural.

    +

    Definitions

    +

    For the purposes of this Cookies Policy:

    +
      +
    • Company (referred to as either "the Company", "We", "Us" or "Our" in this Cookies Policy) refers to Digital Data GmbH, Ludwig Rinn Str. 16, D-35452 Heuchelheim.
    • +
    • Cookies means small files that are placed on Your computer, mobile device or any other device by a website, containing details of your browsing history on that website among its many uses.
    • +
    • Website refers to Digitaldata Unterschrift, accessible from unterschrift.digitaldata.works
    • +
    • You means the individual accessing or using the Website, or a company, or any legal entity on behalf of which such individual is accessing or using the Website, as applicable.
    • +
    +

    The use of the Cookies

    +

    Type of Cookies We Use

    +

    Cookies can be "Persistent" or "Session" Cookies. Persistent Cookies remain on your personal computer or mobile device when You go offline, while Session Cookies are deleted as soon as You close your web browser.

    +

    We use both session and persistent Cookies for the purposes set out below:

    +
      +
    • +

      Necessary / Essential Cookies

      +

      Type: Session Cookies

      +

      Administered by: Us

      +

      Purpose: These Cookies are essential to provide You with services available through the Website and to enable You to use some of its features. They help to authenticate users and prevent fraudulent use of user accounts. Without these Cookies, the services that You have asked for cannot be provided, and We only use these Cookies to provide You with those services.

      +
    • +
    • +

      Functionality Cookies

      +

      Type: Persistent Cookies

      +

      Administered by: Us

      +

      Purpose: These Cookies allow us to remember choices You make when You use the Website, such as remembering your login details or language preference. The purpose of these Cookies is to provide You with a more personal experience and to avoid You having to re-enter your preferences every time You use the Website.

      +
    • +
    +

    Your Choices Regarding Cookies

    +

    If You prefer to avoid the use of Cookies on the Website, first You must disable the use of Cookies in your browser and then delete the Cookies saved in your browser associated with this website. You may use this option for preventing the use of Cookies at any time.

    +

    If You do not accept Our Cookies, You may experience some inconvenience in your use of the Website and some features may not function properly.

    +

    If You'd like to delete Cookies or instruct your web browser to delete or refuse Cookies, please visit the help pages of your web browser.

    + +

    For any other web browser, please visit your web browser's official web pages.

    +

    More Information about Cookies

    +

    You can learn more about cookies here: All About Cookies by TermsFeed.

    +

    Contact Us

    +

    If you have any questions about this Cookies Policy, You can contact us:

    +
      +
    • +

      By visiting this page on our website: unterschrift.digitaldata.works

      +
    • +
    • +

      By phone number: +49(0)-641-202360

      +
    • +
    • +

      By mail: Ludwig Rinn Str. 16, D-35452 Heuchelheim

      +
    • +
    \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main.zip b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main.zip deleted file mode 100644 index 85b930f7acd238b8859e54e3865a2c04984cd130..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18308 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 diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitattributes b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitattributes deleted file mode 100644 index f2bc0acc..00000000 --- a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitattributes +++ /dev/null @@ -1,4 +0,0 @@ -src/bootstrap-cookie-consent-settings.js linguist-vendored=false -index.html linguist-documentation -demo/legal-notice.html linguist-documentation -demo/privacy-policy.html linguist-documentation \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitignore b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitignore deleted file mode 100644 index e0b850e0..00000000 --- a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/.idea -/node_modules \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/LICENSE b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/LICENSE deleted file mode 100644 index 7bd9a202..00000000 --- a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 Stefan Haack - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/README.md b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/README.md deleted file mode 100644 index e087d50b..00000000 --- a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/README.md +++ /dev/null @@ -1,121 +0,0 @@ -# bootstrap-cookie-consent-settings - -A modal dialog (cookie banner) and framework to handle the EU law (as written by EuGH, 1.10.2019 – C-673/17) -about cookies in a website. Needs Bootstrap 5. - -- [Demo page](https://shaack.com/projekte/bootstrap-cookie-consent-settings) -- [GitHub Repository](https://github.com/shaack/bootstrap-cookie-consent-settings) -- [npm package](https://www.npmjs.com/package/bootstrap-cookie-consent-settings) - -## Usage - -### Construct - -Initialize the cookie consent framework with the constructor - -```js -var cookieSettings = new BootstrapCookieConsentSettings(props) -``` - -You should configure the framework with the `props` object, at least the properties `privacyPolicyUrl`, `legalNoticeUrl` -and `contentURL`. The default configuration is - -```js -this.props = { - privacyPolicyUrl: undefined, // the URL of your privacy policy page - legalNoticeUrl: undefined, // the URL of you legal notice page (Impressum) - contentURL: "/cookie-consent-content", // this folder must contain the language-files in the needed languages (`[lang].js`) - buttonAgreeClass: "btn btn-primary", // the "Agree to all" buttons class - buttonDontAgreeClass: "btn btn-link text-decoration-none", // the "I do not agree" buttons class - buttonSaveClass: "btn btn-secondary", // the "Save selection" buttons class - autoShowModal: true, // disable autoShowModal on the privacy policy and legal notice pages, to make these pages readable - alsoUseLocalStorage: true, // if true, the settings are stored in localStorage, too - postSelectionCallback: undefined, // callback function, called after the user has saved the settings - lang: navigator.language, // the language, in which the modal is shown - defaultLang: "en", // default language, if `lang` is not available as translation in `cookie-consent-content` - categories: ["necessary", "statistics", "marketing", "personalization"], // the categories for selection, must be contained in the language files - cookieName: "cookie-consent-settings", // the name of the cookie in which the configuration is stored as JSON - cookieStorageDays: 365, // the duration the cookie configuration is stored on the client - modalId: "bootstrapCookieConsentSettingsModal" // the id of the modal dialog element -} -``` - -### Show dialog - -On a new visit the dialog is shown automatically. - -To allow the user a reconfiguration you can show the Dialog again with - -```js -cookieSettings.showDialog() -``` - -### Read the settings in JavaScript - -Read all cookie settings with - -```js -cookieSettings.getSettings() -``` - -It should return some JSON like - -```json -{ - "necessary": true, - "statistics": true, - "marketing": true, - "personalization": true -} -``` - -or `undefined`, before the user has chosen his cookie options. - -Read a specific cookie setting with - -```js -cookieSettings.getSettings('statistics') -``` - -for the `statistics` cookie settings. Also returns `undefined`, before the user has chosen his cookie options. - -### Read the settings from the backend - -You can read the settings with all server languages, you just have to read the cookie `cookie-consent-settings`. -The content of the cookie is encoded like a http query string. - -``` -necessary=true&statistics=false&marketing=true&personalization=true -``` - -#### PHP helper class - -I provide a PHP helper class that you can use to read and write the settings from a PHP backend. - -It is located in `php/Shaack/BootstrapCookieConsentSettings.php`. - -You can use it as described in the following example. - -```PHP -$cookieSettings = new \Shaack\BootstrapCookieConsentSettings(); -// read all settings -$allSettings = $cookieSettings->getSettings(); -// read a specific setting -$statisticsAllowed = $cookieSettings->getSetting("statistics"); -// write a specific setting -$cookieSettings->setSetting("statistics", false); -``` - -### Internationalization - -You find the language files in `./cookie-consent-content`. You can add here language files or modify the existing. If -you add language files please consider a pull request to also add them in this repository. Thanks. - -## Disclaimer - -You can use this banner for your website free of charge under the [MIT-License](./LICENSE). - -The banner and framework was designed in cooperation with data protection officers and lawyers. However, we can not -guarantee whether the banner is correct for your website and assume no liability for its use. - -bootstrap-cookie-consent-settings is a project of [shaack.com](https://shaack.com). diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/src/bootstrap-cookie-consent-settings.js b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/bootstrap-cookie-consent-settings.js similarity index 100% rename from EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/src/bootstrap-cookie-consent-settings.js rename to EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/bootstrap-cookie-consent-settings.js diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/de.json b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/de.json deleted file mode 100644 index 3da494a4..00000000 --- a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/de.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "title": "Privatsphäre Einstellungen", - "body": "Wir nutzen Cookies und ähnliche Technologien, die zum Betrieb der Website erforderlich sind. Zusätzliche Cookies werden nur mit Ihrer Zustimmung verwendet. Es steht Ihnen frei, Ihre Zustimmung jederzeit zu geben, zu verweigern oder zurückzuziehen, indem Sie den Link \"Cookie-Einstellungen\" unten auf jeder Seite nutzen. Sie können der Verwendung von Cookies durch uns zustimmen, indem Sie auf \"Einverstanden\" klicken. Für weitere Informationen darüber, welche Daten gesammelt und wie sie an unsere Partner weitergegeben werden, lesen Sie bitte unsere --privacy-policy--.", - "privacyPolicy": "Datenschutzerklärung", - "legalNotice": "Impressum", - "mySettings": "Meine Einstellungen", - "buttonNotAgree": "Ich bin nicht einverstanden", - "buttonAgree": "Einverstanden", - "buttonSaveSelection": "Auswahl speichern", - "buttonAgreeAll": "Allen zustimmen", - "categories": { - "necessary": { - "title": "Notwendig", - "description": ["Zum Betrieb der Website erforderlich"] - }, - "statistics": { - "title": "Statistik", - "description": ["Beobachtung der Website-Nutzung und Optimierung der Benutzererfahrung"] - }, - "marketing": { - "title": "Marketing", - "description": ["Bewertung von Marketingaktionen"] - }, - "personalization": { - "title": "Personalisierung", - "description": ["Speicherung Ihrer Präferenzen aus früheren Besuchen", - "Sammeln von Benutzer-Feedback zur Verbesserung unserer Website", - "Erfassung Ihrer Interessen, um maßgeschneiderte Inhalte und Angebote anzubieten"] - } - } -} diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/en.json b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/en.json deleted file mode 100644 index 27d5c9a7..00000000 --- a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/en.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "title": "Privacy Settings", - "body": "We use cookies and similar technologies that are necessary to operate the website. Additional cookies are only used with your consent. You are free to give, deny, or withdraw your consent at any time by using the \"cookie settings\" link at the bottom of each page. You can consent to our use of cookies by clicking \"Agree\". For more information about what information is collected and how it is shared with our partners, please read our --privacy-policy--.", - "privacyPolicy": "Data Protection Statement", - "legalNotice": "Legal Notice", - "mySettings": "My Settings", - "buttonNotAgree": "I do not agree", - "buttonAgree": "Agree", - "buttonSaveSelection": "Save selection", - "buttonAgreeAll": "Agree to all", - "categories": { - "necessary": { - "title": "Necessary", - "description": ["Required to run the website"] - }, - "statistics": { - "title": "Statistics", - "description": ["Monitoring website usage and optimizing the user experience"] - }, - "marketing": { - "title": "Marketing", - "description": ["Evaluation of marketing actions"] - }, - "personalization": { - "title": "Personalization", - "description": ["Storage of your preferences from previous visits", - "Collecting user feedback to improve our website", - "Recording of your interests in order to provide customised content and offers"] - } - } -} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/oc.json b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/oc.json deleted file mode 100644 index 3e211f77..00000000 --- a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/cookie-consent-content/oc.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "title": "Paramètres de confidencialitat", - "body": "Utilizam de cookies e de tecnologias similaras que fan mestièr pel foncionament del site web. De cookies addicionals son sonque utilizats amb vòstre acòrd. Sètz liure de donar, refusar o tirar vòstre acòrd a tot moment en utilizant lo ligam «Paramètres de cookies» enbàs de cada pagina. Podètz consentir a nòstra utilizacion dels cookies en clicant «Acceptar». Per mai d'informacions tocant quina informacion es collectada e partejada amb nòstre socis, vejatz nòstra --privacy-policy--.", - "privacyPolicy": "declaracion de proteccion de las donadas", - "legalNotice": "Mencions legalas", - "mySettings": "Mos paramètres", - "buttonNotAgree": "Soi pas d'acòrd", - "buttonAgree": "Acceptar", - "buttonSaveSelection": "Enregistrar la seleccion", - "buttonAgreeAll": "Tot acceptar", - "categories": { - "necessary": { - "title": "Necessaris", - "description": ["Requerits pel foncionament del site"] - }, - "statistics": { - "title": "Estatisticas", - "description": ["Per susvelhar l'utilizacion del site e melhorar l'experiéncia dels utilizaires"] - }, - "marketing": { - "title": "Marketing", - "description": ["Estudi de las accions de marketing"] - }, - "personalization": { - "title": "Personalizacion", - "description": ["Gardar las preferéncias de visitas precedentas", - "Reculhir los comentaris dels utilizaire per melhorar nòstre site web", - "Enregistrar vòstres interesses per vos fornir de contenguts e publicitats personalizats<"] - } - } -} diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/cookie-banner-example.html b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/cookie-banner-example.html deleted file mode 100644 index c8f40991..00000000 --- a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/cookie-banner-example.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - bootstrap-cookie-banner demo page - - -
    -

    bootstrap-cookie-consent-settings demo page

    -

    This is a modal dialog (cookie banner) and framework to handle the German and EU law (as written by EuGH, - 1.10.2019 – C-673/17) about cookies in a website. This banner requires Bootstrap.

    -

    Usage

    -

    Construct

    -

    Initialize the cookie consent framework with the constructor

    -

    var cookieSettings = new BootstrapCookieConsent()

    -

    Show the Dialog

    -

    On a new visit the dialog is shown automatically. For reconfiguration - show the Dialog again with cookieSettings.showDialog(). -

    -

    - Cookie Settings -

    -

    Read the settings

    -

    Read all cookie settings with cookieSettings.getSettings()

    -
    -
    -
    
    -        
    -
    -

    Read a specific cookie setting with cookieSettings.getSettings('statistics')

    -
    -
    -
    
    -        
    -
    -

    The code of this banner

    -
    -
    -
    var cookieSettings = new BootstrapCookieConsentSettings({
    -    contentURL: "../cookie-consent-content",
    -    privacyPolicyUrl: "privacy-policy.html",
    -    legalNoticeUrl: "legal-notice.html",
    -    postSelectionCallback: function () {
    -        location.reload() // reload after selection
    -    }
    -})
    -
    -
    -

    More documentation

    -

    Find more documentation and - the sourcecode on GitHub

    -
    - - - - - - diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/legal-notice.html b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/legal-notice.html deleted file mode 100644 index 92e24a22..00000000 --- a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/legal-notice.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - bootstrap-cookie-banner demo page - - -
    -

    bootstrap-cookie-consent-settings

    -

    This is the legal notice dummy page.

    -

    You have to set the legal notice URL in your content files.

    -
    - - diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/privacy-policy.html b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/privacy-policy.html deleted file mode 100644 index 89495da2..00000000 --- a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/examples/privacy-policy.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - bootstrap-cookie-banner demo page - - -
    -

    bootstrap-cookie-consent-settings

    -

    This is the privacy policy dummy page.

    -

    You have to set the privacy policy URL in your content files.

    -
    - - diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/favicon.ico b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/favicon.ico deleted file mode 100644 index 55786c3a245c2a851997ed222b022b1eaad89a24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15406 zcmeHNUuYaf7$0rbA}T3ZiN)ff#Rgm9Al}{X#*}+e1VKa$^vyhpjV-y`-K3TlJZ(W= zd{7a6Q9<7XA1nxhwt4YiZ)WeRA&Ryd9}0z5Efl3-N#Zwm`EF+?vwv=L+e_jse9X7= z{hi;;&d$s(AvcgsWMF_mnIq3{CZtFR$>rMjLt6=XAL{b?W%&bye6x*^AshZ&+sl&+7=t@|BqZ&|eCW%@#X8$}^j}%&_TV z#~yfIM?gkuOE*69;t%&BjT}0&yXDKJS6ljV_UIJK;TpTuwAruS+Lvo{w;2xm1?2m@a=*U|+Ij-$i$HwW`^%W5Pa>Js`s0|ZSgyAHVe=2nmlwo1VSMl7(?5$9_7tqu zmF<=D=zVE7n2#JE#t`hoWc$|M4WHj7Zi7C;`aduh@g3MM zBj?`;J7xUV{%(qm!E?Poi7n`)j&He*eI~@>dmC&&ma)&jk3s7A!_TpsFrHj;9AGcC zFOCeyds?(z(f_ay5A#84wH56aeWl^$_^S0!8ox1~PA-+I^_OKbsZ`vq9<97;;1Dw|MsNf`d%e<9R2|3}pSHrd&C zb6;|du<@_5kE-i_{o~^r$QePKqIgb G5%>=~3#UZ@ diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/index.html b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/index.html deleted file mode 100644 index 9363d1d4..00000000 --- a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - bootstrap-cookie-consent-settings demo page - - -
    -

    bootstrap-cookie-consent-settings demo page

    -

    This is a modal dialog (cookie banner) and framework to handle the German and EU law (as written by EuGH, - 1.10.2019 – C-673/17) about cookies in a website. This banner requires Bootstrap.

    -

    We also have another, smaller cookie banner, without dependencies, which - does not offer the user an advanced configuration. You can find it in GitHub as - cookie-consent-js.

    -

    Example

    - -

    Further Information

    - -
    - - diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package-lock.json b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package-lock.json deleted file mode 100644 index 96d3d6fa..00000000 --- a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package-lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "bootstrap-cookie-consent-settings", - "version": "4.1.4", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "bootstrap-cookie-consent-settings", - "version": "4.1.4", - "license": "MIT" - } - } -} diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package.json b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package.json deleted file mode 100644 index e7113652..00000000 --- a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "bootstrap-cookie-consent-settings", - "version": "4.1.4", - "description": "Settings dialog in Bootstrap 5 and framework to handle the EU law (may 2020) about cookies in a website", - "browser": "./src/bootstrap-cookie-banner.js", - "scripts": { - "test": "echo \"No test specified\"" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/shaack/bootstrap-cookie-banner.git" - }, - "keywords": [ - "bootstrap", - "cookie", - "consent", - "eu", - "gdpr", - "dsgvo" - ], - "author": "Stefan Haack (shaack.com)", - "license": "MIT", - "bugs": { - "url": "https://github.com/shaack/bootstrap-cookie-banner/issues" - }, - "homepage": "https://shaack.com", - "main": "src/bootstrap-cookie-consent-settings.js" -} diff --git a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/php/Shaack/BootstrapCookieConsentSettings.php b/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/php/Shaack/BootstrapCookieConsentSettings.php deleted file mode 100644 index 6bb23fd5..00000000 --- a/EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/php/Shaack/BootstrapCookieConsentSettings.php +++ /dev/null @@ -1,64 +0,0 @@ -cookieName = $cookieName; - $this->cookieStorageDays = $cookieStorageDays; - } - - /** - * Read the whole consent cookie into an array. - * @return array - */ - public function getSettings() : array { - parse_str(@$_COOKIE[$this->cookieName], $array); - return array_map(function($value) { - return $value === "true"; - }, $array); - } - - /** - * Write a value to the consent cookie. - * @param string $optionName - * @return bool - */ - public function getSetting(string $optionName) : bool { - return !!$this->getSettings()[$optionName]; - } - - /** - * Write an array of values to the consent cookie. - * @param array $settings - * @return void - */ - public function setSettings(array $settings) : void { - $settings["necessary"] = true; - $encoded = http_build_query(array_map(function($value) { - return $value ? "true" : "false"; - },$settings), "", "&"); - setrawcookie($this->cookieName, $encoded, time() + (86400 * $this->cookieStorageDays), "/"); - } - - /** - * Read a value from the consent cookie. - * @param string $optionName - * @param bool $value - * @return void - */ - public function setSetting(string $optionName, bool $value) : void { - $settings = $this->getSettings(); - $settings[$optionName] = $value; - $this->setSettings($settings); - } - -} diff --git a/EnvelopeGenerator.Web/wwwroot/privacy-policy.en.html b/EnvelopeGenerator.Web/wwwroot/privacy-policy.en.html new file mode 100644 index 00000000..4de34e9e --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/privacy-policy.en.html @@ -0,0 +1,184 @@ +

    Privacy Policy

    +

    Last updated: April 16, 2024

    +

    This Privacy Policy describes Our policies and procedures on the collection, use and disclosure of Your information when You use the Service and tells You about Your privacy rights and how the law protects You.

    +

    We use Your Personal data to provide and improve the Service. By using the Service, You agree to the collection and use of information in accordance with this Privacy Policy. This Privacy Policy has been created with the help of the Privacy Policy Generator.

    +

    Interpretation and Definitions

    +

    Interpretation

    +

    The words of which the initial letter is capitalized have meanings defined under the following conditions. The following definitions shall have the same meaning regardless of whether they appear in singular or in plural.

    +

    Definitions

    +

    For the purposes of this Privacy Policy:

    +
      +
    • +

      Account means a unique account created for You to access our Service or parts of our Service.

      +
    • +
    • +

      Affiliate means an entity that controls, is controlled by or is under common control with a party, where "control" means ownership of 50% or more of the shares, equity interest or other securities entitled to vote for election of directors or other managing authority.

      +
    • +
    • +

      Company (referred to as either "the Company", "We", "Us" or "Our" in this Agreement) refers to Digital Data GmbH, Ludwig Rinn Str. 16, D-35452 Heuchelheim.

      +
    • +
    • +

      Cookies are small files that are placed on Your computer, mobile device or any other device by a website, containing the details of Your browsing history on that website among its many uses.

      +
    • +
    • +

      Country refers to: Hessen, Germany

      +
    • +
    • +

      Device means any device that can access the Service such as a computer, a cellphone or a digital tablet.

      +
    • +
    • +

      Personal Data is any information that relates to an identified or identifiable individual.

      +
    • +
    • +

      Service refers to the Website.

      +
    • +
    • +

      Service Provider means any natural or legal person who processes the data on behalf of the Company. It refers to third-party companies or individuals employed by the Company to facilitate the Service, to provide the Service on behalf of the Company, to perform services related to the Service or to assist the Company in analyzing how the Service is used.

      +
    • +
    • +

      Usage Data refers to data collected automatically, either generated by the use of the Service or from the Service infrastructure itself (for example, the duration of a page visit).

      +
    • +
    • +

      Website refers to Unterschrift, accessible from unterschrift.digitaldata.works

      +
    • +
    • +

      You means the individual accessing or using the Service, or the company, or other legal entity on behalf of which such individual is accessing or using the Service, as applicable.

      +
    • +
    +

    Collecting and Using Your Personal Data

    +

    Types of Data Collected

    +

    Personal Data

    +

    While using Our Service, We may ask You to provide Us with certain personally identifiable information that can be used to contact or identify You. Personally identifiable information may include, but is not limited to:

    +
      +
    • +

      Email address

      +
    • +
    • +

      First name and last name

      +
    • +
    • +

      Usage Data

      +
    • +
    +

    Usage Data

    +

    Usage Data is collected automatically when using the Service.

    +

    Usage Data may include information such as Your Device's Internet Protocol address (e.g. IP address), browser type, browser version, the pages of our Service that You visit, the time and date of Your visit, the time spent on those pages, unique device identifiers and other diagnostic data.

    +

    When You access the Service by or through a mobile device, We may collect certain information automatically, including, but not limited to, the type of mobile device You use, Your mobile device unique ID, the IP address of Your mobile device, Your mobile operating system, the type of mobile Internet browser You use, unique device identifiers and other diagnostic data.

    +

    We may also collect information that Your browser sends whenever You visit our Service or when You access the Service by or through a mobile device.

    +

    Tracking Technologies and Cookies

    +

    We use Cookies and similar tracking technologies to track the activity on Our Service and store certain information. Tracking technologies used are beacons, tags, and scripts to collect and track information and to improve and analyze Our Service. The technologies We use may include:

    +
      +
    • Cookies or Browser Cookies. A cookie is a small file placed on Your Device. You can instruct Your browser to refuse all Cookies or to indicate when a Cookie is being sent. However, if You do not accept Cookies, You may not be able to use some parts of our Service. Unless you have adjusted Your browser setting so that it will refuse Cookies, our Service may use Cookies.
    • +
    • Web Beacons. Certain sections of our Service and our emails may contain small electronic files known as web beacons (also referred to as clear gifs, pixel tags, and single-pixel gifs) that permit the Company, for example, to count users who have visited those pages or opened an email and for other related website statistics (for example, recording the popularity of a certain section and verifying system and server integrity).
    • +
    +

    Cookies can be "Persistent" or "Session" Cookies. Persistent Cookies remain on Your personal computer or mobile device when You go offline, while Session Cookies are deleted as soon as You close Your web browser. You can learn more about cookies on TermsFeed website article.

    +

    We use both Session and Persistent Cookies for the purposes set out below:

    +
      +
    • +

      Necessary / Essential Cookies

      +

      Type: Session Cookies

      +

      Administered by: Us

      +

      Purpose: These Cookies are essential to provide You with services available through the Website and to enable You to use some of its features. They help to authenticate users and prevent fraudulent use of user accounts. Without these Cookies, the services that You have asked for cannot be provided, and We only use these Cookies to provide You with those services.

      +
    • +
    • +

      Cookies Policy / Notice Acceptance Cookies

      +

      Type: Persistent Cookies

      +

      Administered by: Us

      +

      Purpose: These Cookies identify if users have accepted the use of cookies on the Website.

      +
    • +
    • +

      Functionality Cookies

      +

      Type: Persistent Cookies

      +

      Administered by: Us

      +

      Purpose: These Cookies allow us to remember choices You make when You use the Website, such as remembering your login details or language preference. The purpose of these Cookies is to provide You with a more personal experience and to avoid You having to re-enter your preferences every time You use the Website.

      +
    • +
    +

    For more information about the cookies we use and your choices regarding cookies, please visit our Cookies Policy or the Cookies section of our Privacy Policy.

    +

    Use of Your Personal Data

    +

    The Company may use Personal Data for the following purposes:

    +
      +
    • +

      To provide and maintain our Service, including to monitor the usage of our Service.

      +
    • +
    • +

      To manage Your Account: to manage Your registration as a user of the Service. The Personal Data You provide can give You access to different functionalities of the Service that are available to You as a registered user.

      +
    • +
    • +

      For the performance of a contract: the development, compliance and undertaking of the purchase contract for the products, items or services You have purchased or of any other contract with Us through the Service.

      +
    • +
    • +

      To contact You: To contact You by email, telephone calls, SMS, or other equivalent forms of electronic communication, such as a mobile application's push notifications regarding updates or informative communications related to the functionalities, products or contracted services, including the security updates, when necessary or reasonable for their implementation.

      +
    • +
    • +

      To provide You with news, special offers and general information about other goods, services and events which we offer that are similar to those that you have already purchased or enquired about unless You have opted not to receive such information.

      +
    • +
    • +

      To manage Your requests: To attend and manage Your requests to Us.

      +
    • +
    • +

      For business transfers: We may use Your information to evaluate or conduct a merger, divestiture, restructuring, reorganization, dissolution, or other sale or transfer of some or all of Our assets, whether as a going concern or as part of bankruptcy, liquidation, or similar proceeding, in which Personal Data held by Us about our Service users is among the assets transferred.

      +
    • +
    • +

      For other purposes: We may use Your information for other purposes, such as data analysis, identifying usage trends, determining the effectiveness of our promotional campaigns and to evaluate and improve our Service, products, services, marketing and your experience.

      +
    • +
    +

    We may share Your personal information in the following situations:

    +
      +
    • With Service Providers: We may share Your personal information with Service Providers to monitor and analyze the use of our Service, to contact You.
    • +
    • For business transfers: We may share or transfer Your personal information in connection with, or during negotiations of, any merger, sale of Company assets, financing, or acquisition of all or a portion of Our business to another company.
    • +
    • With Affiliates: We may share Your information with Our affiliates, in which case we will require those affiliates to honor this Privacy Policy. Affiliates include Our parent company and any other subsidiaries, joint venture partners or other companies that We control or that are under common control with Us.
    • +
    • With business partners: We may share Your information with Our business partners to offer You certain products, services or promotions.
    • +
    • With other users: when You share personal information or otherwise interact in the public areas with other users, such information may be viewed by all users and may be publicly distributed outside.
    • +
    • With Your consent: We may disclose Your personal information for any other purpose with Your consent.
    • +
    +

    Retention of Your Personal Data

    +

    The Company will retain Your Personal Data only for as long as is necessary for the purposes set out in this Privacy Policy. We will retain and use Your Personal Data to the extent necessary to comply with our legal obligations (for example, if we are required to retain your data to comply with applicable laws), resolve disputes, and enforce our legal agreements and policies.

    +

    The Company will also retain Usage Data for internal analysis purposes. Usage Data is generally retained for a shorter period of time, except when this data is used to strengthen the security or to improve the functionality of Our Service, or We are legally obligated to retain this data for longer time periods.

    +

    Transfer of Your Personal Data

    +

    Your information, including Personal Data, is processed at the Company's operating offices and in any other places where the parties involved in the processing are located. It means that this information may be transferred to — and maintained on — computers located outside of Your state, province, country or other governmental jurisdiction where the data protection laws may differ than those from Your jurisdiction.

    +

    Your consent to this Privacy Policy followed by Your submission of such information represents Your agreement to that transfer.

    +

    The Company will take all steps reasonably necessary to ensure that Your data is treated securely and in accordance with this Privacy Policy and no transfer of Your Personal Data will take place to an organization or a country unless there are adequate controls in place including the security of Your data and other personal information.

    +

    Delete Your Personal Data

    +

    You have the right to delete or request that We assist in deleting the Personal Data that We have collected about You.

    +

    Our Service may give You the ability to delete certain information about You from within the Service.

    +

    You may update, amend, or delete Your information at any time by signing in to Your Account, if you have one, and visiting the account settings section that allows you to manage Your personal information. You may also contact Us to request access to, correct, or delete any personal information that You have provided to Us.

    +

    Please note, however, that We may need to retain certain information when we have a legal obligation or lawful basis to do so.

    +

    Disclosure of Your Personal Data

    +

    Business Transactions

    +

    If the Company is involved in a merger, acquisition or asset sale, Your Personal Data may be transferred. We will provide notice before Your Personal Data is transferred and becomes subject to a different Privacy Policy.

    +

    Law enforcement

    +

    Under certain circumstances, the Company may be required to disclose Your Personal Data if required to do so by law or in response to valid requests by public authorities (e.g. a court or a government agency).

    +

    Other legal requirements

    +

    The Company may disclose Your Personal Data in the good faith belief that such action is necessary to:

    +
      +
    • Comply with a legal obligation
    • +
    • Protect and defend the rights or property of the Company
    • +
    • Prevent or investigate possible wrongdoing in connection with the Service
    • +
    • Protect the personal safety of Users of the Service or the public
    • +
    • Protect against legal liability
    • +
    +

    Security of Your Personal Data

    +

    The security of Your Personal Data is important to Us, but remember that no method of transmission over the Internet, or method of electronic storage is 100% secure. While We strive to use commercially acceptable means to protect Your Personal Data, We cannot guarantee its absolute security.

    +

    Children's Privacy

    +

    Our Service does not address anyone under the age of 13. We do not knowingly collect personally identifiable information from anyone under the age of 13. If You are a parent or guardian and You are aware that Your child has provided Us with Personal Data, please contact Us. If We become aware that We have collected Personal Data from anyone under the age of 13 without verification of parental consent, We take steps to remove that information from Our servers.

    +

    If We need to rely on consent as a legal basis for processing Your information and Your country requires consent from a parent, We may require Your parent's consent before We collect and use that information.

    +

    Links to Other Websites

    +

    Our Service may contain links to other websites that are not operated by Us. If You click on a third party link, You will be directed to that third party's site. We strongly advise You to review the Privacy Policy of every site You visit.

    +

    We have no control over and assume no responsibility for the content, privacy policies or practices of any third party sites or services.

    +

    Changes to this Privacy Policy

    +

    We may update Our Privacy Policy from time to time. We will notify You of any changes by posting the new Privacy Policy on this page.

    +

    We will let You know via email and/or a prominent notice on Our Service, prior to the change becoming effective and update the "Last updated" date at the top of this Privacy Policy.

    +

    You are advised to review this Privacy Policy periodically for any changes. Changes to this Privacy Policy are effective when they are posted on this page.

    +

    Contact Us

    +

    If you have any questions about this Privacy Policy, You can contact us:

    +
      +
    • +

      By email: info-flow(at)digitaldata.works

      +
    • +
    • +

      By phone number: +49(0)-641-202360

      +
    • +
    • +

      By mail: Ludwig Rinn Str. 16, D-35452 Heuchelheim

      +
    • +
    \ No newline at end of file From 23609d2bd78711e7f9a7dc2e6e41a47311fa0cf3 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Tue, 16 Apr 2024 13:28:52 +0200 Subject: [PATCH 3/5] =?UTF-8?q?[Authorize]-Attribut=20zu=20DocumentControl?= =?UTF-8?q?ler=20und=20EnvelopeController=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Authorize]-Attribute wurden zum DocumentController und EnvelopeController hinzugefügt, um die Sicherheit zu erhöhen. [NonAction]-Attribute wurden zu den Methoden DocumentController.Get (api/document/{envelopeKey}) und EnvelopeController.Get (api/envelope/{envelopeKey}) hinzugefügt, um redundante Cookie-basierte Authentifizierung zu vermeiden, da der Datenzugriffscode korrekt gehandhabt wird, nachdem er im HomeController.LogInEnvelope (/EnvelopeKey/{envelopeReceiverId}/Locked) über die entsprechende Razor-Seite (.cshtml) eingegeben wurde. --- EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs | 1 - EnvelopeGenerator.Web/Controllers/DocumentController.cs | 3 +++ EnvelopeGenerator.Web/Controllers/EnvelopeController.cs | 3 +++ EnvelopeGenerator.Web/Views/Home/DebugEnvelopes.cshtml | 4 +--- EnvelopeGenerator.Web/wwwroot/cookie-consent-content/de.json | 3 ++- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs b/EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs index 6a203195..3729af00 100644 --- a/EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs +++ b/EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs @@ -5,7 +5,6 @@ namespace EnvelopeGenerator.Web.Controllers { public static class ControllerBaseExtensions { - public static (string EnvelopeUuid, string ReceiverSignature)? GetAuthenticatedEnvelopeDetails(this ControllerBase controller) { if(controller?.User?.Identity?.IsAuthenticated ?? false) diff --git a/EnvelopeGenerator.Web/Controllers/DocumentController.cs b/EnvelopeGenerator.Web/Controllers/DocumentController.cs index 16b69867..cd23da89 100644 --- a/EnvelopeGenerator.Web/Controllers/DocumentController.cs +++ b/EnvelopeGenerator.Web/Controllers/DocumentController.cs @@ -2,9 +2,11 @@ using EnvelopeGenerator.Common; using EnvelopeGenerator.Web.Services; using EnvelopeGenerator.Application.Contracts; +using Microsoft.AspNetCore.Authorization; namespace EnvelopeGenerator.Web.Controllers { + [Authorize] public class DocumentController : BaseController { private readonly EnvelopeOldService envelopeService; @@ -18,6 +20,7 @@ namespace EnvelopeGenerator.Web.Controllers _envDocService = envDocService; } + [NonAction] [HttpGet] [Route("api/document/{envelopeKey}")] public async Task Get([FromRoute] string envelopeKey, [FromQuery] int index) diff --git a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs index 1b8d59f1..82e56d1e 100644 --- a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs +++ b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs @@ -2,10 +2,12 @@ using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Common; using EnvelopeGenerator.Web.Services; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace EnvelopeGenerator.Web.Controllers { + [Authorize] public class EnvelopeController : BaseController { private readonly EnvelopeOldService envelopeService; @@ -19,6 +21,7 @@ namespace EnvelopeGenerator.Web.Controllers _envelopeService = envService; } + [NonAction] [HttpGet("api/envelope/{envelopeKey}")] public async Task Get([FromRoute] string envelopeKey) { diff --git a/EnvelopeGenerator.Web/Views/Home/DebugEnvelopes.cshtml b/EnvelopeGenerator.Web/Views/Home/DebugEnvelopes.cshtml index 4a34b90a..8c6179fc 100644 --- a/EnvelopeGenerator.Web/Views/Home/DebugEnvelopes.cshtml +++ b/EnvelopeGenerator.Web/Views/Home/DebugEnvelopes.cshtml @@ -28,7 +28,6 @@ Show envelopes @foreach (Envelope envelope in @group) { -
    } - - + \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/cookie-consent-content/de.json b/EnvelopeGenerator.Web/wwwroot/cookie-consent-content/de.json index de868af5..9457be3b 100644 --- a/EnvelopeGenerator.Web/wwwroot/cookie-consent-content/de.json +++ b/EnvelopeGenerator.Web/wwwroot/cookie-consent-content/de.json @@ -14,4 +14,5 @@ "description": [ "Diese Cookies sind notwendig für Funktionen wie Seitensicherheit, Sitzungsverwaltung und Schutz. Unsere Cookies umfassen technische Cookies, die für die Sitzungsverwaltung und zur Gewährleistung der Sicherheit verwendet werden." ] } } -} \ No newline at end of file +} + From 74cb595128c4abb599e41f8c76359a17644ac92f Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Tue, 16 Apr 2024 13:52:09 +0200 Subject: [PATCH 4/5] =?UTF-8?q?Autorisierungspr=C3=BCfung=20zu=20Envelope?= =?UTF-8?q?=20und=20Document=20Controllern=20hinzuf=C3=BCgen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implementiere eine Signaturverifizierung in den EnvelopeController.Update (api/envelope/{envelopeKey}) und DocumentController.Open (api/document/{envelopeKey}) Methoden, die beide mit dem HTTPPost-Attribut gekennzeichnet sind. Diese Prüfung stellt sicher, dass nur der authentifizierte Empfänger mit einer übereinstimmenden Signatur Zugriff auf die spezifizierten Ressourcen hat oder diese ändern kann. Dies erhöht die Sicherheit, indem unautorisierten Zugriff verhindert wird. --- .../Controllers/ControllerBaseExtensions.cs | 22 +++++++++++++++++++ .../Controllers/DocumentController.cs | 6 +++++ .../Controllers/EnvelopeController.cs | 6 +++++ 3 files changed, 34 insertions(+) diff --git a/EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs b/EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs index 3729af00..6616b3fa 100644 --- a/EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs +++ b/EnvelopeGenerator.Web/Controllers/ControllerBaseExtensions.cs @@ -16,5 +16,27 @@ namespace EnvelopeGenerator.Web.Controllers } return null; } + + public static string? GetAuthenticatedEnvelopeUuid(this ControllerBase controller) + { + if (controller?.User?.Identity?.IsAuthenticated ?? false) + { + var envelopeUuid = controller.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; + if (!string.IsNullOrEmpty(envelopeUuid)) + return envelopeUuid; + } + return null; + } + + public static string? GetAuthenticatedReceiverSignature(this ControllerBase controller) + { + if (controller?.User?.Identity?.IsAuthenticated ?? false) + { + var receiverSignature = controller.User.FindFirst(ClaimTypes.Hash)?.Value; + if (!string.IsNullOrEmpty(receiverSignature)) + return receiverSignature; + } + return null; + } } } diff --git a/EnvelopeGenerator.Web/Controllers/DocumentController.cs b/EnvelopeGenerator.Web/Controllers/DocumentController.cs index cd23da89..6da7f1c9 100644 --- a/EnvelopeGenerator.Web/Controllers/DocumentController.cs +++ b/EnvelopeGenerator.Web/Controllers/DocumentController.cs @@ -3,6 +3,7 @@ using EnvelopeGenerator.Common; using EnvelopeGenerator.Web.Services; using EnvelopeGenerator.Application.Contracts; using Microsoft.AspNetCore.Authorization; +using EnvelopeGenerator.Application.Services; namespace EnvelopeGenerator.Web.Controllers { @@ -52,6 +53,11 @@ namespace EnvelopeGenerator.Web.Controllers { try { + var authSignature = this.GetAuthenticatedReceiverSignature(); + + if (authSignature != envelopeKey.GetReceiverSignature()) + return Forbid(); + // Validate Envelope Key and load envelope envelopeService.EnsureValidEnvelopeKey(envelopeKey); EnvelopeResponse response = await envelopeService.LoadEnvelope(envelopeKey); diff --git a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs index 82e56d1e..9cfe0335 100644 --- a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs +++ b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs @@ -1,5 +1,6 @@  using EnvelopeGenerator.Application.Contracts; +using EnvelopeGenerator.Application.Services; using EnvelopeGenerator.Common; using EnvelopeGenerator.Web.Services; using Microsoft.AspNetCore.Authorization; @@ -51,6 +52,11 @@ namespace EnvelopeGenerator.Web.Controllers { try { + var authSignature = this.GetAuthenticatedReceiverSignature(); + + if (authSignature != envelopeKey.GetReceiverSignature()) + return Forbid(); + // Validate Envelope Key and load envelope envelopeService.EnsureValidEnvelopeKey(envelopeKey); EnvelopeResponse response = await envelopeService.LoadEnvelope(envelopeKey); From f2e718565db931a26dd545642d570adccbeb1536 Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Tue, 16 Apr 2024 16:25:55 +0200 Subject: [PATCH 5/5] Add EmailOut components: entity, DTO, repository, and services - Introduced EmailOut and EmailOutDto for data management. - Added EmailOutRepository and service interfaces based on CRUD patterns. --- .../Contracts/IEmailOutService.cs | 11 +++ .../DTOs/EmailOutDto.cs | 25 ++++++ .../MappingProfiles/BasicDtoMappingProfile.cs | 2 + .../Services/EmailOutService.cs | 17 ++++ EnvelopeGenerator.Domain/Entities/EmailOut.cs | 89 +++++++++++++++++++ .../Contracts/IEmailOutRepository.cs | 9 ++ .../Repositories/EmailOutRepository.cs | 14 +++ .../Controllers/HomeController.cs | 7 +- EnvelopeGenerator.Web/Program.cs | 2 + 9 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 EnvelopeGenerator.Application/Contracts/IEmailOutService.cs create mode 100644 EnvelopeGenerator.Application/DTOs/EmailOutDto.cs create mode 100644 EnvelopeGenerator.Application/Services/EmailOutService.cs create mode 100644 EnvelopeGenerator.Domain/Entities/EmailOut.cs create mode 100644 EnvelopeGenerator.Infrastructure/Contracts/IEmailOutRepository.cs create mode 100644 EnvelopeGenerator.Infrastructure/Repositories/EmailOutRepository.cs diff --git a/EnvelopeGenerator.Application/Contracts/IEmailOutService.cs b/EnvelopeGenerator.Application/Contracts/IEmailOutService.cs new file mode 100644 index 00000000..e1f934b5 --- /dev/null +++ b/EnvelopeGenerator.Application/Contracts/IEmailOutService.cs @@ -0,0 +1,11 @@ +using DigitalData.Core.Contracts.Application; +using EnvelopeGenerator.Application.DTOs; +using EnvelopeGenerator.Domain.Entities; +using EnvelopeGenerator.Infrastructure.Contracts; + +namespace EnvelopeGenerator.Application.Contracts +{ + public interface IEmailOutService : IBasicCRUDService + { + } +} diff --git a/EnvelopeGenerator.Application/DTOs/EmailOutDto.cs b/EnvelopeGenerator.Application/DTOs/EmailOutDto.cs new file mode 100644 index 00000000..6455acf7 --- /dev/null +++ b/EnvelopeGenerator.Application/DTOs/EmailOutDto.cs @@ -0,0 +1,25 @@ +namespace EnvelopeGenerator.Application.DTOs +{ + public record EmailOutDto( + int Guid, + int ReminderTypeId, + int SendingProfile, + int ReferenceId, + string? ReferenceString, + int? EntityId, + int WfId, + string? WfReference, + string EmailAdress, + string EmailSubj, + string EmailBody, + string? EmailAttmt1, + DateTime? EmailSent, + string? Comment, + string AddedWho, + DateTime? AddedWhen, + string? ChangedWho, + DateTime? ChangedWhen, + DateTime? ErrorTimestamp, + string? ErrorMsg + ); +} diff --git a/EnvelopeGenerator.Application/MappingProfiles/BasicDtoMappingProfile.cs b/EnvelopeGenerator.Application/MappingProfiles/BasicDtoMappingProfile.cs index 3dbe14a5..cd7304f7 100644 --- a/EnvelopeGenerator.Application/MappingProfiles/BasicDtoMappingProfile.cs +++ b/EnvelopeGenerator.Application/MappingProfiles/BasicDtoMappingProfile.cs @@ -21,6 +21,7 @@ namespace EnvelopeGenerator.Application.MappingProfiles CreateMap(); CreateMap(); CreateMap(); + CreateMap(); // DTO to Entity mappings CreateMap(); @@ -35,6 +36,7 @@ namespace EnvelopeGenerator.Application.MappingProfiles CreateMap(); CreateMap(); CreateMap(); + CreateMap(); } } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Services/EmailOutService.cs b/EnvelopeGenerator.Application/Services/EmailOutService.cs new file mode 100644 index 00000000..e022f369 --- /dev/null +++ b/EnvelopeGenerator.Application/Services/EmailOutService.cs @@ -0,0 +1,17 @@ +using AutoMapper; +using DigitalData.Core.Application; +using DigitalData.Core.Contracts.CultureServices; +using EnvelopeGenerator.Application.Contracts; +using EnvelopeGenerator.Application.DTOs; +using EnvelopeGenerator.Domain.Entities; +using EnvelopeGenerator.Infrastructure.Contracts; + +namespace EnvelopeGenerator.Application.Services +{ + public class EmailOutService : BasicCRUDService, IEmailOutService + { + public EmailOutService(IEmailOutRepository repository, IKeyTranslationService translationService, IMapper mapper) : base(repository, translationService, mapper) + { + } + } +} diff --git a/EnvelopeGenerator.Domain/Entities/EmailOut.cs b/EnvelopeGenerator.Domain/Entities/EmailOut.cs new file mode 100644 index 00000000..68ac00b1 --- /dev/null +++ b/EnvelopeGenerator.Domain/Entities/EmailOut.cs @@ -0,0 +1,89 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace EnvelopeGenerator.Domain.Entities +{ + [Table("TBEMLP_EMAIL_OUT", Schema = "dbo")] + public class EmailOut + { + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + [Column("GUID")] + public int Id { get; set; } + + [Required] + [Column("REMINDER_TYPE_ID")] + public int ReminderTypeId { get; set; } = 1; // Default value + + [Required] + [Column("SENDING_PROFILE")] + public int SendingProfile { get; set; } + + [Required] + [Column("REFERENCE_ID")] + public int ReferenceId { get; set; } + + [StringLength(200)] + [Column("REFERENCE_STRING")] + public string ReferenceString { get; set; } + + [Column("ENTITY_ID")] + public int? EntityId { get; set; } + + [Required] + [Column("WF_ID")] + public int WfId { get; set; } + + [StringLength(200)] + [Column("WF_REFERENCE")] + public string WfReference { get; set; } + + [Required] + [StringLength(1000)] + [Column("EMAIL_ADRESS")] + public string EmailAdress { get; set; } + + [Required] + [StringLength(500)] + [Column("EMAIL_SUBJ")] + public string EmailSubj { get; set; } + + [Required] + [Column("EMAIL_BODY")] + public string EmailBody { get; set; } + + [StringLength(512)] + [Column("EMAIL_ATTMT1")] + public string EmailAttmt1 { get; set; } + + [Column("EMAIL_SENT")] + public DateTime? EmailSent { get; set; } + + [StringLength(500)] + [Column("COMMENT")] + public string Comment { get; set; } + + [Required] + [StringLength(50)] + [Column("ADDED_WHO")] + public string AddedWho { get; set; } = "DEFAULT"; // Default value + + [Column("ADDED_WHEN")] + public DateTime? AddedWhen { get; set; } = DateTime.Now; // Default value + + [StringLength(50)] + [Column("CHANGED_WHO")] + public string ChangedWho { get; set; } + + [Column("CHANGED_WHEN")] + public DateTime? ChangedWhen { get; set; } + + [Column("ERROR_TIMESTAMP")] + public DateTime? ErrorTimestamp { get; set; } + + [StringLength(900)] + [Column("ERROR_MSG")] + public string ErrorMsg { get; set; } + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Infrastructure/Contracts/IEmailOutRepository.cs b/EnvelopeGenerator.Infrastructure/Contracts/IEmailOutRepository.cs new file mode 100644 index 00000000..1b7425f5 --- /dev/null +++ b/EnvelopeGenerator.Infrastructure/Contracts/IEmailOutRepository.cs @@ -0,0 +1,9 @@ +using DigitalData.Core.Contracts.Infrastructure; +using EnvelopeGenerator.Domain.Entities; + +namespace EnvelopeGenerator.Infrastructure.Contracts +{ + public interface IEmailOutRepository : ICRUDRepository + { + } +} diff --git a/EnvelopeGenerator.Infrastructure/Repositories/EmailOutRepository.cs b/EnvelopeGenerator.Infrastructure/Repositories/EmailOutRepository.cs new file mode 100644 index 00000000..397e8b14 --- /dev/null +++ b/EnvelopeGenerator.Infrastructure/Repositories/EmailOutRepository.cs @@ -0,0 +1,14 @@ +using DigitalData.Core.Infrastructure; +using DigitalData.UserManager.Infrastructure.Repositories; +using EnvelopeGenerator.Domain.Entities; +using EnvelopeGenerator.Infrastructure.Contracts; + +namespace EnvelopeGenerator.Infrastructure.Repositories +{ + public class EmailOutRepository : CRUDRepository, IEmailOutRepository + { + public EmailOutRepository(EGDbContext dbContext) : base(dbContext) + { + } + } +} diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index d219e671..5c4426bc 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -38,7 +38,7 @@ namespace EnvelopeGenerator.Web.Controllers { try { - var passwordFromConfig = _config["Config:AdminPassword"] ?? throw new InvalidOperationException("No admin password configured!"); + var passwordFromConfig = _config["Config:AdminPassword"]; if (passwordFromConfig == null) { @@ -56,8 +56,9 @@ namespace EnvelopeGenerator.Web.Controllers return View(envelopes); } - catch (Exception e) + catch(Exception ex) { + _logger.LogError(ex, "Unexpected error"); ViewData["error"] = "Unknown error!"; return View("Index"); } @@ -66,6 +67,8 @@ namespace EnvelopeGenerator.Web.Controllers [HttpGet("/EnvelopeKey/{envelopeReceiverId}")] public async Task SendAccessCode([FromRoute] string envelopeReceiverId) { + var envelope = await _envelopeService.ReadByUuidAsync(envelopeReceiverId.GetEnvelopeUuid()); + EnvelopeResponse response = await envelopeOldService.LoadEnvelope(envelopeReceiverId); if (response.Envelope.UseAccessCode) diff --git a/EnvelopeGenerator.Web/Program.cs b/EnvelopeGenerator.Web/Program.cs index 99d3236e..c254425b 100644 --- a/EnvelopeGenerator.Web/Program.cs +++ b/EnvelopeGenerator.Web/Program.cs @@ -67,6 +67,7 @@ try builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -81,6 +82,7 @@ try builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(); //Auto mapping profiles builder.Services.AddAutoMapper(typeof(BasicDtoMappingProfile).Assembly);