waku-org/go-waku

View on GitHub
waku/v2/protocol/noise/pairing_test.go

Summary

Maintainability
A
2 hrs
Test Coverage
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()
}