Documentation ¶
Overview ¶
Package saltyim is a secure, easy, self-hosted messaging
salty.im is an open specification for a new Saltpack based e2e encrypted messaging protocol and platform for secure communications with a focus on privacy, security and being self-hosted.
For more information please refer to https://salty.im/
Index ¶
- Constants
- Variables
- func DefaultIdentity() string
- func DefaultState() string
- func FixUnixHome(p string) string
- func FormatMessage(msg string) string
- func FullVersion() string
- func GenerateULID() (string, error)
- func MustGenerateULID() string
- func NewRawRequest(r io.Reader) (out []byte, signer string, err error)
- func PackMessage(me Addr, msg string) []byte
- func PackMessageTime(me Addr, msg string, t *lextwt.DateTime) []byte
- func Request(method, uri string, headers http.Header, body io.Reader) (*http.Response, error)
- func Send(endpoint, msg string, cap Capabilities) error
- func SignedRequest(key *keys.EdX25519Key, method, uri string, headers http.Header, body io.Reader) (*http.Response, error)
- func SplitInbox(endpoint string) (string, string)
- type Addr
- type AvatarRequest
- type Blob
- type BlobOption
- type BlobOptions
- type BlobRequest
- type BlobService
- type Capabilities
- type Client
- func (cli *Client) Blobs() BlobService
- func (cli *Client) Env(extraenvs string) []string
- func (cli *Client) Key() *keys.EdX25519PublicKey
- func (cli *Client) Lookup(user string) (Addr, error)
- func (cli *Client) Me() Addr
- func (cli *Client) Outbox() *url.URL
- func (cli *Client) OutboxAddr(_ Addr) Addr
- func (cli *Client) OutboxClient(to Addr) *Client
- func (cli *Client) Read(options ...ReadOption) (Message, error)
- func (cli *Client) Register(brokerURI string) error
- func (cli *Client) Request(method, endpoint string, body []byte) ([]byte, error)
- func (cli *Client) Send(user, msg string) error
- func (cli *Client) SendToAddr(addr Addr, msg string) error
- func (cli *Client) SetAvatar(content []byte) error
- func (cli *Client) SetLookup(lookup Lookuper)
- func (cli *Client) SetSend(send Sender)
- func (cli *Client) State() *State
- func (cli *Client) String() string
- func (cli *Client) Subscribe(ctx context.Context, options ...ReadOption) chan Message
- type ClientOption
- func WithAddr(me Addr) ClientOption
- func WithClientIdentity(options ...IdentityOption) ClientOption
- func WithIdentity(id *Identity) ClientOption
- func WithState(state *State) ClientOption
- func WithStateFromBytes(data []byte) ClientOption
- func WithStateFromFile(fn string) ClientOption
- func WithUser(user string) ClientOption
- type Config
- type DNSOverHTTPResolver
- type DirectLookup
- type DirectSend
- type Identity
- type IdentityOption
- type Lookuper
- type Message
- type MessageEventHandlerFunc
- type MessageTextHandlerFunc
- type ProxyLookup
- type ProxySend
- type ReadOption
- type ReadOptions
- type RegisterRequest
- type Resolver
- type SendRequest
- type Sender
- type Service
- func (svc *Service) EventFunc(name string, fn MessageEventHandlerFunc)
- func (svc *Service) Respond(user, msg string) error
- func (svc *Service) Run(ctx context.Context) error
- func (svc *Service) SetClient(cli *Client)
- func (svc *Service) String() string
- func (svc *Service) TextFunc(name string, fn MessageTextHandlerFunc)
- type StandardResolver
- type State
Constants ¶
const (
// DateTimeFormat is the default date and time format used for displaying messages
DateTimeFormat = "2006-01-02 15:04:05"
)
const (
// DefaultEnvPath is the default PATH for pre and post hooks that are shelled out to
DefaultEnvPath = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
)
Variables ¶
var ( // ErrNoMessages is an error returned when there are no further messages found for an inbox from the broker ErrNoMessages = errors.New("error: no messages found") // ErrNoSender is an error returned when the client is not properly configured with a valid sender ErrNoSender = errors.New("error: no sender configured") // ErrMissingIdentity is an error returned when the client is not properly configured with a valid identity ErrMissingIdentity = errors.New("error: missing identity") )
var ( // Version is the tagged release version in the form <major>.<minor>.<patch> // following semantic versioning and is overwritten by the build system. Version = defaultVersion // Commit is the commit sha of the build (normally from Git) and is overwritten // by the build system. Commit = defaultCommit // Build is the date and time of the build as an RFC3339 formatted string // and is overwritten by the build system. Build = defaultBuild )
Functions ¶
func DefaultIdentity ¶
func DefaultIdentity() string
DefaultIdentity returns a default identity file (if one exists) otherwise returns an empty string
func FixUnixHome ¶
FixUnixHome handles paths with a UNIX Home (i.e: ~)
func FormatMessage ¶
FormatMessage formats the msg for display on the terminal
func GenerateULID ¶
GenerateULID generates a new unique identifer
func MustGenerateULID ¶
func MustGenerateULID() string
MustGenerateULID generates a new unique identifer or fails
func NewRawRequest ¶
NewRawRequest reads the signed request body from a client, verifies its signature and returns the resulting `[]byte` slice and key used to sign the request on success otherwise an empty object and an error on failure.
func PackMessage ¶
PackMessage formats an outgoing message in the Message Format <timestamp>\t(<sender>) <message>
func PackMessageTime ¶
PackMessageTime formats an incoming message in the Message Format using the existing timestamp <timestamp>\t(<sender>) <message>
func Request ¶
Request is a generic request handling function for making artbitrary HTTP requests to Salty endpoints for looking up Salty Addresses, Configs and publishing encrypted messages.
func Send ¶
func Send(endpoint, msg string, cap Capabilities) error
Send sends the encrypted message `msg` to the Endpoint `endpoint` using a `POST` request and returns nil on success or an error on failure.
func SignedRequest ¶
func SignedRequest(key *keys.EdX25519Key, method, uri string, headers http.Header, body io.Reader) (*http.Response, error)
SignedRequest is a generic request handling function for making artbitrary HTPT requests to a Salty broker's API endpoints that require authorization.
func SplitInbox ¶
SplitInbox splits and endpoint into it's components (inbox, uri) where inbox is a topic queue on the Salty broker uri
Types ¶
type Addr ¶
type Addr interface { fmt.Stringer json.Marshaler // IsZero returns true if the address is empty IsZero() bool // User returns the user part of the address user@domain User() string // Domain returns the domain part of the address user@domain Domain() string // Hash returns the Hex(SHA256Sum()) of the Address Hash() string // Formatted returns a formatted user used in the Salty Message Format // <timestamp>\t(<user>) <message>\n Formatted() string // Key returns the Public Key of this User (Salty Addr) as discovered Key() *keys.EdX25519PublicKey // Endpoint returns the discovered Endpoint Endpoint() *url.URL // Cap returns the discovered Capabilities Cap() Capabilities // DiscoveredDomain returns the discovered domain (if any) of fallbacks to the Domain DiscoveredDomain() string // URI returns the Well-Known URI for this Addr URI() string // HashURI returns the Well-Known HashURI for this Addr HashURI() string // Refresh forces a lookup and configuration fetch for a Salty Address Refresh() error // Avatar returns the cached avatar service for a Salty Address or performs a DNS lookup // for the avatar service to use and cached it (if found) and returns that. If there is no // avatar service found, then a default avatar is used for peers. Avatar() string // WithEndpoint returns a clone of this address with a different endpoint // which is mostly useful for sending messages to ourselves or an outbox WithEndpoint(endpoint *url.URL) Addr }
Addr is a Salty Address in the form of user@domain and is used to discover a user's endpoint, domain, avatar service so we can send messages to.
func LookupAddr ¶
LookupAddr looks up a Salty Address for a User by parsing the user's domain and making a request to the user's Well-Known URI expected to be located at https://domain/.well-known/salty/<user>.json
type AvatarRequest ¶
AvatarRequest is the request used by clients to update avatars stored on a broker's avatar service.
func NewAvatarRequest ¶
func NewAvatarRequest(r io.Reader) (req AvatarRequest, signer string, err error)
NewAvatarRequest reads the signed request body from a client, verifies its signature and returns the resulting `AvatarRequest` and key used to sign the request on success otherwise an empty object and en error on failure.
type Blob ¶
type Blob struct { Type string Public bool Filename string Properties map[string]string // contains filtered or unexported fields }
Blob defines the type, filename and whether or not a blob is publicly accessible or not. A Blob also holds zero or more properties as a map of key/value pairs of string interpreted by the client.
func (*Blob) SetHeaders ¶
SetHeaders sets HTTP headers on the net/http.Request object based on the blob's type, filename and various other properties (if any).
type BlobOption ¶
type BlobOption func(opts *BlobOptions) error
BlobOption is a function type that is used to configure blob options
func WithKey ¶
func WithKey(key string) BlobOption
WithKey sets an explicit key (location) for the blob
type BlobOptions ¶
type BlobOptions struct { // Key is the locaiton of the blob option, if omitted a hash of the contents is used as the key Key string // Type is the mimetype of the blob, if omitted the type is auto detected Type string // Public sets whether the blob is public or pviate (default) Public bool // Filename sets the blob's friendly filename (if omitted, no filename is used) Filename string // Properties sets optional properties of a blob which are up to clients to interpet Properties map[string]string }
BlobOptions are various options that define a blob such its type, filename, whether it is public or not (private by default) and any optional properties that clients can interpret.
type BlobRequest ¶
type BlobRequest struct {
Blob
}
BlobRequest is the request used by clients to update blob metadata for blobs stored on a broker.
func NewBlobRequest ¶
func NewBlobRequest(r io.Reader) (req BlobRequest, signer string, err error)
NewBlobRequest reads the signed request body from a client, verifies its signature and returns the resulting `BlobRequest` and key used to sign the request on success otherwise an empty object and an error on failure.
type BlobService ¶
type BlobService interface { Write(r io.Reader, opts ...BlobOption) error Read(key string) ([]byte, error) }
BlobService allows a client to store, retrieve and delete blobs of data as well as store properites for a blob that are useful to other clients or users receiving the blob.
type Capabilities ¶
type Capabilities struct {
AcceptEncoding string
}
Capabilities defines optional capabilities of a client
func (Capabilities) String ¶
func (c Capabilities) String() string
String implements the fmt.Stringer interface and formats capabilities as HTTP headers
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a Salty IM client that handles talking to a Salty IM Broker and Sedngina and Receiving messages to/from Salty IM Users.
func NewClient ¶
func NewClient(options ...ClientOption) (*Client, error)
NewClient returns a new Salty IM client for sending and receiving encrypted messages to other Salty IM users as well as decrypting and displaying messages of the user's own inbox.
func (*Client) Blobs ¶
func (cli *Client) Blobs() BlobService
Blobs returns an object that implements the BlobService which uses this client's identity and the broker this client is connected to (normally an instance of `saltyd`).
func (*Client) Env ¶
Env sets up a sensible (and hopefully secure) environment for running pre and post hooks Extra environment variables are parsed from extraenvs and some default variables injected into the new environment such as PATH, PWD and HOME as well as the current user's Salty address (SALTY_USER) and their public key (SALTY_IDENTITY).
func (*Client) Key ¶
func (cli *Client) Key() *keys.EdX25519PublicKey
Key returns our (self) public key
func (*Client) Lookup ¶
Lookup performs a lookup for a user's address and config If the user has an address already cached, the cached addr is returned, otherwise a full lookup is done.
func (*Client) Outbox ¶
Outbox returns the URL of our (self) outbox for sending copies of our outgoing messages to which is later used by the client as a way to track messages sent.
func (*Client) OutboxAddr ¶
OutboxAddr returns the address of our (self) outbox
func (*Client) OutboxClient ¶
OutboxClient returns a modified client for our (self) outbox
func (*Client) Read ¶
func (cli *Client) Read(options ...ReadOption) (Message, error)
Read reads a single message from this user's inbox
func (*Client) Register ¶
Register sends a registration request to the service user of a Salty Broker
func (*Client) SendToAddr ¶
SendToAddr encrypts and sends the message to a specified address
func (*Client) SetLookup ¶
SetLookup sets the internal lookup interface to use (Lookuper) for looking up Salty Addresses. By default the DirectLookup implementation is used.
func (*Client) SetSend ¶
SetSend sets the internal send interface to use (Sender) for sending messages to endpoints. By default the DirectSend implementation is used.
type ClientOption ¶
ClientOption is a function that configures a client
func WithClientIdentity ¶
func WithClientIdentity(options ...IdentityOption) ClientOption
WithClientIdentity sets the client's identity
func WithIdentity ¶
func WithIdentity(id *Identity) ClientOption
WithIdentity sets the client's identity from an identity object
func WithState ¶
func WithState(state *State) ClientOption
WithState sets the client's state from a state object
func WithStateFromBytes ¶
func WithStateFromBytes(data []byte) ClientOption
WithStateFromBytes sets the client's state from a byte array
func WithStateFromFile ¶
func WithStateFromFile(fn string) ClientOption
WithStateFromFile sets the client's state from a file on disk
func WithUser ¶
func WithUser(user string) ClientOption
WithUser sets the client's `me` Salty Address if a non-nil or non-empty and valid Salty Address for `user` is supplifed, otherwise the user in the client's identity is used.
type Config ¶
Config represents a Salty Config for a User which at a minimum is required to have an Endpoint and Key (Public Key)
type DNSOverHTTPResolver ¶
type DNSOverHTTPResolver struct{}
DNSOverHTTPResolver is a resolver that performs DNS queries using a DNS Over HTTP service where direct DNS queries are not possible (standard resolver).
type DirectLookup ¶
type DirectLookup struct{}
DirectLookup performs a direct lookup request
func (*DirectLookup) LookupAddr ¶
func (l *DirectLookup) LookupAddr(user string) (Addr, error)
LookupAddr performs a lookup of a Salty Addr directly
type DirectSend ¶
type DirectSend struct{}
DirectSend performs a direct send request
func (*DirectSend) Send ¶
func (s *DirectSend) Send(_ *keys.EdX25519Key, endpoint, msg string, cap Capabilities) error
Send posts a message to an endpoint directly
type Identity ¶
type Identity struct {
// contains filtered or unexported fields
}
Identity allows interaction with CreateIdentity, GetIdentity, and NewClient
func CreateIdentity ¶
func CreateIdentity(options ...IdentityOption) (*Identity, error)
CreateIdentity ...
func GetOrCreateIdentity ¶
func GetOrCreateIdentity(options ...IdentityOption) (*Identity, error)
GetOrCreateIdentity ...
func (*Identity) Key ¶
func (i *Identity) Key() *keys.EdX25519Key
Key returns the full private and public Ed25519 key object for this identity
type IdentityOption ¶
type IdentityOption func(*Identity)
IdentityOption represents functional options for various identity operations
func WithIdentityAddr ¶
func WithIdentityAddr(addr Addr) IdentityOption
WithIdentityAddr sets the identity Addr option
func WithIdentityBytes ¶
func WithIdentityBytes(contents []byte) IdentityOption
WithIdentityBytes indicates that the identity should be read from a byte array
func WithIdentityPath ¶
func WithIdentityPath(path string) IdentityOption
WithIdentityPath indicates that an identity should be read / written from a file path
type Lookuper ¶
Lookuper defines an interface for looking up Salty Addresses, primarily used by the PWA and possibly other clients, as a way to either perform direct lookups or to have lookups proxied through a broker.
type Message ¶
type Message struct { Text string Key *keys.EdX25519PublicKey }
Message contains the plaintext (decrypted) message and the sender's public key
type MessageEventHandlerFunc ¶
type MessageEventHandlerFunc func(context.Context, *Service, *keys.EdX25519PublicKey, *lextwt.SaltyEvent) error
MessageEventHandlerFunc defines a function type to handle an inbound event to a service
type MessageTextHandlerFunc ¶
type MessageTextHandlerFunc func(context.Context, *Service, *keys.EdX25519PublicKey, *lextwt.SaltyText) error
MessageTextHandlerFunc defines a function type to handle an inbound message to a service
type ProxyLookup ¶
type ProxyLookup struct { // LookupEndpoint is the uri of the lookup endpoint of a broker LookupEndpoint string }
ProxyLookup proxies lookup requests through a Salty Broker's /api/v1/lookup endpoint
func (*ProxyLookup) LookupAddr ¶
func (l *ProxyLookup) LookupAddr(user string) (Addr, error)
LookupAddr performs a lookup of a Salty Addr directly and if the request fails for whatever reason (usuaully due to Cross-Orogin-Resource-Sharing policies / CORS) it uses the Salty Broker the PWA was served from initially to perform the lookup by proxying the lookup through the broker. Why? CORS sucks.
type ProxySend ¶
type ProxySend struct { // SendEndpoint is the uri of the send endpoint of a broker SendEndpoint string }
ProxySend proxies send requests through a Salty Broker's /api/v1/send endpoint
func (*ProxySend) Send ¶
func (s *ProxySend) Send(key *keys.EdX25519Key, endpoint, msg string, cap Capabilities) error
Send posts a message to an endpoint directly directly and if the request fails for whatever reason (usuaully due to Cross-Orogin-Resource-Sharing policies / CORS) it uses the Salty Broker the PWA was served from initially to perform the send by proxying the send request through the broker. Why? CORS sucks.
type ReadOption ¶
type ReadOption func(opts *ReadOptions) error
ReadOption is a function that configures a client
func WithExtraEnvs ¶
func WithExtraEnvs(extraenvs string) ReadOption
WithExtraEnvs sets extra environment variables for use by pre/post hooks
func WithPostHook ¶
func WithPostHook(posthook string) ReadOption
WithPostHook sets the posthook used for processing incoming messages which is the path to a script that is passed the decrypted message as its standard input.
func WithPreHook ¶
func WithPreHook(prehook string) ReadOption
WithPreHook sets the prehook used for processing incoming messages which is the path to a script that is passed the encrypted message payload as its standard input.
type ReadOptions ¶
ReadOptions allows a client to read from its inbox and provide additional options for processing messages such as extra environment variables for pre/post hooks.
type RegisterRequest ¶
RegisterRequest is the request used by clients to register to a broker
func NewRegisterRequest ¶
func NewRegisterRequest(r io.Reader) (req RegisterRequest, signer string, err error)
NewRegisterRequest reads the signed request body from a client, verifies its signature and returns the resulting `RegisterRequest` and key used to sign the request on success otherwise an empty object and en error on failure.
type Resolver ¶
Resolver is an interface for performing DNS lookups and is primarily used by the PWA and possibly other clients where direct DNS queries are not always possible and instead uses DNS over HTTP to eprform the same functionality.
var ( // ErrSRVRecordNotFound is an error returned by a resolver when there is no SRV record found for the domain of a Salty Address ErrSRVRecordNotFound = errors.New("error: No SRV records found") // DefaultResolver is the default resolver which defaults to the StandardResolver DefaultResolver Resolver = &StandardResolver{} )
type SendRequest ¶
type SendRequest struct { Endpoint string Message string Capabilities Capabilities }
SendRequest is the request used by clients to send messages via a broker
func NewSendRequest ¶
func NewSendRequest(r io.Reader) (req SendRequest, signer string, err error)
NewSendRequest reads the signed request body from a client, verifies its signature and returns the resulting `SendRequest` and key used to sign the request on success otherwise an empty object and en error on failure.
type Sender ¶
type Sender interface {
Send(key *keys.EdX25519Key, endpoint, msg string, cap Capabilities) error
}
Sender defines an interface for sending messages to another Salty Address (user) and is primarily used by the PWA and possibly other clients to send outbound messages where it may not always be possible to send the message directly and instead proxy the message thorugh a broker. Note that even if proxying through a broker, the message is already encrypted at the point of proxying, so there needs not be any trust between the client and broker as the broker is treated as a "dumb" relay.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service is an object that implements an async responder (bot) that responds to textual callbacks (commands) or events. This can be used to implement automated users, bots or services.
func NewService ¶
NewService constructs a new service with the provided address, identity and state
func (*Service) EventFunc ¶
func (svc *Service) EventFunc(name string, fn MessageEventHandlerFunc)
EventFunc registers a handler for processing event callbacks (events)
func (*Service) Respond ¶
Respond is a convenitne method to respond to a user with the provided message
func (*Service) Run ¶
Run runs the service tunil the context is done, if an error occurred at any point an error is returned.
func (*Service) TextFunc ¶
func (svc *Service) TextFunc(name string, fn MessageTextHandlerFunc)
TextFunc registers a handler for processing textual callbacks (commands)
type StandardResolver ¶
type StandardResolver struct{}
StandardResolver is a standard resolver that performs direct DNS queries over the standard networking protocol using port tcp/53 or udp/53
type State ¶
State represents the state of a client and the indices of its inbox(es)
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
cmd
|
|
salty-chat
Package main implements the `salty-chat` command-line (CLI) tool and a terminal user interface (TUI)
|
Package main implements the `salty-chat` command-line (CLI) tool and a terminal user interface (TUI) |
Package internal contains internal implementation details
|
Package internal contains internal implementation details |
app
Package app implements a terminal user interface (tui)
|
Package app implements a terminal user interface (tui) |
authreq
Package authreq signa and verifies HTTP requests using Ed25519 private/public keys
|
Package authreq signa and verifies HTTP requests using Ed25519 private/public keys |