diff --git a/BLAZAM/BLAZAM.csproj b/BLAZAM/BLAZAM.csproj
index 51f23921..63e64f34 100644
--- a/BLAZAM/BLAZAM.csproj
+++ b/BLAZAM/BLAZAM.csproj
@@ -6,7 +6,7 @@
enable
false
1.2.1
- 2024.11.30.2133
+ 2024.12.01.1549
false
BLAZAM
True
diff --git a/BLAZAM/ProgramHelpers.cs b/BLAZAM/ProgramHelpers.cs
index a796bd9b..5fecbe24 100644
--- a/BLAZAM/ProgramHelpers.cs
+++ b/BLAZAM/ProgramHelpers.cs
@@ -176,11 +176,12 @@ public static WebApplicationBuilder InjectServices(this WebApplicationBuilder bu
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true, // Important: Validate the signing key
- IssuerSigningKey = ApplicationInfo.tokenKey,
+ IssuerSigningKey = new SymmetricSecurityKey (Encryption.Instance.Key),
ValidateIssuer = false,
ValidateAudience = false,
ValidateActor = false,
- ValidateLifetime = true
+ ValidateLifetime = true,
+
};
options.Events = new JwtAuthenticationEventsHandler(
builder.Services.BuildServiceProvider().GetRequiredService(),
@@ -234,12 +235,12 @@ public static WebApplicationBuilder InjectServices(this WebApplicationBuilder bu
.SetHandlerLifetime(TimeSpan.FromMinutes(5)) //Set lifetime to five minutes
.AddPolicyHandler(GetWebhookRetryPolicy());
- builder.Services.AddHttpClient(HttpClientNames.WebHookHttpClientNoSSLCheckName)
- .SetHandlerLifetime(TimeSpan.FromMinutes(5)) //Set lifetime to five minutes
- .AddPolicyHandler(GetWebhookRetryPolicy()).ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
- {
- ServerCertificateCustomValidationCallback = (m, c, ch, e) => true
- });
+ builder.Services.AddHttpClient(HttpClientNames.WebHookHttpClientNoSSLCheckName)
+ .SetHandlerLifetime(TimeSpan.FromMinutes(5)) //Set lifetime to five minutes
+ .AddPolicyHandler(GetWebhookRetryPolicy()).ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
+ {
+ ServerCertificateCustomValidationCallback = (m, c, ch, e) => true
+ });
//Also keeping this here for a possible future API, though this would be for internal use
//builder.Services.AddTransient();
@@ -351,32 +352,47 @@ public static WebApplicationBuilder InjectServices(this WebApplicationBuilder bu
builder.Services.AddSwaggerGen(c =>
{
- c.SwaggerDoc("v1", new OpenApiInfo { Title = "Blazam API",
- Version = "v1" ,
- Description="The official Blazam API documentation. Authorization is required for API access.",
- License=new OpenApiLicense() { Name="MIT License", Url= new Uri("https://github.com/Blazam-App/BLAZAM/blob/v1-Dev/LICENSE") },
- Contact=new() { Email = "support@blazam.org",
- Name="Blazam Support",
- Url=new("https://blazam.org/support") },
- TermsOfService=new Uri("https://blazam.org/tos")
- });
-
- // Add descriptions using XML comments
- var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
- c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
-
- // Configure Swagger to use JWT Bearer authorization
- //c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
- //{
- // Description = "JWT Authorization header using the Bearer scheme.Example: \"Authorization: Bearer {token}\"",
- // Name = "Authorization",
- // In = ParameterLocation.Header,
- // Type = SecuritySchemeType.Http,
- // Scheme = "bearer",
- // BearerFormat = "JWT"
- //});
+ c.SwaggerDoc("v1", new OpenApiInfo
+ {
+ Title = "Blazam API",
+ Version = "v1",
+ Description = "The official Blazam API documentation. Authorization is required for API access.",
+ License = new OpenApiLicense() { Name = "MIT License", Url = new Uri("https://github.com/Blazam-App/BLAZAM/blob/v1-Dev/LICENSE") },
+ Contact = new()
+ {
+ Email = "support@blazam.org",
+ Name = "Blazam Support",
+ Url = new("https://blazam.org/support")
+ },
+ TermsOfService = new Uri("https://blazam.org/tos")
});
+ // Add descriptions using XML comments
+ var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
+ c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
+
+ // Configure Swagger to use JWT Bearer authorization
+ var jwtSecurityScheme = new OpenApiSecurityScheme
+ {
+ Description = "JWT Authorization header using the Bearer scheme.Example: \"Authorization: Bearer {token}\"",
+ Name = "Authorization",
+ In = ParameterLocation.Header,
+ Type = SecuritySchemeType.Http,
+ Scheme = JwtBearerDefaults.AuthenticationScheme,
+ BearerFormat = "JWT",
+ Reference = new OpenApiReference
+ {
+ Id = JwtBearerDefaults.AuthenticationScheme,
+ Type = ReferenceType.SecurityScheme
+ }
+ };
+
+ c.AddSecurityDefinition(jwtSecurityScheme.Reference.Id, jwtSecurityScheme);
+ c.AddSecurityRequirement(new OpenApiSecurityRequirement() {
+ { jwtSecurityScheme,Array.Empty() }
+ });
+ });
+
builder.Host.UseWindowsService();
@@ -384,84 +400,84 @@ public static WebApplicationBuilder InjectServices(this WebApplicationBuilder bu
return builder;
}
- public static void PreRun(this WebApplication application)
+ public static void PreRun(this WebApplication application)
+ {
+ //Setup Seq logging if allowed by admin
+ try
{
- //Setup Seq logging if allowed by admin
- try
+ var context = Program.AppInstance.Services.GetRequiredService().CreateDbContext();
+ if (context != null && context.AppSettings.FirstOrDefault()?.SendLogsToDeveloper != null)
{
- var context = Program.AppInstance.Services.GetRequiredService().CreateDbContext();
- if (context != null && context.AppSettings.FirstOrDefault()?.SendLogsToDeveloper != null)
- {
- Loggers.SendToSeqServer = context.AppSettings.FirstOrDefault().SendLogsToDeveloper;
-
- }
+ Loggers.SendToSeqServer = context.AppSettings.FirstOrDefault().SendLogsToDeveloper;
}
- catch (Exception ex)
- {
- Loggers.SystemLogger.Error(ex.Message + " {@Error}", ex);
- }
- PreloadServices();
}
- static IAsyncPolicy GetWebhookRetryPolicy()
+ catch (Exception ex)
{
- var delay = Backoff.DecorrelatedJitterBackoffV2(medianFirstRetryDelay: TimeSpan.FromSeconds(1), retryCount: 5);
+ Loggers.SystemLogger.Error(ex.Message + " {@Error}", ex);
+ }
+ PreloadServices();
+
+ }
+ static IAsyncPolicy GetWebhookRetryPolicy()
+ {
+ var delay = Backoff.DecorrelatedJitterBackoffV2(medianFirstRetryDelay: TimeSpan.FromSeconds(1), retryCount: 5);
- return HttpPolicyExtensions
- .HandleTransientHttpError()
- .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
- .WaitAndRetryAsync(delay);
+ return HttpPolicyExtensions
+ .HandleTransientHttpError()
+ .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
+ .WaitAndRetryAsync(delay);
+ }
+ private static void PreloadServices()
+ {
+ try
+ {
+ var context = Program.AppInstance.Services.GetRequiredService();
}
- private static void PreloadServices()
+ catch (Exception ex)
{
- try
- {
- var context = Program.AppInstance.Services.GetRequiredService();
- }
- catch (Exception ex)
+ Loggers.SystemLogger.Error(ex.Message + " {@Error}", ex);
+ }
+ try
+ {
+ if (ApplicationInfo.installationCompleted)
{
- Loggers.SystemLogger.Error(ex.Message + " {@Error}", ex);
+ var context = Program.AppInstance.Services.GetRequiredService();
}
- try
- {
- if (ApplicationInfo.installationCompleted)
- {
- var context = Program.AppInstance.Services.GetRequiredService();
- }
- }
- catch (Exception ex)
+ }
+ catch (Exception ex)
+ {
+ Loggers.SystemLogger.Error(ex.Message + " {@Error}", ex);
+ }
+ try
+ {
+ if (ApplicationInfo.installationCompleted)
{
- Loggers.SystemLogger.Error(ex.Message + " {@Error}", ex);
+ var context = Program.AppInstance.Services.GetRequiredService();
+ context.Initialize();
}
- try
- {
- if (ApplicationInfo.installationCompleted)
- {
- var context = Program.AppInstance.Services.GetRequiredService();
- context.Initialize();
- }
- }
- catch (Exception ex)
- {
- Loggers.SystemLogger.Error(ex.Message + " {@Error}", ex);
- }
- try
+ }
+ catch (Exception ex)
+ {
+ Loggers.SystemLogger.Error(ex.Message + " {@Error}", ex);
+ }
+ try
+ {
+ if (ApplicationInfo.installationCompleted)
{
- if (ApplicationInfo.installationCompleted)
- {
- var context = Program.AppInstance.Services.GetRequiredService();
-
- }
+ var context = Program.AppInstance.Services.GetRequiredService();
}
- catch (Exception ex)
- {
- Loggers.SystemLogger.Error(ex.Message + " {@Error}", ex);
- }
}
+ catch (Exception ex)
+ {
+ Loggers.SystemLogger.Error(ex.Message + " {@Error}", ex);
+ }
+
}
}
+}
diff --git a/BLAZAMCommon/Data/ApplicationInfo.cs b/BLAZAMCommon/Data/ApplicationInfo.cs
index 10ad5712..4db9320d 100644
--- a/BLAZAMCommon/Data/ApplicationInfo.cs
+++ b/BLAZAMCommon/Data/ApplicationInfo.cs
@@ -78,19 +78,7 @@ public class ApplicationInfo
///
public static IServiceProvider services;
- ///
- /// A symmetric key version of the encryption key
- /// for use with API signing
- ///
- public static SymmetricSecurityKey tokenKey { get {
-
- var keyString = configuration.GetValue("EncryptionKey");
- var keyBytes = Encoding.ASCII.GetBytes(keyString);
- return new SymmetricSecurityKey(keyBytes);
- } }
-
-
-
+
///
/// The running Blazam version
///
@@ -173,11 +161,7 @@ public static bool installationCompleted
/// Unique ID for this machine
///
public Guid InstallationId { get => installationId; set => installationId = value; }
- ///
- /// A symmetric key version of the encryption key
- /// for use with API signing
- ///
- public SymmetricSecurityKey TokenKey { get => tokenKey; }
+
///
/// Use only for UnitTests
diff --git a/BLAZAMGui/Layouts/AppUserApiModalContent.razor b/BLAZAMGui/Layouts/AppUserApiModalContent.razor
index bd8fd032..d4fa8cf3 100644
--- a/BLAZAMGui/Layouts/AppUserApiModalContent.razor
+++ b/BLAZAMGui/Layouts/AppUserApiModalContent.razor
@@ -1,6 +1,12 @@
@inherits AppModalContent
- @AppLocalization["Click to view API documentation"].
+
+ @AppLocalization["Click to view API documentation"].
+
@code{
diff --git a/BLAZAMGui/UI/Outputs/UserApiTokenDataGrid.razor b/BLAZAMGui/UI/Outputs/UserApiTokenDataGrid.razor
index 9036acad..ffcf401d 100644
--- a/BLAZAMGui/UI/Outputs/UserApiTokenDataGrid.razor
+++ b/BLAZAMGui/UI/Outputs/UserApiTokenDataGrid.razor
@@ -23,7 +23,11 @@
@AppLocalization["Forever"]
- @AppLocalization["Generate New API Token"]
+
+ @AppLocalization["Generate New API Token"]
+
@code {
List _tokens = new();
diff --git a/BLAZAMServices/JwtTokenService.cs b/BLAZAMServices/JwtTokenService.cs
index 9f1a3a06..abd284f1 100644
--- a/BLAZAMServices/JwtTokenService.cs
+++ b/BLAZAMServices/JwtTokenService.cs
@@ -18,12 +18,14 @@ namespace BLAZAM.Services
{
public class JwtTokenService
{
+ private readonly IEncryptionService _encryptionService;
private readonly ICurrentUserStateService _currentUserStateService;
private readonly ApplicationInfo _applicationInfo;
- public JwtTokenService(ApplicationInfo applicationInfo, ICurrentUserStateService currentUserStateService)
+ public JwtTokenService(IEncryptionService encryptionService, ApplicationInfo applicationInfo, ICurrentUserStateService currentUserStateService)
{
+ _encryptionService = encryptionService;
_currentUserStateService = currentUserStateService;
_applicationInfo = applicationInfo;
}
@@ -51,7 +53,7 @@ public string GenerateJwtToken(TimeSpan? lifetime=null)
IssuedAt = DateTime.UtcNow,
Issuer = DatabaseCache.ApplicationSettings.AppName,
Expires = (DateTime.UtcNow+lifetime.Value), // Set expiration
- SigningCredentials = new SigningCredentials(_applicationInfo.TokenKey, SecurityAlgorithms.HmacSha256Signature)
+ SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encryption.Instance.Key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var jwtToken = tokenHandler.WriteToken(token);
@@ -72,7 +74,7 @@ public ClaimsPrincipal DecodeJwtToken(string
tokenHandler.ValidateToken(token, new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
- IssuerSigningKey = _applicationInfo.TokenKey,
+ IssuerSigningKey = new SymmetricSecurityKey(Encryption.Instance.Key),
ValidateIssuer = false,
ValidateAudience = false,
ClockSkew = TimeSpan.Zero // Set clock skew to zero
diff --git a/PlaywrightTests/UnitTest1.cs b/PlaywrightTests/UnitTest1.cs
index 15c7d4a6..bd7f7aad 100644
--- a/PlaywrightTests/UnitTest1.cs
+++ b/PlaywrightTests/UnitTest1.cs
@@ -36,17 +36,17 @@ public async Task MainMenuTest()
await OpenRecycleBin();
- await OpenConfigureSubMenu();
+ //await OpenConfigureSubMenu();
- await OpenSettingsPages();
+ //await OpenSettingsPages();
- await OpenManageNotifications();
+ //await OpenManageNotifications();
- await OpenPermissions();
+ //await OpenPermissions();
- await OpenFields();
+ //await OpenFields();
- await OpenTemplates();
+ //await OpenTemplates();
// Expects the URL to contain intro.