From b34b742cebb162221d55b658bd5fa5ed9afd1643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Trung=20Hi=E1=BA=BFu?= Date: Wed, 8 Jul 2026 08:59:05 +0700 Subject: [PATCH] refactor: replace regex JSON parsing with DataContractJsonSerializer - Add GitHubRelease DTO and deserialize the GitHub API response properly. - Use System.Runtime.Serialization.Json.DataContractJsonSerializer (built into .NET Framework 4.8). - Preserve existing fallback behavior: invalid/empty responses yield no tags. - Remove Regex using directive. - dotnet test passes 58/58. Closes #36. --- src/KeePassAutoReload.csproj | 2 ++ src/UpdateChecker.cs | 43 +++++++++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/KeePassAutoReload.csproj b/src/KeePassAutoReload.csproj index a53b5be..c137007 100644 --- a/src/KeePassAutoReload.csproj +++ b/src/KeePassAutoReload.csproj @@ -19,7 +19,9 @@ + + $(KeePassReferencePath)\KeePass.exe diff --git a/src/UpdateChecker.cs b/src/UpdateChecker.cs index 533f92f..4edf880 100644 --- a/src/UpdateChecker.cs +++ b/src/UpdateChecker.cs @@ -4,8 +4,9 @@ using System.Net; using System.Net.Http; using System.Reflection; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Json; using System.Security.Authentication; -using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -20,6 +21,13 @@ internal sealed class UpdateInfo public bool IsUpdateAvailable; } + [DataContract] + internal sealed class GitHubRelease + { + [DataMember] + public string tag_name { get; set; } + } + internal interface IUpdateClient { Task DownloadStringAsync(string url, CancellationToken cancellationToken = default); @@ -110,7 +118,7 @@ public static async Task CheckLatestAsync(IUpdateClient client, Plug cancellationToken.ThrowIfCancellationRequested(); string json = await client.DownloadStringAsync(ReleasesApiUrl, cancellationToken); - string tagName = GetNewestVersionTag(ExtractJsonStrings(json, "tag_name").ToArray()); + string tagName = GetNewestVersionTag(ExtractVersionTags(json)); UpdateInfo info = new UpdateInfo(); info.LatestVersion = tagName; @@ -188,18 +196,33 @@ private static string BuildChecksumUrl(string tagName) return "https://github.com/hieuck/KeePassAutoReload/releases/download/" + tagName + "/SHA256SUMS.txt"; } - private static List ExtractJsonStrings(string json, string name) + private static string[] ExtractVersionTags(string json) { - List values = new List(); - if (string.IsNullOrEmpty(json)) return values; + if (string.IsNullOrWhiteSpace(json)) return new string[0]; - MatchCollection matches = Regex.Matches(json, "\"" + Regex.Escape(name) + "\"\\s*:\\s*\"(?(?:\\\\.|[^\"])*)\""); - foreach (Match match in matches) + try + { + using (MemoryStream stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(json))) + { + DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List)); + List releases = (List)serializer.ReadObject(stream); + if (releases == null) return new string[0]; + + List tags = new List(); + foreach (GitHubRelease release in releases) + { + if (release != null && !string.IsNullOrWhiteSpace(release.tag_name)) + { + tags.Add(release.tag_name); + } + } + return tags.ToArray(); + } + } + catch { - if (match.Success) values.Add(Regex.Unescape(match.Groups["value"].Value)); + return new string[0]; } - - return values; } } }