Skiller9090/Lucifer

View on GitHub
lucifer/GUI/Console.py

Summary

Maintainability
A
0 mins
Test Coverage
import sys
import threading
import tkinter as tk
from tkinter import ttk

from lucifer.Errors import checkErrors
from lucifer.Utils import RetrieveShell


class TextRedirect(object):
    def __init__(self, widget, tag="stdout"):
        """The Object to Redirect output into the tkinter console box."""
        self.all_tags = {
            "30": "black",
            "31": "red",
            "32": "green",
            "33": "yellow",
            "34": "blue",
            "35": "cyan",
            "36": "magenta",
            "37": "white",
            "0": "stdout"
        }
        self.widget = widget
        self.esc_seq = u"\u001b["
        self.tag = tag

    def write(self, string):
        string = str(string)
        if string == "":
            return
        self.widget.configure(state="normal")
        if self.esc_seq in string:
            tag_string = self.process_text(string)
            for insert_tuple in tag_string:
                tags = self.tag_map(insert_tuple[0])
                string = str(insert_tuple[1])
                if string and "\r" == string[0]:
                    self.widget.delete("end-1l", "end")
                    string = "\n" + string
                self.widget.insert("end", string, tags)
        else:
            if str(string) and "\r" == str(string)[0]:
                self.widget.delete("end-1l", "end")
                string = "\n" + string
            self.widget.insert("end", string, (self.tag,))
        self.widget.configure(state="disabled")
        self.widget.see(tk.END)

    def process_text(self, string):
        to_process = string.split(self.esc_seq)
        tag_string = []
        while "" in to_process:
            to_process.remove("")
        for text in to_process:
            if "m" in text:
                m_ind = text.index("m")
                if len(text) - 1 != m_ind:
                    tag_string.append(([text[0:m_ind]], text[(m_ind + 1):]))
            else:
                tag_string.append(("stdout", text))
        return tag_string

    def flush(self):
        pass

    def fileno(self):
        if self.tag == "stdout":
            return 1
        return 2

    def tag_map(self, tag_ids):
        tags = []
        for tid in tag_ids:
            mapped_tag = self.all_tags.get(tid)
            if mapped_tag is None:
                tags.append("stdout")
            else:
                tags.append(mapped_tag)
        return tuple(tags)


class LuciferConsole(tk.Frame, RetrieveShell):
    def __init__(self, luciferManager, parent, GUI, *args, **kwargs):
        """The Console Box Setup"""
        super().__init__(parent, *args, **kwargs)

        self.parent = parent
        self.expand = True
        self.luciferManager = luciferManager
        self.LuciferGui = GUI

        self.console_in = tk.StringVar()
        self.ConsoleBox = tk.Text(self, font=self.LuciferGui.font)
        self.ConsoleBox.configure(state="disabled")
        self.add_colour_tags()
        self.command_history = []
        self.command_index = None
        self.opened_order = [0]

        self.y_scrollbar = ttk.Scrollbar(self)
        self.ConsoleInput = ttk.Entry(self, textvariable=self.console_in, font=self.LuciferGui.font)

        self.setup_console_widget()

        self.luciferManager.stdout = TextRedirect(self.ConsoleBox, "stdout")
        # self.luciferManager.stderr = TextRedirect(self.ConsoleBox, "stderr")
        sys.stdout = self.luciferManager.stdout
        sys.stderr = self.luciferManager.stderr
        print(self.luciferManager.termcolor.colored(self.luciferManager.version, "red", attrs=["bold", "underline"]))
        print(f"{self.shell.program_name}|" +
              f"{self.shell.module if '.py' not in self.shell.module else self.shell.module.replace('.py', '')}" +
              f"|{self.shell.id}> ", end="")

    def add_colour_tags(self):
        self.ConsoleBox.tag_configure("stderr", foreground="#b22222")
        self.ConsoleBox.tag_configure("stdout", foreground="#FFFFFF")
        self.ConsoleBox.tag_configure("black", foreground="#555555")
        self.ConsoleBox.tag_configure("red", foreground="#FF5555")
        self.ConsoleBox.tag_configure("green", foreground="#55FF55")
        self.ConsoleBox.tag_configure("yellow", foreground="#FFFF55")
        self.ConsoleBox.tag_configure("blue", foreground="#0D98BA")
        self.ConsoleBox.tag_configure("cyan", foreground="#FF55FF")
        self.ConsoleBox.tag_configure("magenta", foreground="#55FFFF")
        self.ConsoleBox.tag_configure("white", foreground="#FFFFFF")

    def setup_console_widget(self):
        self.link_scrollbar()
        self.get_shell()
        self.ConsoleBox["bg"] = '#%02x%02x%02x' % (28, 28, 36)
        self.ConsoleBox["foreground"] = '#%02x%02x%02x' % (255, 255, 255)
        self.ConsoleInput.insert(0, 'Enter Command...')
        self.pack_all()
        self.setup_grid()
        self.bind_shortcuts()

    def link_scrollbar(self):
        self.ConsoleBox.config(yscrollcommand=self.y_scrollbar.set)
        self.y_scrollbar.config(command=self.ConsoleBox.yview)

    def pack_all(self):
        self.ConsoleInput.pack(side=tk.BOTTOM, anchor=tk.W, expand=False, fill="x")
        self.y_scrollbar.pack(side=tk.RIGHT, fill="y", anchor=tk.E, expand=False)
        self.ConsoleBox.pack(fill="both", side=tk.LEFT, anchor=tk.E, expand=True)

    def bind_shortcuts(self):
        self.ConsoleInput.bind('<FocusIn>', self.on_entry_click)
        self.ConsoleInput.bind('<FocusOut>', self.on_focusout)
        self.ConsoleInput.bind("<Return>", self.send_command)
        self.ConsoleInput.bind("<Up>", self.history_up)
        self.ConsoleInput.bind("<Down>", self.history_down)

    def setup_grid(self):
        self.grid_columnconfigure(0, weight=1)
        self.grid_columnconfigure(1, weight=1)
        self.grid_rowconfigure(0, weight=1)
        self.grid_rowconfigure(1, weight=1)

    def on_entry_click(self, *args, **kwargs):
        if self.ConsoleInput.get() == 'Enter Command...':
            self.ConsoleInput.delete(0, "end")
            self.ConsoleInput.insert(0, '')

    def on_focusout(self, *args, **kwargs):
        if self.ConsoleInput.get() == '':
            self.ConsoleInput.insert(0, 'Enter Command...')

    def send_command(self, *args, **kwargs):
        if self.luciferManager.gui_thread_free:
            self.luciferManager.gui_thread_free = False
            self.luciferManager.gui.statusFrame.progressBar["value"] = 0
            thread = threading.Thread(target=self.send_command_daemon)
            thread.setDaemon(True)
            thread.start()

    def clear(self):
        self.ConsoleBox.configure(state="normal")
        self.ConsoleBox.delete(1.0, tk.END)
        self.ConsoleBox.configure(state="disabled")

    def send_command_daemon(self):
        try:
            self.luciferManager.gui.statusFrame.status.set("Starting Command")
            self.get_shell()
            self.shell.shell_in = self.console_in.get()
            self.command_index = None
            self.command_history.append(self.shell.shell_in)
            self.luciferManager.gui.statusFrame.status.set(f"Running Command: {self.shell.shell_in}")
            self.console_in.set("")
            print(self.shell.shell_in)
            self.shell.parseShellIn()
            self.get_shell()
            print(f"{self.shell.program_name}|" +
                  f"{self.shell.module if '.py' not in self.shell.module else self.shell.module.replace('.py', '')}" +
                  f"|{self.shell.id}> ", end="")
            if self.luciferManager.log_file is not None:
                if self.luciferManager.log_amount == 1:
                    self.luciferManager.log_command(self.shell.shell_in)
        except Exception as e:
            checkErrors(e)
        self.luciferManager.gui.statusFrame.progressBar["value"] = 100
        self.luciferManager.gui.statusFrame.status.set("Idle")
        self.luciferManager.gui.varView.display_vars()
        self.luciferManager.gui_thread_free = True

    def history_up(self, *args, **kwargs):
        if self.command_index is None:
            if len(self.command_history) > 0:
                self.command_index = len(self.command_history) - 1
                self.ConsoleInput.delete(0, "end")
                self.ConsoleInput.insert(0, self.command_history[self.command_index])
        else:
            if self.command_index > 0:
                self.command_index -= 1
                self.ConsoleInput.delete(0, "end")
                self.ConsoleInput.insert(0, self.command_history[self.command_index])

    def history_down(self, *args, **kwargs):
        if self.command_index is not None:
            if len(self.command_history) - 1 > self.command_index:
                self.command_index += 1
                self.ConsoleInput.delete(0, "end")
                self.ConsoleInput.insert(0, self.command_history[self.command_index])
            else:
                self.command_index = None
                self.ConsoleInput.delete(0, "end")