Cookie-basierte automatische Autorisierung wurde konfiguriert. Middlevare für Benutzerberechtigung hinzugefügt
This commit is contained in:
parent
49cfeb28d9
commit
87c839549a
24
EnvelopeGenerator.Application/Contracts/IJWTService.cs
Normal file
24
EnvelopeGenerator.Application/Contracts/IJWTService.cs
Normal file
@ -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<TClaimValue>
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.18" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,12 +1,14 @@
|
|||||||
using EnvelopeGenerator.Application.Contracts;
|
using EnvelopeGenerator.Application.Contracts;
|
||||||
using EnvelopeGenerator.Application.DTOs;
|
|
||||||
using EnvelopeGenerator.Application.Services;
|
using EnvelopeGenerator.Application.Services;
|
||||||
using EnvelopeGenerator.Common;
|
using EnvelopeGenerator.Common;
|
||||||
using EnvelopeGenerator.Web.Models;
|
using EnvelopeGenerator.Web.Models;
|
||||||
using EnvelopeGenerator.Web.Services;
|
using EnvelopeGenerator.Web.Services;
|
||||||
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Primitives;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Web.Controllers
|
namespace EnvelopeGenerator.Web.Controllers
|
||||||
{
|
{
|
||||||
@ -62,7 +64,7 @@ namespace EnvelopeGenerator.Web.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("/EnvelopeKey/{envelopeReceiverId}")]
|
[HttpGet("/EnvelopeKey/{envelopeReceiverId}")]
|
||||||
public async Task<IActionResult> ShowEnvelope([FromRoute] string envelopeReceiverId)
|
public async Task<IActionResult> SendAccessCode([FromRoute] string envelopeReceiverId)
|
||||||
{
|
{
|
||||||
EnvelopeResponse response = await envelopeOldService.LoadEnvelope(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 actionResult = database.Services.actionService.RequestAccessCode(response.Envelope, response.Receiver);
|
||||||
bool result = database.Services.emailService.SendDocumentAccessCodeReceivedEmail(response.Envelope, response.Receiver);
|
bool result = database.Services.emailService.SendDocumentAccessCodeReceivedEmail(response.Envelope, response.Receiver);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Redirect($"/EnvelopeKey/{envelopeReceiverId}/Locked");
|
return Redirect($"/EnvelopeKey/{envelopeReceiverId}/Locked");
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
[HttpGet("/EnvelopeKey/{envelopeReceiverId}/Locked")]
|
||||||
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
public IActionResult EnvelopeLocked([FromRoute] string envelopeReceiverId)
|
||||||
return View();
|
{
|
||||||
}
|
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
||||||
|
return View();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("/EnvelopeKey/{envelopeReceiverId}/Locked")]
|
[HttpPost("/EnvelopeKey/{envelopeReceiverId}/Locked")]
|
||||||
public async Task<IActionResult> ShowEnvelope([FromRoute] string envelopeReceiverId, [FromForm] string access_code)
|
public async Task<IActionResult> LogInEnvelope([FromRoute] string envelopeReceiverId, [FromForm] string access_code)
|
||||||
{
|
{
|
||||||
var decodedId = envelopeReceiverId.DecodeEnvelopeReceiverId();
|
var decodedId = envelopeReceiverId.DecodeEnvelopeReceiverId();
|
||||||
|
|
||||||
@ -99,16 +103,15 @@ namespace EnvelopeGenerator.Web.Controllers
|
|||||||
|
|
||||||
if (verification.IsSuccess)
|
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);
|
var envelope = await _envelopeService.ReadByUuidAsync(uuid: decodedId.EnvelopeUuid, signature: decodedId.ReceiverSignature, withAll: true);
|
||||||
database.Services.actionService.EnterCorrectAccessCode(response.Envelope, response.Receiver); //for history
|
database.Services.actionService.EnterCorrectAccessCode(response.Envelope, response.Receiver); //for history
|
||||||
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
||||||
ViewData["EnvelopeResponse"] = response;
|
ViewData["EnvelopeResponse"] = response;
|
||||||
ViewData["EnvelopeResponse"] = response;
|
|
||||||
|
|
||||||
if (response.Envelope.Documents.Count() > 0)
|
if (response.Envelope.Documents.Count() > 0)
|
||||||
{
|
{
|
||||||
@ -119,6 +122,22 @@ namespace EnvelopeGenerator.Web.Controllers
|
|||||||
else
|
else
|
||||||
ViewData["DocumentBytes"] = null;
|
ViewData["DocumentBytes"] = null;
|
||||||
|
|
||||||
|
var claims = new List<Claim>
|
||||||
|
{
|
||||||
|
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);
|
return View("ShowEnvelope", envelope);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -129,19 +148,21 @@ namespace EnvelopeGenerator.Web.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("/EnvelopeKey/{envelopeReceiverId}/Locked")]
|
[HttpGet("/EnvelopeKey/{envelopeReceiverId}/Success")]
|
||||||
public async Task<IActionResult> EnvelopeLocked([FromRoute] string envelopeReceiverId)
|
public async Task<IActionResult> EnvelopeSigned(string envelopeReceiverId)
|
||||||
{
|
{
|
||||||
|
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||||
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("/EnvelopeKey/{EnvelopeReceiverId}/Success")]
|
[Authorize]
|
||||||
public IActionResult EnvelopeSigned()
|
[HttpGet("IsAuthenticated")]
|
||||||
|
public IActionResult IsAuthenticated()
|
||||||
{
|
{
|
||||||
ViewData["EnvelopeKey"] = HttpContext.Request.RouteValues["EnvelopeReceiverId"];
|
var envelopeUuid = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||||
|
var receiverSignature = User.FindFirst(ClaimTypes.Hash)?.Value;
|
||||||
return View();
|
return Ok(new { EnvelopeUuid = envelopeUuid, ReceiverSignature = receiverSignature });
|
||||||
}
|
}
|
||||||
|
|
||||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
[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 });
|
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
|
[HttpGet("test")]
|
||||||
|
public string Test() => "Test";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
42
EnvelopeGenerator.Web/Controllers/Test/TestAuthController.cs
Normal file
42
EnvelopeGenerator.Web/Controllers/Test/TestAuthController.cs
Normal file
@ -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<string> _authService;
|
||||||
|
|
||||||
|
public TestAuthController(IJWTService<string> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
|
|
||||||
namespace EnvelopeGenerator.Web.Controllers.Test
|
namespace EnvelopeGenerator.Web.Controllers.Test
|
||||||
{
|
{
|
||||||
//[NonController]
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/test/[controller]")]
|
[Route("api/test/[controller]")]
|
||||||
public class TestControllerBase<TOriginalController, TCRUDService, TCRUDRepository, TDto, TEntity, TId> : BasicCRUDControllerBase<TOriginalController, TCRUDService, TCRUDRepository, TDto, TEntity, TId> where TOriginalController : CRUDControllerBase<TOriginalController, TCRUDService, TCRUDRepository, TDto, TDto, TDto, TEntity, TId> where TCRUDService : ICRUDService<TCRUDRepository, TDto, TDto, TDto, TEntity, TId> where TCRUDRepository : ICRUDRepository<TEntity, TId> where TDto : class where TEntity : class
|
public class TestControllerBase<TOriginalController, TCRUDService, TCRUDRepository, TDto, TEntity, TId> : BasicCRUDControllerBase<TOriginalController, TCRUDService, TCRUDRepository, TDto, TEntity, TId> where TOriginalController : CRUDControllerBase<TOriginalController, TCRUDService, TCRUDRepository, TDto, TDto, TDto, TEntity, TId> where TCRUDService : ICRUDService<TCRUDRepository, TDto, TDto, TDto, TEntity, TId> where TCRUDRepository : ICRUDRepository<TEntity, TId> where TDto : class where TEntity : class
|
||||||
|
|||||||
@ -23,8 +23,10 @@
|
|||||||
<PackageReference Include="Quartz.Plugins" Version="3.8.0" />
|
<PackageReference Include="Quartz.Plugins" Version="3.8.0" />
|
||||||
<PackageReference Include="Quartz.Serialization.Json" Version="3.8.0" />
|
<PackageReference Include="Quartz.Serialization.Json" Version="3.8.0" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||||
|
<PackageReference Include="System.Configuration.ConfigurationManager" Version="7.0.0" />
|
||||||
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
|
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
|
||||||
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
||||||
|
<PackageReference Include="System.Security.Cryptography.Cng" Version="5.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -11,6 +11,8 @@ using NLog;
|
|||||||
using Quartz;
|
using Quartz;
|
||||||
using NLog.Web;
|
using NLog.Web;
|
||||||
using DigitalData.Core.API;
|
using DigitalData.Core.API;
|
||||||
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
|
using DigitalData.Core.Application;
|
||||||
|
|
||||||
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
|
var logger = LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
|
||||||
logger.Info("Logging initialized!");
|
logger.Info("Logging initialized!");
|
||||||
@ -49,7 +51,7 @@ try
|
|||||||
builder.Services.AddDbContext<EGDbContext>(options =>
|
builder.Services.AddDbContext<EGDbContext>(options =>
|
||||||
options.UseSqlServer(connStr));
|
options.UseSqlServer(connStr));
|
||||||
|
|
||||||
//Inject CRUD Service and repositories
|
//Inject CRUD Service and repositoriesad
|
||||||
builder.Services.AddScoped<IConfigRepository, ConfigRepository>();
|
builder.Services.AddScoped<IConfigRepository, ConfigRepository>();
|
||||||
builder.Services.AddScoped<IDocumentReceiverElementRepository, DocumentReceiverElementRepository>();
|
builder.Services.AddScoped<IDocumentReceiverElementRepository, DocumentReceiverElementRepository>();
|
||||||
builder.Services.AddScoped<IEnvelopeDocumentRepository, EnvelopeDocumentRepository>();
|
builder.Services.AddScoped<IEnvelopeDocumentRepository, EnvelopeDocumentRepository>();
|
||||||
@ -83,6 +85,50 @@ try
|
|||||||
//Auto mapping profiles
|
//Auto mapping profiles
|
||||||
builder.Services.AddAutoMapper(typeof(BasicDtoMappingProfile).Assembly);
|
builder.Services.AddAutoMapper(typeof(BasicDtoMappingProfile).Assembly);
|
||||||
|
|
||||||
|
builder.Services.Configure<CookiePolicyOptions>(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();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
@ -98,9 +144,11 @@ try
|
|||||||
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
|
app.UseCookiePolicy();
|
||||||
|
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|
||||||
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
|||||||
@ -1,21 +1,13 @@
|
|||||||
{
|
{
|
||||||
"iisSettings": {
|
|
||||||
"windowsAuthentication": false,
|
|
||||||
"anonymousAuthentication": true,
|
|
||||||
"iisExpress": {
|
|
||||||
"applicationUrl": "http://localhost:30275",
|
|
||||||
"sslPort": 44372
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"profiles": {
|
"profiles": {
|
||||||
"EnvelopeGenerator.Web": {
|
"EnvelopeGenerator.Web": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": true,
|
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"applicationUrl": "https://localhost:7141;http://localhost:5282",
|
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
}
|
},
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"applicationUrl": "https://localhost:7141;http://localhost:5282"
|
||||||
},
|
},
|
||||||
"IIS Express": {
|
"IIS Express": {
|
||||||
"commandName": "IISExpress",
|
"commandName": "IISExpress",
|
||||||
@ -26,13 +18,21 @@
|
|||||||
},
|
},
|
||||||
"swagger": {
|
"swagger": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": true,
|
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"launchUrl": "swagger",
|
"launchUrl": "swagger",
|
||||||
"applicationUrl": "https://localhost:7202;http://localhost:5009",
|
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
}
|
},
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"applicationUrl": "https://localhost:7202;http://localhost:5009"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:30275",
|
||||||
|
"sslPort": 44372
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,6 +4,7 @@
|
|||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Dokument unterschreiben";
|
ViewData["Title"] = "Dokument unterschreiben";
|
||||||
}
|
}
|
||||||
|
<partial name="_CookieConsentPartial" />
|
||||||
@if (Model.IsSuccess && Model.Data is not null)
|
@if (Model.IsSuccess && Model.Data is not null)
|
||||||
{
|
{
|
||||||
var envelope = Model.Data;
|
var envelope = Model.Data;
|
||||||
|
|||||||
@ -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<ITrackingConsentFeature>();
|
||||||
|
var showBanner = !consentFeature?.CanTrack ?? false;
|
||||||
|
var cookieString = consentFeature?.CreateConsentCookie();
|
||||||
|
}
|
||||||
|
@if (showBanner)
|
||||||
|
{
|
||||||
|
<script>
|
||||||
|
@{
|
||||||
|
var serializerSettings = new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
ContractResolver = new CamelCasePropertyNamesContractResolver()
|
||||||
|
};
|
||||||
|
string serializedProps = JsonConvert.SerializeObject(_cookieSettings, serializerSettings);
|
||||||
|
}
|
||||||
|
var props = @Html.Raw(serializedProps);
|
||||||
|
var cookieSettings = new BootstrapCookieConsentSettings(props)
|
||||||
|
</script>
|
||||||
|
}
|
||||||
@ -19,13 +19,12 @@
|
|||||||
<script src="~/js/network.js" asp-append-version="true"></script>
|
<script src="~/js/network.js" asp-append-version="true"></script>
|
||||||
<script src="~/js/app.js" asp-append-version="true"></script>
|
<script src="~/js/app.js" asp-append-version="true"></script>
|
||||||
<script src="~/lib/pspdfkit/pspdfkit.js" asp-append-version="true"></script>
|
<script src="~/lib/pspdfkit/pspdfkit.js" asp-append-version="true"></script>
|
||||||
|
<script src="~/lib/bootstrap-cookie-consent-settings-main/src/bootstrap-cookie-consent-settings.js" asp-append-version="true"></script>
|
||||||
@await RenderSectionAsync("Scripts", required: false)
|
@await RenderSectionAsync("Scripts", required: false)
|
||||||
<main role="main">
|
<main role="main">
|
||||||
|
<partial name="_CookieConsentPartial" />
|
||||||
@RenderBody()
|
@RenderBody()
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Html.AntiForgeryToken()
|
@Html.AntiForgeryToken()
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -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" ]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -136,3 +136,7 @@ footer#page-footer a:focus {
|
|||||||
.envelope-message {
|
.envelope-message {
|
||||||
font-family: 'Roboto', sans-serif;
|
font-family: 'Roboto', sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.none-display {
|
||||||
|
display: none
|
||||||
|
}
|
||||||
Binary file not shown.
4
EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitattributes
vendored
Normal file
4
EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitattributes
vendored
Normal file
@ -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
|
||||||
2
EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitignore
vendored
Normal file
2
EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/.idea
|
||||||
|
/node_modules
|
||||||
@ -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.
|
||||||
@ -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).
|
||||||
@ -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"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0"/>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
|
integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">
|
||||||
|
<title>bootstrap-cookie-banner demo page</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="mt-5 mb-4"><a href="../">bootstrap-cookie-consent-settings</a> demo page</h1>
|
||||||
|
<p>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.</p>
|
||||||
|
<h2>Usage</h2>
|
||||||
|
<h3>Construct</h3>
|
||||||
|
<p>Initialize the cookie consent framework with the constructor</p>
|
||||||
|
<p><code>var cookieSettings = new BootstrapCookieConsent()</code></p>
|
||||||
|
<h3>Show the Dialog</h3>
|
||||||
|
<p>On a new visit the dialog is shown automatically. For reconfiguration
|
||||||
|
show the Dialog again with <code>cookieSettings.showDialog()</code>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="javascript:showSettingsDialog()" class="btn btn-primary">Cookie Settings</a>
|
||||||
|
</p>
|
||||||
|
<h3>Read the settings</h3>
|
||||||
|
<p>Read all cookie settings with <code>cookieSettings.getSettings()</code></p>
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<pre class="mb-0" id="settingsOutput"></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>Read a specific cookie setting with <code>cookieSettings.getSettings('statistics')</code></p>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<pre class="mb-0" id="settingsAnalysisOutput"></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h2 class="mt-4">The code of this banner</h2>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<pre><code>var cookieSettings = new BootstrapCookieConsentSettings({
|
||||||
|
contentURL: "../cookie-consent-content",
|
||||||
|
privacyPolicyUrl: "privacy-policy.html",
|
||||||
|
legalNoticeUrl: "legal-notice.html",
|
||||||
|
postSelectionCallback: function () {
|
||||||
|
location.reload() // reload after selection
|
||||||
|
}
|
||||||
|
})</code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h2 class="mt-4">More documentation</h2>
|
||||||
|
<p class="mb-5"><a href="https://github.com/shaack/bootstrap-cookie-consent-settings">Find more documentation and
|
||||||
|
the sourcecode on GitHub</a></p>
|
||||||
|
</div>
|
||||||
|
<script src="../src/bootstrap-cookie-consent-settings.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/js/bootstrap.bundle.min.js"
|
||||||
|
integrity="sha384-U1DAWAznBHeqEIlVSCgzq+c9gqGAJn5c/t99JyeKa9xxaYpSvHU5awsuZVVFIhvj"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const cookieSettings = new BootstrapCookieConsentSettings({
|
||||||
|
contentURL: "../cookie-consent-content",
|
||||||
|
privacyPolicyUrl: "privacy-policy.html",
|
||||||
|
legalNoticeUrl: "legal-notice.html",
|
||||||
|
postSelectionCallback: function () {
|
||||||
|
location.reload() // reload after selection
|
||||||
|
}
|
||||||
|
})
|
||||||
|
function showSettingsDialog() {
|
||||||
|
cookieSettings.showDialog()
|
||||||
|
}
|
||||||
|
document.getElementById("settingsOutput").innerText = JSON.stringify(cookieSettings.getSettings())
|
||||||
|
document.getElementById("settingsAnalysisOutput").innerText = cookieSettings.getSettings("statistics")
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0"/>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">
|
||||||
|
<title>bootstrap-cookie-banner demo page</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1><a href="../">bootstrap-cookie-consent-settings</a></h1>
|
||||||
|
<p>This is the legal notice dummy page.</p>
|
||||||
|
<p>You have to set the legal notice URL in your content files.</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0"/>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">
|
||||||
|
<title>bootstrap-cookie-banner demo page</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1><a href="../">bootstrap-cookie-consent-settings</a></h1>
|
||||||
|
<p>This is the privacy policy dummy page.</p>
|
||||||
|
<p>You have to set the privacy policy URL in your content files.</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,34 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0"/>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">
|
||||||
|
<title>bootstrap-cookie-consent-settings demo page</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container mt-5">
|
||||||
|
<h1>bootstrap-cookie-consent-settings demo page</h1>
|
||||||
|
<p>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. <b>This banner requires Bootstrap.</b></p>
|
||||||
|
<p>We also have <b>another</b>, smaller cookie banner, <b>without dependencies</b>, which
|
||||||
|
does not offer the user an advanced configuration. You can find it in GitHub as
|
||||||
|
<a href="https://github.com/shaack/cookie-consent-js">cookie-consent-js</a>.</p>
|
||||||
|
<h2>Example</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="examples/cookie-banner-example.html">Cookie consent banner with reload after selection</a></li>
|
||||||
|
</ul>
|
||||||
|
<h2>Further Information</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://github.com/shaack/bootstrap-cookie-consent-settings">GitHub Repository and
|
||||||
|
Documentation</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://www.npmjs.com/package/bootstrap-cookie-consent-settings">npm package</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
13
EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package-lock.json
generated
Normal file
13
EnvelopeGenerator.Web/wwwroot/lib/bootstrap-cookie-consent-settings-main/package-lock.json
generated
Normal file
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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"
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
namespace Shaack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class, to handle the `bootstrap-cookie-content-settings` from a PHP backend.
|
||||||
|
* @author Stefan Haack (https://shaack.com)
|
||||||
|
*/
|
||||||
|
class BootstrapCookieConsentSettings {
|
||||||
|
|
||||||
|
private string $cookieName;
|
||||||
|
private int $cookieStorageDays;
|
||||||
|
|
||||||
|
public function __construct(string $cookieName = "cookie-consent-settings", int $cookieStorageDays = 365)
|
||||||
|
{
|
||||||
|
$this->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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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 = '<a href="' + self.props.privacyPolicyUrl + '">' + _t.privacyPolicy + '</a>'
|
||||||
|
const linkLegalNotice = '<a href="' + self.props.legalNoticeUrl + '">' + _t.legalNotice + '</a>'
|
||||||
|
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 += `<li>${descriptionElement}</li>`
|
||||||
|
}
|
||||||
|
optionsHtml += `<div class="bccs-option" data-name="${category}">
|
||||||
|
<div class="form-check mb-1">
|
||||||
|
<input type="checkbox" class="form-check-input" id="bccs-checkbox-${category}">
|
||||||
|
<label class="form-check-label" for="bccs-checkbox-${category}"><b>${categoryContent.title}</b></label>
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
${descriptionList}
|
||||||
|
</ul>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
self.modalContent = `<!-- cookie banner => https://github.com/shaack/bootstrap-cookie-consent-settings -->
|
||||||
|
<div class="modal-dialog modal-lg shadow" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title">${self.content.title}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="bccs-body-text" style="font-size: 80%">
|
||||||
|
<p>${self.content.body}</p>
|
||||||
|
</div>
|
||||||
|
<p class="d-flex justify-content-between mb-0">
|
||||||
|
${linkLegalNotice}
|
||||||
|
<a href="#bccs-options" data-bs-toggle="collapse">${self.content.mySettings}</a>
|
||||||
|
</p>
|
||||||
|
<div id="bccs-options" class="collapse">
|
||||||
|
<div class="mt-4">
|
||||||
|
${optionsHtml}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button id="bccs-buttonDoNotAgree" type="button"
|
||||||
|
class="${self.props.buttonDontAgreeClass}">
|
||||||
|
${self.content.buttonNotAgree}
|
||||||
|
</button>
|
||||||
|
<button id="bccs-buttonAgree" type="button" class="${self.props.buttonAgreeClass}">${self.content.buttonAgree}</button>
|
||||||
|
<button id="bccs-buttonSave" type="button" class="${self.props.buttonSaveClass}">
|
||||||
|
${self.content.buttonSaveSelection}
|
||||||
|
</button>
|
||||||
|
<button id="bccs-buttonAgreeAll" type="button" class="${self.props.buttonAgreeClass}">${self.content.buttonAgreeAll}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user