Documentation
¶
Overview ¶
Package notifiers runs the notify-only channels (email, ntfy, webhooks, Web Push): it owns their instance settings and hands the channels to the action layer.
Settings come from the environment (EXHALE_SMTP_*, EXHALE_NTFY_*, EXHALE_ALLOW_PRIVATE_DESTINATIONS) or, more usually, from the web, where they are saved in the settings table like the Telegram token. The environment wins. Every message reads the current settings, so a change applies at once, without a restart. Secrets go in and never come back out: Status only says whether one is saved.
Index ¶
- Constants
- Variables
- type ChannelsStatus
- type Manager
- func (m *Manager) AddDevice(ctx context.Context, memberID string, in PushDevice) (string, error)
- func (m *Manager) Channels() []actions.Channel
- func (m *Manager) Describe(ctx context.Context, channel, destination string) (text string, hasTemplate bool)
- func (m *Manager) Forget(ctx context.Context, channel, destination string) error
- func (m *Manager) Notifies(channel string) bool
- func (m *Manager) PushAction(ctx context.Context, token string) (actions.PushResult, error)
- func (m *Manager) PushStatus(ctx context.Context) (PushStatus, error)
- func (m *Manager) RemoveDevice(ctx context.Context, memberID, endpoint string) error
- func (m *Manager) RemoveNtfy(ctx context.Context) error
- func (m *Manager) RemoveSMTP(ctx context.Context) error
- func (m *Manager) SetAllowPrivate(ctx context.Context, allow bool) error
- func (m *Manager) SetNtfy(ctx context.Context, in NtfyInput) error
- func (m *Manager) SetPushActions(a PushActions)
- func (m *Manager) SetSMTP(ctx context.Context, in SMTPInput) error
- func (m *Manager) SetTemplate(ctx context.Context, url, template string) error
- func (m *Manager) Status(ctx context.Context, owner bool) ChannelsStatus
- func (m *Manager) Test(ctx context.Context, channel, destination string) error
- func (m *Manager) Validate(ctx context.Context, channel, destination, template string) (string, error)
- type NtfyInput
- type NtfyStatus
- type Options
- type PushActions
- type PushDevice
- type PushStatus
- type SMTPInput
- type SMTPStatus
Constants ¶
const ( SourceEnv = "env" SourceSettings = "settings" )
Sources of a setting.
const MaxDevices = 10
MaxDevices is how many browsers one member can turn push on in.
Variables ¶
var ErrActionExpired = webpush.ErrBadToken
ErrActionExpired is returned for a notification button whose token is not valid any more; the web opens the charge instead.
Functions ¶
This section is empty.
Types ¶
type ChannelsStatus ¶
type ChannelsStatus struct {
PublicURL string `json:"publicUrl,omitempty" doc:"address used for links in messages; empty when the server was started without --public-url"`
AllowPrivate bool `json:"allowPrivate" doc:"webhooks and ntfy may reach private-network addresses"`
AllowPrivateSource string `json:"allowPrivateSource,omitempty" enum:"env,settings"`
SMTP SMTPStatus `json:"smtp"`
Ntfy NtfyStatus `json:"ntfy"`
}
ChannelsStatus is what the web shows about the notify-only channels.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager configures the channels and sends through them.
func (*Manager) AddDevice ¶
AddDevice saves a browser's subscription for a member and returns its link id. The same browser signed in as someone else moves to them.
func (*Manager) Channels ¶
Channels returns the email, ntfy, webhook and Web Push channels for the action layer.
func (*Manager) Describe ¶
func (m *Manager) Describe(ctx context.Context, channel, destination string) (text string, hasTemplate bool)
Describe returns how a destination is shown to its member: the address, the topic, or only the host of a webhook (the rest of its URL is a secret), and whether it has a body template.
func (*Manager) PushAction ¶
PushAction runs the button of a notification from its token. The device it was sent to must still be the member's.
func (*Manager) PushStatus ¶
func (m *Manager) PushStatus(ctx context.Context) (PushStatus, error)
PushStatus returns the public key, making the keys if needed.
func (*Manager) RemoveDevice ¶
RemoveDevice forgets a browser by its endpoint, if it is the member's (turning push off in that browser).
func (*Manager) RemoveNtfy ¶
RemoveNtfy goes back to the default public server without a token.
func (*Manager) RemoveSMTP ¶
RemoveSMTP forgets the email settings saved from the web.
func (*Manager) SetAllowPrivate ¶
SetAllowPrivate lets webhooks and ntfy reach private-network addresses (a server on the LAN), or stops them. Loopback, link-local and cloud metadata addresses stay out of reach either way.
func (*Manager) SetNtfy ¶
SetNtfy saves the ntfy server after checking its address against the network rules.
func (*Manager) SetPushActions ¶
func (m *Manager) SetPushActions(a PushActions)
SetPushActions wires the action layer, which is built after the manager.
func (*Manager) SetSMTP ¶
SetSMTP checks the settings by connecting and signing in, then saves them.
func (*Manager) SetTemplate ¶
SetTemplate saves the body template of a webhook ("" for the default body). Call it once the destination is linked to the member.
func (*Manager) Status ¶
func (m *Manager) Status(ctx context.Context, owner bool) ChannelsStatus
Status reports the setup. Members who are not owners see whether email works and which ntfy server to use, not how the mail server is reached.
type NtfyInput ¶
type NtfyInput struct {
Server string `json:"server,omitempty" doc:"base address of the ntfy server; default https://ntfy.sh"`
Token string `json:"token,omitempty" doc:"access token (tk_…), for servers that need one to publish; leave empty to keep the saved one"`
RemoveToken bool `json:"removeToken,omitempty" doc:"forget the saved access token"`
}
NtfyInput is the ntfy form. An empty token keeps the saved one unless RemoveToken is set or the server changes.
type NtfyStatus ¶
type NtfyStatus struct {
Source string `json:"source,omitempty" enum:"env,settings" doc:"empty: the default public server"`
Server string `json:"server" doc:"where members subscribe to their topic"`
HasToken bool `json:"hasToken" doc:"an access token is saved; it is never returned"`
}
NtfyStatus describes the ntfy setup without its access token.
type Options ¶
type Options struct {
// PublicURL is the address people open Exhale at (--public-url). Links
// in messages need it; without it they are left out.
PublicURL string
// SMTP comes from EXHALE_SMTP_*; it applies when Host is set.
SMTP email.Config
// NtfyServer and NtfyToken come from EXHALE_NTFY_URL and _TOKEN.
NtfyServer, NtfyToken string
// AllowPrivate comes from EXHALE_ALLOW_PRIVATE_DESTINATIONS; nil when
// it is not set.
AllowPrivate *bool
// Version goes in the User-Agent of webhooks.
Version string
// Guard replaces the network rules' resolver and dialer (tests).
Guard *netguard.Guard
// SMTPRoots replaces the system certificates for SMTP (tests).
SMTPRoots *x509.CertPool
// PushRoots replaces the system certificates for push services (tests).
PushRoots *x509.CertPool
}
Options is what the server was started with.
type PushActions ¶
type PushActions interface {
HandlePush(ctx context.Context, memberID, device, verb, chargeID string) (actions.PushResult, error)
}
PushActions runs a notification button (the action layer implements it).
type PushDevice ¶
type PushDevice struct {
Endpoint string `json:"endpoint" doc:"the push service address from PushSubscription.endpoint"`
P256dh string `json:"p256dh" doc:"keys.p256dh, base64url"`
Auth string `json:"auth" doc:"keys.auth, base64url"`
Device string `json:"device,omitempty" doc:"how to show it, e.g. Chrome on Android"`
}
PushDevice is a browser's PushSubscription (its toJSON()) and a name to show for it.
type PushStatus ¶
type PushStatus struct {
PublicKey string `json:"publicKey" doc:"VAPID public key, base64url: the applicationServerKey to subscribe with"`
}
PushStatus is what the web needs to turn push on.
type SMTPInput ¶
type SMTPInput struct {
Host string `json:"host" doc:"SMTP server, e.g. smtp.example.com"`
Port int `json:"port,omitempty" doc:"default: 587 with starttls, 465 with tls, 25 with none"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty" doc:"leave empty to keep the saved password"`
From string `json:"from" doc:"sender address, e.g. reminders@example.com"`
TLS string `json:"tls,omitempty" enum:"starttls,tls,none" doc:"starttls (default), tls (implicit, port 465) or none (local relays)"`
}
SMTPInput is the email form. An empty password keeps the saved one.
type SMTPStatus ¶
type SMTPStatus struct {
Configured bool `json:"configured"`
Source string `json:"source,omitempty" enum:"env,settings" doc:"env: set by EXHALE_SMTP_* on the server and not editable in the web"`
Host string `json:"host,omitempty"`
Port int `json:"port,omitempty"`
Username string `json:"username,omitempty"`
From string `json:"from,omitempty"`
TLS string `json:"tls,omitempty" enum:"starttls,tls,none"`
HasPassword bool `json:"hasPassword" doc:"a password is saved; it is never returned"`
}
SMTPStatus describes the email setup without its password.