mirror of
https://git.mills.io/saltyim/saltyim.git
synced 2024-06-16 03:48:24 +00:00
Add support for performing lookups via the broker we were served from (#99)
Depends on #95 Co-authored-by: James Mills <prologic@shortcircuit.net.au> Reviewed-on: https://git.mills.io/saltyim/saltyim/pulls/99
This commit is contained in:
parent
554f927eaa
commit
57a6ff5ec1
2
Makefile
2
Makefile
@ -70,7 +70,7 @@ generate: ## Genereate any code required by the build
|
||||
echo 'Running in debug mode...'; \
|
||||
fi
|
||||
|
||||
PWA_SRCS = $(shell ls *.go) $(shell find ./internal/pwa -type f)
|
||||
PWA_SRCS = $(shell ls *.go) ./internal/server.go $(shell find ./internal/pwa -type f)
|
||||
|
||||
internal/web/app.wasm: $(PWA_SRCS)
|
||||
@GOARCH=wasm GOOS=js $(GOCMD) build -o ./internal/web/app.wasm ./internal/pwa/
|
||||
|
21
client.go
21
client.go
@ -98,6 +98,8 @@ type Client struct {
|
||||
id *Identity
|
||||
key *keys.EdX25519Key
|
||||
cache addrCache
|
||||
|
||||
lookup Lookuper
|
||||
}
|
||||
|
||||
// NewClient reeturns a new Salty IM client for sending and receiving
|
||||
@ -125,10 +127,11 @@ func NewClient(me *Addr, options ...IdentityOption) (*Client, error) {
|
||||
log.Debugf("Endpoint is %s", me.Endpoint())
|
||||
|
||||
return &Client{
|
||||
me: me,
|
||||
id: id,
|
||||
key: id.key,
|
||||
cache: make(addrCache),
|
||||
me: me,
|
||||
id: id,
|
||||
key: id.key,
|
||||
cache: make(addrCache),
|
||||
lookup: &DirectLookup{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -138,7 +141,7 @@ func (cli *Client) getAddr(user string) (*Addr, error) {
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
addr, err := LookupAddr(user)
|
||||
addr, err := cli.lookup.LookupAddr(user)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error: failed to lookup user %s: %w", user, err)
|
||||
}
|
||||
@ -252,6 +255,12 @@ func (cli *Client) String() string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// SetLookup sets the internal lookup interface to use (Lookuper) for looking
|
||||
// up Salty Addresses. By default the DirectLookup implementation is used.
|
||||
func (cli *Client) SetLookup(lookup Lookuper) {
|
||||
cli.lookup = lookup
|
||||
}
|
||||
|
||||
// Drain drains this user's inbox by simulteneiously reading until empty anda
|
||||
// subscribing to the inbox for new messages.
|
||||
func (cli *Client) Drain(ctx context.Context, extraenvs, prehook, posthook string) chan Message {
|
||||
@ -376,7 +385,7 @@ func (cli *Client) SendToAddr(addr *Addr, msg string) error {
|
||||
|
||||
// Register sends a registration request to the service user of a Salty Broker
|
||||
func (cli *Client) Register() error {
|
||||
svc, err := LookupAddr(fmt.Sprintf("%s@%s", ServiceUser, cli.Me().Domain))
|
||||
svc, err := cli.lookup.LookupAddr(fmt.Sprintf("%s@%s", ServiceUser, cli.Me().Domain))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error looking up service user on %s: %w", cli.Me().Domain, err)
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ import (
|
||||
"github.com/mlctrez/goapp-mdc/pkg/button"
|
||||
"github.com/mlctrez/goapp-mdc/pkg/icon"
|
||||
"github.com/mlctrez/goapp-mdc/pkg/textfield"
|
||||
"go.mills.io/saltyim"
|
||||
"go.mills.io/saltyim/internal/pwa/storage"
|
||||
"go.mills.io/saltyim/internal/pwa/utils"
|
||||
)
|
||||
|
||||
type NewChat struct {
|
||||
@ -61,7 +61,7 @@ func (n *NewChat) Render() app.UI {
|
||||
func (n *NewChat) newChat() func(button app.HTMLButton) {
|
||||
return func(button app.HTMLButton) {
|
||||
button.OnClick(func(ctx app.Context, e app.Event) {
|
||||
addr, err := saltyim.LookupAddr(n.user.Value)
|
||||
addr, err := utils.LookupAddr(n.user.Value)
|
||||
if err != nil {
|
||||
n.dialog.ShowDialog("error", err.Error())
|
||||
return
|
||||
|
@ -107,6 +107,7 @@ func (h *SaltyChat) connect(ctx app.Context) {
|
||||
h.dialog.ShowDialog("error setting up client", err.Error())
|
||||
return
|
||||
}
|
||||
newClient.SetLookup(&saltyim.ProxyLookup{LookupEndpoint: app.Getenv("LookupEndpoint")})
|
||||
|
||||
client = newClient
|
||||
|
||||
|
41
internal/pwa/utils/lookup.go
Normal file
41
internal/pwa/utils/lookup.go
Normal file
@ -0,0 +1,41 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/maxence-charriere/go-app/v9/pkg/app"
|
||||
"go.mills.io/saltyim"
|
||||
)
|
||||
|
||||
// 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.
|
||||
func LookupAddr(user string) (*saltyim.Addr, error) {
|
||||
addr, err := saltyim.LookupAddr(user)
|
||||
if err == nil {
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
// Fallback to proxying the lookup through the broker...
|
||||
|
||||
res, err := saltyim.Request(http.MethodGet, app.Getenv("LookupEndpoint")+user, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &addr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return addr, nil
|
||||
}
|
@ -7,6 +7,7 @@ import (
|
||||
"net/http"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@ -291,6 +292,11 @@ func (s *Server) initRoutes() {
|
||||
Name: "Salty Chat",
|
||||
ShortName: "Salty Chat",
|
||||
Description: "Secure, easy, self-hosted messaging",
|
||||
|
||||
Env: map[string]string{
|
||||
"LookupEndpoint": strings.TrimSuffix(s.config.BaseURL, "/") + "/api/v1/lookup/",
|
||||
},
|
||||
|
||||
Icon: app.Icon{
|
||||
Large: "/web/favicon-lg.png",
|
||||
Default: "/web/favicon-ap.png",
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:95a9c74c800295301b1cb5a08cba6679ee5c16bd9f91ac0cdf6c44e808a33df7
|
||||
size 27991136
|
||||
oid sha256:6756046e89856a68e31c8dde6a2c1229674064e47dbf815fd87465a193e45e2c
|
||||
size 28023655
|
||||
|
85
lookup.go
85
lookup.go
@ -4,6 +4,7 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@ -13,9 +14,16 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
_ json.Marshaler = (*Addr)(nil)
|
||||
_ json.Marshaler = (*Addr)(nil)
|
||||
_ json.Unmarshaler = (*Addr)(nil)
|
||||
_ Lookuper = (*DirectLookup)(nil)
|
||||
_ Lookuper = (*ProxyLookup)(nil)
|
||||
)
|
||||
|
||||
type Lookuper interface {
|
||||
LookupAddr(user string) (*Addr, error)
|
||||
}
|
||||
|
||||
func fetchConfig(addr string) (Config, Capabilities, error) {
|
||||
// Attempt using hash
|
||||
res, err := Request(http.MethodGet, addr, nil, nil)
|
||||
@ -79,6 +87,37 @@ func (a *Addr) MarshalJSON() ([]byte, error) {
|
||||
})
|
||||
}
|
||||
|
||||
func (a *Addr) UnmarshalJSON(data []byte) error {
|
||||
res := struct {
|
||||
Addr string
|
||||
User string
|
||||
Domain string
|
||||
Key string
|
||||
Endpoint string
|
||||
}{}
|
||||
|
||||
if err := json.Unmarshal(data, &res); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.User = res.User
|
||||
a.Domain = res.Domain
|
||||
|
||||
u, err := url.Parse(res.Endpoint)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing endpoint %q: %w", res.Endpoint, err)
|
||||
}
|
||||
a.endpoint = u
|
||||
|
||||
key, err := keys.NewEdX25519PublicKeyFromID(keys.ID(res.Key))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing public key %q: %w", res.Key, err)
|
||||
}
|
||||
a.key = key
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Addr) String() string {
|
||||
return fmt.Sprintf("%s@%s", a.User, a.Domain)
|
||||
}
|
||||
@ -198,3 +237,47 @@ func LookupAddr(addr string) (*Addr, error) {
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// DirectLookup performs a direct lookup request
|
||||
type DirectLookup struct{}
|
||||
|
||||
// LookupAddr performs a lookup of a Salty Addr directly
|
||||
func (l *DirectLookup) LookupAddr(user string) (*Addr, error) {
|
||||
return LookupAddr(user)
|
||||
}
|
||||
|
||||
// ProxyLookup proxies lookup requests through a Salty Broker's /api/v1/lookup endpoint
|
||||
type ProxyLookup struct {
|
||||
// LookupEndpoint is the uri of the lookup endpoint of a broker
|
||||
LookupEndpoint string
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (l *ProxyLookup) LookupAddr(user string) (*Addr, error) {
|
||||
addr, err := LookupAddr(user)
|
||||
if err == nil {
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
// Fallback to proxying the lookup through the broker...
|
||||
|
||||
res, err := Request(http.MethodGet, l.LookupEndpoint+user, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &addr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return addr, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user