replace zammad contact form with custom form via support-server

Use mCaptcha (self-hosted PoW captcha) + rate limiting for spam protection.
Form submissions send email confirmation to customer and CC support@start9.com.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Matt Hill
2026-02-19 09:03:19 -07:00
parent 874e31531b
commit 5face160ee
3 changed files with 95 additions and 41 deletions

View File

@@ -1,54 +1,62 @@
module.exports = {
url: 'https://start9.com',
torUrl: 'http://privacy34kn4ez3y3nijweec6w4g54i3g54sdv7r5mr6soma3w4begyd.onion',
url: "https://start9.com",
torUrl:
"http://privacy34kn4ez3y3nijweec6w4g54i3g54sdv7r5mr6soma3w4begyd.onion",
pitch: {
url: '#infographics'
url: "#infographics",
},
banner: false,
products: {
buyUrl: 'https://store.start9.com',
diyUrl: 'https://docs.start9.com/0.3.5.x/diy',
servers: 'https://store.start9.com/collections/servers',
gear: 'https://store.start9.com/collections/apparel'
buyUrl: "https://store.start9.com",
diyUrl: "https://docs.start9.com/0.3.5.x/diy",
servers: "https://store.start9.com/collections/servers",
gear: "https://store.start9.com/collections/apparel",
},
bitcoin: {
whyRunBitcoinUrl: 'https://bitcoinmagazine.com/culture/six-reasons-you-should-run-bitcoin-node',
whyRunLightningUrl: '',
whyRunBitcoinUrl:
"https://bitcoinmagazine.com/culture/six-reasons-you-should-run-bitcoin-node",
whyRunLightningUrl: "",
},
beYourOwn: {
url: 'https://marketplace.start9.com'
url: "https://marketplace.start9.com",
},
poweredBy: {
url: 'https://github.com/Start9Labs/start-os'
url: "https://github.com/Start9Labs/start-os",
},
support: {
url: 'https://docs.start9.com/0.3.5.x/support'
url: "https://docs.start9.com/0.3.5.x/support",
},
docs: {
url: 'https://docs.start9.com'
url: "https://docs.start9.com",
},
dev: {
docs: 'https://docs.start9.com/0.3.5.x/developer-docs',
github: 'https://github.com/Start9Labs',
marketplace: 'https://marketplace.start9.com'
docs: "https://docs.start9.com/0.3.5.x/developer-docs",
github: "https://github.com/Start9Labs",
marketplace: "https://marketplace.start9.com",
},
contribute: {
url: 'https://start9.com/latest/contribute',
techDetails: 'https://blog.start9.com/community-tech-program/'
url: "https://start9.com/latest/contribute",
techDetails: "https://blog.start9.com/community-tech-program/",
},
footer: {
copyright: '© ' + new Date().getFullYear() + ' by Start9 Labs, Inc',
canary: 'We have never received a secret government request to hand over user information.',
donate: 'https://donate.start9.com'
copyright: "© " + new Date().getFullYear() + " by Start9 Labs, Inc",
canary:
"We have never received a secret government request to hand over user information.",
donate: "https://donate.start9.com",
},
mcaptcha: {
// Widget URL from mCaptcha dashboard (Dashboard > Sitekeys > Widget Link)
widgetUrl:
"https://mcaptcha.start9.me/widget/?sitekey=VXoIaUB6OaX7JtkF4RlGt05CXyH7k1k4",
},
media: {
// NOTE: the keys here correspond to the name of the svg logo
matrix: 'https://matrix.to/#/#developer-space:matrix.start9labs.com',
support: 'https://start9.me',
twitter: 'https://x.com/start9labs',
youtube: 'https://www.youtube.com/channel/UCGEw4HJDvOn3Oy8ykR36P7Q',
discourse: 'https://community.start9.com',
medium: 'https://start9labs.medium.com',
ghost: 'https://blog.start9.com',
matrix: "https://matrix.to/#/#developer-space:matrix.start9labs.com",
support: "https://start9.me",
twitter: "https://x.com/start9labs",
youtube: "https://www.youtube.com/channel/UCGEw4HJDvOn3Oy8ykR36P7Q",
discourse: "https://community.start9.com",
medium: "https://start9labs.medium.com",
ghost: "https://blog.start9.com",
},
};

View File

@@ -436,7 +436,7 @@ section#contact {
margin-bottom: 24px;
}
.zammad-form {
.contact-form {
font-size: 18px;
input {

View File

@@ -35,19 +35,65 @@ layout: layouts/peripheral.njk
<li>
<h3>Message Us</h3>
<p>Response times are usually between 24-48 hours. For faster support, use one of the options above</p>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<div id="feedback-form">form will be placed in here</div>
<script id="zammad_form_script" src="https://zammad.start9labs.com/assets/form/form.js"></script>
<div class="contact-form">
<form id="contact-form">
<label for="contact-name">Name</label>
<input id="contact-name" class="form-control" type="text" placeholder="Your name" required />
<label for="contact-email">Email</label>
<input id="contact-email" class="form-control" type="email" placeholder="Your email" required />
<label for="contact-message">Message</label>
<textarea id="contact-message" class="form-control" rows="5" placeholder="How can we help?" required></textarea>
<label data-mcaptcha_url="{{ site.mcaptcha.widgetUrl }}" for="mcaptcha__token" id="mcaptcha__token-label"></label>
<div id="mcaptcha__widget-container"></div>
<input type="hidden" name="mcaptcha__token" id="mcaptcha__token" />
<button type="submit">Submit</button>
</form>
<script src="https://unpkg.com/@mcaptcha/vanilla-glue@0.1.0-rc2/dist/index.js"></script>
<div id="contact-success" class="form-alert form-alert--success"></div>
<div id="contact-error" class="form-alert form-alert--error"></div>
</div>
<script>
$(function() {
$('#feedback-form').ZammadForm({
messageTitle: 'Start9 Contact Form',
messageSubmit: 'Submit',
messageThankYou: 'Inquiry received! We will get back to you ASAP.',
attachmentSupport: true
});
document.getElementById('contact-form').addEventListener('submit', async function(e) {
e.preventDefault();
const form = e.target;
const success = document.getElementById('contact-success');
const error = document.getElementById('contact-error');
success.classList.remove('form-alert--visible');
error.classList.remove('form-alert--visible');
const captchaToken = document.getElementById('mcaptcha__token').value;
if (!captchaToken) {
error.textContent = 'Please complete the captcha.';
error.classList.add('form-alert--visible');
return;
}
const body = {
name: document.getElementById('contact-name').value,
email: document.getElementById('contact-email').value,
message: document.getElementById('contact-message').value,
mcaptcha__token: captchaToken,
};
try {
const res = await fetch('https://start9.me/_api/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
if (res.ok) {
form.reset();
success.textContent = 'Inquiry received! We will get back to you within 24 hours.';
success.classList.add('form-alert--visible');
} else {
throw new Error();
}
} catch {
error.innerHTML = "Something went wrong. If this persists, try us on <a href='https://matrix.to/#/#general:start9.me' rel='noopener noreferrer' target='_blank'>Matrix</a> instead.";
error.classList.add('form-alert--visible');
}
});
</script>
</li>