diff --git a/src/Managing.Api/Managing.Api.csproj b/src/Managing.Api/Managing.Api.csproj
index afc1e2cc..4dd45482 100644
--- a/src/Managing.Api/Managing.Api.csproj
+++ b/src/Managing.Api/Managing.Api.csproj
@@ -39,7 +39,6 @@
-
diff --git a/src/Managing.Api/Program.cs b/src/Managing.Api/Program.cs
index ad0bbc0c..9c9b06ba 100644
--- a/src/Managing.Api/Program.cs
+++ b/src/Managing.Api/Program.cs
@@ -70,8 +70,6 @@ SentrySdk.Init(options =>
options.Environment = builder.Environment.EnvironmentName;
});
-// Add Service Defaults - using extension methods directly
-builder.Services.AddServiceDiscovery();
builder.Services.AddHealthChecks()
.AddCheck("self", () => HealthCheckResult.Healthy(), ["api"]);
@@ -167,7 +165,9 @@ builder.Host.UseSerilog((hostBuilder, loggerConfiguration) =>
};
loggerConfiguration
- .MinimumLevel.Override("Microsoft.EntityFrameworkCore.Database.Command", LogEventLevel.Warning) // Filter out EF Core SQL query logs
+ .MinimumLevel
+ .Override("Microsoft.EntityFrameworkCore.Database.Command",
+ LogEventLevel.Warning) // Filter out EF Core SQL query logs
.WriteTo.Console()
.WriteTo.Elasticsearch(es);
});
@@ -225,9 +225,9 @@ var validAudiences = builder.Configuration.GetSection("Authentication:Schemes:Be
.Get() ?? Array.Empty();
// Determine if validation should be enabled (enable in production, allow override via config)
-var enableIssuerValidation = builder.Configuration.GetValue("Jwt:ValidateIssuer",
+var enableIssuerValidation = builder.Configuration.GetValue("Jwt:ValidateIssuer",
!builder.Environment.IsDevelopment());
-var enableAudienceValidation = builder.Configuration.GetValue("Jwt:ValidateAudience",
+var enableAudienceValidation = builder.Configuration.GetValue("Jwt:ValidateAudience",
!builder.Environment.IsDevelopment());
// Configure clock skew (tolerance for time differences between servers)
@@ -268,7 +268,7 @@ builder.Services
context.Token = null;
return Task.CompletedTask;
}
-
+
// Handle tokens sent without "Bearer " prefix for authenticated endpoints
// The standard middleware expects "Bearer " but some clients send just the token
if (string.IsNullOrEmpty(context.Token))
@@ -284,7 +284,7 @@ builder.Services
// Otherwise, let the default middleware extract it (it will strip "Bearer " automatically)
}
}
-
+
// If you want to get the token from a custom header or query string
// var accessToken = context.Request.Query["access_token"];
// if (!string.IsNullOrEmpty(accessToken) &&
@@ -298,30 +298,30 @@ builder.Services
{
var logger = context.HttpContext.RequestServices
.GetService>();
-
+
// Check if the endpoint allows anonymous access
var endpoint = context.HttpContext.GetEndpoint();
var allowAnonymous = endpoint?.Metadata.GetMetadata() != null;
-
+
// For anonymous endpoints with malformed tokens, skip authentication instead of failing
if (allowAnonymous && context.Exception is SecurityTokenMalformedException)
{
- logger?.LogDebug("Skipping malformed token validation for anonymous endpoint: {Path}",
+ logger?.LogDebug("Skipping malformed token validation for anonymous endpoint: {Path}",
context.Request.Path);
context.NoResult(); // Skip authentication, don't fail
return Task.CompletedTask;
}
-
+
if (context.Exception is SecurityTokenExpiredException)
{
context.Response.Headers["Token-Expired"] = "true";
- logger?.LogWarning("JWT token expired for request: {Path}",
+ logger?.LogWarning("JWT token expired for request: {Path}",
context.Request.Path);
}
else
{
- logger?.LogError(context.Exception,
- "JWT authentication failed for request: {Path}",
+ logger?.LogError(context.Exception,
+ "JWT authentication failed for request: {Path}",
context.Request.Path);
}
@@ -332,12 +332,12 @@ builder.Services
{
var logger = context.HttpContext.RequestServices
.GetService>();
-
+
try
{
var userService = context.HttpContext.RequestServices
.GetRequiredService();
-
+
// JWT token contains 'address' claim (not NameIdentifier)
var address = context.Principal.FindFirst("address")?.Value;
@@ -354,7 +354,7 @@ builder.Services
else
{
logger?.LogWarning(
- "JWT token validated but user not found for address: {Address}",
+ "JWT token validated but user not found for address: {Address}",
address);
context.Fail("User not found");
}
@@ -367,7 +367,7 @@ builder.Services
}
catch (Exception ex)
{
- logger?.LogError(ex,
+ logger?.LogError(ex,
"Error during JWT token validation - user lookup failed");
context.Fail("Authentication failed: user lookup error");
}
@@ -482,19 +482,19 @@ app.Use(async (context, next) =>
context.Response.Headers.Append("X-XSS-Protection", "1; mode=block");
context.Response.Headers.Append("Referrer-Policy", "strict-origin-when-cross-origin");
context.Response.Headers.Append("Permissions-Policy", "geolocation=(), microphone=(), camera=()");
-
+
// Content Security Policy - only for non-Swagger endpoints
- if (!context.Request.Path.StartsWithSegments("/swagger") &&
+ if (!context.Request.Path.StartsWithSegments("/swagger") &&
!context.Request.Path.StartsWithSegments("/health") &&
!context.Request.Path.StartsWithSegments("/alive"))
{
- context.Response.Headers.Append("Content-Security-Policy",
+ context.Response.Headers.Append("Content-Security-Policy",
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;");
}
-
+
// Remove server header (optional - Kestrel can be configured separately)
context.Response.Headers.Remove("Server");
-
+
await next();
});
diff --git a/src/Managing.Nswag/Program.cs b/src/Managing.Nswag/Program.cs
index 3796ba53..dbbef41b 100644
--- a/src/Managing.Nswag/Program.cs
+++ b/src/Managing.Nswag/Program.cs
@@ -29,6 +29,9 @@ Directory.CreateDirectory(targetWebAppDirectory); // Ensure the directory exists
var targetWeb3ProxyDirectory = Path.Combine(solutionDirectory, "src", "Managing.Web3Proxy", "src", "generated");
Directory.CreateDirectory(targetWeb3ProxyDirectory);
+var targetKaigenWebDirectory = "/Users/oda/Desktop/Projects/kaigen-web/webapp/src/generated";
+Directory.CreateDirectory(targetKaigenWebDirectory);
+
var settings = new TypeScriptClientGeneratorSettings
{
ClassName = "{controller}Client",
@@ -53,13 +56,38 @@ var settings = new TypeScriptClientGeneratorSettings
var generatorApiClient = new TypeScriptClientGenerator(document, settings);
var codeApiClient = generatorApiClient.GenerateFile();
-// Add the necessary imports after the auto-generated comment
+// Settings for Kaigen web project using Axios
+var settingsAxios = new TypeScriptClientGeneratorSettings
+{
+ ClassName = "{controller}Client",
+ ClientBaseClass = "AuthorizedApiBase",
+ ConfigurationClass = "IConfig",
+ GenerateDtoTypes = true,
+ UseTransformOptionsMethod = true,
+ TypeScriptGeneratorSettings =
+ {
+ EnumStyle = TypeScriptEnumStyle.Enum,
+ DateTimeType = TypeScriptDateTimeType.Date,
+ NullValue = TypeScriptNullValue.Null,
+ TypeStyle = TypeScriptTypeStyle.Interface,
+ GenerateDefaultValues = true,
+ MarkOptionalProperties = true,
+ TypeScriptVersion = 4.3m
+ },
+ OperationNameGenerator = new MultipleClientsFromFirstTagAndOperationIdGenerator(),
+ Template = TypeScriptTemplate.Axios,
+};
+
+var generatorApiClientAxios = new TypeScriptClientGenerator(document, settingsAxios);
+var codeApiClientAxios = generatorApiClientAxios.GenerateFile();
+
+// Add the necessary imports after the auto-generated comment for Fetch version
var requiredImports = @"
import AuthorizedApiBase from ""./AuthorizedApiBase"";
import IConfig from ""./IConfig"";
";
-// Find the end of the auto-generated comment and insert imports
+// Find the end of the auto-generated comment and insert imports for Fetch version
var autoGeneratedEndIndex = codeApiClient.IndexOf("//----------------------");
if (autoGeneratedEndIndex != -1)
{
@@ -72,7 +100,21 @@ if (autoGeneratedEndIndex != -1)
}
}
+// Add the necessary imports for Axios version as well
+var autoGeneratedEndIndexAxios = codeApiClientAxios.IndexOf("//----------------------");
+if (autoGeneratedEndIndexAxios != -1)
+{
+ // Find the second occurrence (end of the comment block)
+ autoGeneratedEndIndexAxios = codeApiClientAxios.IndexOf("//----------------------", autoGeneratedEndIndexAxios + 1);
+ if (autoGeneratedEndIndexAxios != -1)
+ {
+ autoGeneratedEndIndexAxios = codeApiClientAxios.IndexOf("\n", autoGeneratedEndIndexAxios) + 1;
+ codeApiClientAxios = codeApiClientAxios.Insert(autoGeneratedEndIndexAxios, requiredImports);
+ }
+}
+
File.WriteAllText(Path.Combine(targetWebAppDirectory, "ManagingApi.ts"), codeApiClient);
+File.WriteAllText(Path.Combine(targetKaigenWebDirectory, "ManagingApi.ts"), codeApiClientAxios);
var settingsTypes = new TypeScriptClientGeneratorSettings
{
@@ -97,4 +139,5 @@ var generatorTypes = new TypeScriptClientGenerator(document, settingsTypes);
var codeTypes = generatorTypes.GenerateFile();
File.WriteAllText(Path.Combine(targetWebAppDirectory, "ManagingApiTypes.ts"), codeTypes);
-File.WriteAllText(Path.Combine(targetWeb3ProxyDirectory, "ManagingApiTypes.ts"), codeTypes);
\ No newline at end of file
+File.WriteAllText(Path.Combine(targetWeb3ProxyDirectory, "ManagingApiTypes.ts"), codeTypes);
+File.WriteAllText(Path.Combine(targetKaigenWebDirectory, "ManagingApiTypes.ts"), codeTypes);
\ No newline at end of file
diff --git a/src/Managing.WebApp/src/generated/AuthorizedApiBase.ts b/src/Managing.WebApp/src/generated/AuthorizedApiBase.ts
index 4601cbdc..7e267e18 100644
--- a/src/Managing.WebApp/src/generated/AuthorizedApiBase.ts
+++ b/src/Managing.WebApp/src/generated/AuthorizedApiBase.ts
@@ -4,9 +4,10 @@
* API clients inherit from #AuthorizedApiBase and provide the config.
*/
-import { Cookies } from 'react-cookie'
+import {Cookies} from 'react-cookie'
import type IConfig from './IConfig'
+
export default class AuthorizedApiBase {
private readonly config: IConfig
@@ -14,7 +15,7 @@ export default class AuthorizedApiBase {
this.config = config
}
- transformOptions = (options: any): Promise => {
+ transformOptions = (options: any): Promise => {
const cookies = new Cookies()
const bearerToken = cookies.get('token')
if (bearerToken) {
diff --git a/src/Managing.sln b/src/Managing.sln
index 9649225b..cadb2886 100644
--- a/src/Managing.sln
+++ b/src/Managing.sln
@@ -62,10 +62,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Managing.ABI.GmxV2", "Managing.ABI.GmxV2\Managing.ABI.GmxV2.csproj", "{4521E1A9-AF81-4CA8-8B4D-30C261ECE977}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Managing.Aspire.AppHost", "Managing.Aspire.AppHost\Managing.Aspire.AppHost.csproj", "{2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Managing.Aspire.ServiceDefaults", "Managing.Aspire.ServiceDefaults\Managing.Aspire.ServiceDefaults.csproj", "{F58949B8-4173-4F9E-83FF-B88FA2C5C849}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Managing.Nswag", "Managing.Nswag\Managing.Nswag.csproj", "{BE50F950-C1D4-4CE0-B32E-6AAC996770D5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Managing.Workers", "Managing.Workers\Managing.Workers.csproj", "{B7D66A73-CA3A-4DE5-8E88-59D50C4018A6}"
@@ -218,22 +214,6 @@ Global
{4521E1A9-AF81-4CA8-8B4D-30C261ECE977}.Release|Any CPU.Build.0 = Release|Any CPU
{4521E1A9-AF81-4CA8-8B4D-30C261ECE977}.Release|x64.ActiveCfg = Release|Any CPU
{4521E1A9-AF81-4CA8-8B4D-30C261ECE977}.Release|x64.Build.0 = Release|Any CPU
- {2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}.Debug|x64.ActiveCfg = Debug|Any CPU
- {2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}.Debug|x64.Build.0 = Debug|Any CPU
- {2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}.Release|Any CPU.Build.0 = Release|Any CPU
- {2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}.Release|x64.ActiveCfg = Release|Any CPU
- {2A7AC5A7-B4D6-4DF2-976B-6EE771BB4C31}.Release|x64.Build.0 = Release|Any CPU
- {F58949B8-4173-4F9E-83FF-B88FA2C5C849}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F58949B8-4173-4F9E-83FF-B88FA2C5C849}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F58949B8-4173-4F9E-83FF-B88FA2C5C849}.Debug|x64.ActiveCfg = Debug|Any CPU
- {F58949B8-4173-4F9E-83FF-B88FA2C5C849}.Debug|x64.Build.0 = Debug|Any CPU
- {F58949B8-4173-4F9E-83FF-B88FA2C5C849}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F58949B8-4173-4F9E-83FF-B88FA2C5C849}.Release|Any CPU.Build.0 = Release|Any CPU
- {F58949B8-4173-4F9E-83FF-B88FA2C5C849}.Release|x64.ActiveCfg = Release|Any CPU
- {F58949B8-4173-4F9E-83FF-B88FA2C5C849}.Release|x64.Build.0 = Release|Any CPU
{BE50F950-C1D4-4CE0-B32E-6AAC996770D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BE50F950-C1D4-4CE0-B32E-6AAC996770D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BE50F950-C1D4-4CE0-B32E-6AAC996770D5}.Debug|x64.ActiveCfg = Debug|Any CPU