Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,26 @@ env:
IMAGE_NAME: ${{ github.repository }}

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7

- name: Install dependencies
run: npm ci

- name: Install Playwright browser
run: npx playwright install --with-deps chromium

- name: Run browser tests
run: npm test
env:
CI: "true"

semantic-version:
runs-on: ubuntu-latest
needs: [test]
if: github.event_name == 'push'
outputs:
new_tag: ${{ steps.tag.outputs.new_tag }}
Expand Down Expand Up @@ -204,6 +222,7 @@ jobs:

validate-docker:
runs-on: ubuntu-latest
needs: [test]
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- name: Stage site files
run: |
mkdir _site
cp index.html 404.html qr.html manifest.json CNAME _site/
cp index.html 404.html qr.html manifest.json sw.js CNAME _site/
cp favicon.ico favicon.png icon.png icon-512.png icon.svg _site/
- uses: actions/configure-pages@v6
- uses: actions/upload-pages-artifact@v5
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
test-results/
playwright-report/
10 changes: 10 additions & 0 deletions .trivyignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,13 @@
# Not exploitable in our deployment: hashpad serves static files only;
# the JOSE code path is not reached at runtime.
CVE-2026-34986

# Go stdlib 1.26.8 / golang.org/x/net 0.59.0 inside the caddy binary of caddy:2-alpine.
# The newest published caddy:2-alpine (2026-10-06) still ships them, so a base-image
# bump cannot fix this. These are denial-of-service issues (HTTP/2 SETTINGS flood,
# crafted Range headers, TLS ECH) that Caddy does expose; mitigated only by running
# behind the cluster ingress/load balancer. Remove once Caddy rebuilds with Go >= 1.26.9
# and x/net >= 0.60.0 (review by 2026-11-16).
CVE-2026-78667
CVE-2026-78669
CVE-2026-97031
6 changes: 6 additions & 0 deletions Caddyfile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@
}
header @html Cache-Control "public, max-age=3600, must-revalidate"

# Service worker must always revalidate
@sw {
path /sw.js
}
header @sw Cache-Control "no-cache"

# On-the-fly compression (zstd preferred, gzip fallback)
encode zstd gzip

Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ COPY index.html .
COPY qr.html .
COPY 404.html .
COPY manifest.json .
COPY sw.js .
COPY favicon.ico .
COPY favicon.png .
COPY icon.png .
Expand Down
48 changes: 44 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,38 @@ Your document **is** the URL. Share it anywhere, and the recipient gets your exa
- **Zero Backend** - No server storage, no database, no accounts
- **URL-Based Storage** - Content is compressed and encoded in the URL hash
- **Password Protection** - Optional AES-256-GCM encryption with PBKDF2 key derivation
- **Markdown Highlighting** - Real-time syntax highlighting for headings, code, bold, italic, links, and more
- **Markdown Highlighting** - Real-time syntax highlighting while you type (see [Supported Markdown](#supported-markdown))
- **QR Code Sharing** - Generate QR codes for easy mobile sharing
- **Dark/Light Mode** - Automatically follows system preference
- **PWA Support** - Install as a native app on any device
- **PWA & Offline** - Install as a native app on any device; a service worker caches the app so it keeps working offline (the QR page also needs a prior online visit to cache its CDN library)
- **Export Options** - Save as HTML or plain text
- **Undo/Redo** - Full editing history (Ctrl+Z / Ctrl+Shift+Z)

## Supported Markdown

| Syntax | Example |
|--------|---------|
| Headings | `# H1` to `###### H6` |
| Bold | `**bold**`, `__bold__` |
| Italic | `*italic*`, `_italic_` |
| Strikethrough | `~~strike~~` |
| Highlight | `==mark==` |
| Inline code | `` `code` `` |
| Fenced code blocks | `` ``` `` or `~~~` |
| Links | `[text](https://url "title")`, `[text][ref]`, `<https://url>`, bare `https://url` |
| Images | `![alt](url)` |
| Lists | `-`, `*`, `+`, `1.` |
| Task lists | `- [ ]`, `- [x]` |
| Blockquotes with nesting | `> quote`, `> > nested` |
| Horizontal rules | `---`, `***`, `___` |
| Tables | `\| a \| b \|` |
| Footnote references | `[^1]` |
| Backslash escapes | `\*` |

- Syntax is highlighted in place; the text stays plain Markdown and is never rendered to HTML in the editor.
- Images are highlighted only, not loaded, so no third-party requests are made when opening a shared link.
- Only `http(s)` and `mailto:` links are clickable.

## URL Format

| Format | Description |
Expand Down Expand Up @@ -60,10 +85,22 @@ docker run -p 8080:8080 hashpad
### Kubernetes (Helm)

```bash
# Adapt values.yaml for your environment, then:
helm install hashpad ./helm
# Adapt deploy/helm/hashpad/values.yaml for your environment, then:
helm install hashpad ./deploy/helm/hashpad
```

## Testing

Browser tests use Playwright (Chromium) and run against `tests/sample.md`, which exercises every supported Markdown construct.

```bash
npm install
npx playwright install chromium
npm test
```

When adding new Markdown syntax, add it to `tests/sample.md` and add a matching assertion in `tests/markdown.spec.js`.

## Security

### Encryption Details
Expand All @@ -82,11 +119,14 @@ hashpad/
├── qr.html # QR code generator
├── 404.html # Error page
├── manifest.json # PWA manifest
├── sw.js # Service worker (offline cache)
├── favicon.png # App icon
├── icon.svg # Vector icon
├── Dockerfile # Container build (Caddy Alpine)
├── Caddyfile # Web server configuration
├── docker-compose.yml # Container orchestration
├── tests/ # Playwright browser tests and Markdown sample
├── package.json # Test tooling
└── deploy/helm/hashpad # Kubernetes Helm chart
├── Chart.yaml
├── values.yaml
Expand Down
Loading
Loading