Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# This workflow will build a .NET project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
# This workflow will build, test, measure coverage, and pack the library.

name: .NET

Expand All @@ -22,7 +21,7 @@ jobs:
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal
- name: Test with coverage
run: dotnet test --configuration Release --no-restore --verbosity normal -p:ContinuousIntegrationBuild=true
- name: Pack
run: dotnet pack StringExtensionLibrary/StringExtensionLibrary.csproj --configuration Release --no-restore --output ./nupkg -p:ContinuousIntegrationBuild=true
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,7 @@ $RECYCLE.BIN/
# Mac desktop service store files
.DS_Store
packages/
coverage*.xml
coverage.json
TestResults/
nupkg/
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Changelog

## 2.0.0

Breaking changes from the .NET Framework 4.5.1 / Visual Studio 2013 package:

- **Target framework.** The library is now **.NET Standard 2.0** (SDK-style project). It no longer targets .NET Framework 4.5.1 only.
- **Encrypt / Decrypt.** Windows RSA key-container crypto (`CspParameters` / `RSACryptoServiceProvider`) is replaced with **AES-256-CBC**, **HMAC-SHA256** integrity, and **PBKDF2-HMAC-SHA256** (100,000 iterations) for key derivation. Ciphertext is a hyphen-separated hex payload: salt + IV + ciphertext + tag. Payloads produced by 1.x cannot be decrypted. Wrong passphrase or a tampered payload throws `CryptographicException`.
- **CreateParameters removed.** The SQL-concatenation helper is gone. Use parameterized queries.
- **IsValidIPv4.** Uses `IPAddress.TryParse` and requires a canonical dotted-quad (`AddressFamily.InterNetwork`). Scheme-prefixed strings, IPv6, and non-canonical forms such as `127.00.0.1` are rejected.
- **JsonToObject.** Throws `InvalidOperationException` when JSON deserializes to null instead of returning `default(T)`.
- **ReplaceLineFeeds.** Removes CR/LF sequences only. It no longer strips `.` characters (the previous regex matched a literal period).
- **QueryStringToDictionary.** Reads the query after the first `?`, strips a `#` fragment, URL-decodes keys and values (`Uri.UnescapeDataString`; `+` is a space), and last-wins on duplicate keys.

Other notable changes:

- Hash helpers (`CreateHashSha256`, `CreateHashSha512`) and `GetLength` are extension methods (`this`).
- Several P0 contract fixes: `IsLength` honors the maximum bound; `RemoveSuffix` returns the original string when the suffix is missing; `CountOccurrences` treats the needle as a literal; `Capitalize` / `IsEmailAddress` are null-safe.
27 changes: 27 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Contributing

## Null policy

Keep these contracts consistent when adding methods:

- **Predicates** (`Is*`, `DoesNot*`): accept null and never throw. `IsNull` is true for null; other `Is*` methods return false; `DoesNotStartWith` / `DoesNotEndWith` return true when either side is null.
- **Ignore-case start/end**: throw `ArgumentNullException` when `val` or the prefix/suffix is null.
- **Transforms** (`Reverse`, `Left`, `ToBytes`, `SplitTo`, `Replace`, …): throw `ArgumentNullException` (or `ArgumentException` when empty is invalid, e.g. encrypt/hash).
- **Null-coalescing helpers** (`GetEmptyStringIfNull`, `GetDefaultIfEmpty`, `Truncate`): defined results for null (empty string or the provided default).
- Use `nameof` in exception arguments. Use invariant culture for case conversion unless the caller passes a culture.

## Tests

Every public method needs a happy path, a null/empty case, and the documented error case. Split tests by concern (`ConversionTests`, `ValidationTests`, `MutationTests`, `JsonAndQueryTests`, `CryptoTests`).

## SQL

Do not add helpers that concatenate untrusted strings into SQL.

## Crypto

`Encrypt` / `Decrypt` use AES-256-CBC with HMAC-SHA256 over the payload and PBKDF2-HMAC-SHA256 (100,000 iterations) for key derivation on all target frameworks. Ciphertext from the old Windows RSA key-container implementation will not decrypt. This is passphrase-based authenticated encryption for application data, not a key-management system.

## Email and IPv4

`IsEmailAddress` is a practical heuristic (plus-tags allowed, input is trimmed). It is not RFC 5322-complete. `IsValidIPv4` requires a canonical dotted-quad.
12 changes: 12 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project>
<PropertyGroup>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors>$(WarningsAsErrors);NU1605</WarningsAsErrors>
<AnalysisLevel>latest</AnalysisLevel>
<AnalysisMode>Recommended</AnalysisMode>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<Deterministic>true</Deterministic>
</PropertyGroup>
</Project>
Loading
Loading