BinaryONe commited on
Commit
7095e83
·
1 Parent(s): 1feba88
WebSSH/AppHandler.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import tornado.web
3
+ import subprocess
4
+
5
+ # New handler for your custom page
6
+ class AppHandler(tornado.web.RequestHandler):
7
+ HandlerPath = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),'WebSSH', 'templates')
8
+ template_folder = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'WebSSH', 'templates')
9
+
10
+ def get(self):
11
+ self.render(os.path.join(self.template_folder, 'index.html'))
12
+
13
+ def function_two(self):
14
+ # Your logic for function one
15
+ self.write("Function One Called")
16
+
17
+ def run_commands(self):
18
+ data = json.loads(self.request.body)
19
+ command = data.get("command")
20
+ if command:
21
+ try:
22
+ result = subprocess.run(command, shell=True, capture_output=True, text=True)
23
+ return(result.stdout)
24
+ except Exception as e:
25
+ return(str(e))
26
+ else:
27
+ return("No command provided")
28
+
29
+ def post(self):
30
+ username = self.get_argument("username")
31
+ password = self.get_argument("password")
32
+
33
+ # Check if the user already exists
34
+ user_exists = subprocess.run(["id", "-u", username], capture_output=True)
35
+ if user_exists.returncode == 0:
36
+ # User exists, read the existing SSH key
37
+ ssh_dir = f"/home/{username}/.ssh"
38
+ private_key_path = f"{ssh_dir}/id_rsa"
39
+ if os.path.exists(private_key_path):
40
+ with open(private_key_path, "r") as file:
41
+ private_key = file.read()
42
+ else:
43
+ self.set_status(404)
44
+ self.write("SSH key not found for existing user.")
45
+ return
46
+ else:
47
+ """
48
+ # Create the user directory and .ssh directory manually
49
+ user_home = f"/home/{username}"
50
+ ssh_dir = f"{user_home}/.ssh"
51
+ os.makedirs(ssh_dir, exist_ok=True)
52
+
53
+ # Generate SSH key pair for the new user
54
+ subprocess.run(["ssh-keygen", "-t", "rsa", "-b", "2048", "-f", f"{ssh_dir}/id_rsa", "-N", ""])
55
+
56
+ # Read the private key
57
+ with open(f"{ssh_dir}/id_rsa", "r") as file:
58
+ private_key = file.read()
59
+ """
60
+ self.set_status(404)
61
+ self.write("SSH key not found for existing user.")
62
+ return
63
+
64
+ # Return the private key to the user
65
+ self.set_header('Content-Type', 'application/octet-stream')
66
+ self.set_header('Content-Disposition', f'attachment; filename=id_rsa')
67
+ self.write(private_key)
68
+
WebSSH/__main__.py CHANGED
@@ -9,6 +9,7 @@ from tornado.options import define, options
9
  from webssh.handler import IndexHandler, WsockHandler, NotFoundHandler
10
  from .Fonts import Font, get_font_filename, base_dir, font_dirs, max_body_size
11
  from .Tools import get_ssl_context, get_server_settings, check_encoding_setting, print_version
 
12
 
13
  logging.getLogger("tornado.access").setLevel(logging.DEBUG)
14
  logging.getLogger("tornado.application").setLevel(logging.DEBUG)
@@ -41,7 +42,7 @@ separated by comma;
41
  '*': wildcard policy, matches any domain, allowed in debug mode only.""",
42
  )
43
  define('wpintvl', type=float, default=30, help='Websocket ping interval')
44
- define('timeout', type=float, default=60, help='SSH connection timeout')
45
  define('delay', type=float, default=60, help='The delay to call recycle_worker')
46
  define('maxconn', type=int, default=4, help='Maximum live connections (ssh sessions) per client')
47
  define('font', default='', help='custom font filename')
@@ -55,55 +56,6 @@ Example: --encoding='utf-8' to solve the problem with some switches&routers""",
55
 
56
  define('version', type=bool, help='Show version information',callback=print_version)
57
 
58
- # New handler for your custom page
59
- class AppHandler(tornado.web.RequestHandler):
60
- # Define the path to the templates directory
61
- HandlerPath = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),'WebSSH', 'templates')
62
- template_folder = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'WebSSH', 'templates')
63
-
64
- def get(self):
65
- self.render(os.path.join(self.template_folder, 'index.html'))
66
-
67
- def post(self):
68
- username = self.get_argument("username")
69
- password = self.get_argument("password")
70
-
71
- # Check if the user already exists
72
- user_exists = subprocess.run(["id", "-u", username], capture_output=True)
73
- if user_exists.returncode == 0:
74
- # User exists, read the existing SSH key
75
- ssh_dir = f"/home/{username}/.ssh"
76
- private_key_path = f"{ssh_dir}/id_rsa"
77
- if os.path.exists(private_key_path):
78
- with open(private_key_path, "r") as file:
79
- private_key = file.read()
80
- else:
81
- self.set_status(404)
82
- self.write("SSH key not found for existing user.")
83
- return
84
- else:
85
- """
86
- # Create the user directory and .ssh directory manually
87
- user_home = f"/home/{username}"
88
- ssh_dir = f"{user_home}/.ssh"
89
- os.makedirs(ssh_dir, exist_ok=True)
90
-
91
- # Generate SSH key pair for the new user
92
- subprocess.run(["ssh-keygen", "-t", "rsa", "-b", "2048", "-f", f"{ssh_dir}/id_rsa", "-N", ""])
93
-
94
- # Read the private key
95
- with open(f"{ssh_dir}/id_rsa", "r") as file:
96
- private_key = file.read()
97
- """
98
- self.set_status(404)
99
- self.write("SSH key not found for existing user.")
100
- return
101
-
102
- # Return the private key to the user
103
- self.set_header('Content-Type', 'application/octet-stream')
104
- self.set_header('Content-Disposition', f'attachment; filename=id_rsa')
105
- self.write(private_key)
106
-
107
 
108
  def make_app(loop):
109
  # Set SSH host key policy
@@ -125,6 +77,8 @@ def make_app(loop):
125
  (r'/', IndexHandler, dict(loop=loop, policy=policy, host_keys_settings=host_keys_settings)),
126
  (r'/ws', WsockHandler, dict(loop=loop)),
127
  (r'/app', AppHandler), # Route for your new page
 
 
128
  ],
129
  xsrf_cookies=options.xsrf,
130
  debug=options.debug,
 
9
  from webssh.handler import IndexHandler, WsockHandler, NotFoundHandler
10
  from .Fonts import Font, get_font_filename, base_dir, font_dirs, max_body_size
11
  from .Tools import get_ssl_context, get_server_settings, check_encoding_setting, print_version
12
+ from .AppHandler import AppHandler
13
 
14
  logging.getLogger("tornado.access").setLevel(logging.DEBUG)
15
  logging.getLogger("tornado.application").setLevel(logging.DEBUG)
 
42
  '*': wildcard policy, matches any domain, allowed in debug mode only.""",
43
  )
44
  define('wpintvl', type=float, default=30, help='Websocket ping interval')
45
+ define('timeout', type=float, default=20, help='SSH connection timeout')
46
  define('delay', type=float, default=60, help='The delay to call recycle_worker')
47
  define('maxconn', type=int, default=4, help='Maximum live connections (ssh sessions) per client')
48
  define('font', default='', help='custom font filename')
 
56
 
57
  define('version', type=bool, help='Show version information',callback=print_version)
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
  def make_app(loop):
61
  # Set SSH host key policy
 
77
  (r'/', IndexHandler, dict(loop=loop, policy=policy, host_keys_settings=host_keys_settings)),
78
  (r'/ws', WsockHandler, dict(loop=loop)),
79
  (r'/app', AppHandler), # Route for your new page
80
+ (r"/commands", AppHandler, dict(method="run_commands")),
81
+ (r"/function_two", AppHandler, dict(method="function_two")),
82
  ],
83
  xsrf_cookies=options.xsrf,
84
  debug=options.debug,
WebSSH/static/js/AppHandler.js ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function run_commands() {
2
+ const command = document.getElementById('command').value;
3
+ fetch('/run_commands', {
4
+ method: 'POST',
5
+ headers: {
6
+ 'Content-Type': 'application/json'
7
+ },
8
+ body: JSON.stringify({ command: command })
9
+ })
10
+ .then(response => response.text())
11
+ .then(data => {
12
+ console.log(data);
13
+ });
14
+ }
15
+
16
+ function callFunctionTwo() {
17
+ fetch('/function_two', {
18
+ method: 'POST'
19
+ })
20
+ .then(response => response.text())
21
+ .then(data => {
22
+ console.log(data);
23
+ });
24
+ }
WebSSH/templates/index.html CHANGED
@@ -2,19 +2,74 @@
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
5
- <title> WebSSH </title>
6
  <link href="static/img/favicon.png" rel="icon" type="image/png">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  </head>
8
  <body>
9
  <div class="container">
10
  <h1>Create New User</h1>
11
- <form action="/app" method="post">
12
- <label for="username">Username:</label>
13
- <input type="text" id="username" name="username" required><br>
14
- <label for="password">Password:</label>
15
- <input type="password" id="password" name="password" required><br>
16
- <button type="submit">Create User</button>
 
 
 
 
 
 
 
17
  </form>
 
 
 
 
 
18
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </body>
20
  </html>
 
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
5
+ <title>WebSSH</title>
6
  <link href="static/img/favicon.png" rel="icon" type="image/png">
7
+ <script src="static/js/AppHandler.js" type="text/javascript"></script>
8
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" rel="stylesheet">
9
+ <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
10
+ <style>
11
+ body {
12
+ background-color: #f8f9fa;
13
+ display: flex;
14
+ justify-content: center;
15
+ align-items: center;
16
+ height: 100vh;
17
+ }
18
+ .container {
19
+ background-color: #ffffff;
20
+ padding: 30px;
21
+ border-radius: 10px;
22
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
23
+ }
24
+ .error-popup {
25
+ display: none;
26
+ color: #721c24;
27
+ background-color: #f8d7da;
28
+ border-color: #f5c6cb;
29
+ padding: 10px;
30
+ margin-bottom: 15px;
31
+ border: 1px solid transparent;
32
+ border-radius: 5px;
33
+ }
34
+ </style>
35
  </head>
36
  <body>
37
  <div class="container">
38
  <h1>Create New User</h1>
39
+ <div id="error-popup" class="error-popup">
40
+ <i class="fas fa-exclamation-circle"></i> Incorrect password. Please try again.
41
+ </div>
42
+ <form id="user-form" action="/app" method="post">
43
+ <div class="form-group">
44
+ <label for="username">Username:</label>
45
+ <input type="text" id="username" name="username" class="form-control" required>
46
+ </div>
47
+ <div class="form-group">
48
+ <label for="password">Password:</label>
49
+ <input type="password" id="password" name="password" class="form-control" required>
50
+ </div>
51
+ <button type="submit" class="btn btn-primary">Create User</button>
52
  </form>
53
+ <div class="form-group">
54
+ <label for="command">Command:</label>
55
+ <input type="text" id="command" name="command" class="form-control" required>
56
+ </div>
57
+ <button type="button" id="execute-button" class="btn btn-success" onclick="run_commands()">Execute</button>
58
  </div>
59
+
60
+ <script>
61
+ document.getElementById('user-form').addEventListener('submit', function(event) {
62
+ event.preventDefault();
63
+ var username = document.getElementById('username').value;
64
+ var password = document.getElementById('password').value;
65
+
66
+ // Simulate password check (replace with actual validation logic)
67
+ if (password !== 'correct_password') {
68
+ document.getElementById('error-popup').style.display = 'block';
69
+ } else {
70
+ this.submit();
71
+ }
72
+ });
73
+ </script>
74
  </body>
75
  </html>