123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- using System.Globalization;
- using System.Xml;
- using System.Text;
- namespace Wayne.Lib.Log
- {
- /// <summary>
- /// Static support class for managing masking of debug logs.
- /// </summary>
- public static class DebugLoggerMask
- {
- #region Fields
- private static bool forceMask;
- #endregion
- #region XmlWriter Support
- /// <summary>
- /// Writes processing instructions to an XML document to mask a node.
- /// The masking will be active from this point forward in the XML document (until the end or the instruction is redefined).
- /// </summary>
- /// <param name="xmlWriter">The XML writer.</param>
- /// <param name="nodeName">The name of the XML node.</param>
- /// <param name="maskKind">The type of masking to use.</param>
- public static void MaskXmlNode(XmlWriter xmlWriter, string nodeName, DebugLogMaskKind maskKind)
- {
- xmlWriter.WriteProcessingInstruction(XmlLogObject.XmlMaskNode,
- string.Concat(XmlLogObject.XmlNodeName, "=\"", nodeName, "\" ",
- XmlLogObject.XmlMaskKind, "=\"", maskKind, "\""));
- }
- /// <summary>
- /// Writes processing instructions to an XML document to mask the next node.
- /// </summary>
- /// <param name="xmlWriter">The XML writer.</param>
- /// <param name="maskKind">The type of masking to use.</param>
- public static void MaskNextXmlNode(XmlWriter xmlWriter, DebugLogMaskKind maskKind)
- {
- xmlWriter.WriteProcessingInstruction(XmlLogObject.XmlMaskNode,
- string.Concat(XmlLogObject.XmlNodeName, "=\"", XmlLogObject.XmlMaskNextNodeName, "\" ",
- XmlLogObject.XmlMaskKind, "=\"", maskKind, "\""));
- }
- /// <summary>
- /// Writes processing instructions to an XML document to mask an attribute.
- /// The masking will be active from this point forward in the XML document (until the end or the instruction is redefined).
- /// </summary>
- /// <param name="xmlWriter">The XML writer.</param>
- /// <param name="nodeName">The name of the XML node.</param>
- /// <param name="attributeName">The name of the node attribute.</param>
- /// <param name="maskKind">The type of masking to use.</param>
- public static void MaskXmlAttribute(XmlWriter xmlWriter, string nodeName, string attributeName, DebugLogMaskKind maskKind)
- {
- xmlWriter.WriteProcessingInstruction(XmlLogObject.XmlMaskAttribute,
- string.Concat(XmlLogObject.XmlNodeName, "=\"", nodeName, "\" ",
- XmlLogObject.XmlAttributeName, "=\"", attributeName, "\" ",
- XmlLogObject.XmlMaskKind, "=\"", maskKind, "\""));
- }
- #endregion
- #region XmlDocument Support
- /// <summary>
- /// Returns the XmlNode needed to be added to an XML document to mask a node.
- /// The masking will be active from the point forward where the node is inserted (until the end or the instruction is redefined).
- /// </summary>
- /// <param name="xmlDocument">The XML document.</param>
- /// <param name="nodeName">The name of the XML node.</param>
- /// <param name="maskKind">The type of masking to use.</param>
- public static XmlProcessingInstruction CreateXmlNodeToMaskNode(XmlDocument xmlDocument, string nodeName, DebugLogMaskKind maskKind)
- {
- return xmlDocument.CreateProcessingInstruction(XmlLogObject.XmlMaskNode,
- string.Concat(XmlLogObject.XmlNodeName, "=\"", nodeName, "\" ",
- XmlLogObject.XmlMaskKind, "=\"", maskKind, "\""));
- }
- /// <summary>
- /// Returns the XmlNode needed to be added to an XML document to mask the next node.
- /// </summary>
- /// <param name="xmlDocument">The XML document.</param>
- /// <param name="maskKind">The type of masking to use.</param>
- public static XmlProcessingInstruction CreateXmlNodeToMaskNextNode(XmlDocument xmlDocument, DebugLogMaskKind maskKind)
- {
- return xmlDocument.CreateProcessingInstruction(XmlLogObject.XmlMaskNode,
- string.Concat(XmlLogObject.XmlNodeName, "=\"", XmlLogObject.XmlMaskNextNodeName, "\" ",
- XmlLogObject.XmlMaskKind, "=\"", maskKind, "\""));
- }
- /// <summary>
- /// Returns the XmlNode needed to be added to an XML document to mask an attribute.
- /// The masking will be active from this point forward in the XML document (until the end or the instruction is redefined).
- /// </summary>
- /// <param name="xmlDocument">The XML document.</param>
- /// <param name="nodeName">The name of the XML node.</param>
- /// <param name="attributeName">The name of the node attribute.</param>
- /// <param name="maskKind">The type of masking to use.</param>
- public static XmlProcessingInstruction CreateXmlNodeToMaskAttribute(XmlDocument xmlDocument, string nodeName, string attributeName, DebugLogMaskKind maskKind)
- {
- return xmlDocument.CreateProcessingInstruction(XmlLogObject.XmlMaskAttribute,
- string.Concat(XmlLogObject.XmlNodeName, "=\"", nodeName, "\" ",
- XmlLogObject.XmlAttributeName, "=\"", attributeName, "\" ",
- XmlLogObject.XmlMaskKind, "=\"", maskKind, "\""));
- }
- #endregion
- #region Properties
- /// <summary>
- /// Turn on/off masking in debug mode.
- /// </summary>
- public static bool ForceMask
- {
- get { return forceMask; }
- set { forceMask = value; }
- }
- /// <summary>
- /// Should sensitive data be masked?
- /// </summary>
- public static bool MaskSensitiveData
- {
- get
- {
- #if DEBUG
- return forceMask;
- #else
- return true;
- #endif
- }
- }
- #endregion
- #region Methods
- /// <summary>
- /// Masks the data the requested way.
- /// </summary>
- /// <param name="data">The data to mask.</param>
- /// <param name="maskKind">The kind of masking to perform.</param>
- /// <returns></returns>
- public static string MaskData(string data, DebugLogMaskKind maskKind)
- {
- #if DEBUG
- if (forceMask)
- #endif
- {
- switch (maskKind)
- {
- case DebugLogMaskKind.Remove: return string.Empty;
- case DebugLogMaskKind.Empty: return string.Empty;
- case DebugLogMaskKind.Mask: return "****";
- case DebugLogMaskKind.MaskDigits:
- {
- StringBuilder maskedData = new StringBuilder();
- if (!string.IsNullOrEmpty(data))
- {
- for (int i = 0; i < data.Length; i++)
- {
- char dataChar = data[i];
- if ((dataChar >= '0') && (dataChar <= '9'))
- maskedData.Append('*');
- else
- maskedData.Append(dataChar);
- }
- }
- return maskedData.ToString();
- }
- case DebugLogMaskKind.MaskDigitsAppendHash:
- {
- StringBuilder maskedData = new StringBuilder();
- StringBuilder digits = new StringBuilder();
- if (!string.IsNullOrEmpty(data))
- {
- for (int i = 0; i < data.Length; i++)
- {
- char dataChar = data[i];
- if ((dataChar >= '0') && (dataChar <= '9'))
- {
- maskedData.Append('*');
- digits.Append(dataChar);
- }
- else
- maskedData.Append(dataChar);
- }
- }
- return string.Concat(maskedData, "[#", GetHashCode(digits.ToString()), "#]");
- }
- case DebugLogMaskKind.MaskHex:
- {
- StringBuilder maskedData = new StringBuilder();
- if (!string.IsNullOrEmpty(data))
- {
- for (int i = 0; i < data.Length; i++)
- {
- char dataChar = data[i];
- if ((dataChar >= '0') && (dataChar <= '9') || (dataChar >= 'a') && (dataChar <= 'f') || (dataChar >= 'A') && (dataChar <= 'F'))
- maskedData.Append('*');
- else
- maskedData.Append(dataChar);
- }
- }
- return maskedData.ToString();
- }
- case DebugLogMaskKind.MaskHexAppendHash:
- {
- StringBuilder maskedData = new StringBuilder();
- StringBuilder hex = new StringBuilder();
- if (!string.IsNullOrEmpty(data))
- {
- for (int i = 0; i < data.Length; i++)
- {
- char dataChar = data[i];
- if ((dataChar >= '0') && (dataChar <= '9') || (dataChar >= 'a') && (dataChar <= 'f') || (dataChar >= 'A') && (dataChar <= 'F'))
- {
- maskedData.Append('*');
- hex.Append(dataChar);
- }
- else
- maskedData.Append(dataChar);
- }
- }
- return string.Concat(maskedData, "[#", GetHashCode(hex.ToString()), "#]");
- }
- case DebugLogMaskKind.MaskPan:
- {
- if (!string.IsNullOrEmpty(data) && (data.Length > 8))
- return string.Concat(data.Substring(0, 4), string.Empty.PadLeft(data.Length - 8, '*'), data.Substring(data.Length - 4, 4));
- return data;
- }
- case DebugLogMaskKind.MaskPan64:
- {
- if (!string.IsNullOrEmpty(data) && (data.Length > 10))
- return string.Concat(data.Substring(0, 6), string.Empty.PadLeft(data.Length - 10, '*'), data.Substring(data.Length - 4, 4));
- return data;
- }
- case DebugLogMaskKind.MaskTrack64:
- {
- if (!string.IsNullOrEmpty(data) && (data.Length > 10))
- {
- int sepIndex = data.IndexOf("=");
- if (sepIndex < 0)
- {
- return string.Concat(data.Substring(0, 6), string.Empty.PadLeft(data.Length - 10, '*'), data.Substring(data.Length - 4, 4));
- }
- else
- {
- string panData = data.Substring(0, sepIndex);
- string otherData = string.Empty;
- if (data.Length > sepIndex + 1)
- {
- otherData = data.Substring(sepIndex + 1, data.Length - sepIndex - 1);
- }
- return string.Concat(panData.Substring(0, 6), string.Empty.PadLeft(panData.Length - 10, '*'), panData.Substring(panData.Length - 4, 4), "=", otherData);
- }
- }
- return data;
- }
- case DebugLogMaskKind.MaskPanAppendHash:
- {
- if (!string.IsNullOrEmpty(data) && (data.Length > 8))
- return string.Concat(data.Substring(0, 4), string.Empty.PadLeft(data.Length - 8, '*'), data.Substring(data.Length - 4, 4), "[#", GetHashCode(data), "#]");
- return data;
- }
- case DebugLogMaskKind.MaskEmbeddedPan:
- case DebugLogMaskKind.MaskEmbeddedPanAppendHash:
- {
- StringBuilder maskedData = new StringBuilder();
- int stringBuilderOffset = 0;
- if (!string.IsNullOrEmpty(data))
- {
- int digitStart = -1;
- for (int i = 0; i < data.Length; i++)
- {
- char dataChar = data[i];
- bool isDigit = (dataChar >= '0') && (dataChar <= '9');
- bool isLastChar = (i == data.Length - 1);
- bool inDigitSequence = (digitStart > -1);
- maskedData.Append(dataChar);
- if (isDigit && (!isLastChar || !inDigitSequence))
- {
- if (digitStart == -1)
- digitStart = i + stringBuilderOffset;
- }
- else
- {
- if (digitStart > -1)
- {
- int digitLength = i + stringBuilderOffset - digitStart;
- if (isLastChar)
- digitLength++;
- if (digitLength > 8)
- {
- if (maskKind == DebugLogMaskKind.MaskEmbeddedPanAppendHash)
- {
- string hashedPan = string.Concat("[#", GetHashCode(maskedData.ToString(digitStart, digitLength)), "#]");
- maskedData.Remove(digitStart + 4, digitLength - 8).Insert(digitStart + 4, "*", digitLength - 8).Insert(digitStart + digitLength, hashedPan);
- stringBuilderOffset += hashedPan.Length;
- }
- else
- maskedData.Remove(digitStart + 4, digitLength - 8).Insert(digitStart + 4, "*", digitLength - 8);
- }
- }
- digitStart = -1;
- }
- }
- }
- return maskedData.ToString();
- }
- }
- }
- return data;
- }
- /// <summary>
- /// Masks the data the requested way.
- /// </summary>
- /// <param name="bytes">The binary data to mask.</param>
- /// <param name="showLength">Should the original length of the bytes be shown in the log?</param>
- /// <returns></returns>
- public static string MaskData(byte[] bytes, bool showLength)
- {
- return MaskData(bytes, showLength, false);
- }
- /// <summary>
- /// Masks the data the requested way.
- /// </summary>
- /// <param name="bytes">The binary data to mask.</param>
- /// <param name="showLength">Should the original length of the bytes be shown in the log?</param>
- /// <param name="showHashValue">Should a hash value be calculated and shown in the log?</param>
- /// <returns></returns>
- public static string MaskData(byte[] bytes, bool showLength, bool showHashValue)
- {
- bool isDebug = false;
- #if DEBUG
- isDebug = true;
- #endif
- if (forceMask || !isDebug)
- {
- StringBuilder text = new StringBuilder();
- if (!showLength)
- text.Append("***# bytes***");
- else if (bytes == null)
- text.Append("***null bytes***");
- else
- {
- text.Append(bytes.Length);
- text.Append(" bytes");
- }
- if (showHashValue)
- {
- if (showLength)
- text.Append(",");
- if (bytes != null)
- {
- int hashValue = 0;
- for (int i = 0; i < bytes.Length; i++)
- hashValue = (hashValue * 31) ^ bytes[i]; // Just a simple "hash" calculation of a byte array.
- text.Append("[#");
- text.Append(hashValue.ToString("X8"));
- text.Append("#]");
- }
- else
- text.Append("[#--------#]");
- }
- return string.Concat("***", text, "***");
- }
- return Strings.ByteArrayToString(bytes, StringsByteArrayFormat.CompactHex);
- }
- private static string GetHashCode(string text)
- {
- string fullHashCode = text.GetHashCode().ToString("X8");
- int firstHashHalf = int.Parse(fullHashCode.Substring(0, 4), NumberStyles.HexNumber);
- int lastHashHalf = int.Parse(fullHashCode.Substring(4, 4), NumberStyles.HexNumber);
- int hashedHash = firstHashHalf ^ lastHashHalf;
- return hashedHash.ToString("X4");
- }
- #endregion
- }
- }
|