private static Deployment GetExistingAuditDeployment (Deployment deployment) { lock (LockObject) { return HashesInProgress.FirstOrDefault(h => h.ApplicationName == deployment.ApplicationName && h.ServerName == deployment.ServerName); } }
private static void RemoveFromHashingInProgress(Deployment deployment) { lock (LockObject) { HashesInProgress.Remove(deployment); AbortHashing.Remove(deployment.DeploymentId); } }
public async Task InsertDeploymentAsync(Deployment deployment) { var matchingDeployment = await GetActiveDeployment(deployment.ApplicationName, deployment.ServerName); if (matchingDeployment != null) { await ChangeDeploymentEndDateTime(matchingDeployment.DeploymentId, deployment.StartDateTime); } await collection.InsertOneAsync(deployment); }
private static void AbortHashIfNecessary(Deployment deployment) { lock (LockObject) { if (AbortHashing.ContainsKey(deployment.DeploymentId) && AbortHashing[deployment.DeploymentId]) { throw new ApplicationException("The audit running for application " + deployment.ApplicationName + " and server " + deployment.ServerName + " was aborted for a new audit request."); } } }
public async Task<DeploymentAudit> HashDeployment(Deployment deployment, IList<Regex> fileExclusionExpressions, bool hashHiddenFiles, bool overrideExistingAudit) { try { AddToHashesInProgress(deployment, overrideExistingAudit); var audit = await HashDeployment(deployment, fileExclusionExpressions, hashHiddenFiles); return audit; } finally { RemoveFromHashingInProgress(deployment); } }
private static void AddToHashesInProgress(Deployment deployment, bool overrideExistingAudit) { var existingAuditDeployment = GetExistingAuditDeployment(deployment); if (existingAuditDeployment != null) { if (overrideExistingAudit) { AbortExistingAudit(existingAuditDeployment); } else { throw new InvalidOperationException("There is already an audit running for application " + deployment.ApplicationName + " and server " + deployment.ServerName + "."); } } lock (LockObject) { HashesInProgress.Add(deployment); AbortHashing.Add(deployment.DeploymentId, false); } }
private static void AbortExistingAudit(Deployment existingAuditDeployment) { lock (LockObject) { if (AbortHashing.ContainsKey(existingAuditDeployment.DeploymentId)) AbortHashing[existingAuditDeployment.DeploymentId] = true; } bool abortedFlag = false; for (int i = 0; i < 50; i++) { Thread.Sleep(500); lock (LockObject) { if (!AbortHashing.ContainsKey(existingAuditDeployment.DeploymentId)) { abortedFlag = true; break; } } } if (!abortedFlag) { throw new InvalidOperationException("There is already an audit running for application " + existingAuditDeployment.ApplicationName + " and server " + existingAuditDeployment.ServerName + " and it could not be abandoned."); } }
private async Task HashFile(Deployment deployment, string path, bool hashHiddenFiles, IList<FileHash> hashResults ) { AbortHashIfNecessary(deployment); var fileInfo = new FileInfo(path); var fileIsHidden = (fileInfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden; if (fileIsHidden && !hashHiddenFiles) { return; } var hasher = CreateHashAlgorithm(); var buffer = new byte[1024]; //what is optimal here? using (var fileStream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { while (true) { var bytesread = await fileStream.ReadAsync(buffer, 0, 1024); if (bytesread == 0) break; hasher.TransformBlock(buffer, 0, bytesread, null, 0); } } HashString(hasher, path); HashDateTime(hasher, fileInfo.LastWriteTimeUtc); HashIsHidden(hasher, fileIsHidden); hasher.TransformFinalBlock(new byte[0], 0, 0); hashResults.Add(new FileHash {Path = path, IsHidden = fileIsHidden, LastWriteTime = fileInfo.LastWriteTime, Hash = BytesToString(hasher.Hash)}); }
private async Task HashSubDirectoryRecursive(Deployment deployment, string directory, IList<Regex> fileExclusionExpressions, bool hashHiddenFiles, IList<FileHash> hashResults) { var directoryInfo = new DirectoryInfo(directory); if ((directoryInfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden && !hashHiddenFiles) { return; } foreach (var file in Directory.EnumerateFiles(directory, "*", SearchOption.AllDirectories)) { if (!fileExclusionExpressions.Any(f => f.IsMatch(file))) { await HashFile(deployment, file, hashHiddenFiles, hashResults); } } }
private async Task HashDirectory(Deployment deployment, IList<Regex> fileExclusionExpressions, bool hashHiddenFiles, IList<FileHash> hashResults) { foreach (var file in Directory.GetFiles(deployment.NetworkPath, "*")) { if (!fileExclusionExpressions.Any(f => f.IsMatch(file))) { await HashFile(deployment, file, hashHiddenFiles, hashResults); } } foreach (var directory in Directory.GetDirectories(deployment.NetworkPath).Where(d=>!d.EndsWith("RECYCLE.BIN") && !d.EndsWith("System Volume Information"))) { await HashSubDirectoryRecursive(deployment, directory, fileExclusionExpressions, hashHiddenFiles, hashResults); } }
private async Task<DeploymentAudit> HashDeployment(Deployment deployment, IList<Regex> fileExclusionExpressions, bool hashHiddenFiles) { DeploymentAudit audit; try { var hashResults = new List<FileHash>(); IList<FileHashMismatch> hashDifferences = new List<FileHashMismatch>(); var sw = Stopwatch.StartNew(); await HashDirectory(deployment, fileExclusionExpressions, hashHiddenFiles, hashResults); var hash = HashTheHashResults(hashResults); if (deployment.Hash == Deployment.EmptyHash) { deployment.Hash = hash; deployment.FileHashes = hashResults; } bool validHash = deployment.Hash == hash; if (!validHash) { hashDifferences = DetermineHashDifferences(deployment.FileHashes, hashResults); } sw.Stop(); audit = new DeploymentAudit { DeploymentId = deployment.DeploymentId, Hash = hash, ValidHash = validHash, FileHashMismatches = hashDifferences }; if (deployment.MostRecentAudit == Guid.Empty) { deployment.MostRecentAudit = audit.DeploymentAuditId; } if (log.IsDebugEnabled) { log.Debug($"Completed audit for application {deployment.ApplicationName} on server {deployment.ServerName} with hash {hash} in {sw.Elapsed.TotalSeconds} seconds. \r\n Results: {audit.ValidHash} \r\n List of files included in hash: \r\n {string.Join("\r\n", hashResults)}"); } else { log.Info($"Completed audit for application {deployment.ApplicationName} on server {deployment.ServerName} with hash {hash} in {sw.Elapsed.TotalSeconds} seconds. \r\n Results: {audit.ValidHash}"); } } catch (Exception ex) { log.Error("Error while running audit for application {deployment.ApplicationName} on server {deployment.ServerName}.", ex); audit = new DeploymentAudit { DeploymentId = deployment.DeploymentId, Error = ex.Message }; } return audit; }
public async Task<long> ReplaceDeployment(Deployment deployment) { var updateResult = await collection.ReplaceOneAsync(d => d.DeploymentId == deployment.DeploymentId, deployment); return updateResult.ModifiedCount; }
public async Task<IHttpActionResult> Post(string name, string serverName, [FromBody] NewDeployment payload) { try { if (string.IsNullOrWhiteSpace(payload?.NetworkPath)) { return BadRequest("You must include the field `NetworkPath` in the body."); } var application = await applicationRepository.GetApplicationAsync(name); if (application == null) { return BadRequest("The application " + name + " does not exist."); } if (!Directory.Exists(payload.NetworkPath)) { return BadRequest("The path `" + payload.NetworkPath + "` is invalid or inaccessible."); } var deployment = new Deployment { ApplicationName = name, ServerName = serverName, NetworkPath = payload.NetworkPath }; var deploymentAudit = await applicationHashingService.HashDeployment(deployment, application.GetRegularExpressions(), application.HashHiddenFiles, true); await deploymentRepository.InsertDeploymentAsync(deployment); await auditRepository.CreateAuditAsync(deploymentAudit); deployment.FileHashes = null; return Ok(deployment); } catch (Exception ex) { Log.Error("Error in deployment controller:", ex); return InternalServerError(); } }