A URL Shortener Powered by Cloudflare Worker with password protection feature

Introduction

This project is based on the work done by xyTom/Url-Shorten-Worker. I added a small javascript to prompt password to verify the user since ideally you do not want this service to be completely public because this kind of url shorten site usually will gett abused usage as the original author faced. Again, this is a simple javascript and no security consideration. Once tested with a better code, it will be replaced right away.

Cloudflare works has 100k/day requests limistation, which is enough for a small project to use.

Steps

1. Go to Workers KV and create a namespace.



2. Create a new worker.


3. Bind an instance of a KV Namespace to access its data in this new created Worker.

去Worker的Settings选选项卡中绑定KV Namespace

4.Where Variable name should set as LINKS and KV namespace is the namespace you just created in the first step.

其中Variable name填写LINKS, KV namespace填写你刚刚创建的命名空间



5. Copy the index.js code from this project to Cloudflare Worker.

复制本项目中的index.js的代码到Cloudflare Worker




const html404 = `<!DOCTYPE html>
<body>
  <h1>404 Not Found.</h1>
  <p>The url you visit is not found.</p>
</body>`
async function randomString(len) {
  len = len || 6;
  let $chars = ‘ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678’;    
  /****Removed confusing letters an numbers, oOLl,9gq,Vv,Uu,I1****/
 
  let maxPos = $chars.length;
  let result = ;
  for (i = 0; i < len; i++) {
    result += $chars.charAt(Math.floor(Math.random() * maxPos));
  }
  return result;
}
async function checkURL(URL){
    let str=URL;
    let Expression=/http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/;
    let objExp=new RegExp(Expression);
    if(objExp.test(str)==true){
      if (str[0] == ‘h’)
        return true;
      else
        return false;
    }else{
        return false;
    }
}
async function save_url(URL){
    let random_key=await randomString()
    let is_exist=await LINKS.get(random_key)
    console.log(is_exist)
    if (is_exist == null)
        return await LINKS.put(random_key, URL),random_key
    else
        save_url(URL)
}
async function handleRequest(request) {
  console.log(request)
  if (request.method === “POST”) {
    let req=await request.json()
    console.log(req[“url”])
    if(!await checkURL(req[“url”])){
    return new Response(`{“status”:500,”key”:”: Error: Url illegal.”}`, {
      headers: {
      “content-type”: “text/html;charset=UTF-8”,
      “Access-Control-Allow-Origin”:“*”,
      “Access-Control-Allow-Methods”: “POST”,
      },
    })}
    let stat,random_key=await save_url(req[“url”])
    console.log(stat)
    if (typeof(stat) == “undefined”){
      return new Response(`{“status”:200,”key”:”/`+random_key+`”}`, {
      headers: {
      “content-type”: “text/html;charset=UTF-8”,
      “Access-Control-Allow-Origin”:“*”,
      “Access-Control-Allow-Methods”: “POST”,
      },
    })
    }else{
      return new Response(`{“status”:200,”key”:”: Error:Reach the KV write limitation.”}`, {
      headers: {
      “content-type”: “text/html;charset=UTF-8”,
      “Access-Control-Allow-Origin”:“*”,
      “Access-Control-Allow-Methods”: “POST”,
      },
    })}
  }else if(request.method === “OPTIONS”){  
      return new Response(, {
      headers: {
      “content-type”: “text/html;charset=UTF-8”,
      “Access-Control-Allow-Origin”:“*”,
      “Access-Control-Allow-Methods”: “POST”,
      },
    })
  }
  const requestURL = new URL(request.url)
  const path = requestURL.pathname.split(“/”)[1]
  console.log(path)
  if(!path){
    const html= await fetch(“https://cdn.jsdelivr.net/gh/51sec/[email protected]/index.html”)
/****customized index.html at main branch, easier to edit it****/
   
    return new Response(await html.text(), {
    headers: {
      “content-type”: “text/html;charset=UTF-8”,
    },
  })
  }
  const value = await LINKS.get(path)
  console.log(value)
 
  const location = value
  if (location) {
    return Response.redirect(location, 302)
   
  }
  // If request not in kv, return 404
  return new Response(html404, {
    headers: {
      “content-type”: “text/html;charset=UTF-8”,
    },
    status: 404
  })
}
addEventListener(“fetch”, async event => {
  event.respondWith(handleRequest(event.request))
})


6. Click Save and Deploy

点击Save and Deploy

Note

Note: Because someone abuse this demo website, all the generated link will automatically expired after 24 hours. For long-term use, please deploy your own. To test this demo site, please use code ‘cool’. There is a space in the prompt textbox. You might want to delete that space first then enter the password.

注意:由于该示例服务被人滥用,用于转发诈骗网站,故所有由demo网站生成的链接24小时后会自动失效,如需长期使用请自行搭建。

Example Code for Authentication

This code has been put into index.html file. You might want to change it based on your needs.

<SCRIPT language="JavaScript">
var password;
var pass1="cool";
password=prompt('Please enter your password to view this page!',' ');
if (password!=pass1)
    window.location="https://51sec.org";
else
   {
    alert('Password Correct! Click OK to enter!');
    }
</SCRIPT>



Video

References

  • Github project: https://github.com/51sec/Url-Shorten-By-CF-Worker

By netsec

Leave a Reply

%d bloggers like this: