/// <summary> /// Encrypts a file and returns the name of the encrypted file /// </summary> /// <param name="decrFilePath">The file name and path of the file to be encrypted</param> /// <param name="encrFilePath">The file name and path for th encrypted file to be saved</param> public static void Encrypt(string decrFilePath, string encrFilePath, DerivedBytesProvider derivedBytesProvider, FileEncryptOptions options = null) { if (string.IsNullOrWhiteSpace(decrFilePath)) { throw new ArgumentNullException(nameof(decrFilePath)); } if (string.IsNullOrEmpty(encrFilePath)) { throw new ArgumentNullException(nameof(encrFilePath)); } if (derivedBytesProvider == null) { throw new ArgumentNullException(nameof(derivedBytesProvider)); } options ??= new FileEncryptOptions(); var encrStagedFileName = encrFilePath + HelixConsts.StagedHxExtention; var encrBackupFileName = encrFilePath + HelixConsts.BackupExtention; if (!string.IsNullOrEmpty(Path.GetDirectoryName(encrStagedFileName))) { Directory.CreateDirectory(Path.GetDirectoryName(encrStagedFileName)); } FileEntry header = FileEntry.FromFile(decrFilePath, Path.GetDirectoryName(decrFilePath)); if (!string.IsNullOrWhiteSpace(options.StoredFileName)) { header.FileName = options.StoredFileName; } using (Stream streamIn = (header.EntryType != FileEntryType.File) ? (Stream)(new MemoryStream()) : File.Open(decrFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) using (var streamOut = File.Open(encrStagedFileName, FileMode.CreateNew, FileAccess.Write)) using (var encryptor = new HelixFileEncryptor(streamOut, derivedBytesProvider, options.FileVersion)) { options.Log?.Invoke("Writing: Header"); options.BeforeWriteHeader?.Invoke(header); encryptor.WriteHeader(header); options.Log?.Invoke("Writing: Content"); encryptor.WriteContent(streamIn, streamIn.Length); } if (File.Exists(encrFilePath)) { if (File.Exists(encrBackupFileName)) { options.Log?.Invoke("Destaging: Removing incomplete backup"); File.Delete(encrBackupFileName); } options.Log?.Invoke("Destaging: Moving staged to normal"); if (File.Exists(encrFilePath)) { File.Move(encrFilePath, encrBackupFileName); } File.Move(encrStagedFileName, encrFilePath); options.Log?.Invoke("Destaging: Removing backup"); File.Delete(encrBackupFileName); } else { options.Log?.Invoke("Destaging: Moving staged to normal"); File.Move(encrStagedFileName, encrFilePath); } }
public static void Encrypt(string decrFile, string encrFile, string password, FileEncryptOptions options = null) { Encrypt(decrFile, encrFile, DerivedBytesProvider.FromPassword(password), options); }
public SyncResults TrySync(PreSyncDetails entry, ConsoleEx console = null) { const int encrTimespanPrecisionMS = 1000; //todo: ensure the entry direction and operation end up being the same //todo: ensure all the calling methods do something with the results //if (WhatIf) // throw new InvalidOperationException("Unable to perform sync when WhatIf mode is set to true"); if (entry == null) { throw new ArgumentNullException(nameof(entry)); } if (entry.SyncMode == PreSyncMode.DecryptedSide) { SyncLogEntry logEntry = entry.LogEntry; string encrPath = Path.Combine(EncrDirectory.FullName, HelixUtil.PathNative(entry.EncrFileName)); string decrPath = Path.Combine(DecrDirectory.FullName, HelixUtil.PathNative(entry.DecrFileName)); FileEncryptOptions options = new FileEncryptOptions(); FileEntry header = null; options.BeforeWriteHeader = (h) => header = h; options.StoredFileName = entry.DecrFileName; options.FileVersion = Header.FileVersion; options.Log = (s) => console?.WriteLine(VerbosityLevel.Diagnostic, 1, s); if (WhatIf) { EncrDirectory.WhatIfReplaceFile(encrPath, entry.DisplayFileLength); if (entry.DecrInfo == null) { header = new FileEntry() { EntryType = FileEntryType.Removed, FileName = entry.DecrFileName, }; } else { header = entry.DecrInfo.ToFileEntry(); } } else { HelixFile.Encrypt(decrPath, encrPath, DerivedBytesProvider, options); //forces a change if the file was modified to quickly if (logEntry != null && (File.GetLastWriteTimeUtc(encrPath) - logEntry.EncrModified).TotalMilliseconds < encrTimespanPrecisionMS) { File.SetLastWriteTimeUtc(encrPath, logEntry.EncrModified + TimeSpan.FromMilliseconds(encrTimespanPrecisionMS)); } EncrDirectory.RefreshEntry(encrPath); } var newLogEntry = CreateEntryFromHeader(header, EncrDirectory.TryGetEntry(entry.EncrFileName)); SyncLog.Add(newLogEntry); return(SyncResults.Success()); } else if (entry.SyncMode == PreSyncMode.EncryptedSide) { if (entry.DisplayOperation == PreSyncOperation.Purge) { SyncLog.Add(entry.GetUpdatedLogEntry()); return(SyncResults.Success()); } else { //todo: use the DisplayOperation to determine what to do (ensures the counts stay consistant) SyncLogEntry logEntry = entry.LogEntry; SyncLogEntry fileSystemEntry = CreateNewLogEntryFromEncrPath(entry.EncrFileName); if (logEntry?.ToString() == fileSystemEntry?.ToString()) { return(SyncResults.Success()); //Unchanged } //todo: test to see if there are illegal characters //todo: check if the name matches string encrPath = HelixUtil.JoinNative(EncrDirectory.FullName, fileSystemEntry.EncrFileName); string decrPath = HelixUtil.JoinNative(DecrDirectory.FullName, fileSystemEntry.DecrFileName); //todo: if file exists with different case - skip file var exactPath = HelixUtil.GetExactPathName(decrPath); FSEntry decrEntry = DecrDirectory.TryGetEntry(fileSystemEntry.DecrFileName); if (decrEntry != null && decrEntry.RelativePath != fileSystemEntry.DecrFileName) { //todo: throw more specific exception return(SyncResults.Failure(new HelixException($"Case only conflict file \"{decrPath}\" exists as \"{exactPath}\"."))); } if (WhatIf) { if (entry.EncrHeader.EntryType == FileEntryType.File) { DecrDirectory.WhatIfReplaceFile(decrPath, entry.EncrHeader.Length, entry.EncrHeader.LastWriteTimeUtc); } else if (entry.EncrHeader.EntryType == FileEntryType.Removed) { DecrDirectory.WhatIfDeleteFile(decrPath); } else if (entry.EncrHeader.EntryType == FileEntryType.Directory) { DecrDirectory.WhatIfAddDirectory(decrPath); } else { throw new NotSupportedException(); } } else { HelixFile.Decrypt(encrPath, decrPath, DerivedBytesProvider); //todo: get the date on the file system (needed if the filesystem has less precision DecrDirectory.RefreshEntry(decrPath); } SyncLog.Add(fileSystemEntry); return(SyncResults.Success()); } } else if (entry.SyncMode == PreSyncMode.Match) { //Add to Log file (changed to be equal on both sides) SyncLogEntry fileSystemEntry = CreateNewLogEntryFromDecrPath(entry.DecrFileName); SyncLog.Add(fileSystemEntry); return(SyncResults.Success()); } else if (entry.SyncMode == PreSyncMode.Unchanged) { //do nothing return(SyncResults.Success()); } return(SyncResults.Failure(new HelixException($"Invalid sync mode {entry.SyncMode}"))); }