InPanel 1.2.1__py3-none-any.whl
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.
- inpanel/__init__.py +29 -0
- inpanel/acme.py +289 -0
- inpanel/aliyuncs.py +269 -0
- inpanel/app.py +514 -0
- inpanel/apt.py +223 -0
- inpanel/base.py +200 -0
- inpanel/config.py +139 -0
- inpanel/data/config.ini +29 -0
- inpanel/data/history +5 -0
- inpanel/data/runlogs.ini +12 -0
- inpanel/data/update_info.ini +4 -0
- inpanel/dnf.py +225 -0
- inpanel/lib/__init__.py +9 -0
- inpanel/lib/async_process.py +98 -0
- inpanel/lib/filelock.py +82 -0
- inpanel/lib/magic.py +233 -0
- inpanel/lib/pxssh.py +310 -0
- inpanel/lib/pyDes.py +867 -0
- inpanel/mod/__init__.py +0 -0
- inpanel/mod/apt.py +316 -0
- inpanel/mod/certificate.py +268 -0
- inpanel/mod/config.py +372 -0
- inpanel/mod/cron.py +315 -0
- inpanel/mod/disk.py +322 -0
- inpanel/mod/dnf.py +239 -0
- inpanel/mod/file.py +722 -0
- inpanel/mod/firewall.py +199 -0
- inpanel/mod/firewall_base.py +137 -0
- inpanel/mod/firewall_firewalld.py +170 -0
- inpanel/mod/firewall_iptables.py +176 -0
- inpanel/mod/firewall_macos.py +213 -0
- inpanel/mod/firewall_ufw.py +128 -0
- inpanel/mod/ftp.py +231 -0
- inpanel/mod/httpd.py +1205 -0
- inpanel/mod/lighttpd.py +26 -0
- inpanel/mod/login.py +98 -0
- inpanel/mod/mysql.py +577 -0
- inpanel/mod/named.py +26 -0
- inpanel/mod/nginx.py +2327 -0
- inpanel/mod/package.py +33 -0
- inpanel/mod/package_apt.py +62 -0
- inpanel/mod/package_base.py +77 -0
- inpanel/mod/package_dnf.py +62 -0
- inpanel/mod/package_map.py +366 -0
- inpanel/mod/package_yum.py +64 -0
- inpanel/mod/php.py +289 -0
- inpanel/mod/process.py +291 -0
- inpanel/mod/proftpd.py +26 -0
- inpanel/mod/pureftpd.py +26 -0
- inpanel/mod/query.py +108 -0
- inpanel/mod/server.py +1319 -0
- inpanel/mod/service.py +262 -0
- inpanel/mod/setting.py +228 -0
- inpanel/mod/shell.py +78 -0
- inpanel/mod/ssh.py +280 -0
- inpanel/mod/system.py +220 -0
- inpanel/mod/task.py +1337 -0
- inpanel/mod/ufw.py +14 -0
- inpanel/mod/user.py +306 -0
- inpanel/mod/vsftpd.py +67 -0
- inpanel/mod/yum.py +243 -0
- inpanel/plugins/__init__.py +10 -0
- inpanel/plugins/__pycache__/__init__.cpython-313.pyc +0 -0
- inpanel/plugins/acme/static/index.html +10 -0
- inpanel/plugins/acme/static/index.js +13 -0
- inpanel/plugins/shadowsocks-libev/__pycache__/info.cpython-313.pyc +0 -0
- inpanel/plugins/shadowsocks-libev/info.py +73 -0
- inpanel/plugins/shadowsocks-libev/static/index.html +70 -0
- inpanel/plugins/shadowsocks-libev/static/index.js +18 -0
- inpanel/public/css/global.css +138 -0
- inpanel/public/favicon.ico +0 -0
- inpanel/public/images/alipay.jpg +0 -0
- inpanel/public/images/loading.gif +0 -0
- inpanel/public/images/weixin.jpg +0 -0
- inpanel/public/index.html +94 -0
- inpanel/public/js/controllers/controllers.js +566 -0
- inpanel/public/js/controllers/database.js +590 -0
- inpanel/public/js/controllers/ecs.js +624 -0
- inpanel/public/js/controllers/file.js +940 -0
- inpanel/public/js/controllers/plugins.js +105 -0
- inpanel/public/js/controllers/service.js +1460 -0
- inpanel/public/js/controllers/site.js +1241 -0
- inpanel/public/js/controllers/utils.js +2319 -0
- inpanel/public/js/core.js +221 -0
- inpanel/public/js/directives.js +784 -0
- inpanel/public/js/filters.js +395 -0
- inpanel/public/js/services.js +257 -0
- inpanel/public/lib/angular/1.0.2/angular-resource.min.js +10 -0
- inpanel/public/lib/angular/1.0.2/angular.min.js +158 -0
- inpanel/public/lib/bootstrap/css/bootstrap-theme.css +587 -0
- inpanel/public/lib/bootstrap/css/bootstrap-theme.css.map +1 -0
- inpanel/public/lib/bootstrap/css/bootstrap-theme.min.css +6 -0
- inpanel/public/lib/bootstrap/css/bootstrap-theme.min.css.map +1 -0
- inpanel/public/lib/bootstrap/css/bootstrap.css +6757 -0
- inpanel/public/lib/bootstrap/css/bootstrap.css.map +1 -0
- inpanel/public/lib/bootstrap/css/bootstrap.min.css +6 -0
- inpanel/public/lib/bootstrap/css/bootstrap.min.css.map +1 -0
- inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
- inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.svg +288 -0
- inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
- inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
- inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2 +0 -0
- inpanel/public/lib/bootstrap/img/glyphicons-halflings-white.png +0 -0
- inpanel/public/lib/bootstrap/img/glyphicons-halflings.png +0 -0
- inpanel/public/lib/bootstrap/js/bootstrap.js +2377 -0
- inpanel/public/lib/bootstrap/js/bootstrap.min.js +7 -0
- inpanel/public/lib/bootstrap/js/npm.js +13 -0
- inpanel/public/lib/codemirror/codemirror-compressed.js +1 -0
- inpanel/public/lib/codemirror/codemirror.css +173 -0
- inpanel/public/lib/jquery/jquery-1.12.4.min.js +5 -0
- inpanel/public/lib/md5/md5.js +379 -0
- inpanel/public/lib/md5/md5.min.js +1 -0
- inpanel/public/partials/database/index.html +172 -0
- inpanel/public/partials/database/mysql/dbedit.html +462 -0
- inpanel/public/partials/database/mysql/dbnew.html +348 -0
- inpanel/public/partials/database/mysql/useredit.html +310 -0
- inpanel/public/partials/database/mysql/usernew.html +97 -0
- inpanel/public/partials/directives/message.html +20 -0
- inpanel/public/partials/directives/navbar.html +25 -0
- inpanel/public/partials/directives/selector.html +57 -0
- inpanel/public/partials/directives/srvbase.html +72 -0
- inpanel/public/partials/directives/srvext.html +34 -0
- inpanel/public/partials/directives/srvfile.html +23 -0
- inpanel/public/partials/directives/srvinstall.html +34 -0
- inpanel/public/partials/directives/srvlog.html +23 -0
- inpanel/public/partials/directives/srvminiop.html +28 -0
- inpanel/public/partials/directives/srvuninstall.html +38 -0
- inpanel/public/partials/directives/srvupdate.html +30 -0
- inpanel/public/partials/ecs/account.html +156 -0
- inpanel/public/partials/ecs/ecs.html +198 -0
- inpanel/public/partials/ecs/index.html +40 -0
- inpanel/public/partials/ecs/setings.html +459 -0
- inpanel/public/partials/file/file.html +501 -0
- inpanel/public/partials/file/trash.html +95 -0
- inpanel/public/partials/ftp.html +36 -0
- inpanel/public/partials/log.html +83 -0
- inpanel/public/partials/login.html +79 -0
- inpanel/public/partials/logout.html +22 -0
- inpanel/public/partials/main.html +534 -0
- inpanel/public/partials/plugins/index.html +55 -0
- inpanel/public/partials/plugins/plugins.html +13 -0
- inpanel/public/partials/secure.html +13 -0
- inpanel/public/partials/service/apache.html +147 -0
- inpanel/public/partials/service/cron.html +71 -0
- inpanel/public/partials/service/index.html +293 -0
- inpanel/public/partials/service/iptables.html +40 -0
- inpanel/public/partials/service/lighttpd.html +63 -0
- inpanel/public/partials/service/mariadb.html +113 -0
- inpanel/public/partials/service/memcache.html +36 -0
- inpanel/public/partials/service/minio.html +44 -0
- inpanel/public/partials/service/mongodb.html +44 -0
- inpanel/public/partials/service/mysql.html +113 -0
- inpanel/public/partials/service/named.html +61 -0
- inpanel/public/partials/service/nginx.html +296 -0
- inpanel/public/partials/service/ntp.html +40 -0
- inpanel/public/partials/service/php.html +250 -0
- inpanel/public/partials/service/proftpd.html +59 -0
- inpanel/public/partials/service/pureftpd.html +59 -0
- inpanel/public/partials/service/redis.html +40 -0
- inpanel/public/partials/service/samba.html +58 -0
- inpanel/public/partials/service/sendmail.html +40 -0
- inpanel/public/partials/service/ssh.html +186 -0
- inpanel/public/partials/service/tomcat.html +65 -0
- inpanel/public/partials/service/vsftpd.html +195 -0
- inpanel/public/partials/setting.html +299 -0
- inpanel/public/partials/site/apache/site.html +277 -0
- inpanel/public/partials/site/index.html +344 -0
- inpanel/public/partials/site/nginx/site.html +558 -0
- inpanel/public/partials/sorry.html +19 -0
- inpanel/public/partials/storage/autofm.html +103 -0
- inpanel/public/partials/storage/backup.html +42 -0
- inpanel/public/partials/storage/index.html +360 -0
- inpanel/public/partials/storage/migrate.html +93 -0
- inpanel/public/partials/storage/movedata.html +98 -0
- inpanel/public/partials/storage/remote.html +77 -0
- inpanel/public/partials/utils/cron.html +486 -0
- inpanel/public/partials/utils/firewall.html +266 -0
- inpanel/public/partials/utils/index.html +193 -0
- inpanel/public/partials/utils/network.html +118 -0
- inpanel/public/partials/utils/process.html +239 -0
- inpanel/public/partials/utils/repository.html +373 -0
- inpanel/public/partials/utils/shell.html +28 -0
- inpanel/public/partials/utils/ssl.html +319 -0
- inpanel/public/partials/utils/time.html +109 -0
- inpanel/public/partials/utils/user.html +359 -0
- inpanel/public/robots.txt +2 -0
- inpanel/remote.py +109 -0
- inpanel/templates/file/preview.html +34 -0
- inpanel/templates/index.html +93 -0
- inpanel/utils.py +282 -0
- inpanel/web.py +1811 -0
- inpanel/yum.py +756 -0
- inpanel-1.2.1.dist-info/METADATA +399 -0
- inpanel-1.2.1.dist-info/RECORD +198 -0
- inpanel-1.2.1.dist-info/WHEEL +5 -0
- inpanel-1.2.1.dist-info/entry_points.txt +2 -0
- inpanel-1.2.1.dist-info/licenses/LICENSE +30 -0
- inpanel-1.2.1.dist-info/top_level.txt +1 -0
inpanel/mod/ssh.py
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2017-2026 Jackson Dou
|
|
5
|
+
# All rights reserved.
|
|
6
|
+
#
|
|
7
|
+
# InPanel is distributed under the terms of The New BSD License.
|
|
8
|
+
# The full license can be found in 'LICENSE'.
|
|
9
|
+
|
|
10
|
+
'''Module for ssh Management'''
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
import re
|
|
14
|
+
import shlex
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
import pexpect
|
|
18
|
+
|
|
19
|
+
SSHCFG = '/etc/ssh/sshd_config'
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def loadconfig(cfgfile=None, detail=False):
|
|
23
|
+
"""Read config file and parse config item to dict.
|
|
24
|
+
"""
|
|
25
|
+
if not cfgfile:
|
|
26
|
+
cfgfile = SSHCFG
|
|
27
|
+
|
|
28
|
+
settings = {}
|
|
29
|
+
with open(cfgfile, encoding='utf-8') as f:
|
|
30
|
+
for line_i, line in enumerate(f):
|
|
31
|
+
line = line.strip()
|
|
32
|
+
if not line or line.startswith('# '):
|
|
33
|
+
continue
|
|
34
|
+
|
|
35
|
+
# detect if it's commented
|
|
36
|
+
if line.startswith('#'):
|
|
37
|
+
line = line.strip('#')
|
|
38
|
+
commented = True
|
|
39
|
+
if not detail:
|
|
40
|
+
continue
|
|
41
|
+
else:
|
|
42
|
+
commented = False
|
|
43
|
+
|
|
44
|
+
fs = re.split(r'\s+', line, 1)
|
|
45
|
+
if len(fs) != 2:
|
|
46
|
+
continue
|
|
47
|
+
|
|
48
|
+
item = fs[0].strip()
|
|
49
|
+
value = fs[1].strip()
|
|
50
|
+
|
|
51
|
+
if item in settings:
|
|
52
|
+
if detail:
|
|
53
|
+
count = settings[item]['count']+1
|
|
54
|
+
if not commented:
|
|
55
|
+
settings[item] = detail and {
|
|
56
|
+
'file': cfgfile,
|
|
57
|
+
'line': line_i,
|
|
58
|
+
'value': value,
|
|
59
|
+
'commented': commented,
|
|
60
|
+
} or value
|
|
61
|
+
else:
|
|
62
|
+
count = 1
|
|
63
|
+
settings[item] = detail and {
|
|
64
|
+
'file': cfgfile,
|
|
65
|
+
'line': line_i,
|
|
66
|
+
'value': fs[1].strip(),
|
|
67
|
+
'commented': commented,
|
|
68
|
+
} or value
|
|
69
|
+
if detail:
|
|
70
|
+
settings[item]['count'] = count
|
|
71
|
+
|
|
72
|
+
return settings
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def cfg_get(item, detail=False, config=None):
|
|
76
|
+
"""Get value of a config item.
|
|
77
|
+
"""
|
|
78
|
+
if not config:
|
|
79
|
+
config = loadconfig(detail=detail)
|
|
80
|
+
if item in config:
|
|
81
|
+
return config[item]
|
|
82
|
+
else:
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def cfg_set(item, value, commented=False, config=None):
|
|
87
|
+
"""Set value of a config item.
|
|
88
|
+
"""
|
|
89
|
+
cfgfile = SSHCFG
|
|
90
|
+
v = cfg_get(item, detail=True, config=config)
|
|
91
|
+
|
|
92
|
+
if v:
|
|
93
|
+
# detect if value change
|
|
94
|
+
if v['commented'] == commented and v['value'] == value:
|
|
95
|
+
return True
|
|
96
|
+
|
|
97
|
+
# empty value should be commented
|
|
98
|
+
if value == '':
|
|
99
|
+
commented = True
|
|
100
|
+
|
|
101
|
+
# replace item in line
|
|
102
|
+
lines = []
|
|
103
|
+
with open(v['file'], encoding='utf-8') as f:
|
|
104
|
+
for line_i, line in enumerate(f):
|
|
105
|
+
if line_i == v['line']:
|
|
106
|
+
if not v['commented']:
|
|
107
|
+
if commented:
|
|
108
|
+
if v['count'] > 1:
|
|
109
|
+
# delete this line, just ignore it
|
|
110
|
+
pass
|
|
111
|
+
else:
|
|
112
|
+
# comment this line
|
|
113
|
+
lines.append('#%s %s\n' % (item, value))
|
|
114
|
+
else:
|
|
115
|
+
lines.append('%s %s\n' % (item, value))
|
|
116
|
+
else:
|
|
117
|
+
if commented:
|
|
118
|
+
# do not allow change comment value
|
|
119
|
+
lines.append(line)
|
|
120
|
+
pass
|
|
121
|
+
else:
|
|
122
|
+
# append a new line after comment line
|
|
123
|
+
lines.append(line)
|
|
124
|
+
lines.append('%s %s\n' % (item, value))
|
|
125
|
+
else:
|
|
126
|
+
lines.append(line)
|
|
127
|
+
with open(v['file'], 'w', encoding='utf-8') as f:
|
|
128
|
+
f.write(''.join(lines))
|
|
129
|
+
else:
|
|
130
|
+
# append to the end of file
|
|
131
|
+
with open(inifile, 'a', encoding='utf-8') as f:
|
|
132
|
+
f.write('\n%s%s = %s\n' % (commented and '#' or '', item, value))
|
|
133
|
+
|
|
134
|
+
return True
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def genkey(path, password=''):
|
|
138
|
+
"""Generate a ssh key pair.
|
|
139
|
+
"""
|
|
140
|
+
cmd = shlex.split('ssh-keygen -t rsa')
|
|
141
|
+
child = pexpect.spawn(cmd[0], cmd[1:])
|
|
142
|
+
i = child.expect(['Enter file in which to save the key', pexpect.EOF])
|
|
143
|
+
if i == 1:
|
|
144
|
+
if child.isalive():
|
|
145
|
+
child.wait()
|
|
146
|
+
return False
|
|
147
|
+
|
|
148
|
+
child.sendline(path)
|
|
149
|
+
i = child.expect(['Overwrite', 'Enter passphrase', pexpect.EOF])
|
|
150
|
+
if i == 0:
|
|
151
|
+
child.sendline('y')
|
|
152
|
+
i = child.expect(['Enter passphrase', pexpect.EOF])
|
|
153
|
+
if i == 1:
|
|
154
|
+
if child.isalive():
|
|
155
|
+
child.wait()
|
|
156
|
+
return False
|
|
157
|
+
elif i == 2:
|
|
158
|
+
if child.isalive():
|
|
159
|
+
child.wait()
|
|
160
|
+
return False
|
|
161
|
+
|
|
162
|
+
child.sendline(password)
|
|
163
|
+
i = child.expect(['Enter same passphrase', pexpect.EOF])
|
|
164
|
+
if i == 1:
|
|
165
|
+
if child.isalive():
|
|
166
|
+
child.wait()
|
|
167
|
+
return False
|
|
168
|
+
|
|
169
|
+
child.sendline(password)
|
|
170
|
+
child.expect(pexpect.EOF)
|
|
171
|
+
|
|
172
|
+
if child.isalive():
|
|
173
|
+
return child.wait() == 0
|
|
174
|
+
return True
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def chpasswd(path, oldpassword, newpassword):
|
|
178
|
+
"""Change password of a private key.
|
|
179
|
+
"""
|
|
180
|
+
if len(newpassword) != 0 and not len(newpassword) > 4:
|
|
181
|
+
return False
|
|
182
|
+
|
|
183
|
+
cmd = shlex.split('ssh-keygen -p')
|
|
184
|
+
child = pexpect.spawn(cmd[0], cmd[1:])
|
|
185
|
+
i = child.expect(['Enter file in which the key is', pexpect.EOF])
|
|
186
|
+
if i == 1:
|
|
187
|
+
if child.isalive():
|
|
188
|
+
child.wait()
|
|
189
|
+
return False
|
|
190
|
+
|
|
191
|
+
child.sendline(path)
|
|
192
|
+
i = child.expect(
|
|
193
|
+
['Enter old passphrase', 'Enter new passphrase', pexpect.EOF])
|
|
194
|
+
if i == 0:
|
|
195
|
+
child.sendline(oldpassword)
|
|
196
|
+
i = child.expect(
|
|
197
|
+
['Enter new passphrase', 'Bad passphrase', pexpect.EOF])
|
|
198
|
+
if i != 0:
|
|
199
|
+
if child.isalive():
|
|
200
|
+
child.wait()
|
|
201
|
+
return False
|
|
202
|
+
elif i == 2:
|
|
203
|
+
if child.isalive():
|
|
204
|
+
child.wait()
|
|
205
|
+
return False
|
|
206
|
+
|
|
207
|
+
child.sendline(newpassword)
|
|
208
|
+
i = child.expect(['Enter same passphrase again', pexpect.EOF])
|
|
209
|
+
if i == 1:
|
|
210
|
+
if child.isalive():
|
|
211
|
+
child.wait()
|
|
212
|
+
return False
|
|
213
|
+
|
|
214
|
+
child.sendline(newpassword)
|
|
215
|
+
child.expect(pexpect.EOF)
|
|
216
|
+
|
|
217
|
+
if child.isalive():
|
|
218
|
+
return child.wait() == 0
|
|
219
|
+
return True
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def web_handler(context):
|
|
223
|
+
action = context.get_argument('action', '')
|
|
224
|
+
|
|
225
|
+
if action == 'getsettings':
|
|
226
|
+
port = cfg_get('Port')
|
|
227
|
+
enable_pwdauth = cfg_get('PasswordAuthentication') == 'yes'
|
|
228
|
+
enable_pubkauth = cfg_get('PubkeyAuthentication') == 'yes'
|
|
229
|
+
subsystem = cfg_get('Subsystem')
|
|
230
|
+
enable_sftp = subsystem and 'sftp' in subsystem
|
|
231
|
+
pubkey_path = '/root/.ssh/sshkey_inpanel.pub'
|
|
232
|
+
prvkey_path = '/root/.ssh/sshkey_inpanel'
|
|
233
|
+
context.write({'code': 0, 'msg': '获取 SSH 服务配置信息成功!', 'data': {
|
|
234
|
+
'port': port,
|
|
235
|
+
'enable_pwdauth': enable_pwdauth,
|
|
236
|
+
'enable_pubkauth': enable_pubkauth,
|
|
237
|
+
'enable_sftp': enable_sftp,
|
|
238
|
+
'pubkey': Path(pubkey_path).is_file() and pubkey_path or '',
|
|
239
|
+
'prvkey': Path(prvkey_path).is_file() and prvkey_path or '',
|
|
240
|
+
}})
|
|
241
|
+
|
|
242
|
+
elif action == 'savesettings':
|
|
243
|
+
if context.config.get('runtime', 'mode') == 'demo':
|
|
244
|
+
context.write({'code': -1, 'msg': '演示模式不允许修改 SSH 服务设置!'})
|
|
245
|
+
return
|
|
246
|
+
|
|
247
|
+
port = context.get_argument('port', '')
|
|
248
|
+
if port:
|
|
249
|
+
cfg_set('Port', port)
|
|
250
|
+
enable_pwdauth = context.get_argument('enable_pwdauth', '')
|
|
251
|
+
if enable_pwdauth:
|
|
252
|
+
cfg_set('PasswordAuthentication', enable_pwdauth=='on' and 'yes' or 'no')
|
|
253
|
+
enable_pubkauth = context.get_argument('enable_pubkauth', '')
|
|
254
|
+
if enable_pubkauth:
|
|
255
|
+
if enable_pubkauth == 'on':
|
|
256
|
+
pubkey_path = context.get_argument('pubkey', '')
|
|
257
|
+
if not Path(pubkey_path).is_file():
|
|
258
|
+
context.write({'code': -1, 'msg': '公钥文件不存在!'})
|
|
259
|
+
return
|
|
260
|
+
cfg_set('PubkeyAuthentication', enable_pubkauth=='on' and 'yes' or 'no')
|
|
261
|
+
cfg_set('AuthorizedKeysFile', pubkey_path)
|
|
262
|
+
|
|
263
|
+
enable_sftp = context.get_argument('enable_sftp', '')
|
|
264
|
+
if enable_sftp:
|
|
265
|
+
cfg_set('Subsystem', 'sftp /usr/libexec/openssh/sftp-server', enable_sftp!='on')
|
|
266
|
+
context.write({'code': 0, 'msg': 'SSH 服务配置保存成功!'})
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
if __name__ == '__main__':
|
|
270
|
+
import pprint
|
|
271
|
+
pp = pprint.PrettyPrinter(indent=4)
|
|
272
|
+
|
|
273
|
+
# pp.pprint(loadconfig())
|
|
274
|
+
#print cfg_get('Port')
|
|
275
|
+
#print cfg_get('Subsystem', detail=True)
|
|
276
|
+
#print cfg_set('Protocol', '2', commented=False)
|
|
277
|
+
#print cfg_set('Subsystem', 'sftp\t/usr/libexec/openssh/sftp-server', commented=True)
|
|
278
|
+
|
|
279
|
+
#print genkey('/root/.ssh/sshkey_inpanel')
|
|
280
|
+
#print chpasswd('/root/.ssh/sshkey_inpanel', '', 'aaaaaa')
|
inpanel/mod/system.py
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2020-2026 Jackson Dou
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# InPanel is distributed under the terms of The New BSD License.
|
|
7
|
+
# The full license can be found in 'LICENSE'.
|
|
8
|
+
'''Module for System Detection and Information'''
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import shutil
|
|
12
|
+
from platform import mac_ver, platform, uname, win32_ver
|
|
13
|
+
from typing import Dict, Optional, Tuple
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_os_release() -> Dict[str, str]:
|
|
17
|
+
"""读取 /etc/os-release 文件,返回系统信息字典"""
|
|
18
|
+
info = {}
|
|
19
|
+
try:
|
|
20
|
+
with open("/etc/os-release", "r") as f:
|
|
21
|
+
for line in f:
|
|
22
|
+
if "=" in line:
|
|
23
|
+
k, v = line.strip().split("=", 1)
|
|
24
|
+
info[k] = v.strip('"')
|
|
25
|
+
except FileNotFoundError:
|
|
26
|
+
pass
|
|
27
|
+
return info
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
_os_release = get_os_release()
|
|
31
|
+
|
|
32
|
+
OS_ID = _os_release.get("ID", "")
|
|
33
|
+
OS_ID_LIKE = _os_release.get("ID_LIKE", "")
|
|
34
|
+
OS_VERSION_ID = _os_release.get("VERSION_ID", "")
|
|
35
|
+
OS_PRETTY_NAME = _os_release.get("PRETTY_NAME", "")
|
|
36
|
+
OS_NAME = _os_release.get("NAME", "")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_os_family() -> str:
|
|
40
|
+
"""获取操作系统家族:rhel 或 debian 或 darwin 或 windows"""
|
|
41
|
+
if OS_ID in ("almalinux", "rocky", "centos", "rhel", "fedora", "ol", "scientific", "centos-stream"):
|
|
42
|
+
return "rhel"
|
|
43
|
+
if OS_ID in ("debian", "ubuntu", "linuxmint", "pop", "elementary", "kali"):
|
|
44
|
+
return "debian"
|
|
45
|
+
if OS_ID_LIKE:
|
|
46
|
+
if "rhel" in OS_ID_LIKE:
|
|
47
|
+
return "rhel"
|
|
48
|
+
if "debian" in OS_ID_LIKE:
|
|
49
|
+
return "debian"
|
|
50
|
+
kernel_name, _, _, _, _, _ = uname()
|
|
51
|
+
if kernel_name == "Darwin":
|
|
52
|
+
return "darwin"
|
|
53
|
+
if kernel_name == "Windows":
|
|
54
|
+
return "windows"
|
|
55
|
+
return "unknown"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_os_id() -> str:
|
|
59
|
+
"""获取操作系统 ID"""
|
|
60
|
+
return OS_ID
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_os_version() -> str:
|
|
64
|
+
"""获取操作系统版本号(完整)"""
|
|
65
|
+
return OS_VERSION_ID
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_os_version_major() -> int:
|
|
69
|
+
"""获取操作系统主版本号(整数)"""
|
|
70
|
+
if OS_VERSION_ID:
|
|
71
|
+
try:
|
|
72
|
+
return int(OS_VERSION_ID.split(".")[0])
|
|
73
|
+
except (ValueError, IndexError):
|
|
74
|
+
pass
|
|
75
|
+
return 0
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def get_os_version_full() -> Tuple[int, int]:
|
|
79
|
+
"""获取操作系统版本号(主版本,次版本)"""
|
|
80
|
+
major = 0
|
|
81
|
+
minor = 0
|
|
82
|
+
if OS_VERSION_ID:
|
|
83
|
+
parts = OS_VERSION_ID.split(".")
|
|
84
|
+
try:
|
|
85
|
+
major = int(parts[0])
|
|
86
|
+
if len(parts) > 1:
|
|
87
|
+
minor = int(parts[1])
|
|
88
|
+
except ValueError:
|
|
89
|
+
pass
|
|
90
|
+
return (major, minor)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_os_title() -> str:
|
|
94
|
+
"""获取操作系统全称"""
|
|
95
|
+
if OS_PRETTY_NAME:
|
|
96
|
+
return OS_PRETTY_NAME
|
|
97
|
+
if OS_NAME:
|
|
98
|
+
if OS_VERSION_ID:
|
|
99
|
+
return f"{OS_NAME} {OS_VERSION_ID}"
|
|
100
|
+
return OS_NAME
|
|
101
|
+
kernel_name, _, _, _, _, _ = uname()
|
|
102
|
+
if kernel_name == "Darwin":
|
|
103
|
+
os_version, _, _ = mac_ver()
|
|
104
|
+
return f"macOS {os_version}"
|
|
105
|
+
if kernel_name == "Windows":
|
|
106
|
+
os_version, _, _ = win32_ver()
|
|
107
|
+
return f"Windows {os_version}"
|
|
108
|
+
return "Unknown"
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def get_os_name() -> str:
|
|
112
|
+
"""获取操作系统发行名称"""
|
|
113
|
+
if OS_ID:
|
|
114
|
+
return OS_ID.capitalize()
|
|
115
|
+
kernel_name, _, _, _, _, _ = uname()
|
|
116
|
+
if kernel_name == "Darwin":
|
|
117
|
+
return "macOS"
|
|
118
|
+
if kernel_name == "Windows":
|
|
119
|
+
return "Windows"
|
|
120
|
+
return "Unknown"
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def is_rhel_family() -> bool:
|
|
124
|
+
"""是否为 RHEL 家族系统"""
|
|
125
|
+
return get_os_family() == "rhel"
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def is_debian_family() -> bool:
|
|
129
|
+
"""是否为 Debian 家族系统"""
|
|
130
|
+
return get_os_family() == "debian"
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def is_darwin() -> bool:
|
|
134
|
+
"""是否为 macOS 系统"""
|
|
135
|
+
return get_os_family() == "darwin"
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def is_windows() -> bool:
|
|
139
|
+
"""是否为 Windows 系统"""
|
|
140
|
+
return get_os_family() == "windows"
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def compare_version(version_str: str) -> int:
|
|
144
|
+
"""
|
|
145
|
+
比较当前系统版本与指定版本
|
|
146
|
+
返回值: -1 (小于), 0 (等于), 1 (大于)
|
|
147
|
+
"""
|
|
148
|
+
current_major, current_minor = get_os_version_full()
|
|
149
|
+
parts = version_str.split(".")
|
|
150
|
+
try:
|
|
151
|
+
major = int(parts[0])
|
|
152
|
+
minor = int(parts[1]) if len(parts) > 1 else 0
|
|
153
|
+
except ValueError:
|
|
154
|
+
return 0
|
|
155
|
+
|
|
156
|
+
if current_major > major:
|
|
157
|
+
return 1
|
|
158
|
+
elif current_major < major:
|
|
159
|
+
return -1
|
|
160
|
+
else:
|
|
161
|
+
if current_minor > minor:
|
|
162
|
+
return 1
|
|
163
|
+
elif current_minor < minor:
|
|
164
|
+
return -1
|
|
165
|
+
return 0
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def has_package_manager() -> bool:
|
|
169
|
+
"""检查系统是否有包管理器"""
|
|
170
|
+
return any([
|
|
171
|
+
shutil.which("yum"),
|
|
172
|
+
shutil.which("dnf"),
|
|
173
|
+
shutil.which("apt"),
|
|
174
|
+
shutil.which("zypper"),
|
|
175
|
+
shutil.which("pacman"),
|
|
176
|
+
])
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def get_system_info() -> Dict[str, str]:
|
|
180
|
+
"""返回完整的系统信息字典"""
|
|
181
|
+
kernel_name, hostname, kernel_release, kernel_version, machine, processor = uname()
|
|
182
|
+
return {
|
|
183
|
+
'os_title': get_os_title(),
|
|
184
|
+
'os_name': get_os_name(),
|
|
185
|
+
'os_version': get_os_version(),
|
|
186
|
+
'os_versint': str(get_os_version_major()),
|
|
187
|
+
'os_platform': platform(),
|
|
188
|
+
'os_family': get_os_family(),
|
|
189
|
+
'os_id': get_os_id(),
|
|
190
|
+
'hostname': hostname,
|
|
191
|
+
'kernel_name': kernel_name,
|
|
192
|
+
'kernel_release': kernel_release,
|
|
193
|
+
'kernel_version': kernel_version,
|
|
194
|
+
'machine': machine,
|
|
195
|
+
'processor': processor,
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
__all__ = [
|
|
200
|
+
'get_os_release',
|
|
201
|
+
'OS_ID',
|
|
202
|
+
'OS_ID_LIKE',
|
|
203
|
+
'OS_VERSION_ID',
|
|
204
|
+
'OS_PRETTY_NAME',
|
|
205
|
+
'OS_NAME',
|
|
206
|
+
'get_os_family',
|
|
207
|
+
'get_os_id',
|
|
208
|
+
'get_os_version',
|
|
209
|
+
'get_os_version_major',
|
|
210
|
+
'get_os_version_full',
|
|
211
|
+
'get_os_title',
|
|
212
|
+
'get_os_name',
|
|
213
|
+
'is_rhel_family',
|
|
214
|
+
'is_debian_family',
|
|
215
|
+
'is_darwin',
|
|
216
|
+
'is_windows',
|
|
217
|
+
'compare_version',
|
|
218
|
+
'has_package_manager',
|
|
219
|
+
'get_system_info',
|
|
220
|
+
]
|