Compare commits

..
471 Commits
Author SHA1 Message Date
Mr Chen 9615fb2203 Update config.py 2018-12-25 10:09:33 +08:00
Mr Chen 49c181c577 Update cli.sh 2018-12-25 10:07:16 +08:00
midoks 0fa5e4fb48 update 2018-12-24 22:33:49 +08:00
Mr Chen 8e7130c382 Update app.py 2018-12-24 15:38:55 +08:00
Mr Chen 33c1ac82c8 Update index.html 2018-12-24 11:48:07 +08:00
Mr Chen df5aec2e8f Update install.sh 2018-12-24 11:37:53 +08:00
Mr Chen 6c864177ee Update install.sh 2018-12-24 11:37:35 +08:00
Mr Chen 9ee09b0e7d update 2018-12-24 11:14:51 +08:00
Mr Chen b7da91f92b update 2018-12-21 11:44:38 +08:00
Mr Chen 17e6703c07 Update site.js 2018-12-21 10:52:21 +08:00
Mr Chen a5f77a37f2 Update mw.tpl 2018-12-21 10:07:24 +08:00
midoks 78fc9fd90f u 2018-12-20 23:41:26 +08:00
midoks 700f042033 防盗链 ok 2018-12-20 22:30:00 +08:00
midoks e44768e608 update 2018-12-20 21:45:09 +08:00
midoks 2acef86207 Update config.py 2018-12-20 21:35:49 +08:00
midoks 6256bb02da Update cli.sh 2018-12-20 21:34:52 +08:00
midoks 04f5a27492 Update system_api.py 2018-12-20 21:34:47 +08:00
Mr Chen 7cd476696a Update site.js 2018-12-20 19:28:47 +08:00
Mr Chen 2ecaf0e2a3 update 2018-12-20 19:22:33 +08:00
Mr Chen c5d3494a94 update 2018-12-20 14:15:13 +08:00
Mr Chen af0658fd41 update 2018-12-20 14:05:57 +08:00
Mr Chen cccbd88145 站点添加优化 2018-12-20 13:39:43 +08:00
Mr Chen 48aad5b248 Update index.py 2018-12-20 13:29:05 +08:00
Mr Chen d843213c39 流量控制功能ok 2018-12-20 13:27:50 +08:00
Mr Chen 7ad33c5c59 update 2018-12-20 11:12:39 +08:00
Mr Chen ee56cfe5ab Update README.md 2018-12-20 11:07:36 +08:00
Mr Chen c6b38aa996 update 2018-12-20 10:45:43 +08:00
midoks c5205c2d55 文件保存 2018-12-20 00:48:41 +08:00
midoks 1be07f96ff Update install.sh 2018-12-20 00:26:07 +08:00
midoks 9f4af88c1e update 2018-12-19 23:37:31 +08:00
Mr Chen ebc0559dff up 2018-12-19 20:43:33 +08:00
Mr Chen fe320ecd3b phpinfo ok 2018-12-19 17:17:07 +08:00
Mr Chen 02c06e7ff1 update 2018-12-19 16:50:15 +08:00
Mr Chen 6d90d6fde5 update 2018-12-19 15:50:07 +08:00
Mr Chen bfc0b9efa3 update 2018-12-19 15:41:00 +08:00
Mr Chen 6e4e7bcf68 update 2018-12-19 15:21:31 +08:00
Mr Chen 5da505084d update 2018-12-19 13:54:19 +08:00
Mr Chen f19df17ef5 update 2018-12-19 10:42:37 +08:00
Mr Chen d99e89744d Update index.py 2018-12-19 10:34:18 +08:00
midoks 9695fe4b9b Update index.py 2018-12-18 23:22:08 +08:00
Mr Chen 5907dc36c5 Update index.py 2018-12-18 19:50:57 +08:00
Mr Chen d694af9358 update 2018-12-18 19:43:41 +08:00
Mr Chen 4dc2828c59 update 2018-12-18 19:37:46 +08:00
Mr Chen 37519b4c92 超时限制,上传限制 2018-12-18 18:09:54 +08:00
Mr Chen 90999c7ae1 u 2018-12-18 15:37:02 +08:00
Mr Chen f16d9ea269 update 2018-12-18 15:23:48 +08:00
Mr Chen 86098541e0 PHP update 2018-12-18 15:13:33 +08:00
Mr Chen 9ef04a4d9e Create php.ini 2018-12-18 15:13:22 +08:00
Mr Chen 752f8fae5a Update csvn.js 2018-12-18 15:13:19 +08:00
Mr Chen c5fdecf459 up 2018-12-18 13:43:24 +08:00
Mr Chen 19284cd5ef update 2018-12-18 13:17:37 +08:00
Mr Chen da92ab1c89 update 2018-12-18 10:38:46 +08:00
midoks 18ca47e8b3 up 2018-12-17 23:26:00 +08:00
midoks 8b624297ba Update site_api.py 2018-12-17 21:40:08 +08:00
midoks f0d9ff2ae9 Update cli.sh 2018-12-17 21:38:15 +08:00
midoks 21b2c17220 Update site_api.py 2018-12-17 21:38:11 +08:00
midoks 0df898a7d9 Update install.sh 2018-12-17 21:38:08 +08:00
midoks cf1f4c8538 Update default.sql 2018-12-17 21:35:13 +08:00
Mr Chen 89ecdcd29a update 2018-12-17 19:17:51 +08:00
Mr Chen 0c8fa5e616 Update site.py 2018-12-17 18:21:06 +08:00
Mr Chen f9252da1b0 update 2018-12-17 18:16:59 +08:00
Mr Chen e31cbad7dd update 2018-12-17 17:21:33 +08:00
Mr Chen 5bed9f0802 update 2018-12-17 16:47:40 +08:00
Mr Chen 1ae4b54779 update 2018-12-17 15:20:30 +08:00
Mr Chen 2b2a75adf0 Update openresty.js 2018-12-17 11:23:05 +08:00
Mr Chen 55184341d7 Update install.sh 2018-12-17 11:17:58 +08:00
Mr Chen 6504decc30 update 2018-12-17 11:11:33 +08:00
Mr Chen 843d798b91 update 2018-12-17 11:06:58 +08:00
midoks 087a6b4809 update 2018-12-16 23:29:35 +08:00
midoks 44438bd9aa Update install.sh 2018-12-15 11:18:33 +08:00
midoks c33cba0e85 update 2018-12-15 01:22:00 +08:00
midoks cdc3c95367 update 2018-12-14 23:29:47 +08:00
midoks 222cebe1b3 update 2018-12-14 21:53:33 +08:00
midoks 2fc2eff97e Update install.sh 2018-12-14 21:35:59 +08:00
midoks 79f8baeeb3 update 2018-12-14 21:35:55 +08:00
midoks 0399219df6 Update pick_filter.txt 2018-12-14 21:34:13 +08:00
midoks cd0d5ede16 Update pick_filter.txt 2018-12-14 21:31:58 +08:00
Mr Chen 1e6d1c6127 Update info.json 2018-12-14 19:21:23 +08:00
Mr Chen ff87dbe258 Update index.py 2018-12-14 18:38:27 +08:00
Mr Chen 7d6ddb40db update 2018-12-14 18:29:53 +08:00
Mr Chen 1cb57d3f65 update 2018-12-14 18:04:50 +08:00
Mr Chen 9ed434d274 update 2018-12-14 17:39:47 +08:00
Mr Chen f532a376a7 update 2018-12-14 16:06:59 +08:00
Mr Chen 4405f7720b Update info.json 2018-12-14 15:20:16 +08:00
Mr Chen fbde4aab88 Update commit.tpl 2018-12-14 15:20:11 +08:00
Mr Chen 864691d357 同步数据处理 2018-12-14 14:52:33 +08:00
Mr Chen 95bf0cb1e8 修正权限格式 2018-12-14 13:56:16 +08:00
midoks 126f2d553d Update index.py 2018-12-13 23:17:49 +08:00
midoks 2fb88be080 update 2018-12-13 23:15:33 +08:00
midoks fa307cdb49 Update commit.tpl 2018-12-13 23:05:55 +08:00
midoks 0850b6ed44 Update index.py 2018-12-13 22:52:20 +08:00
midoks ec1e99f9ca Update index.py 2018-12-13 22:47:45 +08:00
midoks 546dc4d7eb Update index.py 2018-12-13 22:45:16 +08:00
midoks 9b0b4ac305 Update index.py 2018-12-13 22:40:37 +08:00
midoks 23a1f3936d update 2018-12-13 22:37:27 +08:00
Mr Chen 4cb22a1e35 update 2018-12-13 20:01:29 +08:00
Mr Chen 3e3cdbe18c update 2018-12-13 18:20:27 +08:00
Mr Chen bdc46d9401 Update pick_filter.txt 2018-12-13 18:08:55 +08:00
Mr Chen 64986dd125 gogs ready 2018-12-13 18:07:44 +08:00
Mr Chen 7ee00ab0b5 Update csvn.js 2018-12-13 17:13:48 +08:00
Mr Chen 488d92ba19 update 2018-12-13 17:09:23 +08:00
Mr Chen 9cebfb64cb 查找更新 2018-12-13 15:36:19 +08:00
Mr Chen 7800429f8d update 2018-12-13 15:20:47 +08:00
Mr Chen 7954714bb7 update 2018-12-13 14:57:30 +08:00
Mr Chen 1d396b73f0 Update index.html 2018-12-13 14:37:49 +08:00
Mr Chen 5f95a1d56a update 2018-12-13 14:37:38 +08:00
Mr Chen 51951a2685 update 2018-12-13 14:37:31 +08:00
Mr Chen 737453600d Update csvn.js 2018-12-13 13:51:14 +08:00
Mr Chen 17ef460f4c update 2018-12-13 13:34:06 +08:00
Mr Chen 38be955738 add debug 2018-12-13 12:56:06 +08:00
Mr Chen daf5c7c2b0 Update pick_filter.txt 2018-12-13 12:51:22 +08:00
Mr Chen acdb35f395 Update install.sh 2018-12-13 11:14:54 +08:00
midoks 5e8a15c230 update 2018-12-13 01:28:54 +08:00
midoks 34bcdd915c Update setting.py 2018-12-13 01:14:25 +08:00
midoks aa718adfea Update setting.py 2018-12-13 01:10:07 +08:00
midoks 936592661b update 2018-12-13 01:09:38 +08:00
midoks c740b4affb Update config.py 2018-12-13 00:54:13 +08:00
midoks 042b07efa2 Update csvn.js 2018-12-13 00:49:11 +08:00
midoks 6a6d22fd2d Update index.py 2018-12-12 23:37:11 +08:00
midoks f99502d2c8 Update config.py 2018-12-12 21:57:24 +08:00
midoks 1cf41348b7 Update config.py 2018-12-12 21:40:24 +08:00
midoks acdb226df9 update 2018-12-12 21:35:04 +08:00
Mr Chen 6259f21196 update 2018-12-12 19:30:42 +08:00
Mr Chen 6ad1292003 Update task.py 2018-12-12 19:26:28 +08:00
Mr Chen a682ba3e43 Update mw.tpl 2018-12-12 19:21:44 +08:00
Mr Chen 7509b259e7 Update setting.py 2018-12-12 18:47:42 +08:00
Mr Chen 8d170d87e4 update 2018-12-12 18:45:33 +08:00
Mr Chen bc4e5f6a87 update 2018-12-12 18:06:02 +08:00
Mr Chen 954f66c8dc update 2018-12-12 15:11:55 +08:00
Mr Chen a7f860de2b Update index.py 2018-12-12 14:06:10 +08:00
Mr Chen 6e7e291da3 update 2018-12-12 13:57:43 +08:00
Mr Chen 2bca78c32d update 2018-12-12 10:31:01 +08:00
midoks fb4311cdbf update 2018-12-12 00:07:01 +08:00
Mr Chen d889bf2cf3 Update index.py 2018-12-11 19:51:01 +08:00
Mr Chen 511a7ac12b Update index.py 2018-12-11 19:30:02 +08:00
Mr Chen 03e126cb48 Update index.py 2018-12-11 17:56:05 +08:00
Mr Chen 2acbe56e21 update 2018-12-11 17:53:37 +08:00
Mr Chen 8425aa4942 update 2018-12-11 14:49:26 +08:00
Mr Chen 17ad9abe6b update 2018-12-11 14:25:12 +08:00
Mr Chen 11166bbab1 Update files.py 2018-12-11 13:54:50 +08:00
Mr Chen f5f3f7ded5 update 2018-12-11 13:46:27 +08:00
Mr Chen 26bae283be update 2018-12-11 13:29:27 +08:00
Mr Chen bfb12692a6 Update csvn.js 2018-12-11 11:01:28 +08:00
Mr Chen 6bc6f17783 Update csvn.js 2018-12-11 10:37:45 +08:00
Mr Chen cd6f86ebfa Update csvn.js 2018-12-11 10:34:20 +08:00
Mr Chen 5abb2613a1 update 2018-12-11 10:31:53 +08:00
midoks a08dee242a Update csvn.js 2018-12-11 01:17:09 +08:00
midoks 2700b6b67b Update csvn.js 2018-12-11 01:15:09 +08:00
midoks e41148d72d Update index.py 2018-12-11 00:46:36 +08:00
midoks 9b5c80bc72 Update csvn.js 2018-12-11 00:44:29 +08:00
midoks 958755d18d update 2018-12-11 00:28:09 +08:00
Mr Chen 9af7e0f95b up 2018-12-10 19:37:38 +08:00
Mr Chen 90e86cda0d update 2018-12-10 19:17:40 +08:00
Mr Chen ea2ed9d003 Update crontab.html 2018-12-10 17:35:46 +08:00
Mr Chen 67eb3590c7 update 2018-12-10 17:27:09 +08:00
Mr Chen e66afbbb2d Update index.py 2018-12-10 16:41:01 +08:00
Mr Chen f959391b85 Create mw.sh 2018-12-10 16:29:04 +08:00
Mr Chen 663e95288a update 2018-12-10 16:18:35 +08:00
Mr Chen 0af3c7622d update 2018-12-10 15:53:06 +08:00
Mr Chen 40e2186a5b update 2018-12-10 15:32:31 +08:00
Mr Chen 121c972951 优化显示 2018-12-10 15:10:07 +08:00
Mr Chen 229cb977a1 update 2018-12-10 14:22:22 +08:00
Mr Chen ae845a702c u 2018-12-10 13:12:33 +08:00
Mr Chen 35b0b1d153 Update public.js 2018-12-10 11:43:20 +08:00
Mr Chen 4801850373 openresty error_logs 2018-12-10 11:42:13 +08:00
Mr Chen 8b3d0cbba4 update 2018-12-10 10:45:30 +08:00
Mr Chen 4f580d0427 update 2018-12-10 10:44:54 +08:00
Mr Chen 2f794c5b73 update 2018-12-10 10:33:03 +08:00
midoks 21cd34d272 Update index.html 2018-12-09 23:30:57 +08:00
midoks c58e1f7278 Update index.py 2018-12-09 23:30:54 +08:00
midoks 5b49f24a8d Update php56.tpl 2018-12-09 23:30:52 +08:00
midoks ce89a2a275 Update php.js 2018-12-09 23:30:50 +08:00
midoks 35f905e94c Update public.js 2018-12-09 23:30:46 +08:00
midoks 1c431286e4 Update index.py 2018-12-09 21:23:56 +08:00
midoks 705cef730b Update public.js 2018-12-09 20:33:16 +08:00
midoks 2a5da5593b Update soft.js 2018-12-09 20:33:14 +08:00
midoks 22692d8ed4 Update index.py 2018-12-09 20:31:39 +08:00
midoks 5cdae707e9 Create php56.tpl 2018-12-09 20:31:31 +08:00
midoks 5be9f1ae66 Update public.js 2018-12-09 20:31:28 +08:00
midoks ba931a0c2a Update index.py 2018-12-09 19:10:14 +08:00
midoks 5b87572bff up 2018-12-09 18:58:41 +08:00
midoks d51de312ac Update index.py 2018-12-09 14:07:13 +08:00
midoks bcd2e7298b update 2018-12-09 13:37:52 +08:00
midoks a985511b3b Update index.py 2018-12-09 13:28:36 +08:00
midoks abb9fb72f0 Update index.py 2018-12-09 13:23:37 +08:00
midoks b36ad3a595 Update index.py 2018-12-09 13:20:05 +08:00
midoks a118f33f57 Update index.py 2018-12-09 13:17:15 +08:00
midoks 58b888edcd Update index.py 2018-12-09 13:06:15 +08:00
midoks 43d906139e Update index.py 2018-12-09 13:00:18 +08:00
midoks b91bc040d4 Update index.py 2018-12-09 12:59:36 +08:00
midoks c6eba5bbf1 Update index.py 2018-12-09 12:52:41 +08:00
midoks 1adbf733d8 Update index.py 2018-12-09 12:50:30 +08:00
midoks 913d483e63 Update index.py 2018-12-09 12:40:43 +08:00
midoks 9951f7151e Update index.py 2018-12-09 12:37:49 +08:00
midoks 167a386a0d update 2018-12-09 11:59:00 +08:00
midoks 5473ee74cb Update install.sh 2018-12-09 11:43:57 +08:00
midoks dbeefc06c8 update 2018-12-09 11:42:11 +08:00
midoks 444730e553 Update install.sh 2018-12-09 11:36:18 +08:00
midoks 8a2e17198e Update index.py 2018-12-09 11:16:32 +08:00
midoks bc41788d49 u 2018-12-08 23:26:34 +08:00
midoks ebd8e93b16 update 2018-12-08 23:02:58 +08:00
midoks a45994c3c7 update 2018-12-08 22:33:32 +08:00
midoks f41f616daf update 2018-12-08 17:30:58 +08:00
midoks da5b9351e2 Update install.sh 2018-12-08 17:19:17 +08:00
midoks 3c080e0264 Update index.py 2018-12-08 17:09:36 +08:00
midoks dc62aabfd4 Update index.html 2018-12-08 17:09:33 +08:00
midoks c6da2e56ee Create csvn.js 2018-12-08 17:09:30 +08:00
midoks 461f3dcb0a Update index.html 2018-12-08 17:09:25 +08:00
midoks ee5b9f35ad Update soft.js 2018-12-08 17:07:51 +08:00
midoks 3ad8496daf Update public.js 2018-12-08 16:49:37 +08:00
midoks 77023263a6 Update index.py 2018-12-08 16:25:45 +08:00
midoks 6497627931 update 2018-12-08 16:24:36 +08:00
midoks 2ae3426c82 Update index.py 2018-12-08 15:47:40 +08:00
midoks dbeb919f05 update 2018-12-08 14:43:32 +08:00
midoks 2106746f6c Delete phpfpm_status.conf 2018-12-08 14:43:21 +08:00
midoks 31d5b90670 公共js 2018-12-08 14:43:17 +08:00
midoks ceaf9c42db update 2018-12-08 12:42:02 +08:00
Mr Chen 9067778bf3 u 2018-12-07 19:12:18 +08:00
Mr Chen 99053b67ce 调整 2018-12-07 18:47:33 +08:00
Mr Chen 07b8d91f31 redis调整ok 2018-12-07 17:44:32 +08:00
Mr Chen e9d4e09049 Update index.py 2018-12-07 16:44:08 +08:00
Mr Chen 629416760f Update install.sh 2018-12-07 15:55:12 +08:00
Mr Chen d1ade4355e Update index.py 2018-12-07 15:52:40 +08:00
Mr Chen 4508e30ea7 加入自启动选项功能
1.memcached 调整ok
2018-12-07 15:49:59 +08:00
Mr Chen b1c5c90bef update 2018-12-07 14:18:30 +08:00
midoks e9a7db2c1d update 2018-12-06 23:29:41 +08:00
Mr Chen 63e5f26491 u 2018-12-06 19:49:54 +08:00
Mr Chen ed93ccc0ee Update plugin_api.py 2018-12-06 15:41:57 +08:00
midoks 929a50c137 up 2018-12-06 00:09:25 +08:00
Mr Chen fe87092750 Update soft.js 2018-12-05 20:26:38 +08:00
Mr Chen c144cead18 u 2018-12-05 20:15:00 +08:00
Mr Chen afdc9720fc u 2018-12-05 18:46:45 +08:00
Mr Chen 194c7b9d45 Delete control.conf 2018-12-05 18:45:57 +08:00
Mr Chen 162557230a u 2018-12-05 17:35:24 +08:00
Mr Chen f4dfe502cb u 2018-12-05 17:34:32 +08:00
Mr Chen 7a3d49a9cf u 2018-12-05 17:04:20 +08:00
Mr Chen 49f1407c42 u 2018-12-05 16:24:39 +08:00
Mr Chen 319f72865d Update install.sh 2018-12-05 15:13:28 +08:00
Mr Chen 0eaa6f38e0 update 2018-12-05 14:56:50 +08:00
Mr Chen eeef8d488c Update info.json 2018-12-05 14:20:34 +08:00
Mr Chen 4e69f9540a u 2018-12-05 14:12:10 +08:00
Mr Chen a0e8d75af7 u 2018-12-05 14:00:31 +08:00
Mr Chen f54f7d4ce3 Update soft.js 2018-12-05 11:22:38 +08:00
Mr Chen 5f4893c115 u 2018-12-05 11:18:31 +08:00
Mr Chen a48b869fe9 abkill 2018-12-05 11:15:06 +08:00
Mr Chen 266a8cf806 up 2018-12-05 11:09:48 +08:00
Mr Chen 13e4dcf8ad u 2018-12-05 11:01:25 +08:00
Mr Chen 1ca469518d csvn update 2018-12-05 10:36:41 +08:00
midoks 4284a3daf4 Update site.html 2018-12-04 23:35:33 +08:00
midoks 84995650ee Update task.py 2018-12-04 23:16:47 +08:00
midoks fa662d75d6 update 2018-12-04 23:15:00 +08:00
Mr Chen 842c0daf70 up 2018-12-04 19:38:27 +08:00
Mr Chen 798608287e Update info.json 2018-12-04 19:22:10 +08:00
Mr Chen 437225374e u 2018-12-04 19:20:54 +08:00
Mr Chen 3a442570db Update system_api.py 2018-12-04 19:19:26 +08:00
Mr Chen 366c3677c2 u 2018-12-04 18:55:42 +08:00
Mr Chen 6dcf1db856 u 2018-12-04 18:55:27 +08:00
Mr Chen b3ca295e51 Update info.json 2018-12-04 13:59:48 +08:00
Mr Chen 03f06ee384 Update .gitignore 2018-12-04 13:56:47 +08:00
Mr Chen 2dc96cd04e u 2018-12-04 13:38:08 +08:00
Mr Chen a875293116 u 2018-12-04 13:26:58 +08:00
Mr Chen 8735fb9238 u 2018-12-04 13:22:22 +08:00
Mr Chen 58fcf0e8f9 Update install.sh 2018-12-04 13:13:36 +08:00
Mr Chen fccc30ebb1 Update system_api.py 2018-12-04 13:05:15 +08:00
Mr Chen 6b9da57ff2 u 2018-12-03 19:37:46 +08:00
Mr Chen cd6b2ad65e 代码打包 2018-12-03 18:22:04 +08:00
Mr Chen 60b2834adf Update system_api.py 2018-12-03 18:03:28 +08:00
Mr Chen c74e0428fd Update info.json 2018-12-03 17:57:08 +08:00
Mr Chen 20d486629e u 2018-12-03 17:52:11 +08:00
Mr Chen f984e4ecc7 u 2018-12-03 17:50:43 +08:00
Mr Chen 0bdea14560 Update .gitignore 2018-12-03 17:24:57 +08:00
Mr Chen 0c3599facb u 2018-12-03 17:24:49 +08:00
Mr Chen 05eb434bf8 Update system_api.py 2018-12-03 16:44:35 +08:00
Mr Chen 12dccc1df0 u 2018-12-03 16:44:29 +08:00
Mr Chen 11e7316911 Update info.json 2018-12-03 14:24:40 +08:00
Mr Chen 26a6a80504 u 2018-12-03 13:52:12 +08:00
Mr Chen 498799578a u 2018-12-03 13:44:20 +08:00
Mr Chen 6a5b009766 u 2018-12-03 13:39:06 +08:00
Mr Chen 8e23411be8 u 2018-12-03 13:11:43 +08:00
Mr Chen b597255d68 u 2018-12-03 12:49:03 +08:00
Mr Chen 8979011ec3 u 2018-12-03 10:58:41 +08:00
midoks 11a21f9a8b Update crontab.html 2018-12-02 23:27:47 +08:00
midoks 1a12f625cd up 2018-12-02 22:58:14 +08:00
midoks 11e44d5b0e 监控完成 2018-12-02 21:59:33 +08:00
midoks 47c1394de6 u 2018-12-02 12:58:59 +08:00
midoks 5e7fa28feb Update task.py 2018-12-01 18:04:59 +08:00
midoks d04f891ee7 up 2018-12-01 18:02:30 +08:00
midoks 3d28e0a3cb u 2018-12-01 17:20:10 +08:00
Mr Chen 37112546b9 Delete system.db 2018-11-30 19:13:20 +08:00
Mr Chen cb719c9973 Update .gitignore 2018-11-30 19:13:01 +08:00
Mr Chen 7ec5fe84b2 update 2018-11-30 19:12:16 +08:00
Mr Chen c68cce0198 up 2018-11-30 17:39:38 +08:00
Mr Chen 0d7fd11de5 up 2018-11-30 16:58:50 +08:00
Mr Chen 643a2e8cf8 u 2018-11-30 14:54:06 +08:00
midoks 35ee7d3d10 优化 2018-11-30 02:03:05 +08:00
midoks 2ce3871ee2 Update .gitignore 2018-11-29 21:04:39 +08:00
midoks 812ce86187 u 2018-11-29 21:04:13 +08:00
Mr Chen 3d44b3014f u 2018-11-29 19:16:12 +08:00
Mr Chen 092494a216 Update soft.js 2018-11-29 19:09:27 +08:00
Mr Chen a21ad254b7 Update soft.js 2018-11-29 19:07:28 +08:00
Mr Chen ebd6b9f389 u 2018-11-29 18:19:18 +08:00
midoks 33b90a976b 版本显示优化 2018-11-28 23:56:10 +08:00
midoks 2518d32019 wd 2018-11-28 21:35:26 +08:00
Mr Chen 4ded4679f3 up 2018-11-28 19:11:55 +08:00
midoks 28d3996d17 openresty 2018-11-27 23:29:28 +08:00
midoks b76950ed3b php 72 2018-11-27 23:05:01 +08:00
Mr Chen d49aa168eb u 2018-11-27 19:20:46 +08:00
Mr Chen 5304d0b228 u 2018-11-27 14:37:24 +08:00
Mr Chen 56e4ef1a4e u 2018-11-27 13:17:06 +08:00
Mr Chen 91fc83e0ba a 2018-11-26 19:18:50 +08:00
Mr Chen fc0fdd5772 u 2018-11-26 16:08:19 +08:00
Mr Chen 0d0007d9a1 u 2018-11-26 15:57:49 +08:00
Mr Chen a74ace856a u 2018-11-26 15:54:42 +08:00
Mr Chen f46af799a9 代码调整 2018-11-26 14:35:52 +08:00
Mr Chen 3e4facbf57 u 2018-11-26 13:57:06 +08:00
Mr Chen ff9466d0a4 wd 2018-11-26 11:51:27 +08:00
Mr Chen 9cbcff5dbc 优化 2018-11-26 10:55:53 +08:00
midoks 90834415bf update 2018-11-25 23:30:19 +08:00
midoks c2862ab5d4 Update index.js 2018-11-25 18:11:30 +08:00
midoks 664a7864bc 首页界面更新 2018-11-25 18:05:39 +08:00
midoks 9cf6a40493 update 2018-11-25 17:48:48 +08:00
midoks 028422337e mem 2018-11-25 16:46:23 +08:00
midoks 5f10d9433c redis 设置 2018-11-25 16:13:59 +08:00
Mr Chen ed49f0b0bd Update redis.js 2018-11-23 19:14:18 +08:00
Mr Chen 090fc0f243 redis文件修改 2018-11-23 15:02:02 +08:00
Mr Chen f2df81694f Update install.sh 2018-11-23 11:45:53 +08:00
Mr Chen 6cf2e2d6b6 wd 2018-11-23 11:39:15 +08:00
Mr Chen defdc3d3b8 Update README.md 2018-11-23 10:09:19 +08:00
Mr Chen 6d1d1b882e Update install.sh 2018-11-22 18:58:46 +08:00
Mr Chen 54f90c9300 Update install.sh 2018-11-22 18:56:28 +08:00
Mr Chen a1aa7d465d Update README.md 2018-11-22 18:49:41 +08:00
Mr Chen 62214c2a88 Update plugins.py 2018-11-22 18:44:19 +08:00
Mr Chen d5a4958566 wd 2018-11-22 17:47:19 +08:00
Mr Chen 0bca4a3589 wd 2018-11-22 17:08:26 +08:00
Mr Chen 30bc8b1ec1 u 2018-11-21 19:27:26 +08:00
Mr Chen 0472102a3a u 2018-11-21 19:15:37 +08:00
Mr Chen 2da863d98a u 2018-11-21 18:18:17 +08:00
Mr Chen 88bab4b15b wq 2018-11-21 10:15:35 +08:00
Mr Chen d1b4a1cde1 up 2018-11-20 19:11:09 +08:00
Mr Chen d88f6903da Update task.py 2018-11-20 18:54:29 +08:00
Mr Chen 3a53b360b7 o 2018-11-20 17:43:29 +08:00
Mr Chen 3e5b951a41 wd 2018-11-20 14:01:17 +08:00
Mr Chen 272b6fdeea up 2018-11-19 13:32:17 +08:00
Mr Chen 49ac781e87 wq 2018-11-13 14:18:06 +08:00
Mr Chen b4f9fa0976 Update route/dashboard.py 2018-11-12 17:24:59 +08:00
Mr Chen 96baa99bdc wq 2018-11-12 17:22:47 +08:00
Mr Chen 5db4f39c76 o 2018-11-12 14:43:14 +08:00
Mr Chen 23dadd7f6f wq 2018-11-12 14:38:35 +08:00
Mr Chen 7d8d48f3d5 wq 2018-11-12 12:55:17 +08:00
Mr Chen 74fd4bbe08 o 2018-11-12 11:41:00 +08:00
midoks 30240443e6 update 2018-11-11 23:51:11 +08:00
Mr Chen e069c3a24e w 2018-11-09 16:41:11 +08:00
Mr Chen 73e75abb5f w 2018-11-09 16:23:17 +08:00
Mr Chen b35d516a8e o 2018-11-09 15:46:28 +08:00
Mr Chen aa1875612b Update templates/default/layout.html 2018-11-09 11:10:33 +08:00
Mr Chen b189d5b485 Update templates/default/layout.html 2018-11-09 11:10:11 +08:00
Mr Chen 33b43b253c Update templates/default/layout.html 2018-11-09 11:09:47 +08:00
midoks 86cfb1b9cf q 2018-11-08 22:56:12 +08:00
Mr Chen f93afb772c Update templates/default/login.html 2018-11-08 17:59:31 +08:00
Mr Chen bd49bd3004 Update scripts/install.sh 2018-11-08 17:54:27 +08:00
Mr Chen db26b09eba q 2018-11-08 17:38:15 +08:00
Mr Chen 85da65ad1e Update templates/default/login.html 2018-11-08 17:24:44 +08:00
Mr Chen d9a409ffcc Update app.py 2018-11-08 17:22:03 +08:00
Mr Chen ea923a45a6 q 2018-11-08 17:19:13 +08:00
Mr Chen 7480cfb5d8 Update static/css/install.css 2018-11-08 17:18:59 +08:00
Mr Chen be513af18e q 2018-11-08 17:09:25 +08:00
Mr Chen 1c5e61a3de q 2018-11-08 17:09:06 +08:00
Mr Chen d26474f222 a 2018-11-08 17:08:41 +08:00
Mr Chen 03c796775a Update static/js/jquery.qrcode.min.js 2018-11-08 17:06:06 +08:00
Mr Chen 182d434f84 d 2018-11-08 17:04:57 +08:00
Mr Chen 7c1d409e61 o 2018-11-08 16:53:01 +08:00
midoks dab12535f2 Update templates/default/login.html 2018-11-08 00:02:08 +08:00
midoks deffb3d61b Update route/dashboard.py 2018-11-08 00:02:05 +08:00
Mr Chen a4a45f2005 Update route/files.py 2018-11-07 18:45:34 +08:00
Mr Chen 32d6a89bd4 Update route/dashboard.py 2018-11-07 18:28:48 +08:00
Mr Chen f41c2454ee u 2018-11-07 18:13:05 +08:00
midoks 76dba077c0 o 2018-11-06 23:45:28 +08:00
Mr Chen 1c34488abb Update templates/default/login.html 2018-11-06 19:10:33 +08:00
Mr Chen 6742d971eb u 2018-11-06 13:42:24 +08:00
Mr Chen 3de01da4ba Update models/index.html 2018-11-06 13:23:16 +08:00
midoks 4ba526ca2b up 2018-11-06 00:28:02 +08:00
midoks a4e8b6a137 u 2018-11-05 23:47:37 +08:00
midoks 50ad3ed7e7 ww 2018-11-05 23:42:01 +08:00
Mr Chen 64d29659f7 u 2018-11-05 19:25:07 +08:00
Mr Chen 2794f49df4 u 2018-11-05 19:05:33 +08:00
Mr Chen 3e27f85719 u 2018-11-05 17:19:02 +08:00
Mr Chen a4d70f2294 up 2018-11-05 16:49:37 +08:00
midoks f3cd1f597e up 2018-11-04 23:37:33 +08:00
midoks 489c363daf u 2018-11-04 23:20:06 +08:00
midoks 77f44481b3 up 2018-11-04 23:02:45 +08:00
midoks fcd4ba024a u 2018-11-03 18:19:47 +08:00
Mr Chen ce6b15939d dd 2018-11-02 14:43:41 +08:00
Mr Chen baaccb7960 u 2018-11-02 13:38:20 +08:00
Mr Chen fb559e9f11 u 2018-11-02 10:18:58 +08:00
Mr Chen 283a2c052b u 2018-10-29 20:19:59 +08:00
Mr Chen a7bd9e3290 csvn dev 2018-10-29 14:10:41 +08:00
Mr Chen b64dbb9aa4 Update data/system.db 2018-10-26 16:56:15 +08:00
Mr Chen d9f63c3a9a u 2018-10-26 16:53:20 +08:00
Mr Chen 3c02af41bc u 2018-10-26 15:54:23 +08:00
Mr Chen ac87a6c8b1 Update app.py 2018-10-26 15:02:57 +08:00
Mr Chen f19dd2a2b9 u 2018-10-26 15:01:33 +08:00
Mr Chen cef7215fdc u 2018-10-26 13:53:39 +08:00
Mr Chen edb4fc96e1 u 2018-10-26 13:17:19 +08:00
midoks af9f8b73ba 修改模板 2018-10-25 23:23:37 +08:00
Mr Chen c85152e85a update 2018-10-25 19:32:21 +08:00
Mr Chen 2ee2440c68 u 2018-10-25 17:33:34 +08:00
Mr Chen ecfafc9723 u 2018-10-25 16:40:45 +08:00
Mr Chen dbb4414e65 Update .idea/vcs.xml 2018-10-24 17:27:45 +08:00
midoks a028e93881 u 2018-10-17 22:57:37 +08:00
midoks 475cb5176d u 2018-10-17 00:29:33 +08:00
midoks 8b07bd80e6 u 2018-10-17 00:17:59 +08:00
midoks 50d26d932f Update templates/default/config.html 2018-10-17 00:08:44 +08:00
midoks 22b5ab1179 Update del_pyc.sh 2018-10-14 20:55:05 +08:00
midoks f7c76fb261 画 2018-10-14 20:49:20 +08:00
midoks 6531f686ad Update templates/default/database.html 2018-10-14 18:20:27 +08:00
midoks b716f05fb4 u 2018-10-14 17:37:43 +08:00
midoks 9a98f1c859 u 2018-10-14 12:47:54 +08:00
midoks e92fc4cfd1 u 2018-10-14 11:49:24 +08:00
midoks da1a76cbef u 2018-10-13 22:54:11 +08:00
Mr Chen fa6b7c21ac u 2018-10-12 19:09:54 +08:00
Mr Chen 11748fd33b Update plugins/deployment/icon.png 2018-10-12 18:46:22 +08:00
midoks 267bbe3865 u 2018-10-12 10:35:29 +08:00
midoks dd27e4b076 Update class/page.py 2018-10-12 10:28:52 +08:00
Mr Chen 459229ba15 Update plugins/nginx/install.sh 2018-10-11 19:30:01 +08:00
Mr Chen 94c5161fde u 2018-10-11 19:26:06 +08:00
Mr Chen 5646d1404c u 2018-10-11 09:55:27 +08:00
Mr Chen ef8a10b68d Update views/plugins.py 2018-10-09 19:53:03 +08:00
Mr Chen c772696f3e Update views/plugins.py 2018-10-09 19:51:23 +08:00
Mr Chen 45faf4e9dd Update views/plugins.py 2018-10-08 20:10:44 +08:00
Mr Chen 5cbca9232c Update app.py 2018-10-08 11:52:55 +08:00
midoks 742bb6d86d u 2018-10-07 23:51:22 +08:00
midoks b14accd83e u 2018-10-07 20:54:10 +08:00
midoks 8ae01d8d36 u 2018-10-07 20:38:30 +08:00
midoks 5db1e58e6a u 2018-10-07 18:51:52 +08:00
midoks a2e6d2f280 u 2018-10-07 18:25:51 +08:00
midoks 83f3d224ed d 2018-10-07 17:57:08 +08:00
midoks 73693620df u 2018-10-07 17:42:46 +08:00
midoks 72eb67dfda u 2018-10-07 16:29:42 +08:00
midoks c55b4a02c8 插件 2018-10-02 21:50:10 +08:00
midoks 721efd6a16 up 2018-10-02 18:00:48 +08:00
midoks 61c8ce4b6f up 2018-10-02 17:24:26 +08:00
midoks ce95ca6905 up 2018-10-02 16:59:56 +08:00
Mr Chen 01dee5fe1f up 2018-09-26 20:03:12 +08:00
Mr Chen 1a72edee9a 更新 2018-09-26 20:02:11 +08:00
Mr Chen 27b6ad0280 up 2018-09-26 14:59:06 +08:00
Mr Chen ae9e6921c3 up 2018-09-26 13:32:57 +08:00
Mr Chen b51eb99027 up 2018-09-25 18:43:26 +08:00
Mr Chen 2e584c540d up 2018-09-25 17:01:20 +08:00
Mr Chen bbf258e1a7 up 2018-09-25 16:37:56 +08:00
Mr Chen 53d57716aa o 2018-09-25 14:16:10 +08:00
Mr Chen e9a6e5477d up 2018-09-25 13:59:20 +08:00
Mr Chen 46ca8a6b44 up 2018-09-25 12:50:06 +08:00
Mr Chen d6f88caf3d up 2018-09-21 14:18:29 +08:00
midoks abc85902a2 up 2018-09-15 16:45:14 +08:00
Mr Chen 9edc8bbea2 up 2018-09-14 19:18:36 +08:00
Mr Chen 443d3efd37 up 2018-09-14 15:23:04 +08:00
midoks 948bcde358 模版 2018-09-13 22:30:37 +08:00
midoks 83aa3cfca6 up 2018-09-13 22:26:34 +08:00
Mr Chen 976c88ed44 Delete .DS_Store 2018-09-13 22:24:06 +08:00
midoks 0db16797b5 up 2018-09-13 22:23:05 +08:00
midoks b7802fc898 更新说明 2018-09-13 22:22:23 +08:00
midoks 741dffd5db up 2018-09-13 22:20:52 +08:00
Mr Chen 2c9f11bcfe static 2018-09-13 13:36:11 +08:00
midoks 16893e51e6 up 2018-09-11 23:02:52 +08:00
midoks 34a43a6af9 up 2018-09-11 22:42:43 +08:00
midoks 4dd5d946d9 up 2018-09-11 22:39:22 +08:00
Mr Chen 7e63f686b9 up 2018-09-11 16:27:09 +08:00
Mr Chen 7b57972179 up 2018-09-11 14:50:44 +08:00
Mr Chen a758a36bdc test 2018-09-11 14:48:31 +08:00
Mr Chen 84123c603d Create README.md 2018-09-11 14:44:23 +08:00
Mr Chen 33f9c09a07 Initial commit 2018-09-11 14:44:15 +08:00
1240 changed files with 16526 additions and 129240 deletions
-5
View File
@@ -1,5 +0,0 @@
# These are supported funding model platforms
github: midoks
custom: https://afdian.net/a/mdserver-web
@@ -1,29 +0,0 @@
---
name: BUG提交
about: 问题描述
---
## 什么系统 ?
Debian x, Centos x, Centos x stream, Ubuntu x?
## 错误信息 ?
Ex:
```bash
一个issue,一个问题。多余问题,视情况而答。
```
## 错误截图 ?
...
## 浏览器版本 ?
...
## 软件版本(插件/面板) ?
...
@@ -1,14 +0,0 @@
---
name: 需求提交
about: 需求描述
---
## 需求
想开发一个什么插件?
想有什么功能?
## 提供参考
给开发者提供参考!
-24
View File
@@ -1,24 +0,0 @@
name: Bug提交
description: 提交错误报告以帮助我们改进
labels: ["\U0001F48A bug"]
body:
- type: markdown
attributes:
value: |
感谢您花时间填写此错误报告!
- 如有疑问,请讨论[Discussions](https://github.com/midoks/mdserver-web/discussions).
- 检查以确保尚未有人打开类似的[issue](https://github.com/midoks/mdserver-web/issues).
- type: input
attributes:
label: 操作系统
description: |
请指定您报告的确切操作系统名称和版本,例如"CentOS 7"、"Ubuntu 20.04"。
validations:
required: true
- type: textarea
attributes:
label: 描述错误
description: 对bug的清晰而简洁的描述。
validations:
required: true
-8
View File
@@ -1,8 +0,0 @@
blank_issues_enabled: true
contact_links:
- name: 提出问题
url: https://github.com/midoks/mdserver-web/discussions
about: 请在讨论中提出问题。
- name: 提出建议
url: https://github.com/midoks/mdserver-web/discussions/categories/proposal
about: 请在讨论中提出建议。
-24
View File
@@ -1,24 +0,0 @@
name: Bug提交
description: 提交错误报告以帮助我们改进
labels: ["\U0001F48A bug"]
body:
- type: markdown
attributes:
value: |
感谢您花时间填写此错误报告!
- 如有疑问,请讨论[Discussions](https://github.com/midoks/mdserver-web/discussions).
- 检查以确保尚未有人打开类似的[issue](https://github.com/midoks/mdserver-web/issues).
- type: input
attributes:
label: 操作系统
description: |
请指定您报告的确切操作系统名称和版本,例如"CentOS 7"、"Ubuntu 20.04"。
validations:
required: true
- type: textarea
attributes:
label: 描述错误
description: 对bug的清晰而简洁的描述。
validations:
required: true
@@ -1,24 +0,0 @@
name: Bug提交
description: 提交错误报告以帮助我们改进
labels: ["\U0001F48A bug"]
body:
- type: markdown
attributes:
value: |
感谢您花时间填写此错误报告!
- 如有疑问,请讨论[Discussions](https://github.com/midoks/mdserver-web/discussions).
- 检查以确保尚未有人打开类似的[issue](https://github.com/midoks/mdserver-web/issues).
- type: input
attributes:
label: 操作系统
description: |
请指定您报告的确切操作系统名称和版本,例如"CentOS 7"、"Ubuntu 20.04"。
validations:
required: true
- type: textarea
attributes:
label: 描述错误
description: 对bug的清晰而简洁的描述。
validations:
required: true
-3
View File
@@ -1,3 +0,0 @@
### 合并描述
- 我添加了测试用例来覆盖新代码。
-38
View File
@@ -1,38 +0,0 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: MW APP MySQL55
on:
push:
branches: [ "run_test" ]
pull_request:
branches: [ "run_test" ]
permissions:
contents: read
jobs:
build:
strategy:
matrix:
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-22.04]
runs-on: ${{ matrix.os }}
#runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install MW
run: |
sudo bash scripts/install_dev.sh
- name: Install MySQL55
run: |
cd /www/server/mdserver-web/plugins/mysql && sudo bash install.sh install 5.5
- name: Start DEBUG
run: |
gunicorn -c setting.py app:app
python3 task.py &
-38
View File
@@ -1,38 +0,0 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: MW APP MySQL56
on:
push:
branches: [ "run_test" ]
pull_request:
branches: [ "run_test" ]
permissions:
contents: read
jobs:
build:
strategy:
matrix:
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-22.04]
runs-on: ${{ matrix.os }}
#runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install MW
run: |
sudo bash scripts/install_dev.sh
- name: Install MySQL56
run: |
cd /www/server/mdserver-web/plugins/mysql && sudo bash install.sh install 5.6
- name: Start DEBUG
run: |
gunicorn -c setting.py app:app
python3 task.py &
-38
View File
@@ -1,38 +0,0 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: MW APP MySQL57
on:
push:
branches: [ "run_test" ]
pull_request:
branches: [ "run_test" ]
permissions:
contents: read
jobs:
build:
strategy:
matrix:
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-22.04]
runs-on: ${{ matrix.os }}
#runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install MW
run: |
sudo bash scripts/install_dev.sh
- name: Install MySQL57
run: |
cd /www/server/mdserver-web/plugins/mysql && sudo bash install.sh install 5.7
- name: Start DEBUG
run: |
gunicorn -c setting.py app:app
python3 task.py &
-38
View File
@@ -1,38 +0,0 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: MW APP MySQL80
on:
push:
branches: [ "run_test" ]
pull_request:
branches: [ "run_test" ]
permissions:
contents: read
jobs:
build:
strategy:
matrix:
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-22.04]
runs-on: ${{ matrix.os }}
#runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install MW
run: |
sudo bash scripts/install_dev.sh
- name: Install MySQL80
run: |
cd /www/server/mdserver-web/plugins/mysql && sudo bash install.sh install 8.0
- name: Start DEBUG
run: |
gunicorn -c setting.py app:app
python3 task.py &
-38
View File
@@ -1,38 +0,0 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: MW APP OpenResty
on:
push:
branches: [ "master", "dev" ]
pull_request:
branches: [ "master", "dev" ]
permissions:
contents: read
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
#runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install MW
run: |
sudo bash scripts/install_dev.sh
- name: Install OpenResty
run: |
cd /www/server/mdserver-web/plugins/openresty && sudo bash install.sh install 1.21.4.1
- name: Start DEBUG
run: |
gunicorn -c setting.py app:app
python3 task.py &
-68
View File
@@ -1,68 +0,0 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: MW APP PHP
on:
push:
branches: [ "run_test" ]
pull_request:
branches: [ "run_test" ]
permissions:
contents: read
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
#runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install MW
run: |
sudo bash scripts/install_dev.sh
- name: Install PHP53
run: |
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 53
- name: Install PHP54
run: |
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 54
- name: Install PHP55
run: |
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 55
- name: Install PHP56
run: |
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 56
- name: Install PHP70
run: |
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 70
- name: Install PHP71
run: |
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 71
- name: Install PHP72
run: |
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 72
- name: Install PHP73
run: |
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 73
- name: Install PHP74
run: |
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 74
- name: Install PHP80
run: |
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 80
- name: Install PHP81
run: |
cd /www/server/mdserver-web/plugins/php && sudo bash install.sh install 81
- name: Start DEBUG
run: |
gunicorn -c setting.py app:app
python3 task.py &
+4 -69
View File
@@ -8,6 +8,7 @@ __pycache__/
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
@@ -104,79 +105,13 @@ venv.bak/
.DS_Store
.idea/*.xml
.idea/*.iml
tmp/*
tmp/*.pl
tmp/*.log
*.swp
*.pem
*.zip
scripts/init.d/mw
logs/*
data/*.db
data/control.conf
data/iplist.txt
data/json/index.json
data/json/config.json
data/site.pl
data/admin_path.pl
data/close.pl
data/datadir.pl
data/502Task.pl
data/default.pl
data/backup.pl
data/debug.pl
data/default_site.pl
ssl/input.pl
lib/python*
bin
pyvenv.cfg
include
share
pip-selfcheck.json
scripts/init.d/mw
scripts/mdserver-web
data/api_login.txt
data/sessions
data/ssl.pl
data/port.pl
data/ipv6.pl
data/restart.pl
data/ssl.pl
data/edate.pl
data/osname.pl
data/only_netio_counters.pl
data/system.db-journal
data/hook_*.json
data/letsencrypt.json
data/basic_auth.json
data/notify.json
data/api.json
data/bind_domain.pl
data/unauthorized_status.pl
plugins/vip_*
plugins/own_*
plugins/my_*
plugins/l2tp
plugins/openlitespeed
plugins/system_safe
plugins/tamper_proof
plugins/tamper_proof_*
plugins/cryptocurrency_trade
plugins/op_load_balance
plugins/gdrive
plugins/mtproxy
plugins/zimg
plugins/bk_demo
plugins/mail
plugins/fastdfs
plugins/v2ray
plugins/frp
plugins/file_search
debug.out
+1 -1
View File
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [midoks] [midoks of copyright owner]
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+5 -204
View File
@@ -1,206 +1,7 @@
<p align="center">
<img alt="logo" src="https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/logo.png" height="140" />
<h3 align="center">mdserver-web</h3>
<p align="center">一款简单Linux面板服务</p>
<p align="center">强烈推荐系统:debian</p>
</p>
### 简介
简单的Linux面板,感谢BT.CN写出如此好的web管理软件。我一看到,就知道这是我一直想要的页面化管理方式。
复制了后台管理界面,按照自己想要的方式写了一版。
![Debian](https://img.shields.io/badge/LINUX-Debian-blue?style=for-the-badge&logo=Debian)
![Ubuntu](https://img.shields.io/badge/LINUX-Ubuntu-blue?style=for-the-badge&logo=Ubuntu)
![Fedora](https://img.shields.io/badge/LINUX-Fedora-blue?style=for-the-badge&logo=Fedora)
![CentOS](https://img.shields.io/badge/LINUX-CentOS-blue?style=for-the-badge&logo=CentOS)
[![Wiki](https://img.shields.io/badge/MW-Wiki-red?style=for-the-badge&logo=wiki)](https://github.com/midoks/mdserver-web/wiki)
[![](https://data.jsdelivr.com/v1/package/gh/midoks/mdserver-web/badge?style=for-the-badge)](https://www.jsdelivr.com/package/gh/midoks/mdserver-web)
* SSH终端工具
* 面板收藏功能
* 网站子目录绑定
* 网站备份功能
* 插件方式管理
基本上可以使用,后续会继续优化!欢迎提供意见!
- 吹水组 - https://t.me/mdserver_web
- 交流论坛 - https://bbs.midoks.me
# mdserver-web
简单的Linux面板
### 自动安装
```
如果出现问题,最好私给我面板信息。不要让我猜。如果不提供,不要提出问题,自行解决。 — 座右铭
Talk is cheap, show me the code. -- linus
```
- [兼容性测试报告](/compatibility.md)
- [常用命令说明](/cmd.md)
### 主要插件介绍
* OpenResty - 轻量级,占有内存少,并发能力强。
* PHP[53-82] - PHP是世界上最好的编程语言。
* MySQL - 一种关系数据库管理系统。
* MariaDB - 是MySQL的一个重要分支。
* MySQL[APT/YUM] - 一种关系数据库管理系统。
* MongoDB - 一种非关系NOSQL数据库管理系统。
* phpMyAdmin - 著名Web端MySQL管理工具。
* Memcached - 一个高性能的分布式内存对象缓存系统。
* Redis - 一个高性能的KV数据库。
* PureFtpd - 一款专注于程序健壮和软件安全的免费FTP服务器软件。
* Gogs - 一款极易搭建的自助Git服务。
* Rsyncd - 通用同步服务。
### 插件开发相关
```
插件文档还不完善,如果有不明白的地方提Issue! 我会尽力完善。
如果你自己写了插件,想分享出来,也可以提Issue。
```
- 简单例子 - https://github.com/mw-plugin/simple-plugin
- 插件地址 - https://github.com/mw-plugin
- 开发文档 - https://github.com/midoks/mdserver-web/wiki/插件开发
# Note
```
phpMyAdmin[4.4.15]支持MySQL[5.5-5.7]
phpMyAdmin[5.2.0]支持MySQL[8.0]
PHP[53-72]支持phpMyAdmin[4.4.15]
PHP[72-82]支持phpMyAdmin[5.2.0]
```
# 特别赞助
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan.la/)
# AD - VPS推荐 - 🙏
- [ZZZ评测](https://www.zzzvps.com/)
| 服务商 | LOGO | 推广地址 | 优惠码 |
| ------------- |----------|-----------|-------|
| digitalvirt |[![digitalvirt](https://digitalvirt.com/templates/BlueWhite/img/logo-dark.svg)](https://digitalvirt.com/aff.php?aff=154) | https://digitalvirt.com/aff.php?aff=154 | mdserver-web |
# Docker
- 由[DDSRem](https://github.com/DDSRem)开发维护。
- https://hub.docker.com/r/ddsderek/mw
```
docker run -itd --name mw-server --privileged=true -p 7200:7200 -p 80:80 -p 443:443 -p 888:888 ddsderek/mw-server:latest
```
### 版本更新 0.13.2
* supervisor添加重启功能。
* 加入滚动写入日志 mw.writeFileLog方法。
* mysql导出优化优化。
* 添加tgbot插件[仅测试]。
* TelegramBot机器人通知-加入配置。
* mariadb更新版本。
* 在线文件编辑优化。
### JSDelivr安装地址
- 初始安装
```
curl -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/install.sh | bash
```
- 直接更新
```
curl -fsSL https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/update.sh | bash
```
- 卸载脚本
```
wget -O uninstall.sh https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/scripts/uninstall.sh && bash uninstall.sh
```
### 备用地址
- 初始安装
```
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/install.sh | bash
curl --insecure -fsSL https://gitee.com/midoks/mdserver-web/raw/master/scripts/install.sh | bash
```
- 直接更新
```
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/update.sh | bash
```
- 卸载脚本
```
wget -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/uninstall.sh && bash uninstall.sh
```
### 通用软件安装[命令行安装]
- 需已经安装mdserver-web
```
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/app.sh | bash
```
### DEV使用
```
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/install_dev.sh | bash
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/update_dev.sh | bash
wget -O uninstall.sh https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/uninstall.sh && bash uninstall.sh
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/quick/debug.sh | bash
curl -fsSL https://gitee.com/midoks/mdserver-web/raw/dev/scripts/install_dev.sh | bash
curl -fsSL https://gitee.com/midoks/mdserver-web/raw/dev/scripts/update_dev.sh | bash
```
### 捐赠地址 USDT(TRC20)
TVbNgrpeGBGZVm5gTLa21ADP7RpnPFhjya
日行一善,以后必定大富大贵
### 微信赞助
[![截图](https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/img/weixin_zz.jpg)](https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/img/weixin_zz.jpg)
### 无图不真相
[![截图](https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/mdw.jpg)](https://cdn.jsdelivr.net/gh/midoks/mdserver-web@latest/route/static/mdw.jpg)
### Stargazers over time
[![Stargazers over time](https://starchart.cc/midoks/mdserver-web.svg)](https://starchart.cc/midoks/mdserver-web)
### 感谢开发赞助
[![digitalvirt](https://digitalvirt.com/templates/BlueWhite/img/logo-dark.svg)](https://digitalvirt.com/aff.php?aff=154)
### 授权许可
本项目采用 Apache 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://github.com/midoks/mdserver-web/blob/master/LICENSE) 文件中。
curl -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/master/scripts/install.sh | sh
```
+5 -40
View File
@@ -1,51 +1,16 @@
# coding:utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# 入口文件
# ---------------------------------------------------------------------------------
# pip install profiler_online
# 性能测试
# from profiler_online import run_profiler
# run_profiler()
import sys
import io
import os
sys.dont_write_bytecode = True
from route import app, socketio
sys.path.append(os.getcwd() + "/class/core")
import config
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler
from gevent import monkey
monkey.patch_all()
app = config.config().makeApp(__name__)
try:
if __name__ == "__main__":
PORT = 7200
if os.path.exists('data/port.pl'):
f = open('data/port.pl')
PORT = int(f.read())
f.close()
# HOST = '0.0.0.0'
# app.run(host=HOST, port=PORT)
http_server = WSGIServer(
(HOST, PORT), app, handler_class=WebSocketHandler)
http_server.serve_forever()
socketio.run(app, host=HOST, port=PORT)
app.run()
except Exception as ex:
print(ex)
print ex
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-144
View File
@@ -1,144 +0,0 @@
# coding: utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# 公共操作
# ---------------------------------------------------------------------------------
import os
import sys
import time
import string
import json
import hashlib
import shlex
import datetime
import subprocess
import re
import hashlib
from random import Random
import mw
import db
from flask import redirect
def init():
initDB()
initUserInfo()
initInitD()
initInitTask()
def local():
result = checkClose()
if result:
return result
# 检查面板是否关闭
def checkClose():
if os.path.exists('data/close.pl'):
return redirect('/close')
def initDB():
try:
sql = db.Sql().dbfile('default')
csql = mw.readFile('data/sql/default.sql')
csql_list = csql.split(';')
for index in range(len(csql_list)):
sql.execute(csql_list[index], ())
except Exception as ex:
print(str(ex))
def doContentReplace(src, dst):
content = mw.readFile(src)
content = content.replace("{$SERVER_PATH}", mw.getRunDir())
mw.writeFile(dst, content)
def initInitD():
# systemctl
# sysCfgDir = mw.systemdCfgDir()
# if os.path.exists(sysCfgDir) and mw.getOsName() == 'centos' and mw.getOsID() == '9':
# systemd_mw = sysCfgDir + '/mw.service'
# systemd_mw_task = sysCfgDir + '/mw-task.service'
# systemd_mw_tpl = mw.getRunDir() + '/scripts/init.d/mw.service.tpl'
# systemd_mw_task_tpl = mw.getRunDir() + '/scripts/init.d/mw-task.service.tpl'
# if os.path.exists(systemd_mw):
# os.remove(systemd_mw)
# if os.path.exists(systemd_mw_task):
# os.remove(systemd_mw_task)
# doContentReplace(systemd_mw_tpl, systemd_mw)
# doContentReplace(systemd_mw_task_tpl, systemd_mw_task)
# mw.execShell('systemctl enable mw')
# mw.execShell('systemctl enable mw-task')
# mw.execShell('systemctl daemon-reload')
script = mw.getRunDir() + '/scripts/init.d/mw.tpl'
script_bin = mw.getRunDir() + '/scripts/init.d/mw'
doContentReplace(script, script_bin)
mw.execShell('chmod +x ' + script_bin)
# 在linux系统中,确保/etc/init.d存在
if not mw.isAppleSystem() and not os.path.exists("/etc/rc.d/init.d"):
mw.execShell('mkdir -p /etc/rc.d/init.d')
if not mw.isAppleSystem() and not os.path.exists("/etc/init.d"):
mw.execShell('mkdir -p /etc/init.d')
# initd
if os.path.exists('/etc/rc.d/init.d'):
initd_bin = '/etc/rc.d/init.d/mw'
if not os.path.exists(initd_bin):
import shutil
shutil.copyfile(script_bin, initd_bin)
mw.execShell('chmod +x ' + initd_bin)
# 加入自启动
mw.execShell('which chkconfig && chkconfig --add mw')
if os.path.exists('/etc/init.d'):
initd_bin = '/etc/init.d/mw'
if not os.path.exists(initd_bin):
import shutil
shutil.copyfile(script_bin, initd_bin)
mw.execShell('chmod +x ' + initd_bin)
# 加入自启动
mw.execShell('which update-rc.d && update-rc.d -f mw defaults')
# 获取系统IPV4
mw.setHostAddr(mw.getLocalIp())
def initInitTask():
# 创建证书同步命令
import cert_api
api = cert_api.cert_api()
api.createCertCron()
def initUserInfo():
data = mw.M('users').where('id=?', (1,)).getField('password')
if data == '21232f297a57a5a743894a0e4a801fc3':
pwd = mw.getRandomString(8).lower()
file_pw = mw.getRunDir() + '/data/default.pl'
mw.writeFile(file_pw, pwd)
mw.M('users').where('id=?', (1,)).setField(
'password', mw.md5(pwd))
+114
View File
@@ -0,0 +1,114 @@
# coding:utf-8
import sys
import io
import os
import time
import shutil
reload(sys)
sys.setdefaultencoding('utf8')
from flask import Flask, session
from datetime import timedelta
sys.path.append(os.getcwd() + "/class/core")
import db
import public
class middleWare:
def __init__(self, wsgi_app):
self.wsgi_app = wsgi_app
def __call__(self, *args, **kwargs):
return self.wsgi_app(*args, **kwargs)
class config:
__version = '0.0.1'
__app = None
__modules = None
def __init__(self):
pass
def makeApp(self, name):
app = Flask(name)
self.__app = app
app.config.version = self.__version
app.config['SECRET_KEY'] = os.urandom(24)
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
self.initDB()
self.initInitD()
self.initRoute()
# self.startDebug()
app.wsgi_app = middleWare(app.wsgi_app)
return app
def startDebug(self):
self.__app.debug = True
self.__app.config.version = self.__version + str(time.time())
def initDB(self):
try:
sql = db.Sql().dbfile('default')
csql = public.readFile('data/sql/default.sql')
csql_list = csql.split(';')
for index in range(len(csql_list)):
sql.execute(csql_list[index], ())
except Exception, ex:
print str(ex)
def initUser(self):
pass
def initInitD(self):
script = public.getRunDir() + '/scripts/init.d/mw.tpl'
script_bin = public.getRunDir() + '/scripts/init.d/mw'
if os.path.exists(script_bin):
return
content = public.readFile(script)
content = content.replace("{$SERVER_PATH}", public.getRunDir())
public.writeFile(script_bin, content)
public.execShell('chmod +x ' + script_bin)
if public.getOs() != 'darwin':
initd_bin = '/etc/init.d/mw'
if not os.path.exists(initd_bin):
shutil.copyfile(script_bin, initd_bin)
public.execShell('chmod +x ' + initd_bin)
def getVersion(self):
return self.__version
def getApp(self):
return self.__app
def initRoute(self):
import route
DEFAULT_MODULES = (
(route.dashboard, "/"),
(route.site, "/site"),
(route.files, "/files"),
(route.soft, "/soft"),
(route.config, "/config"),
(route.plugins, "/plugins"),
(route.task, "/task"),
(route.system, "/system"),
(route.database, "/database"),
(route.crontab, "/crontab"),
(route.firewall, "/firewall"),
(route.control, "/control")
)
self.modules = DEFAULT_MODULES
self.settingModules(self.__app, DEFAULT_MODULES)
def settingModules(self, app, modules):
for module, url_prefix in modules:
app.register_blueprint(module, url_prefix=url_prefix)
-920
View File
@@ -1,920 +0,0 @@
# coding: utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# 配置操作
# ---------------------------------------------------------------------------------
import psutil
import time
import os
import sys
import mw
import re
import json
import pwd
from flask import session
from flask import request
class config_api:
__version = '0.13.2'
__api_addr = 'data/api.json'
def __init__(self):
pass
def getVersion(self):
return self.__version
##### ----- start ----- ###
# 取面板列表
def getPanelListApi(self):
data = mw.M('panel').field(
'id,title,url,username,password,click,addtime').order('click desc').select()
return mw.getJson(data)
def addPanelInfoApi(self):
title = request.form.get('title', '')
url = request.form.get('url', '')
username = request.form.get('username', '')
password = request.form.get('password', '')
# 校验是还是重复
isAdd = mw.M('panel').where(
'title=? OR url=?', (title, url)).count()
if isAdd:
return mw.returnJson(False, '备注或面板地址重复!')
isRe = mw.M('panel').add('title,url,username,password,click,addtime',
(title, url, username, password, 0, int(time.time())))
if isRe:
return mw.returnJson(True, '添加成功!')
return mw.returnJson(False, '添加失败!')
# 删除面板资料
def delPanelInfoApi(self):
mid = request.form.get('id', '')
isExists = mw.M('panel').where('id=?', (mid,)).count()
if not isExists:
return mw.returnJson(False, '指定面板资料不存在!')
mw.M('panel').where('id=?', (mid,)).delete()
return mw.returnJson(True, '删除成功!')
# 修改面板资料
def setPanelInfoApi(self):
title = request.form.get('title', '')
url = request.form.get('url', '')
username = request.form.get('username', '')
password = request.form.get('password', '')
mid = request.form.get('id', '')
# 校验是还是重复
isSave = mw.M('panel').where(
'(title=? OR url=?) AND id!=?', (title, url, mid)).count()
if isSave:
return mw.returnJson(False, '备注或面板地址重复!')
# 更新到数据库
isRe = mw.M('panel').where('id=?', (mid,)).save(
'title,url,username,password', (title, url, username, password))
if isRe:
return mw.returnJson(True, '修改成功!')
return mw.returnJson(False, '修改失败!')
def syncDateApi(self):
if mw.isAppleSystem():
return mw.returnJson(True, '开发系统不必同步时间!')
data = mw.execShell('ntpdate -s time.nist.gov')
if data[0] == '':
return mw.returnJson(True, '同步成功!')
return mw.returnJson(False, '同步失败:' + data[0])
def setPasswordApi(self):
password1 = request.form.get('password1', '')
password2 = request.form.get('password2', '')
if password1 != password2:
return mw.returnJson(False, '两次输入的密码不一致,请重新输入!')
if len(password1) < 5:
return mw.returnJson(False, '用户密码不能小于5位!')
mw.M('users').where("username=?", (session['username'],)).setField(
'password', mw.md5(password1.strip()))
return mw.returnJson(True, '密码修改成功!')
def setNameApi(self):
name1 = request.form.get('name1', '')
name2 = request.form.get('name2', '')
if name1 != name2:
return mw.returnJson(False, '两次输入的用户名不一致,请重新输入!')
if len(name1) < 3:
return mw.returnJson(False, '用户名长度不能少于3位')
mw.M('users').where("username=?", (session['username'],)).setField(
'username', name1.strip())
session['username'] = name1
return mw.returnJson(True, '用户修改成功!')
def setWebnameApi(self):
webname = request.form.get('webname', '')
if webname != mw.getConfig('title'):
mw.setConfig('title', webname)
return mw.returnJson(True, '面板别名保存成功!')
def setPortApi(self):
port = request.form.get('port', '')
if port != mw.getHostPort():
import system_api
import firewall_api
sysCfgDir = mw.systemdCfgDir()
if os.path.exists(sysCfgDir + "/firewalld.service"):
if not firewall_api.firewall_api().getFwStatus():
return mw.returnJson(False, 'firewalld必须先启动!')
mw.setHostPort(port)
msg = mw.getInfo('放行端口[{1}]成功', (port,))
mw.writeLog("防火墙管理", msg)
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
mw.M('firewall').add('port,ps,addtime', (port, "配置修改", addtime))
firewall_api.firewall_api().addAcceptPort(port)
firewall_api.firewall_api().firewallReload()
system_api.system_api().restartMw()
return mw.returnJson(True, '端口保存成功!')
def setIpApi(self):
host_ip = request.form.get('host_ip', '')
if host_ip != mw.getHostAddr():
mw.setHostAddr(host_ip)
return mw.returnJson(True, 'IP保存成功!')
def setWwwDirApi(self):
sites_path = request.form.get('sites_path', '')
if sites_path != mw.getWwwDir():
mw.setWwwDir(sites_path)
return mw.returnJson(True, '修改默认建站目录成功!')
def setBackupDirApi(self):
backup_path = request.form.get('backup_path', '')
if backup_path != mw.getBackupDir():
mw.setBackupDir(backup_path)
return mw.returnJson(True, '修改默认备份目录成功!')
def setBasicAuthApi(self):
basic_user = request.form.get('basic_user', '').strip()
basic_pwd = request.form.get('basic_pwd', '').strip()
basic_open = request.form.get('is_open', '').strip()
salt = '_md_salt'
path = 'data/basic_auth.json'
is_open = True
if basic_open == 'false':
if os.path.exists(path):
os.remove(path)
return mw.returnJson(True, '删除BasicAuth成功!')
if basic_user == '' or basic_pwd == '':
return mw.returnJson(True, '用户和密码不能为空!')
ba_conf = None
if os.path.exists(path):
try:
ba_conf = json.loads(public.readFile(path))
except:
os.remove(path)
if not ba_conf:
ba_conf = {
"basic_user": mw.md5(basic_user + salt),
"basic_pwd": mw.md5(basic_pwd + salt),
"open": is_open
}
else:
ba_conf['basic_user'] = mw.md5(basic_user + salt)
ba_conf['basic_pwd'] = mw.md5(basic_pwd + salt)
ba_conf['open'] = is_open
mw.writeFile(path, json.dumps(ba_conf))
os.chmod(path, 384)
mw.writeLog('面板设置', '设置BasicAuth状态为: %s' % is_open)
mw.restartMw()
return mw.returnJson(True, '设置成功!')
def setApi(self):
webname = request.form.get('webname', '')
port = request.form.get('port', '')
host_ip = request.form.get('host_ip', '')
domain = request.form.get('domain', '')
sites_path = request.form.get('sites_path', '')
backup_path = request.form.get('backup_path', '')
if domain != '':
reg = "^([\w\-\*]{1,100}\.){1,4}(\w{1,10}|\w{1,10}\.\w{1,10})$"
if not re.match(reg, domain):
return mw.returnJson(False, '主域名格式不正确')
if int(port) >= 65535 or int(port) < 100:
return mw.returnJson(False, '端口范围不正确!')
if webname != mw.getConfig('title'):
mw.setConfig('title', webname)
if sites_path != mw.getWwwDir():
mw.setWwwDir(sites_path)
if backup_path != mw.getWwwDir():
mw.setBackupDir(backup_path)
if port != mw.getHostPort():
import system_api
import firewall_api
sysCfgDir = mw.systemdCfgDir()
if os.path.exists(sysCfgDir + "/firewalld.service"):
if not firewall_api.firewall_api().getFwStatus():
return mw.returnJson(False, 'firewalld必须先启动!')
mw.setHostPort(port)
msg = mw.getInfo('放行端口[{1}]成功', (port,))
mw.writeLog("防火墙管理", msg)
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
mw.M('firewall').add('port,ps,addtime', (port, "配置修改", addtime))
firewall_api.firewall_api().addAcceptPort(port)
firewall_api.firewall_api().firewallReload()
system_api.system_api().restartMw()
if host_ip != mw.getHostAddr():
mw.setHostAddr(host_ip)
mhost = mw.getHostAddr()
info = {
'uri': '/config',
'host': mhost + ':' + port
}
return mw.returnJson(True, '保存成功!', info)
def setAdminPathApi(self):
admin_path = request.form.get('admin_path', '').strip()
admin_path_checks = ['/', '/close', '/login',
'/do_login', '/site', '/sites',
'/download_file', '/control', '/crontab',
'/firewall', '/files', 'config',
'/soft', '/system', '/code',
'/ssl', '/plugins', '/hook']
if admin_path == '':
admin_path = '/'
if admin_path != '/':
if len(admin_path) < 6:
return mw.returnJson(False, '安全入口地址长度不能小于6位!')
if admin_path in admin_path_checks:
return mw.returnJson(False, '该入口已被面板占用,请使用其它入口!')
if not re.match("^/[\w\./-_]+$", admin_path):
return mw.returnJson(False, '入口地址格式不正确,示例: /mw_rand')
# else:
# domain = mw.readFile('data/bind_domain.pl')
# if not domain:
# domain = ''
# limitip = mw.readFile('data/bind_limitip.pl')
# if not limitip:
# limitip = ''
# if not domain.strip() and not limitip.strip():
# return mw.returnJson(False,
# '警告,关闭安全入口等于直接暴露你的后台地址在外网,十分危险,至少开启以下一种安全方式才能关闭:<a
# style="color:red;"><br>1、绑定访问域名<br>2、绑定授权IP</a>')
admin_path_file = 'data/admin_path.pl'
admin_path_old = '/'
if os.path.exists(admin_path_file):
admin_path_old = mw.readFile(admin_path_file).strip()
if admin_path_old != admin_path:
mw.writeFile(admin_path_file, admin_path)
mw.restartMw()
return mw.returnJson(True, '修改成功!')
def closePanelApi(self):
filename = 'data/close.pl'
if os.path.exists(filename):
os.remove(filename)
return mw.returnJson(True, '开启成功')
mw.writeFile(filename, 'True')
mw.execShell("chmod 600 " + filename)
mw.execShell("chown root.root " + filename)
return mw.returnJson(True, '面板已关闭!')
def openDebugApi(self):
filename = 'data/debug.pl'
if os.path.exists(filename):
os.remove(filename)
return mw.returnJson(True, '开发模式关闭!')
mw.writeFile(filename, 'True')
return mw.returnJson(True, '开发模式开启!')
def setIpv6StatusApi(self):
ipv6_file = 'data/ipv6.pl'
if os.path.exists('data/ipv6.pl'):
os.remove(ipv6_file)
mw.writeLog('面板设置', '关闭面板IPv6兼容!')
else:
mw.writeFile(ipv6_file, 'True')
mw.writeLog('面板设置', '开启面板IPv6兼容!')
mw.restartMw()
return mw.returnJson(True, '设置成功!')
# 获取面板证书
def getPanelSslApi(self):
cert = self.getPanelSslData()
return mw.getJson(cert)
def getPanelSslData(self):
cert = {}
keyPath = 'ssl/private.pem'
certPath = 'ssl/cert.pem'
if not os.path.exists(certPath):
mw.createSSL()
cert['privateKey'] = mw.readFile(keyPath)
cert['certPem'] = mw.readFile(certPath)
cert['rep'] = os.path.exists('ssl/input.pl')
cert['info'] = mw.getCertName(certPath)
return cert
# 保存面板证书
def savePanelSslApi(self):
keyPath = 'ssl/private.pem'
certPath = 'ssl/cert.pem'
checkCert = '/tmp/cert.pl'
certPem = request.form.get('certPem', '').strip()
privateKey = request.form.get('privateKey', '').strip()
if(privateKey.find('KEY') == -1):
return mw.returnJson(False, '秘钥错误,请检查!')
if(certPem.find('CERTIFICATE') == -1):
return mw.returnJson(False, '证书错误,请检查!')
mw.writeFile(checkCert, certPem)
if privateKey:
mw.writeFile(keyPath, privateKey)
if certPem:
mw.writeFile(certPath, certPem)
if not mw.checkCert(checkCert):
return mw.returnJson(False, '证书错误,请检查!')
mw.writeFile('ssl/input.pl', 'True')
return mw.returnJson(True, '证书已保存!')
# 申请面板let证书
def applyPanelLetSslApi(self):
# check domain is bind?
bind_domain = 'data/bind_domain.pl'
if not os.path.exists(bind_domain):
return mw.returnJson(False, '未绑定域名!')
siteName = mw.readFile(bind_domain).strip()
auth_to = mw.getRunDir() + "/tmp"
to_args = {
'domains': [siteName],
'auth_type': 'http',
'auth_to': auth_to,
}
src_letpath = mw.getServerDir() + '/web_conf/letsencrypt/' + siteName
src_csrpath = src_letpath + "/fullchain.pem" # 生成证书路径
src_keypath = src_letpath + "/privkey.pem" # 密钥文件路径
dst_letpath = mw.getRunDir() + '/ssl'
dst_csrpath = dst_letpath + '/cert.pem'
dst_keypath = dst_letpath + '/private.pem'
if not os.path.exists(src_letpath):
import cert_api
data = cert_api.cert_api().applyCertApi(to_args)
if not data['status']:
msg = data['msg']
if type(data['msg']) != str:
msg = data['msg'][0]
emsg = data['msg'][1]['challenges'][0]['error']
msg = msg + '<p><span>响应状态:</span>' + str(emsg['status']) + '</p><p><span>错误类型:</span>' + emsg[
'type'] + '</p><p><span>错误代码:</span>' + emsg['detail'] + '</p>'
return mw.returnJson(data['status'], msg, data['msg'])
mw.buildSoftLink(src_csrpath, dst_csrpath, True)
mw.buildSoftLink(src_keypath, dst_keypath, True)
mw.execShell('echo "lets" > "' + dst_letpath + '/README"')
data = self.getPanelSslData()
tmp_well_know = auth_to + '/.well-known'
if os.path.exists(tmp_well_know):
mw.execShell('rm -rf ' + tmp_well_know)
return mw.returnJson(True, '申请成功!', data)
def setPanelDomainApi(self):
domain = request.form.get('domain', '')
panel_tpl = mw.getRunDir() + "/data/tpl/nginx_panel.conf"
dst_panel_path = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
cfg_domain = 'data/bind_domain.pl'
if domain == '':
os.remove(cfg_domain)
os.remove(dst_panel_path)
mw.restartWeb()
return mw.returnJson(True, '清空域名成功!')
reg = r"^([\w\-\*]{1,100}\.){1,4}(\w{1,10}|\w{1,10}\.\w{1,10})$"
if not re.match(reg, domain):
return mw.returnJson(False, '主域名格式不正确')
op_dir = mw.getServerDir() + "/openresty"
if not os.path.exists(op_dir):
return mw.returnJson(False, '依赖OpenResty,先安装启动它!')
content = mw.readFile(panel_tpl)
content = content.replace("{$PORT}", "80")
content = content.replace("{$SERVER_NAME}", domain)
content = content.replace("{$PANAL_PORT}", mw.readFile('data/port.pl'))
content = content.replace("{$LOGPATH}", mw.getRunDir() + '/logs')
content = content.replace("{$PANAL_ADDR}", mw.getRunDir())
mw.writeFile(dst_panel_path, content)
mw.restartWeb()
mw.writeFile(cfg_domain, domain)
return mw.returnJson(True, '设置域名成功!')
# 设置面板SSL
def setPanelSslApi(self):
sslConf = mw.getRunDir() + '/data/ssl.pl'
panel_tpl = mw.getRunDir() + "/data/tpl/nginx_panel.conf"
dst_panel_path = mw.getServerDir() + "/web_conf/nginx/vhost/panel.conf"
if os.path.exists(sslConf):
os.system('rm -f ' + sslConf)
conf = mw.readFile(dst_panel_path)
if conf:
rep = "\s+ssl_certificate\s+.+;\s+ssl_certificate_key\s+.+;"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_protocols\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_ciphers\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_prefer_server_ciphers\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_session_cache\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_session_timeout\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_ecdh_curve\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_session_tickets\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_stapling\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl_stapling_verify\s+.+;\n"
conf = re.sub(rep, '', conf)
rep = "\s+ssl\s+on;"
conf = re.sub(rep, '', conf)
rep = "\s+error_page\s497.+;"
conf = re.sub(rep, '', conf)
rep = "\s+if.+server_port.+\n.+\n\s+\s*}"
conf = re.sub(rep, '', conf)
rep = "\s+listen\s+443.*;"
conf = re.sub(rep, '', conf)
rep = "\s+listen\s+\[\:\:\]\:443.*;"
conf = re.sub(rep, '', conf)
mw.writeFile(dst_panel_path, conf)
mw.writeLog('面板配置', '面板SSL关闭成功!')
mw.restartWeb()
return mw.returnJson(True, 'SSL已关闭,请使用http协议访问面板!')
else:
try:
if not os.path.exists('ssl/input.ssl'):
mw.createSSL()
mw.writeFile(sslConf, 'True')
keyPath = mw.getRunDir() + '/ssl/private.pem'
certPath = mw.getRunDir() + '/ssl/cert.pem'
conf = mw.readFile(dst_panel_path)
if conf:
if conf.find('ssl_certificate') == -1:
sslStr = """#error_page 404/404.html;
ssl_certificate %s;
ssl_certificate_key %s;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
error_page 497 https://$host$request_uri;""" % (certPath, keyPath)
if(conf.find('ssl_certificate') != -1):
return mw.returnJson(True, 'SSL开启成功!')
conf = conf.replace('#error_page 404/404.html;', sslStr)
rep = "listen\s+([0-9]+)\s*[default_server]*;"
tmp = re.findall(rep, conf)
if not mw.inArray(tmp, '443'):
listen = re.search(rep, conf).group()
http_ssl = "\n\tlisten 443 ssl http2;"
http_ssl = http_ssl + "\n\tlisten [::]:443 ssl http2;"
conf = conf.replace(listen, listen + http_ssl)
mw.backFile(dst_panel_path)
mw.writeFile(dst_panel_path, conf)
isError = mw.checkWebConfig()
if(isError != True):
mw.restoreFile(dst_panel_path)
return mw.returnJson(False, '证书错误: <br><a style="color:red;">' + isError.replace("\n", '<br>') + '</a>')
except Exception as ex:
return mw.returnJson(False, '开启失败:' + str(ex))
mw.restartWeb()
return mw.returnJson(True, '开启成功,请使用https协议访问面板!')
def getApi(self):
data = {}
return mw.getJson(data)
##### ----- end ----- ###
# 获取临时登录列表
def getTempLoginApi(self):
if 'tmp_login_expire' in session:
return mw.returnJson(False, '没有权限')
limit = request.form.get('limit', '10').strip()
p = request.form.get('p', '1').strip()
tojs = request.form.get('tojs', '').strip()
tempLoginM = mw.M('temp_login')
tempLoginM.where('state=? and expire<?',
(0, int(time.time()))).setField('state', -1)
start = (int(p) - 1) * (int(limit))
vlist = tempLoginM.limit(str(start) + ',' + str(limit)).order('id desc').field(
'id,addtime,expire,login_time,login_addr,state').select()
data = {}
data['data'] = vlist
count = tempLoginM.count()
page_args = {}
page_args['count'] = count
page_args['tojs'] = 'get_temp_login'
page_args['p'] = p
page_args['row'] = limit
data['page'] = mw.getPage(page_args)
return mw.getJson(data)
# 删除临时登录
def removeTempLoginApi(self):
if 'tmp_login_expire' in session:
return mw.returnJson(False, '没有权限')
sid = request.form.get('id', '10').strip()
if mw.M('temp_login').where('id=?', (sid,)).delete():
mw.writeLog('面板设置', '删除临时登录连接')
return mw.returnJson(True, '删除成功')
return mw.returnJson(False, '删除失败')
def setTempLoginApi(self):
if 'tmp_login_expire' in session:
return mw.returnJson(False, '没有权限')
s_time = int(time.time())
mw.M('temp_login').where(
'state=? and expire>?', (0, s_time)).delete()
token = mw.getRandomString(48)
salt = mw.getRandomString(12)
pdata = {
'token': mw.md5(token + salt),
'salt': salt,
'state': 0,
'login_time': 0,
'login_addr': '',
'expire': s_time + 3600,
'addtime': s_time
}
if not mw.M('temp_login').count():
pdata['id'] = 101
if mw.M('temp_login').insert(pdata):
mw.writeLog('面板设置', '生成临时连接,过期时间:{}'.format(
mw.formatDate(times=pdata['expire'])))
return mw.getJson({'status': True, 'msg': "临时连接已生成", 'token': token, 'expire': pdata['expire']})
return mw.returnJson(False, '连接生成失败')
def getTempLoginLogsApi(self):
if 'tmp_login_expire' in session:
return mw.returnJson(False, '没有权限')
logs_id = request.form.get('id', '').strip()
logs_id = int(logs_id)
data = mw.M('logs').where(
'uid=?', (logs_id,)).order('id desc').field(
'id,type,uid,log,addtime').select()
return mw.returnJson(False, 'ok', data)
def checkPanelToken(self):
api_file = self.__api_addr
if not os.path.exists(api_file):
return False, ''
tmp = mw.readFile(api_file)
data = json.loads(tmp)
if data['open']:
return True, data
else:
return False, ''
def setStatusCodeApi(self):
status_code = request.form.get('status_code', '').strip()
if re.match("^\d+$", status_code):
status_code = int(status_code)
if status_code != 0:
if status_code < 100 or status_code > 999:
return mw.returnJson(False, '状态码范围错误!')
else:
return mw.returnJson(False, '状态码范围错误!')
mw.writeFile('data/unauthorized_status.pl', str(status_code))
mw.writeLog('面板设置', '将未授权响应状态码设置为:{}'.format(status_code))
return mw.returnJson(True, '设置成功!')
def getNotifyApi(self):
# 获取
data = mw.getNotifyData(True)
return mw.returnData(True, 'ok', data)
def setNotifyApi(self):
tag = request.form.get('tag', '').strip()
data = request.form.get('data', '').strip()
cfg = mw.getNotifyData(False)
crypt_data = mw.enDoubleCrypt(tag, data)
if tag in cfg:
cfg[tag]['cfg'] = crypt_data
else:
t = {'cfg': crypt_data}
cfg[tag] = t
mw.writeNotify(cfg)
return mw.returnData(True, '设置成功')
def setNotifyTestApi(self):
# 异步通知验证
tag = request.form.get('tag', '').strip()
tag_data = request.form.get('data', '').strip()
if tag == 'tgbot':
t = json.loads(tag_data)
test_bool = mw.tgbotNotifyTest(t['app_token'], t['chat_id'])
if test_bool:
return mw.returnData(True, '验证成功')
return mw.returnData(False, '验证失败')
return mw.returnData(False, '暂时未支持该验证')
def setNotifyEnableApi(self):
# 异步通知验证
tag = request.form.get('tag', '').strip()
tag_enable = request.form.get('enable', '').strip()
data = mw.getNotifyData(False)
op_enable = True
op_action = '开启'
if tag_enable != 'true':
op_enable = False
op_action = '关闭'
if tag in data:
data[tag]['enable'] = op_enable
mw.writeNotify(data)
return mw.returnData(True, op_action + '成功')
def getPanelTokenApi(self):
api_file = self.__api_addr
tmp = mw.readFile(api_file)
if not os.path.exists(api_file):
ready_data = {"open": False, "token": "", "limit_addr": []}
mw.writeFile(api_file, json.dumps(ready_data))
mw.execShell("chmod 600 " + api_file)
tmp = mw.readFile(api_file)
data = json.loads(tmp)
if not 'key' in data:
data['key'] = mw.getRandomString(16)
mw.writeFile(api_file, json.dumps(data))
if 'token_crypt' in data:
data['token'] = mw.deCrypt(data['token'], data['token_crypt'])
else:
token = mw.getRandomString(32)
data['token'] = mw.md5(token)
data['token_crypt'] = mw.enCrypt(
data['token'], token)
mw.writeFile(api_file, json.dumps(data))
data['token'] = "***********************************"
data['limit_addr'] = '\n'.join(data['limit_addr'])
del(data['key'])
return mw.returnJson(True, 'ok', data)
def setPanelTokenApi(self):
op_type = request.form.get('op_type', '').strip()
if op_type == '1':
token = mw.getRandomString(32)
data['token'] = mw.md5(token)
data['token_crypt'] = mw.enCrypt(
data['token'], token).decode('utf-8')
mw.writeLog('API配置', '重新生成API-Token')
mw.writeFile(api_file, json.dumps(data))
return mw.returnJson(True, 'ok', token)
api_file = self.__api_addr
if not os.path.exists(api_file):
return mw.returnJson(False, "先在API接口配置")
else:
tmp = mw.readFile(api_file)
data = json.loads(tmp)
if op_type == '2':
data['open'] = not data['open']
stats = {True: '开启', False: '关闭'}
if not 'token_crypt' in data:
token = mw.getRandomString(32)
data['token'] = mw.md5(token)
data['token_crypt'] = mw.enCrypt(
data['token'], token).decode('utf-8')
token = stats[data['open']] + '成功!'
mw.writeLog('API配置', '%sAPI接口' % stats[data['open']])
mw.writeFile(api_file, json.dumps(data))
return mw.returnJson(not not data['open'], token)
elif op_type == '3':
limit_addr = request.form.get('limit_addr', '').strip()
data['limit_addr'] = limit_addr.split('\n')
mw.writeLog('API配置', '变更IP限制为[%s]' % limit_addr)
mw.writeFile(api_file, json.dumps(data))
return mw.returnJson(True, '保存成功!')
def renderUnauthorizedStatus(self, data):
cfg_unauth_status = 'data/unauthorized_status.pl'
if os.path.exists(cfg_unauth_status):
status_code = mw.readFile(cfg_unauth_status)
data['status_code'] = status_code
data['status_code_msg'] = status_code
if status_code == '0':
data['status_code_msg'] = "默认-安全入口错误提示"
elif status_code == '400':
data['status_code_msg'] = "400-客户端请求错误"
elif status_code == '401':
data['status_code_msg'] = "401-未授权访问"
elif status_code == '403':
data['status_code_msg'] = "403-拒绝访问"
elif status_code == '404':
data['status_code_msg'] = "404-页面不存在"
elif status_code == '408':
data['status_code_msg'] = "408-客户端超时"
elif status_code == '416':
data['status_code_msg'] = "416-无效的请求"
else:
data['status_code'] = '0'
data['status_code_msg'] = "默认-安全入口错误提示"
return data
def get(self):
data = {}
data['title'] = mw.getConfig('title')
data['site_path'] = mw.getWwwDir()
data['backup_path'] = mw.getBackupDir()
sformat = 'date +"%Y-%m-%d %H:%M:%S %Z %z"'
data['systemdate'] = mw.execShell(sformat)[0].strip()
data['port'] = mw.getHostPort()
data['ip'] = mw.getHostAddr()
admin_path_file = 'data/admin_path.pl'
if not os.path.exists(admin_path_file):
data['admin_path'] = '/'
else:
data['admin_path'] = mw.readFile(admin_path_file)
ipv6_file = 'data/ipv6.pl'
if os.path.exists(ipv6_file):
data['ipv6'] = 'checked'
else:
data['ipv6'] = ''
debug_file = 'data/debug.pl'
if os.path.exists(debug_file):
data['debug'] = 'checked'
else:
data['debug'] = ''
ssl_file = 'data/ssl.pl'
if os.path.exists('data/ssl.pl'):
data['ssl'] = 'checked'
else:
data['ssl'] = ''
basic_auth = 'data/basic_auth.json'
if os.path.exists(basic_auth):
bac = mw.readFile(basic_auth)
bac = json.loads(bac)
if bac['open']:
data['basic_auth'] = 'checked'
else:
data['basic_auth'] = ''
cfg_domain = 'data/bind_domain.pl'
if os.path.exists(cfg_domain):
domain = mw.readFile(cfg_domain)
data['bind_domain'] = domain.strip()
else:
data['bind_domain'] = ''
data = self.renderUnauthorizedStatus(data)
api_token = self.__api_addr
if os.path.exists(api_token):
bac = mw.readFile(api_token)
bac = json.loads(bac)
if bac['open']:
data['api_token'] = 'checked'
else:
data['api_token'] = ''
data['site_count'] = mw.M('sites').count()
data['username'] = mw.M('users').where(
"id=?", (1,)).getField('username')
data['hook_tag'] = request.args.get('tag', '')
# databases hook
database_hook_file = 'data/hook_database.json'
if os.path.exists(database_hook_file):
df = mw.readFile(database_hook_file)
df = json.loads(df)
data['hook_database'] = df
else:
data['hook_database'] = []
# menu hook
menu_hook_file = 'data/hook_menu.json'
if os.path.exists(menu_hook_file):
df = mw.readFile(menu_hook_file)
df = json.loads(df)
data['hook_menu'] = df
else:
data['hook_menu'] = []
# global_static hook
global_static_hook_file = 'data/hook_global_static.json'
if os.path.exists(global_static_hook_file):
df = mw.readFile(global_static_hook_file)
df = json.loads(df)
data['hook_global_static'] = df
else:
data['hook_global_static'] = []
# notiy config
notify_data = mw.getNotifyData(True)
notify_tag_list = ['tgbot', 'email']
for tag in notify_tag_list:
new_tag = 'notify_' + tag + '_enable'
data[new_tag] = ''
if tag in notify_data and 'enable' in notify_data[tag]:
if notify_data[tag]['enable']:
data[new_tag] = 'checked'
return data
-664
View File
@@ -1,664 +0,0 @@
# coding: utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# 计划任务操作
# ---------------------------------------------------------------------------------
import psutil
import time
import os
import sys
import mw
import re
import json
import pwd
from flask import request
class crontab_api:
field = 'id,name,type,where1,where_hour,where_minute,echo,addtime,status,save,backup_to,stype,sname,sbody,urladdress'
def __init__(self):
pass
##### ----- start ----- ###
def listApi(self):
p = request.args.get('p', 1)
psize = 10
startPage = (int(p) - 1) * psize
pageInfo = str(startPage) + ',' + str(psize)
_list = mw.M('crontab').where('', ()).field(
self.field).limit(pageInfo).order('id desc').select()
data = []
for i in range(len(_list)):
tmp = _list[i]
if _list[i]['type'] == "day":
tmp['type'] = '每天'
tmp['cycle'] = mw.getInfo('每天, {1}点{2}分 执行', (str(
_list[i]['where_hour']), str(_list[i]['where_minute'])))
elif _list[i]['type'] == "day-n":
tmp['type'] = mw.getInfo(
'每{1}天', (str(_list[i]['where1']),))
tmp['cycle'] = mw.getInfo('每隔{1}天, {2}点{3}分 执行', (str(
_list[i]['where1']), str(_list[i]['where_hour']), str(_list[i]['where_minute'])))
elif _list[i]['type'] == "hour":
tmp['type'] = '每小时'
tmp['cycle'] = mw.getInfo(
'每小时, 第{1}分钟 执行', (str(_list[i]['where_minute']),))
elif _list[i]['type'] == "hour-n":
tmp['type'] = mw.getInfo(
'每{1}小时', (str(_list[i]['where1']),))
tmp['cycle'] = mw.getInfo('每{1}小时, 第{2}分钟 执行', (str(
_list[i]['where1']), str(_list[i]['where_minute'])))
elif _list[i]['type'] == "minute-n":
tmp['type'] = mw.getInfo(
'每{1}分钟', (str(_list[i]['where1']),))
tmp['cycle'] = mw.getInfo(
'每隔{1}分钟执行', (str(_list[i]['where1']),))
elif _list[i]['type'] == "week":
tmp['type'] = '每周'
if not _list[i]['where1']:
_list[i]['where1'] = '0'
tmp['cycle'] = mw.getInfo('每周{1}, {2}点{3}分执行', (self.toWeek(int(
_list[i]['where1'])), str(_list[i]['where_hour']), str(_list[i]['where_minute'])))
elif _list[i]['type'] == "month":
tmp['type'] = '每月'
tmp['cycle'] = mw.getInfo('每月, {1}日 {2}点{3}分执行', (str(_list[i]['where1']), str(
_list[i]['where_hour']), str(_list[i]['where_minute'])))
data.append(tmp)
rdata = {}
rdata['data'] = data
count = mw.M('crontab').where('', ()).count()
_page = {}
_page['count'] = count
_page['p'] = p
_page['row'] = psize
_page['tojs'] = "getCronData"
rdata['list'] = mw.getPage(_page)
rdata['p'] = p
# backup hook
bh_file = mw.getPanelDataDir() + "/hook_backup.json"
if os.path.exists(bh_file):
hb_data = mw.readFile(bh_file)
hb_data = json.loads(hb_data)
rdata['backup_hook'] = hb_data
return mw.getJson(rdata)
# 设置计划任务状态
def setCronStatusApi(self):
mid = request.form.get('id', '')
cronInfo = mw.M('crontab').where(
'id=?', (mid,)).field(self.field).find()
status = 1
if cronInfo['status'] == status:
status = 0
self.removeForCrond(cronInfo['echo'])
else:
cronInfo['status'] = 1
self.syncToCrond(cronInfo)
mw.M('crontab').where('id=?', (mid,)).setField('status', status)
mw.writeLog(
'计划任务', '修改计划任务[' + cronInfo['name'] + ']状态为[' + str(status) + ']')
return mw.returnJson(True, '设置成功')
# 获取指定任务数据
def getCrondFindApi(self):
sid = request.form.get('id', '')
data = mw.M('crontab').where(
'id=?', (sid,)).field(self.field).find()
return mw.getJson(data)
# 参数校验
def cronCheck(self, params):
if params['stype'] == 'site' or params['stype'] == 'database' or params['stype'].find('database_') > -1 or params['stype'] == 'logs' or params['stype'] == 'path':
if params['save'] == '':
return False, '保留份数不能为空!'
if params['type'] == 'day':
if params['hour'] == '':
return False, '小时不能为空!'
if params['minute'] == '':
return False, '分钟不能为空!'
if params['type'] == 'day-n':
if params['where1'] == '':
return False, '天不能为空!'
if params['hour'] == '':
return False, '小时不能为空!'
if params['minute'] == '':
return False, '分钟不能为空!'
if params['type'] == 'hour':
if params['minute'] == '':
return False, '分钟不能为空!'
if params['type'] == 'hour-n':
if params['where1'] == '':
return False, '小时不能为空!'
if params['minute'] == '':
return False, '分钟不能为空!'
if params['type'] == 'minute-n':
if params['where1'] == '':
return False, '分钟不能为空!'
if params['type'] == 'week':
if params['hour'] == '':
return False, '小时不能为空!'
if params['minute'] == '':
return False, '分钟不能为空!'
if params['type'] == 'month':
if params['where1'] == '':
return False, '日不能为空!'
if params['hour'] == '':
return False, '小时不能为空!'
if params['minute'] == '':
return False, '分钟不能为空!'
return True, 'OK'
def modifyCrondApi(self):
sid = request.form.get('id', '')
iname = request.form.get('name', '')
field_type = request.form.get('type', '')
week = request.form.get('week', '')
where1 = request.form.get('where1', '')
hour = request.form.get('hour', '')
minute = request.form.get('minute', '')
save = request.form.get('save', '')
backup_to = request.form.get('backup_to', '')
stype = request.form.get('stype', '')
sname = request.form.get('sname', '')
sbody = request.form.get('sbody', '')
urladdress = request.form.get('urladdress', '')
if len(iname) < 1:
return mw.returnJson(False, '任务名称不能为空!')
params = {
'name': iname,
'type': field_type,
'week': week,
'where1': where1,
'hour': hour,
'minute': minute,
'save': save,
'backup_to': backup_to,
'stype': stype,
'sname': sname,
'sbody': sbody,
'urladdress': urladdress,
}
is_check_pass, msg = self.cronCheck(params)
if not is_check_pass:
return mw.returnJson(is_check_pass, msg)
cuonConfig, get, name = self.getCrondCycle(params)
cronInfo = mw.M('crontab').where(
'id=?', (sid,)).field(self.field).find()
del(cronInfo['id'])
del(cronInfo['addtime'])
cronInfo['name'] = get['name']
cronInfo['type'] = get['type']
cronInfo['where1'] = get['where1']
cronInfo['where_hour'] = get['hour']
cronInfo['where_minute'] = get['minute']
cronInfo['save'] = get['save']
cronInfo['backup_to'] = get['backup_to']
cronInfo['sbody'] = get['sbody']
cronInfo['urladdress'] = get['urladdress']
addData = mw.M('crontab').where('id=?', (sid,)).save('name,type,where1,where_hour,where_minute,save,backup_to, sname, sbody,urladdress',
(iname, field_type, get['where1'], get['hour'], get['minute'], get['save'], get['backup_to'], sname, get['sbody'], get['urladdress']))
self.removeForCrond(cronInfo['echo'])
self.syncToCrond(cronInfo)
mw.writeLog('计划任务', '修改计划任务[' + cronInfo['name'] + ']成功')
return mw.returnJson(True, '修改成功')
def logsApi(self):
sid = request.form.get('id', '')
echo = mw.M('crontab').where("id=?", (sid,)).field('echo').find()
logFile = mw.getServerDir() + '/cron/' + echo['echo'] + '.log'
if not os.path.exists(logFile):
return mw.returnJson(False, '当前日志为空!')
log = mw.getLastLine(logFile, 500)
return mw.returnJson(True, log)
def addApi(self):
iname = request.form.get('name', '')
field_type = request.form.get('type', '')
week = request.form.get('week', '')
where1 = request.form.get('where1', '')
hour = request.form.get('hour', '')
minute = request.form.get('minute', '')
save = request.form.get('save', '')
backup_to = request.form.get('backupTo', '')
stype = request.form.get('sType', '')
sname = request.form.get('sName', '')
sbody = request.form.get('sBody', '')
urladdress = request.form.get('urladdress', '')
if len(iname) < 1:
return mw.returnJson(False, '任务名称不能为空!')
params = {
'name': iname,
'type': field_type,
'week': week,
'where1': where1,
'hour': hour,
'minute': minute,
'save': save,
'backup_to': backup_to,
'stype': stype,
'sname': sname,
'sbody': sbody,
'urladdress': urladdress,
}
is_check_pass, msg = self.cronCheck(params)
if not is_check_pass:
return mw.returnJson(is_check_pass, msg)
addData = self.add(params)
if addData > 0:
return mw.returnJson(True, '添加成功')
return mw.returnJson(False, '添加失败')
def add(self, params):
iname = params["name"]
field_type = params["type"]
week = params["week"]
where1 = params["where1"]
hour = params["hour"]
minute = params["minute"]
save = params["save"]
backup_to = params["backup_to"]
stype = params["stype"]
sname = params["sname"]
sbody = params["sbody"]
urladdress = params["urladdress"]
# print params
cronConfig, get, name = self.getCrondCycle(params)
cronPath = mw.getServerDir() + '/cron'
cronName = self.getShell(params)
if type(cronName) == dict:
return cronName
cronConfig += ' ' + cronPath + '/' + cronName + \
' >> ' + cronPath + '/' + cronName + '.log 2>&1'
# print(cronConfig)
if not mw.isAppleSystem():
wRes = self.writeShell(cronConfig)
if type(wRes) != bool:
return wRes
self.crondReload()
add_time = time.strftime('%Y-%m-%d %X', time.localtime())
task_id = mw.M('crontab').add('name,type,where1,where_hour,where_minute,echo,addtime,status,save,backup_to,stype,sname,sbody,urladdress',
(iname, field_type, where1, hour, minute, cronName, add_time, 1, save, backup_to, stype, sname, sbody, urladdress,))
return task_id
def startTaskApi(self):
sid = request.form.get('id', '')
echo = mw.M('crontab').where('id=?', (sid,)).getField('echo')
execstr = mw.getServerDir() + '/cron/' + echo
os.system('chmod +x ' + execstr)
os.system('nohup ' + execstr + ' >> ' + execstr + '.log 2>&1 &')
return mw.returnJson(True, '任务已执行!')
def delApi(self):
task_id = request.form.get('id', '')
try:
data = self.delete(task_id)
if not data[0]:
return mw.returnJson(False, data[1])
return mw.returnJson(True, '删除成功')
except Exception as e:
return mw.returnJson(False, '删除失败:' + str(e))
def delete(self, tid):
find = mw.M('crontab').where("id=?", (tid,)).field('name,echo').find()
if not self.removeForCrond(find['echo']):
return (False, '无法写入文件,请检查是否开启了系统加固功能!')
cronPath = mw.getServerDir() + '/cron'
sfile = cronPath + '/' + find['echo']
if os.path.exists(sfile):
os.remove(sfile)
sfile = cronPath + '/' + find['echo'] + '.log'
if os.path.exists(sfile):
os.remove(sfile)
mw.M('crontab').where("id=?", (tid,)).delete()
mw.writeLog('计划任务', mw.getInfo('删除计划任务[{1}]成功!', (find['name'],)))
return (True, "OK")
def delLogsApi(self):
sid = request.form.get('id', '')
try:
echo = mw.M('crontab').where("id=?", (sid,)).getField('echo')
logFile = mw.getServerDir() + '/cron/' + echo + '.log'
os.remove(logFile)
return mw.returnJson(True, '任务日志已清空!')
except:
return mw.returnJson(False, '任务日志清空失败!')
# 取数据列表
def getDataListApi(self):
stype = request.form.get('type', '')
bak_data = []
if stype == 'site' or stype == 'sites' or stype == 'database' or stype.find('database_') > -1 or stype == 'path':
hookPath = mw.getPanelDataDir() + "/hook_backup.json"
if os.path.exists(hookPath):
t = mw.readFile(hookPath)
bak_data = json.loads(t)
if stype == 'database' or stype.find('database_') > -1:
sqlite3_name = 'mysql'
path = mw.getServerDir() + '/mysql'
if stype != 'database':
soft_name = stype.replace('database_', '')
path = mw.getServerDir() + '/' + soft_name
if soft_name == 'postgresql':
sqlite3_name = 'pgsql'
db_list = {}
db_list['orderOpt'] = bak_data
if not os.path.exists(path + '/' + sqlite3_name + '.db'):
db_list['data'] = []
else:
db_list['data'] = mw.M('databases').dbPos(
path, sqlite3_name).field('name,ps').select()
return mw.getJson(db_list)
if stype == 'path':
db_list = {}
db_list['data'] = [{"name": mw.getWwwDir(), "ps": "www"}]
db_list['orderOpt'] = bak_data
return mw.getJson(db_list)
data = {}
data['orderOpt'] = bak_data
default_db = 'sites'
# if stype == 'site' or stype == 'logs':
# stype == 'sites'
data['data'] = mw.M(default_db).field('name,ps').select()
return mw.getJson(data)
##### ----- start ----- ###
# 转换大写星期
def toWeek(self, num):
wheres = {
0: '日',
1: '一',
2: '二',
3: '三',
4: '四',
5: '五',
6: '六'
}
try:
return wheres[num]
except:
return ''
def getCrondCycle(self, params):
cuonConfig = ''
name = ''
if params['type'] == "day":
cuonConfig = self.getDay(params)
name = '每天'
elif params['type'] == "day-n":
cuonConfig = self.getDay_N(params)
name = mw.getInfo('每{1}天', (params['where1'],))
elif params['type'] == "hour":
cuonConfig = self.getHour(params)
name = '每小时'
elif params['type'] == "hour-n":
cuonConfig = self.getHour_N(params)
name = '每小时'
elif params['type'] == "minute-n":
cuonConfig = self.minute_N(params)
elif params['type'] == "week":
params['where1'] = params['week']
cuonConfig = self.week(params)
elif params['type'] == "month":
cuonConfig = self.month(params)
return cuonConfig, params, name
# 取任务构造Day
def getDay(self, param):
cuonConfig = "{0} {1} * * * ".format(param['minute'], param['hour'])
return cuonConfig
# 取任务构造Day_n
def getDay_N(self, param):
cuonConfig = "{0} {1} */{2} * * ".format(
param['minute'], param['hour'], param['where1'])
return cuonConfig
# 取任务构造Hour
def getHour(self, param):
cuonConfig = "{0} * * * * ".format(param['minute'])
return cuonConfig
# 取任务构造Hour-N
def getHour_N(self, param):
cuonConfig = "{0} */{1} * * * ".format(
param['minute'], param['where1'])
return cuonConfig
# 取任务构造Minute-N
def minute_N(self, param):
cuonConfig = "*/{0} * * * * ".format(param['where1'])
return cuonConfig
# 取任务构造week
def week(self, param):
cuonConfig = "{0} {1} * * {2}".format(
param['minute'], param['hour'], param['week'])
return cuonConfig
# 取任务构造Month
def month(self, param):
cuonConfig = "{0} {1} {2} * * ".format(
param['minute'], param['hour'], param['where1'])
return cuonConfig
# 取执行脚本
def getShell(self, param):
# try:
stype = param['stype']
if stype == 'toFile':
shell = param.sFile
else:
head = "#!/bin/bash\nPATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin\nexport PATH\n"
source_bin_activate = '''
export LANG=en_US.UTF-8
MW_PATH=%s/bin/activate
if [ -f $MW_PATH ];then
source $MW_PATH
fi''' % (mw.getRunDir(),)
head = head + source_bin_activate + "\n"
log = '.log'
script_dir = mw.getRunDir() + "/scripts"
source_stype = 'database'
if stype.find('database_') > -1:
plugin_name = stype.replace('database_', '')
script_dir = mw.getRunDir() + "/plugins/" + plugin_name + "/scripts"
source_stype = stype
stype = 'database'
wheres = {
'path': head + "python3 " + script_dir + "/backup.py path " + param['sname'] + " " + str(param['save']),
'site': head + "python3 " + script_dir + "/backup.py site " + param['sname'] + " " + str(param['save']),
'database': head + "python3 " + script_dir + "/backup.py database " + param['sname'] + " " + str(param['save']),
'logs': head + "python3 " + script_dir + "/logs_backup.py " + param['sname'] + log + " " + str(param['save']),
'rememory': head + "/bin/bash " + script_dir + '/rememory.sh'
}
if param['backup_to'] != 'localhost':
cfile = mw.getPluginDir() + "/" + \
param['backup_to'] + "/index.py"
wheres['path'] = head + "python3 " + cfile + \
" path " + param['sname'] + " " + str(param['save'])
wheres['site'] = head + "python3 " + cfile + \
" site " + param['sname'] + " " + str(param['save'])
wheres['database'] = head + "python3 " + cfile + " " + \
source_stype + " " + \
param['sname'] + " " + str(param['save'])
try:
shell = wheres[stype]
except:
if stype == 'toUrl':
shell = head + "curl -sS --connect-timeout 10 -m 60 '" + \
param['urladdress'] + "'"
else:
shell = head + param['sbody'].replace("\r\n", "\n")
shell += '''
echo "----------------------------------------------------------------------------"
endDate=`date +"%Y-%m-%d %H:%M:%S"`
echo "★[$endDate] Successful"
echo "----------------------------------------------------------------------------"
'''
cronPath = mw.getServerDir() + '/cron'
if not os.path.exists(cronPath):
mw.execShell('mkdir -p ' + cronPath)
if not 'echo' in param:
cronName = mw.md5(mw.md5(str(time.time()) + '_mw'))
else:
cronName = param['echo']
file = cronPath + '/' + cronName
mw.writeFile(file, self.checkScript(shell))
mw.execShell('chmod 750 ' + file)
return cronName
# 检查脚本
def checkScript(self, shell):
keys = ['shutdown', 'init 0', 'mkfs', 'passwd',
'chpasswd', '--stdin', 'mkfs.ext', 'mke2fs']
for key in keys:
shell = shell.replace(key, '[***]')
return shell
# 将Shell脚本写到文件
def writeShell(self, config):
u_file = '/var/spool/cron/crontabs/root'
if not os.path.exists(u_file):
file = '/var/spool/cron/root'
if mw.isAppleSystem():
file = '/etc/crontab'
else:
file = u_file
if not os.path.exists(file):
mw.writeFile(file, '')
conf = mw.readFile(file)
conf += str(config) + "\n"
if mw.writeFile(file, conf):
if not os.path.exists(u_file):
mw.execShell("chmod 600 '" + file +
"' && chown root.root " + file)
else:
mw.execShell("chmod 600 '" + file +
"' && chown root.crontab " + file)
return True
return mw.returnJson(False, '文件写入失败,请检查是否开启系统加固功能!')
# 重载配置
def crondReload(self):
if mw.isAppleSystem():
# mw.execShell('/usr/sbin/cron restart')
if os.path.exists('/etc/crontab'):
pass
else:
if os.path.exists('/etc/init.d/crond'):
mw.execShell('/etc/init.d/crond reload')
elif os.path.exists('/etc/init.d/cron'):
mw.execShell('service cron restart')
else:
mw.execShell("systemctl reload crond")
# 从crond删除
def removeForCrond(self, echo):
u_file = '/var/spool/cron/crontabs/root'
if not os.path.exists(u_file):
file = '/var/spool/cron/root'
if mw.isAppleSystem():
file = '/etc/crontab'
if not os.path.exists(file):
return False
else:
file = u_file
if mw.isAppleSystem():
return True
conf = mw.readFile(file)
rep = ".+" + str(echo) + ".+\n"
conf = re.sub(rep, "", conf)
if not mw.writeFile(file, conf):
return False
self.crondReload()
return True
def syncToCrond(self, cronInfo):
if 'status' in cronInfo:
if cronInfo['status'] == 0:
return False
if 'where_hour' in cronInfo:
cronInfo['hour'] = cronInfo['where_hour']
cronInfo['minute'] = cronInfo['where_minute']
cronInfo['week'] = cronInfo['where1']
cuonConfig, cronInfo, name = self.getCrondCycle(cronInfo)
cronPath = mw.getServerDir() + '/cron'
cronName = self.getShell(cronInfo)
if type(cronName) == dict:
return cronName
cuonConfig += ' ' + cronPath + '/' + cronName + \
' >> ' + cronPath + '/' + cronName + '.log 2>&1'
wRes = self.writeShell(cuonConfig)
if type(wRes) != bool:
return False
self.crondReload()
+40 -158
View File
@@ -1,21 +1,8 @@
# coding: utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# sqlite3操作
# ---------------------------------------------------------------------------------
import sqlite3
import os
import sys
class Sql():
@@ -24,42 +11,28 @@ class Sql():
#------------------------------
__DB_FILE = None # 数据库文件
__DB_CONN = None # 数据库连接对象
__DB_TABLE = "" # 被操作的表名称
__OPT_WHERE = "" # where条件
__OPT_LIMIT = "" # limit条件
__OPT_GROUP = "" # group条件
__OPT_ORDER = "" # order条件
__OPT_FIELD = "*" # field条件
__OPT_PARAM = () # where值
__DB_TABLE = "" # 被操作的表名称
__OPT_WHERE = "" # where条件
__OPT_LIMIT = "" # limit条件
__OPT_ORDER = "" # order条件
__OPT_FIELD = "*" # field条件
__OPT_PARAM = () # where值
def __init__(self):
self.__DB_FILE = 'data/default.db'
def __getConn(self):
def __GetConn(self):
# 取数据库对象
try:
if self.__DB_CONN == None:
self.__DB_CONN = sqlite3.connect(self.__DB_FILE)
self.__DB_CONN.text_factory = str
except Exception as ex:
except Exception, ex:
return "error: " + str(ex)
def autoTextFactory(self):
if sys.version_info[0] == 3:
self.__DB_CONN.text_factory = lambda x: str(
x, encoding="utf-8", errors='ignore')
else:
self.__DB_CONN.text_factory = lambda x: unicode(
x, "utf-8", "ignore")
def dbfile(self, name):
self.__DB_FILE = 'data/' + name + '.db'
return self
def dbPos(self, path, name):
self.__DB_FILE = path + '/' + name + '.db'
return self
def table(self, table):
# 设置表名
self.__DB_TABLE = table
@@ -72,36 +45,16 @@ class Sql():
self.__OPT_PARAM = param
return self
def andWhere(self, where, param):
# WHERE条件
if where:
self.__OPT_WHERE = self.__OPT_WHERE + " and " + where
# print(param)
# print(self.__OPT_PARAM)
self.__OPT_PARAM = self.__OPT_PARAM + param
return self
def order(self, order):
# ORDER条件
if len(order):
self.__OPT_ORDER = " ORDER BY " + order
else:
self.__OPT_ORDER = ""
return self
def group(self, group):
if len(group):
self.__OPT_GROUP = " GROUP BY " + group
else:
self.__OPT_GROUP = ""
return self
def limit(self, limit):
# LIMIT条件
if len(limit):
self.__OPT_LIMIT = " LIMIT " + limit
else:
self.__OPT_LIMIT = ""
return self
def field(self, field):
@@ -112,12 +65,10 @@ class Sql():
def select(self):
# 查询数据集
self.__getConn()
self.__GetConn()
try:
sql = "SELECT " + self.__OPT_FIELD + " FROM " + self.__DB_TABLE + \
self.__OPT_WHERE + self.__OPT_GROUP + self.__OPT_ORDER + self.__OPT_LIMIT
# print(sql)
# print(self.__OPT_PARAM)
self.__OPT_WHERE + self.__OPT_ORDER + self.__OPT_LIMIT
result = self.__DB_CONN.execute(sql, self.__OPT_PARAM)
data = result.fetchall()
# 构造字曲系列
@@ -141,51 +92,12 @@ class Sql():
del(tmp)
self.__close()
return data
except Exception as ex:
return "error: " + str(ex)
def inquiry(self, input_field=''):
# 查询数据集
# 不清空查询参数
self.__getConn()
try:
sql = "SELECT " + self.__OPT_FIELD + " FROM " + self.__DB_TABLE + \
self.__OPT_WHERE + self.__OPT_GROUP + self.__OPT_ORDER + self.__OPT_LIMIT
# print(sql, self.__OPT_PARAM)
result = self.__DB_CONN.execute(sql, self.__OPT_PARAM)
data = result.fetchall()
# 构造字曲系列
if self.__OPT_FIELD != "*":
if input_field != "":
field = input_field.split(',')
else:
field = self.__OPT_FIELD.split(',')
tmp = []
for row in data:
i = 0
tmp1 = {}
for key in field:
tmp1[key] = row[i]
i += 1
tmp.append(tmp1)
del(tmp1)
data = tmp
del(tmp)
else:
# 将元组转换成列表
tmp = map(list, data)
data = tmp
del(tmp)
return data
except Exception as ex:
except Exception, ex:
return "error: " + str(ex)
def getField(self, keyName):
# 取回指定字段
result = self.field(keyName).select()
# print(result)
if len(result) == 1:
return result[0][keyName]
return result
@@ -212,7 +124,8 @@ class Sql():
def add(self, keys, param):
# 插入数据
self.__getConn()
self.__GetConn()
self.__DB_CONN.text_factory = str
try:
values = ""
for key in keys.split(','):
@@ -221,36 +134,13 @@ class Sql():
sql = "INSERT INTO " + self.__DB_TABLE + \
"(" + keys + ") " + "VALUES(" + values + ")"
result = self.__DB_CONN.execute(sql, param)
last_id = result.lastrowid
id = result.lastrowid
self.__close()
self.__DB_CONN.commit()
return last_id
except Exception as ex:
return id
except Exception, ex:
return "error: " + str(ex)
# 插入数据
def insert(self, pdata):
if not pdata:
return False
keys, param = self.__format_pdata(pdata)
return self.add(keys, param)
# 更新数据
def update(self, pdata):
if not pdata:
return False
keys, param = self.__format_pdata(pdata)
return self.save(keys, param)
# 构造数据
def __format_pdata(self, pdata):
keys = pdata.keys()
keys_str = ','.join(keys)
param = []
for k in keys:
param.append(pdata[k])
return keys_str, tuple(param)
def checkInput(self, data):
if not data:
return data
@@ -271,7 +161,8 @@ class Sql():
def addAll(self, keys, param):
# 插入数据
self.__getConn()
self.__GetConn()
self.__DB_CONN.text_factory = str
try:
values = ""
for key in keys.split(','):
@@ -281,7 +172,7 @@ class Sql():
"(" + keys + ") " + "VALUES(" + values + ")"
result = self.__DB_CONN.execute(sql, param)
return True
except Exception as ex:
except Exception, ex:
return "error: " + str(ex)
def commit(self):
@@ -290,7 +181,8 @@ class Sql():
def save(self, keys, param):
# 更新数据
self.__getConn()
self.__GetConn()
self.__DB_CONN.text_factory = str
try:
opt = ""
for key in keys.split(','):
@@ -298,8 +190,8 @@ class Sql():
opt = opt[0:len(opt) - 1]
sql = "UPDATE " + self.__DB_TABLE + " SET " + opt + self.__OPT_WHERE
# import mw
# mw.writeFile('/tmp/test.pl', sql)
import public
public.writeFile('/tmp/test.pl', sql)
# 处理拼接WHERE与UPDATE参数
tmp = list(param)
@@ -310,12 +202,12 @@ class Sql():
self.__close()
self.__DB_CONN.commit()
return result.rowcount
except Exception as ex:
except Exception, ex:
return "error: " + str(ex)
def delete(self, id=None):
# 删除数据
self.__getConn()
self.__GetConn()
try:
if id:
self.__OPT_WHERE = " WHERE id=?"
@@ -325,54 +217,44 @@ class Sql():
self.__close()
self.__DB_CONN.commit()
return result.rowcount
except Exception as ex:
except Exception, ex:
return "error: " + str(ex)
def originExecute(self, sql, param=()):
self.__getConn()
try:
result = self.__DB_CONN.execute(sql, param)
self.__DB_CONN.commit()
return result
except Exception as ex:
return "error: " + str(ex)
def execute(self, sql, param=()):
def execute(self, sql, param):
# 执行SQL语句返回受影响行
self.__getConn()
# print sql, param
self.__GetConn()
try:
result = self.__DB_CONN.execute(sql, param)
self.__DB_CONN.commit()
return result.rowcount
except Exception as ex:
except Exception, ex:
return "error: " + str(ex)
def query(self, sql, param=()):
def query(self, sql, param):
# 执行SQL语句返回数据集
self.__getConn()
self.__GetConn()
try:
result = self.__DB_CONN.execute(sql, param)
# 将元组转换成列表
# data = map(list, result)
return result
except Exception as ex:
data = map(list, result)
return data
except Exception, ex:
return "error: " + str(ex)
def create(self, name):
# 创建数据表
self.__getConn()
import mw
script = mw.readFile('data/' + name + '.sql')
self.__GetConn()
import public
script = public.readFile('data/' + name + '.sql')
result = self.__DB_CONN.executescript(script)
self.__DB_CONN.commit()
return result.rowcount
def fofile(self, filename):
# 执行脚本
self.__getConn()
import mw
script = mw.readFile(filename)
self.__GetConn()
import public
script = public.readFile(filename)
result = self.__DB_CONN.executescript(script)
self.__DB_CONN.commit()
return result.rowcount
+250
View File
@@ -0,0 +1,250 @@
# coding: utf-8
import psutil
import time
import os
import sys
import public
import re
import json
import pwd
class file_api:
def __init__(self):
pass
def setFileAccept(self, filename):
auth = 'www:www'
if public.getOs() == 'darwin':
user = public.execShell(
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
auth = user + ':staff'
os.system('chown -R ' + auth + ' ' + filename)
os.system('chmod -R 755 ' + filename)
# 移动到回收站
def mvRecycleBin(self, path):
rPath = public.getRootDir() + '/recycle_bin/'
if not os.path.exists(rPath):
os.system('mkdir -p ' + rPath)
rFile = rPath + path.replace('/', '_mw_') + '_t_' + str(time.time())
try:
import shutil
shutil.move(path, rFile)
public.writeLog('TYPE_FILE', public.getInfo(
'移动文件[{1}]到回收站成功!', (path)))
return True
except:
public.writeLog('TYPE_FILE', public.getInfo(
'移动文件[{1}]到回收站失败!', (path)))
return False
def getBody(self, path):
if not os.path.exists(path):
return public.returnJson(False, '文件不存在', (path,))
if os.path.getsize(path) > 2097152:
return public.returnJson(False, u'不能在线编辑大于2MB的文件!')
fp = open(path, 'rb')
data = {}
data['status'] = True
try:
if fp:
from chardet.universaldetector import UniversalDetector
detector = UniversalDetector()
srcBody = b""
for line in fp.readlines():
detector.feed(line)
srcBody += line
detector.close()
char = detector.result
data['encoding'] = char['encoding']
if char['encoding'] == 'GB2312' or not char['encoding'] or char[
'encoding'] == 'TIS-620' or char['encoding'] == 'ISO-8859-9':
data['encoding'] = 'GBK'
if char['encoding'] == 'ascii' or char[
'encoding'] == 'ISO-8859-1':
data['encoding'] = 'utf-8'
if char['encoding'] == 'Big5':
data['encoding'] = 'BIG5'
if not char['encoding'] in ['GBK', 'utf-8',
'BIG5']:
data['encoding'] = 'utf-8'
try:
if sys.version_info[0] == 2:
data['data'] = srcBody.decode(
data['encoding']).encode('utf-8', errors='ignore')
else:
data['data'] = srcBody.decode(data['encoding'])
except:
data['encoding'] = char['encoding']
if sys.version_info[0] == 2:
data['data'] = srcBody.decode(
data['encoding']).encode('utf-8', errors='ignore')
else:
data['data'] = srcBody.decode(data['encoding'])
else:
if sys.version_info[0] == 2:
data['data'] = srcBody.decode('utf-8').encode('utf-8')
else:
data['data'] = srcBody.decode('utf-8')
data['encoding'] = u'utf-8'
return public.returnJson(True, 'OK', data)
except Exception as ex:
return public.returnJson(False, u'文件编码不被兼容,无法正确读取文件!' + str(ex))
def saveBody(self, path, data, encoding='utf-8'):
if not os.path.exists(path):
return public.returnJson(False, '文件不存在')
try:
if encoding == 'ascii':
encoding = 'utf-8'
if sys.version_info[0] == 2:
data = data.encode(encoding, errors='ignore')
fp = open(path, 'w+')
else:
data = data.encode(
encoding, errors='ignore').decode(encoding)
fp = open(path, 'w+', encoding=encoding)
fp.write(data)
fp.close()
public.writeLog('TYPE_FILE', '文件保存成功', (path,))
return public.returnJson(True, '文件保存成功')
except Exception as ex:
return public.returnJson(False, 'FILE_SAVE_ERR:' + str(ex))
def zip(self, sfile, dfile, stype, path):
if sfile.find(',') == -1:
if not os.path.exists(path + '/' + sfile):
return public.returnMsg(False, '指定文件不存在!')
try:
tmps = public.getRunDir() + '/tmp/panelExec.log'
if stype == 'zip':
os.system("cd '" + path + "' && zip '" + dfile +
"' -r '" + sfile + "' > " + tmps + " 2>&1")
else:
sfiles = ''
for sfile in sfile.split(','):
if not sfile:
continue
sfiles += " '" + sfile + "'"
os.system("cd '" + path + "' && tar -zcvf '" +
dfile + "' " + sfiles + " > " + tmps + " 2>&1")
self.setFileAccept(dfile)
public.writeLog("TYPE_FILE", '文件压缩成功!', (sfile, dfile))
return public.returnJson(True, '文件压缩成功!')
except:
return public.returnJson(False, '文件压缩失败!')
def delete(self, path):
if not os.path.exists(path):
return public.returnJson(False, '指定文件不存在!')
# 检查是否为.user.ini
if path.find('.user.ini') >= 0:
os.system("chattr -i '" + path + "'")
try:
if os.path.exists('data/recycle_bin.pl'):
if self.mvRecycleBin(path):
return public.returnJson(True, '已将文件移动到回收站!')
os.remove(path)
public.writeLog('TYPE_FILE', public.getInfo(
'删除文件[{1}]成功!', (path)))
return public.returnJson(True, '删除文件成功!')
except:
return public.returnJson(False, '删除文件失败!')
def getAccess(self, filename):
data = {}
try:
stat = os.stat(filename)
data['chmod'] = str(oct(stat.st_mode)[-3:])
data['chown'] = pwd.getpwuid(stat.st_uid).pw_name
except:
data['chmod'] = 755
data['chown'] = 'www'
return data
# 计算文件数量
def getCount(self, path, search):
i = 0
for name in os.listdir(path):
if search:
if name.lower().find(search) == -1:
continue
# if name[0:1] == '.':
# continue
i += 1
return i
def getDir(self, path, page=1, page_size=10, search=None):
data = {}
dirnames = []
filenames = []
info = {}
info['count'] = self.getCount(path, search)
info['row'] = page_size
info['p'] = page
info['tojs'] = 'getFiles'
pageObj = public.getPageObject(info, '1,2,3,4,5,6,7,8')
data['PAGE'] = pageObj[0]
i = 0
n = 0
for filename in os.listdir(path):
if search:
if filename.lower().find(search) == -1:
continue
i += 1
if n >= pageObj[1].ROW:
break
if i < pageObj[1].SHIFT:
continue
try:
filePath = (path + '/' + filename).encode('utf8')
link = ''
if os.path.islink(filePath):
filePath = os.readlink(filePath)
link = ' -> ' + filePath
if not os.path.exists(filePath):
filePath = path + '/' + filePath
if not os.path.exists(filePath):
continue
stat = os.stat(filePath)
accept = str(oct(stat.st_mode)[-3:])
mtime = str(int(stat.st_mtime))
user = ''
try:
user = pwd.getpwuid(stat.st_uid).pw_name
except:
user = str(stat.st_uid)
size = str(stat.st_size)
if os.path.isdir(filePath):
dirnames.append(filename + ';' + size + ';' +
mtime + ';' + accept + ';' + user + ';' + link)
else:
filenames.append(filename + ';' + size + ';' +
mtime + ';' + accept + ';' + user + ';' + link)
n += 1
except:
continue
data['DIR'] = sorted(dirnames)
data['FILES'] = sorted(filenames)
if path[0:2] == '//':
data['PATH'] = path[1:]
else:
data['PATH'] = path
return public.getJson(data)
File diff suppressed because it is too large Load Diff
+10 -439
View File
@@ -1,418 +1,37 @@
# coding: utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# 防火墙操作
# ---------------------------------------------------------------------------------
import psutil
import time
import os
import sys
import mw
import public
import re
import json
import pwd
from flask import request
class firewall_api:
__isFirewalld = False
__isIptables = False
__isUfw = False
__isMac = False
def __init__(self):
iptables_file = mw.systemdCfgDir() + '/iptables.service'
if os.path.exists('/usr/sbin/firewalld'):
self.__isFirewalld = True
elif os.path.exists('/usr/sbin/ufw'):
self.__isUfw = True
elif os.path.exists(iptables_file):
self.__isIptables = True
elif mw.isAppleSystem():
self.__isMac = True
##### ----- start ----- ###
# 添加屏蔽IP
def addDropAddressApi(self):
import re
port = request.form.get('port', '').strip()
ps = request.form.get('ps', '').strip()
rep = "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$"
if not re.search(rep, port):
return mw.returnJson(False, '您输入的IP地址不合法!')
address = port
if mw.M('firewall').where("port=?", (address,)).count() > 0:
return mw.returnJson(False, '您要放屏蔽的IP已存在屏蔽列表,无需重复处理!')
if self.__isUfw:
mw.execShell('ufw deny from ' + address + ' to any')
else:
if self.__isIptables:
cmd = 'iptables -I INPUT -s ' + address + ' -j DROP'
mw.execShell(cmd)
elif self.__isFirewalld:
cmd = 'firewall-cmd --permanent --add-rich-rule=\'rule family=ipv4 source address="' + \
address + '" drop\''
mw.execShell(cmd)
else:
pass
msg = mw.getInfo('屏蔽IP[{1}]成功!', (address,))
mw.writeLog("防火墙管理", msg)
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
mw.M('firewall').add('port,ps,addtime', (address, ps, addtime))
self.firewallReload()
return mw.returnJson(True, '添加成功!')
# 添加放行端口
def addAcceptPortApi(self):
if not self.getFwStatus():
return mw.returnJson(False, '防火墙启动时,才能添加规则!')
port = request.form.get('port', '').strip()
ps = request.form.get('ps', '').strip()
stype = request.form.get('type', '').strip()
data = self.addAcceptPortArgs(port, ps, stype)
return mw.getJson(data)
# 添加放行端口
def addAcceptPortArgs(self, port, ps, stype):
import re
import time
if not self.getFwStatus():
self.setFw(0)
rep = "^\d{1,5}(:\d{1,5})?$"
if not re.search(rep, port):
return mw.returnData(False, '端口范围不正确!')
if mw.M('firewall').where("port=?", (port,)).count() > 0:
return mw.returnData(False, '您要放行的端口已存在,无需重复放行!')
msg = mw.getInfo('放行端口[{1}]成功', (port,))
mw.writeLog("防火墙管理", msg)
addtime = time.strftime('%Y-%m-%d %X', time.localtime())
mw.M('firewall').add('port,ps,addtime', (port, ps, addtime))
self.addAcceptPort(port)
self.firewallReload()
return mw.returnData(True, '添加放行(' + port + ')端口成功!')
# 删除IP屏蔽
def delDropAddressApi(self):
if not self.getFwStatus():
return mw.returnJson(False, '防火墙启动时,才能删除规则!')
port = request.form.get('port', '').strip()
ps = request.form.get('ps', '').strip()
sid = request.form.get('id', '').strip()
address = port
if self.__isUfw:
mw.execShell('ufw delete deny from ' + address + ' to any')
elif self.__isFirewalld:
mw.execShell(
'firewall-cmd --permanent --remove-rich-rule=\'rule family=ipv4 source address="' + address + '" drop\'')
elif self.__isIptables:
cmd = 'iptables -D INPUT -s ' + address + ' -j DROP'
mw.execShell(cmd)
else:
pass
msg = mw.getInfo('解除IP[{1}]的屏蔽!', (address,))
mw.writeLog("防火墙管理", msg)
mw.M('firewall').where("id=?", (sid,)).delete()
self.firewallReload()
return mw.returnJson(True, '删除成功!')
# 删除放行端口
def delAcceptPortApi(self):
port = request.form.get('port', '').strip()
sid = request.form.get('id', '').strip()
mw_port = mw.readFile('data/port.pl')
try:
if(port == mw_port):
return mw.returnJson(False, '失败,不能删除当前面板端口!')
if self.__isUfw:
mw.execShell('ufw delete allow ' + port + '/tcp')
elif self.__isFirewalld:
port = port.replace(':', '-')
mw.execShell(
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/tcp')
mw.execShell(
'firewall-cmd --permanent --zone=public --remove-port=' + port + '/udp')
elif self.__isIptables:
mw.execShell(
'iptables -D INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT')
else:
pass
msg = mw.getInfo('删除防火墙放行端口[{1}]成功!', (port,))
mw.writeLog("防火墙管理", msg)
mw.M('firewall').where("id=?", (sid,)).delete()
self.firewallReload()
return mw.returnJson(True, '删除成功!')
except Exception as e:
return mw.returnJson(False, '删除失败!:' + str(e))
def getWwwPathApi(self):
path = mw.getLogsDir()
return mw.getJson({'path': path})
def getListApi(self):
p = request.form.get('p', '1').strip()
limit = request.form.get('limit', '10').strip()
return self.getList(int(p), int(limit))
def getLogListApi(self):
p = request.form.get('p', '1').strip()
limit = request.form.get('limit', '10').strip()
search = request.form.get('search', '').strip()
return self.getLogList(int(p), int(limit), search)
def getSshInfoApi(self):
data = {}
file = '/etc/ssh/sshd_config'
conf = mw.readFile(file)
rep = "#*Port\s+([0-9]+)\s*\n"
port = re.search(rep, conf).groups(0)[0]
isPing = True
try:
if mw.isAppleSystem():
isPing = True
else:
file = '/etc/sysctl.conf'
sys_conf = mw.readFile(file)
rep = "#*net\.ipv4\.icmp_echo_ignore_all\s*=\s*([0-9]+)"
tmp = re.search(rep, sys_conf).groups(0)[0]
if tmp == '1':
isPing = False
except:
isPing = True
# sshd 检测
status = True
cmd = "service sshd status | grep -P '(dead|stop)'|grep -v grep"
ssh_status = mw.execShell(cmd)
if ssh_status[0] != '':
status = False
cmd = "systemctl status sshd.service | grep 'dead'|grep -v grep"
ssh_status = mw.execShell(cmd)
if ssh_status[0] != '':
status = False
data['pass_prohibit_status'] = False
# 密码登陆配置检查
pass_rep = "#PasswordAuthentication\s+(\w*)\s*\n"
pass_status = re.search(pass_rep, conf)
if pass_status:
data['pass_prohibit_status'] = True
if not data['pass_prohibit_status']:
pass_rep = "PasswordAuthentication\s+(\w*)\s*\n"
pass_status = re.search(pass_rep, conf)
if pass_status and pass_status.groups(0)[0].strip() == 'no':
data['pass_prohibit_status'] = True
data['port'] = port
data['status'] = status
data['ping'] = isPing
if mw.isAppleSystem():
data['firewall_status'] = False
else:
data['firewall_status'] = self.getFwStatus()
return mw.getJson(data)
def setSshPortApi(self):
port = request.form.get('port', '1').strip()
if int(port) < 22 or int(port) > 65535:
return mw.returnJson(False, '端口范围必需在22-65535之间!')
ports = ['21', '25', '80', '443', '888']
if port in ports:
return mw.returnJson(False, '(' + port + ')' + '特殊端口不可设置!')
file = '/etc/ssh/sshd_config'
conf = mw.readFile(file)
rep = "#*Port\s+([0-9]+)\s*\n"
conf = re.sub(rep, "Port " + port + "\n", conf)
mw.writeFile(file, conf)
self.addAcceptPortArgs(port, 'SSH端口修改', 'port')
if self.__isUfw:
mw.execShell("service ssh restart")
elif self.__isIptables:
mw.execShell("/etc/init.d/sshd restart")
elif self.__isFirewalld:
mw.execShell("systemctl restart sshd.service")
else:
return mw.returnJson(False, '修改失败!')
return mw.returnJson(True, '修改成功!')
def setSshStatusApi(self):
if mw.isAppleSystem():
return mw.returnJson(True, '开发机不能操作!')
status = request.form.get('status', '1').strip()
msg = 'SSH服务已启用'
act = 'start'
if status == "1":
msg = 'SSH服务已停用'
act = 'stop'
ssh_service = mw.systemdCfgDir() + '/sshd.service'
if os.path.exists(ssh_service):
mw.execShell("systemctl " + act + " sshd.service")
else:
mw.execShell('service sshd ' + act)
if os.path.exists('/etc/init.d/sshd'):
mw.execShell('/etc/init.d/sshd ' + act)
mw.writeLog("防火墙管理", msg)
return mw.returnJson(True, '操作成功!')
def setSshPassStatusApi(self):
if mw.isAppleSystem():
return mw.returnJson(True, '开发机不能操作!')
status = request.form.get('status', '1').strip()
msg = '禁止密码登陆成功'
if status == "1":
msg = '开启密码登陆成功'
file = '/etc/ssh/sshd_config'
if not os.path.exists(file):
return mw.returnJson(False, '无法设置!')
conf = mw.readFile(file)
if status == '1':
rep = "(#)?PasswordAuthentication\s+(\w*)\s*\n"
conf = re.sub(rep, "PasswordAuthentication yes\n", conf)
else:
rep = "(#)?PasswordAuthentication\s+(\w*)\s*\n"
conf = re.sub(rep, "PasswordAuthentication no\n", conf)
mw.writeFile(file, conf)
mw.execShell("systemctl restart sshd.service")
mw.writeLog("SSH管理", msg)
return mw.returnJson(True, msg)
def setPingApi(self):
if mw.isAppleSystem():
return mw.returnJson(True, '开发机不能操作!')
status = request.form.get('status')
filename = '/etc/sysctl.conf'
conf = mw.readFile(filename)
if conf.find('net.ipv4.icmp_echo') != -1:
rep = u"net\.ipv4\.icmp_echo.*"
conf = re.sub(rep, 'net.ipv4.icmp_echo_ignore_all=' + status, conf)
else:
conf += "\nnet.ipv4.icmp_echo_ignore_all=" + status
mw.writeFile(filename, conf)
mw.execShell('sysctl -p')
return mw.returnJson(True, '设置成功!')
def setFwApi(self):
if mw.isAppleSystem():
return mw.returnJson(True, '开发机不能设置!')
status = request.form.get('status', '1')
return mw.getJson(self.setFw(status))
def setFwIptables(self, status):
# iptables特殊处理
if status == '1':
mw.execShell('service iptables save')
mw.execShell('service iptables stop')
else:
# 重新导入数据
_list = mw.M('firewall').field('id,port,ps,addtime').limit(
'0,1000').order('id desc').select()
mw.execShell('iptables -P INPUT DROP')
mw.execShell('iptables -P OUTPUT ACCEPT')
for x in _list:
port = x['port']
if mw.isIpAddr(port):
cmd = 'iptables -I INPUT -s ' + port + ' -j DROP'
mw.execShell(cmd)
else:
self.addAcceptPort(port)
mw.execShell('service iptables save')
mw.execShell('service iptables start')
def setFw(self, status):
if self.__isIptables:
self.setFwIptables(status)
return mw.returnData(True, '设置成功!')
if status == '1':
if self.__isUfw:
mw.execShell('/usr/sbin/ufw disable')
elif self.__isFirewalld:
mw.execShell('systemctl stop firewalld.service')
mw.execShell('systemctl disable firewalld.service')
else:
pass
else:
if self.__isUfw:
mw.execShell("echo 'y'| ufw enable")
elif self.__isFirewalld:
mw.execShell('systemctl start firewalld.service')
mw.execShell('systemctl enable firewalld.service')
else:
pass
return mw.returnData(True, '设置成功!')
def delPanelLogsApi(self):
mw.M('logs').where('id>?', (0,)).delete()
mw.writeLog('面板设置', '面板操作日志已清空!')
return mw.returnJson(True, '面板操作日志已清空!')
##### ----- start ----- ###
pass
def getList(self, page, limit):
start = (page - 1) * limit
_list = mw.M('firewall').field('id,port,ps,addtime').limit(
_list = public.M('firewall').field('id,port,ps,addtime').limit(
str(start) + ',' + str(limit)).order('id desc').select()
data = {}
data['data'] = _list
count = mw.M('firewall').count()
count = public.M('firewall').count()
_page = {}
_page['count'] = count
_page['tojs'] = 'showAccept'
_page['p'] = page
data['page'] = mw.getPage(_page)
return mw.getJson(data)
data['page'] = public.getPage(_page)
return public.getJson(data)
def getLogList(self, page, limit, search=''):
find_search = ''
@@ -422,64 +41,16 @@ class firewall_api:
start = (page - 1) * limit
_list = mw.M('logs').where(find_search, ()).field(
_list = public.M('logs').where(find_search, ()).field(
'id,type,log,addtime').limit(str(start) + ',' + str(limit)).order('id desc').select()
data = {}
data['data'] = _list
count = mw.M('logs').where(find_search, ()).count()
count = public.M('logs').where(find_search, ()).count()
_page = {}
_page['count'] = count
_page['tojs'] = 'getLogs'
_page['p'] = page
data['page'] = mw.getPage(_page)
return mw.getJson(data)
def addAcceptPort(self, port):
if self.__isUfw:
mw.execShell('ufw allow ' + port + '/tcp')
elif self.__isFirewalld:
port = port.replace(':', '-')
cmd = 'firewall-cmd --permanent --zone=public --add-port=' + port + '/tcp'
mw.execShell(cmd)
elif self.__isIptables:
cmd = 'iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ' + port + ' -j ACCEPT'
mw.execShell(cmd)
else:
pass
return True
def firewallReload(self):
if self.__isUfw:
mw.execShell('/usr/sbin/ufw reload')
return
elif self.__isIptables:
mw.execShell('service iptables save')
mw.execShell('service iptables restart')
elif self.__isFirewalld:
mw.execShell('firewall-cmd --reload')
else:
pass
def getFwStatus(self):
if self.__isUfw:
cmd = "/usr/sbin/ufw status| grep Status | awk -F ':' '{print $2}'"
data = mw.execShell(cmd)
if data[0].strip() == 'inactive':
return False
return True
elif self.__isIptables:
cmd = "systemctl status iptables | grep 'inactive'"
data = mw.execShell(cmd)
if data[0] != '':
return False
return True
elif self.__isFirewalld:
cmd = "ps -ef|grep firewalld |grep -v grep | awk '{print $2}'"
data = mw.execShell(cmd)
if data[0] == '':
return False
return True
else:
return False
data['page'] = public.getPage(_page)
return public.getJson(data)
-1947
View File
File diff suppressed because it is too large Load Diff
+26 -41
View File
@@ -1,20 +1,8 @@
# coding: utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# 分页库操作
# ---------------------------------------------------------------------------------
import math
import string
import public
class Page():
@@ -41,7 +29,8 @@ class Page():
__END_NUM = None # 结束行
def __init__(self):
if False:
tmp = public.getMsg('PAGE')
if tmp:
self.__PREV = tmp['PREV']
self.__NEXT = tmp['NEXT']
self.__START = tmp['START']
@@ -66,6 +55,7 @@ class Page():
self.SHIFT = self.__START_NUM - 1
keys = limit.split(',')
pages = {}
# 起始页
pages['1'] = self.__GetStart()
@@ -80,16 +70,14 @@ class Page():
# 当前显示页与总页数
pages['6'] = "<span class='Pnumber'>" + \
str(self.__C_PAGE) + "/" + \
str(self.__COUNT_PAGE) + "</span>"
bytes(self.__C_PAGE) + "/" + bytes(self.__COUNT_PAGE) + "</span>"
# 本页显示开始与结束行
pages['7'] = "<span class='Pline'>" + str(self.__FO) + \
str(self.__START_NUM) + "-" + \
str(self.__END_NUM) + str(self.__LINE) + "</span>"
pages['7'] = "<span class='Pline'>" + self.__FO + \
bytes(self.__START_NUM) + "-" + \
bytes(self.__END_NUM) + self.__LINE + "</span>"
# 行数
pages['8'] = "<span class='Pcount'>" + str(self.__COUNT_START) + \
str(self.__COUNT_ROW) + str(self.__COUNT_END) + "</span>"
pages['8'] = "<span class='Pcount'>" + self.__COUNT_START + \
bytes(self.__COUNT_ROW) + self.__COUNT_END + "</span>"
# 构造返回数据
retuls = '<div>'
@@ -108,11 +96,10 @@ class Page():
else:
if self.__RTURN_JS == "":
endStr = "<a class='Pend' href='" + self.__URI + "p=" + \
str(self.__COUNT_PAGE) + "'>" + str(self.__END) + "</a>"
bytes(self.__COUNT_PAGE) + "'>" + self.__END + "</a>"
else:
endStr = "<a class='Pend' onclick='" + self.__RTURN_JS + \
"(" + str(self.__COUNT_PAGE) + ")'>" + \
str(self.__END) + "</a>"
"(" + bytes(self.__COUNT_PAGE) + ")'>" + self.__END + "</a>"
return endStr
def __GetNext(self):
@@ -123,11 +110,10 @@ class Page():
else:
if self.__RTURN_JS == "":
nextStr = "<a class='Pnext' href='" + self.__URI + "p=" + \
str(self.__C_PAGE + 1) + "'>" + str(self.__NEXT) + "</a>"
bytes(self.__C_PAGE + 1) + "'>" + self.__NEXT + "</a>"
else:
nextStr = "<a class='Pnext' onclick='" + self.__RTURN_JS + \
"(" + str(self.__C_PAGE + 1) + ")'>" + \
str(self.__NEXT) + "</a>"
"(" + bytes(self.__C_PAGE + 1) + ")'>" + self.__NEXT + "</a>"
return nextStr
@@ -148,15 +134,15 @@ class Page():
if page > 0:
if self.__RTURN_JS == "":
pages += "<a class='Pnum' href='" + self.__URI + \
"p=" + str(page) + "'>" + str(page) + "</a>"
"p=" + bytes(page) + "'>" + bytes(page) + "</a>"
else:
pages += "<a class='Pnum' onclick='" + self.__RTURN_JS + \
"(" + str(page) + ")'>" + str(page) + "</a>"
"(" + bytes(page) + ")'>" + bytes(page) + "</a>"
# 当前页
if self.__C_PAGE > 0:
pages += "<span class='Pcurrent'>" + \
str(self.__C_PAGE) + "</span>"
bytes(self.__C_PAGE) + "</span>"
# 当前页之后
if self.__C_PAGE <= self.__LIST_NUM:
@@ -171,10 +157,10 @@ class Page():
break
if self.__RTURN_JS == "":
pages += "<a class='Pnum' href='" + self.__URI + \
"p=" + str(page) + "'>" + str(page) + "</a>"
"p=" + bytes(page) + "'>" + bytes(page) + "</a>"
else:
pages += "<a class='Pnum' onclick='" + self.__RTURN_JS + \
"(" + str(page) + ")'>" + str(page) + "</a>"
"(" + bytes(page) + ")'>" + bytes(page) + "</a>"
return pages
@@ -186,11 +172,10 @@ class Page():
else:
if self.__RTURN_JS == "":
startStr = "<a class='Ppren' href='" + self.__URI + "p=" + \
str(self.__C_PAGE - 1) + "'>" + str(self.__PREV) + "</a>"
bytes(self.__C_PAGE - 1) + "'>" + self.__PREV + "</a>"
else:
startStr = "<a class='Ppren' onclick='" + self.__RTURN_JS + \
"(" + str(self.__C_PAGE - 1) + ")'>" + \
str(self.__PREV) + "</a>"
"(" + bytes(self.__C_PAGE - 1) + ")'>" + self.__PREV + "</a>"
return startStr
def __GetStart(self):
@@ -201,10 +186,10 @@ class Page():
else:
if self.__RTURN_JS == "":
startStr = "<a class='Pstart' href='" + \
self.__URI + "p=1'>" + str(self.__START) + "</a>"
self.__URI + "p=1'>" + self.__START + "</a>"
else:
startStr = "<a class='Pstart' onclick='" + \
self.__RTURN_JS + "(1)'>" + str(self.__START) + "</a>"
self.__RTURN_JS + "(1)'>" + self.__START + "</a>"
return startStr
def __GetCpage(self, p):
@@ -227,11 +212,11 @@ class Page():
# 取总页数
return int(math.ceil(self.__COUNT_ROW / float(self.ROW)))
def __SetUri(self, sinput):
def __SetUri(self, input):
# 构造URI
uri = '?'
for key in sinput:
for key in input:
if key == 'p':
continue
uri += key + '=' + sinput[key] + '&'
uri += key + '=' + input[key] + '&'
return str(uri)
+512
View File
@@ -0,0 +1,512 @@
# coding: utf-8
import psutil
import time
import os
import public
import re
import json
import threading
import multiprocessing
class pa_thread(threading.Thread):
def __init__(self, func, args, name=''):
threading.Thread.__init__(self)
self.name = name
self.func = func
self.args = args
self.result = self.func(*self.args)
def getResult(self):
try:
return self.result
except Exception:
return None
class plugin_api:
__tasks = None
__plugin_dir = 'plugins'
__type = 'data/json/type.json'
__index = 'data/json/index.json'
setupPath = None
def __init__(self):
self.setupPath = 'server'
# self.__plugin_dir = public.getRunDir() + '/plugins'
# 进程是否存在
def processExists(self, pname, exe=None):
try:
if not self.pids:
self.pids = psutil.pids()
for pid in self.pids:
try:
p = psutil.Process(pid)
if p.name() == pname:
if not exe:
return True
else:
if p.exe() == exe:
return True
except:
pass
return False
except:
return True
# 检查是否正在安装
def checkSetupTask(self, sName):
if not self.__tasks:
self.__tasks = public.M('tasks').where(
"status!=?", ('1',)).field('status,name').select()
if sName.find('php-') != -1:
tmp = sName.split('-')
sName = tmp[0]
version = tmp[1]
isTask = '1'
for task in self.__tasks:
tmpt = public.getStrBetween('[', ']', task['name'])
if not tmpt:
continue
tmp1 = tmpt.split('-')
name1 = tmp1[0].lower()
if sName == 'php':
if name1 == sName and tmp1[1] == version:
isTask = task['status']
else:
if name1 == 'pure':
name1 = 'pure-ftpd'
if name1 == sName:
isTask = task['status']
return isTask
def checkStatus(self, info):
if not info['setup']:
return False
data = self.run(info['name'], 'status', info['setup_version'])
if data[0] == 'start':
return True
return False
def checkStatusProcess(self, info, i, return_dict):
if not info['setup']:
return_dict[i] = False
return
data = self.run(info['name'], 'status', info['setup_version'])
if data[0] == 'start':
return_dict[i] = True
else:
return_dict[i] = False
def checkStatusMProcess(self, plugins_info):
manager = multiprocessing.Manager()
return_dict = manager.dict()
jobs = []
ntmp_list = range(len(plugins_info))
for i in ntmp_list:
p = multiprocessing.Process(
target=self.checkStatusProcess, args=(plugins_info[i], i, return_dict))
jobs.append(p)
p.start()
for proc in jobs:
proc.join()
returnData = return_dict.values()
for i in ntmp_list:
plugins_info[i]['status'] = returnData[i]
return plugins_info
def checkDisplayIndex(self, name, version):
if not os.path.exists(self.__index):
public.writeFile(self.__index, '[]')
indexList = json.loads(public.readFile(self.__index))
if type(version) == list:
for index in range(len(version)):
vname = name + '-' + version[index]
if vname in indexList:
return True
else:
vname = name + '-' + version
if vname in indexList:
return True
return False
def getVersion(self, path):
version_f = path + '/version.pl'
if os.path.exists(version_f):
return public.readFile(version_f).strip()
return ''
# 构造本地插件信息
def getPluginInfo(self, info):
checks = ''
path = ''
coexist = False
if info["checks"][0:1] == '/':
checks = info["checks"]
else:
checks = public.getRootDir() + '/' + info['checks']
if info.has_key('path'):
path = info['path']
if path[0:1] != '/':
path = public.getRootDir() + '/' + path
if info.has_key('coexist') and info['coexist']:
coexist = True
pluginInfo = {
"id": 10000,
"pid": info['pid'],
"type": 1000,
"name": info['name'],
"title": info['title'],
"ps": info['ps'],
"dependnet": "",
"mutex": "",
"path": path,
"install_checks": checks,
"uninsatll_checks": checks,
"coexist": coexist,
"versions": info['versions'],
# "updates": info['updates'],
"display": False,
"setup": False,
"setup_version": "",
"status": False,
}
pluginInfo['task'] = self.checkSetupTask(pluginInfo['name'])
if checks.find('VERSION') > -1:
pluginInfo['install_checks'] = checks.replace(
'VERSION', info['versions'])
if path.find('VERSION') > -1:
pluginInfo['path'] = path.replace(
'VERSION', info['versions'])
pluginInfo['display'] = self.checkDisplayIndex(
info['name'], pluginInfo['versions'])
pluginInfo['setup'] = os.path.exists(pluginInfo['install_checks'])
if coexist and pluginInfo['setup']:
pluginInfo['setup_version'] = info['versions']
else:
pluginInfo['setup_version'] = self.getVersion(
pluginInfo['install_checks'])
# pluginInfo['status'] = self.checkStatus(pluginInfo)
return pluginInfo
def makeCoexist(self, data):
plugins_info = []
for index in range(len(data['versions'])):
tmp = data.copy()
tmp['title'] = tmp['title'] + \
'-' + data['versions'][index]
tmp['versions'] = data['versions'][index]
pg = self.getPluginInfo(tmp)
plugins_info.append(pg)
return plugins_info
def makeList(self, data, sType='0'):
plugins_info = []
if (data['pid'] == sType):
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
tmp_data = self.makeCoexist(data)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
else:
pg = self.getPluginInfo(data)
plugins_info.append(pg)
return plugins_info
if sType == '0':
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
tmp_data = self.makeCoexist(data)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
else:
pg = self.getPluginInfo(data)
plugins_info.append(pg)
# print plugins_info, data
return plugins_info
def getAllList(self, sType='0'):
plugins_info = []
for dirinfo in os.listdir(self.__plugin_dir):
if dirinfo[0:1] == '.':
continue
path = self.__plugin_dir + '/' + dirinfo
if os.path.isdir(path):
json_file = path + '/info.json'
if os.path.exists(json_file):
try:
data = json.loads(public.readFile(json_file))
tmp_data = self.makeList(data, sType)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
except Exception, e:
print e
return plugins_info
def getAllListPage(self, sType='0', page=1, pageSize=10):
plugins_info = []
for dirinfo in os.listdir(self.__plugin_dir):
if dirinfo[0:1] == '.':
continue
path = self.__plugin_dir + '/' + dirinfo
if os.path.isdir(path):
json_file = path + '/info.json'
if os.path.exists(json_file):
try:
data = json.loads(public.readFile(json_file))
tmp_data = self.makeList(data, sType)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
except Exception, e:
print e
start = (page - 1) * pageSize
end = start + pageSize
_plugins_info = plugins_info[start:end]
_plugins_info = self.checkStatusMProcess(_plugins_info)
return (_plugins_info, len(plugins_info))
def makeListThread(self, data, sType='0'):
plugins_info = []
if (data['pid'] == sType):
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
tmp_data = self.makeCoexist(data)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
else:
pg = self.getPluginInfo(data)
plugins_info.append(pg)
return plugins_info
if sType == '0':
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
tmp_data = self.makeCoexist(data)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
else:
pg = self.getPluginInfo(data)
plugins_info.append(pg)
# print plugins_info, data
return plugins_info
def getAllListThread(self, sType='0'):
plugins_info = []
tmp_list = []
threads = []
for dirinfo in os.listdir(self.__plugin_dir):
if dirinfo[0:1] == '.':
continue
path = self.__plugin_dir + '/' + dirinfo
if os.path.isdir(path):
json_file = path + '/info.json'
if os.path.exists(json_file):
data = json.loads(public.readFile(json_file))
if sType == '0':
tmp_list.append(data)
if (data['pid'] == sType):
tmp_list.append(data)
ntmp_list = range(len(tmp_list))
for i in ntmp_list:
t = pa_thread(self.makeListThread, (tmp_list[i], sType))
threads.append(t)
for i in ntmp_list:
threads[i].start()
for i in ntmp_list:
threads[i].join()
for i in ntmp_list:
t = threads[i].getResult()
for index in range(len(t)):
plugins_info.append(t[index])
return plugins_info
def makeListProcess(self, data, sType, i, return_dict):
plugins_info = []
if (data['pid'] == sType):
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
tmp_data = self.makeCoexist(data)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
else:
pg = self.getPluginInfo(data)
plugins_info.append(pg)
# return plugins_info
if sType == '0':
if type(data['versions']) == list and data.has_key('coexist') and data['coexist']:
tmp_data = self.makeCoexist(data)
for index in range(len(tmp_data)):
plugins_info.append(tmp_data[index])
else:
pg = self.getPluginInfo(data)
plugins_info.append(pg)
return_dict[i] = plugins_info
# return plugins_info
def getAllListProcess(self, sType='0'):
plugins_info = []
tmp_list = []
manager = multiprocessing.Manager()
return_dict = manager.dict()
jobs = []
for dirinfo in os.listdir(self.__plugin_dir):
if dirinfo[0:1] == '.':
continue
path = self.__plugin_dir + '/' + dirinfo
if os.path.isdir(path):
json_file = path + '/info.json'
if os.path.exists(json_file):
data = json.loads(public.readFile(json_file))
if sType == '0':
tmp_list.append(data)
if (data['pid'] == sType):
tmp_list.append(data)
ntmp_list = range(len(tmp_list))
for i in ntmp_list:
p = multiprocessing.Process(
target=self.makeListProcess, args=(tmp_list[i], sType, i, return_dict))
jobs.append(p)
p.start()
for proc in jobs:
proc.join()
returnData = return_dict.values()
for i in ntmp_list:
for index in range(len(returnData[i])):
plugins_info.append(returnData[i][index])
return plugins_info
def getPluginList(self, sType, sPage=1, sPageSize=10):
ret = {}
ret['type'] = json.loads(public.readFile(self.__type))
# plugins_info = self.getAllListThread(sType)
# plugins_info = self.getAllListProcess(sType)
data = self.getAllListPage(sType, sPage, sPageSize)
ret['data'] = data[0]
args = {}
args['count'] = data[1]
args['p'] = sPage
args['tojs'] = 'getSList'
args['row'] = sPageSize
ret['list'] = public.getPage(args)
return ret
def getIndexList(self):
if not os.path.exists(self.__index):
public.writeFile(self.__index, '[]')
indexList = json.loads(public.readFile(self.__index))
plist = []
app = []
for i in indexList:
info = i.split('-')
if not info[0] in app:
app.append(info[0])
path = self.__plugin_dir + '/' + info[0]
if os.path.isdir(path):
json_file = path + '/info.json'
if os.path.exists(json_file):
try:
data = json.loads(public.readFile(json_file))
tmp_data = self.makeList(data)
for index in range(len(tmp_data)):
if tmp_data[index]['versions'] == info[1] or info[1] in tmp_data[index]['versions']:
tmp_data[index]['display'] = True
plist.append(tmp_data[index])
continue
except Exception, e:
print e
plist = self.checkStatusMProcess(plist)
return plist
def setIndexSort(self, sort):
data = sort.split('|')
public.writeFile(self.__index, json.dumps(data))
return True
def addIndex(self, name, version):
if not os.path.exists(self.__index):
public.writeFile(self.__index, '[]')
indexList = json.loads(public.readFile(self.__index))
vname = name + '-' + version
if vname in indexList:
return public.returnJson(False, '请不要重复添加!')
if len(indexList) >= 12:
return public.returnJson(False, '首页最多只能显示12个软件!')
indexList.append(vname)
public.writeFile(self.__index, json.dumps(indexList))
return public.returnJson(True, '添加成功!')
def removeIndex(self, name, version):
if not os.path.exists(self.__index):
public.writeFile(self.__index, '[]')
indexList = json.loads(public.readFile(self.__index))
vname = name + '-' + version
if not vname in indexList:
return public.returnJson(True, '删除成功!')
indexList.remove(vname)
public.writeFile(self.__index, json.dumps(indexList))
return public.returnJson(True, '删除成功!')
def run(self, name, func, version, args='', script='index'):
path = public.getRunDir() + '/' + self.__plugin_dir + \
'/' + name + '/' + script + '.py'
py = 'python ' + path
if args == '':
py_cmd = py + ' ' + func + ' ' + version
else:
py_cmd = py + ' ' + func + ' ' + version + ' ' + args
if not os.path.exists(path):
return ('', '')
data = public.execShell(py_cmd)
print py_cmd
# print os.path.exists(py_cmd)
return (data[0].strip(), data[1].strip())
File diff suppressed because it is too large Load Diff
+723
View File
@@ -0,0 +1,723 @@
# coding: utf-8
import os
import sys
import time
import string
import json
import hashlib
import shlex
import datetime
import subprocess
import re
import hashlib
import db
from random import Random
def execShell(cmdstring, cwd=None, timeout=None, shell=True):
if shell:
cmdstring_list = cmdstring
else:
cmdstring_list = shlex.split(cmdstring)
if timeout:
end_time = datetime.datetime.now() + datetime.timedelta(seconds=timeout)
sub = subprocess.Popen(cmdstring_list, cwd=cwd, stdin=subprocess.PIPE,
shell=shell, bufsize=4096, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while sub.poll() is None:
time.sleep(0.1)
if timeout:
if end_time <= datetime.datetime.now():
raise Exception("Timeout:%s" % cmdstring)
return sub.communicate()
def getRunDir():
return os.getcwd()
def getRootDir():
return os.path.dirname(os.path.dirname(getRunDir()))
def getPluginDir():
return getRunDir() + '/plugins'
def getServerDir():
return getRootDir() + '/server'
def getWwwDir():
return getRootDir() + '/wwwroot'
def getLogsDir():
return getRootDir() + '/wwwlogs'
def getOs():
os = execShell('uname')
return os[0].lower().strip()
def isAppleSystem():
if getOs() == 'darwin':
return True
return False
def isInstalledWeb():
path = getServerDir() + '/openresty/nginx/sbin/nginx'
if os.path.exists(path):
return True
return False
def restartWeb():
if isInstalledWeb():
initd = getServerDir() + '/openresty/init.d/openresty'
execShell(initd + ' ' + 'reload')
def M(table):
sql = db.Sql()
return sql.table(table)
def getPage(args, result='1,2,3,4,5,8'):
data = getPageObject(args, result)
return data[0]
def getPageObject(args, result='1,2,3,4,5,8'):
# 取分页
import page
# 实例化分页类
page = page.Page()
info = {}
info['count'] = 0
if args.has_key('count'):
info['count'] = int(args['count'])
info['row'] = 10
if args.has_key('row'):
info['row'] = int(args['row'])
info['p'] = 1
if args.has_key('p'):
info['p'] = int(args['p'])
info['uri'] = {}
info['return_js'] = ''
if args.has_key('tojs'):
info['return_js'] = args['tojs']
return (page.GetPage(info, result), page)
def md5(str):
# 生成MD5
try:
m = hashlib.md5()
m.update(str)
return m.hexdigest()
except:
return False
def getFileMd5(filename):
# 文件的MD5值
if not os.path.isfile(filename):
return False
myhash = hashlib.md5()
f = file(filename, 'rb')
while True:
b = f.read(8096)
if not b:
break
myhash.update(b)
f.close()
return myhash.hexdigest()
def getRandomString(length):
# 取随机字符串
str = ''
chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
chrlen = len(chars) - 1
random = Random()
for i in range(length):
str += chars[random.randint(0, chrlen)]
return str
def getJson(data):
import json
return json.dumps(data)
def returnJson(status, msg, args=()):
# 取通用Json返回
return getJson(returnMsg(status, msg, args))
def returnMsg(status, msg, args=()):
# 取通用字曲返回
pjson = 'static/language/' + getLanguage() + '/public.json'
logMessage = json.loads(readFile(pjson))
keys = logMessage.keys()
if msg in keys:
msg = logMessage[msg]
for i in range(len(args)):
rep = '{' + str(i + 1) + '}'
msg = msg.replace(rep, args[i])
return {'status': status, 'msg': msg, 'data': args}
def getInfo(msg, args=()):
# 取提示消息
for i in range(len(args)):
rep = '{' + str(i + 1) + '}'
msg = msg.replace(rep, args[i])
return msg
def getMsg(key, args=()):
# 取提示消息
try:
logMessage = json.loads(
readFile('static/language/' + getLanguage() + '/public.json'))
keys = logMessage.keys()
msg = None
if key in keys:
msg = logMessage[key]
for i in range(len(args)):
rep = '{' + str(i + 1) + '}'
msg = msg.replace(rep, args[i])
return msg
except:
return key
def getLan(key):
# 取提示消息
logMessage = json.loads(
readFile('static/language/' + getLanguage() + '/template.json'))
keys = logMessage.keys()
msg = None
if key in keys:
msg = logMessage[key]
return msg
def readFile(filename):
# 读文件内容
try:
fp = open(filename, 'r')
fBody = fp.read()
fp.close()
return fBody
except:
return False
def getDate():
# 取格式时间
import time
return time.strftime('%Y-%m-%d %X', time.localtime())
def getLanguage():
path = 'data/language.pl'
if not os.path.exists(path):
return 'Simplified_Chinese'
return readFile(path).strip()
def writeLog(type, logMsg, args=()):
# 写日志
try:
import time
import db
import json
logMessage = json.loads(
readFile('static/language/' + getLanguage() + '/log.json'))
keys = logMessage.keys()
if logMsg in keys:
logMsg = logMessage[logMsg]
for i in range(len(args)):
rep = '{' + str(i + 1) + '}'
logMsg = logMsg.replace(rep, args[i])
if type in keys:
type = logMessage[type]
sql = db.Sql()
mDate = time.strftime('%Y-%m-%d %X', time.localtime())
data = (type, logMsg, mDate)
result = sql.table('logs').add('type,log,addtime', data)
except:
pass
def writeFile(filename, str):
# 写文件内容
try:
fp = open(filename, 'w+')
fp.write(str)
fp.close()
return True
except:
return False
def httpGet(url, timeout=30):
# 发送GET请求
try:
import urllib2
import ssl
try:
ssl._create_default_https_context = ssl._create_unverified_context
except:
pass
response = urllib2.urlopen(url, timeout=timeout)
return response.read()
except Exception, ex:
# WriteLog('网络诊断',str(ex) + '['+url+']');
return str(ex)
def httpPost(url, data, timeout=30):
# 发送POST请求
try:
import urllib
import urllib2
import ssl
try:
ssl._create_default_https_context = ssl._create_unverified_context
except:
pass
data = urllib.urlencode(data)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req, timeout=timeout)
return response.read()
except Exception, ex:
# WriteLog('网络诊断',str(ex) + '['+url+']');
return str(ex)
def writeSpeed(title, used, total, speed=0):
# 写进度
if not title:
data = {'title': None, 'progress': 0,
'total': 0, 'used': 0, 'speed': 0}
else:
progress = int((100.0 * used / total))
data = {'title': title, 'progress': progress,
'total': total, 'used': used, 'speed': speed}
writeFile('/tmp/panelSpeed.pl', json.dumps(data))
return True
def getSpeed():
# 取进度
data = readFile('/tmp/panelSpeed.pl')
if not data:
data = json.dumps({'title': None, 'progress': 0,
'total': 0, 'used': 0, 'speed': 0})
writeFile('/tmp/panelSpeed.pl', data)
return json.loads(data)
def getLastLine(inputfile, lineNum):
# 读文件指定倒数行数
try:
fp = open(inputfile, 'r')
lastLine = ""
lines = fp.readlines()
count = len(lines)
if count > lineNum:
num = lineNum
else:
num = count
i = 1
lastre = []
for i in range(1, (num + 1)):
if lines:
n = -i
lastLine = lines[n].strip()
fp.close()
lastre.append(lastLine)
result = ''
num -= 1
while num >= 0:
result += lastre[num] + "\n"
num -= 1
return result
except:
return getMsg('TASK_SLEEP')
def downloadFile(url, filename):
import urllib
urllib.urlretrieve(url, filename=filename, reporthook=downloadHook)
def downloadHook(count, blockSize, totalSize):
speed = {'total': totalSize, 'block': blockSize, 'count': count}
print speed
print '%02d%%' % (100.0 * count * blockSize / totalSize)
def getLocalIp():
# 取本地外网IP
try:
import re
filename = 'data/iplist.txt'
ipaddress = readFile(filename)
if not ipaddress:
import urllib2
url = 'http://pv.sohu.com/cityjson?ie=utf-8'
opener = urllib2.urlopen(url)
str = opener.read()
ipaddress = re.search('\d+.\d+.\d+.\d+', str).group(0)
writeFile(filename, ipaddress)
ipaddress = re.search('\d+.\d+.\d+.\d+', ipaddress).group(0)
return ipaddress
except:
return '127.0.0.1'
def inArray(arrays, searchStr):
# 搜索数据中是否存在
for key in arrays:
if key == searchStr:
return True
return False
def checkIp(ip):
# 检查是否为IPv4地址
import re
p = re.compile(
'^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$')
if p.match(ip):
return True
else:
return False
def checkPort(port):
# 检查端口是否合法
ports = ['21', '25', '443', '8080', '888', '8888', '8443']
if port in ports:
return False
intport = int(port)
if intport < 1 or intport > 65535:
return False
return True
def getStrBetween(startStr, endStr, srcStr):
# 字符串取中间
start = srcStr.find(startStr)
if start == -1:
return None
end = srcStr.find(endStr)
if end == -1:
return None
return srcStr[start + 1:end]
def getCpuType():
# 取CPU类型
cpuinfo = open('/proc/cpuinfo', 'r').read()
rep = "model\s+name\s+:\s+(.+)"
tmp = re.search(rep, cpuinfo)
cpuType = None
if tmp:
cpuType = tmp.groups()[0]
return cpuType
def isRestart():
# 检查是否允许重启
num = M('tasks').where('status!=?', ('1',)).count()
if num > 0:
return False
return True
def isUpdateLocalSoft():
num = M('tasks').where('status!=?', ('1',)).count()
if os.path.exists('mdserver-web.zip'):
return True
if num > 0:
data = M('tasks').where('status!=?', ('1',)).field(
'id,type,execstr').limit('1').select()
argv = data[0]['execstr'].split('|dl|')
if data[0]['type'] == 'download' and argv[1] == 'mdserver-web.zip':
return True
return False
def hasPwd(password):
# 加密密码字符
import crypt
return crypt.crypt(password, password)
def getTimeout(url):
start = time.time()
result = httpGet(url)
if result != 'True':
return False
return int((time.time() - start) * 1000)
def auth_decode(data):
# 解密数据
token = GetToken()
# 是否有生成Token
if not token:
return returnMsg(False, 'REQUEST_ERR')
# 校验access_key是否正确
if token['access_key'] != data['btauth_key']:
return returnMsg(False, 'REQUEST_ERR')
# 解码数据
import binascii
import hashlib
import urllib
import hmac
import json
tdata = binascii.unhexlify(data['data'])
# 校验signature是否正确
signature = binascii.hexlify(
hmac.new(token['secret_key'], tdata, digestmod=hashlib.sha256).digest())
if signature != data['signature']:
return returnMsg(False, 'REQUEST_ERR')
# 返回
return json.loads(urllib.unquote(tdata))
# 数据加密
def auth_encode(data):
token = GetToken()
pdata = {}
# 是否有生成Token
if not token:
return returnMsg(False, 'REQUEST_ERR')
# 生成signature
import binascii
import hashlib
import urllib
import hmac
import json
tdata = urllib.quote(json.dumps(data))
# 公式 hex(hmac_sha256(data))
pdata['signature'] = binascii.hexlify(
hmac.new(token['secret_key'], tdata, digestmod=hashlib.sha256).digest())
# 加密数据
pdata['btauth_key'] = token['access_key']
pdata['data'] = binascii.hexlify(tdata)
pdata['timestamp'] = time.time()
# 返回
return pdata
def checkToken(get):
# 检查Token
tempFile = 'data/tempToken.json'
if not os.path.exists(tempFile):
return False
import json
import time
tempToken = json.loads(readFile(tempFile))
if time.time() > tempToken['timeout']:
return False
if get.token != tempToken['token']:
return False
return True
def checkInput(data):
# 过滤输入
if not data:
return data
if type(data) != str:
return data
checkList = [
{'d': '<', 'r': '<'},
{'d': '>', 'r': '>'},
{'d': '\'', 'r': '‘'},
{'d': '"', 'r': '“'},
{'d': '&', 'r': '&'},
{'d': '#', 'r': '#'},
{'d': '<', 'r': '<'}
]
for v in checkList:
data = data.replace(v['d'], v['r'])
return data
def getNumLines(path, num, p=1):
# 取文件指定尾行数
try:
import cgi
if not os.path.exists(path):
return ""
start_line = (p - 1) * num
count = start_line + num
fp = open(path)
buf = ""
fp.seek(-1, 2)
if fp.read(1) == "\n":
fp.seek(-1, 2)
data = []
b = True
n = 0
for i in range(count):
while True:
newline_pos = string.rfind(buf, "\n")
pos = fp.tell()
if newline_pos != -1:
if n >= start_line:
line = buf[newline_pos + 1:]
try:
data.insert(0, cgi.escape(line))
except:
pass
buf = buf[:newline_pos]
n += 1
break
else:
if pos == 0:
b = False
break
to_read = min(4096, pos)
fp.seek(-to_read, 1)
buf = fp.read(to_read) + buf
fp.seek(-to_read, 1)
if pos - to_read == 0:
buf = "\n" + buf
if not b:
break
fp.close()
except:
data = []
return "\n".join(data)
def checkCert(certPath='ssl/certificate.pem'):
# 验证证书
openssl = '/usr/local/openssl/bin/openssl'
if not os.path.exists(openssl):
openssl = 'openssl'
certPem = readFile(certPath)
s = "\n-----BEGIN CERTIFICATE-----"
tmp = certPem.strip().split(s)
for tmp1 in tmp:
if tmp1.find('-----BEGIN CERTIFICATE-----') == -1:
tmp1 = s + tmp1
writeFile(certPath, tmp1)
result = execShell(openssl + " x509 -in " +
certPath + " -noout -subject")
if result[1].find('-bash:') != -1:
return True
if len(result[1]) > 2:
return False
if result[0].find('error:') != -1:
return False
return True
# 获取面板地址
# def getPanelAddr():
# import web
# protocol = 'https://' if os.path.exists("data/ssl.pl") else 'http://'
# h = web.ctx.host.split(':')
# try:
# result = protocol + h[0] + ':' + h[1]
# except:
# result = protocol + h[0] + ':' + readFile('data/port.pl').strip()
# return result
def toSize(size):
# 字节单位转换
d = ('b', 'KB', 'MB', 'GB', 'TB')
s = d[0]
for b in d:
if size < 1024:
return str(size) + ' ' + b
size = size / 1024
s = b
return str(size) + ' ' + b
def getMacAddress():
# 获取mac
import uuid
mac = uuid.UUID(int=uuid.getnode()).hex[-12:]
return ":".join([mac[e:e + 2] for e in range(0, 11, 2)])
def get_string(t):
if t != -1:
max = 126
m_types = [{'m': 122, 'n': 97}, {'m': 90, 'n': 65}, {'m': 57, 'n': 48}, {
'm': 47, 'n': 32}, {'m': 64, 'n': 58}, {'m': 96, 'n': 91}, {'m': 125, 'n': 123}]
else:
max = 256
t = 0
m_types = [{'m': 255, 'n': 0}]
arr = []
for i in range(max):
if i < m_types[t]['n'] or i > m_types[t]['m']:
continue
arr.append(chr(i))
return arr
def get_string_find(t):
if type(t) != list:
t = [t]
return_str = ''
for s1 in t:
return_str += get_string(int(s1[0]))[int(s1[1:])]
return return_str
def get_string_arr(t):
s_arr = {}
t_arr = []
for s1 in t:
for i in range(6):
if not i in s_arr:
s_arr[i] = get_string(i)
for j in range(len(s_arr[i])):
if s1 == s_arr[i][j]:
t_arr.append(str(i) + str(j))
return t_arr
+130 -2484
View File
File diff suppressed because it is too large Load Diff
-456
View File
@@ -1,456 +0,0 @@
# coding: utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# SSH终端操作
# ---------------------------------------------------------------------------------
import json
import time
import os
import sys
import socket
import threading
import re
from io import BytesIO, StringIO
import mw
import paramiko
from flask_socketio import SocketIO, emit, send
class ssh_terminal:
__debug_file = 'logs/terminal.log'
__log_type = 'SSH终端'
# websocketio 唯一标识
__sid = ''
__host = None
__type = '0'
__port = 22
__user = None
__pass = None
__pkey = None
__key_passwd = None
__rep_ssh_config = False
__rep_ssh_service = False
__sshd_config_backup = None
__ssh = None
__tp = None
__ps = None
__ssh_list = {}
__ssh_last_request_time = {}
def __init__(self):
ht = threading.Thread(target=self.heartbeat)
ht.start()
def debug(self, msg):
msg = "{} - {}:{} => {} \n".format(mw.formatDate(),
self.__host, self.__port, msg)
if not mw.isDebugMode():
return
mw.writeFile(self.__debug_file, msg, 'a+')
def returnMsg(self, status, msg):
return {'status': status, 'msg': msg}
def restartSsh(self, act='reload'):
'''
重启ssh 无参数传递
'''
version = mw.readFile('/etc/redhat-release')
if not os.path.exists('/etc/redhat-release'):
mw.execShell('service ssh ' + act)
elif version.find(' 7.') != -1 or version.find(' 8.') != -1:
mw.execShell("systemctl " + act + " sshd.service")
else:
mw.execShell("/etc/init.d/sshd " + act)
def isRunning(self, rep=False):
try:
if rep and self.__rep_ssh_service:
self.restartSsh('stop')
return True
status = self.getSshStatus()
if not status:
self.restartSsh('start')
self.__rep_ssh_service = True
return True
return False
except:
return False
def setSshdConfig(self, rep=False):
self.isRunning(rep)
if rep and not self.__rep_ssh_config:
return False
try:
sshd_config_file = '/etc/ssh/sshd_config'
if not os.path.exists(sshd_config_file):
return False
sshd_config = mw.readFile(sshd_config_file)
if not sshd_config:
return False
if rep:
if self.__sshd_config_backup:
mw.writeFile(sshd_config_file, self.__sshd_config_backup)
self.restartSsh()
return True
pin = r'^\s*PubkeyAuthentication\s+(yes|no)'
pubkey_status = re.findall(pin, sshd_config, re.I)
if pubkey_status:
if pubkey_status[0] == 'yes':
pubkey_status = True
else:
pubkey_status = False
pin = r'^\s*RSAAuthentication\s+(yes|no)'
rsa_status = re.findall(pin, sshd_config, re.I)
if rsa_status:
if rsa_status[0] == 'yes':
rsa_status = True
else:
rsa_status = False
self._sshd_config_backup = sshd_config
is_write = False
if not pubkey_status:
sshd_config = re.sub(
r'\n#?PubkeyAuthentication\s\w+', '\nPubkeyAuthentication yes', sshd_config)
is_write = True
if not rsa_status:
sshd_config = re.sub(
r'\n#?RSAAuthentication\s\w+', '\nRSAAuthentication yes', sshd_config)
is_write = True
if is_write:
mw.writeFile(sshd_config_file, sshd_config)
self.__rep_ssh_config = True
self.restartSsh()
else:
self.__sshd_config_backup = None
return True
except:
return False
def setSid(self, sid):
self.__sid = sid
def connect(self, sid):
# self.connectBySocket()
if self.__host in ['127.0.0.1', 'localhost']:
return self.connectLocalSsh(sid)
else:
return self.connectBySocket(sid)
def connectLocalSsh(self, sid):
mw.createSshInfo()
self.__ps = paramiko.SSHClient()
self.__ps.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.__port = mw.getSSHPort()
try:
self.__ps.connect(self.__host, self.__port, timeout=60)
except Exception as e:
self.__ps.connect('127.0.0.1', self.__port)
except Exception as e:
self.__ps.connect('localhost', self.__port)
except Exception as e:
self.setSshdConfig(True)
self.__ps.close()
e = str(e)
if e.find('websocket error!') != -1:
return self.returnMsg(True, '连接成功')
if e.find('Authentication timeout') != -1:
self.debug("认证超时{}".format(e))
return self.returnMsg(False, '认证超时,请按回车重试!{}'.format(e))
if e.find('Connection reset by peer') != -1:
self.debug('目标服务器主动拒绝连接')
return self.returnMsg(False, '目标服务器主动拒绝连接')
if e.find('Error reading SSH protocol banner') != -1:
self.debug('协议头响应超时')
return self.returnMsg(False, '协议头响应超时,与目标服务器之间的网络质量太糟糕:' + e)
if not e:
self.debug('SSH协议握手超时')
return self.returnMsg(False, "SSH协议握手超时,与目标服务器之间的网络质量太糟糕")
err = mw.getTracebackInfo()
self.debug(err)
return self.returnMsg(False, "未知错误: {}".format(err))
self.debug('local-ssh:认证成功,正在构建会话通道')
ssh = self.__ps.invoke_shell(
term='xterm', width=83, height=21)
ssh.setblocking(0)
self.__ssh_list[sid] = ssh
mw.writeLog(self.__log_type, '成功登录到SSH服务器 [{}:{}]'.format(
self.__host, self.__port))
self.debug('local-ssh:通道已构建')
return self.returnMsg(True, '连接成功!')
def connectBySocket(self, sid):
if not self.__host:
return self.returnMsg(False, '错误的连接地址')
if not self.__user:
self.__user = 'root'
if not self.__port:
self.__port = 22
self.setSshdConfig(True)
num = 0
while num < 5:
num += 1
try:
self.debug('正在尝试第{}次连接'.format(num))
if self.__rep_ssh_config:
time.sleep(0.1)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(2 + num)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 8192)
sock.connect((self.__host, self.__port))
break
except Exception as e:
if num == 5:
self.setSshdConfig(True)
self.debug('重试连接失败,{}'.format(e))
return self.returnMsg(False, '连接目标服务器失败, {}:{}'.format(self.__host, self.__port))
else:
time.sleep(0.2)
# print(self.__host, sock)
self.__tp = paramiko.Transport(sock)
try:
self.__tp.start_client()
self.__tp.banner_timeout = 60
if not self.__pass and not self.__pkey:
return self.returnMsg(False, '密码或私钥不能都为空: {}:{}'.format(self.__host, self.__port))
if self.__pkey != '' and self.__type != '0':
self.debug('正在认证私钥')
p_file = StringIO(str(self.__pkey.replace('\\n', '\n')))
# p_file = "/tmp/t_ssh_pkey.txt"
# mw.writeFile(p_file, self.__pkey.replace('\\n', '\n'))
# mw.execShell('chmod 600 ' + p_file)
try:
p_file.seek(0)
pkey = paramiko.RSAKey.from_private_key(p_file)
except:
try:
p_file.seek(0) # 重置游标
pkey = paramiko.Ed25519Key.from_private_key(
p_file)
except:
try:
p_file.seek(0)
pkey = paramiko.ECDSAKey.from_private_key(p_file)
except:
p_file.seek(0)
pkey = paramiko.DSSKey.from_private_key(p_file)
self.__tp.auth_publickey(username=self.__user, key=pkey)
else:
try:
self.__tp.auth_none(self.__user)
except Exception as e:
e = str(e)
if e.find('keyboard-interactive') >= 0:
self._auth_interactive()
else:
self.debug('正在认证密码')
self.__tp.auth_password(
username=self.__user, password=self.__pass)
except Exception as e:
self.setSshdConfig(True)
self.__tp.close()
e = str(e)
# print(e)
if e.find('Authentication timeout') != -1:
self.debug("认证超时{}".format(e))
return self.returnMsg(False, '认证超时,请按回车重试!{}'.format(e))
if e.find('Authentication failed') != -1:
self.debug('认证失败{}'.format(e))
return self.returnMsg(False, '帐号或密码错误: {}'.format(e + "," + self.__user + "@" + self.__host + ":" + str(self.__port)))
if e.find('Bad authentication type; allowed types') != -1:
self.debug('认证失败{}'.format(e))
if self.__host in ['127.0.0.1', 'localhost'] and self.__pass == 'none':
return self.returnMsg(False, '帐号或密码错误: {}'.format("Authentication failed ," + self.__user + "@" + self.__host + ":" + str(self.__port)))
return self.returnMsg(False, '不支持的身份验证类型: {}'.format(e))
if e.find('Connection reset by peer') != -1:
self.debug('目标服务器主动拒绝连接')
return self.returnMsg(False, '目标服务器主动拒绝连接')
if e.find('Error reading SSH protocol banner') != -1:
self.debug('协议头响应超时')
return self.returnMsg(False, '协议头响应超时,与目标服务器之间的网络质量太糟糕:' + e)
if not e:
self.debug('SSH协议握手超时')
return self.returnMsg(False, "SSH协议握手超时,与目标服务器之间的网络质量太糟糕")
err = mw.getTracebackInfo()
self.debug(err)
return self.returnMsg(False, "未知错误: {}".format(err))
self.debug('认证成功,正在构建会话通道')
ssh = self.__tp.open_session()
ssh.get_pty(term='xterm', width=100, height=34)
ssh.invoke_shell()
self.__ssh_list[sid] = ssh
mw.writeLog(self.__log_type, '成功登录到SSH服务器 [{}:{}]'.format(
self.__host, self.__port))
self.debug('通道已构建')
return self.returnMsg(True, '连接成功.')
def getSshInfo(self, file):
rdata = mw.readFile(file)
destr = mw.enDoubleCrypt('mdserver-web', rdata)
return json.loads(destr)
def setAttr(self, sid, info):
self.__host = info['host'].strip()
# 外部连接获取
if not self.__host in ['127.0.0.1', 'localhost']:
dst_info = mw.getServerDir() + '/webssh/host/' + self.__host + '/info.json'
if os.path.exists(dst_info):
info = self.getSshInfo(dst_info)
if 'type' in info:
self.__type = info['type']
if 'port' in info:
self.__port = int(info['port'])
if 'username' in info:
self.__user = info['username']
if 'pkey' in info:
self.__pkey = info['pkey']
if 'password' in info:
self.__pass = info['password']
if 'pkey_passwd' in info:
self.__key_passwd = info['pkey_passwd']
# print(self.__host, self.__pass, self.__key_passwd)
try:
result = self.connect(sid)
# print(result)
except Exception as ex:
if str(ex).find("NoneType") == -1:
raise ex
return result
def send(self):
pass
def close(self):
try:
if self.__ssh:
self.__ssh.close()
if self.__tp: # 关闭宿主服务
self.__tp.close()
if self.__ps:
self.__ps.close()
except:
pass
def resize(self, sid, data):
try:
self.__ssh_list[sid].resize_pty(
width=data['cols'], height=data['rows'])
return True
except:
return False
def wsSend(self, recv):
try:
t = recv.decode("utf-8")
return emit('server_response', {'data': t})
except Exception as e:
return emit('server_response', {'data': recv})
def wsSendConnect(self):
return emit('connect', {'data': 'ok'})
def wsSendReConnect(self):
return emit('reconnect', {'data': 'ok'})
def heartbeat(self):
# limit_cos = 10
while True:
time.sleep(3)
cur_time = time.time()
for x in list(self.__ssh_list.keys()):
ssh_last_time = self.__ssh_last_request_time[x]
sid_off_cos = cur_time - ssh_last_time
# print("heartbeat off cos :", x, sid_off_cos)
if sid_off_cos > 3:
cur_ssh = self.__ssh_list[x]
if not cur_ssh:
del(self.__ssh_list[x])
del(self.__ssh_last_request_time[x])
continue
if cur_ssh.exit_status_ready():
del(self.__ssh_list[x])
del(self.__ssh_last_request_time[x])
continue
cur_ssh.send("exit\r\n")
del(self.__ssh_list[x])
del(self.__ssh_last_request_time[x])
def run(self, sid, info):
self.__sid = sid
if not self.__sid:
return self.wsSend('WebSocketIO无效')
self.__ssh_last_request_time[sid] = time.time()
if not sid in self.__ssh_list:
if type(info) == dict and 'host' in info:
result = self.setAttr(sid, info)
if result['status']:
return self.wsSendConnect()
else:
return self.wsSend(result['msg'])
else:
return self.wsSendReConnect()
result = self.returnMsg(False, '')
if sid in self.__ssh_list:
if 'resize' in info:
self.resize(sid, info)
result = self.returnMsg(True, '已连接')
if result['status']:
if type(info) == str:
time.sleep(0.1)
cur_ssh = self.__ssh_list[sid]
if cur_ssh.exit_status_ready():
self.wsSend("logout\r\n")
del(self.__ssh_list[sid])
return
cur_ssh.send(info)
try:
time.sleep(0.005)
recv = cur_ssh.recv(8192)
return self.wsSend(recv)
except Exception as ex:
return self.wsSend('')
else:
return self.wsSend(result['msg'])
+201 -349
View File
@@ -1,44 +1,17 @@
# coding: utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# 系统信息操作
# ---------------------------------------------------------------------------------
import psutil
import time
import os
import re
import math
import sys
import json
from flask import Flask, session
from flask import request
import db
import mw
import config_api
import requests
from threading import Thread
from time import sleep
def mw_async(f):
def wrapper(*args, **kwargs):
thr = Thread(target=f, args=args, kwargs=kwargs)
thr.start()
return wrapper
import public
import config
class system_api:
@@ -46,93 +19,9 @@ class system_api:
pids = None
def __init__(self):
self.setupPath = mw.getServerDir()
self.setupPath = public.getServerDir()
##### ----- start ----- ###
def networkApi(self):
data = self.getNetWork()
return mw.getJson(data)
def updateServerApi(self):
stype = request.args.get('type', 'check')
version = request.args.get('version', '')
return self.updateServer(stype, version)
def systemTotalApi(self):
data = self.getSystemTotal()
return mw.getJson(data)
def diskInfoApi(self):
diskInfo = self.getDiskInfo()
return mw.getJson(diskInfo)
def setControlApi(self):
stype = request.form.get('type', '')
day = request.form.get('day', '')
data = self.setControl(stype, day)
return data
def getLoadAverageApi(self):
start = request.args.get('start', '')
end = request.args.get('end', '')
data = self.getLoadAverageData(start, end)
return mw.getJson(data)
def getCpuIoApi(self):
start = request.args.get('start', '')
end = request.args.get('end', '')
data = self.getCpuIoData(start, end)
return mw.getJson(data)
def getDiskIoApi(self):
start = request.args.get('start', '')
end = request.args.get('end', '')
data = self.getDiskIoData(start, end)
return mw.getJson(data)
def getNetworkIoApi(self):
start = request.args.get('start', '')
end = request.args.get('end', '')
data = self.getNetWorkIoData(start, end)
return mw.getJson(data)
def rememoryApi(self):
os.system('sync')
scriptFile = mw.getRunDir() + '/script/rememory.sh'
mw.execShell("/bin/bash " + scriptFile)
data = self.getMemInfo()
return mw.getJson(data)
# 重启面板
def restartApi(self):
self.restartMw()
return mw.returnJson(True, '面板已重启!')
def restartServerApi(self):
if mw.isAppleSystem():
return mw.returnJson(False, "开发环境不可重起")
self.restartServer()
return mw.returnJson(True, '正在重启服务器!')
##### ----- end ----- ###
def restartTask(self):
initd = mw.getRunDir() + '/scripts/init.d/mw'
if os.path.exists(initd):
os.system(initd + ' ' + 'restart_task')
return True
def restartMw(self):
mw.writeFile('data/restart.pl', 'True')
return True
@mw_async
def restartServer(self):
if not mw.isRestart():
return mw.returnJson(False, '请等待所有安装任务完成再执行!')
mw.execShell("sync && init 6 &")
return mw.returnJson(True, '命令发送成功!')
# 名取PID
# 名取PID
def getPid(self, pname):
try:
if not self.pids:
@@ -166,59 +55,32 @@ class system_api:
except:
return False
def getEnvInfoApi(self, get=None):
serverInfo = {}
serverInfo['status'] = True
sdir = mw.getServerDir()
serverInfo['webserver'] = '未安装'
if os.path.exists(sdir + '/openresty/nginx/sbin/nginx'):
serverInfo['webserver'] = 'OpenResty'
serverInfo['php'] = []
phpversions = ['52', '53', '54', '55', '56', '70', '71',
'72', '73', '74', '80', '81', '82', '83', '84']
phpPath = sdir + '/php/'
for pv in phpversions:
if not os.path.exists(phpPath + pv + '/bin/php'):
continue
serverInfo['php'].append(pv)
serverInfo['mysql'] = False
if os.path.exists(sdir + '/mysql/bin/mysql'):
serverInfo['mysql'] = True
import psutil
try:
diskInfo = psutil.disk_usage('/www')
except:
diskInfo = psutil.disk_usage('/')
serverInfo['disk'] = diskInfo[2]
return mw.returnJson(True, 'ok', serverInfo)
def getPanelInfo(self, get=None):
# 取面板配置
address = mw.GetLocalIp()
address = public.GetLocalIp()
try:
try:
port = web.ctx.host.split(':')[1]
except:
port = mw.readFile('data/port.pl')
port = public.readFile('data/port.pl')
except:
port = '7200'
port = '8888'
domain = ''
if os.path.exists('data/domain.conf'):
domain = mw.readFile('data/domain.conf')
domain = public.readFile('data/domain.conf')
autoUpdate = ''
if os.path.exists('data/autoUpdate.pl'):
autoUpdate = 'checked'
limitip = ''
if os.path.exists('data/limitip.conf'):
limitip = mw.readFile('data/limitip.conf')
limitip = public.readFile('data/limitip.conf')
templates = []
for template in os.listdir('templates/'):
if os.path.isdir('templates/' + template):
templates.append(template)
template = mw.readFile('data/templates.pl')
template = public.readFile('data/templates.pl')
check502 = ''
if os.path.exists('data/502Task.pl'):
@@ -233,17 +95,17 @@ class system_api:
data['cpuRealUsed'] = cpu[0]
data['time'] = self.getBootTime()
data['system'] = self.getSystemVersion()
data['isuser'] = mw.M('users').where(
data['isuser'] = public.M('users').where(
'username=?', ('admin',)).count()
data['version'] = '0.0.1'
return data
def getLoadAverage(self):
def getLoadAverage(self, get=None):
c = os.getloadavg()
data = {}
data['one'] = round(float(c[0]), 2)
data['five'] = round(float(c[1]), 2)
data['fifteen'] = round(float(c[2]), 2)
data['one'] = float(c[0])
data['five'] = float(c[1])
data['fifteen'] = float(c[2])
data['max'] = psutil.cpu_count() * 2
data['limit'] = data['max']
data['safe'] = data['max'] * 0.75
@@ -255,7 +117,7 @@ class system_api:
data['title'] = self.GetTitle()
data['network'] = self.GetNetWorkApi(get)
data['panel_status'] = not os.path.exists(
'/www/server/mdserver-web/data/close.pl')
'/www/server/panel/data/close.pl')
import firewalls
ssh_info = firewalls.firewalls().GetSshInfo(None)
data['enable_ssh_status'] = ssh_info['status']
@@ -268,70 +130,53 @@ class system_api:
def getTitle(self):
titlePl = 'data/title.pl'
title = 'Linux面板'
title = '宝塔Linux面板'
if os.path.exists(titlePl):
title = mw.readFile(titlePl).strip()
title = public.readFile(titlePl).strip()
return title
def getSystemVersion(self):
# 取操作系统版本
if mw.getOs() == 'darwin':
data = mw.execShell('sw_vers')[0]
os = public.getOs()
if os == 'darwin':
data = public.execShell('sw_vers')[0]
data_list = data.strip().split("\n")
mac_version = ''
for x in data_list:
mac_version += x.split("\t")[1] + ' '
return mac_version
redhat_series = '/etc/redhat-release'
if os.path.exists(redhat_series):
version = mw.readFile('/etc/redhat-release')
version = public.readFile('/etc/redhat-release')
if not version:
version = public.readFile(
'/etc/issue').strip().split("\n")[0].replace('\\n', '').replace('\l', '').strip()
else:
version = version.replace('release ', '').strip()
return version
os_series = '/etc/os-release'
if os.path.exists(os_series):
version = mw.execShell(
"cat /etc/*-release | grep PRETTY_NAME | awk -F = '{print $2}' | awk -F '\"' '{print $2}'")
return version[0].strip()
return '未识别系统信息'
return version
def getBootTime(self):
# 取系统启动时间
uptime = mw.readFile('/proc/uptime')
if uptime == False:
start_time = psutil.boot_time()
run_time = time.time() - start_time
else:
run_time = uptime.split()[0]
start_time = psutil.boot_time()
run_time = time.time() - start_time
# conf = public.readFile('/proc/uptime').split()
tStr = float(run_time)
min = tStr / 60
hours = min / 60
days = math.floor(hours / 24)
hours = math.floor(hours - (days * 24))
min = math.floor(min - (days * 60 * 24) - (hours * 60))
return mw.getInfo('已不间断运行: {1}天{2}小时{3}分钟', (str(int(days)), str(int(hours)), str(int(min))))
return public.getInfo('已不间断运行: {1}天{2}小时{3}分钟', (str(int(days)), str(int(hours)), str(int(min))))
def getCpuInfo(self, interval=1):
# 取CPU信息
cpuCount = psutil.cpu_count()
cpuLogicalNum = psutil.cpu_count(logical=False)
used = psutil.cpu_percent(interval=interval)
return used, cpuCount
if os.path.exists('/proc/cpuinfo'):
c_tmp = mw.readFile('/proc/cpuinfo')
d_tmp = re.findall("physical id.+", c_tmp)
cpuLogicalNum = len(set(d_tmp))
used_all = psutil.cpu_percent(percpu=True)
cpu_name = mw.getCpuType() + " * {}".format(cpuLogicalNum)
return used, cpuCount, used_all, cpu_name, cpuCount, cpuLogicalNum
def getMemInfo(self):
def getMemInfo(self, get=None):
# 取内存信息
mem = psutil.virtual_memory()
if mw.getOs() == 'darwin':
if public.getOs() == 'darwin':
memInfo = {
'memTotal': mem.total / 1024 / 1024
}
@@ -355,7 +200,7 @@ class system_api:
import psutil
mem = psutil.virtual_memory()
if mw.getOs() == 'darwin':
if public.getOs() == 'darwin':
return mem.percent
memInfo = {'memTotal': mem.total / 1024 / 1024, 'memFree': mem.free / 1024 / 1024,
@@ -364,14 +209,11 @@ class system_api:
memInfo['memBuffers'] - memInfo['memCached']
tmp1 = memInfo['memTotal'] / 100
return (tmp / tmp1)
except Exception as ex:
except Exception, ex:
return 1
def getDiskInfo(self):
info = self.getDiskInfo2()
if len(info) != 0:
return info
def getDiskInfo(self, get=None):
return self.getDiskInfo2()
# 取磁盘分区信息
diskIo = psutil.disk_partitions()
diskInfo = []
@@ -383,24 +225,22 @@ class system_api:
continue
tmp = {}
tmp['path'] = disk[1]
size_tmp = psutil.disk_usage(disk[1])
tmp['size'] = [mw.toSize(size_tmp[0]), mw.toSize(
size_tmp[1]), mw.toSize(size_tmp[2]), str(size_tmp[3]) + '%']
tmp['size'] = psutil.disk_usage(disk[1])
diskInfo.append(tmp)
return diskInfo
def getDiskInfo2(self):
# 取磁盘分区信息
temp = mw.execShell(
temp = public.execShell(
"df -h -P|grep '/'|grep -v tmpfs | grep -v devfs")[0]
tempInodes = mw.execShell(
tempInodes = public.execShell(
"df -i -P|grep '/'|grep -v tmpfs | grep -v devfs")[0]
temp1 = temp.split('\n')
tempInodes1 = tempInodes.split('\n')
diskInfo = []
n = 0
cuts = ['/mnt/cdrom', '/boot', '/boot/efi', '/dev',
'/dev/shm', '/zroot', '/run/lock', '/run', '/run/shm', '/run/user']
'/dev/shm', '/run/lock', '/run', '/run/shm', '/run/user']
for tmp in temp1:
n += 1
inodes = tempInodes1[n - 1].split()
@@ -420,7 +260,16 @@ class system_api:
tmp1 = [disk[1], disk[2], disk[3], disk[4]]
arr['size'] = tmp1
arr['inodes'] = [inodes[1], inodes[2], inodes[3], inodes[4]]
diskInfo.append(arr)
if disk[5] == '/':
bootLog = os.getcwd() + '/tmp/panelBoot.pl'
if disk[2].find('M') != -1:
if os.path.exists(bootLog):
os.system('rm -f ' + bootLog)
else:
if not os.path.exists(bootLog):
pass
if inodes[2] != '0':
diskInfo.append(arr)
return diskInfo
# 清理系统垃圾
@@ -454,7 +303,7 @@ class system_api:
shutil.rmtree(filename)
else:
os.remove(filename)
print('mail clear ok')
print '\t\033[1;32m[OK]\033[0m'
num += 1
total += size
count += num
@@ -463,10 +312,10 @@ class system_api:
# 清理其它
def clearOther(self):
clearPath = [
{'path': '/www/server/mdserver-web', 'find': 'testDisk_'},
{'path': '/www/server/panel', 'find': 'testDisk_'},
{'path': '/www/wwwlogs', 'find': 'log'},
{'path': '/tmp', 'find': 'panelBoot.pl'},
{'path': '/www/server/mdserver-web/install', 'find': '.rpm'}
{'path': '/www/server/panel/install', 'find': '.rpm'}
]
total = count = 0
@@ -482,39 +331,16 @@ class system_api:
else:
os.remove(filename)
count += 1
mw.restartWeb()
public.serviceReload()
os.system('echo > /tmp/panelBoot.pl')
return total, count
def psutilNetIoCounters(self):
'''
统计网卡流量
'''
stat_pl = 'data/only_netio_counters.pl'
if os.path.exists(stat_pl):
local_lo = (0, 0, 0, 0)
ioName = psutil.net_io_counters(pernic=True).keys()
for x in ioName:
if x.find("lo") > -1:
local_lo = psutil.net_io_counters(
pernic=True).get(x)[:4]
all_io = psutil.net_io_counters()[:4]
result_io = tuple([all_io[i] - local_lo[i]
for i in range(0, len(all_io))])
# print(local_lo)
# print(all_io)
# print(result_io)
return result_io
return psutil.net_io_counters()[:4]
def getNetWork(self):
def getNetWork(self, get=None):
# return self.GetNetWorkApi(get);
# 取网络流量信息
try:
# 取网络流量信息
networkIo = self.psutilNetIoCounters()
networkIo = psutil.net_io_counters()[:4]
if not "otime" in session:
session['up'] = networkIo[0]
session['down'] = networkIo[1]
@@ -537,34 +363,82 @@ class system_api:
session['otime'] = time.time()
networkInfo['cpu'] = self.getCpuInfo()
networkInfo['load'] = self.getLoadAverage()
networkInfo['mem'] = self.getMemInfo()
networkInfo['load'] = self.getLoadAverage(get)
networkInfo['mem'] = self.getMemInfo(get)
return networkInfo
except Exception as e:
print("getNetWork error:", e)
except Exception, e:
print e
return None
def getNetWorkApi(self, get=None):
# 取网络流量信息
try:
tmpfile = 'data/network.temp'
networkIo = psutil.net_io_counters()[:4]
if not os.path.exists(tmpfile):
public.writeFile(tmpfile, str(
networkIo[0]) + '|' + str(networkIo[1]) + '|' + str(int(time.time())))
lastValue = public.readFile(tmpfile).split('|')
ntime = time.time()
networkInfo = {}
networkInfo['upTotal'] = networkIo[0]
networkInfo['downTotal'] = networkIo[1]
networkInfo['up'] = round(
float(networkIo[0] - int(lastValue[0])) / 1024 / (ntime - int(lastValue[2])), 2)
networkInfo['down'] = round(
float(networkIo[1] - int(lastValue[1])) / 1024 / (ntime - int(lastValue[2])), 2)
networkInfo['downPackets'] = networkIo[3]
networkInfo['upPackets'] = networkIo[2]
public.writeFile(tmpfile, str(
networkIo[0]) + '|' + str(networkIo[1]) + '|' + str(int(time.time())))
# networkInfo['cpu'] = self.GetCpuInfo(0.1)
return networkInfo
except:
return None
def restartServer(self, get):
if not public.isRestart():
return public.returnMsg(False, 'EXEC_ERR_TASK')
public.ExecShell("sync && /etc/init.d/bt stop && init 6 &")
return public.returnMsg(True, 'SYS_REBOOT')
# 释放内存
def reMemory(self, get):
os.system('sync')
scriptFile = 'script/rememory.sh'
if not os.path.exists(scriptFile):
public.downloadFile(web.ctx.session.home +
'/script/rememory.sh', scriptFile)
public.ExecShell("/bin/bash " + self.setupPath +
'/panel/' + scriptFile)
return self.GetMemInfo()
def getNetWorkIoData(self, start, end):
# 取指定时间段的网络Io
data = mw.M('network').dbfile('system').where("addtime>=? AND addtime<=?", (start, end)).field(
data = public.M('network').dbfile('system').where("addtime>=? AND addtime<=?", (start, end)).field(
'id,up,down,total_up,total_down,down_packets,up_packets,addtime').order('id asc').select()
return self.toAddtime(data)
def getDiskIoData(self, start, end):
# 取指定时间段的磁盘Io
data = mw.M('diskio').dbfile('system').where("addtime>=? AND addtime<=?", (start, end)).field(
data = public.M('diskio').dbfile('system').where("addtime>=? AND addtime<=?", (start, end)).field(
'id,read_count,write_count,read_bytes,write_bytes,read_time,write_time,addtime').order('id asc').select()
return self.toAddtime(data)
def getCpuIoData(self, start, end):
# 取指定时间段的CpuIo
data = mw.M('cpuio').dbfile('system').where("addtime>=? AND addtime<=?",
(start, end)).field('id,pro,mem,addtime').order('id asc').select()
data = public.M('cpuio').dbfile('system').where("addtime>=? AND addtime<=?",
(start, end)).field('id,pro,mem,addtime').order('id asc').select()
return self.toAddtime(data, True)
def getLoadAverageData(self, start, end):
data = mw.M('load_average').dbfile('system').where("addtime>=? AND addtime<=?", (
data = public.M('load_average').dbfile('system').where("addtime>=? AND addtime<=?", (
start, end)).field('id,pro,one,five,fifteen,addtime').order('id asc').select()
return self.toAddtime(data)
@@ -608,50 +482,39 @@ class system_api:
def setControl(self, stype, day):
filename = 'data/control.conf'
stat_pl = 'data/only_netio_counters.pl'
if stype == '0':
mw.execShell("rm -rf " + filename)
public.execShell("rm -f " + filename)
elif stype == '1':
_day = int(day)
if _day < 1:
return mw.returnJson(False, "设置失败!")
mw.writeFile(filename, day)
elif stype == '2':
mw.execShell("rm -rf " + stat_pl)
elif stype == '3':
mw.execShell("echo 'True' > " + stat_pl)
return public.returnJson(False, "设置失败!")
public.writeFile(filename, day)
elif stype == 'del':
if not mw.isRestart():
return mw.returnJson(False, '请等待所有安装任务完成再执行')
if not public.isRestart():
return public.returnJson(False, '请等待所有安装任务完成再执行')
os.remove("data/system.db")
sql = db.Sql().dbfile('system')
csql = mw.readFile('data/sql/system.sql')
csql = public.readFile('data/sql/system.sql')
csql_list = csql.split(';')
for index in range(len(csql_list)):
sql.execute(csql_list[index], ())
return mw.returnJson(True, "监控服务已关闭")
return public.returnJson(True, "监控服务已关闭")
else:
data = {}
if os.path.exists(filename):
try:
data['day'] = int(mw.readFile(filename))
data['day'] = int(public.readFile(filename))
except:
data['day'] = 30
data['status'] = True
else:
data['day'] = 30
data['status'] = False
return public.getJson(data)
if os.path.exists(stat_pl):
data['stat_all_status'] = True
else:
data['stat_all_status'] = False
return mw.getJson(data)
return mw.returnJson(True, "设置成功!")
return public.returnJson(True, "设置成功!")
def versionDiff(self, old, new):
'''
@@ -664,128 +527,117 @@ class system_api:
return 'test'
old_list = old.split('.')
ret = 'none'
isHasNew = True
if int(new_list[0]) == int(old_list[0]) and int(new_list[1]) == int(old_list[1]) and int(new_list[2]) == int(old_list[2]):
isHasNew = False
if isHasNew:
return 'new'
for i in range(len(old_list)):
tm_new = int(new_list[i])
tm_old = int(new_list[i])
if tm_new > tm_old:
return 'new'
return ret
def getServerInfo(self):
import urllib.request
import ssl
upAddr = 'https://api.github.com/repos/midoks/mdserver-web/releases/latest'
upAddr = 'https://raw.githubusercontent.com/midoks/mdserver-web/master/version'
try:
context = ssl._create_unverified_context()
req = urllib.request.urlopen(upAddr, context=context, timeout=3)
result = req.read().decode('utf-8')
version = json.loads(result)
return version
version = public.httpGet(
upAddr + '/info.json')
version = json.loads(version)
return version[0]
except Exception as e:
print('getServerInfo', e)
print e
return {}
def updateServer(self, stype, version=''):
# 更新服务
try:
if not mw.isRestart():
return mw.returnJson(False, '请等待所有安装任务完成再执行!')
version_new_info = self.getServerInfo()
version_now = config_api.config_api().getVersion()
if public.isUpdateLocalSoft():
if stype == 'check' or stype == 'info' or stype == 'update':
return public.returnJson(True, '正在安装中...', 'download')
if stype == 'update_status':
new_ver = version_new_info['name']
data = public.readFile('tmp/panelExec.log')
if data == 'done':
return public.returnJson(True, '进度!', 100)
else:
_data = json.loads(data)
return public.returnJson(True, '进度!', _data['pre'])
if os.path.exists('mdserver-web.zip'):
return public.returnJson(True, '进度!', 100)
if not public.isRestart():
return public.returnJson(False, '请等待所有安装任务完成再执行!')
if stype == 'check':
if not 'name' in version_new_info:
return mw.returnJson(False, '服务器数据或网络有问题!')
version_now = config.config().getVersion()
version_new_info = self.getServerInfo()
if not 'version' in version_new_info:
return public.returnJson(False, '服务器数据有问题!')
diff = self.versionDiff(version_now, new_ver)
diff = self.versionDiff(
version_now, version_new_info['version'])
if diff == 'new':
return mw.returnJson(True, '有新版本!', new_ver)
return public.returnJson(True, '有新版本!', version_new_info['version'])
elif diff == 'test':
return mw.returnJson(True, '有测试版本!', new_ver)
return public.returnJson(True, '有测试版本!', version_new_info['version'])
else:
return mw.returnJson(False, '已经是最新,无需更新!')
return public.returnJson(False, '已经是最新,无需更新!')
if stype == 'info':
if not 'name' in version_new_info:
return mw.returnJson(False, '服务器数据有问题!')
diff = self.versionDiff(version_now, new_ver)
data = {}
data['version'] = new_ver
data['content'] = version_new_info[
'body'].replace("\n", "<br/>")
return mw.returnJson(True, '更新信息!', data)
version_new_info = self.getServerInfo()
version_now = config.config().getVersion()
if not 'version' in version_new_info:
return public.returnJson(False, '服务器数据有问题!')
diff = self.versionDiff(
version_now, version_new_info['version'])
return public.returnJson(True, '更新信息!', version_new_info)
if stype == 'update':
if version == '':
return mw.returnJson(False, '缺少版本信息!')
return public.returnJson(False, '缺少版本信息!')
if new_ver != version:
return mw.returnJson(False, '更新失败,请重试!')
v_new_info = self.getServerInfo()
if v_new_info['version'] != version:
return public.returnJson(False, '更新失败,请重试!')
toPath = mw.getRootDir() + '/temp'
if not os.path.exists(toPath):
mw.execShell('mkdir -p ' + toPath)
if not 'path' in v_new_info or v_new_info['path'] == '':
return public.returnJson(False, '下载地址不存在!')
newUrl = "https://github.com/midoks/mdserver-web/archive/refs/tags/" + version + ".zip"
execstr = v_new_info['path'] + '|dl|mdserver-web.zip'
taskAdd = (None, '下载[mdserver-web-' + v_new_info['version'] + ']',
'download', '0', time.strftime('%Y-%m-%d %H:%M:%S'), execstr)
dist_mw = toPath + '/mw.zip'
if not os.path.exists(dist_mw):
mw.execShell(
'wget --no-check-certificate -O ' + dist_mw + ' ' + newUrl)
public.M('tasks').add(
'id,name,type,status,addtime, execstr', taskAdd)
return public.returnJson(True, '下载中...')
dist_to = toPath + "/mdserver-web-" + version
if not os.path.exists(dist_to):
os.system('unzip -o ' + toPath +
'/mw.zip' + ' -d ' + toPath)
if stype == 'update_install':
public.execShell('unzip -o mdserver-web.zip -d ./')
public.execShell('rm -f mdserver-web.zip')
return public.returnJson(True, '安装更新成功!')
cmd_cp = 'cp -rf ' + toPath + '/mdserver-web-' + \
version + '/* ' + mw.getServerDir() + '/mdserver-web'
mw.execShell(cmd_cp)
mw.execShell('rm -rf ' + toPath + '/mdserver-web-' + version)
mw.execShell('rm -rf ' + toPath + '/mw.zip')
update_env = '''
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
if [ ! -f /www/server/mdserver-web/bin/activate ];then
cd /www/server/mdserver-web && python3 -m venv .
cd /www/server/mdserver-web && source /www/server/mdserver-web/bin/activate
else
cd /www/server/mdserver-web && source /www/server/mdserver-web/bin/activate
fi
cn=$(curl -fsSL -m 10 http://ipinfo.io/json | grep "\"country\": \"CN\"")
PIPSRC="https://pypi.python.org/simple"
if [ ! -z "$cn" ];then
PIPSRC="https://pypi.tuna.tsinghua.edu.cn/simple"
fi
cd /www/server/mdserver-web && pip3 install -r /www/server/mdserver-web/requirements.txt -i $PIPSRC
'''
os.system(update_env)
self.restartMw()
return mw.returnJson(True, '安装更新成功!')
return mw.returnJson(False, '已经是最新,无需更新!')
return public.returnJson(False, '已经是最新,无需更新!')
except Exception as ex:
# print('updateServer', ex)
return mw.returnJson(False, "连接服务器失败!" + str(ex))
print ex
return public.returnJson(False, "连接服务器失败!")
# 重启面板
def reWeb(self, get):
if not public.isRestart():
public.returnMsg(False, '请等待所有安装任务完成再执行!')
# public.ExecShell('/etc/init.d/bt restart &')
public.returnMsg(True, '执行成功!')
# 修复面板
def repPanel(self, get):
vp = ''
if mw.readFile('/www/server/mdserver-web/class/common.py').find('checkSafe') != -1:
if public.readFile('/www/server/panel/class/common.py').find('checkSafe') != -1:
vp = '_pro'
mw.ExecShell("wget -O update.sh " + mw.get_url() +
"/install/update" + vp + ".sh && bash update.sh")
public.ExecShell("wget -O update.sh " + public.get_url() +
"/install/update" + vp + ".sh && bash update.sh")
if hasattr(web.ctx.session, 'getCloudPlugin'):
del(web.ctx.session['getCloudPlugin'])
return True
-103
View File
@@ -1,103 +0,0 @@
# coding: utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# 任务页操作
# ---------------------------------------------------------------------------------
import psutil
import time
import os
import sys
import mw
import re
import json
import pwd
from flask import request
class task_api:
def __init__(self):
pass
def countApi(self):
c = mw.M('tasks').where("status!=?", ('1',)).count()
return str(c)
def listApi(self):
p = request.form.get('p', '1')
limit = request.form.get('limit', '10').strip()
search = request.form.get('search', '').strip()
start = (int(p) - 1) * int(limit)
limit_str = str(start) + ',' + str(limit)
_list = mw.M('tasks').where('', ()).field(
'id,name,type,status,addtime,start,end').limit(limit_str).order('id desc').select()
_ret = {}
_ret['data'] = _list
count = mw.M('tasks').where('', ()).count()
_page = {}
_page['count'] = count
_page['tojs'] = 'remind'
_page['p'] = p
# return data
_ret['count'] = count
_ret['page'] = mw.getPage(_page)
return mw.getJson(_ret)
def getExecLogApi(self):
file = os.getcwd() + "/tmp/panelExec.log"
v = mw.getLastLine(file, 100)
return v
def getTaskSpeedApi(self):
tempFile = mw.getRunDir() + '/tmp/panelExec.log'
freshFile = mw.getRunDir() + '/tmp/panelFresh'
find = mw.M('tasks').where('status=? OR status=?',
('-1', '0')).field('id,type,name,execstr').find()
if not len(find):
return mw.returnJson(False, '当前没有任务队列在执行-2!')
mw.triggerTask()
data = {}
data['name'] = find['name']
data['execstr'] = find['execstr']
if find['type'] == 'download':
readLine = ""
for i in range(3):
try:
readLine = mw.readFile(tempFile)
if len(readLine) > 10:
data['msg'] = json.loads(readLine)
data['isDownload'] = True
break
except Exception as e:
if i == 2:
mw.M('tasks').where("id=?", (find['id'],)).save(
'status', ('0',))
return mw.returnJson(False, '当前没有任务队列在执行-4:' + str(e))
time.sleep(0.5)
else:
data['msg'] = mw.getLastLine(tempFile, 10)
data['isDownload'] = False
data['task'] = mw.M('tasks').where("status!=?", ('1',)).field(
'id,status,name,type').order("id asc").select()
return mw.getJson(data)
+5 -16
View File
@@ -1,17 +1,6 @@
#!/usr/bin/env python
# coding: utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------
# 验证码操作
# ---------------------------------------------------------------------------------
import random
import math
@@ -86,7 +75,7 @@ class vieCode:
if not self.__inNoise:
return
font = ImageFont.truetype(self.__fontPatn, int(self.__fontSize / 1.5))
for i in range(5):
for i in xrange(5):
# 杂点颜色
noiseColor = (random.randint(150, 200), random.randint(
150, 200), random.randint(150, 200))
@@ -115,9 +104,9 @@ class vieCode:
# 画曲线
color = (random.randint(30, 150), random.randint(
30, 150), random.randint(30, 150))
for x in range(xend):
for x in xrange(xend):
if w != 0:
for k in range(int(self.__heigth / 10)):
for k in xrange(int(self.__heigth / 10)):
y = a * math.sin(w * x + f) + b + self.__heigth / 2
i = int(self.__fontSize / 5)
while i > 0:
@@ -131,7 +120,7 @@ class vieCode:
font = ImageFont.truetype(self.__fontPatn, self.__fontSize)
x = 0
# 打印字符到画板
for i in range(self.__length):
for i in xrange(self.__length):
# 设置字体随机颜色
color = (random.randint(30, 150), random.randint(
30, 150), random.randint(30, 150))
-5
View File
@@ -1,5 +0,0 @@
- fcgi-client.py
```
https://pypi.org/project/flup6/1.1.1/#files
```
-408
View File
@@ -1,408 +0,0 @@
# Copyright (c) 2006 Allan Saddi <allan@saddi.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $Id$
#
# Copyright (c) 2011 Vladimir Rusinov <vladimir@greenmice.info>
__author__ = 'Allan Saddi <allan@saddi.com>'
__version__ = '$Revision$'
import sys
import select
import struct
import socket
import errno
import types
__all__ = ['FCGIApp']
# Constants from the spec.
FCGI_LISTENSOCK_FILENO = 0
FCGI_HEADER_LEN = 8
FCGI_VERSION_1 = 1
FCGI_BEGIN_REQUEST = 1
FCGI_ABORT_REQUEST = 2
FCGI_END_REQUEST = 3
FCGI_PARAMS = 4
FCGI_STDIN = 5
FCGI_STDOUT = 6
FCGI_STDERR = 7
FCGI_DATA = 8
FCGI_GET_VALUES = 9
FCGI_GET_VALUES_RESULT = 10
FCGI_UNKNOWN_TYPE = 11
FCGI_MAXTYPE = FCGI_UNKNOWN_TYPE
FCGI_NULL_REQUEST_ID = 0
FCGI_KEEP_CONN = 1
FCGI_RESPONDER = 1
FCGI_AUTHORIZER = 2
FCGI_FILTER = 3
FCGI_REQUEST_COMPLETE = 0
FCGI_CANT_MPX_CONN = 1
FCGI_OVERLOADED = 2
FCGI_UNKNOWN_ROLE = 3
FCGI_MAX_CONNS = 'FCGI_MAX_CONNS'
FCGI_MAX_REQS = 'FCGI_MAX_REQS'
FCGI_MPXS_CONNS = 'FCGI_MPXS_CONNS'
FCGI_Header = '!BBHHBx'
FCGI_BeginRequestBody = '!HB5x'
FCGI_EndRequestBody = '!LB3x'
FCGI_UnknownTypeBody = '!B7x'
FCGI_BeginRequestBody_LEN = struct.calcsize(FCGI_BeginRequestBody)
FCGI_EndRequestBody_LEN = struct.calcsize(FCGI_EndRequestBody)
FCGI_UnknownTypeBody_LEN = struct.calcsize(FCGI_UnknownTypeBody)
if __debug__:
import time
# Set non-zero to write debug output to a file.
DEBUG = 0
DEBUGLOG = '/www/server/mdserver-web/logs/fastcgi.log'
def _debug(level, msg):
if DEBUG < level:
return
try:
f = open(DEBUGLOG, 'a')
f.write('%sfcgi: %s\n' % (time.ctime()[4:-4], msg))
f.close()
except:
pass
def decode_pair(s, pos=0):
"""
Decodes a name/value pair.
The number of bytes decoded as well as the name/value pair
are returned.
"""
nameLength = ord(s[pos])
if nameLength & 128:
nameLength = struct.unpack('!L', s[pos:pos + 4])[0] & 0x7fffffff
pos += 4
else:
pos += 1
valueLength = ord(s[pos])
if valueLength & 128:
valueLength = struct.unpack('!L', s[pos:pos + 4])[0] & 0x7fffffff
pos += 4
else:
pos += 1
name = s[pos:pos + nameLength]
pos += nameLength
value = s[pos:pos + valueLength]
pos += valueLength
return (pos, (name, value))
def encode_pair(name, value):
"""
Encodes a name/value pair.
The encoded string is returned.
"""
nameLength = len(name)
if nameLength < 128:
s = chr(nameLength).encode()
else:
s = struct.pack('!L', nameLength | 0x80000000)
valueLength = len(value)
if valueLength < 128:
s += chr(valueLength).encode()
else:
s += struct.pack('!L', valueLength | 0x80000000)
return s + name + value
class Record(object):
"""
A FastCGI Record.
Used for encoding/decoding records.
"""
def __init__(self, type=FCGI_UNKNOWN_TYPE, requestId=FCGI_NULL_REQUEST_ID):
self.version = FCGI_VERSION_1
self.type = type
self.requestId = requestId
self.contentLength = 0
self.paddingLength = 0
self.contentData = ''
def _recvall(sock, length):
"""
Attempts to receive length bytes from a socket, blocking if necessary.
(Socket may be blocking or non-blocking.)
"""
dataList = []
recvLen = 0
while length:
try:
data = sock.recv(length)
except socket.error as e:
if e[0] == errno.EAGAIN:
select.select([sock], [], [])
continue
else:
raise
if not data: # EOF
break
dataList.append(data)
dataLen = len(data)
recvLen += dataLen
length -= dataLen
return b''.join(dataList), recvLen
_recvall = staticmethod(_recvall)
def read(self, sock):
"""Read and decode a Record from a socket."""
try:
header, length = self._recvall(sock, FCGI_HEADER_LEN)
except:
raise EOFError
if length < FCGI_HEADER_LEN:
raise EOFError
self.version, self.type, self.requestId, self.contentLength, \
self.paddingLength = struct.unpack(FCGI_Header, header)
if __debug__:
_debug(9, 'read: fd = %d, type = %d, requestId = %d, '
'contentLength = %d' %
(sock.fileno(), self.type, self.requestId,
self.contentLength))
if self.contentLength:
try:
self.contentData, length = self._recvall(sock,
self.contentLength)
except:
raise EOFError
if length < self.contentLength:
raise EOFError
if self.paddingLength:
try:
self._recvall(sock, self.paddingLength)
except:
raise EOFError
def _sendall(sock, data):
"""
Writes data to a socket and does not return until all the data is sent.
"""
length = len(data)
while length:
try:
sent = sock.send(data)
except socket.error as e:
if e[0] == errno.EAGAIN:
select.select([], [sock], [])
continue
else:
raise
data = data[sent:]
length -= sent
_sendall = staticmethod(_sendall)
def write(self, sock):
"""Encode and write a Record to a socket."""
self.paddingLength = -self.contentLength & 7
if __debug__:
_debug(9, 'write: fd = %d, type = %d, requestId = %d, '
'contentLength = %d' %
(sock.fileno(), self.type, self.requestId,
self.contentLength))
header = struct.pack(FCGI_Header, self.version, self.type,
self.requestId, self.contentLength,
self.paddingLength)
self._sendall(sock, header)
if self.contentLength:
self._sendall(sock, self.contentData)
if self.paddingLength:
self._sendall(sock, b'\x00' * self.paddingLength)
class FCGIApp(object):
def __init__(self, connect=None, host=None, port=None, filterEnviron=True):
if host is not None:
assert port is not None
connect = (host, port)
self._connect = connect
self._filterEnviron = filterEnviron
def __call__(self, environ, io, start_response=None):
# For sanity's sake, we don't care about FCGI_MPXS_CONN
# (connection multiplexing). For every request, we obtain a new
# transport socket, perform the request, then discard the socket.
# This is, I believe, how mod_fastcgi does things...
sock = self._getConnection()
# Since this is going to be the only request on this connection,
# set the request ID to 1.
requestId = 1
# Begin the request
rec = Record(FCGI_BEGIN_REQUEST, requestId)
rec.contentData = struct.pack(FCGI_BeginRequestBody, FCGI_RESPONDER, 0)
rec.contentLength = FCGI_BeginRequestBody_LEN
rec.write(sock)
# Filter WSGI environ and send it as FCGI_PARAMS
if self._filterEnviron:
params = self._defaultFilterEnviron(environ)
else:
params = self._lightFilterEnviron(environ)
# TODO: Anything not from environ that needs to be sent also?
# return '200 OK',[],str(params),''
self._fcgiParams(sock, requestId, params)
self._fcgiParams(sock, requestId, {})
# Transfer wsgi.input to FCGI_STDIN
content_length = int(environ.get('CONTENT_LENGTH') or 0)
s = ''
#io = StringIO(stdin)
while True:
if not io:
break
chunk_size = min(content_length, 4096)
s = io.read(chunk_size)
content_length -= len(s)
rec = Record(FCGI_STDIN, requestId)
rec.contentData = s
rec.contentLength = len(s)
rec.write(sock)
if not s:
break
# Empty FCGI_DATA stream
rec = Record(FCGI_DATA, requestId)
rec.write(sock)
return sock
def _getConnection(self):
if self._connect is not None:
# The simple case. Create a socket and connect to the
# application.
if isinstance(self._connect, str):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(self._connect)
elif hasattr(socket, 'create_connection'):
sock = socket.create_connection(self._connect)
else:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(self._connect)
return sock
# To be done when I have more time...
# , 'Launching and managing FastCGI programs not yet implemented'
raise NotImplementedError
def _fcgiGetValues(self, sock, vars):
# Construct FCGI_GET_VALUES record
outrec = Record(FCGI_GET_VALUES)
data = []
for name in vars:
data.append(encode_pair(name, ''))
data = ''.join(data)
outrec.contentData = data
outrec.contentLength = len(data)
outrec.write(sock)
# Await response
inrec = Record()
inrec.read(sock)
result = {}
if inrec.type == FCGI_GET_VALUES_RESULT:
pos = 0
while pos < inrec.contentLength:
pos, (name, value) = decode_pair(inrec.contentData, pos)
result[name] = value
return result
def _fcgiParams(self, sock, requestId, params):
rec = Record(FCGI_PARAMS, requestId)
data = []
for name, value in params.items():
data.append(encode_pair(name.encode(
'latin-1'), value.encode('latin-1')))
data = b''.join(data)
rec.contentData = data
rec.contentLength = len(data)
rec.write(sock)
_environPrefixes = ['SERVER_', 'HTTP_', 'REQUEST_', 'REMOTE_', 'PATH_',
'CONTENT_', 'DOCUMENT_', 'SCRIPT_']
_environCopies = ['SCRIPT_NAME', 'QUERY_STRING', 'AUTH_TYPE']
_environRenames = []
def _defaultFilterEnviron(self, environ):
result = {}
for n in environ.keys():
iv = False
for p in self._environPrefixes:
if n.startswith(p):
result[n] = environ[n]
iv = True
if n in self._environCopies:
result[n] = environ[n]
iv = True
if n in self._environRenames:
result[self._environRenames[n]] = environ[n]
iv = True
if not iv:
result[n] = environ[n]
return result
def _lightFilterEnviron(self, environ):
result = {}
for n in environ.keys():
if n.upper() == n:
result[n] = environ[n]
return result
-208
View File
@@ -1,208 +0,0 @@
# coding:utf-8
import json
import os
import time
import re
import sys
import time
import struct
import fcgi_client
FCGI_Header = '!BBHHBx'
if sys.version_info[0] == 2:
try:
from cStringIO import StringIO
except:
from StringIO import StringIO
else:
from io import BytesIO as StringIO
def get_header_data(sock):
'''
@name 获取头部32KB数据
@param sock socketobject(fastcgi套接字对象)
@return bytes
'''
headers_data = b''
total_len = 0
header_len = 1024 * 128
while True:
fastcgi_header = sock.recv(8)
if not fastcgi_header:
break
if len(fastcgi_header) != 8:
headers_data += fastcgi_header
break
fast_pack = struct.unpack(FCGI_Header, fastcgi_header)
if fast_pack[1] == 3:
break
tlen = fast_pack[3]
while tlen > 0:
sd = sock.recv(tlen)
if not sd:
break
headers_data += sd
tlen -= len(sd)
total_len += fast_pack[3]
if fast_pack[4]:
sock.recv(fast_pack[4])
if total_len > header_len:
break
return headers_data
def format_header_data(headers_data):
'''
@name 格式化响应头
@param headers_data bytes(fastcgi头部32KB数据)
@return status int(响应状态), headers dict(响应头), bdata bytes(格式化响应头后的多余数据)
'''
status = '200 OK'
headers = {}
pos = 0
while True:
eolpos = headers_data.find(b'\n', pos)
if eolpos < 0:
break
line = headers_data[pos:eolpos - 1]
pos = eolpos + 1
line = line.strip()
if len(line) < 2:
break
if line.find(b':') == -1:
continue
header, value = line.split(b':', 1)
header = header.strip()
value = value.strip()
if isinstance(header, bytes):
header = header.decode()
value = value.decode()
if header == 'Status':
status = value
if status.find(' ') < 0:
status += ' BTPanel'
else:
headers[header] = value
bdata = headers_data[pos:]
status = int(status.split(' ')[0])
return status, headers, bdata
def resp_sock(sock, bdata):
'''
@name 以流的方式发送剩余数据
@param sock socketobject(fastcgi套接字对象)
@param bdata bytes(格式化响应头后的多余数据)
@return yield bytes
'''
# 发送除响应头以外的多余头部数据
yield bdata
while True:
fastcgi_header = sock.recv(8)
if not fastcgi_header:
break
if len(fastcgi_header) != 8:
yield fastcgi_header
break
fast_pack = struct.unpack(FCGI_Header, fastcgi_header)
if fast_pack[1] == 3:
break
tlen = fast_pack[3]
while tlen > 0:
sd = sock.recv(tlen)
if not sd:
break
tlen -= len(sd)
if sd:
yield sd
if fast_pack[4]:
sock.recv(fast_pack[4])
sock.close()
class fpm(object):
def __init__(self, sock=None, document_root='', last_path=''):
'''
@name 实例化FPM对象
@param sock string(unixsocket路径)
@param document_root string(PHP文档根目录)
@return FPM
'''
if sock:
self.fcgi_sock = sock
if document_root[-1:] != '/':
document_root += '/'
self.document_root = document_root
self.last_path = last_path
def load_url_public(self, url, content=b'', method='GET', content_type='application/x-www-form-urlencoded'):
'''
@name 转发URL到PHP-FPM 公共
@param url string(URI地址)
@param content stream(POST数据io对象)
@return fastcgi-socket
'''
fcgi = fcgi_client.FCGIApp(connect=self.fcgi_sock)
try:
script_name, query_string = url.split('?')
except ValueError:
script_name = url
query_string = ''
content_length = len(content)
if content:
content = StringIO(content)
env = {
'SCRIPT_FILENAME': '%s%s' % (self.document_root, script_name),
'QUERY_STRING': query_string,
'REQUEST_METHOD': method,
'SCRIPT_NAME': self.last_path + script_name,
'REQUEST_URI': url,
'GATEWAY_INTERFACE': 'CGI/1.1',
'SERVER_SOFTWARE': 'MW-Panel',
'REDIRECT_STATUS': '200',
'CONTENT_TYPE': content_type,
'CONTENT_LENGTH': str(content_length),
'DOCUMENT_URI': script_name,
'DOCUMENT_ROOT': self.document_root,
'SERVER_PROTOCOL': 'HTTP/1.1',
'REMOTE_ADDR': '127.0.0.1',
'REMOTE_PORT': '7200',
'SERVER_ADDR': '127.0.0.1',
'SERVER_PORT': '80',
'SERVER_NAME': 'MW-Panel'
}
fpm_sock = fcgi(env, content)
_data = b''
while True:
fastcgi_header = fpm_sock.recv(8)
if not fastcgi_header:
break
if len(fastcgi_header) != 8:
_data += fastcgi_header
break
fast_pack = struct.unpack(FCGI_Header, fastcgi_header)
if fast_pack[1] == 3:
break
tlen = fast_pack[3]
while tlen > 0:
sd = fpm_sock.recv(tlen)
if not sd:
break
tlen -= len(sd)
_data += sd
if fast_pack[4]:
fpm_sock.recv(fast_pack[4])
status, headers, data = format_header_data(_data)
return data
-116
View File
@@ -1,116 +0,0 @@
# coding: utf-8
import re
import os
import sys
import pymysql.cursors
class ORM:
__DB_PASS = None
__DB_USER = 'root'
__DB_PORT = 3306
__DB_NAME = ''
__DB_HOST = 'localhost'
__DB_CONN = None
__DB_CUR = None
__DB_ERR = None
__DB_CNF = '/etc/my.cnf'
__DB_SOCKET = '/www/server/mysql/mysql.sock'
__DB_CHARSET = "utf8"
def __Conn(self):
'''连接数据库'''
try:
if os.path.exists(self.__DB_SOCKET):
try:
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
database=self.__DB_NAME,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
unix_socket=self.__DB_SOCKET, cursorclass=pymysql.cursors.DictCursor)
except Exception as e:
self.__DB_HOST = '127.0.0.1'
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
database=self.__DB_NAME,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
unix_socket=self.__DB_SOCKET, cursorclass=pymysql.cursors.DictCursor)
else:
try:
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
database=self.__DB_NAME,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
cursorclass=pymysql.cursors.DictCursor)
except Exception as e:
self.__DB_HOST = '127.0.0.1'
self.__DB_CONN = pymysql.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
database=self.__DB_NAME,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1,
cursorclass=pymysql.cursors.DictCursor)
self.__DB_CUR = self.__DB_CONN.cursor()
return True
except Exception as e:
self.__DB_ERR = e
return False
def setDbConf(self, conf):
self.__DB_CNF = conf
def setSocket(self, sock):
self.__DB_SOCKET = sock
def setCharset(self, charset):
self.__DB_CHARSET = charset
def setHost(self, host):
self.__DB_HOST = host
def setPort(self, port):
self.__DB_PORT = port
def setUser(self, user):
self.__DB_USER = user
def setPwd(self, pwd):
self.__DB_PASS = pwd
def getPwd(self):
return self.__DB_PASS
def setDbName(self, name):
self.__DB_NAME = name
def execute(self, sql):
# 执行SQL语句返回受影响行
if not self.__Conn():
return self.__DB_ERR
try:
result = self.__DB_CUR.execute(sql)
self.__DB_CONN.commit()
self.__Close()
return result
except Exception as ex:
return ex
def query(self, sql):
# 执行SQL语句返回数据集
if not self.__Conn():
return self.__DB_ERR
try:
self.__DB_CUR.execute(sql)
result = self.__DB_CUR.fetchall()
# print(result)
# 将元组转换成列表
# data = map(list, result)
self.__Close()
return result
except Exception as ex:
return ex
def __Close(self):
# 关闭连接
self.__DB_CUR.close()
self.__DB_CONN.close()
-115
View File
@@ -1,115 +0,0 @@
# coding: utf-8
import re
import os
import sys
class ORM:
__DB_PASS = None
__DB_USER = 'root'
__DB_PORT = 3306
__DB_HOST = 'localhost'
__DB_CONN = None
__DB_CUR = None
__DB_ERR = None
__DB_CNF = '/etc/my.cnf'
__DB_SOCKET = '/www/server/mysql/mysql.sock'
__DB_CHARSET = 'utf8'
def __Conn(self):
'''连接MYSQL数据库'''
try:
try:
import MySQLdb
except Exception as ex:
self.__DB_ERR = ex
return False
# print(self.__DB_HOST)
# print(self.__DB_USER)
# print(self.__DB_PASS)
# print(self.__DB_PORT)
# print(self.__DB_CHARSET)
# print(self.__DB_SOCKET)
if os.path.exists(self.__DB_SOCKET):
try:
self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1, unix_socket=self.__DB_SOCKET)
except Exception as e:
print(e)
self.__DB_HOST = '127.0.0.1'
self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1, unix_socket=self.__DB_SOCKET)
else:
try:
self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1)
except Exception as e:
self.__DB_HOST = '127.0.0.1'
self.__DB_CONN = MySQLdb.connect(host=self.__DB_HOST, user=self.__DB_USER, passwd=self.__DB_PASS,
port=int(self.__DB_PORT), charset=self.__DB_CHARSET, connect_timeout=1)
self.__DB_CUR = self.__DB_CONN.cursor()
return True
except MySQLdb.Error as e:
self.__DB_ERR = e
return False
def setDbConf(self, conf):
self.__DB_CNF = conf
def setSocket(self, sock):
self.__DB_SOCKET = sock
def setCharset(self, charset):
self.__DB_CHARSET = charset
def setPort(self, port):
self.__DB_PORT = port
def setPwd(self, pwd):
self.__DB_PASS = pwd
def getPwd(self):
return self.__DB_PASS
def setDbName(self, name):
self.__DB_NAME = name
def setUser(self, user):
self.__DB_USER = user
def execute(self, sql):
# 执行SQL语句返回受影响行
if not self.__Conn():
return self.__DB_ERR
try:
result = self.__DB_CUR.execute(sql)
self.__DB_CONN.commit()
self.__Close()
return result
except Exception as ex:
return ex
def query(self, sql):
# 执行SQL语句返回数据集
if not self.__Conn():
return self.__DB_ERR
try:
self.__DB_CUR.execute(sql)
result = self.__DB_CUR.fetchall()
# 将元组转换成列表
data = map(list, result)
self.__Close()
return data
except Exception as ex:
return ex
# 关闭连接
def __Close(self):
self.__DB_CUR.close()
self.__DB_CONN.close()
-7
View File
@@ -1,7 +0,0 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/usr/local/lib/python2.7/bin
find . -name .DS_Store | xargs rm -rf
find . -type d -name "*.pyc" | xargs rm -rf
+9 -63
View File
@@ -1,76 +1,26 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
DIR=$(cd "$(dirname "$0")"; pwd)
MDIR=$(dirname "$DIR")
PATH=$PATH:$DIR/bin
if [ -f bin/activate ];then
source bin/activate
fi
export LC_ALL="en_US.UTF-8"
mw_start_task()
{
isStart=$(ps aux |grep 'task.py'|grep -v grep|awk '{print $2}')
if [ "$isStart" == '' ];then
echo -e "Starting mw-tasks... \c"
cd $DIR && python3 task.py >> ${DIR}/logs/task.log 2>&1 &
sleep 0.3
isStart=$(ps aux |grep 'task.py'|grep -v grep|awk '{print $2}')
if [ "$isStart" == '' ];then
echo -e "\033[31mfailed\033[0m"
echo '------------------------------------------------------'
tail -n 20 $DIR/logs/task.log
echo '------------------------------------------------------'
echo -e "\033[31mError: mw-tasks service startup failed.\033[0m"
return;
fi
echo -e "\033[32mdone\033[0m"
else
echo "Starting mw-tasks... mw-tasks (pid $(echo $isStart)) already running"
fi
}
mw_start(){
gunicorn -c setting.py app:app
#安全启动
mw_start_task
gunicorn -c setting.py app:app &
python task.py &
}
mw_start_debug(){
python3 task.py >> $DIR/logs/task.log 2>&1 &
port=7200
if [ -f /www/server/mdserver-web/data/port.pl ];then
port=$(cat /www/server/mdserver-web/data/port.pl)
fi
# gunicorn -b :${port} -k gevent -w 1 app:app
gunicorn -b :${port} -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 app:app
# gunicorn -c setting.py app:app
python task.py &
gunicorn -b :7200 app:app
# gunicorn -c setting.py app:app
}
mw_start_debug2(){
python3 task.py >> $DIR/logs/task.log 2>&1 &
gunicorn -b :7200 -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 app:app
}
mw_stop()
{
PLIST=`ps -ef|grep app:app |grep -v grep|awk '{print $2}'`
for i in $PLIST
do
kill -9 $i > /dev/null 2>&1
done
pids=`ps -ef|grep task.py | grep -v grep |awk '{print $2}'`
arr=($pids)
for p in ${arr[@]}
do
kill -9 $p > /dev/null 2>&1
done
ps -ef|grep app:app |grep -v grep|awk '{print $2}'|xargs kill -9
ps -ef|grep task.py |grep -v grep|awk '{print $2}'|xargs kill -9
}
case "$1" in
@@ -84,8 +34,4 @@ case "$1" in
mw_stop
mw_start_debug
;;
'debug2')
mw_stop
mw_start_debug2
;;
esac
-68
View File
@@ -1,68 +0,0 @@
### 常用命令说明
- 面板相关命令
```
/etc/init.d/mw default
service mw [start|stop|reload|restart|status]
```
- OpenResty
```
systemctl [start|stop|reload|restart|status] openresty
```
- MySQL
```
systemctl [start|stop|reload|restart|status] mysql
```
- MariaDB
```
systemctl [start|stop|reload|restart|status] mariadb
```
- PHP
```
systemctl [start|stop|reload|restart|status] php[54-81]
systemctl start php71
```
- Redis
```
systemctl [start|stop|reload|restart|status] redis
```
- Memcached
```
systemctl [start|stop|reload|restart|status] memcached
```
- sphinx
```
systemctl [start|stop|reload|restart|status] sphinx
```
-68
View File
@@ -1,68 +0,0 @@
### 兼容性测试报告
快速测试命令
```
cd /www/server/mdserver-web/scripts/quick && bash debug.sh
cd /www/server/mdserver-web/plugins/php/versions && bash all_test.sh
```
| 系统名称 | 面板 | OpenResty |
| ----------------- |---------------|---------------|
| CentOS 7.9 |✅ |✅ |
| CentOS 8.4 |✅ |✅ |
| CentOS 8 Stream |✅ |✅ |
| CentOS 9 Stream |✅ |✅ |
| Debian 10.3 |✅ |✅ |
| Debian 11.3 |✅ |✅ |
| Ubuntu 18.04 |✅ |✅ |
| Ubuntu 20.04 |✅ |✅ |
| Ubuntu 22.04 |✅ |✅ |
| Fedora 31 |✅ |✅ |
| Fedora 32 |✅ |✅ |
| AlmaLinux 9 |✅ |✅ |
| RockyLinux 8.6 |✅ |✅ |
| Arch Linux  |✅ |✅ |
| openSUSE 15.4 |✅ |✅ |
| 系统名称 |PHP53 |PHP54 |PHP55 |PHP56 |PHP70 |PHP71 |PHP72 |PHP73 |PHP74 |PHP80 |PHP81 |
| ----------------- |-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|
| CentOS 7.9 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| CentOS 8.4 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| CentOS 8 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| CentOS 9 Stream |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Debian 10.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Debian 11.3 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Ubuntu 18.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Ubuntu 20.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Ubuntu 22.04 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Fedora 31 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Fedora 32 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| AlmaLinux 9 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| RockyLinux 8.6 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| Arch Linux |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| openSUSE 15.4 |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |✅ |
| 系统名称 | MySQL55|MySQL56|MySQL57|MySQL80|
| ----------------- |-------|--------|-------|-------|
| CentOS 7.9 |✅ |✅ |✅ |✅ |
| CentOS 8.4 |✅ |✅ |✅ |✅ |
| CentOS 8 Stream |✅ |✅ |✅ |✅ |
| CentOS 9 Stream |✅ |✅ |✅ |✅ |
| Debian 10.3 |✅ |✅ |✅ |✅ |
| Debian 11.3 |✅ |✅ |✅ |✅ |
| Ubuntu 18.04 |✅ |✅ |✅ |✅ |
| Ubuntu 20.04 |✅ |✅ |✅ |✅ |
| Ubuntu 22.04 |✅ |✅ |✅ |✅ |
| Fedora 31 |✅ |✅ |✅ |✅ |
| Fedora 32 |✅ |✅ |✅ |✅ |
| AlmaLinux 9 |✅ |✅ |✅ |✅ |
| RockyLinux 8.6 |✅ |✅ |✅ |✅ |
| Arch Linux |✅ |✅ |✅ |✅ |
| openSUSE 15.4 |✅ |✅ |✅ |✅ |
-10
View File
@@ -4,11 +4,6 @@
"type":0,
"ps":""
},
{
"title":"已安装",
"type":-1,
"ps":""
},
{
"title":"运行环境",
"type":1,
@@ -33,10 +28,5 @@
"title":"其他插件",
"type":5,
"ps":""
},
{
"title":"辅助插件",
"type":6,
"ps":""
}
]
Executable
+1
View File
@@ -0,0 +1 @@
7200
+41 -43
View File
@@ -19,6 +19,19 @@ CREATE TABLE IF NOT EXISTS `binding` (
);
CREATE TABLE IF NOT EXISTS `config` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`webserver` TEXT,
`backup_path` TEXT,
`sites_path` TEXT,
`status` INTEGER,
`mysql_root` TEXT
);
INSERT INTO `config` (`id`, `webserver`, `backup_path`, `sites_path`, `status`, `mysql_root`) VALUES
(1, 'nginx', '/www/backup', '/www/wwwroot', 0, 'admin');
CREATE TABLE IF NOT EXISTS `crontab` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`name` TEXT,
@@ -27,14 +40,18 @@ CREATE TABLE IF NOT EXISTS `crontab` (
`where_hour` INTEGER,
`where_minute` INTEGER,
`echo` TEXT,
`addtime` TEXT,
`status` INTEGER DEFAULT '1',
`save` INTEGER DEFAULT '3',
`backup_to` TEXT DEFAULT 'off',
`sname` TEXT,
`sbody` TEXT,
'stype' TEXT,
`urladdress` TEXT
`addtime` TEXT
);
CREATE TABLE IF NOT EXISTS `databases` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`pid` INTEGER,
`name` TEXT,
`username` TEXT,
`password` TEXT,
`accept` TEXT,
`ps` TEXT,
`addtime` TEXT
);
CREATE TABLE IF NOT EXISTS `firewall` (
@@ -45,21 +62,30 @@ CREATE TABLE IF NOT EXISTS `firewall` (
);
INSERT INTO `firewall` (`id`, `port`, `ps`, `addtime`) VALUES
(1, '80', '网站默认端口', '0000-00-00 00:00:00'),
(2, '22', 'SSH远程管理服务', '0000-00-00 00:00:00'),
(3, '443', 'HTTPS', '0000-00-00 00:00:00'),
(4, '888', 'phpMyAdmin默认端口', '0000-00-00 00:00:00');
(2, '80', '网站默认端口', '0000-00-00 00:00:00'),
(3, '8888', 'WEB面板', '0000-00-00 00:00:00'),
(4, '21', 'FTP服务', '0000-00-00 00:00:00'),
(5, '22', 'SSH远程管理服务', '0000-00-00 00:00:00');
CREATE TABLE IF NOT EXISTS `ftps` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`pid` INTEGER,
`name` TEXT,
`password` TEXT,
`path` TEXT,
`status` TEXT,
`ps` TEXT,
`addtime` TEXT
);
CREATE TABLE IF NOT EXISTS `logs` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`type` TEXT,
`log` TEXT,
`uid` TEXT,
`addtime` TEXT
);
ALTER TABLE `logs` ADD COLUMN `uid` INTEGER DEFAULT '1';
CREATE TABLE IF NOT EXISTS `sites` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -67,17 +93,11 @@ CREATE TABLE IF NOT EXISTS `sites` (
`path` TEXT,
`status` TEXT,
`index` TEXT,
`type_id` INTEGER,
`ps` TEXT,
`edate` TEXT,
`addtime` TEXT
);
CREATE TABLE IF NOT EXISTS `site_types` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`name` TEXT
);
CREATE TABLE IF NOT EXISTS `domain` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`pid` INTEGER,
@@ -97,7 +117,7 @@ CREATE TABLE IF NOT EXISTS `users` (
);
INSERT INTO `users` (`id`, `username`, `password`, `login_ip`, `login_time`, `phone`, `email`) VALUES
(1, 'admin', '21232f297a57a5a743894a0e4a801fc3', '192.168.0.10', '2022-02-02 00:00:00', 0, 'midoks@163.com');
(1, 'admin', '21232f297a57a5a743894a0e4a801fc3', '192.168.0.10', '2016-12-10 15:12:56', 0, '287962566@qq.com');
CREATE TABLE IF NOT EXISTS `tasks` (
@@ -110,25 +130,3 @@ CREATE TABLE IF NOT EXISTS `tasks` (
`end` INTEGER,
`execstr` TEXT
);
CREATE TABLE IF NOT EXISTS `temp_login` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`token` REAL,
`salt` REAL,
`state` INTEGER,
`login_time` INTEGER,
`login_addr` REAL,
`logout_time` INTEGER,
`expire` INTEGER,
`addtime` INTEGER
);
CREATE TABLE IF NOT EXISTS `panel` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`title` TEXT,
`url` TEXT,
`username` TEXT,
`password` TEXT,
`click` INTEGER,
`addtime` INTEGER
);
+8 -14
View File
@@ -1,33 +1,27 @@
server
{
listen {$PORT};
listen [::]:{$PORT};
server_name {$SERVER_NAME};
index index.php index.html index.htm default.php default.htm default.html;
root {$ROOT_DIR};
#SSL-START
#SSL-START %s
#error_page 404/404.html;
#SSL-END
#301-START
#PROXY-START
#ERROR-PAGE-START
#error_page 404 /404.html;
#error_page 502 /502.html;
#ERROR-PAGE-START %s
error_page 404 /404.html;
error_page 502 /502.html;
#ERROR-PAGE-END
#PHP-INFO-START
include {$PHP_DIR}/conf/enable-php-{$PHPVER}.conf;
#PHP-INFO-START %s
include enable-php-{$PHPVER}.conf;
#PHP-INFO-END
#REWRITE-START
#REWRITE-START %s
include {$OR_REWRITE}/{$SERVER_NAME}.conf;
#REWRITE-END
#禁止访问的文件或目录
location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
{
@@ -53,6 +47,6 @@ server
access_log /dev/null;
}
access_log {$LOGPATH}/{$SERVER_NAME}.log main;
access_log {$LOGPATH}/{$SERVER_NAME}.log;
error_log {$LOGPATH}/{$SERVER_NAME}.error.log;
}
-55
View File
@@ -1,55 +0,0 @@
#BINDING-{$DIRBIND}-START
server
{
listen {$PORT};
server_name {$DIRBIND};
index index.php index.html index.htm default.php default.htm default.html;
root {$ROOT_DIR};
#SSL-START
#error_page 404/404.html;
#SSL-END
#ERROR-PAGE-START
#error_page 404 /404.html;
#error_page 502 /502.html;
#ERROR-PAGE-END
#PHP-INFO-START
include {$PHP_DIR}/conf/enable-php-{$PHPVER}.conf;
#PHP-INFO-END
#REWRITE-START
include {$OR_REWRITE}/{$SERVER_MAIN}.conf;
#REWRITE-END
#禁止访问的文件或目录
location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
{
return 404;
}
#一键申请SSL证书验证目录相关设置
location ~ \.well-known{
allow all;
}
location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
error_log off;
access_log /dev/null;
}
location ~ .*\\.(js|css)?$
{
expires 12h;
error_log off;
access_log /dev/null;
}
access_log {$LOGPATH}/{$SERVER_MAIN}_{$DIRBIND}.log;
error_log {$LOGPATH}/{$SERVER_MAIN}_{$DIRBIND}.error.log;
}
#BINDING-{$DIRBIND}-END
-23
View File
@@ -1,23 +0,0 @@
server
{
listen {$PORT};
listen [::]:{$PORT};
server_name {$SERVER_NAME};
index index.php index.html index.htm default.php default.htm default.html;
#SSL-START
#error_page 404/404.html;
#SSL-END
#PROXY-START
location ^~ / {
proxy_pass http://0.0.0.0:{$PANAL_PORT}/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
}
#PROXY-END
error_log {$LOGPATH}/{$SERVER_NAME}.error.log;
}
-62
View File
@@ -1,62 +0,0 @@
FROM debian:10.12-slim
STOPSIGNAL SIGRTMIN+3
RUN rm -f /lib/systemd/system/multi-user.target.wants/* \
/etc/systemd/system/*.wants/* \
/lib/systemd/system/local-fs.target.wants/* \
/lib/systemd/system/sockets.target.wants/*udev* \
/lib/systemd/system/sockets.target.wants/*initctl* \
/lib/systemd/system/sysinit.target.wants/systemd-tmpfiles-setup* \
/lib/systemd/system/systemd-update-utmp*
RUN apt update -y && \
apt install -y devscripts && \
apt install -y wget zip unzip && \
apt-get install -y locales && \
localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 && \
locale-gen en_US.UTF-8 && \
export LC_ALL=en_US.UTF-8 && \
export LANG=en_US.UTF-8 && \
export LANGUAGE=en_US.UTF-8 && \
localedef -i en_US -f UTF-8 en_US.UTF-8 && \
mkdir -p /www/server && \
mkdir -p /www/wwwroot && \
mkdir -p /www/wwwlogs && \
mkdir -p /www/backup/database && \
mkdir -p /www/backup/site && \
wget -O /tmp/dev.zip https://github.com/midoks/mdserver-web/archive/refs/heads/dev.zip && \
cd /tmp && unzip /tmp/dev.zip && \
mv -f /tmp/mdserver-web-dev /www/server/mdserver-web && \
rm -rf /tmp/dev.zip && \
rm -rf /tmp/mdserver-web-dev && \
cd /www/server/mdserver-web && \
bash scripts/install/debian.sh && \
cd /www/server/mdserver-web/ && \
/www/server/mdserver-web/bin/python tools.py username username && \
cd /www/server/mdserver-web/ && \
/www/server/mdserver-web/bin/python tools.py panel password
RUN cd /www/server/mdserver-web/plugins/php && \
bash install.sh install 74 && \
cd /www/server/mdserver-web/plugins/openresty && \
bash install.sh install 1.21.4.1 && \
cd /www/server/mdserver-web/plugins/mysql && \
bash install.sh install 5.6 && \
cd /www/server/mdserver-web/plugins/phpmyadmin && \
bash install.sh install 4.4.15 && \
systemctl enable openresty && \
systemctl enable php74 && \
systemctl enable mysql
RUN rm -rf /www/server/mysql/data
ADD ./start.sh /start.sh
ADD start.service /usr/lib/systemd/system/start.service
#RUN systemctl enable start
CMD [ "/lib/systemd/systemd", "log-level=info", "unit=sysinit.target" ]
EXPOSE 7200 80 443 888
VOLUME [ "/www" ]
-9
View File
@@ -1,9 +0,0 @@
[Unit]
Description=Customize the script
After=network.target
[Service]
ExecStart=/start.sh
[Install]
WantedBy=multi-user.target
-1
View File
@@ -1 +0,0 @@
#!/bin/bash
Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

+16
View File
@@ -0,0 +1,16 @@
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('abkill');">服务</p>
<p onclick="pluginInitD('abkill');">自启动</p>
<p onclick="pluginConfig('abkill');">黑名单</p>
<p onclick="pluginConfig('abkill');">异常日志</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
</div>
</div>
</div>
<script type="text/javascript">
$.getScript( "/plugins/file?name=abkill&f=js/abkill.js");
</script>
+172
View File
@@ -0,0 +1,172 @@
# coding: utf-8
import time
import random
import os
import urllib
import binascii
import json
import re
import sys
import subprocess
sys.path.append(os.getcwd() + "/class/core")
import public
app_debug = False
if public.getOs() == 'darwin':
app_debug = True
def getPluginName():
return 'abkill'
def getPluginDir():
return public.getPluginDir() + '/' + getPluginName()
def getServerDir():
return public.getServerDir() + '/' + getPluginName()
def getInitDFile():
if app_debug:
return '/tmp/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def initDreplace():
initd_file = getInitDFile()
if not os.path.exists(initd_file):
return getServerDir()
return initd_file
def status():
data = public.execShell(
"ps -ef|grep " + getPluginName() + " |grep -v grep | grep -v python | awk '{print $2}'")
if data[0] == '':
return 'stop'
return 'start'
def csvnOp(method):
if app_debug:
os_name = public.getOs()
if os_name == 'darwin':
return "Apple Computer does not support"
_initd_csvn = '/etc/init.d/csvn'
_initd_csvn_httpd = '/etc/init.d/csvn-httpd'
#_csvn = getServerDir() + '/bin/csvn'
#_csvn_httpd = getServerDir() + '/bin/csvn-httpd'
ret_csvn_httpd = public.execShell(_initd_csvn_httpd + ' ' + method)
# ret_csvn = public.execShell(_initd_csvn + ' ' + method)
subprocess.Popen(_initd_csvn + ' ' + method,
stdout=subprocess.PIPE, shell=True)
if ret_csvn_httpd[1] == '':
return 'ok'
return 'fail'
def start():
return csvnOp('start')
def stop():
return csvnOp('stop')
def restart():
return csvnOp('restart')
def reload():
return csvnOp('reload')
def initdStatus():
if not app_debug:
if public.getOs() == 'darwin':
return "Apple Computer does not support"
_initd_csvn = '/etc/init.d/csvn'
_initd_csvn_httpd = '/etc/init.d/csvn-httpd'
if os.path.exists(_initd_csvn) and os.path.exists(_initd_csvn_httpd):
return 'ok'
return 'fail'
def initdInstall():
import shutil
if not app_debug:
if public.getOs() == 'darwin':
return "Apple Computer does not support"
_csvn = getServerDir() + '/bin/csvn'
_csvn_httpd = getServerDir() + '/bin/csvn-httpd'
ret_csvn = public.execShell(_csvn + ' install')
ret_csvn_httpd = public.execShell(_csvn_httpd + ' install')
if ret_csvn[1] == '' and ret_csvn_httpd[1] == '':
return 'ok'
return 'fail'
def initdUinstall():
if not app_debug:
if public.getOs() == 'darwin':
return "Apple Computer does not support"
_csvn = getServerDir() + '/bin/csvn'
_csvn_httpd = getServerDir() + '/bin/csvn-httpd'
ret_csvn = public.execShell(_csvn + ' remove')
ret_csvn_httpd = public.execShell(_csvn_httpd + ' remove')
return 'ok'
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print status()
elif func == 'start':
print start()
elif func == 'stop':
print stop()
elif func == 'restart':
print restart()
elif func == 'reload':
print reload()
elif func == 'initd_status':
print initdStatus()
elif func == 'initd_install':
print initdInstall()
elif func == 'initd_uninstall':
print initdUinstall()
else:
print 'fail'
+16
View File
@@ -0,0 +1,16 @@
{
"sort": 7,
"ps": "异常程序监控和KILL",
"shell": "install.sh",
"name": "abkill",
"title": "异常程序监控",
"versions": "0.1",
"updates":"0.1",
"tip": "soft",
"checks": "server/abkill",
"author": "midoks",
"date": "201-04-01",
"home": "https://www.collab.net",
"type": "异常程序监控和KILL",
"pid": "4"
}
+76
View File
@@ -0,0 +1,76 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
ak_path={$SERVER_PATH}/abkill
ak_start(){
isStart=$(ps aux |grep 'abkill.py'|grep -v grep|awk '{print $2}')
if [ "$isStart" == '' ];then
echo -e "Starting abkill... \c"
cd $ak_path && nohup python abkill.py >> $ak_path/task.log 2>&1 &
sleep 0.3
isStart=$(ps aux |grep 'abkill.py'|grep -v grep|awk '{print $2}')
if [ "$isStart" == '' ];then
echo -e "\033[31mfailed\033[0m"
echo '------------------------------------------------------'
tail -n 20 $ak_path/task.log
echo '------------------------------------------------------'
echo -e "\033[31mError: abkill service startup failed.\033[0m"
return;
fi
echo -e "\033[32mdone\033[0m"
else
echo "Starting abkill(pid $isStart) already running"
fi
}
ak_stop()
{
echo -e "Stopping abkill... \c";
pids=$(ps aux | grep 'abkill.py' | grep -v grep|awk '{print $2}')
arr=($pids)
for p in ${arr[@]}
do
kill -9 $p
done
echo -e "\033[32mdone\033[0m"
}
ak_status()
{
isStart=$(ps aux|grep 'abkill.py'|grep -v grep|awk '{print $2}')
if [ "$isStart" != '' ];then
echo -e "\033[32mabkill (pid $(echo $isStart)) already running\033[0m"
else
echo -e "\033[31mabkill not running\033[0m"
fi
}
ak_reload()
{
isStart=$(ps aux|grep 'abkill.py'|grep -v grep|awk '{print $2}')
if [ "$isStart" != '' ];then
ak_stop
ak_start
else
echo -e "\033[31mmw not running\033[0m"
mw_start
fi
}
case "$1" in
'start') ak_start;;
'stop') ak_stop;;
'reload') ak_reload;;
'restart')
ak_stop
sleep 0.3
ak_start;;
'status') ak_status;;
esac
@@ -2,34 +2,31 @@
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
install_tmp=${rootPath}/tmp/bt_install.pl
Install_sysopt()
Install_abkill()
{
echo '正在安装脚本文件...' > $install_tmp
mkdir -p $serverPath/sys-opt
echo '1.0' > $serverPath/sys-opt/version.pl
mkdir -p $serverPath/abkill
echo '0.1' > $serverPath/abkill/version.pl
echo '安装完成' > $install_tmp
}
Uninstall_sysopt()
Uninstall_abkill()
{
rm -rf $serverPath/sys-opt
rm -f $serverPath/abkill
echo "卸载完成" > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_sysopt
Install_abkill
else
Uninstall_sysopt
Uninstall_abkill
fi
+1
View File
@@ -0,0 +1 @@
pluginService('abkill');
+85
View File
@@ -0,0 +1,85 @@
# coding: utf-8
# 使用示例:
# 1、将此文件重命名为btkill.py , 然后上传到服务器/root目录
# 2、执行 python /root/btkill.py
import time
import os
import sys
sys.path.append("/usr/local/lib/python2.7/site-packages")
import psutil
class btkill:
__limit = 10 # Cpu使用率触发上限
__vmsize = 1048576 / 4 # 虚拟内存触发上限(字节)
def checkMain(self):
pids = psutil.pids()
print pids
num = 0
for pid in pids:
try:
p = psutil.Process(pid)
if p.exe() == "":
continue
name = p.name()
if self.whiteList(name):
continue
cputimes = p.cpu_times()
if cputimes.user < 0.1:
continue
print p
percent = p.cpu_percent(interval=1)
vm = p.memory_info().vms
if percent > self.__limit or vm > self.__vmsize:
log = time.strftime('%Y-%m-%d %X', time.localtime()) + " (PID=" + str(
pid) + ", NAME=" + name + ", VMS=" + str(vm) + ", PERCENT=" + str(percent) + "%)"
# p.kill()
num += 1
print log + " >> killed\n"
except Exception as ex:
print str(ex)
return num
# 检查白名单
def whiteList(self, name):
wlist = ['yum', 'apt-get', 'apt', 'redis-cli', 'memcached', 'sshd', 'vm', 'vim', 'htop', 'top', 'sh', 'bash', 'zip', 'gzip', 'rsync',
'tar', 'unzip', 'php', 'composer', 'pkill', 'mongo', 'mongod', 'php-fpm', 'nginx', 'httpd', 'lsof', 'ps', 'redis-server',
'mysqld', 'mysqld_safe', 'mysql', 'pure-ftpd', 'sparse_dd', 'stunnel', 'squeezed', 'vncterm', 'awk', 'ruby', 'postgres',
'mpathalert', 'vncterm', 'multipathd', 'fe', 'elasticsyslog', 'syslogd', 'v6d', 'xapi', 'screen', 'runsvdir', 'svlogd',
'java', 'udevd', 'ntpd', 'irqbalance', 'qmgr', 'wpa_supplicant', 'mysqld_safe', 'sftp-server', 'lvmetad', 'gitlab-web',
'pure-ftpd', 'auditd', 'master', 'dbus-daemon', 'tapdisk', 'sshd', 'init', 'ksoftirqd', 'kworker', 'kmpathd',
'kmpath_handlerd', 'python', 'kdmflush', 'bioset', 'crond', 'kthreadd', 'migration', 'rcu_sched', 'kjournald',
'gcc', 'gcc++', 'nginx', 'mysqld', 'php-cgi', 'login', 'firewalld', 'iptables', 'systemd', 'network', 'dhclient',
'systemd-journald', 'NetworkManager', 'systemd-logind', 'systemd-udevd', 'polkitd', 'tuned', 'rsyslogd', 'AliYunDunUpdate', 'AliYunDun', 'sendmail']
wslist = ['vif', 'qemu', 'scsi_eh', 'xcp',
'xen', 'docker', 'yunsuo', 'aliyun', 'PM2']
for key in wlist:
if key == name:
return True
for key in wslist:
if name.find(key) != -1:
return True
return False
# 开始处理
def start(self):
num = 0
while True:
num += self.checkMain()
print "查杀完成, 共查杀[" + str(num) + "]个异常进程!"
time.sleep(3)
print '======================================='
print "查杀完成, 共查杀[" + str(num) + "]个异常进程!"
if __name__ == "__main__":
print "正在检测异常进程..."
print '======================================='
c = btkill()
c.start()
-420
View File
@@ -1,420 +0,0 @@
# coding:utf-8
'''
doc: https://docs.python.org/zh-cn/3/library/ftplib.html
'''
import sys
import io
import os
import time
import re
import json
import paramiko
import ftplib
sys.path.append(os.getcwd() + "/class/core")
import mw
DEBUG = True
BLOCK_SIZE = 1024 * 1024 * 2
# BLOCK_SIZE = 50
PROGRESS_FILE_NAME = "PROGRESS_FILE_NAME"
"""
=============自定义异常===================
"""
class OsError(Exception):
"""OS端异常"""
class ObjectNotFound(OsError):
"""对象不存在时抛出的异常"""
def __init__(self, *args, **kwargs):
message = "文件对象不存在。"
super(ObjectNotFound, self).__init__(message, *args, **kwargs)
class APIError(Exception):
"""API参数错误异常"""
def __init__(self, *args, **kwargs):
_api_error_msg = 'API资料校验失败,请核实!'
super(APIError, self).__init__(_api_error_msg, *args, **kwargs)
class FtpPSClient:
_title = "FTP"
_name = "ftp"
__host = None
__port = None
__user = None
__password = None
default_port = 21
default_backup_path = "/backup/"
config_file = "cfg.json"
def __init__(self, load_config=True, timeout=10):
self.timeout = timeout
if load_config:
data = self.get_config()
self.injection_config(data)
def get_config(self):
default_config = {
"ftp_host": '',
"ftp_user": '',
"ftp_pass": '',
"backup_path": self.default_backup_path
}
cfg = mw.getServerDir() + "/backup_ftp/" + self.config_file
if os.path.exists(cfg):
data = mw.readFile(cfg)
return json.loads(data)
else:
return default_config
def injection_config(self, data):
self.__host = host = data["ftp_host"].strip()
if host.find(':') == -1:
self.__port = self.default_port
else:
self.__host = host.split(':')[0]
self.__port = host.split(':')[1]
self.__user = data['ftp_user'].strip()
self.__password = data['ftp_pass'].strip()
bp = data['backup_path'].strip()
if bp:
self.backup_path = self.getPath(bp)
else:
self.backup_path = self.getPath(self.default_backup_path)
def authorize(self):
try:
if self.timeout is not None:
ftp = ftplib.FTP(timeout=self.timeout)
else:
ftp = ftplib.FTP()
debuglevel = 0
# if DEBUG:
# debuglevel = 3
ftp.set_debuglevel(debuglevel)
# ftp.set_pasv(True)
ftp.connect(self.__host, int(self.__port))
ftp.login(self.__user, self.__password)
return ftp
except Exception as e:
raise OsError("无法连接FTP客户端,请检查配置参数是否正确!")
# 取目录路径
def getPath(self, path):
if path[-1:] != '/':
path += '/'
if path[:1] != '/':
path = '/' + path
return path.replace('//', '/')
def generateDownloadUrl(self, object_name):
return 'ftp://' + \
self.__user + ':' + \
self.__password + '@' + \
self.__host + ':' + \
"/" + object_name
def buildDirName(self, data_type, file_name):
import re
prefix_dict = {
"site": "web",
"database": "db",
"path": "path",
}
file_regx = prefix_dict.get(data_type) + "_(.+)_20\d+_\d+\."
sub_search = re.search(file_regx, file_name)
sub_path_name = ""
if sub_search:
sub_path_name = sub_search.groups()[0]
sub_path_name += '/'
# 构建OS存储路径
object_name = self.backup_path + \
data_type + '/' + \
sub_path_name + \
file_name
return object_name
def uploadFile(self, filename, data_type=None, *args, **kwargs):
client = self.authorize()
local_file_name = filename
filename = os.path.abspath(filename)
dirname = os.path.dirname(filename)
temp_name = os.path.split(filename)[1]
object_name = self.buildDirName(data_type, temp_name)
upload_tmp_dir = os.path.join(dirname, ".upload_tmp")
if not os.path.exists(upload_tmp_dir):
os.mkdir(upload_tmp_dir)
print("|-正在上传文件到 {}".format(object_name))
total_bytes = os.path.getsize(filename)
object_md5_name = mw.md5(object_name)
pg_file = os.path.join(upload_tmp_dir, object_md5_name + ".pl")
block_size = BLOCK_SIZE
if kwargs.get("block_size"):
try:
block_size = float(kwargs.get("block_size"))
except:
pass
remote_file_size = None
if not os.path.exists(pg_file):
# import uuid
# uid = str(uuid.uuid1())
progress_info = {
"filename": local_file_name,
"total_bytes": total_bytes,
"uploaded_bytes": 0,
}
mw.writeFile(pg_file, json.dumps(progress_info))
else:
progress_info = json.loads(mw.readFile(pg_file))
if total_bytes == progress_info.get("total_bytes"):
# 取远程文件大小
_max_loop = 10
while _max_loop > 0:
try:
time.sleep(1)
remote_file_size = client.size(object_name)
if remote_file_size > total_bytes:
remote_file_size = None
break
except Exception as e:
if DEBUG:
print(type(e))
print(e)
_max_loop -= 1
else:
remote_file_size = None
uploaded_bytes = 0 if remote_file_size is None else remote_file_size
dir_name = os.path.split(object_name)[0]
if dir_name:
self.createDirP(dir_name)
upload_start = time.time()
try:
if total_bytes > 1024 * 1024 * 1024:
with open(local_file_name, 'rb') as file_handler:
if remote_file_size is not None:
file_handler.seek(remote_file_size)
client.voidcmd("TYPE I")
datasock = ''
esize = ''
datasock, esize = client.ntransfercmd(
"STOR " + object_name, remote_file_size)
while True:
buf = file_handler.read(block_size)
if not len(buf):
break
datasock.sendall(buf)
uploaded_bytes += len(buf)
if DEBUG:
print('\ruploading %.2f%%' %
(float(uploaded_bytes) / total_bytes * 100))
print("uploaded_bytes", uploaded_bytes)
if uploaded_bytes == total_bytes:
break
datasock.close()
if DEBUG:
print('close data handle')
try:
client.voidcmd('NOOP')
except Exception as e:
if DEBUG:
print("Send NOOP command error:")
print(e)
else:
if DEBUG:
print('keep alive cmd success')
client.voidresp()
if DEBUG:
print('No loop cmd')
else:
# 小于1G文件直接上传
file_handler = open(local_file_name, "rb")
client.storbinary('STOR %s' % object_name,
file_handler, blocksize=block_size)
file_handler.close()
except Exception as e:
print(str(e))
completed_file_size = None
_max_loop = 10
while _max_loop > 0:
try:
time.sleep(1)
completed_file_size = client.size(object_name)
break
except Exception as e:
_max_loop -= 1
if DEBUG:
print("size error:" + str(e))
# 上传完成
if completed_file_size == total_bytes:
if DEBUG:
upload_completed = time.time()
upload_diff = upload_completed - upload_start
print("文件上传成功, 耗时: {}s。".format(upload_diff))
if os.path.exists(pg_file):
os.remove(pg_file)
return True
else:
if os.path.exists(pg_file):
os.remove(pg_file)
print("文件上传后大小不一致!")
print("completed_file_size:" + str(completed_file_size))
print("total_bytes:", total_bytes)
print("object_md5_name:", object_md5_name)
print("pg_file:", pg_file)
print("filename:", filename)
print("dirname:", dirname)
print("object_name:", object_name)
return False
def createDirP(self, dir_name):
"""创建远程目录
:param dir_name: 目录名称
:return:
"""
try:
dirnames = dir_name.split('/')
ftp = self.authorize()
# ftp.cwd(get.path);
for dirname in dirnames:
if not dirname or not dirname.strip():
continue
try:
flist = ftp.nlst()
if not dirname in flist:
ftp.mkd(dirname)
except:
# print("mlsd mode.")
try:
flist = list(ftp.mlsd())[1:]
for f in flist:
if dirname == f[0]:
break
else:
ftp.mkd(dirname)
except:
return False
ftp.cwd(dirname)
return True
except:
return False
def createDir(self, path, name):
ftp = self.authorize()
path = self.getPath(path)
ftp.cwd(path)
try:
ftp.mkd(name)
ftp.close()
return True
except Exception as e:
print(str(e))
ftp.close()
return False
def deleteDir(self, path, dir_name):
try:
ftp = self.authorize()
ftp.rmd(dir_name)
return True
except ftplib.error_perm as e:
print("deleteDir:" + str(e) + ":" + dir_name)
except Exception as e:
print(e)
return False
def deleteFile(self, filename):
try:
ftp = self.authorize()
ftp.delete(filename)
return True
except Exception as e:
print(str(e))
return False
def getList(self, path="/"):
ftp = self.authorize()
path = self.getPath(path)
ftp.cwd(path)
mlsd = False
try:
files = list(ftp.mlsd())
mlsd = True
except:
try:
files = ftp.nlst(path)
mlsd = False
except:
raise RuntimeError("FTP服务器数据返回异常!")
ftp.close()
# print(files)
f_list = []
dirs = []
data = []
default_time = '1971/01/01 01:01:01'
for dt in files:
# print(dt)
if mlsd:
dt_name = dt[0]
dt_info = dt[1]
else:
if dt.find("/") >= 0:
dt = dt.split("/")[-1]
tmp = {}
tmp['name'] = dt_name
if dt_name == '.' or dt_name == '..':
continue
tmp['time'] = dt_info['modify']
try:
tmp['size'] = dt_info['size']
tmp['type'] = "File"
tmp['download'] = self.generateDownloadUrl(path + dt_name)
f_list.append(tmp)
except:
tmp['size'] = dt_info['sizd']
tmp['type'] = None
tmp['download'] = ''
dirs.append(tmp)
data = dirs + f_list
mlist = {}
mlist['path'] = path
mlist['list'] = data
return mlist
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

-101
View File
@@ -1,101 +0,0 @@
<style>
.upyunCon {
height: 428px;
}
.up-place {
height: 62px;
border-bottom: 1px solid #ddd;
}
.up-place .btn {
border-radius: 0;
}
.up-place .place-input {
background-color: #f3f3f3;
border: 1px solid #ccc;
height: 30px;
line-height: 28px;
overflow: hidden;
margin: 1px 0 0 -1px;
width: 340px;
}
.place-input ul {
display: inline-block;
position: relative;
width: auto;
}
.place-input ul li {
background: url("/static/img/ico/ico-ltr.png") no-repeat right center;
float: left;
padding-left: 10px;
padding-right: 18px;
}
.place-input ul li a {
height: 28px;
cursor: pointer;
display: inline-block;
}
.upyunlist {
height: 516px;
overflow: auto;
}
.up-bottom {
background-color: #fafafa;
border-top: 1px solid #eee;
bottom: 0;
position: absolute;
width: 100%;
}
.up-use {
line-height: 50px
}
.list-list .cursor span {
line-height: 30px;
}
.btn-title {
margin-top: 1px
}
.tip {
font-size: 10px;
font-style: oblique;
color: green;
}
</style>
<div class="upyunCon">
<div class="up-place pd15">
<button id="backBtn" class="btn btn-default btn-sm glyphicon glyphicon-arrow-left pull-left" title="后退"></button>
<input id="myPath" style="display:none;" type="text" value="">
<div class="place-input pull-left">
<div style="width:1400px;height:28px"><ul></ul></div>
</div>
<button class="refreshBtn btn btn-default btn-sm glyphicon glyphicon-refresh pull-left mr20" title="刷新" style="margin-left:-1px;"></button>
<button class="btn btn-default btn-sm pull-right btn-title" onclick="upyunApi()">帐户设置</button>
<button class="btn btn-default btn-sm pull-right mr20 btn-title" onclick="createDir()">新建文件夹</button>
</div>
<div class="upyunlist pd15">
<div class="divtable" style="margin-bottom:15px">
<table class="table table-hover">
<thead><tr><th>名称</th><th>大小</th><th>更新时间</th><th class="text-right">操作</th></tr></thead>
<tbody class="list-list"></tbody>
</table>
</div>
</div>
</div>
<script type="text/javascript">
$.getScript( "/plugins/file?name=backup_ftp&f=js/backup_ftp.js", function(){
osList('/');
});
</script>
-268
View File
@@ -1,268 +0,0 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import json
# print(sys.platform)
if sys.platform != "darwin":
os.chdir("/www/server/mdserver-web")
sys.path.append(os.getcwd() + "/class/core")
import mw
_ver = sys.version_info
is_py2 = (_ver[0] == 2)
is_py3 = (_ver[0] == 3)
DEBUG = False
if is_py2:
reload(sys)
sys.setdefaultencoding('utf-8')
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'backup_ftp'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
sys.path.append(getPluginDir() + "/class")
from ftp_client import FtpPSClient
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':', 1)
tmp[t[0]] = t[1]
return tmp
def checkArgs(data, ck=[]):
for i in range(len(ck)):
if not ck[i] in data:
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
return (True, mw.returnJson(True, 'ok'))
def status():
return 'start'
def getConf():
cfg = getServerDir() + "/cfg.json"
if not os.path.exists(cfg):
return mw.returnJson(False, "未配置", [])
data = mw.readFile(cfg)
data = json.loads(data)
return mw.returnJson(True, "OK", data)
def setConf():
args = getArgs()
data = checkArgs(args, ['use_sftp', 'ftp_user',
'ftp_pass', 'ftp_host', 'backup_path'])
if not data[0]:
return data[1]
cfg = getServerDir() + "/cfg.json"
values = ['ftp_user',
'ftp_pass',
'ftp_host']
for v in values:
if args[v] == '':
return mw.returnJson(False, '必填资料不能为空,请核实!', [])
if args['backup_path'] == '':
args['backup_path'] = "/backup"
try:
ftp = FtpPSClient(load_config=False)
ftp.injection_config(args)
data = ftp.getList("/")
if data:
mw.writeFile(cfg, mw.getJson(args))
return mw.returnJson(True, '设置成功', [])
except Exception as e:
return mw.returnJson(False, "FTP校验失败,请核实!\n" + str(e), [])
def getList():
cfg = getServerDir() + "/cfg.json"
if not os.path.exists(cfg):
return mw.returnJson(False, "未配置FTP,请点击`账户设置`", [])
args = getArgs()
data = checkArgs(args, ['path'])
if not data[0]:
return data[1]
try:
ftp = FtpPSClient()
flist = ftp.getList(args['path'])
return mw.returnJson(True, "ok", flist)
except Exception as e:
return mw.returnJson(False, str(e), [])
def createDir():
cfg = getServerDir() + "/cfg.json"
if not os.path.exists(cfg):
return mw.returnJson(False, "未配置FTP,请点击`账户设置`", [])
args = getArgs()
data = checkArgs(args, ['path', 'name'])
if not data[0]:
return data[1]
ftp = FtpPSClient()
isok = ftp.createDir(args['path'], args['name'])
if isok:
return mw.returnJson(True, "创建成功")
return mw.returnJson(False, "创建失败")
def deleteDir():
args = getArgs()
data = checkArgs(args, ['dir_name', 'path'])
if not data[0]:
return data[1]
ftp = FtpPSClient()
isok = ftp.deleteDir(args['path'], args['dir_name'])
if isok:
return mw.returnJson(True, "删除成功")
return mw.returnJson(False, "删除失败")
def deleteFile():
args = getArgs()
data = checkArgs(args, ['path', 'filename'])
if not data[0]:
return data[1]
ftp = FtpPSClient()
isok = ftp.deleteFile(args['path'] + "/" + args['filename'])
if isok:
return mw.returnJson(True, "删除成功")
return mw.returnJson(False, "删除失败")
def backupAllFunc(stype):
os.chdir(mw.getRunDir())
name = sys.argv[2]
num = sys.argv[3]
prefix_dict = {
"site": "web",
"database": "db",
"path": "path",
}
args = stype + " " + name + " " + num
cmd = 'python3 ' + mw.getRunDir() + '/scripts/backup.py ' + args
if stype.find('database_') > -1:
plugin_name = stype.replace('database_', '')
args = "database " + name + " " + num
cmd = 'python3 ' + mw.getRunDir() + '/plugins/' + plugin_name + \
'/scripts/backup.py ' + args
os.system(cmd)
# 开始执行上传信息.
if stype.find('database_') > -1:
bk_name = 'database'
plugin_name = stype.replace('database_', '')
bk_prefix = plugin_name + '/db'
stype = 'database'
else:
bk_prefix = prefix_dict[stype]
bk_name = stype
find_path = mw.getBackupDir() + '/' + bk_name + '/' + bk_prefix + '_' + name
find_new_file = "ls " + find_path + \
"_* | grep '.gz' | cut -d \ -f 1 | awk 'END {print}'"
filename = mw.execShell(find_new_file)[0].strip()
if filename == "":
mw.echoInfo("not find upload file!")
return False
print("|-准备上传文件 {}".format(filename))
ftp = FtpPSClient()
ftp.uploadFile(filename, stype)
return ''
def backupSite():
# 备份站点
pass
def in_array(name, arr=[]):
for x in arr:
if name == x:
return True
return False
def installPreInspection():
return 'ok'
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print(status())
elif func == 'start':
print(start())
elif func == 'stop':
print(stop())
elif func == 'restart':
print(restart())
elif func == 'reload':
print(reload())
elif func == 'install_pre_inspection':
print(installPreInspection())
elif func == 'conf':
print(getConf())
elif func == 'set_config':
print(setConf())
elif func == "get_list":
print(getList())
elif func == "create_dir":
print(createDir())
elif func == "delete_dir":
print(deleteDir())
elif func == 'delete_file':
print(deleteFile())
elif in_array(func, ['site', 'database', 'path']) or func.find('database_') > -1:
print(backupAllFunc(func))
else:
print('error')
-17
View File
@@ -1,17 +0,0 @@
{
"title":"FTP存储空间",
"hook":["backup"],
"tip":"soft",
"name":"backup_ftp",
"type":"运行环境",
"ps":"将网站或数据库打包备份到FTP存储空间",
"versions":["1.0"],
"install_pre_inspection":false,
"shell":"install.sh",
"checks":"server/backup_ftp",
"path": "server/backup_ftp",
"author":"midoks",
"home":"https://github.com/midoks/mdserver-web",
"date":"2022-10-23",
"pid": "4"
}
-258
View File
@@ -1,258 +0,0 @@
function bkfPost(method,args,callback){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'backup_ftp', func:method, args:_args}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function getFtpLocalTime(data){
var str = data.slice(0,4)+"/"+data.slice(4,6)+"/"+data.slice(6,8)
+ " " + data.slice(8,10)+":"+data.slice(10,12)+":"+data.slice(12,14);
return str;
}
// 自定义部分
var i = null;
//设置API
function upyunApi(){
bkfPost('conf', {}, function(rdata){
var rdata = $.parseJSON(rdata.data);
var token = rdata.data;
var check_status = token.use_sftp;
var sftp_checked = check_status === "true" ? " checked=\"checked\"" : "";
if (typeof(token.ftp_host) == 'undefined'){
token.ftp_host = '';
}
if (typeof(token.ftp_user) == 'undefined'){
token.ftp_user = '';
}
if (typeof(token.ftp_pass) == 'undefined'){
token.ftp_pass = '';
}
if (typeof(token.backup_path) == 'undefined'){
token.backup_path = '';
}
var apicon = '<div class="bingfa mtb15" style="padding-bottom:0px;">\
<p>\
<span class="span_tit">使用SFTP:</span>\ <input style="width: 20px; vertical-align:middle;" type="checkbox" name="use_sftp"'+sftp_checked+'> 是否使用SFTP进行数据传输 \
</p>\
<p>\
<span class="span_tit">Host:</span>\
<input placeholder="请输入主机地址" style="width: 200px;" type="text" name="upyun_service" value="'+token.ftp_host+'"> *服务器地址,FTP默认端口21, SFTP默认端口22\
</p>\
<p>\
<span class="span_tit">用户名:</span>\
<input style="width: 200px;" type="text" name="ftp_username" value="'+token.ftp_user+'"> *指定用户名\
</p>\
<p>\
<span class="span_tit">密码:</span>\
<input style="width: 200px;" type="password" name="ftp_password" value="'+token.ftp_pass+'"> *登录密码\
</p>\
<p>\
<span class="span_tit">存储位置:</span>\
<input placeholder="请输入存储位置" style="width: 200px;" type="text" name="backup_path" value="'+token.backup_path+'"> *相对于根目录的路径,默认是/backup\
</p>\
</div>';
layer.open({
type: 1,
area: "600px",
title: "FTP/SFTP帐户设置",
closeBtn: 1,
shift: 5,
shadeClose: false,
btn: ['确定','取消'],
content:apicon,
yes:function(index,layero){
var data = {
use_sftp:$("input[name='use_sftp']").prop('checked'),
ftp_user:$("input[name='ftp_username']").val(),
ftp_pass:$("input[name='ftp_password']").val(),
ftp_host:$("input[name='upyun_service']").val(),
backup_path:$("input[name='backup_path']").val()
}
bkfPost('set_config', data, function(rdata){
var rdata = $.parseJSON(rdata.data);
if (rdata.status){
showMsg(rdata.msg,function(){
layer.close(index);
osList("/");
},{icon:1},2000);
} else{
layer.msg(rdata.msg,{icon:2});
}
})
},
});
});
}
function createDir(){
layer.open({
type: 1,
area: "400px",
title: "创建目录",
closeBtn: 1,
shift: 5,
shadeClose: false,
btn: ['确定','取消'],
content:'<div class="bingfa bt-form c6" style="padding-bottom: 10px;">\
<p>\
<span class="span_tit">目录名称:</span>\
<input style="width: 200px;" type="text" name="newPath" value="">\
</p>\
</div>',
success:function(){
$("input[name='newPath']").focus().keyup(function(e){
if(e.keyCode == 13) $(".layui-layer-btn0").click();
});
},
yes:function(index,layero){
var name = $("input[name='newPath']").val();
if(name == ''){
layer.msg('目录名称不能为空!',{icon:2});
return;
}
var path = $("#myPath").val();
var dirname = name;
// var loadT = layer.msg('正在创建目录['+dirname+']...',{icon:16,time:0,shade: [0.3, '#000']});
bkfPost('create_dir', {path:path,name:dirname}, function(data){
var rdata = $.parseJSON(data.data);
if(rdata.status) {
showMsg(rdata.msg, function(){
layer.close(index);
osList(path);
} ,{icon:1}, 2000);
} else{
layer.msg(rdata.msg,{icon:2});
}
});
}
});
}
//删除文件
function deleteFile(name, is_dir){
if (is_dir === false){
safeMessage('删除文件','删除后将无法恢复,真的要删除['+name+']吗?',function(){
var path = $("#myPath").val();
var filename = name;
bkfPost('delete_file', {filename:filename,path:path}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
osList(path);
},{icon:rdata.status?1:2},2000);
});
});
} else {
safeMessage('删除文件夹','删除后将无法恢复,真的要删除['+name+']吗?',function(){
var path = $("#myPath").val();
bkfPost('delete_dir', {dir_name:name,path:path}, function(rdata){
var rdata = $.parseJSON(rdata.data);
showMsg(rdata.msg,function(){
osList(path);
},{icon:rdata.status?1:2},2000);
});
});
}
}
function osList(path){
bkfPost('get_list', {path:path}, function(rdata){
var rdata = $.parseJSON(rdata.data);
if(rdata.status === false){
showMsg(rdata.msg,function(){
upyunApi();
},{icon:2},2000);
return;
}
var mlist = rdata.data;
// console.log(mlist);
var listBody = ''
var listFiles = ''
for(var i=0;i<mlist.list.length;i++){
if(mlist.list[i].type == null){
listBody += '<tr><td class="cursor" onclick="osList(\''+(path+'/'+mlist.list[i].name).replace('//','/')+'\')"><span class="ico ico-folder"></span>\<span>'+mlist.list[i].name+'</span></td>\
<td>-</td>\
<td>-</td>\
<td class="text-right"><a class="btlink" onclick="deleteFile(\''+mlist.list[i].name+'\', true)">删除</a></td></tr>'
}else{
listFiles += '<tr><td class="cursor"><span class="ico ico-file"></span>\<span>'+mlist.list[i].name+'</span></td>\
<td>'+toSize(mlist.list[i].size)+'</td>\
<td>'+getFtpLocalTime(mlist.list[i].time)+'</td>\
<td class="text-right"><a target="_blank" href="'+mlist.list[i].download+'" class="btlink">下载</a> | <a class="btlink" onclick="deleteFile(\''+mlist.list[i].name+'\', false)">删除</a></td></tr>'
}
}
listBody += listFiles;
var pathLi='';
var tmp = path.split('/')
var pathname = '';
var n = 0;
for(var i=0;i<tmp.length;i++){
if(n > 0 && tmp[i] == '') continue;
var dirname = tmp[i];
if(dirname == '') {
dirname = '根目录';
n++;
}
pathname += '/' + tmp[i];
pathname = pathname.replace('//','/');
pathLi += '<li><a title="'+pathname+'" onclick="osList(\''+pathname+'\')">'+dirname+'</a></li>';
}
var um = 1;
if(tmp[tmp.length-1] == '') um = 2;
var backPath = tmp.slice(0,tmp.length-um).join('/') || '/';
$('#myPath').val(path);
$(".upyunCon .place-input ul").html(pathLi);
$(".upyunlist .list-list").html(listBody);
upPathLeft();
$('#backBtn').unbind().click(function() {
osList(backPath);
});
$('.upyunCon .refreshBtn').unbind().click(function(){
osList(path);
});
});
}
//计算当前目录偏移
function upPathLeft(){
var UlWidth = $(".place-input ul").width();
var SpanPathWidth = $(".place-input").width() - 20;
var Ml = UlWidth - SpanPathWidth;
if(UlWidth > SpanPathWidth ){
$(".place-input ul").css("left",-Ml)
}
else{
$(".place-input ul").css("left",0)
}
}
// $('.layui-layer-page').css('height','670px');
Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 B

-28
View File
@@ -1,28 +0,0 @@
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('clean');">服务</p>
<p onclick="pluginConfig('clean');">配置修改</p>
<p onclick="pluginLogs('clean',null,'run_log');">运行日志</p>
<p onclick="pRead()">说明</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
</div>
</div>
</div>
<script type="text/javascript">
pluginService('clean');
function pRead(){
var readme = '<ul class="help-info-text c7">';
readme += '<li>启动后,加入到计划中[2:30]执行。</li>';
readme += '<li>【*】代表要删除。</li>';
readme += '<li>添加/删除清除日志,可在`配置修改`中添加/删除。</li>';
readme += '<li>如果是目录,会寻找【.log】后缀的文件清空。</li>';
readme += '</ul>';
$('.soft-man-con').html(readme);
}
</script>
-227
View File
@@ -1,227 +0,0 @@
# coding:utf-8
import sys
import io
import os
import time
sys.path.append(os.getcwd() + "/class/core")
import mw
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'clean'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getInitDFile():
if app_debug:
return '/tmp/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getConf():
path = getServerDir() + "/clean.conf"
return path
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def getLockFile():
return getServerDir() + "/installed_lock.pl"
def runLog():
return getServerDir() + "/clean.log"
def status():
initConf()
if os.path.exists(getLockFile()):
return "start"
return 'stop'
def initConf():
conf = getConf()
if not os.path.exists(conf):
content = ""
clog = [
"/var/spool/clientmqueue/*",
"/var/log/cron-*",
"/var/log/maillog-*",
"/var/log/secure-*",
"/var/log/spooler-*",
"/var/log/yum.log-*",
"/var/log/messages-*",
"/var/log/btmp-*",
"/var/log/audit/audit.log.*",
"/var/log/rhsm/rhsm.log-*",
"/var/log/rhsm/rhsmcertd.log-*",
"/tmp/yum_save_*",
"/tmp/tmp.*",
]
for i in clog:
content += i + "\n"
# 常用日志
clogcom = [
"/var/log/messages",
"/var/log/btmp",
"/var/log/wtmp",
"/var/log/secure",
"/var/log/lastlog",
"/var/log/cron",
"/www/server/cron"
]
for i in clogcom:
if os.path.exists(i):
content += i + "\n"
# 清理日志
rootDir = "/var/log"
l = os.listdir(rootDir)
for x in range(len(l)):
abspath = rootDir + "/" + l[x]
content += abspath + "\n"
mw.writeFile(conf, content)
def start():
initConf()
lock_file = getLockFile()
if not os.path.exists(lock_file):
mw.writeFile(lock_file, "")
import tool_task
tool_task.createBgTask()
return 'ok'
return 'fail'
def stop():
initConf()
lock_file = getLockFile()
if os.path.exists(lock_file):
os.remove(lock_file)
import tool_task
tool_task.removeBgTask()
return 'ok'
return 'fail'
def reload():
return 'ok'
def get_filePath_fileName_fileExt(filename):
(filepath, tempfilename) = os.path.split(filename)
(shotname, extension) = os.path.splitext(tempfilename)
return filepath, shotname, extension
def cleanFileLog(path):
filepath, shotname, extension = get_filePath_fileName_fileExt(path)
if extension == ".log":
cmd = "echo \"\" > " + path
tmp = mw.execShell(cmd)
if tmp[1] != "":
cmd += " | error:" + tmp[1].strip()
print(cmd)
def cleanSelfFileLog(path):
filepath, shotname, extension = get_filePath_fileName_fileExt(path)
if extension == ".log":
cmd = "echo \"\" > " + path
tmp = mw.execShell(cmd)
if tmp[1] != "":
cmd += " | error:" + tmp[1].strip()
print(cmd)
def cleanDirLog(path):
l = os.listdir(path)
for x in range(len(l)):
abspath = path + "/" + l[x]
if os.path.isfile(abspath):
cleanFileLog(abspath)
if os.path.isdir(abspath):
cleanDirLog(abspath)
def cleanLog():
conf = getConf()
clist = mw.readFile(conf).strip()
clist = clist.split("\n")
for x in clist:
abspath = x.strip()
if abspath.find('*') > 1:
cmd = 'rm -rf ' + abspath
print(cmd)
data = mw.execShell(cmd)
# print(data)
continue
if os.path.exists(abspath):
if os.path.isfile(abspath):
cleanSelfFileLog(abspath)
continue
if os.path.isdir(abspath):
cleanDirLog(abspath)
continue
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print(status())
elif func == 'start':
print(start())
elif func == 'stop':
print(stop())
elif func == 'restart':
print(restart())
elif func == 'reload':
print(reload())
elif func == 'conf':
print(getConf())
elif func == 'run_log':
print(runLog())
elif func == 'clean':
cleanLog()
else:
print('error')
-16
View File
@@ -1,16 +0,0 @@
{
"title":"日志清理",
"tip":"soft",
"name":"clean",
"type":"运行环境",
"ps":"日志清理",
"versions":"1.0",
"updates":"1.0",
"shell":"install.sh",
"checks":"server/clean",
"path": "server/clean",
"author":"clean",
"home":"https://github.com/midoks",
"date":"2021-11-23",
"pid": "5"
}
-43
View File
@@ -1,43 +0,0 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/mongodb && /bin/bash install.sh install 5.0.4
# cd /www/server/mdserver-web/plugins/mongodb && /bin/bash install.sh install 5.0.4
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
VERSION=$2
if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi
Install_app()
{
echo '正在安装脚本文件...' > $install_tmp
mkdir -p $serverPath/clean
cd ${rootPath} && python3 ${rootPath}/plugins/clean/index.py start
echo "${VERSION}" > $serverPath/clean/version.pl
echo '安装完成' > $install_tmp
}
Uninstall_app()
{
cd ${rootPath} && python3 ${rootPath}/plugins/clean/index.py stop
rm -rf $serverPath/clean
echo "Uninstall_clean" > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_app
else
Uninstall_app
fi
-156
View File
@@ -1,156 +0,0 @@
# coding:utf-8
import sys
import io
import os
import time
import json
sys.path.append(os.getcwd() + "/class/core")
import mw
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'clean'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getTaskConf():
conf = getServerDir() + "/task_config.json"
return conf
def getConfigData():
try:
return json.loads(mw.readFile(getTaskConf()))
except:
pass
return []
def getConfigTpl():
tpl = {
"name": "",
"task_id": -1,
}
return tpl
def createBgTask():
removeBgTask()
args = {
"period": "day",
"hour": "2",
"minute": "30",
}
createBgTaskByName(getPluginName(), args)
def createBgTaskByName(name, args):
cfg = getConfigTpl()
_name = "[勿删]日志清理[" + name + "]"
res = mw.M("crontab").field("id, name").where("name=?", (_name,)).find()
if res:
return True
if "task_id" in cfg.keys() and cfg["task_id"] > 0:
res = mw.M("crontab").field("id, name").where(
"id=?", (cfg["task_id"],)).find()
if res and res["id"] == cfg["task_id"]:
print("计划任务已经存在!")
return True
import crontab_api
api = crontab_api.crontab_api()
period = args['period']
_hour = ''
_minute = ''
_where1 = ''
_type_day = "day"
if period == 'day':
_type_day = 'day'
_hour = args['hour']
_minute = args['minute']
elif period == 'minute-n':
_type_day = 'minute-n'
_where1 = args['minute-n']
_minute = ''
mw_dir = mw.getRunDir()
cmd = '''
mw_dir=%s
rname=%s
plugin_path=%s
script_path=%s
logs_file=$plugin_path/${rname}.log
''' % (mw_dir, name, getServerDir(), getPluginDir())
cmd += 'echo "★【`date +"%Y-%m-%d %H:%M:%S"`】 STSRT★" >> $logs_file' + "\n"
cmd += 'echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" >> $logs_file' + "\n"
cmd += 'echo "python3 $script_path/index.py clean >> $logs_file 2>&1"' + "\n"
cmd += 'cd $mw_dir && python3 $script_path/index.py clean >> $logs_file 2>&1' + "\n"
cmd += 'echo "【`date +"%Y-%m-%d %H:%M:%S"`】 END★" >> $logs_file' + "\n"
cmd += 'echo "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" >> $logs_file' + "\n"
params = {
'name': _name,
'type': _type_day,
'week': "",
'where1': _where1,
'hour': _hour,
'minute': _minute,
'save': "",
'backup_to': "",
'stype': "toShell",
'sname': '',
'sbody': cmd,
'urladdress': '',
}
task_id = api.add(params)
if task_id > 0:
cfg["task_id"] = task_id
cfg["name"] = name
_dd = getConfigData()
_dd.append(cfg)
mw.writeFile(getTaskConf(), json.dumps(_dd))
def removeBgTask():
cfg_list = getConfigData()
for x in range(len(cfg_list)):
cfg = cfg_list[x]
if "task_id" in cfg.keys() and cfg["task_id"] > 0:
res = mw.M("crontab").field("id, name").where(
"id=?", (cfg["task_id"],)).find()
if res and res["id"] == cfg["task_id"]:
import crontab_api
api = crontab_api.crontab_api()
data = api.delete(cfg["task_id"])
if data[0]:
cfg["task_id"] = -1
cfg_list[x] = cfg
mw.writeFile(getTaskConf(), '[]')
return True
return False
if __name__ == "__main__":
if len(sys.argv) > 1:
action = sys.argv[1]
if action == "remove":
removeBgTask()
elif action == "add":
createBgTask()
+23
View File
@@ -0,0 +1,23 @@
#!/bin/bash
export LC_ALL=en_US.UTF-8
export LC_CTYPE=zh_CN.UTF-8
REPOS="$1"
REV="$2"
TXN_NAME="$3"
WEB_PATH={$PROJECT_DIR}/wwwroot/$REPOS
SVN_PATH=http://127.0.0.1:{$PORT}/svn/$REPOS
if [ ! -d $WEB_PATH ]; then
svn co $SVN_PATH $WEB_PATH \
--username={$CSVN_USER} \
--password={$CSVN_PWD} \
--no-auth-cache \
--non-interactive
fi
cd $WEB_PATH && svn update --username={$CSVN_USER} --password={$CSVN_PWD}
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
REPOS="$1"
REV="$2"
TXN_NAME="$3"
REPOS_NAME=${REPOS##*/}
sh -x $REPOS/hooks/commit $REPOS_NAME $REV $TXN_NAME 2>$REPOS/sh.log
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

+37
View File
@@ -0,0 +1,37 @@
<style type="text/css">
.outline_no {
outline:none;
}
</style>
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('csvn');">服务</p>
<p onclick="pluginInitD('csvn');">自启动</p>
<p onclick="csvnEdit();">手动编辑</p>
<p onclick="csvnUserList(1);">用户管理</p>
<p onclick="csvnProjectList(1);">项目管理</p>
<p onclick="csvnReadme();">使用说明</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
</div>
</div>
</div>
<script type="text/javascript">
resetPluginWinWidth(700);
$.getScript( "/plugins/file?name=csvn&f=js/csvn.js");
function csvnReadme(){
var html = '<p>* 注意:在启动时会比较慢,需要耐心等待一会</p>';
html += '<p>* 注意:csvn需要java环境,在安装会自动检查并安装</p>';
html += '<p>* 注意:默认后台密码admin:admin,最好马上修改</p>';
html += '<p>* 注意:牢记admin的密码,在后csvn的管理后台和这里不同步</p>';
html += '<p>* 注意:在这里添加用户和csvn后台并不同步</p>';
html += '<p>* 注意:项目管理的地址一般是正确的,但在特殊环境下,地址可能不一致</p>';
$('.bt-w-main .soft-man-con').html(html);
}
</script>
+692
View File
@@ -0,0 +1,692 @@
# coding: utf-8
import time
import random
import os
import urllib
import binascii
import json
import re
import sys
import subprocess
sys.path.append(os.getcwd() + "/class/core")
import public
app_debug = False
if public.getOs() == 'darwin':
app_debug = True
def getPluginName():
return 'csvn'
def getPluginDir():
return public.getPluginDir() + '/' + getPluginName()
def getServerDir():
return public.getServerDir() + '/' + getPluginName()
def getInitDFile():
if app_debug:
return '/tmp/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def initDreplace():
initd_file = getInitDFile()
if not os.path.exists(initd_file):
return getServerDir()
return initd_file
def status():
data = public.execShell(
"ps -ef|grep " + getPluginName() + " |grep -v grep | grep -v python | awk '{print $2}'")
if data[0] == '':
return 'stop'
return 'start'
def csvnOp(method):
if app_debug:
os_name = public.getOs()
if os_name == 'darwin':
return "Apple Computer does not support"
_initd_csvn = '/etc/init.d/csvn'
_initd_csvn_httpd = '/etc/init.d/csvn-httpd'
#_csvn = getServerDir() + '/bin/csvn'
#_csvn_httpd = getServerDir() + '/bin/csvn-httpd'
ret_csvn_httpd = public.execShell(_initd_csvn_httpd + ' ' + method)
# ret_csvn = public.execShell(_initd_csvn + ' ' + method)
subprocess.Popen(_initd_csvn + ' ' + method,
stdout=subprocess.PIPE, shell=True)
if ret_csvn_httpd[1] == '':
return 'ok'
return 'fail'
def start():
return csvnOp('start')
def stop():
return csvnOp('stop')
def restart():
return csvnOp('restart')
def reload():
return csvnOp('reload')
def initdStatus():
if not app_debug:
if public.getOs() == 'darwin':
return "Apple Computer does not support"
_initd_csvn = '/etc/init.d/csvn'
_initd_csvn_httpd = '/etc/init.d/csvn-httpd'
if os.path.exists(_initd_csvn) and os.path.exists(_initd_csvn_httpd):
return 'ok'
return 'fail'
def initdInstall():
import shutil
if not app_debug:
if public.getOs() == 'darwin':
return "Apple Computer does not support"
_csvn = getServerDir() + '/bin/csvn'
_csvn_httpd = getServerDir() + '/bin/csvn-httpd'
ret_csvn = public.execShell(_csvn + ' install')
ret_csvn_httpd = public.execShell(_csvn_httpd + ' install')
if ret_csvn[1] == '' and ret_csvn_httpd[1] == '':
return 'ok'
return 'fail'
def initdUinstall():
if not app_debug:
if public.getOs() == 'darwin':
return "Apple Computer does not support"
_csvn = getServerDir() + '/bin/csvn'
_csvn_httpd = getServerDir() + '/bin/csvn-httpd'
ret_csvn = public.execShell(_csvn + ' remove')
ret_csvn_httpd = public.execShell(_csvn_httpd + ' remove')
return 'ok'
def csvnEdit():
data = {}
data['svn_access_file'] = getServerDir() + '/data/conf/svn_access_file'
data['commit_tpl'] = getPluginDir() + '/hook/commit.tpl'
data['post_commit_tpl'] = getPluginDir() + '/hook/post-commit.tpl'
return public.getJson(data)
def userAdd():
args = getArgs()
if not 'username' in args:
return 'name missing'
if not 'password' in args:
return 'password missing'
htpasswd = getServerDir() + "/bin/htpasswd"
svn_auth_file = getServerDir() + "/data/conf/svn_auth_file"
cmd = htpasswd + ' -b ' + svn_auth_file + ' ' + \
args['username'] + ' ' + args['password']
data = public.execShell(cmd)
# print data
if data[0] == '':
return 'ok'
return 'fail'
def userDel():
args = getArgs()
if not 'username' in args:
return 'name missing'
htpasswd = getServerDir() + "/bin/htpasswd"
svn_auth_file = getServerDir() + "/data/conf/svn_auth_file"
cmd = htpasswd + ' -D ' + svn_auth_file + ' ' + args['username']
data = public.execShell(cmd)
if data[0] == '':
return 'ok'
return 'fail'
def getAllUser(search=''):
svn_auth_file = getServerDir() + '/data/conf/svn_auth_file'
if not os.path.exists(svn_auth_file):
return public.getJson([])
auth = public.readFile(svn_auth_file)
auth = auth.strip()
auth_list = auth.split("\n")
ulist = []
for x in range(len(auth_list)):
tmp = auth_list[x].split(':')
if search != '':
if tmp[0].find(search) != -1:
ulist.append(tmp[0])
else:
ulist.append(tmp[0])
return ulist
def userList():
import math
args = getArgs()
page = 1
page_size = 10
search = ''
if 'page' in args:
page = int(args['page'])
if 'page_size' in args:
page_size = int(args['page_size'])
if 'search' in args:
search = args['search']
ulist = getAllUser(search)
ulist_sum = len(ulist)
page_info = {'count': ulist_sum, 'p': page,
'row': 10, 'tojs': 'csvnUserList'}
data = {}
data['list'] = public.getPage(page_info)
data['page'] = page
data['page_size'] = page_size
data['page_count'] = int(math.ceil(ulist_sum / page_size))
start = (page - 1) * page_size
data['data'] = ulist[start:start + page_size]
return public.getJson(data)
def projectAdd():
args = getArgs()
if not 'name' in args:
return 'project name missing'
path = getServerDir() + '/bin/svnadmin'
dest = getServerDir() + '/data/repositories/' + args['name']
cmd = path + ' create ' + dest
data = public.execShell(cmd)
if data[1] == '':
public.execShell('chown -R csvn:csvn ' + dest)
return 'ok'
return 'fail'
def projectDel():
args = getArgs()
if not 'name' in args:
return 'project name missing'
dest = getServerDir() + '/data/repositories/' + args['name']
cmd = 'rm -rf ' + dest
data = public.execShell(cmd)
if data[0] == '':
return 'ok'
return 'fail'
def getHttpPort():
http_main_conf = getServerDir() + '/data/conf/csvn_main_httpd.conf'
try:
if os.path.exists(http_main_conf):
content = public.readFile(http_main_conf)
return re.search('Listen\s(\d+)', content).groups()[0]
except Exception as e:
pass # print e
return '80'
def getCsvnPort():
http_main_conf = getServerDir() + '/data/conf/csvn-wrapper.conf'
try:
if os.path.exists(http_main_conf):
content = public.readFile(http_main_conf)
return re.search('wrapper.java.additional.3=-Djetty.port=(\d+)', content).groups()[0]
except Exception as e:
pass # print e
return '3343'
def getALlProjectList(search=''):
path = getServerDir() + '/data/repositories'
dlist = []
if os.path.exists(path):
for filename in os.listdir(path):
tmp = {}
filePath = path + '/' + filename
if os.path.isdir(filePath):
if search == '':
tmp['name'] = filename
dlist.append(tmp)
else:
if filename.find(search) != -1:
tmp['name'] = filename
dlist.append(tmp)
return dlist
def checkProjectListIsHasScript(data):
dlen = len(data)
for x in range(dlen):
path = getServerDir() + '/data/repositories/' + \
data[x]['name'] + '/hooks/post-commit'
if os.path.exists(path):
data[x]['has_hook'] = True
else:
data[x]['has_hook'] = False
return data
def projectList():
import math
args = getArgs()
page = 1
page_size = 10
search = ''
if 'page' in args:
page = int(args['page'])
if 'page_size' in args:
page_size = int(args['page_size'])
if 'search' in args:
search = args['search']
dlist = getALlProjectList(search)
dlist_sum = len(dlist)
start = (page - 1) * page_size
ret_data = dlist[start:start + page_size]
ret_data = checkProjectListIsHasScript(ret_data)
data = {}
data['data'] = ret_data
data['list'] = public.getPage(
{'count': dlist_sum, 'p': page, 'row': 10, 'tojs': 'csvnProjectList'})
data['ip'] = public.getLocalIp()
data['port'] = getHttpPort()
data['csvn_port'] = getCsvnPort()
return public.getJson(data)
def getAllAclList():
svn_access_file = getServerDir() + '/data/conf/svn_access_file'
aData = public.readFile(svn_access_file)
aData = re.sub('#.*', '', aData)
aData = aData.strip().split('[')[1:]
allAcl = {}
for i in range(len(aData)):
oData = aData[i].strip().split(']')
name = oData[0].strip('/').strip(':')
if oData[1] == '':
allAcl[name] = []
else:
user = oData[1].strip().split('\n')
userAll = []
for iu in range(len(user)):
ulist = user[iu].split('=')
utmp = {}
utmp['user'] = ulist[0].strip()
utmp['acl'] = ulist[1].strip()
userAll.append(utmp)
allAcl[name] = userAll
return allAcl
def makeAclFile(content):
# print content
svn_access_file = getServerDir() + '/data/conf/svn_access_file'
tmp = "\n"
for k, v in content.items():
if k == '':
tmp += "[/]\n"
else:
tmp += "[" + k + ":/]\n"
for iv in range(len(v)):
tmp += v[iv]['user'] + ' = ' + v[iv]['acl'] + "\n"
tmp += "\n"
# svn_tmp_path = getServerDir() + '/data/conf/svn_access_file.log'
return public.writeFile(svn_access_file, tmp)
def projectAclList():
args = getArgs()
if not 'name' in args:
return 'name missing!'
name = args['name']
acl = getAllAclList()
if name in acl:
return public.getJson(acl[name])
else:
return 'fail'
def projectAclAdd():
args = getArgs()
if not 'uname' in args:
return 'username missing'
if not 'pname' in args:
return 'project name missing'
uname = args['uname']
pname = args['pname']
ulist = getAllUser()
if not uname in ulist:
return uname + " user not exists!"
acl = getAllAclList()
tmp_acl = {'user': uname, 'acl': 'rw'}
if not pname in acl:
acl[pname] = [tmp_acl]
makeAclFile(acl)
return 'ok'
tmp = acl[pname]
tmp_len = len(tmp)
if tmp_len == 0:
acl[pname] = [tmp_acl]
else:
is_have = False
for x in range(tmp_len):
if tmp[x]['user'] == uname:
is_have = True
return uname + ' users already exist!'
if not is_have:
tmp.append(tmp_acl)
acl[pname] = tmp
makeAclFile(acl)
return 'ok'
def projectAclDel():
args = getArgs()
if not 'uname' in args:
return 'username missing'
if not 'pname' in args:
return 'project name missing'
uname = args['uname']
pname = args['pname']
ulist = getAllUser()
if not uname in ulist:
return uname + " user not exists!"
acl = getAllAclList()
if not pname in acl:
return 'project not exists!'
tmp = acl[pname]
tmp_len = len(tmp)
if tmp_len == 0:
return 'project no have user:' + uname
else:
is_have = False
rtmp = []
for x in range(tmp_len):
if tmp[x]['user'] != uname:
rtmp.append(tmp[x])
acl[pname] = rtmp
makeAclFile(acl)
return 'ok'
def projectAclSet():
args = getArgs()
if not 'uname' in args:
return 'username missing'
if not 'pname' in args:
return 'project name missing'
if not 'acl' in args:
return 'acl missing'
uname = args['uname']
pname = args['pname']
up_acl = args['acl']
ulist = getAllUser()
if not uname in ulist:
return uname + " user not exists!"
acl = getAllAclList()
if not pname in acl:
return 'project not exists!'
tmp = acl[pname]
tmp_len = len(tmp)
if tmp_len == 0:
return 'project no have user:' + uname
else:
is_have = False
for x in range(tmp_len):
if tmp[x]['user'] == uname:
tmp[x]['acl'] = up_acl
acl[pname] = tmp
makeAclFile(acl)
return 'ok'
def getCsvnUser():
user = 'admin_sync'
acl = getAllAclList()
if '' in acl:
tmp = acl['']
is_has = False
for data in tmp:
if data['user'] == user:
is_has = True
if not is_has:
tmp.append({'user': user, 'acl': 'r'})
acl[''] = tmp
makeAclFile(acl)
return user
def getCsvnPwd(user):
if app_debug:
return user + '123'
pwd_file = 'data/csvn_sync.pl'
if os.path.exists(pwd_file):
return public.readFile(pwd_file).strip()
import time
cur_time = time.time()
rand_pwd = public.md5(str(cur_time))
pwd = user + rand_pwd[:5]
htpasswd = getServerDir() + "/bin/htpasswd"
svn_auth_file = getServerDir() + "/data/conf/svn_auth_file"
cmd = htpasswd + ' -b ' + svn_auth_file + ' ' + user + ' ' + pwd
data = public.execShell(cmd)
public.writeFile(pwd_file, pwd)
return pwd
def projectScriptLoad():
args = getArgs()
if not 'pname' in args:
return 'project name missing'
post_commit_tpl = getPluginDir() + '/hook/post-commit.tpl'
hook_path = getServerDir() + '/data/repositories/' + \
args['pname'] + '/hooks'
post_commit_file = hook_path + '/post-commit'
pct_content = public.readFile(post_commit_tpl)
public.writeFile(post_commit_file, pct_content)
public.execShell('chmod 777 ' + post_commit_file)
commit_tpl = getPluginDir() + '/hook/commit.tpl'
commit_file = hook_path + '/commit'
ct_content = public.readFile(commit_tpl)
ct_content = ct_content.replace('{$PROJECT_DIR}', public.getRootDir())
ct_content = ct_content.replace('{$PORT}', getHttpPort())
ct_content = ct_content.replace('{$CSVN_USER}', getCsvnUser())
ct_content = ct_content.replace('{$CSVN_PWD}', getCsvnPwd(getCsvnUser()))
public.writeFile(commit_file, ct_content)
public.execShell('chmod 777 ' + commit_file)
return 'ok'
def projectScriptUnload():
args = getArgs()
if not 'pname' in args:
return 'project name missing'
post_commit_file = getServerDir() + '/data/repositories/' + '/' + \
args['pname'] + '/hooks/post-commit'
public.execShell('rm -f ' + post_commit_file)
commit_file = getServerDir() + '/data/repositories/' + '/' + \
args['pname'] + '/hooks/commit'
public.execShell('rm -f ' + commit_file)
return 'ok'
def projectScriptEdit():
args = getArgs()
if not 'pname' in args:
return 'project name missing'
data = {}
commit_file = getServerDir() + '/data/repositories/' + \
args['pname'] + '/hooks/commit'
if os.path.exists(commit_file):
data['status'] = True
data['path'] = commit_file
else:
data['status'] = False
data['msg'] = 'file does not exist'
return public.getJson(data)
def projectScriptDebug():
args = getArgs()
if not 'pname' in args:
return 'project name missing'
data = {}
commit_log = getServerDir() + '/data/repositories/' + \
args['pname'] + '/sh.log'
if os.path.exists(commit_log):
data['status'] = True
data['path'] = commit_log
else:
data['status'] = False
data['msg'] = 'file does not exist'
return public.getJson(data)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print status()
elif func == 'start':
print start()
elif func == 'stop':
print stop()
elif func == 'restart':
print restart()
elif func == 'reload':
print reload()
elif func == 'initd_status':
print initdStatus()
elif func == 'initd_install':
print initdInstall()
elif func == 'initd_uninstall':
print initdUinstall()
elif func == 'csvn_edit':
print csvnEdit()
elif func == 'user_list':
print userList()
elif func == 'user_add':
print userAdd()
elif func == 'user_del':
print userDel()
elif func == 'project_list':
print projectList()
elif func == 'project_del':
print projectDel()
elif func == 'project_add':
print projectAdd()
elif func == 'project_acl_list':
print projectAclList()
elif func == 'project_acl_add':
print projectAclAdd()
elif func == 'project_acl_del':
print projectAclDel()
elif func == 'project_acl_set':
print projectAclSet()
elif func == 'project_script_load':
print projectScriptLoad()
elif func == 'project_script_unload':
print projectScriptUnload()
elif func == 'project_script_edit':
print projectScriptEdit()
elif func == 'project_script_debug':
print projectScriptDebug()
else:
print 'fail'
+16
View File
@@ -0,0 +1,16 @@
{
"sort": 7,
"ps": "最流行的SVN代码共享管理软件",
"shell": "install.sh",
"name": "csvn",
"title": "CSVN",
"versions": "5.1",
"updates":"5.1.4",
"tip": "soft",
"checks": "server/csvn",
"author": "midoks",
"date": "2017-04-01",
"home": "https://www.collab.net",
"type": "SVN代码共享管理软件",
"pid": "3"
}
+58
View File
@@ -0,0 +1,58 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/bt_install.pl
CSVN_SOURCE='https://github.com/midoks/mdserver-web/releases/download/init/CollabNetSubversionEdge-5.1.4_linux-x86_64.tar.xz'
Install_csvn()
{
mkdir -p $serverPath/source
echo '正在安装脚本文件...' > $install_tmp
if [ ! -f $serverPath/source/csvn.tar.xz ];then
wget -O $serverPath/source/csvn.tar.xz ${CSVN_SOURCE}
fi
cd $serverPath/source && tar -Jxf $serverPath/source/csvn.tar.xz
mv $serverPath/source/csvn $serverPath/csvn
echo '5.1' > $serverPath/csvn/version.pl
if id -u csvn > /dev/null 2>&1; then
echo "csvn user exists"
else
useradd csvn
cp /etc/sudoers{,.`date +"%Y-%m-%d_%H-%M-%S"`}
echo "csvn ALL=(ALL) ALL" >> /etc/sudoers
fi
chown -R csvn:csvn $serverPath/csvn
# $serverPath/csvn/bin/csvn install
# $serverPath/csvn/bin/csvn-httpd install
echo '安装完成' > $install_tmp
}
Uninstall_csvn()
{
rm -rf $serverPath/csvn
}
action=$1
host=$2
if [ "${1}" == 'install' ];then
Install_csvn
else
Uninstall_csvn
fi
+504
View File
@@ -0,0 +1,504 @@
pluginService('csvn');
function csvnPost(method,args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'csvn', func:method, args:JSON.stringify(args)}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function csvnEdit(){
csvnPost('csvn_edit',{} , function(data){
// console.log(data);
var rdata = $.parseJSON(data.data);
var edit = '<p class="status">通用的手动编辑:</p>';
edit +='<div class="sfm-opt">\
<button class="btn btn-default btn-sm" onclick="onlineEditFile(0,\''+rdata['svn_access_file']+'\');">权限编辑</button>\
<button class="btn btn-default btn-sm" onclick="onlineEditFile(0,\''+rdata['post_commit_tpl']+'\');">post_commit_tpl</button>\
<button class="btn btn-default btn-sm" onclick="onlineEditFile(0,\''+rdata['commit_tpl']+'\');">commit_tpl</button>\
</div>';
$(".soft-man-con").html(edit);
});
}
function csvnUserFind(){
var search = $('#csvn_find_user').val();
if (search==''){
layer.msg('搜索字符不能为空!',{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
csvnUserList(1, search);
}
function csvnUserList(page, search) {
var _data = {};
if (typeof(page) =='undefined'){
var page = 1;
}
_data['page'] = page;
_data['page_size'] = 10;
if(typeof(search) != 'undefined'){
_data['search'] = search;
}
csvnPost('user_list', _data, function(data){
var rdata = $.parseJSON(data.data);
// console.log(rdata);
content = '<div class="finduser"><input class="bt-input-text mr5 outline_no" type="text" placeholder="查找用户名" id="csvn_find_user" style="height: 28px; border-radius: 3px;width: 505px;">';
content += '<button class="btn btn-success btn-sm" onclick="csvnUserFind();">查找</button></div>';
content += '<div class="divtable" style="margin-top:5px;"><table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">';
content += '<thead><tr>';
content += '<th>用户名</th>';
content += '<th>操作(<a class="btlink" onclick="csvnAddUser();">添加</a>)</th>';
content += '</tr></thead>';
content += '<tbody>';
ulist = rdata.data;
for (i in ulist){
content += '<tr><td>'+ulist[i]+'</td><td>'+
'<a class="btlink" onclick="csvnDelUser(\''+ulist[i]+'\')">删除</a> | ' +
'<a class="btlink" onclick="csvnModPwdUser(\''+ulist[i]+'\')">改密</a></td></tr>';
}
content += '</tbody>';
content += '</table></div>';
page = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="softPage" class="page"><div>';
page += rdata.list;
page += '</div></ul></div>';
content += page;
$(".soft-man-con").html(content);
});
}
function csvnDelUser(name){
var loadOpen = layer.open({
type: 1,
title: '删除用户',
area: '350px',
content:"<div class='bt-form pd20 pb70 c6'>\
<div class='version line'>你要确认要删除"+ name + "账户?</div>\
<div class='bt-form-submit-btn'>\
<button type='button' id='csvn_del_close' class='btn btn-danger btn-sm btn-title'>关闭</button>\
<button type='button' id='csvn_del_ok' class='btn btn-success btn-sm btn-title bi-btn'>确认</button>\
</div>\
</div>"
});
$('#csvn_del_close').click(function(){
layer.close(loadOpen);
});
$('#csvn_del_ok').click(function(){
_data = {};
_data['username'] = name;
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'csvn', func:'user_del', args:JSON.stringify(_data)}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if (data.data !='ok'){
layer.msg(data.data,{icon:2,time:2000,shade: [0.3, '#000']});
}
layer.close(loadOpen);
layer.msg("删除成功!",{icon:1,time:3000,shade: [0.3, '#000']});
},'json');
});
}
function csvnAddUser(username){
user_input = ''
if (typeof(username) == 'undefined'){
user_input = "<div><input class='bt-input-text mr5 outline_no' type='text' id='csvn_username' name='username' style='height: 28px; border-radius: 3px;width: 200px;' placeholder='输入用户名'></div>";
} else {
user_input = "<div><input value='"+ username +"' class='bt-input-text mr5 outline_no' type='text' id='csvn_username' name='username' style='height: 28px; border-radius: 3px;width: 200px;' disabled='true'></div>";
}
var loadOpen = layer.open({
type: 1,
title: '添加用户',
area: '240px',
content:"<div class='bt-form pd20 pb70 c6'>\
<div class='version line'>\
"+user_input+"\
<div style='padding-top:3px;'><input class='bt-input-text mr5 outline_no' type='text' id='csvn_password' name='password' style='height: 28px; border-radius: 3px;width: 200px;' placeholder='输入密码'></div>\
</div>\
<div class='bt-form-submit-btn'>\
<button type='button' id='csvn_add_close' class='btn btn-danger btn-sm btn-title'>关闭</button>\
<button type='button' id='csvn_add_ok' class='btn btn-success btn-sm btn-title bi-btn'>确认</button>\
</div>\
</div>"
});
$('#csvn_add_close').click(function(){
layer.close(loadOpen);
});
$('#csvn_add_ok').click(function(){
_data = {};
_data['username'] = $('#csvn_username').val();
_data['password'] = $('#csvn_password').val();
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'csvn', func:'user_add', args:JSON.stringify(_data)}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if (data.data !='ok'){
layer.msg(data.data,{icon:2,time:2000,shade: [0.3, '#000']});
}
csvnUserList();
layer.close(loadOpen);
layer.msg("操作成功!",{icon:1,time:3000,shade: [0.3, '#000']});
},'json');
});
}
function csvnModPwdUser(name){
csvnAddUser(name);
}
function csvnProjectFind(){
var search = $('#csvn_project_find').val();
if (search == ''){
layer.msg('查找字符不能为空!',{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
csvnProjectList(1, search);
}
function csvnProjectList(page, search){
var _data = {};
_data['page_size'] = 10;
if (typeof(search) != 'undefined'){
_data['search'] = search;
}
if (typeof(page) != 'undefined'){
_data['page'] = page;
setCookie('csvnProjectListPage',page);
} else {
_data['page'] = 1;
cookie_page = getCookie('csvnProjectListPage')
if (cookie_page >0){
_data['page'] = cookie_page;
}
}
csvnPost('project_list', _data, function(data){
var rdata = $.parseJSON($.trim(data.data));
var csvn_mg = project_url = 'http://' +rdata['ip'] +(rdata['csvn_port'] == '80' ? '': ':'+rdata['csvn_port']);
content = '<div><input class="bt-input-text mr5" type="text" placeholder="查找项目" id="csvn_project_find" style="height: 28px; border-radius: 3px;width: 505px;">';
content += '<button class="btn btn-success btn-sm" onclick="csvnProjectFind();">查找</button></div>';
content += '<div class="divtable" style="margin-top:5px;"><table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">';
content += '<thead><tr>';
content += '<th>项目名</th>';
content += '<th>地址</th>';
content += '<th>操作(<a class="btlink" onclick="csvnAddProject();">添加</a>) | <a class="btlink" target="_blank" href="'+csvn_mg+'">后台管理</a> </th>';
content += '</tr></thead>';
content += '<tbody>';
// console.log(rdata);
ulist = rdata.data;
for (i in ulist){
var project_url = 'http://' +rdata['ip'] +(rdata['port'] == '80' ? '': ':'+rdata['port'])+ '/svn/'+ulist[i]['name'];
var code_url = 'http://' +rdata['ip'] +(rdata['port'] == '80' ? '': ':'+rdata['port'])+ '/viewvc/'+ulist[i]['name'];
content += '<tr><td>'+ulist[i]['name']+'</td>'+
'<td>'+project_url+'</td><td>'+
'<a class="btlink" onclick="csvnDelProject(\''+ulist[i]['name']+'\')">删除</a> | ' +
'<a class="btlink" onclick="csvnAclProject(\''+ulist[i]['name']+'\')">权限</a> | ' +
'<a class="btlink" target="_blank" href="' + code_url +'">源码</a> | ' +
'<a class="btlink" onclick="csvnProjectScript(\''+ulist[i]['name']+'\','+ ulist[i]['has_hook']+')">脚本</a>' +
'</td></tr>';
}
content += '</tbody>';
content += '</table></div>';
page = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="softPage" class="page"><div>';
page += rdata.list;
page += '</div></ul></div>';
content += page;
$(".soft-man-con").html(content);
});
}
function csvnDelProject(name){
var loadOpen = layer.open({
type: 1,
title: '删除用户',
area: '350px',
content:"<div class='bt-form pd20 pb70 c6'>\
<div class='version line'>你要确认要删除"+ name + "账户?</div>\
<div class='bt-form-submit-btn'>\
<button type='button' id='csvn_del_close' class='btn btn-danger btn-sm btn-title'>关闭</button>\
<button type='button' id='csvn_del_ok' class='btn btn-success btn-sm btn-title bi-btn'>确认</button>\
</div>\
</div>"
});
$('#csvn_del_close').click(function(){
layer.close(loadOpen);
});
$('#csvn_del_ok').click(function(){
var _data = {};
_data['name'] = name;
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'csvn', func:'project_del', args:JSON.stringify(_data)}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if (data.data !='ok'){
layer.msg(data.data,{icon:2,time:2000,shade: [0.3, '#000']});
return;
}
csvnProjectList();
layer.close(loadOpen);
layer.msg("删除成功!",{icon:1,time:3000,shade: [0.3, '#000']});
},'json');
});
}
function csvnAddProject(){
var loadOpen = layer.open({
type: 1,
title: '添加项目',
area: '240px',
content:"<div class='bt-form pd20 pb70 c6'>\
<div class='version line'>\
<div><input class='bt-input-text mr5 outline_no' type='text' id='csvn_name' name='username' style='height: 28px; border-radius: 3px;width: 200px;' placeholder='输入项目名'></div>\
</div>\
<div class='bt-form-submit-btn'>\
<button type='button' id='csvn_project_close' class='btn btn-danger btn-sm btn-title'>关闭</button>\
<button type='button' id='csvn_project_ok' class='btn btn-success btn-sm btn-title bi-btn'>确认</button>\
</div>\
</div>"
});
$('#csvn_project_close').click(function(){
layer.close(loadOpen);
});
$('#csvn_project_ok').click(function(){
var _data = {};
_data['name'] = $('#csvn_name').val();
csvnPost('project_add', _data, function(data){
if (data.data !='ok'){
layer.msg(data.data,{icon:2,time:2000,shade: [0.3, '#000']});
return;
}
csvnProjectList();
layer.close(loadOpen);
layer.msg("操作成功!",{icon:1,time:3000,shade: [0.3, '#000']});
});
});
}
function csvnProjectScript(pnanm, has_hook){
var html = '';
if (has_hook){
html += '<button onclick="csvnProjectScriptEdit(\''+pnanm+'\')" class="btn btn-default btn-sm">手动编辑</button>';
html += '<button onclick="csvnProjectScriptDebug(\''+pnanm+'\')" class="btn btn-default btn-sm">调试日志</button>';
html += '<button onclick="csvnProjectScriptLoad(\''+pnanm+'\')" class="btn btn-default btn-sm">重新加载</button>';
html += '<button onclick="csvnProjectScriptUnload(\''+pnanm+'\')" class="btn btn-default btn-sm">卸载脚本</button>';
} else {
html += '<button onclick="csvnProjectScriptLoad(\''+pnanm+'\')" class="btn btn-default btn-sm">加载脚本</button>';
}
var loadOpen = layer.open({
type: 1,
title: '脚本设置',
area: '240px',
content:'<div class="change-default pd20">'+html+'</div>'
});
}
function csvnProjectScriptLoad(pname){
csvnPost('project_script_load', {'pname':pname}, function(data){
if (data.data != 'ok'){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
layer.msg('加载成功!',{icon:1,time:2000,shade: [0.3, '#000']});
setTimeout(function(){
$('.layui-layer-close1').click();
csvnProjectList();
},2000);
});
}
function csvnProjectScriptUnload(pname){
csvnPost('project_script_unload', {'pname':pname}, function(data){
if (data.data != 'ok'){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
layer.msg('卸载成功!',{icon:1,time:2000,shade: [0.3, '#000']});
setTimeout(function(){
$('.layui-layer-close1').click();
csvnProjectList();
},2000);
});
}
function csvnProjectScriptEdit(pname){
csvnPost('project_script_edit', {'pname':pname}, function(data){
var rdata = $.parseJSON(data.data);
if (rdata['status']){
onlineEditFile(0, rdata['path']);
$('.layui-layer-close1').click();
csvnProjectList();
} else {
layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']});
}
});
}
function csvnProjectScriptDebug(pname){
csvnPost('project_script_debug', {'pname':pname}, function(data){
var rdata = $.parseJSON(data.data);
if (rdata['status']){
onlineEditFile(0, rdata['path']);
$('.layui-layer-close1').click();
csvnProjectList();
} else {
layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']});
}
});
}
function csvnAclAdd(pname){
var uname = $('#csvn_username').val();
if (uname == ''){
layer.msg('添加用户名不能为空!',{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
csvnPost('project_acl_add', {'pname':pname,'uname':uname}, function(data){
if (data.data != 'ok'){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
$('.layui-layer-close1').click();
csvnAclProject(pname);
});
}
function csvnAclDel(pname, uname){
csvnPost('project_acl_del', {'pname':pname,'uname':uname}, function(data){
if (data.data != 'ok'){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
$('.layui-layer-close1').click();
csvnAclProject(pname);
});
}
function csvnAclSet(obj, pname, uname, acl, selected){
if (selected){
$(obj).prop('checked',true);
layer.msg('权限没有变化!',{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
csvnPost('project_acl_set', {'pname':pname,'uname':uname, 'acl':acl}, function(data){
if (data.data != 'ok'){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
$('.layui-layer-close1').click();
csvnAclProject(pname);
});
}
function csvnAclProject(pname){
csvnPost('project_acl_list', {'name':pname}, function(data){
var rdata = [];
try {
rdata = $.parseJSON(data.data);
} catch(e){}
var list = '';
for (i in rdata) {
var user = rdata[i]['user'];
var acl = '';
if (rdata[i]['acl'] == 'r'){
acl += '<input type="checkbox" onclick="csvnAclSet(this,\''+pname+'\',\''+user+'\',\'r\',true)" checked="true"> 只读 | <input type="checkbox" onclick="csvnAclSet(this,\''+pname+'\',\''+user+'\',\'rw\', false)"> 读写';
} else {
acl += '<input type="checkbox" onclick="csvnAclSet(this,\''+pname+'\',\''+user+'\',\'r\',false)"> 只读 | <input type="checkbox" onclick="csvnAclSet(this,\''+pname+'\',\''+user+'\',\'rw\',true)" checked="true"> 读写';
}
list += '<tr><td>'+user+'</td><td>' + acl +'</td>'+
'<td><a class="btlink" onclick="csvnAclDel(\''+pname+'\',\''+user+'\')">删除</a></td>'+'</tr>';
}
var loadOpen = layer.open({
type: 1,
title: '项目('+pname+')权限设置',
area: '300px',
content:"<div class='bt-form pd20 c6'>\
<div>\
<div><input class='bt-input-text mr5 outline_no' type='text' id='csvn_username' name='username' style='height: 28px; border-radius: 3px;width: 205px;' placeholder='用户名'>\
<button class='btn btn-success btn-sm' onclick='csvnAclAdd(\""+pname+"\");'>添加</button></div>\
<div class='divtable' style='margin-top:5px;'><table class='table table-hover'><thead><tr><th>用户</th><th>权限</th><th>操作</th></tr></thead>\
<tbody>"+list+"</tbody>\
</table></div>\
</div>\
</div>"
});
});
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

+23
View File
@@ -0,0 +1,23 @@
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="readme();">插件说明</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con">
</div>
</div>
</div>
</div>
<script type="text/javascript">
function readme() {
$('.bt-w-main .soft-man-con').hide();
$('.bt-w-main .v0').show();
}
//../google-cloud-sdk/bin/gcloud app deploy << y
</script>
+20
View File
@@ -0,0 +1,20 @@
# coding: utf-8
import time
import random
import os
import json
import re
import sys
sys.path.append(os.getcwd() + "/class/core")
import public
def status():
return 'start'
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print status()
+14
View File
@@ -0,0 +1,14 @@
{
"title":"GAE",
"tip":"soft",
"name":"gae",
"ps":"GAE 英文全称为 Google App Engine。它是 Google 管理的数据中心中用于 WEB 应用程序的开发和托管的平台",
"versions": "0.1",
"shell":"install.sh",
"checks":"server/gae",
"path":"server/gae",
"author":"mdserver-web",
"home":"https://github.com/midoks/mdserver-web",
"date":"2018-11-30",
"pid":"5"
}
+51
View File
@@ -0,0 +1,51 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/bt_install.pl
Install_gae()
{
mkdir -p ${serverPath}/gae
mkdir -p ${serverPath}/source/gae
os=`uname`
if [ "Darwin" == "$os" ];then
file=google-cloud-sdk-218.0.0-darwin-x86_64.tar.gz
else
file=google-cloud-sdk-218.0.0-linux-x86_64.tar.gz
fi
if [ ! -f $serverPath/source/gae/$file ];then
wget -O $serverPath/source/gae/$file https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/$file
fi
if [ ! -d $serverPath/source/gae/google-cloud-sdk ];then
cd $serverPath/source/gae && tar zxvf $file
fi
cp -r $serverPath/source/gae/google-cloud-sdk ${serverPath}/gae
echo "${1}" > ${serverPath}/gae/version.pl
echo '安装完成' > $install_tmp
}
Uninstall_gae()
{
rm -rf ${serverPath}/gae
echo '卸载完成' > $install_tmp
}
action=$1
if [ "${1}" == 'install' ];then
Install_gae $2
else
Uninstall_gae $2
fi
-49
View File
@@ -1,49 +0,0 @@
#!/bin/bash
echo `date`
GITADDR="{$GITROOTURL}/{$USERNAME}/{$PROJECT}.git"
GIT_SDIR="{$CODE_DIR}"
GIT_USER_DIR="${GIT_SDIR}/{$USERNAME}"
GIT_PROJECT_DIR="${GIT_USER_DIR}/{$PROJECT}"
git config --global credential.helper store
git config --global pull.rebase false
# echo $GIT_PROJECT_DIR
if [ ! -d $GIT_PROJECT_DIR ];then
mkdir -p $GIT_USER_DIR && cd $GIT_USER_DIR
git clone $GITADDR
fi
unset GIT_DIR
cd $GIT_PROJECT_DIR && git pull
# func 2
# cd $GIT_PROJECT_DIR && env -i git pull origin master
#更新的目的地址
WEB_PATH={$WEB_ROOT}/{$USERNAME}/{$PROJECT}
if [ ! -d $WEB_PATH ];then
mkdir -p $WEB_PATH
rsync -vauP --delete --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
else
if [ -f $GIT_PROJECT_DIR/exclude.list ];then
rsync -vauP --delete --exclude-from="$GIT_PROJECT_DIR/exclude.list" $GIT_PROJECT_DIR/ $WEB_PATH
else
rsync -vauP --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
fi
fi
sysName=`uname`
if [ $sysName == 'Darwin' ]; then
USER=$(who | sed -n "2,1p" |awk '{print $1}')
chown -R $USER:staff $WEB_PATH
else
chown -R www:www $WEB_PATH
fi
-38
View File
@@ -1,38 +0,0 @@
#!/bin/bash
echo `date`
GITADDR="{$GITROOTURL}/{$USERNAME}/{$PROJECT}"
GIT_SDIR="{$CODE_DIR}"
GIT_USER_DIR="${GIT_SDIR}/{$USERNAME}"
GIT_PROJECT_DIR="${GIT_USER_DIR}/{$PROJECT}"
# echo $GIT_PROJECT_DIR
if [ ! -d $GIT_PROJECT_DIR ];then
mkdir -p $GIT_USER_DIR && cd $GIT_USER_DIR
git clone $GITADDR
fi
unset GIT_DIR
git config pull.rebase false
cd $GIT_PROJECT_DIR && git pull
# func 2
# cd $GIT_PROJECT_DIR && env -i git pull origin master
WEB_PATH={$WEB_ROOT}/{$USERNAME}/{$PROJECT}
mkdir -p $WEB_PATH
rsync -vauP --delete --exclude=".*" $GIT_PROJECT_DIR/ $WEB_PATH
sysName=`uname`
if [ $sysName == 'Darwin' ]; then
USER=$(who | sed -n "2,1p" |awk '{print $1}')
chown -R $USER:staff $WEB_PATH
else
chown -R www:www $WEB_PATH
fi
-3
View File
@@ -1,3 +0,0 @@
#!/bin/bash
sh -x {$PATH}/commit 2>{$PATH}/sh.log
Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

-24
View File
@@ -1,24 +0,0 @@
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('gitea');">服务</p>
<p onclick="pluginInitD('gitea');">自启动</p>
<!-- <p onclick="pluginConfig('gitea',null, 'init_conf');">启动配置</p> -->
<p onclick="gogsEdit();">手动编辑</p>
<p onclick="pluginConfig('gitea',null, 'conf');">配置文件</p>
<p onclick="gogsSetConfig();">配置修改</p>
<p onclick="giteaUserList();">用户列表</p>
<!-- <p onclick="pluginLogs('gitea',null,'run_log');">运行日志</p> -->
<!-- <p onclick="pluginLogs('gitea',null,'post_receive_log');" title="提交post-receive日志">提交日志</p> -->
<p onclick="giteaRead();">使用说明</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
</div>
</div>
</div>
<script type="text/javascript">
$.getScript( "/plugins/file?name=gitea&f=js/gitea.js",function(){
pluginService('gitea');
});
</script>
-767
View File
@@ -1,767 +0,0 @@
# coding: utf-8
import time
import os
import sys
import re
sys.path.append(os.getcwd() + "/class/core")
import mw
# cmd = 'ls /usr/local/lib/ | grep python | cut -d \\ -f 1 | awk \'END {print}\''
# info = mw.execShell(cmd)
# p = "/usr/local/lib/" + info[0].strip() + "/site-packages"
# sys.path.append(p)
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'gitea'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getInitDFile():
if app_debug:
return '/tmp/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':', 1)
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':', 1)
tmp[t[0]] = t[1]
return tmp
def checkArgs(data, ck=[]):
for i in range(len(ck)):
if not ck[i] in data:
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
return (True, mw.returnJson(True, 'ok'))
def getInitdConfTpl():
path = getPluginDir() + "/init.d/gitea.tpl"
return path
def getInitdConf():
path = getServerDir() + "/init.d/gitea"
return path
def getConf():
path = getServerDir() + "/custom/conf/app.ini"
if not os.path.exists(path):
return mw.returnJson(False, "请先安装初始化!<br/>默认地址:http://" + mw.getLocalIp() + ":3000")
return path
def getConfTpl():
path = getPluginDir() + "/conf/app.ini"
return path
def status():
data = mw.execShell(
"ps -ef|grep " + getPluginName() + " |grep -v grep | grep -v python | awk '{print $2}'")
if data[0] == '':
return 'stop'
return 'start'
def getHomeDir():
if mw.isAppleSystem():
user = mw.execShell(
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
return '/Users/' + user
else:
return 'www'
def getRunUser():
if mw.isAppleSystem():
user = mw.execShell(
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
return user
else:
return 'www'
__SR = '''#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
export USER=%s
export HOME=%s && ''' % ( getRunUser(), getHomeDir())
def contentReplace(content):
service_path = mw.getServerDir()
content = content.replace('{$ROOT_PATH}', mw.getRootDir())
content = content.replace('{$SERVER_PATH}', service_path)
content = content.replace('{$RUN_USER}', getRunUser())
content = content.replace('{$HOME_DIR}', getHomeDir())
return content
def initDreplace():
file_tpl = getInitdConfTpl()
service_path = mw.getServerDir()
git_dir = mw.getServerDir() + '/git'
if not os.path.exists(git_dir):
mw.execShell('mkdir -p ' + git_dir)
initD_path = getServerDir() + '/init.d'
if not os.path.exists(initD_path):
os.mkdir(initD_path)
file_bin = initD_path + '/' + getPluginName()
if not os.path.exists(file_bin):
content = mw.readFile(file_tpl)
content = contentReplace(content)
mw.writeFile(file_bin, content)
mw.execShell('chmod +x ' + file_bin)
# systemd
systemDir = mw.systemdCfgDir()
systemService = systemDir + '/gitea.service'
systemServiceTpl = getPluginDir() + '/init.d/gitea.service.tpl'
if os.path.exists(systemDir) and not os.path.exists(systemService):
service_path = mw.getServerDir()
se_content = mw.readFile(systemServiceTpl)
se_content = se_content.replace('{$SERVER_PATH}', service_path)
mw.writeFile(systemService, se_content)
mw.execShell('systemctl daemon-reload')
log_path = getServerDir() + '/log'
if not os.path.exists(log_path):
os.mkdir(log_path)
return file_bin
def getRootUrl():
content = mw.readFile(getConf())
rep = 'ROOT_URL\s*=\s*(.*)'
tmp = re.search(rep, content)
if tmp:
return tmp.groups()[0]
rep = 'EXTERNAL_URL\s*=\s*(.*)'
tmp = re.search(rep, content)
if tmp:
return tmp.groups()[0]
return ''
def getSshPort():
content = mw.readFile(getConf())
rep = 'SSH_PORT\s*=\s*(.*)'
tmp = re.search(rep, content)
if not tmp:
return ''
return tmp.groups()[0]
def getHttpPort():
content = mw.readFile(getConf())
rep = 'HTTP_PORT\s*=\s*(.*)'
tmp = re.search(rep, content)
if not tmp:
return ''
return tmp.groups()[0]
def getRootPath():
content = mw.readFile(getConf())
rep = 'ROOT\s*=\s*(.*)'
tmp = re.search(rep, content)
if not tmp:
return ''
return tmp.groups()[0]
def getDbConfValue():
conf = getConf()
if not os.path.exists(conf):
return {}
content = mw.readFile(conf)
rep_scope = "\[database\](.*?)\["
tmp = re.findall(rep_scope, content, re.S)
rep = '(\w*)\s*=\s*(.*)'
tmp = re.findall(rep, tmp[0])
r = {}
for x in range(len(tmp)):
k = tmp[x][0]
v = tmp[x][1]
r[k] = v
return r
def pMysqlDb(conf):
host = conf['HOST'].split(':')
# pymysql
db = mw.getMyORM()
# MySQLdb |
# db = mw.getMyORMDb()
db.setPort(int(host[1]))
db.setUser(conf['USER'])
if 'PASSWD' in conf:
db.setPwd(conf['PASSWD'])
else:
db.setPwd(conf['PASSWORD'])
db.setDbName(conf['NAME'])
# db.setSocket(getSocketFile())
db.setCharset("utf8")
return db
def pSqliteDb(conf):
# print(conf)
import db
psDb = db.Sql()
# 默认
gsdir = getServerDir() + '/data'
dbname = 'gitea'
if conf['PATH'][0] == '/':
# 绝对路径
pass
else:
path = conf['PATH'].split('/')
gsdir = getServerDir() + '/' + path[0]
dbname = path[1].split('.')[0]
# print(gsdir, dbname)
psDb.dbPos(gsdir, dbname)
return psDb
def getGiteaDbType(conf):
if 'DB_TYPE' in conf:
return conf['DB_TYPE']
if 'TYPE' in conf:
return conf['TYPE']
return 'NONE'
def pQuery(sql):
conf = getDbConfValue()
gtype = getGiteaDbType(conf)
if gtype == 'sqlite3':
db = pSqliteDb(conf)
data = db.query(sql, []).fetchall()
return data
elif gtype == 'mysql':
db = pMysqlDb(conf)
return db.query(sql)
print("仅支持mysql|sqlite3配置")
exit(0)
def isSqlError(mysqlMsg):
# 检测数据库执行错误
_mysqlMsg = str(mysqlMsg)
# print _mysqlMsg
if "MySQLdb" in _mysqlMsg:
return mw.returnData(False, 'MySQLdb组件缺失! <br>进入SSH命令行输入: pip install mysql-python')
if "2002," in _mysqlMsg:
return mw.returnData(False, '数据库连接失败,请检查数据库服务是否启动!')
if "using password:" in _mysqlMsg:
return mw.returnData(False, '数据库管理密码错误!')
if "Connection refused" in _mysqlMsg:
return mw.returnData(False, '数据库连接失败,请检查数据库服务是否启动!')
if "1133," in _mysqlMsg:
return mw.returnData(False, '数据库用户不存在!')
if "1007," in _mysqlMsg:
return mw.returnData(False, '数据库已经存在!')
if "1044," in _mysqlMsg:
return mw.returnData(False, mysqlMsg[1])
if "2003," in _mysqlMsg:
return mw.returnData(False, "Can't connect to MySQL server on '127.0.0.1' (61)")
return mw.returnData(True, 'OK')
def appOp(method):
file = initDreplace()
if not mw.isAppleSystem():
data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
if data[1] == '':
return 'ok'
return 'fail'
data = mw.execShell(__SR + file + ' ' + method)
if data[1] == '':
return 'ok'
return data[0]
def start():
return appOp('start')
def stop():
return appOp('stop')
def restart():
return appOp('restart')
def reload():
return appOp('reload')
def initdStatus():
if mw.isAppleSystem():
return "Apple Computer does not support"
shell_cmd = 'systemctl status gitea | grep loaded | grep "enabled;"'
data = mw.execShell(shell_cmd)
if data[0] == '':
return 'fail'
return 'ok'
def initdInstall():
if mw.isAppleSystem():
return "Apple Computer does not support"
mw.execShell('systemctl enable gitea')
return 'ok'
def initdUinstall():
if mw.isAppleSystem():
return "Apple Computer does not support"
mw.execShell('systemctl disable gitea')
return 'ok'
def runLog():
log_path = getServerDir() + '/log/gitea.log'
return log_path
def postReceiveLog():
log_path = getServerDir() + '/log/hooks/post-receive.log'
return log_path
def getGogsConf():
conf = getConf()
if not os.path.exists(conf):
return mw.returnJson(False, "请先安装初始化!<br/>默认地址:http://" + mw.getLocalIp() + ":3000")
gets = [
{'name': 'DOMAIN', 'type': -1, 'ps': '服务器域名'},
{'name': 'ROOT_URL', 'type': -1, 'ps': '公开的完整URL路径'},
{'name': 'HTTP_ADDR', 'type': -1, 'ps': '应用HTTP监听地址'},
{'name': 'HTTP_PORT', 'type': -1, 'ps': '应用 HTTP 监听端口号'},
{'name': 'START_SSH_SERVER', 'type': 2, 'ps': '启动内置SSH服务器'},
{'name': 'SSH_PORT', 'type': -1, 'ps': 'SSH 端口号'},
{'name': 'REQUIRE_SIGNIN_VIEW', 'type': 2, 'ps': '强制登录浏览'},
{'name': 'ENABLE_CAPTCHA', 'type': 2, 'ps': '启用验证码服务'},
{'name': 'DISABLE_REGISTRATION', 'type': 2, 'ps': '禁止注册,只能由管理员创建帐号'},
{'name': 'ENABLE_NOTIFY_MAIL', 'type': 2, 'ps': '是否开启邮件通知'},
{'name': 'FORCE_PRIVATE', 'type': 2, 'ps': '强制要求所有新建的仓库都是私有'},
{'name': 'SHOW_FOOTER_BRANDING', 'type': 2, 'ps': 'Gogs推广信息'},
{'name': 'SHOW_FOOTER_VERSION', 'type': 2, 'ps': 'Gogs版本信息'},
{'name': 'SHOW_FOOTER_TEMPLATE_LOAD_TIME', 'type': 2, 'ps': 'Gogs模板加载时间'},
]
conf = mw.readFile(conf)
result = []
for g in gets:
rep = g['name'] + '\s*=\s*(.*)'
tmp = re.search(rep, conf)
if not tmp:
continue
g['value'] = tmp.groups()[0]
result.append(g)
return mw.returnJson(True, 'OK', result)
def submitGogsConf():
gets = ['DOMAIN',
'ROOT_URL',
'HTTP_ADDR',
'HTTP_PORT',
'START_SSH_SERVER',
'SSH_PORT',
'REQUIRE_SIGNIN_VIEW',
'FORCE_PRIVATE',
'ENABLE_CAPTCHA',
'DISABLE_REGISTRATION',
'ENABLE_NOTIFY_MAIL',
'SHOW_FOOTER_BRANDING',
'SHOW_FOOTER_VERSION',
'SHOW_FOOTER_TEMPLATE_LOAD_TIME']
args = getArgs()
filename = getConf()
conf = mw.readFile(filename)
for g in gets:
if g in args:
rep = g + '\s*=\s*(.*)'
val = g + ' = ' + args[g]
conf = re.sub(rep, val, conf)
mw.writeFile(filename, conf)
restart()
return mw.returnJson(True, '设置成功')
def userList():
conf = getConf()
if not os.path.exists(conf):
return mw.returnJson(False, "请先安装初始化!<br/>默认地址:http://" + mw.getLocalIp() + ":3000")
conf = getDbConfValue()
gtype = getGiteaDbType(conf)
if gtype != 'mysql':
return mw.returnJson(False, "仅支持mysql数据操作!")
import math
args = getArgs()
data = checkArgs(args, ['page', 'page_size'])
if not data[0]:
return data[1]
page = int(args['page'])
page_size = int(args['page_size'])
tojs = args['tojs']
search = ''
if 'search' in args:
search = args['search']
data = {}
data['root_url'] = getRootUrl()
start = (page - 1) * page_size
list_count = pQuery('select count(id) as num from user')
count = list_count[0]["num"]
list_data = pQuery(
'select id,name,email from user order by id desc limit ' + str(start) + ',' + str(page_size))
data['list'] = mw.getPage(
{'count': count, 'p': page, 'row': page_size, 'tojs': tojs})
data['page'] = page
data['page_size'] = page_size
data['page_count'] = int(math.ceil(count / page_size))
data['data'] = list_data
return mw.returnJson(True, 'OK', data)
def getAllUserProject(user, search=''):
path = getRootPath() + '/' + user
dlist = []
if os.path.exists(path):
for filename in os.listdir(path):
tmp = {}
filePath = path + '/' + filename
if os.path.isdir(filePath):
if search == '':
tmp['name'] = filename.replace('.git', '')
dlist.append(tmp)
else:
if filename.find(search) != -1:
tmp['name'] = filename.replace('.git', '')
dlist.append(tmp)
return dlist
def checkProjectListIsHasScript(user, data):
path = getRootPath() + '/' + user
for x in range(len(data)):
name = data[x]['name'] + '.git'
path_tmp = path + '/' + name + '/hooks/post-receive.d/post-receive'
if os.path.exists(path_tmp):
data[x]['has_hook'] = True
else:
data[x]['has_hook'] = False
return data
def userProjectList():
import math
args = getArgs()
# print args
page = 1
page_size = 5
search = ''
if not 'name' in args:
return mw.returnJson(False, '缺少参数name')
if 'page' in args:
page = int(args['page'])
if 'page_size' in args:
page_size = int(args['page_size'])
if 'search' in args:
search = args['search']
data = {}
ulist = getAllUserProject(args['name'])
dlist_sum = len(ulist)
start = (page - 1) * page_size
ret_data = ulist[start:start + page_size]
ret_data = checkProjectListIsHasScript(args['name'], ret_data)
data['root_url'] = getRootUrl()
data['data'] = ret_data
data['args'] = args
data['list'] = mw.getPage(
{'count': dlist_sum, 'p': page, 'row': page_size, 'tojs': 'userProjectListPost'})
return mw.returnJson(True, 'OK', data)
def projectScriptEdit():
args = getArgs()
if not 'user' in args:
return mw.returnJson(True, 'username missing')
if not 'name' in args:
return mw.returnJson(True, 'project name missing')
user = args['user']
name = args['name'] + '.git'
post_receive = getRootPath() + '/' + user + '/' + name + \
'/custom_hooks/commit'
if os.path.exists(post_receive):
return mw.returnJson(True, 'OK', {'path': post_receive})
else:
return mw.returnJson(False, 'file does not exist')
def projectScriptLoad():
args = getArgs()
if not 'user' in args:
return mw.returnJson(True, 'username missing')
if not 'name' in args:
return mw.returnJson(True, 'project name missing')
user = args['user']
name = args['name'] + '.git'
path = getRootPath() + '/' + user + '/' + name
post_receive_tpl = getPluginDir() + '/hook/post-receive.tpl'
post_receive = path + '/hooks/post-receive.d/post-receive'
if not os.path.exists(path + '/custom_hooks'):
mw.execShell('mkdir -p ' + path + '/custom_hooks')
mw.execShell('chown -R www:www ' + path + '/custom_hooks')
pct_content = mw.readFile(post_receive_tpl)
pct_content = pct_content.replace('{$PATH}', path + '/custom_hooks')
mw.writeFile(post_receive, pct_content)
mw.execShell('chmod 777 ' + post_receive)
mw.execShell('chown -R www:www ' + post_receive)
commit_tpl = getPluginDir() + '/hook/commit.tpl'
commit = path + '/custom_hooks/commit'
codeDir = mw.getRootDir() + '/git'
cc_content = mw.readFile(commit_tpl)
gitPath = getRootPath()
cc_content = cc_content.replace('{$GITROOTURL}', gitPath)
cc_content = cc_content.replace('{$CODE_DIR}', codeDir)
cc_content = cc_content.replace('{$USERNAME}', user)
cc_content = cc_content.replace('{$PROJECT}', args['name'])
cc_content = cc_content.replace('{$WEB_ROOT}', mw.getWwwDir())
mw.writeFile(commit, cc_content)
mw.execShell('chmod 777 ' + commit)
mw.execShell('chown -R www:www ' + commit)
return 'ok'
def projectScriptUnload():
args = getArgs()
data = checkArgs(args, ['user', 'name'])
if not data[0]:
return data[1]
user = args['user']
name = args['name'] + '.git'
post_receive = getRootPath() + '/' + user + '/' + name + \
'/hooks/post-receive.d/post-receive'
mw.execShell('rm -f ' + post_receive)
commit = getRootPath() + '/' + user + '/' + name + \
'/custom_hooks/commit'
mw.execShell('rm -f ' + commit)
return 'ok'
def projectScriptDebug():
args = getArgs()
data = checkArgs(args, ['user', 'name'])
if not data[0]:
return data[1]
user = args['user']
name = args['name'] + '.git'
commit_log = getRootPath() + '/' + user + '/' + name + \
'/custom_hooks/sh.log'
data = {}
if os.path.exists(commit_log):
data['status'] = True
data['path'] = commit_log
else:
data['status'] = False
data['msg'] = '没有日志文件'
return mw.getJson(data)
def gogsEdit():
data = {}
data['post_receive'] = getPluginDir() + '/hook/post-receive.tpl'
data['commit'] = getPluginDir() + '/hook/commit.tpl'
return mw.getJson(data)
def getRsaPublic():
path = getHomeDir()
path += '/.ssh/id_rsa.pub'
content = mw.readFile(path)
data = {}
data['mw'] = content
return mw.getJson(data)
def getTotalStatistics():
st = status()
data = {}
if st.strip() == 'start':
list_count = pQuery('select count(id) as num from repository')
count = list_count[0]["num"]
data['status'] = True
data['count'] = count
data['ver'] = mw.readFile(getServerDir() + '/version.pl').strip()
return mw.returnJson(True, 'ok', data)
data['status'] = False
data['count'] = 0
return mw.returnJson(False, 'fail', data)
def uninstallPreInspection():
repo_dir = getServerDir() + "/data/gitea-repositories"
if not os.path.exists(repo_dir):
return 'ok'
dir_list = os.listdir(repo_dir)
if len(dir_list) > 0:
return "有项目数据!请手动删除Gitea<br/> rm -rf {}".format(getServerDir())
return 'ok'
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print(status())
elif func == 'start':
print(start())
elif func == 'stop':
print(stop())
elif func == 'restart':
print(restart())
elif func == 'reload':
print(reload())
elif func == 'initd_status':
print(initdStatus())
elif func == 'initd_install':
print(initdInstall())
elif func == 'initd_uninstall':
print(initdUinstall())
elif func == 'uninstall_pre_inspection':
print(uninstallPreInspection())
elif func == 'run_log':
print(runLog())
elif func == 'post_receive_log':
print(postReceiveLog())
elif func == 'conf':
print(getConf())
elif func == 'init_conf':
print(getInitdConf())
elif func == 'get_gogs_conf':
print(getGogsConf())
elif func == 'submit_gogs_conf':
print(submitGogsConf())
elif func == 'user_list':
print(userList())
elif func == 'user_project_list':
print(userProjectList())
elif func == 'project_script_edit':
print(projectScriptEdit())
elif func == 'project_script_load':
print(projectScriptLoad())
elif func == 'project_script_unload':
print(projectScriptUnload())
elif func == 'project_script_debug':
print(projectScriptDebug())
elif func == 'gogs_edit':
print(gogsEdit())
elif func == 'get_rsa_public':
print(getRsaPublic())
elif func == 'get_total_statistics':
print(getTotalStatistics())
else:
print('fail')
-18
View File
@@ -1,18 +0,0 @@
{
"ps": "Gitea 是一个开源社区驱动的轻量级代码托管解决方案。",
"name": "gitea",
"title": "Gitea",
"versions": ["1.17.2"],
"tip": "soft",
"install_pre_inspection":false,
"uninstall_pre_inspection":true,
"checks": "server/gitea",
"path":"server/gitea",
"author": "gitea",
"date": "2022-10-03",
"home": "https://dl.gitea.io/",
"type": "Git服务器",
"shell": "install.sh",
"pid": "3",
"sort": 7
}
-20
View File
@@ -1,20 +0,0 @@
[Unit]
Description=Gitea (Git with a cup of tea)
After=syslog.target
After=network.target
[Service]
RestartSec=2s
Type=simple
User=www
Group=www
WorkingDirectory={$SERVER_PATH}/gitea
ExecStart={$SERVER_PATH}/gitea/gitea web
Restart=always
Environment=USER=www HOME=/home/www GITEA_WORK_DIR={$SERVER_PATH}/gitea
RemainAfterExit=yes
#AmbientCapabilities=CAP_NET_BIND_SERVICE
#CapabilityBoundingSet=CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
-110
View File
@@ -1,110 +0,0 @@
#!/bin/sh
#
# /etc/rc.d/init.d/Gitea
#
# Runs the Gogs
#
#
# chkconfig: - 85 15
#
### BEGIN INIT INFO
# Provides: Gitea
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Should-Start: mysql postgresql
# Should-Stop: mysql postgresql
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start Gitea at boot time.
# Description: Control Gitea.
### END INIT INFO
# Source function library.
if [ -f /etc/init.d/functions ];then
. /etc/init.d/functions
fi
if [ -f /etc/rc.d/init.d/functions ];then
. /etc/rc.d/init.d/functions
fi
# Default values
export HOME={$HOME_DIR}
export USER={$RUN_USER}
NAME=gitea
GOGS_HOME={$SERVER_PATH}/gitea
GOGS_PATH=${GOGS_HOME}/$NAME
GOGS_USER={$RUN_USER}
SERVICENAME="gitea"
LOCKFILE=/tmp/gitea.lock
LOGPATH=${GOGS_HOME}/log
LOGFILE=${LOGPATH}/gitea.log
RETVAL=0
[ -r /etc/sysconfig/$NAME ] && . /etc/sysconfig/$NAME
DAEMON_OPTS="--check $NAME"
[ ! -z "$GOGS_USER" ] && DAEMON_OPTS="$DAEMON_OPTS --user=${GOGS_USER}"
status(){
isStart=`ps -ef|grep 'gitea web' |grep -v grep|awk '{print $2}'`
if [ "$isStart" == '' ];then
echo -e "${SERVICENAME} not running"
else
echo -e "${SERVICENAME}(pid $(echo $isStart)) already running"
fi
}
start() {
isStart=`ps -ef|grep 'gitea web' |grep -v grep|awk '{print $2}'`
if [ "$isStart" != '' ];then
echo "${SERVICENAME}(pid $(echo $isStart)) already running"
return $RETVAL
fi
cd ${GOGS_HOME}
echo -e "Starting ${SERVICENAME}: \c"
${GOGS_PATH} web > ${LOGFILE} 2>&1 &
RETVAL=$?
[ $RETVAL = 0 ] && touch ${LOCKFILE} && echo -e "\033[32mdone\033[0m"
return $RETVAL
}
stop() {
pids=`ps -ef|grep 'gitea web' |grep -v grep|awk '{print $2}'`
arr=($pids)
echo -e "Stopping gitea... \c"
for p in ${arr[@]}
do
kill -9 $p
done
echo -e "\033[32mdone\033[0m"
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
stop
start
;;
reload)
stop
start
;;
*)
echo "Usage: ${NAME} {start|stop|status|restart}"
exit 1
;;
esac
exit $RETVAL
-128
View File
@@ -1,128 +0,0 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
install_tmp=${rootPath}/tmp/mw_install.pl
if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi
URL_DOWNLOAD=https://dl.gitea.io/
bash ${rootPath}/scripts/getos.sh
OSNAME=`cat ${rootPath}/data/osname.pl`
OSNAME_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
getBit(){
echo `getconf LONG_BIT`
}
Install_Rsync(){
if [ "$OSNAME" == "debian" ] || [ "$OSNAME" == "ubuntu" ];then
apt install -y rsync
elif [[ "$OSNAME" == "arch" ]]; then
echo y | pacman -Sy rsync
elif [[ "$OSNAME" == "macos" ]]; then
# brew install rsync
# brew install lsyncd
echo "ok"
else
yum install -y rsync
fi
}
Install_App()
{
Install_Rsync
mkdir -p $serverPath/source/gitea
if id www &> /dev/null ;then
echo "www uid is `id -u www`"
echo "www shell is `grep "^www:" /etc/passwd |cut -d':' -f7 `"
else
groupadd www
useradd -g www www
fi
if [ "macos" != "$OSNAME" ];then
if [ ! -d /home/www ];then
mkdir -p /home/www
chown -R www:www /home/www
fi
fi
echo '正在安装脚本文件...' > $install_tmp
version=$1
git config --global push.default simple
if [ "macos" == "$OSNAME" ];then
file=gitea-${version}-darwin-10.12-amd64
else
file=gitea-${version}-linux-amd64
fi
file_xz="${file}.xz"
echo "wget -O $serverPath/source/gitea/$file_xz ${URL_DOWNLOAD}/gitea/${version}/${file_xz}"
if [ ! -f $serverPath/source/gitea/$file_xz ];then
wget --no-check-certificate -O $serverPath/source/gitea/$file_xz ${URL_DOWNLOAD}/gitea/${version}/${file_xz}
fi
cd $serverPath/source/gitea && xz -k -d $file_xz
if [ -f $file ];then
mkdir -p $serverPath/gitea
mv $serverPath/source/gitea/$file $serverPath/gitea/gitea
chmod +x $serverPath/gitea/gitea
chown -R www:www $serverPath/gitea
fi
if [ -d $serverPath/gitea ];then
echo $version > $serverPath/gitea/version.pl
cd ${rootPath} && python3 plugins/gitea/index.py start
cd ${rootPath} && python3 plugins/gitea/index.py initd_install
fi
echo 'install success' > $install_tmp
}
Uninstall_App()
{
if [ -f /usr/lib/systemd/system/gitea.service ];then
systemctl stop gitea
systemctl disable gitea
rm -rf /usr/lib/systemd/system/gitea.service
systemctl daemon-reload
fi
if [ -f $serverPath/gitea/initd/gitea ];then
$serverPath/gitea/initd/gitea stop
fi
rm -rf $serverPath/gitea
echo 'uninstall success' > $install_tmp
}
action=$1
version=$2
if [ "${1}" == 'install' ];then
Install_App $version
else
Uninstall_App $version
fi
-370
View File
@@ -1,370 +0,0 @@
function gogsPost(method,args,callback, title){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
var _title = '正在获取...';
if (typeof(title) != 'undefined'){
_title = title;
}
var loadT = layer.msg(_title, { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'gitea', func:method, args:_args}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function gogsSetConfig(){
gogsPost('get_gogs_conf', '', function(data){
var rrdata = $.parseJSON(data.data);
if (!rrdata.status){
layer.msg(rrdata.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
var rdata = rrdata.data;
var mlist = '';
for (var i = 0; i < rdata.length; i++) {
var w = '140';
if (rdata[i].name == 'error_reporting') w = '250';
var ibody = '<input style="width: ' + w + 'px;" class="bt-input-text mr5" name="' + rdata[i].name + '" value="' + rdata[i].value + '" type="text" >';
switch (rdata[i].type) {
case 0:
var selected_1 = (rdata[i].value == 1) ? 'selected' : '';
var selected_0 = (rdata[i].value == 0) ? 'selected' : '';
ibody = '<select class="bt-input-text mr5" name="' + rdata[i].name + '" style="width: ' + w + 'px;">\
<option value="1" ' + selected_1 + '>开启</option>\
<option value="0" ' + selected_0 + '>关闭</option>\
</select>';
break;
case 1:
var selected_1 = (rdata[i].value == 'On') ? 'selected' : '';
var selected_0 = (rdata[i].value == 'Off') ? 'selected' : '';
ibody = '<select class="bt-input-text mr5" name="' + rdata[i].name + '" style="width: ' + w + 'px;">\
<option value="On" ' + selected_1 + '>开启</option>\
<option value="Off" ' + selected_0 + '>关闭</option></select>'
break;
case 2:
var selected_1 = (rdata[i].value == 'true') ? 'selected' : '';
var selected_0 = (rdata[i].value == 'false') ? 'selected' : '';
ibody = '<select class="bt-input-text mr5" name="' + rdata[i].name + '" style="width: ' + w + 'px;">\
<option value="true" ' + selected_1 + '>开启</option>\
<option value="false" ' + selected_0 + '>关闭</option></select>'
break;
}
mlist += '<p><span>' + rdata[i].name + '</span>' + ibody + ', <font>' + rdata[i].ps + '</font></p>'
}
var html = '<style>.conf_p p{margin-bottom: 2px}</style><div class="conf_p" style="margin-bottom:0">\
' + mlist + '\
<div style="margin-top:10px; padding-right:15px" class="text-right">\
<button class="btn btn-success btn-sm mr5" onclick="gogsSetConfig()">刷新</button>\
<button class="btn btn-success btn-sm" onclick="submitGogsConf()">保存</button></div>\
</div>';
$(".soft-man-con").html(html);
});
}
//提交PHP配置
function submitGogsConf() {
var data = {
DOMAIN: $("input[name='DOMAIN']").val(),
ROOT_URL: $("input[name='ROOT_URL']").val(),
HTTP_ADDR: $("select[name='HTTP_ADDR']").val(),
HTTP_PORT: $("input[name='HTTP_PORT']").val(),
START_SSH_SERVER: $("select[name='START_SSH_SERVER']").val() || 'false',
SSH_PORT: $("input[name='SSH_PORT']").val(),
REQUIRE_SIGNIN_VIEW: $("select[name='REQUIRE_SIGNIN_VIEW']").val() || 'false',
ENABLE_CAPTCHA: $("select[name='ENABLE_CAPTCHA']").val() || 'true',
DISABLE_REGISTRATION: $("select[name='DISABLE_REGISTRATION']").val() || 'false',
ENABLE_NOTIFY_MAIL: $("select[name='ENABLE_NOTIFY_MAIL']").val() || 'false',
FORCE_PRIVATE: $("select[name='FORCE_PRIVATE']").val() || 'false',
SHOW_FOOTER_BRANDING: $("select[name='SHOW_FOOTER_BRANDING']").val() || 'false',
SHOW_FOOTER_VERSION: $("select[name='SHOW_FOOTER_VERSION']").val() || 'false',
SHOW_FOOTER_TEMPLATE_LOAD_TIME: $("select[name='SHOW_FOOTER_TEMPLATE_LOAD_TIME']").val() || 'false',
};
gogsPost('submit_gogs_conf', data, function(ret_data){
var rdata = $.parseJSON(ret_data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
gogsSetConfig();
});
}
function gogsEdit(){
gogsPost('gogs_edit',{} , function(data){
// console.log(data);
var rdata = $.parseJSON(data.data);
var edit = '<p class="status">通用的手动编辑:</p>';
edit +='<div class="sfm-opt">\
<button class="btn btn-default btn-sm" onclick="onlineEditFile(0,\''+rdata['post_receive']+'\');">post-receive.tpl</button>\
<button class="btn btn-default btn-sm" onclick="onlineEditFile(0,\''+rdata['commit']+'\');">commit.tpl</button>\
</div>';
$(".soft-man-con").html(edit);
});
}
function giteaUserList(page, search) {
var _data = {};
if (typeof(page) =='undefined'){
var page = 1;
}
_data['page'] = page;
_data['page_size'] = 10;
if(typeof(search) != 'undefined'){
_data['search'] = search;
}
_data['tojs'] = 'giteaUserList';
gogsPost('user_list', _data, function(data){
var rdata = $.parseJSON(data.data);
if (!rdata.status){
layer.msg(rdata.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
content = '<div class="finduser"><input class="bt-input-text mr5 outline_no" type="text" placeholder="查找用户名" id="find_user" style="height: 28px; border-radius: 3px;width: 435px;">';
content += '<button class="btn btn-success btn-sm" onclick="userFind();">查找</button></div>';
content += '<div class="divtable" style="margin-top:5px;"><table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">';
content += '<thead><tr>';
content += '<th>序号</th>';
content += '<th>用户或组织</th>';
content += '<th>邮件地址</th>';
content += '<th>操作(<a href="'+rdata['data']['root_url']+'" class="btlink" target="_blank">WEB管理</a>)</th>';
content += '</tr></thead>';
content += '<tbody>';
ulist = rdata['data']['data'];
for (i in ulist){
email = ulist[i]["email"] == '' ? '无' : ulist[i]["email"];
content += '<tr><td>'+ulist[i]["id"]+'</td>'+
'<td>'+ulist[i]["name"]+'</td>'+
'<td>'+email+'</td>'+
'<td><a class="btlink" onclick="userProjectList(\''+ulist[i]["name"]+'\')">项目管理</a></td>'+
'</tr>';
}
content += '</tbody>';
content += '</table></div>';
var page = '<div class="dataTables_paginate paging_bootstrap pagination" style="margin-top:0px;"><ul id="softPage" class="page"><div>';
page += rdata['data']['list'];
page += '</div></ul></div>';
content += page;
$(".soft-man-con").html(content);
});
}
function userProjectList(user, search){
var loadOpen = layer.open({
type: 1,
title: '用户('+user+')项目列表',
area: '500px',
content:"<div class='bt-form pd20 c6'>\
<div>\
<div id='gitea_table' class='divtable' style='margin-top:5px;'>\
<table class='table table-hover'>\
<thead><tr><th>项目</th><th>操作</th></tr></thead>\
<tbody></tbody>\
</table>\
<div class='dataTables_paginate paging_bootstrap pagination' style='margin-top:0px;'><ul class='page'><div class='gitea_page'></div></ul></div>\
</div>\
</div>\
</div>",
success:function(){
userProjectListPost(user,search);
}
});
}
function userProjectListPost(user, search){
var req = {};
if (!isNaN(user)){
req['page'] = user;
req['name'] = user = getCookie('gogsUserSelected');
} else {
req['page'] = 1;
req['name'] = user;
setCookie('gogsUserSelected', user);
}
req['page_size'] = 5;
req['search'] = '';
if(typeof(search) != 'undefined'){
req['search'] = search;
}
gogsPost('user_project_list', req, function(data){
var rdata = [];
try {
rdata = $.parseJSON(data.data);
} catch(e){}
if (!rdata['status']){
layer.msg(rdata['msg'], { icon: 2 });
return;
}
var list = '';
// console.log(rdata);
var project_list = rdata['data']['data'];
for (i in project_list) {
var name = project_list[i]['name'];
list += '<tr>\
<td>'+name+'</td>\
<td>\
<a class="btlink" target="_blank" href="'+rdata['data']['root_url']+user+'/'+name+'">源码</a> | \
<a class="btlink" onclick="projectScript(\''+user+'\',\''+name+'\','+project_list[i]['has_hook']+');">脚本</a>\
</td>\
</tr>';
}
$('#gitea_table tbody').html(list);
var page = rdata['data']['list'];
$('#gitea_table .gitea_page').html(page);
});
}
function projectScript(user, name,has_hook){
// console.log(user,name,has_hook);
var html = '';
if (has_hook){
html += '<button class="btn btn-default btn-sm hook_edit">手动编辑</button>';
html += '<button class="btn btn-default btn-sm hook_log">调试日志</button>';
html += '<button class="btn btn-default btn-sm hook_load">重新加载</button>';
html += '<button class="btn btn-default btn-sm hook_unload">卸载脚本</button>';
} else {
html += '<button class="btn btn-default btn-sm hook_load">加载脚本</button>';
}
var loadOpen = layer.open({
type: 1,
title: '['+user+']['+name+']脚本设置',
area: '240px',
content:'<div class="change-default pd20">'+html+'</div>',
success:function(layero,index) {
$('.hook_edit').click(function(){
projectScriptEdit(user,name,index);
});
$('.hook_log').click(function(){
projectScriptDebug(user,name,index);
});
$('.hook_load').click(function(){
projectScriptLoad(user,name,index);
});
$('.hook_unload').click(function(){
projectScriptUnload(user,name,index);
});
}
});
}
function projectScriptEdit(user,name,index){
gogsPost('project_script_edit', {'user':user,'name':name}, function(data){
var rdata = $.parseJSON(data.data);
if (rdata['status']){
onlineEditFile(0, rdata['data']['path']);
} else {
layer.msg(rdata.msg,{icon:1,time:2000,shade: [0.3, '#000']});
}
});
}
function projectScriptLoad(user,name,index){
gogsPost('project_script_load', {'user':user,'name':name}, function(data){
if (data.data != 'ok'){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
showMsg('加载成功!',function(){
layer.close(index);
userProjectListPost(1);
},{icon:1,time:2000,shade: [0.3, '#000']},2000);
});
}
function projectScriptUnload(user,name,index){
gogsPost('project_script_unload', {'user':user,'name':name}, function(data){
if (data.data != 'ok'){
layer.msg(data.data,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
showMsg('卸载成功!',function(){
layer.close(index);
userProjectListPost(1);
},{icon:1,time:2000,shade: [0.3, '#000']},2000);
});
}
function projectScriptDebug(user,name,index){
gogsPost('project_script_debug', {'user':user,'name':name}, function(data){
var rdata = $.parseJSON(data.data);
if (rdata['status']){
onlineEditFile(0, rdata['path']);
} else {
showMsg(rdata.msg,function(){
},{icon:1,time:2000,shade: [0.3, '#000']},2000);
}
});
}
function getRsaPublic(){
gogsPost('get_rsa_public', {}, function(data){
var rdata = $.parseJSON(data.data);
var con = '<div class="tab-con">\
<div class="myKeyCon ptb15">\
<textarea style="margin:0px;width:580px;height:110px;outline:none;" spellcheck="false">'+rdata.mw+'</textarea>\
</div>\
<ul class="help-info-text c7 pull-left"></ul>\
</div>'
layer.open({
type: 1,
area: "600px",
title: '本机公钥',
closeBtn: 2,
shift: 5,
shadeClose: false,
content:con
});
});
}
function giteaRead(){
var readme = '<ul class="help-info-text c7">';
readme += '<li>默认使用MySQL,第一个启动加载各种配置,并修改成正确的数据库配置</li>';
readme += '<li>邮件端口使用456,gogs仅支持使用STARTTLS的SMTP协议</li>';
readme += '<li>如果使用项目中脚本本地同步,<a target="_blank" href="https://github.com/midoks/mdserver-web/wiki/%E6%8F%92%E4%BB%B6%E7%AE%A1%E7%90%86%5Bgogs%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E%5D#%E5%90%AF%E5%8A%A8gogs%E5%90%8E%E5%A6%82%E6%9E%9C%E8%A6%81%E4%BD%BF%E7%94%A8hook%E8%84%9A%E6%9C%AC%E5%90%8C%E6%AD%A5%E4%BB%A3%E7%A0%81%E9%9C%80%E8%A6%81%E5%BC%80%E5%90%AFssh%E7%AB%AF%E5%8F%A3">点击查看</></li>';
readme += '<li><a href="#" onclick="getRsaPublic();">点击查看本机公钥</></li>';
readme += '</ul>';
$('.soft-man-con').html(readme);
}

Some files were not shown because too many files have changed in this diff Show More