Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to Prosopo Procaptcha #372

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
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
8 changes: 8 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,11 @@ SMF_CONFIG_DB_PORT=5432
SMF_CONFIG_DB_USERNAME=postgres
SMF_CONFIG_DB_PASSWORD=postgres
SMF_CONFIG_DB_DATABASE_NAME=faucet

# Captcha provider details
SMF_CONFIG_CAPTCHA_PROVIDER=procaptcha
SMF_CONFIG_PROSOPO_DEFAULT_ENVIRONMENT=production
SMF_CONFIG_PROSOPO_DEFAULT_NETWORK=rococo
SMF_CONFIG_PROSOPO_DAPP_NAME=Polkadot
SMF_CONFIG_PROSOPO_SUBSTRATE_ENDPOINT=wss://rococo-contracts-rpc.polkadot.io:443
SMF_CONFIG_PROSOPO_SITE_KEY=5C4hrfjw9DjXZTzV3MwzrrAr9P1MJhSrvWGWqi1eSuyUpnhM
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
data
build
test
test
3 changes: 2 additions & 1 deletion .github/workflows/E2E.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ jobs:
--dir zombienet_logs \
spawn zombienet.native.toml \
> polkadot.txt 2>&1 &
source wait_until.sh 'curl -s "127.0.0.1:9933"'
source wait_until.sh 'curl -s "127.0.0.1:9923"'
source wait_until.sh 'curl -s "127.0.0.1:9934"'
source wait_until.sh 'curl -s "127.0.0.1:9988"'
working-directory: e2e
- name: Build e2e types
run: yarn generate:papi:e2e
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
- run: yarn install --frozen-lockfile
- run: yarn run check
- name: Install Playwright
run: npx playwright install
run: yarn playwright install --with-deps
- run: yarn run test
- run: yarn run build
env:
Expand Down
29 changes: 20 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Example requests:
curl -X POST \
localhost:5555/drip/web \
-H "Content-Type: application/json" \
-d '{"address": "xxx", "parachain_id": "1002", "recaptcha": "captcha_token"}'
-d '{"address": "xxx", "parachain_id": "1002", "captchaResponse": "captcha_token"}'
```

In React:
Expand All @@ -76,7 +76,7 @@ const request = async () => {
const body = {
address: "xxx",
parachain_id: "1002",
recaptcha: captcha_token
captchaResponse: captcha_token
}

const fetchResult = await fetch("http://localhost:5555/drip/web", {
Expand All @@ -89,15 +89,26 @@ const request = async () => {
}
```

Where the `captcha_token` is a recaptcha token created with a `sitekey`
is matching the recaptcha secret specified in `SMF_BACKEND_RECAPTCHA_SECRET`.
Where the `captcha_token` is either a

For testing, you can use a public, testing recaptcha secret which will allow any captcha token to pass.
- JSON payload that includes a verified rococo address [procaptcha](https://docs.prosopo.io)

```shell
# Public testing secret, will accept all tokens.
SMF_BACKEND_RECAPTCHA_SECRET="6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe"
```
or

- a recaptcha token created with a `sitekey` matching the [recaptcha](https://developers.google.com/recaptcha/) secret specified in `SMF_BACKEND_RECAPTCHA_SECRET`.

For testing, you can use

- Alice's address `5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY` with procaptcha

or

- a public, testing captcha secret which will allow any captcha token to pass with recaptcha.

```shell
# Public testing secret, will accept all tokens.
SMF_BACKEND_RECAPTCHA_SECRET="6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe"
```

### Helm chart

Expand Down
6 changes: 5 additions & 1 deletion client/.env
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
PUBLIC_DEMO_MODE=
PUBLIC_CAPTCHA_KEY=6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
PUBLIC_RECAPTCHA_KEY=6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
PUBLIC_PROSOPO_SITE_KEY=5C4hrfjw9DjXZTzV3MwzrrAr9P1MJhSrvWGWqi1eSuyUpnhM

PUBLIC_FAUCET_URL=
# uncomment to direct requests to local instance
# PUBLIC_FAUCET_URL=http://localhost:5555/drip/web/

PUBLIC_ISSUE_LINK=https://github.com/paritytech/polkadot-testnet-faucet/issues/new/choose
PUBLIC_FORUM="https://forum.polkadot.network/t/experiencing-trouble-accessing-our-rococo-faucet-please-post-here/2952"
PUBLIC_CAPTCHA_PROVIDER=procaptcha


6 changes: 4 additions & 2 deletions client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ Two current options are to [access Matrix and contact a bot](https://wiki.polkad

## Development

To develop you need two env variables:
To develop you need three env variables:

- `PUBLIC_CAPTCHA_KEY`: The [reCaptcha v2 site key](https://www.google.com/u/0/recaptcha/admin).
- `PUBLIC_CAPTCHA_PROVIDER`: The captcha provider. Currently `procaptcha` and `recaptcha` are supported. You will then need one of the following site keys:
- `PUBLIC_PROSOPO_SITE_KEY`: The [Prosopo site key](https://prosopo.io/) which is `5HUBceb4Du6dvMA9BiwN5VzUrzUsX9Zp7z7nSR2cC1TCv5jg`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this key generated by you? If we want to change it we need to create an account and update it?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is generated by us but you can generate your own by registering on our website. I think it would be best if we hop on a call to go through everything next week. I'll reach out to you on Element to arrange.

- `PUBLIC_RECAPTCHA_KEY`: The [reCaptcha v2 site key](https://www.google.com/u/0/recaptcha/admin).
- `PUBLIC_FAUCET_URL`: The endpoint to contact the faucet backend. Keep unset to run client-side code with production backend.

The reason for which these variables have `PUBLIC_` as a prefix is a security measure to not upload any unnecessary data. [More info here](https://kit.svelte.dev/docs/modules#$env-static-public)
Expand Down
5 changes: 4 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"test": "playwright test",
"test:recaptcha": "playwright test --config playwright.config.recaptcha.ts",
"test:procaptcha": "playwright test --config playwright.config.procaptcha.ts",
Bullrich marked this conversation as resolved.
Show resolved Hide resolved
"test": "yarn test:recaptcha && yarn test:procaptcha",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
},
"devDependencies": {
"@playwright/test": "^1.40.0",
"@polkadot/util": "^12.6.2",
"@sveltejs/adapter-auto": "^2.1.1",
"@sveltejs/adapter-node": "^1.3.1",
"@sveltejs/adapter-static": "^2.0.3",
Expand Down
17 changes: 17 additions & 0 deletions client/playwright.config.procaptcha.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { PlaywrightTestConfig } from "@playwright/test";

const config: PlaywrightTestConfig = {
webServer: {
command: "npm run build && npm run preview",
port: 4173,
env: {
PUBLIC_CAPTCHA_PROVIDER: "procaptcha",
PUBLIC_PROSOPO_SITE_KEY: "5HUBceb4Du6dvMA9BiwN5VzUrzUsX9Zp7z7nSR2cC1TCv5jg",
PUBLIC_DEMO_MODE: "",
PUBLIC_FAUCET_URL: "https://example.com/test",
},
},
testDir: "tests",
};

export default config;
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ const config: PlaywrightTestConfig = {
command: "npm run build && npm run preview",
port: 4173,
env: {
PUBLIC_CAPTCHA_KEY: "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI",
PUBLIC_CAPTCHA_PROVIDER: "recaptcha",
PUBLIC_RECAPTCHA_KEY: "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI",
PUBLIC_DEMO_MODE: "",
PUBLIC_FAUCET_URL: "https://example.com/test",
},
},

testDir: "tests",
};

Expand Down
5 changes: 1 addition & 4 deletions client/src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,7 @@ body {
background-repeat: no-repeat;
position: absolute;
background-position-y: 10%, 73%, 50%;
background-position-x:
25%,
-13%,
115%;
background-position-x: 25%, -13%, 115%;
background-size: 20%, 20%, 30%;
bottom: 0px;
right: 0px;
Expand Down
20 changes: 17 additions & 3 deletions client/src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ declare global {
}

declare interface Window {
grecaptcha?: Captcha;
grecaptcha?: Recaptcha;
procaptcha?: Procaptcha;
captchaLoaded: () => void;
onToken: (token: string) => void;
onExpiredToken: () => void;
}
}

interface Captcha {
interface Recaptcha {
render: (
element: string,
key: {
Expand All @@ -30,4 +30,18 @@ interface Captcha {
getResponse: () => string;
}

interface Procaptcha {
render: (
element: string,
key: {
siteKey: string;
callback?: string;
theme?: "light" | "dark";
"chalexpired-callback"?: string;
captchaType?: "image";
},
) => void;
default: (callback: () => void) => void;
}

export {};
2 changes: 1 addition & 1 deletion client/src/app.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
Expand Down
59 changes: 45 additions & 14 deletions client/src/lib/components/CaptchaV2.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<script lang="ts">
<script type="module" lang="ts">
import { createEventDispatcher, onMount } from "svelte";
import Cross from "./icons/Cross.svelte";
import { CaptchaProvider } from "$lib/utils/captcha";

export let captchaKey: string;

export let captchaProvider: CaptchaProvider;
const dispatch = createEventDispatcher<{ token: string }>();

const captchaId = "captcha_element";
Expand All @@ -22,21 +23,42 @@
: theme;
const mobileScreen = window.innerHeight > window.innerWidth;

if (!window.grecaptcha) {
if (captchaProvider === CaptchaProvider.procaptcha) {
if (!window.procaptcha) {
captchaError = true;
throw new Error(`${captchaProvider} is undefined!`);
}
window.procaptcha.render(captchaId, {
siteKey: captchaKey,
theme: colorTheme,
callback: "onToken",
"chalexpired-callback": "onExpiredToken",
captchaType: "image",
});
} else if (captchaProvider === CaptchaProvider.recaptcha) {
if (!window.grecaptcha) {
captchaError = true;
throw new Error("grecaptcha is undefined!");
}
window.grecaptcha.render(captchaId, {
sitekey: captchaKey,
theme: colorTheme,
callback: "onToken",
size: mobileScreen ? "compact" : "normal",
"expired-callback": "onExpiredToken",
});
} else {
captchaError = true;
throw new Error("grecaptcha is undefined!");
throw new Error(`Unknown captcha provider: ${captchaProvider}`);
}
window.grecaptcha.render(captchaId, {
sitekey: captchaKey,
theme: colorTheme,
callback: "onToken",
size: mobileScreen ? "compact" : "normal",
"expired-callback": "onExpiredToken",
});
};

window.onToken = (token) => {
dispatch("token", token);
// Forces a new captcha on page reload
if (captchaProvider === CaptchaProvider.procaptcha) {
window.localStorage.removeItem("@prosopo/procaptcha");
}
};

// clean the token so the form becomes invalid
Expand All @@ -52,16 +74,25 @@

<svelte:head>
{#if componentMounted}
<script src="https://www.google.com/recaptcha/api.js?onload=captchaLoaded&render=explicit" async defer></script>
forgetso marked this conversation as resolved.
Show resolved Hide resolved
{#if captchaProvider === "procaptcha"}
<script
type="module"
src="https://js.prosopo.io/js/procaptcha.bundle.js?render=implicit&onload=captchaLoaded"
async
defer
></script>
{:else}
<script src="https://www.google.com/recaptcha/api.js?onload=captchaLoaded&render=explicit" async defer></script>
{/if}
{/if}
</svelte:head>

{#if captchaError}
<div class="alert alert-error shadow-lg" data-testid="error">
<div>
<Cross />
<span>Error loading Google Captcha. Please reload the page.</span>
<span>Error loading {captchaProvider} Captcha. Please reload the page.</span>
</div>
</div>
{/if}
<div id={captchaId} />
<div id={captchaId} class="z-0" />
14 changes: 8 additions & 6 deletions client/src/lib/components/Form.svelte
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
<script lang="ts">
import { PUBLIC_CAPTCHA_KEY } from "$env/static/public";
import type { NetworkData } from "$lib/utils/networkData";
import { PUBLIC_CAPTCHA_PROVIDER, PUBLIC_PROSOPO_SITE_KEY, PUBLIC_RECAPTCHA_KEY } from "$env/static/public";
import { operation, testnet } from "$lib/utils/stores";
import { request as faucetRequest } from "../utils";
import CaptchaV2 from "./CaptchaV2.svelte";
import NetworkDropdown from "./NetworkDropdown.svelte";
import NetworkInput from "./NetworkInput.svelte";
import { CaptchaProvider, getCaptchaProvider } from "$lib/utils/captcha";
import NetworkDropdown from "./NetworkDropdown.svelte";
import type { NetworkData } from "$lib/utils/networkData";

let address: string = "";
export let network: number = -1;
export let networkData: NetworkData;
let token: string = "";
let formValid: boolean;
$: formValid = !!address && !!token && !!network;

const captchaProvider = getCaptchaProvider(PUBLIC_CAPTCHA_PROVIDER);
const captchaKey = captchaProvider === CaptchaProvider.procaptcha ? PUBLIC_PROSOPO_SITE_KEY : PUBLIC_RECAPTCHA_KEY;
let webRequest: Promise<string>;

function onSubmit() {
Expand Down Expand Up @@ -57,8 +59,8 @@
/>
</div>
{#if !webRequest}
<div class="grid place-items-center">
<CaptchaV2 captchaKey={PUBLIC_CAPTCHA_KEY ?? ""} on:token={onToken} theme="dark" />
<div class="place-items-center">
<CaptchaV2 {captchaKey} {captchaProvider} on:token={onToken} theme="dark" />
</div>
<button class="submit-btn" type="submit" data-testid="submit-button" disabled={!formValid}>
Get some {$testnet.currency}s
Expand Down
2 changes: 1 addition & 1 deletion client/src/lib/components/NetworkDropdown.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<Chevron />
</div>
</div>
<ul tabindex="-1" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-full text-white">
<ul tabindex="-1" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-full text-white z-10">
forgetso marked this conversation as resolved.
Show resolved Hide resolved
{#each Networks as { network, url }}
<li class:selected={network.networkName === currentNetwork.networkName}>
<a data-testid={`network-${network.networkName}`} href={url}>{network.networkName} </a>
Expand Down
2 changes: 1 addition & 1 deletion client/src/lib/components/NetworkInput.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
<Chevron />
</div>
</div>
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-full text-white">
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-full text-white z-10">
{#each $testnet.chains as chain, i}
<li class:selected={network === chain.id} data-testid={`network-${i}`}>
<a on:click={() => selectChain(chain.id)}>{chain.name}</a>
Expand Down
10 changes: 10 additions & 0 deletions client/src/lib/utils/captcha.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export enum CaptchaProvider {
procaptcha = "procaptcha",
recaptcha = "recaptcha",
}

export const getCaptchaProvider = (provider: string): CaptchaProvider => {
if (provider === CaptchaProvider.procaptcha) return CaptchaProvider.procaptcha;
if (provider === CaptchaProvider.recaptcha) return CaptchaProvider.recaptcha;
throw new Error(`⭕ - Invalid captcha provider: ${provider}`);
};
Loading
Loading