bdsh 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
bdsh-0.2.1/PKG-INFO ADDED
@@ -0,0 +1,52 @@
1
+ Metadata-Version: 2.4
2
+ Name: bdsh
3
+ Version: 0.2.1
4
+ Summary: BadOS Dynamic Shell
5
+ Author-email: Logan Dhillon <dev@logandhillon.com>
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+
9
+ # BadOS Dynamic Shell (bdsh)
10
+
11
+ Read the docs at 🔗 [badtechnologies.github.io/bdsh](https://badtechnologies.github.io/bdsh).
12
+
13
+ ## Quick Install
14
+
15
+ Run the following command:
16
+
17
+ ```sh
18
+ curl -O https://raw.githubusercontent.com/badtechnologies/bdsh/main/install.py
19
+ python3 install.py
20
+ ```
21
+
22
+ After completing setup, bdsh should be good to go!
23
+
24
+
25
+ ## Installation (Manual)
26
+
27
+ 1. **Download the latest release**
28
+
29
+ Or, you can directly download `install.py` from the [repo](https://github.com/badtechnologies/bdsh).
30
+
31
+ > [!TIP]
32
+ > The only file needed to create a bdsh installation is `install.py`.<br>
33
+ > Running `install.py` generates, downloads, or installs everything else.
34
+
35
+ 2. **Setup bdsh:**
36
+
37
+ ```sh
38
+ python3 install.py
39
+ ```
40
+
41
+ Follow the on-screen instructions.
42
+
43
+ Once the `/bdsh` directory and your configs are prepared, you can start bdsh with `bdsh` to launch the interactive shell.
44
+
45
+ 3. **Launch bdsh:**
46
+
47
+ ```sh
48
+ bdsh
49
+ ```
50
+
51
+ > [!NOTE]
52
+ > This may change depending on how you created your launcher scripts.
bdsh-0.2.1/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # BadOS Dynamic Shell (bdsh)
2
+
3
+ Read the docs at 🔗 [badtechnologies.github.io/bdsh](https://badtechnologies.github.io/bdsh).
4
+
5
+ ## Quick Install
6
+
7
+ Run the following command:
8
+
9
+ ```sh
10
+ curl -O https://raw.githubusercontent.com/badtechnologies/bdsh/main/install.py
11
+ python3 install.py
12
+ ```
13
+
14
+ After completing setup, bdsh should be good to go!
15
+
16
+
17
+ ## Installation (Manual)
18
+
19
+ 1. **Download the latest release**
20
+
21
+ Or, you can directly download `install.py` from the [repo](https://github.com/badtechnologies/bdsh).
22
+
23
+ > [!TIP]
24
+ > The only file needed to create a bdsh installation is `install.py`.<br>
25
+ > Running `install.py` generates, downloads, or installs everything else.
26
+
27
+ 2. **Setup bdsh:**
28
+
29
+ ```sh
30
+ python3 install.py
31
+ ```
32
+
33
+ Follow the on-screen instructions.
34
+
35
+ Once the `/bdsh` directory and your configs are prepared, you can start bdsh with `bdsh` to launch the interactive shell.
36
+
37
+ 3. **Launch bdsh:**
38
+
39
+ ```sh
40
+ bdsh
41
+ ```
42
+
43
+ > [!NOTE]
44
+ > This may change depending on how you created your launcher scripts.
@@ -0,0 +1,22 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "bdsh"
7
+ authors = [
8
+ { name = "Logan Dhillon", email = "dev@logandhillon.com" }
9
+ ]
10
+ dynamic = ["version"]
11
+ description = "BadOS Dynamic Shell"
12
+ requires-python = ">=3.10"
13
+ readme = "README.md"
14
+
15
+ [project.scripts]
16
+ bdsh = "bdsh.__main__:main"
17
+
18
+ [tool.setuptools.packages.find]
19
+ where = ["src"]
20
+
21
+ [tool.setuptools.dynamic]
22
+ version = {attr = "bdsh.__version__.__version__"}
bdsh-0.2.1/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ from .__version__ import __version__
2
+
3
+ NL = '\r\n'
@@ -0,0 +1,15 @@
1
+ # BadOS Dynamic Shell (bdsh)
2
+
3
+ import os
4
+ import sys
5
+
6
+ from bdsh.shell import Shell
7
+
8
+ def main():
9
+ _cwd = os.getcwd()
10
+ bdsh = Shell(sys.stdout, sys.stdin)
11
+ bdsh.start()
12
+ os.chdir(_cwd)
13
+
14
+ if __name__ == "__main__":
15
+ main()
@@ -0,0 +1 @@
1
+ __version__ = "0.2.1"
@@ -0,0 +1,32 @@
1
+ from abc import ABC, abstractmethod
2
+ from collections.abc import Callable
3
+ from typing import List, Any, TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from bdsh.shell import Shell
7
+
8
+
9
+ class Command(ABC):
10
+ def __init__(self, shell: Shell):
11
+ self.shell = shell
12
+
13
+ @abstractmethod
14
+ def execute(self, args: List[str]):
15
+ pass
16
+
17
+ @abstractmethod
18
+ def help(self) -> str:
19
+ pass
20
+
21
+
22
+ class AnonymousCommand(Command):
23
+ def __init__(self, shell: Shell, execute: Callable[[List[str]], Any], help_msg: str):
24
+ super().__init__(shell)
25
+ self.help_msg = help_msg
26
+ self.execute = execute
27
+
28
+ def execute(self, args: List[str]):
29
+ self.execute(args)
30
+
31
+ def help(self) -> str:
32
+ return self.help_msg
@@ -0,0 +1,110 @@
1
+ import os
2
+ from typing import List, TYPE_CHECKING, Dict
3
+
4
+ from bdsh import NL
5
+ from bdsh.command import Command, AnonymousCommand
6
+
7
+ if TYPE_CHECKING:
8
+ from bdsh.shell import Shell
9
+
10
+
11
+ class HelpCommand(Command):
12
+ def execute(self, args: List[str]):
13
+ if len(args) > 1:
14
+ subcommand = self.shell.commands.get(args[1])
15
+ if isinstance(subcommand, Command):
16
+ msg = subcommand.help()
17
+
18
+ if not msg:
19
+ self.shell.print(f"help: {args[1]} does not have a manual or help message")
20
+ else:
21
+ self.shell.print(f"{args[1]}: {msg}")
22
+ else:
23
+ raise TypeError(f"{args[1]} is not a valid command")
24
+ else:
25
+ self.shell.print(f"bdsh commands:{NL}" + '\t'.join(self.shell.commands.keys()))
26
+
27
+ def help(self) -> str:
28
+ return "lists all commands, or displays the help message for individual commands"
29
+
30
+
31
+ class ListDirectoryCommand(Command):
32
+ def execute(self, args: List[str]):
33
+ try:
34
+ path = self.shell.get_path(args[1]) if len(args) > 1 else self.shell.path
35
+ items = os.listdir(path)
36
+ self.shell.print('\t'.join([item + '/' if os.path.isdir(os.path.join(path, item)) else item for item in items]))
37
+ except FileNotFoundError:
38
+ raise FileNotFoundError(f"{args[1]}: does not exist")
39
+
40
+ def help(self) -> str:
41
+ return "lists the contents of a directory"
42
+
43
+
44
+ class DefineCommand(Command):
45
+ def execute(self, args: List[str]):
46
+ if '-h' in args or '--help' in args:
47
+ self.shell.print(
48
+ f"usage: def <keyword> <definition>{NL}binds <keyword> to <definition>{NL}executing <keyword> will execute <definition>")
49
+ return
50
+
51
+ if len(args) < 3:
52
+ raise ValueError("missing params (at least 3)")
53
+
54
+ definition = " ".join(args[2:])
55
+
56
+ if args[1] == definition:
57
+ raise SyntaxError("keyword cannot be the same as the definition")
58
+
59
+ self.shell.definitions[args[1]] = definition
60
+ self.shell.print(f"defined '{args[1]}' to run '{definition}'")
61
+
62
+ def help(self) -> str:
63
+ return "defines a 'definition', which maps a string to a command"
64
+
65
+
66
+ class ThrowCommand(Command):
67
+ def execute(self, args: List[str]):
68
+ raise Exception(' '.join(args[1:]))
69
+
70
+ def help(self) -> str:
71
+ return "throws an exception"
72
+
73
+
74
+ class GoCommand(Command):
75
+ def execute(self, args: List[str]):
76
+ if os.path.exists(path := self.shell.get_path(args[1])):
77
+ self.shell.path = path
78
+ os.chdir(path)
79
+ else:
80
+ raise FileNotFoundError(f"{args[1]}: no such file or folder")
81
+
82
+ def help(self) -> str:
83
+ return "goes to a directory"
84
+
85
+
86
+ class PeekCommand(Command):
87
+ def execute(self, args: List[str]):
88
+ if os.path.isfile(path := os.path.join(self.shell.path, args[1])):
89
+ with open(path, 'r') as f:
90
+ self.shell.print(f.read())
91
+ else:
92
+ raise FileNotFoundError(f"{args[1]}: no such file")
93
+
94
+ def help(self) -> str:
95
+ return "peeks the contents of a file"
96
+
97
+
98
+ def register_commands(shell: Shell) -> Dict[str, Command]:
99
+ return {
100
+ "exit": AnonymousCommand(shell, lambda _: exit(0), ""),
101
+ "help": HelpCommand(shell),
102
+ "echo": AnonymousCommand(shell, lambda args: shell.print(' '.join(args[1:])), ""),
103
+ "ld": ListDirectoryCommand(shell),
104
+ "ver": AnonymousCommand(shell, lambda _: shell.print(shell.header), ""),
105
+ "def": DefineCommand(shell),
106
+ "throw": ThrowCommand(shell),
107
+ "cwd": AnonymousCommand(shell, lambda _: shell.print(shell.cwd()), ""),
108
+ "go": GoCommand(shell),
109
+ "peek": PeekCommand(shell),
110
+ }
@@ -0,0 +1,112 @@
1
+ import os
2
+ import subprocess
3
+ import sys
4
+ from typing import TextIO
5
+
6
+ from bdsh import NL, __version__
7
+ from bdsh.command.commands import register_commands
8
+
9
+ ROOT_DIR = os.path.abspath('bdsh')
10
+
11
+
12
+ class Shell:
13
+ def __init__(self, stdout: TextIO | None, stdin: TextIO | None, **is_ssh: bool):
14
+ self.stdout = stdout
15
+ self.stdin = stdin
16
+ self.print = lambda s: self.stdout.write(s)
17
+ self.readchar = lambda: self.stdin.read(1)
18
+ self.is_ssh = is_ssh
19
+ self.path = self.get_path()
20
+ self.cwd = lambda: os.path.relpath(self.path, ROOT_DIR).replace('.', '/', 1)
21
+
22
+ self.header = f"BadOS Dynamic Shell (v{__version__}) {'(BadBandSSH)' if is_ssh else ''}{NL}(c) Bad Technologies. All rights reserved.{NL}"
23
+
24
+ self.commands = register_commands(self)
25
+
26
+ self.definitions = {
27
+ "ls": "ld",
28
+ "dir": "ld",
29
+ "cd": "go"
30
+ }
31
+
32
+ self.env = os.environ.copy()
33
+ self.env['PYTHONPATH'] = os.path.dirname(os.path.realpath(__file__))
34
+
35
+ def run_line(self, line: str):
36
+ line = line.strip() # dont want to process invisible characters
37
+
38
+ if line == "":
39
+ return
40
+
41
+ args = line.split(' ')
42
+
43
+ if args[0] in self.definitions:
44
+ self.run_line(self.definitions[args[0]] + " " + ' '.join(args[1:]))
45
+ elif args[0] in self.commands:
46
+ try:
47
+ self.commands[args[0]].execute(args)
48
+ except Exception as e:
49
+ self.print(f"{args[0]}: {e}")
50
+ elif os.path.exists(binary := self.get_path("exec", args[0])):
51
+ if self.is_ssh:
52
+ self.print(f"{args[0]} is unsupported over SSH")
53
+ return
54
+
55
+ subprocess.run([sys.executable, binary] + args[1:], stdout=self.stdout, stderr=subprocess.STDOUT,
56
+ stdin=self.stdin, text=True, env=self.env)
57
+ else:
58
+ self.print(f"Invalid command: {args[0]}")
59
+
60
+ def get_prompt(self):
61
+ return f"{NL}{self.cwd()}$ "
62
+
63
+ @staticmethod
64
+ def get_path(*paths: str):
65
+ path = os.path.abspath(os.path.join(ROOT_DIR, *paths))
66
+ return path if path.startswith(ROOT_DIR) else ROOT_DIR
67
+
68
+ def start(self):
69
+ os.chdir(self.get_path())
70
+ self.run_line("ver")
71
+
72
+ if not os.path.exists(self.get_path()):
73
+ self.print(f"bdsh: bdsh directory does not exist{NL}")
74
+ exit(1)
75
+
76
+ self.print(self.get_prompt())
77
+
78
+ buffer = []
79
+
80
+ while True:
81
+ try:
82
+ char = self.readchar()
83
+
84
+ if self.is_ssh:
85
+ self.print(char)
86
+
87
+ if char in {'\n', '\r'}:
88
+ if char == '\r':
89
+ self.print('\n')
90
+ self.run_line(''.join(buffer))
91
+ buffer.clear()
92
+ self.print(self.get_prompt())
93
+ elif char == '\x03': # ^C
94
+ buffer.clear()
95
+ self.print(self.get_prompt())
96
+ elif char == '\x7f': # backspace
97
+ if len(buffer) <= 0:
98
+ continue
99
+ self.print('\x08 \x08')
100
+ buffer.pop()
101
+ else:
102
+ buffer.append(char)
103
+
104
+ except KeyboardInterrupt:
105
+ buffer.clear()
106
+ self.print(self.get_prompt())
107
+ continue
108
+
109
+ except Exception as e:
110
+ buffer.clear()
111
+ self.print(f"bdsh: unhandled exception: {e}{NL}{self.get_prompt()}")
112
+ continue
@@ -0,0 +1,52 @@
1
+ Metadata-Version: 2.4
2
+ Name: bdsh
3
+ Version: 0.2.1
4
+ Summary: BadOS Dynamic Shell
5
+ Author-email: Logan Dhillon <dev@logandhillon.com>
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+
9
+ # BadOS Dynamic Shell (bdsh)
10
+
11
+ Read the docs at 🔗 [badtechnologies.github.io/bdsh](https://badtechnologies.github.io/bdsh).
12
+
13
+ ## Quick Install
14
+
15
+ Run the following command:
16
+
17
+ ```sh
18
+ curl -O https://raw.githubusercontent.com/badtechnologies/bdsh/main/install.py
19
+ python3 install.py
20
+ ```
21
+
22
+ After completing setup, bdsh should be good to go!
23
+
24
+
25
+ ## Installation (Manual)
26
+
27
+ 1. **Download the latest release**
28
+
29
+ Or, you can directly download `install.py` from the [repo](https://github.com/badtechnologies/bdsh).
30
+
31
+ > [!TIP]
32
+ > The only file needed to create a bdsh installation is `install.py`.<br>
33
+ > Running `install.py` generates, downloads, or installs everything else.
34
+
35
+ 2. **Setup bdsh:**
36
+
37
+ ```sh
38
+ python3 install.py
39
+ ```
40
+
41
+ Follow the on-screen instructions.
42
+
43
+ Once the `/bdsh` directory and your configs are prepared, you can start bdsh with `bdsh` to launch the interactive shell.
44
+
45
+ 3. **Launch bdsh:**
46
+
47
+ ```sh
48
+ bdsh
49
+ ```
50
+
51
+ > [!NOTE]
52
+ > This may change depending on how you created your launcher scripts.
@@ -0,0 +1,13 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/bdsh/__init__.py
4
+ src/bdsh/__main__.py
5
+ src/bdsh/__version__.py
6
+ src/bdsh/shell.py
7
+ src/bdsh.egg-info/PKG-INFO
8
+ src/bdsh.egg-info/SOURCES.txt
9
+ src/bdsh.egg-info/dependency_links.txt
10
+ src/bdsh.egg-info/entry_points.txt
11
+ src/bdsh.egg-info/top_level.txt
12
+ src/bdsh/command/__init__.py
13
+ src/bdsh/command/commands.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ bdsh = bdsh.__main__:main
@@ -0,0 +1 @@
1
+ bdsh