| 
1 | 1 | # -*- coding: utf-8 -*-  | 
2 |  | -import paramiko  | 
3 |  | -import threading  | 
4 |  | -import time  | 
5 |  | -import os  | 
6 |  | -from socket import timeout  | 
7 |  | -from assets.tasks import admin_file  | 
8 |  | -from channels.generic.websocket import WebsocketConsumer  | 
9 |  | -from assets.models import ServerAssets, AdminRecord  | 
10 |  | -from django.conf import settings  | 
 | 2 | +from utils.ssh import MySSH  | 
11 | 3 | from utils.crypt_pwd import CryptPwd  | 
12 |  | -from conf.logger import fort_logger  | 
 | 4 | +from assets.models import ServerAssets  | 
13 | 5 | 
 
  | 
14 | 6 | 
 
  | 
15 |  | -class MyThread(threading.Thread):  | 
16 |  | -    def __init__(self, chan):  | 
17 |  | -        super(MyThread, self).__init__()  | 
18 |  | -        self.chan = chan  | 
19 |  | -        self._stop_event = threading.Event()  | 
20 |  | -        self.start_time = time.time()  | 
21 |  | -        self.current_time = time.strftime(settings.TIME_FORMAT)  | 
22 |  | -        self.stdout = []  | 
23 |  | - | 
24 |  | -    def stop(self):  | 
25 |  | -        self._stop_event.set()  | 
26 |  | - | 
27 |  | -    def run(self):  | 
28 |  | -        while not self._stop_event.is_set() or not self.chan.chan.exit_status_ready():  | 
29 |  | -            time.sleep(0.1)  | 
30 |  | -            try:  | 
31 |  | -                data = self.chan.chan.recv(1024)  | 
32 |  | -                if data:  | 
33 |  | -                    str_data = data.decode('utf-8', 'ignore')  | 
34 |  | -                    self.chan.send(str_data)  | 
35 |  | -                    self.stdout.append([time.time() - self.start_time, 'o', str_data])  | 
36 |  | -            except timeout:  | 
37 |  | -                self.chan.send('\n由于长时间没有操作,连接已断开!', close=True)  | 
38 |  | -                self.stdout.append([time.time() - self.start_time, 'o', '\n由于长时间没有操作,连接已断开!'])  | 
39 |  | -                break  | 
40 |  | - | 
41 |  | -    def record(self):  | 
42 |  | -        record_path = os.path.join(settings.MEDIA_ROOT, 'admin_ssh_records', self.chan.scope['user'].username,  | 
43 |  | -                                   time.strftime('%Y-%m-%d'))  | 
44 |  | -        if not os.path.exists(record_path):  | 
45 |  | -            os.makedirs(record_path, exist_ok=True)  | 
46 |  | -        record_file_name = '{}.{}.cast'.format(self.chan.host_ip, time.strftime('%Y%m%d%H%M%S'))  | 
47 |  | -        record_file_path = os.path.join(record_path, record_file_name)  | 
48 |  | - | 
49 |  | -        header = {  | 
50 |  | -            "version": 2,  | 
51 |  | -            "width": self.chan.width,  | 
52 |  | -            "height": self.chan.height,  | 
53 |  | -            "timestamp": round(self.start_time),  | 
54 |  | -            "title": "Demo",  | 
55 |  | -            "env": {  | 
56 |  | -                "TERM": os.environ.get('TERM'),  | 
57 |  | -                "SHELL": os.environ.get('SHELL', '/bin/bash')  | 
58 |  | -            },  | 
59 |  | -        }  | 
60 |  | - | 
61 |  | -        admin_file.delay(record_file_path, self.stdout, header)  | 
62 |  | - | 
63 |  | -        login_status_time = time.time() - self.start_time  | 
64 |  | -        if login_status_time >= 60:  | 
65 |  | -            login_status_time = '{} m'.format(round(login_status_time / 60, 2))  | 
66 |  | -        elif login_status_time >= 3600:  | 
67 |  | -            login_status_time = '{} h'.format(round(login_status_time / 3660, 2))  | 
68 |  | -        else:  | 
69 |  | -            login_status_time = '{} s'.format(round(login_status_time))  | 
70 |  | - | 
71 |  | -        try:  | 
72 |  | -            AdminRecord.objects.create(  | 
73 |  | -                admin_login_user=self.chan.scope['user'],  | 
74 |  | -                admin_server=self.chan.host_ip,  | 
75 |  | -                admin_remote_ip=self.chan.remote_ip,  | 
76 |  | -                admin_start_time=self.current_time,  | 
77 |  | -                admin_login_status_time=login_status_time,  | 
78 |  | -                admin_record_file=record_file_path.split('media/')[1]  | 
79 |  | -            )  | 
80 |  | -        except Exception as e:  | 
81 |  | -            fort_logger.error('数据库添加用户操作记录失败,原因:{}'.format(e))  | 
82 |  | - | 
83 |  | - | 
84 |  | -class SSHConsumer(WebsocketConsumer):  | 
 | 7 | +class SSHConsumer(MySSH):  | 
85 | 8 |     def __init__(self, *args, **kwargs):  | 
86 | 9 |         super(SSHConsumer, self).__init__(*args, **kwargs)  | 
87 |  | -        self.ssh = paramiko.SSHClient()  | 
88 | 10 |         self.server = ServerAssets.objects.select_related('assets').get(id=self.scope['path'].split('/')[3])  | 
89 |  | -        self.host_ip = self.server.assets.asset_management_ip  | 
90 |  | -        self.width = 150  | 
91 |  | -        self.height = 30  | 
92 |  | -        self.t1 = MyThread(self)  | 
93 |  | -        self.remote_ip = self.scope['query_string'].decode('utf8')  | 
94 |  | -        self.chan = None  | 
95 |  | - | 
96 |  | -    def connect(self):  | 
97 |  | -        if self.scope["user"].is_anonymous:  | 
98 |  | -            self.close(code=1007)  | 
99 |  | -        else:  | 
100 |  | -            self.accept()  | 
101 |  | - | 
102 |  | -        username = self.server.username  | 
103 |  | -        try:  | 
104 |  | -            self.ssh.load_system_host_keys()  | 
105 |  | -            self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())  | 
106 |  | -            self.ssh.connect(self.host_ip, int(self.server.port), username,  | 
107 |  | -                             CryptPwd().decrypt_pwd(self.server.password), timeout=5)  | 
108 |  | -        except Exception as e:  | 
109 |  | -            fort_logger.error('用户{}通过webssh连接{}失败!原因:{}'.format(username, self.host_ip, e))  | 
110 |  | -            self.send('用户{}通过webssh连接{}失败!原因:{}'.format(username, self.host_ip, e))  | 
111 |  | -            self.close()  | 
112 |  | -        self.chan = self.ssh.invoke_shell(term='xterm', width=self.width, height=self.height)  | 
113 |  | -        # 设置如果3分钟没有任何输入,就断开连接  | 
114 |  | -        self.chan.settimeout(60 * 3)  | 
115 |  | -        self.t1.setDaemon(True)  | 
116 |  | -        self.t1.start()  | 
117 |  | - | 
118 |  | -    def receive(self, text_data=None, bytes_data=None):  | 
119 |  | -        self.chan.send(text_data)  | 
120 |  | - | 
121 |  | -    def disconnect(self, close_code):  | 
122 |  | -        try:  | 
123 |  | -            self.t1.record()  | 
124 |  | -            self.t1.stop()  | 
125 |  | -        finally:  | 
126 |  | -            self.ssh.close()  | 
 | 11 | +        self.ip = self.server.assets.asset_management_ip  | 
 | 12 | +        self.port = self.server.port  | 
 | 13 | +        self.username = self.server.username  | 
 | 14 | +        self.password = CryptPwd().decrypt_pwd(self.server.password)  | 
0 commit comments