diff --git a/src/Controller/School/VoteController.php b/src/Controller/School/VoteController.php
index 790a923..1e9dca7 100644
--- a/src/Controller/School/VoteController.php
+++ b/src/Controller/School/VoteController.php
@@ -21,6 +21,10 @@
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Translation\TranslatorInterface;
+/**
+ * Class VoteController
+ * @deprecated No longer used.
+ */
class VoteController extends AbstractController
{
/**
diff --git a/src/Controller/User/UserController.php b/src/Controller/User/UserController.php
index fd8e32c..dfa0a8c 100644
--- a/src/Controller/User/UserController.php
+++ b/src/Controller/User/UserController.php
@@ -480,13 +480,13 @@ public function openid()
/**
* @Route("/user/code", methods="POST")
*/
- public function code(Request $request, NotificationService $service, TranslatorInterface $translator)
+ public function code(Request $request, NotificationService $service, TranslatorInterface $translator, CacheService $cacheService)
{
- if (!$this->verifyCaptcha($request->request->get("captcha")))
- return $this->response()->response($translator->trans("incorrect-captcha"), Response::HTTP_UNAUTHORIZED);
$type = $request->request->getInt("type");
if($type == AliyunTemplateType::BIND)
$this->denyAccessUnlessGranted(Permission::IS_LOGIN);
+ if(!$cacheService->canSend($request->getClientIp(), $request->request->get("email") ?? $request->request->get("phone")))
+ return $this->response()->response($translator->trans("rate-limited"), Response::HTTP_FORBIDDEN);
$error = $service->code($request->request->get("email"), $request->request->get("phone"), $type);
if($error)
return $this->response()->response(null);
diff --git a/src/Service/CacheService.php b/src/Service/CacheService.php
index 16dc43b..60c727d 100644
--- a/src/Service/CacheService.php
+++ b/src/Service/CacheService.php
@@ -45,6 +45,24 @@ public function antiSpiderUse(User $user, int $target) {
}
}
+ public function canSend(string $ip, string $target) {
+ $current = (int)$this->client->get($this->getIdentifierForCode($ip));
+ if($current > 5)
+ return false;
+ $current ++;
+ $this->client->set($this->getIdentifierForCode($ip), $current);
+ $this->client->expire($this->getIdentifierForCode($ip), 1800);
+
+ $current = (int)$this->client->get($this->getIdentifierForCode($target));
+ if($current > 3)
+ return false;
+ $current ++;
+ $this->client->set($this->getIdentifierForCode($target), $current);
+ $this->client->expire($this->getIdentifierForCode($target), 1800);
+
+ return true;
+ }
+
public function rateWrite(User $user) {
$current = (int)$this->client->get($this->getIdentifierForRate($user));
$current ++;
@@ -84,6 +102,10 @@ private function getIdentifierForAntiSpider(User $user){
return "antispider.".(string)$user->getId();
}
+ private function getIdentifierForCode(string $target){
+ return "code.".$target;
+ }
+
private function getIdentifierForRate(User $user) {
return "rate.".(string)$user->getId();
}
diff --git a/src/Service/NotificationService.php b/src/Service/NotificationService.php
index e608c66..f5d2dea 100644
--- a/src/Service/NotificationService.php
+++ b/src/Service/NotificationService.php
@@ -81,7 +81,6 @@ public function code($email = null, $phone = null, int $action) {
$phone,
AliyunTemplateType::REGISTER,
["code" => $code]);
-
}
return false;
case CodeActionType::RESET:
diff --git a/web/components/User/Register.vue b/web/components/User/Register.vue
index f08a4fe..7dc4db4 100644
--- a/web/components/User/Register.vue
+++ b/web/components/User/Register.vue
@@ -41,7 +41,7 @@
- {{$t('send')}}
+ {{$t('send')}}
@@ -173,13 +173,12 @@
}
}
},
- ct() {
+ send() {
this.sending = true
this.axios.post("/user/code", {
"type": 1,
"email": this.form.email,
- "phone": this.form.phone,
- "captcha": grecaptcha.getResponse()
+ "phone": this.form.phone
}).then((response) => {
this.sending = false
if (response.data["code"] === 200) {
@@ -191,7 +190,6 @@
this.sending = false
this.$emit("generalError",error)
})
- grecaptcha.reset()
},
register() {
this.validateItems = {
@@ -249,7 +247,7 @@
this.$v.$touch()
if (!this.$v.$invalid) {
this.form.email = null
- grecaptcha.execute()
+ this.send()
}
},
sendEmail() {
@@ -262,7 +260,7 @@
this.$v.$touch()
if (!this.$v.$invalid) {
this.form.phone = null
- grecaptcha.execute()
+ this.send()
}
},
showMsg(msg) {
@@ -271,14 +269,6 @@
},
mounted: function () {
this.$emit("changeTitle", this.$t("register-title"))
- this.$emit("prepareRecaptcha")
- },
- watch: {
- gResponse: {
- handler: function (val, newVal) {
- this.ct();
- }
- }
}
}
diff --git a/web/components/User/Reset.vue b/web/components/User/Reset.vue
index 045ccc1..8bdcfe5 100644
--- a/web/components/User/Reset.vue
+++ b/web/components/User/Reset.vue
@@ -150,13 +150,12 @@
}
}
},
- ct() {
+ send() {
this.sending = true
this.axios.post("/user/code", {
"type": 2,
"phone": this.form.phone,
- "email": this.form.email,
- "captcha": grecaptcha.getResponse()
+ "email": this.form.email
}).then((response) => {
this.sending = false
if (response.data["code"] === 200) {
@@ -168,7 +167,6 @@
this.sending = false
this.$emit("generalError",error)
})
- grecaptcha.reset()
},
reset() {
this.validateItems = {
@@ -218,7 +216,7 @@
this.$v.$touch()
if (!this.$v.$invalid) {
this.form.email = null
- grecaptcha.execute()
+ this.send()
}
},
sendEmail() {
@@ -231,7 +229,7 @@
this.$v.$touch()
if (!this.$v.$invalid) {
this.form.phone = null
- grecaptcha.execute()
+ this.send()
}
},
showMsg(msg) {
@@ -240,14 +238,6 @@
},
mounted: function () {
this.$emit("changeTitle", this.$t("reset-title"))
- this.$emit("prepareRecaptcha")
- },
- watch: {
- gResponse: {
- handler: function (val, newVal) {
- this.ct();
- }
- }
}
}
diff --git a/web/components/User/Security.vue b/web/components/User/Security.vue
index 8e53e4b..3fe4e5e 100644
--- a/web/components/User/Security.vue
+++ b/web/components/User/Security.vue
@@ -112,7 +112,6 @@
},
mounted: function () {
this.$emit("changeTitle", this.$t("security-title"))
- this.$emit("prepareRecaptcha")
this.incomplete = (this.$route.query.reason === 'incomplete')
},
methods: {
@@ -157,19 +156,18 @@
},
sendEmail() {
this.task = "email"
- grecaptcha.execute()
+ this.send()
},
sendSMS() {
this.task = "sms"
- grecaptcha.execute()
+ this.send()
},
- ct() {
+ send() {
switch (this.task) {
case "email":
this.axios.post("/user/code", {
"type": 3,
- "email": this.form.newEmail,
- "captcha": grecaptcha.getResponse()
+ "email": this.form.newEmail
}).then((response) => {
if (response.data["code"] === 200) {
this.showMsg(this.$t("send-succeeded"))
@@ -197,18 +195,10 @@
}
this.task = ""
- grecaptcha.reset()
},
showMsg(msg) {
this.$emit("showMsg", msg)
}
- },
- watch: {
- gResponse: {
- handler: function (val, newVal) {
- this.ct();
- }
- }
}
}
diff --git a/web/main.js b/web/main.js
index 9605d05..af04901 100644
--- a/web/main.js
+++ b/web/main.js
@@ -10,7 +10,6 @@ import VueAxios from 'vue-axios'
import VuePreview from 'vue-preview'
import 'vue-material/dist/vue-material.css'
import 'vue-material/dist/theme/default.css'
-import VueMarkdown from 'vue-markdown'
import VueAnalytics from 'vue-analytics'
import Raven from 'raven-js'
import RavenVue from 'raven-js/plugins/vue'