2021-10-08 12:39:31 +00:00
|
|
|
// SPDX-FileCopyrightText: 2021 The NGI Pointer Secure-Scuttlebutt Team of 2020/2021
|
|
|
|
//
|
2021-02-09 11:53:33 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
2021-01-25 12:23:03 +00:00
|
|
|
package go_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-04-12 13:00:34 +00:00
|
|
|
"crypto/rand"
|
2021-04-22 08:19:03 +00:00
|
|
|
"encoding/base64"
|
2021-01-25 12:23:03 +00:00
|
|
|
"errors"
|
2021-04-12 13:00:34 +00:00
|
|
|
"fmt"
|
2021-01-25 12:23:03 +00:00
|
|
|
"io"
|
2021-01-26 17:33:29 +00:00
|
|
|
"net"
|
2021-01-25 15:35:22 +00:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"sync"
|
|
|
|
"testing"
|
2021-04-12 13:00:34 +00:00
|
|
|
"time"
|
|
|
|
|
2021-02-11 15:43:19 +00:00
|
|
|
_ "github.com/mattn/go-sqlite3"
|
2021-01-25 15:35:22 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2021-04-22 08:19:03 +00:00
|
|
|
"go.cryptoscope.co/muxrpc/v2"
|
2021-01-26 17:33:29 +00:00
|
|
|
"go.cryptoscope.co/muxrpc/v2/debug"
|
2021-04-22 08:19:03 +00:00
|
|
|
"go.cryptoscope.co/netwrap"
|
|
|
|
"go.cryptoscope.co/secretstream"
|
2021-05-21 07:27:12 +00:00
|
|
|
"go.mindeco.de/log"
|
|
|
|
"go.mindeco.de/log/level"
|
2021-04-22 08:19:03 +00:00
|
|
|
"golang.org/x/sync/errgroup"
|
2021-01-25 15:35:22 +00:00
|
|
|
|
2021-05-31 12:50:44 +00:00
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/v2/internal/maybemod/keys"
|
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/v2/internal/maybemod/testutils"
|
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/v2/internal/network"
|
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/v2/internal/repo"
|
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/v2/internal/signinwithssb"
|
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/v2/muxrpc/handlers/tunnel/server"
|
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/v2/roomdb"
|
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/v2/roomdb/sqlite"
|
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/v2/roomsrv"
|
2021-04-22 08:19:03 +00:00
|
|
|
refs "go.mindeco.de/ssb-refs"
|
2021-01-25 12:23:03 +00:00
|
|
|
)
|
|
|
|
|
2021-01-25 15:35:22 +00:00
|
|
|
var (
|
|
|
|
initLogging sync.Once
|
|
|
|
mainLog = log.NewNopLogger()
|
|
|
|
)
|
|
|
|
|
|
|
|
// cant call testing.pkg in init()
|
|
|
|
func testInit(t *testing.T) {
|
|
|
|
initLogging.Do(func() {
|
|
|
|
if testing.Verbose() {
|
|
|
|
mainLog = testutils.NewRelativeTimeLogger(nil)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
os.RemoveAll(filepath.Join("testrun", t.Name()))
|
|
|
|
}
|
|
|
|
|
2021-01-25 12:23:03 +00:00
|
|
|
type botServer struct {
|
|
|
|
ctx context.Context
|
|
|
|
log log.Logger
|
|
|
|
}
|
|
|
|
|
|
|
|
func newBotServer(ctx context.Context, log log.Logger) botServer {
|
|
|
|
return botServer{ctx, log}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (bs botServer) Serve(s *roomsrv.Server) func() error {
|
|
|
|
return func() error {
|
|
|
|
err := s.Network.Serve(bs.ctx)
|
|
|
|
if err != nil {
|
|
|
|
if errors.Is(err, io.EOF) || errors.Is(err, context.Canceled) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
level.Warn(bs.log).Log("event", "bot serve exited", "err", err)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2021-01-25 15:35:22 +00:00
|
|
|
|
2021-04-20 10:14:24 +00:00
|
|
|
type testSession struct {
|
|
|
|
t testing.TB
|
|
|
|
|
|
|
|
srv *roomsrv.Server
|
|
|
|
|
|
|
|
ctx context.Context
|
|
|
|
serveGroup *errgroup.Group
|
2021-04-22 10:13:34 +00:00
|
|
|
|
|
|
|
// so that we can re-spawn clients
|
|
|
|
clientKeys map[string]*keys.KeyPair
|
2021-04-20 10:14:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func makeNamedTestBot(t testing.TB, name string, ctx context.Context, opts []roomsrv.Option) *testSession {
|
2021-01-25 15:35:22 +00:00
|
|
|
r := require.New(t)
|
|
|
|
testPath := filepath.Join("testrun", t.Name(), "bot-"+name)
|
2021-01-26 17:33:29 +00:00
|
|
|
os.RemoveAll(testPath)
|
2021-01-25 15:35:22 +00:00
|
|
|
|
|
|
|
botOptions := append(opts,
|
|
|
|
roomsrv.WithLogger(log.With(mainLog, "bot", name)),
|
|
|
|
roomsrv.WithRepoPath(testPath),
|
|
|
|
roomsrv.WithNetworkConnTracker(network.NewLastWinsTracker()),
|
2021-01-26 17:33:29 +00:00
|
|
|
roomsrv.WithPostSecureConnWrapper(func(conn net.Conn) (net.Conn, error) {
|
|
|
|
return debug.WrapDump(filepath.Join(testPath, "muxdump"), conn)
|
|
|
|
}),
|
2021-01-25 15:35:22 +00:00
|
|
|
)
|
|
|
|
|
2021-02-11 15:43:19 +00:00
|
|
|
// could also use the mocks
|
|
|
|
db, err := sqlite.Open(repo.New(testPath))
|
|
|
|
r.NoError(err)
|
|
|
|
t.Cleanup(func() {
|
2021-03-12 11:16:00 +00:00
|
|
|
if err := db.Close(); err != nil {
|
|
|
|
t.Log("db close failed: ", err)
|
|
|
|
}
|
2021-02-11 15:43:19 +00:00
|
|
|
})
|
2021-04-12 14:34:45 +00:00
|
|
|
|
|
|
|
err = db.Config.SetPrivacyMode(context.TODO(), roomdb.ModeRestricted)
|
|
|
|
r.NoError(err)
|
|
|
|
|
2021-04-19 12:52:12 +00:00
|
|
|
netInfo := network.ServerEndpointDetails{
|
|
|
|
Domain: name,
|
|
|
|
|
|
|
|
ListenAddressMUXRPC: ":0",
|
2021-04-19 12:57:42 +00:00
|
|
|
|
|
|
|
UseSubdomainForAliases: true,
|
2021-04-19 12:52:12 +00:00
|
|
|
}
|
|
|
|
|
2021-03-24 17:31:37 +00:00
|
|
|
sb := signinwithssb.NewSignalBridge()
|
2021-04-19 12:52:12 +00:00
|
|
|
theBot, err := roomsrv.New(db.Members, db.DeniedKeys, db.Aliases, db.AuthWithSSB, sb, db.Config, netInfo, botOptions...)
|
2021-01-25 15:35:22 +00:00
|
|
|
r.NoError(err)
|
2021-04-12 13:00:34 +00:00
|
|
|
|
2021-04-20 10:14:24 +00:00
|
|
|
ts := testSession{
|
2021-04-22 10:13:34 +00:00
|
|
|
t: t,
|
|
|
|
srv: theBot,
|
|
|
|
clientKeys: make(map[string]*keys.KeyPair),
|
2021-04-20 10:14:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ts.serveGroup, ts.ctx = errgroup.WithContext(ctx)
|
|
|
|
|
|
|
|
ts.serveGroup.Go(func() error {
|
|
|
|
return theBot.Network.Serve(ts.ctx)
|
|
|
|
})
|
|
|
|
|
|
|
|
return &ts
|
2021-04-12 13:00:34 +00:00
|
|
|
}
|
|
|
|
|
2021-04-22 10:13:34 +00:00
|
|
|
type testClient struct {
|
|
|
|
muxrpc.Endpoint
|
|
|
|
|
|
|
|
feed refs.FeedRef
|
|
|
|
|
2021-04-22 14:19:53 +00:00
|
|
|
mockedHandler *muxrpc.FakeHandler
|
2021-04-22 10:13:34 +00:00
|
|
|
}
|
|
|
|
|
2021-05-21 13:52:04 +00:00
|
|
|
var clientNo = 0
|
|
|
|
|
2021-04-22 10:13:34 +00:00
|
|
|
func (ts *testSession) makeTestClient(name string) testClient {
|
2021-04-22 08:19:03 +00:00
|
|
|
r := require.New(ts.t)
|
|
|
|
|
2021-05-21 13:52:04 +00:00
|
|
|
clientNo++
|
|
|
|
|
2021-04-22 08:19:03 +00:00
|
|
|
// create a fresh keypairs for the clients
|
2021-04-22 10:13:34 +00:00
|
|
|
client, has := ts.clientKeys[name]
|
|
|
|
if !has {
|
|
|
|
var err error
|
|
|
|
client, err = keys.NewKeyPair(nil)
|
|
|
|
r.NoError(err)
|
|
|
|
ts.clientKeys[name] = client
|
|
|
|
}
|
2021-04-22 08:19:03 +00:00
|
|
|
|
|
|
|
ts.t.Log(name, "is", client.Feed.ShortRef())
|
|
|
|
|
2021-04-22 10:13:34 +00:00
|
|
|
// add it as a memeber, if it isnt already
|
|
|
|
_, err := ts.srv.Members.GetByFeed(ts.ctx, client.Feed)
|
|
|
|
if errors.Is(err, roomdb.ErrNotFound) {
|
|
|
|
memberID, err := ts.srv.Members.Add(ts.ctx, client.Feed, roomdb.RoleMember)
|
|
|
|
r.NoError(err)
|
|
|
|
ts.t.Log(name, "is member ID:", memberID)
|
|
|
|
} else {
|
|
|
|
r.NoError(err)
|
|
|
|
}
|
2021-04-22 08:19:03 +00:00
|
|
|
|
|
|
|
// default app key for the secret-handshake connection
|
|
|
|
ak, err := base64.StdEncoding.DecodeString("1KHLiKZvAvjbY1ziZEHMXawbCEIM6qwjCDm3VYRan/s=")
|
|
|
|
r.NoError(err)
|
|
|
|
|
|
|
|
// create a shs client to authenticate and encrypt the connection
|
|
|
|
clientSHS, err := secretstream.NewClient(client.Pair, ak)
|
|
|
|
r.NoError(err)
|
|
|
|
|
|
|
|
// returns a new connection that went through shs and does boxstream
|
|
|
|
tcpAddr := netwrap.GetAddr(ts.srv.Network.GetListenAddr(), "tcp")
|
|
|
|
authedConn, err := netwrap.Dial(tcpAddr, clientSHS.ConnWrapper(ts.srv.Whoami().PubKey()))
|
|
|
|
r.NoError(err)
|
|
|
|
|
2021-05-21 13:52:04 +00:00
|
|
|
testPath := filepath.Join("testrun", ts.t.Name())
|
|
|
|
dbgPath := filepath.Join(testPath, fmt.Sprintf("client-%d-%s", clientNo, name))
|
|
|
|
dbgConn := debug.Dump(dbgPath, authedConn)
|
|
|
|
pkr := muxrpc.NewPacker(dbgConn)
|
2021-04-22 08:19:03 +00:00
|
|
|
|
2021-04-22 14:19:53 +00:00
|
|
|
var muxMock = new(muxrpc.FakeHandler)
|
|
|
|
wsEndpoint := muxrpc.Handle(pkr, muxMock,
|
|
|
|
muxrpc.WithLogger(log.With(mainLog, "client", name)),
|
|
|
|
muxrpc.WithContext(ts.ctx),
|
|
|
|
)
|
2021-04-22 08:19:03 +00:00
|
|
|
|
|
|
|
srv := wsEndpoint.(muxrpc.Server)
|
|
|
|
ts.serveGroup.Go(func() error {
|
|
|
|
err = srv.Serve()
|
|
|
|
if err != nil {
|
|
|
|
ts.t.Logf("mux server %s error: %v", name, err)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
})
|
|
|
|
|
|
|
|
// check we are talking to a room
|
2021-05-17 07:11:29 +00:00
|
|
|
var meta server.MetadataReply
|
|
|
|
err = wsEndpoint.Async(ts.ctx, &meta, muxrpc.TypeJSON, muxrpc.Method{"tunnel", "isRoom"})
|
2021-04-22 08:19:03 +00:00
|
|
|
r.NoError(err)
|
2021-05-17 07:11:29 +00:00
|
|
|
r.Equal("server", meta.Name)
|
|
|
|
r.True(meta.Membership, "not a member?")
|
2021-04-22 08:19:03 +00:00
|
|
|
|
2021-04-22 10:13:34 +00:00
|
|
|
return testClient{
|
|
|
|
feed: client.Feed,
|
|
|
|
Endpoint: wsEndpoint,
|
|
|
|
mockedHandler: muxMock,
|
|
|
|
}
|
2021-04-22 08:19:03 +00:00
|
|
|
}
|
|
|
|
|
2021-04-20 10:14:24 +00:00
|
|
|
// TODO: refactor for single test session and use makeTestClient()
|
|
|
|
func createServerAndBots(t *testing.T, ctx context.Context, count uint) []*testSession {
|
2021-04-12 13:00:34 +00:00
|
|
|
testInit(t)
|
|
|
|
r := require.New(t)
|
|
|
|
|
|
|
|
appKey := make([]byte, 32)
|
|
|
|
rand.Read(appKey)
|
|
|
|
|
|
|
|
netOpts := []roomsrv.Option{
|
|
|
|
roomsrv.WithAppKey(appKey),
|
|
|
|
roomsrv.WithContext(ctx),
|
|
|
|
}
|
|
|
|
|
2021-04-20 10:14:24 +00:00
|
|
|
theBots := []*testSession{}
|
|
|
|
|
|
|
|
session := makeNamedTestBot(t, "srv", ctx, netOpts)
|
|
|
|
|
|
|
|
theBots = append(theBots, session)
|
2021-04-12 13:00:34 +00:00
|
|
|
|
|
|
|
for i := uint(1); i < count+1; i++ {
|
2021-04-20 10:14:24 +00:00
|
|
|
// TODO: replace with makeClient?!
|
|
|
|
clientSession := makeNamedTestBot(t, fmt.Sprintf("%d", i), ctx, netOpts)
|
|
|
|
theBots = append(theBots, clientSession)
|
2021-04-12 13:00:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
t.Cleanup(func() {
|
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
for _, bot := range theBots {
|
2021-04-20 10:14:24 +00:00
|
|
|
bot.srv.Shutdown()
|
|
|
|
r.NoError(bot.srv.Close())
|
2021-04-12 13:00:34 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
return theBots
|
|
|
|
}
|