mirror of
https://github.com/PR0M3TH3AN/Nostr-Static-Contact-Form.git
synced 2025-09-07 06:48:42 +00:00
update
This commit is contained in:
73
README.md
Normal file
73
README.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# Nostr Static Contact Form
|
||||
|
||||
The **Nostr Static Contact Form** is an embeddable, static contact form that securely sends messages using the decentralized Nostr protocol. Each submission generates an ephemeral Nostr account, encrypts your message using NIP‑04, and publishes the event to a relay network. This form is ideal for any website that needs a simple, modern, mobile‑friendly contact solution without relying on centralized servers.
|
||||
|
||||
## What is Nostr?
|
||||
|
||||
[Nostr](https://github.com/nostr-protocol/nostr) (Notes and Other Stuff Transmitted by Relays) is an open, decentralized protocol designed to create, sign, and publish content. Nostr is censorship-resistant and relies on a network of relays rather than a single central server. It is used for messaging and data publication while focusing on privacy and resilience.
|
||||
|
||||
## Features
|
||||
|
||||
- **Embeddable & Static:** A single HTML file that can be hosted on any static site.
|
||||
- **Modern & Mobile-Friendly:** Responsive design with a clean, minimal interface.
|
||||
- **Decentralized Messaging:** Publishes encrypted messages as Nostr events to multiple relays.
|
||||
- **Ephemeral Security:** Generates a new ephemeral key pair for each submission.
|
||||
- **Admin Configurable:** The recipient NPUB is set in the code so that all messages go directly to your account.
|
||||
- **Simple Feedback:** After submission, users see only a "Success" or "Failed" message.
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **User Submission:** The user fills out the basic contact fields (Name, Email, Message) and submits the form.
|
||||
2. **Message Assembly:** The form data is compiled into a Markdown‑formatted message.
|
||||
3. **Ephemeral Key Generation:** A new ephemeral key pair is generated for that submission.
|
||||
4. **Encryption:** The message is encrypted using NIP‑04 with the admin’s NPUB.
|
||||
5. **Event Publishing:** The encrypted message is packaged as a Nostr event (kind 4) and published to a set of relays.
|
||||
6. **User Feedback:** The form displays a success or failure message depending on whether at least one relay accepted the event.
|
||||
|
||||
## How to Use
|
||||
|
||||
### 1. Configure the Recipient NPUB
|
||||
|
||||
Open the HTML file and locate the following line in the JavaScript section:
|
||||
|
||||
```js
|
||||
const recipientNpub = "npubYOURADMINNPUBHERE"; // Replace with your NPUB
|
||||
```
|
||||
|
||||
Replace `"npubYOURADMINNPUBHERE"` with your actual Nostr public key (NPUB). This key will be used to receive all messages submitted through the form.
|
||||
|
||||
### 2. Deploy the Form
|
||||
|
||||
Since the form is a single HTML file, you can host it on any static hosting provider such as GitHub Pages, Netlify, or Vercel.
|
||||
|
||||
### 3. Embedding as an iFrame
|
||||
|
||||
To use the contact form on another website, simply embed it within an `<iframe>`. For example:
|
||||
|
||||
```html
|
||||
<iframe
|
||||
src="https://yourdomain.com/path/to/nostr-static-contact-form.html"
|
||||
style="width:100%; border:none; height:500px;">
|
||||
</iframe>
|
||||
```
|
||||
|
||||
Place this code on any page where you want the form to appear. Adjust the `height` and other styles as needed to fit your design.
|
||||
|
||||
### 4. Test It Out
|
||||
|
||||
Visit your deployed page (or the page containing the iframe) and submit a message. A success or failure message will display based on the relay response.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **Nostr Tools v2.10.4:**
|
||||
The form relies on [nostr-tools](https://github.com/fiatjaf/nostr-tools) (loaded via CDN) for key generation, encryption, and event publishing.
|
||||
|
||||
## License
|
||||
|
||||
This project is open source and available under the [MIT License](LICENSE).
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Nostr Protocol Documentation](https://github.com/nostr-protocol/nostr)
|
||||
- [Nostr Tools GitHub Repository](https://github.com/fiatjaf/nostr-tools)
|
||||
```
|
163
src/nostr-static-contact-form.html
Normal file
163
src/nostr-static-contact-form.html
Normal file
@@ -0,0 +1,163 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Contact Form</title>
|
||||
<style>
|
||||
/* Basic reset and typography */
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
color: #333;
|
||||
}
|
||||
/* Centered container */
|
||||
.form-container {
|
||||
max-width: 600px;
|
||||
margin: auto;
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
h2 {
|
||||
margin-top: 0;
|
||||
font-size: 1.5em;
|
||||
text-align: center;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-top: 15px;
|
||||
font-weight: bold;
|
||||
}
|
||||
input[type="text"],
|
||||
input[type="email"],
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
margin-top: 5px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
textarea {
|
||||
resize: vertical;
|
||||
min-height: 100px;
|
||||
}
|
||||
button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
margin-top: 20px;
|
||||
background-color: #3b82f6;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 1em;
|
||||
cursor: pointer;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #2563eb;
|
||||
}
|
||||
#result {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
<!-- Load nostr‑tools v2.10.4 -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/nostr-tools@2.10.4/lib/nostr.bundle.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="form-container">
|
||||
<h2>Contact Us</h2>
|
||||
<form id="contact-form">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" id="name" placeholder="Your name" required />
|
||||
<label for="email">Email</label>
|
||||
<input type="email" id="email" placeholder="Your email" required />
|
||||
<label for="message">Message</label>
|
||||
<textarea id="message" placeholder="Your message" required></textarea>
|
||||
<button type="submit">Send Message</button>
|
||||
</form>
|
||||
<div id="result"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const form = document.getElementById("contact-form");
|
||||
const resultDiv = document.getElementById("result");
|
||||
|
||||
// Set the admin recipient NPUB here.
|
||||
const recipientNpub = "npubYOURADMINNPUBHERE"; // Replace with your NPUB
|
||||
|
||||
// Relay URLs for publishing events.
|
||||
const RELAYS = [
|
||||
"wss://relay.snort.social",
|
||||
"wss://relay.damus.io",
|
||||
"wss://relay.primal.net"
|
||||
];
|
||||
const pool = new window.NostrTools.SimplePool();
|
||||
|
||||
form.addEventListener("submit", async (ev) => {
|
||||
ev.preventDefault();
|
||||
resultDiv.textContent = "";
|
||||
// Collect form values.
|
||||
const name = document.getElementById("name").value.trim();
|
||||
const email = document.getElementById("email").value.trim();
|
||||
const message = document.getElementById("message").value.trim();
|
||||
|
||||
// Build the Markdown message.
|
||||
const content = `
|
||||
# Contact Form Submission
|
||||
|
||||
**Name:** ${name}
|
||||
**Email:** ${email}
|
||||
**Message:**
|
||||
${message}
|
||||
`.trim();
|
||||
|
||||
try {
|
||||
// Decode the recipient NPUB to get its public key.
|
||||
const decoded = window.NostrTools.nip19.decode(recipientNpub);
|
||||
if (decoded.type !== "npub") {
|
||||
throw new Error("Invalid recipient NPUB");
|
||||
}
|
||||
const targetPubHex = decoded.data;
|
||||
|
||||
// Generate an ephemeral key pair.
|
||||
const ephemeralPriv = window.NostrTools.generateSecretKey();
|
||||
const ephemeralPubHex = window.NostrTools.getPublicKey(ephemeralPriv);
|
||||
|
||||
// Encrypt the content using NIP-04.
|
||||
const ciphertext = await window.NostrTools.nip04.encrypt(ephemeralPriv, targetPubHex, content);
|
||||
|
||||
// Build the event template (kind 4 for DMs).
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const eventTemplate = {
|
||||
kind: 4,
|
||||
created_at: now,
|
||||
tags: [["p", targetPubHex]],
|
||||
content: ciphertext,
|
||||
};
|
||||
|
||||
// Finalize the event (this computes the event ID and signature).
|
||||
const event = window.NostrTools.finalizeEvent(eventTemplate, ephemeralPriv);
|
||||
|
||||
// Publish the event to the relays.
|
||||
await Promise.any(pool.publish(RELAYS, event));
|
||||
|
||||
resultDiv.textContent = "Success: Your message has been sent.";
|
||||
form.reset();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
resultDiv.textContent = "Failed: Your message could not be sent.";
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user