You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

500 lines
19 KiB

1 year ago
11 months ago
1 year ago
11 months ago
1 year ago
1 month ago
1 year ago
1 month ago
1 year ago
1 month ago
1 year ago
1 month ago
1 year ago
1 month ago
1 year ago
10 months ago
8 months ago
10 months ago
1 year ago
10 months ago
1 year ago
10 months ago
1 year ago
10 months ago
1 year ago
10 months ago
1 year ago
10 months ago
1 year ago
10 months ago
1 year ago
10 months ago
1 year ago
10 months ago
1 year ago
10 months ago
1 month ago
1 month ago
1 year ago
  1. <?php
  2. namespace app\controller;
  3. use think\facade\Db;
  4. use app\BaseController;
  5. use app\lib\Plugins;
  6. class Api extends BaseController
  7. {
  8. //获取插件列表
  9. public function get_plugin_list(){
  10. if(!$this->checklist()) return json('你的服务器被禁止使用此云端');
  11. $record = Db::name('record')->where('ip',$this->clientip)->find();
  12. if($record){
  13. Db::name('record')->where('id',$record['id'])->update(['usetime'=>date("Y-m-d H:i:s")]);
  14. }else{
  15. Db::name('record')->insert(['ip'=>$this->clientip, 'addtime'=>date("Y-m-d H:i:s"), 'usetime'=>date("Y-m-d H:i:s")]);
  16. }
  17. $json_arr = Plugins::get_plugin_list();
  18. if(!$json_arr) return json((object)[]);
  19. return json($json_arr);
  20. }
  21. //获取插件列表(win)
  22. public function get_plugin_list_win(){
  23. if(!$this->checklist()) return json('你的服务器被禁止使用此云端');
  24. $record = Db::name('record')->where('ip',$this->clientip)->find();
  25. if($record){
  26. Db::name('record')->where('id',$record['id'])->update(['usetime'=>date("Y-m-d H:i:s")]);
  27. }else{
  28. Db::name('record')->insert(['ip'=>$this->clientip, 'addtime'=>date("Y-m-d H:i:s"), 'usetime'=>date("Y-m-d H:i:s")]);
  29. }
  30. $json_arr = Plugins::get_plugin_list('Windows');
  31. if(!$json_arr) return json((object)[]);
  32. return json($json_arr);
  33. }
  34. //下载插件包
  35. public function download_plugin(){
  36. $plugin_name = input('post.name');
  37. $version = input('post.version');
  38. $os = input('post.os');
  39. if(!$plugin_name || !$version){
  40. return '参数不能为空';
  41. }
  42. if(!in_array($os,['Windows','Linux'])) $os = 'Linux';
  43. if(!preg_match('/^[a-zA-Z0-9_]+$/', $plugin_name) || !preg_match('/^[0-9.]+$/', $version)){
  44. return '参数不正确';
  45. }
  46. if(!$this->checklist()) return '你的服务器被禁止使用此云端';
  47. $filepath = get_data_dir($os).'plugins/package/'.$plugin_name.'-'.$version.'.zip';
  48. if(file_exists($filepath)){
  49. $filename = $plugin_name.'.zip';
  50. $this->output_file($filepath, $filename);
  51. }else{
  52. return '云端不存在该插件包';
  53. }
  54. }
  55. //下载插件主文件
  56. public function download_plugin_main(){
  57. $plugin_name = input('post.name');
  58. $version = input('post.version');
  59. $os = input('post.os');
  60. if(!$plugin_name || !$version){
  61. return '参数不能为空';
  62. }
  63. if(!in_array($os,['Windows','Linux'])) $os = 'Linux';
  64. if(!preg_match('/^[a-zA-Z0-9_]+$/', $plugin_name) || !preg_match('/^[0-9.]+$/', $version)){
  65. return '参数不正确';
  66. }
  67. if(!$this->checklist()) return '你的服务器被禁止使用此云端';
  68. $filepath = get_data_dir($os).'plugins/package/'.$plugin_name.'-'.$version.'.zip';
  69. $mainfilepath = get_data_dir($os).'plugins/folder/'.$plugin_name.'-'.$version.'/'.$plugin_name.'/'.$plugin_name.'_main.py';
  70. if(file_exists($mainfilepath)){
  71. $filename = $plugin_name.'_main.py';
  72. $this->output_file($mainfilepath, $filename);
  73. }elseif(file_exists($filepath)){
  74. $zip = new \ZipArchive;
  75. if ($zip->open($filepath) === true){
  76. echo $zip->getFromName($plugin_name.'/'.$plugin_name.'_main.py');
  77. }else{
  78. return '插件包解压缩失败';
  79. }
  80. }else{
  81. return '云端不存在该插件主文件';
  82. }
  83. }
  84. //下载插件其他文件
  85. public function download_plugin_other(){
  86. $fname = input('get.fname');
  87. if(!$fname){
  88. return json(['status'=>false, 'msg'=>'参数不能为空']);
  89. }
  90. if(strpos(dirname($fname),'.')!==false)return json(['status'=>false, 'msg'=>'参数不正确']);
  91. if(!$this->checklist()) return json(['status'=>false, 'msg'=>'你的服务器被禁止使用此云端']);
  92. $filepath = get_data_dir().'plugins/other/'.$fname;
  93. if(file_exists($filepath)){
  94. $filename = basename($fname);
  95. $this->output_file($filepath, $filename);
  96. }else{
  97. return json(['status'=>false, 'msg'=>'云端不存在该插件文件']);
  98. }
  99. }
  100. public function get_update_logs(){
  101. $type = input('get.type');
  102. if($type == 'Windows'){
  103. $version = config_get('new_version_win');
  104. $data = [
  105. [
  106. 'title' => 'Linux面板'.$version,
  107. 'body' => config_get('update_msg_win'),
  108. 'addtime' => config_get('update_date_win')
  109. ]
  110. ];
  111. }else{
  112. $version = config_get('new_version');
  113. $data = [
  114. [
  115. 'title' => 'Linux面板'.$version,
  116. 'body' => config_get('update_msg'),
  117. 'addtime' => config_get('update_date')
  118. ]
  119. ];
  120. }
  121. return jsonp($data);
  122. }
  123. public function get_version(){
  124. $version = config_get('new_version');
  125. return $version;
  126. }
  127. public function get_version_win(){
  128. $version = config_get('new_version_win');
  129. return $version;
  130. }
  131. //安装统计
  132. public function setup_count(){
  133. return 'ok';
  134. }
  135. //检测更新
  136. public function check_update(){
  137. $version = config_get('new_version');
  138. $down_url = request()->root(true).'/install/update/LinuxPanel-'.$version.'.zip';
  139. $data = [
  140. 'force' => false,
  141. 'version' => $version,
  142. 'downUrl' => $down_url,
  143. 'updateMsg' => config_get('update_msg'),
  144. 'uptime' => config_get('update_date'),
  145. 'is_beta' => 0,
  146. 'adviser' => -1,
  147. 'btb' => '',
  148. 'beta' => [
  149. 'version' => $version,
  150. 'downUrl' => $down_url,
  151. 'updateMsg' => config_get('update_msg'),
  152. 'uptime' => config_get('update_date'),
  153. ]
  154. ];
  155. return json($data);
  156. }
  157. //检测更新(win)
  158. public function check_update_win(){
  159. $version = config_get('new_version_win');
  160. $down_url = request()->root(true).'/win/panel/panel_'.$version.'.zip';
  161. $data = [
  162. 'force' => false,
  163. 'version' => $version,
  164. 'downUrl' => $down_url,
  165. 'updateMsg' => config_get('update_msg_win'),
  166. 'uptime' => config_get('update_date_win'),
  167. 'is_beta' => 0,
  168. 'py_version' => '3.8.6',
  169. 'adviser' => -1,
  170. 'is_rec' => -1,
  171. 'btb' => '',
  172. 'beta' => [
  173. 'py_version' => '3.8.6',
  174. 'version' => $version,
  175. 'downUrl' => $down_url,
  176. 'updateMsg' => config_get('update_msg_win'),
  177. 'uptime' => config_get('update_date_win'),
  178. ]
  179. ];
  180. return json($data);
  181. }
  182. //宝塔云监控获取最新版本
  183. public function btm_latest_version(){
  184. $data = [
  185. 'version' => config_get('new_version_btm'),
  186. 'description' => config_get('update_msg_btm'),
  187. 'create_time' => config_get('update_date_btm')
  188. ];
  189. return json($data);
  190. }
  191. //宝塔云监控更新日志
  192. public function btm_update_history(){
  193. $data = [
  194. [
  195. 'version' => config_get('new_version_btm'),
  196. 'description' => config_get('update_msg_btm'),
  197. 'create_time' => config_get('update_date_btm')
  198. ]
  199. ];
  200. return json($data);
  201. }
  202. //宝塔云WAF最新版本
  203. public function btwaf_latest_version(){
  204. $type = input('?post.type') ? input('post.type') : 0;
  205. if($type == 1){
  206. $data = [
  207. 'version' => '1.1',
  208. 'description' => '暂无更新日志',
  209. 'create_time' => 1705315163,
  210. ];
  211. }else{
  212. $data = [
  213. 'version' => '3.0',
  214. 'description' => '暂无更新日志',
  215. 'create_time' => 1705315163,
  216. ];
  217. }
  218. $data = bin2hex(json_encode($data));
  219. return json(['status'=>true,'err_no'=>0,'msg'=>'获取成功','data'=>$data]);
  220. }
  221. //获取内测版更新日志
  222. public function get_beta_logs(){
  223. return json(['beta_ps'=>'当前暂无内测版', 'list'=>[]]);
  224. }
  225. //检查用户绑定是否正确
  226. public function check_auth_key(){
  227. return '1';
  228. }
  229. //从云端验证域名是否可访问
  230. public function check_domain(){
  231. $domain = input('post.domain',null,'trim');
  232. $ssl = input('post.ssl/d');
  233. if(!$domain) return json(['status'=>false, 'msg'=>'域名不能为空']);
  234. if(!strpos($domain,'.')) return json(['status'=>false, 'msg'=>'域名格式不正确']);
  235. $domain = str_replace('*.','',$domain);
  236. $ip = gethostbyname($domain);
  237. if(!$ip || $ip == $domain){
  238. return json(['status'=>false, 'msg'=>'无法访问']);
  239. }else{
  240. return json(['status'=>true, 'msg'=>'访问正常']);
  241. }
  242. }
  243. //同步时间
  244. public function get_time(){
  245. return time();
  246. }
  247. //同步时间
  248. public function get_win_date(){
  249. return date("Y-m-d H:i:s");
  250. }
  251. //查询是否专业版(废弃)
  252. public function is_pro(){
  253. return json(['endtime'=>true, 'code'=>1]);
  254. }
  255. //获取产品推荐信息
  256. public function get_plugin_remarks(){
  257. return json(['list'=>[], 'pro_list'=>[], 'kfqq'=>'', 'kf'=>'', 'qun'=>'']);
  258. }
  259. //获取指定插件评分
  260. public function get_plugin_socre(){
  261. return json(['total'=>0, 'split'=>[0,0,0,0,0],'page'=>"<div><span class='Pcurrent'>1</span><span class='Pcount'>共计0条数据</span></div>",'data'=>[]]);
  262. }
  263. //提交插件评分
  264. public function plugin_score(){
  265. return json(['status'=>true, 'msg'=>'您的评分已成功提交,感谢您的支持!']);
  266. }
  267. //获取IP地址
  268. public function get_ip_address(){
  269. return $this->clientip;
  270. }
  271. //绑定账号
  272. public function get_auth_token(){
  273. if(!input('?post.data')) return json(['status'=>false, 'msg'=>'参数不能为空']);
  274. $reqData = hex2bin(input('post.data'));
  275. parse_str($reqData, $arr);
  276. $serverid = $arr['serverid'];
  277. $userinfo = ['uid'=>1, 'username'=>'Administrator', 'address'=>'127.0.0.1', 'serverid'=>$serverid, 'access_key'=>random(48), 'secret_key'=>random(48), 'ukey'=>md5(time()), 'state'=>1];
  278. $data = bin2hex(json_encode($userinfo));
  279. return json(['status'=>true, 'msg'=>'登录成功!', 'data'=>$data]);
  280. }
  281. //绑定账号新
  282. public function authorization_login(){
  283. if(!input('?post.data')) return json(['status'=>false, 'msg'=>'参数不能为空']);
  284. $reqData = hex2bin(input('post.data'));
  285. parse_str($reqData, $arr);
  286. $serverid = $arr['serverid'];
  287. $userinfo = ['uid'=>1, 'username'=>'Administrator', 'ip'=>'127.0.0.1', 'server_id'=>$serverid, 'access_key'=>random(48), 'secret_key'=>random(48)];
  288. $data = bin2hex(json_encode($userinfo));
  289. return json(['status'=>true, 'err_no'=>0, 'msg'=>'账号绑定成功', 'data'=>$data]);
  290. }
  291. //刷新授权信息
  292. public function authorization_info(){
  293. if(!input('?post.data')) return json(['status'=>false, 'msg'=>'参数不能为空']);
  294. $reqData = hex2bin(input('post.data'));
  295. parse_str($reqData, $arr);
  296. $id = isset($arr['id'])&&$arr['id']>0?$arr['id']:1;
  297. $userinfo = ['id'=>$id, 'product'=>$arr['product'], 'status'=>2, 'clients'=>9999, 'durations'=>0, 'end_time'=>strtotime('+10 year')];
  298. $data = bin2hex(json_encode($userinfo));
  299. return json(['status'=>true, 'err_no'=>0, 'data'=>$data]);
  300. }
  301. //刷新授权信息
  302. public function update_license(){
  303. if(!input('?post.data')) return json(['status'=>false, 'msg'=>'参数不能为空']);
  304. $reqData = hex2bin(input('post.data'));
  305. parse_str($reqData, $arr);
  306. if(!isset($arr['product']) || !isset($arr['serverid'])) return json(['status'=>false, 'msg'=>'缺少参数']);
  307. $license_data = ['product'=>$arr['product'], 'uid'=>random(32), 'phone'=>'138****8888', 'auth_id'=>random(32), 'server_id'=>substr($arr['serverid'], 0, 32), 'auth'=>['apis'=>[], 'menu'=>[], 'extra'=>['type'=>3,'location'=>-1,'smart_cc'=>-1,'site'=>0]], 'pages'=>[], 'end_time'=>strtotime('+10 year')];
  308. $json = json_encode($license_data);
  309. [$public_key, $private_key] = generateKeyPairs();
  310. $public_key = pemToBase64($public_key);
  311. $key1 = random(32);
  312. $key2 = substr($public_key, 0, 32);
  313. $encrypted1 = licenseEncrypt($json, $key1);
  314. $encrypted2 = licenseEncrypt($key1, $key2);
  315. $sign_data = $encrypted1.'.'.$encrypted2;
  316. openssl_sign($sign_data, $signature, $private_key, OPENSSL_ALGO_SHA256);
  317. $signature = base64_encode($signature);
  318. $license = base64_encode($sign_data.'.'.$signature);
  319. $data = bin2hex(json_encode(['public_key'=>$public_key, 'license'=>$license]));
  320. return json(['status'=>true, 'err_no'=>0, 'msg'=>'授权获取成功', 'data'=>$data]);
  321. }
  322. public function is_obtained_btw_trial(){
  323. $data = ['is_obtained'=>0];
  324. $data = bin2hex(json_encode($data));
  325. return json(['status'=>true, 'err_no'=>0, 'data'=>$data, 'msg'=>'检测成功']);
  326. }
  327. //一键部署列表
  328. public function get_deplist(){
  329. $os = input('post.os');
  330. $json_arr = Plugins::get_deplist($os);
  331. if(!$json_arr) return json([]);
  332. return json($json_arr);
  333. }
  334. //获取宝塔SSL列表
  335. public function get_ssl_list(){
  336. $data = bin2hex('[]');
  337. return json(['status'=>true, 'msg'=>'', 'data'=>$data]);
  338. }
  339. public function return_success(){
  340. return json(['status'=>true, 'msg'=>1, 'data'=>(object)[]]);
  341. }
  342. public function return_error(){
  343. return json(['status'=>false, 'msg'=>'不支持当前操作']);
  344. }
  345. public function return_error2(){
  346. return json(['success'=>false, 'res'=>'不支持当前操作']);
  347. }
  348. public function return_empty(){
  349. return '';
  350. }
  351. public function return_empty_array(){
  352. return json([]);
  353. }
  354. public function return_page_data(){
  355. return json(['page'=>"<div><span class='Pcurrent'>1</span><span class='Pnumber'>1/0</span><span class='Pline'>从1-1000条</span><span class='Pcount'>共计0条数据</span></div>", 'data'=>[]]);
  356. }
  357. //获取所有蜘蛛IP列表
  358. public function btwaf_getspiders(){
  359. try{
  360. $result = Plugins::btwaf_getspiders();
  361. return json($result);
  362. }catch(\Exception $e){
  363. return json(['status'=>false, 'msg'=>$e->getMessage()]);
  364. }
  365. }
  366. //分类获取蜘蛛IP列表
  367. public function get_spider(){
  368. $type = input('get.spider/d');
  369. if(!$type) return json([]);
  370. $result = Plugins::get_spider($type);
  371. return json($result);
  372. }
  373. //检查黑白名单
  374. private function checklist(){
  375. if(config_get('whitelist') == 1){
  376. if(Db::name('white')->where('ip', $this->clientip)->where('enable', 1)->find()){
  377. return true;
  378. }
  379. return false;
  380. }else{
  381. if(Db::name('black')->where('ip', $this->clientip)->where('enable', 1)->find()){
  382. return false;
  383. }
  384. return true;
  385. }
  386. }
  387. //下载大文件
  388. private function output_file($filepath, $filename){
  389. $filesize = filesize($filepath);
  390. $filemd5 = md5_file($filepath);
  391. ob_clean();
  392. header("Content-Type: application/octet-stream");
  393. header("Content-Disposition: attachment; filename={$filename}.zip");
  394. header("Content-Length: {$filesize}");
  395. header("File-size: {$filesize}");
  396. header("Content-md5: {$filemd5}");
  397. $read_buffer = 1024 * 100;
  398. $handle = fopen($filepath, 'rb');
  399. $sum_buffer = 0;
  400. while(!feof($handle) && $sum_buffer<$filesize) {
  401. echo fread($handle, min($read_buffer, ($filesize - $sum_buffer) + 1));
  402. $sum_buffer += $read_buffer;
  403. flush();
  404. }
  405. fclose($handle);
  406. exit;
  407. }
  408. public function logerror(){
  409. $content = date('Y-m-d H:i:s')."\r\n";
  410. $content.=$_SERVER['REQUEST_METHOD'].' '.$_SERVER['REQUEST_URI']."\r\n";
  411. if($_SERVER['REQUEST_METHOD'] == 'POST'){
  412. $content.=file_get_contents('php://input')."\r\n";
  413. }
  414. $handle = fopen(app()->getRootPath()."record.txt", 'a');
  415. fwrite($handle, $content."\r\n");
  416. fclose($handle);
  417. return json(['status'=>false, 'msg'=>'不支持当前操作']);
  418. }
  419. //生成自签名SSL证书
  420. public function bt_cert(){
  421. $data = input('post.data');
  422. $param = json_decode($data, true);
  423. if(!$param || !isset($param['action']) || !isset($param['domain'])) return json(['status'=>false, 'msg'=>'参数错误']);
  424. $dir = app()->getBasePath().'script/';
  425. $ssl_path = app()->getRootPath().'public/ssl/baota_root.pfx';
  426. $isca = file_exists($dir.'ca.crt') && file_exists($dir.'ca.key') && file_exists($ssl_path);
  427. if(!$isca) return json(['status'=>false, 'msg'=>'CA证书不存在']);
  428. if($param['action'] == 'get_domain_cert'){
  429. if(!$this->checklist()) return json(['status'=>false, 'msg'=>'你的服务器被禁止使用此云端']);
  430. $domain = $param['domain'];
  431. if(empty($domain)) return json(['status'=>false, 'msg'=>'域名不能为空']);
  432. $domain_list = explode(',', $domain);
  433. foreach($domain_list as $d){
  434. if(!checkDomain($d)) return json(['status'=>false, 'msg'=>'域名或IP格式不正确:'.$d]);
  435. }
  436. $common_name = $domain_list[0];
  437. $validity = 3650;
  438. $result = makeSelfSignSSL($common_name, $domain_list, $validity);
  439. if(!$result){
  440. return json(['status'=>false, 'msg'=>'生成证书失败']);
  441. }
  442. $ca_pfx = base64_encode(file_get_contents($ssl_path));
  443. return json(['status'=>true, 'msg'=>'生成证书成功', 'cert'=>$result['cert'], 'key'=>$result['key'], 'pfx'=>$ca_pfx, 'password'=>'']);
  444. }else{
  445. return json(['status'=>false, 'msg'=>'不支持当前操作']);
  446. }
  447. }
  448. }