using Hcs.ClientNet.Internal; using GostXades; using System.IO; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Dispatcher; using System.Text; using System.Xml; namespace Hcs.ClientNet.Api.Request { /// /// Фильтр сообщений добавляет в XML-сообщение электронную подпись XADES/GOST /// internal class GostSigningMessageInspector(ClientBase client) : IClientMessageInspector { private readonly ClientBase client = client; public object BeforeSendRequest(ref Message request, IClientChannel channel) { try { var filterHeader = "[Message Inspector]"; PurgeDebuggerHeaders(ref request); var messageBody = GetMessageBodyString(ref request, Encoding.UTF8); if (!messageBody.Contains(Constants.SIGNED_XML_ELEMENT_ID)) { client.TryCaptureMessage(true, messageBody); } else { var certInfo = X509Tools.GetFullnameWithExpirationDateStr(client.Certificate); client.TryLog($"{filterHeader} signing message with key [{certInfo}]..."); var stopwatch = System.Diagnostics.Stopwatch.StartNew(); var service = new GostXadesBesService(client.CryptoProviderType); var signedXml = service.Sign(messageBody, Constants.SIGNED_XML_ELEMENT_ID, client.CertificateThumbprint, client.CertificatePassword); stopwatch.Stop(); client.TryLog($"{filterHeader} message signed in {stopwatch.ElapsedMilliseconds} ms"); client.TryCaptureMessage(true, signedXml); request = Message.CreateMessage( XmlReaderFromString(signedXml), int.MaxValue, request.Version); } } catch (System.Exception ex) { throw new System.Exception($"Exception occured in {GetType().Name}", ex); } return null; } private void PurgeDebuggerHeaders(ref Message request) { var limit = request.Headers.Count; for (var i = 0; i < limit; ++i) { if (request.Headers[i].Name.Equals("VsDebuggerCausalityData")) { request.Headers.RemoveAt(i); break; } } } private string GetMessageBodyString(ref Message request, Encoding encoding) { var mb = request.CreateBufferedCopy(int.MaxValue); request = mb.CreateMessage(); var s = new MemoryStream(); var xw = XmlWriter.Create(s); mb.CreateMessage().WriteMessage(xw); xw.Flush(); s.Position = 0; var bXML = new byte[s.Length]; s.Read(bXML, 0, (int)s.Length); if (bXML[0] != (byte)'<') { return encoding.GetString(bXML, 3, bXML.Length - 3); } else { return encoding.GetString(bXML, 0, bXML.Length); } } private XmlReader XmlReaderFromString(string xml) { var stream = new MemoryStream(); var writer = new StreamWriter(stream); writer.Write(xml); writer.Flush(); stream.Position = 0; return XmlReader.Create(stream); } public void AfterReceiveReply(ref Message reply, object correlationState) { client.TryCaptureMessage(false, reply.ToString()); } } }