URL Shorten Serviec Powered By Cloudflare Workers - NETSEC

Latest

Learning, Sharing, Creating

Cybersecurity Memo

Wednesday, June 29, 2022

URL Shorten Serviec Powered By Cloudflare Workers

A URL Shortener Powered by Cloudflare Worker with a simple password protection feature to prevent abusing online. 

URL Shorten service is gonna to give you a short URL to replace your orginal long URL so you can easily copy/paste to somewhere else such as youtube. 



In this post, I am going to show you how to deploy a basic password protected Cloudflare Worker project to shorten your URL.

Short URL: https://go.51sec.org/

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. But pleae keep an eye on the usage in case your service is used abusely. 





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/Url-Shorten-By-CF-Worker@main/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. A few seconds, the change will take into effect. 



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>

Here is the interface how it looks like. You will need to enter 'cool' this password to log into system. 


After log in,  you will be able to see a textbox to enter your long URL. After clicked 'Shorten it' butten,  you will get a short url for you to copy and paste somewhere else. 





Video







References


No comments:

Post a Comment