No description
  • JavaScript 63.5%
  • HTML 36.5%
Find a file
2025-05-07 20:36:24 -07:00
functions Update create.js 2023-11-05 00:59:37 -07:00
index.html Update index.html 2023-11-05 00:54:55 -07:00
README.md Create README.md 2025-05-07 20:36:24 -07:00

Guarded Link Shortener

This project implements a URL shortener that "guards" links with a Google reCAPTCHA v2 challenge before redirecting to the original destination. This helps protect the destination URL from bots and unwanted automated access.

The frontend allows users to submit a URL and choose an expiration time. The backend, designed for a serverless environment like Cloudflare Workers, handles link creation, serves the reCAPTCHA interstitial page, and verifies the CAPTCHA response before redirection.

Features

  • URL Shortening: Creates short, tokenized links.
  • Customizable Expiration: Links can be set to expire after 1 hour, 1 day, 1 week, 1 month, 1 year, or never.
  • reCAPTCHA Protection: Users clicking a guarded link must pass a Google reCAPTCHA challenge.
  • Copy to Clipboard: Easy copying of the generated guarded link.
  • Serverless Backend: Designed to run on platforms like Cloudflare Workers/Pages.

How It Works

  1. Link Creation (index.html -> POST /create):
    • A user enters a URL and selects an expiration time on the index.html page.
    • A POST request is made to the /create endpoint with the URL and expiry.
    • The /create endpoint:
      • Generates a unique token.
      • Stores the original URL and its token in a Key-Value store (e.g., Cloudflare KV) with the specified expirationTtl.
      • Returns the tokenized link (e.g., https://yourdomain.com/go/TOKEN).
  2. Accessing Guarded Link (GET /go/[token]):
    • A user clicks or navigates to the tokenized link (e.g., https://yourdomain.com/go/TOKEN).
    • The [token].js worker (/go/[token]) handles this request.
    • It retrieves the original URL associated with the token from the KV store.
    • If found, it serves an interstitial HTML page containing a Google reCAPTCHA v2 challenge. The token is embedded in this page.
  3. CAPTCHA Verification (POST /verify-captcha):
    • The user completes the reCAPTCHA on the interstitial page.
    • The form on the interstitial page submits the g-recaptcha-response and the token to the /verify-captcha endpoint.
    • The /verify-captcha endpoint:
      • Verifies the g-recaptcha-response with Google's reCAPTCHA API using your secret key.
      • If verification is successful:
        • It retrieves the original URL from the KV store using the token.
        • It issues a 302 redirect to the original URL.
      • If verification fails, it displays an error message.

Technology Stack

  • Frontend: HTML, CSS, Vanilla JavaScript
  • Backend: Serverless Functions (e.g., Cloudflare Workers / Cloudflare Pages Functions)
  • Storage: Key-Value Store (e.g., Cloudflare KV for storing token-URL mappings)
  • CAPTCHA: Google reCAPTCHA v2 ("I'm not a robot" checkbox)

Project Structure

This project is structured to be deployable on Cloudflare Pages.

.
├── index.html               # Frontend for creating links
├── functions/               # Backend Cloudflare Functions
│   ├── create.js            # Handles POST /create (Needs to be implemented)
│   ├── go/
│   │   └── [token].js       # Handles GET /go/:token (Provided)
│   └── verify-captcha.js    # Handles POST /verify-captcha (Needs to be implemented)
└── README.md                # This file

Setup and Deployment (Cloudflare Pages Example)

Prerequisites

  1. Cloudflare Account: Required for Workers, KV, and Pages.
  2. Wrangler CLI: (Optional, but recommended for advanced Cloudflare Workers development) Install via npm install -g wrangler or yarn global add wrangler.
  3. Google reCAPTCHA v2 Keys:
    • Go to the Google reCAPTCHA Admin Console.
    • Register a new site. Choose "reCAPTCHA v2" and then "I'm not a robot" Checkbox.
    • Add your domain(s) where this will be hosted. For local testing, add localhost.
    • You will receive a Site Key and a Secret Key.

Configuration

  1. Cloudflare KV Namespace:

    • Create a KV namespace (e.g., LINKS) in your Cloudflare dashboard or via Wrangler:
      wrangler kv:namespace create LINKS
      
    • Note the id for this namespace. You'll need to bind this to your Pages Functions or Worker.
    • For Cloudflare Pages, add a binding in your Pages project settings:
      • Variable name: LINKS
      • KV namespace: Select the namespace you created.
  2. Environment Variables (Secrets): Configure these in your Cloudflare Pages project settings (Settings > Functions > Environment Variables) or for your Worker:

    • RECAPTCHA_SITE_KEY: Your Google reCAPTCHA v2 Site Key.
    • RECAPTCHA_SECRET_KEY: Your Google reCAPTCHA v2 Secret Key. This is highly sensitive.
  3. Update reCAPTCHA Site Key in [token].js: It's best practice to use the environment variable for the site key in [token].js rather than hardcoding it. Modify functions/go/[token].js:

    // In functions/go/[token].js, near the top or where interstitialHtml is defined:
    // const RECAPTCHA_SITE_KEY_PLACEHOLDER = '{{RECAPTCHA_SITE_KEY}}'; // Placeholder for build/deploy script
                                                                     // or directly use env.RECAPTCHA_SITE_KEY if available at request time in interstitialHtml generation
                                                                     // For Pages Functions, env vars are available in context.env
    
    // ... later in the file ...
    // Inside onRequestGet, before returning the response:
    const siteKey = context.env.RECAPTCHA_SITE_KEY; // Access from environment variables
    return new Response(
      interstitialHtml
        .replace('{{token}}', token)
        .replace('data-sitekey="6Lc2C_goAAAAACJIpAGHm_9Z2c6ysrhR9hkwLgHq"', `data-sitekey="${siteKey}"`), // Dynamically insert site key
      {
        headers: { 'Content-Type': 'text/html' },
        status: 200,
      }
    );
    

    Note: The provided reCAPTCHA key 6Lc2C_goAAAAACJIpAGHm_9Z2c6ysrhR9hkwLgHq is a test key for localhost. Replace it with your actual site key.

Backend Endpoints Implementation

  • functions/create.js (POST /create):
    • This function needs to be implemented.
    • It should:
      • Parse url and expiry from the JSON request body.
      • Generate a unique short token (e.g., using crypto.randomUUID() or a nanoid-like library).
      • Store the mapping in the LINKS KV namespace: await context.env.LINKS.put(token, originalUrl, { expirationTtl: expiryInSeconds });
      • Return a JSON response like: { "tokenizedLink": "https://yourdomain.com/go/YOUR_TOKEN" }.
  • functions/go/[token].js (GET /go/:token):
    • This is mostly provided. Ensure it correctly accesses the RECAPTCHA_SITE_KEY from context.env.
  • functions/verify-captcha.js (POST /verify-captcha):
    • This function needs to be implemented.
    • It should:
      • Get g-recaptcha-response and token from the form data.
      • Make a POST request to https://www.google.com/recaptcha/api/siteverify with secret (your RECAPTCHA_SECRET_KEY from context.env), response (the g-recaptcha-response), and optionally remoteip.
      • If Google's response indicates success:
        • Retrieve originalUrl from context.env.LINKS.get(token).
        • If originalUrl exists, return Response.redirect(originalUrl, 302).
      • Otherwise, return an error page or message.

Deployment

  1. Commit your code to a Git repository (GitHub, GitLab).
  2. Create a new Cloudflare Pages project:
    • Connect your Git repository.
    • Configure build settings (often, no build command is needed for static HTML + Functions).
    • Set up the KV binding and environment variables as described above.
  3. Deploy!