Support invisible reCAPTCHA
This commit is contained in:
parent
d5903f6412
commit
04b8f73ac4
|
|
@ -236,6 +236,7 @@ class AdminController extends Controller
|
||||||
$recaptcha = Option::form('recaptcha', 'reCAPTCHA', function ($form) {
|
$recaptcha = Option::form('recaptcha', 'reCAPTCHA', function ($form) {
|
||||||
$form->text('recaptcha_sitekey', 'sitekey');
|
$form->text('recaptcha_sitekey', 'sitekey');
|
||||||
$form->text('recaptcha_secretkey', 'secretkey');
|
$form->text('recaptcha_secretkey', 'secretkey');
|
||||||
|
$form->checkbox('recaptcha_invisible')->label();
|
||||||
})->handle();
|
})->handle();
|
||||||
|
|
||||||
return view('admin.options')
|
return view('admin.options')
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@ class AuthController extends Controller
|
||||||
'extra' => [
|
'extra' => [
|
||||||
'player' => option('register_with_player_name'),
|
'player' => option('register_with_player_name'),
|
||||||
'recaptcha' => option('recaptcha_sitekey'),
|
'recaptcha' => option('recaptcha_sitekey'),
|
||||||
|
'invisible' => (bool) option('recaptcha_invisible'),
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -52,4 +52,5 @@ return [
|
||||||
'cdn_address' => '',
|
'cdn_address' => '',
|
||||||
'recaptcha_sitekey' => '',
|
'recaptcha_sitekey' => '',
|
||||||
'recaptcha_secretkey' => '',
|
'recaptcha_secretkey' => '',
|
||||||
|
'recaptcha_invisible' => 'false',
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,9 @@
|
||||||
<div class="col-xs-12" style="padding-bottom: 5px">
|
<div class="col-xs-12" style="padding-bottom: 5px">
|
||||||
<vue-recaptcha
|
<vue-recaptcha
|
||||||
ref="recaptcha"
|
ref="recaptcha"
|
||||||
|
:size="invisible ? 'invisible' : ''"
|
||||||
:sitekey="recaptcha"
|
:sitekey="recaptcha"
|
||||||
@verify="$emit('change', $event)"
|
@verify="onVerify"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -13,10 +14,10 @@
|
||||||
<div class="form-group has-feedback">
|
<div class="form-group has-feedback">
|
||||||
<input
|
<input
|
||||||
ref="captcha"
|
ref="captcha"
|
||||||
|
v-model="value"
|
||||||
type="text"
|
type="text"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
:placeholder="$t('auth.captcha')"
|
:placeholder="$t('auth.captcha')"
|
||||||
@input="$emit('change', $event.target.value)"
|
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -50,11 +51,26 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
value: '',
|
||||||
time: Date.now(),
|
time: Date.now(),
|
||||||
recaptcha: blessing.extra.recaptcha,
|
recaptcha: blessing.extra.recaptcha,
|
||||||
|
invisible: blessing.extra.invisible,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
execute() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
if (this.invisible) {
|
||||||
|
this.$refs.recaptcha.$once('verify', resolve)
|
||||||
|
this.$refs.recaptcha.execute()
|
||||||
|
} else {
|
||||||
|
resolve(this.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onVerify(response) {
|
||||||
|
this.value = response
|
||||||
|
},
|
||||||
refreshCaptcha() {
|
refreshCaptcha() {
|
||||||
if (this.recaptcha) {
|
if (this.recaptcha) {
|
||||||
this.$refs.recaptcha.reset()
|
this.$refs.recaptcha.reset()
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
import Vue from 'vue'
|
|
||||||
|
|
||||||
export default Vue.extend({
|
|
||||||
data: () => ({
|
|
||||||
captcha: '',
|
|
||||||
}),
|
|
||||||
methods: {
|
|
||||||
updateCaptcha(value: string) {
|
|
||||||
this.captcha = value
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<form>
|
<form @submit.prevent="login">
|
||||||
<div class="form-group has-feedback">
|
<div class="form-group has-feedback">
|
||||||
<input
|
<input
|
||||||
ref="identification"
|
ref="identification"
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
<span class="glyphicon glyphicon-lock form-control-feedback" />
|
<span class="glyphicon glyphicon-lock form-control-feedback" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<captcha v-if="tooManyFails" ref="captcha" @change="updateCaptcha" />
|
<captcha v-if="tooManyFails" ref="captcha" />
|
||||||
|
|
||||||
<div class="callout callout-info" :class="{ hide: !infoMsg }">{{ infoMsg }}</div>
|
<div class="callout callout-info" :class="{ hide: !infoMsg }">{{ infoMsg }}</div>
|
||||||
<div class="callout callout-warning" :class="{ hide: !warningMsg }">{{ warningMsg }}</div>
|
<div class="callout callout-warning" :class="{ hide: !warningMsg }">{{ warningMsg }}</div>
|
||||||
|
|
@ -47,7 +47,7 @@
|
||||||
<button
|
<button
|
||||||
v-else
|
v-else
|
||||||
class="btn btn-primary btn-block btn-flat"
|
class="btn btn-primary btn-block btn-flat"
|
||||||
@click.prevent="login"
|
type="submit"
|
||||||
>
|
>
|
||||||
{{ $t('auth.login') }}
|
{{ $t('auth.login') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -59,16 +59,12 @@
|
||||||
<script>
|
<script>
|
||||||
import { swal } from '../../js/notify'
|
import { swal } from '../../js/notify'
|
||||||
import Captcha from '../../components/Captcha.vue'
|
import Captcha from '../../components/Captcha.vue'
|
||||||
import updateCaptcha from '../../components/mixins/updateCaptcha'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Login',
|
name: 'Login',
|
||||||
components: {
|
components: {
|
||||||
Captcha,
|
Captcha,
|
||||||
},
|
},
|
||||||
mixins: [
|
|
||||||
updateCaptcha,
|
|
||||||
],
|
|
||||||
props: {
|
props: {
|
||||||
baseUrl: {
|
baseUrl: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|
@ -79,7 +75,6 @@ export default {
|
||||||
return {
|
return {
|
||||||
identification: '',
|
identification: '',
|
||||||
password: '',
|
password: '',
|
||||||
captcha: '',
|
|
||||||
remember: false,
|
remember: false,
|
||||||
tooManyFails: blessing.extra.tooManyFails,
|
tooManyFails: blessing.extra.tooManyFails,
|
||||||
infoMsg: '',
|
infoMsg: '',
|
||||||
|
|
@ -90,7 +85,7 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
async login() {
|
async login() {
|
||||||
const {
|
const {
|
||||||
identification, password, captcha, remember,
|
identification, password, remember,
|
||||||
} = this
|
} = this
|
||||||
|
|
||||||
if (!identification) {
|
if (!identification) {
|
||||||
|
|
@ -114,7 +109,9 @@ export default {
|
||||||
identification,
|
identification,
|
||||||
password,
|
password,
|
||||||
keep: remember,
|
keep: remember,
|
||||||
captcha: this.tooManyFails ? captcha : undefined,
|
captcha: this.tooManyFails
|
||||||
|
? await this.$refs.captcha.execute()
|
||||||
|
: void 0,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if (errno === 0) {
|
if (errno === 0) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<form>
|
<form @submit.prevent="submit">
|
||||||
<div class="form-group has-feedback">
|
<div class="form-group has-feedback">
|
||||||
<input
|
<input
|
||||||
ref="email"
|
ref="email"
|
||||||
|
|
@ -80,7 +80,7 @@
|
||||||
<button
|
<button
|
||||||
v-else
|
v-else
|
||||||
class="btn btn-primary btn-block btn-flat"
|
class="btn btn-primary btn-block btn-flat"
|
||||||
@click.prevent="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
{{ $t('auth.register-button') }}
|
{{ $t('auth.register-button') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -92,16 +92,12 @@
|
||||||
<script>
|
<script>
|
||||||
import { swal } from '../../js/notify'
|
import { swal } from '../../js/notify'
|
||||||
import Captcha from '../../components/Captcha.vue'
|
import Captcha from '../../components/Captcha.vue'
|
||||||
import updateCaptcha from '../../components/mixins/updateCaptcha'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Register',
|
name: 'Register',
|
||||||
components: {
|
components: {
|
||||||
Captcha,
|
Captcha,
|
||||||
},
|
},
|
||||||
mixins: [
|
|
||||||
updateCaptcha,
|
|
||||||
],
|
|
||||||
props: {
|
props: {
|
||||||
baseUrl: {
|
baseUrl: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|
@ -114,7 +110,6 @@ export default {
|
||||||
confirm: '',
|
confirm: '',
|
||||||
nickname: '',
|
nickname: '',
|
||||||
playerName: '',
|
playerName: '',
|
||||||
captcha: '',
|
|
||||||
infoMsg: '',
|
infoMsg: '',
|
||||||
warningMsg: '',
|
warningMsg: '',
|
||||||
pending: false,
|
pending: false,
|
||||||
|
|
@ -174,7 +169,7 @@ export default {
|
||||||
Object.assign({
|
Object.assign({
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
captcha,
|
captcha: await this.$refs.captcha.execute(),
|
||||||
}, this.requirePlayer ? { player_name: playerName } : { nickname })
|
}, this.requirePlayer ? { player_name: playerName } : { nickname })
|
||||||
)
|
)
|
||||||
if (errno === 0) {
|
if (errno === 0) {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,14 @@ import Vue from 'vue'
|
||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import Captcha from '@/components/Captcha.vue'
|
import Captcha from '@/components/Captcha.vue'
|
||||||
|
|
||||||
|
const VueRecaptcha = Vue.extend({
|
||||||
|
methods: {
|
||||||
|
execute() {
|
||||||
|
this.$emit('verify', 'value')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
test('display recaptcha', () => {
|
test('display recaptcha', () => {
|
||||||
blessing.extra = { recaptcha: 'sitekey' }
|
blessing.extra = { recaptcha: 'sitekey' }
|
||||||
const wrapper = mount(Captcha)
|
const wrapper = mount(Captcha)
|
||||||
|
|
@ -13,12 +21,28 @@ test('refresh recaptcha', () => {
|
||||||
wrapper.vm.refreshCaptcha()
|
wrapper.vm.refreshCaptcha()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('display characters captcha', () => {
|
test('recaptcha verified', () => {
|
||||||
|
const wrapper =
|
||||||
|
mount<Vue & { onVerify(response: string): void, value: string }>(Captcha)
|
||||||
|
wrapper.vm.onVerify('value')
|
||||||
|
expect(wrapper.vm.value).toBe('value')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('invoke recaptcha', async () => {
|
||||||
|
const wrapper = mount<Vue & { execute(): Promise<string> }>(Captcha, { stubs: { VueRecaptcha } })
|
||||||
|
wrapper.setData({ invisible: true })
|
||||||
|
expect(await wrapper.vm.execute()).toBe('value')
|
||||||
|
|
||||||
|
wrapper.setData({ invisible: false, value: 'haha' })
|
||||||
|
expect(await wrapper.vm.execute()).toBe('haha')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('display characters captcha', async () => {
|
||||||
blessing.extra = {}
|
blessing.extra = {}
|
||||||
const wrapper = mount(Captcha)
|
const wrapper = mount<Vue & { execute(): Promise<string> }>(Captcha)
|
||||||
expect(wrapper.find('img').exists()).toBeTrue()
|
expect(wrapper.find('img').exists()).toBeTrue()
|
||||||
wrapper.find('input').setValue('abc')
|
wrapper.find('input').setValue('abc')
|
||||||
expect(wrapper.emitted().change[0][0]).toBe('abc')
|
expect(await wrapper.vm.execute()).toBe('abc')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('refresh captcha', () => {
|
test('refresh captcha', () => {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
import { mount } from '@vue/test-utils'
|
|
||||||
import updateCaptcha from '@/components/mixins/updateCaptcha'
|
|
||||||
|
|
||||||
test('update captcha', () => {
|
|
||||||
const wrapper = mount(updateCaptcha)
|
|
||||||
wrapper.vm.updateCaptcha('value')
|
|
||||||
expect(wrapper.vm.captcha).toBe('value')
|
|
||||||
})
|
|
||||||
|
|
@ -5,6 +5,16 @@ import { swal } from '@/js/notify'
|
||||||
|
|
||||||
jest.mock('@/js/notify')
|
jest.mock('@/js/notify')
|
||||||
|
|
||||||
|
const Captcha = Vue.extend({
|
||||||
|
methods: {
|
||||||
|
execute() {
|
||||||
|
return Promise.resolve('a')
|
||||||
|
},
|
||||||
|
refreshCaptcha() { /* */ },
|
||||||
|
},
|
||||||
|
template: '<img>',
|
||||||
|
})
|
||||||
|
|
||||||
test('show captcha if too many login fails', () => {
|
test('show captcha if too many login fails', () => {
|
||||||
window.blessing.extra = { tooManyFails: true }
|
window.blessing.extra = { tooManyFails: true }
|
||||||
const wrapper = mount(Login)
|
const wrapper = mount(Login)
|
||||||
|
|
@ -17,22 +27,22 @@ test('login', async () => {
|
||||||
.mockResolvedValueOnce({ errno: 1, msg: 'fail' })
|
.mockResolvedValueOnce({ errno: 1, msg: 'fail' })
|
||||||
.mockResolvedValueOnce({ errno: 1, login_fails: 4 })
|
.mockResolvedValueOnce({ errno: 1, login_fails: 4 })
|
||||||
.mockResolvedValueOnce({ errno: 0, msg: 'ok' })
|
.mockResolvedValueOnce({ errno: 0, msg: 'ok' })
|
||||||
const wrapper = mount(Login)
|
const wrapper = mount(Login, { stubs: { Captcha } })
|
||||||
const button = wrapper.find('button')
|
const form = wrapper.find('form')
|
||||||
const info = wrapper.find('.callout-info')
|
const info = wrapper.find('.callout-info')
|
||||||
const warning = wrapper.find('.callout-warning')
|
const warning = wrapper.find('.callout-warning')
|
||||||
|
|
||||||
button.trigger('click')
|
form.trigger('submit')
|
||||||
expect(Vue.prototype.$http.post).not.toBeCalled()
|
expect(Vue.prototype.$http.post).not.toBeCalled()
|
||||||
expect(info.text()).toBe('auth.emptyIdentification')
|
expect(info.text()).toBe('auth.emptyIdentification')
|
||||||
|
|
||||||
wrapper.find('[type="email"]').setValue('a@b.c')
|
wrapper.find('[type="email"]').setValue('a@b.c')
|
||||||
button.trigger('click')
|
form.trigger('submit')
|
||||||
expect(Vue.prototype.$http.post).not.toBeCalled()
|
expect(Vue.prototype.$http.post).not.toBeCalled()
|
||||||
expect(info.text()).toBe('auth.emptyPassword')
|
expect(info.text()).toBe('auth.emptyPassword')
|
||||||
|
|
||||||
wrapper.find('[type="password"]').setValue('123')
|
wrapper.find('[type="password"]').setValue('123')
|
||||||
button.trigger('click')
|
form.trigger('submit')
|
||||||
await wrapper.vm.$nextTick()
|
await wrapper.vm.$nextTick()
|
||||||
expect(Vue.prototype.$http.post).toBeCalledWith(
|
expect(Vue.prototype.$http.post).toBeCalledWith(
|
||||||
'/auth/login',
|
'/auth/login',
|
||||||
|
|
@ -42,14 +52,14 @@ test('login', async () => {
|
||||||
)
|
)
|
||||||
expect(warning.text()).toBe('fail')
|
expect(warning.text()).toBe('fail')
|
||||||
|
|
||||||
button.trigger('click')
|
form.trigger('submit')
|
||||||
await wrapper.vm.$nextTick()
|
await wrapper.vm.$nextTick()
|
||||||
expect(swal).toBeCalledWith({ type: 'error', text: 'auth.tooManyFails' })
|
expect(swal).toBeCalledWith({ type: 'error', text: 'auth.tooManyFails' })
|
||||||
expect(wrapper.find('img').exists()).toBeTrue()
|
expect(wrapper.find('img').exists()).toBeTrue()
|
||||||
|
|
||||||
wrapper.find('[type="text"]').setValue('a')
|
|
||||||
wrapper.find('[type="checkbox"]').setChecked()
|
wrapper.find('[type="checkbox"]').setChecked()
|
||||||
button.trigger('click')
|
form.trigger('submit')
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
expect(Vue.prototype.$http.post).toBeCalledWith(
|
expect(Vue.prototype.$http.post).toBeCalledWith(
|
||||||
'/auth/login',
|
'/auth/login',
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,21 @@ import Vue from 'vue'
|
||||||
import { mount } from '@vue/test-utils'
|
import { mount } from '@vue/test-utils'
|
||||||
import Register from '@/views/auth/Register.vue'
|
import Register from '@/views/auth/Register.vue'
|
||||||
import { swal } from '@/js/notify'
|
import { swal } from '@/js/notify'
|
||||||
|
import { flushPromises } from '../../utils'
|
||||||
|
|
||||||
jest.mock('@/js/notify')
|
jest.mock('@/js/notify')
|
||||||
|
|
||||||
window.blessing.extra = { player: false }
|
window.blessing.extra = { player: false }
|
||||||
|
|
||||||
|
const Captcha = Vue.extend({
|
||||||
|
methods: {
|
||||||
|
execute() {
|
||||||
|
return Promise.resolve('captcha')
|
||||||
|
},
|
||||||
|
refreshCaptcha() { /* */ },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
test('require player name', () => {
|
test('require player name', () => {
|
||||||
window.blessing.extra = { player: true }
|
window.blessing.extra = { player: true }
|
||||||
|
|
||||||
|
|
@ -22,54 +32,52 @@ test('register', 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(Register)
|
const wrapper = mount(Register, { stubs: { Captcha } })
|
||||||
const button = wrapper.find('button')
|
const form = wrapper.find('form')
|
||||||
const info = wrapper.find('.callout-info')
|
const info = wrapper.find('.callout-info')
|
||||||
const warning = wrapper.find('.callout-warning')
|
const warning = wrapper.find('.callout-warning')
|
||||||
|
|
||||||
button.trigger('click')
|
form.trigger('submit')
|
||||||
expect(Vue.prototype.$http.post).not.toBeCalled()
|
expect(Vue.prototype.$http.post).not.toBeCalled()
|
||||||
expect(info.text()).toBe('auth.emptyEmail')
|
expect(info.text()).toBe('auth.emptyEmail')
|
||||||
|
|
||||||
wrapper.find('[type="email"]').setValue('a')
|
wrapper.find('[type="email"]').setValue('a')
|
||||||
button.trigger('click')
|
form.trigger('submit')
|
||||||
expect(Vue.prototype.$http.post).not.toBeCalled()
|
expect(Vue.prototype.$http.post).not.toBeCalled()
|
||||||
expect(info.text()).toBe('auth.invalidEmail')
|
expect(info.text()).toBe('auth.invalidEmail')
|
||||||
|
|
||||||
wrapper.find('[type="email"]').setValue('a@b.c')
|
wrapper.find('[type="email"]').setValue('a@b.c')
|
||||||
button.trigger('click')
|
form.trigger('submit')
|
||||||
expect(Vue.prototype.$http.post).not.toBeCalled()
|
expect(Vue.prototype.$http.post).not.toBeCalled()
|
||||||
expect(info.text()).toBe('auth.emptyPassword')
|
expect(info.text()).toBe('auth.emptyPassword')
|
||||||
|
|
||||||
wrapper.findAll('[type="password"]').at(0)
|
wrapper.findAll('[type="password"]').at(0)
|
||||||
.setValue('123456')
|
.setValue('123456')
|
||||||
button.trigger('click')
|
form.trigger('submit')
|
||||||
expect(Vue.prototype.$http.post).not.toBeCalled()
|
expect(Vue.prototype.$http.post).not.toBeCalled()
|
||||||
expect(info.text()).toBe('auth.invalidPassword')
|
expect(info.text()).toBe('auth.invalidPassword')
|
||||||
|
|
||||||
wrapper.findAll('[type="password"]').at(0)
|
wrapper.findAll('[type="password"]').at(0)
|
||||||
.setValue('12345678')
|
.setValue('12345678')
|
||||||
button.trigger('click')
|
form.trigger('submit')
|
||||||
expect(Vue.prototype.$http.post).not.toBeCalled()
|
expect(Vue.prototype.$http.post).not.toBeCalled()
|
||||||
expect(info.text()).toBe('auth.invalidConfirmPwd')
|
expect(info.text()).toBe('auth.invalidConfirmPwd')
|
||||||
|
|
||||||
wrapper.findAll('[type="password"]').at(1)
|
wrapper.findAll('[type="password"]').at(1)
|
||||||
.setValue('123456')
|
.setValue('123456')
|
||||||
button.trigger('click')
|
form.trigger('submit')
|
||||||
expect(Vue.prototype.$http.post).not.toBeCalled()
|
expect(Vue.prototype.$http.post).not.toBeCalled()
|
||||||
expect(info.text()).toBe('auth.invalidConfirmPwd')
|
expect(info.text()).toBe('auth.invalidConfirmPwd')
|
||||||
|
|
||||||
wrapper.findAll('[type="password"]').at(1)
|
wrapper.findAll('[type="password"]').at(1)
|
||||||
.setValue('12345678')
|
.setValue('12345678')
|
||||||
button.trigger('click')
|
form.trigger('submit')
|
||||||
expect(Vue.prototype.$http.post).not.toBeCalled()
|
expect(Vue.prototype.$http.post).not.toBeCalled()
|
||||||
expect(info.text()).toBe('auth.emptyNickname')
|
expect(info.text()).toBe('auth.emptyNickname')
|
||||||
|
|
||||||
wrapper.findAll('[type="text"]').at(0)
|
wrapper.findAll('[type="text"]').at(0)
|
||||||
.setValue('abc')
|
.setValue('abc')
|
||||||
wrapper.findAll('[type="text"]').at(1)
|
form.trigger('submit')
|
||||||
.setValue('captcha')
|
|
||||||
button.trigger('click')
|
|
||||||
await wrapper.vm.$nextTick()
|
await wrapper.vm.$nextTick()
|
||||||
expect(Vue.prototype.$http.post).toBeCalledWith(
|
expect(Vue.prototype.$http.post).toBeCalledWith(
|
||||||
'/auth/register',
|
'/auth/register',
|
||||||
|
|
@ -80,11 +88,11 @@ test('register', async () => {
|
||||||
captcha: 'captcha',
|
captcha: 'captcha',
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
expect(warning.text()).toBe('fail')
|
|
||||||
expect(Date.now).toBeCalledTimes(2)
|
|
||||||
|
|
||||||
button.trigger('click')
|
|
||||||
await wrapper.vm.$nextTick()
|
await wrapper.vm.$nextTick()
|
||||||
|
expect(warning.text()).toBe('fail')
|
||||||
|
|
||||||
|
form.trigger('submit')
|
||||||
|
await flushPromises()
|
||||||
jest.runAllTimers()
|
jest.runAllTimers()
|
||||||
expect(swal).toBeCalledWith({ type: 'success', text: 'ok' })
|
expect(swal).toBeCalledWith({ type: 'success', text: 'ok' })
|
||||||
})
|
})
|
||||||
|
|
@ -92,24 +100,22 @@ test('register', async () => {
|
||||||
test('register with player name', async () => {
|
test('register with player name', async () => {
|
||||||
window.blessing.extra = { player: true }
|
window.blessing.extra = { player: true }
|
||||||
Vue.prototype.$http.post.mockResolvedValue({ errno: 0, msg: 'ok' })
|
Vue.prototype.$http.post.mockResolvedValue({ errno: 0, msg: 'ok' })
|
||||||
const wrapper = mount(Register)
|
const wrapper = mount(Register, { stubs: { Captcha } })
|
||||||
const button = wrapper.find('button')
|
const form = wrapper.find('form')
|
||||||
const info = wrapper.find('.callout-info')
|
const info = wrapper.find('.callout-info')
|
||||||
wrapper.find('[type="email"]').setValue('a@b.c')
|
wrapper.find('[type="email"]').setValue('a@b.c')
|
||||||
wrapper.findAll('[type="password"]').at(0)
|
wrapper.findAll('[type="password"]').at(0)
|
||||||
.setValue('12345678')
|
.setValue('12345678')
|
||||||
wrapper.findAll('[type="password"]').at(1)
|
wrapper.findAll('[type="password"]').at(1)
|
||||||
.setValue('12345678')
|
.setValue('12345678')
|
||||||
wrapper.findAll('[type="text"]').at(1)
|
|
||||||
.setValue('captcha')
|
|
||||||
|
|
||||||
button.trigger('click')
|
form.trigger('submit')
|
||||||
expect(Vue.prototype.$http.post).not.toBeCalled()
|
expect(Vue.prototype.$http.post).not.toBeCalled()
|
||||||
expect(info.text()).toBe('auth.emptyPlayerName')
|
expect(info.text()).toBe('auth.emptyPlayerName')
|
||||||
|
|
||||||
wrapper.findAll('[type="text"]').at(0)
|
wrapper.findAll('[type="text"]').at(0)
|
||||||
.setValue('abc')
|
.setValue('abc')
|
||||||
button.trigger('click')
|
form.trigger('submit')
|
||||||
await wrapper.vm.$nextTick()
|
await wrapper.vm.$nextTick()
|
||||||
expect(Vue.prototype.$http.post).toBeCalledWith(
|
expect(Vue.prototype.$http.post).toBeCalledWith(
|
||||||
'/auth/register',
|
'/auth/register',
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,11 @@ meta:
|
||||||
meta_extras:
|
meta_extras:
|
||||||
title: Other Custom <meta> Tags
|
title: Other Custom <meta> Tags
|
||||||
|
|
||||||
|
recaptcha:
|
||||||
|
recaptcha_invisible:
|
||||||
|
title: Invisible
|
||||||
|
label: Enable Invisible Mode
|
||||||
|
|
||||||
res-warning: This page is ONLY for advanced users. If you aren't familiar with these, please don't modify them!
|
res-warning: This page is ONLY for advanced users. If you aren't familiar with these, please don't modify them!
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,11 @@ meta:
|
||||||
meta_extras:
|
meta_extras:
|
||||||
title: 其它自定义 <meta> 标签
|
title: 其它自定义 <meta> 标签
|
||||||
|
|
||||||
|
recaptcha:
|
||||||
|
recaptcha_invisible:
|
||||||
|
title: 隐藏
|
||||||
|
label: 开启隐藏式人机验证模式
|
||||||
|
|
||||||
res-warning: 本页面仅供高级用户使用。如果您不清楚这些设置的含义,请不要随意修改它们!
|
res-warning: 本页面仅供高级用户使用。如果您不清楚这些设置的含义,请不要随意修改它们!
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
|
|
|
||||||
|
|
@ -24,13 +24,17 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- /.login-box -->
|
<!-- /.login-box -->
|
||||||
@include('common.recaptcha')
|
@include('common.recaptcha')
|
||||||
|
@php
|
||||||
|
$extra = [
|
||||||
|
'tooManyFails' => cache(sha1('login_fails_'.get_client_ip())) > 3,
|
||||||
|
'recaptcha' => option('recaptcha_sitekey'),
|
||||||
|
'invisible' => (bool) option('recaptcha_invisible'),
|
||||||
|
];
|
||||||
|
@endphp
|
||||||
<script>
|
<script>
|
||||||
Object.defineProperty(blessing, 'extra', {
|
Object.defineProperty(blessing, 'extra', {
|
||||||
configurable: false,
|
configurable: false,
|
||||||
get: () => Object.freeze(@json([
|
get: () => Object.freeze(@json($extra))
|
||||||
'tooManyFails' => cache(sha1('login_fails_'.get_client_ip())) > 3,
|
|
||||||
'recaptcha' => option('recaptcha_sitekey'),
|
|
||||||
]))
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -163,9 +163,11 @@ class AdminControllerTest extends BrowserKitTestCase
|
||||||
$this->visit('/admin/options')
|
$this->visit('/admin/options')
|
||||||
->type('key', 'recaptcha_sitekey')
|
->type('key', 'recaptcha_sitekey')
|
||||||
->type('secret', 'recaptcha_secretkey')
|
->type('secret', 'recaptcha_secretkey')
|
||||||
|
->check('recaptcha_invisible')
|
||||||
->press('submit_recaptcha');
|
->press('submit_recaptcha');
|
||||||
$this->assertEquals('key', option('recaptcha_sitekey'));
|
$this->assertEquals('key', option('recaptcha_sitekey'));
|
||||||
$this->assertEquals('secret', option('recaptcha_secretkey'));
|
$this->assertEquals('secret', option('recaptcha_secretkey'));
|
||||||
|
$this->assertTrue(option('recaptcha_invisible'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testResource()
|
public function testResource()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user