Feat: Add reCAPTCHA to link creation form

This commit is contained in:
2025-09-28 12:11:14 -07:00
parent 8c2e898bd4
commit 5ab4bd54dd

View File

@@ -7,6 +7,7 @@
<script src="https://cdn.tailwindcss.com"></script>
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>
<body class="bg-slate-50 text-slate-800 font-sans">
<script>if (!sessionStorage.getItem('username')) window.location.href = '/';</script>
@@ -60,7 +61,8 @@
<input x-model="slug" type="text" id="customSlug" placeholder="my-custom-link" class="w-full p-3 bg-slate-50 border border-slate-300 rounded-r-md focus:outline-none focus:ring-2 focus:ring-slate-400 focus:border-slate-400 transition">
</div>
</div>
<p x-text="error" x-show="error" class="text-rose-500 text-sm h-5"></p>
<div class="g-recaptcha my-4 flex justify-center" data-sitekey="6LeXhdYrAAAAALW6DdgxNeHU0kwBncdicLnVYvXT"></div>
<p x-text="error" x-show="error" class="text-rose-500 text-sm h-5 -mt-2 text-center"></p>
<button type="submit" :disabled="loading" class="w-full py-3 font-semibold rounded-lg text-white bg-slate-800 hover:bg-slate-900 transition-colors flex items-center justify-center disabled:opacity-50 disabled:cursor-not-allowed">
<span x-show="!loading">Create Short Link</span>
<i x-show="loading" data-lucide="loader-2" class="animate-spin w-6 h-6"></i>
@@ -74,7 +76,7 @@
</div>
<script>
function linkForm(){return{destination_url:"",slug:"",loading:!1,error:"",result:{},copied:!1,async createLink(){this.loading=!0,this.error="",this.result={};try{const e=sessionStorage.getItem("username"),s=sessionStorage.getItem("pass_hash");if(!e||!s)throw new Error("Authentication error. Please log in again.");const t=await fetch("/api/links/create",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({destination_url:this.destination_url,slug:this.slug||null,username:e,pass_hash:s})});if(!t.ok)throw new Error(await t.text()||"Failed to create link.");const i=await t.json(),o=window.location.host;this.result={...i,url:`https://${o}/${i.slug}`},this.destination_url="",this.slug="",this.$nextTick(()=>lucide.createIcons())}catch(e){this.error=e.message}finally{this.loading=!1}}}}
function linkForm(){return{destination_url:"",slug:"",loading:!1,error:"",result:{},copied:!1,async createLink(){this.loading=!0,this.error="",this.result={};const o=grecaptcha.getResponse();if(!o)return this.error="Please complete the CAPTCHA.",this.loading=!1,void 0;try{const e=sessionStorage.getItem("username"),s=sessionStorage.getItem("pass_hash");if(!e||!s)throw new Error("Authentication error. Please log in again.");const t=await fetch("/api/links/create",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({destination_url:this.destination_url,slug:this.slug||null,username:e,pass_hash:s,"g-recaptcha-response":o})});if(!t.ok)throw new Error(await t.text()||"Failed to create link.");const i=await t.json(),r=window.location.host;this.result={...i,url:`https://${r}/${i.slug}`},this.destination_url="",this.slug="",this.$nextTick(()=>lucide.createIcons())}catch(e){this.error=e.message}finally{this.loading=!1,grecaptcha.reset()}}}}
lucide.createIcons();
</script>
</body>