Skip to content

Commit

Permalink
Frictionless server verification (#1111)
Browse files Browse the repository at this point in the history
* wip

* nearly there

* revert html changes

* building

* remove commented

* Update vite build config

* lint:fix

* Add small wait to test

* Address Hugh's comments and remove a couple of s

* type cleanup

* Implement pow payload form injection and server side checking

* Remove captcha-contract dep in util

* Fix pow state management

* Frictionless cypress tests

* remove empty vars

* lint:fix

* lint bundle

* make sure bundled js is not linted

* Commit folder

* Make frictionless the default

* try fix for dodgy test

* Add random task ID

* Remove botd.html

* Fix docs generation process

* Comment dodgy test
  • Loading branch information
forgetso authored Mar 20, 2024
1 parent cb556a1 commit 8f4ad15
Show file tree
Hide file tree
Showing 36 changed files with 3,308 additions and 638 deletions.
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,5 @@ protocol/target
.nvmrc
diagram.svg
.env.*
**/assets/*.js
*.min.js
Empty file.
36 changes: 36 additions & 0 deletions demos/client-bundle-example/src/frictionless.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!doctype html>
<html lang="en">
<head>
<title>Procaptcha demo: Live Test</title>
<script type="module">
async function captchaLoaded() {
const render = (await import('./assets/procaptcha.bundle')).render
console.log('Captcha loaded')
render('procaptcha-container', {
siteKey: '5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw',
theme: 'dark',
callback: 'onCaptchaVerified',
captchaType: 'frictionless',
})
}
window.captchaLoaded = captchaLoaded

// Define a callback function to be called when the CAPTCHA is verified
window.onCaptchaVerified = function (output) {
console.log('Captcha verified, output: ' + JSON.stringify(output))
}
</script>
<script
id="procaptchaScript"
type="module"
src="./procaptcha.bundle.js?onload=captchaLoaded&render=explicit"
async
defer
></script>
</head>
<body>
<form>
<div id="procaptcha-container"></div>
</form>
</body>
</html>
4 changes: 2 additions & 2 deletions demos/client-bundle-example/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<link href="//cdn.muicss.com/mui-0.10.3/css/mui.min.css" rel="stylesheet" type="text/css" />
<title>Procaptcha demo: Simple page</title>
<script id="procaptchaScript" type="module" src="procaptcha.bundle.js" async defer></script>
<script id="procaptchaScript" type="module" src="./assets/procaptcha.bundle.js" async defer></script>
</head>
<body>
<div class="mui-container">
Expand Down Expand Up @@ -33,7 +33,7 @@
</div>
<script type="module">
// Pattern to avoid race condition between Procaptcha script loading and Procaptcha render function call
import { render } from './procaptcha.bundle.js'
import { render } from './assets/procaptcha.bundle.js'

// Define a callback function to be called when the CAPTCHA is verified
window.onCaptchaVerified = function (output) {
Expand Down
4 changes: 2 additions & 2 deletions demos/client-bundle-example/src/urlParams.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<title>Procaptcha demo: Live Test</title>
<script type="module">
async function captchaLoaded() {
const render = (await import('./procaptcha.bundle')).render
const render = (await import('./assets/procaptcha.bundle')).render
console.log('Captcha loaded')
render('procaptcha-container', {
siteKey: '5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw',
Expand All @@ -22,7 +22,7 @@
<script
id="procaptchaScript"
type="module"
src="./procaptcha.bundle.js?onload=captchaLoaded&render=explicit"
src="./assets/procaptcha.bundle.js?onload=captchaLoaded&render=explicit"
async
defer
></script>
Expand Down
1 change: 1 addition & 0 deletions demos/client-example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"electron": "25.8.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.22.3",
"web-vitals": "^2.1.4"
},
"devDependencies": {
Expand Down
21 changes: 14 additions & 7 deletions demos/client-example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,22 @@ import {
import { ExtensionAccountSelect, Procaptcha } from '@prosopo/procaptcha-react'
import { ProcaptchaFrictionless } from '@prosopo/procaptcha-frictionless'
import { useState } from 'react'

const corsHeaders = {
'Access-Control-Allow-Origin': '*', // Required for CORS support to work
'Access-Control-Allow-Methods': 'GET, POST, PUT, PATCH, DELETE',
'Access-Control-Allow-Headers': 'Origin, Content-Type, X-Auth-Token, Authorization',
}

function App() {
interface AppProps {
captchaType?: string
}

function App(props: AppProps) {
const [email, setEmail] = useState<string>('')
const [name, setName] = useState<string>('')
const [password, setPassword] = useState('')
const [account, setAccount] = useState<string>('')

const [isError, setIsError] = useState(false)
const [message, setMessage] = useState('')
// whether the form is doing a login or a signup action
Expand Down Expand Up @@ -201,11 +205,14 @@ function App() {
</FormControl>

<FormControl sx={{ m: 1 }}>
<ProcaptchaFrictionless
config={config}
callbacks={{ onError, onHuman, onExpired }}
/>
<Procaptcha config={config} callbacks={{ onError, onHuman, onExpired }} />
{props.captchaType === 'frictionless' ? (
<ProcaptchaFrictionless
config={config}
callbacks={{ onError, onHuman, onExpired }}
/>
) : (
<Procaptcha config={config} callbacks={{ onError, onHuman, onExpired }} />
)}
</FormControl>
<FormControl>
<Box sx={{ p: 1 }}>
Expand Down
17 changes: 15 additions & 2 deletions demos/client-example/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,30 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { CssBaseline } from '@mui/material'
import App from './App.js'
import { RouterProvider, createBrowserRouter } from 'react-router-dom'
import FrictionlessRoot from './routes/frictionless.js'
import ImageCaptchaRoot from './routes/root.js'
import React from 'react'
import ReactDOM from 'react-dom/client'
import reportWebVitals from './reportWebVitals.js'

const router = createBrowserRouter([
{
path: '/',
element: <ImageCaptchaRoot />,
},
{
path: '/frictionless',
element: <FrictionlessRoot />,
},
])

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)

root.render(
<React.Fragment>
<CssBaseline />
<App />
<RouterProvider router={router} />
</React.Fragment>
)

Expand Down
23 changes: 23 additions & 0 deletions demos/client-example/src/routes/frictionless.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2021-2024 Prosopo (UK) Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import App from '../App.js'
import React from 'react'

export default function Root() {
return (
<React.Fragment>
<App captchaType={'frictionless'} />
</React.Fragment>
)
}
23 changes: 23 additions & 0 deletions demos/client-example/src/routes/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2021-2024 Prosopo (UK) Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import App from '../App.js'
import React from 'react'

export default function Root() {
return (
<React.Fragment>
<App />
</React.Fragment>
)
}
17 changes: 0 additions & 17 deletions demos/cypress-shared/cypress/e2e/captcha.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,4 @@ describe('Captchas', () => {
})
})
})

//
// it('Solution is rejected when incorrect', () => {
// const captchas = await cy.clickIAmHuman().promisify()
//
// cy.intercept('POST', '**/solution').as('postSolution')
//
// captchas.forEach((_, index) => {
// cy.get(`[data-cy='captcha-${index}'] > [data-cy='captcha-item']`).each(($el) => $el.trigger('click'))
//
// cy.get('[data-cy="button-next"]').click()
// })
//
// cy.wait('@postSolution').then(
// (interception) => expect(interception.response!.body.solutionApproved).to.be.false
// )
// })
})
2 changes: 2 additions & 0 deletions demos/cypress-shared/cypress/e2e/correct.captcha.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ describe('Captchas', () => {
})
}

cy.intercept('/dummy').as('dummy')

// visit the base URL specified on command line when running cypress
return cy.visit(Cypress.env('default_page')).then(() => {
cy.get(checkboxClass).should('be.visible')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// <reference types="cypress" />
import '@cypress/xpath'
import { Captcha } from '@prosopo/types'
Expand All @@ -32,6 +31,8 @@ describe('Captchas', () => {
})
}

cy.intercept('/dummy').as('dummy')

// visit the base URL specified on command line when running cypress
return cy.visit(Cypress.env('default_page')).then(() => {
cy.get(checkboxClass).should('be.visible')
Expand Down
4 changes: 4 additions & 0 deletions demos/cypress-shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,14 @@
"clean": "tsc --build --clean",
"cypress:open:client-example": "CYPRESS_BASE_URL='http://0.0.0.0:9230' cypress open",
"cypress:run:client-example": "CYPRESS_BASE_URL='http://0.0.0.0:9230' cypress run",
"cypress:open:client-example:frictionless": "CYPRESS_BASE_URL='http://0.0.0.0:9230' cypress open --env default_page='/frictionless'",
"cypress:run:client-example:frictionless": "CYPRESS_BASE_URL='http://0.0.0.0:9230' cypress run --env default_page='/frictionless'",
"cypress:open:client-bundle-example": "CYPRESS_BASE_URL='http://localhost:9232' cypress open",
"cypress:run:client-bundle-example": "CYPRESS_BASE_URL='http://localhost:9232' cypress run --spec 'cypress/e2e/captcha.cy.ts,cypress/e2e/correct.captcha.cy.ts'",
"cypress:open:client-bundle-example:explicit": "CYPRESS_BASE_URL='http://localhost:9232' cypress open --env default_page='/urlParams.html'",
"cypress:run:client-bundle-example:explicit": "CYPRESS_BASE_URL='http://localhost:9232' cypress run --env default_page='/urlParams.html' --spec 'cypress/e2e/captcha.cy.ts'",
"cypress:open:client-bundle-example:frictionless": "CYPRESS_BASE_URL='http://localhost:9232' cypress open --env default_page='/frictionless.html'",
"cypress:run:client-bundle-example:frictionless": "CYPRESS_BASE_URL='http://localhost:9232' cypress run --env default_page='/frictionless.html'",
"cypress:open:client-bundle-example:js_server": "CYPRESS_BASE_URL='http://localhost:9232' cypress open --env default_page='/jsBundleTest.html'",
"cypress:run:client-bundle-example:js_server": "CYPRESS_BASE_URL='http://localhost:9232' cypress run --env default_page='/jsBundleTest.html' --spec 'cypress/e2e/captcha.cy.ts'",
"eslint": "npx eslint . --no-error-on-unmatched-pattern --ignore-path ../../.eslintignore",
Expand Down
4 changes: 2 additions & 2 deletions demos/provider-mock/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,14 @@ export function prosopoRouter(): Router {
statusMessage = 'API.USER_VERIFIED'
return res.json({
status: req.t(statusMessage),
solutionApproved: approved,
verified: approved,
commitmentId: testCommitmentId,
})
}

return res.json({
status: req.t(statusMessage),
solutionApproved: false,
verified: false,
})
} catch (err) {
return next(new ProsopoApiError('API.UNKNOWN', { context: { error: err, errorCode: 500 } }))
Expand Down
Loading

0 comments on commit 8f4ad15

Please sign in to comment.