Merge pull request #1089 from hargata/Hargata/server.config.endpoints

Allow users to configure HTTPS and HTTP endpoints entirely within the…
This commit is contained in:
Hargata Softworks 2025-10-08 12:09:54 -06:00 committed by GitHub
commit 505bc5b3c6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 138 additions and 7 deletions

View File

@ -597,7 +597,8 @@ namespace CarCareTracker.Controllers
EnableAuth = _config.GetServerAuthEnabled(),
DefaultReminderEmail = _config.GetDefaultReminderEmail(),
EnableRootUserOIDC = _config.GetEnableRootUserOIDC(),
CookieLifeSpan = _config.GetAuthCookieLifeSpan().ToString()
CookieLifeSpan = _config.GetAuthCookieLifeSpan().ToString(),
KestrelAppConfig = _config.GetKestrelAppConfig()
};
return View(viewModel);
}

View File

@ -12,6 +12,7 @@ namespace CarCareTracker.Helper
ReminderUrgencyConfig GetReminderUrgencyConfig();
MailConfig GetMailConfig();
UserConfig GetUserConfig(ClaimsPrincipal user);
KestrelAppConfig GetKestrelAppConfig();
bool SaveUserConfig(ClaimsPrincipal user, UserConfig configData);
bool SaveServerConfig(ServerConfig serverConfig);
bool AuthenticateRootUser(string username, string password);
@ -53,6 +54,12 @@ namespace CarCareTracker.Helper
_cache = memoryCache;
_logger = logger;
}
public KestrelAppConfig GetKestrelAppConfig()
{
KestrelAppConfig kestrelConfig = _config.GetSection("Kestrel").Get<KestrelAppConfig>() ?? new KestrelAppConfig();
return kestrelConfig;
}
public string GetWebHookUrl()
{
var webhook = CheckString("LUBELOGGER_WEBHOOK");
@ -269,6 +276,43 @@ namespace CarCareTracker.Helper
{
serverConfig.CookieLifeSpan = null;
}
if (serverConfig.KestrelAppConfig != null)
{
if (serverConfig.KestrelAppConfig.Endpoints.Http != null)
{
//validate http endpoint
if (string.IsNullOrWhiteSpace(serverConfig.KestrelAppConfig.Endpoints.Http.Url))
{
serverConfig.KestrelAppConfig.Endpoints.Http = null;
}
}
if (serverConfig.KestrelAppConfig.Endpoints.HttpsInlineCertFile != null)
{
//https endpoint provided
if (string.IsNullOrWhiteSpace(serverConfig.KestrelAppConfig.Endpoints.HttpsInlineCertFile.Url))
{
serverConfig.KestrelAppConfig.Endpoints.HttpsInlineCertFile = null;
}
else if (serverConfig.KestrelAppConfig.Endpoints.HttpsInlineCertFile.Certificate != null)
{
if (string.IsNullOrWhiteSpace(serverConfig.KestrelAppConfig.Endpoints.HttpsInlineCertFile.Certificate.Password))
{
//cert not null but password is null
serverConfig.KestrelAppConfig.Endpoints.HttpsInlineCertFile.Certificate.Password = null;
}
if (string.IsNullOrWhiteSpace(serverConfig.KestrelAppConfig.Endpoints.HttpsInlineCertFile.Certificate.Path))
{
//cert not null but path is null
serverConfig.KestrelAppConfig.Endpoints.HttpsInlineCertFile.Certificate = null;
}
}
}
if (serverConfig.KestrelAppConfig.Endpoints.Http == null && serverConfig.KestrelAppConfig.Endpoints.HttpsInlineCertFile == null)
{
//if no endpoints are provided
serverConfig.KestrelAppConfig = null;
}
}
try
{
File.WriteAllText(StaticHelper.ServerConfigPath, JsonSerializer.Serialize(serverConfig));

View File

@ -77,5 +77,8 @@ namespace CarCareTracker.Models
[JsonPropertyName("LUBELOGGER_COOKIE_LIFESPAN")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? CookieLifeSpan { get; set; } = string.Empty;
[JsonPropertyName("Kestrel")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public KestrelAppConfig? KestrelAppConfig { get; set; }
}
}

View File

@ -0,0 +1,32 @@
using System.Text.Json.Serialization;
namespace CarCareTracker.Models
{
public class KestrelAppConfig
{
public KestrelAppConfigEndpoints Endpoints { get; set; } = new KestrelAppConfigEndpoints();
}
public class KestrelAppConfigEndpoints
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public KestrelAppConfigHttpEndpoint? Http { get; set; } = new KestrelAppConfigHttpEndpoint();
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public KestrelAppConfigHttpsEndpoint? HttpsInlineCertFile { get; set; } = new KestrelAppConfigHttpsEndpoint();
}
public class KestrelAppConfigHttpEndpoint
{
public string? Url { get; set; } = string.Empty;
}
public class KestrelAppConfigHttpsEndpoint
{
public string? Url { get; set; } = string.Empty;
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public KestrelAppConfigHttpsCertificate? Certificate { get; set; } = new KestrelAppConfigHttpsCertificate();
}
public class KestrelAppConfigHttpsCertificate
{
public string? Path { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Password { get; set; }
}
}

View File

@ -23,5 +23,6 @@ namespace CarCareTracker.Models
public bool EnableAuth { get; set; }
public List<string> AvailableLocales { get; set; }
public string CookieLifeSpan { get; set; }
public KestrelAppConfig KestrelAppConfig { get; set; }
}
}

View File

@ -163,6 +163,38 @@
</form>
</div>
<div class="setup-wizard-content" data-page="3" style="display:none;">
<div class="d-flex justify-content-between align-items-center">
<span class="display-5">@translator.Translate(userLanguage, "Server Endpoints")</span>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" onchange="nextOnSkip(this)" role="switch" id="skipHTTPS">
<label class="form-check-label" for="skipHTTPS">@translator.Translate(userLanguage, "Skip")</label>
</div>
</div>
<hr />
<form class="form-inline">
<div class="form-group">
<label for="inputHTTPURL">@translator.Translate(userLanguage, "Http Endpoint")</label>
<input type="text" id="inputHTTPURL" class="form-control" placeholder="@translator.Translate(userLanguage, "Not Configured")" value="@Model.KestrelAppConfig.Endpoints.Http.Url">
<small class="text-body-secondary">@translator.Translate(userLanguage, "Restart Required")</small>
</div>
<div class="form-group">
<label for="inputHTTPSURL">@translator.Translate(userLanguage, "Https Endpoint")</label>
<input type="text" id="inputHTTPSURL" class="form-control" placeholder="@translator.Translate(userLanguage, "Not Configured")" value="@Model.KestrelAppConfig.Endpoints.HttpsInlineCertFile.Url">
<small class="text-body-secondary">@translator.Translate(userLanguage, "Restart Required")</small>
</div>
<div class="form-group">
<label for="inputHTTPSCertLocation">@translator.Translate(userLanguage, "HTTPS Certificate Location")</label>
<input type="text" id="inputHTTPSCertLocation" class="form-control" placeholder="@translator.Translate(userLanguage, "Not Configured")" value="@Model.KestrelAppConfig.Endpoints.HttpsInlineCertFile.Certificate.Path">
<small class="text-body-secondary">@translator.Translate(userLanguage, "Restart Required")</small>
</div>
<div class="form-group">
<label for="inputHTTPSCertPassword">@translator.Translate(userLanguage, "HTTPS Certificate Password")</label>
<input type="text" id="inputHTTPSCertPassword" class="form-control" placeholder="@translator.Translate(userLanguage, "Not Configured")" value="@Model.KestrelAppConfig.Endpoints.HttpsInlineCertFile.Certificate.Password">
<small class="text-body-secondary">@translator.Translate(userLanguage, "Restart Required")</small>
</div>
</form>
</div>
<div class="setup-wizard-content" data-page="4" style="display:none;">
<div class="d-flex justify-content-between align-items-center">
<span class="display-5">@translator.Translate(userLanguage, "Single Sign On")</span>
<div class="form-check form-switch">
@ -236,7 +268,7 @@
</div>
</form>
</div>
<div class="setup-wizard-content" data-page="4" style="display:none;">
<div class="setup-wizard-content" data-page="5" style="display:none;">
<span class="display-5">@translator.Translate(userLanguage, "Miscellaneous")</span>
<hr />
<form class="form-inline">
@ -284,7 +316,7 @@
</div>
</form>
</div>
<div class="setup-wizard-content" data-page="5" style="display:none;">
<div class="setup-wizard-content" data-page="6" style="display:none;">
<div class="d-flex text-center align-items-center justify-content-center flex-column" style="height:100%;">
<div><span class="display-5">@translator.Translate(userLanguage, "Server Settings Saved")<span class="text-success"><i class="bi bi-check-lg"></i></span></span></div>
<div class="mt-2"><a class="btn btn-secondary me-2" onclick="loadSetupPage(0)">@translator.Translate(userLanguage, "Restart Wizard")</a><a class="btn btn-primary" onclick="returnToGarage()">@translator.Translate(userLanguage, "Return to Garage")</a></div>

File diff suppressed because one or more lines are too long

View File

@ -10,18 +10,19 @@ function determineSetupButtons() {
let currentVisiblePage = $(".setup-wizard-content:visible").attr('data-page');
switch (currentVisiblePage) {
case '0':
case '5':
case '6':
$(".setup-wizard-nav").hide();
break;
case '1':
case '2':
case '3':
case '4':
$(".setup-wizard-nav").show();
$(".btn-prev").show();
$(".btn-next").show();
$(".btn-save").hide();
break;
case '4':
case '5':
$(".setup-wizard-nav").show();
$(".btn-prev").show();
$(".btn-next").hide();
@ -98,7 +99,21 @@ function saveSetup() {
VeryUrgentDistance: $("#inputVeryUrgentDistance").val()
},
DefaultReminderEmail: $("#inputDefaultReminderEmail").val(),
EnableRootUserOIDC: $("#inputOIDCRootUser").val()
EnableRootUserOIDC: $("#inputOIDCRootUser").val(),
KestrelAppConfig: {
Endpoints: {
Http: {
Url: $("#inputHTTPURL").val()
},
HttpsInlineCertFile: {
Url: $("#inputHTTPSURL").val(),
Certificate: {
Path: $("#inputHTTPSCertLocation").val(),
Password: $("#inputHTTPSCertPassword").val()
}
}
}
}
};
let registrationMode = $("#inputRegistrationMode");
if (registrationMode.length > 0) {
@ -127,6 +142,9 @@ function saveSetup() {
if ($("#skipPostgres").is(":checked")) {
setupData["PostgresConnection"] = null;
}
if ($("#skipHTTPS").is(":checked")) {
setupData["KestrelAppConfig"] = null;
}
let rootUserOIDC = $("#inputOIDCRootUser");
if (rootUserOIDC.length > 0) {
setupData["EnableRootUserOIDC"] = $("#inputOIDCRootUser").val();