From 515587de06dfaf63192293387c7940dceb5db7f8 Mon Sep 17 00:00:00 2001 From: Jason Naylor Date: Tue, 14 Jul 2026 15:28:52 -0700 Subject: [PATCH] Fix LT-22614: FLEx does not restart after a Send/Receive merge The .NET 4.8 retarget changed the hash WCF uses in named-pipe names, so FLEx and FLEx Bridge (net462) could no longer find each other's endpoints and the "changes received" signal was silently lost. Co-Authored-By: Claude Fable 5 --- Src/Common/FwUtils/FLExBridgeHelper.cs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Src/Common/FwUtils/FLExBridgeHelper.cs b/Src/Common/FwUtils/FLExBridgeHelper.cs index f14f6c6331..4df3663eec 100644 --- a/Src/Common/FwUtils/FLExBridgeHelper.cs +++ b/Src/Common/FwUtils/FLExBridgeHelper.cs @@ -8,7 +8,9 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Security.Cryptography; using System.ServiceModel; +using System.Text; using System.Threading; using SIL.LCModel; using SIL.LCModel.Utils; @@ -245,7 +247,7 @@ public static bool LaunchFieldworksBridge(string projectFolder, string userName, int fwmodelVersionNumber, string liftModelVersionNumber, string writingSystemId, Action onNonBlockerCommandComplete, out bool changesReceived, out string projectName, Uri projectUri, string name, string credentialsPassword, string repoIdentifier) { - _pipeID = string.Format(@"SendReceive{0}{1}", projectFolder, command); + _pipeID = GeneratePipeId(projectFolder, command); _flexBridgeTerminated = false; changesReceived = false; var args = ""; @@ -324,6 +326,27 @@ public static bool LaunchFieldworksBridge(string projectFolder, string userName, return true; } + /// + /// Generates the pipe ID embedded in the WCF endpoint names shared with FLEx Bridge, which + /// receives it via '-pipeID' and uses it verbatim. The project path is digested rather than + /// used directly (LT-22614): WCF hashes long pipe URIs with an algorithm that differs between + /// FieldWorks (net48, SHA256) and FLEx Bridge (net462, SHA1), so long paths silently broke all + /// bridge signalling; a short ID is always used literally on both sides. Must stay + /// deterministic per (projectFolder, command) so duplicate launches collide. + /// + private static string GeneratePipeId(string projectFolder, string command) + { + using (var sha = SHA256.Create()) + { + // SHA256.Create() is stable across processes and FIPS-safe (unlike GetHashCode or MD5). + var digest = sha.ComputeHash(Encoding.UTF8.GetBytes(projectFolder ?? string.Empty)); + // First 8 bytes as hex: unique enough, and URI-safe where Base64 is not. + // (On .NET 5+ this would be Convert.ToHexString(digest.AsSpan(0, 8)).) + var token = BitConverter.ToString(digest, 0, 8).Replace("-", string.Empty); + return "SendReceive" + token + command; + } + } + private static void LaunchFlexBridge(IIPCHost host, string command, string args, Action onNonBlockerCommandComplete, string userPass, ref bool changesReceived, ref string projectName) {