2021-02-09 11:53:33 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
2021-02-01 15:45:30 +00:00
|
|
|
package server
|
2021-01-25 17:31:09 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-01-26 17:33:29 +00:00
|
|
|
"encoding/json"
|
2021-05-17 07:11:29 +00:00
|
|
|
"errors"
|
2021-03-24 09:58:32 +00:00
|
|
|
"fmt"
|
2021-04-05 09:33:28 +00:00
|
|
|
"sync"
|
2021-01-25 17:31:09 +00:00
|
|
|
"time"
|
|
|
|
|
2021-05-31 12:50:44 +00:00
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/v2/internal/network"
|
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/v2/roomdb"
|
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/v2/roomstate"
|
2021-01-26 17:33:29 +00:00
|
|
|
|
2021-01-25 17:31:09 +00:00
|
|
|
"go.cryptoscope.co/muxrpc/v2"
|
2021-05-21 07:27:12 +00:00
|
|
|
kitlog "go.mindeco.de/log"
|
2021-01-25 17:31:09 +00:00
|
|
|
)
|
|
|
|
|
2021-03-11 17:40:33 +00:00
|
|
|
type Handler struct {
|
2021-01-25 17:31:09 +00:00
|
|
|
logger kitlog.Logger
|
2021-01-26 17:33:29 +00:00
|
|
|
|
2021-05-17 07:11:29 +00:00
|
|
|
netInfo network.ServerEndpointDetails
|
2021-03-24 09:58:32 +00:00
|
|
|
state *roomstate.Manager
|
|
|
|
members roomdb.MembersService
|
|
|
|
config roomdb.RoomConfig
|
2021-01-26 17:33:29 +00:00
|
|
|
}
|
|
|
|
|
2021-05-17 07:11:29 +00:00
|
|
|
type MetadataReply struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
Membership bool `json:"membership"`
|
|
|
|
Features []string `json:"features"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *Handler) metadata(ctx context.Context, req *muxrpc.Request) (interface{}, error) {
|
|
|
|
ref, err := network.GetFeedRefFromAddr(req.RemoteAddr())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
pm, err := h.config.GetPrivacyMode(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var reply MetadataReply
|
|
|
|
reply.Name = h.netInfo.Domain
|
|
|
|
|
|
|
|
// check if caller is a member
|
|
|
|
if _, err := h.members.GetByFeed(ctx, *ref); err != nil {
|
|
|
|
if !errors.Is(err, roomdb.ErrNotFound) {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// already initialized as false, just to be clear
|
|
|
|
reply.Membership = false
|
|
|
|
} else {
|
|
|
|
reply.Membership = true
|
|
|
|
}
|
|
|
|
|
|
|
|
// always-on features
|
|
|
|
reply.Features = []string{
|
|
|
|
"tunnel",
|
|
|
|
"httpAuth",
|
|
|
|
"httpInvite",
|
|
|
|
// TODO: add "room2" once implemented
|
|
|
|
}
|
|
|
|
|
|
|
|
if pm == roomdb.ModeOpen {
|
|
|
|
reply.Features = append(reply.Features, "room1")
|
|
|
|
}
|
|
|
|
|
|
|
|
if pm == roomdb.ModeOpen || pm == roomdb.ModeCommunity {
|
|
|
|
reply.Features = append(reply.Features, "alias")
|
|
|
|
}
|
|
|
|
|
|
|
|
return reply, nil
|
2021-01-25 17:31:09 +00:00
|
|
|
}
|
|
|
|
|
2021-03-11 17:40:33 +00:00
|
|
|
func (h *Handler) ping(context.Context, *muxrpc.Request) (interface{}, error) {
|
2021-01-25 17:31:09 +00:00
|
|
|
now := time.Now().UnixNano() / 1000
|
|
|
|
return now, nil
|
|
|
|
}
|
|
|
|
|
2021-03-11 17:40:33 +00:00
|
|
|
func (h *Handler) announce(_ context.Context, req *muxrpc.Request) (interface{}, error) {
|
2021-01-26 17:33:29 +00:00
|
|
|
ref, err := network.GetFeedRefFromAddr(req.RemoteAddr())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-02-10 14:50:36 +00:00
|
|
|
h.state.AddEndpoint(*ref, req.Endpoint())
|
2021-01-26 17:33:29 +00:00
|
|
|
|
2021-04-20 10:14:35 +00:00
|
|
|
return true, nil
|
2021-01-25 17:31:09 +00:00
|
|
|
}
|
|
|
|
|
2021-03-11 17:40:33 +00:00
|
|
|
func (h *Handler) leave(_ context.Context, req *muxrpc.Request) (interface{}, error) {
|
2021-01-26 17:33:29 +00:00
|
|
|
ref, err := network.GetFeedRefFromAddr(req.RemoteAddr())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-02-10 14:50:36 +00:00
|
|
|
h.state.Remove(*ref)
|
2021-01-26 17:33:29 +00:00
|
|
|
|
2021-04-20 10:14:35 +00:00
|
|
|
return true, nil
|
2021-01-25 17:31:09 +00:00
|
|
|
}
|
|
|
|
|
2021-03-24 09:58:32 +00:00
|
|
|
func (h *Handler) endpoints(ctx context.Context, req *muxrpc.Request, snk *muxrpc.ByteSink) error {
|
2021-01-29 10:55:40 +00:00
|
|
|
|
2021-04-21 07:44:44 +00:00
|
|
|
// get public key from the calling peer
|
|
|
|
peer, err := network.GetFeedRefFromAddr(req.RemoteAddr())
|
2021-01-28 14:06:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-03-24 09:58:32 +00:00
|
|
|
pm, err := h.config.GetPrivacyMode(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("running with unknown privacy mode")
|
|
|
|
}
|
|
|
|
|
|
|
|
switch pm {
|
|
|
|
case roomdb.ModeCommunity:
|
|
|
|
fallthrough
|
|
|
|
case roomdb.ModeRestricted:
|
2021-04-21 07:44:44 +00:00
|
|
|
_, err := h.members.GetByFeed(ctx, *peer)
|
2021-03-24 09:58:32 +00:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("external user are not allowed to enumerate members")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-21 13:52:04 +00:00
|
|
|
// for future updates
|
|
|
|
toPeer := newEndpointsForwarder(snk)
|
|
|
|
h.state.RegisterLegacyEndpoints(toPeer)
|
|
|
|
|
2021-04-21 07:44:44 +00:00
|
|
|
// add the peer to the room state if they arent already
|
|
|
|
h.state.AlreadyAdded(*peer, req.Endpoint())
|
|
|
|
|
|
|
|
// update the peer with
|
2021-04-20 10:14:35 +00:00
|
|
|
toPeer.Update(h.state.List())
|
|
|
|
|
2021-01-26 17:33:29 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-05-17 13:31:49 +00:00
|
|
|
// a muxrpc json encoder for endpoints broadcasts
|
|
|
|
type endpointsJSONEncoder struct {
|
2021-04-05 09:33:28 +00:00
|
|
|
mu sync.Mutex // only one caller to forwarder at a time
|
2021-01-26 17:33:29 +00:00
|
|
|
snk *muxrpc.ByteSink
|
|
|
|
enc *json.Encoder
|
|
|
|
}
|
|
|
|
|
2021-05-17 14:05:51 +00:00
|
|
|
func newEndpointsForwarder(snk *muxrpc.ByteSink) *endpointsJSONEncoder {
|
2021-01-26 17:33:29 +00:00
|
|
|
enc := json.NewEncoder(snk)
|
|
|
|
snk.SetEncoding(muxrpc.TypeJSON)
|
2021-05-17 13:31:49 +00:00
|
|
|
return &endpointsJSONEncoder{
|
2021-01-26 17:33:29 +00:00
|
|
|
snk: snk,
|
|
|
|
enc: enc,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-17 13:31:49 +00:00
|
|
|
func (uf *endpointsJSONEncoder) Update(members []string) error {
|
2021-04-05 09:33:28 +00:00
|
|
|
uf.mu.Lock()
|
|
|
|
defer uf.mu.Unlock()
|
2021-01-27 10:05:06 +00:00
|
|
|
return uf.enc.Encode(members)
|
2021-01-26 17:33:29 +00:00
|
|
|
}
|
|
|
|
|
2021-05-17 13:31:49 +00:00
|
|
|
func (uf *endpointsJSONEncoder) Close() error {
|
2021-04-05 09:33:28 +00:00
|
|
|
uf.mu.Lock()
|
|
|
|
defer uf.mu.Unlock()
|
2021-01-26 17:33:29 +00:00
|
|
|
return uf.snk.Close()
|
2021-01-25 17:31:09 +00:00
|
|
|
}
|