2021-10-08 12:39:31 +00:00
|
|
|
// SPDX-FileCopyrightText: 2021 The NGI Pointer Secure-Scuttlebutt Team of 2020/2021
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
2021-04-05 09:33:28 +00:00
|
|
|
package go_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/base64"
|
|
|
|
"encoding/json"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/gorilla/websocket"
|
2022-11-07 09:18:13 +00:00
|
|
|
"github.com/ssbc/go-muxrpc/v2"
|
|
|
|
"github.com/ssbc/go-muxrpc/v2/debug"
|
|
|
|
"github.com/ssbc/go-secretstream"
|
2021-04-05 09:33:28 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2021-05-17 07:11:29 +00:00
|
|
|
"go.mindeco.de/encodedTime"
|
2021-04-05 09:33:28 +00:00
|
|
|
|
2022-11-07 09:18:13 +00:00
|
|
|
"github.com/ssbc/go-ssb-room/v2/internal/maybemod/keys"
|
|
|
|
"github.com/ssbc/go-ssb-room/v2/internal/network"
|
|
|
|
tunserv "github.com/ssbc/go-ssb-room/v2/muxrpc/handlers/tunnel/server"
|
|
|
|
"github.com/ssbc/go-ssb-room/v2/roomdb"
|
2021-04-05 09:33:28 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestWebsocketDialing(t *testing.T) {
|
|
|
|
r := require.New(t)
|
|
|
|
|
|
|
|
testPath := filepath.Join("testrun", t.Name())
|
|
|
|
os.RemoveAll(testPath)
|
|
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
|
|
t.Cleanup(cancel)
|
|
|
|
|
|
|
|
// create the roomsrv
|
2021-04-20 10:14:24 +00:00
|
|
|
session := makeNamedTestBot(t, "server", ctx, nil)
|
|
|
|
server := session.srv
|
2021-04-05 09:33:28 +00:00
|
|
|
|
|
|
|
// open a TCP listener for HTTP
|
|
|
|
l, err := net.Listen("tcp4", "localhost:0")
|
|
|
|
r.NoError(err)
|
|
|
|
|
|
|
|
var fh = failHandler{t: t}
|
|
|
|
|
|
|
|
// serve the websocket handler
|
|
|
|
handler := server.Network.WebsockHandler(fh)
|
|
|
|
go http.Serve(l, handler)
|
|
|
|
|
|
|
|
// create a fresh keypair for the client
|
|
|
|
client, err := keys.NewKeyPair(nil)
|
|
|
|
r.NoError(err)
|
|
|
|
|
|
|
|
// add it as a memeber
|
2021-04-20 10:14:24 +00:00
|
|
|
memberID, err := server.Members.Add(ctx, client.Feed, roomdb.RoleMember)
|
2021-04-05 09:33:28 +00:00
|
|
|
r.NoError(err)
|
|
|
|
t.Log("client member:", memberID)
|
|
|
|
|
|
|
|
// construct the websocket http address
|
|
|
|
var wsURL url.URL
|
|
|
|
wsURL.Scheme = "ws"
|
|
|
|
wsURL.Host = l.Addr().String()
|
|
|
|
wsURL.Path = "/"
|
|
|
|
|
|
|
|
// create a websocket connection
|
|
|
|
conn, resp, err := websocket.DefaultDialer.DialContext(ctx, wsURL.String(), nil)
|
|
|
|
r.NoError(err)
|
|
|
|
t.Log(resp.Status)
|
|
|
|
r.Equal(http.StatusSwitchingProtocols, resp.StatusCode)
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
|
|
|
|
// the returned wrapper: func(net.Conn) (net.Conn, error)
|
|
|
|
// returns a new connection that went through shs and does boxstream
|
|
|
|
connAuther := clientSHS.ConnWrapper(server.Whoami().PubKey())
|
|
|
|
|
|
|
|
// turn a websocket conn into a net.Conn
|
|
|
|
wrappedConn := network.NewWebsockConn(conn)
|
|
|
|
|
|
|
|
authedConn, err := connAuther(wrappedConn)
|
|
|
|
r.NoError(err)
|
|
|
|
|
|
|
|
var muxMock muxrpc.FakeHandler
|
|
|
|
|
|
|
|
debugConn := debug.Dump(filepath.Join(testPath, "client"), authedConn)
|
|
|
|
pkr := muxrpc.NewPacker(debugConn)
|
|
|
|
|
|
|
|
wsEndpoint := muxrpc.Handle(pkr, &muxMock, muxrpc.WithContext(ctx))
|
|
|
|
|
|
|
|
srv := wsEndpoint.(muxrpc.Server)
|
|
|
|
go func() {
|
|
|
|
err = srv.Serve()
|
|
|
|
r.NoError(err)
|
|
|
|
t.Log("mux server error:", err)
|
|
|
|
}()
|
|
|
|
|
|
|
|
// check we are talking to a room
|
2021-05-17 07:11:29 +00:00
|
|
|
var meta tunserv.MetadataReply
|
|
|
|
err = wsEndpoint.Async(ctx, &meta, muxrpc.TypeJSON, muxrpc.Method{"tunnel", "isRoom"})
|
2021-04-05 09:33:28 +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-05 09:33:28 +00:00
|
|
|
|
|
|
|
// open the gossip.ping channel
|
|
|
|
src, snk, err := wsEndpoint.Duplex(ctx, muxrpc.TypeJSON, muxrpc.Method{"gossip", "ping"})
|
|
|
|
r.NoError(err)
|
|
|
|
|
|
|
|
pingTS := encodedTime.NewMillisecs(time.Now().Unix())
|
|
|
|
err = json.NewEncoder(snk).Encode(pingTS)
|
|
|
|
r.NoError(err)
|
|
|
|
|
|
|
|
r.True(src.Next(ctx))
|
|
|
|
pong, err := src.Bytes()
|
|
|
|
r.NoError(err)
|
|
|
|
|
|
|
|
var pongTS encodedTime.Millisecs
|
|
|
|
err = json.Unmarshal(pong, &pongTS)
|
|
|
|
r.NoError(err)
|
|
|
|
r.False(time.Time(pongTS).IsZero())
|
|
|
|
}
|
|
|
|
|
|
|
|
type failHandler struct {
|
|
|
|
t *testing.T
|
|
|
|
}
|
|
|
|
|
|
|
|
func (fh failHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|
|
|
fh.t.Error("next handler called", req.URL.String())
|
|
|
|
}
|