From 1fa155c21301517dee54fe1bc18aafafcdf091de Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Sun, 24 Mar 2019 09:58:37 +0800 Subject: [PATCH] Support reCAPTCHA --- app/Http/Controllers/AdminController.php | 8 ++- app/Http/Controllers/AuthController.php | 12 +++- app/Rules/Captcha.php | 43 ++++++++++++++ config/options.php | 3 + package.json | 1 + resources/assets/src/components/Captcha.vue | 59 +++++++++++++++++++ .../src/components/mixins/updateCaptcha.ts | 12 ++++ resources/assets/src/views/auth/Login.vue | 45 ++++---------- resources/assets/src/views/auth/Register.vue | 45 ++++---------- .../assets/tests/components/Captcha.test.ts | 23 ++++++++ .../components/mixins/updateCaptcha.test.ts | 8 +++ .../assets/tests/views/auth/Login.test.ts | 11 ---- .../assets/tests/views/auth/Register.test.ts | 11 ---- resources/lang/en/options.yml | 5 ++ resources/lang/en/validation.yml | 1 + resources/lang/zh_CN/options.yml | 5 ++ resources/lang/zh_CN/validation.yml | 1 + resources/views/admin/options.blade.php | 2 + resources/views/auth/login.blade.php | 7 ++- resources/views/auth/register.blade.php | 2 +- resources/views/common/recaptcha.blade.php | 11 ++++ tests/AdminControllerTest.php | 9 +++ yarn.lock | 5 ++ 23 files changed, 230 insertions(+), 99 deletions(-) create mode 100644 app/Rules/Captcha.php create mode 100644 resources/assets/src/components/Captcha.vue create mode 100644 resources/assets/src/components/mixins/updateCaptcha.ts create mode 100644 resources/assets/tests/components/Captcha.test.ts create mode 100644 resources/assets/tests/components/mixins/updateCaptcha.test.ts create mode 100644 resources/views/common/recaptcha.blade.php diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index 8b0faa02..7a694e2a 100644 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/AdminController.php @@ -233,8 +233,14 @@ class AdminController extends Controller $form->textarea('meta_extras')->rows(6); })->handle(); + $recaptcha = Option::form('recaptcha', 'reCAPTCHA', function ($form) { + $form->text('recaptcha_sitekey', 'sitekey'); + $form->text('recaptcha_secretkey', 'secretkey'); + $form->checkbox('recaptcha_mirror')->label(); + })->handle(); + return view('admin.options') - ->with('forms', compact('general', 'announ', 'meta')); + ->with('forms', compact('general', 'announ', 'meta', 'recaptcha')); } public function resource(Request $request) diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index fe75e91e..ce0de1c3 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -10,6 +10,7 @@ use Session; use App\Events; use App\Models\User; use App\Models\Player; +use App\Rules\Captcha; use App\Mail\ForgotPassword; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; @@ -43,7 +44,7 @@ class AuthController extends Controller $loginFails = (int) Cache::get($loginFailsCacheKey, 0); if ($loginFails > 3) { - $this->validate($request, ['captcha' => 'required|captcha']); + $this->validate($request, ['captcha' => ['required', new Captcha]]); } if (! $user) { @@ -83,7 +84,12 @@ class AuthController extends Controller public function register() { if (option('user_can_register')) { - return view('auth.register', ['extra' => ['player' => option('register_with_player_name')]]); + return view('auth.register', [ + 'extra' => [ + 'player' => option('register_with_player_name'), + 'recaptcha' => option('recaptcha_sitekey'), + ] + ]); } else { throw new PrettyPageException(trans('auth.register.close'), 7); } @@ -101,7 +107,7 @@ class AuthController extends Controller $data = $this->validate($request, array_merge([ 'email' => 'required|email|unique:users', 'password' => 'required|min:8|max:32', - 'captcha' => 'required'.(app()->environment('testing') ? '' : '|captcha'), + 'captcha' => ['required', new Captcha], ], $rule)); if (option('register_with_player_name')) { diff --git a/app/Rules/Captcha.php b/app/Rules/Captcha.php new file mode 100644 index 00000000..9a1e4190 --- /dev/null +++ b/app/Rules/Captcha.php @@ -0,0 +1,43 @@ +environment('testing')) { + return true; + } + + $secretkey = option('recaptcha_secretkey'); + if ($secretkey) { + $client = new \GuzzleHttp\Client(); + $url = option('recaptcha_mirror') + ? 'https://www.recaptcha.net/recaptcha/api/siteverify' + : 'https://www.google.com/recaptcha/api/siteverify'; + $response = $client->post($url, [ + 'form_params' => [ + 'secret' => $secretkey, + 'response' => $value, + ] + ]); + if ($response->getStatusCode() == 200) { + $body = json_decode((string) $response->getBody()); + return $body->success; + } + return false; + } + + return captcha_check($value); + } + + public function message() + { + return option('recaptcha_secretkey') + ? trans('validation.recaptcha') + : trans('validation.captcha'); + } +} diff --git a/config/options.php b/config/options.php index ac9c7eb6..a36ff41c 100644 --- a/config/options.php +++ b/config/options.php @@ -50,4 +50,7 @@ return [ 'meta_description' => '', 'meta_extras' => '', 'cdn_address' => '', + 'recaptcha_sitekey' => '', + 'recaptcha_secretkey' => '', + 'recaptcha_mirror' => 'false', ]; diff --git a/package.json b/package.json index a71c57e5..bcecde8b 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "toastr": "^2.1.4", "vue": "^2.6.9", "vue-good-table": "^2.16.3", + "vue-recaptcha": "^1.1.1", "vue-upload-component": "^2.8.19", "vuejs-paginate": "^2.1.0" }, diff --git a/resources/assets/src/components/Captcha.vue b/resources/assets/src/components/Captcha.vue new file mode 100644 index 00000000..18b04eb4 --- /dev/null +++ b/resources/assets/src/components/Captcha.vue @@ -0,0 +1,59 @@ + + + diff --git a/resources/assets/src/components/mixins/updateCaptcha.ts b/resources/assets/src/components/mixins/updateCaptcha.ts new file mode 100644 index 00000000..b74fb54e --- /dev/null +++ b/resources/assets/src/components/mixins/updateCaptcha.ts @@ -0,0 +1,12 @@ +import Vue from 'vue' + +export default Vue.extend({ + data: () => ({ + captcha: '', + }), + methods: { + updateCaptcha(value: string) { + this.captcha = value + }, + }, +}) diff --git a/resources/assets/src/views/auth/Login.vue b/resources/assets/src/views/auth/Login.vue index c4dcf0df..52617def 100644 --- a/resources/assets/src/views/auth/Login.vue +++ b/resources/assets/src/views/auth/Login.vue @@ -21,30 +21,7 @@ -
-
-
- -
-
-
- CAPTCHA -
-
+
{{ infoMsg }}
{{ warningMsg }}
@@ -81,9 +58,17 @@ diff --git a/resources/assets/src/views/auth/Register.vue b/resources/assets/src/views/auth/Register.vue index 20a62648..7dde105b 100644 --- a/resources/assets/src/views/auth/Register.vue +++ b/resources/assets/src/views/auth/Register.vue @@ -64,30 +64,7 @@