BinToss/Intern

View on GitHub
Tasks.cs

Summary

Maintainability
D
1 day
Test Coverage
///////
/// Copyright Noah Sherwin 2021
/// This file is part of the 'Intern' project

using Intern.Helpers;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.IO;

namespace Intern
{
    public class Tasks
    {
        /** TODO: Create template functions for each task. Result will resemble the System.Threading.Task namespace */

        /// <summary>
        ///     The Type of Task to execute.
        /// </summary>
        public enum Type
        {
            None,
            FileSystemDelete,
            ComparePermissions,
            ModifyPermissions,
            ReadPermissions
        }

        public List<Task> TaskList;

        /// <summary>
        ///     A structured template for a Task's metadata.
        /// </summary>
        public struct Task
        {
            public Type Type;
            public string Path;
            public string Parameters;
        }

        /// <summary> Execute the specified task—with the given path if necessary. </summary> <param
        /// name="task">The <see cref="Type"> of task to execute.</param> <param name="path">A
        /// network, filesystem, Window Registry path.</param>
        public static void DoTask(Task task)
        {
            switch (task.Type)
            {
                case Type.FileSystemDelete:
                    FileSystemDelete(task);
                    break;

                case Type.ComparePermissions: // TODO: What do I want from this?
                    if (task.Path == null) throw Exceptions.PathIsNullException(task.Type);
                    // TODO: Check these per parameter. We might be given a procID and a file

                    var str1 = task.Path.Split(';')[0];
                    var str2 = task.Path.Split(';')[1];

                    bool arePaths = Path.IsPathRooted(str1) && Path.IsPathRooted(str2);

                    /// Check if Reg Keys
                    try
                    {
                        string[] hkeyNames = new string[]
                        {
                              "HKEY_CLASSES_ROOT",
                              "HKCR",
                              "HKEY_CURRENT_USER",
                              "HKCU",
                              "HKEY_LOCAL_MACHINE",
                              "HKLM",
                              "HKEY_USERS",
                              "HKU",
                              "HKEY_PERFORMANCE_DATA",
                              "HKEY_CURRENT_CONFIG",
                              "HKEY_DYN_DATA"
                        };

                        bool str1HasBase = false;
                        string objABase;
                        bool str2HasBase = false;
                        string objBBase;

                        foreach (string hkeyname in hkeyNames)
                        {
                            if (str1.StartsWith(hkeyname))
                            {
                                str1HasBase = true;
                                objABase = hkeyname;
                            }
                        }

                        foreach (string hkeyname in hkeyNames)
                        {
                            if (str2.StartsWith(hkeyname))
                            {
                                str2HasBase = true;
                                objBBase = hkeyname;
                            }
                        }

                        if (!str1HasBase || !str2HasBase)
                            throw new ArgumentException();

                        var hiveA = GetHiveByName(str1.Split('\\')[0]);
                        var hiveB = GetHiveByName(str2.Split('\\')[0]);
                        using (var keyA = RegistryKey.OpenBaseKey(hiveA, RegistryView.Default))
                        using (var keyB = RegistryKey.OpenBaseKey(hiveB, RegistryView.Default))
                        {
                            // TODO: Compare RegKey ACLs; Difficulty: easier than processes
                        }

                        RegistryHive GetHiveByName(string name)
                        {
                            RegistryHive hive;

                            if (name.Equals(hkeyNames[0], StringComparison.CurrentCultureIgnoreCase) ||
                                name.Equals(hkeyNames[1], StringComparison.CurrentCultureIgnoreCase))
                                hive = RegistryHive.ClassesRoot;
                            else if (name.Equals(hkeyNames[2], StringComparison.CurrentCultureIgnoreCase) ||
                                    name.Equals(hkeyNames[3], StringComparison.CurrentCultureIgnoreCase))
                                hive = RegistryHive.CurrentUser;
                            else if (name.Equals(hkeyNames[4], StringComparison.CurrentCultureIgnoreCase) ||
                                    name.Equals(hkeyNames[5], StringComparison.CurrentCultureIgnoreCase))
                                hive = RegistryHive.LocalMachine;
                            else if (name.Equals(hkeyNames[6], StringComparison.CurrentCultureIgnoreCase) ||
                                    name.Equals(hkeyNames[7], StringComparison.CurrentCultureIgnoreCase))
                                hive = RegistryHive.Users;
                            else if (name.Equals(hkeyNames[8], StringComparison.CurrentCultureIgnoreCase))
                                hive = RegistryHive.PerformanceData;
                            else if (name.Equals(hkeyNames[9], StringComparison.CurrentCultureIgnoreCase))
                                hive = RegistryHive.CurrentConfig;
                            else if (name.Equals(hkeyNames[10], StringComparison.CurrentCultureIgnoreCase))
                                hive = RegistryHive.DynData;
                            else throw new IndexOutOfRangeException();

                            return hive;
                        }
                    }
                    catch (ArgumentException) { }
                    catch (IndexOutOfRangeException) { }
                    catch (Exception) { }

                    // probably a process ID
                    if (!arePaths)
                    {
                        int ID1 = int.Parse(str1);
                        int ID2 = int.Parse(str2);
                        var proc1 = System.Diagnostics.Process.GetProcessById(ID1);
                        var proc2 = System.Diagnostics.Process.GetProcessById(ID2);
                    }

                    break;

                case Type.ModifyPermissions:
                    if (task.Path == null) throw Exceptions.PathIsNullException(task.Type);

                    break;

                default: throw new ArgumentOutOfRangeException($"The Intern does not recognize the task, \"{task}\".");
            }
        }

        private static void FileSystemDelete(Task task)
        {
            if (string.IsNullOrEmpty(task.Path)) throw Exceptions.PathIsNullException(task.Type);

            /// <see href="https://stackoverflow.com/a/1395226/14894786" />
            try
            {
                FileAttributes attr = File.GetAttributes(task.Path);
                bool isDir = attr.HasFlag(FileAttributes.Directory);

                if (attr.HasFlag(FileAttributes.Directory))
                    new DirectoryInfo(task.Path).Delete(recursive: true);
                else new FileInfo(task.Path).Delete();
            }
            catch (ArgumentException) { } /** invalid path */
            catch (PathTooLongException) { }
            catch (NotSupportedException) { } /** invalid format */
            catch (FileNotFoundException) { }
            catch (DirectoryNotFoundException) { }
            catch (IOException) /** The file is in use by another process */
            {
                // TODO: try to close the handle(s) of the file; Employ
            }
            catch (UnauthorizedAccessException)
            {
                // TODO: determine if we can obtain permission to continue
                // - new process with elevation or alternative authorization or change the item's permissions
            }
        }

        public static class Exceptions
        {
            public static ArgumentNullException PathIsNullException(Type task)
            {
                throw new ArgumentNullException($"The Intern must be provided with a file or directory path for the task \"{task}\".");
            }

            public static UnauthorizedAccessException UnauthorizedAccessException(Type task, string path)
            {
                throw new UnauthorizedAccessException($"The Intern was denied required permissions for \"{path}\" while working on the task, \"{task}\".");
            }
        }
    }
}