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/ufw.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
|
|
9
|
+
'''Module for UFW (Uncomplicated Firewall) Management'''
|
|
10
|
+
|
|
11
|
+
from .firewall_ufw import UfwPM
|
|
12
|
+
|
|
13
|
+
if __name__ == '__main__':
|
|
14
|
+
print('Module for UFW Management')
|
inpanel/mod/user.py
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2017-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
|
+
|
|
9
|
+
'''Module for system user management.'''
|
|
10
|
+
|
|
11
|
+
import grp
|
|
12
|
+
import pwd
|
|
13
|
+
import shlex
|
|
14
|
+
import subprocess
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
import pexpect
|
|
18
|
+
|
|
19
|
+
from ..base import kernel_name
|
|
20
|
+
|
|
21
|
+
def listuser(fullinfo=True):
|
|
22
|
+
if not fullinfo:
|
|
23
|
+
return [pw.pw_name for pw in pwd.getpwall()]
|
|
24
|
+
|
|
25
|
+
locks = {}
|
|
26
|
+
if kernel_name == 'Linux':
|
|
27
|
+
# get lock status from /etc/shadow
|
|
28
|
+
with open('/etc/shadow', encoding='utf-8') as f:
|
|
29
|
+
for line in f:
|
|
30
|
+
fields = line.split(':', 2)
|
|
31
|
+
locks[fields[0]] = fields[1].startswith('!')
|
|
32
|
+
|
|
33
|
+
users = pwd.getpwall()
|
|
34
|
+
for i, user in enumerate(users):
|
|
35
|
+
users[i] = dict((name, getattr(user, name))
|
|
36
|
+
for name in dir(user)
|
|
37
|
+
if not name.startswith('__')
|
|
38
|
+
and name not in ('count', 'index'))
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
gname = grp.getgrgid(user.pw_gid).gr_name
|
|
42
|
+
except:
|
|
43
|
+
gname = ''
|
|
44
|
+
|
|
45
|
+
users[i]['pw_gname'] = gname
|
|
46
|
+
if user.pw_name in locks:
|
|
47
|
+
users[i]['lock'] = locks[user.pw_name]
|
|
48
|
+
else:
|
|
49
|
+
users[i]['lock'] = False
|
|
50
|
+
return users
|
|
51
|
+
|
|
52
|
+
def passwd(username, password):
|
|
53
|
+
try:
|
|
54
|
+
cmd = shlex.split('passwd \'%s\'' % username)
|
|
55
|
+
except:
|
|
56
|
+
return False
|
|
57
|
+
child = pexpect.spawn(cmd[0], cmd[1:])
|
|
58
|
+
i = child.expect(['New password', 'Unknown user name'])
|
|
59
|
+
if i == 1:
|
|
60
|
+
if child.isalive():
|
|
61
|
+
child.wait()
|
|
62
|
+
return False
|
|
63
|
+
child.sendline(password)
|
|
64
|
+
child.expect('Retype new password')
|
|
65
|
+
child.sendline(password)
|
|
66
|
+
i = child.expect(['updated successfully', pexpect.EOF])
|
|
67
|
+
if child.isalive():
|
|
68
|
+
child.wait()
|
|
69
|
+
return i == 0
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def useradd(username, options):
|
|
73
|
+
# command like: useradd -c 'New User' -g newgroup -s /bin/bash -m newuser
|
|
74
|
+
cmd = ['useradd']
|
|
75
|
+
if 'pw_gname' in options and options['pw_gname']:
|
|
76
|
+
cmd.extend(['-g', options['pw_gname']])
|
|
77
|
+
if 'pw_gecos' in options:
|
|
78
|
+
cmd.extend(['-c', options['pw_gecos']])
|
|
79
|
+
if 'pw_shell' in options:
|
|
80
|
+
cmd.extend(['-s', options['pw_shell']])
|
|
81
|
+
if 'createhome' in options and options['createhome']:
|
|
82
|
+
cmd.append('-m')
|
|
83
|
+
else:
|
|
84
|
+
cmd.append('-M')
|
|
85
|
+
cmd.append(username)
|
|
86
|
+
p = subprocess.Popen(cmd,
|
|
87
|
+
stdout=subprocess.PIPE,
|
|
88
|
+
stderr=subprocess.PIPE,
|
|
89
|
+
close_fds=True)
|
|
90
|
+
p.stdout.read()
|
|
91
|
+
p.stderr.read()
|
|
92
|
+
if p.wait() != 0:
|
|
93
|
+
return False
|
|
94
|
+
|
|
95
|
+
# check if need to lock/unlock the new account
|
|
96
|
+
if 'lock' in options and options['lock']:
|
|
97
|
+
if not usermod(username, {'lock': options['lock']}):
|
|
98
|
+
return False
|
|
99
|
+
|
|
100
|
+
# check if need to set passwd
|
|
101
|
+
if 'pw_passwd' in options:
|
|
102
|
+
if not passwd(username, options['pw_passwd']):
|
|
103
|
+
return False
|
|
104
|
+
|
|
105
|
+
return True
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def usermod(username, options):
|
|
109
|
+
user = pwd.getpwnam(username)
|
|
110
|
+
# command like: usermod -c 'I am root' -g root -d /root/ -s /bin/bash -U root
|
|
111
|
+
cmd = ['usermod']
|
|
112
|
+
if 'pw_gname' in options:
|
|
113
|
+
cmd.extend(['-g', options['pw_gname']])
|
|
114
|
+
if 'pw_gecos' in options and options['pw_gecos'] != user.pw_gecos:
|
|
115
|
+
cmd.extend(['-c', options['pw_gecos']])
|
|
116
|
+
if 'pw_dir' in options and options['pw_dir'] != user.pw_dir:
|
|
117
|
+
cmd.extend(['-d', options['pw_dir']])
|
|
118
|
+
if 'pw_shell' in options and options['pw_shell'] != user.pw_shell:
|
|
119
|
+
cmd.extend(['-s', options['pw_shell']])
|
|
120
|
+
if 'lock' in options and options['lock']:
|
|
121
|
+
cmd.append('-L')
|
|
122
|
+
else:
|
|
123
|
+
cmd.append('-U')
|
|
124
|
+
cmd.append(username)
|
|
125
|
+
if len(cmd) > 2:
|
|
126
|
+
p = subprocess.Popen(cmd,
|
|
127
|
+
stdout=subprocess.PIPE,
|
|
128
|
+
stderr=subprocess.PIPE,
|
|
129
|
+
close_fds=True)
|
|
130
|
+
p.stdout.read()
|
|
131
|
+
msg = p.stderr.read()
|
|
132
|
+
if p.wait() != 0:
|
|
133
|
+
if not 'no changes' in msg:
|
|
134
|
+
return False
|
|
135
|
+
|
|
136
|
+
# check if need to change passwd
|
|
137
|
+
if 'pw_passwd' in options:
|
|
138
|
+
if not passwd(username, options['pw_passwd']):
|
|
139
|
+
return False
|
|
140
|
+
|
|
141
|
+
return True
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def userdel(username):
|
|
145
|
+
p = subprocess.Popen(['userdel', username],
|
|
146
|
+
stdout=subprocess.PIPE,
|
|
147
|
+
stderr=subprocess.PIPE,
|
|
148
|
+
close_fds=True)
|
|
149
|
+
p.stdout.read()
|
|
150
|
+
p.stderr.read()
|
|
151
|
+
return p.wait() == 0
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def listgroup(fullinfo=True):
|
|
155
|
+
if fullinfo:
|
|
156
|
+
groups = grp.getgrall()
|
|
157
|
+
for i, group in enumerate(groups):
|
|
158
|
+
groups[i] = dict((name, getattr(group, name))
|
|
159
|
+
for name in dir(group)
|
|
160
|
+
if not name.startswith('__')
|
|
161
|
+
and name not in ('count', 'index'))
|
|
162
|
+
else:
|
|
163
|
+
groups = [gr.gr_name for gr in grp.getgrall()]
|
|
164
|
+
return groups
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def groupadd(groupname):
|
|
168
|
+
p = subprocess.Popen(['groupadd', groupname],
|
|
169
|
+
stdout=subprocess.PIPE,
|
|
170
|
+
stderr=subprocess.PIPE,
|
|
171
|
+
close_fds=True)
|
|
172
|
+
p.stdout.read()
|
|
173
|
+
p.stderr.read()
|
|
174
|
+
return p.wait() == 0
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def groupmod(groupname, newgroupname):
|
|
178
|
+
p = subprocess.Popen(['groupmod', '-n', newgroupname, groupname],
|
|
179
|
+
stdout=subprocess.PIPE,
|
|
180
|
+
stderr=subprocess.PIPE,
|
|
181
|
+
close_fds=True)
|
|
182
|
+
p.stdout.read()
|
|
183
|
+
p.stderr.read()
|
|
184
|
+
return p.wait() == 0
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def groupdel(groupname):
|
|
188
|
+
p = subprocess.Popen(['groupdel', groupname],
|
|
189
|
+
stdout=subprocess.PIPE,
|
|
190
|
+
stderr=subprocess.PIPE,
|
|
191
|
+
close_fds=True)
|
|
192
|
+
p.stdout.read()
|
|
193
|
+
p.stderr.read()
|
|
194
|
+
return p.wait() == 0
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def groupmems(groupname, option, mem):
|
|
198
|
+
cmd = ['groupmems', '-g', groupname]
|
|
199
|
+
if option == 'add':
|
|
200
|
+
cmd.extend(['-a', mem])
|
|
201
|
+
elif option == 'del':
|
|
202
|
+
cmd.extend(['-d', mem])
|
|
203
|
+
p = subprocess.Popen(cmd,
|
|
204
|
+
stdout=subprocess.PIPE,
|
|
205
|
+
stderr=subprocess.PIPE,
|
|
206
|
+
close_fds=True)
|
|
207
|
+
p.stdout.read()
|
|
208
|
+
p.stderr.read()
|
|
209
|
+
return p.wait() == 0
|
|
210
|
+
|
|
211
|
+
def web_handler(context):
|
|
212
|
+
action = context.get_argument('action', '')
|
|
213
|
+
|
|
214
|
+
if action == 'listuser':
|
|
215
|
+
fullinfo = context.get_argument('fullinfo', 'on')
|
|
216
|
+
context.write({'code': 0, 'msg': '成功获取用户列表!', 'data': listuser(fullinfo=='on')})
|
|
217
|
+
|
|
218
|
+
elif action == 'listgroup':
|
|
219
|
+
fullinfo = context.get_argument('fullinfo', 'on')
|
|
220
|
+
context.write({'code': 0, 'msg': '成功获取用户组列表!', 'data': listgroup(fullinfo=='on')})
|
|
221
|
+
|
|
222
|
+
elif action in ('useradd', 'usermod'):
|
|
223
|
+
if context.config.get('runtime', 'mode') == 'demo':
|
|
224
|
+
context.write({'code': -1, 'msg': '演示模式不允许添加和修改用户!'})
|
|
225
|
+
return
|
|
226
|
+
|
|
227
|
+
pw_name = context.get_argument('pw_name', '')
|
|
228
|
+
pw_gecos = context.get_argument('pw_gecos', '')
|
|
229
|
+
pw_gname = context.get_argument('pw_gname', '')
|
|
230
|
+
pw_dir = context.get_argument('pw_dir', '')
|
|
231
|
+
pw_shell = context.get_argument('pw_shell', '')
|
|
232
|
+
pw_passwd = context.get_argument('pw_passwd', '')
|
|
233
|
+
pw_passwdc = context.get_argument('pw_passwdc', '')
|
|
234
|
+
lock = context.get_argument('lock', '')
|
|
235
|
+
lock = (lock == 'on') and True or False
|
|
236
|
+
|
|
237
|
+
if pw_passwd != pw_passwdc:
|
|
238
|
+
context.write({'code': -1, 'msg': '两次输入的密码不一致!'})
|
|
239
|
+
return
|
|
240
|
+
|
|
241
|
+
options = {
|
|
242
|
+
'pw_gecos': pw_gecos,
|
|
243
|
+
'pw_gname': pw_gname,
|
|
244
|
+
'pw_dir': pw_dir,
|
|
245
|
+
'pw_shell': pw_shell,
|
|
246
|
+
'lock': lock
|
|
247
|
+
}
|
|
248
|
+
if len(pw_passwd) > 0:
|
|
249
|
+
options['pw_passwd'] = pw_passwd
|
|
250
|
+
|
|
251
|
+
if action == 'useradd':
|
|
252
|
+
createhome = context.get_argument('createhome', '')
|
|
253
|
+
createhome = (createhome == 'on') and True or False
|
|
254
|
+
options['createhome'] = createhome
|
|
255
|
+
if useradd(pw_name, options):
|
|
256
|
+
context.write({'code': 0, 'msg': '用户添加成功!'})
|
|
257
|
+
else:
|
|
258
|
+
context.write({'code': -1, 'msg': '用户添加失败!'})
|
|
259
|
+
elif action == 'usermod':
|
|
260
|
+
if usermod(pw_name, options):
|
|
261
|
+
context.write({'code': 0, 'msg': '用户修改成功!'})
|
|
262
|
+
else:
|
|
263
|
+
context.write({'code': -1, 'msg': '用户修改失败!'})
|
|
264
|
+
|
|
265
|
+
elif action == 'userdel':
|
|
266
|
+
if context.config.get('runtime', 'mode') == 'demo':
|
|
267
|
+
context.write({'code': -1, 'msg': '演示模式不允许删除用户!'})
|
|
268
|
+
return
|
|
269
|
+
|
|
270
|
+
pw_name = context.get_argument('pw_name', '')
|
|
271
|
+
if userdel(pw_name):
|
|
272
|
+
context.write({'code': 0, 'msg': '用户删除成功!'})
|
|
273
|
+
else:
|
|
274
|
+
context.write({'code': -1, 'msg': '用户删除失败!'})
|
|
275
|
+
|
|
276
|
+
elif action in ('groupadd', 'groupmod', 'groupdel'):
|
|
277
|
+
if context.config.get('runtime', 'mode') == 'demo':
|
|
278
|
+
context.write({'code': -1, 'msg': '演示模式不允许操作用户组!'})
|
|
279
|
+
return
|
|
280
|
+
|
|
281
|
+
gr_name = context.get_argument('gr_name', '')
|
|
282
|
+
gr_newname = context.get_argument('gr_newname', '')
|
|
283
|
+
actionstr = {'groupadd': '添加', 'groupmod': '修改', 'groupdel': '删除'}
|
|
284
|
+
|
|
285
|
+
if action == 'groupmod':
|
|
286
|
+
rt = groupmod(gr_name, gr_newname)
|
|
287
|
+
else:
|
|
288
|
+
rt = getattr(sys.modules[__name__], action)(gr_name)
|
|
289
|
+
if rt:
|
|
290
|
+
context.write({'code': 0, 'msg': '用户组%s成功!' % actionstr[action]})
|
|
291
|
+
else:
|
|
292
|
+
context.write({'code': -1, 'msg': '用户组%s失败!' % actionstr[action]})
|
|
293
|
+
|
|
294
|
+
elif action in ('groupmems_add', 'groupmems_del'):
|
|
295
|
+
if context.config.get('runtime', 'mode') == 'demo':
|
|
296
|
+
context.write({'code': -1, 'msg': '演示模式不允许操作用户组成员!'})
|
|
297
|
+
return
|
|
298
|
+
|
|
299
|
+
gr_name = context.get_argument('gr_name', '')
|
|
300
|
+
mem = context.get_argument('mem', '')
|
|
301
|
+
option = action.split('_')[1]
|
|
302
|
+
optionstr = {'add': '添加', 'del': '删除'}
|
|
303
|
+
if groupmems(gr_name, option, mem):
|
|
304
|
+
context.write({'code': 0, 'msg': '用户组成员%s成功!' % optionstr[option]})
|
|
305
|
+
else:
|
|
306
|
+
context.write({'code': -1, 'msg': '用户组成员%s失败!' % optionstr[option]})
|
inpanel/mod/vsftpd.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2017-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
|
+
|
|
9
|
+
'''Module for vsftpd Management'''
|
|
10
|
+
|
|
11
|
+
from ..utils import cfg_get_array, cfg_set_array
|
|
12
|
+
|
|
13
|
+
config_file = '/etc/vsftpd/vsftpd.conf'
|
|
14
|
+
delimiter = '='
|
|
15
|
+
|
|
16
|
+
base_configs = {
|
|
17
|
+
'anonymous_enable': '',
|
|
18
|
+
'local_enable': '',
|
|
19
|
+
'local_umask': '',
|
|
20
|
+
'anon_upload_enable': '',
|
|
21
|
+
'anon_mkdir_write_enable': '',
|
|
22
|
+
'dirmessage_enable': '',
|
|
23
|
+
'xferlog_enable': '',
|
|
24
|
+
'connect_from_port_20': '',
|
|
25
|
+
'chown_upload': '',
|
|
26
|
+
'chown_username': '',
|
|
27
|
+
'xferlog_file': '',
|
|
28
|
+
'xferlog_std_format': '',
|
|
29
|
+
'idle_session_timeout': '',
|
|
30
|
+
'data_connection_timeout': '',
|
|
31
|
+
'nopriv_user': '',
|
|
32
|
+
'async_abor_enable': '',
|
|
33
|
+
'ascii_upload_enable': '',
|
|
34
|
+
'ascii_download_enable': '',
|
|
35
|
+
'ftpd_banner': '',
|
|
36
|
+
'deny_email_enable': '',
|
|
37
|
+
'banned_email_file': '',
|
|
38
|
+
'chroot_list_enable': '',
|
|
39
|
+
'chroot_list_file': '',
|
|
40
|
+
'max_clients': '',
|
|
41
|
+
'message_file': '',
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
def web_handler(context):
|
|
45
|
+
action = context.get_argument('action', '')
|
|
46
|
+
if action == 'getsettings':
|
|
47
|
+
context.write({
|
|
48
|
+
'code': 0,
|
|
49
|
+
'msg': 'vsftpd 配置信息获取成功!',
|
|
50
|
+
'data': get_config()
|
|
51
|
+
})
|
|
52
|
+
elif action == 'savesettings':
|
|
53
|
+
context.write({
|
|
54
|
+
'code': 0,
|
|
55
|
+
'msg': 'vsftpd 服务配置保存成功!',
|
|
56
|
+
'data': set_config()
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def get_config():
|
|
61
|
+
array_configs = cfg_get_array(config_file, base_configs, delimiter)
|
|
62
|
+
return array_configs
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def set_config():
|
|
66
|
+
result = cfg_set_array(config_file, base_configs, delimiter)
|
|
67
|
+
return result
|
inpanel/mod/yum.py
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
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 YUM Management'''
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
from .. import base
|
|
14
|
+
from . import config
|
|
15
|
+
from . import file
|
|
16
|
+
from ..yum import yum_reporpms
|
|
17
|
+
|
|
18
|
+
config_path = '/etc/yum.repos.d'
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_list():
|
|
22
|
+
'''get repo list'''
|
|
23
|
+
res = []
|
|
24
|
+
if base.kernel_name in ('Linux'):
|
|
25
|
+
d = str(Path(config_path))
|
|
26
|
+
if not Path(d).exists() or not Path(d).is_dir():
|
|
27
|
+
return None
|
|
28
|
+
items = sorted(os.listdir(d))
|
|
29
|
+
return items if len(items) > 0 else []
|
|
30
|
+
elif base.kernel_name in ('Darwin'):
|
|
31
|
+
return None
|
|
32
|
+
else:
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def item_exists(repo):
|
|
37
|
+
'''exists'''
|
|
38
|
+
return Path(str(Path(config_path) / repo)).exists()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_item(repo):
|
|
42
|
+
'''get repo config'''
|
|
43
|
+
if not repo:
|
|
44
|
+
return None
|
|
45
|
+
repo_file = str(Path(config_path) / repo)
|
|
46
|
+
if Path(repo_file).exists():
|
|
47
|
+
_config = config.Config(repo_file)
|
|
48
|
+
return _config.get_config()
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def set_item(repo, data):
|
|
53
|
+
'''set repo config'''
|
|
54
|
+
if not repo:
|
|
55
|
+
return None
|
|
56
|
+
if not data:
|
|
57
|
+
return None
|
|
58
|
+
repo_file = str(Path(config_path) / repo)
|
|
59
|
+
if Path(repo_file).exists():
|
|
60
|
+
_config = config.Config(repo_file, data)
|
|
61
|
+
return True
|
|
62
|
+
# return _config.update()
|
|
63
|
+
else:
|
|
64
|
+
return False
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def add_item(repo, data):
|
|
68
|
+
'''add repo config'''
|
|
69
|
+
if not repo:
|
|
70
|
+
return None
|
|
71
|
+
if not data:
|
|
72
|
+
return None
|
|
73
|
+
repo_file = str(Path(config_path) / repo)
|
|
74
|
+
if Path(repo_file).exists():
|
|
75
|
+
return False
|
|
76
|
+
else:
|
|
77
|
+
_config = config.Config(repo_file, data)
|
|
78
|
+
return True
|
|
79
|
+
# return _config.update()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def del_item(repo):
|
|
83
|
+
'''delete repo file'''
|
|
84
|
+
if not repo:
|
|
85
|
+
return None
|
|
86
|
+
repo_file = str(Path(config_path) / repo)
|
|
87
|
+
return file.delete(repo_file)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def get_repo_release(os_versint, os_name, arch):
|
|
91
|
+
'''install release'''
|
|
92
|
+
cmds = []
|
|
93
|
+
if os_versint == 5:
|
|
94
|
+
if os_name == 'redhat':
|
|
95
|
+
# backup system version info
|
|
96
|
+
cmds.append('cp -f /etc/redhat-release /etc/redhat-release.inpanel')
|
|
97
|
+
cmds.append('cp -f /etc/issue /etc/issue.inpanel')
|
|
98
|
+
cmds.append('rpm -e redhat-release-5Server --nodeps')
|
|
99
|
+
elif os_versint == 7:
|
|
100
|
+
if os_name == 'centos':
|
|
101
|
+
cmds.append('yum install -y centos-release')
|
|
102
|
+
elif os_versint == 8:
|
|
103
|
+
if os_name == 'centos':
|
|
104
|
+
cmds.append('yum install -y centos-release')
|
|
105
|
+
else:
|
|
106
|
+
for rpm in yum_reporpms['base'][os_versint][arch]:
|
|
107
|
+
cmds.append('rpm -U %s' % rpm)
|
|
108
|
+
|
|
109
|
+
if Path('/etc/issue.inpanel').exists():
|
|
110
|
+
cmds.append('cp -f /etc/issue.inpanel /etc/issue')
|
|
111
|
+
if Path('/etc/redhat-release.inpanel').exists():
|
|
112
|
+
cmds.append(
|
|
113
|
+
'cp -f /etc/redhat-release.inpanel /etc/redhat-release')
|
|
114
|
+
return cmds
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def get_repo_epel(os_versint, os_name, arch):
|
|
118
|
+
'''install epel'''
|
|
119
|
+
# CentALT and ius depends on epel
|
|
120
|
+
cmds = []
|
|
121
|
+
|
|
122
|
+
if os_versint == 7:
|
|
123
|
+
if os_name == 'centos':
|
|
124
|
+
cmds.append('yum install -y epel-release')
|
|
125
|
+
if os_versint == 8:
|
|
126
|
+
if os_name == 'centos':
|
|
127
|
+
cmds.append('yum install -y epel-release')
|
|
128
|
+
else:
|
|
129
|
+
for rpm in yum_reporpms['epel'][os_versint][arch]:
|
|
130
|
+
cmds.append('rpm -U %s' % rpm)
|
|
131
|
+
|
|
132
|
+
return cmds
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def web_handler(context):
|
|
136
|
+
'''Handle web requests for YUM repository management'''
|
|
137
|
+
action = context.get('action', '')
|
|
138
|
+
repo = context.get('repo', '')
|
|
139
|
+
|
|
140
|
+
if action == 'list':
|
|
141
|
+
items = get_list()
|
|
142
|
+
if items is None:
|
|
143
|
+
return {'code': -1, 'msg': '获取配置失败!'}
|
|
144
|
+
else:
|
|
145
|
+
return {'code': 0, 'msg': '', 'data': items}
|
|
146
|
+
|
|
147
|
+
elif action == 'item':
|
|
148
|
+
if not repo:
|
|
149
|
+
return {'code': -1, 'msg': '配置文件不能为空!'}
|
|
150
|
+
data = get_item(repo)
|
|
151
|
+
if data is None:
|
|
152
|
+
return {'code': -1, 'msg': '配置文件不存在!'}
|
|
153
|
+
else:
|
|
154
|
+
return {'code': 0, 'msg': '', 'data': data}
|
|
155
|
+
|
|
156
|
+
elif action == 'add':
|
|
157
|
+
if not repo:
|
|
158
|
+
return {'code': -1, 'msg': '配置文件不能为空!'}
|
|
159
|
+
serverid = context.get('serverid', '')
|
|
160
|
+
if not serverid:
|
|
161
|
+
return {'code': -1, 'msg': '仓库标识ID不能为空!'}
|
|
162
|
+
name = context.get('name', '')
|
|
163
|
+
if not name:
|
|
164
|
+
return {'code': -1, 'msg': '仓库名称不能为空!'}
|
|
165
|
+
baseurl = context.get('baseurl', '')
|
|
166
|
+
if not baseurl:
|
|
167
|
+
return {'code': -1, 'msg': '仓库路径不能为空!'}
|
|
168
|
+
|
|
169
|
+
enabled = context.get('enabled', True)
|
|
170
|
+
gpgcheck = context.get('gpgcheck', False)
|
|
171
|
+
|
|
172
|
+
data = {
|
|
173
|
+
serverid: {
|
|
174
|
+
'name': name,
|
|
175
|
+
'enabled': 0 if not enabled else 1,
|
|
176
|
+
'baseurl': baseurl,
|
|
177
|
+
'gpgcheck': 0 if not gpgcheck else 1,
|
|
178
|
+
'gpgkey': ''
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if item_exists(repo):
|
|
183
|
+
return {'code': -1, 'msg': '配置文件已存在!'}
|
|
184
|
+
if add_item(repo, data) is True:
|
|
185
|
+
return {'code': 0, 'msg': '配置添加成功!'}
|
|
186
|
+
else:
|
|
187
|
+
return {'code': -1, 'msg': '配置添加失败!'}
|
|
188
|
+
|
|
189
|
+
elif action == 'edit':
|
|
190
|
+
if not repo:
|
|
191
|
+
return {'code': -1, 'msg': '配置文件不能为空!'}
|
|
192
|
+
serverid = context.get('serverid', '')
|
|
193
|
+
if not serverid:
|
|
194
|
+
return {'code': -1, 'msg': '仓库标识ID不能为空!'}
|
|
195
|
+
name = context.get('name', '')
|
|
196
|
+
if not name:
|
|
197
|
+
return {'code': -1, 'msg': '仓库名称不能为空!'}
|
|
198
|
+
baseurl = context.get('baseurl', '')
|
|
199
|
+
if not baseurl:
|
|
200
|
+
return {'code': -1, 'msg': '仓库路径不能为空!'}
|
|
201
|
+
|
|
202
|
+
enabled = context.get('enabled', True)
|
|
203
|
+
gpgcheck = context.get('gpgcheck', False)
|
|
204
|
+
|
|
205
|
+
data = {
|
|
206
|
+
serverid: {
|
|
207
|
+
'name': name,
|
|
208
|
+
'enabled': 0 if not enabled else 1,
|
|
209
|
+
'baseurl': baseurl,
|
|
210
|
+
'gpgcheck': 0 if not gpgcheck else 1,
|
|
211
|
+
'gpgkey': ''
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if not item_exists(repo):
|
|
216
|
+
return {'code': -1, 'msg': '配置文件不存在!'}
|
|
217
|
+
if set_item(repo, data) is True:
|
|
218
|
+
return {'code': 0, 'msg': '配置修改成功!'}
|
|
219
|
+
else:
|
|
220
|
+
return {'code': -1, 'msg': '配置修改失败!'}
|
|
221
|
+
|
|
222
|
+
elif action == 'del':
|
|
223
|
+
if not repo:
|
|
224
|
+
return {'code': -1, 'msg': '配置文件不能为空!'}
|
|
225
|
+
if not item_exists(repo):
|
|
226
|
+
return {'code': -1, 'msg': '配置文件不存在!'}
|
|
227
|
+
if del_item(repo) is True:
|
|
228
|
+
return {'code': 0, 'msg': '配置文件已移入回收站!'}
|
|
229
|
+
else:
|
|
230
|
+
return {'code': -1, 'msg': '删除失败!'}
|
|
231
|
+
|
|
232
|
+
else:
|
|
233
|
+
return {'code': -1, 'msg': '未定义的操作!'}
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
if __name__ == '__main__':
|
|
237
|
+
l = get_list()
|
|
238
|
+
print(l)
|
|
239
|
+
if l:
|
|
240
|
+
i = l[0]
|
|
241
|
+
print(i)
|
|
242
|
+
c = get_item(i)
|
|
243
|
+
print(c)
|
|
Binary file
|
|
Binary file
|