Coder Social home page Coder Social logo

cf-pages-genuine-user's Introduction

Cloudflare Pages with Static Forms and hCaptcha

This project demonstrates how to create a serverless function on Cloudflare Pages using static forms and hCaptcha verification. The form allows users to verify their contact information, and the data is stored in a Cloudflare KV Namespace.

Setup

Prerequisites

  1. Node.js and npm installed on your machine.
  2. A Cloudflare account.
  3. Cloudflare Workers and KV Namespace set up.
  4. hCaptcha account for obtaining the secret and site key.

Dependencies

This project requires two libraries:

Make sure install them or include them in your project.

Installation:

npm i @cloudflare/pages-plugin-static-forms @cloudflare/pages-plugin-hcaptcha

Environment Variables

Create a .env file in the root of your project and add the following environment variables:

HCAPTCHA_SECRET=<your-hcaptcha-secret-key>
HCAPTCHA_SITE_KEY=<your-hcaptcha-site-key>

Installation

  1. Clone the repository:

    git clone https://github.com/rastislavcore/cf-pages-genuine-user.git
    cd cf-pages-genuine-user
  2. Install dependencies:

    npm i
  3. Deploy to Cloudflare Pages:

    npx wrangler publish

Key-Value (KV) Storage

Set up KV storage and binding for the system in read-only mode.

Set KV namespace bindings

  1. Open CLoudflare Dashboard - Workers & Pages - Your deployed page.
  2. Go to project Settings - Functions tab.
  3. Scroll down to KV namespace bindings.
  4. Click on "Get started" button.
  5. Click on "Create a namespace" button.
  6. Fill in Namespace Name as AUTHORIZED_CONTACTS and click "Add".
  7. Now you can add the entries.

Read more here.

You can define different KV binding for staging and production, which is recommended.

Database structure

Key Value
type:username representative
  • type: The provider type in lowercase characters.
  • username: The username of the representative in lowercase characters, with the first character @ or + trimmed.
  • representative: The public name of representative for the requester. Output example: User: '${representative}' is an official representative under this contact.

Building

If you would like build JavaScript file, you can use command:

npm i && npm build

If you need just Typescript file, installing required libraries is enough:

npm i

API

API structure:

Endpoint Version Action
/api /1 /verify

You can customize the path simply changing the structure in the /functions folder and changing action in the form.

Usage

HTML / JS

Use the following HTML for your form. Place this in an HTML file that you serve from your Cloudflare Pages site.

<form id="verify-form" data-static-form-name="verify-person" method="post" action="/api/1/verify">
    <select id="type" name="type" required></select>
    <input type="text" id="username" name="username" pattern="[a-zA-Z0-9%_@.+\-]+" title="Insert valid username without any prefixes or suffixes." required />
    <div class="h-captcha" data-sitekey="your_site_key"></div>
    <script src="https://hcaptcha.com/1/api.js" async defer></script>
    <button type="submit">Verify</button>
</form>

And script for showing the result:

<div id="response-message"></div>

<script>
    document.getElementById('verify-form').addEventListener('submit', async (event) => {
        event.preventDefault();

        const form = event.target;
        const formData = new FormData(form);

        try {
            const response = await fetch(form.action, {
                method: form.method,
                body: formData
            });

            const messageDiv = document.getElementById('response-message');
            if (response.ok) {
                const result = await response.json();
                messageDiv.textContent = result.message;
            } else {
                const errorData = await response.json();
                messageDiv.textContent = `Error: ${errorData.message}`;
            }
        } catch (error) {
            document.getElementById('response-message').textContent = `Server error. Please, contact the support department.`;
        }
    });
</script>

React

import React, { useEffect } from 'react';

declare global {
  interface Window {
    hcaptcha: any;
  }
}

useEffect(() => {
    const loadScript = () => {
        const script = document.createElement('script');
        script.src = 'https://hcaptcha.com/1/api.js';
        script.async = true;
        script.defer = true;
        document.body.appendChild(script);

        script.onload = () => {
            console.log('hCaptcha script loaded successfully');
        };

        script.onerror = () => {
            console.error('Error loading hCaptcha script');
        };
    };

    loadScript();

    const form = document.getElementById('verify-form');
    const messageDiv = document.getElementById('response-message');

    const handleSubmit = async (event: Event) => {
        event.preventDefault();
        if (!form || !messageDiv) return;

        const formData = new FormData(form as HTMLFormElement);

        try {
            const response = await fetch(form.getAttribute('action') || '', {
                method: form.getAttribute('method') || 'POST',
                body: formData,
            });

            if (response.ok) {
                const result = await response.json();
                messageDiv.textContent = result.message;
                if (result.valid) {
                    messageDiv.style.color = 'green';
                } else {
                    messageDiv.style.color = 'red';
                }
                if (window.hcaptcha) {
                    window.hcaptcha.reset();
                }
            } else {
                const errorData = await response.json();
                messageDiv.textContent = `Error: ${errorData.message}`;
                messageDiv.style.color = 'red';
                if (window.hcaptcha) {
                    window.hcaptcha.reset();
                }
            }
        } catch (error) {
            messageDiv.textContent = 'Server error. Please, contact the support department.';
            messageDiv.style.color = 'red';
            if (window.hcaptcha) {
                window.hcaptcha.reset();
            }
        }
    };

    form?.addEventListener('submit', handleSubmit);

    return () => {
        form?.removeEventListener('submit', handleSubmit);
    };
}, []);

License

This project is licensed under the Core License.

cf-pages-genuine-user's People

Contributors

rastislavcore avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.