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
98 changes: 88 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,106 @@
# BeeBuzz

Simple, private push notifications with real end-to-end encryption.
BeeBuzz delivers alerts over Web Push with a small, auditable stack. In E2E mode, the server stores ciphertext instead of plaintext.
Simple, private push notifications for servers, scripts, apps, and webhooks.

## Start Here
BeeBuzz is a focused Web Push delivery system for alerts that should reach your own
paired devices without becoming another chat surface. It supports both fast
server-trusted notifications and real end-to-end encrypted delivery, where message
content is encrypted before it reaches BeeBuzz and the server stores ciphertext
instead of plaintext.

## Why BeeBuzz

- **Private alerting**: send high-signal machine-to-person notifications to paired devices.
- **Two delivery modes**: start quickly with trusted delivery, or use E2E mode when content privacy matters.
- **Real E2E push flow**: in E2E mode, the CLI encrypts locally for paired device keys and Hive decrypts locally on the receiving device.
- **Small auditable stack**: Go, SQLite, SvelteKit, Web Push, and a Hive PWA receiver.
- **Focused scope**: BeeBuzz is not a team chat, inbox, or general messaging platform.

## Architecture

BeeBuzz is split into a few small pieces:

- **Server**: Go + SQLite API for accounts, topics, API tokens, devices, attachments, and Web Push dispatch.
- **Site**: SvelteKit web app for sign-in, device pairing, API tokens, webhook setup, and administration.
- **Hive**: PWA receiver that handles Web Push, stores pairing state locally, and decrypts E2E notifications on-device.
- **CLI**: sender for end-to-end encrypted notifications from terminals, scripts, and automation.

## Delivery Modes

### Server-trusted

Use JSON or multipart requests when the sender trusts the BeeBuzz server with the
notification payload.

```text
sender -> BeeBuzz API -> Web Push -> Hive
```

BeeBuzz authenticates the API token, reads and validates the payload, optionally
handles an attachment, then sends a Web Push notification to subscribed devices.
This is the fastest path for tests, simple integrations, and webhooks.

### End-to-end encrypted

Use the CLI or an `application/octet-stream` request when notification content
should stay opaque to BeeBuzz.

```text
CLI -> encrypt locally for paired devices -> BeeBuzz stores ciphertext -> Hive fetches and decrypts locally
```

The CLI fetches paired device public keys, encrypts the notification locally with
age/X25519, and sends only ciphertext to BeeBuzz. The server stores the opaque
blob temporarily and pushes a small envelope containing the notification ID,
attachment token, and server acceptance time. Hive receives the envelope, fetches
the blob, and decrypts the final notification locally.

## Try It

- Read the docs: <https://beebuzz.app/docs>
- Use the hosted BeeBuzz beta: <https://beebuzz.app/docs/quickstart>
- Run BeeBuzz locally for development: <https://beebuzz.app/docs/local-dev>

## Beta Focus
Install the CLI from a [GitHub release](https://github.com/lucor/beebuzz/releases) (no Go required) or with Go:

```bash
go install lucor.dev/beebuzz/cmd/beebuzz@latest
```

Send an encrypted notification after connecting the CLI:

```bash
beebuzz send "Hello from BeeBuzz"
```

## Security Model

In E2E mode:

- BeeBuzz should not recover notification plaintext from stored blobs alone.
- BeeBuzz stores paired device public recipients, not device private identities.
- A database compromise alone should not reveal stored E2E message plaintext or device private keys.

E2E protects message content, not metadata. BeeBuzz still sees operational metadata
such as users, topics, device mappings, timestamps, delivery results, and whether
E2E mode was used. It also does not protect against a compromised endpoint or an
actively malicious server serving malicious client code or replacing recipient keys.

See [docs/E2E_ENCRYPTION.md](docs/E2E_ENCRYPTION.md) and
[docs/THREAT_MODEL.md](docs/THREAT_MODEL.md) for the full model.

## Project Status

BeeBuzz is currently optimized for two workflows:

1. get approved for the beta and send your first notification in seconds
1. get approved for the hosted beta and send your first notification in seconds
2. run the stack locally with a fast development loop

Detailed production self-hosting docs will come later.

## Install The CLI

```bash
go install lucor.dev/beebuzz/cmd/beebuzz@latest
```
Hosted access is free during beta. After beta, the hosted service will move to a
single paid plan, priced to keep the project sustainable. Self-hosting remains
free, open source, and available under the AGPL license.

## License

Expand Down
41 changes: 24 additions & 17 deletions web/apps/site/src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,20 @@
ShieldCheck,
Zap
} from '@lucide/svelte';
import { BeeBuzzLogo } from '@beebuzz/shared/components';
import { BeeBuzzLogo, isLoggedIn } from '@beebuzz/shared';
import { onMount } from 'svelte';

import { isSaasMode } from '$lib/config/deployment';
import PublicFooter from '$lib/components/PublicFooter.svelte';

let loggedIn = $state(false);

onMount(() => {
loggedIn = isLoggedIn();
});

const GITHUB_REPO_URL = 'https://github.com/lucor/beebuzz';
const STATUS_URL = 'https://status.beebuzz.app';
const QUICKSTART_PATH = '/docs/quickstart';
const CONTACT_PATH = '/contact';

type UseCase = {
title: string;
Expand Down Expand Up @@ -102,17 +107,6 @@
<a href={resolve(QUICKSTART_PATH)} class="transition-colors hover:text-base-content"
>Quickstart</a
>
<a href={resolve(CONTACT_PATH)} class="transition-colors hover:text-base-content"
>Contact</a
>
<a
href={STATUS_URL}
target="_blank"
rel="noopener noreferrer"
class="transition-colors hover:text-base-content"
>
Status
</a>
{/if}
<a
href={GITHUB_REPO_URL}
Expand All @@ -122,6 +116,14 @@
>
GitHub
</a>
{#if isSaasMode}
<a
href={resolve(loggedIn ? '/account/overview' : '/login')}
class="transition-colors hover:text-base-content"
>
{loggedIn ? 'Dashboard' : 'Sign in'}
</a>
{/if}
</nav>
</div>
</header>
Expand Down Expand Up @@ -150,7 +152,7 @@
href={resolve('/login')}
class="btn btn-primary btn-lg gap-2 text-base font-semibold"
>
Get Started
Request beta access
<ArrowRight class="h-5 w-5" />
</a>
<a href={resolve(QUICKSTART_PATH)} class="btn btn-outline btn-lg">
Expand All @@ -170,8 +172,13 @@

{#if isSaasMode}
<p class="mt-4 text-sm leading-6 text-base-content/65">
The hosted service is in beta. If your email is already approved, you can sign in now.
Otherwise the same flow submits your access request.
Hosted access is free during beta. After beta, the hosted service will move to a
single paid plan, priced to keep the project sustainable. Self-hosting remains free
and open source.
</p>
<p class="mt-2 text-sm leading-6 text-base-content/65">
If your email is already approved, you can sign in now. Otherwise the same flow
submits your access request.
</p>
{/if}

Expand Down
1 change: 1 addition & 0 deletions web/apps/site/src/routes/docs/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
icon: Zap,
items: [
{ label: 'Quickstart', href: '/docs/quickstart' },
{ label: 'Webhooks', href: '/docs/webhooks' },
{ label: 'Local Dev', href: '/docs/local-dev' },
{ label: 'Browser Support', href: '/docs/browser-support' }
]
Expand Down
Loading