Skip to content

Instantly share code, notes, and snippets.

@lionello
Last active December 12, 2024 19:41
Stateless rate limiting using Proof-of-Work in JS/HTML
<script>
async function powFetch(url, options = {}) {
if (window.crypto && window.crypto.subtle) {
let bodyHash, nonceArray = new Uint32Array(1), nonce = 0;
const body = new TextEncoder().encode(options.body);
const bodyWithNonce = new Uint8Array(nonceArray.byteLength + body.byteLength);
bodyWithNonce.set(body, nonceArray.byteLength);
do {
nonceArray[0] = ++nonce;
bodyWithNonce.set(new Uint8Array(nonceArray.buffer));
bodyHash = await crypto.subtle.digest('SHA-256', bodyWithNonce);
} while (new DataView(bodyHash).getUint32(0) > 0x50000);
options.headers = {
...options.headers,
'X-Nonce': nonce,
}
}
return fetch(url, options);
}
async function submitForm(event) {
event.preventDefault();
const submitButton = event.target.querySelector('input[type="submit"]');
submitButton.disabled = true;
const form = event.target;
const popup = document.getElementById("popup");
const popupMessage = document.getElementById("popup-message");
try {
const response = await powFetch('https://defang-dfngw--80.prod1.defang.dev/dfn.v1.ContactFormService/SendEmail', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
date: new Date().toISOString(),
name: form.name.value,
email: form.email.value,
message: form.message.value,
honeypot: form.website.value
})
});
if (response.status !== 200) {
throw Error(response.statusText)
}
popupMessage.textContent = "Thank you for your message!";
event.target.reset();
} catch (error) {
console.error(error);
popupMessage.textContent = "Oops! Something went wrong. Please try again.";
}
popup.style.display = "block";
setTimeout(() => {
popup.style.display = "none";
submitButton.disabled = false;
}, 3000);
}
document.getElementById("email-form").addEventListener('submit', submitForm);
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment