mirror of
https://github.com/opf/openproject.git
synced 2026-06-13 19:20:00 +00:00
Implement recaptcha v2/v3 module
This commit is contained in:
@@ -205,6 +205,12 @@ PATH
|
||||
pdf-inspector (~> 1.3.0)
|
||||
prawn (~> 2.2)
|
||||
|
||||
PATH
|
||||
remote: modules/recaptcha
|
||||
specs:
|
||||
openproject-recaptcha (1.0.0)
|
||||
recaptcha (~> 5.1.0)
|
||||
|
||||
PATH
|
||||
remote: modules/reporting_engine
|
||||
specs:
|
||||
@@ -716,6 +722,8 @@ GEM
|
||||
rake (12.3.2)
|
||||
rbtree (0.4.2)
|
||||
rdoc (6.1.1)
|
||||
recaptcha (5.1.0)
|
||||
json
|
||||
redcarpet (3.4.0)
|
||||
reform (2.2.4)
|
||||
disposable (>= 0.4.1)
|
||||
@@ -984,6 +992,7 @@ DEPENDENCIES
|
||||
openproject-meeting!
|
||||
openproject-openid_connect!
|
||||
openproject-pdf_export!
|
||||
openproject-recaptcha!
|
||||
openproject-reporting!
|
||||
openproject-token (~> 1.0.1)
|
||||
openproject-translations!
|
||||
|
||||
@@ -37,6 +37,7 @@ group :opf_plugins do
|
||||
gem 'openproject-webhooks', path: 'modules/webhooks'
|
||||
gem 'openproject-github_integration', path: 'modules/github_integration'
|
||||
gem 'openproject-ldap_groups', path: 'modules/ldap_groups'
|
||||
gem 'openproject-recaptcha', path: 'modules/recaptcha'
|
||||
|
||||
gem 'grids', path: 'modules/grids'
|
||||
gem 'my_page', path: 'modules/my_page'
|
||||
|
||||
Generated
+52
-52
@@ -1507,7 +1507,7 @@
|
||||
},
|
||||
"@types/q": {
|
||||
"version": "0.0.32",
|
||||
"resolved": "http://registry.npmjs.org/@types/q/-/q-0.0.32.tgz",
|
||||
"resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz",
|
||||
"integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=",
|
||||
"dev": true
|
||||
},
|
||||
@@ -2204,7 +2204,7 @@
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"requires": {
|
||||
"ansi-styles": "^2.2.1",
|
||||
@@ -2570,7 +2570,7 @@
|
||||
},
|
||||
"browserify-aes": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
|
||||
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
|
||||
"requires": {
|
||||
"buffer-xor": "^1.0.3",
|
||||
@@ -2806,7 +2806,7 @@
|
||||
},
|
||||
"camelcase-keys": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
|
||||
"integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
|
||||
"requires": {
|
||||
"camelcase": "^2.0.0",
|
||||
@@ -2884,7 +2884,7 @@
|
||||
"dependencies": {
|
||||
"color-convert": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "http://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz",
|
||||
"integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0="
|
||||
}
|
||||
}
|
||||
@@ -3115,7 +3115,7 @@
|
||||
},
|
||||
"colors": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "http://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
|
||||
"integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
|
||||
"dev": true
|
||||
},
|
||||
@@ -3400,7 +3400,7 @@
|
||||
},
|
||||
"create-hash": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
|
||||
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
|
||||
"requires": {
|
||||
"cipher-base": "^1.0.1",
|
||||
@@ -3412,7 +3412,7 @@
|
||||
},
|
||||
"create-hmac": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
|
||||
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
|
||||
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
|
||||
"requires": {
|
||||
"cipher-base": "^1.0.3",
|
||||
@@ -3520,7 +3520,7 @@
|
||||
},
|
||||
"d": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "http://registry.npmjs.org/d/-/d-0.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz",
|
||||
"integrity": "sha1-2hhMU10Y2O57oqoim5FACfrhEwk=",
|
||||
"requires": {
|
||||
"es5-ext": "~0.10.2"
|
||||
@@ -3784,7 +3784,7 @@
|
||||
},
|
||||
"diffie-hellman": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
|
||||
"integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
|
||||
"requires": {
|
||||
"bn.js": "^4.1.0",
|
||||
@@ -4001,7 +4001,7 @@
|
||||
},
|
||||
"engine.io-client": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "http://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz",
|
||||
"integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -4124,7 +4124,7 @@
|
||||
"dependencies": {
|
||||
"d": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "http://registry.npmjs.org/d/-/d-1.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
|
||||
"integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
|
||||
"requires": {
|
||||
"es5-ext": "^0.10.9"
|
||||
@@ -4139,7 +4139,7 @@
|
||||
},
|
||||
"es6-promisify": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
|
||||
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
|
||||
"requires": {
|
||||
"es6-promise": "^4.0.3"
|
||||
@@ -4161,7 +4161,7 @@
|
||||
"dependencies": {
|
||||
"d": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "http://registry.npmjs.org/d/-/d-1.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
|
||||
"integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
|
||||
"requires": {
|
||||
"es5-ext": "^0.10.9"
|
||||
@@ -4259,7 +4259,7 @@
|
||||
"dependencies": {
|
||||
"d": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "http://registry.npmjs.org/d/-/d-1.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
|
||||
"integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
|
||||
"requires": {
|
||||
"es5-ext": "^0.10.9"
|
||||
@@ -5123,7 +5123,7 @@
|
||||
"dependencies": {
|
||||
"async": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "http://registry.npmjs.org/async/-/async-1.5.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-1.5.0.tgz",
|
||||
"integrity": "sha1-J5ZkJyNXOFlWVjP8YnRES+4vjOM="
|
||||
}
|
||||
}
|
||||
@@ -5939,7 +5939,7 @@
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "http://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
|
||||
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
@@ -6088,13 +6088,13 @@
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "http://registry.npmjs.org/commander/-/commander-0.6.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz",
|
||||
"integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.3.5",
|
||||
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz",
|
||||
"integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=",
|
||||
"dev": true
|
||||
}
|
||||
@@ -6200,7 +6200,7 @@
|
||||
},
|
||||
"jsesc": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
|
||||
"integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s="
|
||||
},
|
||||
"json-parse-better-errors": {
|
||||
@@ -6595,7 +6595,7 @@
|
||||
},
|
||||
"load-json-file": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
|
||||
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
@@ -6607,7 +6607,7 @@
|
||||
"dependencies": {
|
||||
"pify": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
|
||||
}
|
||||
}
|
||||
@@ -6873,7 +6873,7 @@
|
||||
},
|
||||
"media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
|
||||
},
|
||||
"mem": {
|
||||
@@ -6902,7 +6902,7 @@
|
||||
"dependencies": {
|
||||
"next-tick": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "http://registry.npmjs.org/next-tick/-/next-tick-0.2.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-0.2.2.tgz",
|
||||
"integrity": "sha1-ddpKkn7liH45BliABltzNkE7MQ0="
|
||||
}
|
||||
}
|
||||
@@ -6918,7 +6918,7 @@
|
||||
},
|
||||
"meow": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
|
||||
"integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
|
||||
"requires": {
|
||||
"camelcase-keys": "^2.0.0",
|
||||
@@ -7191,7 +7191,7 @@
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
@@ -7221,7 +7221,7 @@
|
||||
"dependencies": {
|
||||
"readdirp": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "http://registry.npmjs.org/readdirp/-/readdirp-0.2.5.tgz",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-0.2.5.tgz",
|
||||
"integrity": "sha1-xMJ25Sl3riXbUZH+UdAIVQ8V2bs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -7307,7 +7307,7 @@
|
||||
},
|
||||
"next-tick": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "http://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
|
||||
"integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
|
||||
},
|
||||
"ng-dynamic-component": {
|
||||
@@ -7378,7 +7378,7 @@
|
||||
"dependencies": {
|
||||
"jsesc": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
|
||||
"integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0="
|
||||
}
|
||||
}
|
||||
@@ -7429,7 +7429,7 @@
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
|
||||
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8="
|
||||
},
|
||||
"tar": {
|
||||
@@ -7520,7 +7520,7 @@
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"requires": {
|
||||
"ansi-styles": "^2.2.1",
|
||||
@@ -7876,7 +7876,7 @@
|
||||
},
|
||||
"os-homedir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
|
||||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
|
||||
},
|
||||
"os-locale": {
|
||||
@@ -7891,7 +7891,7 @@
|
||||
},
|
||||
"os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
|
||||
},
|
||||
"osenv": {
|
||||
@@ -8129,7 +8129,7 @@
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
||||
},
|
||||
"path-is-inside": {
|
||||
@@ -8381,7 +8381,7 @@
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -8409,7 +8409,7 @@
|
||||
},
|
||||
"globby": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "http://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
|
||||
"integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -8429,7 +8429,7 @@
|
||||
},
|
||||
"pify": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
||||
"dev": true
|
||||
},
|
||||
@@ -8692,7 +8692,7 @@
|
||||
"dependencies": {
|
||||
"pify": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
|
||||
}
|
||||
}
|
||||
@@ -8741,7 +8741,7 @@
|
||||
},
|
||||
"pify": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
|
||||
}
|
||||
}
|
||||
@@ -8776,7 +8776,7 @@
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
@@ -9049,7 +9049,7 @@
|
||||
},
|
||||
"safe-regex": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
|
||||
"integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
|
||||
"requires": {
|
||||
"ret": "~0.1.10"
|
||||
@@ -9233,7 +9233,7 @@
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "http://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
|
||||
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
|
||||
"requires": {
|
||||
"amdefine": ">=0.0.4"
|
||||
@@ -9360,7 +9360,7 @@
|
||||
},
|
||||
"serialize-error": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "http://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz",
|
||||
"integrity": "sha1-ULZ51WNc34Rme9yOWa9OW4HV9go="
|
||||
},
|
||||
"serialize-javascript": {
|
||||
@@ -9437,7 +9437,7 @@
|
||||
},
|
||||
"sha.js": {
|
||||
"version": "2.4.11",
|
||||
"resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
|
||||
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
|
||||
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.1",
|
||||
@@ -9667,7 +9667,7 @@
|
||||
},
|
||||
"socket.io-parser": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "http://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz",
|
||||
"integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -10109,7 +10109,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
@@ -10117,7 +10117,7 @@
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
@@ -10133,7 +10133,7 @@
|
||||
},
|
||||
"strip-eof": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
|
||||
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
|
||||
},
|
||||
"strip-indent": {
|
||||
@@ -10314,7 +10314,7 @@
|
||||
},
|
||||
"through": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
|
||||
},
|
||||
"through2": {
|
||||
@@ -10452,7 +10452,7 @@
|
||||
},
|
||||
"promise": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "http://registry.npmjs.org/promise/-/promise-2.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/promise/-/promise-2.0.0.tgz",
|
||||
"integrity": "sha1-RmSKqdYFr10ucMMCS/WUNtoCuA4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -12431,7 +12431,7 @@
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
|
||||
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
|
||||
"requires": {
|
||||
"string-width": "^1.0.1",
|
||||
@@ -12494,7 +12494,7 @@
|
||||
},
|
||||
"xmlbuilder": {
|
||||
"version": "9.0.7",
|
||||
"resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
|
||||
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=",
|
||||
"dev": true
|
||||
},
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
source 'https://rubygems.org'
|
||||
gemspec
|
||||
@@ -0,0 +1,38 @@
|
||||
module ::Recaptcha
|
||||
class AdminController < ApplicationController
|
||||
include ::RecaptchaHelper
|
||||
|
||||
before_action :require_admin
|
||||
before_action :validate_settings, only: :update
|
||||
layout 'admin'
|
||||
|
||||
menu_item :plugin_recaptcha
|
||||
|
||||
def show; end
|
||||
|
||||
def update
|
||||
Setting.plugin_openproject_recaptcha = @settings
|
||||
flash[:notice] = I18n.t(:notice_successful_update)
|
||||
redirect_to action: :show
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_settings
|
||||
new_params = permitted_params
|
||||
allowed_options = recaptcha_available_options.map(&:last)
|
||||
|
||||
unless allowed_options.include? new_params[:recaptcha_type]
|
||||
flash[:error] = I18n.t(:error_code, code: '400')
|
||||
redirect_to action: :show
|
||||
return
|
||||
end
|
||||
|
||||
@settings = new_params.to_h.symbolize_keys
|
||||
end
|
||||
|
||||
def permitted_params
|
||||
params.permit(:recaptcha_type, :website_key, :secret_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,111 @@
|
||||
require 'recaptcha'
|
||||
|
||||
module ::Recaptcha
|
||||
class RequestController < ApplicationController
|
||||
# Include global layout helper
|
||||
layout 'no_menu'
|
||||
|
||||
# User is not yet logged in, so skip login required check
|
||||
skip_before_action :check_if_login_required
|
||||
|
||||
# Skip if recaptcha was disabled
|
||||
before_action :skip_if_disabled
|
||||
|
||||
# Require authenticated user from the core to be present
|
||||
before_action :require_authenticated_user
|
||||
|
||||
# Skip if user has confirmed already
|
||||
before_action :skip_if_user_verified
|
||||
|
||||
##
|
||||
# Request verification form
|
||||
def perform
|
||||
use_content_security_policy_named_append(:recaptcha)
|
||||
end
|
||||
|
||||
def verify
|
||||
if valid_recaptcha?
|
||||
save_recpatcha_verification_success!
|
||||
complete_stage_redirect
|
||||
else
|
||||
fail_recaptcha I18n.t('recaptcha.error_captcha')
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
##
|
||||
# Insert that the account was verified
|
||||
def save_recpatcha_verification_success!
|
||||
# Remove all previous
|
||||
::Recaptcha::Entry.where(user_id: @authenticated_user.id).delete_all
|
||||
::Recaptcha::Entry.create!(user_id: @authenticated_user.id, version: recaptcha_version)
|
||||
end
|
||||
|
||||
def recaptcha_version
|
||||
case recaptcha_settings[:recaptcha_type]
|
||||
when ::OpenProject::Recaptcha::TYPE_DISABLED
|
||||
0
|
||||
when ::OpenProject::Recaptcha::TYPE_V2
|
||||
2
|
||||
when ::OpenProject::Recaptcha::TYPE_V3
|
||||
3
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
#
|
||||
def valid_recaptcha?
|
||||
call_args = { secret_key: recaptcha_settings[:secret_key] }
|
||||
if recaptcha_version == 3
|
||||
call_args[:action] = 'login'
|
||||
end
|
||||
|
||||
verify_recaptcha call_args
|
||||
end
|
||||
|
||||
##
|
||||
# fail the recaptcha
|
||||
def fail_recaptcha(msg)
|
||||
flash[:error] = msg
|
||||
failure_stage_redirect
|
||||
end
|
||||
|
||||
##
|
||||
# Ensure the authentication stage from the core provided the authenticated user
|
||||
def require_authenticated_user
|
||||
@authenticated_user = User.find(session[:authenticated_user_id])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
Rails.logger.error "Failed to find authenticated_user for recaptcha verify."
|
||||
failure_stage_redirect
|
||||
end
|
||||
|
||||
def recaptcha_settings
|
||||
Setting.plugin_openproject_recaptcha
|
||||
end
|
||||
|
||||
def skip_if_disabled
|
||||
if recaptcha_settings[:recaptcha_type] == ::OpenProject::Recaptcha::TYPE_DISABLED
|
||||
complete_stage_redirect
|
||||
end
|
||||
end
|
||||
|
||||
def skip_if_user_verified
|
||||
if ::Recaptcha::Entry.where(user_id: @authenticated_user.id).exists?
|
||||
Rails.logger.debug { "User #{@authenticated_user.id} already provided recaptcha. Skipping. " }
|
||||
complete_stage_redirect
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Complete this authentication step and return to core
|
||||
# logging in the user
|
||||
def complete_stage_redirect
|
||||
redirect_to authentication_stage_complete_path :recaptcha
|
||||
end
|
||||
|
||||
def failure_stage_redirect
|
||||
redirect_to authentication_stage_failure_path :recaptcha
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,13 @@
|
||||
module RecaptchaHelper
|
||||
def recaptcha_available_options
|
||||
[
|
||||
[I18n.t('recaptcha.settings.type_disabled'), ::OpenProject::Recaptcha::TYPE_DISABLED],
|
||||
[I18n.t('recaptcha.settings.type_v2'), ::OpenProject::Recaptcha::TYPE_V2],
|
||||
[I18n.t('recaptcha.settings.type_v3'), ::OpenProject::Recaptcha::TYPE_V3]
|
||||
]
|
||||
end
|
||||
|
||||
def recaptcha_settings
|
||||
Setting.plugin_openproject_recaptcha
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
module Recaptcha
|
||||
class Entry < ::ApplicationRecord
|
||||
self.table_name_prefix = 'recaptcha_'
|
||||
belongs_to :user
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,46 @@
|
||||
<% html_title(t(:label_administration), t('recaptcha.label_recaptcha')) -%>
|
||||
|
||||
<%= breadcrumb_toolbar t('recaptcha.label_recaptcha') %>
|
||||
|
||||
<section class="admin--edit-section">
|
||||
<%= styled_form_tag({ action: :update },
|
||||
method: :post,
|
||||
id: 'update-recaptcha-settings-form') do %>
|
||||
<fieldset class="form--fieldset">
|
||||
<legend class="form--fieldset-legend"><%= t(:label_settings) %></legend>
|
||||
<div class="form--field">
|
||||
<label class="form--label" for='recaptcha_type'><%= t('recaptcha.settings.type') %></label>
|
||||
<div class="form--field-container">
|
||||
<%= styled_select_tag 'recaptcha_type',
|
||||
options_for_select(recaptcha_available_options, Setting.plugin_openproject_recaptcha[:recaptcha_type]),
|
||||
container_class: '-middle' %>
|
||||
</div>
|
||||
<div class="form--field-instructions">
|
||||
<%= I18n.t('recaptcha.settings.recaptcha_description_html',
|
||||
recaptcha_link: link_to('https://www.google.com/recaptcha', 'https://www.google.com/recaptcha', target: '_blank')).html_safe %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form--field">
|
||||
<label class="form--label" for='website_key'><%= t('recaptcha.settings.website_key') %></label>
|
||||
<div class="form--field-container">
|
||||
<%= styled_text_field_tag 'website_key',
|
||||
Setting.plugin_openproject_recaptcha[:website_key] %>
|
||||
</div>
|
||||
<div class="form--field-instructions">
|
||||
<%= I18n.t('recaptcha.settings.website_key_text') %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form--field">
|
||||
<label class="form--label" for='secret_key'><%= t('recaptcha.settings.secret_key') %></label>
|
||||
<div class="form--field-container">
|
||||
<%= styled_text_field_tag 'secret_key',
|
||||
Setting.plugin_openproject_recaptcha[:secret_key] %>
|
||||
</div>
|
||||
<div class="form--field-instructions">
|
||||
<%= I18n.t('recaptcha.settings.secret_key_text') %>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<%= styled_submit_tag l(:button_apply), class: '-highlight' %>
|
||||
<% end %>
|
||||
</section>
|
||||
@@ -0,0 +1,32 @@
|
||||
<% html_title t('recaptcha.label_recaptcha') %>
|
||||
<% breadcrumb_paths(t('recaptcha.label_recaptcha')) %>
|
||||
<div id="login-form" class="form -bordered">
|
||||
<%= styled_form_tag({ action: :verify }, { :autocomplete => "off", :id => 'submit_captcha' }) do %>
|
||||
<h2><%= t 'recaptcha.verify_account' %></h2>
|
||||
<% if recaptcha_settings[:recaptcha_type] == ::OpenProject::Recaptcha::TYPE_V2 %>
|
||||
<input type="hidden" name="g-recaptcha-response" />
|
||||
<%= recaptcha_tags nonce: content_security_policy_script_nonce,
|
||||
callback: 'submitRecaptchaForm',
|
||||
site_key: recaptcha_settings[:website_key] %>
|
||||
<%= nonced_javascript_tag do %>
|
||||
function submitRecaptchaForm(val) {
|
||||
document.getElementById('g-recaptcha-response').value = val;
|
||||
document.getElementById('submit_captcha').submit();
|
||||
}
|
||||
<% end %>
|
||||
<% elsif recaptcha_settings[:recaptcha_type] == ::OpenProject::Recaptcha::TYPE_V3 %>
|
||||
<%= recaptcha_v3 action: 'login',
|
||||
nonce: content_security_policy_script_nonce,
|
||||
callback: 'submitRecaptchaForm',
|
||||
site_key: recaptcha_settings[:website_key] %>
|
||||
|
||||
<p><%= t('recaptcha.button_please_wait') %></p>
|
||||
<%= nonced_javascript_tag do %>
|
||||
function submitRecaptchaForm(id, val) {
|
||||
document.getElementById(id).value = val;
|
||||
document.getElementById('submit_captcha').submit();
|
||||
}
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -0,0 +1,22 @@
|
||||
# English strings go here for Rails i18n
|
||||
en:
|
||||
recaptcha:
|
||||
label_recaptcha: "reCAPTCHA"
|
||||
button_please_wait: 'Please wait ...'
|
||||
verify_account: "Verify your account"
|
||||
error_captcha: "You're account could not be verified. Please contact an administrator."
|
||||
settings:
|
||||
website_key: 'Website key'
|
||||
website_key_text: 'Enter the website key you created on the reCAPTCHA admin console for this domain.'
|
||||
secret_key: 'Secret key'
|
||||
secret_key_text: 'Enter the secret key you created on the reCAPTCHA admin console.'
|
||||
type: 'Use reCAPTCHA'
|
||||
type_disabled: 'Disable reCAPTCHA'
|
||||
type_v2: 'reCAPTCHA v2'
|
||||
type_v3: 'reCAPTCHA v3'
|
||||
recaptcha_description_html: >
|
||||
reCAPTCHA is a free service by Google that can be enabled for your OpenProject instance.
|
||||
If enabled, a captcha form will be rendered upon login for all users that have not verified a captcha yet.
|
||||
<br/>
|
||||
Please see the following link for more details on reCAPTCHA and their versions, and how
|
||||
to create the website and secret keys: %{recaptcha_link}
|
||||
@@ -0,0 +1,10 @@
|
||||
OpenProject::Application::routes.draw do
|
||||
|
||||
namespace 'recaptcha' do
|
||||
get :settings, to: 'admin#show'
|
||||
post :settings, to: 'admin#update'
|
||||
|
||||
get :request, to: 'request#perform', as: 'request'
|
||||
post :verify, to: 'request#verify', as: 'verify'
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
class AddRecaptchaEntries < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
create_table :recaptcha_entries, id: :integer do |t|
|
||||
t.references :user, index: true, foreign_key: { on_delete: :cascade }
|
||||
t.timestamps
|
||||
t.integer :version, null: false
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
module OpenProject
|
||||
module Recaptcha
|
||||
TYPE_DISABLED ||= 'disabled'
|
||||
TYPE_V2 ||= 'v2'
|
||||
TYPE_V3 ||= 'v3'
|
||||
|
||||
require "open_project/recaptcha/engine"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,44 @@
|
||||
require 'open_project/plugins'
|
||||
require 'recaptcha'
|
||||
|
||||
module OpenProject::Recaptcha
|
||||
class Engine < ::Rails::Engine
|
||||
engine_name :openproject_recaptcha
|
||||
|
||||
include OpenProject::Plugins::ActsAsOpEngine
|
||||
|
||||
register 'openproject-recaptcha',
|
||||
author_url: 'http://openproject.com',
|
||||
settings: {
|
||||
default: {
|
||||
recaptcha_type: ::OpenProject::Recaptcha::TYPE_DISABLED
|
||||
}
|
||||
},
|
||||
bundled: true do
|
||||
menu :admin_menu,
|
||||
:plugin_recaptcha,
|
||||
{ controller: '/recaptcha/admin', action: :show },
|
||||
parent: :authentication,
|
||||
caption: ->(*) { I18n.t('recaptcha.label_recaptcha') }
|
||||
end
|
||||
|
||||
config.after_initialize do
|
||||
OpenProject::Authentication::Stage.register(:recaptcha,
|
||||
nil,
|
||||
run_after_activation: true,
|
||||
active: -> {
|
||||
type = Setting.plugin_openproject_recaptcha[:recaptcha_type]
|
||||
type.present? && type.to_s != ::OpenProject::Recaptcha::TYPE_DISABLED
|
||||
}) do
|
||||
recaptcha_request_path
|
||||
end
|
||||
end
|
||||
|
||||
config.to_prepare do
|
||||
SecureHeaders::Configuration.named_append(:recaptcha) do |request|
|
||||
{ frame_src: %w(https://www.google.com/recaptcha/) }
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
module OpenProject
|
||||
module Recaptcha
|
||||
require "open_project/recaptcha/engine"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
require 'open_project/recaptcha'
|
||||
@@ -0,0 +1,16 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "openproject-recaptcha"
|
||||
s.version = '1.0.0'
|
||||
s.authors = "OpenProject GmbH"
|
||||
s.email = "info@openproject.com"
|
||||
s.homepage = "https://community.openproject.org/"
|
||||
s.summary = "OpenProject ReCaptcha"
|
||||
s.description = "This module provides recaptcha checks during login"
|
||||
|
||||
s.files = Dir["{app,config,db,lib}/**/*", "CHANGELOG.md", "README.rdoc"]
|
||||
s.test_files = Dir["spec/**/*"]
|
||||
|
||||
s.add_dependency 'recaptcha', '~> 5.1.0'
|
||||
end
|
||||
@@ -0,0 +1,49 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe ::Recaptcha::AdminController, type: :controller do
|
||||
let(:user) { FactoryBot.build_stubbed :admin }
|
||||
before do
|
||||
login_as user
|
||||
end
|
||||
|
||||
describe 'as non admin' do
|
||||
let(:user) { FactoryBot.build_stubbed :user }
|
||||
|
||||
it 'does not allow access' do
|
||||
get :show
|
||||
expect(response.status).to eq 403
|
||||
|
||||
post :update
|
||||
expect(response.status).to eq 403
|
||||
end
|
||||
end
|
||||
|
||||
describe 'show' do
|
||||
it 'renders show' do
|
||||
get :show
|
||||
expect(response).to be_successful
|
||||
expect(response).to render_template 'recaptcha/admin/show'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update' do
|
||||
it 'fails if invalid param' do
|
||||
post :update, params: { recaptcha_type: :unknown }
|
||||
expect(response).to be_redirect
|
||||
expect(flash[:error]).to be_present
|
||||
end
|
||||
|
||||
it 'succeeds' do
|
||||
expected = { recaptcha_type: 'v2', website_key: 'B', secret_key: 'A' }
|
||||
|
||||
expect(Setting)
|
||||
.to receive(:plugin_openproject_recaptcha=)
|
||||
.with(expected)
|
||||
|
||||
post :update, params: expected
|
||||
expect(response).to be_redirect
|
||||
expect(flash[:error]).to be_nil
|
||||
expect(flash[:notice]).to be_present
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,48 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe ::Recaptcha::RequestController, type: :controller do
|
||||
let(:user) { FactoryBot.create :user }
|
||||
before do
|
||||
login_as user
|
||||
allow(Setting)
|
||||
.to receive(:plugin_openproject_recaptcha)
|
||||
.and_return(recaptcha_type: 'v2', website_key: 'A', secret_key: 'B')
|
||||
|
||||
session[:authenticated_user_id] = user.id
|
||||
session[:stage_secrets] = { recaptcha: 'asdf' }
|
||||
end
|
||||
|
||||
describe 'request' do
|
||||
it 'renders the template' do
|
||||
get :perform
|
||||
expect(response).to be_successful
|
||||
expect(response).to render_template 'recaptcha/request/perform'
|
||||
end
|
||||
|
||||
it 'skips if user is verified' do
|
||||
allow(::Recaptcha::Entry)
|
||||
.to receive_message_chain(:where, :exists?)
|
||||
.and_return true
|
||||
|
||||
get :perform
|
||||
expect(response).to redirect_to stage_success_path(stage: :recaptcha, secret: 'asdf')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'verify' do
|
||||
it 'succeeds assuming verification works' do
|
||||
allow(@controller).to receive(:valid_recaptcha?).and_return true
|
||||
expect(@controller).to receive(:save_recpatcha_verification_success!)
|
||||
post :verify
|
||||
expect(flash[:error]).to be_nil
|
||||
expect(response).to redirect_to stage_success_path(stage: :recaptcha, secret: 'asdf')
|
||||
end
|
||||
|
||||
it 'fails assuming verification fails' do
|
||||
allow(@controller).to receive(:valid_recaptcha?).and_return false
|
||||
post :verify
|
||||
expect(flash[:error]).to be_present
|
||||
expect(response).to redirect_to stage_failure_path(stage: :recaptcha)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,2 @@
|
||||
# -- load spec_helper from OpenProject core
|
||||
require "spec_helper"
|
||||
Reference in New Issue
Block a user