- JavaScript 63.5%
- HTML 36.5%
| functions | ||
| index.html | ||
| README.md | ||
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
- Link Creation (
index.html->POST /create):- A user enters a URL and selects an expiration time on the
index.htmlpage. - A
POSTrequest is made to the/createendpoint with the URL and expiry. - The
/createendpoint:- 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).
- A user enters a URL and selects an expiration time on the
- Accessing Guarded Link (
GET /go/[token]):- A user clicks or navigates to the tokenized link (e.g.,
https://yourdomain.com/go/TOKEN). - The
[token].jsworker (/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.
- A user clicks or navigates to the tokenized link (e.g.,
- CAPTCHA Verification (
POST /verify-captcha):- The user completes the reCAPTCHA on the interstitial page.
- The form on the interstitial page submits the
g-recaptcha-responseand thetokento the/verify-captchaendpoint. - The
/verify-captchaendpoint:- Verifies the
g-recaptcha-responsewith 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.
- Verifies the
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
- Cloudflare Account: Required for Workers, KV, and Pages.
- Wrangler CLI: (Optional, but recommended for advanced Cloudflare Workers development) Install via
npm install -g wrangleroryarn global add wrangler. - 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
-
Cloudflare KV Namespace:
- Create a KV namespace (e.g.,
LINKS) in your Cloudflare dashboard or via Wrangler:wrangler kv:namespace create LINKS - Note the
idfor 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.
- Variable name:
- Create a KV namespace (e.g.,
-
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.
-
Update reCAPTCHA Site Key in
[token].js: It's best practice to use the environment variable for the site key in[token].jsrather than hardcoding it. Modifyfunctions/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_9Z2c6ysrhR9hkwLgHqis a test key forlocalhost. Replace it with your actual site key.
Backend Endpoints Implementation
functions/create.js(POST/create):- This function needs to be implemented.
- It should:
- Parse
urlandexpiryfrom the JSON request body. - Generate a unique short token (e.g., using
crypto.randomUUID()or a nanoid-like library). - Store the mapping in the
LINKSKV namespace:await context.env.LINKS.put(token, originalUrl, { expirationTtl: expiryInSeconds }); - Return a JSON response like:
{ "tokenizedLink": "https://yourdomain.com/go/YOUR_TOKEN" }.
- Parse
functions/go/[token].js(GET/go/:token):- This is mostly provided. Ensure it correctly accesses the
RECAPTCHA_SITE_KEYfromcontext.env.
- This is mostly provided. Ensure it correctly accesses the
functions/verify-captcha.js(POST/verify-captcha):- This function needs to be implemented.
- It should:
- Get
g-recaptcha-responseandtokenfrom the form data. - Make a POST request to
https://www.google.com/recaptcha/api/siteverifywithsecret(yourRECAPTCHA_SECRET_KEYfromcontext.env),response(theg-recaptcha-response), and optionallyremoteip. - If Google's response indicates success:
- Retrieve
originalUrlfromcontext.env.LINKS.get(token). - If
originalUrlexists, returnResponse.redirect(originalUrl, 302).
- Retrieve
- Otherwise, return an error page or message.
- Get
Deployment
- Commit your code to a Git repository (GitHub, GitLab).
- 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.
- Deploy!