<commit_before>﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Security;
using System.Text;

using System.Management;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using System.Net.NetworkInformation;

[assembly: AllowPartiallyTrustedCallers()]
[assembly: CLSCompliant(true)]
namespace SKGL
{
    /// <summary>
    /// This class contains additional methods to ease serial key validation with Serial Key Manager. For definitions of some variables, please go to https://serialkeymanager.com/Ext/Val.
    /// </summary>
    public static class SKM
    {
        #region TimeCheck
        /// <summary>
        /// This method checks whether the network time is different from the local time (client computer). This helps to prevent date changes caused by a client.
        /// </summary>
        /// <returns>Returns FALSE if time was NOT changed and TRUE if the time was changed.</returns>
        public static bool TimeCheck()
        {
            if (GetNetworkTime().ToShortDateString() == DateTime.Now.ToShortDateString())
            {
                // continue validation after this
                return false;
            }
            else
            {
                // the date was altered. stop validation.
                return true;
            }

        }
        private static DateTime GetNetworkTime()
        {
            //From: http://stackoverflow.com/questions/1193955/how-to-query-an-ntp-server-using-c
            //By: @Nasreddine

            //default Windows time server
            const string ntpServer = "time.windows.com";

            // NTP message size - 16 bytes of the digest (RFC 2030)
            var ntpData = new byte[48];

            //Setting the Leap Indicator, Version Number and Mode values
            ntpData[0] = 0x1B; //LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode)

            var addresses = System.Net.Dns.GetHostEntry(ntpServer).AddressList;

            //The UDP port number assigned to NTP is 123
            var ipEndPoint = new System.Net.IPEndPoint(addresses[0], 123);
            //NTP uses UDP
            var socket = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp);

            socket.Connect(ipEndPoint);

            //Stops code hang if NTP is blocked
            socket.ReceiveTimeout = 3000;

            socket.Send(ntpData);
            socket.Receive(ntpData);
            socket.Close();

            //Offset to get to the "Transmit Timestamp" field (time at which the reply 
            //departed the server for the client, in 64-bit timestamp format."
            const byte serverReplyTime = 40;

            //Get the seconds part
            ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime);

            //Get the seconds fraction
            ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4);

            //Convert From big-endian to little-endian
            intPart = SwapEndianness(intPart);
            fractPart = SwapEndianness(fractPart);

            var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);

            //**UTC** time
            var networkDateTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds((long)milliseconds);

            return networkDateTime.ToLocalTime();
        }

        // stackoverflow.com/a/3294698/162671
        private static uint SwapEndianness(ulong x)
        {
            return (uint)(((x & 0x000000ff) << 24) +
                           ((x & 0x0000ff00) << 8) +
                           ((x & 0x00ff0000) >> 8) +
                           ((x & 0xff000000) >> 24));
        }

        #endregion

        #region KeyValidation
        /// <summary>
        /// This method will check whether the key is valid or invalid against the Serial Key Manager database
        /// The method will return an object (KeyInformation) only if:
        ///  * the key exists in the database (it has been generated)
        ///  * the key is not blocked
        /// </summary>
        /// <param name="pid">pid</param>
        /// <param name="uid">uid</param>
        /// <param name="hsum">hsum</param>
        /// <param name="sid">Serial Key that is to be validated</param>
        /// <param name="secure">If true, the key information will contain a signature of itself that you can validate with IsKeyInformationGenuine</param>
        /// <returns>KeyInformation or null.</returns>
        public static KeyInformation KeyValidation(string pid, string uid, string hsum, string sid, bool secure=false)
        {

            Dictionary<string,string> input = new Dictionary<string,string>();
            input.Add("uid", uid);
            input.Add("pid", pid);
            input.Add("hsum", hsum);
            input.Add("sid", sid);
            input.Add("sign", secure.ToString());

            var result = GetParameters(input, "Validate");

            if(result.ContainsKey("error"))
            {
#if DEBUG
                System.Diagnostics.Debug.WriteLine("Error: " + result["error"]);
#endif
                return null;
            }

            return GetKeyInformationFromParameters(result);

        }


        /// <summary>
        /// This method will check whether the key is valid or invalid against the Serial Key Manager database.
        /// The method will return an object (KeyInformation) only if:
        ///  * the key exists in the database (it has been generated)</summary>
        ///  * the key is not blocked
        ///  * the machine code that is activated has not been activated before
        ///  * the limit for maximum number of machine codes has not been achieved
        ///  * the machine code exists in the Allowed Machine codes.
        ///  NOTE: In Addition, depending on the settings, this method will activate a machine code.
        /// <param name="pid">pid</param>
        /// <param name="uid">uid</param>
        /// <param name="hsum">hsum</param>
        /// <param name="sid">Serial Key that is to be validated</param>
        /// <param name="mid">Machine code</param>
        /// <param name="json">If true, additional information is returned in JSON format</param>
        /// <param name="secure">If true, the key information will contain a signature of itself that you can validate with IsKeyInformationGenuine</param>
        /// <param name="signMid">if set to true, the mid parameter will be included into the signature (requires secure to be true)</param>
        /// <returns>Returns a KeyInformation object if all rules were satisfied and null if an error occured.</returns>
        public static KeyInformation KeyActivation(string pid, string uid, string hsum, string sid, string mid, bool secure = false, bool signMid = false )
        {
            Dictionary<string, string> input = new Dictionary<string, string>();
            input.Add("uid", uid);
            input.Add("pid", pid);
            input.Add("hsum", hsum);
            input.Add("mid", mid);
            input.Add("sid", sid);
            input.Add("sign", secure.ToString());
            input.Add("signMid", signMid.ToString());

            var result = GetParameters(input, "Activate");

            if (result.ContainsKey("error"))
            {
#if DEBUG
                System.Diagnostics.Debug.WriteLine("Error: " + result["error"]);
#endif
                return null;
            }

            return GetKeyInformationFromParameters(result);
            
        }


        /// <summary>
        /// This method will attempt to de-activate a machine code from the given key.
        /// If the given machine code was de-activated, KeyInformation confirming the key and the machine code will be returned.
        /// If something went wrong, for instance, if the machine code did not exist, null will be returned.
        /// <param name="pid">pid</param>
        /// <param name="uid">uid</param>
        /// <param name="hsum">hsum</param>
        /// <param name="sid">Serial Key that is to be validated</param>
        /// <param name="mid">Machine code</param>
        /// <remarks>In Debug mode, the error is going to be displayed in the Output Window.<br/>
        /// Note: The key is going to be stored in "NewKey" field, while the machine code is going to be stored in "mid".
        /// </remarks>
        /// <returns>Returns a KeyInformation object (with a key and machine code only) or null.</returns>
        public static KeyInformation KeyDeactivation(string pid, string uid, string hsum, string sid, string mid)
        {
            Dictionary<string, string> input = new Dictionary<string, string>();
            input.Add("uid", uid);
            input.Add("pid", pid);
            input.Add("hsum", hsum);
            input.Add("mid", mid);
            input.Add("sid", sid);

            var result = GetParameters(input, "Deactivate");

            if (result.ContainsKey("error"))
            {
#if DEBUG
                System.Diagnostics.Debug.WriteLine("Error: " + result["error"]);
#endif<commit_msg>Fixed a tag.<commit_after>﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Security;
using System.Text;

using System.Management;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using System.Net.NetworkInformation;

[assembly: AllowPartiallyTrustedCallers()]
[assembly: CLSCompliant(true)]
namespace SKGL
{
    /// <summary>
    /// This class contains additional methods to ease serial key validation with Serial Key Manager. For definitions of some variables, please go to https://serialkeymanager.com/Ext/Val.
    /// </summary>
    public static class SKM
    {
        #region TimeCheck
        /// <summary>
        /// This method checks whether the network time is different from the local time (client computer). This helps to prevent date changes caused by a client.
        /// </summary>
        /// <returns>Returns FALSE if time was NOT changed and TRUE if the time was changed.</returns>
        public static bool TimeCheck()
        {
            if (GetNetworkTime().ToShortDateString() == DateTime.Now.ToShortDateString())
            {
                // continue validation after this
                return false;
            }
            else
            {
                // the date was altered. stop validation.
                return true;
            }

        }
        private static DateTime GetNetworkTime()
        {
            //From: http://stackoverflow.com/questions/1193955/how-to-query-an-ntp-server-using-c
            //By: @Nasreddine

            //default Windows time server
            const string ntpServer = "time.windows.com";

            // NTP message size - 16 bytes of the digest (RFC 2030)
            var ntpData = new byte[48];

            //Setting the Leap Indicator, Version Number and Mode values
            ntpData[0] = 0x1B; //LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode)

            var addresses = System.Net.Dns.GetHostEntry(ntpServer).AddressList;

            //The UDP port number assigned to NTP is 123
            var ipEndPoint = new System.Net.IPEndPoint(addresses[0], 123);
            //NTP uses UDP
            var socket = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp);

            socket.Connect(ipEndPoint);

            //Stops code hang if NTP is blocked
            socket.ReceiveTimeout = 3000;

            socket.Send(ntpData);
            socket.Receive(ntpData);
            socket.Close();

            //Offset to get to the "Transmit Timestamp" field (time at which the reply 
            //departed the server for the client, in 64-bit timestamp format."
            const byte serverReplyTime = 40;

            //Get the seconds part
            ulong intPart = BitConverter.ToUInt32(ntpData, serverReplyTime);

            //Get the seconds fraction
            ulong fractPart = BitConverter.ToUInt32(ntpData, serverReplyTime + 4);

            //Convert From big-endian to little-endian
            intPart = SwapEndianness(intPart);
            fractPart = SwapEndianness(fractPart);

            var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);

            //**UTC** time
            var networkDateTime = (new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds((long)milliseconds);

            return networkDateTime.ToLocalTime();
        }

        // stackoverflow.com/a/3294698/162671
        private static uint SwapEndianness(ulong x)
        {
            return (uint)(((x & 0x000000ff) << 24) +
                           ((x & 0x0000ff00) << 8) +
                           ((x & 0x00ff0000) >> 8) +
                           ((x & 0xff000000) >> 24));
        }

        #endregion

        #region KeyValidation
        /// <summary>
        /// This method will check whether the key is valid or invalid against the Serial Key Manager database
        /// The method will return an object (KeyInformation) only if:
        ///  * the key exists in the database (it has been generated)
        ///  * the key is not blocked
        /// </summary>
        /// <param name="pid">pid</param>
        /// <param name="uid">uid</param>
        /// <param name="hsum">hsum</param>
        /// <param name="sid">Serial Key that is to be validated</param>
        /// <param name="secure">If true, the key information will contain a signature of itself that you can validate with IsKeyInformationGenuine</param>
        /// <returns>KeyInformation or null.</returns>
        public static KeyInformation KeyValidation(string pid, string uid, string hsum, string sid, bool secure=false)
        {

            Dictionary<string,string> input = new Dictionary<string,string>();
            input.Add("uid", uid);
            input.Add("pid", pid);
            input.Add("hsum", hsum);
            input.Add("sid", sid);
            input.Add("sign", secure.ToString());

            var result = GetParameters(input, "Validate");

            if(result.ContainsKey("error"))
            {
#if DEBUG
                System.Diagnostics.Debug.WriteLine("Error: " + result["error"]);
#endif
                return null;
            }

            return GetKeyInformationFromParameters(result);

        }


        /// <summary>
        /// This method will check whether the key is valid or invalid against the Serial Key Manager database.
        /// The method will return an object (KeyInformation) only if:
        ///  * the key exists in the database (it has been generated)</summary>
        ///  * the key is not blocked
        ///  * the machine code that is activated has not been activated before
        ///  * the limit for maximum number of machine codes has not been achieved
        ///  * the machine code exists in the Allowed Machine codes.
        ///  NOTE: In Addition, depending on the settings, this method will activate a machine code.
        /// <param name="pid">pid</param>
        /// <param name="uid">uid</param>
        /// <param name="hsum">hsum</param>
        /// <param name="sid">Serial Key that is to be validated</param>
        /// <param name="mid">Machine code</param>
        /// <param name="json">If true, additional information is returned in JSON format</param>
        /// <param name="secure">If true, the key information will contain a signature of itself that you can validate with IsKeyInformationGenuine</param>
        /// <param name="signMid">if set to true, the mid parameter will be included into the signature (requires secure to be true)</param>
        /// <returns>Returns a KeyInformation object if all rules were satisfied and null if an error occured.</returns>
        public static KeyInformation KeyActivation(string pid, string uid, string hsum, string sid, string mid, bool secure = false, bool signMid = false )
        {
            Dictionary<string, string> input = new Dictionary<string, string>();
            input.Add("uid", uid);
            input.Add("pid", pid);
            input.Add("hsum", hsum);
            input.Add("mid", mid);
            input.Add("sid", sid);
            input.Add("sign", secure.ToString());
            input.Add("signMid", signMid.ToString());

            var result = GetParameters(input, "Activate");

            if (result.ContainsKey("error"))
            {
#if DEBUG
                System.Diagnostics.Debug.WriteLine("Error: " + result["error"]);
#endif
                return null;
            }

            return GetKeyInformationFromParameters(result);
            
        }


        /// <summary>
        /// This method will attempt to de-activate a machine code from the given key.
        /// If the given machine code was de-activated, KeyInformation confirming the key and the machine code will be returned.
        /// If something went wrong, for instance, if the machine code did not exist, null will be returned.</summary>
        /// <param name="pid">pid</param>
        /// <param name="uid">uid</param>
        /// <param name="hsum">hsum</param>
        /// <param name="sid">Serial Key that is to be validated</param>
        /// <param name="mid">Machine code</param>
        /// <remarks>In Debug mode, the error is going to be displayed in the Output Window.<br/>
        /// Note: The key is going to be stored in "NewKey" field, while the machine code is going to be stored in "mid".
        /// </remarks>
        /// <returns>Returns a KeyInformation object (with a key and machine code only) or null.</returns>
        public static KeyInformation KeyDeactivation(string pid, string uid, string hsum, string sid, string mid)
        {
            Dictionary<string, string> input = new Dictionary<string, string>();
            input.Add("uid", uid);
            input.Add("pid", pid);
            input.Add("hsum", hsum);
            input.Add("mid", mid);
            input.Add("sid", sid);

            var result = GetParameters(input, "Deactivate");

            if (result.ContainsKey("error"))
            {
#if DEBUG
                System.Diagnostics.Debug.WriteLine("Error: " + result["error"]);
#endif
{'fraction_non_alphanumeric': 0.11115315997188734, 'fraction_numerical': 0.012542574471535924, 'mean_word_length': 2.0753117206982545, 'pattern_counts': {'":': 0, '<': 136, '<?xml version=': 0, '>': 136, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4836334', 'n_tokens_mistral': 4941, 'n_tokens_neox': 4648, 'n_words': 1613}