AuthController.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. <?php
  2. namespace App\Controllers;
  3. use App\Models\InviteCode;
  4. use App\Services\Config;
  5. use App\Utils\Check;
  6. use App\Utils\Tools;
  7. use App\Utils\Radius;
  8. use Exception;
  9. use voku\helper\AntiXSS;
  10. use App\Utils\Hash;
  11. use App\Utils\Da;
  12. use App\Services\Auth;
  13. use App\Services\Mail;
  14. use App\Models\User;
  15. use App\Models\LoginIp;
  16. use App\Models\EmailVerify;
  17. use App\Utils\GA;
  18. use App\Utils\Geetest;
  19. use App\Utils\TelegramSessionManager;
  20. /**
  21. * AuthController
  22. */
  23. class AuthController extends BaseController
  24. {
  25. public function login()
  26. {
  27. $GtSdk = null;
  28. $recaptcha_sitekey = null;
  29. if (Config::get('enable_login_captcha') === 'true') {
  30. switch (Config::get('captcha_provider')) {
  31. case 'recaptcha':
  32. $recaptcha_sitekey = Config::get('recaptcha_sitekey');
  33. break;
  34. case 'geetest':
  35. $uid = time() . random_int(1, 10000);
  36. $GtSdk = Geetest::get($uid);
  37. break;
  38. }
  39. }
  40. if (Config::get('enable_telegram') === 'true') {
  41. $login_text = TelegramSessionManager::add_login_session();
  42. $login = explode('|', $login_text);
  43. $login_token = $login[0];
  44. $login_number = $login[1];
  45. } else {
  46. $login_token = '';
  47. $login_number = '';
  48. }
  49. return $this->view()
  50. ->assign('geetest_html', $GtSdk)
  51. ->assign('login_token', $login_token)
  52. ->assign('login_number', $login_number)
  53. ->assign('telegram_bot', Config::get('telegram_bot'))
  54. ->assign('base_url', Config::get('baseUrl'))
  55. ->assign('recaptcha_sitekey', $recaptcha_sitekey)
  56. ->display('auth/login.tpl');
  57. }
  58. public function getCaptcha($request, $response, $args)
  59. {
  60. $GtSdk = null;
  61. $recaptcha_sitekey = null;
  62. if (Config::get('captcha_provider') != '') {
  63. switch (Config::get('captcha_provider')) {
  64. case 'recaptcha':
  65. $recaptcha_sitekey = Config::get('recaptcha_sitekey');
  66. $res['recaptchaKey'] = $recaptcha_sitekey;
  67. break;
  68. case 'geetest':
  69. $uid = time() . random_int(1, 10000);
  70. $GtSdk = Geetest::get($uid);
  71. $res['GtSdk'] = $GtSdk;
  72. break;
  73. }
  74. }
  75. $res['respon'] = 1;
  76. return $response->getBody()->write(json_encode($res));
  77. }
  78. public function loginHandle($request, $response, $args)
  79. {
  80. // $data = $request->post('sdf');
  81. $email = $request->getParam('email');
  82. $email = trim($email);
  83. $email = strtolower($email);
  84. $passwd = $request->getParam('passwd');
  85. $code = $request->getParam('code');
  86. $rememberMe = $request->getParam('remember_me');
  87. if (Config::get('enable_login_captcha') === 'true') {
  88. switch (Config::get('captcha_provider')) {
  89. case 'recaptcha':
  90. $recaptcha = $request->getParam('recaptcha');
  91. if ($recaptcha == '') {
  92. $ret = false;
  93. } else {
  94. $json = file_get_contents('https://recaptcha.net/recaptcha/api/siteverify?secret=' . Config::get('recaptcha_secret') . '&response=' . $recaptcha);
  95. $ret = json_decode($json)->success;
  96. }
  97. break;
  98. case 'geetest':
  99. $ret = Geetest::verify($request->getParam('geetest_challenge'), $request->getParam('geetest_validate'), $request->getParam('geetest_seccode'));
  100. break;
  101. }
  102. if (!$ret) {
  103. $res['ret'] = 0;
  104. $res['msg'] = '系统无法接受您的验证结果,请刷新页面后重试。';
  105. return $response->getBody()->write(json_encode($res));
  106. }
  107. }
  108. // Handle Login
  109. $user = User::where('email', '=', $email)->first();
  110. if ($user == null) {
  111. $rs['ret'] = 0;
  112. $rs['msg'] = '邮箱不存在';
  113. return $response->getBody()->write(json_encode($rs));
  114. }
  115. if (!Hash::checkPassword($user->pass, $passwd)) {
  116. $rs['ret'] = 0;
  117. $rs['msg'] = '邮箱或者密码错误';
  118. $loginIP = new LoginIp();
  119. $loginIP->ip = $_SERVER['REMOTE_ADDR'];
  120. $loginIP->userid = $user->id;
  121. $loginIP->datetime = time();
  122. $loginIP->type = 1;
  123. $loginIP->save();
  124. return $response->getBody()->write(json_encode($rs));
  125. }
  126. $time = 3600 * 24;
  127. if ($rememberMe) {
  128. $time = 3600 * 24 * (Config::get('rememberMeDuration') ?: 7);
  129. }
  130. if ($user->ga_enable == 1) {
  131. $ga = new GA();
  132. $rcode = $ga->verifyCode($user->ga_token, $code);
  133. if (!$rcode) {
  134. $res['ret'] = 0;
  135. $res['msg'] = '两步验证码错误,如果您是丢失了生成器或者错误地设置了这个选项,您可以尝试重置密码,即可取消这个选项。';
  136. return $response->getBody()->write(json_encode($res));
  137. }
  138. }
  139. Auth::login($user->id, $time);
  140. $rs['ret'] = 1;
  141. $rs['msg'] = '登录成功';
  142. $loginIP = new LoginIp();
  143. $loginIP->ip = $_SERVER['REMOTE_ADDR'];
  144. $loginIP->userid = $user->id;
  145. $loginIP->datetime = time();
  146. $loginIP->type = 0;
  147. $loginIP->save();
  148. return $response->getBody()->write(json_encode($rs));
  149. }
  150. public function qrcode_loginHandle($request, $response, $args)
  151. {
  152. // $data = $request->post('sdf');
  153. $token = $request->getParam('token');
  154. $number = $request->getParam('number');
  155. $ret = TelegramSessionManager::step2_verify_login_session($token, $number);
  156. if (!$ret) {
  157. $res['ret'] = 0;
  158. $res['msg'] = '此令牌无法被使用。';
  159. return $response->getBody()->write(json_encode($res));
  160. }
  161. // Handle Login
  162. $user = User::where('id', '=', $ret)->first();
  163. // @todo
  164. $time = 3600 * 24;
  165. Auth::login($user->id, $time);
  166. $rs['ret'] = 1;
  167. $rs['msg'] = '登录成功';
  168. $this->logUserIp($user->id, $_SERVER['REMOTE_ADDR']);
  169. return $response->getBody()->write(json_encode($rs));
  170. }
  171. private function logUserIp($id, $ip)
  172. {
  173. $loginip = new LoginIp();
  174. $loginip->ip = $ip;
  175. $loginip->userid = $id;
  176. $loginip->datetime = time();
  177. $loginip->type = 0;
  178. $loginip->save();
  179. }
  180. public function register($request, $response, $next)
  181. {
  182. $ary = $request->getQueryParams();
  183. $code = '';
  184. if (isset($ary['code'])) {
  185. $antiXss = new AntiXSS();
  186. $code = $antiXss->xss_clean($ary['code']);
  187. }
  188. $GtSdk = null;
  189. $recaptcha_sitekey = null;
  190. if (Config::get('enable_reg_captcha') === 'true') {
  191. switch (Config::get('captcha_provider')) {
  192. case 'recaptcha':
  193. $recaptcha_sitekey = Config::get('recaptcha_sitekey');
  194. break;
  195. case 'geetest':
  196. $uid = time() . random_int(1, 10000);
  197. $GtSdk = Geetest::get($uid);
  198. break;
  199. }
  200. }
  201. return $this->view()
  202. ->assign('geetest_html', $GtSdk)
  203. ->assign('enable_email_verify', Config::get('enable_email_verify'))
  204. ->assign('code', $code)
  205. ->assign('recaptcha_sitekey', $recaptcha_sitekey)
  206. ->display('auth/register.tpl');
  207. }
  208. public function sendVerify($request, $response, $next)
  209. {
  210. if (Config::get('enable_email_verify') === 'true') {
  211. $email = $request->getParam('email');
  212. $email = trim($email);
  213. if ($email == '') {
  214. $res['ret'] = 0;
  215. $res['msg'] = '未填写邮箱';
  216. return $response->getBody()->write(json_encode($res));
  217. }
  218. // check email format
  219. if (!Check::isEmailLegal($email)) {
  220. $res['ret'] = 0;
  221. $res['msg'] = '邮箱无效';
  222. return $response->getBody()->write(json_encode($res));
  223. }
  224. $user = User::where('email', '=', $email)->first();
  225. if ($user != null) {
  226. $res['ret'] = 0;
  227. $res['msg'] = '此邮箱已经注册';
  228. return $response->getBody()->write(json_encode($res));
  229. }
  230. $ipcount = EmailVerify::where('ip', '=', $_SERVER['REMOTE_ADDR'])->where('expire_in', '>', time())->count();
  231. if ($ipcount >= (int)Config::get('email_verify_iplimit')) {
  232. $res['ret'] = 0;
  233. $res['msg'] = '此IP请求次数过多';
  234. return $response->getBody()->write(json_encode($res));
  235. }
  236. $mailcount = EmailVerify::where('email', '=', $email)->where('expire_in', '>', time())->count();
  237. if ($mailcount >= 3) {
  238. $res['ret'] = 0;
  239. $res['msg'] = '此邮箱请求次数过多';
  240. return $response->getBody()->write(json_encode($res));
  241. }
  242. $code = Tools::genRandomNum(6);
  243. $ev = new EmailVerify();
  244. $ev->expire_in = time() + Config::get('email_verify_ttl');
  245. $ev->ip = $_SERVER['REMOTE_ADDR'];
  246. $ev->email = $email;
  247. $ev->code = $code;
  248. $ev->save();
  249. $subject = Config::get('appName') . '- 验证邮件';
  250. try {
  251. Mail::send($email, $subject, 'auth/verify.tpl', [
  252. 'code' => $code, 'expire' => date('Y-m-d H:i:s', time() + Config::get('email_verify_ttl'))
  253. ], [
  254. //BASE_PATH.'/public/assets/email/styles.css'
  255. ]);
  256. } catch (Exception $e) {
  257. $res['ret'] = 1;
  258. $res['msg'] = '邮件发送失败,请联系网站管理员。';
  259. return $response->getBody()->write(json_encode($res));
  260. }
  261. $res['ret'] = 1;
  262. $res['msg'] = '验证码发送成功,请查收邮件。';
  263. return $response->getBody()->write(json_encode($res));
  264. }
  265. $res['ret'] = 0;
  266. return $response->getBody()->write(json_encode($res));
  267. }
  268. public function registerHandle($request, $response)
  269. {
  270. if (Config::get('register_mode') === 'close') {
  271. $res['ret'] = 0;
  272. $res['msg'] = '未开放注册。';
  273. return $response->getBody()->write(json_encode($res));
  274. }
  275. $name = $request->getParam('name');
  276. $email = $request->getParam('email');
  277. $email = trim($email);
  278. $email = strtolower($email);
  279. $passwd = $request->getParam('passwd');
  280. $repasswd = $request->getParam('repasswd');
  281. $code = $request->getParam('code');
  282. $code = trim($code);
  283. $imtype = $request->getParam('imtype');
  284. $emailcode = $request->getParam('emailcode');
  285. $emailcode = trim($emailcode);
  286. $wechat = $request->getParam('wechat');
  287. $wechat = trim($wechat);
  288. // check code
  289. if (Config::get('enable_reg_captcha') === 'true') {
  290. switch (Config::get('captcha_provider')) {
  291. case 'recaptcha':
  292. $recaptcha = $request->getParam('recaptcha');
  293. if ($recaptcha == '') {
  294. $ret = false;
  295. } else {
  296. $json = file_get_contents('https://recaptcha.net/recaptcha/api/siteverify?secret=' . Config::get('recaptcha_secret') . '&response=' . $recaptcha);
  297. $ret = json_decode($json)->success;
  298. }
  299. break;
  300. case 'geetest':
  301. $ret = Geetest::verify($request->getParam('geetest_challenge'), $request->getParam('geetest_validate'), $request->getParam('geetest_seccode'));
  302. break;
  303. }
  304. if (!$ret) {
  305. $res['ret'] = 0;
  306. $res['msg'] = '系统无法接受您的验证结果,请刷新页面后重试。';
  307. return $response->getBody()->write(json_encode($res));
  308. }
  309. }
  310. //dumplin:1、邀请人等级为0则邀请码不可用;2、邀请人invite_num为可邀请次数,填负数则为无限
  311. $c = InviteCode::where('code', $code)->first();
  312. if ($c == null) {
  313. if (Config::get('register_mode') === 'invite') {
  314. $res['ret'] = 0;
  315. $res['msg'] = '邀请码无效';
  316. return $response->getBody()->write(json_encode($res));
  317. }
  318. } elseif ($c->user_id != 0) {
  319. $gift_user = User::where('id', '=', $c->user_id)->first();
  320. if ($gift_user == null) {
  321. $res['ret'] = 0;
  322. $res['msg'] = '邀请人不存在';
  323. return $response->getBody()->write(json_encode($res));
  324. }
  325. if ($gift_user->class == 0) {
  326. $res['ret'] = 0;
  327. $res['msg'] = '邀请人不是VIP';
  328. return $response->getBody()->write(json_encode($res));
  329. }
  330. if ($gift_user->invite_num == 0) {
  331. $res['ret'] = 0;
  332. $res['msg'] = '邀请人可用邀请次数为0';
  333. return $response->getBody()->write(json_encode($res));
  334. }
  335. }
  336. // check email format
  337. if (!Check::isEmailLegal($email)) {
  338. $res['ret'] = 0;
  339. $res['msg'] = '邮箱无效';
  340. return $response->getBody()->write(json_encode($res));
  341. }
  342. // check email
  343. $user = User::where('email', $email)->first();
  344. if ($user != null) {
  345. $res['ret'] = 0;
  346. $res['msg'] = '邮箱已经被注册了';
  347. return $response->getBody()->write(json_encode($res));
  348. }
  349. if (Config::get('enable_email_verify') === 'true') {
  350. $mailcount = EmailVerify::where('email', '=', $email)->where('code', '=', $emailcode)->where('expire_in', '>', time())->first();
  351. if ($mailcount == null) {
  352. $res['ret'] = 0;
  353. $res['msg'] = '您的邮箱验证码不正确';
  354. return $response->getBody()->write(json_encode($res));
  355. }
  356. }
  357. // check pwd length
  358. if (strlen($passwd) < 8) {
  359. $res['ret'] = 0;
  360. $res['msg'] = '密码请大于8位';
  361. return $response->getBody()->write(json_encode($res));
  362. }
  363. // check pwd re
  364. if ($passwd != $repasswd) {
  365. $res['ret'] = 0;
  366. $res['msg'] = '两次密码输入不符';
  367. return $response->getBody()->write(json_encode($res));
  368. }
  369. if ($imtype == '' || $wechat == '') {
  370. $res['ret'] = 0;
  371. $res['msg'] = '请填上你的联络方式';
  372. return $response->getBody()->write(json_encode($res));
  373. }
  374. $user = User::where('im_value', $wechat)->where('im_type', $imtype)->first();
  375. if ($user != null) {
  376. $res['ret'] = 0;
  377. $res['msg'] = '此联络方式已注册';
  378. return $response->getBody()->write(json_encode($res));
  379. }
  380. if (Config::get('enable_email_verify') === 'true') {
  381. EmailVerify::where('email', '=', $email)->delete();
  382. }
  383. // do reg user
  384. $user = new User();
  385. $antiXss = new AntiXSS();
  386. $user->user_name = $antiXss->xss_clean($name);
  387. $user->email = $email;
  388. $user->pass = Hash::passwordHash($passwd);
  389. $user->passwd = Tools::genRandomChar(6);
  390. $user->port = Tools::getAvPort();
  391. $user->t = 0;
  392. $user->u = 0;
  393. $user->d = 0;
  394. $user->method = Config::get('reg_method');
  395. $user->protocol = Config::get('reg_protocol');
  396. $user->protocol_param = Config::get('reg_protocol_param');
  397. $user->obfs = Config::get('reg_obfs');
  398. $user->obfs_param = Config::get('reg_obfs_param');
  399. $user->forbidden_ip = Config::get('reg_forbidden_ip');
  400. $user->forbidden_port = Config::get('reg_forbidden_port');
  401. $user->im_type = $imtype;
  402. $user->im_value = $antiXss->xss_clean($wechat);
  403. $user->transfer_enable = Tools::toGB(Config::get('defaultTraffic'));
  404. $user->invite_num = Config::get('inviteNum');
  405. $user->auto_reset_day = Config::get('reg_auto_reset_day');
  406. $user->auto_reset_bandwidth = Config::get('reg_auto_reset_bandwidth');
  407. $user->money = 0;
  408. //dumplin:填写邀请人,写入邀请奖励
  409. $user->ref_by = 0;
  410. if (($c != null) && $c->user_id != 0) {
  411. $gift_user = User::where('id', '=', $c->user_id)->first();
  412. $user->ref_by = $c->user_id;
  413. $user->money = Config::get('invite_get_money');
  414. $gift_user->transfer_enable += Config::get('invite_gift') * 1024 * 1024 * 1024;
  415. --$gift_user->invite_num;
  416. $gift_user->save();
  417. }
  418. $user->class_expire = date('Y-m-d H:i:s', time() + Config::get('user_class_expire_default') * 3600);
  419. $user->class = Config::get('user_class_default');
  420. $user->node_connector = Config::get('user_conn');
  421. $user->node_speedlimit = Config::get('user_speedlimit');
  422. $user->expire_in = date('Y-m-d H:i:s', time() + Config::get('user_expire_in_default') * 86400);
  423. $user->reg_date = date('Y-m-d H:i:s');
  424. $user->reg_ip = $_SERVER['REMOTE_ADDR'];
  425. $user->plan = 'A';
  426. $user->theme = Config::get('theme');
  427. $groups = explode(',', Config::get('ramdom_group'));
  428. $user->node_group = $groups[array_rand($groups)];
  429. $ga = new GA();
  430. $secret = $ga->createSecret();
  431. $user->ga_token = $secret;
  432. $user->ga_enable = 0;
  433. if ($user->save()) {
  434. $res['ret'] = 1;
  435. $res['msg'] = '注册成功!正在进入登录界面';
  436. Radius::Add($user, $user->passwd);
  437. return $response->getBody()->write(json_encode($res));
  438. }
  439. $res['ret'] = 0;
  440. $res['msg'] = '未知错误';
  441. return $response->getBody()->write(json_encode($res));
  442. }
  443. public function logout($request, $response, $next)
  444. {
  445. Auth::logout();
  446. return $response->withStatus(302)->withHeader('Location', '/auth/login');
  447. }
  448. public function qrcode_check($request, $response, $args)
  449. {
  450. $token = $request->getParam('token');
  451. $number = $request->getParam('number');
  452. $user = Auth::getUser();
  453. if ($user->isLogin) {
  454. $res['ret'] = 0;
  455. return $response->getBody()->write(json_encode($res));
  456. }
  457. if (Config::get('enable_telegram') === 'true') {
  458. $ret = TelegramSessionManager::check_login_session($token, $number);
  459. $res['ret'] = $ret;
  460. return $response->getBody()->write(json_encode($res));
  461. }
  462. $res['ret'] = 0;
  463. return $response->getBody()->write(json_encode($res));
  464. }
  465. public function telegram_oauth($request, $response, $args)
  466. {
  467. if (Config::get('enable_telegram') === 'true') {
  468. $auth_data = $request->getQueryParams();
  469. if ($this->telegram_oauth_check($auth_data) === true) { // Looks good, proceed.
  470. $telegram_id = $auth_data['id'];
  471. $user = User::query()->where('telegram_id', $telegram_id)->firstOrFail(); // Welcome Back :)
  472. if ($user == null) {
  473. return $this->view()->assign('title', '您需要先进行邮箱注册后绑定Telegram才能使用授权登录')->assign('message', '很抱歉带来的不便,请重新试试')->assign('redirect', '/auth/login')->display('telegram_error.tpl');
  474. }
  475. Auth::login($user->id, 3600);
  476. $this->logUserIp($user->id, $_SERVER['REMOTE_ADDR']);
  477. // 登陆成功!
  478. return $this->view()->assign('title', '登录成功')->assign('message', '正在前往仪表盘')->assign('redirect', '/user')->display('telegram_success.tpl');
  479. }
  480. // 验证失败
  481. return $this->view()->assign('title', '登陆超时或非法构造信息')->assign('message', '很抱歉带来的不便,请重新试试')->assign('redirect', '/auth/login')->display('telegram_error.tpl');
  482. }
  483. return $response->withRedirect('/404');
  484. }
  485. private function telegram_oauth_check($auth_data)
  486. {
  487. $check_hash = $auth_data['hash'];
  488. $bot_token = Config::get('telegram_token');
  489. unset($auth_data['hash']);
  490. $data_check_arr = [];
  491. foreach ($auth_data as $key => $value) {
  492. $data_check_arr[] = $key . '=' . $value;
  493. }
  494. sort($data_check_arr);
  495. $data_check_string = implode("\n", $data_check_arr);
  496. $secret_key = hash('sha256', $bot_token, true);
  497. $hash = hash_hmac('sha256', $data_check_string, $secret_key);
  498. if (strcmp($hash, $check_hash) !== 0) {
  499. return false; // Bad Data :(
  500. }
  501. if ((time() - $auth_data['auth_date']) > 300) { // Expire @ 5mins
  502. return false;
  503. }
  504. return true; // Good to Go
  505. }
  506. }