Narrow ISmtpClient to the four operations MailSender actually uses,
behind a Yavsc.Interfaces.ISmtpClientFactory. Production wires
MailKitSmtpClient (SmtpClientFactory); tests wire a recording fake
(RecordingSmtpClientFactory). The fake is pre-registered in
WebServerFixture so SMTP calls are short-circuited; the EMailling
test now asserts the Connect -> Authenticate -> Send -> Disconnect
sequence. Yavsc.Abstract stays free of MailKit/MimeKit.
Move product-local package versions out of the root Directory.Packages.props
into per-product props files under src/<Product>/. The root file now only
contains versions for packages declared by two or more top-level products,
which is the actual shared set.
Each per-product Directory.Packages.props imports the root via
GetPathOfFileAbove so that the shared versions are inherited; this is
necessary because the .NET SDK picks the closest Directory.Packages.props
in the hierarchy and does not merge multiple ones.
Per-product file contents:
- src/cli/ Microsoft.AspNetCore.Razor.Language,
Microsoft.Extensions.{CommandLineUtils,Configuration,Hosting}
- src/PostIt/ Avalonia* and CommunityToolkit.Mvvm
- src/PostIt.Tests/ Avalonia.Headless{,XUnit}
- src/Yavsc.Org/ AsciiDocSharp*, Google.Apis.Compute.v1,
HigginsSoft.IdentityServer8.AspNetIdentity,
IdentityServer8.EntityFramework.Storage,
IdentityServer8.Security, IdentityServer8.Storage,
Microsoft.AspNetCore.Antiforgery, Authentication.Google,
Diagnostics.EntityFrameworkCore, Mvc.NewtonsoftJson,
SignalR, EntityFrameworkCore.Tools, Swashbuckle,
System.Security.Cryptography.Pkcs, YamlDotNet
- src/Yavsc.Org.Tests/ Microsoft.AspNetCore.Hosting,
Extensions.Caching.Memory, Options,
Options.ConfigurationExtensions,
Selenium.WebDriver, xunit.v3.{common,extensibility.core}
- src/Yavsc.Server/ Anthropic.SDK, Google.Apis.Calendar.v3,
Magick.NET-Q8-AnyCPU, MailKit, MimeKit,
Microsoft.AspNetCore.Http.Features, StaticFiles,
EntityFrameworkCore.SqlServer,
Npgsql.EntityFrameworkCore.PostgreSQL,
PayPalMerchantSDK, pazof.rules, RazorEngine.NetCore
- src/Yavsc.Web/ IdentityModel.AspNetCore
No per-product file is created for Yavsc.Api, Yavsc.Blogs, Yavsc.Abstract,
or templateWeb: Api and Blogs only declare the shared JwtBearer, Abstract
and templateWeb declare no package references at all.
Also includes a minor cosmetic update to FirstUIStript.cs (Firefox -> Chrome
driver, dedent, comment header). Tests previously failing on DataProtection
keyset / SMTP were unrelated environment issues (resolved by fixing the
SMTP password locally).
The Site:Audience setting was conflating two distinct concepts: an OAuth
JWT audience (a single resource identifier) and a CORS allow-list (an
array of origins). Collapsing them caused several latent bugs:
- OAuth/JWT validation expected a single string while CORS WithOrigins
accepts an array.
- Password-reset callback URLs and OAuth client RedirectUri/Origin were
being built from what was meant to be an audience identifier, not a
base URL.
- Yavsc.Org's main CORS policy was hardcoded to '*', with no way to
restrict it without code changes.
Changes:
- SiteSettings.Audience (string) replaced with CorsAllowedOrigins
(IList<string>).
- OAuth JWT Authority still reads Site:Authority; Audience now reads
Site:ExternalUrl (Org only; Api/Blogs use ValidateAudience=false).
- MailSender and AccountController build reset-callback URLs from
Site:ExternalUrl.
- ClientController uses Site:ExternalUrl for OAuth RedirectUri/Origin
defaults on newly created clients.
- Yavsc.Api and Yavsc.Blogs now read CORS origins from
Site:CorsAllowedOrigins instead of hardcoded URLs.
Add shared AddYavscCors / AddYavscJwtBearer extension methods in
Yavsc.Server/Helpers/ServiceExtensions.cs to enforce a single
configuration contract across all runtime services (Api, Blogs, Org).
Fails closed when CorsAllowedOrigins is empty; fails fast at startup
when Site:Authority is missing.
Remove obsolete ConfigurationHelpers.GetAudience (no remaining callers).
Local appsettings-*.json files (which carry deployment-specific values
and are gitignored) must be updated to add Site:CorsAllowedOrigins.
- Add in-memory database support for test isolation in WebServerFixture
- Implement TestMailSender fake SMTP provider for email test support
- Add thread synchronization to billing service registration to prevent race conditions
- Make RegisterBilling<T> idempotent to safely handle reconfiguration
- Configure test environment via in-memory settings (UseTestEmailSender, UseInMemoryDatabase)
- Add regression tests for billing module idempotency and duplicate registration detection
- Fix tests: EMaillingTests.SendEMailSynchrone, BillingServiceTests (2 tests), HaveConfigurationRoot (3 tests)
All core test infrastructure tests now passing.