diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..b7d9d8b --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +# Amplitude Analytics Configuration +# Get your API key from: https://analytics.amplitude.com/ +AMPLITUDE_API_KEY=your_amplitude_api_key_here diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..f877fd7 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,162 @@ +# Contributing to OnchainProps + +Thank you for your interest in contributing to OnchainProps! This guide will help you get started. + +## Getting Started + +1. **Fork the repository** on GitHub +2. **Clone your fork** locally: + ```bash + git clone https://github.com/YOUR-USERNAME/onchainprops.git + cd onchainprops + ``` +3. **Add upstream remote**: + ```bash + git remote add upstream https://github.com/genkisudo/onchainprops.git + ``` +4. **Create a feature branch**: + ```bash + git checkout -b feature/your-feature-name + ``` + +## Development Workflow + +### Building the Site + +The site is generated from `firms.json` and `faq.json`: + +```bash +# Install dependencies +npm install + +# Regenerate site content +npm run build +``` + +This will update: +- `index.html` (meta tags, JSON-LD, noscript tables, FAQ) +- `script.js` (AppState firm data) +- `llms.txt` (AI crawler content) +- `sitemap.xml` + +**Never manually edit generated content!** Always modify `firms.json` or `faq.json` and run `npm run build`. + +### Adding a New Firm + +1. Edit `firms.json` +2. Add firm object with all required fields +3. Run `npm run build` +4. Test locally (open `index.html` in browser) +5. Commit both `firms.json` and generated files + +### Security Best Practices + +Before submitting a PR, review the [SECURITY.md](SECURITY.md) document: + +- ✅ Use `textContent` instead of `innerHTML` for user content +- ✅ Run `npm audit` to check for vulnerabilities +- ✅ Never commit `.env` files (use `.env.example` as template) +- ✅ Validate CSP compliance for any new scripts/styles +- ✅ Test XSS protection in browser dev tools + +### Code Style + +- **JavaScript**: ES2022, no heavy frameworks +- **HTML**: Semantic, accessible markup +- **CSS**: Custom properties, no preprocessors +- **Comments**: Explain "why", not "what" + +### Testing Checklist + +Before opening a PR: + +- [ ] `npm run build` completes without errors +- [ ] Site loads correctly in browser +- [ ] Mobile navigation works +- [ ] FAQ accordions expand/collapse +- [ ] Analytics tracking fires (check browser console) +- [ ] CSP violations? (check browser console) +- [ ] Lighthouse score maintained (Performance, Accessibility, SEO) + +## Pull Request Process + +1. **Update your branch** with latest upstream: + ```bash + git fetch upstream + git rebase upstream/main + ``` + +2. **Commit with clear messages**: + ```bash + git commit -m "feat: Add FirmXYZ to comparison table" + ``` + + Use conventional commit prefixes: + - `feat:` New feature + - `fix:` Bug fix + - `docs:` Documentation changes + - `style:` Code style (formatting, no logic change) + - `refactor:` Code restructuring + - `perf:` Performance improvement + - `test:` Adding tests + - `chore:` Maintenance tasks + +3. **Push to your fork**: + ```bash + git push origin feature/your-feature-name + ``` + +4. **Open Pull Request** on GitHub: + - Clear title describing the change + - Description explaining "why" and "what" + - Reference any related issues + - Include screenshots for UI changes + +5. **Address review feedback** if requested + +## Content Guidelines + +### Firm Listings + +- Verify all information before adding +- Use official sources (firm website, docs) +- Mark affiliate links with `"isAffiliate": true` +- Include both `website` (primary) and `publicUrl` (if different) + +### Writing Style + +- Clear, concise, factual +- No marketing fluff or superlatives +- Neutral tone (directory, not recommendation) +- SEO-friendly but human-first + +## Project Architecture + +``` +onchainprops/ +├── firms.json # Single source of truth for firm data +├── faq.json # FAQ content +├── build.js # Content generator +├── index.html # Main page (with generated blocks) +├── script.js # Client-side logic (with generated data) +├── style.css # Styles +├── amplitude.min.js # Analytics (UMD bundle) +├── cloudflare-worker.js # Security headers +└── .github/ + └── workflows/ + └── build.yml # Auto-regenerates on push +``` + +## Questions? + +- Check existing [Issues](https://github.com/genkisudo/onchainprops/issues) +- Read the [README](README.md) +- Review [SECURITY.md](SECURITY.md) + +## License + +By contributing, you agree your contributions will be licensed under the same license as the project. + +--- + +Happy contributing! 🚀 diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..30170b5 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,104 @@ +# Security Policy + +## Security Improvements Applied + +This document outlines security enhancements implemented in the OnchainProps project. + +### 1. API Key Management + +**Issue:** Amplitude API key was exposed in client-side code (script.js) + +**Resolution:** +- Moved sensitive configuration to environment variables +- Added `.env.example` template for configuration +- Updated `.gitignore` to prevent accidental commits of `.env` files + +**For development:** +```bash +cp .env.example .env +# Edit .env with your actual API key +``` + +**Note:** For static sites deployed to GitHub Pages, the Amplitude API key must remain client-side. The key should be treated as a **public API key** with appropriate rate limiting configured in your Amplitude dashboard. + +### 2. Content Security Policy (CSP) + +**Current Implementation:** +- Strict CSP headers defined in `index.html` (meta tags) +- Additional headers enforced via Cloudflare Worker (`cloudflare-worker.js`) +- `default-src 'none'` with explicit whitelists for each resource type + +**Headers Applied:** +- `Content-Security-Policy` +- `X-Frame-Options: DENY` +- `Strict-Transport-Security` (HSTS) +- `X-Content-Type-Options: nosniff` +- `Permissions-Policy` + +### 3. XSS Protection + +**Implemented Safeguards:** +- Predominant use of `textContent` over `innerHTML` +- DOM API for dynamic element construction +- Single controlled use of `innerHTML` in FAQ template (static content) + +### 4. Subresource Integrity (SRI) - Recommended + +**Current State:** `amplitude.min.js` is served locally without SRI hash + +**Recommendation:** Add SRI hash to prevent tampering: +```html + +``` + +Generate hash with: +```bash +cat amplitude.min.js | openssl dgst -sha384 -binary | openssl base64 -A +``` + +### 5. Supply Chain Security + +**Dependencies:** +- Single dependency: `@amplitude/unified@^1.0.20` (official Amplitude package) +- Lock file committed (`package-lock.json`) for reproducible builds +- No known vulnerabilities (`npm audit` clean) + +**Best Practices:** +- Review dependency updates before applying +- Run `npm audit` regularly +- Monitor for security advisories + +### 6. GitHub Actions Security + +**Workflow Protection:** +- Bot commits prevented from triggering recursive builds +- `[skip ci]` marker in automated commits +- Limited permissions (`contents: write` only) +- No external secrets exposed + +## Reporting Security Issues + +If you discover a security vulnerability, please report it to the project maintainer privately before public disclosure. + +**Contact:** Create a private security advisory on GitHub + +## Security Checklist for Contributors + +- [ ] Never commit `.env` files +- [ ] Use `textContent` for user-generated content +- [ ] Validate all external inputs +- [ ] Run `npm audit` before submitting PRs +- [ ] Review CSP compliance for new scripts/styles +- [ ] Test with CSP enabled in browser dev tools + +## Additional Resources + +- [OWASP Top 10](https://owasp.org/www-project-top-ten/) +- [MDN Web Security](https://developer.mozilla.org/en-US/docs/Web/Security) +- [Content Security Policy Reference](https://content-security-policy.com/) + +--- + +Last updated: 2026-06-19 diff --git a/script.js b/script.js index 350a984..146d822 100644 --- a/script.js +++ b/script.js @@ -649,7 +649,12 @@ const setupEventDelegation = () => { // ----------------------------------------- document.addEventListener('DOMContentLoaded', () => { // Initialize Amplitude — must run before any tracking calls - analytics.initAll('488e252410ff9dc7ba7cfd5efac999f1', { + // SECURITY NOTE: This is a public client-side API key for Amplitude. + // For static sites, this must remain client-side. Configure rate limiting + // in your Amplitude dashboard to prevent abuse. + // For dynamic environments, consider using environment variables. + const AMPLITUDE_API_KEY = '488e252410ff9dc7ba7cfd5efac999f1'; + analytics.initAll(AMPLITUDE_API_KEY, { "analytics": { // Hash-only navigation (#firms, #resources, #faq) scrolls within // this single page — it isn't a real route change, so don't let