Enable reCAPTCHA on "forgot" page
This commit is contained in:
parent
3e7836b9ff
commit
64658fd9f2
|
|
@ -162,7 +162,12 @@ class AuthController extends Controller
|
||||||
public function forgot()
|
public function forgot()
|
||||||
{
|
{
|
||||||
if (config('mail.driver') != '') {
|
if (config('mail.driver') != '') {
|
||||||
return view('auth.forgot');
|
return view('auth.forgot', [
|
||||||
|
'extra' => [
|
||||||
|
'recaptcha' => option('recaptcha_sitekey'),
|
||||||
|
'invisible' => (bool) option('recaptcha_invisible'),
|
||||||
|
]
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
throw new PrettyPageException(trans('auth.forgot.disabled'), 8);
|
throw new PrettyPageException(trans('auth.forgot.disabled'), 8);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,30 +11,7 @@
|
||||||
<span class="glyphicon glyphicon-envelope form-control-feedback" />
|
<span class="glyphicon glyphicon-envelope form-control-feedback" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<captcha ref="captcha" />
|
||||||
<div class="col-xs-8">
|
|
||||||
<div class="form-group has-feedback">
|
|
||||||
<input
|
|
||||||
ref="captcha"
|
|
||||||
v-model="captcha"
|
|
||||||
type="text"
|
|
||||||
class="form-control"
|
|
||||||
:placeholder="$t('auth.captcha')"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-4">
|
|
||||||
<img
|
|
||||||
class="pull-right captcha"
|
|
||||||
:src="`${baseUrl}/auth/captcha?v=${time}`"
|
|
||||||
alt="CAPTCHA"
|
|
||||||
:title="$t('auth.change-captcha')"
|
|
||||||
data-placement="top"
|
|
||||||
data-toggle="tooltip"
|
|
||||||
@click="refreshCaptcha"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="callout callout-success" :class="{ hide: !successMsg }">{{ successMsg }}</div>
|
<div class="callout callout-success" :class="{ hide: !successMsg }">{{ successMsg }}</div>
|
||||||
<div class="callout callout-info" :class="{ hide: !infoMsg }">{{ infoMsg }}</div>
|
<div class="callout callout-info" :class="{ hide: !infoMsg }">{{ infoMsg }}</div>
|
||||||
|
|
@ -61,8 +38,13 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Captcha from '../../components/Captcha.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Forgot',
|
name: 'Forgot',
|
||||||
|
components: {
|
||||||
|
Captcha,
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
baseUrl: {
|
baseUrl: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|
@ -71,8 +53,6 @@ export default {
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
email: '',
|
email: '',
|
||||||
captcha: '',
|
|
||||||
time: Date.now(),
|
|
||||||
successMsg: '',
|
successMsg: '',
|
||||||
infoMsg: '',
|
infoMsg: '',
|
||||||
warningMsg: '',
|
warningMsg: '',
|
||||||
|
|
@ -80,7 +60,7 @@ export default {
|
||||||
}),
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
async submit() {
|
async submit() {
|
||||||
const { email, captcha } = this
|
const { email } = this
|
||||||
|
|
||||||
if (!email) {
|
if (!email) {
|
||||||
this.infoMsg = this.$t('auth.emptyEmail')
|
this.infoMsg = this.$t('auth.emptyEmail')
|
||||||
|
|
@ -94,16 +74,10 @@ export default {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!captcha) {
|
|
||||||
this.infoMsg = this.$t('auth.emptyCaptcha')
|
|
||||||
this.$refs.captcha.focus()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.pending = true
|
this.pending = true
|
||||||
const { errno, msg } = await this.$http.post(
|
const { errno, msg } = await this.$http.post(
|
||||||
'/auth/forgot',
|
'/auth/forgot',
|
||||||
{ email, captcha }
|
{ email, captcha: await this.$refs.captcha.execute() }
|
||||||
)
|
)
|
||||||
if (errno === 0) {
|
if (errno === 0) {
|
||||||
this.infoMsg = ''
|
this.infoMsg = ''
|
||||||
|
|
@ -113,13 +87,10 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
this.infoMsg = ''
|
this.infoMsg = ''
|
||||||
this.warningMsg = msg
|
this.warningMsg = msg
|
||||||
this.refreshCaptcha()
|
|
||||||
this.pending = false
|
this.pending = false
|
||||||
|
this.$refs.captcha.refreshCaptcha()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
refreshCaptcha() {
|
|
||||||
this.time = Date.now()
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import Forgot from '@/views/auth/Forgot.vue'
|
import Forgot from '@/views/auth/Forgot.vue'
|
||||||
|
import { flushPromises } from '../../utils'
|
||||||
|
|
||||||
test('click to refresh captcha', () => {
|
window.blessing.extra = {}
|
||||||
jest.spyOn(Date, 'now')
|
const Captcha = Vue.extend({
|
||||||
const wrapper = mount(Forgot)
|
methods: {
|
||||||
wrapper.find('img').trigger('click')
|
execute() {
|
||||||
expect(Date.now).toBeCalledTimes(2)
|
return Promise.resolve('captcha')
|
||||||
|
},
|
||||||
|
refreshCaptcha() { /* */ },
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
test('submit forgot form', async () => {
|
test('submit forgot form', async () => {
|
||||||
|
|
@ -14,7 +18,7 @@ test('submit forgot form', async () => {
|
||||||
Vue.prototype.$http.post
|
Vue.prototype.$http.post
|
||||||
.mockResolvedValueOnce({ errno: 1, msg: 'fail' })
|
.mockResolvedValueOnce({ errno: 1, msg: 'fail' })
|
||||||
.mockResolvedValueOnce({ errno: 0, msg: 'ok' })
|
.mockResolvedValueOnce({ errno: 0, msg: 'ok' })
|
||||||
const wrapper = mount(Forgot)
|
const wrapper = mount(Forgot, { stubs: { Captcha } })
|
||||||
const button = wrapper.find('button')
|
const button = wrapper.find('button')
|
||||||
const info = wrapper.find('.callout-info')
|
const info = wrapper.find('.callout-info')
|
||||||
const warning = wrapper.find('.callout-warning')
|
const warning = wrapper.find('.callout-warning')
|
||||||
|
|
@ -31,20 +35,14 @@ test('submit forgot form', async () => {
|
||||||
|
|
||||||
wrapper.find('[type="email"]').setValue('a@b.c')
|
wrapper.find('[type="email"]').setValue('a@b.c')
|
||||||
button.trigger('click')
|
button.trigger('click')
|
||||||
expect(Vue.prototype.$http.post).not.toBeCalled()
|
await flushPromises()
|
||||||
expect(info.text()).toBe('auth.emptyCaptcha')
|
|
||||||
|
|
||||||
wrapper.find('[type="text"]').setValue('captcha')
|
|
||||||
button.trigger('click')
|
|
||||||
await wrapper.vm.$nextTick()
|
|
||||||
expect(Vue.prototype.$http.post).toBeCalledWith(
|
expect(Vue.prototype.$http.post).toBeCalledWith(
|
||||||
'/auth/forgot',
|
'/auth/forgot',
|
||||||
{ email: 'a@b.c', captcha: 'captcha' }
|
{ email: 'a@b.c', captcha: 'captcha' }
|
||||||
)
|
)
|
||||||
expect(warning.text()).toBe('fail')
|
expect(warning.text()).toBe('fail')
|
||||||
expect(Date.now).toBeCalledTimes(2)
|
|
||||||
|
|
||||||
button.trigger('click')
|
button.trigger('click')
|
||||||
await wrapper.vm.$nextTick()
|
await flushPromises()
|
||||||
expect(success.text()).toBe('ok')
|
expect(success.text()).toBe('ok')
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -22,5 +22,11 @@
|
||||||
<!-- /.login-box-body -->
|
<!-- /.login-box-body -->
|
||||||
</div>
|
</div>
|
||||||
<!-- /.login-box -->
|
<!-- /.login-box -->
|
||||||
|
@include('common.recaptcha')
|
||||||
|
<script>
|
||||||
|
Object.defineProperty(blessing, 'extra', {
|
||||||
|
get: () => Object.freeze(@json($extra)),
|
||||||
|
configurable: false
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user