waku/v2/protocol/noise/pairing_test.go
package noise
import (
"bytes"
"context"
"crypto/rand"
"sync"
"testing"
"time"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/peerstore"
"github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/require"
n "github.com/waku-org/go-noise"
"github.com/waku-org/go-waku/tests"
"github.com/waku-org/go-waku/waku/v2/protocol/relay"
"github.com/waku-org/go-waku/waku/v2/timesource"
"github.com/waku-org/go-waku/waku/v2/utils"
)
func createRelayNode(t *testing.T) (host.Host, *relay.WakuRelay) {
port, err := tests.FindFreePort(t, "", 5)
require.NoError(t, err)
host, err := tests.MakeHost(context.Background(), port, rand.Reader)
require.NoError(t, err)
b := relay.NewBroadcaster(1024)
require.NoError(t, b.Start(context.Background()))
relay := relay.NewWakuRelay(b, 0, timesource.NewDefaultClock(), prometheus.DefaultRegisterer, utils.Logger())
relay.SetHost(host)
err = relay.Start(context.Background())
require.NoError(t, err)
return host, relay
}
func TestPairingObj1Success(t *testing.T) {
host1, relay1 := createRelayNode(t)
host2, relay2 := createRelayNode(t)
defer host1.Close()
defer host2.Close()
defer relay1.Stop()
defer relay2.Stop()
host1.Peerstore().AddAddr(host2.ID(), tests.GetHostAddress(host2), peerstore.PermanentAddrTTL)
err := host1.Peerstore().AddProtocols(host2.ID(), relay.WakuRelayID_v200)
require.NoError(t, err)
_, err = host1.Network().DialPeer(context.Background(), host2.ID())
require.NoError(t, err)
time.Sleep(2 * time.Second) // Wait for relay to form mesh
bobStaticKey, _ := n.DH25519.GenerateKeypair()
bobEphemeralKey, _ := n.DH25519.GenerateKeypair()
bobMessenger, err := NewWakuRelayMessenger(context.Background(), relay1, nil, timesource.NewDefaultClock())
require.NoError(t, err)
bobPairingObj, err := NewPairing(bobStaticKey, bobEphemeralKey, WithDefaultResponderParameters(), bobMessenger, utils.Logger())
require.NoError(t, err)
authCodeCheckCh := make(chan string, 2)
time.Sleep(1 * time.Second)
wg := sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
// Check that authcodes match
authcode1 := <-authCodeCheckCh
authcode2 := <-authCodeCheckCh
require.Equal(t, authcode1, authcode2)
}()
// Execute in separate go routine
wg.Add(1)
go func() {
defer wg.Done()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
err := bobPairingObj.Execute(ctx)
require.NoError(t, err)
}()
// Confirmation is done by manually
go func() {
authCode := <-bobPairingObj.AuthCode()
authCodeCheckCh <- authCode
err := bobPairingObj.ConfirmAuthCode(true)
require.NoError(t, err)
}()
aliceStaticKey, _ := n.DH25519.GenerateKeypair()
aliceEphemeralKey, _ := n.DH25519.GenerateKeypair()
aliceMessenger, err := NewWakuRelayMessenger(context.Background(), relay2, nil, timesource.NewDefaultClock())
require.NoError(t, err)
qrString, qrMessageNameTag := bobPairingObj.PairingInfo()
alicePairingObj, err := NewPairing(aliceStaticKey, aliceEphemeralKey, WithInitiatorParameters(qrString, qrMessageNameTag), aliceMessenger, utils.Logger())
require.NoError(t, err)
// Execute in separate go routine
wg.Add(1)
go func() {
defer wg.Done()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
err := alicePairingObj.Execute(ctx)
require.NoError(t, err)
}()
// Alice waits for authcode and confirms it
wg.Add(1)
go func() {
defer wg.Done()
authCode := <-alicePairingObj.AuthCode()
authCodeCheckCh <- authCode
err := alicePairingObj.ConfirmAuthCode(true)
require.NoError(t, err)
}()
wg.Wait()
// We test read/write of random messages exchanged between Alice and Bob
// Note that we exchange more than the number of messages contained in the nametag buffer to test if they are filled correctly as the communication proceeds
// We assume messages are sent via one of waku protocols
for i := 0; i < 10*n.MessageNametagBufferSize; i++ {
// Alice writes to Bob
message := generateRandomBytes(t, 32)
msg, err := alicePairingObj.Encrypt(message)
require.NoError(t, err)
readMessage, err := bobPairingObj.Decrypt(msg)
require.NoError(t, err)
require.True(t, bytes.Equal(message, readMessage))
// Bob writes to Alice
message = generateRandomBytes(t, 32)
msg, err = alicePairingObj.Encrypt(message)
require.NoError(t, err)
readMessage, err = bobPairingObj.Decrypt(msg)
require.NoError(t, err)
require.True(t, bytes.Equal(message, readMessage))
}
}
func TestPairingObj1ShouldTimeout(t *testing.T) {
host1, relay1 := createRelayNode(t)
host2, relay2 := createRelayNode(t)
defer host1.Close()
defer host2.Close()
defer relay1.Stop()
defer relay2.Stop()
host1.Peerstore().AddAddr(host2.ID(), tests.GetHostAddress(host2), peerstore.PermanentAddrTTL)
err := host1.Peerstore().AddProtocols(host2.ID(), relay.WakuRelayID_v200)
require.NoError(t, err)
_, err = host1.Network().DialPeer(context.Background(), host2.ID())
require.NoError(t, err)
time.Sleep(2 * time.Second) // Wait for relay to form mesh
bobStaticKey, _ := n.DH25519.GenerateKeypair()
bobEphemeralKey, _ := n.DH25519.GenerateKeypair()
bobMessenger, err := NewWakuRelayMessenger(context.Background(), relay1, nil, timesource.NewDefaultClock())
require.NoError(t, err)
bobPairingObj, err := NewPairing(bobStaticKey, bobEphemeralKey, WithDefaultResponderParameters(), bobMessenger, utils.Logger())
require.NoError(t, err)
aliceStaticKey, _ := n.DH25519.GenerateKeypair()
aliceEphemeralKey, _ := n.DH25519.GenerateKeypair()
aliceMessenger, err := NewWakuRelayMessenger(context.Background(), relay2, nil, timesource.NewDefaultClock())
require.NoError(t, err)
qrString, qrMessageNameTag := bobPairingObj.PairingInfo()
alicePairingObj, err := NewPairing(aliceStaticKey, aliceEphemeralKey, WithInitiatorParameters(qrString, qrMessageNameTag), aliceMessenger, utils.Logger())
require.NoError(t, err)
wg := sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
err := bobPairingObj.Execute(ctx)
require.ErrorIs(t, err, ErrPairingTimeout)
}()
go func() {
defer wg.Done()
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
err := alicePairingObj.Execute(ctx)
require.ErrorIs(t, err, ErrPairingTimeout)
}()
wg.Wait()
}