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.
Files changed (198) hide show
  1. inpanel/__init__.py +29 -0
  2. inpanel/acme.py +289 -0
  3. inpanel/aliyuncs.py +269 -0
  4. inpanel/app.py +514 -0
  5. inpanel/apt.py +223 -0
  6. inpanel/base.py +200 -0
  7. inpanel/config.py +139 -0
  8. inpanel/data/config.ini +29 -0
  9. inpanel/data/history +5 -0
  10. inpanel/data/runlogs.ini +12 -0
  11. inpanel/data/update_info.ini +4 -0
  12. inpanel/dnf.py +225 -0
  13. inpanel/lib/__init__.py +9 -0
  14. inpanel/lib/async_process.py +98 -0
  15. inpanel/lib/filelock.py +82 -0
  16. inpanel/lib/magic.py +233 -0
  17. inpanel/lib/pxssh.py +310 -0
  18. inpanel/lib/pyDes.py +867 -0
  19. inpanel/mod/__init__.py +0 -0
  20. inpanel/mod/apt.py +316 -0
  21. inpanel/mod/certificate.py +268 -0
  22. inpanel/mod/config.py +372 -0
  23. inpanel/mod/cron.py +315 -0
  24. inpanel/mod/disk.py +322 -0
  25. inpanel/mod/dnf.py +239 -0
  26. inpanel/mod/file.py +722 -0
  27. inpanel/mod/firewall.py +199 -0
  28. inpanel/mod/firewall_base.py +137 -0
  29. inpanel/mod/firewall_firewalld.py +170 -0
  30. inpanel/mod/firewall_iptables.py +176 -0
  31. inpanel/mod/firewall_macos.py +213 -0
  32. inpanel/mod/firewall_ufw.py +128 -0
  33. inpanel/mod/ftp.py +231 -0
  34. inpanel/mod/httpd.py +1205 -0
  35. inpanel/mod/lighttpd.py +26 -0
  36. inpanel/mod/login.py +98 -0
  37. inpanel/mod/mysql.py +577 -0
  38. inpanel/mod/named.py +26 -0
  39. inpanel/mod/nginx.py +2327 -0
  40. inpanel/mod/package.py +33 -0
  41. inpanel/mod/package_apt.py +62 -0
  42. inpanel/mod/package_base.py +77 -0
  43. inpanel/mod/package_dnf.py +62 -0
  44. inpanel/mod/package_map.py +366 -0
  45. inpanel/mod/package_yum.py +64 -0
  46. inpanel/mod/php.py +289 -0
  47. inpanel/mod/process.py +291 -0
  48. inpanel/mod/proftpd.py +26 -0
  49. inpanel/mod/pureftpd.py +26 -0
  50. inpanel/mod/query.py +108 -0
  51. inpanel/mod/server.py +1319 -0
  52. inpanel/mod/service.py +262 -0
  53. inpanel/mod/setting.py +228 -0
  54. inpanel/mod/shell.py +78 -0
  55. inpanel/mod/ssh.py +280 -0
  56. inpanel/mod/system.py +220 -0
  57. inpanel/mod/task.py +1337 -0
  58. inpanel/mod/ufw.py +14 -0
  59. inpanel/mod/user.py +306 -0
  60. inpanel/mod/vsftpd.py +67 -0
  61. inpanel/mod/yum.py +243 -0
  62. inpanel/plugins/__init__.py +10 -0
  63. inpanel/plugins/__pycache__/__init__.cpython-313.pyc +0 -0
  64. inpanel/plugins/acme/static/index.html +10 -0
  65. inpanel/plugins/acme/static/index.js +13 -0
  66. inpanel/plugins/shadowsocks-libev/__pycache__/info.cpython-313.pyc +0 -0
  67. inpanel/plugins/shadowsocks-libev/info.py +73 -0
  68. inpanel/plugins/shadowsocks-libev/static/index.html +70 -0
  69. inpanel/plugins/shadowsocks-libev/static/index.js +18 -0
  70. inpanel/public/css/global.css +138 -0
  71. inpanel/public/favicon.ico +0 -0
  72. inpanel/public/images/alipay.jpg +0 -0
  73. inpanel/public/images/loading.gif +0 -0
  74. inpanel/public/images/weixin.jpg +0 -0
  75. inpanel/public/index.html +94 -0
  76. inpanel/public/js/controllers/controllers.js +566 -0
  77. inpanel/public/js/controllers/database.js +590 -0
  78. inpanel/public/js/controllers/ecs.js +624 -0
  79. inpanel/public/js/controllers/file.js +940 -0
  80. inpanel/public/js/controllers/plugins.js +105 -0
  81. inpanel/public/js/controllers/service.js +1460 -0
  82. inpanel/public/js/controllers/site.js +1241 -0
  83. inpanel/public/js/controllers/utils.js +2319 -0
  84. inpanel/public/js/core.js +221 -0
  85. inpanel/public/js/directives.js +784 -0
  86. inpanel/public/js/filters.js +395 -0
  87. inpanel/public/js/services.js +257 -0
  88. inpanel/public/lib/angular/1.0.2/angular-resource.min.js +10 -0
  89. inpanel/public/lib/angular/1.0.2/angular.min.js +158 -0
  90. inpanel/public/lib/bootstrap/css/bootstrap-theme.css +587 -0
  91. inpanel/public/lib/bootstrap/css/bootstrap-theme.css.map +1 -0
  92. inpanel/public/lib/bootstrap/css/bootstrap-theme.min.css +6 -0
  93. inpanel/public/lib/bootstrap/css/bootstrap-theme.min.css.map +1 -0
  94. inpanel/public/lib/bootstrap/css/bootstrap.css +6757 -0
  95. inpanel/public/lib/bootstrap/css/bootstrap.css.map +1 -0
  96. inpanel/public/lib/bootstrap/css/bootstrap.min.css +6 -0
  97. inpanel/public/lib/bootstrap/css/bootstrap.min.css.map +1 -0
  98. inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.eot +0 -0
  99. inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.svg +288 -0
  100. inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf +0 -0
  101. inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.woff +0 -0
  102. inpanel/public/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2 +0 -0
  103. inpanel/public/lib/bootstrap/img/glyphicons-halflings-white.png +0 -0
  104. inpanel/public/lib/bootstrap/img/glyphicons-halflings.png +0 -0
  105. inpanel/public/lib/bootstrap/js/bootstrap.js +2377 -0
  106. inpanel/public/lib/bootstrap/js/bootstrap.min.js +7 -0
  107. inpanel/public/lib/bootstrap/js/npm.js +13 -0
  108. inpanel/public/lib/codemirror/codemirror-compressed.js +1 -0
  109. inpanel/public/lib/codemirror/codemirror.css +173 -0
  110. inpanel/public/lib/jquery/jquery-1.12.4.min.js +5 -0
  111. inpanel/public/lib/md5/md5.js +379 -0
  112. inpanel/public/lib/md5/md5.min.js +1 -0
  113. inpanel/public/partials/database/index.html +172 -0
  114. inpanel/public/partials/database/mysql/dbedit.html +462 -0
  115. inpanel/public/partials/database/mysql/dbnew.html +348 -0
  116. inpanel/public/partials/database/mysql/useredit.html +310 -0
  117. inpanel/public/partials/database/mysql/usernew.html +97 -0
  118. inpanel/public/partials/directives/message.html +20 -0
  119. inpanel/public/partials/directives/navbar.html +25 -0
  120. inpanel/public/partials/directives/selector.html +57 -0
  121. inpanel/public/partials/directives/srvbase.html +72 -0
  122. inpanel/public/partials/directives/srvext.html +34 -0
  123. inpanel/public/partials/directives/srvfile.html +23 -0
  124. inpanel/public/partials/directives/srvinstall.html +34 -0
  125. inpanel/public/partials/directives/srvlog.html +23 -0
  126. inpanel/public/partials/directives/srvminiop.html +28 -0
  127. inpanel/public/partials/directives/srvuninstall.html +38 -0
  128. inpanel/public/partials/directives/srvupdate.html +30 -0
  129. inpanel/public/partials/ecs/account.html +156 -0
  130. inpanel/public/partials/ecs/ecs.html +198 -0
  131. inpanel/public/partials/ecs/index.html +40 -0
  132. inpanel/public/partials/ecs/setings.html +459 -0
  133. inpanel/public/partials/file/file.html +501 -0
  134. inpanel/public/partials/file/trash.html +95 -0
  135. inpanel/public/partials/ftp.html +36 -0
  136. inpanel/public/partials/log.html +83 -0
  137. inpanel/public/partials/login.html +79 -0
  138. inpanel/public/partials/logout.html +22 -0
  139. inpanel/public/partials/main.html +534 -0
  140. inpanel/public/partials/plugins/index.html +55 -0
  141. inpanel/public/partials/plugins/plugins.html +13 -0
  142. inpanel/public/partials/secure.html +13 -0
  143. inpanel/public/partials/service/apache.html +147 -0
  144. inpanel/public/partials/service/cron.html +71 -0
  145. inpanel/public/partials/service/index.html +293 -0
  146. inpanel/public/partials/service/iptables.html +40 -0
  147. inpanel/public/partials/service/lighttpd.html +63 -0
  148. inpanel/public/partials/service/mariadb.html +113 -0
  149. inpanel/public/partials/service/memcache.html +36 -0
  150. inpanel/public/partials/service/minio.html +44 -0
  151. inpanel/public/partials/service/mongodb.html +44 -0
  152. inpanel/public/partials/service/mysql.html +113 -0
  153. inpanel/public/partials/service/named.html +61 -0
  154. inpanel/public/partials/service/nginx.html +296 -0
  155. inpanel/public/partials/service/ntp.html +40 -0
  156. inpanel/public/partials/service/php.html +250 -0
  157. inpanel/public/partials/service/proftpd.html +59 -0
  158. inpanel/public/partials/service/pureftpd.html +59 -0
  159. inpanel/public/partials/service/redis.html +40 -0
  160. inpanel/public/partials/service/samba.html +58 -0
  161. inpanel/public/partials/service/sendmail.html +40 -0
  162. inpanel/public/partials/service/ssh.html +186 -0
  163. inpanel/public/partials/service/tomcat.html +65 -0
  164. inpanel/public/partials/service/vsftpd.html +195 -0
  165. inpanel/public/partials/setting.html +299 -0
  166. inpanel/public/partials/site/apache/site.html +277 -0
  167. inpanel/public/partials/site/index.html +344 -0
  168. inpanel/public/partials/site/nginx/site.html +558 -0
  169. inpanel/public/partials/sorry.html +19 -0
  170. inpanel/public/partials/storage/autofm.html +103 -0
  171. inpanel/public/partials/storage/backup.html +42 -0
  172. inpanel/public/partials/storage/index.html +360 -0
  173. inpanel/public/partials/storage/migrate.html +93 -0
  174. inpanel/public/partials/storage/movedata.html +98 -0
  175. inpanel/public/partials/storage/remote.html +77 -0
  176. inpanel/public/partials/utils/cron.html +486 -0
  177. inpanel/public/partials/utils/firewall.html +266 -0
  178. inpanel/public/partials/utils/index.html +193 -0
  179. inpanel/public/partials/utils/network.html +118 -0
  180. inpanel/public/partials/utils/process.html +239 -0
  181. inpanel/public/partials/utils/repository.html +373 -0
  182. inpanel/public/partials/utils/shell.html +28 -0
  183. inpanel/public/partials/utils/ssl.html +319 -0
  184. inpanel/public/partials/utils/time.html +109 -0
  185. inpanel/public/partials/utils/user.html +359 -0
  186. inpanel/public/robots.txt +2 -0
  187. inpanel/remote.py +109 -0
  188. inpanel/templates/file/preview.html +34 -0
  189. inpanel/templates/index.html +93 -0
  190. inpanel/utils.py +282 -0
  191. inpanel/web.py +1811 -0
  192. inpanel/yum.py +756 -0
  193. inpanel-1.2.1.dist-info/METADATA +399 -0
  194. inpanel-1.2.1.dist-info/RECORD +198 -0
  195. inpanel-1.2.1.dist-info/WHEEL +5 -0
  196. inpanel-1.2.1.dist-info/entry_points.txt +2 -0
  197. inpanel-1.2.1.dist-info/licenses/LICENSE +30 -0
  198. 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)
@@ -0,0 +1,10 @@
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
+ '''Plugins for InPanel'''
10
+
@@ -0,0 +1,10 @@
1
+ <div>
2
+ <div class="module-header">
3
+ <h3>ACME 协议设置</h3>
4
+ </div>
5
+
6
+ <div class="well">
7
+ <p>我们使用 ACME 协议 申请和管理 Let’s Encrypt 证书,这里可以对 ACME 进行简单的设置</p>
8
+ </div>
9
+
10
+ </div>
@@ -0,0 +1,13 @@
1
+
2
+ var PluginsCACMEtrl = [
3
+ '$scope', 'Module',
4
+ function ($scope, Module) {
5
+ var module = 'plugins.acme';
6
+ Module.init(module, 'ACME');
7
+ $scope.loaded = false;
8
+
9
+ $scope.load = function () {
10
+ $scope.loaded = true;
11
+ };
12
+ }
13
+ ];