1
0

UserEmailForgotController.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. <?php
  2. namespace App\Http\Controllers;
  3. use Illuminate\Http\Request;
  4. use App\User;
  5. use App\Models\UserEmailForgot;
  6. use Illuminate\Support\Facades\Cache;
  7. use Illuminate\Support\Facades\Mail;
  8. use App\Mail\UserEmailForgotReminder;
  9. use Illuminate\Support\Facades\RateLimiter;
  10. class UserEmailForgotController extends Controller
  11. {
  12. public function __construct()
  13. {
  14. $this->middleware('guest');
  15. abort_unless(config('security.forgot-email.enabled'), 404);
  16. }
  17. public function index(Request $request)
  18. {
  19. abort_if($request->user(), 404);
  20. return view('auth.email.forgot');
  21. }
  22. public function store(Request $request)
  23. {
  24. $rules = [
  25. 'username' => 'required|min:2|max:30|exists:users'
  26. ];
  27. $messages = [
  28. 'username.exists' => 'This username is no longer active or does not exist!'
  29. ];
  30. if((bool) config_cache('captcha.enabled')) {
  31. $rules['h-captcha-response'] = 'required|captcha';
  32. $messages['h-captcha-response.required'] = 'You need to complete the captcha!';
  33. }
  34. $randomDelay = random_int(500000, 2000000);
  35. usleep($randomDelay);
  36. $this->validate($request, $rules, $messages);
  37. $check = self::checkLimits();
  38. if(!$check) {
  39. return redirect()->back()->withErrors([
  40. 'username' => 'Please try again later, we\'ve reached our quota and cannot process any more requests at this time.'
  41. ]);
  42. }
  43. $user = User::whereUsername($request->input('username'))
  44. ->whereNotNull('email_verified_at')
  45. ->whereNull('status')
  46. ->whereIsAdmin(false)
  47. ->first();
  48. if(!$user) {
  49. return redirect()->back()->withErrors([
  50. 'username' => 'Invalid username or account. It may not exist, or does not have a verified email, is an admin account or is disabled.'
  51. ]);
  52. }
  53. $exists = UserEmailForgot::whereUserId($user->id)
  54. ->where('email_sent_at', '>', now()->subHours(24))
  55. ->count();
  56. if($exists) {
  57. return redirect()->back()->withErrors([
  58. 'username' => 'An email reminder was recently sent to this account, please try again after 24 hours!'
  59. ]);
  60. }
  61. return $this->storeHandle($request, $user);
  62. }
  63. protected function storeHandle($request, $user)
  64. {
  65. UserEmailForgot::create([
  66. 'user_id' => $user->id,
  67. 'ip_address' => $request->ip(),
  68. 'user_agent' => $request->userAgent(),
  69. 'email_sent_at' => now()
  70. ]);
  71. Mail::to($user->email)->send(new UserEmailForgotReminder($user));
  72. self::getLimits(true);
  73. return redirect()->back()->with(['status' => 'Successfully sent an email reminder!']);
  74. }
  75. public static function checkLimits()
  76. {
  77. $limits = self::getLimits();
  78. if(
  79. $limits['current']['hourly'] >= $limits['max']['hourly'] ||
  80. $limits['current']['daily'] >= $limits['max']['daily'] ||
  81. $limits['current']['weekly'] >= $limits['max']['weekly'] ||
  82. $limits['current']['monthly'] >= $limits['max']['monthly']
  83. ) {
  84. return false;
  85. }
  86. return true;
  87. }
  88. public static function getLimits($forget = false)
  89. {
  90. return [
  91. 'max' => config('security.forgot-email.limits.max'),
  92. 'current' => [
  93. 'hourly' => self::activeCount(60, $forget),
  94. 'daily' => self::activeCount(1440, $forget),
  95. 'weekly' => self::activeCount(10080, $forget),
  96. 'monthly' => self::activeCount(43800, $forget)
  97. ]
  98. ];
  99. }
  100. public static function activeCount($mins, $forget = false)
  101. {
  102. if($forget) {
  103. Cache::forget('pf:auth:forgot-email:active-count:dur-' . $mins);
  104. }
  105. return Cache::remember('pf:auth:forgot-email:active-count:dur-' . $mins, 14200, function() use($mins) {
  106. return UserEmailForgot::where('email_sent_at', '>', now()->subMinutes($mins))->count();
  107. });
  108. }
  109. }