saltyim is the Go library and reference client and broker implementation for Salty IM it contains a command-line client (cli), a terminal user interface (tui), builtin server/broker and a Mobile / Desktop App PWA (progressive web app) https://salty.im/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
saltyim/send.go

93 lines
2.5 KiB

package saltyim
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"github.com/keys-pub/keys"
"github.com/timewasted/go-accept-headers"
"go.mills.io/salty"
)
var (
_ Sender = (*DirectSend)(nil)
_ Sender = (*ProxySend)(nil)
acceptEncodings = []string{"br", "gzip", ""}
)
type Sender interface {
Send(key *keys.EdX25519Key, 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 Send(endpoint, msg string, cap Capabilities) error {
headers := make(http.Header)
if cap.AcceptEncoding != "" {
ae, err := accept.Negotiate(cap.AcceptEncoding, acceptEncodings...)
if err != nil {
return fmt.Errorf("error publishing message to %s: %w", endpoint, err)
}
headers.Set("Content-Encoding", ae)
}
res, err := Request(http.MethodPost, endpoint, headers, bytes.NewBufferString(msg))
if err != nil {
return fmt.Errorf("error publishing message to %s: %w", endpoint, err)
}
defer res.Body.Close()
return nil
}
// DirectSend performs a direct send request
type DirectSend struct{}
// Send posts a message to an endpoint directly
func (s *DirectSend) Send(key *keys.EdX25519Key, endpoint, msg string, cap Capabilities) error {
return Send(endpoint, msg, cap)
}
// ProxySend proxies send requests through a Salty Broker's /api/v1/send endpoint
type ProxySend struct {
// SendEndpoint is the uri of the send endpoint of a broker
SendEndpoint string
}
// 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.
func (s *ProxySend) Send(key *keys.EdX25519Key, endpoint, msg string, cap Capabilities) error {
err := Send(endpoint, msg, cap)
if err == nil {
return nil
}
// Fallback to proxying the send request through the broker...
req := SendRequest{
Endpoint: endpoint,
Message: msg,
Capabilities: cap,
}
data, err := json.Marshal(req)
if err != nil {
return fmt.Errorf("error serializing send request: %w", err)
}
signed, err := salty.Sign(key, data)
if err != nil {
return fmt.Errorf("error signing send request: %w", err)
}
res, err := Request(http.MethodPost, s.SendEndpoint, nil, bytes.NewBuffer(signed))
if err != nil {
return err
}
defer res.Body.Close()
return nil
}