mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-25 15:08:47 -07:00
feat: Enhance domain configuration to support hyphen subdomains and update related methods
This commit is contained in:
@@ -12,14 +12,22 @@ public sealed class DomainConfig
|
|||||||
{
|
{
|
||||||
public string Apex { get; }
|
public string Apex { get; }
|
||||||
public string Scheme { get; }
|
public string Scheme { get; }
|
||||||
|
public string HostStyle { get; }
|
||||||
|
public bool UsesHyphenSubdomains => HostStyle == "hyphen";
|
||||||
|
|
||||||
public DomainConfig(string apex, string scheme = "https")
|
public DomainConfig(string apex, string scheme = "https", string hostStyle = "dot")
|
||||||
{
|
{
|
||||||
Apex = apex;
|
Apex = apex;
|
||||||
Scheme = NormalizeScheme(scheme);
|
Scheme = NormalizeScheme(scheme);
|
||||||
|
HostStyle = NormalizeHostStyle(hostStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Sub(string prefix)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(prefix)) return Apex;
|
||||||
|
return UsesHyphenSubdomains ? $"{prefix}-{Apex}" : $"{prefix}.{Apex}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Sub(string prefix) => $"{prefix}.{Apex}";
|
|
||||||
public string Url(string prefix, string path = "")
|
public string Url(string prefix, string path = "")
|
||||||
{
|
{
|
||||||
var host = string.IsNullOrEmpty(prefix) ? Apex : Sub(prefix);
|
var host = string.IsNullOrEmpty(prefix) ? Apex : Sub(prefix);
|
||||||
@@ -28,11 +36,18 @@ public sealed class DomainConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static bool MatchesSubdomain(string host, string prefix)
|
public static bool MatchesSubdomain(string host, string prefix)
|
||||||
=> host.StartsWith(prefix + ".", StringComparison.OrdinalIgnoreCase);
|
=> host.StartsWith(prefix + ".", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| host.StartsWith(prefix + "-", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
private static string NormalizeScheme(string? value)
|
private static string NormalizeScheme(string? value)
|
||||||
{
|
{
|
||||||
var scheme = string.IsNullOrWhiteSpace(value) ? "https" : value.Trim().TrimEnd(':', '/', '\\').ToLowerInvariant();
|
var scheme = string.IsNullOrWhiteSpace(value) ? "https" : value.Trim().TrimEnd(':', '/', '\\').ToLowerInvariant();
|
||||||
return scheme is "http" or "https" ? scheme : "https";
|
return scheme is "http" or "https" ? scheme : "https";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string NormalizeHostStyle(string? value)
|
||||||
|
{
|
||||||
|
var style = string.IsNullOrWhiteSpace(value) ? "dot" : value.Trim().ToLowerInvariant();
|
||||||
|
return style is "hyphen" or "dash" or "flat" ? "hyphen" : "dot";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ public static class MiddlewarePipelineExtensions
|
|||||||
// Public-facing site at the apex (e.g. localhost + www variant).
|
// Public-facing site at the apex (e.g. localhost + www variant).
|
||||||
// React-router routes are client-side so spaFallback must be true.
|
// React-router routes are client-side so spaFallback must be true.
|
||||||
app.MountStaticHost(domainCfg.Apex, "site", spaFallback: true);
|
app.MountStaticHost(domainCfg.Apex, "site", spaFallback: true);
|
||||||
app.MountStaticHost($"www.{domainCfg.Apex}", "site", spaFallback: true);
|
app.MountStaticHost(domainCfg.Sub("www"), "site", spaFallback: true);
|
||||||
// Old feed.* subdomain kept as legacy; new visitors land on the apex.
|
// Old feed.* subdomain kept as legacy; new visitors land on the apex.
|
||||||
app.MountStaticHost(domainCfg.Sub("feed"), "feed");
|
app.MountStaticHost(domainCfg.Sub("feed"), "feed");
|
||||||
|
|
||||||
|
|||||||
@@ -115,7 +115,23 @@ public static class ServiceCollectionExtensions
|
|||||||
?? Environment.GetEnvironmentVariable("DORKNET_DOMAIN")
|
?? Environment.GetEnvironmentVariable("DORKNET_DOMAIN")
|
||||||
?? "localhost";
|
?? "localhost";
|
||||||
var scheme = builder.Configuration["Domain:Scheme"] ?? "https";
|
var scheme = builder.Configuration["Domain:Scheme"] ?? "https";
|
||||||
var allowedHosts = new List<string> { apex, $"*.{apex}", "localhost", "127.0.0.1" };
|
var hostStyle =
|
||||||
|
builder.Configuration["Domain:HostStyle"]
|
||||||
|
?? Environment.GetEnvironmentVariable("DORKNET_DOMAIN_STYLE")
|
||||||
|
?? "dot";
|
||||||
|
var domain = new DomainConfig(apex, scheme, hostStyle);
|
||||||
|
var allowedHosts = new List<string> { apex, "localhost", "127.0.0.1" };
|
||||||
|
if (domain.UsesHyphenSubdomains)
|
||||||
|
{
|
||||||
|
allowedHosts.AddRange(KnownServiceSubdomains
|
||||||
|
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||||
|
.Select(domain.Sub));
|
||||||
|
allowedHosts.Add(domain.Sub("www"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
allowedHosts.Add($"*.{apex}");
|
||||||
|
}
|
||||||
var bootstrapApex = builder.Configuration["Domain:BootstrapApex"];
|
var bootstrapApex = builder.Configuration["Domain:BootstrapApex"];
|
||||||
if (!string.IsNullOrWhiteSpace(bootstrapApex))
|
if (!string.IsNullOrWhiteSpace(bootstrapApex))
|
||||||
{
|
{
|
||||||
@@ -123,16 +139,57 @@ public static class ServiceCollectionExtensions
|
|||||||
allowedHosts.Add($"*.{bootstrapApex}");
|
allowedHosts.Add($"*.{bootstrapApex}");
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.Services.AddSingleton(new DomainConfig(apex, scheme));
|
builder.Services.AddSingleton(domain);
|
||||||
builder.Services.Configure<Microsoft.AspNetCore.HostFiltering.HostFilteringOptions>(opt =>
|
builder.Services.Configure<Microsoft.AspNetCore.HostFiltering.HostFilteringOptions>(opt =>
|
||||||
{
|
{
|
||||||
opt.AllowedHosts = allowedHosts.Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
|
opt.AllowedHosts = allowedHosts.Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
|
||||||
opt.AllowEmptyHosts = true;
|
opt.AllowEmptyHosts = true;
|
||||||
opt.IncludeFailureMessage = true;
|
opt.IncludeFailureMessage = true;
|
||||||
});
|
});
|
||||||
Console.WriteLine($"[domain] apex={apex}, allowedHosts=[{string.Join(", ", allowedHosts)}]");
|
Console.WriteLine($"[domain] apex={apex}, style={domain.HostStyle}, allowedHosts=[{string.Join(", ", allowedHosts)}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly string[] KnownServiceSubdomains =
|
||||||
|
{
|
||||||
|
"admin",
|
||||||
|
"api",
|
||||||
|
"accounts",
|
||||||
|
"auth",
|
||||||
|
"bugreporting",
|
||||||
|
"cards",
|
||||||
|
"cdn",
|
||||||
|
"chat",
|
||||||
|
"clubs",
|
||||||
|
"cms",
|
||||||
|
"commerce",
|
||||||
|
"data",
|
||||||
|
"datacollection",
|
||||||
|
"discovery",
|
||||||
|
"econ",
|
||||||
|
"feed",
|
||||||
|
"gamelogs",
|
||||||
|
"geo",
|
||||||
|
"img",
|
||||||
|
"leaderboard",
|
||||||
|
"link",
|
||||||
|
"lists",
|
||||||
|
"match",
|
||||||
|
"moderation",
|
||||||
|
"notify",
|
||||||
|
"ns",
|
||||||
|
"platformnotifications",
|
||||||
|
"playersettings",
|
||||||
|
"roomcomments",
|
||||||
|
"roomieintegrations",
|
||||||
|
"rooms",
|
||||||
|
"storage",
|
||||||
|
"strings",
|
||||||
|
"strings-cdn",
|
||||||
|
"studio",
|
||||||
|
"thorn",
|
||||||
|
"videos",
|
||||||
|
};
|
||||||
|
|
||||||
// ── Services ──────────────────────────────────────────────────────────────
|
// ── Services ──────────────────────────────────────────────────────────────
|
||||||
private static void AddCoreServices(IServiceCollection services)
|
private static void AddCoreServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -54,11 +54,18 @@ export function adminApex(): string {
|
|||||||
|
|
||||||
const host = window.location.hostname.toLowerCase();
|
const host = window.location.hostname.toLowerCase();
|
||||||
if (host === 'localhost' || host.endsWith('.localhost')) return 'localhost';
|
if (host === 'localhost' || host.endsWith('.localhost')) return 'localhost';
|
||||||
|
if (host.endsWith('-dev.example.com')) return 'dev.example.com';
|
||||||
|
|
||||||
const parts = host.split('.');
|
const parts = host.split('.');
|
||||||
return parts.length > 2 ? parts.slice(1).join('.') : host;
|
return parts.length > 2 ? parts.slice(1).join('.') : host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function serviceHost(subdomain: string, apex: string): string {
|
||||||
|
return apex === 'dev.example.com'
|
||||||
|
? `${subdomain}-${apex}`
|
||||||
|
: `${subdomain}.${apex}`;
|
||||||
|
}
|
||||||
|
|
||||||
function subdomainUrl(subdomain: string, path: string | null | undefined, query?: string, preserveSlashes = false): string | null {
|
function subdomainUrl(subdomain: string, path: string | null | undefined, query?: string, preserveSlashes = false): string | null {
|
||||||
if (!path) return null;
|
if (!path) return null;
|
||||||
const apex = adminApex();
|
const apex = adminApex();
|
||||||
@@ -67,7 +74,7 @@ function subdomainUrl(subdomain: string, path: string | null | undefined, query?
|
|||||||
const encodedPath = preserveSlashes
|
const encodedPath = preserveSlashes
|
||||||
? path.split('/').map(encodeURIComponent).join('/')
|
? path.split('/').map(encodeURIComponent).join('/')
|
||||||
: encodeURIComponent(path);
|
: encodeURIComponent(path);
|
||||||
return `${scheme}://${subdomain}.${apex}/${encodedPath}${suffix}`;
|
return `${scheme}://${serviceHost(subdomain, apex)}/${encodedPath}${suffix}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Room {
|
export interface Room {
|
||||||
|
|||||||
Reference in New Issue
Block a user