From ca54072159948b13def9e0401f5b9f0419b363cb Mon Sep 17 00:00:00 2001 From: shannonwells Date: Thu, 19 Sep 2024 10:01:23 -0700 Subject: [PATCH] favicon update, rename a component Integrate HCaptcha IDE failed to add these * Fix tests for hcaptcha * Some renames to reflect the switch Update .env.example --- .env.example | 5 +- client/env.sample | 7 +- client/package.json | 1 + client/playwright.config.ts | 4 +- client/src/app.html | 2 +- client/src/lib/assets/logo.svg | 4 +- client/src/lib/components/CaptchaV2.svelte | 74 ++++++--------- ...tworkInput.svelte => ChainDropdown.svelte} | 0 client/src/lib/components/Form.svelte | 5 +- client/src/lib/utils/networkData.ts | 42 +-------- client/src/lib/utils/stores.ts | 4 +- client/src/routes/trappist/+page.svelte | 12 --- client/src/routes/westend/+page.svelte | 12 --- client/static/favicon-192.png | Bin 0 -> 2919 bytes client/static/favicon-512.png | Bin 0 -> 7873 bytes client/static/favicon.ico | Bin 0 -> 106851 bytes client/static/favicon.svg | 16 ++++ client/tests/faucet.ts | 44 +++------ client/tests/test.ts | 69 ++------------ client/vite.config.ts | 1 + client/yarn.lock | 5 ++ e2e/bootstrap.sh | 2 +- env.faucet.config.json | 2 +- src/dripper/Captcha.spec.ts | 18 ++++ src/dripper/{Recaptcha.ts => Captcha.ts} | 10 +-- src/dripper/DripRequestHandler.spec.ts | 8 +- src/dripper/DripRequestHandler.ts | 6 +- src/dripper/Recaptcha.spec.ts | 18 ---- src/dripper/polkadot/utils.spec.ts | 20 ++--- src/networkData.ts | 84 +++--------------- src/server/routes/actions.spec.ts | 2 +- src/test/globalSetup.unit.ts | 2 +- src/test/setupE2E.ts | 24 +++-- src/utils.spec.ts | 16 ---- 34 files changed, 149 insertions(+), 370 deletions(-) rename client/src/lib/components/{NetworkInput.svelte => ChainDropdown.svelte} (100%) delete mode 100644 client/src/routes/trappist/+page.svelte delete mode 100644 client/src/routes/westend/+page.svelte create mode 100644 client/static/favicon-192.png create mode 100644 client/static/favicon-512.png create mode 100644 client/static/favicon.ico create mode 100644 client/static/favicon.svg create mode 100644 src/dripper/Captcha.spec.ts rename src/dripper/{Recaptcha.ts => Captcha.ts} (60%) delete mode 100644 src/dripper/Recaptcha.spec.ts diff --git a/.env.example b/.env.example index 44c1b653..4841362b 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,6 @@ +# See src/networkData for available configuration networks. SMF_CONFIG_NETWORK="frequencyPaseo" +#SMF_CONFIG_NETWORK="localhost" SMF_CONFIG_PORT=5555 SMF_CONFIG_DEPLOYED_REF=local @@ -24,4 +26,5 @@ SMF_CONFIG_DEPLOYED_REF=local SMF_CONFIG_FAUCET_ACCOUNT_MNEMONIC="//Alice" # Only used with external access -SMF_CONFIG_RECAPTCHA_SECRET="6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe" # Public testing secret, will accept all tokens. +# HCaptcha Test secret, see https://docs.hcaptcha.com/#integration-testing-test-keys +SMF_CONFIG_CAPTCHA_SECRET=0x0000000000000000000000000000000000000000 diff --git a/client/env.sample b/client/env.sample index 124dfb56..e1229f9c 100644 --- a/client/env.sample +++ b/client/env.sample @@ -1,9 +1,12 @@ +# leave blank to turn off demo mode PUBLIC_DEMO_MODE= -PUBLIC_CAPTCHA_KEY=6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI +# test key for hcaptcha, see https://docs.hcaptcha.com/#integration-testing-test-keys +PUBLIC_CAPTCHA_KEY=10000000-ffff-ffff-ffff-000000000001 -# Direct requests to local instance +# Direct requests to local instance. Leave blank to use external default # PUBLIC_FAUCET_URL=http://localhost:5555/drip/web/ PUBLIC_FAUCET_URL= +# No need to edit these. PUBLIC_ISSUE_LINK=https://github.com/frequency-chain/testnet-faucet/issues/new/choose PUBLIC_FORUM="https://discord.com/channels/969001918460469250/969308337864867840" diff --git a/client/package.json b/client/package.json index 2e34f329..91ae0edf 100644 --- a/client/package.json +++ b/client/package.json @@ -25,6 +25,7 @@ "postcss-load-config": "^6.0.1", "svelte": "^4.2.19", "svelte-check": "^4.0.2", + "svelte-hcaptcha": "^0.1.1", "svelte-markdown": "^0.4.1", "svelte-meta-tags": "^3.1.4", "svelte-preprocess": "^6.0.2", diff --git a/client/playwright.config.ts b/client/playwright.config.ts index ed75383e..c8e5fa26 100644 --- a/client/playwright.config.ts +++ b/client/playwright.config.ts @@ -5,10 +5,8 @@ const config: PlaywrightTestConfig = { command: "npm run build && npm run preview", port: 4173, env: { - PUBLIC_CAPTCHA_KEY: "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI", - PUBLIC_DEMO_MODE: "", + PUBLIC_CAPTCHA_KEY: "10000000-ffff-ffff-ffff-000000000001", PUBLIC_FAUCET_URL: "https://example.com/test", - PUBLIC_FORUM: "", }, }, testDir: "tests", diff --git a/client/src/app.html b/client/src/app.html index 5e309a9a..69604632 100644 --- a/client/src/app.html +++ b/client/src/app.html @@ -2,7 +2,7 @@ - + %sveltekit.head% diff --git a/client/src/lib/assets/logo.svg b/client/src/lib/assets/logo.svg index c7c199dc..ff90cc6f 100644 --- a/client/src/lib/assets/logo.svg +++ b/client/src/lib/assets/logo.svg @@ -1,13 +1,13 @@ - + - + diff --git a/client/src/lib/components/CaptchaV2.svelte b/client/src/lib/components/CaptchaV2.svelte index fba9b121..f45bddf8 100644 --- a/client/src/lib/components/CaptchaV2.svelte +++ b/client/src/lib/components/CaptchaV2.svelte @@ -1,66 +1,42 @@ + } - - {#if componentMounted} - - {/if} - + const handleError = (error: Error) => { + captchaError = true; + console.error(error) + } + + {#if captchaError}
- Error loading Google Captcha. Please reload the page. + Error loading HCaptcha. Please reload the page.
{/if} diff --git a/client/src/lib/components/NetworkInput.svelte b/client/src/lib/components/ChainDropdown.svelte similarity index 100% rename from client/src/lib/components/NetworkInput.svelte rename to client/src/lib/components/ChainDropdown.svelte diff --git a/client/src/lib/components/Form.svelte b/client/src/lib/components/Form.svelte index 6433cfdd..7ac9c2f8 100644 --- a/client/src/lib/components/Form.svelte +++ b/client/src/lib/components/Form.svelte @@ -1,11 +1,10 @@ - - diff --git a/client/src/routes/westend/+page.svelte b/client/src/routes/westend/+page.svelte deleted file mode 100644 index 06e85b50..00000000 --- a/client/src/routes/westend/+page.svelte +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/client/static/favicon-192.png b/client/static/favicon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..79c5877c77e15eb4692004162b6c186a2d50878e GIT binary patch literal 2919 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 uG7KrjXtF!XQA=dq*t#2J21RH|A|{KlMM+n6{Gu literal 0 HcmV?d00001 diff --git a/client/static/favicon.ico b/client/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..f92e3348d1235c59cd13044e9002440c56ced87a GIT binary patch literal 106851 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 literal 0 HcmV?d00001 diff --git a/client/static/favicon.svg b/client/static/favicon.svg new file mode 100644 index 00000000..057ecfc7 --- /dev/null +++ b/client/static/favicon.svg @@ -0,0 +1,16 @@ + + + + + + + + \ No newline at end of file diff --git a/client/tests/faucet.ts b/client/tests/faucet.ts index 441edcd9..def5560f 100644 --- a/client/tests/faucet.ts +++ b/client/tests/faucet.ts @@ -1,10 +1,10 @@ import { - type Frame, - type FullConfig, - type Locator, - type Page, - expect, - test + type Frame, + type FullConfig, + type Locator, + type Page, + expect, + test, type ElementHandle, type Route } from "@playwright/test"; type FormSubmit = { @@ -17,29 +17,7 @@ const getFormElements = async (page: Page, getCaptcha = false) => { // eslint-disable-next-line @typescript-eslint/consistent-type-assertions let captcha: Locator = {} as Locator; if (getCaptcha) { - // ?: Hack. We need to wait for the frame to load and then invade it. - await page.reload(); - const captchaFrame = await new Promise((resolve, reject) => { - let i = 0; - // function that waits for the frame and timeouts after 3 seconds - // FIXME consider "until" from "@eng-automation/js"? - // eslint-disable-next-line no-restricted-syntax - (function waitForFrame() { - const captchaFrames = page - .frames() - .filter((f) => f.url().includes("https://www.google.com/recaptcha/api2/")); - if (captchaFrames.length > 0) { - return resolve(captchaFrames[0]); - } else { - i++; - if (i > 10) { - reject(new Error("Timeout")); - } - } - setTimeout(waitForFrame, 300); - })(); - }); - captcha = captchaFrame?.locator("#recaptcha-anchor") as Locator; + captcha = await page.locator('iframe[title="Widget containing checkbox for hCaptcha security challenge"]'); } return { address: page.getByTestId("address"), @@ -222,10 +200,10 @@ export class FaucetTests { const { address, captcha, submit } = await getFormElements(page, true); await expect(submit).toBeDisabled(); await address.fill(validAddress); - await captcha.click(); + await captcha.contentFrame().getByLabel('hCaptcha checkbox with text').click(); const faucetUrl = this.getFaucetUrl(config); - await page.route(faucetUrl, (route) => + await page.route(faucetUrl, (route: Route) => route.fulfill({ body: JSON.stringify({ hash: "hash" }) }) ); @@ -254,7 +232,7 @@ export class FaucetTests { const networkBtn = page.getByTestId(`network-${i}`); await expect(networkBtn).toBeVisible(); await networkBtn.click(); - await captcha.click(); + await captcha.contentFrame().getByLabel('hCaptcha checkbox with text').click(); await expect(submit).toBeEnabled(); const faucetUrl = this.getFaucetUrl(config); await page.route(faucetUrl, (route) => @@ -284,7 +262,7 @@ export class FaucetTests { const customChainDiv = page.getByTestId("custom-network-button"); await customChainDiv.click(); await network.fill("9999"); - await captcha.click(); + await captcha.contentFrame().getByLabel('hCaptcha checkbox with text').click(); await expect(submit).toBeEnabled(); const faucetUrl = this.getFaucetUrl(config); await page.route(faucetUrl, (route) => diff --git a/client/tests/test.ts b/client/tests/test.ts index a2c144f0..cfa1cc9a 100644 --- a/client/tests/test.ts +++ b/client/tests/test.ts @@ -7,7 +7,7 @@ import { test } from "@playwright/test"; -const chains = [{ name: "Frequency Rococo Testnet Chain", id: -1 }]; +const chains = [{ name: "Frequency Paseo Testnet Chain", id: -1 }]; type FormSubmit = { address: string; @@ -19,28 +19,10 @@ const testAddress = '5G3r2K1cEi4vtdBjMNHpjWCofRdyg2AFSdVVxMGkDGvuJgaG'; const getFormElements = async (page: Page, getCaptcha = false) => { let captcha: Locator = {} as Locator; + let captchaFrame: Locator = {} as Locator; if (getCaptcha) { - // ?: Hack. We need to wait for the frame to load and then invade it. - await page.reload(); - const captchaFrame = await new Promise((resolve, reject) => { - let i = 0; - // function that waits for the frame and timeouts after 3 seconds - (function waitForFrame() { - const captchaFrame = page - .frames() - .filter((f) => f.url().includes("https://www.google.com/recaptcha/api2/")); - if (captchaFrame.length > 0) { - return resolve(captchaFrame[0]); - } else { - i++; - if (i > 10) { - reject(new Error("Timout")); - } - } - setTimeout(waitForFrame, 300); - })(); - }); - captcha = captchaFrame?.locator("#recaptcha-anchor") as Locator; + captchaFrame = await page.locator('iframe[title="Widget containing checkbox for hCaptcha security challenge"]'); + captcha = await captchaFrame.locator("#anchor") } return { address: page.getByTestId("address"), @@ -118,7 +100,7 @@ test.describe("form interaction", () => { const { address, captcha, submit } = await getFormElements(page, true); await expect(submit).toBeDisabled(); await address.fill(testAddress); - await captcha.click(); + await captcha.contentFrame().getByLabel('hCaptcha checkbox with text').click(); await expect(submit).toBeEnabled(); }); @@ -128,7 +110,7 @@ test.describe("form interaction", () => { await expect(submit).toBeDisabled(); const myAddress = "0x000000001"; await address.fill(myAddress); - await captcha.click(); + await captcha.contentFrame().getByLabel('hCaptcha checkbox with text').click(); const url = getFaucetUrl(config); await page.route(url, (route) => route.fulfill({ @@ -149,43 +131,6 @@ test.describe("form interaction", () => { await request; }); - for (let i = 1; i < chains.length; i++) { - const chain = chains[i]; - test(`sends data with ${chain.name} chain on submit`, async ({ page }, { config }) => { - await page.goto("/"); - const { address, captcha, submit } = await getFormElements(page, true); - const dropdown = page.getByTestId(dropdownId); - await expect(submit).toBeDisabled(); - const myAddress = "0x000000002"; - await address.fill(myAddress); - await dropdown.click(); - const networkBtn = page.getByTestId(`network-${i}`); - await expect(networkBtn).toBeVisible(); - await networkBtn.click(); - await captcha.click(); - await expect(submit).toBeEnabled(); - const url = getFaucetUrl(config); - await page.route(url, (route) => - route.fulfill({ - body: JSON.stringify({ hash: "hash" }) - }) - ); - - const request = page.waitForRequest((req) => { - if (req.url() === url) { - const data = req.postDataJSON() as FormSubmit; - const parachain_id = chain.id > 0 ? chain.id.toString() : undefined; - expect(data).toMatchObject({ address: myAddress, parachain_id }); - return !!data.recaptcha; - } - return false; - }); - - await submit.click(); - await request; - }); - } - // test("display link to transaction", async ({ page }, { config }) => { // await page.goto("/"); // const operationHash = "0x0123435423412343214"; @@ -211,7 +156,7 @@ test.describe("form interaction", () => { const { address, captcha, submit } = await getFormElements(page, true); await expect(submit).toBeDisabled(); await address.fill("0x123"); - await captcha.click(); + await captcha.contentFrame().getByLabel('hCaptcha checkbox with text').click(); await page.route(getFaucetUrl(config), (route) => route.fulfill({ body: JSON.stringify({ error }) diff --git a/client/vite.config.ts b/client/vite.config.ts index 7102f34d..934cc732 100644 --- a/client/vite.config.ts +++ b/client/vite.config.ts @@ -1,4 +1,5 @@ import { sveltekit } from "@sveltejs/kit/vite"; +// @ts-ignore import { defineConfig } from "vite"; // eslint-disable-next-line @typescript-eslint/no-unsafe-call diff --git a/client/yarn.lock b/client/yarn.lock index bbf73943..54991b89 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -1700,6 +1700,11 @@ svelte-check@^4.0.2: picocolors "^1.0.0" sade "^1.7.4" +svelte-hcaptcha@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/svelte-hcaptcha/-/svelte-hcaptcha-0.1.1.tgz#b2db3ae317d93de3ffba570f27e2f3b32dcd02b1" + integrity sha512-iFF3HwfrCRciJnDs4Y9/rpP/BM2U/5zt+vh+9d4tALPAHVkcANiJIKqYuS835pIaTm6gt+xOzjfFI3cgiRI29A== + svelte-hmr@^0.16.0: version "0.16.0" resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.16.0.tgz#9f345b7d1c1662f1613747ed7e82507e376c1716" diff --git a/e2e/bootstrap.sh b/e2e/bootstrap.sh index 83d9eb8f..5102e974 100755 --- a/e2e/bootstrap.sh +++ b/e2e/bootstrap.sh @@ -71,5 +71,5 @@ SMF_BACKEND_PORT=5555 SMF_BACKEND_DEPLOYED_REF=local SMF_BACKEND_DEPLOYED_TIME=local SMF_BACKEND_EXTERNAL_ACCESS=true -SMF_BACKEND_RECAPTCHA_SECRET="6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe" # Public testing secret, will accept all tokens. +SMF_BACKEND_CAPTCHA_SECRET="0x0000000000000000000000000000000000000000" # Public testing secret, will accept all tokens. EOF diff --git a/env.faucet.config.json b/env.faucet.config.json index b6f78426..6559f769 100644 --- a/env.faucet.config.json +++ b/env.faucet.config.json @@ -43,7 +43,7 @@ "default": 5555, "type": "number" }, - "RECAPTCHA_SECRET": { + "CAPTCHA_SECRET": { "description": "A secret recaptcha token used to validate external requests", "default": "", "masked": true, diff --git a/src/dripper/Captcha.spec.ts b/src/dripper/Captcha.spec.ts new file mode 100644 index 00000000..240a49e7 --- /dev/null +++ b/src/dripper/Captcha.spec.ts @@ -0,0 +1,18 @@ +import { Captcha } from "./Captcha"; + +describe("HCaptcha", () => { + it("Validates captcha positively", async () => { + const validTestSecretKey = "0x0000000000000000000000000000000000000000"; + const validTestResponseToken = "10000000-aaaa-bbbb-cccc-000000000001"; + const recaptcha = new Captcha(validTestSecretKey); + const result = await recaptcha.validate(validTestResponseToken); + expect(result).toBeTruthy(); + }); + + it("Validates captcha negatively", async () => { + const badSecretKey = "AAAAAAAAAAAAAAA-AAAAAAAAAAAAAAAAAAAAAAAA"; + const recaptcha = new Captcha(badSecretKey); + const result = await recaptcha.validate("doesnt matter"); + expect(result).toBeFalsy(); + }); +}); diff --git a/src/dripper/Recaptcha.ts b/src/dripper/Captcha.ts similarity index 60% rename from src/dripper/Recaptcha.ts rename to src/dripper/Captcha.ts index ce1af0ad..2f20b82f 100644 --- a/src/dripper/Recaptcha.ts +++ b/src/dripper/Captcha.ts @@ -4,10 +4,10 @@ import { URLSearchParams } from "url"; import { config } from "../config"; import { logger } from "../logger"; -export class Recaptcha { - constructor(private secret: string = config.Get("RECAPTCHA_SECRET")) { +export class Captcha { + constructor(private secret: string = config.Get("CAPTCHA_SECRET")) { if (!this.secret) { - throw new Error(`⭕ Recaptcha is not configured. Check the RECAPTCHA_SECRET variable.`); + throw new Error(`⭕ HCaptcha is not configured. Check the CAPTCHA_SECRET variable.`); } } @@ -16,9 +16,9 @@ export class Recaptcha { const params = new URLSearchParams(); params.append("secret", this.secret); params.append("response", captcha); - const captchaResult = await axios.post("https://www.google.com/recaptcha/api/siteverify", params); + const captchaResult = await axios.post("https://api.hcaptcha.com/siteverify", params); if (captchaResult.data.success === true) return true; - logger.debug("Negative recaptcha validation result", captchaResult.data); + logger.debug("❌Negative recaptcha validation result", captchaResult.data); return false; } catch (e) { logger.error(`⭕ An error occurred when validating captcha`, e); diff --git a/src/dripper/DripRequestHandler.spec.ts b/src/dripper/DripRequestHandler.spec.ts index 9b76c82d..b35fea8a 100644 --- a/src/dripper/DripRequestHandler.spec.ts +++ b/src/dripper/DripRequestHandler.spec.ts @@ -1,8 +1,8 @@ +import type { Captcha } from "./Captcha"; import { hasDrippedToday, saveDrip } from "./dripperStorage"; import { DripRequestHandler } from "./DripRequestHandler"; import type { PolkadotActions } from "./polkadot/PolkadotActions"; import { convertAmountToBn } from "./polkadot/utils"; -import type { Recaptcha } from "./Recaptcha"; jest.mock("./dripperStorage"); @@ -12,7 +12,7 @@ const actionsMock: PolkadotActions = { addr === "unlucky" ? { error: "An error occurred when sending tokens" } : { hash: "0x123" }, } as any; // eslint-disable-line @typescript-eslint/no-explicit-any -const recaptcha: Recaptcha = { validate: async (captcha: string) => captcha === "valid" } as any; // eslint-disable-line @typescript-eslint/no-explicit-any +const recaptcha: Captcha = { validate: async (captcha: string) => captcha === "valid" } as any; // eslint-disable-line @typescript-eslint/no-explicit-any function assumeMocked(f: (...args: A) => R): jest.Mock { return f as jest.Mock; @@ -70,12 +70,12 @@ describe("DripRequestHandler", () => { it("Parity members are privileged in terms of repeated requests", async () => { assumeMocked(hasDrippedToday).mockResolvedValueOnce(true); - const result = await handler.handleRequest({ ...defaultRequest, sender: "someone:parity.io" }); + const result = await handler.handleRequest({ ...defaultRequest, sender: "@erin:parity.io" }); expect(result).toEqual({ hash: "0x123" }); }); it("Parity members are privileged in terms of balance cap", async () => { - const result = await handler.handleRequest({ ...defaultRequest, sender: "someone:parity.io", address: "rich" }); + const result = await handler.handleRequest({ ...defaultRequest, sender: "@pierre:parity.io", address: "rich" }); expect(result).toEqual({ hash: "0x123" }); }); diff --git a/src/dripper/DripRequestHandler.ts b/src/dripper/DripRequestHandler.ts index f44f14b9..aca8dd94 100644 --- a/src/dripper/DripRequestHandler.ts +++ b/src/dripper/DripRequestHandler.ts @@ -3,9 +3,9 @@ import { logger } from "../logger"; import { counters } from "../metrics"; import { DripRequestType, DripResponse } from "../types"; import { isAccountPrivileged } from "../utils"; +import { Captcha } from "./Captcha"; import { hasDrippedToday, saveDrip } from "./dripperStorage"; import type { PolkadotActions } from "./polkadot/PolkadotActions"; -import { Recaptcha } from "./Recaptcha"; const isParachainValid = (parachain: string): boolean => { if (!parachain) { @@ -22,7 +22,7 @@ const isParachainValid = (parachain: string): boolean => { export class DripRequestHandler { constructor( private actions: PolkadotActions, - private recaptcha: Recaptcha, + private recaptcha: Captcha, ) {} async handleRequest( @@ -66,7 +66,7 @@ export class DripRequestHandler { let instance: DripRequestHandler | undefined; export const getDripRequestHandlerInstance = (polkadotActions: PolkadotActions) => { if (!instance) { - const recaptchaService = new Recaptcha(); + const recaptchaService = new Captcha(); instance = new DripRequestHandler(polkadotActions, recaptchaService); } return instance; diff --git a/src/dripper/Recaptcha.spec.ts b/src/dripper/Recaptcha.spec.ts deleted file mode 100644 index e8263cc5..00000000 --- a/src/dripper/Recaptcha.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Recaptcha } from "./Recaptcha"; - -const PUBLIC_TESTING_RECAPTCHA_SECRET_KEY = "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe"; -const OTHER_SECRET_KEY = "AAAAAAAAAAAAAAA-AAAAAAAAAAAAAAAAAAAAAAAA"; - -describe("Recaptcha", () => { - it("Validates captcha positively", async () => { - const recaptcha = new Recaptcha(PUBLIC_TESTING_RECAPTCHA_SECRET_KEY); - const result = await recaptcha.validate("something"); - expect(result).toBeTruthy(); - }); - - it("Validates captcha negatively", async () => { - const recaptcha = new Recaptcha(OTHER_SECRET_KEY); - const result = await recaptcha.validate("something"); - expect(result).toBeFalsy(); - }); -}); diff --git a/src/dripper/polkadot/utils.spec.ts b/src/dripper/polkadot/utils.spec.ts index 59484774..83d7994e 100644 --- a/src/dripper/polkadot/utils.spec.ts +++ b/src/dripper/polkadot/utils.spec.ts @@ -3,21 +3,21 @@ import { convertAmountToBn } from "./utils"; describe("utils", () => { [ { amount: "0", expected: "0" }, - { amount: "1", expected: "1000000000000" }, - { amount: "100", expected: "100000000000000" }, - { amount: "1.45", expected: "1450000000000" }, - { amount: "145.454141111", expected: "145454141111000" }, - { amount: "99999999.9", expected: "99999999900000000000" }, - { amount: "999999999", expected: "999999999000000000000" }, - { amount: "999999999.9", expected: "999999999900000000000" }, - { amount: "999999999999999.9", expected: "999999999999999900000000000" }, + { amount: "1", expected: "10000000000" }, + { amount: "100", expected: "1000000000000" }, + { amount: "1.45", expected: "14500000000" }, + { amount: "145.454141111", expected: "1454541411110" }, + { amount: "99999999.9", expected: "999999999000000000" }, + { amount: "999999999", expected: "9999999990000000000" }, + { amount: "999999999.9", expected: "9999999999000000000" }, + { amount: "999999999999999.9", expected: "9999999999999999000000000" }, { amount: "999999999999999999999999999999999999999999999999999999", - expected: "999999999999999999999999999999999999999999999999999999000000000000", + expected: "9999999999999999999999999999999999999999999999999999990000000000", }, { amount: "999999999999999999999999999999999999999999999999999999.7", - expected: "999999999999999999999999999999999999999999999999999999700000000000", + expected: "9999999999999999999999999999999999999999999999999999997000000000", }, ].forEach((t) => test(`convertAmountToBn ${t.amount} => ${t.expected}`, () => { diff --git a/src/networkData.ts b/src/networkData.ts index a249877c..31151875 100644 --- a/src/networkData.ts +++ b/src/networkData.ts @@ -17,24 +17,16 @@ export interface NetworkData { matrixWhitelistPatterns: RegExp[]; } -const parityWhitelist = [/^.*:parity.io$/, /^.*:web3.foundation$/]; - -const rococo: NetworkData = { +const localhost: NetworkData = { balanceCap: 1000, - chains: [ - { name: "Rococo Relay Chain", id: -1 }, - { name: "Rockmine", id: 1000 }, - { name: "Contracts", id: 1002 }, - { name: "Encointer Lietaer", id: 1003 }, - { name: "Bridgehub", id: 1013 }, - ], - currency: "ROC", - decimals: 12, - dripAmount: "100", - explorer: "https://rococo.subscan.io", - networkName: "Rococo", - rpcEndpoint: "wss://rococo-rpc.polkadot.io/", - matrixWhitelistPatterns: parityWhitelist, + chains: [{ name: "Localhost", id: 1000 }], + currency: "UNIT", + decimals: 8, + dripAmount: "10", + explorer: "", + networkName: "Localhost", + rpcEndpoint: "ws://127.0.0.1:9944", + matrixWhitelistPatterns: [], }; const frequencyPaseo: NetworkData = { @@ -49,46 +41,6 @@ const frequencyPaseo: NetworkData = { matrixWhitelistPatterns: [], }; -const westend: NetworkData = { - balanceCap: 100, - chains: [ - { name: "Westend Relay Chain", id: -1 }, - { name: "Westmint", id: 1000 }, - { name: "Collectives", id: 1001 }, - ], - currency: "WND", - decimals: 12, - dripAmount: "10", - explorer: "https://westend.subscan.io", - networkName: "Westend", - rpcEndpoint: "wss://westend-rpc.polkadot.io/", - matrixWhitelistPatterns: parityWhitelist, -}; - -const versi: NetworkData = { - balanceCap: 1000, - chains: [], - currency: "VRS", - decimals: 12, - dripAmount: "100", - explorer: null, - networkName: "Versi", - rpcEndpoint: "wss://versi-rpc-node-0.parity-versi.parity.io/", - matrixWhitelistPatterns: parityWhitelist, -}; - -const trappist: NetworkData = { - balanceCap: 100, - chains: [], - currency: "HOP", - decimals: 12, - dripAmount: "10", - explorer: null, - networkName: "Trappist", - rpcEndpoint: "wss://rococo-trappist-rpc.polkadot.io/", - matrixWhitelistPatterns: parityWhitelist, -}; - const paseo: NetworkData = { balanceCap: 500, chains: [], @@ -111,26 +63,10 @@ const paseo: NetworkData = { ], }; -const e2e: NetworkData = { - balanceCap: 100, - chains: [], - currency: "UNIT", - decimals: 12, - dripAmount: "10", - explorer: null, - networkName: "Rococo", - rpcEndpoint: "ws://host.docker.internal:9933/", - matrixWhitelistPatterns: parityWhitelist, -}; - export const networks: Record = { - rococo, - versi, - westend, - e2e, - trappist, paseo, frequencyPaseo, + localhost, }; export function getNetworkData(networkName: string): NetworkData { diff --git a/src/server/routes/actions.spec.ts b/src/server/routes/actions.spec.ts index 94afb0b7..ef1e0f0a 100644 --- a/src/server/routes/actions.spec.ts +++ b/src/server/routes/actions.spec.ts @@ -36,7 +36,7 @@ jest.mock("../../config", () => { Get: mockConfig.mockImplementation( (key: string) => // eslint-disable-next-line security/detect-object-injection - ({ NETWORK: "rococo" })[key], // minimal viable config on the initial import + ({ NETWORK: "paseo" })[key], // minimal viable config on the initial import ), }, }; diff --git a/src/test/globalSetup.unit.ts b/src/test/globalSetup.unit.ts index b63d9c43..011f918f 100644 --- a/src/test/globalSetup.unit.ts +++ b/src/test/globalSetup.unit.ts @@ -1,3 +1,3 @@ export default function() { - process.env.SMF_CONFIG_NETWORK = "rococo" + process.env.SMF_CONFIG_NETWORK = "paseo" } diff --git a/src/test/setupE2E.ts b/src/test/setupE2E.ts index 4bc25910..7c793977 100644 --- a/src/test/setupE2E.ts +++ b/src/test/setupE2E.ts @@ -112,18 +112,16 @@ export async function teardown(setup: E2ESetup): Promise { async function setupMatrixContainer(): Promise { const image = await GenericContainer.fromDockerfile("e2e", "matrix_container.Dockerfile").build(); - const matrixContainer = image - .withExposedPorts(8008) - .withEnvironment({ - SYNAPSE_SERVER_NAME: "parity.io", - SYNAPSE_REPORT_STATS: "no" - }) - .withCommand(["run"]) - .withWaitStrategy(Wait.forHealthCheck()) - .withLogConsumer(logConsumer("faucet-test-matrix")) - .start(); - - return matrixContainer; + return image + .withExposedPorts(8008) + .withEnvironment({ + SYNAPSE_SERVER_NAME: "parity.io", + SYNAPSE_REPORT_STATS: "no" + }) + .withCommand(["run"]) + .withWaitStrategy(Wait.forHealthCheck()) + .withLogConsumer(logConsumer("faucet-test-matrix")) + .start(); } async function setupMatrix(matrixContainer: StartedTestContainer): Promise { @@ -224,7 +222,7 @@ async function setupAppContainer(params: { SMF_CONFIG_DB_DATABASE_NAME: "faucet", // Public testing secret, will accept all tokens. - SMF_CONFIG_RECAPTCHA_SECRET: "6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe" + SMF_CONFIG_CAPTCHA_SECRET: "0x0000000000000000000000000000000000000000" }) .withWaitStrategy(Wait.forListeningPorts()) .withExtraHosts([{ host: "host.docker.internal", ipAddress: "host-gateway" }]) diff --git a/src/utils.spec.ts b/src/utils.spec.ts index 24ef664f..cbd316fb 100644 --- a/src/utils.spec.ts +++ b/src/utils.spec.ts @@ -9,22 +9,6 @@ type DataProvider = { jest.mock("./networkData"); -describe("test rococo", () => { - const dataProvider: DataProvider[] = [ - { username: "1", expected: false }, - { username: "", expected: false }, - { username: "@username:matrix.org", expected: false }, - { username: "@1:parity.io", expected: true }, - { username: "@1:matrix.parity.io", expected: false }, - { username: "@1:web3.foundation", expected: true }, - { username: "@1:web3.foundati", expected: false }, - ]; - - test.each(dataProvider)("$username, $expect", ({ username, expected }) => { - expect(isAccountPrivileged(username)).toBe(expected); - }); -}); - describe("test paseo", () => { beforeAll(() => { process.env.SMF_CONFIG_NETWORK = "paseo";