public static async Task <IActionResult> GetKeys(HttpRequest req, TraceWriter log, ExecutionContext context, bool returnAppSKey)
        {
            string devAddr = req.Query["devAddr"];

            if (devAddr == null)
            {
                string errorMsg = "Missing devAddr in querystring";
                //log.Error(errorMsg);
                throw new Exception(errorMsg);
            }



            var config = new ConfigurationBuilder()
                         .SetBasePath(context.FunctionAppDirectory)
                         .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
                         .AddEnvironmentVariables()
                         .Build();
            string connectionString = config.GetConnectionString("IoTHubConnectionString");

            if (connectionString == null)
            {
                string errorMsg = "Missing IoTHubConnectionString in settings";
                //log.Error(errorMsg);
                throw new Exception(errorMsg);
            }


            RegistryManager registryManager = RegistryManager.CreateFromConnectionString(connectionString);

            //Currently registry manager query only support select so we need to check for injection on the devaddr only for "'"
            //TODO check for sql injection
            devAddr = devAddr.Replace('\'', ' ');

            var query = registryManager.CreateQuery($"SELECT * FROM devices WHERE tags.DevAddr = '{devAddr}'", 1);

            LoraDeviceInfo loraDeviceInfo = new LoraDeviceInfo();

            loraDeviceInfo.DevAddr = devAddr;



            while (query.HasMoreResults)
            {
                var page = await query.GetNextAsTwinAsync();

                //we query only for 1 result
                foreach (var twin in page)
                {
                    loraDeviceInfo.DevEUI = twin.DeviceId;
                    if (returnAppSKey)
                    {
                        loraDeviceInfo.AppSKey = twin.Tags["AppSKey"].Value;
                    }
                    loraDeviceInfo.NwkSKey = twin.Tags["NwkSKey"].Value;
                    if (twin.Tags.Contains("GatewayID"))
                    {
                        loraDeviceInfo.GatewayID = twin.Tags["GatewayID"].Value;
                    }
                    if (twin.Tags.Contains("SensorDecoder"))
                    {
                        loraDeviceInfo.SensorDecoder = twin.Tags["SensorDecoder"].Value;
                    }

                    if (twin.Tags.Contains("AppEUI"))
                    {
                        loraDeviceInfo.AppEUI = twin.Tags["AppEUI"].Value;
                    }
                    loraDeviceInfo.IsOurDevice = true;
                    if (twin.Properties.Reported.Contains("FCntUp"))
                    {
                        loraDeviceInfo.FCntUp = twin.Properties.Reported["FCntUp"];
                    }
                    if (twin.Properties.Reported.Contains("FCntDown"))
                    {
                        loraDeviceInfo.FCntDown = twin.Properties.Reported["FCntDown"];
                    }
                }
            }

            if (loraDeviceInfo.IsOurDevice)
            {
                var device = await registryManager.GetDeviceAsync(loraDeviceInfo.DevEUI);

                loraDeviceInfo.PrimaryKey = device.Authentication.SymmetricKey.PrimaryKey;
            }

            string json = JsonConvert.SerializeObject(loraDeviceInfo);

            return((ActionResult) new OkObjectResult(json));
        }
        public static async Task <IActionResult> PerformOTAA(HttpRequest req, TraceWriter log, ExecutionContext context, bool returnAppSKey)
        {
            string json;

            string AppKey;
            string AppSKey;
            string NwkSKey;
            string DevAddr;
            string DevNonce;
            string AppNonce;



            string devEUI = req.Query["devEUI"];

            if (devEUI == null)
            {
                string errorMsg = "Missing devEUI in querystring";
                //log.Error(errorMsg);
                throw new Exception(errorMsg);
            }

            string appEUI = req.Query["appEUI"];

            if (appEUI == null)
            {
                string errorMsg = "Missing appEUI in querystring";
                //log.Error(errorMsg);
                throw new Exception(errorMsg);
            }

            DevNonce = req.Query["devNonce"];

            if (DevNonce == null)
            {
                string errorMsg = "Missing devNonce in querystring";
                //log.Error(errorMsg);
                throw new Exception(errorMsg);
            }

            string GatewayID = req.Query["GatewayID"];

            var config = new ConfigurationBuilder()
                         .SetBasePath(context.FunctionAppDirectory)
                         .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
                         .AddEnvironmentVariables()
                         .Build();

            var connectionString = config.GetConnectionString("IoTHubConnectionString");

            if (connectionString == null)
            {
                string errorMsg = "Missing IoTHubConnectionString in settings";
                //log.Error(errorMsg);
                throw new Exception(errorMsg);
            }



            RegistryManager registryManager = RegistryManager.CreateFromConnectionString(connectionString);


            LoraDeviceInfo loraDeviceInfo = new LoraDeviceInfo();


            loraDeviceInfo.DevEUI = devEUI;

            var twin = await registryManager.GetTwinAsync(devEUI);

            if (twin != null)
            {
                loraDeviceInfo.IsOurDevice = true;

                //Make sure that there is the AppEUI and it matches if not we cannot do the OTAA
                if (!twin.Tags.Contains("AppEUI"))
                {
                    string errorMsg = $"Missing AppEUI for OTAA for device {devEUI}";
                    //log.Error(errorMsg);
                    throw new Exception(errorMsg);
                }
                else
                {
                    if (twin.Tags["AppEUI"].Value != appEUI)
                    {
                        string errorMsg = $"AppEUI for OTAA does not match for device {devEUI}";
                        //log.Error(errorMsg);
                        throw new Exception(errorMsg);
                    }
                }

                //Make sure that there is the AppKey if not we cannot do the OTAA
                if (!twin.Tags.Contains("AppKey"))
                {
                    string errorMsg = $"Missing AppKey for OTAA for device {devEUI}";
                    //log.Error(errorMsg);
                    throw new Exception(errorMsg);
                }
                else
                {
                    AppKey = twin.Tags["AppKey"].Value;
                }

                //Make sure that is a new request and not a replay
                if (twin.Tags.Contains("DevNonce"))
                {
                    if (twin.Tags["DevNonce"] == DevNonce)
                    {
                        string errorMsg = $"DevNonce already used for device {devEUI}";
                        log.Info(errorMsg);
                        loraDeviceInfo.DevAddr     = DevNonce;
                        loraDeviceInfo.IsJoinValid = false;
                        json = JsonConvert.SerializeObject(loraDeviceInfo);
                        return((ActionResult) new OkObjectResult(json));
                    }
                }

                //Check that the device is joining throught the linked gateway and not another
                if (twin.Tags.Contains("GatewayID"))
                {
                    if (!String.IsNullOrEmpty(twin.Tags["GatewayID"].Value) && twin.Tags["GatewayID"].Value.ToUpper() != GatewayID.ToUpper())
                    {
                        string errorMsg = $"Not the right gateway device-gateway:{twin.Tags["GatewayID"].Value} current-gateway:{GatewayID}";
                        log.Info(errorMsg);
                        loraDeviceInfo.DevAddr = DevNonce;
                        if (twin.Tags.Contains("GatewayID"))
                        {
                            loraDeviceInfo.GatewayID = twin.Tags["GatewayID"].Value;
                        }
                        loraDeviceInfo.IsJoinValid = false;
                        json = JsonConvert.SerializeObject(loraDeviceInfo);
                        return((ActionResult) new OkObjectResult(json));
                    }
                }


                byte[] netId = new byte[3] {
                    0, 0, 1
                };

                AppNonce = OTAAKeysGenerator.getAppNonce();

                AppSKey = OTAAKeysGenerator.calculateKey(new byte[1] {
                    0x02
                }, OTAAKeysGenerator.StringToByteArray(AppNonce), netId, OTAAKeysGenerator.StringToByteArray(DevNonce), OTAAKeysGenerator.StringToByteArray(AppKey));
                NwkSKey = OTAAKeysGenerator.calculateKey(new byte[1] {
                    0x01
                }, OTAAKeysGenerator.StringToByteArray(AppNonce), netId, OTAAKeysGenerator.StringToByteArray(DevNonce), OTAAKeysGenerator.StringToByteArray(AppKey));;



                //check that the devaddr is unique in the IoTHub registry
                bool isDevAddrUnique = false;

                do
                {
                    DevAddr = OTAAKeysGenerator.getDevAddr(netId);



                    var query = registryManager.CreateQuery($"SELECT * FROM devices WHERE tags.DevAddr = '{DevAddr}'", 1);
                    if (query.HasMoreResults)
                    {
                        var page = await query.GetNextAsTwinAsync();

                        if (!page.GetEnumerator().MoveNext())
                        {
                            isDevAddrUnique = true;
                        }
                        else
                        {
                            isDevAddrUnique = false;
                        }
                    }
                    else
                    {
                        isDevAddrUnique = true;
                    }
                } while (!isDevAddrUnique);



                var patch = new
                {
                    tags = new
                    {
                        AppSKey,
                        NwkSKey,
                        DevAddr,
                        DevNonce
                    }
                };

                await registryManager.UpdateTwinAsync(loraDeviceInfo.DevEUI, JsonConvert.SerializeObject(patch), twin.ETag);

                loraDeviceInfo.DevAddr  = DevAddr;
                loraDeviceInfo.AppKey   = twin.Tags["AppKey"].Value;
                loraDeviceInfo.NwkSKey  = NwkSKey;
                loraDeviceInfo.AppSKey  = AppSKey;
                loraDeviceInfo.AppNonce = AppNonce;
                loraDeviceInfo.AppEUI   = appEUI;
                loraDeviceInfo.NetId    = BitConverter.ToString(netId).Replace("-", "");;

                if (!returnAppSKey)
                {
                    loraDeviceInfo.AppSKey = null;
                }

                //Accept the JOIN Request and the futher messages
                loraDeviceInfo.IsJoinValid = true;

                var device = await registryManager.GetDeviceAsync(loraDeviceInfo.DevEUI);

                loraDeviceInfo.PrimaryKey = device.Authentication.SymmetricKey.PrimaryKey;

                if (twin.Tags.Contains("GatewayID"))
                {
                    loraDeviceInfo.GatewayID = twin.Tags["GatewayID"].Value;
                }
                if (twin.Tags.Contains("SensorDecoder"))
                {
                    loraDeviceInfo.SensorDecoder = twin.Tags["SensorDecoder"].Value;
                }
            }
            else
            {
                loraDeviceInfo.IsOurDevice = false;
            }


            json = JsonConvert.SerializeObject(loraDeviceInfo);
            return((ActionResult) new OkObjectResult(json));
        }