Migrate auth to Open.IdentityServer

This commit is contained in:
Alexa
2026-06-30 15:47:27 +03:00
parent c192d9c051
commit 399f49fa8a
28 changed files with 47 additions and 77 deletions
+4 -4
View File
@@ -1,14 +1,14 @@
# DorkNet.Server container image — Coolify deploy target. # DorkNet.Server container image — Coolify deploy target.
# ──────────────────────────────────────────────────────────────────── # ────────────────────────────────────────────────────────────────────
# Multi-stage: SDK image builds + publishes, runtime image is the # Multi-stage: SDK image builds + publishes, runtime image is the
# slimmer aspnet:9.0 with only the published output. # slimmer aspnet:10.0 with only the published output.
# #
# Build context: repo root (so Tools/ and DorkNet.Models/ are visible # Build context: repo root (so Tools/ and DorkNet.Models/ are visible
# to ProjectReference + dotnet restore). The .dockerignore at the # to ProjectReference + dotnet restore). The .dockerignore at the
# repo root keeps the bin/, obj/, and other dev junk out of the # repo root keeps the bin/, obj/, and other dev junk out of the
# context. # context.
ARG DOTNET_VERSION=9.0 ARG DOTNET_VERSION=10.0
ARG NODE_VERSION=20 ARG NODE_VERSION=20
# ── admin SPA build stage ────────────────────────────────────────── # ── admin SPA build stage ──────────────────────────────────────────
@@ -78,13 +78,13 @@ WORKDIR /app
# curl + wget for healthcheck probes — Coolify v4 defaults to wget for # curl + wget for healthcheck probes — Coolify v4 defaults to wget for
# its own probe regardless of what the image's HEALTHCHECK uses, so # its own probe regardless of what the image's HEALTHCHECK uses, so
# both have to be present. The aspnet:9.0 base image strips both by # both have to be present. The aspnet:10.0 base image strips both by
# default to keep the surface area small. # default to keep the surface area small.
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y --no-install-recommends curl wget \ && apt-get install -y --no-install-recommends curl wget \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# Run as a non-root user — aspnet:9.0 ships with the `app` UID 1654. # Run as a non-root user — aspnet:10.0 ships with the `app` UID 1654.
# Coolify mounts persistent volumes with write permission for this UID. # Coolify mounts persistent volumes with write permission for this UID.
USER app USER app
+1 -1
View File
@@ -1,4 +1,4 @@
ARG DOTNET_VERSION=9.0 ARG DOTNET_VERSION=10.0
ARG NODE_VERSION=20 ARG NODE_VERSION=20
FROM node:${NODE_VERSION}-alpine AS admin-ui FROM node:${NODE_VERSION}-alpine AS admin-ui
+1 -1
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
+1 -1
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
+2 -2
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
@@ -9,7 +9,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2" /> <PackageReference Include="coverlet.collector" Version="6.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="9.0.4" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.9" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="xunit" Version="2.9.2" /> <PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
@@ -1,11 +1,8 @@
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HostFiltering; using Microsoft.AspNetCore.HostFiltering;
using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
namespace DorkNet.Server.Tests; namespace DorkNet.Server.Tests;
@@ -56,18 +53,6 @@ public sealed class DorkNetServerFactory : WebApplicationFactory<Program>
options.AllowEmptyHosts = true; options.AllowEmptyHosts = true;
options.IncludeFailureMessage = true; options.IncludeFailureMessage = true;
}); });
services.PostConfigure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtSecret)),
ValidateIssuer = true,
ValidIssuer = "https://api.rec.net/",
ValidateAudience = false,
ClockSkew = TimeSpan.Zero,
};
});
}); });
} }
@@ -26,6 +26,8 @@ public static class GameClientSessionFactory
tokenRequest.Content = new FormUrlEncodedContent(new Dictionary<string, string> tokenRequest.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{ {
["grant_type"] = "password", ["grant_type"] = "password",
["client_id"] = "recroom",
["client_secret"] = "VxZ53kgbbEaRoZAeMe00MagtgD12GLL2",
["username"] = "EndpointContract", ["username"] = "EndpointContract",
["device_id"] = deviceId, ["device_id"] = deviceId,
["platform"] = "0", ["platform"] = "0",
@@ -3,10 +3,10 @@ using System.Security.Claims;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using Duende.IdentityServer; using Open.IdentityServer;
using Duende.IdentityServer.Models; using Open.IdentityServer.Models;
using Duende.IdentityServer.Services; using Open.IdentityServer.Services;
using Duende.IdentityServer.Validation; using Open.IdentityServer.Validation;
using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Http.Features;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
@@ -206,12 +206,6 @@ public static class RecRoomIdentityServerRegistration
.AddIdentityServer(options => .AddIdentityServer(options =>
{ {
options.IssuerUri = domain.AuthIssuer.TrimEnd('/'); options.IssuerUri = domain.AuthIssuer.TrimEnd('/');
options.KeyManagement.Enabled = false;
var licenseKey =
Environment.GetEnvironmentVariable("DUENDE_IDENTITYSERVER_LICENSE_KEY")
?? config["IdentityServer:LicenseKey"];
if (!string.IsNullOrWhiteSpace(licenseKey))
options.LicenseKey = licenseKey;
}) })
.AddInMemoryIdentityResources(RecRoomIdentityServerConfig.IdentityResources) .AddInMemoryIdentityResources(RecRoomIdentityServerConfig.IdentityResources)
.AddInMemoryApiScopes(RecRoomIdentityServerConfig.ApiScopes) .AddInMemoryApiScopes(RecRoomIdentityServerConfig.ApiScopes)
@@ -256,7 +250,7 @@ internal static class RecRoomIdentityServerConfig
ClientName = "Rec Room game client", ClientName = "Rec Room game client",
RequireClientSecret = true, RequireClientSecret = true,
ClientSecrets = { new Secret(ClientSecret.Sha256()) }, ClientSecrets = { new Secret(ClientSecret.Sha256()) },
AllowedGrantTypes = { GrantType.ResourceOwnerPassword, GrantType.RefreshToken, CachedLoginGrantType }, AllowedGrantTypes = { GrantType.ResourceOwnerPassword, "refresh_token", CachedLoginGrantType },
AllowedScopes = RecRoomScopes(), AllowedScopes = RecRoomScopes(),
AllowOfflineAccess = true, AllowOfflineAccess = true,
AccessTokenLifetime = 60 * 60 * 12, AccessTokenLifetime = 60 * 60 * 12,
@@ -40,7 +40,6 @@ public class AdminController(
SignupCodeService signupCodes, SignupCodeService signupCodes,
IObjectStorage storage, IObjectStorage storage,
DomainConfig domain, DomainConfig domain,
IConfiguration config,
IdentityServerSigningKeyProvider signingKeys, IdentityServerSigningKeyProvider signingKeys,
ILogger<AdminController> adminLogger) : ControllerBase ILogger<AdminController> adminLogger) : ControllerBase
{ {
@@ -1471,9 +1470,6 @@ public class AdminController(
var certPath = signingKeys.CertificatePath; var certPath = signingKeys.CertificatePath;
var fullCertPath = Path.GetFullPath(certPath); var fullCertPath = Path.GetFullPath(certPath);
var certificateExists = signingKeys.LoadedFromBase64 || System.IO.File.Exists(fullCertPath); var certificateExists = signingKeys.LoadedFromBase64 || System.IO.File.Exists(fullCertPath);
var licenseConfigured =
!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("DUENDE_IDENTITYSERVER_LICENSE_KEY"))
|| !string.IsNullOrWhiteSpace(config["IdentityServer:LicenseKey"]);
return Ok(new return Ok(new
{ {
@@ -1505,10 +1501,6 @@ public class AdminController(
NotAfterUtc = signingKeys.Certificate.NotAfter.ToUniversalTime(), NotAfterUtc = signingKeys.Certificate.NotAfter.ToUniversalTime(),
Algorithm = SecurityAlgorithms.RsaSha256, Algorithm = SecurityAlgorithms.RsaSha256,
}, },
License = new
{
Configured = licenseConfigured,
},
PersistedGrants = new PersistedGrants = new
{ {
Store = "in-memory", Store = "in-memory",
@@ -6,7 +6,7 @@ using DorkNet.Server.Services;
namespace DorkNet.Server.Controllers.Auth; namespace DorkNet.Server.Controllers.Auth;
/// <summary> /// <summary>
/// auth.rec.net game-specific auth helpers. OAuth/OIDC endpoints are owned by Duende IdentityServer. /// auth.rec.net game-specific auth helpers. OAuth/OIDC endpoints are owned by IdentityServer.
/// </summary> /// </summary>
[ApiController] [ApiController]
public class AuthController( public class AuthController(
+11 -10
View File
@@ -1,21 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Duende.IdentityServer" Version="7.4.7" /> <PackageReference Include="Open.IdentityServer" Version="1.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.4" /> <PackageReference Include="MessagePack" Version="3.1.7" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.15" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.4"> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.9">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.4" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.9" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.2" />
<!-- RenderedCompactJsonFormatter for stdout JSON logs in production <!-- RenderedCompactJsonFormatter for stdout JSON logs in production
(Coolify-friendly). The host pipeline reads stdout line-by-line, (Coolify-friendly). The host pipeline reads stdout line-by-line,
and structured JSON lets a future Loki/Datadog ingest parse fields and structured JSON lets a future Loki/Datadog ingest parse fields
@@ -26,8 +27,8 @@
scale: SignalR group fanout, OrphanAccountTracker (sticky-session scale: SignalR group fanout, OrphanAccountTracker (sticky-session
account-creation flow), and PlayerPresenceService heartbeats all account-creation flow), and PlayerPresenceService heartbeats all
need shared state across replicas. --> need shared state across replicas. -->
<PackageReference Include="StackExchange.Redis" Version="2.8.16" /> <PackageReference Include="StackExchange.Redis" Version="2.13.17" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="9.0.4" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="10.0.9" />
<!-- S3-compatible object storage. Production target: Garage in <!-- S3-compatible object storage. Production target: Garage in
Coolify (one-click). Dev fallback: local MinIO for parity Coolify (one-click). Dev fallback: local MinIO for parity
testing. The SDK speaks plain S3, so swapping endpoints testing. The SDK speaks plain S3, so swapping endpoints
@@ -39,7 +40,7 @@
cost+salt in the output string so we only need one column. --> cost+salt in the output string so we only need one column. -->
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" /> <PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" /> <PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.3.1" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="10.2.3" />
<!-- Server-side crop/resize for img.* CDN transforms (?cropSquare=1&width=N <!-- Server-side crop/resize for img.* CDN transforms (?cropSquare=1&width=N
on profile thumbnails). The 2020 client treats this as part of the on profile thumbnails). The 2020 client treats this as part of the
image CDN contract — it uploads a full-frame capture and expects the image CDN contract — it uploads a full-frame capture and expects the
@@ -29,9 +29,6 @@ interface IdentityServerSettings {
notAfterUtc: string; notAfterUtc: string;
algorithm: string; algorithm: string;
}; };
license: {
configured: boolean;
};
persistedGrants: { persistedGrants: {
store: string; store: string;
warning: string; warning: string;
@@ -86,7 +83,6 @@ export function IdentityServer() {
</div> </div>
<div className="flex flex-wrap gap-2 text-xs"> <div className="flex flex-wrap gap-2 text-xs">
<StatusBadge ok={settings.signing.certificateExists} on="Signing key" off="Missing key" /> <StatusBadge ok={settings.signing.certificateExists} on="Signing key" off="Missing key" />
<StatusBadge ok={settings.license.configured} on="License set" off="No license key" />
</div> </div>
</div> </div>
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
+1 -1
View File
@@ -82,7 +82,7 @@ discovery and JWT validation agree on `https://auth.<domain>`.
dotnet run --project DorkNet.Server dotnet run --project DorkNet.Server
``` ```
First boot creates `bin/Debug/net9.0/data/dorknet.db`, runs every First boot creates `bin/Debug/net10.0/data/dorknet.db`, runs every
`LegacyUpgrades` pass, seeds canonical rooms / store catalog / club `LegacyUpgrades` pass, seeds canonical rooms / store catalog / club
categories / playlists, and starts listening. You should see categories / playlists, and starts listening. You should see
`Application started.` in the log; `curl http://localhost:8080/healthz` `Application started.` in the log; `curl http://localhost:8080/healthz`
@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
+2 -2
View File
@@ -51,8 +51,8 @@ static Assembly LoadServerAssembly(string[] args)
var repositoryRoot = FindRepositoryRoot(); var repositoryRoot = FindRepositoryRoot();
var candidates = new[] var candidates = new[]
{ {
Path.Combine(repositoryRoot, "DorkNet.Server", "bin", "Debug", "net9.0", "DorkNet.Server.dll"), Path.Combine(repositoryRoot, "DorkNet.Server", "bin", "Debug", "net10.0", "DorkNet.Server.dll"),
Path.Combine(repositoryRoot, "DorkNet.Server", "bin", "Release", "net9.0", "DorkNet.Server.dll") Path.Combine(repositoryRoot, "DorkNet.Server", "bin", "Release", "net10.0", "DorkNet.Server.dll")
}; };
var existingCandidates = candidates.Where(File.Exists).ToArray(); var existingCandidates = candidates.Where(File.Exists).ToArray();
@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
+2 -2
View File
@@ -333,8 +333,8 @@ static Assembly LoadServerAssembly(string? configuredPath)
var repositoryRoot = FindRepositoryRoot(); var repositoryRoot = FindRepositoryRoot();
var candidates = new[] var candidates = new[]
{ {
Path.Combine(repositoryRoot, "DorkNet.Server", "bin", "Debug", "net9.0", "DorkNet.Server.dll"), Path.Combine(repositoryRoot, "DorkNet.Server", "bin", "Debug", "net10.0", "DorkNet.Server.dll"),
Path.Combine(repositoryRoot, "DorkNet.Server", "bin", "Release", "net9.0", "DorkNet.Server.dll") Path.Combine(repositoryRoot, "DorkNet.Server", "bin", "Release", "net10.0", "DorkNet.Server.dll")
}; };
var existingCandidates = candidates.Where(File.Exists).ToArray(); var existingCandidates = candidates.Where(File.Exists).ToArray();
if (existingCandidates.Length == 0) if (existingCandidates.Length == 0)