Beispiel #1
0
        public void InitializeFull(ConsoleEx consoleEx, HelixFileVersion fileVersion = null)
        {
            PreInitializationCheck();

            //Initialize Encr Directory
            consoleEx?.WriteLine(VerbosityLevel.Detailed, 0, "Initializing Encrypted Directory...");
            Header = DirectoryHeader.New();

            EncrDirectory.Create();
            if (WhatIf)
            {
                EncrDirectory.WhatIfAddFile(HelixConsts.HeaderFileName, 10);
            }
            else
            {
                Header.Save(EncrDirectory.PathFull(HelixConsts.HeaderFileName), DerivedBytesProvider, fileVersion);
                EncrDirectory.RefreshEntry(HelixConsts.HeaderFileName);
            }

            this.FileNameEncoder = new FileNameEncoder(Header.FileNameKey);
            consoleEx?.WriteLine(VerbosityLevel.Detailed, 1, "Encrypted Directory Initialized (" + Header.DirectoryId.Substring(0, 6) + "...)");


            InitializeDecr(consoleEx);
        }
Beispiel #2
0
 public void OpenEncr(ConsoleEx consoleEx)
 {
     if (Header == null)
     {
         consoleEx?.WriteLine(VerbosityLevel.Detailed, 0, "Opening Encrypted Directory...");
         Header = DirectoryHeader.Load(EncrDirectory.PathFull(HelixConsts.HeaderFileName), DerivedBytesProvider);
         consoleEx?.WriteLine(VerbosityLevel.Detailed, 0, "Opened Encrypted Directory (" + Header.DirectoryId.Substring(0, 6) + "...)");
     }
     this.FileNameEncoder = new FileNameEncoder(Header.FileNameKey);
 }
Beispiel #3
0
        public void InitializeDecr(ConsoleEx consoleEx)
        {
            consoleEx?.WriteLine(VerbosityLevel.Detailed, 0, "Initializing Decrypted Directory...");

            //Initialize Decr Directory
            DecrDirectory.Create();
            DecrDirectory.CreateDirectory(HelixConsts.SyncLogDirectory);
            if (WhatIf)
            {
                DecrDirectory.WhatIfAddFile(SyncLogPath, 10);
            }
            else
            {
                using var stream = File.CreateText(DecrDirectory.PathFull(SyncLogPath));
                stream.WriteLine(HelixConsts.SyncLogHeader);
            }

            consoleEx?.WriteLine(VerbosityLevel.Detailed, 1, "Decrypted Directory Initialized");
        }
Beispiel #4
0
        /// <summary>
        /// Loads the EncrHeaders for new and updated encripted files
        /// </summary>
        private void FindChanges_St05_RefreshEncrHeaders(ConsoleEx console, List <ChangeBuilder> matchesA)
        {
            int statsRefreshHeaderCount = 0;

            foreach (ChangeBuilder preSyncDetails in matchesA.Where(m => m.EncrInfo != null && m.EncrInfo.LastWriteTimeUtc != m.LogEntry?.EncrModified))
            {
                string encrFullPath = Path.Combine(EncrDirectory.FullName, HelixUtil.PathNative(preSyncDetails.EncrFileName));
                if (File.Exists(encrFullPath))
                {
                    preSyncDetails.EncrHeader = HelixFile.DecryptHeader(encrFullPath, this.DerivedBytesProvider);

                    //Updates the DecrFileName (if necessary)
                    if (string.IsNullOrEmpty(preSyncDetails.DecrFileName) &&
                        FileNameEncoder.EncodeName(preSyncDetails.EncrHeader.FileName) == preSyncDetails.EncrInfo.RelativePath)
                    {
                        preSyncDetails.DecrFileName = preSyncDetails.EncrHeader.FileName;
                    }
                }

                statsRefreshHeaderCount++;
            }
            console?.WriteLine(VerbosityLevel.Diagnostic, 2, $"Updated {statsRefreshHeaderCount} headers");
        }
Beispiel #5
0
        /// <summary>
        /// Matches files from Encr, Decr and Log Entry
        /// </summary>
        private List <ChangeBuilder> FindChanges_St04_ThreeWayJoin(List <FSEntry> encrDirectoryFiles, List <FSEntry> decrDirectoryFiles, SyncLog syncLog, ConsoleEx console)
        {
            List <ChangeBuilder> preSyncDetails = new List <ChangeBuilder>();

            //Adds Logs
            console?.WriteLine(VerbosityLevel.Diagnostic, 2, "Merging in log...");
            preSyncDetails.AddRange(syncLog.Select(entry => new ChangeBuilder {
                LogEntry = entry
            }));
            console?.WriteLine(VerbosityLevel.Diagnostic, 3, $"{preSyncDetails.Count} added");

            //Updates/Adds Decrypted File Information
            console?.WriteLine(VerbosityLevel.Diagnostic, 2, "Merging in decrypted information...");
            int decrStatAdd   = 0;
            int decrStatMerge = 0;
            var decrJoin      = decrDirectoryFiles
                                .GroupJoin(preSyncDetails,
                                           o => o.RelativePath,
                                           i => i?.LogEntry?.DecrFileName,
                                           (o, i) => new Tuple <FSEntry, ChangeBuilder>(o, i.FirstOrDefault()));

            foreach (var entry in decrJoin.ToList())
            {
                if (entry.Item2 == null)
                {
                    //New Entry (not in log)
                    preSyncDetails.Add(new ChangeBuilder {
                        DecrInfo = entry.Item1
                    });
                    decrStatAdd++;
                }
                else
                {
                    //Existing Entry (update only)
                    entry.Item2.DecrInfo = entry.Item1;
                    if (entry.Item1 != null)
                    {
                        decrStatMerge++;
                    }
                }
            }
            console?.WriteLine(VerbosityLevel.Diagnostic, 3, $"{decrStatAdd} added, {decrStatMerge} merged");

            //find encrypted file names
            foreach (var entry in preSyncDetails)
            {
                entry.DecrFileName = entry.LogEntry?.DecrFileName ?? entry.DecrInfo.RelativePath;
                entry.EncrFileName = FileNameEncoder.EncodeName(entry.DecrFileName);
            }


            //Updates/adds encrypted File Information
            console?.WriteLine(VerbosityLevel.Diagnostic, 2, "Merging in encrypted information...");
            int encrStatAdd   = 0;
            int encrStatMerge = 0;
            var encrJoin      = encrDirectoryFiles
                                .GroupJoin(preSyncDetails,
                                           o => o.RelativePath,
                                           i => i.EncrFileName,
                                           (o, i) => new Tuple <FSEntry, ChangeBuilder>(o, i.FirstOrDefault()));

            foreach (var entry in encrJoin.ToList())
            {
                if (entry.Item2 == null)
                {
                    //New Entry (not in log or decrypted file)
                    preSyncDetails.Add(new ChangeBuilder {
                        EncrInfo = entry.Item1, EncrFileName = entry.Item1.RelativePath
                    });
                    encrStatAdd++;
                }
                else
                {
                    //Existing Entry
                    entry.Item2.EncrInfo = entry.Item1;
                    if (entry.Item1 != null)
                    {
                        encrStatMerge++;
                    }
                }
            }
            console?.WriteLine(VerbosityLevel.Diagnostic, 3, $"{encrStatAdd} added, {encrStatMerge} merged");

            return(preSyncDetails);
        }
Beispiel #6
0
        /// <summary>
        /// Returns a list of changes that need to be performed as part of the sync.
        /// </summary>
        public List <PreSyncDetails> FindChanges(bool clearCache = true, ConsoleEx console = null)
        {
            //todo: disable default for reset
            console?.WriteLine(VerbosityLevel.Diagnostic, 0, "Finding Changes...");
            if (clearCache)
            {
                ClearCache();
            }

            using var rng = RandomNumberGenerator.Create();

            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Enumerating Encr Directory...");
            List <FSEntry> encrDirectoryFiles = EncrDirectory.GetEntries(SearchOption.AllDirectories).Where(EncrFilter).ToList();

            console?.WriteLine(VerbosityLevel.Diagnostic, 2, $"{encrDirectoryFiles.Count} files found");

            console?.WriteLine(VerbosityLevel.Diagnostic, 1, $"Enumerating Decr Directory...");
            console?.WriteLine(VerbosityLevel.Diagnostic, 2, $"Path: {DecrDirectory.FullName}");
            List <FSEntry> decrDirectoryFiles = DecrDirectory.GetEntries(SearchOption.AllDirectories).Where(DecrFilter).ToList();

            console?.WriteLine(VerbosityLevel.Diagnostic, 2, $"{decrDirectoryFiles.Count} files found");

            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Reading sync log (decr side)...");
            console?.WriteLine(VerbosityLevel.Diagnostic, 2, $"{SyncLog.Count()} entries found");
            //todo: filter out log entries where the decr file name and the encr file name does not match


            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Performing 3 way join...");
            List <ChangeBuilder> changes = FindChanges_St04_ThreeWayJoin(encrDirectoryFiles, decrDirectoryFiles, SyncLog, console).ToList();


            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Refreshing EncrHeaders...");
            FindChanges_St05_RefreshEncrHeaders(console, changes);


            //todo: detect conflicts

            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Adding Relationships...");
            FindChanges_St06_AddRelationships(changes);

#if DEBUG
            Debug.Assert(changes.All(c => c.RelationParents != null));
            Debug.Assert(changes.All(c => c.RelationChildren != null));
            Debug.Assert(changes.All(c => c.RelationCaseDifference != null));
#endif


            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Calculating Operation...");
            FindChanges_St07_CalculateOperation(changes);

            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Calculating Sync Mode...");
            FindChanges_St08_CalculateSyncMode(changes);

            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Calculating Dependencies...");
            FindChanges_St09_CalculateDependencies(changes);

            console?.WriteLine(VerbosityLevel.Diagnostic, 1, "Sorting...");
            changes = FindChanges_St10_Sort(rng, changes);



            return(changes
                   .Where(m => m.SyncMode != PreSyncMode.Unchanged)
                   .Select(m => m.ToSyncEntry())
                   .ToList());
        }
Beispiel #7
0
        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}")));
        }
Beispiel #8
0
        public static SyncSummary Sync(SyncOptions options, ConsoleEx consoleEx = null, HelixFileVersion fileVersion = null)
        {
            var sum = new SyncSummary();

            consoleEx ??= new ConsoleEx();
            consoleEx.Verbosity = options.Verbosity;

            consoleEx.WriteLine("Sync");
            if (options.WhatIf)
            {
                consoleEx.WriteLine("..Options: WhatIf");
            }
            consoleEx.WriteLine($"..DecrDir: {options.DecrDirectory}");
            consoleEx.WriteLine($"..EncrDir: {options.EncrDirectory}");
            //consoleEx.WriteLine($"..Direction: {options.Direction}");
            consoleEx.WriteLine($"..Verbosity: {options.Verbosity}");

            consoleEx.WriteLine();

            if (options.WhatIf)
            {
                consoleEx.WriteLine("** WhatIf Mode - No Changes Made **");
                consoleEx.WriteLine("");
            }


            DerivedBytesProvider derivedBytesProvider = DerivedBytesProvider.FromPassword(options.Password, options.KeyFile);

            using DirectoryPair pair = new DirectoryPair(options.DecrDirectory, options.EncrDirectory, derivedBytesProvider, options.WhatIf);
            pair.PreInitializationCheck();

            if (pair.InitializeFullNeeded())
            {
                if (options.Initialize)
                {
                    //continue, unprompted
                    if (pair.InitializeMergeWarning())
                    {
                        consoleEx.WriteLine("WARNING: Decrypted directory is not empty and will be merged");
                    }
                }
                else
                {
                    consoleEx.WriteLine("Directories require initialization...");

                    if (!consoleEx.PromptBool("Initialized encrypted and decrypted directories now? [y/N] ", false))
                    {
                        consoleEx.WriteErrorLine("Operation cancelled");
                        sum.Error = new InitializationCanceledException();
                        return(sum);
                    }

                    if (pair.InitializeMergeWarning())
                    {
                        if (!consoleEx.PromptBool("Decrypted directory is not empty and will be merged, continue? [y/N] ", false))
                        {
                            consoleEx.WriteErrorLine("Operation cancelled");
                            sum.Error = new InitializationCanceledException();
                            return(sum);
                        }
                    }
                }

                pair.InitializeFull(consoleEx);
            }

            pair.OpenEncr(consoleEx);

            if (pair.InitializeDecrNeeded())
            {
                if (options.Initialize)
                {
                    //continue, unprompted
                    if (pair.InitializeMergeWarning())
                    {
                        consoleEx.WriteLine("WARNING: Decrypted directory is not empty and will be merged");
                    }
                }
                else
                {
                    consoleEx.WriteLine("Decrypted directory require initialization...");

                    if (!consoleEx.PromptBool("Initialized decrypted directories now? [y/N] ", false))
                    {
                        consoleEx.WriteErrorLine("Operation cancelled");
                        sum.Error = new InitializationCanceledException();
                        return(sum);
                    }

                    if (pair.InitializeMergeWarning())
                    {
                        if (!consoleEx.PromptBool("Decrypted directory is not empty and will be merged, continue? [y/N] ", false))
                        {
                            consoleEx.WriteErrorLine("Operation cancelled");
                            sum.Error = new InitializationCanceledException();
                            return(sum);
                        }
                    }
                }

                pair.InitializeDecr(consoleEx);
            }

            pair.OpenDecr(consoleEx);

            pair.Cleanup(consoleEx);

            List <PreSyncDetails> changes = pair.FindChanges(clearCache: false, console: consoleEx);

            if (changes.Count == 0)
            {
                consoleEx.WriteLine("--No Changes--");
            }



            var defaultConflictAction = "";

            consoleEx.WriteLine(VerbosityLevel.Normal, 0, "Performing Sync...");
            foreach (PreSyncDetails change in changes)
            {
                consoleEx.WriteLine(change);

                if (change.SyncMode == PreSyncMode.Conflict)
                {
                    var decrModified = change.DecrInfo == null ? (object)null : change.DecrInfo.LastWriteTimeUtc.ToLocalTime();
                    var decrSize     = change.DecrInfo == null ? (object)null : HelixUtil.FormatBytes5(change.DecrInfo.Length);
                    var encrModified = change.EncrInfo == null ? (object)null : change.EncrInfo.LastWriteTimeUtc.ToLocalTime();
                    var encrSize     = change.EncrHeader == null ? (object)null : HelixUtil.FormatBytes5(change.EncrHeader.Length);


                    string response;
                    if (defaultConflictAction != "")
                    {
                        response = defaultConflictAction;
                    }
                    else
                    {
                        consoleEx.WriteLine($"    Decrypted - Modified: {decrModified}, Size: {decrSize}");
                        consoleEx.WriteLine($"    Encrypted - Modified: {encrModified}, Size: {encrSize}");
                        consoleEx.WriteLine($"");
                        consoleEx.WriteLine($"    D - Decrypted, E - Encrypted, S - Skip, + Always perform this action"); //todo: support newer, support always
                        response = consoleEx.PromptChoice("    Select Option [D,E,S,D+,E+,S+]? ", new string[] { "D", "E", "S", "D+", "E+", "S+" }, "S");
                        if (response.EndsWith("+"))
                        {
                            response = response.Substring(0, 1);
                            defaultConflictAction = response;
                        }
                    }
                    if (response == "D")
                    {
                        change.SyncMode = PreSyncMode.DecryptedSide;
                    }
                    else if (response == "E")
                    {
                        change.SyncMode = PreSyncMode.EncryptedSide;
                    }

                    if (change.SyncMode != PreSyncMode.Conflict)
                    {
                        consoleEx.WriteLine(change);
                    }
                }

                if (change.SyncMode == PreSyncMode.EncryptedSide)
                {
                    //todo: make display operation be the actual operation
                    if (change.DisplayOperation == PreSyncOperation.Add)
                    {
                        sum.EncrAdd++;
                    }
                    else if (change.DisplayOperation == PreSyncOperation.Remove)
                    {
                        sum.EncrRemove++;
                    }
                    else if (change.DisplayOperation == PreSyncOperation.Change)
                    {
                        sum.EncrChange++;
                    }
                    else
                    {
                        sum.EncrOther++;
                    }
                }
                else if (change.SyncMode == PreSyncMode.DecryptedSide)
                {
                    if (change.DisplayOperation == PreSyncOperation.Add)
                    {
                        sum.DecrAdd++;
                    }
                    else if (change.DisplayOperation == PreSyncOperation.Remove)
                    {
                        sum.DecrRemove++;
                    }
                    else if (change.DisplayOperation == PreSyncOperation.Change)
                    {
                        sum.DecrChange++;
                    }
                    else
                    {
                        sum.DecrOther++;
                    }
                }
                else if (change.SyncMode == PreSyncMode.Conflict)
                {
                    sum.Conflict++;
                }


                var syncResult = pair.TrySync(change, consoleEx);
                //todo: add to error log
                if (syncResult.Exception != null)
                {
                    consoleEx.WriteErrorLine("..." + syncResult.Exception.Message);
                }
            }

            consoleEx.WriteLine("== Summary ==");
            consoleEx.WriteLine(sum);

            //todo: fix unchanged
            consoleEx.WriteLine();


            //consoleEx.WriteLine(VerbosityLevel.Diagnostic, 0, "");
            //consoleEx.WriteLine(VerbosityLevel.Diagnostic, 0, "==Decr Directory==");
            //foreach (var entry in decrDirectory.FSDirectory.GetEntries(SearchOption.AllDirectories))
            //{
            //    if (entry is FSDirectory dirEntry)
            //        consoleEx.WriteLine(VerbosityLevel.Diagnostic, 1, $"<dir> {entry.RelativePath}");
            //    else if (entry is FSFile fileEntry)
            //        consoleEx.WriteLine(VerbosityLevel.Diagnostic, 1, $"{HelixUtil.FormatBytes5(entry.Length)} {entry.RelativePath}");
            //}

            //consoleEx.WriteLine(VerbosityLevel.Diagnostic, 0, "");
            //consoleEx.WriteLine(VerbosityLevel.Diagnostic, 0, "==Encr Directory==");
            //foreach (var entry in encrDirectory.FSDirectory.GetEntries(SearchOption.AllDirectories))
            //{
            //    if (entry is FSDirectory dirEntry)
            //        consoleEx.WriteLine(VerbosityLevel.Diagnostic, 1, $"<dir> {entry.RelativePath}");
            //    else if (entry is FSFile fileEntry)
            //        consoleEx.WriteLine(VerbosityLevel.Diagnostic, 1, $"{HelixUtil.FormatBytes5(entry.Length)} {entry.RelativePath}");
            //}

            return(sum);
        }
Beispiel #9
0
        /// <summary>
        /// Displays a preview of the content (to the console), automatically determining the best viewer.
        /// </summary>
        /// <param name="stream">The stream for which to load the preview data</param>
        /// <param name="type">(option) used to override the automatic detected viewer</param>
        /// <param name="targetLength">(option) used to override the default length of preview</param>
        private static void ContentPreview(Stream stream, ConsoleEx consoleEx, string type = "auto", int targetLength = -1)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }
            if (!stream.CanRead)
            {
                throw new ArgumentException("steam must be readable", nameof(stream));
            }

            const int defaultLength       = 512;
            const int defaultBinaryLength = 256;



            int offset = 0;

            byte[] content = new byte[targetLength <= 0 ? defaultLength : targetLength];
            int    length  = stream.Read(content, 0, content.Length);

            string display;

            if (string.IsNullOrEmpty(type) || type == "auto")
            {
                type = DetectType(content, offset, length);
            }

            //Reduces size by two for binary due to the fact that it takes a lot of screen realestate
            if (type == "binary" && targetLength < 0 && length > defaultBinaryLength)
            {
                length = defaultBinaryLength;
            }


            bool partial = length < stream.Length;

            if (length < stream.Length)
            {
                display = "== Content Preview (" + type + " " + FormatSizeBytes(length) + " of " + FormatSizeBytes(stream.Length) + ") ==" + Environment.NewLine;
            }
            else
            {
                display = "== Content Preview (" + type + ", size: " + FormatSizeBytes(stream.Length) + ") ==" + Environment.NewLine;
            }

            if (type == "text")
            {
                display += TextDisplay(content, offset, length);
                if (partial)
                {
                    display += "...";
                }
            }
            else if (type == "json")
            {
                display += JsonDisplay(content, offset, length);
                if (partial)
                {
                    display += "...";
                }
            }
            else
            {
                display += HexDisplay(content, offset, length);
            }

            consoleEx.WriteLine(display);
        }
Beispiel #10
0
        public static int Inspect(InspectOptions options, ConsoleEx consoleEx = null)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            consoleEx ??= new ConsoleEx();

            using (Stream fileIn = File.OpenRead(options.File))
                using (HelixFileDecryptor decryptor = new HelixFileDecryptor(fileIn))
                {
                    consoleEx.WriteLine("== Outer Header ==");
                    Dictionary <string, byte[]> header = null;
                    decryptor.Initialize(DerivedBytesProvider.FromPassword(options.Password, options.KeyFile), (h) => header = h);
                    consoleEx.WriteLine("Designator:    "
                                        + BitConverter.ToString(header[nameof(FileHeader.fileDesignator)]).Replace("-", "")
                                        + " (" + new string(Encoding.ASCII.GetString(header[nameof(FileHeader.fileDesignator)])
                                                            .Select(c => Char.IsControl(c) ? '?' : c)
                                                            .ToArray()) + ")");
                    consoleEx.WriteLine("Password Salt: " + BitConverter.ToString(header[nameof(FileHeader.passwordSalt)]).Replace("-", ""));
                    consoleEx.WriteLine("HMAC Salt:     " + BitConverter.ToString(header[nameof(FileHeader.hmacSalt)]).Replace("-", ""));
                    consoleEx.WriteLine("IV:            " + BitConverter.ToString(header[nameof(FileHeader.iv)]).Replace("-", ""));
                    consoleEx.WriteLine("Authn (HMAC):  " + BitConverter.ToString(header[nameof(FileHeader.headerAuthnDisk)]).Replace("-", ""));
                    consoleEx.WriteLine();

                    consoleEx.WriteLine("== Inner Header ==");
                    decryptor.ReadHeader(
                        afterRawMetadata: (r) => consoleEx.WriteLine(JsonFormat(r)));
                    consoleEx.WriteLine();

                    using Stream content = decryptor.GetContentStream();
                    ContentPreview(content, consoleEx, options.ContentFormat);
                    consoleEx.WriteLine();
                }

            //Reopen to calculate the checksum
            using (Stream fileIn = File.OpenRead(options.File))
                using (HelixFileDecryptor decryptor = new HelixFileDecryptor(fileIn))
                {
                    decryptor.Initialize(DerivedBytesProvider.FromPassword(options.Password, options.KeyFile));
                    decryptor.ReadHeader();
                    using Stream content = decryptor.GetContentStream();
                    Checksum(content, consoleEx);


                    return(0);
                }
        }