示例#1
0
        static void ResponseThread()
        {
            while (true)
            {
                HttpListenerContext context = httpListener.GetContext(); // get a context
                try
                {
                    if (context.Request.Url.OriginalString.Contains("/api/"))
                    {
                        WriteMessage(context.Request.Url.ToString());

                        // adapted from https://stackoverflow.com/a/700307/1275924
                        var            original     = context.Request;
                        var            pathAndQuery = new Uri(context.Request.Url.OriginalString).PathAndQuery;
                        HttpWebRequest newRequest   = (HttpWebRequest)WebRequest.Create("https://app.cryptolens.io/" + pathAndQuery);

                        newRequest.ContentType = original.ContentType;
                        newRequest.Method      = original.HttpMethod;
                        newRequest.UserAgent   = original.UserAgent;

                        byte[] originalStream = Helpers.ReadToByteArray(original.InputStream, 1024);

                        if (original.HttpMethod == "GET")
                        {
                            WriteMessage("GET requests are not supported. Error.");

                            Helpers.ReturnResponse(Newtonsoft.Json.JsonConvert.SerializeObject(new BasicResult {
                                Result = ResultType.Error, Message = "GET requests are not supported in this version of the license server."
                            }), context);
                        }
                        else
                        {
                            // for POST

                            APIMethod method = Helpers.GetAPIMethod(pathAndQuery);

                            if (method == APIMethod.Activate || method == APIMethod.GetKey)
                            {
                                var activateResponse = Helpers.ProcessActivateRequest(originalStream, licenseCache, cacheLength, newRequest, context, keysToUpdate, attemptToRefresh, localFloatingServer, activatedMachinesFloating, method);

                                if (activateResponse != null)
                                {
                                    WriteMessage(activateResponse);
                                }
                            }
                            else if (method == APIMethod.IncrementIntValueToKey ||
                                     method == APIMethod.DecrementIntValueToKey)
                            {
                                var incrementDecrementResponse = Helpers.ProcessIncrementDecrementValueRequest(originalStream, newRequest, context, Helpers.GetAPIMethod(pathAndQuery));

                                if (incrementDecrementResponse != null)
                                {
                                    WriteMessage(incrementDecrementResponse);
                                }
                            }
                            else
                            {
                                Stream reqStream = newRequest.GetRequestStream();

                                reqStream.Write(originalStream, 0, originalStream.Length);
                                reqStream.Close();

                                var output = Helpers.ReadToByteArray(newRequest.GetResponse().GetResponseStream());

                                context.Response.OutputStream.Write(output, 0, output.Length);
                                context.Response.KeepAlive = false;
                                context.Response.Close();
                            }
                        }
                    }
                    else if (context.Request.Url.LocalPath.ToLower().StartsWith("/stats"))
                    {
                        var totalFloatingMachines = activatedMachinesFloating.Values.Sum(x => x.Count);
                        Helpers.HTMLResponse("Stats", $"<table border=1><tr><th>Property</th><th>Value</th></tr>" +
                                             $"<tr><td>Licenses in cache</td><td>{licenseCache.Keys.Count}</td></tr>" +
                                             $"<tr><td>Number of licenses (floating offline)</td><td>{activatedMachinesFloating.Keys.Count}</td></tr>" +
                                             $"<tr><td>Number of machines (floating offline)</td><td>{totalFloatingMachines}</td></tr></table>", context);
                        WriteMessage("Web dashboard served successfully.");
                    }
                    else if (context.Request.Url.LocalPath.ToLower().StartsWith("/licenses"))
                    {
                        var totalFloatingMachines = activatedMachinesFloating.Values.Sum(x => x.Count);

                        var sb = new StringBuilder();
                        sb.Append("<p>The following licenses are cached by the license server.</p>");
                        sb.Append("<table border=1 style='border-style:groove;'><tr><th>License</th><th>Operations</th></tr>");
                        foreach (var license in licenseCache)
                        {
                            sb.Append($"<tr><td>{license.Key.Key}</td><td></td></tr>");
                        }
                        sb.Append("</table>");

                        Helpers.HTMLResponse("Stats", sb.ToString(), context);
                        WriteMessage("Web dashboard served successfully.");
                    }
                    else if (context.Request.Url.LocalPath.ToLower().StartsWith("/report/floatingusage"))
                    {
                        var totalFloatingMachines = activatedMachinesFloating.Values.Sum(x => x.Count);

                        string product = context.Request.QueryString.Get("productId");
                        string key     = context.Request.QueryString.Get("license");

                        int productId = -1;
                        int.TryParse(product, out productId);

                        int maxNoOfMachines = 0;

                        LAResult res = null;

                        if (!licenseCache.TryGetValue(new LAKey()
                        {
                            Key = key, ProductId = productId, SignMethod = 1
                        }, out res))
                        {
                            licenseCache.TryGetValue(new LAKey()
                            {
                                Key = key, ProductId = productId, SignMethod = 0
                            }, out res);
                        }

                        if (res != null)
                        {
                            maxNoOfMachines = res.LicenseKey.MaxNoOfMachines;
                        }

                        var sb = new StringBuilder();
                        sb.Append("<p>The following licenses are cached by the license server.</p>");

                        sb.Append(AnalyticsMethods.SummaryAuditFloating(productId, key, "", maxNoOfMachines));


                        Helpers.HTMLResponse("Stats", sb.ToString(), context);
                        WriteMessage("Web dashboard served successfully.");
                    }
                    else
                    {
                        byte[] responseArray = Encoding.UTF8.GetBytes($"<html><head><title>Cryptolens License Server {versionInfo} -- port {port}</title></head>" +
                                                                      $"<body><p>Welcome to the <strong>Cryptolens License Server {versionInfo}</strong> -- port {port}! If you see this message, it means " +
                                                                      "everything is working properly.</em></p><p>" +
                                                                      "If you can find its documentation <a href='https://github.com/cryptolens/license-server'>here</a>." +
                                                                      "</p></body></html>");
                        context.Response.OutputStream.Write(responseArray, 0, responseArray.Length);
                        context.Response.KeepAlive = false;
                        context.Response.Close();
                        WriteMessage("Web dashboard served successfully.");
                    }
                }
                catch (Exception ex)
                {
                    WriteMessage(ex?.Message + "\n" + ex?.InnerException?.ToString() + "\n" + ex?.StackTrace);
                }
                finally
                {
                    context.Response.Close();
                }
            }
        }
示例#2
0
        public static string LoadFromLocalCache(Dictionary <LAKey, LAResult> licenseCache, Action <string> updates, string pathToCacheFolder = null)
        {
            string path = "";

            if (!string.IsNullOrWhiteSpace(pathToCacheFolder))
            {
                path = Path.Combine(pathToCacheFolder, "cache");
            }
            else
            {
                path = Path.Combine(Directory.GetCurrentDirectory(), "cache");
            }

            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            if (!Directory.Exists(path))
            {
                return("Could not load the cache.");
            }

            var files = Directory.GetFiles(path);

            int filecount = 0;

            foreach (var file in files)
            {
                var      fileContent       = File.ReadAllText(file);
                string[] extractedFileInfo = Path.GetFileName(file).Split('.');

                LicenseKey license = new LicenseKey();

                var key = new LAKey
                {
                    ProductId  = Convert.ToInt32(extractedFileInfo[0]),
                    Key        = extractedFileInfo[1],
                    SignMethod = Convert.ToInt32(extractedFileInfo[2])
                };

                var result = new LAResult();
                result.Response = fileContent;

                if (key.SignMethod == 0)
                {
                    result.LicenseKey = Newtonsoft.Json.JsonConvert.DeserializeObject <KeyInfoResult>(fileContent).LicenseKey;
                    result.SignDate   = result.LicenseKey.SignDate;
                }
                else
                {
                    var response = Newtonsoft.Json.JsonConvert.DeserializeObject <RawResponse>(fileContent);
                    result.LicenseKey = JsonConvert.DeserializeObject <LicenseKeyPI>(System.Text.UTF8Encoding.UTF8.GetString(Convert.FromBase64String(response.LicenseKey))).ToLicenseKey();
                    result.SignDate   = result.LicenseKey.SignDate;
                }


                if (!string.IsNullOrEmpty(Program.RSAPublicKey) && !result.LicenseKey.HasValidSignature(Program.RSAPublicKey, Program.cacheLength).IsValid())
                {
                    updates($"The file '{file}' was not loaded from the cache. The signature check failed or the file is too old.");
                    continue;
                }

                if (licenseCache.ContainsKey(key))
                {
                    if (licenseCache[key].SignDate < result.SignDate)
                    {
                        filecount++;
                        licenseCache[key] = result;
                        updates($"The cache was updated with '{file}'. The license was previously loaded from file was overridden.");
                    }
                    else
                    {
                        updates($"The file '{file}' was not loaded from the cache, since a newer version was provided manually.");
                    }
                }
                else
                {
                    licenseCache.Add(key, result);
                    filecount++;
                    updates($"The file '{file}' was loaded from the cache.");
                }
            }

            return($"Loaded {filecount}/{files.Count()} file(s) from cache.");
        }
示例#3
0
        public static bool LoadLicenseFromFile(Dictionary <LAKey, LAResult> licenseCache, ConcurrentDictionary <LAKey, string> keysToUpdate, string pathToFile, out string errorMessage)
        {
            errorMessage = null;

            try
            {
                var file = System.IO.File.ReadAllText(pathToFile);

                var response = Newtonsoft.Json.JsonConvert.DeserializeObject <RawResponse>(file);

                LAKey    key;
                LAResult result;

                if (!string.IsNullOrEmpty(response.LicenseKey))
                {
                    // SignMethod = 1

                    var licenseBytes = Convert.FromBase64String(response.LicenseKey);
                    var licenseKey   = JsonConvert.DeserializeObject <LicenseKeyPI>(System.Text.UTF8Encoding.UTF8.GetString(licenseBytes)).ToLicenseKey();
                    licenseKey.RawResponse = response;

                    key = new LAKey {
                        Key = licenseKey.Key, ProductId = licenseKey.ProductId, SignMethod = 1
                    };

                    result = new LAResult
                    {
                        LicenseKey = licenseKey,
                        SignDate   = licenseKey.SignDate,
                        Response   = file
                    };
                }
                else
                {
                    // SignMethod = 0

                    var licenseKey = Newtonsoft.Json.JsonConvert.DeserializeObject <LicenseKey>(file);

                    key = new LAKey {
                        Key = licenseKey.Key, ProductId = licenseKey.ProductId, SignMethod = 0
                    };
                    result = new LAResult
                    {
                        LicenseKey = licenseKey,
                        SignDate   = licenseKey.SignDate,
                        Response   =
                            JsonConvert.SerializeObject(new KeyInfoResult {
                            Result = ResultType.Success, LicenseKey = licenseKey
                        })
                    };
                }

                if (!string.IsNullOrEmpty(Program.RSAPublicKey) && !result.LicenseKey.HasValidSignature(Program.RSAPublicKey, Program.cacheLength).IsValid())
                {
                    errorMessage = $"The file '{pathToFile}' was not loaded from the cache. The signature check failed.";
                    return(false);
                }

                if (licenseCache.ContainsKey(key))
                {
                    if (licenseCache[key].SignDate < result.SignDate)
                    {
                        licenseCache[key] = result;
                        keysToUpdate[key] = result.Response;
                    }
                }
                else
                {
                    licenseCache.Add(key, result);
                    keysToUpdate.TryAdd(key, result.Response);
                }
            }
            catch (Exception ex)
            {
                return(false);
            }

            return(true);
        }
示例#4
0
        public static string ProcessIncrementDecrementValueRequest(byte[] stream, HttpWebRequest newRequest, HttpListenerContext context, APIMethod method)
        {
            string bodyParams = System.Text.Encoding.Default.GetString(stream);
            var    nvc        = HttpUtility.ParseQueryString(bodyParams);

            int productId = -1;

            int.TryParse(nvc.Get("ProductId"), out productId);

            var licenseKey = nvc.Get("Key");
            int intValue   = -1;

            int.TryParse(nvc.Get("IntValue"), out intValue);

            int doId = -1;

            int.TryParse(nvc.Get("Id"), out doId);

            if (method == APIMethod.DecrementIntValueToKey)
            {
                doId = -1 * Math.Abs(doId);
            }
            else
            {
                doId = Math.Abs(doId);
            }

            if (!Program.attemptToRefresh && !string.IsNullOrEmpty(Program.RSAPublicKey))
            {
                LAResult result = null;

                var key = new LAKey {
                    Key = licenseKey, ProductId = productId, SignMethod = 0
                };

                var keyAlt = new LAKey {
                    Key = licenseKey, ProductId = productId, SignMethod = 1
                };

                if (!Program.licenseCache.TryGetValue(key, out result) && !Program.licenseCache.TryGetValue(keyAlt, out result))
                {
                    var error = JsonConvert.SerializeObject(new BasicResult {
                        Result = ResultType.Error, Message = "License server error: could not find the license file (to increment/decrement the data object)."
                    });
                    ReturnResponse(error, context);
                    return($"Could not find the license file for '{licenseKey}' to continue with the increment or decrement operation.");
                }

                if (!result.LicenseKey.DataObjects.Any(x => x.Id == doId))
                {
                    var error = JsonConvert.SerializeObject(new BasicResult {
                        Result = ResultType.Error, Message = "License server error: could not find the data object in the license file (to increment/decrement the data object)."
                    });
                    ReturnResponse(error, context);
                    return($"Could not find the data object with ID {doId} in the license file for '{licenseKey}' to continue with the increment or decrement operation.");
                }

                var doKey = new DOKey {
                    DOID = doId, Key = licenseKey, ProductId = productId
                };
                Program.DOOperations.AddOrUpdate(doKey, doId, (x, y) => y + doId);

                var success = JsonConvert.SerializeObject(new BasicResult {
                    Result = ResultType.Success, Message = ""
                });
                ReturnResponse(success, context);
                return($"Updated data object successfully.");
            }
            else
            {
                // for now, just forward the request.
                ForwardRequest(stream, newRequest, context);

                //try
                //{
                //}
                //catch (Exception ex)
                //{

                //}
            }


            // add and store log.


            return(null);
        }
示例#5
0
        public static void FloatingResult(LAResult result, ActivationData activation, string machineCode, HttpListenerContext context, int signmetod = 1, List <ActivationData> activations = null)
        {
            if (signmetod == 1)
            {
                var licenseKeyToReturn = new LicenseKeyPI {
                };

                if (activations != null)
                {
                    licenseKeyToReturn.ActivatedMachines = activations.Select(x => new ActivationDataPIV3 {
                        FriendlyName = x.FriendlyName, IP = x.IP, Time = ToUnixTimestamp(x.Time.Value), Mid = $"floating:{x.Mid}", FloatingExpires = ToUnixTimestamp(x.FloatingExpires.Value)
                    }).ToList();
                }
                else
                {
                    licenseKeyToReturn.ActivatedMachines = new List <ActivationDataPIV3>()
                    {
                        new ActivationDataPIV3 {
                            Mid = $"floating:{machineCode}", Time =
                                ToUnixTimestamp(activation.Time.Value), FriendlyName = activation.FriendlyName, IP = activation.IP, FloatingExpires = ToUnixTimestamp(activation.FloatingExpires.Value)
                        }
                    };
                }

                licenseKeyToReturn.Block   = result.LicenseKey.Block;
                licenseKeyToReturn.Created = ToUnixTimestamp(result.LicenseKey.Created);
                licenseKeyToReturn.Expires = ToUnixTimestamp(result.LicenseKey.Expires);

                if (licenseKeyToReturn != null)
                {
                    licenseKeyToReturn.Customer = new CustomerPI {
                        CompanyName = result.LicenseKey.Customer.CompanyName, Created = ToUnixTimestamp(result.LicenseKey.Customer.Created), Email = result.LicenseKey.Customer.Email, Id = result.LicenseKey.Customer.Id, Name = result.LicenseKey.Customer.Name
                    };
                }

                licenseKeyToReturn.DataObjects = result.LicenseKey.DataObjects;
                licenseKeyToReturn.F1          = result.LicenseKey.F1;
                licenseKeyToReturn.F2          = result.LicenseKey.F2;
                licenseKeyToReturn.F3          = result.LicenseKey.F3;
                licenseKeyToReturn.F4          = result.LicenseKey.F4;
                licenseKeyToReturn.F5          = result.LicenseKey.F5;
                licenseKeyToReturn.F6          = result.LicenseKey.F6;
                licenseKeyToReturn.F7          = result.LicenseKey.F7;
                licenseKeyToReturn.F8          = result.LicenseKey.F8;

                licenseKeyToReturn.GlobalId        = result.LicenseKey.GlobalId;
                licenseKeyToReturn.MaxNoOfMachines = result.LicenseKey.MaxNoOfMachines;
                licenseKeyToReturn.ID  = result.LicenseKey.ID;
                licenseKeyToReturn.Key = result.LicenseKey.Key;

                licenseKeyToReturn.Notes           = result.LicenseKey.Notes;
                licenseKeyToReturn.Period          = result.LicenseKey.Period;
                licenseKeyToReturn.TrialActivation = result.LicenseKey.TrialActivation;
                licenseKeyToReturn.ProductId       = result.LicenseKey.ProductId;
                licenseKeyToReturn.SignDate        = ToUnixTimestamp(DateTime.UtcNow);

                var data = Newtonsoft.Json.JsonConvert.SerializeObject(licenseKeyToReturn);

                var signature = "";

                byte[] dataSign = System.Text.UTF8Encoding.UTF8.GetBytes(data);

                System.Security.Cryptography.RSACryptoServiceProvider rsa = new System.Security.Cryptography.RSACryptoServiceProvider(2048);

                rsa.FromXmlString(Program.RSAServerKey);

                byte[] signedData = rsa.SignData(dataSign, "SHA256");
                signature = Convert.ToBase64String(signedData);

                var result2 = Newtonsoft.Json.JsonConvert.SerializeObject(new RawResponse
                {
                    LicenseKey = Convert.ToBase64String(dataSign),
                    Signature  = signature,
                    Message    = "",
                    Result     = ResultType.Success
                });

                ReturnResponse(result2, context);
            }
            else
            {
            }
        }
示例#6
0
        public static string ProcessActivateRequest(byte[] stream, Dictionary <LAKey, LAResult> licenseCache, int cacheLength, HttpWebRequest newRequest, HttpListenerContext context, ConcurrentDictionary <LAKey, string> keysToUpdate, bool attemptToRefresh, bool localFloatingServer, ConcurrentDictionary <LAKeyBase, ConcurrentDictionary <string, ActivationData> > activatedMachinesFloating, APIMethod method = APIMethod.Unknown)
        {
            string bodyParams = System.Text.Encoding.Default.GetString(stream);
            var    nvc        = HttpUtility.ParseQueryString(bodyParams);

            int productId = -1;

            int.TryParse(nvc.Get("ProductId"), out productId);
            int signMethod = -1;

            int.TryParse(nvc.Get("SignMethod"), out signMethod);

            if (nvc.Get("SignMethod") == "StringSign")
            {
                signMethod = 1;
            }

            var licenseKey           = nvc.Get("Key");
            var machineCode          = nvc.Get("MachineCode");
            var friendlyName         = nvc.Get("FriendlyName");
            int floatingTimeInterval = -1;

            int.TryParse(nvc.Get("FloatingTimeInterval"), out floatingTimeInterval);

            LAResult result = null;

            var key = new LAKey {
                Key = licenseKey, ProductId = productId, SignMethod = signMethod
            };

            var keyAlt = new LAKey {
                Key = licenseKey, ProductId = productId, SignMethod = Math.Abs(signMethod - 1)
            };

            if ((method == APIMethod.GetKey || floatingTimeInterval > 0) && localFloatingServer)
            {
                if (signMethod == 0)
                {
                    var error = JsonConvert.SerializeObject(new BasicResult {
                        Result = ResultType.Error, Message = "License server error: SignMethod=1 is needed to use floating licensing offline."
                    });
                    ReturnResponse(error, context);
                    return($"SignMethod was not set to 1 for '{licenseKey}', which is needed to continue with the floating activation.");
                }

                if (Program.ConfigurationExpires != null && Program.ConfigurationExpires < DateTimeOffset.UtcNow)
                {
                    var error = JsonConvert.SerializeObject(new BasicResult {
                        Result = ResultType.Error, Message = "License server error: The configuration has expired. Please contact the vendor to receive a new version of the license server to continue to use floating licenses offline."
                    });
                    ReturnResponse(error, context);
                    return($"The configuration has expired. Please contact the vendor to receive a new version of the license server to continue to use floating licenses offline.");
                }

                //floating license

                if (!licenseCache.TryGetValue(key, out result) && !licenseCache.TryGetValue(keyAlt, out result))
                {
                    var error = JsonConvert.SerializeObject(new BasicResult {
                        Result = ResultType.Error, Message = "License server error: could not find the license file (floating license)."
                    });
                    ReturnResponse(error, context);
                    return($"Could not find the license file for '{licenseKey}' to continue with the floating activation.");
                }

                if (result.LicenseKey.MaxNoOfMachines > 0 || method == APIMethod.GetKey)
                {
                    var activationData = new ConcurrentDictionary <string, ActivationData>();
                    activatedMachinesFloating.TryGetValue(key, out activationData);

                    if (activationData == null)
                    {
                        activationData = activatedMachinesFloating.AddOrUpdate(key, x => new ConcurrentDictionary <string, ActivationData>(), (x, y) => y);
                    }

                    if (method == APIMethod.GetKey)
                    {
                        FloatingResult(result, null, null, context, 1, activationData.Values.Select(x => new ActivationData {
                            Time = x.Time, FloatingExpires = x.FloatingExpires, FriendlyName = x.FriendlyName, IP = x.IP, Mid = x.Mid
                        }).ToList());
                        return($"Floating license {licenseKey} returned successfully using a GetKey request. The data from the local license server is used.");
                    }

                    var activation = new ActivationData();

                    activationData.TryGetValue(machineCode, out activation);

                    if (activation != null && activation.FloatingExpires > DateTime.UtcNow)
                    {
                        activation.FloatingExpires = DateTime.UtcNow.AddSeconds(floatingTimeInterval);
                        activation.FriendlyName    = friendlyName;
                        activation.IP = context.Request.RemoteEndPoint.ToString();
                        FloatingResult(result, activation, machineCode, context);
                        return($"Floating license {licenseKey} returned successfully.");
                    }
                    else if (activationData.Count(x => x.Value.FloatingExpires > DateTime.UtcNow) < result.LicenseKey.MaxNoOfMachines)
                    {
                        activation = activationData.AddOrUpdate(machineCode, x => new ActivationData {
                            Mid = machineCode, Time = DateTime.UtcNow, FloatingExpires = DateTime.UtcNow.AddSeconds(floatingTimeInterval), FriendlyName = friendlyName, IP = context.Request.RemoteEndPoint.ToString()
                        }, (x, y) => new ActivationData {
                            Mid = machineCode, Time = y.Time, FloatingExpires = DateTime.UtcNow.AddSeconds(floatingTimeInterval), FriendlyName = friendlyName, IP = context.Request.RemoteEndPoint.ToString()
                        });

                        FloatingResult(result, activation, machineCode, context);
                        return($"Floating license {licenseKey} returned successfully.");
                    }
                    else
                    {
                        var error = JsonConvert.SerializeObject(new BasicResult {
                            Result = ResultType.Error, Message = "Cannot activate the new device as the limit has been reached."
                        });
                        ReturnResponse(error, context);
                        return($"The limit of the number of concurrent devices for '{licenseKey}' was reached. Activation failed.");
                    }

                    // return new license
                }
                else
                {
                    var activation = new ActivationData {
                        Mid = machineCode, FriendlyName = friendlyName, IP = context.Request.RemoteEndPoint.ToString(), Time = DateTime.UtcNow, FloatingExpires = DateTime.UtcNow.AddSeconds(floatingTimeInterval)
                    };
                    FloatingResult(result, activation, machineCode, context);
                    return($"Floating license {licenseKey} returned successfully.");
                }
            }
            else if (licenseCache.TryGetValue(key, out result) && (method == APIMethod.GetKey || result?.LicenseKey?.ActivatedMachines.Any(x => x.Mid == machineCode) == true) && cacheLength > 0)
            {
                TimeSpan ts = DateTime.UtcNow - result.SignDate;
                if (ts.Days >= cacheLength || attemptToRefresh)
                {
                    // need to obtain new license

                    try
                    {
                        result.Response = ForwardRequest(stream, newRequest, context);
                    }
                    catch (Exception ex)
                    {
                        if (ts.Days >= cacheLength)
                        {
                            if (method == APIMethod.GetKey)
                            {
                                return($"Could not retrieve an updated license '{licenseKey}'.");
                            }
                            else
                            {
                                return($"Could not retrieve an updated license '{licenseKey}' and machine code '{machineCode}'.");
                            }
                        }
                        else if (attemptToRefresh)
                        {
                            ReturnResponse(result.Response, context);

                            if (method == APIMethod.GetKey)
                            {
                                return($"Retrieved cached version of the license '{licenseKey}'.");
                            }
                            else
                            {
                                return($"Retrieved cached version of the license '{licenseKey}' and machine code '{machineCode}'.");
                            }
                        }
                    }


                    if (signMethod == 1)
                    {
                        var resultObject = JsonConvert.DeserializeObject <RawResponse>(result.Response);
                        var license2     = JsonConvert.DeserializeObject <LicenseKeyPI>(System.Text.UTF8Encoding.UTF8.GetString(Convert.FromBase64String(resultObject.LicenseKey))).ToLicenseKey();
                        result.SignDate   = license2.SignDate;
                        result.LicenseKey = license2;
                    }
                    else
                    {
                        var resultObject = JsonConvert.DeserializeObject <KeyInfoResult>(result.Response);
                        result.SignDate   = resultObject.LicenseKey.SignDate;
                        result.LicenseKey = resultObject.LicenseKey;
                    }

                    keysToUpdate.AddOrUpdate(key, x => result.Response, (x, y) => result.Response);

                    if (method == APIMethod.GetKey)
                    {
                        return($"Cache updated for license '{licenseKey}'.");
                    }
                    else
                    {
                        return($"Cache updated for license '{licenseKey}' and machine code '{machineCode}'.");
                    }
                }
                else
                {
                    ReturnResponse(result.Response, context);
                    if (method == APIMethod.GetKey)
                    {
                        return($"Retrieved cached version of the license '{licenseKey}'.");
                    }
                    else
                    {
                        return($"Retrieved cached version of the license '{licenseKey}' and machine code '{machineCode}'.");
                    }
                }
            }
            else
            {
                result = new LAResult();

                try
                {
                    result.Response = ForwardRequest(stream, newRequest, context);
                }
                catch (WebException ex)
                {
                    try
                    {
                        var output = ReadToByteArray(ex.Response.GetResponseStream());

                        context.Response.OutputStream.Write(output, 0, output.Length);
                        context.Response.KeepAlive = false;
                        context.Response.Close();

                        return($"Could not contact the server '{licenseKey}' and machine code '{machineCode}'. Error message {ex?.Message}.");
                    }
                    catch (Exception ex2)
                    {
                        ReturnResponse(JsonConvert.SerializeObject(new BasicResult {
                            Result = ResultType.Error, Message = "Could not contact the central sever (api.cryptolens.io:443)."
                        }), context);
                        return($"Could not contact the server '{licenseKey}' and machine code '{machineCode}'. Error message {ex2?.Message} and stack trace {ex2?.StackTrace}");
                    }
                }
                catch (Exception ex)
                {
                    ReturnResponse(JsonConvert.SerializeObject(new BasicResult {
                        Result = ResultType.Error, Message = "Could not contact the central sever (api.cryptolens.io:443)."
                    }), context);
                    return($"Could not contact the server '{licenseKey}' and machine code '{machineCode}'. Error message {ex?.Message} and stack trace {ex?.StackTrace}");
                }

                if (cacheLength > 0)
                {
                    if (signMethod == 1)
                    {
                        var resultObject = JsonConvert.DeserializeObject <RawResponse>(result.Response);

                        if (!SKM.V3.Methods.Helpers.IsSuccessful(resultObject))
                        {
                            return($"The error '{resultObject?.Message}' was received from the server for license '{licenseKey}' and machine code '{machineCode}'. The method {method} was used. Read more at https://help.cryptolens.io/faq/index#troubleshooting-api-errors.");
                        }

                        var license2 = JsonConvert.DeserializeObject <LicenseKeyPI>(System.Text.UTF8Encoding.UTF8.GetString(Convert.FromBase64String(resultObject.LicenseKey))).ToLicenseKey();
                        result.SignDate   = license2.SignDate;
                        result.LicenseKey = license2;
                    }
                    else
                    {
                        var resultObject = JsonConvert.DeserializeObject <KeyInfoResult>(result.Response);
                        result.SignDate   = resultObject.LicenseKey.SignDate;
                        result.LicenseKey = resultObject.LicenseKey;
                    }

                    if (licenseCache.ContainsKey(key))
                    {
                        licenseCache[key] = result;
                    }
                    else
                    {
                        licenseCache.Add(key, result);
                    }

                    keysToUpdate.AddOrUpdate(key, x => result.Response, (x, y) => result.Response);

                    return($"Added to the cache the license '{licenseKey}' and machine code '{machineCode}'.");
                }

                return(null);
            }
        }