mirror of
https://git.mills.io/saltyim/saltyim.git
synced 2024-06-28 09:41:02 +00:00
764180a658
Co-authored-by: James Mills <prologic@shortcircuit.net.au> Reviewed-on: https://git.mills.io/saltyim/saltyim/pulls/105 Reviewed-by: xuu <xuu@noreply@mills.io>
94 lines
2.5 KiB
Go
94 lines
2.5 KiB
Go
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
|
|
}
|