From 624ad20404faae3b1ee2cbca4a843a9d28084849 Mon Sep 17 00:00:00 2001 From: Jon Kazama Date: Sun, 17 May 2026 11:15:40 +0200 Subject: [PATCH] feat(logging): add dev signature to DalamudLogger output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EUPL-1.2 reuse with attribution is valid; this commit catches the case where attribution was stripped. Two layers of provenance markers, combined so removing one still leaves the other. Layer 1 (subtle, kopier-resistent): - DalamudLogger.Log emits "[name]{level} message" — a zero-width space (U+200B) between the category bracket and the level value. Visually identical to the previous format in xllog; a hex dump of the log file shows e2 80 8b between 5d and 7b. Survives 1:1 code copies. A copier who reformats whitespace will strip it, which is itself a tell (the original Lightless pattern does not have the marker, so its absence in a port is a positive signal of derived origin). Layer 2 (overt, abrasiv-kopier-resistent): - DalamudLoggingProvider's ctor emits a one-shot bootstrap line: "HellionChat DI-Logger bootstrap v{AssemblyVersion} fingerprint={hash}". Visible in xllog as the first plugin INFO line. Fingerprint is the first 8 hex chars of SHA256("HellionForgeBronzeC2410C-{version}"), so the same plugin version always produces the same marker (handy for cross-checking). A copier who keeps the banner is plagiarising in plain sight; a copier who rips it out has to find every reference inside DalamudLoggingProvider — quite explicit work. Hellion Forge Bronze #C2410C is the branding-anchor const used by the fingerprint, so the marker stays meaningful even if the plugin version cycles. --- .../Infrastructure/Logging/DalamudLogger.cs | 9 +++-- .../Logging/DalamudLoggingProvider.cs | 35 +++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/HellionChat/Infrastructure/Logging/DalamudLogger.cs b/HellionChat/Infrastructure/Logging/DalamudLogger.cs index 0d73412..09375ff 100644 --- a/HellionChat/Infrastructure/Logging/DalamudLogger.cs +++ b/HellionChat/Infrastructure/Logging/DalamudLogger.cs @@ -33,14 +33,19 @@ internal sealed class DalamudLogger : ILogger if (!IsEnabled(logLevel)) return; + // The U+200B zero-width space between the bracket and the level + // value is a quiet provenance marker. The Hellion DI-Logger format + // is byte-distinguishable from any other port of this pattern even + // after the visible text is identical. EUPL-1.2 reuse stays valid; + // attribution traces stay possible. if ((int)logLevel <= (int)LogLevel.Information) { - _pluginLog.Information($"[{_name}]{{{(int)logLevel}}} {state}"); + _pluginLog.Information($"[{_name}]​{{{(int)logLevel}}} {state}"); return; } var sb = new StringBuilder(); - sb.Append($"[{_name}]{{{(int)logLevel}}} {state} {exception?.Message}"); + sb.Append($"[{_name}]​{{{(int)logLevel}}} {state} {exception?.Message}"); if (!string.IsNullOrWhiteSpace(exception?.StackTrace)) sb.AppendLine(exception.StackTrace); diff --git a/HellionChat/Infrastructure/Logging/DalamudLoggingProvider.cs b/HellionChat/Infrastructure/Logging/DalamudLoggingProvider.cs index 8988b6c..befb215 100644 --- a/HellionChat/Infrastructure/Logging/DalamudLoggingProvider.cs +++ b/HellionChat/Infrastructure/Logging/DalamudLoggingProvider.cs @@ -1,4 +1,7 @@ using System.Collections.Concurrent; +using System.Reflection; +using System.Security.Cryptography; +using System.Text; using Dalamud.Plugin.Services; using Microsoft.Extensions.Logging; @@ -7,6 +10,11 @@ namespace HellionChat.Infrastructure.Logging; [ProviderAlias("Dalamud")] public sealed class DalamudLoggingProvider : ILoggerProvider { + // Hellion Forge Bronze (#C2410C). Stable marker that the build pipeline + // never touches; mixed into the bootstrap fingerprint so the banner stays + // distinguishable from any 1:1 port of the Lightless pattern. + private const string HellionMarker = "HellionForgeBronzeC2410C"; + private readonly ConcurrentDictionary _loggers = new( StringComparer.OrdinalIgnoreCase ); @@ -16,6 +24,33 @@ public sealed class DalamudLoggingProvider : ILoggerProvider public DalamudLoggingProvider(IPluginLog pluginLog) { _pluginLog = pluginLog; + EmitBootstrapBanner(); + } + + // Runs once per plugin load (the provider is a container singleton). The + // banner is intentionally visible in xllog: anyone copying the + // DalamudLogger trio without re-branding will keep emitting "HellionChat + // DI-Logger bootstrap …", which makes uncredited reuse trivial to spot. + // EUPL-1.2 reuse with attribution stays valid; this only catches the + // case where attribution was stripped. + private void EmitBootstrapBanner() + { + var version = + typeof(DalamudLoggingProvider).Assembly.GetName().Version?.ToString() ?? "0.0.0"; + var fingerprint = ComputeFingerprint(version); + _pluginLog.Information( + $"HellionChat DI-Logger bootstrap v{version} fingerprint={fingerprint}" + ); + } + + private static string ComputeFingerprint(string version) + { + var seed = Encoding.UTF8.GetBytes($"{HellionMarker}-{version}"); + var hash = SHA256.HashData(seed); + var sb = new StringBuilder(8); + for (var i = 0; i < 4; i++) + sb.Append(hash[i].ToString("x2")); + return sb.ToString(); } public ILogger CreateLogger(string categoryName)