Example #1
0
 public SnapshotDTO(Snapshot snapshot)
 {
     TimeBlock = snapshot.TimeBlock;
     ApplicationName = snapshot.ApplicationName;
     LogName = snapshot.LogName;
     SnapshotValue = snapshot.SnapshotValue;
     Status = snapshot.Status;
 }
        public HttpResponseMessage Log(Snapshot snapshot)
        {
            if (ModelState.IsValid)
            {
                Subscription subscriber = FindSubscription(snapshot.ApplicationName, snapshot.LogName);
                if (subscriber == null)
                {
                    return Request.CreateResponse(
                        HttpStatusCode.OK,
                        new
                        {
                            Success = false,
                            Error = "Such a log has not been subscribed"
                        },
                        Configuration.Formatters.JsonFormatter
                        );
                }
                else if (!subscriber.APIKey.Equals(snapshot.APIKey, StringComparison.OrdinalIgnoreCase))
                {
                    return Request.CreateResponse(
                        HttpStatusCode.Unauthorized,
                        new
                        {
                            Success = false,
                            Error = "Invalid API Key"
                        },
                        Configuration.Formatters.JsonFormatter
                        );
                }
                else if (subscriber.Verified == false)
                {
                    return Request.CreateResponse(
                        HttpStatusCode.OK,
                        new
                        {
                            Success = false,
                            Error = "Not verified"
                        },
                        Configuration.Formatters.JsonFormatter
                        );
                }
                else
                {
                    Snapshot existing = FindSnapshot(snapshot.ApplicationName, snapshot.LogName);
                    if (existing != null)
                    {
                        if (existing.Status != "Pending")
                        {
                            return Request.CreateResponse(
                                HttpStatusCode.OK,
                                new
                                {
                                    Success = false,
                                    Error = string.Format(
                                        "Snapshot cannot be edited in {0} status",
                                        existing.Status
                                        )
                                },
                                Configuration.Formatters.JsonFormatter
                                );
                        }
                        else
                        {
                            existing.SnapshotValue = snapshot.SnapshotValue;
                            var replaceOperation = TableOperation.Replace(existing);
                            snapshotsTable.Execute(replaceOperation);
                            return Request.CreateResponse(
                                HttpStatusCode.OK,
                                new
                                {
                                    Success = true,
                                    Message = "Updated existing Snapshot, Logging is still Pending",
                                    Snapshot = new SnapshotDTO(snapshot),
                                },
                                Configuration.Formatters.JsonFormatter
                                );
                        }
                    }
                    else
                    {
                        snapshot.APIKey = null;
                        var insertOperation = TableOperation.Insert(snapshot);
                        snapshotsTable.Execute(insertOperation);
                        return Request.CreateResponse(
                            HttpStatusCode.OK,
                            new
                            {
                                Success = true,
                                Message = "Created Snapshot, Logging is Pending",
                                Snapshot = new SnapshotDTO(snapshot)
                            },
                            Configuration.Formatters.JsonFormatter
                            );
                    }
                }
            }

            List<string> errorList = ModelState.Values
                .SelectMany(m => m.Errors)
                .Select(e => e.ErrorMessage)
                .Where(s => !string.IsNullOrWhiteSpace(s))
                .ToList();
            return Request.CreateResponse(
                HttpStatusCode.OK,
                new
                {
                    Success = false,
                    Errors = errorList,
                    Snapshot = new SnapshotDTO(snapshot)
                },
                Configuration.Formatters.JsonFormatter
                );
        }
        public ActionResult Log(Snapshot snapshot)
        {
            if (ModelState.IsValid)
            {
                Subscription subscriber = FindSubscription(snapshot.ApplicationName, snapshot.LogName);
                if (subscriber == null)
                {
                    ModelState.AddModelError(string.Empty, "Such a log has not been subscribed");
                }
                else if (!subscriber.APIKey.Equals(snapshot.APIKey, StringComparison.OrdinalIgnoreCase))
                {
                    ModelState.AddModelError(string.Empty, "Invalid API Key");
                }
                else if (subscriber.Verified == false)
                {
                    ModelState.AddModelError(string.Empty, "Not currently verified");
                }
                else
                {
                    Snapshot existing = FindSnapshot(snapshot.ApplicationName, snapshot.LogName);
                    if (existing != null)
                    {
                        if (existing.Status != "Pending")
                        {
                            ModelState.AddModelError(string.Empty, "Snapshot cannot be edited because it isn't in Pending status");
                        }
                        else
                        {
                            existing.SnapshotValue = snapshot.SnapshotValue;
                            var replaceOperation = TableOperation.Replace(existing);
                            snapshotsTable.Execute(replaceOperation);
                            return RedirectToAction("Index");
                        }
                    }
                    else
                    {
                        snapshot.APIKey = null; //  No need to store this after verification
                        var insertOperation = TableOperation.Insert(snapshot);
                        snapshotsTable.Execute(insertOperation);
                        return RedirectToAction("Index");
                    }
                }
            }

            return View(snapshot);
        }
        public ActionResult Audit(Proof proof)
        {
            ViewData["BlobURL"] = blobContainer.Uri.AbsoluteUri;
            ViewBag.ApplicationName = proof.ApplicationName;
            ViewBag.LogName = proof.LogName;
            ViewBag.LatestBlockNumber = BlockchainAPI.GetLatestBlock().BlockHeight;
            if (ModelState.IsValid)
            {
                DateTime dt;
                DateTime.TryParse(proof.TimeBlock, out dt);
                // Validate Query
                if (string.IsNullOrWhiteSpace(proof.ApplicationName))
                {
                    return View("Proofs", model:new List<Proof>());
                }
                else if (string.IsNullOrWhiteSpace(proof.LogName))
                {
                    return View("Proofs", model:new List<Proof>());
                }
                else if (dt.Ticks <= 0)
                {
                    dt = DateTime.Now;
                }

                Subscription subscriber = FindSubscription(proof.ApplicationName, proof.LogName);

                if (subscriber == null)
                {
                    return View("Proofs", model: new List<Proof>());
                }
                else if (subscriber.Verified != true)
                {
                    return View("Proofs", model: new List<Proof>());
                }

                TableRequestOptions reqOptions = new TableRequestOptions()
                {
                    MaximumExecutionTime = TimeSpan.FromSeconds(10),
                    RetryPolicy = new LinearRetry(TimeSpan.FromSeconds(3), 3)
                };

                List<Proof> proofs;
                try
                {
                    Snapshot snapshot = new Snapshot()
                    {
                        ApplicationName = proof.ApplicationName,
                        LogName = proof.LogName,
                        TimeBlock = dt
                    };

                    var tableQuery = new TableQuery<Proof>().Where(
                        TableQuery.CombineFilters(
                            TableQuery.CombineFilters(
                                TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, proof.ApplicationName),
                                TableOperators.And,
                                TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThanOrEqual, snapshot.RowKey)
                                ),
                            TableOperators.And,
                            TableQuery.GenerateFilterCondition("LogName", QueryComparisons.Equal, proof.LogName)
                            )
                        );

                    proofs = proofsArchiveTable.ExecuteQuery(tableQuery, reqOptions).ToList();
                    if (proofs.Count == 0)
                    {
                        return View("Proofs", model: new List<Proof>());
                    }

                    Proof proofToAudit = null;
                    long maxTicks = 0;
                    foreach (Proof singleProof in proofs)
                    {
                        long ticks = DateTime.Parse(singleProof.TimeBlock).Ticks;
                        if (ticks > maxTicks)
                        {
                            maxTicks = ticks;
                            proofToAudit = singleProof;
                        }
                    }

                    //
                    // TODO: Make API Call, Update Database!
                    //
                    if (proofToAudit.BitcoinBlockNumber == null
                        || proofToAudit.BitcoinTransactionHash == null)
                    {
                        if (PopulateBitcoinInformation(proofToAudit))
                        {
                            var replaceOperation = TableOperation.Replace(proofToAudit);
                            proofsArchiveTable.Execute(replaceOperation);
                        }
                    }

                    return View("Proofs", model: new List<Proof>() { proofToAudit });
                }
                catch (StorageException se)
                {
                    ViewBag.errorMessage = "Timeout error, try again.";
                    Trace.TraceError(se.Message);
                    return View("Error: " + se.Message);
                }
            }

            return View("Proofs", model: new List<Proof>());
        }
        //
        // GET: /Proof/appName=X&?logName=Y
        //
        public ActionResult GetProofs(string appName, string logName)
        {
            ViewData["BlobURL"] = blobContainer.Uri.AbsoluteUri;
            ViewBag.ApplicationName = appName;
            ViewBag.LogName = logName;
            ViewBag.LatestBlockNumber = BlockchainAPI.GetLatestBlock().BlockHeight;
            if (appName == null || logName == null)
            {
                return View();
            }

            Subscription subscriber = FindSubscription(appName, logName);

            if (subscriber == null)
            {
                ViewBag.errorMessage = "Subscriber does not exist.";
                ModelState.AddModelError(string.Empty, "Subscriber does not exist.");
                return View("Proofs", model: new List<Proof>());
            }
            else if (subscriber.Verified != true)
            {
                ViewBag.errorMessage = "Subscriber is not currently verified, no proofs exist.";
                ModelState.AddModelError(string.Empty, "Subscriber is not currently verified, no proofs exist.");
                return View("Proofs", model: new List<Proof>());
            }

            TableRequestOptions reqOptions = new TableRequestOptions()
            {
                MaximumExecutionTime = TimeSpan.FromSeconds(10),
                RetryPolicy = new LinearRetry(TimeSpan.FromSeconds(3), 3)
            };

            List<Proof> proofs;
            try
            {
                Snapshot snapshot = new Snapshot()
                {
                    ApplicationName = appName,
                    LogName = logName,
                    TimeBlock = Utils.NextOperationTB
                };

                var query = new TableQuery<Proof>().Where(
                    TableQuery.CombineFilters(
                        TableQuery.CombineFilters(
                            TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, appName),
                            TableOperators.And,
                            TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThanOrEqual, snapshot.RowKey)
                            ),
                        TableOperators.And,
                        TableQuery.GenerateFilterCondition("LogName", QueryComparisons.Equal, logName)
                        )
                    );

                proofs = proofsArchiveTable.ExecuteQuery(query, reqOptions).ToList();
                return View("Proofs", model:proofs);
            }
            catch (StorageException se)
            {
                ViewBag.errorMessage = "Timeout error, try again.";
                Trace.TraceError(se.Message);
                return View("Error: " + se.Message);
            }
        }
Example #6
0
        private void ProcessSnapshot(Snapshot snapshotToProcess, string restartFlag)
        {
            Trace.TraceInformation("ProcessMessage Beginning PK: "
                + snapshotToProcess.PartitionKey);

            // When we add the this snapshot to the queue, we may be adding it twice if
            // the worker goes down down after adding previously before marking it as
            // processed and then restarted.  In this case the restartFlag would be marked.

            // Create the queue message.
            string queueMessageString =
                snapshotToProcess.PartitionKey + "," +
                snapshotToProcess.RowKey + "," +
                restartFlag;
            var queueMessage = new CloudQueueMessage(queueMessageString);
            snapshotsQueue.AddMessage(queueMessage);

            Trace.TraceInformation("ProcessMessage end PK: "
                + snapshotToProcess.PartitionKey);
        }
        public HttpResponseMessage Audit(ProofQueryDTO query)
        {
            if (ModelState.IsValid)
            {
                // Validate Query
                if (string.IsNullOrWhiteSpace(query.ApplicationName))
                {
                    return Request.CreateResponse(
                        HttpStatusCode.OK,
                        new
                        {
                            Success = false,
                            Error = "Must provide an Application Name to Audit"
                        },
                        Configuration.Formatters.JsonFormatter
                        );
                }
                else if (string.IsNullOrWhiteSpace(query.LogName))
                {
                    return Request.CreateResponse(
                        HttpStatusCode.OK,
                        new
                        {
                            Success = false,
                            Error = "Must provide a Log Name to Audit"
                        },
                        Configuration.Formatters.JsonFormatter
                        );
                }
                else if (query.TimeBlock.Ticks <= 0)
                {
                    query.TimeBlock = DateTime.Now;
                }

                Subscription subscriber = FindSubscription(query.ApplicationName, query.LogName);

                if (subscriber == null)
                {
                    return Request.CreateResponse(
                        HttpStatusCode.OK,
                        new
                        {
                            Success = false,
                            Error = "Subscriber does not exist"
                        },
                        Configuration.Formatters.JsonFormatter
                        );
                }
                else if (subscriber.Verified != true)
                {
                    return Request.CreateResponse(
                        HttpStatusCode.OK,
                        new
                        {
                            Success = false,
                            Error = "Subscriber is not verified"
                        },
                        Configuration.Formatters.JsonFormatter
                        );
                }

                TableRequestOptions reqOptions = new TableRequestOptions()
                {
                    MaximumExecutionTime = TimeSpan.FromSeconds(10),
                    RetryPolicy = new LinearRetry(TimeSpan.FromSeconds(3), 3)
                };

                List<Proof> proofs;
                try
                {
                    Snapshot snapshot = new Snapshot()
                    {
                        ApplicationName = query.ApplicationName,
                        LogName = query.LogName,
                        TimeBlock = query.TimeBlock
                    };

                    var tableQuery = new TableQuery<Proof>().Where(
                        TableQuery.CombineFilters(
                            TableQuery.CombineFilters(
                                TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, query.ApplicationName),
                                TableOperators.And,
                                TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThanOrEqual, snapshot.RowKey)
                                ),
                            TableOperators.And,
                            TableQuery.GenerateFilterCondition("LogName", QueryComparisons.Equal, query.LogName)
                            )
                        );

                    proofs = proofsArchiveTable.ExecuteQuery(tableQuery, reqOptions).ToList();
                    if (proofs.Count == 0)
                    {
                        return Request.CreateResponse(
                            HttpStatusCode.OK,
                            new
                            {
                                Success = false,
                                Error = string.Format("No proofs as of {0}", query.TimeBlock.ToString())
                            },
                            Configuration.Formatters.JsonFormatter
                            );
                    }

                    Proof proofToAudit = null;
                    long maxTicks = 0;
                    foreach (Proof proof in proofs)
                    {
                        long ticks = DateTime.Parse(proof.TimeBlock).Ticks;
                        if (ticks > maxTicks)
                        {
                            maxTicks = ticks;
                            proofToAudit = proof;
                        }
                    }

                    //
                    // TODO: Make API Call
                    //
                    if (proofToAudit.BitcoinBlockNumber == null
                        || proofToAudit.BitcoinTransactionHash == null)
                    {
                        if (PopulateBitcoinInformation(proofToAudit))
                        {
                            var replaceOperation = TableOperation.Replace(proofToAudit);
                            proofsArchiveTable.Execute(replaceOperation);
                        }
                    }

                    return Request.CreateResponse(
                        HttpStatusCode.OK,
                        new
                        {
                            Success = true,
                            Proof = new ProofDTO(proofToAudit)
                        },
                        Configuration.Formatters.JsonFormatter
                        );
                }
                catch (StorageException se)
                {
                    Trace.TraceError(se.Message);
                    throw new HttpResponseException(Request.CreateErrorResponse(
                        HttpStatusCode.ServiceUnavailable,
                        "Timeout error, try again."
                        ));
                }
            }

            List<string> errorList = ModelState.Values
                .SelectMany(m => m.Errors)
                .Select(e => e.ErrorMessage)
                .Where(s => !string.IsNullOrWhiteSpace(s))
                .ToList();
            return Request.CreateResponse(
                HttpStatusCode.OK,
                new
                {
                    Success = false,
                    Errors = errorList
                },
                Configuration.Formatters.JsonFormatter
                );
        }
        public HttpResponseMessage Query(ProofQueryDTO query)
        {
            if (ModelState.IsValid)
            {
                if (string.IsNullOrWhiteSpace(query.ApplicationName))
                {
                    return Request.CreateResponse(
                        HttpStatusCode.OK,
                        new
                        {
                            Success = false,
                            Error = "Must provide an Application Name to search for Proofs"
                        },
                        Configuration.Formatters.JsonFormatter
                        );
                }

                if (string.IsNullOrWhiteSpace(query.LogName))
                {
                    if (query.TimeBlock.Ticks > 0)
                    {
                        return Request.CreateResponse(
                            HttpStatusCode.OK,
                            new
                            {
                                Success = false,
                                Error = "Cannot query for Specific TimeBlock without Specific Log"
                            },
                            Configuration.Formatters.JsonFormatter
                            );
                    }

                    List<Subscription> subscriptions = FindSubscriptions(query.ApplicationName);

                    if (subscriptions.Count == 0)
                    {
                        return Request.CreateResponse(
                            HttpStatusCode.OK,
                            new
                            {
                                Success = false,
                                Error = string.Format("{0} has no Subscriptions", query.ApplicationName)
                            },
                            Configuration.Formatters.JsonFormatter
                            );
                    }

                    bool foundVerified = false;
                    foreach (Subscription subscription in subscriptions)
                    {
                        if (subscription.Verified == true)
                        {
                            foundVerified = true;
                            break;
                        }
                    }
                    if (!foundVerified)
                    {
                        return Request.CreateResponse(
                            HttpStatusCode.OK,
                            new
                            {
                                Success = false,
                                Error = string.Format("{0} has no Verified Subscriptions", query.ApplicationName)
                            },
                            Configuration.Formatters.JsonFormatter
                            );
                    }
                }
                else
                {
                    Subscription subscriber = FindSubscription(query.ApplicationName, query.LogName);

                    if (subscriber == null)
                    {
                        return Request.CreateResponse(
                            HttpStatusCode.OK,
                            new
                            {
                                Success = false,
                                Error = "Subscriber does not exist"
                            },
                            Configuration.Formatters.JsonFormatter
                            );
                    }
                    else if (subscriber.Verified != true)
                    {
                        return Request.CreateResponse(
                            HttpStatusCode.OK,
                            new
                            {
                                Success = false,
                                Error = "Subscriber is not verified"
                            },
                            Configuration.Formatters.JsonFormatter
                            );
                    }
                }

                TableRequestOptions reqOptions = new TableRequestOptions()
                {
                    MaximumExecutionTime = TimeSpan.FromSeconds(10),
                    RetryPolicy = new LinearRetry(TimeSpan.FromSeconds(3), 3)
                };

                List<Proof> proofs;
                try
                {
                    TableQuery<Proof> tableQuery;

                    if (string.IsNullOrWhiteSpace(query.LogName))
                    {
                        // Guaranteed from above that TB is null
                        tableQuery = new TableQuery<Proof>().Where(
                            TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, query.ApplicationName)
                            );
                    }
                    else
                    {
                        if (query.TimeBlock.Ticks <= 0)
                        {
                            Snapshot snapshot = new Snapshot()
                            {
                                ApplicationName = query.ApplicationName,
                                LogName = query.LogName,
                                TimeBlock = Utils.NextOperationTB
                            };
                            tableQuery = new TableQuery<Proof>().Where(
                                TableQuery.CombineFilters(
                                    TableQuery.CombineFilters(
                                        TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, query.ApplicationName),
                                        TableOperators.And,
                                        TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThanOrEqual, snapshot.RowKey)
                                        ),
                                    TableOperators.And,
                                    TableQuery.GenerateFilterCondition("LogName", QueryComparisons.Equal, query.LogName)
                                    )
                                );
                        }
                        else
                        {
                            Snapshot snapshot = new Snapshot()
                            {
                                ApplicationName = query.ApplicationName,
                                LogName = query.LogName,
                                TimeBlock = query.TimeBlock
                            };

                            string queryComparison;
                            if (query.QueryComparison.Equals("Equal", StringComparison.InvariantCultureIgnoreCase))
                            {
                                queryComparison = QueryComparisons.Equal;
                            }
                            else if (query.QueryComparison.Equals("LessThan", StringComparison.InvariantCultureIgnoreCase))
                            {
                                queryComparison = QueryComparisons.LessThan;
                            }
                            else if (query.QueryComparison.Equals("GreaterThan", StringComparison.InvariantCultureIgnoreCase))
                            {
                                queryComparison = QueryComparisons.GreaterThan;
                            }
                            else if (query.QueryComparison.Equals("LessThanOrEqual", StringComparison.InvariantCultureIgnoreCase))
                            {
                                queryComparison = QueryComparisons.LessThanOrEqual;
                            }
                            else if (query.QueryComparison.Equals("GreaterThanOrEqual", StringComparison.InvariantCultureIgnoreCase))
                            {
                                queryComparison = QueryComparisons.GreaterThanOrEqual;
                            }
                            else
                            {
                                queryComparison = QueryComparisons.LessThanOrEqual;
                            }

                            tableQuery = new TableQuery<Proof>().Where(
                                TableQuery.CombineFilters(
                                    TableQuery.CombineFilters(
                                        TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, query.ApplicationName),
                                        TableOperators.And,
                                        TableQuery.GenerateFilterCondition("RowKey", queryComparison, snapshot.RowKey)
                                        ),
                                    TableOperators.And,
                                    TableQuery.GenerateFilterCondition("LogName", QueryComparisons.Equal, query.LogName)
                                    )
                                );
                        }
                    }

                    proofs = proofsArchiveTable.ExecuteQuery(tableQuery, reqOptions).ToList();
                    return Request.CreateResponse(
                        HttpStatusCode.OK,
                        new
                        {
                            Success = true,
                            Proofs = proofs.Select(x => new ProofDTO(x))
                        },
                        Configuration.Formatters.JsonFormatter
                        );
                }
                catch (StorageException se)
                {
                    Trace.TraceError(se.Message);
                    throw new HttpResponseException(Request.CreateErrorResponse(
                        HttpStatusCode.ServiceUnavailable,
                        "Timeout error, try again."
                        ));
                }
            }

            List<string> errorList = ModelState.Values
                .SelectMany(m => m.Errors)
                .Select(e => e.ErrorMessage)
                .Where(s => !string.IsNullOrWhiteSpace(s))
                .ToList();
            return Request.CreateResponse(
                HttpStatusCode.OK,
                new
                {
                    Success = false,
                    Errors = errorList
                },
                Configuration.Formatters.JsonFormatter
                );
        }
        public HttpResponseMessage GetProofs(string appName, string logName)
        {
            if (string.IsNullOrWhiteSpace(appName))
            {
                return Request.CreateResponse(
                    HttpStatusCode.OK,
                    new
                    {
                        Success = false,
                        Error = "Must provide an Application Name to search for Proofs"
                    },
                    Configuration.Formatters.JsonFormatter
                    );
            }

            if (string.IsNullOrWhiteSpace(logName))
            {
                List<Subscription> subscriptions = FindSubscriptions(appName);

                if (subscriptions.Count == 0)
                {
                    return Request.CreateResponse(
                        HttpStatusCode.OK,
                        new
                        {
                            Success = false,
                            Error = string.Format("{0} has no Subscriptions", appName)
                        },
                        Configuration.Formatters.JsonFormatter
                        );
                }

                bool foundVerified = false;
                foreach (Subscription subscription in subscriptions)
                {
                    if (subscription.Verified == true)
                    {
                        foundVerified = true;
                        break;
                    }
                }
                if (!foundVerified)
                {
                    return Request.CreateResponse(
                        HttpStatusCode.OK,
                        new
                        {
                            Success = false,
                            Error = string.Format("{0} has no Verified Subscriptions", appName)
                        },
                        Configuration.Formatters.JsonFormatter
                        );
                }
            }
            else
            {
                Subscription subscriber = FindSubscription(appName, logName);

                if (subscriber == null)
                {
                    return Request.CreateResponse(
                        HttpStatusCode.OK,
                        new
                        {
                            Success = false,
                            Error = "Subscriber does not exist"
                        },
                        Configuration.Formatters.JsonFormatter
                        );
                }
                else if (subscriber.Verified != true)
                {
                    return Request.CreateResponse(
                        HttpStatusCode.OK,
                        new
                        {
                            Success = false,
                            Error = "Subscriber is not verified"
                        },
                        Configuration.Formatters.JsonFormatter
                        );
                }
            }

            TableRequestOptions reqOptions = new TableRequestOptions()
            {
                MaximumExecutionTime = TimeSpan.FromSeconds(10),
                RetryPolicy = new LinearRetry(TimeSpan.FromSeconds(3), 3)
            };

            List<Proof> proofs;
            try
            {
                TableQuery<Proof> query;

                if (string.IsNullOrWhiteSpace(logName))
                {
                    query = new TableQuery<Proof>().Where(
                        TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, appName)
                        );
                }
                else
                {
                    Snapshot snapshot = new Snapshot()
                    {
                        ApplicationName = appName,
                        LogName = logName,
                        TimeBlock = Utils.NextOperationTB
                    };

                    query = new TableQuery<Proof>().Where(
                        TableQuery.CombineFilters(
                            TableQuery.CombineFilters(
                                TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, appName),
                                TableOperators.And,
                                TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThanOrEqual, snapshot.RowKey)
                                ),
                            TableOperators.And,
                            TableQuery.GenerateFilterCondition("LogName", QueryComparisons.Equal, logName)
                            )
                        );
                }

                proofs = proofsArchiveTable.ExecuteQuery(query, reqOptions).ToList();
                return Request.CreateResponse(
                    HttpStatusCode.OK,
                    new
                    {
                        Success = true,
                        Proofs = proofs.Select(x => new ProofDTO(x))
                    },
                    Configuration.Formatters.JsonFormatter
                    );
            }
            catch (StorageException se)
            {
                Trace.TraceError(se.Message);
                throw new HttpResponseException(Request.CreateErrorResponse(
                    HttpStatusCode.ServiceUnavailable,
                    "Timeout error, try again."
                    ));
            }
        }