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 +52 -0
- bdsh-0.2.1/README.md +44 -0
- bdsh-0.2.1/pyproject.toml +22 -0
- bdsh-0.2.1/setup.cfg +4 -0
- bdsh-0.2.1/src/bdsh/__init__.py +3 -0
- bdsh-0.2.1/src/bdsh/__main__.py +15 -0
- bdsh-0.2.1/src/bdsh/__version__.py +1 -0
- bdsh-0.2.1/src/bdsh/command/__init__.py +32 -0
- bdsh-0.2.1/src/bdsh/command/commands.py +110 -0
- bdsh-0.2.1/src/bdsh/shell.py +112 -0
- bdsh-0.2.1/src/bdsh.egg-info/PKG-INFO +52 -0
- bdsh-0.2.1/src/bdsh.egg-info/SOURCES.txt +13 -0
- bdsh-0.2.1/src/bdsh.egg-info/dependency_links.txt +1 -0
- bdsh-0.2.1/src/bdsh.egg-info/entry_points.txt +2 -0
- bdsh-0.2.1/src/bdsh.egg-info/top_level.txt +1 -0
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 @@
|
|
|
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 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bdsh
|