Documentation
¶
Overview ¶
Package push delivers Web Push notifications to subscribed browsers, implementing VAPID (RFC 8292) authorization and the aes128gcm content encoding (RFC 8291 + RFC 8188) on top of the Go standard library — keeping harness-deck dependency-free.
Two long-lived state objects live in the config directory next to config.json:
- vapid.json the ECDSA P-256 application-server identity keypair, generated once via `harness-deck vapid`.
- subscriptions.json the list of phones / browsers that asked to be notified.
For every notification we generate a fresh ephemeral ECDH P-256 keypair, derive a content-encryption key + nonce per RFC 8291, encrypt the JSON payload, and POST it to the subscription endpoint with a VAPID-signed JWT in the Authorization header.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Keys ¶
type Keys struct {
// contains filtered or unexported fields
}
Keys holds the application-server VAPID identity — a P-256 ECDSA keypair kept stable across restarts so existing subscriptions remain valid.
func LoadOrMissing ¶
LoadOrMissing returns the keys if present, or nil, false (no error) when the file simply doesn't exist — push features stay dormant until the user runs `harness-deck vapid`.
func (*Keys) PrivateB64URL ¶
PrivateB64URL returns the 32-byte private scalar as base64url.
func (*Keys) PublicB64URL ¶
PublicB64URL returns the uncompressed P-256 public key as base64url (no padding) — the form expected by the browser's applicationServerKey and by the VAPID Authorization header's `k=` parameter.
type Payload ¶
type Payload struct {
Title string `json:"title"`
Body string `json:"body"`
Tag string `json:"tag,omitempty"`
URL string `json:"url,omitempty"`
Project string `json:"project,omitempty"`
Run string `json:"run,omitempty"`
}
Payload is the JSON object delivered to the service worker as the notification body. We keep it small and explicit; the service worker renders it as a system notification.
type Sender ¶
type Sender struct {
// contains filtered or unexported fields
}
Sender pushes payloads to subscriptions using a single long-lived VAPID identity. It is safe for concurrent use.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store persists the set of push Subscriptions we deliver notifications to. It is safe for concurrent use. One Subscription per push endpoint URL — the same browser/device resubscribing replaces its prior record.
func NewStore ¶
NewStore opens the JSON-backed subscription store at path. A missing file is fine: it materializes on first Save.
func (*Store) Add ¶
func (s *Store) Add(sub Subscription) error
Add inserts sub, replacing any existing entry with the same endpoint.
func (*Store) All ¶
func (s *Store) All() []Subscription
All returns every stored subscription (snapshot copy).
func (*Store) Remove ¶
Remove deletes the subscription with the given endpoint. A missing endpoint is a no-op so unsubscribe is idempotent.
func (*Store) RemoveIfMatches ¶ added in v0.2.7
func (s *Store) RemoveIfMatches(endpoint string, keys SubscriptionKeys) error
RemoveIfMatches deletes the subscription only when both the endpoint and the keys match. Pruning a 410-Gone subscription this way avoids deleting a fresh re-subscription that reused the same endpoint URL with new keys. A non-matching endpoint or keys is a no-op.
type Subscription ¶
type Subscription struct {
Endpoint string `json:"endpoint"`
Keys SubscriptionKeys `json:"keys"`
}
Subscription is the shape the browser's PushSubscription.toJSON() produces — what we receive from /api/push/subscribe and store verbatim.
type SubscriptionKeys ¶
SubscriptionKeys carries the UA's P-256 ECDH public key (uncompressed, base64url) and a 16-byte shared auth secret (base64url).