From 82744aa6340ff42919e79978f33484ebe9286ff9 Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Mon, 29 Jun 2026 14:41:22 +1000 Subject: [PATCH 01/17] docs: design spec for consolidating Abstractions + Common into Essentials --- ...6-06-29-essentials-consolidation-design.md | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 docs/superpowers/specs/2026-06-29-essentials-consolidation-design.md diff --git a/docs/superpowers/specs/2026-06-29-essentials-consolidation-design.md b/docs/superpowers/specs/2026-06-29-essentials-consolidation-design.md new file mode 100644 index 0000000..567a21d --- /dev/null +++ b/docs/superpowers/specs/2026-06-29-essentials-consolidation-design.md @@ -0,0 +1,123 @@ +# Consolidating `Abstractions` + `Common` into `Essentials` + +**Date:** 2026-06-29 +**Status:** Approved design — ready for implementation planning +**Repos affected:** `ktsu-dev/Essentials` (canonical), `ktsu-dev/Abstractions` (retire), `ktsu-dev/Common` (retire) + +## Background + +Three repos in the ktsu ecosystem cover the same ground: + +- **`ktsu.Abstractions`** (v1.4.x) — the provider *interfaces* (`IHashProvider`, `ICompressionProvider`, …) plus ~34 bundled reference provider-implementation packages (`ktsu..`). +- **`ktsu.Common`** (v1.1.x) — ~36 additional provider-implementation packages that depend on `ktsu.Abstractions`. Has **no core package** of its own. +- **`ktsu.Essentials`** (v1.1.x) — a clone of the `Abstractions` repo (shared initial git history, same Aug 2025 seed commit). In Feb 2026 it absorbed Common's providers (`merge-common-providers` PR) and was renamed to `Essentials`, with the intent of becoming a single batteries-included package family (interfaces + implementations under `ktsu.Essentials.*`). + +The Feb 2026 consolidation stalled: `Essentials` was published but never adopted (**0 in-tree dependents**), while `Abstractions` + `Common` kept all real development and the entire ecosystem's references (the only in-tree consumer of either is `Ecosystem`, which is itself abandoned). A cross-repo "Sync" bot kept re-applying identical maintenance commits to all repos, leaving `Abstractions` and `Essentials` near-identical twins. The only real code differences today: `Essentials` uses `ktsu.Essentials.*` namespaces and has a polished README; `Abstractions` retains two extra interfaces (`IConfigurationProvider`, `IObfuscationProvider`) that `Essentials` dropped. + +The shared interface files are byte-identical modulo line endings and the namespace token — verified by normalized diff across all 17 common interface/helper files. + +## Goal + +Finish the original consolidation: make `ktsu.Essentials` the single canonical provider family — a faithful superset of `Abstractions` + `Common` — and retire the other two repos without losing capability for external consumers. + +## Non-goals + +- Migrating `Ecosystem` — it is abandoned and stays on the old packages. +- Source-compat shims for the ~70 leaf provider-implementation packages (interface-level compat only; see Retirement). +- Any change to the 17 already-identical interface/helper contracts beyond adding `IObfuscationProvider`. + +## Design + +### 1. Packaging — tiered (granular + meta) + +Keep the existing model and add a convenience meta-package: + +- `ktsu.Essentials` — core interfaces and helpers (unchanged). +- `ktsu.Essentials..` — one NuGet package per provider implementation (unchanged model). +- **New:** `ktsu.Essentials.All` — a meta-package with `PackageReference`s to every provider-implementation package, so consumers who want everything get one install while others continue to cherry-pick. + +### 2. Reconciled taxonomy — compose, don't duplicate + +Primitive categories remain first-class. Higher-level concepts are expressed as compositions of primitives rather than parallel duplicate categories. + +#### Serialization (format primitive: object ↔ text) +- Keep: `Json` (System.Text.Json), `Yaml`, `Toml`. +- **Add:** port Common's `NewtonsoftJson` as an alternative JSON serializer → `ktsu.Essentials.SerializationProviders.NewtonsoftJson`. `Json` (System.Text.Json) remains the default/canonical JSON serializer; both implement `ISerializationProvider`. + +#### Persistence (storage primitive — already composes a serializer) +- Keep: `FileSystem`, `AppData`, `Temp`, `InMemory`. +- `IPersistenceProvider` stores/retrieves *typed* objects; e.g. `FileSystem` is constructed with an `ISerializationProvider` + `IFileSystemProvider` and serializes on store / deserializes on retrieve. This is the "serialization + storage" aggregate. + +#### Configuration — dropped, not ported +- `IConfigurationProvider` (Abstractions) is a text serialize/deserialize contract with no storage — a worse-named subset of `ISerializationProvider`. +- "Configuration" = `IPersistenceProvider` over a serializer + a store. The JSON/YAML/TOML "config formats" are already serialization providers. +- **Action:** do **not** introduce `IConfigurationProvider` or `ConfigurationProviders/*` into `Essentials`. Common's `ConfigurationProviders/{Json,Toml,Yaml}` are not ported (their formats already exist as serialization providers). + +#### Obfuscation — kept as a distinct intent, implemented by composition +- Keep `IObfuscationProvider` as a distinct, intent-revealing interface (obfuscation is explicitly *not* encryption). Port the interface from `Abstractions` into the `ktsu.Essentials` namespace verbatim (it already uses the shared `ProviderHelpers` patterns). +- Implementations are thin compositions over `IEncodingProvider` and simple reversible byte transforms — not copies of the Base64/Hex encoder code. + +**Obfuscator implementations** (`ktsu.Essentials.ObfuscationProviders.`): + +| Impl | Behavior | Reversibility | +|---|---|---| +| `Base64` | Wraps the Base64 `IEncodingProvider`. | encoding is reversible | +| `Hex` | Wraps the Hex `IEncodingProvider`. | encoding is reversible | +| `Xor` | XOR each byte with a repeating key (configurable key bytes). | self-inverse with same key | +| `Caesar` | Add a configurable shift to each byte (mod 256). | deobfuscate subtracts the shift | +| `Reverse` | Reverse the byte sequence. | self-inverse | +| `BitRotate` | Rotate the bits of each byte by a configurable amount. | deobfuscate rotates the other way | +| `Composite` | Pipelines an ordered list of `IObfuscationProvider`s (e.g. `Xor` → `Base64`); deobfuscation applies them in reverse order. | composed of reversible steps | + +All implement the core `TryObfuscate`/`TryDeobfuscate` (Span + Stream) methods; convenience and async members come from the interface's default implementations. + +### 3. Retirement of `Abstractions` + `Common` + +Compatibility at the interface level, clean-break deprecation for leaf implementation packages. + +**`ktsu.Abstractions` core (interfaces):** publish a final release where every interface is `[Obsolete("Moved to ktsu.Essentials. This package is deprecated.")]` and **inherits** its `ktsu.Essentials` counterpart, e.g.: + +```csharp +namespace ktsu.Abstractions; + +[Obsolete("Moved to ktsu.Essentials. This package is deprecated.")] +public interface IHashProvider : ktsu.Essentials.IHashProvider { } +``` + +Existing external implementers (`class MyHasher : ktsu.Abstractions.IHashProvider`) keep compiling, and their instances are usable wherever a `ktsu.Essentials.IHashProvider` is expected (inheritance), giving a non-breaking migration path. Generic interfaces (`IPersistenceProvider`, `ICacheProvider`, `IValidationProvider`, `INavigationProvider`) shim the same way with their type parameters forwarded. + +- **Exception — `IConfigurationProvider`:** no Essentials counterpart exists. Mark it `[Obsolete("Configuration is now persistence over a serializer; use ktsu.Essentials.IPersistenceProvider.")]` with no base interface. +- **Exception — `IObfuscationProvider`:** shim it to inherit `ktsu.Essentials.IObfuscationProvider` like the others. + +**Provider-implementation packages (~70 total: Abstractions-bundled `ktsu..*` + all `ktsu.Common.*`):** no code shims. Mark each **Deprecated on NuGet** with a message naming its `ktsu.Essentials..` replacement. Retargeting is a one-line `PackageReference` + `using` change for consumers. + +**Repos:** after the final deprecation release of each, archive `Abstractions` and `Common` on GitHub, and **remove both from the cross-repo Sync bot** configuration so they stop generating twin maintenance commits. `Essentials` remains on the Sync bot. + +### 4. Tests + +- Add a `ObfuscationProviderTests` suite covering round-trip (obfuscate → deobfuscate → original) for every obfuscator, including `Composite` ordering, across Span, Stream, string, and async paths. +- Add `NewtonsoftJson` coverage to the existing serialization tests. +- Do not port `ConfigurationProviderTests` (Configuration is dropped). +- Keep the rest of the existing `Essentials.Tests` suite as-is. + +### 5. Documentation + +Refresh `Essentials` docs via the `update-docs` skill: +- `README.md`, `CLAUDE.md`, `DESCRIPTION.md`, `TAGS.md` — document the composition model (Configuration = Persistence + Serialization; Obfuscation composes Encoding), the new obfuscators and `NewtonsoftJson` serializer, the `ktsu.Essentials.All` meta-package, and that `Essentials` supersedes `Abstractions` + `Common`. + +## Work breakdown (high level) + +1. Port `IObfuscationProvider` into `ktsu.Essentials`. +2. Implement the seven obfuscator packages + tests. +3. Port the `NewtonsoftJson` serializer package + tests. +4. Add the `ktsu.Essentials.All` meta-package. +5. Refresh Essentials docs. +6. `Abstractions`: convert core interfaces to `[Obsolete]` inheriting shims (with the two noted exceptions); final release; NuGet-deprecate the bundled provider packages. +7. `Common`: NuGet-deprecate all provider packages (no core to shim). +8. Remove `Abstractions` + `Common` from the cross-repo Sync bot; archive both repos. + +(The detailed, sequenced implementation plan is produced by the writing-plans step.) + +## Open questions + +None outstanding — all design decisions resolved during brainstorming. From a493872555d6246a2f386ddb3550cfae39f19c03 Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Mon, 29 Jun 2026 14:49:19 +1000 Subject: [PATCH 02/17] docs: implementation plan for Essentials consolidation (Phase 1) --- .../2026-06-29-essentials-consolidation.md | 1450 +++++++++++++++++ 1 file changed, 1450 insertions(+) create mode 100644 docs/superpowers/plans/2026-06-29-essentials-consolidation.md diff --git a/docs/superpowers/plans/2026-06-29-essentials-consolidation.md b/docs/superpowers/plans/2026-06-29-essentials-consolidation.md new file mode 100644 index 0000000..bfee400 --- /dev/null +++ b/docs/superpowers/plans/2026-06-29-essentials-consolidation.md @@ -0,0 +1,1450 @@ +# Essentials Consolidation Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Make `ktsu.Essentials` a faithful superset of `ktsu.Abstractions` + `ktsu.Common` by adding obfuscation providers, the `NewtonsoftJson` serializer, and a `ktsu.Essentials.All` meta-package, so the other two repos can be retired. + +**Architecture:** `ktsu.Essentials` is a core interfaces package plus one NuGet package per provider implementation. New providers are added as sibling projects under category folders, registered for DI in the test `ServiceCollectionExtensions`, and exercised by `[DynamicData]`-driven contract tests that enumerate every registered provider of an interface. Obfuscation is a distinct intent-revealing concept implemented by composing `IEncodingProvider` and simple reversible byte transforms (compose, don't duplicate). + +**Tech Stack:** C# (multi-target `net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1`), `ktsu.Sdk` 2.13.0, MSTest.Sdk, Microsoft.Extensions.DependencyInjection, Polyfill, Newtonsoft.Json 13.0.4. + +## Global Constraints + +- Indentation: **tabs** in C# files. Line endings: **CRLF**. +- File-scoped namespaces; `using` directives **inside** the namespace where existing files do so (provider impl files put framework usings after the namespace — match the neighbouring file exactly). +- Every `.cs` file starts with the 3-line header: + ``` + // Copyright (c) ktsu.dev + // All rights reserved. + // Licensed under the MIT license. + ``` +- Nullable reference types enabled; treat warnings as errors. No global suppressions — use targeted `[SuppressMessage]` with justification only if unavoidable. +- Interfaces live in namespace `ktsu.Essentials`. Provider implementations live in `ktsu.Essentials.` and their packages are `ktsu.Essentials..` (set via `AssemblyName`; `RootNamespace` is `ktsu.Essentials.`). +- Implementers provide ONLY the core `Try*` methods (Span + Stream variants); all convenience/async members come from default interface implementations. +- Provider classes are `public` and **not** `sealed` (they must remain inheritable for the Phase 2 compat shims). +- Each provider project references `..\..\Essentials\Essentials.csproj` and `Polyfill` (`PrivateAssets="All"`), and has ``. +- New projects must be added to `Essentials.slnx` and referenced from `Essentials.Tests/Essentials.Tests.csproj`. +- Build/test commands run from the repo root `C:\dev\ktsu-dev\Essentials`. Tests target `net10.0` only. +- Work happens on branch `consolidate-into-essentials` (already created). + +--- + +## File Structure + +New files (Phase 1): + +- `Essentials/Essentials/IObfuscationProvider.cs` — obfuscation interface (ported from Abstractions, re-namespaced). +- `Essentials/ObfuscationProviders/Xor/{Xor.csproj,Xor.cs}` — repeating-key XOR (self-inverse). +- `Essentials/ObfuscationProviders/Caesar/{Caesar.csproj,Caesar.cs}` — per-byte additive shift. +- `Essentials/ObfuscationProviders/Reverse/{Reverse.csproj,Reverse.cs}` — byte-order reversal (self-inverse). +- `Essentials/ObfuscationProviders/BitRotate/{BitRotate.csproj,BitRotate.cs}` — per-byte bit rotation. +- `Essentials/ObfuscationProviders/Base64/{Base64.csproj,Base64.cs}` — wraps the Base64 `IEncodingProvider`. +- `Essentials/ObfuscationProviders/Hex/{Hex.csproj,Hex.cs}` — wraps the Hex `IEncodingProvider`. +- `Essentials/ObfuscationProviders/Composite/{Composite.csproj,Composite.cs}` — pipelines an ordered list of obfuscators. +- `Essentials/SerializationProviders/NewtonsoftJson/{NewtonsoftJson.csproj,NewtonsoftJson.cs}` — Newtonsoft.Json serializer. +- `Essentials/All/All.csproj` — `ktsu.Essentials.All` meta-package (no code). +- `Essentials/Essentials.Tests/ObfuscationProviderTests.cs` — DynamicData contract tests for all obfuscators. + +Modified files: + +- `Essentials/Essentials.Tests/ServiceCollectionExtensions.cs` — add `AddObfuscationProviders`, register `NewtonsoftJson`. +- `Essentials/Essentials.Tests/Essentials.Tests.csproj` — add `ProjectReference`s to the 8 new provider projects. +- `Essentials/Directory.Packages.props` — add `Newtonsoft.Json` version pin. +- `Essentials/README.md`, `CLAUDE.md`, `DESCRIPTION.md`, `TAGS.md` — doc refresh (Task 11). + +--- + +## Task 1: Port `IObfuscationProvider` into Essentials core + +**Files:** +- Create: `Essentials/Essentials/IObfuscationProvider.cs` + +**Interfaces:** +- Produces: `ktsu.Essentials.IObfuscationProvider` with core members an implementer must provide: + - `bool TryObfuscate(ReadOnlySpan data, Span destination)` + - `bool TryObfuscate(Stream data, Stream destination)` + - `bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Span destination)` + - `bool TryDeobfuscate(Stream obfuscatedData, Stream destination)` + - Plus default-implemented convenience/async members (`Obfuscate`/`Deobfuscate`/`*Async`) identical to the Abstractions version. + +- [ ] **Step 1: Copy the interface and re-namespace it** + +Copy `C:\dev\ktsu-dev\Abstractions\Abstractions\IObfuscationProvider.cs` to `Essentials/Essentials/IObfuscationProvider.cs`, changing **only** line 5 from `namespace ktsu.Abstractions;` to `namespace ktsu.Essentials;`. Everything else (the full member set, which already uses `ProviderHelpers.SpanToStreamBridge`, `ProviderHelpers.ExecuteToByteArray`, `ProviderHelpers.Utf8Transform`, `ProviderHelpers.RunAsync`) is unchanged — those helpers already exist in `Essentials/Essentials/ProviderHelpers.cs`. + +- [ ] **Step 2: Build the core project to verify it compiles** + +Run: `dotnet build Essentials/Essentials/Essentials.csproj` +Expected: Build succeeded, 0 errors. + +- [ ] **Step 3: Commit** + +```bash +git add Essentials/Essentials/IObfuscationProvider.cs +git commit -m "feat: add IObfuscationProvider interface to Essentials core" +``` + +--- + +## Task 2: `Xor` obfuscator + obfuscation test harness + DI wiring + +This task establishes the obfuscator project pattern, the DI registration method, and the shared `[DynamicData]` round-trip test harness, using the simplest transform. + +**Files:** +- Create: `Essentials/ObfuscationProviders/Xor/Xor.csproj` +- Create: `Essentials/ObfuscationProviders/Xor/Xor.cs` +- Create: `Essentials/Essentials.Tests/ObfuscationProviderTests.cs` +- Modify: `Essentials/Essentials.Tests/ServiceCollectionExtensions.cs` +- Modify: `Essentials/Essentials.Tests/Essentials.Tests.csproj` + +**Interfaces:** +- Consumes: `ktsu.Essentials.IObfuscationProvider` (Task 1). +- Produces: `ktsu.Essentials.ObfuscationProviders.Xor` with a parameterless constructor (default key) and `Xor(byte[] key)`; `ServiceCollectionExtensions.AddObfuscationProviders(this ServiceCollection)`. + +- [ ] **Step 1: Write the failing test (shared obfuscation harness)** + +Create `Essentials/Essentials.Tests/ObfuscationProviderTests.cs`: + +```csharp +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.Tests; + +using System.Collections.Generic; +using System.Text; +using ktsu.Essentials; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +public class ObfuscationProviderTests +{ + private static ServiceProvider BuildProvider() + { + ServiceCollection services = new(); + services.AddObfuscationProviders(); + return services.BuildServiceProvider(); + } + + public static IEnumerable ObfuscationProviders => BuildProvider().EnumerateProviders(); + + public TestContext TestContext { get; set; } = null!; + + [TestMethod] + [DynamicData(nameof(ObfuscationProviders))] + public void Obfuscation_Roundtrip_Bytes(IObfuscationProvider provider, string providerName) + { + byte[] original = Encoding.UTF8.GetBytes("obfuscate me with " + providerName); + + byte[] obfuscated = provider.Obfuscate(original); + byte[] restored = provider.Deobfuscate(obfuscated); + + CollectionAssert.AreEqual(original, restored, $"{providerName} should restore original bytes"); + } + + [TestMethod] + [DynamicData(nameof(ObfuscationProviders))] + public void Obfuscation_Roundtrip_Stream(IObfuscationProvider provider, string providerName) + { + byte[] original = Encoding.UTF8.GetBytes("stream obfuscate with " + providerName); + + using MemoryStream input = new(original); + using MemoryStream obfuscated = new(); + Assert.IsTrue(provider.TryObfuscate(input, obfuscated), $"{providerName} should obfuscate stream"); + + obfuscated.Position = 0; + using MemoryStream restored = new(); + Assert.IsTrue(provider.TryDeobfuscate(obfuscated, restored), $"{providerName} should deobfuscate stream"); + + CollectionAssert.AreEqual(original, restored.ToArray(), $"{providerName} should restore original from stream"); + } + + [TestMethod] + [DynamicData(nameof(ObfuscationProviders))] + public void Obfuscation_Roundtrip_String(IObfuscationProvider provider, string providerName) + { + string original = "string obfuscate with " + providerName; + + string obfuscated = provider.Obfuscate(original); + byte[] obfuscatedBytes = Encoding.UTF8.GetBytes(obfuscated); + byte[] restoredBytes = provider.Deobfuscate(obfuscatedBytes); + string restored = Encoding.UTF8.GetString(restoredBytes); + + Assert.AreEqual(original, restored, $"{providerName} should restore original string"); + } + + [TestMethod] + [DynamicData(nameof(ObfuscationProviders))] + public void Obfuscation_Async_Roundtrip(IObfuscationProvider provider, string providerName) + { + byte[] original = Encoding.UTF8.GetBytes("async obfuscate with " + providerName); + + using MemoryStream input = new(original); + using MemoryStream obfuscated = new(); + Assert.IsTrue(provider.TryObfuscateAsync(input, obfuscated, TestContext.CancellationToken).Result, $"{providerName} async obfuscate"); + + obfuscated.Position = 0; + using MemoryStream restored = new(); + Assert.IsTrue(provider.TryDeobfuscateAsync(obfuscated, restored, TestContext.CancellationToken).Result, $"{providerName} async deobfuscate"); + + CollectionAssert.AreEqual(original, restored.ToArray(), $"{providerName} async should restore original"); + } +} +``` + +> Note: `Obfuscation_Roundtrip_String` relies on the obfuscated bytes being valid UTF-8. For `Xor`/`Caesar`/`BitRotate` the obfuscated bytes may not be valid UTF-8; the string convenience method uses `ProviderHelpers.Utf8Transform`, which round-trips through UTF-8 string⇄bytes. Because `Obfuscate(string)` returns a UTF-8 string built from the obfuscated bytes and `Deobfuscate` reverses it, the assertion holds for length-preserving transforms. If a specific transform fails this assertion in practice, keep the byte/stream/async tests and move the string assertion into a per-transform test for the encoding-based providers only — but attempt the shared version first. + +- [ ] **Step 2: Add the `AddObfuscationProviders` registration** + +In `Essentials/Essentials.Tests/ServiceCollectionExtensions.cs`, add `using ktsu.Essentials.ObfuscationProviders;` to the using block, add the call inside `AddCommon` (after `AddNavigationProviders();`), and add the new method: + +```csharp + public static ServiceCollection AddObfuscationProviders(this ServiceCollection services) + { + services.AddSingleton(); + return services; + } +``` + +And inside `AddCommon`, add the line: + +```csharp + services.AddObfuscationProviders(); +``` + +- [ ] **Step 3: Create the Xor project file** + +Create `Essentials/ObfuscationProviders/Xor/Xor.csproj`: + +```xml + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + ktsu.Essentials.ObfuscationProviders.Xor + ktsu.Essentials.ObfuscationProviders + + + + + + + + + + + + +``` + +- [ ] **Step 4: Implement `Xor`** + +Create `Essentials/ObfuscationProviders/Xor/Xor.cs`: + +```csharp +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.ObfuscationProviders; + +using ktsu.Essentials; +using System; +using System.IO; + +/// +/// An obfuscation provider that XORs each byte with a repeating key. Self-inverse: obfuscation and +/// deobfuscation are the same transform. This is NOT encryption and provides no confidentiality. +/// +public class Xor : IObfuscationProvider +{ + private readonly byte[] _key; + + /// Initializes a new instance with the default single-byte key. + public Xor() : this([0x5A]) { } + + /// Initializes a new instance with the specified repeating key. + /// The non-empty key bytes to XOR against. + public Xor(byte[] key) + { + Ensure.NotNull(key); + if (key.Length == 0) + { + throw new ArgumentException("Key must contain at least one byte.", nameof(key)); + } + + _key = key; + } + + /// + public bool TryObfuscate(ReadOnlySpan data, Span destination) + { + if (destination.Length < data.Length) + { + return false; + } + + for (int i = 0; i < data.Length; i++) + { + destination[i] = (byte)(data[i] ^ _key[i % _key.Length]); + } + + destination[data.Length..].Clear(); + return true; + } + + /// + public bool TryObfuscate(Stream data, Stream destination) + { + if (data is null || destination is null) + { + return false; + } + + int b; + long i = 0; + while ((b = data.ReadByte()) >= 0) + { + destination.WriteByte((byte)(b ^ _key[(int)(i % _key.Length)])); + i++; + } + + return true; + } + + /// + public bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Span destination) + => TryObfuscate(obfuscatedData, destination); + + /// + public bool TryDeobfuscate(Stream obfuscatedData, Stream destination) + => TryObfuscate(obfuscatedData, destination); +} +``` + +- [ ] **Step 5: Wire the project into the solution and test project** + +Add a `ProjectReference` to `Essentials/Essentials.Tests/Essentials.Tests.csproj` (inside the second `` with the other provider refs): + +```xml + +``` + +Add to the solution: + +```bash +dotnet sln Essentials.slnx add Essentials/ObfuscationProviders/Xor/Xor.csproj +``` + +- [ ] **Step 6: Run the obfuscation tests to verify they pass** + +Run: `dotnet test --filter "FullyQualifiedName~ObfuscationProviderTests"` +Expected: PASS — 4 tests (one per DynamicData row for the single `Xor` provider). + +- [ ] **Step 7: Commit** + +```bash +git add Essentials/ObfuscationProviders/Xor Essentials/Essentials.Tests/ObfuscationProviderTests.cs Essentials/Essentials.Tests/ServiceCollectionExtensions.cs Essentials/Essentials.Tests/Essentials.Tests.csproj Essentials.slnx +git commit -m "feat: add Xor obfuscation provider and obfuscation test harness" +``` + +--- + +## Task 3: `Caesar` obfuscator + +**Files:** +- Create: `Essentials/ObfuscationProviders/Caesar/Caesar.csproj` +- Create: `Essentials/ObfuscationProviders/Caesar/Caesar.cs` +- Modify: `Essentials/Essentials.Tests/ServiceCollectionExtensions.cs` +- Modify: `Essentials/Essentials.Tests/Essentials.Tests.csproj` + +**Interfaces:** +- Produces: `ktsu.Essentials.ObfuscationProviders.Caesar` with `Caesar()` (default shift 13) and `Caesar(byte shift)`. + +- [ ] **Step 1: Register the provider (extend the failing harness)** + +In `ServiceCollectionExtensions.cs`, add to `AddObfuscationProviders`: + +```csharp + services.AddSingleton(); +``` + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `dotnet test --filter "FullyQualifiedName~ObfuscationProviderTests"` +Expected: FAIL — `Caesar` does not exist (compile error). + +- [ ] **Step 3: Create the project file** + +Create `Essentials/ObfuscationProviders/Caesar/Caesar.csproj` identical to Task 2 Step 3 but with `ktsu.Essentials.ObfuscationProviders.Caesar`. + +- [ ] **Step 4: Implement `Caesar`** + +Create `Essentials/ObfuscationProviders/Caesar/Caesar.cs`: + +```csharp +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.ObfuscationProviders; + +using ktsu.Essentials; +using System; +using System.IO; + +/// +/// An obfuscation provider that adds a fixed shift to each byte (wrapping at 256). This is NOT +/// encryption and provides no confidentiality. +/// +public class Caesar : IObfuscationProvider +{ + private readonly byte _shift; + + /// Initializes a new instance with the default shift of 13. + public Caesar() : this(13) { } + + /// Initializes a new instance with the specified shift. + /// The amount added to each byte when obfuscating. + public Caesar(byte shift) => _shift = shift; + + /// + public bool TryObfuscate(ReadOnlySpan data, Span destination) + { + if (destination.Length < data.Length) + { + return false; + } + + for (int i = 0; i < data.Length; i++) + { + destination[i] = (byte)(data[i] + _shift); + } + + destination[data.Length..].Clear(); + return true; + } + + /// + public bool TryObfuscate(Stream data, Stream destination) + { + if (data is null || destination is null) + { + return false; + } + + int b; + while ((b = data.ReadByte()) >= 0) + { + destination.WriteByte((byte)(b + _shift)); + } + + return true; + } + + /// + public bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Span destination) + { + if (destination.Length < obfuscatedData.Length) + { + return false; + } + + for (int i = 0; i < obfuscatedData.Length; i++) + { + destination[i] = (byte)(obfuscatedData[i] - _shift); + } + + destination[obfuscatedData.Length..].Clear(); + return true; + } + + /// + public bool TryDeobfuscate(Stream obfuscatedData, Stream destination) + { + if (obfuscatedData is null || destination is null) + { + return false; + } + + int b; + while ((b = obfuscatedData.ReadByte()) >= 0) + { + destination.WriteByte((byte)(b - _shift)); + } + + return true; + } +} +``` + +- [ ] **Step 5: Wire into solution and test project** + +Add `` to `Essentials.Tests.csproj`, then: + +```bash +dotnet sln Essentials.slnx add Essentials/ObfuscationProviders/Caesar/Caesar.csproj +``` + +- [ ] **Step 6: Run tests to verify pass** + +Run: `dotnet test --filter "FullyQualifiedName~ObfuscationProviderTests"` +Expected: PASS — 8 tests (Xor + Caesar). + +- [ ] **Step 7: Commit** + +```bash +git add Essentials/ObfuscationProviders/Caesar Essentials/Essentials.Tests/ServiceCollectionExtensions.cs Essentials/Essentials.Tests/Essentials.Tests.csproj Essentials.slnx +git commit -m "feat: add Caesar obfuscation provider" +``` + +--- + +## Task 4: `Reverse` obfuscator + +**Files:** +- Create: `Essentials/ObfuscationProviders/Reverse/Reverse.csproj` +- Create: `Essentials/ObfuscationProviders/Reverse/Reverse.cs` +- Modify: `ServiceCollectionExtensions.cs`, `Essentials.Tests.csproj` + +**Interfaces:** +- Produces: `ktsu.Essentials.ObfuscationProviders.Reverse` with a parameterless constructor. + +- [ ] **Step 1: Register** + +Add to `AddObfuscationProviders`: `services.AddSingleton();` + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `dotnet test --filter "FullyQualifiedName~ObfuscationProviderTests"` +Expected: FAIL — `Reverse` does not exist. + +- [ ] **Step 3: Create the project file** + +Create `Essentials/ObfuscationProviders/Reverse/Reverse.csproj` as in Task 2 Step 3 with `ktsu.Essentials.ObfuscationProviders.Reverse`. + +- [ ] **Step 4: Implement `Reverse`** + +Create `Essentials/ObfuscationProviders/Reverse/Reverse.cs`: + +```csharp +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.ObfuscationProviders; + +using ktsu.Essentials; +using System; +using System.IO; + +/// +/// An obfuscation provider that reverses the byte order. Self-inverse. This is NOT encryption and +/// provides no confidentiality. +/// +public class Reverse : IObfuscationProvider +{ + /// + public bool TryObfuscate(ReadOnlySpan data, Span destination) + { + if (destination.Length < data.Length) + { + return false; + } + + for (int i = 0; i < data.Length; i++) + { + destination[i] = data[data.Length - 1 - i]; + } + + destination[data.Length..].Clear(); + return true; + } + + /// + public bool TryObfuscate(Stream data, Stream destination) + { + if (data is null || destination is null) + { + return false; + } + + using MemoryStream buffer = new(); + data.CopyTo(buffer); + byte[] bytes = buffer.ToArray(); + Array.Reverse(bytes); + destination.Write(bytes, 0, bytes.Length); + return true; + } + + /// + public bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Span destination) + => TryObfuscate(obfuscatedData, destination); + + /// + public bool TryDeobfuscate(Stream obfuscatedData, Stream destination) + => TryObfuscate(obfuscatedData, destination); +} +``` + +- [ ] **Step 5: Wire into solution and test project** + +Add `` to `Essentials.Tests.csproj`, then: + +```bash +dotnet sln Essentials.slnx add Essentials/ObfuscationProviders/Reverse/Reverse.csproj +``` + +- [ ] **Step 6: Run tests to verify pass** + +Run: `dotnet test --filter "FullyQualifiedName~ObfuscationProviderTests"` +Expected: PASS — 12 tests. + +- [ ] **Step 7: Commit** + +```bash +git add Essentials/ObfuscationProviders/Reverse Essentials/Essentials.Tests/ServiceCollectionExtensions.cs Essentials/Essentials.Tests/Essentials.Tests.csproj Essentials.slnx +git commit -m "feat: add Reverse obfuscation provider" +``` + +--- + +## Task 5: `BitRotate` obfuscator + +**Files:** +- Create: `Essentials/ObfuscationProviders/BitRotate/BitRotate.csproj` +- Create: `Essentials/ObfuscationProviders/BitRotate/BitRotate.cs` +- Modify: `ServiceCollectionExtensions.cs`, `Essentials.Tests.csproj` + +**Interfaces:** +- Produces: `ktsu.Essentials.ObfuscationProviders.BitRotate` with `BitRotate()` (default rotate 3) and `BitRotate(int bits)` where `bits` is 1–7. + +- [ ] **Step 1: Register** + +Add to `AddObfuscationProviders`: `services.AddSingleton();` + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `dotnet test --filter "FullyQualifiedName~ObfuscationProviderTests"` +Expected: FAIL — `BitRotate` does not exist. + +- [ ] **Step 3: Create the project file** + +Create `Essentials/ObfuscationProviders/BitRotate/BitRotate.csproj` as in Task 2 Step 3 with `ktsu.Essentials.ObfuscationProviders.BitRotate`. + +- [ ] **Step 4: Implement `BitRotate`** + +Create `Essentials/ObfuscationProviders/BitRotate/BitRotate.cs`: + +```csharp +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.ObfuscationProviders; + +using ktsu.Essentials; +using System; +using System.IO; + +/// +/// An obfuscation provider that rotates the bits of each byte left when obfuscating and right when +/// deobfuscating. This is NOT encryption and provides no confidentiality. +/// +public class BitRotate : IObfuscationProvider +{ + private readonly int _bits; + + /// Initializes a new instance rotating by 3 bits. + public BitRotate() : this(3) { } + + /// Initializes a new instance rotating by the specified number of bits (1–7). + /// The number of bits to rotate; must be between 1 and 7 inclusive. + public BitRotate(int bits) + { + if (bits is < 1 or > 7) + { + throw new ArgumentOutOfRangeException(nameof(bits), bits, "Rotation must be between 1 and 7 bits."); + } + + _bits = bits; + } + + private static byte RotateLeft(byte value, int bits) => (byte)((value << bits) | (value >> (8 - bits))); + + private static byte RotateRight(byte value, int bits) => (byte)((value >> bits) | (value << (8 - bits))); + + /// + public bool TryObfuscate(ReadOnlySpan data, Span destination) + { + if (destination.Length < data.Length) + { + return false; + } + + for (int i = 0; i < data.Length; i++) + { + destination[i] = RotateLeft(data[i], _bits); + } + + destination[data.Length..].Clear(); + return true; + } + + /// + public bool TryObfuscate(Stream data, Stream destination) + { + if (data is null || destination is null) + { + return false; + } + + int b; + while ((b = data.ReadByte()) >= 0) + { + destination.WriteByte(RotateLeft((byte)b, _bits)); + } + + return true; + } + + /// + public bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Span destination) + { + if (destination.Length < obfuscatedData.Length) + { + return false; + } + + for (int i = 0; i < obfuscatedData.Length; i++) + { + destination[i] = RotateRight(obfuscatedData[i], _bits); + } + + destination[obfuscatedData.Length..].Clear(); + return true; + } + + /// + public bool TryDeobfuscate(Stream obfuscatedData, Stream destination) + { + if (obfuscatedData is null || destination is null) + { + return false; + } + + int b; + while ((b = obfuscatedData.ReadByte()) >= 0) + { + destination.WriteByte(RotateRight((byte)b, _bits)); + } + + return true; + } +} +``` + +- [ ] **Step 5: Wire into solution and test project** + +Add `` to `Essentials.Tests.csproj`, then: + +```bash +dotnet sln Essentials.slnx add Essentials/ObfuscationProviders/BitRotate/BitRotate.csproj +``` + +- [ ] **Step 6: Run tests to verify pass** + +Run: `dotnet test --filter "FullyQualifiedName~ObfuscationProviderTests"` +Expected: PASS — 16 tests. + +- [ ] **Step 7: Commit** + +```bash +git add Essentials/ObfuscationProviders/BitRotate Essentials/Essentials.Tests/ServiceCollectionExtensions.cs Essentials/Essentials.Tests/Essentials.Tests.csproj Essentials.slnx +git commit -m "feat: add BitRotate obfuscation provider" +``` + +--- + +## Task 6: `Base64` obfuscator (composes the Base64 encoder) + +**Files:** +- Create: `Essentials/ObfuscationProviders/Base64/Base64.csproj` +- Create: `Essentials/ObfuscationProviders/Base64/Base64.cs` +- Modify: `ServiceCollectionExtensions.cs`, `Essentials.Tests.csproj` + +**Interfaces:** +- Consumes: `ktsu.Essentials.IEncodingProvider`, `ktsu.Essentials.EncodingProviders.Base64` (existing encoder). +- Produces: `ktsu.Essentials.ObfuscationProviders.Base64` with `Base64()` and `Base64(IEncodingProvider encoder)`. + +- [ ] **Step 1: Register** + +In `ServiceCollectionExtensions.cs` add to `AddObfuscationProviders`: + +```csharp + services.AddSingleton(); +``` + +(Use the fully-qualified `ObfuscationProviders.Base64` because `EncodingProviders.Base64` is also referenced in this file.) + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `dotnet test --filter "FullyQualifiedName~ObfuscationProviderTests"` +Expected: FAIL — `ObfuscationProviders.Base64` does not exist. + +- [ ] **Step 3: Create the project file** + +Create `Essentials/ObfuscationProviders/Base64/Base64.csproj` — like Task 2 Step 3, with `ktsu.Essentials.ObfuscationProviders.Base64` and an **extra** project reference to the encoder: + +```xml + + + + + +``` + +- [ ] **Step 4: Implement `Base64`** + +Create `Essentials/ObfuscationProviders/Base64/Base64.cs`: + +```csharp +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.ObfuscationProviders; + +using ktsu.Essentials; +using System; +using System.IO; + +/// +/// An obfuscation provider that composes a Base64 : obfuscation is +/// Base64 encoding, deobfuscation is Base64 decoding. This is NOT encryption. +/// +public class Base64 : IObfuscationProvider +{ + private readonly IEncodingProvider _encoder; + + /// Initializes a new instance using the default Base64 encoder. + public Base64() : this(new EncodingProviders.Base64()) { } + + /// Initializes a new instance using the supplied encoder. + /// The encoding provider used to perform the transform. + public Base64(IEncodingProvider encoder) => _encoder = Ensure.NotNull(encoder); + + /// + public bool TryObfuscate(ReadOnlySpan data, Span destination) => _encoder.TryEncode(data, destination); + + /// + public bool TryObfuscate(Stream data, Stream destination) => _encoder.TryEncode(data, destination); + + /// + public bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Span destination) => _encoder.TryDecode(obfuscatedData, destination); + + /// + public bool TryDeobfuscate(Stream obfuscatedData, Stream destination) => _encoder.TryDecode(obfuscatedData, destination); +} +``` + +- [ ] **Step 5: Wire into solution and test project** + +Add `` to `Essentials.Tests.csproj`, then: + +```bash +dotnet sln Essentials.slnx add Essentials/ObfuscationProviders/Base64/Base64.csproj +``` + +- [ ] **Step 6: Run tests to verify pass** + +Run: `dotnet test --filter "FullyQualifiedName~ObfuscationProviderTests"` +Expected: PASS — 20 tests. If `Obfuscation_Roundtrip_String` fails for this provider only, that indicates a UTF-8 edge case; in that case keep the other 3 shared tests passing and move the string assertion into provider-specific tests as noted in Task 2 Step 1. + +- [ ] **Step 7: Commit** + +```bash +git add Essentials/ObfuscationProviders/Base64 Essentials/Essentials.Tests/ServiceCollectionExtensions.cs Essentials/Essentials.Tests/Essentials.Tests.csproj Essentials.slnx +git commit -m "feat: add Base64 obfuscation provider composing the Base64 encoder" +``` + +--- + +## Task 7: `Hex` obfuscator (composes the Hex encoder) + +**Files:** +- Create: `Essentials/ObfuscationProviders/Hex/Hex.csproj` +- Create: `Essentials/ObfuscationProviders/Hex/Hex.cs` +- Modify: `ServiceCollectionExtensions.cs`, `Essentials.Tests.csproj` + +**Interfaces:** +- Consumes: `ktsu.Essentials.EncodingProviders.Hex` (existing encoder). +- Produces: `ktsu.Essentials.ObfuscationProviders.Hex` with `Hex()` and `Hex(IEncodingProvider encoder)`. + +- [ ] **Step 1: Register** + +Add to `AddObfuscationProviders`: `services.AddSingleton();` + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `dotnet test --filter "FullyQualifiedName~ObfuscationProviderTests"` +Expected: FAIL — `ObfuscationProviders.Hex` does not exist. + +- [ ] **Step 3: Create the project file** + +Create `Essentials/ObfuscationProviders/Hex/Hex.csproj` like Task 6 Step 3 but `ktsu.Essentials.ObfuscationProviders.Hex` and the extra reference pointing to the Hex encoder: + +```xml + +``` + +- [ ] **Step 4: Implement `Hex`** + +Create `Essentials/ObfuscationProviders/Hex/Hex.cs` — identical body to Task 6 Step 4 but with class `Hex`, default ctor `Hex() : this(new EncodingProviders.Hex())`, and the summary referencing Hex: + +```csharp +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.ObfuscationProviders; + +using ktsu.Essentials; +using System; +using System.IO; + +/// +/// An obfuscation provider that composes a Hex : obfuscation is hex +/// encoding, deobfuscation is hex decoding. This is NOT encryption. +/// +public class Hex : IObfuscationProvider +{ + private readonly IEncodingProvider _encoder; + + /// Initializes a new instance using the default Hex encoder. + public Hex() : this(new EncodingProviders.Hex()) { } + + /// Initializes a new instance using the supplied encoder. + /// The encoding provider used to perform the transform. + public Hex(IEncodingProvider encoder) => _encoder = Ensure.NotNull(encoder); + + /// + public bool TryObfuscate(ReadOnlySpan data, Span destination) => _encoder.TryEncode(data, destination); + + /// + public bool TryObfuscate(Stream data, Stream destination) => _encoder.TryEncode(data, destination); + + /// + public bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Span destination) => _encoder.TryDecode(obfuscatedData, destination); + + /// + public bool TryDeobfuscate(Stream obfuscatedData, Stream destination) => _encoder.TryDecode(obfuscatedData, destination); +} +``` + +- [ ] **Step 5: Wire into solution and test project** + +Add `` to `Essentials.Tests.csproj`, then: + +```bash +dotnet sln Essentials.slnx add Essentials/ObfuscationProviders/Hex/Hex.csproj +``` + +- [ ] **Step 6: Run tests to verify pass** + +Run: `dotnet test --filter "FullyQualifiedName~ObfuscationProviderTests"` +Expected: PASS — 24 tests. + +- [ ] **Step 7: Commit** + +```bash +git add Essentials/ObfuscationProviders/Hex Essentials/Essentials.Tests/ServiceCollectionExtensions.cs Essentials/Essentials.Tests/Essentials.Tests.csproj Essentials.slnx +git commit -m "feat: add Hex obfuscation provider composing the Hex encoder" +``` + +--- + +## Task 8: `Composite` obfuscator (pipelines a chain) + +**Files:** +- Create: `Essentials/ObfuscationProviders/Composite/Composite.csproj` +- Create: `Essentials/ObfuscationProviders/Composite/Composite.cs` +- Modify: `ServiceCollectionExtensions.cs`, `Essentials.Tests.csproj` + +**Interfaces:** +- Consumes: `ktsu.Essentials.IObfuscationProvider`. +- Produces: `ktsu.Essentials.ObfuscationProviders.Composite` with `Composite(IReadOnlyList stages)`. No parameterless constructor — it is configured by composition. Obfuscation applies stages in order; deobfuscation applies them in reverse order. + +- [ ] **Step 1: Register via factory (a default Xor → BitRotate chain)** + +In `ServiceCollectionExtensions.cs` add to `AddObfuscationProviders`: + +```csharp + services.AddSingleton(_ => new Composite([new Xor(), new BitRotate()])); +``` + +- [ ] **Step 2: Run tests to verify they fail** + +Run: `dotnet test --filter "FullyQualifiedName~ObfuscationProviderTests"` +Expected: FAIL — `Composite` does not exist. + +- [ ] **Step 3: Create the project file** + +Create `Essentials/ObfuscationProviders/Composite/Composite.csproj` as in Task 2 Step 3 with `ktsu.Essentials.ObfuscationProviders.Composite`. It references only `Essentials.csproj` + `Polyfill` — the chain stages are supplied by the caller, so no references to sibling obfuscator projects are needed. + +- [ ] **Step 4: Implement `Composite`** + +Create `Essentials/ObfuscationProviders/Composite/Composite.cs`: + +```csharp +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.ObfuscationProviders; + +using ktsu.Essentials; +using System; +using System.Collections.Generic; +using System.IO; + +/// +/// An obfuscation provider that pipelines an ordered list of obfuscators. Obfuscation applies the +/// stages in order; deobfuscation applies them in reverse order. This is NOT encryption. +/// +public class Composite : IObfuscationProvider +{ + private readonly IReadOnlyList _stages; + + /// Initializes a new instance with the ordered obfuscation stages. + /// The non-empty ordered list of obfuscators to pipeline. + public Composite(IReadOnlyList stages) + { + Ensure.NotNull(stages); + if (stages.Count == 0) + { + throw new ArgumentException("At least one stage is required.", nameof(stages)); + } + + _stages = stages; + } + + /// + public bool TryObfuscate(ReadOnlySpan data, Span destination) + { + byte[] current = data.ToArray(); + foreach (IObfuscationProvider stage in _stages) + { + current = stage.Obfuscate(current); + } + + if (destination.Length < current.Length) + { + return false; + } + + current.CopyTo(destination); + destination[current.Length..].Clear(); + return true; + } + + /// + public bool TryObfuscate(Stream data, Stream destination) + { + if (data is null || destination is null) + { + return false; + } + + using MemoryStream buffer = new(); + data.CopyTo(buffer); + byte[] current = buffer.ToArray(); + foreach (IObfuscationProvider stage in _stages) + { + current = stage.Obfuscate(current); + } + + destination.Write(current, 0, current.Length); + return true; + } + + /// + public bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Span destination) + { + byte[] current = obfuscatedData.ToArray(); + for (int i = _stages.Count - 1; i >= 0; i--) + { + current = _stages[i].Deobfuscate(current); + } + + if (destination.Length < current.Length) + { + return false; + } + + current.CopyTo(destination); + destination[current.Length..].Clear(); + return true; + } + + /// + public bool TryDeobfuscate(Stream obfuscatedData, Stream destination) + { + if (obfuscatedData is null || destination is null) + { + return false; + } + + using MemoryStream buffer = new(); + obfuscatedData.CopyTo(buffer); + byte[] current = buffer.ToArray(); + for (int i = _stages.Count - 1; i >= 0; i--) + { + current = _stages[i].Deobfuscate(current); + } + + destination.Write(current, 0, current.Length); + return true; + } +} +``` + +- [ ] **Step 5: Wire into solution and test project** + +Add `` to `Essentials.Tests.csproj`, then: + +```bash +dotnet sln Essentials.slnx add Essentials/ObfuscationProviders/Composite/Composite.csproj +``` + +- [ ] **Step 6: Run tests to verify pass** + +Run: `dotnet test --filter "FullyQualifiedName~ObfuscationProviderTests"` +Expected: PASS — 28 tests (Xor, Caesar, Reverse, BitRotate, Base64, Hex, Composite). + +- [ ] **Step 7: Commit** + +```bash +git add Essentials/ObfuscationProviders/Composite Essentials/Essentials.Tests/ServiceCollectionExtensions.cs Essentials/Essentials.Tests/Essentials.Tests.csproj Essentials.slnx +git commit -m "feat: add Composite obfuscation provider that pipelines a chain" +``` + +--- + +## Task 9: Port the `NewtonsoftJson` serialization provider + +**Files:** +- Create: `Essentials/SerializationProviders/NewtonsoftJson/NewtonsoftJson.csproj` +- Create: `Essentials/SerializationProviders/NewtonsoftJson/NewtonsoftJson.cs` +- Modify: `Essentials/Directory.Packages.props` +- Modify: `ServiceCollectionExtensions.cs`, `Essentials.Tests.csproj` + +**Interfaces:** +- Consumes: `ktsu.Essentials.ISerializationProvider` (core: `bool TrySerialize(object obj, TextWriter writer)`, `T? Deserialize(ReadOnlySpan data)`). +- Produces: `ktsu.Essentials.SerializationProviders.NewtonsoftJson` (parameterless constructor). + +- [ ] **Step 1: Add the package version pin** + +In `Essentials/Directory.Packages.props`, add inside the ``: + +```xml + +``` + +- [ ] **Step 2: Register the provider (extend the failing serialization suite)** + +In `ServiceCollectionExtensions.cs`, in `AddSerializationProviders`, add: + +```csharp + services.AddSingleton(); +``` + +- [ ] **Step 3: Run tests to verify they fail** + +Run: `dotnet test --filter "FullyQualifiedName~SerializationProviderTests"` +Expected: FAIL — `NewtonsoftJson` does not exist. + +- [ ] **Step 4: Create the project file** + +Create `Essentials/SerializationProviders/NewtonsoftJson/NewtonsoftJson.csproj`: + +```xml + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + ktsu.Essentials.SerializationProviders.NewtonsoftJson + ktsu.Essentials.SerializationProviders + + + + + + + + + + + + + +``` + +- [ ] **Step 5: Implement `NewtonsoftJson`** + +Copy `C:\dev\ktsu-dev\Common\SerializationProviders\NewtonsoftJson\NewtonsoftJson.cs` to the new path, changing line 5 from `namespace ktsu.SerializationProviders;` to `namespace ktsu.Essentials.SerializationProviders;` and line 10 from `using ktsu.Abstractions;` to `using ktsu.Essentials;`. The class body is unchanged. Result: + +```csharp +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.SerializationProviders; + +using System; +using System.IO; +using System.Text; +using ktsu.Essentials; +using Newtonsoft.Json; + +/// +/// A serialization provider that uses Newtonsoft.Json for JSON serialization and deserialization. +/// +public class NewtonsoftJson : ISerializationProvider +{ + private readonly JsonSerializerSettings settings = new(); + + /// + public T? Deserialize(ReadOnlySpan data) + { + if (data.IsEmpty) + { + return default; + } + + try + { + string jsonString = Encoding.UTF8.GetString(data); + return JsonConvert.DeserializeObject(jsonString, settings); + } + catch (JsonReaderException) + { + return default; + } + catch (ArgumentException) + { + return default; + } + } + + /// + public bool TrySerialize(object obj, TextWriter writer) + { + if (writer is null) + { + return false; + } + + try + { + using JsonTextWriter jsonWriter = new(writer); + JsonSerializer serializer = JsonSerializer.Create(settings); + serializer.Serialize(jsonWriter, obj); + return true; + } + catch (JsonSerializationException) + { + return false; + } + catch (JsonWriterException) + { + return false; + } + } +} +``` + +- [ ] **Step 6: Wire into solution and test project** + +Add `` to `Essentials.Tests.csproj`, then: + +```bash +dotnet sln Essentials.slnx add Essentials/SerializationProviders/NewtonsoftJson/NewtonsoftJson.csproj +``` + +- [ ] **Step 7: Run tests to verify pass** + +Run: `dotnet test --filter "FullyQualifiedName~SerializationProviderTests"` +Expected: PASS — the existing serialization contract tests now also run against `NewtonsoftJson`. + +- [ ] **Step 8: Commit** + +```bash +git add Essentials/SerializationProviders/NewtonsoftJson Essentials/Directory.Packages.props Essentials/Essentials.Tests/ServiceCollectionExtensions.cs Essentials/Essentials.Tests/Essentials.Tests.csproj Essentials.slnx +git commit -m "feat: port NewtonsoftJson serialization provider from Common" +``` + +--- + +## Task 10: `ktsu.Essentials.All` meta-package + +**Files:** +- Create: `Essentials/All/All.csproj` + +**Interfaces:** +- Produces: NuGet package `ktsu.Essentials.All` whose only content is `PackageReference`-equivalent dependencies on every `ktsu.Essentials.*` provider package (emitted from `ProjectReference`s when packed). No assembly output. + +- [ ] **Step 1: Create the meta-package project** + +Create `Essentials/All/All.csproj`. List a `ProjectReference` for **every** provider implementation project in the repo (all `CacheProviders`, `CommandExecutors`, `CompressionProviders`, `EncodingProviders`, `EncryptionProviders`, `FileSystemProviders`, `HashProviders`, `LoggingProviders`, `NavigationProviders`, `ObfuscationProviders`, `PersistenceProviders`, `SerializationProviders` leaf projects). Use the test project's `ProjectReference` list as the source of truth and add the 8 new providers (7 obfuscators + NewtonsoftJson): + +```xml + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + ktsu.Essentials.All + ktsu.Essentials.All + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +- [ ] **Step 2: Add to the solution and verify it packs with dependencies (no lib output)** + +```bash +dotnet sln Essentials.slnx add Essentials/All/All.csproj +dotnet pack Essentials/All/All.csproj -o ./staging +``` +Expected: `ktsu.Essentials.All..nupkg` is produced. Inspect that the nuspec lists every provider package as a `` and the package contains no `lib/*/ktsu.Essentials.All.dll`. + +> If `ProjectReference`s do not surface as package dependencies under `ktsu.Sdk` packing, convert them to `PackageReference`s to the published `ktsu.Essentials..` packages (add each version to `Directory.Packages.props`). Verify the produced nuspec either way. + +- [ ] **Step 3: Build the whole solution to confirm nothing regressed** + +Run: `dotnet build Essentials.slnx` +Expected: Build succeeded, 0 warnings (warnings-as-errors), 0 errors. + +- [ ] **Step 4: Commit** + +```bash +git add Essentials/All/All.csproj Essentials.slnx +git commit -m "feat: add ktsu.Essentials.All meta-package" +``` + +--- + +## Task 11: Refresh Essentials documentation + +**Files:** +- Modify: `Essentials/README.md`, `Essentials/CLAUDE.md`, `Essentials/DESCRIPTION.md`, `Essentials/TAGS.md` + +- [ ] **Step 1: Run the docs skill** + +Invoke the `update-docs` skill for the `Essentials` repo. Ensure the refreshed docs state: +- The composition model: **Configuration = Persistence + Serialization** (no separate configuration providers); **Obfuscation composes Encoding**. +- New `ObfuscationProviders`: `Xor`, `Caesar`, `Reverse`, `BitRotate`, `Base64`, `Hex`, `Composite`, plus the `IObfuscationProvider` interface (obfuscation is explicitly **not** encryption). +- New `SerializationProviders/NewtonsoftJson` (System.Text.Json `Json` remains the default). +- The new `ktsu.Essentials.All` meta-package and the cherry-pick model. +- That `ktsu.Essentials` supersedes `ktsu.Abstractions` and `ktsu.Common`. + +- [ ] **Step 2: Full verification build + test** + +Run: `dotnet build Essentials.slnx && dotnet test` +Expected: Build succeeded; all tests pass (including the 28 obfuscation tests and the serialization tests covering `NewtonsoftJson`). + +- [ ] **Step 3: Commit** + +```bash +git add Essentials/README.md Essentials/CLAUDE.md Essentials/DESCRIPTION.md Essentials/TAGS.md +git commit -m "docs: document obfuscation, NewtonsoftJson, the All meta-package, and supersession" +``` + +--- + +## Phase 1 done → ship + +After Task 11, open a PR from `consolidate-into-essentials` to `main`, merge, and let CI publish the new `ktsu.Essentials.*` packages (including `ktsu.Essentials.All`). Phase 2 cannot begin until the new packages are live on nuget.org (the Abstractions shims inherit from them). + +--- + +## Phase 2: Retirement of `Abstractions` + `Common` (separate plan) + +These are release/operations tasks that produce no testable software and depend on Phase 1 being published. They will be expanded into their own plan (`docs/superpowers/plans/-retire-abstractions-common.md`) once Phase 1 ships. Captured here for traceability against the spec: + +1. **`Abstractions` core compat shim release.** In `ktsu.Abstractions`, change each interface to inherit its `ktsu.Essentials` counterpart and mark it `[Obsolete("Moved to ktsu.Essentials. This package is deprecated.")]`, e.g. `public interface IHashProvider : ktsu.Essentials.IHashProvider { }`. Add a `PackageReference` to `ktsu.Essentials`. Interfaces to shim (with generic arity): `ICacheProvider`, `ICommandExecutor`, `ICompressionProvider`, `IEncodingProvider`, `IEncryptionProvider`, `IFileSystemProvider`, `IHashProvider`, `ILoggingProvider`, `INavigationProvider`, `IObfuscationProvider`, `IPersistenceProvider`, `ISerializationOptions`, `ISerializationProvider`, `IValidationProvider`. **Exception:** `IConfigurationProvider` has no Essentials counterpart — mark `[Obsolete("Configuration is now persistence over a serializer; use ktsu.Essentials.IPersistenceProvider.")]` with no base interface. Publish as a final major-version release. +2. **NuGet-deprecate the provider-impl packages.** Mark every published `ktsu.Abstractions`-repo provider package (`ktsu..`) and every `ktsu.Common.*` package as Deprecated on nuget.org with `AlternatePackage` = the matching `ktsu.Essentials..` (via the nuget.org UI or the registration/deprecation API). Enumerate the package IDs from each repo's provider folders. +3. **Remove from the Sync bot.** Remove `Abstractions` and `Common` from the cross-repo Sync bot configuration so they stop receiving twin maintenance commits. +4. **Archive the repos.** Archive `ktsu-dev/Abstractions` and `ktsu-dev/Common` on GitHub after their final releases. + +(`Ecosystem` is abandoned and intentionally not migrated.) + +--- + +## Self-Review + +**Spec coverage:** +- Tiered packaging (granular + `All` meta) → Tasks 2–9 keep granular packages; Task 10 adds the meta. ✅ +- Configuration dropped → no task ports it; called out in docs (Task 11) and Phase 2 shim exception. ✅ +- Obfuscation kept, composed over encoding, with the 7-obfuscator set → Tasks 1–8. ✅ +- NewtonsoftJson ported → Task 9. ✅ +- Interface shims (Q4=B) + impl deprecation (Q5=A), Sync-bot removal, archival → Phase 2. ✅ +- Tests for obfuscators + NewtonsoftJson coverage; no Configuration tests → Tasks 2–9. ✅ +- Docs refresh → Task 11. ✅ + +**Placeholder scan:** No TBD/TODO; every code step shows complete code; csproj/DI edits are explicit. The two conditional notes (string-roundtrip fallback in Task 6; ProjectReference-vs-PackageReference packing in Task 10) give a concrete primary action plus a concrete fallback, not a placeholder. ✅ + +**Type consistency:** Core members `TryObfuscate`/`TryDeobfuscate` (Span + Stream) and convenience `Obfuscate`/`Deobfuscate` match `IObfuscationProvider` (Task 1). `AddObfuscationProviders` defined in Task 2 and extended in Tasks 3–8. `NewtonsoftJson` implements `TrySerialize(object, TextWriter)` + `Deserialize(ReadOnlySpan)` matching `ISerializationProvider`. `Composite(IReadOnlyList)` constructor used consistently in the Task 8 DI factory. ✅ From 55434792f41a7244f86f58ac5a90bd387b6edebb Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Mon, 29 Jun 2026 15:16:09 +1000 Subject: [PATCH 03/17] feat: add IObfuscationProvider interface to Essentials core --- Essentials/Essentials/IObfuscationProvider.cs | 233 ++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 Essentials/Essentials/IObfuscationProvider.cs diff --git a/Essentials/Essentials/IObfuscationProvider.cs b/Essentials/Essentials/IObfuscationProvider.cs new file mode 100644 index 0000000..be6146c --- /dev/null +++ b/Essentials/Essentials/IObfuscationProvider.cs @@ -0,0 +1,233 @@ +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials; + +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +/// +/// Interface for obfuscation providers that can obfuscate and deobfuscate data using reversible transforms such as Base64. +/// Obfuscation is NOT encryption — it provides no confidentiality guarantees and is intended only to make data +/// non-obvious at rest or in transit. +/// +public interface IObfuscationProvider +{ + /// + /// Tries to obfuscate the data from the span and write the result to the destination. + /// + /// The data to obfuscate. + /// The destination to write the obfuscated data to. + /// True if the obfuscation was successful, false otherwise. + public bool TryObfuscate(ReadOnlySpan data, Span destination); + + /// + /// Tries to obfuscate the data from the stream and write the result to the destination. + /// + /// The data to obfuscate. + /// The destination to write the obfuscated data to. + /// True if the obfuscation was successful, false otherwise. + public bool TryObfuscate(Stream data, Stream destination); + + /// + /// Tries to obfuscate the data from the span and write the result to the destination stream. + /// + /// The data to obfuscate. + /// The destination stream to write the obfuscated data to. + /// True if the obfuscation was successful, false otherwise. + public bool TryObfuscate(ReadOnlySpan data, Stream destination) + => ProviderHelpers.SpanToStreamBridge(data, destination, TryObfuscate); + + /// + /// Obfuscates the data from the span and returns the result. + /// + /// The data to obfuscate. + /// The obfuscated data. + public byte[] Obfuscate(ReadOnlySpan data) + { + using MemoryStream outputStream = new(); + if (!TryObfuscate(data, outputStream)) + { + throw new InvalidOperationException("Obfuscation failed to produce output with the allocated buffer."); + } + + return outputStream.ToArray(); + } + + /// + /// Obfuscates the data from the stream and returns the result. + /// + /// The data to obfuscate. + /// The obfuscated data. + public byte[] Obfuscate(Stream data) + => ProviderHelpers.ExecuteToByteArray( + output => TryObfuscate(data, output), + "Obfuscation failed to produce output with the allocated buffer."); + + /// + /// Obfuscates the data from the string and returns the result. + /// + /// The data to obfuscate. + /// The obfuscated data. + public string Obfuscate(string data) + => ProviderHelpers.Utf8Transform(data, bytes => Obfuscate(bytes)); + + /// + /// Tries to obfuscate the data from the span and write the result to the destination asynchronously. + /// + /// The data to obfuscate. + /// The destination to write the obfuscated data to. + /// The cancellation token. + /// True if the obfuscation was successful, false otherwise. + public Task TryObfuscateAsync(ReadOnlyMemory data, Memory destination, CancellationToken cancellationToken = default) + => ProviderHelpers.RunAsync(() => TryObfuscate(data.Span, destination.Span), cancellationToken); + + /// + /// Tries to obfuscate the data from the span and write the result to the destination stream asynchronously. + /// + /// The data to obfuscate. + /// The destination stream to write the obfuscated data to. + /// The cancellation token. + /// True if the obfuscation was successful, false otherwise. + public Task TryObfuscateAsync(ReadOnlyMemory data, Stream destination, CancellationToken cancellationToken = default) + => ProviderHelpers.RunAsync(() => TryObfuscate(data.Span, destination), cancellationToken); + + /// + /// Tries to obfuscate the data from the stream and write the result to the destination stream asynchronously. + /// + /// The data to obfuscate. + /// The destination stream to write the obfuscated data to. + /// The cancellation token. + /// True if the obfuscation was successful, false otherwise. + public Task TryObfuscateAsync(Stream data, Stream destination, CancellationToken cancellationToken = default) + => ProviderHelpers.RunAsync(() => TryObfuscate(data, destination), cancellationToken); + + /// + /// Obfuscates the data from the span and returns the result asynchronously. + /// + /// The data to obfuscate. + /// The cancellation token. + /// The obfuscated data. + public Task ObfuscateAsync(ReadOnlyMemory data, CancellationToken cancellationToken = default) + => ProviderHelpers.RunAsync(() => Obfuscate(data.Span), cancellationToken); + + /// + /// Obfuscates the data from the stream and returns the result asynchronously. + /// + /// The data to obfuscate. + /// The cancellation token. + /// The obfuscated data. + public Task ObfuscateAsync(Stream data, CancellationToken cancellationToken = default) + => ProviderHelpers.RunAsync(() => Obfuscate(data), cancellationToken); + + /// + /// Obfuscates the data from the string and returns the result asynchronously. + /// + /// The data to obfuscate. + /// The cancellation token. + /// The obfuscated data. + public Task ObfuscateAsync(string data, CancellationToken cancellationToken = default) + => ProviderHelpers.RunAsync(() => Obfuscate(data), cancellationToken); + + /// + /// Tries to deobfuscate the data from the span and write the result to the destination. + /// + /// The obfuscated data to deobfuscate. + /// The destination to write the deobfuscated data to. + /// True if the deobfuscation was successful, false otherwise. + public bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Span destination); + + /// + /// Tries to deobfuscate the data from the stream and write the result to the destination. + /// + /// The obfuscated data to deobfuscate. + /// The destination to write the deobfuscated data to. + /// True if the deobfuscation was successful, false otherwise. + public bool TryDeobfuscate(Stream obfuscatedData, Stream destination); + + /// + /// Tries to deobfuscate the data from the span and write the result to the destination stream. + /// + /// The obfuscated data to deobfuscate. + /// The destination stream to write the deobfuscated data to. + /// True if the deobfuscation was successful, false otherwise. + public bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Stream destination) + => ProviderHelpers.SpanToStreamBridge(obfuscatedData, destination, TryDeobfuscate); + + /// + /// Deobfuscates the data from the span and returns the result. + /// + /// The obfuscated data to deobfuscate. + /// The deobfuscated data. + public byte[] Deobfuscate(ReadOnlySpan obfuscatedData) + { + using MemoryStream outputStream = new(); + if (!TryDeobfuscate(obfuscatedData, outputStream)) + { + throw new InvalidOperationException("Deobfuscation failed to produce output with the allocated buffer."); + } + + return outputStream.ToArray(); + } + + /// + /// Deobfuscates the data from the stream and returns the result. + /// + /// The obfuscated data to deobfuscate. + /// The deobfuscated data. + public byte[] Deobfuscate(Stream obfuscatedData) + => ProviderHelpers.ExecuteToByteArray( + output => TryDeobfuscate(obfuscatedData, output), + "Deobfuscation failed to produce output with the allocated buffer."); + + /// + /// Tries to deobfuscate the data from the span and write the result to the destination asynchronously. + /// + /// The obfuscated data to deobfuscate. + /// The destination to write the deobfuscated data to. + /// The cancellation token. + /// True if the deobfuscation was successful, false otherwise. + public Task TryDeobfuscateAsync(ReadOnlyMemory obfuscatedData, Memory destination, CancellationToken cancellationToken = default) + => ProviderHelpers.RunAsync(() => TryDeobfuscate(obfuscatedData.Span, destination.Span), cancellationToken); + + /// + /// Tries to deobfuscate the data from the span and write the result to the destination stream asynchronously. + /// + /// The obfuscated data to deobfuscate. + /// The destination stream to write the deobfuscated data to. + /// The cancellation token. + /// True if the deobfuscation was successful, false otherwise. + public Task TryDeobfuscateAsync(ReadOnlyMemory obfuscatedData, Stream destination, CancellationToken cancellationToken = default) + => ProviderHelpers.RunAsync(() => TryDeobfuscate(obfuscatedData.Span, destination), cancellationToken); + + /// + /// Tries to deobfuscate the data from the stream and write the result to the destination stream asynchronously. + /// + /// The obfuscated data to deobfuscate. + /// The destination stream to write the deobfuscated data to. + /// The cancellation token. + /// True if the deobfuscation was successful, false otherwise. + public Task TryDeobfuscateAsync(Stream obfuscatedData, Stream destination, CancellationToken cancellationToken = default) + => ProviderHelpers.RunAsync(() => TryDeobfuscate(obfuscatedData, destination), cancellationToken); + + /// + /// Deobfuscates the data from the span and returns the result asynchronously. + /// + /// The obfuscated data to deobfuscate. + /// The cancellation token. + /// The deobfuscated data. + public Task DeobfuscateAsync(ReadOnlyMemory obfuscatedData, CancellationToken cancellationToken = default) + => ProviderHelpers.RunAsync(() => Deobfuscate(obfuscatedData.Span), cancellationToken); + + /// + /// Deobfuscates the data from the stream and returns the result asynchronously. + /// + /// The obfuscated data to deobfuscate. + /// The cancellation token. + /// The deobfuscated data. + public Task DeobfuscateAsync(Stream obfuscatedData, CancellationToken cancellationToken = default) + => ProviderHelpers.RunAsync(() => Deobfuscate(obfuscatedData), cancellationToken); +} From 1505afda48e8de9c87bb50f449b5134a9b588fef Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Mon, 29 Jun 2026 16:23:27 +1000 Subject: [PATCH 04/17] feat: add Xor obfuscation provider and obfuscation test harness --- Essentials.Tests/Essentials.Tests.csproj | 1 + Essentials.Tests/ObfuscationProviderTests.cs | 86 +++++++++++++++++++ .../ServiceCollectionExtensions.cs | 8 ++ Essentials.slnx | 3 + ObfuscationProviders/Xor/Xor.cs | 80 +++++++++++++++++ ObfuscationProviders/Xor/Xor.csproj | 20 +++++ 6 files changed, 198 insertions(+) create mode 100644 Essentials.Tests/ObfuscationProviderTests.cs create mode 100644 ObfuscationProviders/Xor/Xor.cs create mode 100644 ObfuscationProviders/Xor/Xor.csproj diff --git a/Essentials.Tests/Essentials.Tests.csproj b/Essentials.Tests/Essentials.Tests.csproj index 1db193c..13d758f 100644 --- a/Essentials.Tests/Essentials.Tests.csproj +++ b/Essentials.Tests/Essentials.Tests.csproj @@ -16,6 +16,7 @@ + diff --git a/Essentials.Tests/ObfuscationProviderTests.cs b/Essentials.Tests/ObfuscationProviderTests.cs new file mode 100644 index 0000000..73fac47 --- /dev/null +++ b/Essentials.Tests/ObfuscationProviderTests.cs @@ -0,0 +1,86 @@ +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.Tests; + +using System.Collections.Generic; +using System.Text; +using ktsu.Essentials; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +[TestClass] +public class ObfuscationProviderTests +{ + private static ServiceProvider BuildProvider() + { + ServiceCollection services = new(); + services.AddObfuscationProviders(); + return services.BuildServiceProvider(); + } + + public static IEnumerable ObfuscationProviders => BuildProvider().EnumerateProviders(); + + public TestContext TestContext { get; set; } = null!; + + [TestMethod] + [DynamicData(nameof(ObfuscationProviders))] + public void Obfuscation_Roundtrip_Bytes(IObfuscationProvider provider, string providerName) + { + byte[] original = Encoding.UTF8.GetBytes("obfuscate me with " + providerName); + + byte[] obfuscated = provider.Obfuscate(original); + byte[] restored = provider.Deobfuscate(obfuscated); + + CollectionAssert.AreEqual(original, restored, $"{providerName} should restore original bytes"); + } + + [TestMethod] + [DynamicData(nameof(ObfuscationProviders))] + public void Obfuscation_Roundtrip_Stream(IObfuscationProvider provider, string providerName) + { + byte[] original = Encoding.UTF8.GetBytes("stream obfuscate with " + providerName); + + using MemoryStream input = new(original); + using MemoryStream obfuscated = new(); + Assert.IsTrue(provider.TryObfuscate(input, obfuscated), $"{providerName} should obfuscate stream"); + + obfuscated.Position = 0; + using MemoryStream restored = new(); + Assert.IsTrue(provider.TryDeobfuscate(obfuscated, restored), $"{providerName} should deobfuscate stream"); + + CollectionAssert.AreEqual(original, restored.ToArray(), $"{providerName} should restore original from stream"); + } + + [TestMethod] + [DynamicData(nameof(ObfuscationProviders))] + public void Obfuscation_Roundtrip_String(IObfuscationProvider provider, string providerName) + { + string original = "string obfuscate with " + providerName; + + string obfuscated = provider.Obfuscate(original); + byte[] obfuscatedBytes = Encoding.UTF8.GetBytes(obfuscated); + byte[] restoredBytes = provider.Deobfuscate(obfuscatedBytes); + string restored = Encoding.UTF8.GetString(restoredBytes); + + Assert.AreEqual(original, restored, $"{providerName} should restore original string"); + } + + [TestMethod] + [DynamicData(nameof(ObfuscationProviders))] + public void Obfuscation_Async_Roundtrip(IObfuscationProvider provider, string providerName) + { + byte[] original = Encoding.UTF8.GetBytes("async obfuscate with " + providerName); + + using MemoryStream input = new(original); + using MemoryStream obfuscated = new(); + Assert.IsTrue(provider.TryObfuscateAsync(input, obfuscated, TestContext.CancellationToken).Result, $"{providerName} async obfuscate"); + + obfuscated.Position = 0; + using MemoryStream restored = new(); + Assert.IsTrue(provider.TryDeobfuscateAsync(obfuscated, restored, TestContext.CancellationToken).Result, $"{providerName} async deobfuscate"); + + CollectionAssert.AreEqual(original, restored.ToArray(), $"{providerName} async should restore original"); + } +} \ No newline at end of file diff --git a/Essentials.Tests/ServiceCollectionExtensions.cs b/Essentials.Tests/ServiceCollectionExtensions.cs index 0f50dee..333d1f4 100644 --- a/Essentials.Tests/ServiceCollectionExtensions.cs +++ b/Essentials.Tests/ServiceCollectionExtensions.cs @@ -8,6 +8,7 @@ namespace ktsu.Essentials.Tests; using ktsu.Essentials.CompressionProviders; using ktsu.Essentials.EncryptionProviders; using ktsu.Essentials.HashProviders; +using ktsu.Essentials.ObfuscationProviders; using ktsu.Essentials.SerializationProviders; using Microsoft.Extensions.DependencyInjection; @@ -24,6 +25,7 @@ public static ServiceCollection AddCommon(this ServiceCollection services) services.AddHashProviders(); services.AddLoggingProviders(); services.AddNavigationProviders(); + services.AddObfuscationProviders(); services.AddPersistenceProviders(); services.AddSerializationProviders(); return services; @@ -44,6 +46,12 @@ public static ServiceCollection AddEncryptionProviders(this ServiceCollection se return services; } + public static ServiceCollection AddObfuscationProviders(this ServiceCollection services) + { + services.AddSingleton(); + return services; + } + public static ServiceCollection AddFileSystemProviders(this ServiceCollection services) { services.AddSingleton(); diff --git a/Essentials.slnx b/Essentials.slnx index 6a3a5c7..4030cb1 100644 --- a/Essentials.slnx +++ b/Essentials.slnx @@ -23,6 +23,9 @@ + + + diff --git a/ObfuscationProviders/Xor/Xor.cs b/ObfuscationProviders/Xor/Xor.cs new file mode 100644 index 0000000..7b09430 --- /dev/null +++ b/ObfuscationProviders/Xor/Xor.cs @@ -0,0 +1,80 @@ +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.ObfuscationProviders; + +using System; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using ktsu.Essentials; + +/// +/// An obfuscation provider that XORs each byte with a repeating key. Self-inverse: obfuscation and +/// deobfuscation are the same transform. This is NOT encryption and provides no confidentiality. +/// +[SuppressMessage("Naming", "CA1716:Identifiers should not match keywords", Justification = "Xor is the appropriate name for this obfuscation provider")] +public class Xor : IObfuscationProvider +{ + private readonly byte[] _key; + + /// Initializes a new instance with the default single-byte key. + public Xor() : this([0x5A]) { } + + /// Initializes a new instance with the specified repeating key. + /// The non-empty key bytes to XOR against. + public Xor(byte[] key) + { + Ensure.NotNull(key); + if (key.Length == 0) + { + throw new ArgumentException("Key must contain at least one byte.", nameof(key)); + } + + _key = key; + } + + /// + public bool TryObfuscate(ReadOnlySpan data, Span destination) + { + if (destination.Length < data.Length) + { + return false; + } + + for (int i = 0; i < data.Length; i++) + { + destination[i] = (byte)(data[i] ^ _key[i % _key.Length]); + } + + destination[data.Length..].Clear(); + return true; + } + + /// + public bool TryObfuscate(Stream data, Stream destination) + { + if (data is null || destination is null) + { + return false; + } + + int b; + long i = 0; + while ((b = data.ReadByte()) >= 0) + { + destination.WriteByte((byte)(b ^ _key[(int)(i % _key.Length)])); + i++; + } + + return true; + } + + /// + public bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Span destination) + => TryObfuscate(obfuscatedData, destination); + + /// + public bool TryDeobfuscate(Stream obfuscatedData, Stream destination) + => TryObfuscate(obfuscatedData, destination); +} \ No newline at end of file diff --git a/ObfuscationProviders/Xor/Xor.csproj b/ObfuscationProviders/Xor/Xor.csproj new file mode 100644 index 0000000..ceb3163 --- /dev/null +++ b/ObfuscationProviders/Xor/Xor.csproj @@ -0,0 +1,20 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + ktsu.Essentials.ObfuscationProviders.Xor + ktsu.Essentials.ObfuscationProviders + + + + + + + + + + + + From fa61814e276f24135e41887febdfce01d79a5aa9 Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Mon, 29 Jun 2026 17:14:24 +1000 Subject: [PATCH 05/17] feat: add Caesar obfuscation provider --- Essentials.Tests/Essentials.Tests.csproj | 1 + .../ServiceCollectionExtensions.cs | 1 + Essentials.slnx | 1 + ObfuscationProviders/Caesar/Caesar.cs | 86 +++++++++++++++++++ ObfuscationProviders/Caesar/Caesar.csproj | 20 +++++ 5 files changed, 109 insertions(+) create mode 100644 ObfuscationProviders/Caesar/Caesar.cs create mode 100644 ObfuscationProviders/Caesar/Caesar.csproj diff --git a/Essentials.Tests/Essentials.Tests.csproj b/Essentials.Tests/Essentials.Tests.csproj index 13d758f..c11a3fb 100644 --- a/Essentials.Tests/Essentials.Tests.csproj +++ b/Essentials.Tests/Essentials.Tests.csproj @@ -17,6 +17,7 @@ + diff --git a/Essentials.Tests/ServiceCollectionExtensions.cs b/Essentials.Tests/ServiceCollectionExtensions.cs index 333d1f4..12e3ced 100644 --- a/Essentials.Tests/ServiceCollectionExtensions.cs +++ b/Essentials.Tests/ServiceCollectionExtensions.cs @@ -49,6 +49,7 @@ public static ServiceCollection AddEncryptionProviders(this ServiceCollection se public static ServiceCollection AddObfuscationProviders(this ServiceCollection services) { services.AddSingleton(); + services.AddSingleton(); return services; } diff --git a/Essentials.slnx b/Essentials.slnx index 4030cb1..737e6a8 100644 --- a/Essentials.slnx +++ b/Essentials.slnx @@ -24,6 +24,7 @@ + diff --git a/ObfuscationProviders/Caesar/Caesar.cs b/ObfuscationProviders/Caesar/Caesar.cs new file mode 100644 index 0000000..9dec3a3 --- /dev/null +++ b/ObfuscationProviders/Caesar/Caesar.cs @@ -0,0 +1,86 @@ +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.ObfuscationProviders; + +using System; +using System.IO; +using ktsu.Essentials; + +/// +/// An obfuscation provider that adds a fixed shift to each byte (wrapping at 256). This is NOT +/// encryption and provides no confidentiality. +/// +public class Caesar(byte shift = 13) : IObfuscationProvider +{ + private readonly byte _shift = shift; + + /// + public bool TryObfuscate(ReadOnlySpan data, Span destination) + { + if (destination.Length < data.Length) + { + return false; + } + + for (int i = 0; i < data.Length; i++) + { + destination[i] = (byte)(data[i] + _shift); + } + + destination[data.Length..].Clear(); + return true; + } + + /// + public bool TryObfuscate(Stream data, Stream destination) + { + if (data is null || destination is null) + { + return false; + } + + int b; + while ((b = data.ReadByte()) >= 0) + { + destination.WriteByte((byte)(b + _shift)); + } + + return true; + } + + /// + public bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Span destination) + { + if (destination.Length < obfuscatedData.Length) + { + return false; + } + + for (int i = 0; i < obfuscatedData.Length; i++) + { + destination[i] = (byte)(obfuscatedData[i] - _shift); + } + + destination[obfuscatedData.Length..].Clear(); + return true; + } + + /// + public bool TryDeobfuscate(Stream obfuscatedData, Stream destination) + { + if (obfuscatedData is null || destination is null) + { + return false; + } + + int b; + while ((b = obfuscatedData.ReadByte()) >= 0) + { + destination.WriteByte((byte)(b - _shift)); + } + + return true; + } +} diff --git a/ObfuscationProviders/Caesar/Caesar.csproj b/ObfuscationProviders/Caesar/Caesar.csproj new file mode 100644 index 0000000..9f2fc98 --- /dev/null +++ b/ObfuscationProviders/Caesar/Caesar.csproj @@ -0,0 +1,20 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + ktsu.Essentials.ObfuscationProviders.Caesar + ktsu.Essentials.ObfuscationProviders + + + + + + + + + + + + From ab27e260762b94122d0a66e3c7f6facb0b8d5f4c Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Mon, 29 Jun 2026 17:22:46 +1000 Subject: [PATCH 06/17] test: scope obfuscation string round-trip out of the shared byte-transform harness --- Essentials.Tests/ObfuscationProviderTests.cs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Essentials.Tests/ObfuscationProviderTests.cs b/Essentials.Tests/ObfuscationProviderTests.cs index 73fac47..62364ea 100644 --- a/Essentials.Tests/ObfuscationProviderTests.cs +++ b/Essentials.Tests/ObfuscationProviderTests.cs @@ -53,20 +53,6 @@ public void Obfuscation_Roundtrip_Stream(IObfuscationProvider provider, string p CollectionAssert.AreEqual(original, restored.ToArray(), $"{providerName} should restore original from stream"); } - [TestMethod] - [DynamicData(nameof(ObfuscationProviders))] - public void Obfuscation_Roundtrip_String(IObfuscationProvider provider, string providerName) - { - string original = "string obfuscate with " + providerName; - - string obfuscated = provider.Obfuscate(original); - byte[] obfuscatedBytes = Encoding.UTF8.GetBytes(obfuscated); - byte[] restoredBytes = provider.Deobfuscate(obfuscatedBytes); - string restored = Encoding.UTF8.GetString(restoredBytes); - - Assert.AreEqual(original, restored, $"{providerName} should restore original string"); - } - [TestMethod] [DynamicData(nameof(ObfuscationProviders))] public void Obfuscation_Async_Roundtrip(IObfuscationProvider provider, string providerName) From f935f7f82bb6d672d8874c175ae97f3472f939ef Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Mon, 29 Jun 2026 19:03:31 +1000 Subject: [PATCH 07/17] feat: add Reverse obfuscation provider --- Essentials.Tests/Essentials.Tests.csproj | 1 + .../ServiceCollectionExtensions.cs | 1 + Essentials.slnx | 2 + ObfuscationProviders/Reverse/Reverse.cs | 57 +++++++++++++++++++ ObfuscationProviders/Reverse/Reverse.csproj | 20 +++++++ 5 files changed, 81 insertions(+) create mode 100644 ObfuscationProviders/Reverse/Reverse.cs create mode 100644 ObfuscationProviders/Reverse/Reverse.csproj diff --git a/Essentials.Tests/Essentials.Tests.csproj b/Essentials.Tests/Essentials.Tests.csproj index c11a3fb..5f3df85 100644 --- a/Essentials.Tests/Essentials.Tests.csproj +++ b/Essentials.Tests/Essentials.Tests.csproj @@ -18,6 +18,7 @@ + diff --git a/Essentials.Tests/ServiceCollectionExtensions.cs b/Essentials.Tests/ServiceCollectionExtensions.cs index 12e3ced..ad12502 100644 --- a/Essentials.Tests/ServiceCollectionExtensions.cs +++ b/Essentials.Tests/ServiceCollectionExtensions.cs @@ -50,6 +50,7 @@ public static ServiceCollection AddObfuscationProviders(this ServiceCollection s { services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); return services; } diff --git a/Essentials.slnx b/Essentials.slnx index 737e6a8..c2ac196 100644 --- a/Essentials.slnx +++ b/Essentials.slnx @@ -25,8 +25,10 @@ + + diff --git a/ObfuscationProviders/Reverse/Reverse.cs b/ObfuscationProviders/Reverse/Reverse.cs new file mode 100644 index 0000000..f59f1f2 --- /dev/null +++ b/ObfuscationProviders/Reverse/Reverse.cs @@ -0,0 +1,57 @@ +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.ObfuscationProviders; + +using ktsu.Essentials; +using System; +using System.IO; + +/// +/// An obfuscation provider that reverses the byte order. Self-inverse. This is NOT encryption and +/// provides no confidentiality. +/// +public class Reverse : IObfuscationProvider +{ + /// + public bool TryObfuscate(ReadOnlySpan data, Span destination) + { + if (destination.Length < data.Length) + { + return false; + } + + for (int i = 0; i < data.Length; i++) + { + destination[i] = data[data.Length - 1 - i]; + } + + destination[data.Length..].Clear(); + return true; + } + + /// + public bool TryObfuscate(Stream data, Stream destination) + { + if (data is null || destination is null) + { + return false; + } + + using MemoryStream buffer = new(); + data.CopyTo(buffer); + byte[] bytes = buffer.ToArray(); + Array.Reverse(bytes); + destination.Write(bytes, 0, bytes.Length); + return true; + } + + /// + public bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Span destination) + => TryObfuscate(obfuscatedData, destination); + + /// + public bool TryDeobfuscate(Stream obfuscatedData, Stream destination) + => TryObfuscate(obfuscatedData, destination); +} diff --git a/ObfuscationProviders/Reverse/Reverse.csproj b/ObfuscationProviders/Reverse/Reverse.csproj new file mode 100644 index 0000000..d37b468 --- /dev/null +++ b/ObfuscationProviders/Reverse/Reverse.csproj @@ -0,0 +1,20 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + ktsu.Essentials.ObfuscationProviders.Reverse + ktsu.Essentials.ObfuscationProviders + + + + + + + + + + + + From 342b44d01abe7bbeea1dad8129b6687687cbc654 Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Mon, 29 Jun 2026 20:28:25 +1000 Subject: [PATCH 08/17] feat: add BitRotate obfuscation provider --- Essentials.Tests/Essentials.Tests.csproj | 1 + .../ServiceCollectionExtensions.cs | 1 + Essentials.slnx | 1 + ObfuscationProviders/BitRotate/BitRotate.cs | 105 ++++++++++++++++++ .../BitRotate/BitRotate.csproj | 20 ++++ 5 files changed, 128 insertions(+) create mode 100644 ObfuscationProviders/BitRotate/BitRotate.cs create mode 100644 ObfuscationProviders/BitRotate/BitRotate.csproj diff --git a/Essentials.Tests/Essentials.Tests.csproj b/Essentials.Tests/Essentials.Tests.csproj index 5f3df85..1ccf972 100644 --- a/Essentials.Tests/Essentials.Tests.csproj +++ b/Essentials.Tests/Essentials.Tests.csproj @@ -19,6 +19,7 @@ + diff --git a/Essentials.Tests/ServiceCollectionExtensions.cs b/Essentials.Tests/ServiceCollectionExtensions.cs index ad12502..7eed554 100644 --- a/Essentials.Tests/ServiceCollectionExtensions.cs +++ b/Essentials.Tests/ServiceCollectionExtensions.cs @@ -51,6 +51,7 @@ public static ServiceCollection AddObfuscationProviders(this ServiceCollection s services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); return services; } diff --git a/Essentials.slnx b/Essentials.slnx index c2ac196..d6c608d 100644 --- a/Essentials.slnx +++ b/Essentials.slnx @@ -24,6 +24,7 @@ + diff --git a/ObfuscationProviders/BitRotate/BitRotate.cs b/ObfuscationProviders/BitRotate/BitRotate.cs new file mode 100644 index 0000000..b475e08 --- /dev/null +++ b/ObfuscationProviders/BitRotate/BitRotate.cs @@ -0,0 +1,105 @@ +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.ObfuscationProviders; + +using ktsu.Essentials; +using System; +using System.IO; + +/// +/// An obfuscation provider that rotates the bits of each byte left when obfuscating and right when +/// deobfuscating. This is NOT encryption and provides no confidentiality. +/// +public class BitRotate : IObfuscationProvider +{ + private readonly int _bits; + + /// Initializes a new instance rotating by 3 bits. + public BitRotate() : this(3) { } + + /// Initializes a new instance rotating by the specified number of bits (1–7). + /// The number of bits to rotate; must be between 1 and 7 inclusive. + public BitRotate(int bits) + { + if (bits is < 1 or > 7) + { + throw new ArgumentOutOfRangeException(nameof(bits), bits, "Rotation must be between 1 and 7 bits."); + } + + _bits = bits; + } + + private static byte RotateLeft(byte value, int bits) => (byte)((value << bits) | (value >> (8 - bits))); + + private static byte RotateRight(byte value, int bits) => (byte)((value >> bits) | (value << (8 - bits))); + + /// + public bool TryObfuscate(ReadOnlySpan data, Span destination) + { + if (destination.Length < data.Length) + { + return false; + } + + for (int i = 0; i < data.Length; i++) + { + destination[i] = RotateLeft(data[i], _bits); + } + + destination[data.Length..].Clear(); + return true; + } + + /// + public bool TryObfuscate(Stream data, Stream destination) + { + if (data is null || destination is null) + { + return false; + } + + int b; + while ((b = data.ReadByte()) >= 0) + { + destination.WriteByte(RotateLeft((byte)b, _bits)); + } + + return true; + } + + /// + public bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Span destination) + { + if (destination.Length < obfuscatedData.Length) + { + return false; + } + + for (int i = 0; i < obfuscatedData.Length; i++) + { + destination[i] = RotateRight(obfuscatedData[i], _bits); + } + + destination[obfuscatedData.Length..].Clear(); + return true; + } + + /// + public bool TryDeobfuscate(Stream obfuscatedData, Stream destination) + { + if (obfuscatedData is null || destination is null) + { + return false; + } + + int b; + while ((b = obfuscatedData.ReadByte()) >= 0) + { + destination.WriteByte(RotateRight((byte)b, _bits)); + } + + return true; + } +} diff --git a/ObfuscationProviders/BitRotate/BitRotate.csproj b/ObfuscationProviders/BitRotate/BitRotate.csproj new file mode 100644 index 0000000..c421862 --- /dev/null +++ b/ObfuscationProviders/BitRotate/BitRotate.csproj @@ -0,0 +1,20 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + ktsu.Essentials.ObfuscationProviders.BitRotate + ktsu.Essentials.ObfuscationProviders + + + + + + + + + + + + From dda0e339b55948044e0d701aa94447f501ce71a3 Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Mon, 29 Jun 2026 22:55:11 +1000 Subject: [PATCH 09/17] feat: add Base64 obfuscation provider composing the Base64 encoder --- Essentials.Tests/Essentials.Tests.csproj | 1 + Essentials.Tests/ObfuscationProviderTests.cs | 12 ++++++ .../ServiceCollectionExtensions.cs | 1 + Essentials.slnx | 1 + ObfuscationProviders/Base64/Base64.cs | 37 +++++++++++++++++++ ObfuscationProviders/Base64/Base64.csproj | 21 +++++++++++ 6 files changed, 73 insertions(+) create mode 100644 ObfuscationProviders/Base64/Base64.cs create mode 100644 ObfuscationProviders/Base64/Base64.csproj diff --git a/Essentials.Tests/Essentials.Tests.csproj b/Essentials.Tests/Essentials.Tests.csproj index 1ccf972..6a71408 100644 --- a/Essentials.Tests/Essentials.Tests.csproj +++ b/Essentials.Tests/Essentials.Tests.csproj @@ -20,6 +20,7 @@ + diff --git a/Essentials.Tests/ObfuscationProviderTests.cs b/Essentials.Tests/ObfuscationProviderTests.cs index 62364ea..0991a8c 100644 --- a/Essentials.Tests/ObfuscationProviderTests.cs +++ b/Essentials.Tests/ObfuscationProviderTests.cs @@ -69,4 +69,16 @@ public void Obfuscation_Async_Roundtrip(IObfuscationProvider provider, string pr CollectionAssert.AreEqual(original, restored.ToArray(), $"{providerName} async should restore original"); } + + [TestMethod] + public void Obfuscation_Base64_Roundtrip_String() + { + IObfuscationProvider provider = new ObfuscationProviders.Base64(); + string original = "string obfuscate via base64"; + string obfuscated = provider.Obfuscate(original); + byte[] obfuscatedBytes = System.Text.Encoding.UTF8.GetBytes(obfuscated); + byte[] restoredBytes = provider.Deobfuscate(obfuscatedBytes); + string restored = System.Text.Encoding.UTF8.GetString(restoredBytes); + Assert.AreEqual(original, restored); + } } \ No newline at end of file diff --git a/Essentials.Tests/ServiceCollectionExtensions.cs b/Essentials.Tests/ServiceCollectionExtensions.cs index 7eed554..13cdb59 100644 --- a/Essentials.Tests/ServiceCollectionExtensions.cs +++ b/Essentials.Tests/ServiceCollectionExtensions.cs @@ -52,6 +52,7 @@ public static ServiceCollection AddObfuscationProviders(this ServiceCollection s services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); return services; } diff --git a/Essentials.slnx b/Essentials.slnx index d6c608d..bdec02d 100644 --- a/Essentials.slnx +++ b/Essentials.slnx @@ -24,6 +24,7 @@ + diff --git a/ObfuscationProviders/Base64/Base64.cs b/ObfuscationProviders/Base64/Base64.cs new file mode 100644 index 0000000..fb9a6c4 --- /dev/null +++ b/ObfuscationProviders/Base64/Base64.cs @@ -0,0 +1,37 @@ +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.ObfuscationProviders; + +using ktsu.Essentials; +using System; +using System.IO; + +/// +/// An obfuscation provider that composes a Base64 : obfuscation is +/// Base64 encoding, deobfuscation is Base64 decoding. This is NOT encryption. +/// +public class Base64 : IObfuscationProvider +{ + private readonly IEncodingProvider _encoder; + + /// Initializes a new instance using the default Base64 encoder. + public Base64() : this(new EncodingProviders.Base64()) { } + + /// Initializes a new instance using the supplied encoder. + /// The encoding provider used to perform the transform. + private Base64(IEncodingProvider encoder) => _encoder = Ensure.NotNull(encoder); + + /// + public bool TryObfuscate(ReadOnlySpan data, Span destination) => _encoder.TryEncode(data, destination); + + /// + public bool TryObfuscate(Stream data, Stream destination) => _encoder.TryEncode(data, destination); + + /// + public bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Span destination) => _encoder.TryDecode(obfuscatedData, destination); + + /// + public bool TryDeobfuscate(Stream obfuscatedData, Stream destination) => _encoder.TryDecode(obfuscatedData, destination); +} diff --git a/ObfuscationProviders/Base64/Base64.csproj b/ObfuscationProviders/Base64/Base64.csproj new file mode 100644 index 0000000..78bb194 --- /dev/null +++ b/ObfuscationProviders/Base64/Base64.csproj @@ -0,0 +1,21 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + ktsu.Essentials.ObfuscationProviders.Base64 + ktsu.Essentials.ObfuscationProviders + + + + + + + + + + + + + From d4f03a2ef7127b7be2091b05b5db8352d446009d Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Mon, 29 Jun 2026 23:10:13 +1000 Subject: [PATCH 10/17] fix: keep Base64 obfuscator encoder ctor public; register via factory to avoid DI greedy-ctor --- Essentials.Tests/ServiceCollectionExtensions.cs | 2 +- ObfuscationProviders/Base64/Base64.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Essentials.Tests/ServiceCollectionExtensions.cs b/Essentials.Tests/ServiceCollectionExtensions.cs index 13cdb59..f9695c0 100644 --- a/Essentials.Tests/ServiceCollectionExtensions.cs +++ b/Essentials.Tests/ServiceCollectionExtensions.cs @@ -52,7 +52,7 @@ public static ServiceCollection AddObfuscationProviders(this ServiceCollection s services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(_ => new ObfuscationProviders.Base64()); return services; } diff --git a/ObfuscationProviders/Base64/Base64.cs b/ObfuscationProviders/Base64/Base64.cs index fb9a6c4..b7ea487 100644 --- a/ObfuscationProviders/Base64/Base64.cs +++ b/ObfuscationProviders/Base64/Base64.cs @@ -21,7 +21,8 @@ public Base64() : this(new EncodingProviders.Base64()) { } /// Initializes a new instance using the supplied encoder. /// The encoding provider used to perform the transform. - private Base64(IEncodingProvider encoder) => _encoder = Ensure.NotNull(encoder); + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Public constructor required for DI registration via factory lambda")] + public Base64(IEncodingProvider encoder) => _encoder = Ensure.NotNull(encoder); /// public bool TryObfuscate(ReadOnlySpan data, Span destination) => _encoder.TryEncode(data, destination); From 786b4fc6a408627ade75aa0786c0c7a45e3bfafa Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Tue, 30 Jun 2026 00:22:53 +1000 Subject: [PATCH 11/17] feat: add Hex obfuscation provider composing the Hex encoder --- Essentials.Tests/Essentials.Tests.csproj | 1 + Essentials.Tests/ObfuscationProviderTests.cs | 12 ++++++ .../ServiceCollectionExtensions.cs | 1 + Essentials.slnx | 1 + ObfuscationProviders/Hex/Hex.cs | 38 +++++++++++++++++++ ObfuscationProviders/Hex/Hex.csproj | 21 ++++++++++ 6 files changed, 74 insertions(+) create mode 100644 ObfuscationProviders/Hex/Hex.cs create mode 100644 ObfuscationProviders/Hex/Hex.csproj diff --git a/Essentials.Tests/Essentials.Tests.csproj b/Essentials.Tests/Essentials.Tests.csproj index 6a71408..64d1a41 100644 --- a/Essentials.Tests/Essentials.Tests.csproj +++ b/Essentials.Tests/Essentials.Tests.csproj @@ -21,6 +21,7 @@ + diff --git a/Essentials.Tests/ObfuscationProviderTests.cs b/Essentials.Tests/ObfuscationProviderTests.cs index 0991a8c..c75aa06 100644 --- a/Essentials.Tests/ObfuscationProviderTests.cs +++ b/Essentials.Tests/ObfuscationProviderTests.cs @@ -81,4 +81,16 @@ public void Obfuscation_Base64_Roundtrip_String() string restored = System.Text.Encoding.UTF8.GetString(restoredBytes); Assert.AreEqual(original, restored); } + + [TestMethod] + public void Obfuscation_Hex_Roundtrip_String() + { + IObfuscationProvider provider = new ObfuscationProviders.Hex(); + string original = "string obfuscate via hex"; + string obfuscated = provider.Obfuscate(original); + byte[] obfuscatedBytes = System.Text.Encoding.UTF8.GetBytes(obfuscated); + byte[] restoredBytes = provider.Deobfuscate(obfuscatedBytes); + string restored = System.Text.Encoding.UTF8.GetString(restoredBytes); + Assert.AreEqual(original, restored); + } } \ No newline at end of file diff --git a/Essentials.Tests/ServiceCollectionExtensions.cs b/Essentials.Tests/ServiceCollectionExtensions.cs index f9695c0..670b9b6 100644 --- a/Essentials.Tests/ServiceCollectionExtensions.cs +++ b/Essentials.Tests/ServiceCollectionExtensions.cs @@ -53,6 +53,7 @@ public static ServiceCollection AddObfuscationProviders(this ServiceCollection s services.AddSingleton(); services.AddSingleton(); services.AddSingleton(_ => new ObfuscationProviders.Base64()); + services.AddSingleton(_ => new ObfuscationProviders.Hex()); return services; } diff --git a/Essentials.slnx b/Essentials.slnx index bdec02d..7b3a895 100644 --- a/Essentials.slnx +++ b/Essentials.slnx @@ -27,6 +27,7 @@ + diff --git a/ObfuscationProviders/Hex/Hex.cs b/ObfuscationProviders/Hex/Hex.cs new file mode 100644 index 0000000..00cc8e2 --- /dev/null +++ b/ObfuscationProviders/Hex/Hex.cs @@ -0,0 +1,38 @@ +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.ObfuscationProviders; + +using ktsu.Essentials; +using System; +using System.IO; + +/// +/// An obfuscation provider that composes a Hex : obfuscation is hex +/// encoding, deobfuscation is hex decoding. This is NOT encryption. +/// +public class Hex : IObfuscationProvider +{ + private readonly IEncodingProvider _encoder; + + /// Initializes a new instance using the default Hex encoder. + public Hex() : this(new EncodingProviders.Hex()) { } + + /// Initializes a new instance using the supplied encoder. + /// The encoding provider used to perform the transform. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Public constructor required for DI registration via factory lambda")] + public Hex(IEncodingProvider encoder) => _encoder = Ensure.NotNull(encoder); + + /// + public bool TryObfuscate(ReadOnlySpan data, Span destination) => _encoder.TryEncode(data, destination); + + /// + public bool TryObfuscate(Stream data, Stream destination) => _encoder.TryEncode(data, destination); + + /// + public bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Span destination) => _encoder.TryDecode(obfuscatedData, destination); + + /// + public bool TryDeobfuscate(Stream obfuscatedData, Stream destination) => _encoder.TryDecode(obfuscatedData, destination); +} diff --git a/ObfuscationProviders/Hex/Hex.csproj b/ObfuscationProviders/Hex/Hex.csproj new file mode 100644 index 0000000..877f755 --- /dev/null +++ b/ObfuscationProviders/Hex/Hex.csproj @@ -0,0 +1,21 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + ktsu.Essentials.ObfuscationProviders.Hex + ktsu.Essentials.ObfuscationProviders + + + + + + + + + + + + + From d156bb1c7797da873ef307a325eeca27ee69a63d Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Tue, 30 Jun 2026 01:37:52 +1000 Subject: [PATCH 12/17] feat: add Composite obfuscation provider that pipelines a chain --- Essentials.Tests/Essentials.Tests.csproj | 9 +- .../ServiceCollectionExtensions.cs | 1 + Essentials.slnx | 1 + ObfuscationProviders/Composite/Composite.cs | 110 ++++++++++++++++++ .../Composite/Composite.csproj | 20 ++++ 5 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 ObfuscationProviders/Composite/Composite.cs create mode 100644 ObfuscationProviders/Composite/Composite.csproj diff --git a/Essentials.Tests/Essentials.Tests.csproj b/Essentials.Tests/Essentials.Tests.csproj index 64d1a41..1c8ff57 100644 --- a/Essentials.Tests/Essentials.Tests.csproj +++ b/Essentials.Tests/Essentials.Tests.csproj @@ -16,12 +16,13 @@ - - - - + + + + + diff --git a/Essentials.Tests/ServiceCollectionExtensions.cs b/Essentials.Tests/ServiceCollectionExtensions.cs index 670b9b6..bcc7ab8 100644 --- a/Essentials.Tests/ServiceCollectionExtensions.cs +++ b/Essentials.Tests/ServiceCollectionExtensions.cs @@ -54,6 +54,7 @@ public static ServiceCollection AddObfuscationProviders(this ServiceCollection s services.AddSingleton(); services.AddSingleton(_ => new ObfuscationProviders.Base64()); services.AddSingleton(_ => new ObfuscationProviders.Hex()); + services.AddSingleton(_ => new Composite([new Xor(), new BitRotate()])); return services; } diff --git a/Essentials.slnx b/Essentials.slnx index 7b3a895..edd24a4 100644 --- a/Essentials.slnx +++ b/Essentials.slnx @@ -27,6 +27,7 @@ + diff --git a/ObfuscationProviders/Composite/Composite.cs b/ObfuscationProviders/Composite/Composite.cs new file mode 100644 index 0000000..343bd6f --- /dev/null +++ b/ObfuscationProviders/Composite/Composite.cs @@ -0,0 +1,110 @@ +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.ObfuscationProviders; + +using System; +using System.Collections.Generic; +using System.IO; +using ktsu.Essentials; + +/// +/// An obfuscation provider that pipelines an ordered list of obfuscators. Obfuscation applies the +/// stages in order; deobfuscation applies them in reverse order. This is NOT encryption. +/// +public class Composite : IObfuscationProvider +{ + private readonly IReadOnlyList _stages; + + /// Initializes a new instance with the ordered obfuscation stages. + /// The non-empty ordered list of obfuscators to pipeline. + public Composite(IReadOnlyList stages) + { + Ensure.NotNull(stages); + if (stages.Count == 0) + { + throw new ArgumentException("At least one stage is required.", nameof(stages)); + } + + _stages = stages; + } + + /// + public bool TryObfuscate(ReadOnlySpan data, Span destination) + { + byte[] current = data.ToArray(); + foreach (IObfuscationProvider stage in _stages) + { + current = stage.Obfuscate(current); + } + + if (destination.Length < current.Length) + { + return false; + } + + current.CopyTo(destination); + destination[current.Length..].Clear(); + return true; + } + + /// + public bool TryObfuscate(Stream data, Stream destination) + { + if (data is null || destination is null) + { + return false; + } + + using MemoryStream buffer = new(); + data.CopyTo(buffer); + byte[] current = buffer.ToArray(); + foreach (IObfuscationProvider stage in _stages) + { + current = stage.Obfuscate(current); + } + + destination.Write(current, 0, current.Length); + return true; + } + + /// + public bool TryDeobfuscate(ReadOnlySpan obfuscatedData, Span destination) + { + byte[] current = obfuscatedData.ToArray(); + for (int i = _stages.Count - 1; i >= 0; i--) + { + current = _stages[i].Deobfuscate(current); + } + + if (destination.Length < current.Length) + { + return false; + } + + current.CopyTo(destination); + destination[current.Length..].Clear(); + return true; + } + + /// + public bool TryDeobfuscate(Stream obfuscatedData, Stream destination) + { + if (obfuscatedData is null || destination is null) + { + return false; + } + + using MemoryStream buffer = new(); + obfuscatedData.CopyTo(buffer); + byte[] current = buffer.ToArray(); + for (int i = _stages.Count - 1; i >= 0; i--) + { + current = _stages[i].Deobfuscate(current); + } + + destination.Write(current, 0, current.Length); + return true; + } +} \ No newline at end of file diff --git a/ObfuscationProviders/Composite/Composite.csproj b/ObfuscationProviders/Composite/Composite.csproj new file mode 100644 index 0000000..710c854 --- /dev/null +++ b/ObfuscationProviders/Composite/Composite.csproj @@ -0,0 +1,20 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + ktsu.Essentials.ObfuscationProviders.Composite + ktsu.Essentials.ObfuscationProviders + + + + + + + + + + + + From f88ff75a9c7db00e8e007a83dcfa9fbd5a655c86 Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Tue, 30 Jun 2026 16:45:45 +1000 Subject: [PATCH 13/17] refactor: conform serialization providers to SDK naming convention Rename SerializationProviders/{Json,Toml,Yaml} to flat dotted-name root folders matching the Semantics convention, drop the AssemblyName/RootNamespace overrides, and let ktsu.Sdk derive identity from the folder path. Fixes the PackageId that was frozen to ktsu.SerializationProviders.Json (missing the Essentials prefix) before the csproj override could apply. Classes renamed to SerializationProvider to avoid namespace/type collisions. --- .../CompatibilitySuppressions.xml | 0 ...entials.SerializationProviders.Json.csproj | 4 +--- .../JsonSerializationProvider.cs | 4 ++-- .../CompatibilitySuppressions.xml | 0 ...entials.SerializationProviders.Toml.csproj | 4 +--- .../TomlSerializationProvider.cs | 4 ++-- .../CompatibilitySuppressions.xml | 0 ...entials.SerializationProviders.Yaml.csproj | 4 +--- .../YamlSerializationProvider.cs | 4 ++-- Essentials.Tests/DiTests.cs | 2 +- Essentials.Tests/Essentials.Tests.csproj | 6 ++--- Essentials.Tests/PersistenceProviderTests.cs | 23 ++++++++++--------- .../SerializationProviderTests.cs | 10 ++++---- .../ServiceCollectionExtensions.cs | 10 ++++---- Essentials.slnx | 6 ++--- 15 files changed, 40 insertions(+), 41 deletions(-) rename {SerializationProviders/Json => Essentials.SerializationProviders.Json}/CompatibilitySuppressions.xml (100%) rename SerializationProviders/Json/Json.csproj => Essentials.SerializationProviders.Json/Essentials.SerializationProviders.Json.csproj (70%) rename SerializationProviders/Json/Json.cs => Essentials.SerializationProviders.Json/JsonSerializationProvider.cs (93%) rename {SerializationProviders/Toml => Essentials.SerializationProviders.Toml}/CompatibilitySuppressions.xml (100%) rename SerializationProviders/Toml/Toml.csproj => Essentials.SerializationProviders.Toml/Essentials.SerializationProviders.Toml.csproj (69%) rename SerializationProviders/Toml/Toml.cs => Essentials.SerializationProviders.Toml/TomlSerializationProvider.cs (95%) rename {SerializationProviders/Yaml => Essentials.SerializationProviders.Yaml}/CompatibilitySuppressions.xml (100%) rename SerializationProviders/Yaml/Yaml.csproj => Essentials.SerializationProviders.Yaml/Essentials.SerializationProviders.Yaml.csproj (69%) rename SerializationProviders/Yaml/Yaml.cs => Essentials.SerializationProviders.Yaml/YamlSerializationProvider.cs (94%) diff --git a/SerializationProviders/Json/CompatibilitySuppressions.xml b/Essentials.SerializationProviders.Json/CompatibilitySuppressions.xml similarity index 100% rename from SerializationProviders/Json/CompatibilitySuppressions.xml rename to Essentials.SerializationProviders.Json/CompatibilitySuppressions.xml diff --git a/SerializationProviders/Json/Json.csproj b/Essentials.SerializationProviders.Json/Essentials.SerializationProviders.Json.csproj similarity index 70% rename from SerializationProviders/Json/Json.csproj rename to Essentials.SerializationProviders.Json/Essentials.SerializationProviders.Json.csproj index 33cd051..64913d6 100644 --- a/SerializationProviders/Json/Json.csproj +++ b/Essentials.SerializationProviders.Json/Essentials.SerializationProviders.Json.csproj @@ -4,12 +4,10 @@ net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 true - ktsu.Essentials.SerializationProviders.Json - ktsu.Essentials.SerializationProviders - + diff --git a/SerializationProviders/Json/Json.cs b/Essentials.SerializationProviders.Json/JsonSerializationProvider.cs similarity index 93% rename from SerializationProviders/Json/Json.cs rename to Essentials.SerializationProviders.Json/JsonSerializationProvider.cs index 203bb46..04b787b 100644 --- a/SerializationProviders/Json/Json.cs +++ b/Essentials.SerializationProviders.Json/JsonSerializationProvider.cs @@ -2,7 +2,7 @@ // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.SerializationProviders; +namespace ktsu.Essentials.SerializationProviders.Json; using ktsu.Essentials; using System; @@ -12,7 +12,7 @@ namespace ktsu.Essentials.SerializationProviders; /// /// A serialization provider that uses System.Text.Json for serializing and deserializing objects. /// -public class Json : ISerializationProvider +public class JsonSerializationProvider : ISerializationProvider { private readonly JsonSerializerOptions options = new() { diff --git a/SerializationProviders/Toml/CompatibilitySuppressions.xml b/Essentials.SerializationProviders.Toml/CompatibilitySuppressions.xml similarity index 100% rename from SerializationProviders/Toml/CompatibilitySuppressions.xml rename to Essentials.SerializationProviders.Toml/CompatibilitySuppressions.xml diff --git a/SerializationProviders/Toml/Toml.csproj b/Essentials.SerializationProviders.Toml/Essentials.SerializationProviders.Toml.csproj similarity index 69% rename from SerializationProviders/Toml/Toml.csproj rename to Essentials.SerializationProviders.Toml/Essentials.SerializationProviders.Toml.csproj index b379a69..ebbf48d 100644 --- a/SerializationProviders/Toml/Toml.csproj +++ b/Essentials.SerializationProviders.Toml/Essentials.SerializationProviders.Toml.csproj @@ -4,12 +4,10 @@ net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 true - ktsu.Essentials.SerializationProviders.Toml - ktsu.Essentials.SerializationProviders - + diff --git a/SerializationProviders/Toml/Toml.cs b/Essentials.SerializationProviders.Toml/TomlSerializationProvider.cs similarity index 95% rename from SerializationProviders/Toml/Toml.cs rename to Essentials.SerializationProviders.Toml/TomlSerializationProvider.cs index fc76510..b5660ec 100644 --- a/SerializationProviders/Toml/Toml.cs +++ b/Essentials.SerializationProviders.Toml/TomlSerializationProvider.cs @@ -2,7 +2,7 @@ // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.SerializationProviders; +namespace ktsu.Essentials.SerializationProviders.Toml; using ktsu.Essentials; using System; @@ -17,7 +17,7 @@ namespace ktsu.Essentials.SerializationProviders; /// /// A serialization provider that uses Tomlyn for serializing and deserializing objects. /// -public class Toml : ISerializationProvider +public class TomlSerializationProvider : ISerializationProvider { /// /// Tries to serialize the specified object into the writer. diff --git a/SerializationProviders/Yaml/CompatibilitySuppressions.xml b/Essentials.SerializationProviders.Yaml/CompatibilitySuppressions.xml similarity index 100% rename from SerializationProviders/Yaml/CompatibilitySuppressions.xml rename to Essentials.SerializationProviders.Yaml/CompatibilitySuppressions.xml diff --git a/SerializationProviders/Yaml/Yaml.csproj b/Essentials.SerializationProviders.Yaml/Essentials.SerializationProviders.Yaml.csproj similarity index 69% rename from SerializationProviders/Yaml/Yaml.csproj rename to Essentials.SerializationProviders.Yaml/Essentials.SerializationProviders.Yaml.csproj index e05228b..03bb26b 100644 --- a/SerializationProviders/Yaml/Yaml.csproj +++ b/Essentials.SerializationProviders.Yaml/Essentials.SerializationProviders.Yaml.csproj @@ -4,12 +4,10 @@ net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 true - ktsu.Essentials.SerializationProviders.Yaml - ktsu.Essentials.SerializationProviders - + diff --git a/SerializationProviders/Yaml/Yaml.cs b/Essentials.SerializationProviders.Yaml/YamlSerializationProvider.cs similarity index 94% rename from SerializationProviders/Yaml/Yaml.cs rename to Essentials.SerializationProviders.Yaml/YamlSerializationProvider.cs index 0abd3b9..524eef7 100644 --- a/SerializationProviders/Yaml/Yaml.cs +++ b/Essentials.SerializationProviders.Yaml/YamlSerializationProvider.cs @@ -2,7 +2,7 @@ // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.SerializationProviders; +namespace ktsu.Essentials.SerializationProviders.Yaml; using ktsu.Essentials; using System; @@ -15,7 +15,7 @@ namespace ktsu.Essentials.SerializationProviders; /// /// A serialization provider that uses YamlDotNet for serializing and deserializing objects. /// -public class Yaml : ISerializationProvider +public class YamlSerializationProvider : ISerializationProvider { private readonly IDeserializer deserializer = new DeserializerBuilder() .WithNamingConvention(CamelCaseNamingConvention.Instance) diff --git a/Essentials.Tests/DiTests.cs b/Essentials.Tests/DiTests.cs index 8dcee75..8fff198 100644 --- a/Essentials.Tests/DiTests.cs +++ b/Essentials.Tests/DiTests.cs @@ -116,7 +116,7 @@ public void DI_Can_Resolve_Multiple_Serialization_Providers() Assert.HasCount(3, providers, "Should resolve all 3 serialization providers"); // Verify all expected types are present - string[] expectedTypes = ["Json", "Toml", "Yaml"]; + string[] expectedTypes = ["JsonSerializationProvider", "TomlSerializationProvider", "YamlSerializationProvider"]; string[] actualTypes = [.. providers.Select(p => p.GetType().Name).OrderBy(n => n)]; CollectionAssert.AreEquivalent(expectedTypes, actualTypes); } diff --git a/Essentials.Tests/Essentials.Tests.csproj b/Essentials.Tests/Essentials.Tests.csproj index 1c8ff57..2f058ac 100644 --- a/Essentials.Tests/Essentials.Tests.csproj +++ b/Essentials.Tests/Essentials.Tests.csproj @@ -44,9 +44,9 @@ - - - + + + diff --git a/Essentials.Tests/PersistenceProviderTests.cs b/Essentials.Tests/PersistenceProviderTests.cs index bbf5a88..41b0ac4 100644 --- a/Essentials.Tests/PersistenceProviderTests.cs +++ b/Essentials.Tests/PersistenceProviderTests.cs @@ -8,6 +8,7 @@ namespace ktsu.Essentials.Tests; using System.IO; using ktsu.Essentials; using ktsu.Essentials.PersistenceProviders; +using ktsu.Essentials.SerializationProviders.Json; using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -147,7 +148,7 @@ public async System.Threading.Tasks.Task FileSystem_Store_And_Retrieve() try { FileSystemProviders.Native fs = new(); - SerializationProviders.Json serializer = new(); + JsonSerializationProvider serializer = new(); FileSystem persistence = new(fs, serializer, tempDir); await persistence.StoreAsync("key1", new TestData { Name = "test" }, TestContext.CancellationToken).ConfigureAwait(false); @@ -169,7 +170,7 @@ public async System.Threading.Tasks.Task FileSystem_Exists_And_Remove() try { FileSystemProviders.Native fs = new(); - SerializationProviders.Json serializer = new(); + JsonSerializationProvider serializer = new(); FileSystem persistence = new(fs, serializer, tempDir); await persistence.StoreAsync("key1", "value1", TestContext.CancellationToken).ConfigureAwait(false); @@ -192,7 +193,7 @@ public async System.Threading.Tasks.Task FileSystem_GetAllKeys_And_Clear() try { FileSystemProviders.Native fs = new(); - SerializationProviders.Json serializer = new(); + JsonSerializationProvider serializer = new(); FileSystem persistence = new(fs, serializer, tempDir); await persistence.StoreAsync("a", "1", TestContext.CancellationToken).ConfigureAwait(false); @@ -216,7 +217,7 @@ public void FileSystem_Properties() { string tempDir = Path.Combine(Path.GetTempPath(), "PersistenceTests_FS_" + Guid.NewGuid().ToString("N")[..8]); FileSystemProviders.Native fs = new(); - SerializationProviders.Json serializer = new(); + JsonSerializationProvider serializer = new(); FileSystem persistence = new(fs, serializer, tempDir); Assert.AreEqual("FileSystem", persistence.ProviderName); @@ -230,7 +231,7 @@ public async System.Threading.Tasks.Task AppData_Store_And_Retrieve() { string appName = "PersistenceTests_AD_" + Guid.NewGuid().ToString("N")[..8]; FileSystemProviders.Native fs = new(); - SerializationProviders.Json serializer = new(); + JsonSerializationProvider serializer = new(); AppData persistence = new(fs, serializer, appName); try @@ -254,7 +255,7 @@ public async System.Threading.Tasks.Task AppData_Exists_And_Remove() { string appName = "PersistenceTests_AD_" + Guid.NewGuid().ToString("N")[..8]; FileSystemProviders.Native fs = new(); - SerializationProviders.Json serializer = new(); + JsonSerializationProvider serializer = new(); AppData persistence = new(fs, serializer, appName); try @@ -278,7 +279,7 @@ public void AppData_Properties() { string appName = "PersistenceTests_AD_" + Guid.NewGuid().ToString("N")[..8]; FileSystemProviders.Native fs = new(); - SerializationProviders.Json serializer = new(); + JsonSerializationProvider serializer = new(); AppData persistence = new(fs, serializer, appName); Assert.AreEqual("AppData", persistence.ProviderName); @@ -291,7 +292,7 @@ public void AppData_Properties() public async System.Threading.Tasks.Task Temp_Store_And_Retrieve() { FileSystemProviders.Native fs = new(); - SerializationProviders.Json serializer = new(); + JsonSerializationProvider serializer = new(); using Temp persistence = new(fs, serializer, "PersistenceTests_Temp"); try @@ -312,7 +313,7 @@ public async System.Threading.Tasks.Task Temp_Store_And_Retrieve() public async System.Threading.Tasks.Task Temp_Exists_And_Remove() { FileSystemProviders.Native fs = new(); - SerializationProviders.Json serializer = new(); + JsonSerializationProvider serializer = new(); using Temp persistence = new(fs, serializer, "PersistenceTests_Temp"); try @@ -334,7 +335,7 @@ public async System.Threading.Tasks.Task Temp_Exists_And_Remove() public async System.Threading.Tasks.Task Temp_GetAllKeys_And_Clear() { FileSystemProviders.Native fs = new(); - SerializationProviders.Json serializer = new(); + JsonSerializationProvider serializer = new(); using Temp persistence = new(fs, serializer, "PersistenceTests_Temp"); try @@ -359,7 +360,7 @@ public async System.Threading.Tasks.Task Temp_GetAllKeys_And_Clear() public void Temp_Properties() { FileSystemProviders.Native fs = new(); - SerializationProviders.Json serializer = new(); + JsonSerializationProvider serializer = new(); using Temp persistence = new(fs, serializer, "PersistenceTests_Temp"); try diff --git a/Essentials.Tests/SerializationProviderTests.cs b/Essentials.Tests/SerializationProviderTests.cs index d7d2ecb..23bd8ed 100644 --- a/Essentials.Tests/SerializationProviderTests.cs +++ b/Essentials.Tests/SerializationProviderTests.cs @@ -7,7 +7,9 @@ namespace ktsu.Essentials.Tests; using System.Collections.Generic; using System.Text; using ktsu.Essentials; -using ktsu.Essentials.SerializationProviders; +using ktsu.Essentials.SerializationProviders.Json; +using ktsu.Essentials.SerializationProviders.Toml; +using ktsu.Essentials.SerializationProviders.Yaml; using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -17,9 +19,9 @@ public class ConfigurationProviderTests private static ServiceProvider BuildProvider() { ServiceCollection services = new(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); return services.BuildServiceProvider(); } diff --git a/Essentials.Tests/ServiceCollectionExtensions.cs b/Essentials.Tests/ServiceCollectionExtensions.cs index bcc7ab8..d431c60 100644 --- a/Essentials.Tests/ServiceCollectionExtensions.cs +++ b/Essentials.Tests/ServiceCollectionExtensions.cs @@ -9,7 +9,9 @@ namespace ktsu.Essentials.Tests; using ktsu.Essentials.EncryptionProviders; using ktsu.Essentials.HashProviders; using ktsu.Essentials.ObfuscationProviders; -using ktsu.Essentials.SerializationProviders; +using ktsu.Essentials.SerializationProviders.Json; +using ktsu.Essentials.SerializationProviders.Toml; +using ktsu.Essentials.SerializationProviders.Yaml; using Microsoft.Extensions.DependencyInjection; public static class ServiceCollectionExtensions @@ -86,9 +88,9 @@ public static ServiceCollection AddHashProviders(this ServiceCollection services public static ServiceCollection AddSerializationProviders(this ServiceCollection services) { - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); return services; } diff --git a/Essentials.slnx b/Essentials.slnx index edd24a4..4149b5b 100644 --- a/Essentials.slnx +++ b/Essentials.slnx @@ -66,9 +66,9 @@ - - - + + + From 614ad9ab250b0dc62d21d72db6e88ac173b286c7 Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Tue, 30 Jun 2026 20:23:15 +1000 Subject: [PATCH 14/17] refactor: conform all providers to SDK naming convention Apply the same fix piloted on the serialization providers to all 38 remaining provider projects across the 11 other categories. Each provider: - moves to a flat dotted-name root folder (Essentials..), matching the Semantics.* convention - drops the AssemblyName/RootNamespace overrides so ktsu.Sdk derives identity from the folder path (fixes PackageId, which was frozen to the prefix-less ktsu.. before the override could apply) - gets its own namespace ktsu.Essentials.. and a collision-free class name (e.g. Gzip -> GzipCompressionProvider, SHA256 -> SHA256HashProvider) The Xor provider's namespace keeps a targeted, namespace-scoped CA1716 suppression (Xor is a reserved keyword) in GlobalSuppressions.cs. Test project, DI registrations, and type-name assertions updated accordingly. Build: 0 warnings across all TFMs. Tests: 286/286 passing. --- CacheProviders/InMemory/InMemory.csproj | 20 ---- CommandExecutors/Native/Native.csproj | 20 ---- CompressionProviders/Brotli/Brotli.csproj | 20 ---- CompressionProviders/Deflate/Deflate.csproj | 20 ---- CompressionProviders/Gzip/Gzip.csproj | 20 ---- EncodingProviders/Base64/Base64.csproj | 20 ---- EncodingProviders/Hex/Hex.csproj | 20 ---- EncryptionProviders/Aes/Aes.csproj | 20 ---- .../CompatibilitySuppressions.xml | 0 .../Essentials.CacheProviders.InMemory.csproj | 4 +- .../InMemoryCacheProvider.cs | 6 +- .../CompatibilitySuppressions.xml | 0 .../Essentials.CommandExecutors.Native.csproj | 4 +- .../NativeCommandExecutor.cs | 6 +- .../BrotliCompressionProvider.cs | 6 +- .../CompatibilitySuppressions.xml | 0 ...entials.CompressionProviders.Brotli.csproj | 4 +- .../CompatibilitySuppressions.xml | 0 .../DeflateCompressionProvider.cs | 6 +- ...ntials.CompressionProviders.Deflate.csproj | 4 +- .../CompatibilitySuppressions.xml | 0 ...ssentials.CompressionProviders.Gzip.csproj | 18 +++ .../GlobalSuppressions.cs | 2 +- .../GzipCompressionProvider.cs | 6 +- .../CompatibilitySuppressions.xml | 0 ...ssentials.CompressionProviders.ZLib.csproj | 4 +- .../ZLibCompressionProvider.cs | 6 +- .../Base64EncodingProvider.cs | 6 +- .../CompatibilitySuppressions.xml | 0 ...Essentials.EncodingProviders.Base64.csproj | 18 +++ .../CompatibilitySuppressions.xml | 0 .../Essentials.EncodingProviders.Hex.csproj | 18 +++ .../HexEncodingProvider.cs | 6 +- .../AesEncryptionProvider.cs | 10 +- .../CompatibilitySuppressions.xml | 0 .../Essentials.EncryptionProviders.Aes.csproj | 18 +++ .../GlobalSuppressions.cs | 2 +- .../CompatibilitySuppressions.xml | 0 ...sentials.FileSystemProviders.Native.csproj | 6 +- .../GlobalSuppressions.cs | 2 +- .../NativeFileSystemProvider.cs | 10 +- .../CRC32HashProvider.cs | 6 +- .../CompatibilitySuppressions.xml | 0 .../Essentials.HashProviders.CRC32.csproj | 4 +- .../CRC64HashProvider.cs | 6 +- .../CompatibilitySuppressions.xml | 0 .../Essentials.HashProviders.CRC64.csproj | 4 +- .../CompatibilitySuppressions.xml | 0 .../Essentials.HashProviders.FNV1_32.csproj | 18 +++ .../FNV1_32HashProvider.cs | 6 +- .../GlobalSuppressions.cs | 2 +- .../CompatibilitySuppressions.xml | 0 .../Essentials.HashProviders.FNV1_64.csproj | 18 +++ .../FNV1_64HashProvider.cs | 6 +- .../GlobalSuppressions.cs | 2 +- .../CompatibilitySuppressions.xml | 0 .../Essentials.HashProviders.FNV1a_32.csproj | 18 +++ .../FNV1a_32HashProvider.cs | 6 +- .../GlobalSuppressions.cs | 2 +- .../CompatibilitySuppressions.xml | 0 .../Essentials.HashProviders.FNV1a_64.csproj | 18 +++ .../FNV1a_64HashProvider.cs | 6 +- .../GlobalSuppressions.cs | 2 +- .../CompatibilitySuppressions.xml | 0 .../Essentials.HashProviders.MD5.csproj | 18 +++ .../GlobalSuppressions.cs | 2 +- .../MD5HashProvider.cs | 10 +- .../CompatibilitySuppressions.xml | 0 .../Essentials.HashProviders.SHA1.csproj | 18 +++ .../GlobalSuppressions.cs | 2 +- .../SHA1HashProvider.cs | 14 +-- .../CompatibilitySuppressions.xml | 0 .../Essentials.HashProviders.SHA256.csproj | 18 +++ .../GlobalSuppressions.cs | 2 +- .../SHA256HashProvider.cs | 14 +-- .../CompatibilitySuppressions.xml | 0 .../Essentials.HashProviders.SHA384.csproj | 18 +++ .../GlobalSuppressions.cs | 2 +- .../SHA384HashProvider.cs | 14 +-- .../CompatibilitySuppressions.xml | 0 .../Essentials.HashProviders.SHA512.csproj | 18 +++ .../GlobalSuppressions.cs | 2 +- .../SHA512HashProvider.cs | 14 +-- .../CompatibilitySuppressions.xml | 0 .../Essentials.HashProviders.XxHash128.csproj | 4 +- .../XxHash128HashProvider.cs | 6 +- .../CompatibilitySuppressions.xml | 0 .../Essentials.HashProviders.XxHash3.csproj | 4 +- .../XxHash3HashProvider.cs | 6 +- .../CompatibilitySuppressions.xml | 0 .../Essentials.HashProviders.XxHash32.csproj | 19 +++ .../XxHash32HashProvider.cs | 6 +- .../CompatibilitySuppressions.xml | 0 .../Essentials.HashProviders.XxHash64.csproj | 19 +++ .../XxHash64HashProvider.cs | 6 +- .../CompatibilitySuppressions.xml | 0 .../ConsoleLoggingProvider.cs | 6 +- ...Essentials.LoggingProviders.Console.csproj | 18 +++ .../CompatibilitySuppressions.xml | 0 ...ntials.NavigationProviders.InMemory.csproj | 18 +++ .../InMemoryNavigationProvider.cs | 6 +- .../Base64ObfuscationProvider.cs | 8 +- ...entials.ObfuscationProviders.Base64.csproj | 19 +++ .../BitRotateObfuscationProvider.cs | 10 +- ...ials.ObfuscationProviders.BitRotate.csproj | 18 +++ .../CaesarObfuscationProvider.cs | 4 +- ...entials.ObfuscationProviders.Caesar.csproj | 18 +++ .../CompositeObfuscationProvider.cs | 6 +- ...ials.ObfuscationProviders.Composite.csproj | 18 +++ ...Essentials.ObfuscationProviders.Hex.csproj | 19 +++ .../HexObfuscationProvider.cs | 8 +- ...ntials.ObfuscationProviders.Reverse.csproj | 18 +++ .../ReverseObfuscationProvider.cs | 6 +- ...Essentials.ObfuscationProviders.Xor.csproj | 18 +++ .../GlobalSuppressions.cs | 7 ++ .../XorObfuscationProvider.cs | 10 +- .../AppDataPersistenceProvider.cs | 10 +- ...ntials.PersistenceProviders.AppData.csproj | 6 +- ...als.PersistenceProviders.FileSystem.csproj | 6 +- .../FileSystemPersistenceProvider.cs | 8 +- .../CompatibilitySuppressions.xml | 0 ...tials.PersistenceProviders.InMemory.csproj | 18 +++ .../InMemoryPersistenceProvider.cs | 6 +- ...ssentials.PersistenceProviders.Temp.csproj | 6 +- .../TempPersistenceProvider.cs | 8 +- Essentials.Tests/DiTests.cs | 19 +-- Essentials.Tests/Essentials.Tests.csproj | 78 ++++++------- Essentials.Tests/HashProviderTests.cs | 18 +-- Essentials.Tests/ObfuscationProviderTests.cs | 6 +- Essentials.Tests/PersistenceProviderTests.cs | 81 ++++++------- .../ServiceCollectionExtensions.cs | 109 +++++++++++------- Essentials.slnx | 78 ++++++------- HashProviders/FNV1_32/FNV1_32.csproj | 20 ---- HashProviders/FNV1_64/FNV1_64.csproj | 20 ---- HashProviders/FNV1a_32/FNV1a_32.csproj | 20 ---- HashProviders/FNV1a_64/FNV1a_64.csproj | 20 ---- HashProviders/SHA512/SHA512.csproj | 20 ---- HashProviders/XxHash128/XxHash128.csproj | 21 ---- HashProviders/XxHash64/XxHash64.csproj | 21 ---- LoggingProviders/Console/Console.csproj | 20 ---- NavigationProviders/InMemory/InMemory.csproj | 20 ---- ObfuscationProviders/Base64/Base64.csproj | 21 ---- .../BitRotate/BitRotate.csproj | 20 ---- ObfuscationProviders/Caesar/Caesar.csproj | 20 ---- .../Composite/Composite.csproj | 20 ---- ObfuscationProviders/Hex/Hex.csproj | 21 ---- ObfuscationProviders/Reverse/Reverse.csproj | 20 ---- ObfuscationProviders/Xor/Xor.csproj | 20 ---- PersistenceProviders/InMemory/InMemory.csproj | 20 ---- 149 files changed, 848 insertions(+), 880 deletions(-) delete mode 100644 CacheProviders/InMemory/InMemory.csproj delete mode 100644 CommandExecutors/Native/Native.csproj delete mode 100644 CompressionProviders/Brotli/Brotli.csproj delete mode 100644 CompressionProviders/Deflate/Deflate.csproj delete mode 100644 CompressionProviders/Gzip/Gzip.csproj delete mode 100644 EncodingProviders/Base64/Base64.csproj delete mode 100644 EncodingProviders/Hex/Hex.csproj delete mode 100644 EncryptionProviders/Aes/Aes.csproj rename {CacheProviders/InMemory => Essentials.CacheProviders.InMemory}/CompatibilitySuppressions.xml (100%) rename HashProviders/MD5/MD5.csproj => Essentials.CacheProviders.InMemory/Essentials.CacheProviders.InMemory.csproj (69%) rename CacheProviders/InMemory/InMemory.cs => Essentials.CacheProviders.InMemory/InMemoryCacheProvider.cs (92%) rename {CommandExecutors/Native => Essentials.CommandExecutors.Native}/CompatibilitySuppressions.xml (100%) rename HashProviders/SHA1/SHA1.csproj => Essentials.CommandExecutors.Native/Essentials.CommandExecutors.Native.csproj (69%) rename CommandExecutors/Native/Native.cs => Essentials.CommandExecutors.Native/NativeCommandExecutor.cs (96%) rename CompressionProviders/Brotli/Brotli.cs => Essentials.CompressionProviders.Brotli/BrotliCompressionProvider.cs (96%) rename {CompressionProviders/Brotli => Essentials.CompressionProviders.Brotli}/CompatibilitySuppressions.xml (100%) rename HashProviders/SHA256/SHA256.csproj => Essentials.CompressionProviders.Brotli/Essentials.CompressionProviders.Brotli.csproj (69%) rename {CompressionProviders/Deflate => Essentials.CompressionProviders.Deflate}/CompatibilitySuppressions.xml (100%) rename CompressionProviders/Deflate/Deflate.cs => Essentials.CompressionProviders.Deflate/DeflateCompressionProvider.cs (96%) rename HashProviders/SHA384/SHA384.csproj => Essentials.CompressionProviders.Deflate/Essentials.CompressionProviders.Deflate.csproj (69%) rename {CompressionProviders/Gzip => Essentials.CompressionProviders.Gzip}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.CompressionProviders.Gzip/Essentials.CompressionProviders.Gzip.csproj rename {CompressionProviders/Gzip => Essentials.CompressionProviders.Gzip}/GlobalSuppressions.cs (67%) rename CompressionProviders/Gzip/Gzip.cs => Essentials.CompressionProviders.Gzip/GzipCompressionProvider.cs (96%) rename {CompressionProviders/ZLib => Essentials.CompressionProviders.ZLib}/CompatibilitySuppressions.xml (100%) rename CompressionProviders/ZLib/ZLib.csproj => Essentials.CompressionProviders.ZLib/Essentials.CompressionProviders.ZLib.csproj (67%) rename CompressionProviders/ZLib/ZLib.cs => Essentials.CompressionProviders.ZLib/ZLibCompressionProvider.cs (96%) rename EncodingProviders/Base64/Base64.cs => Essentials.EncodingProviders.Base64/Base64EncodingProvider.cs (96%) rename {EncodingProviders/Base64 => Essentials.EncodingProviders.Base64}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.EncodingProviders.Base64/Essentials.EncodingProviders.Base64.csproj rename {EncodingProviders/Hex => Essentials.EncodingProviders.Hex}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.EncodingProviders.Hex/Essentials.EncodingProviders.Hex.csproj rename EncodingProviders/Hex/Hex.cs => Essentials.EncodingProviders.Hex/HexEncodingProvider.cs (97%) rename EncryptionProviders/Aes/Aes.cs => Essentials.EncryptionProviders.Aes/AesEncryptionProvider.cs (96%) rename {EncryptionProviders/Aes => Essentials.EncryptionProviders.Aes}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.EncryptionProviders.Aes/Essentials.EncryptionProviders.Aes.csproj rename {EncryptionProviders/Aes => Essentials.EncryptionProviders.Aes}/GlobalSuppressions.cs (90%) rename {FileSystemProviders/Native => Essentials.FileSystemProviders.Native}/CompatibilitySuppressions.xml (100%) rename FileSystemProviders/Native/Native.csproj => Essentials.FileSystemProviders.Native/Essentials.FileSystemProviders.Native.csproj (69%) rename {FileSystemProviders/Native => Essentials.FileSystemProviders.Native}/GlobalSuppressions.cs (67%) rename FileSystemProviders/Native/Native.cs => Essentials.FileSystemProviders.Native/NativeFileSystemProvider.cs (83%) rename HashProviders/CRC32/CRC32.cs => Essentials.HashProviders.CRC32/CRC32HashProvider.cs (94%) rename {HashProviders/CRC32 => Essentials.HashProviders.CRC32}/CompatibilitySuppressions.xml (100%) rename HashProviders/CRC32/CRC32.csproj => Essentials.HashProviders.CRC32/Essentials.HashProviders.CRC32.csproj (71%) rename HashProviders/CRC64/CRC64.cs => Essentials.HashProviders.CRC64/CRC64HashProvider.cs (94%) rename {HashProviders/CRC64 => Essentials.HashProviders.CRC64}/CompatibilitySuppressions.xml (100%) rename HashProviders/CRC64/CRC64.csproj => Essentials.HashProviders.CRC64/Essentials.HashProviders.CRC64.csproj (71%) rename {HashProviders/FNV1_32 => Essentials.HashProviders.FNV1_32}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.HashProviders.FNV1_32/Essentials.HashProviders.FNV1_32.csproj rename HashProviders/FNV1_32/FNV1_32.cs => Essentials.HashProviders.FNV1_32/FNV1_32HashProvider.cs (95%) rename {HashProviders/FNV1_64 => Essentials.HashProviders.FNV1_32}/GlobalSuppressions.cs (90%) rename {HashProviders/FNV1_64 => Essentials.HashProviders.FNV1_64}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.HashProviders.FNV1_64/Essentials.HashProviders.FNV1_64.csproj rename HashProviders/FNV1_64/FNV1_64.cs => Essentials.HashProviders.FNV1_64/FNV1_64HashProvider.cs (95%) rename {HashProviders/FNV1a_64 => Essentials.HashProviders.FNV1_64}/GlobalSuppressions.cs (90%) rename {HashProviders/FNV1a_32 => Essentials.HashProviders.FNV1a_32}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.HashProviders.FNV1a_32/Essentials.HashProviders.FNV1a_32.csproj rename HashProviders/FNV1a_32/FNV1a_32.cs => Essentials.HashProviders.FNV1a_32/FNV1a_32HashProvider.cs (95%) rename {HashProviders/FNV1a_32 => Essentials.HashProviders.FNV1a_32}/GlobalSuppressions.cs (90%) rename {HashProviders/FNV1a_64 => Essentials.HashProviders.FNV1a_64}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.HashProviders.FNV1a_64/Essentials.HashProviders.FNV1a_64.csproj rename HashProviders/FNV1a_64/FNV1a_64.cs => Essentials.HashProviders.FNV1a_64/FNV1a_64HashProvider.cs (95%) rename {HashProviders/FNV1_32 => Essentials.HashProviders.FNV1a_64}/GlobalSuppressions.cs (90%) rename {HashProviders/MD5 => Essentials.HashProviders.MD5}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.HashProviders.MD5/Essentials.HashProviders.MD5.csproj rename {HashProviders/MD5 => Essentials.HashProviders.MD5}/GlobalSuppressions.cs (94%) rename HashProviders/MD5/MD5.cs => Essentials.HashProviders.MD5/MD5HashProvider.cs (90%) rename {HashProviders/SHA1 => Essentials.HashProviders.SHA1}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.HashProviders.SHA1/Essentials.HashProviders.SHA1.csproj rename {HashProviders/SHA1 => Essentials.HashProviders.SHA1}/GlobalSuppressions.cs (94%) rename HashProviders/SHA1/SHA1.cs => Essentials.HashProviders.SHA1/SHA1HashProvider.cs (85%) rename {HashProviders/SHA256 => Essentials.HashProviders.SHA256}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.HashProviders.SHA256/Essentials.HashProviders.SHA256.csproj rename {HashProviders/SHA256 => Essentials.HashProviders.SHA256}/GlobalSuppressions.cs (91%) rename HashProviders/SHA256/SHA256.cs => Essentials.HashProviders.SHA256/SHA256HashProvider.cs (84%) rename {HashProviders/SHA384 => Essentials.HashProviders.SHA384}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.HashProviders.SHA384/Essentials.HashProviders.SHA384.csproj rename {HashProviders/SHA384 => Essentials.HashProviders.SHA384}/GlobalSuppressions.cs (91%) rename HashProviders/SHA384/SHA384.cs => Essentials.HashProviders.SHA384/SHA384HashProvider.cs (85%) rename {HashProviders/SHA512 => Essentials.HashProviders.SHA512}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.HashProviders.SHA512/Essentials.HashProviders.SHA512.csproj rename {HashProviders/SHA512 => Essentials.HashProviders.SHA512}/GlobalSuppressions.cs (91%) rename HashProviders/SHA512/SHA512.cs => Essentials.HashProviders.SHA512/SHA512HashProvider.cs (85%) rename {HashProviders/XxHash128 => Essentials.HashProviders.XxHash128}/CompatibilitySuppressions.xml (100%) rename HashProviders/XxHash3/XxHash3.csproj => Essentials.HashProviders.XxHash128/Essentials.HashProviders.XxHash128.csproj (71%) rename HashProviders/XxHash128/XxHash128.cs => Essentials.HashProviders.XxHash128/XxHash128HashProvider.cs (93%) rename {HashProviders/XxHash3 => Essentials.HashProviders.XxHash3}/CompatibilitySuppressions.xml (100%) rename HashProviders/XxHash32/XxHash32.csproj => Essentials.HashProviders.XxHash3/Essentials.HashProviders.XxHash3.csproj (71%) rename HashProviders/XxHash3/XxHash3.cs => Essentials.HashProviders.XxHash3/XxHash3HashProvider.cs (93%) rename {HashProviders/XxHash32 => Essentials.HashProviders.XxHash32}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.HashProviders.XxHash32/Essentials.HashProviders.XxHash32.csproj rename HashProviders/XxHash32/XxHash32.cs => Essentials.HashProviders.XxHash32/XxHash32HashProvider.cs (93%) rename {HashProviders/XxHash64 => Essentials.HashProviders.XxHash64}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.HashProviders.XxHash64/Essentials.HashProviders.XxHash64.csproj rename HashProviders/XxHash64/XxHash64.cs => Essentials.HashProviders.XxHash64/XxHash64HashProvider.cs (93%) rename {LoggingProviders/Console => Essentials.LoggingProviders.Console}/CompatibilitySuppressions.xml (100%) rename LoggingProviders/Console/Console.cs => Essentials.LoggingProviders.Console/ConsoleLoggingProvider.cs (94%) create mode 100644 Essentials.LoggingProviders.Console/Essentials.LoggingProviders.Console.csproj rename {NavigationProviders/InMemory => Essentials.NavigationProviders.InMemory}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.NavigationProviders.InMemory/Essentials.NavigationProviders.InMemory.csproj rename NavigationProviders/InMemory/InMemory.cs => Essentials.NavigationProviders.InMemory/InMemoryNavigationProvider.cs (95%) rename ObfuscationProviders/Base64/Base64.cs => Essentials.ObfuscationProviders.Base64/Base64ObfuscationProvider.cs (81%) create mode 100644 Essentials.ObfuscationProviders.Base64/Essentials.ObfuscationProviders.Base64.csproj rename ObfuscationProviders/BitRotate/BitRotate.cs => Essentials.ObfuscationProviders.BitRotate/BitRotateObfuscationProvider.cs (90%) create mode 100644 Essentials.ObfuscationProviders.BitRotate/Essentials.ObfuscationProviders.BitRotate.csproj rename ObfuscationProviders/Caesar/Caesar.cs => Essentials.ObfuscationProviders.Caesar/CaesarObfuscationProvider.cs (92%) create mode 100644 Essentials.ObfuscationProviders.Caesar/Essentials.ObfuscationProviders.Caesar.csproj rename ObfuscationProviders/Composite/Composite.cs => Essentials.ObfuscationProviders.Composite/CompositeObfuscationProvider.cs (92%) create mode 100644 Essentials.ObfuscationProviders.Composite/Essentials.ObfuscationProviders.Composite.csproj create mode 100644 Essentials.ObfuscationProviders.Hex/Essentials.ObfuscationProviders.Hex.csproj rename ObfuscationProviders/Hex/Hex.cs => Essentials.ObfuscationProviders.Hex/HexObfuscationProvider.cs (82%) create mode 100644 Essentials.ObfuscationProviders.Reverse/Essentials.ObfuscationProviders.Reverse.csproj rename ObfuscationProviders/Reverse/Reverse.cs => Essentials.ObfuscationProviders.Reverse/ReverseObfuscationProvider.cs (89%) create mode 100644 Essentials.ObfuscationProviders.Xor/Essentials.ObfuscationProviders.Xor.csproj create mode 100644 Essentials.ObfuscationProviders.Xor/GlobalSuppressions.cs rename ObfuscationProviders/Xor/Xor.cs => Essentials.ObfuscationProviders.Xor/XorObfuscationProvider.cs (83%) rename PersistenceProviders/AppData/AppData.cs => Essentials.PersistenceProviders.AppData/AppDataPersistenceProvider.cs (96%) rename PersistenceProviders/Temp/Temp.csproj => Essentials.PersistenceProviders.AppData/Essentials.PersistenceProviders.AppData.csproj (69%) rename PersistenceProviders/AppData/AppData.csproj => Essentials.PersistenceProviders.FileSystem/Essentials.PersistenceProviders.FileSystem.csproj (68%) rename PersistenceProviders/FileSystem/FileSystem.cs => Essentials.PersistenceProviders.FileSystem/FileSystemPersistenceProvider.cs (96%) rename {PersistenceProviders/InMemory => Essentials.PersistenceProviders.InMemory}/CompatibilitySuppressions.xml (100%) create mode 100644 Essentials.PersistenceProviders.InMemory/Essentials.PersistenceProviders.InMemory.csproj rename PersistenceProviders/InMemory/InMemory.cs => Essentials.PersistenceProviders.InMemory/InMemoryPersistenceProvider.cs (95%) rename PersistenceProviders/FileSystem/FileSystem.csproj => Essentials.PersistenceProviders.Temp/Essentials.PersistenceProviders.Temp.csproj (68%) rename PersistenceProviders/Temp/Temp.cs => Essentials.PersistenceProviders.Temp/TempPersistenceProvider.cs (97%) delete mode 100644 HashProviders/FNV1_32/FNV1_32.csproj delete mode 100644 HashProviders/FNV1_64/FNV1_64.csproj delete mode 100644 HashProviders/FNV1a_32/FNV1a_32.csproj delete mode 100644 HashProviders/FNV1a_64/FNV1a_64.csproj delete mode 100644 HashProviders/SHA512/SHA512.csproj delete mode 100644 HashProviders/XxHash128/XxHash128.csproj delete mode 100644 HashProviders/XxHash64/XxHash64.csproj delete mode 100644 LoggingProviders/Console/Console.csproj delete mode 100644 NavigationProviders/InMemory/InMemory.csproj delete mode 100644 ObfuscationProviders/Base64/Base64.csproj delete mode 100644 ObfuscationProviders/BitRotate/BitRotate.csproj delete mode 100644 ObfuscationProviders/Caesar/Caesar.csproj delete mode 100644 ObfuscationProviders/Composite/Composite.csproj delete mode 100644 ObfuscationProviders/Hex/Hex.csproj delete mode 100644 ObfuscationProviders/Reverse/Reverse.csproj delete mode 100644 ObfuscationProviders/Xor/Xor.csproj delete mode 100644 PersistenceProviders/InMemory/InMemory.csproj diff --git a/CacheProviders/InMemory/InMemory.csproj b/CacheProviders/InMemory/InMemory.csproj deleted file mode 100644 index 9ff43cc..0000000 --- a/CacheProviders/InMemory/InMemory.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.CacheProviders.InMemory - ktsu.Essentials.CacheProviders - - - - - - - - - - - - diff --git a/CommandExecutors/Native/Native.csproj b/CommandExecutors/Native/Native.csproj deleted file mode 100644 index ad719b7..0000000 --- a/CommandExecutors/Native/Native.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.CommandExecutors.Native - ktsu.Essentials.CommandExecutors - - - - - - - - - - - - diff --git a/CompressionProviders/Brotli/Brotli.csproj b/CompressionProviders/Brotli/Brotli.csproj deleted file mode 100644 index c371860..0000000 --- a/CompressionProviders/Brotli/Brotli.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.CompressionProviders.Brotli - ktsu.Essentials.CompressionProviders - - - - - - - - - - - - diff --git a/CompressionProviders/Deflate/Deflate.csproj b/CompressionProviders/Deflate/Deflate.csproj deleted file mode 100644 index 6f73ce2..0000000 --- a/CompressionProviders/Deflate/Deflate.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.CompressionProviders.Deflate - ktsu.Essentials.CompressionProviders - - - - - - - - - - - - diff --git a/CompressionProviders/Gzip/Gzip.csproj b/CompressionProviders/Gzip/Gzip.csproj deleted file mode 100644 index c19bd39..0000000 --- a/CompressionProviders/Gzip/Gzip.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.CompressionProviders.Gzip - ktsu.Essentials.CompressionProviders - - - - - - - - - - - - diff --git a/EncodingProviders/Base64/Base64.csproj b/EncodingProviders/Base64/Base64.csproj deleted file mode 100644 index b276616..0000000 --- a/EncodingProviders/Base64/Base64.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.EncodingProviders.Base64 - ktsu.Essentials.EncodingProviders - - - - - - - - - - - - diff --git a/EncodingProviders/Hex/Hex.csproj b/EncodingProviders/Hex/Hex.csproj deleted file mode 100644 index e32155c..0000000 --- a/EncodingProviders/Hex/Hex.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.EncodingProviders.Hex - ktsu.Essentials.EncodingProviders - - - - - - - - - - - - diff --git a/EncryptionProviders/Aes/Aes.csproj b/EncryptionProviders/Aes/Aes.csproj deleted file mode 100644 index 824e8a8..0000000 --- a/EncryptionProviders/Aes/Aes.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.EncryptionProviders.Aes - ktsu.Essentials.EncryptionProviders - - - - - - - - - - - - diff --git a/CacheProviders/InMemory/CompatibilitySuppressions.xml b/Essentials.CacheProviders.InMemory/CompatibilitySuppressions.xml similarity index 100% rename from CacheProviders/InMemory/CompatibilitySuppressions.xml rename to Essentials.CacheProviders.InMemory/CompatibilitySuppressions.xml diff --git a/HashProviders/MD5/MD5.csproj b/Essentials.CacheProviders.InMemory/Essentials.CacheProviders.InMemory.csproj similarity index 69% rename from HashProviders/MD5/MD5.csproj rename to Essentials.CacheProviders.InMemory/Essentials.CacheProviders.InMemory.csproj index c309554..db750c2 100644 --- a/HashProviders/MD5/MD5.csproj +++ b/Essentials.CacheProviders.InMemory/Essentials.CacheProviders.InMemory.csproj @@ -4,12 +4,10 @@ net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 true - ktsu.Essentials.HashProviders.MD5 - ktsu.Essentials.HashProviders - + diff --git a/CacheProviders/InMemory/InMemory.cs b/Essentials.CacheProviders.InMemory/InMemoryCacheProvider.cs similarity index 92% rename from CacheProviders/InMemory/InMemory.cs rename to Essentials.CacheProviders.InMemory/InMemoryCacheProvider.cs index e421af2..c9ef2a3 100644 --- a/CacheProviders/InMemory/InMemory.cs +++ b/Essentials.CacheProviders.InMemory/InMemoryCacheProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.CacheProviders; +namespace ktsu.Essentials.CacheProviders.InMemory; using ktsu.Essentials; using System; @@ -13,7 +13,7 @@ namespace ktsu.Essentials.CacheProviders; /// /// The type of the cache key. /// The type of the cached value. -public class InMemory : ICacheProvider where TKey : notnull +public class InMemoryCacheProvider : ICacheProvider where TKey : notnull { private readonly ConcurrentDictionary cache = new(); diff --git a/CommandExecutors/Native/CompatibilitySuppressions.xml b/Essentials.CommandExecutors.Native/CompatibilitySuppressions.xml similarity index 100% rename from CommandExecutors/Native/CompatibilitySuppressions.xml rename to Essentials.CommandExecutors.Native/CompatibilitySuppressions.xml diff --git a/HashProviders/SHA1/SHA1.csproj b/Essentials.CommandExecutors.Native/Essentials.CommandExecutors.Native.csproj similarity index 69% rename from HashProviders/SHA1/SHA1.csproj rename to Essentials.CommandExecutors.Native/Essentials.CommandExecutors.Native.csproj index 7abed09..db750c2 100644 --- a/HashProviders/SHA1/SHA1.csproj +++ b/Essentials.CommandExecutors.Native/Essentials.CommandExecutors.Native.csproj @@ -4,12 +4,10 @@ net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 true - ktsu.Essentials.HashProviders.SHA1 - ktsu.Essentials.HashProviders - + diff --git a/CommandExecutors/Native/Native.cs b/Essentials.CommandExecutors.Native/NativeCommandExecutor.cs similarity index 96% rename from CommandExecutors/Native/Native.cs rename to Essentials.CommandExecutors.Native/NativeCommandExecutor.cs index ab5b24c..9548d0f 100644 --- a/CommandExecutors/Native/Native.cs +++ b/Essentials.CommandExecutors.Native/NativeCommandExecutor.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.CommandExecutors; +namespace ktsu.Essentials.CommandExecutors.Native; using ktsu.Essentials; using System; @@ -15,7 +15,7 @@ namespace ktsu.Essentials.CommandExecutors; /// /// A command executor that uses the native operating system shell to execute commands. /// -public class Native : ICommandExecutor +public class NativeCommandExecutor : ICommandExecutor { /// /// Executes a command asynchronously and returns the result. diff --git a/CompressionProviders/Brotli/Brotli.cs b/Essentials.CompressionProviders.Brotli/BrotliCompressionProvider.cs similarity index 96% rename from CompressionProviders/Brotli/Brotli.cs rename to Essentials.CompressionProviders.Brotli/BrotliCompressionProvider.cs index dcdb0f7..f23c29e 100644 --- a/CompressionProviders/Brotli/Brotli.cs +++ b/Essentials.CompressionProviders.Brotli/BrotliCompressionProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.CompressionProviders; +namespace ktsu.Essentials.CompressionProviders.Brotli; using ktsu.Essentials; using System; @@ -12,7 +12,7 @@ namespace ktsu.Essentials.CompressionProviders; /// /// A compression provider that uses Brotli for data compression and decompression. /// -public class Brotli : ICompressionProvider +public class BrotliCompressionProvider : ICompressionProvider { /// /// Tries to compress the data from the span and write the result to the destination. diff --git a/CompressionProviders/Brotli/CompatibilitySuppressions.xml b/Essentials.CompressionProviders.Brotli/CompatibilitySuppressions.xml similarity index 100% rename from CompressionProviders/Brotli/CompatibilitySuppressions.xml rename to Essentials.CompressionProviders.Brotli/CompatibilitySuppressions.xml diff --git a/HashProviders/SHA256/SHA256.csproj b/Essentials.CompressionProviders.Brotli/Essentials.CompressionProviders.Brotli.csproj similarity index 69% rename from HashProviders/SHA256/SHA256.csproj rename to Essentials.CompressionProviders.Brotli/Essentials.CompressionProviders.Brotli.csproj index 23c4c68..db750c2 100644 --- a/HashProviders/SHA256/SHA256.csproj +++ b/Essentials.CompressionProviders.Brotli/Essentials.CompressionProviders.Brotli.csproj @@ -4,12 +4,10 @@ net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 true - ktsu.Essentials.HashProviders.SHA256 - ktsu.Essentials.HashProviders - + diff --git a/CompressionProviders/Deflate/CompatibilitySuppressions.xml b/Essentials.CompressionProviders.Deflate/CompatibilitySuppressions.xml similarity index 100% rename from CompressionProviders/Deflate/CompatibilitySuppressions.xml rename to Essentials.CompressionProviders.Deflate/CompatibilitySuppressions.xml diff --git a/CompressionProviders/Deflate/Deflate.cs b/Essentials.CompressionProviders.Deflate/DeflateCompressionProvider.cs similarity index 96% rename from CompressionProviders/Deflate/Deflate.cs rename to Essentials.CompressionProviders.Deflate/DeflateCompressionProvider.cs index b9afb52..0ce342b 100644 --- a/CompressionProviders/Deflate/Deflate.cs +++ b/Essentials.CompressionProviders.Deflate/DeflateCompressionProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.CompressionProviders; +namespace ktsu.Essentials.CompressionProviders.Deflate; using ktsu.Essentials; using System; @@ -12,7 +12,7 @@ namespace ktsu.Essentials.CompressionProviders; /// /// A compression provider that uses Deflate for data compression and decompression. /// -public class Deflate : ICompressionProvider +public class DeflateCompressionProvider : ICompressionProvider { /// /// Tries to compress the data from the span and write the result to the destination. diff --git a/HashProviders/SHA384/SHA384.csproj b/Essentials.CompressionProviders.Deflate/Essentials.CompressionProviders.Deflate.csproj similarity index 69% rename from HashProviders/SHA384/SHA384.csproj rename to Essentials.CompressionProviders.Deflate/Essentials.CompressionProviders.Deflate.csproj index 08126bc..db750c2 100644 --- a/HashProviders/SHA384/SHA384.csproj +++ b/Essentials.CompressionProviders.Deflate/Essentials.CompressionProviders.Deflate.csproj @@ -4,12 +4,10 @@ net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 true - ktsu.Essentials.HashProviders.SHA384 - ktsu.Essentials.HashProviders - + diff --git a/CompressionProviders/Gzip/CompatibilitySuppressions.xml b/Essentials.CompressionProviders.Gzip/CompatibilitySuppressions.xml similarity index 100% rename from CompressionProviders/Gzip/CompatibilitySuppressions.xml rename to Essentials.CompressionProviders.Gzip/CompatibilitySuppressions.xml diff --git a/Essentials.CompressionProviders.Gzip/Essentials.CompressionProviders.Gzip.csproj b/Essentials.CompressionProviders.Gzip/Essentials.CompressionProviders.Gzip.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.CompressionProviders.Gzip/Essentials.CompressionProviders.Gzip.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/CompressionProviders/Gzip/GlobalSuppressions.cs b/Essentials.CompressionProviders.Gzip/GlobalSuppressions.cs similarity index 67% rename from CompressionProviders/Gzip/GlobalSuppressions.cs rename to Essentials.CompressionProviders.Gzip/GlobalSuppressions.cs index e8451a9..2a5064c 100644 --- a/CompressionProviders/Gzip/GlobalSuppressions.cs +++ b/Essentials.CompressionProviders.Gzip/GlobalSuppressions.cs @@ -1,3 +1,3 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. diff --git a/CompressionProviders/Gzip/Gzip.cs b/Essentials.CompressionProviders.Gzip/GzipCompressionProvider.cs similarity index 96% rename from CompressionProviders/Gzip/Gzip.cs rename to Essentials.CompressionProviders.Gzip/GzipCompressionProvider.cs index f9046ec..41c2839 100644 --- a/CompressionProviders/Gzip/Gzip.cs +++ b/Essentials.CompressionProviders.Gzip/GzipCompressionProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.CompressionProviders; +namespace ktsu.Essentials.CompressionProviders.Gzip; using ktsu.Essentials; using System; @@ -12,7 +12,7 @@ namespace ktsu.Essentials.CompressionProviders; /// /// A compression provider that uses GZip for data compression and decompression. /// -public class Gzip : ICompressionProvider +public class GzipCompressionProvider : ICompressionProvider { /// /// Tries to compress the data from the span and write the result to the destination. diff --git a/CompressionProviders/ZLib/CompatibilitySuppressions.xml b/Essentials.CompressionProviders.ZLib/CompatibilitySuppressions.xml similarity index 100% rename from CompressionProviders/ZLib/CompatibilitySuppressions.xml rename to Essentials.CompressionProviders.ZLib/CompatibilitySuppressions.xml diff --git a/CompressionProviders/ZLib/ZLib.csproj b/Essentials.CompressionProviders.ZLib/Essentials.CompressionProviders.ZLib.csproj similarity index 67% rename from CompressionProviders/ZLib/ZLib.csproj rename to Essentials.CompressionProviders.ZLib/Essentials.CompressionProviders.ZLib.csproj index 7a21419..38cfeb1 100644 --- a/CompressionProviders/ZLib/ZLib.csproj +++ b/Essentials.CompressionProviders.ZLib/Essentials.CompressionProviders.ZLib.csproj @@ -4,12 +4,10 @@ net10.0;net9.0;net8.0;net7.0;net6.0 true - ktsu.Essentials.CompressionProviders.ZLib - ktsu.Essentials.CompressionProviders - + diff --git a/CompressionProviders/ZLib/ZLib.cs b/Essentials.CompressionProviders.ZLib/ZLibCompressionProvider.cs similarity index 96% rename from CompressionProviders/ZLib/ZLib.cs rename to Essentials.CompressionProviders.ZLib/ZLibCompressionProvider.cs index 86b1e62..e3882eb 100644 --- a/CompressionProviders/ZLib/ZLib.cs +++ b/Essentials.CompressionProviders.ZLib/ZLibCompressionProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.CompressionProviders; +namespace ktsu.Essentials.CompressionProviders.ZLib; using ktsu.Essentials; using System; @@ -12,7 +12,7 @@ namespace ktsu.Essentials.CompressionProviders; /// /// A compression provider that uses ZLib for data compression and decompression. /// -public class ZLib : ICompressionProvider +public class ZLibCompressionProvider : ICompressionProvider { /// /// Tries to compress the data from the span and write the result to the destination. diff --git a/EncodingProviders/Base64/Base64.cs b/Essentials.EncodingProviders.Base64/Base64EncodingProvider.cs similarity index 96% rename from EncodingProviders/Base64/Base64.cs rename to Essentials.EncodingProviders.Base64/Base64EncodingProvider.cs index 91b6c1d..e84f46b 100644 --- a/EncodingProviders/Base64/Base64.cs +++ b/Essentials.EncodingProviders.Base64/Base64EncodingProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.EncodingProviders; +namespace ktsu.Essentials.EncodingProviders.Base64; using ktsu.Essentials; using System; @@ -12,7 +12,7 @@ namespace ktsu.Essentials.EncodingProviders; /// /// An encoding provider that uses Base64 encoding for data encoding and decoding. /// -public class Base64 : IEncodingProvider +public class Base64EncodingProvider : IEncodingProvider { /// /// Tries to encode the data from the span and write the result to the destination. diff --git a/EncodingProviders/Base64/CompatibilitySuppressions.xml b/Essentials.EncodingProviders.Base64/CompatibilitySuppressions.xml similarity index 100% rename from EncodingProviders/Base64/CompatibilitySuppressions.xml rename to Essentials.EncodingProviders.Base64/CompatibilitySuppressions.xml diff --git a/Essentials.EncodingProviders.Base64/Essentials.EncodingProviders.Base64.csproj b/Essentials.EncodingProviders.Base64/Essentials.EncodingProviders.Base64.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.EncodingProviders.Base64/Essentials.EncodingProviders.Base64.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/EncodingProviders/Hex/CompatibilitySuppressions.xml b/Essentials.EncodingProviders.Hex/CompatibilitySuppressions.xml similarity index 100% rename from EncodingProviders/Hex/CompatibilitySuppressions.xml rename to Essentials.EncodingProviders.Hex/CompatibilitySuppressions.xml diff --git a/Essentials.EncodingProviders.Hex/Essentials.EncodingProviders.Hex.csproj b/Essentials.EncodingProviders.Hex/Essentials.EncodingProviders.Hex.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.EncodingProviders.Hex/Essentials.EncodingProviders.Hex.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/EncodingProviders/Hex/Hex.cs b/Essentials.EncodingProviders.Hex/HexEncodingProvider.cs similarity index 97% rename from EncodingProviders/Hex/Hex.cs rename to Essentials.EncodingProviders.Hex/HexEncodingProvider.cs index 4138f0d..f4857f8 100644 --- a/EncodingProviders/Hex/Hex.cs +++ b/Essentials.EncodingProviders.Hex/HexEncodingProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.EncodingProviders; +namespace ktsu.Essentials.EncodingProviders.Hex; using ktsu.Essentials; using System; @@ -12,7 +12,7 @@ namespace ktsu.Essentials.EncodingProviders; /// /// An encoding provider that uses hexadecimal encoding for data encoding and decoding. /// -public class Hex : IEncodingProvider +public class HexEncodingProvider : IEncodingProvider { /// /// Tries to encode the data from the span and write the result to the destination. diff --git a/EncryptionProviders/Aes/Aes.cs b/Essentials.EncryptionProviders.Aes/AesEncryptionProvider.cs similarity index 96% rename from EncryptionProviders/Aes/Aes.cs rename to Essentials.EncryptionProviders.Aes/AesEncryptionProvider.cs index 9c2fca1..39cd82d 100644 --- a/EncryptionProviders/Aes/Aes.cs +++ b/Essentials.EncryptionProviders.Aes/AesEncryptionProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.EncryptionProviders; +namespace ktsu.Essentials.EncryptionProviders.Aes; using ktsu.Essentials; using System; @@ -12,7 +12,7 @@ namespace ktsu.Essentials.EncryptionProviders; /// /// An encryption provider that uses AES for data encryption and decryption. /// -public class Aes : IEncryptionProvider, IDisposable +public class AesEncryptionProvider : IEncryptionProvider, IDisposable { private const int KeySize = 32; // 256 bits private const int IVSize = 16; // 128 bits @@ -22,9 +22,9 @@ public class Aes : IEncryptionProvider, IDisposable private readonly Lazy _generator; /// - /// Creates a new instance of the class. + /// Creates a new instance of the class. /// - public Aes() + public AesEncryptionProvider() { _aes = new(System.Security.Cryptography.Aes.Create); _generator = new(System.Security.Cryptography.Aes.Create); diff --git a/EncryptionProviders/Aes/CompatibilitySuppressions.xml b/Essentials.EncryptionProviders.Aes/CompatibilitySuppressions.xml similarity index 100% rename from EncryptionProviders/Aes/CompatibilitySuppressions.xml rename to Essentials.EncryptionProviders.Aes/CompatibilitySuppressions.xml diff --git a/Essentials.EncryptionProviders.Aes/Essentials.EncryptionProviders.Aes.csproj b/Essentials.EncryptionProviders.Aes/Essentials.EncryptionProviders.Aes.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.EncryptionProviders.Aes/Essentials.EncryptionProviders.Aes.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/EncryptionProviders/Aes/GlobalSuppressions.cs b/Essentials.EncryptionProviders.Aes/GlobalSuppressions.cs similarity index 90% rename from EncryptionProviders/Aes/GlobalSuppressions.cs rename to Essentials.EncryptionProviders.Aes/GlobalSuppressions.cs index 16af0fb..bbbd0e4 100644 --- a/EncryptionProviders/Aes/GlobalSuppressions.cs +++ b/Essentials.EncryptionProviders.Aes/GlobalSuppressions.cs @@ -1,4 +1,4 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. diff --git a/FileSystemProviders/Native/CompatibilitySuppressions.xml b/Essentials.FileSystemProviders.Native/CompatibilitySuppressions.xml similarity index 100% rename from FileSystemProviders/Native/CompatibilitySuppressions.xml rename to Essentials.FileSystemProviders.Native/CompatibilitySuppressions.xml diff --git a/FileSystemProviders/Native/Native.csproj b/Essentials.FileSystemProviders.Native/Essentials.FileSystemProviders.Native.csproj similarity index 69% rename from FileSystemProviders/Native/Native.csproj rename to Essentials.FileSystemProviders.Native/Essentials.FileSystemProviders.Native.csproj index f35965a..0b91d16 100644 --- a/FileSystemProviders/Native/Native.csproj +++ b/Essentials.FileSystemProviders.Native/Essentials.FileSystemProviders.Native.csproj @@ -1,15 +1,13 @@ - + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 true - ktsu.Essentials.FileSystemProviders.Native - ktsu.Essentials.FileSystemProviders - + diff --git a/FileSystemProviders/Native/GlobalSuppressions.cs b/Essentials.FileSystemProviders.Native/GlobalSuppressions.cs similarity index 67% rename from FileSystemProviders/Native/GlobalSuppressions.cs rename to Essentials.FileSystemProviders.Native/GlobalSuppressions.cs index e8451a9..2a5064c 100644 --- a/FileSystemProviders/Native/GlobalSuppressions.cs +++ b/Essentials.FileSystemProviders.Native/GlobalSuppressions.cs @@ -1,3 +1,3 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. diff --git a/FileSystemProviders/Native/Native.cs b/Essentials.FileSystemProviders.Native/NativeFileSystemProvider.cs similarity index 83% rename from FileSystemProviders/Native/Native.cs rename to Essentials.FileSystemProviders.Native/NativeFileSystemProvider.cs index 567879b..93ee481 100644 --- a/FileSystemProviders/Native/Native.cs +++ b/Essentials.FileSystemProviders.Native/NativeFileSystemProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.FileSystemProviders; +namespace ktsu.Essentials.FileSystemProviders.Native; using ktsu.Essentials; using System.IO.Abstractions; @@ -11,14 +11,14 @@ namespace ktsu.Essentials.FileSystemProviders; /// /// A default file system provider that provides access to the real file system. /// -public class Native : IFileSystemProvider +public class NativeFileSystemProvider : IFileSystemProvider { private readonly RealFileSystem fileSystem; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public Native() => fileSystem = new RealFileSystem(); + public NativeFileSystemProvider() => fileSystem = new RealFileSystem(); /// /// Gets the directory operations. diff --git a/HashProviders/CRC32/CRC32.cs b/Essentials.HashProviders.CRC32/CRC32HashProvider.cs similarity index 94% rename from HashProviders/CRC32/CRC32.cs rename to Essentials.HashProviders.CRC32/CRC32HashProvider.cs index 8eac85c..af901de 100644 --- a/HashProviders/CRC32/CRC32.cs +++ b/Essentials.HashProviders.CRC32/CRC32HashProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.HashProviders; +namespace ktsu.Essentials.HashProviders.CRC32; using ktsu.Essentials; using System; @@ -12,7 +12,7 @@ namespace ktsu.Essentials.HashProviders; /// /// A hash provider that uses CRC-32 for hashing data. /// -public class CRC32 : IHashProvider +public class CRC32HashProvider : IHashProvider { /// /// The length of the CRC-32 hash in bytes (4 bytes / 32 bits). diff --git a/HashProviders/CRC32/CompatibilitySuppressions.xml b/Essentials.HashProviders.CRC32/CompatibilitySuppressions.xml similarity index 100% rename from HashProviders/CRC32/CompatibilitySuppressions.xml rename to Essentials.HashProviders.CRC32/CompatibilitySuppressions.xml diff --git a/HashProviders/CRC32/CRC32.csproj b/Essentials.HashProviders.CRC32/Essentials.HashProviders.CRC32.csproj similarity index 71% rename from HashProviders/CRC32/CRC32.csproj rename to Essentials.HashProviders.CRC32/Essentials.HashProviders.CRC32.csproj index 342a6ae..8f33eb6 100644 --- a/HashProviders/CRC32/CRC32.csproj +++ b/Essentials.HashProviders.CRC32/Essentials.HashProviders.CRC32.csproj @@ -4,12 +4,10 @@ net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 true - ktsu.Essentials.HashProviders.CRC32 - ktsu.Essentials.HashProviders - + diff --git a/HashProviders/CRC64/CRC64.cs b/Essentials.HashProviders.CRC64/CRC64HashProvider.cs similarity index 94% rename from HashProviders/CRC64/CRC64.cs rename to Essentials.HashProviders.CRC64/CRC64HashProvider.cs index cc2b5db..b6ea6c9 100644 --- a/HashProviders/CRC64/CRC64.cs +++ b/Essentials.HashProviders.CRC64/CRC64HashProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.HashProviders; +namespace ktsu.Essentials.HashProviders.CRC64; using ktsu.Essentials; using System; @@ -12,7 +12,7 @@ namespace ktsu.Essentials.HashProviders; /// /// A hash provider that uses CRC-64 for hashing data. /// -public class CRC64 : IHashProvider +public class CRC64HashProvider : IHashProvider { /// /// The length of the CRC-64 hash in bytes (8 bytes / 64 bits). diff --git a/HashProviders/CRC64/CompatibilitySuppressions.xml b/Essentials.HashProviders.CRC64/CompatibilitySuppressions.xml similarity index 100% rename from HashProviders/CRC64/CompatibilitySuppressions.xml rename to Essentials.HashProviders.CRC64/CompatibilitySuppressions.xml diff --git a/HashProviders/CRC64/CRC64.csproj b/Essentials.HashProviders.CRC64/Essentials.HashProviders.CRC64.csproj similarity index 71% rename from HashProviders/CRC64/CRC64.csproj rename to Essentials.HashProviders.CRC64/Essentials.HashProviders.CRC64.csproj index e3d5807..8f33eb6 100644 --- a/HashProviders/CRC64/CRC64.csproj +++ b/Essentials.HashProviders.CRC64/Essentials.HashProviders.CRC64.csproj @@ -4,12 +4,10 @@ net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 true - ktsu.Essentials.HashProviders.CRC64 - ktsu.Essentials.HashProviders - + diff --git a/HashProviders/FNV1_32/CompatibilitySuppressions.xml b/Essentials.HashProviders.FNV1_32/CompatibilitySuppressions.xml similarity index 100% rename from HashProviders/FNV1_32/CompatibilitySuppressions.xml rename to Essentials.HashProviders.FNV1_32/CompatibilitySuppressions.xml diff --git a/Essentials.HashProviders.FNV1_32/Essentials.HashProviders.FNV1_32.csproj b/Essentials.HashProviders.FNV1_32/Essentials.HashProviders.FNV1_32.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.HashProviders.FNV1_32/Essentials.HashProviders.FNV1_32.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/HashProviders/FNV1_32/FNV1_32.cs b/Essentials.HashProviders.FNV1_32/FNV1_32HashProvider.cs similarity index 95% rename from HashProviders/FNV1_32/FNV1_32.cs rename to Essentials.HashProviders.FNV1_32/FNV1_32HashProvider.cs index a0bce48..d5d60fc 100644 --- a/HashProviders/FNV1_32/FNV1_32.cs +++ b/Essentials.HashProviders.FNV1_32/FNV1_32HashProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.HashProviders; +namespace ktsu.Essentials.HashProviders.FNV1_32; using ktsu.Essentials; using System; @@ -11,7 +11,7 @@ namespace ktsu.Essentials.HashProviders; /// /// A hash provider that uses FNV-1 32-bit for hashing data. /// -public class FNV1_32 : IHashProvider +public class FNV1_32HashProvider : IHashProvider { private const uint FnvOffsetBasis32 = 0x811c9dc5; private const uint FnvPrime32 = 0x01000193; diff --git a/HashProviders/FNV1_64/GlobalSuppressions.cs b/Essentials.HashProviders.FNV1_32/GlobalSuppressions.cs similarity index 90% rename from HashProviders/FNV1_64/GlobalSuppressions.cs rename to Essentials.HashProviders.FNV1_32/GlobalSuppressions.cs index 2ee3640..69ad67c 100644 --- a/HashProviders/FNV1_64/GlobalSuppressions.cs +++ b/Essentials.HashProviders.FNV1_32/GlobalSuppressions.cs @@ -1,4 +1,4 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. diff --git a/HashProviders/FNV1_64/CompatibilitySuppressions.xml b/Essentials.HashProviders.FNV1_64/CompatibilitySuppressions.xml similarity index 100% rename from HashProviders/FNV1_64/CompatibilitySuppressions.xml rename to Essentials.HashProviders.FNV1_64/CompatibilitySuppressions.xml diff --git a/Essentials.HashProviders.FNV1_64/Essentials.HashProviders.FNV1_64.csproj b/Essentials.HashProviders.FNV1_64/Essentials.HashProviders.FNV1_64.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.HashProviders.FNV1_64/Essentials.HashProviders.FNV1_64.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/HashProviders/FNV1_64/FNV1_64.cs b/Essentials.HashProviders.FNV1_64/FNV1_64HashProvider.cs similarity index 95% rename from HashProviders/FNV1_64/FNV1_64.cs rename to Essentials.HashProviders.FNV1_64/FNV1_64HashProvider.cs index 1b0b4e1..2f5ae6c 100644 --- a/HashProviders/FNV1_64/FNV1_64.cs +++ b/Essentials.HashProviders.FNV1_64/FNV1_64HashProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.HashProviders; +namespace ktsu.Essentials.HashProviders.FNV1_64; using ktsu.Essentials; using System; @@ -11,7 +11,7 @@ namespace ktsu.Essentials.HashProviders; /// /// A hash provider that uses FNV-1 64-bit for hashing data. /// -public class FNV1_64 : IHashProvider +public class FNV1_64HashProvider : IHashProvider { private const ulong FnvOffsetBasis64 = 0xcbf29ce484222325; private const ulong FnvPrime64 = 0x00000100000001b3; diff --git a/HashProviders/FNV1a_64/GlobalSuppressions.cs b/Essentials.HashProviders.FNV1_64/GlobalSuppressions.cs similarity index 90% rename from HashProviders/FNV1a_64/GlobalSuppressions.cs rename to Essentials.HashProviders.FNV1_64/GlobalSuppressions.cs index 2ee3640..69ad67c 100644 --- a/HashProviders/FNV1a_64/GlobalSuppressions.cs +++ b/Essentials.HashProviders.FNV1_64/GlobalSuppressions.cs @@ -1,4 +1,4 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. diff --git a/HashProviders/FNV1a_32/CompatibilitySuppressions.xml b/Essentials.HashProviders.FNV1a_32/CompatibilitySuppressions.xml similarity index 100% rename from HashProviders/FNV1a_32/CompatibilitySuppressions.xml rename to Essentials.HashProviders.FNV1a_32/CompatibilitySuppressions.xml diff --git a/Essentials.HashProviders.FNV1a_32/Essentials.HashProviders.FNV1a_32.csproj b/Essentials.HashProviders.FNV1a_32/Essentials.HashProviders.FNV1a_32.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.HashProviders.FNV1a_32/Essentials.HashProviders.FNV1a_32.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/HashProviders/FNV1a_32/FNV1a_32.cs b/Essentials.HashProviders.FNV1a_32/FNV1a_32HashProvider.cs similarity index 95% rename from HashProviders/FNV1a_32/FNV1a_32.cs rename to Essentials.HashProviders.FNV1a_32/FNV1a_32HashProvider.cs index f9bbf10..693b847 100644 --- a/HashProviders/FNV1a_32/FNV1a_32.cs +++ b/Essentials.HashProviders.FNV1a_32/FNV1a_32HashProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.HashProviders; +namespace ktsu.Essentials.HashProviders.FNV1a_32; using ktsu.Essentials; using System; @@ -11,7 +11,7 @@ namespace ktsu.Essentials.HashProviders; /// /// A hash provider that uses FNV-1a 32-bit for hashing data. /// -public class FNV1a_32 : IHashProvider +public class FNV1a_32HashProvider : IHashProvider { private const uint FnvOffsetBasis32 = 0x811c9dc5; private const uint FnvPrime32 = 0x01000193; diff --git a/HashProviders/FNV1a_32/GlobalSuppressions.cs b/Essentials.HashProviders.FNV1a_32/GlobalSuppressions.cs similarity index 90% rename from HashProviders/FNV1a_32/GlobalSuppressions.cs rename to Essentials.HashProviders.FNV1a_32/GlobalSuppressions.cs index 2ee3640..69ad67c 100644 --- a/HashProviders/FNV1a_32/GlobalSuppressions.cs +++ b/Essentials.HashProviders.FNV1a_32/GlobalSuppressions.cs @@ -1,4 +1,4 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. diff --git a/HashProviders/FNV1a_64/CompatibilitySuppressions.xml b/Essentials.HashProviders.FNV1a_64/CompatibilitySuppressions.xml similarity index 100% rename from HashProviders/FNV1a_64/CompatibilitySuppressions.xml rename to Essentials.HashProviders.FNV1a_64/CompatibilitySuppressions.xml diff --git a/Essentials.HashProviders.FNV1a_64/Essentials.HashProviders.FNV1a_64.csproj b/Essentials.HashProviders.FNV1a_64/Essentials.HashProviders.FNV1a_64.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.HashProviders.FNV1a_64/Essentials.HashProviders.FNV1a_64.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/HashProviders/FNV1a_64/FNV1a_64.cs b/Essentials.HashProviders.FNV1a_64/FNV1a_64HashProvider.cs similarity index 95% rename from HashProviders/FNV1a_64/FNV1a_64.cs rename to Essentials.HashProviders.FNV1a_64/FNV1a_64HashProvider.cs index 62ca515..30945eb 100644 --- a/HashProviders/FNV1a_64/FNV1a_64.cs +++ b/Essentials.HashProviders.FNV1a_64/FNV1a_64HashProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.HashProviders; +namespace ktsu.Essentials.HashProviders.FNV1a_64; using ktsu.Essentials; using System; @@ -11,7 +11,7 @@ namespace ktsu.Essentials.HashProviders; /// /// A hash provider that uses FNV-1a 64-bit for hashing data. /// -public class FNV1a_64 : IHashProvider +public class FNV1a_64HashProvider : IHashProvider { private const ulong FnvOffsetBasis64 = 0xcbf29ce484222325; private const ulong FnvPrime64 = 0x00000100000001b3; diff --git a/HashProviders/FNV1_32/GlobalSuppressions.cs b/Essentials.HashProviders.FNV1a_64/GlobalSuppressions.cs similarity index 90% rename from HashProviders/FNV1_32/GlobalSuppressions.cs rename to Essentials.HashProviders.FNV1a_64/GlobalSuppressions.cs index 2ee3640..69ad67c 100644 --- a/HashProviders/FNV1_32/GlobalSuppressions.cs +++ b/Essentials.HashProviders.FNV1a_64/GlobalSuppressions.cs @@ -1,4 +1,4 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. diff --git a/HashProviders/MD5/CompatibilitySuppressions.xml b/Essentials.HashProviders.MD5/CompatibilitySuppressions.xml similarity index 100% rename from HashProviders/MD5/CompatibilitySuppressions.xml rename to Essentials.HashProviders.MD5/CompatibilitySuppressions.xml diff --git a/Essentials.HashProviders.MD5/Essentials.HashProviders.MD5.csproj b/Essentials.HashProviders.MD5/Essentials.HashProviders.MD5.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.HashProviders.MD5/Essentials.HashProviders.MD5.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/HashProviders/MD5/GlobalSuppressions.cs b/Essentials.HashProviders.MD5/GlobalSuppressions.cs similarity index 94% rename from HashProviders/MD5/GlobalSuppressions.cs rename to Essentials.HashProviders.MD5/GlobalSuppressions.cs index 48ac7c7..1bcd7ab 100644 --- a/HashProviders/MD5/GlobalSuppressions.cs +++ b/Essentials.HashProviders.MD5/GlobalSuppressions.cs @@ -1,4 +1,4 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. diff --git a/HashProviders/MD5/MD5.cs b/Essentials.HashProviders.MD5/MD5HashProvider.cs similarity index 90% rename from HashProviders/MD5/MD5.cs rename to Essentials.HashProviders.MD5/MD5HashProvider.cs index c1da46f..aea875c 100644 --- a/HashProviders/MD5/MD5.cs +++ b/Essentials.HashProviders.MD5/MD5HashProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.HashProviders; +namespace ktsu.Essentials.HashProviders.MD5; using ktsu.Essentials; using System; @@ -11,7 +11,7 @@ namespace ktsu.Essentials.HashProviders; /// /// A hash provider that uses MD5 for hashing data. /// -public class MD5 : IHashProvider, IDisposable +public class MD5HashProvider : IHashProvider, IDisposable { private bool disposedValue; private readonly Lazy _md5; @@ -22,9 +22,9 @@ public class MD5 : IHashProvider, IDisposable public int HashLengthBytes => 16; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public MD5() => _md5 = new(System.Security.Cryptography.MD5.Create); + public MD5HashProvider() => _md5 = new(System.Security.Cryptography.MD5.Create); /// /// Tries to hash the specified data into the provided hash buffer using MD5. diff --git a/HashProviders/SHA1/CompatibilitySuppressions.xml b/Essentials.HashProviders.SHA1/CompatibilitySuppressions.xml similarity index 100% rename from HashProviders/SHA1/CompatibilitySuppressions.xml rename to Essentials.HashProviders.SHA1/CompatibilitySuppressions.xml diff --git a/Essentials.HashProviders.SHA1/Essentials.HashProviders.SHA1.csproj b/Essentials.HashProviders.SHA1/Essentials.HashProviders.SHA1.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.HashProviders.SHA1/Essentials.HashProviders.SHA1.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/HashProviders/SHA1/GlobalSuppressions.cs b/Essentials.HashProviders.SHA1/GlobalSuppressions.cs similarity index 94% rename from HashProviders/SHA1/GlobalSuppressions.cs rename to Essentials.HashProviders.SHA1/GlobalSuppressions.cs index 33686c3..5edddde 100644 --- a/HashProviders/SHA1/GlobalSuppressions.cs +++ b/Essentials.HashProviders.SHA1/GlobalSuppressions.cs @@ -1,4 +1,4 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. diff --git a/HashProviders/SHA1/SHA1.cs b/Essentials.HashProviders.SHA1/SHA1HashProvider.cs similarity index 85% rename from HashProviders/SHA1/SHA1.cs rename to Essentials.HashProviders.SHA1/SHA1HashProvider.cs index d2effe4..c29e708 100644 --- a/HashProviders/SHA1/SHA1.cs +++ b/Essentials.HashProviders.SHA1/SHA1HashProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.HashProviders; +namespace ktsu.Essentials.HashProviders.SHA1; using ktsu.Essentials; using System; @@ -11,7 +11,7 @@ namespace ktsu.Essentials.HashProviders; /// /// A hash provider that uses SHA1 for hashing data. /// -public class SHA1 : IHashProvider, IDisposable +public class SHA1HashProvider : IHashProvider, IDisposable { private bool disposedValue; private readonly Lazy _sha1; @@ -22,9 +22,9 @@ public class SHA1 : IHashProvider, IDisposable public int HashLengthBytes => 20; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public SHA1() => _sha1 = new(System.Security.Cryptography.SHA1.Create); + public SHA1HashProvider() => _sha1 = new(System.Security.Cryptography.SHA1.Create); /// /// Tries to hash the specified data into the provided hash buffer using SHA1. @@ -106,7 +106,7 @@ public bool TryHash(Stream data, Span destination) } /// - /// Releases the unmanaged resources used by the instance and optionally releases the managed resources. + /// Releases the unmanaged resources used by the instance and optionally releases the managed resources. /// protected virtual void Dispose(bool disposing) { @@ -125,7 +125,7 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases all resources used by the instance. + /// Releases all resources used by the instance. /// public void Dispose() { diff --git a/HashProviders/SHA256/CompatibilitySuppressions.xml b/Essentials.HashProviders.SHA256/CompatibilitySuppressions.xml similarity index 100% rename from HashProviders/SHA256/CompatibilitySuppressions.xml rename to Essentials.HashProviders.SHA256/CompatibilitySuppressions.xml diff --git a/Essentials.HashProviders.SHA256/Essentials.HashProviders.SHA256.csproj b/Essentials.HashProviders.SHA256/Essentials.HashProviders.SHA256.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.HashProviders.SHA256/Essentials.HashProviders.SHA256.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/HashProviders/SHA256/GlobalSuppressions.cs b/Essentials.HashProviders.SHA256/GlobalSuppressions.cs similarity index 91% rename from HashProviders/SHA256/GlobalSuppressions.cs rename to Essentials.HashProviders.SHA256/GlobalSuppressions.cs index 44ab2fb..d26c171 100644 --- a/HashProviders/SHA256/GlobalSuppressions.cs +++ b/Essentials.HashProviders.SHA256/GlobalSuppressions.cs @@ -1,4 +1,4 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. diff --git a/HashProviders/SHA256/SHA256.cs b/Essentials.HashProviders.SHA256/SHA256HashProvider.cs similarity index 84% rename from HashProviders/SHA256/SHA256.cs rename to Essentials.HashProviders.SHA256/SHA256HashProvider.cs index 916ca1f..c9ae729 100644 --- a/HashProviders/SHA256/SHA256.cs +++ b/Essentials.HashProviders.SHA256/SHA256HashProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.HashProviders; +namespace ktsu.Essentials.HashProviders.SHA256; using ktsu.Essentials; using System; @@ -11,7 +11,7 @@ namespace ktsu.Essentials.HashProviders; /// /// A hash provider that uses SHA256 for hashing data. /// -public class SHA256 : IHashProvider, IDisposable +public class SHA256HashProvider : IHashProvider, IDisposable { private bool disposedValue; private readonly Lazy _sha256; @@ -22,9 +22,9 @@ public class SHA256 : IHashProvider, IDisposable public int HashLengthBytes => 32; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public SHA256() => _sha256 = new(System.Security.Cryptography.SHA256.Create); + public SHA256HashProvider() => _sha256 = new(System.Security.Cryptography.SHA256.Create); /// /// Tries to hash the specified data into the provided hash buffer using SHA256. @@ -106,7 +106,7 @@ public bool TryHash(Stream data, Span destination) } /// - /// Releases the resources used by the instance. + /// Releases the resources used by the instance. /// protected virtual void Dispose(bool disposing) { @@ -125,7 +125,7 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases the resources used by the instance. + /// Releases the resources used by the instance. /// public void Dispose() { diff --git a/HashProviders/SHA384/CompatibilitySuppressions.xml b/Essentials.HashProviders.SHA384/CompatibilitySuppressions.xml similarity index 100% rename from HashProviders/SHA384/CompatibilitySuppressions.xml rename to Essentials.HashProviders.SHA384/CompatibilitySuppressions.xml diff --git a/Essentials.HashProviders.SHA384/Essentials.HashProviders.SHA384.csproj b/Essentials.HashProviders.SHA384/Essentials.HashProviders.SHA384.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.HashProviders.SHA384/Essentials.HashProviders.SHA384.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/HashProviders/SHA384/GlobalSuppressions.cs b/Essentials.HashProviders.SHA384/GlobalSuppressions.cs similarity index 91% rename from HashProviders/SHA384/GlobalSuppressions.cs rename to Essentials.HashProviders.SHA384/GlobalSuppressions.cs index c1cc651..40e48fe 100644 --- a/HashProviders/SHA384/GlobalSuppressions.cs +++ b/Essentials.HashProviders.SHA384/GlobalSuppressions.cs @@ -1,4 +1,4 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. diff --git a/HashProviders/SHA384/SHA384.cs b/Essentials.HashProviders.SHA384/SHA384HashProvider.cs similarity index 85% rename from HashProviders/SHA384/SHA384.cs rename to Essentials.HashProviders.SHA384/SHA384HashProvider.cs index aae1b4b..07a1d16 100644 --- a/HashProviders/SHA384/SHA384.cs +++ b/Essentials.HashProviders.SHA384/SHA384HashProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.HashProviders; +namespace ktsu.Essentials.HashProviders.SHA384; using ktsu.Essentials; using System; @@ -11,7 +11,7 @@ namespace ktsu.Essentials.HashProviders; /// /// A hash provider that uses SHA384 for hashing data. /// -public class SHA384 : IHashProvider, IDisposable +public class SHA384HashProvider : IHashProvider, IDisposable { private bool disposedValue; private readonly Lazy _sha384; @@ -22,9 +22,9 @@ public class SHA384 : IHashProvider, IDisposable public int HashLengthBytes => 48; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public SHA384() => _sha384 = new(System.Security.Cryptography.SHA384.Create); + public SHA384HashProvider() => _sha384 = new(System.Security.Cryptography.SHA384.Create); /// /// Tries to hash the specified data into the provided hash buffer using SHA384. @@ -106,7 +106,7 @@ public bool TryHash(Stream data, Span destination) } /// - /// Releases the unmanaged resources used by the instance and optionally releases the managed resources. + /// Releases the unmanaged resources used by the instance and optionally releases the managed resources. /// protected virtual void Dispose(bool disposing) { @@ -125,7 +125,7 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases all resources used by the instance. + /// Releases all resources used by the instance. /// public void Dispose() { diff --git a/HashProviders/SHA512/CompatibilitySuppressions.xml b/Essentials.HashProviders.SHA512/CompatibilitySuppressions.xml similarity index 100% rename from HashProviders/SHA512/CompatibilitySuppressions.xml rename to Essentials.HashProviders.SHA512/CompatibilitySuppressions.xml diff --git a/Essentials.HashProviders.SHA512/Essentials.HashProviders.SHA512.csproj b/Essentials.HashProviders.SHA512/Essentials.HashProviders.SHA512.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.HashProviders.SHA512/Essentials.HashProviders.SHA512.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/HashProviders/SHA512/GlobalSuppressions.cs b/Essentials.HashProviders.SHA512/GlobalSuppressions.cs similarity index 91% rename from HashProviders/SHA512/GlobalSuppressions.cs rename to Essentials.HashProviders.SHA512/GlobalSuppressions.cs index ba2dd8a..82266a4 100644 --- a/HashProviders/SHA512/GlobalSuppressions.cs +++ b/Essentials.HashProviders.SHA512/GlobalSuppressions.cs @@ -1,4 +1,4 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. diff --git a/HashProviders/SHA512/SHA512.cs b/Essentials.HashProviders.SHA512/SHA512HashProvider.cs similarity index 85% rename from HashProviders/SHA512/SHA512.cs rename to Essentials.HashProviders.SHA512/SHA512HashProvider.cs index 20a1553..09a89b5 100644 --- a/HashProviders/SHA512/SHA512.cs +++ b/Essentials.HashProviders.SHA512/SHA512HashProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.HashProviders; +namespace ktsu.Essentials.HashProviders.SHA512; using ktsu.Essentials; using System; @@ -11,7 +11,7 @@ namespace ktsu.Essentials.HashProviders; /// /// A hash provider that uses SHA512 for hashing data. /// -public class SHA512 : IHashProvider, IDisposable +public class SHA512HashProvider : IHashProvider, IDisposable { private bool disposedValue; private readonly Lazy _sha512; @@ -22,9 +22,9 @@ public class SHA512 : IHashProvider, IDisposable public int HashLengthBytes => 64; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public SHA512() => _sha512 = new(System.Security.Cryptography.SHA512.Create); + public SHA512HashProvider() => _sha512 = new(System.Security.Cryptography.SHA512.Create); /// /// Tries to hash the specified data into the provided hash buffer using SHA512. @@ -106,7 +106,7 @@ public bool TryHash(Stream data, Span destination) } /// - /// Releases the unmanaged resources used by the instance and optionally releases the managed resources. + /// Releases the unmanaged resources used by the instance and optionally releases the managed resources. /// protected virtual void Dispose(bool disposing) { @@ -125,7 +125,7 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases all resources used by the instance. + /// Releases all resources used by the instance. /// public void Dispose() { diff --git a/HashProviders/XxHash128/CompatibilitySuppressions.xml b/Essentials.HashProviders.XxHash128/CompatibilitySuppressions.xml similarity index 100% rename from HashProviders/XxHash128/CompatibilitySuppressions.xml rename to Essentials.HashProviders.XxHash128/CompatibilitySuppressions.xml diff --git a/HashProviders/XxHash3/XxHash3.csproj b/Essentials.HashProviders.XxHash128/Essentials.HashProviders.XxHash128.csproj similarity index 71% rename from HashProviders/XxHash3/XxHash3.csproj rename to Essentials.HashProviders.XxHash128/Essentials.HashProviders.XxHash128.csproj index cc4d916..8f33eb6 100644 --- a/HashProviders/XxHash3/XxHash3.csproj +++ b/Essentials.HashProviders.XxHash128/Essentials.HashProviders.XxHash128.csproj @@ -4,12 +4,10 @@ net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 true - ktsu.Essentials.HashProviders.XxHash3 - ktsu.Essentials.HashProviders - + diff --git a/HashProviders/XxHash128/XxHash128.cs b/Essentials.HashProviders.XxHash128/XxHash128HashProvider.cs similarity index 93% rename from HashProviders/XxHash128/XxHash128.cs rename to Essentials.HashProviders.XxHash128/XxHash128HashProvider.cs index 4ea72bf..98147fe 100644 --- a/HashProviders/XxHash128/XxHash128.cs +++ b/Essentials.HashProviders.XxHash128/XxHash128HashProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.HashProviders; +namespace ktsu.Essentials.HashProviders.XxHash128; using ktsu.Essentials; using System; @@ -12,7 +12,7 @@ namespace ktsu.Essentials.HashProviders; /// /// A hash provider that uses xxHash128 for hashing data. /// -public class XxHash128 : IHashProvider +public class XxHash128HashProvider : IHashProvider { /// /// The length of the xxHash128 hash in bytes (16 bytes / 128 bits). diff --git a/HashProviders/XxHash3/CompatibilitySuppressions.xml b/Essentials.HashProviders.XxHash3/CompatibilitySuppressions.xml similarity index 100% rename from HashProviders/XxHash3/CompatibilitySuppressions.xml rename to Essentials.HashProviders.XxHash3/CompatibilitySuppressions.xml diff --git a/HashProviders/XxHash32/XxHash32.csproj b/Essentials.HashProviders.XxHash3/Essentials.HashProviders.XxHash3.csproj similarity index 71% rename from HashProviders/XxHash32/XxHash32.csproj rename to Essentials.HashProviders.XxHash3/Essentials.HashProviders.XxHash3.csproj index defcbff..8f33eb6 100644 --- a/HashProviders/XxHash32/XxHash32.csproj +++ b/Essentials.HashProviders.XxHash3/Essentials.HashProviders.XxHash3.csproj @@ -4,12 +4,10 @@ net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 true - ktsu.Essentials.HashProviders.XxHash32 - ktsu.Essentials.HashProviders - + diff --git a/HashProviders/XxHash3/XxHash3.cs b/Essentials.HashProviders.XxHash3/XxHash3HashProvider.cs similarity index 93% rename from HashProviders/XxHash3/XxHash3.cs rename to Essentials.HashProviders.XxHash3/XxHash3HashProvider.cs index 88363b6..f685dbf 100644 --- a/HashProviders/XxHash3/XxHash3.cs +++ b/Essentials.HashProviders.XxHash3/XxHash3HashProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.HashProviders; +namespace ktsu.Essentials.HashProviders.XxHash3; using ktsu.Essentials; using System; @@ -12,7 +12,7 @@ namespace ktsu.Essentials.HashProviders; /// /// A hash provider that uses xxHash3 for hashing data. /// -public class XxHash3 : IHashProvider +public class XxHash3HashProvider : IHashProvider { /// /// The length of the xxHash3 hash in bytes (8 bytes / 64 bits). diff --git a/HashProviders/XxHash32/CompatibilitySuppressions.xml b/Essentials.HashProviders.XxHash32/CompatibilitySuppressions.xml similarity index 100% rename from HashProviders/XxHash32/CompatibilitySuppressions.xml rename to Essentials.HashProviders.XxHash32/CompatibilitySuppressions.xml diff --git a/Essentials.HashProviders.XxHash32/Essentials.HashProviders.XxHash32.csproj b/Essentials.HashProviders.XxHash32/Essentials.HashProviders.XxHash32.csproj new file mode 100644 index 0000000..8f33eb6 --- /dev/null +++ b/Essentials.HashProviders.XxHash32/Essentials.HashProviders.XxHash32.csproj @@ -0,0 +1,19 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + + diff --git a/HashProviders/XxHash32/XxHash32.cs b/Essentials.HashProviders.XxHash32/XxHash32HashProvider.cs similarity index 93% rename from HashProviders/XxHash32/XxHash32.cs rename to Essentials.HashProviders.XxHash32/XxHash32HashProvider.cs index 0db0d3f..282d17a 100644 --- a/HashProviders/XxHash32/XxHash32.cs +++ b/Essentials.HashProviders.XxHash32/XxHash32HashProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.HashProviders; +namespace ktsu.Essentials.HashProviders.XxHash32; using ktsu.Essentials; using System; @@ -12,7 +12,7 @@ namespace ktsu.Essentials.HashProviders; /// /// A hash provider that uses xxHash32 for hashing data. /// -public class XxHash32 : IHashProvider +public class XxHash32HashProvider : IHashProvider { /// /// The length of the xxHash32 hash in bytes (4 bytes / 32 bits). diff --git a/HashProviders/XxHash64/CompatibilitySuppressions.xml b/Essentials.HashProviders.XxHash64/CompatibilitySuppressions.xml similarity index 100% rename from HashProviders/XxHash64/CompatibilitySuppressions.xml rename to Essentials.HashProviders.XxHash64/CompatibilitySuppressions.xml diff --git a/Essentials.HashProviders.XxHash64/Essentials.HashProviders.XxHash64.csproj b/Essentials.HashProviders.XxHash64/Essentials.HashProviders.XxHash64.csproj new file mode 100644 index 0000000..8f33eb6 --- /dev/null +++ b/Essentials.HashProviders.XxHash64/Essentials.HashProviders.XxHash64.csproj @@ -0,0 +1,19 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + + diff --git a/HashProviders/XxHash64/XxHash64.cs b/Essentials.HashProviders.XxHash64/XxHash64HashProvider.cs similarity index 93% rename from HashProviders/XxHash64/XxHash64.cs rename to Essentials.HashProviders.XxHash64/XxHash64HashProvider.cs index 96b31a9..0303428 100644 --- a/HashProviders/XxHash64/XxHash64.cs +++ b/Essentials.HashProviders.XxHash64/XxHash64HashProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.HashProviders; +namespace ktsu.Essentials.HashProviders.XxHash64; using ktsu.Essentials; using System; @@ -12,7 +12,7 @@ namespace ktsu.Essentials.HashProviders; /// /// A hash provider that uses xxHash64 for hashing data. /// -public class XxHash64 : IHashProvider +public class XxHash64HashProvider : IHashProvider { /// /// The length of the xxHash64 hash in bytes (8 bytes / 64 bits). diff --git a/LoggingProviders/Console/CompatibilitySuppressions.xml b/Essentials.LoggingProviders.Console/CompatibilitySuppressions.xml similarity index 100% rename from LoggingProviders/Console/CompatibilitySuppressions.xml rename to Essentials.LoggingProviders.Console/CompatibilitySuppressions.xml diff --git a/LoggingProviders/Console/Console.cs b/Essentials.LoggingProviders.Console/ConsoleLoggingProvider.cs similarity index 94% rename from LoggingProviders/Console/Console.cs rename to Essentials.LoggingProviders.Console/ConsoleLoggingProvider.cs index 899f535..10a9643 100644 --- a/LoggingProviders/Console/Console.cs +++ b/Essentials.LoggingProviders.Console/ConsoleLoggingProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.LoggingProviders; +namespace ktsu.Essentials.LoggingProviders.Console; using ktsu.Essentials; using System; @@ -11,7 +11,7 @@ namespace ktsu.Essentials.LoggingProviders; /// A logging provider that writes log messages to the console. /// Messages at Warning level and above are written to standard error; others to standard output. /// -public class Console : ILoggingProvider +public class ConsoleLoggingProvider : ILoggingProvider { /// /// Gets or sets the minimum log level. Messages below this level will be ignored. diff --git a/Essentials.LoggingProviders.Console/Essentials.LoggingProviders.Console.csproj b/Essentials.LoggingProviders.Console/Essentials.LoggingProviders.Console.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.LoggingProviders.Console/Essentials.LoggingProviders.Console.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/NavigationProviders/InMemory/CompatibilitySuppressions.xml b/Essentials.NavigationProviders.InMemory/CompatibilitySuppressions.xml similarity index 100% rename from NavigationProviders/InMemory/CompatibilitySuppressions.xml rename to Essentials.NavigationProviders.InMemory/CompatibilitySuppressions.xml diff --git a/Essentials.NavigationProviders.InMemory/Essentials.NavigationProviders.InMemory.csproj b/Essentials.NavigationProviders.InMemory/Essentials.NavigationProviders.InMemory.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.NavigationProviders.InMemory/Essentials.NavigationProviders.InMemory.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/NavigationProviders/InMemory/InMemory.cs b/Essentials.NavigationProviders.InMemory/InMemoryNavigationProvider.cs similarity index 95% rename from NavigationProviders/InMemory/InMemory.cs rename to Essentials.NavigationProviders.InMemory/InMemoryNavigationProvider.cs index a01f91c..27e6fba 100644 --- a/NavigationProviders/InMemory/InMemory.cs +++ b/Essentials.NavigationProviders.InMemory/InMemoryNavigationProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.NavigationProviders; +namespace ktsu.Essentials.NavigationProviders.InMemory; using ktsu.Essentials; using System.Collections.Generic; @@ -11,7 +11,7 @@ namespace ktsu.Essentials.NavigationProviders; /// An in-memory navigation provider that manages back/forward navigation with history using lists. /// /// The type of the navigation destination. -public class InMemory : INavigationProvider +public class InMemoryNavigationProvider : INavigationProvider { private readonly List backStack = []; private readonly List forwardStack = []; diff --git a/ObfuscationProviders/Base64/Base64.cs b/Essentials.ObfuscationProviders.Base64/Base64ObfuscationProvider.cs similarity index 81% rename from ObfuscationProviders/Base64/Base64.cs rename to Essentials.ObfuscationProviders.Base64/Base64ObfuscationProvider.cs index b7ea487..13f79ca 100644 --- a/ObfuscationProviders/Base64/Base64.cs +++ b/Essentials.ObfuscationProviders.Base64/Base64ObfuscationProvider.cs @@ -2,7 +2,7 @@ // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.ObfuscationProviders; +namespace ktsu.Essentials.ObfuscationProviders.Base64; using ktsu.Essentials; using System; @@ -12,17 +12,17 @@ namespace ktsu.Essentials.ObfuscationProviders; /// An obfuscation provider that composes a Base64 : obfuscation is /// Base64 encoding, deobfuscation is Base64 decoding. This is NOT encryption. /// -public class Base64 : IObfuscationProvider +public class Base64ObfuscationProvider : IObfuscationProvider { private readonly IEncodingProvider _encoder; /// Initializes a new instance using the default Base64 encoder. - public Base64() : this(new EncodingProviders.Base64()) { } + public Base64ObfuscationProvider() : this(new EncodingProviders.Base64.Base64EncodingProvider()) { } /// Initializes a new instance using the supplied encoder. /// The encoding provider used to perform the transform. [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Public constructor required for DI registration via factory lambda")] - public Base64(IEncodingProvider encoder) => _encoder = Ensure.NotNull(encoder); + public Base64ObfuscationProvider(IEncodingProvider encoder) => _encoder = Ensure.NotNull(encoder); /// public bool TryObfuscate(ReadOnlySpan data, Span destination) => _encoder.TryEncode(data, destination); diff --git a/Essentials.ObfuscationProviders.Base64/Essentials.ObfuscationProviders.Base64.csproj b/Essentials.ObfuscationProviders.Base64/Essentials.ObfuscationProviders.Base64.csproj new file mode 100644 index 0000000..c1a44d5 --- /dev/null +++ b/Essentials.ObfuscationProviders.Base64/Essentials.ObfuscationProviders.Base64.csproj @@ -0,0 +1,19 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + + diff --git a/ObfuscationProviders/BitRotate/BitRotate.cs b/Essentials.ObfuscationProviders.BitRotate/BitRotateObfuscationProvider.cs similarity index 90% rename from ObfuscationProviders/BitRotate/BitRotate.cs rename to Essentials.ObfuscationProviders.BitRotate/BitRotateObfuscationProvider.cs index b475e08..e272d82 100644 --- a/ObfuscationProviders/BitRotate/BitRotate.cs +++ b/Essentials.ObfuscationProviders.BitRotate/BitRotateObfuscationProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.ObfuscationProviders; +namespace ktsu.Essentials.ObfuscationProviders.BitRotate; using ktsu.Essentials; using System; @@ -12,16 +12,16 @@ namespace ktsu.Essentials.ObfuscationProviders; /// An obfuscation provider that rotates the bits of each byte left when obfuscating and right when /// deobfuscating. This is NOT encryption and provides no confidentiality. /// -public class BitRotate : IObfuscationProvider +public class BitRotateObfuscationProvider : IObfuscationProvider { private readonly int _bits; /// Initializes a new instance rotating by 3 bits. - public BitRotate() : this(3) { } + public BitRotateObfuscationProvider() : this(3) { } /// Initializes a new instance rotating by the specified number of bits (1–7). /// The number of bits to rotate; must be between 1 and 7 inclusive. - public BitRotate(int bits) + public BitRotateObfuscationProvider(int bits) { if (bits is < 1 or > 7) { diff --git a/Essentials.ObfuscationProviders.BitRotate/Essentials.ObfuscationProviders.BitRotate.csproj b/Essentials.ObfuscationProviders.BitRotate/Essentials.ObfuscationProviders.BitRotate.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.ObfuscationProviders.BitRotate/Essentials.ObfuscationProviders.BitRotate.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/ObfuscationProviders/Caesar/Caesar.cs b/Essentials.ObfuscationProviders.Caesar/CaesarObfuscationProvider.cs similarity index 92% rename from ObfuscationProviders/Caesar/Caesar.cs rename to Essentials.ObfuscationProviders.Caesar/CaesarObfuscationProvider.cs index 9dec3a3..6b9fad5 100644 --- a/ObfuscationProviders/Caesar/Caesar.cs +++ b/Essentials.ObfuscationProviders.Caesar/CaesarObfuscationProvider.cs @@ -2,7 +2,7 @@ // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.ObfuscationProviders; +namespace ktsu.Essentials.ObfuscationProviders.Caesar; using System; using System.IO; @@ -12,7 +12,7 @@ namespace ktsu.Essentials.ObfuscationProviders; /// An obfuscation provider that adds a fixed shift to each byte (wrapping at 256). This is NOT /// encryption and provides no confidentiality. /// -public class Caesar(byte shift = 13) : IObfuscationProvider +public class CaesarObfuscationProvider(byte shift = 13) : IObfuscationProvider { private readonly byte _shift = shift; diff --git a/Essentials.ObfuscationProviders.Caesar/Essentials.ObfuscationProviders.Caesar.csproj b/Essentials.ObfuscationProviders.Caesar/Essentials.ObfuscationProviders.Caesar.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.ObfuscationProviders.Caesar/Essentials.ObfuscationProviders.Caesar.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/ObfuscationProviders/Composite/Composite.cs b/Essentials.ObfuscationProviders.Composite/CompositeObfuscationProvider.cs similarity index 92% rename from ObfuscationProviders/Composite/Composite.cs rename to Essentials.ObfuscationProviders.Composite/CompositeObfuscationProvider.cs index 343bd6f..2e7a39e 100644 --- a/ObfuscationProviders/Composite/Composite.cs +++ b/Essentials.ObfuscationProviders.Composite/CompositeObfuscationProvider.cs @@ -2,7 +2,7 @@ // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.ObfuscationProviders; +namespace ktsu.Essentials.ObfuscationProviders.Composite; using System; using System.Collections.Generic; @@ -13,13 +13,13 @@ namespace ktsu.Essentials.ObfuscationProviders; /// An obfuscation provider that pipelines an ordered list of obfuscators. Obfuscation applies the /// stages in order; deobfuscation applies them in reverse order. This is NOT encryption. /// -public class Composite : IObfuscationProvider +public class CompositeObfuscationProvider : IObfuscationProvider { private readonly IReadOnlyList _stages; /// Initializes a new instance with the ordered obfuscation stages. /// The non-empty ordered list of obfuscators to pipeline. - public Composite(IReadOnlyList stages) + public CompositeObfuscationProvider(IReadOnlyList stages) { Ensure.NotNull(stages); if (stages.Count == 0) diff --git a/Essentials.ObfuscationProviders.Composite/Essentials.ObfuscationProviders.Composite.csproj b/Essentials.ObfuscationProviders.Composite/Essentials.ObfuscationProviders.Composite.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.ObfuscationProviders.Composite/Essentials.ObfuscationProviders.Composite.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/Essentials.ObfuscationProviders.Hex/Essentials.ObfuscationProviders.Hex.csproj b/Essentials.ObfuscationProviders.Hex/Essentials.ObfuscationProviders.Hex.csproj new file mode 100644 index 0000000..54bf883 --- /dev/null +++ b/Essentials.ObfuscationProviders.Hex/Essentials.ObfuscationProviders.Hex.csproj @@ -0,0 +1,19 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + + diff --git a/ObfuscationProviders/Hex/Hex.cs b/Essentials.ObfuscationProviders.Hex/HexObfuscationProvider.cs similarity index 82% rename from ObfuscationProviders/Hex/Hex.cs rename to Essentials.ObfuscationProviders.Hex/HexObfuscationProvider.cs index 00cc8e2..73e4f12 100644 --- a/ObfuscationProviders/Hex/Hex.cs +++ b/Essentials.ObfuscationProviders.Hex/HexObfuscationProvider.cs @@ -2,7 +2,7 @@ // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.ObfuscationProviders; +namespace ktsu.Essentials.ObfuscationProviders.Hex; using ktsu.Essentials; using System; @@ -12,17 +12,17 @@ namespace ktsu.Essentials.ObfuscationProviders; /// An obfuscation provider that composes a Hex : obfuscation is hex /// encoding, deobfuscation is hex decoding. This is NOT encryption. /// -public class Hex : IObfuscationProvider +public class HexObfuscationProvider : IObfuscationProvider { private readonly IEncodingProvider _encoder; /// Initializes a new instance using the default Hex encoder. - public Hex() : this(new EncodingProviders.Hex()) { } + public HexObfuscationProvider() : this(new EncodingProviders.Hex.HexEncodingProvider()) { } /// Initializes a new instance using the supplied encoder. /// The encoding provider used to perform the transform. [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Public constructor required for DI registration via factory lambda")] - public Hex(IEncodingProvider encoder) => _encoder = Ensure.NotNull(encoder); + public HexObfuscationProvider(IEncodingProvider encoder) => _encoder = Ensure.NotNull(encoder); /// public bool TryObfuscate(ReadOnlySpan data, Span destination) => _encoder.TryEncode(data, destination); diff --git a/Essentials.ObfuscationProviders.Reverse/Essentials.ObfuscationProviders.Reverse.csproj b/Essentials.ObfuscationProviders.Reverse/Essentials.ObfuscationProviders.Reverse.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.ObfuscationProviders.Reverse/Essentials.ObfuscationProviders.Reverse.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/ObfuscationProviders/Reverse/Reverse.cs b/Essentials.ObfuscationProviders.Reverse/ReverseObfuscationProvider.cs similarity index 89% rename from ObfuscationProviders/Reverse/Reverse.cs rename to Essentials.ObfuscationProviders.Reverse/ReverseObfuscationProvider.cs index f59f1f2..a18a90a 100644 --- a/ObfuscationProviders/Reverse/Reverse.cs +++ b/Essentials.ObfuscationProviders.Reverse/ReverseObfuscationProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.ObfuscationProviders; +namespace ktsu.Essentials.ObfuscationProviders.Reverse; using ktsu.Essentials; using System; @@ -12,7 +12,7 @@ namespace ktsu.Essentials.ObfuscationProviders; /// An obfuscation provider that reverses the byte order. Self-inverse. This is NOT encryption and /// provides no confidentiality. /// -public class Reverse : IObfuscationProvider +public class ReverseObfuscationProvider : IObfuscationProvider { /// public bool TryObfuscate(ReadOnlySpan data, Span destination) diff --git a/Essentials.ObfuscationProviders.Xor/Essentials.ObfuscationProviders.Xor.csproj b/Essentials.ObfuscationProviders.Xor/Essentials.ObfuscationProviders.Xor.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.ObfuscationProviders.Xor/Essentials.ObfuscationProviders.Xor.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/Essentials.ObfuscationProviders.Xor/GlobalSuppressions.cs b/Essentials.ObfuscationProviders.Xor/GlobalSuppressions.cs new file mode 100644 index 0000000..9175e41 --- /dev/null +++ b/Essentials.ObfuscationProviders.Xor/GlobalSuppressions.cs @@ -0,0 +1,7 @@ +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Naming", "CA1716:Identifiers should not match keywords", Scope = "namespace", Target = "~N:ktsu.Essentials.ObfuscationProviders.Xor", Justification = "Xor names the XOR obfuscation algorithm; the namespace segment is derived from the provider folder per the ktsu naming convention.")] diff --git a/ObfuscationProviders/Xor/Xor.cs b/Essentials.ObfuscationProviders.Xor/XorObfuscationProvider.cs similarity index 83% rename from ObfuscationProviders/Xor/Xor.cs rename to Essentials.ObfuscationProviders.Xor/XorObfuscationProvider.cs index 7b09430..e02d78e 100644 --- a/ObfuscationProviders/Xor/Xor.cs +++ b/Essentials.ObfuscationProviders.Xor/XorObfuscationProvider.cs @@ -2,10 +2,9 @@ // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.ObfuscationProviders; +namespace ktsu.Essentials.ObfuscationProviders.Xor; using System; -using System.Diagnostics.CodeAnalysis; using System.IO; using ktsu.Essentials; @@ -13,17 +12,16 @@ namespace ktsu.Essentials.ObfuscationProviders; /// An obfuscation provider that XORs each byte with a repeating key. Self-inverse: obfuscation and /// deobfuscation are the same transform. This is NOT encryption and provides no confidentiality. /// -[SuppressMessage("Naming", "CA1716:Identifiers should not match keywords", Justification = "Xor is the appropriate name for this obfuscation provider")] -public class Xor : IObfuscationProvider +public class XorObfuscationProvider : IObfuscationProvider { private readonly byte[] _key; /// Initializes a new instance with the default single-byte key. - public Xor() : this([0x5A]) { } + public XorObfuscationProvider() : this([0x5A]) { } /// Initializes a new instance with the specified repeating key. /// The non-empty key bytes to XOR against. - public Xor(byte[] key) + public XorObfuscationProvider(byte[] key) { Ensure.NotNull(key); if (key.Length == 0) diff --git a/PersistenceProviders/AppData/AppData.cs b/Essentials.PersistenceProviders.AppData/AppDataPersistenceProvider.cs similarity index 96% rename from PersistenceProviders/AppData/AppData.cs rename to Essentials.PersistenceProviders.AppData/AppDataPersistenceProvider.cs index e96471e..007d733 100644 --- a/PersistenceProviders/AppData/AppData.cs +++ b/Essentials.PersistenceProviders.AppData/AppDataPersistenceProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.PersistenceProviders; +namespace ktsu.Essentials.PersistenceProviders.AppData; using ktsu.Essentials; using System; @@ -17,7 +17,7 @@ namespace ktsu.Essentials.PersistenceProviders; /// Objects persist in the application's data directory using standard file system operations. /// /// The type used to identify stored objects. -public sealed class AppData : IPersistenceProvider +public sealed class AppDataPersistenceProvider : IPersistenceProvider where TKey : notnull { private readonly IFileSystemProvider _fileSystemProvider; @@ -25,13 +25,13 @@ public sealed class AppData : IPersistenceProvider private readonly string _baseDirectory; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The file system provider to use for file operations. /// The serialization provider to use for object serialization. /// The application name to use for the data directory. /// Optional subdirectory within the AppData folder to store objects. - public AppData( + public AppDataPersistenceProvider( IFileSystemProvider fileSystemProvider, ISerializationProvider serializationProvider, string applicationName, diff --git a/PersistenceProviders/Temp/Temp.csproj b/Essentials.PersistenceProviders.AppData/Essentials.PersistenceProviders.AppData.csproj similarity index 69% rename from PersistenceProviders/Temp/Temp.csproj rename to Essentials.PersistenceProviders.AppData/Essentials.PersistenceProviders.AppData.csproj index d8a869b..0b91d16 100644 --- a/PersistenceProviders/Temp/Temp.csproj +++ b/Essentials.PersistenceProviders.AppData/Essentials.PersistenceProviders.AppData.csproj @@ -1,15 +1,13 @@ - + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 true - ktsu.Essentials.PersistenceProviders.Temp - ktsu.Essentials.PersistenceProviders - + diff --git a/PersistenceProviders/AppData/AppData.csproj b/Essentials.PersistenceProviders.FileSystem/Essentials.PersistenceProviders.FileSystem.csproj similarity index 68% rename from PersistenceProviders/AppData/AppData.csproj rename to Essentials.PersistenceProviders.FileSystem/Essentials.PersistenceProviders.FileSystem.csproj index 3abfd50..0b91d16 100644 --- a/PersistenceProviders/AppData/AppData.csproj +++ b/Essentials.PersistenceProviders.FileSystem/Essentials.PersistenceProviders.FileSystem.csproj @@ -1,15 +1,13 @@ - + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 true - ktsu.Essentials.PersistenceProviders.AppData - ktsu.Essentials.PersistenceProviders - + diff --git a/PersistenceProviders/FileSystem/FileSystem.cs b/Essentials.PersistenceProviders.FileSystem/FileSystemPersistenceProvider.cs similarity index 96% rename from PersistenceProviders/FileSystem/FileSystem.cs rename to Essentials.PersistenceProviders.FileSystem/FileSystemPersistenceProvider.cs index b630d2d..40d701a 100644 --- a/PersistenceProviders/FileSystem/FileSystem.cs +++ b/Essentials.PersistenceProviders.FileSystem/FileSystemPersistenceProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.PersistenceProviders; +namespace ktsu.Essentials.PersistenceProviders.FileSystem; using ktsu.Essentials; using System; @@ -18,12 +18,12 @@ namespace ktsu.Essentials.PersistenceProviders; /// /// The type used to identify stored objects. /// -/// Initializes a new instance of the class. +/// Initializes a new instance of the class. /// /// The file system provider to use for file operations. /// The serialization provider to use for object serialization. /// The base directory where objects will be stored. -public sealed class FileSystem( +public sealed class FileSystemPersistenceProvider( IFileSystemProvider fileSystemProvider, ISerializationProvider serializationProvider, string baseDirectory) : IPersistenceProvider diff --git a/PersistenceProviders/InMemory/CompatibilitySuppressions.xml b/Essentials.PersistenceProviders.InMemory/CompatibilitySuppressions.xml similarity index 100% rename from PersistenceProviders/InMemory/CompatibilitySuppressions.xml rename to Essentials.PersistenceProviders.InMemory/CompatibilitySuppressions.xml diff --git a/Essentials.PersistenceProviders.InMemory/Essentials.PersistenceProviders.InMemory.csproj b/Essentials.PersistenceProviders.InMemory/Essentials.PersistenceProviders.InMemory.csproj new file mode 100644 index 0000000..db750c2 --- /dev/null +++ b/Essentials.PersistenceProviders.InMemory/Essentials.PersistenceProviders.InMemory.csproj @@ -0,0 +1,18 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + diff --git a/PersistenceProviders/InMemory/InMemory.cs b/Essentials.PersistenceProviders.InMemory/InMemoryPersistenceProvider.cs similarity index 95% rename from PersistenceProviders/InMemory/InMemory.cs rename to Essentials.PersistenceProviders.InMemory/InMemoryPersistenceProvider.cs index e07fc6f..0e42343 100644 --- a/PersistenceProviders/InMemory/InMemory.cs +++ b/Essentials.PersistenceProviders.InMemory/InMemoryPersistenceProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.PersistenceProviders; +namespace ktsu.Essentials.PersistenceProviders.InMemory; using ktsu.Essentials; using System.Collections.Concurrent; @@ -15,7 +15,7 @@ namespace ktsu.Essentials.PersistenceProviders; /// Data does not persist beyond the application lifecycle. /// /// The type used to identify stored objects. -public class InMemory : IPersistenceProvider where TKey : notnull +public class InMemoryPersistenceProvider : IPersistenceProvider where TKey : notnull { private readonly ConcurrentDictionary store = new(); diff --git a/PersistenceProviders/FileSystem/FileSystem.csproj b/Essentials.PersistenceProviders.Temp/Essentials.PersistenceProviders.Temp.csproj similarity index 68% rename from PersistenceProviders/FileSystem/FileSystem.csproj rename to Essentials.PersistenceProviders.Temp/Essentials.PersistenceProviders.Temp.csproj index c0034e8..0b91d16 100644 --- a/PersistenceProviders/FileSystem/FileSystem.csproj +++ b/Essentials.PersistenceProviders.Temp/Essentials.PersistenceProviders.Temp.csproj @@ -1,15 +1,13 @@ - + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 true - ktsu.Essentials.PersistenceProviders.FileSystem - ktsu.Essentials.PersistenceProviders - + diff --git a/PersistenceProviders/Temp/Temp.cs b/Essentials.PersistenceProviders.Temp/TempPersistenceProvider.cs similarity index 97% rename from PersistenceProviders/Temp/Temp.cs rename to Essentials.PersistenceProviders.Temp/TempPersistenceProvider.cs index 8fcda0f..48ce814 100644 --- a/PersistenceProviders/Temp/Temp.cs +++ b/Essentials.PersistenceProviders.Temp/TempPersistenceProvider.cs @@ -1,8 +1,8 @@ -// Copyright (c) ktsu.dev +// Copyright (c) ktsu.dev // All rights reserved. // Licensed under the MIT license. -namespace ktsu.Essentials.PersistenceProviders; +namespace ktsu.Essentials.PersistenceProviders.Temp; using ktsu.Essentials; using System; @@ -19,12 +19,12 @@ namespace ktsu.Essentials.PersistenceProviders; /// /// The type used to identify stored objects. /// -/// Initializes a new instance of the class. +/// Initializes a new instance of the class. /// /// The file system provider to use for file operations. /// The serialization provider to use for object serialization. /// Optional application name to create a subdirectory in temp folder. -public sealed class Temp( +public sealed class TempPersistenceProvider( IFileSystemProvider fileSystemProvider, ISerializationProvider serializationProvider, string? applicationName = null) : IPersistenceProvider, IDisposable diff --git a/Essentials.Tests/DiTests.cs b/Essentials.Tests/DiTests.cs index 8fff198..c41c3ce 100644 --- a/Essentials.Tests/DiTests.cs +++ b/Essentials.Tests/DiTests.cs @@ -6,7 +6,10 @@ namespace ktsu.Essentials.Tests; using System.Collections.Generic; using ktsu.Essentials; -using ktsu.Essentials.EncryptionProviders; +using ktsu.Essentials.CommandExecutors.Native; +using ktsu.Essentials.EncryptionProviders.Aes; +using ktsu.Essentials.FileSystemProviders.Native; +using ktsu.Essentials.LoggingProviders.Console; using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -29,19 +32,19 @@ public void DI_Can_Resolve_All_Singleton_Providers() // Test single-implementation providers IEncryptionProvider encryption = serviceProvider.GetRequiredService(); Assert.IsNotNull(encryption); - Assert.IsInstanceOfType(encryption); + Assert.IsInstanceOfType(encryption); IFileSystemProvider fileSystem = serviceProvider.GetRequiredService(); Assert.IsNotNull(fileSystem); - Assert.IsInstanceOfType(fileSystem); + Assert.IsInstanceOfType(fileSystem); ICommandExecutor commandExecutor = serviceProvider.GetRequiredService(); Assert.IsNotNull(commandExecutor); - Assert.IsInstanceOfType(commandExecutor); + Assert.IsInstanceOfType(commandExecutor); ILoggingProvider logging = serviceProvider.GetRequiredService(); Assert.IsNotNull(logging); - Assert.IsInstanceOfType(logging); + Assert.IsInstanceOfType(logging); } [TestMethod] @@ -54,7 +57,7 @@ public void DI_Can_Resolve_Multiple_Compression_Providers() Assert.HasCount(4, providers, "Should resolve all 4 compression providers"); - string[] expectedTypes = ["Brotli", "Deflate", "Gzip", "ZLib"]; + string[] expectedTypes = ["BrotliCompressionProvider", "DeflateCompressionProvider", "GzipCompressionProvider", "ZLibCompressionProvider"]; string[] actualTypes = [.. providers.Select(p => p.GetType().Name).OrderBy(n => n)]; CollectionAssert.AreEquivalent(expectedTypes, actualTypes); } @@ -70,7 +73,7 @@ public void DI_Can_Resolve_Multiple_Hash_Providers() Assert.HasCount(15, providers, "Should resolve all 15 hash providers"); // Verify all expected types are present - string[] expectedTypes = ["MD5", "SHA1", "SHA256", "SHA384", "SHA512", "FNV1_32", "FNV1a_32", "FNV1_64", "FNV1a_64", "CRC32", "CRC64", "XxHash32", "XxHash64", "XxHash3", "XxHash128"]; + string[] expectedTypes = ["MD5HashProvider", "SHA1HashProvider", "SHA256HashProvider", "SHA384HashProvider", "SHA512HashProvider", "FNV1_32HashProvider", "FNV1a_32HashProvider", "FNV1_64HashProvider", "FNV1a_64HashProvider", "CRC32HashProvider", "CRC64HashProvider", "XxHash32HashProvider", "XxHash64HashProvider", "XxHash3HashProvider", "XxHash128HashProvider"]; string[] actualTypes = [.. providers.Select(p => p.GetType().Name).OrderBy(n => n)]; CollectionAssert.AreEquivalent(expectedTypes, actualTypes); } @@ -85,7 +88,7 @@ public void DI_Can_Resolve_Multiple_Encoding_Providers() Assert.HasCount(2, providers, "Should resolve both encoding providers"); - string[] expectedTypes = ["Base64", "Hex"]; + string[] expectedTypes = ["Base64EncodingProvider", "HexEncodingProvider"]; string[] actualTypes = [.. providers.Select(p => p.GetType().Name).OrderBy(n => n)]; CollectionAssert.AreEquivalent(expectedTypes, actualTypes); } diff --git a/Essentials.Tests/Essentials.Tests.csproj b/Essentials.Tests/Essentials.Tests.csproj index 2f058ac..8935650 100644 --- a/Essentials.Tests/Essentials.Tests.csproj +++ b/Essentials.Tests/Essentials.Tests.csproj @@ -1,4 +1,4 @@ - + @@ -14,47 +14,47 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + diff --git a/Essentials.Tests/HashProviderTests.cs b/Essentials.Tests/HashProviderTests.cs index 4680e29..ef804a6 100644 --- a/Essentials.Tests/HashProviderTests.cs +++ b/Essentials.Tests/HashProviderTests.cs @@ -157,7 +157,7 @@ public void HashProviders_MD5_Known_Vector() { using ServiceProvider serviceProvider = BuildProvider(); IEnumerable hashes = serviceProvider.GetServices(); - IHashProvider? md5 = hashes.FirstOrDefault(h => h.GetType().Name == "MD5"); + IHashProvider? md5 = hashes.FirstOrDefault(h => h.GetType().Name == "MD5HashProvider"); Assert.IsNotNull(md5); // MD5 of "abc" should be 900150983cd24fb0d6963f7d28e17f72 @@ -172,7 +172,7 @@ public void HashProviders_SHA1_Known_Vector() { using ServiceProvider serviceProvider = BuildProvider(); IEnumerable hashes = serviceProvider.GetServices(); - IHashProvider? sha1 = hashes.FirstOrDefault(h => h.GetType().Name == "SHA1"); + IHashProvider? sha1 = hashes.FirstOrDefault(h => h.GetType().Name == "SHA1HashProvider"); Assert.IsNotNull(sha1); // SHA1 of "abc" should be a9993e364706816aba3e25717850c26c9cd0d89d @@ -187,7 +187,7 @@ public void HashProviders_SHA256_Known_Vector() { using ServiceProvider serviceProvider = BuildProvider(); IEnumerable hashes = serviceProvider.GetServices(); - IHashProvider? sha256 = hashes.FirstOrDefault(h => h.GetType().Name == "SHA256"); + IHashProvider? sha256 = hashes.FirstOrDefault(h => h.GetType().Name == "SHA256HashProvider"); Assert.IsNotNull(sha256); // SHA256 of "abc" should be ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad @@ -202,7 +202,7 @@ public void HashProviders_SHA384_Known_Vector() { using ServiceProvider serviceProvider = BuildProvider(); IEnumerable hashes = serviceProvider.GetServices(); - IHashProvider? sha384 = hashes.FirstOrDefault(h => h.GetType().Name == "SHA384"); + IHashProvider? sha384 = hashes.FirstOrDefault(h => h.GetType().Name == "SHA384HashProvider"); Assert.IsNotNull(sha384); // SHA384 of "abc" should be cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7 @@ -217,7 +217,7 @@ public void HashProviders_SHA512_Known_Vector() { using ServiceProvider serviceProvider = BuildProvider(); IEnumerable hashes = serviceProvider.GetServices(); - IHashProvider? sha512 = hashes.FirstOrDefault(h => h.GetType().Name == "SHA512"); + IHashProvider? sha512 = hashes.FirstOrDefault(h => h.GetType().Name == "SHA512HashProvider"); Assert.IsNotNull(sha512); // SHA512 of "abc" should be ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f @@ -232,7 +232,7 @@ public void HashProviders_FNV1_32_Known_Vector() { using ServiceProvider serviceProvider = BuildProvider(); IEnumerable hashes = serviceProvider.GetServices(); - IHashProvider? fnv1_32 = hashes.FirstOrDefault(h => h.GetType().Name == "FNV1_32"); + IHashProvider? fnv1_32 = hashes.FirstOrDefault(h => h.GetType().Name == "FNV1_32HashProvider"); Assert.IsNotNull(fnv1_32); // FNV-1 32-bit of "hello" produces 0xb7049f97 (3069866343) @@ -247,7 +247,7 @@ public void HashProviders_FNV1a_32_Known_Vector() { using ServiceProvider serviceProvider = BuildProvider(); IEnumerable hashes = serviceProvider.GetServices(); - IHashProvider? fnv1a_32 = hashes.FirstOrDefault(h => h.GetType().Name == "FNV1a_32"); + IHashProvider? fnv1a_32 = hashes.FirstOrDefault(h => h.GetType().Name == "FNV1a_32HashProvider"); Assert.IsNotNull(fnv1a_32); // FNV-1a 32-bit of "hello" produces 0x4f9f2cab (1335831723) @@ -262,7 +262,7 @@ public void HashProviders_FNV1_64_Known_Vector() { using ServiceProvider serviceProvider = BuildProvider(); IEnumerable hashes = serviceProvider.GetServices(); - IHashProvider? fnv1_64 = hashes.FirstOrDefault(h => h.GetType().Name == "FNV1_64"); + IHashProvider? fnv1_64 = hashes.FirstOrDefault(h => h.GetType().Name == "FNV1_64HashProvider"); Assert.IsNotNull(fnv1_64); // FNV-1 64-bit of "hello" produces 0x7b495389bdbdd4c7 (8883723591023973575) @@ -277,7 +277,7 @@ public void HashProviders_FNV1a_64_Known_Vector() { using ServiceProvider serviceProvider = BuildProvider(); IEnumerable hashes = serviceProvider.GetServices(); - IHashProvider? fnv1a_64 = hashes.FirstOrDefault(h => h.GetType().Name == "FNV1a_64"); + IHashProvider? fnv1a_64 = hashes.FirstOrDefault(h => h.GetType().Name == "FNV1a_64HashProvider"); Assert.IsNotNull(fnv1a_64); // FNV-1a 64-bit of "hello" produces 0xa430d84680aabd0b (11831194018420276491) diff --git a/Essentials.Tests/ObfuscationProviderTests.cs b/Essentials.Tests/ObfuscationProviderTests.cs index c75aa06..9c5cd3e 100644 --- a/Essentials.Tests/ObfuscationProviderTests.cs +++ b/Essentials.Tests/ObfuscationProviderTests.cs @@ -7,6 +7,8 @@ namespace ktsu.Essentials.Tests; using System.Collections.Generic; using System.Text; using ktsu.Essentials; +using ktsu.Essentials.ObfuscationProviders.Base64; +using ktsu.Essentials.ObfuscationProviders.Hex; using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -73,7 +75,7 @@ public void Obfuscation_Async_Roundtrip(IObfuscationProvider provider, string pr [TestMethod] public void Obfuscation_Base64_Roundtrip_String() { - IObfuscationProvider provider = new ObfuscationProviders.Base64(); + IObfuscationProvider provider = new Base64ObfuscationProvider(); string original = "string obfuscate via base64"; string obfuscated = provider.Obfuscate(original); byte[] obfuscatedBytes = System.Text.Encoding.UTF8.GetBytes(obfuscated); @@ -85,7 +87,7 @@ public void Obfuscation_Base64_Roundtrip_String() [TestMethod] public void Obfuscation_Hex_Roundtrip_String() { - IObfuscationProvider provider = new ObfuscationProviders.Hex(); + IObfuscationProvider provider = new HexObfuscationProvider(); string original = "string obfuscate via hex"; string obfuscated = provider.Obfuscate(original); byte[] obfuscatedBytes = System.Text.Encoding.UTF8.GetBytes(obfuscated); diff --git a/Essentials.Tests/PersistenceProviderTests.cs b/Essentials.Tests/PersistenceProviderTests.cs index 41b0ac4..78134bb 100644 --- a/Essentials.Tests/PersistenceProviderTests.cs +++ b/Essentials.Tests/PersistenceProviderTests.cs @@ -7,7 +7,10 @@ namespace ktsu.Essentials.Tests; using System; using System.IO; using ktsu.Essentials; -using ktsu.Essentials.PersistenceProviders; +using ktsu.Essentials.FileSystemProviders.Native; +using ktsu.Essentials.PersistenceProviders.AppData; +using ktsu.Essentials.PersistenceProviders.FileSystem; +using ktsu.Essentials.PersistenceProviders.Temp; using ktsu.Essentials.SerializationProviders.Json; using Microsoft.Extensions.DependencyInjection; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -26,7 +29,7 @@ private static IPersistenceProvider CreatePersistence() } [TestMethod] - public async System.Threading.Tasks.Task Persistence_Store_And_Retrieve() + public async Task Persistence_Store_And_Retrieve() { IPersistenceProvider persistence = CreatePersistence(); @@ -37,7 +40,7 @@ public async System.Threading.Tasks.Task Persistence_Store_And_Retrieve() } [TestMethod] - public async System.Threading.Tasks.Task Persistence_Retrieve_Missing_Returns_Default() + public async Task Persistence_Retrieve_Missing_Returns_Default() { IPersistenceProvider persistence = CreatePersistence(); @@ -47,7 +50,7 @@ public async System.Threading.Tasks.Task Persistence_Retrieve_Missing_Returns_De } [TestMethod] - public async System.Threading.Tasks.Task Persistence_Exists() + public async Task Persistence_Exists() { IPersistenceProvider persistence = CreatePersistence(); @@ -61,7 +64,7 @@ public async System.Threading.Tasks.Task Persistence_Exists() } [TestMethod] - public async System.Threading.Tasks.Task Persistence_Remove() + public async Task Persistence_Remove() { IPersistenceProvider persistence = CreatePersistence(); @@ -73,7 +76,7 @@ public async System.Threading.Tasks.Task Persistence_Remove() } [TestMethod] - public async System.Threading.Tasks.Task Persistence_Remove_Missing_Returns_False() + public async Task Persistence_Remove_Missing_Returns_False() { IPersistenceProvider persistence = CreatePersistence(); @@ -82,7 +85,7 @@ public async System.Threading.Tasks.Task Persistence_Remove_Missing_Returns_Fals } [TestMethod] - public async System.Threading.Tasks.Task Persistence_GetAllKeys() + public async Task Persistence_GetAllKeys() { IPersistenceProvider persistence = CreatePersistence(); @@ -98,7 +101,7 @@ public async System.Threading.Tasks.Task Persistence_GetAllKeys() } [TestMethod] - public async System.Threading.Tasks.Task Persistence_Clear() + public async Task Persistence_Clear() { IPersistenceProvider persistence = CreatePersistence(); @@ -111,7 +114,7 @@ public async System.Threading.Tasks.Task Persistence_Clear() } [TestMethod] - public async System.Threading.Tasks.Task Persistence_RetrieveOrCreate() + public async Task Persistence_RetrieveOrCreate() { IPersistenceProvider persistence = CreatePersistence(); @@ -142,14 +145,14 @@ private static void CleanupDirectory(string path) } [TestMethod] - public async System.Threading.Tasks.Task FileSystem_Store_And_Retrieve() + public async Task FileSystem_Store_And_Retrieve() { string tempDir = Path.Combine(Path.GetTempPath(), "PersistenceTests_FS_" + Guid.NewGuid().ToString("N")[..8]); try { - FileSystemProviders.Native fs = new(); + NativeFileSystemProvider fs = new(); JsonSerializationProvider serializer = new(); - FileSystem persistence = new(fs, serializer, tempDir); + FileSystemPersistenceProvider persistence = new(fs, serializer, tempDir); await persistence.StoreAsync("key1", new TestData { Name = "test" }, TestContext.CancellationToken).ConfigureAwait(false); TestData? result = await persistence.RetrieveAsync("key1", TestContext.CancellationToken).ConfigureAwait(false); @@ -164,14 +167,14 @@ public async System.Threading.Tasks.Task FileSystem_Store_And_Retrieve() } [TestMethod] - public async System.Threading.Tasks.Task FileSystem_Exists_And_Remove() + public async Task FileSystem_Exists_And_Remove() { string tempDir = Path.Combine(Path.GetTempPath(), "PersistenceTests_FS_" + Guid.NewGuid().ToString("N")[..8]); try { - FileSystemProviders.Native fs = new(); + NativeFileSystemProvider fs = new(); JsonSerializationProvider serializer = new(); - FileSystem persistence = new(fs, serializer, tempDir); + FileSystemPersistenceProvider persistence = new(fs, serializer, tempDir); await persistence.StoreAsync("key1", "value1", TestContext.CancellationToken).ConfigureAwait(false); Assert.IsTrue(await persistence.ExistsAsync("key1", TestContext.CancellationToken).ConfigureAwait(false)); @@ -187,14 +190,14 @@ public async System.Threading.Tasks.Task FileSystem_Exists_And_Remove() } [TestMethod] - public async System.Threading.Tasks.Task FileSystem_GetAllKeys_And_Clear() + public async Task FileSystem_GetAllKeys_And_Clear() { string tempDir = Path.Combine(Path.GetTempPath(), "PersistenceTests_FS_" + Guid.NewGuid().ToString("N")[..8]); try { - FileSystemProviders.Native fs = new(); + NativeFileSystemProvider fs = new(); JsonSerializationProvider serializer = new(); - FileSystem persistence = new(fs, serializer, tempDir); + FileSystemPersistenceProvider persistence = new(fs, serializer, tempDir); await persistence.StoreAsync("a", "1", TestContext.CancellationToken).ConfigureAwait(false); await persistence.StoreAsync("b", "2", TestContext.CancellationToken).ConfigureAwait(false); @@ -216,9 +219,9 @@ public async System.Threading.Tasks.Task FileSystem_GetAllKeys_And_Clear() public void FileSystem_Properties() { string tempDir = Path.Combine(Path.GetTempPath(), "PersistenceTests_FS_" + Guid.NewGuid().ToString("N")[..8]); - FileSystemProviders.Native fs = new(); + NativeFileSystemProvider fs = new(); JsonSerializationProvider serializer = new(); - FileSystem persistence = new(fs, serializer, tempDir); + FileSystemPersistenceProvider persistence = new(fs, serializer, tempDir); Assert.AreEqual("FileSystem", persistence.ProviderName); Assert.IsTrue(persistence.IsPersistent); @@ -227,12 +230,12 @@ public void FileSystem_Properties() // --- AppData Provider Tests --- [TestMethod] - public async System.Threading.Tasks.Task AppData_Store_And_Retrieve() + public async Task AppData_Store_And_Retrieve() { string appName = "PersistenceTests_AD_" + Guid.NewGuid().ToString("N")[..8]; - FileSystemProviders.Native fs = new(); + NativeFileSystemProvider fs = new(); JsonSerializationProvider serializer = new(); - AppData persistence = new(fs, serializer, appName); + AppDataPersistenceProvider persistence = new(fs, serializer, appName); try { @@ -251,12 +254,12 @@ public async System.Threading.Tasks.Task AppData_Store_And_Retrieve() } [TestMethod] - public async System.Threading.Tasks.Task AppData_Exists_And_Remove() + public async Task AppData_Exists_And_Remove() { string appName = "PersistenceTests_AD_" + Guid.NewGuid().ToString("N")[..8]; - FileSystemProviders.Native fs = new(); + NativeFileSystemProvider fs = new(); JsonSerializationProvider serializer = new(); - AppData persistence = new(fs, serializer, appName); + AppDataPersistenceProvider persistence = new(fs, serializer, appName); try { @@ -278,9 +281,9 @@ public async System.Threading.Tasks.Task AppData_Exists_And_Remove() public void AppData_Properties() { string appName = "PersistenceTests_AD_" + Guid.NewGuid().ToString("N")[..8]; - FileSystemProviders.Native fs = new(); + NativeFileSystemProvider fs = new(); JsonSerializationProvider serializer = new(); - AppData persistence = new(fs, serializer, appName); + AppDataPersistenceProvider persistence = new(fs, serializer, appName); Assert.AreEqual("AppData", persistence.ProviderName); Assert.IsTrue(persistence.IsPersistent); @@ -289,11 +292,11 @@ public void AppData_Properties() // --- Temp Provider Tests --- [TestMethod] - public async System.Threading.Tasks.Task Temp_Store_And_Retrieve() + public async Task Temp_Store_And_Retrieve() { - FileSystemProviders.Native fs = new(); + NativeFileSystemProvider fs = new(); JsonSerializationProvider serializer = new(); - using Temp persistence = new(fs, serializer, "PersistenceTests_Temp"); + using TempPersistenceProvider persistence = new(fs, serializer, "PersistenceTests_Temp"); try { @@ -310,11 +313,11 @@ public async System.Threading.Tasks.Task Temp_Store_And_Retrieve() } [TestMethod] - public async System.Threading.Tasks.Task Temp_Exists_And_Remove() + public async Task Temp_Exists_And_Remove() { - FileSystemProviders.Native fs = new(); + NativeFileSystemProvider fs = new(); JsonSerializationProvider serializer = new(); - using Temp persistence = new(fs, serializer, "PersistenceTests_Temp"); + using TempPersistenceProvider persistence = new(fs, serializer, "PersistenceTests_Temp"); try { @@ -332,11 +335,11 @@ public async System.Threading.Tasks.Task Temp_Exists_And_Remove() } [TestMethod] - public async System.Threading.Tasks.Task Temp_GetAllKeys_And_Clear() + public async Task Temp_GetAllKeys_And_Clear() { - FileSystemProviders.Native fs = new(); + NativeFileSystemProvider fs = new(); JsonSerializationProvider serializer = new(); - using Temp persistence = new(fs, serializer, "PersistenceTests_Temp"); + using TempPersistenceProvider persistence = new(fs, serializer, "PersistenceTests_Temp"); try { @@ -359,9 +362,9 @@ public async System.Threading.Tasks.Task Temp_GetAllKeys_And_Clear() [TestMethod] public void Temp_Properties() { - FileSystemProviders.Native fs = new(); + NativeFileSystemProvider fs = new(); JsonSerializationProvider serializer = new(); - using Temp persistence = new(fs, serializer, "PersistenceTests_Temp"); + using TempPersistenceProvider persistence = new(fs, serializer, "PersistenceTests_Temp"); try { diff --git a/Essentials.Tests/ServiceCollectionExtensions.cs b/Essentials.Tests/ServiceCollectionExtensions.cs index d431c60..df6f27e 100644 --- a/Essentials.Tests/ServiceCollectionExtensions.cs +++ b/Essentials.Tests/ServiceCollectionExtensions.cs @@ -5,10 +5,41 @@ namespace ktsu.Essentials.Tests; using ktsu.Essentials; -using ktsu.Essentials.CompressionProviders; -using ktsu.Essentials.EncryptionProviders; -using ktsu.Essentials.HashProviders; -using ktsu.Essentials.ObfuscationProviders; +using ktsu.Essentials.CacheProviders.InMemory; +using ktsu.Essentials.CommandExecutors.Native; +using ktsu.Essentials.CompressionProviders.Brotli; +using ktsu.Essentials.CompressionProviders.Deflate; +using ktsu.Essentials.CompressionProviders.Gzip; +using ktsu.Essentials.CompressionProviders.ZLib; +using ktsu.Essentials.EncodingProviders.Base64; +using ktsu.Essentials.EncodingProviders.Hex; +using ktsu.Essentials.EncryptionProviders.Aes; +using ktsu.Essentials.FileSystemProviders.Native; +using ktsu.Essentials.HashProviders.CRC32; +using ktsu.Essentials.HashProviders.CRC64; +using ktsu.Essentials.HashProviders.FNV1_32; +using ktsu.Essentials.HashProviders.FNV1_64; +using ktsu.Essentials.HashProviders.FNV1a_32; +using ktsu.Essentials.HashProviders.FNV1a_64; +using ktsu.Essentials.HashProviders.MD5; +using ktsu.Essentials.HashProviders.SHA1; +using ktsu.Essentials.HashProviders.SHA256; +using ktsu.Essentials.HashProviders.SHA384; +using ktsu.Essentials.HashProviders.SHA512; +using ktsu.Essentials.HashProviders.XxHash128; +using ktsu.Essentials.HashProviders.XxHash3; +using ktsu.Essentials.HashProviders.XxHash32; +using ktsu.Essentials.HashProviders.XxHash64; +using ktsu.Essentials.LoggingProviders.Console; +using ktsu.Essentials.NavigationProviders.InMemory; +using ktsu.Essentials.ObfuscationProviders.Base64; +using ktsu.Essentials.ObfuscationProviders.BitRotate; +using ktsu.Essentials.ObfuscationProviders.Caesar; +using ktsu.Essentials.ObfuscationProviders.Composite; +using ktsu.Essentials.ObfuscationProviders.Hex; +using ktsu.Essentials.ObfuscationProviders.Reverse; +using ktsu.Essentials.ObfuscationProviders.Xor; +using ktsu.Essentials.PersistenceProviders.InMemory; using ktsu.Essentials.SerializationProviders.Json; using ktsu.Essentials.SerializationProviders.Toml; using ktsu.Essentials.SerializationProviders.Yaml; @@ -35,54 +66,54 @@ public static ServiceCollection AddCommon(this ServiceCollection services) public static ServiceCollection AddCompressionProviders(this ServiceCollection services) { - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); return services; } public static ServiceCollection AddEncryptionProviders(this ServiceCollection services) { - services.AddSingleton(); + services.AddSingleton(); return services; } public static ServiceCollection AddObfuscationProviders(this ServiceCollection services) { - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(_ => new ObfuscationProviders.Base64()); - services.AddSingleton(_ => new ObfuscationProviders.Hex()); - services.AddSingleton(_ => new Composite([new Xor(), new BitRotate()])); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(_ => new Base64ObfuscationProvider()); + services.AddSingleton(_ => new HexObfuscationProvider()); + services.AddSingleton(_ => new CompositeObfuscationProvider([new XorObfuscationProvider(), new BitRotateObfuscationProvider()])); return services; } public static ServiceCollection AddFileSystemProviders(this ServiceCollection services) { - services.AddSingleton(); + services.AddSingleton(); return services; } public static ServiceCollection AddHashProviders(this ServiceCollection services) { - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); return services; } @@ -96,38 +127,38 @@ public static ServiceCollection AddSerializationProviders(this ServiceCollection public static ServiceCollection AddEncodingProviders(this ServiceCollection services) { - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); return services; } public static ServiceCollection AddCommandExecutors(this ServiceCollection services) { - services.AddSingleton(); + services.AddSingleton(); return services; } public static ServiceCollection AddLoggingProviders(this ServiceCollection services) { - services.AddSingleton(); + services.AddSingleton(); return services; } public static ServiceCollection AddCacheProviders(this ServiceCollection services) { - services.AddSingleton(typeof(ICacheProvider<,>), typeof(CacheProviders.InMemory<,>)); + services.AddSingleton(typeof(ICacheProvider<,>), typeof(InMemoryCacheProvider<,>)); return services; } public static ServiceCollection AddNavigationProviders(this ServiceCollection services) { - services.AddTransient(typeof(INavigationProvider<>), typeof(NavigationProviders.InMemory<>)); + services.AddTransient(typeof(INavigationProvider<>), typeof(InMemoryNavigationProvider<>)); return services; } public static ServiceCollection AddPersistenceProviders(this ServiceCollection services) { - services.AddSingleton(typeof(IPersistenceProvider<>), typeof(PersistenceProviders.InMemory<>)); + services.AddSingleton(typeof(IPersistenceProvider<>), typeof(InMemoryPersistenceProvider<>)); return services; } } diff --git a/Essentials.slnx b/Essentials.slnx index 4149b5b..2513c0b 100644 --- a/Essentials.slnx +++ b/Essentials.slnx @@ -1,69 +1,69 @@ - + - + - + - - - - + + + + - - + + - + - - - - - - - + + + + + + + - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - + - + - - - - + + + + diff --git a/HashProviders/FNV1_32/FNV1_32.csproj b/HashProviders/FNV1_32/FNV1_32.csproj deleted file mode 100644 index 10a56d8..0000000 --- a/HashProviders/FNV1_32/FNV1_32.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.HashProviders.FNV1_32 - ktsu.Essentials.HashProviders - - - - - - - - - - - - diff --git a/HashProviders/FNV1_64/FNV1_64.csproj b/HashProviders/FNV1_64/FNV1_64.csproj deleted file mode 100644 index 3b71062..0000000 --- a/HashProviders/FNV1_64/FNV1_64.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.HashProviders.FNV1_64 - ktsu.Essentials.HashProviders - - - - - - - - - - - - diff --git a/HashProviders/FNV1a_32/FNV1a_32.csproj b/HashProviders/FNV1a_32/FNV1a_32.csproj deleted file mode 100644 index 6ccc765..0000000 --- a/HashProviders/FNV1a_32/FNV1a_32.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.HashProviders.FNV1a_32 - ktsu.Essentials.HashProviders - - - - - - - - - - - - diff --git a/HashProviders/FNV1a_64/FNV1a_64.csproj b/HashProviders/FNV1a_64/FNV1a_64.csproj deleted file mode 100644 index 7d69df9..0000000 --- a/HashProviders/FNV1a_64/FNV1a_64.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.HashProviders.FNV1a_64 - ktsu.Essentials.HashProviders - - - - - - - - - - - - diff --git a/HashProviders/SHA512/SHA512.csproj b/HashProviders/SHA512/SHA512.csproj deleted file mode 100644 index 0c45989..0000000 --- a/HashProviders/SHA512/SHA512.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.HashProviders.SHA512 - ktsu.Essentials.HashProviders - - - - - - - - - - - - diff --git a/HashProviders/XxHash128/XxHash128.csproj b/HashProviders/XxHash128/XxHash128.csproj deleted file mode 100644 index a7673dc..0000000 --- a/HashProviders/XxHash128/XxHash128.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.HashProviders.XxHash128 - ktsu.Essentials.HashProviders - - - - - - - - - - - - - diff --git a/HashProviders/XxHash64/XxHash64.csproj b/HashProviders/XxHash64/XxHash64.csproj deleted file mode 100644 index 0a8473a..0000000 --- a/HashProviders/XxHash64/XxHash64.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.HashProviders.XxHash64 - ktsu.Essentials.HashProviders - - - - - - - - - - - - - diff --git a/LoggingProviders/Console/Console.csproj b/LoggingProviders/Console/Console.csproj deleted file mode 100644 index 17c21f5..0000000 --- a/LoggingProviders/Console/Console.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.LoggingProviders.Console - ktsu.Essentials.LoggingProviders - - - - - - - - - - - - diff --git a/NavigationProviders/InMemory/InMemory.csproj b/NavigationProviders/InMemory/InMemory.csproj deleted file mode 100644 index 65838b2..0000000 --- a/NavigationProviders/InMemory/InMemory.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.NavigationProviders.InMemory - ktsu.Essentials.NavigationProviders - - - - - - - - - - - - diff --git a/ObfuscationProviders/Base64/Base64.csproj b/ObfuscationProviders/Base64/Base64.csproj deleted file mode 100644 index 78bb194..0000000 --- a/ObfuscationProviders/Base64/Base64.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.ObfuscationProviders.Base64 - ktsu.Essentials.ObfuscationProviders - - - - - - - - - - - - - diff --git a/ObfuscationProviders/BitRotate/BitRotate.csproj b/ObfuscationProviders/BitRotate/BitRotate.csproj deleted file mode 100644 index c421862..0000000 --- a/ObfuscationProviders/BitRotate/BitRotate.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.ObfuscationProviders.BitRotate - ktsu.Essentials.ObfuscationProviders - - - - - - - - - - - - diff --git a/ObfuscationProviders/Caesar/Caesar.csproj b/ObfuscationProviders/Caesar/Caesar.csproj deleted file mode 100644 index 9f2fc98..0000000 --- a/ObfuscationProviders/Caesar/Caesar.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.ObfuscationProviders.Caesar - ktsu.Essentials.ObfuscationProviders - - - - - - - - - - - - diff --git a/ObfuscationProviders/Composite/Composite.csproj b/ObfuscationProviders/Composite/Composite.csproj deleted file mode 100644 index 710c854..0000000 --- a/ObfuscationProviders/Composite/Composite.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.ObfuscationProviders.Composite - ktsu.Essentials.ObfuscationProviders - - - - - - - - - - - - diff --git a/ObfuscationProviders/Hex/Hex.csproj b/ObfuscationProviders/Hex/Hex.csproj deleted file mode 100644 index 877f755..0000000 --- a/ObfuscationProviders/Hex/Hex.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.ObfuscationProviders.Hex - ktsu.Essentials.ObfuscationProviders - - - - - - - - - - - - - diff --git a/ObfuscationProviders/Reverse/Reverse.csproj b/ObfuscationProviders/Reverse/Reverse.csproj deleted file mode 100644 index d37b468..0000000 --- a/ObfuscationProviders/Reverse/Reverse.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.ObfuscationProviders.Reverse - ktsu.Essentials.ObfuscationProviders - - - - - - - - - - - - diff --git a/ObfuscationProviders/Xor/Xor.csproj b/ObfuscationProviders/Xor/Xor.csproj deleted file mode 100644 index ceb3163..0000000 --- a/ObfuscationProviders/Xor/Xor.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.ObfuscationProviders.Xor - ktsu.Essentials.ObfuscationProviders - - - - - - - - - - - - diff --git a/PersistenceProviders/InMemory/InMemory.csproj b/PersistenceProviders/InMemory/InMemory.csproj deleted file mode 100644 index 6319921..0000000 --- a/PersistenceProviders/InMemory/InMemory.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 - true - ktsu.Essentials.PersistenceProviders.InMemory - ktsu.Essentials.PersistenceProviders - - - - - - - - - - - - From b602dee365c8022df796aec185cad50407176c15 Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Wed, 1 Jul 2026 11:40:23 +1000 Subject: [PATCH 15/17] feat: port NewtonsoftJson serialization provider from Common Adds Essentials.SerializationProviders.NewtonsoftJson (ktsu.Sdk naming convention), registers it in test DI, pins Newtonsoft.Json 13.0.4, and updates DiTests to expect 4 serialization providers. Full suite: 288/288 passing. --- Directory.Packages.props | 1 + ...rializationProviders.NewtonsoftJson.csproj | 19 +++++ .../NewtonsoftJsonSerializationProvider.cs | 77 +++++++++++++++++++ Essentials.Tests/DiTests.cs | 4 +- Essentials.Tests/Essentials.Tests.csproj | 1 + .../ServiceCollectionExtensions.cs | 2 + Essentials.slnx | 3 +- 7 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 Essentials.SerializationProviders.NewtonsoftJson/Essentials.SerializationProviders.NewtonsoftJson.csproj create mode 100644 Essentials.SerializationProviders.NewtonsoftJson/NewtonsoftJsonSerializationProvider.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index 8e03c60..b1bb395 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -11,6 +11,7 @@ + diff --git a/Essentials.SerializationProviders.NewtonsoftJson/Essentials.SerializationProviders.NewtonsoftJson.csproj b/Essentials.SerializationProviders.NewtonsoftJson/Essentials.SerializationProviders.NewtonsoftJson.csproj new file mode 100644 index 0000000..9d05359 --- /dev/null +++ b/Essentials.SerializationProviders.NewtonsoftJson/Essentials.SerializationProviders.NewtonsoftJson.csproj @@ -0,0 +1,19 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + + + + + + + + + + + + + diff --git a/Essentials.SerializationProviders.NewtonsoftJson/NewtonsoftJsonSerializationProvider.cs b/Essentials.SerializationProviders.NewtonsoftJson/NewtonsoftJsonSerializationProvider.cs new file mode 100644 index 0000000..01d2056 --- /dev/null +++ b/Essentials.SerializationProviders.NewtonsoftJson/NewtonsoftJsonSerializationProvider.cs @@ -0,0 +1,77 @@ +// Copyright (c) ktsu.dev +// All rights reserved. +// Licensed under the MIT license. + +namespace ktsu.Essentials.SerializationProviders.NewtonsoftJson; + +using ktsu.Essentials; +using System; +using System.IO; +using System.Text; +using Newtonsoft.Json; + +/// +/// A serialization provider that uses Newtonsoft.Json for JSON serialization and deserialization. +/// +public class NewtonsoftJsonSerializationProvider : ISerializationProvider +{ + private readonly JsonSerializerSettings settings = new(); + + /// + /// Tries to serialize the specified object into the writer. + /// + /// The object to serialize. + /// The writer to write the serialized data to. + /// True if the serialization was successful, false otherwise. + public bool TrySerialize(object obj, TextWriter writer) + { + if (writer is null) + { + return false; + } + + try + { + using JsonTextWriter jsonWriter = new(writer); + JsonSerializer serializer = JsonSerializer.Create(settings); + serializer.Serialize(jsonWriter, obj); + return true; + } + catch (JsonSerializationException) + { + return false; + } + catch (JsonWriterException) + { + return false; + } + } + + /// + /// Deserializes the specified data into a specific type. + /// + /// The type to deserialize into. + /// The UTF-8 encoded data to deserialize. + /// The deserialized object, or default if deserialization fails. + public T? Deserialize(ReadOnlySpan data) + { + if (data.IsEmpty) + { + return default; + } + + try + { + string jsonString = Encoding.UTF8.GetString(data); + return JsonConvert.DeserializeObject(jsonString, settings); + } + catch (JsonReaderException) + { + return default; + } + catch (ArgumentException) + { + return default; + } + } +} diff --git a/Essentials.Tests/DiTests.cs b/Essentials.Tests/DiTests.cs index c41c3ce..95cebea 100644 --- a/Essentials.Tests/DiTests.cs +++ b/Essentials.Tests/DiTests.cs @@ -116,10 +116,10 @@ public void DI_Can_Resolve_Multiple_Serialization_Providers() IEnumerable serializationProviders = serviceProvider.GetServices(); ISerializationProvider[] providers = [.. serializationProviders]; - Assert.HasCount(3, providers, "Should resolve all 3 serialization providers"); + Assert.HasCount(4, providers, "Should resolve all 4 serialization providers"); // Verify all expected types are present - string[] expectedTypes = ["JsonSerializationProvider", "TomlSerializationProvider", "YamlSerializationProvider"]; + string[] expectedTypes = ["JsonSerializationProvider", "NewtonsoftJsonSerializationProvider", "TomlSerializationProvider", "YamlSerializationProvider"]; string[] actualTypes = [.. providers.Select(p => p.GetType().Name).OrderBy(n => n)]; CollectionAssert.AreEquivalent(expectedTypes, actualTypes); } diff --git a/Essentials.Tests/Essentials.Tests.csproj b/Essentials.Tests/Essentials.Tests.csproj index 8935650..bf48808 100644 --- a/Essentials.Tests/Essentials.Tests.csproj +++ b/Essentials.Tests/Essentials.Tests.csproj @@ -45,6 +45,7 @@ + diff --git a/Essentials.Tests/ServiceCollectionExtensions.cs b/Essentials.Tests/ServiceCollectionExtensions.cs index df6f27e..4e784ab 100644 --- a/Essentials.Tests/ServiceCollectionExtensions.cs +++ b/Essentials.Tests/ServiceCollectionExtensions.cs @@ -41,6 +41,7 @@ namespace ktsu.Essentials.Tests; using ktsu.Essentials.ObfuscationProviders.Xor; using ktsu.Essentials.PersistenceProviders.InMemory; using ktsu.Essentials.SerializationProviders.Json; +using ktsu.Essentials.SerializationProviders.NewtonsoftJson; using ktsu.Essentials.SerializationProviders.Toml; using ktsu.Essentials.SerializationProviders.Yaml; using Microsoft.Extensions.DependencyInjection; @@ -120,6 +121,7 @@ public static ServiceCollection AddHashProviders(this ServiceCollection services public static ServiceCollection AddSerializationProviders(this ServiceCollection services) { services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); return services; diff --git a/Essentials.slnx b/Essentials.slnx index 2513c0b..2f8c9c4 100644 --- a/Essentials.slnx +++ b/Essentials.slnx @@ -1,4 +1,4 @@ - + @@ -71,5 +71,6 @@ + From 3ac1ffd3c483440bdd7987daa1c2da238d90e285 Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Wed, 1 Jul 2026 11:53:54 +1000 Subject: [PATCH 16/17] feat: add ktsu.Essentials.All meta-package References all 42 provider implementation projects as package dependencies (IncludeBuildOutput=false, no lib). ZLib is conditionally excluded from netstandard2.1 (it targets net6.0+ only). Restores cleanly. Note: full dotnet pack is currently blocked repo-wide by a pre-existing NU1510 (System.Text.Json pruning warning-as-error), unrelated to this meta-package. --- Essentials.All/Essentials.All.csproj | 57 ++++++++++++++++++++++++++++ Essentials.slnx | 1 + 2 files changed, 58 insertions(+) create mode 100644 Essentials.All/Essentials.All.csproj diff --git a/Essentials.All/Essentials.All.csproj b/Essentials.All/Essentials.All.csproj new file mode 100644 index 0000000..7bb901f --- /dev/null +++ b/Essentials.All/Essentials.All.csproj @@ -0,0 +1,57 @@ + + + + + net10.0;net9.0;net8.0;net7.0;net6.0;netstandard2.1 + true + false + Batteries-included meta-package that references every ktsu.Essentials provider implementation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Essentials.slnx b/Essentials.slnx index 2f8c9c4..3e4be51 100644 --- a/Essentials.slnx +++ b/Essentials.slnx @@ -71,6 +71,7 @@ + From bce97a24a7f9c4db4a15d17370d57a4afcae2630 Mon Sep 17 00:00:00 2001 From: Matt Edmondson Date: Wed, 1 Jul 2026 11:57:48 +1000 Subject: [PATCH 17/17] docs: document obfuscation, NewtonsoftJson, All meta-package, and new naming convention --- CLAUDE.md | 35 +++++++++++++++++++++-------------- DESCRIPTION.md | 2 +- README.md | 8 +++++--- TAGS.md | 2 +- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index d1afa2d..a2c79b3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -19,7 +19,7 @@ dotnet build -c Release ## Project Structure -This is a .NET library (`ktsu.Essentials`) providing high-performance interfaces and implementations for common cross-cutting concerns: compression, encoding, encryption, hashing, serialization, caching, persistence, validation, logging, navigation, command execution, and filesystem access. The solution uses: +This is a .NET library (`ktsu.Essentials`) providing high-performance interfaces and implementations for common cross-cutting concerns: compression, encoding, obfuscation, encryption, hashing, serialization, caching, persistence, validation, logging, navigation, command execution, and filesystem access. The solution uses: - **ktsu.Sdk** - Custom SDK providing shared build configuration - **MSTest.Sdk** - Test project SDK with Microsoft Testing Platform @@ -29,6 +29,7 @@ This is a .NET library (`ktsu.Essentials`) providing high-performance interfaces - `Essentials/ICompressionProvider.cs` - Compression/decompression interface with Span, Stream, and string support - `Essentials/IEncodingProvider.cs` - Format/transport encoding interface (Base64, Hex) +- `Essentials/IObfuscationProvider.cs` - Reversible obfuscation interface (NOT encryption); implementations compose encoding transforms and simple byte operations - `Essentials/IEncryptionProvider.cs` - Encryption/decryption interface with key/IV management - `Essentials/IHashProvider.cs` - Hashing interface with configurable output length - `Essentials/ISerializationProvider.cs` - Object serialization/deserialization interface @@ -46,21 +47,26 @@ This is a .NET library (`ktsu.Essentials`) providing high-performance interfaces ### Provider Implementations (in solution) -- **CompressionProviders/**: Gzip, Brotli, Deflate, ZLib — namespace `ktsu.Essentials.CompressionProviders` -- **EncodingProviders/**: Base64, Hex — namespace `ktsu.Essentials.EncodingProviders` -- **EncryptionProviders/**: Aes — namespace `ktsu.Essentials.EncryptionProviders` -- **HashProviders/**: MD5, SHA1, SHA256, SHA384, SHA512, FNV1_32, FNV1a_32, FNV1_64, FNV1a_64, CRC32, CRC64, XxHash32, XxHash64, XxHash3, XxHash128 — namespace `ktsu.Essentials.HashProviders` -- **SerializationProviders/**: Json, Yaml, Toml — namespace `ktsu.Essentials.SerializationProviders` -- **FileSystemProviders/**: Native — namespace `ktsu.Essentials.FileSystemProviders` -- **CommandExecutors/**: Native — namespace `ktsu.Essentials.CommandExecutors` -- **LoggingProviders/**: Console — namespace `ktsu.Essentials.LoggingProviders` -- **CacheProviders/**: InMemory — namespace `ktsu.Essentials.CacheProviders` -- **NavigationProviders/**: InMemory — namespace `ktsu.Essentials.NavigationProviders` -- **PersistenceProviders/**: AppData, FileSystem, InMemory, Temp — namespace `ktsu.Essentials.PersistenceProviders` +Each provider implementation ships as its own project/package named `Essentials..` (NuGet id `ktsu.Essentials..`): -### Namespace Convention +- **CompressionProviders**: Gzip, Brotli, Deflate, ZLib (ZLib targets net6.0+ only, not netstandard2.1) +- **EncodingProviders**: Base64, Hex +- **ObfuscationProviders**: Xor, Caesar, Reverse, BitRotate, Base64, Hex, Composite +- **EncryptionProviders**: Aes +- **HashProviders**: MD5, SHA1, SHA256, SHA384, SHA512, FNV1_32, FNV1a_32, FNV1_64, FNV1a_64, CRC32, CRC64, XxHash32, XxHash64, XxHash3, XxHash128 +- **SerializationProviders**: Json (System.Text.Json), NewtonsoftJson, Yaml, Toml +- **FileSystemProviders**: Native +- **CommandExecutors**: Native +- **LoggingProviders**: Console +- **CacheProviders**: InMemory +- **NavigationProviders**: InMemory +- **PersistenceProviders**: AppData, FileSystem, InMemory, Temp -Interfaces are defined in the `ktsu.Essentials` namespace (in the `Essentials/` directory). Provider implementations use sub-namespaces matching their category directory: `ktsu.Essentials.`. For example, `SHA256` is in `ktsu.Essentials.HashProviders` and `Gzip` is in `ktsu.Essentials.CompressionProviders`. +The **`Essentials.All`** project (`ktsu.Essentials.All`) is a meta-package that references every provider implementation for a one-install "batteries-included" experience; consumers can otherwise cherry-pick individual provider packages. + +### Namespace & Naming Convention + +Interfaces are defined in the `ktsu.Essentials` namespace (in the `Essentials/` directory). Each provider implementation lives in its own directory `Essentials../`, in namespace `ktsu.Essentials..`, with the class named `Provider`. For example, the SHA-256 hash provider is class `SHA256HashProvider` in namespace `ktsu.Essentials.HashProviders.SHA256`, and the XOR obfuscator is class `XorObfuscationProvider` in `ktsu.Essentials.ObfuscationProviders.Xor`. Higher-level concerns compose primitives rather than duplicating them: configuration is an `IPersistenceProvider` over a serializer, and each obfuscator composes an encoding transform or a simple reversible byte operation. Obfuscators that wrap an `IEncodingProvider` (Base64, Hex) keep both a parameterless and an encoder-accepting constructor public and are registered via a DI factory lambda to avoid greedy-constructor selection. ### Dependencies @@ -95,6 +101,7 @@ Tests use **MSTest.Sdk** targeting net10.0 only. The test project (`Essentials.T - `CacheProviderTests.cs` - Tests cache operations including expiration - `CommandExecutorTests.cs` - Tests command execution - `EncodingProviderTests.cs` - Tests Base64 and Hex encoding +- `ObfuscationProviderTests.cs` - Tests all obfuscation providers via round-trip (obfuscate → deobfuscate) - `FileSystemProviderTests.cs` - Tests filesystem operations - `LoggingProviderTests.cs` - Tests logging provider - `NavigationProviderTests.cs` - Tests navigation stack behavior diff --git a/DESCRIPTION.md b/DESCRIPTION.md index d2525bb..23aa370 100644 --- a/DESCRIPTION.md +++ b/DESCRIPTION.md @@ -1 +1 @@ -A comprehensive .NET library providing high-performance interfaces and ready-to-use implementations for common cross-cutting concerns including compression (Gzip, Brotli, Deflate, ZLib), encoding (Base64, Hex), encryption (AES), hashing (15 algorithms including SHA, MD5, CRC, FNV, XxHash), serialization (JSON, YAML, TOML), caching, persistence, validation, logging, navigation, command execution, and filesystem access. Features zero-allocation Span-based operations, default interface implementations to minimize boilerplate, and comprehensive async support with CancellationToken. +A comprehensive .NET library providing high-performance interfaces and ready-to-use implementations for common cross-cutting concerns including compression (Gzip, Brotli, Deflate, ZLib), encoding (Base64, Hex), obfuscation (XOR, Caesar, bit-rotation, byte-reversal, Base64, Hex, and composable chains), encryption (AES), hashing (15 algorithms including SHA, MD5, CRC, FNV, XxHash), serialization (System.Text.Json, Newtonsoft.Json, YAML, TOML), caching, persistence, validation, logging, navigation, command execution, and filesystem access. Features zero-allocation Span-based operations, default interface implementations to minimize boilerplate, and comprehensive async support with CancellationToken. Install everything with the ktsu.Essentials.All meta-package, or cherry-pick individual provider packages. diff --git a/README.md b/README.md index c15c0d3..06f1301 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ktsu.Essentials -> A comprehensive .NET library providing high-performance interfaces and implementations for common cross-cutting concerns including compression, encoding, encryption, hashing, serialization, caching, persistence, validation, logging, navigation, command execution, and filesystem access. +> A comprehensive .NET library providing high-performance interfaces and implementations for common cross-cutting concerns including compression, encoding, obfuscation, encryption, hashing, serialization, caching, persistence, validation, logging, navigation, command execution, and filesystem access. [![License](https://img.shields.io/github/license/ktsu-dev/Essentials.svg?label=License&logo=nuget)](LICENSE.md) [![NuGet Version](https://img.shields.io/nuget/v/ktsu.Essentials?label=Stable&logo=nuget)](https://nuget.org/packages/ktsu.Essentials) @@ -12,15 +12,16 @@ ## Introduction -`ktsu.Essentials` defines a consistent, high-performance API for common cross-cutting concerns in .NET applications. Each provider interface follows a three-tier pattern: zero-allocation `Try*` methods using `Span` and `Stream`, convenient self-allocating methods, and async variants with `CancellationToken` support. Implementers only need to provide the core `Try*` methods — all convenience and async methods are provided via default interface implementations. The package also includes ready-to-use provider implementations for compression, hashing, encoding, encryption, serialization, caching, persistence, logging, navigation, and command execution. +`ktsu.Essentials` defines a consistent, high-performance API for common cross-cutting concerns in .NET applications. Each provider interface follows a three-tier pattern: zero-allocation `Try*` methods using `Span` and `Stream`, convenient self-allocating methods, and async variants with `CancellationToken` support. Implementers only need to provide the core `Try*` methods — all convenience and async methods are provided via default interface implementations. The package also includes ready-to-use provider implementations for compression, hashing, encoding, obfuscation, encryption, serialization, caching, persistence, logging, navigation, and command execution. Higher-level concerns are expressed by composition rather than duplication — configuration is simply an `IPersistenceProvider` over a serializer, and obfuscation composes encoding transforms. ## Features - **Compression**: `ICompressionProvider` with Gzip, Brotli, Deflate, and ZLib implementations - **Encoding**: `IEncodingProvider` with Base64 and Hex implementations for format/transport encoding +- **Obfuscation**: `IObfuscationProvider` with XOR, Caesar, bit-rotation, byte-reversal, Base64, and Hex implementations, plus a `Composite` provider that pipelines several together. Obfuscation is reversible but is **not** encryption — it provides no confidentiality - **Encryption**: `IEncryptionProvider` with AES implementation including key and IV generation - **Hashing**: `IHashProvider` with 15 implementations (MD5, SHA1/256/384/512, FNV1/FNV1a 32/64-bit, CRC32/64, XxHash32/64/3/128) -- **Serialization**: `ISerializationProvider` with JSON, YAML, and TOML implementations plus configurable `ISerializationOptions` +- **Serialization**: `ISerializationProvider` with System.Text.Json, Newtonsoft.Json, YAML, and TOML implementations plus configurable `ISerializationOptions` - **Caching**: `ICacheProvider` with in-memory implementation supporting expiration and get-or-add semantics - **Persistence**: `IPersistenceProvider` with AppData, FileSystem, InMemory, and Temp implementations - **Validation**: `IValidationProvider` with structured results, error codes, and throw-on-failure support @@ -31,6 +32,7 @@ - **Zero-Allocation Core**: All byte-oriented providers support `Span` and `Stream` for allocation-free operations - **Minimal Implementation Burden**: Default interface implementations reduce boilerplate — implement only the core `Try*` methods - **Comprehensive Async Support**: Every operation has async variants with proper `CancellationToken` support +- **Batteries-Included or Cherry-Pick**: Each provider ships as its own `ktsu.Essentials..` package; install the `ktsu.Essentials.All` meta-package to get every provider at once, or reference only the ones you need ## Installation diff --git a/TAGS.md b/TAGS.md index 2ac8d66..3a97386 100644 --- a/TAGS.md +++ b/TAGS.md @@ -1 +1 @@ -.NET;C#;dotnet;csharp;abstractions;interfaces;provider pattern;dependency injection;compression;gzip;brotli;deflate;zlib;encoding;base64;hex;encryption;aes;hashing;md5;sha256;sha512;crc32;fnv;xxhash;serialization;json;yaml;toml;caching;persistence;validation;logging;navigation;command execution;filesystem;zero-allocation;span;async;default interface implementations +.NET;C#;dotnet;csharp;essentials;interfaces;provider pattern;dependency injection;compression;gzip;brotli;deflate;zlib;encoding;base64;hex;obfuscation;xor;caesar;bit rotation;encryption;aes;hashing;md5;sha256;sha512;crc32;fnv;xxhash;serialization;json;newtonsoft;yaml;toml;caching;persistence;validation;logging;navigation;command execution;filesystem;zero-allocation;span;async;default interface implementations;meta-package