Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ docker compose run ui npm install
docker compose up -d
```

reCAPTCHA is disabled in the UI's Docker Compose development server by default;
set `VUE_APP_RECAPTCHA_ENABLED=1` and configure the API's
`RECAPTCHA_ENABLED=true` to test with real reCAPTCHA keys.

#### Running scripts

```
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ services:
ui:
env_file:
- .env
environment:
VUE_APP_RECAPTCHA_ENABLED: ${VUE_APP_RECAPTCHA_ENABLED:-0}
image: node:22
user: "node"
working_dir: /home/node/app
Expand Down
2 changes: 2 additions & 0 deletions src/backend/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import * as api from './api'
import axios from './axios'
import { getRecaptchaToken } from './recaptcha'

export {
api,
axios,
getRecaptchaToken,
}
9 changes: 9 additions & 0 deletions src/backend/recaptcha.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import config from '../config'

export const getRecaptchaToken = (app, action) => {
if (!config.RECAPTCHA_ENABLED) {
return Promise.resolve('local-development')
}

return app.$recaptcha(action)
}
10 changes: 7 additions & 3 deletions src/components/Cards/CreateAccount.vue
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
</template>
</v-checkbox>
</v-skeleton-loader>
<p>
<p v-if="recaptchaEnabled">
This site is protected by reCAPTCHA. Wikibase Cloud
<a target="_blank" href="https://www.wikibase.cloud/privacy-policy">Privacy Policy</a> and Google
<a target="_blank" href="https://policies.google.com/terms">Terms of Service</a> apply.
Expand All @@ -97,7 +97,9 @@
</template>

<script>
import config from '~/config'
import PolicyList from '../Components/PolicyList'
import { getRecaptchaToken } from '~/backend'

export default {
name: 'CreateAccountCard',
Expand All @@ -112,6 +114,9 @@ export default {
isLoggedIn: function () {
return this.$store.getters.isLoggedIn
},
recaptchaEnabled: function () {
return config.RECAPTCHA_ENABLED
},
},
data () {
return {
Expand Down Expand Up @@ -192,9 +197,8 @@ export default {

// TODO once emailing is setup add emailVerificationRequired option to user model in model-config.json

// TODO recaptcha check should be optional for development (env var switch?)
// Recaptcha check
this.$recaptcha('login').then((token) => {
getRecaptchaToken(this, 'login').then((token) => {
this.$api.register(
{
email: this.email,
Expand Down
4 changes: 3 additions & 1 deletion src/components/Pages/Complaint.vue
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@
</template>

<script>
import { getRecaptchaToken } from '~/backend'

export default {
data: () => ({
contenturl: '',
Expand All @@ -116,7 +118,7 @@ export default {
const name = this.name
const email = this.email
if (this.$refs.form.validate() === true) {
this.$recaptcha('complaint').then((recaptcha) => {
getRecaptchaToken(this, 'complaint').then((recaptcha) => {
this.$api.complaint(
{
name,
Expand Down
4 changes: 3 additions & 1 deletion src/components/Pages/Contact.vue
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@
</template>

<script>
import { getRecaptchaToken } from '~/backend'

export default {
data: () => ({
items: [
Expand Down Expand Up @@ -99,7 +101,7 @@ export default {
const message = this.message
const contactDetails = this.contactDetails
// Recaptcha check
this.$recaptcha('contact').then((recaptcha) => {
getRecaptchaToken(this, 'contact').then((recaptcha) => {
this.$api.contact(
{
name,
Expand Down
1 change: 1 addition & 0 deletions src/config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// keep in sync with src/config.template.js
export default {
RECAPTCHA_SITE_KEY: process.env.VUE_APP_RECAPTCHA_SITE_KEY,
RECAPTCHA_ENABLED: process.env.VUE_APP_RECAPTCHA_ENABLED !== '0',
SUBDOMAIN_SUFFIX: process.env.VUE_APP_SUBDOMAIN_SUFFIX,
CNAME_RECORD: process.env.VUE_APP_CNAME_RECORD,
API_MOCK: process.env.VUE_APP_API_MOCK,
Expand Down
1 change: 1 addition & 0 deletions src/config.template.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// keep in sync with src/config.js
window.config = {
RECAPTCHA_SITE_KEY: '${RECAPTCHA_SITE_KEY}',
RECAPTCHA_ENABLED: '${RECAPTCHA_ENABLED}' !== '0',
SUBDOMAIN_SUFFIX: '${SUBDOMAIN_SUFFIX}',
CNAME_RECORD: '${CNAME_RECORD}',
API_MOCK: '${API_MOCK}',
Expand Down
10 changes: 6 additions & 4 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ enableMocking().then(() => {

Vue.use(Vuetify)

Vue.use(VueReCaptcha, {
siteKey: config.RECAPTCHA_SITE_KEY,
loaderOptions: { useRecaptchaNet: true },
})
if (config.RECAPTCHA_ENABLED) {
Vue.use(VueReCaptcha, {
siteKey: config.RECAPTCHA_SITE_KEY,
loaderOptions: { useRecaptchaNet: true },
})
}

// allow components to access api without importing it
Vue.prototype.$api = api
Expand Down
26 changes: 26 additions & 0 deletions tests/unit/recaptcha.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import config from '../../src/config'
import { getRecaptchaToken } from '../../src/backend/recaptcha'

describe('getRecaptchaToken', () => {
const recaptchaEnabled = config.RECAPTCHA_ENABLED

afterEach(() => {
config.RECAPTCHA_ENABLED = recaptchaEnabled
})

it('returns a local token without contacting reCAPTCHA when disabled', async () => {
config.RECAPTCHA_ENABLED = false
const app = { $recaptcha: jest.fn() }

await expect(getRecaptchaToken(app, 'login')).resolves.toBe('local-development')
expect(app.$recaptcha).not.toHaveBeenCalled()
})

it('requests a reCAPTCHA token when enabled', async () => {
config.RECAPTCHA_ENABLED = true
const app = { $recaptcha: jest.fn().mockResolvedValue('captcha-token') }

await expect(getRecaptchaToken(app, 'login')).resolves.toBe('captcha-token')
expect(app.$recaptcha).toHaveBeenCalledWith('login')
})
})
Loading