oxen-mq/tests/test_address.cpp

132 lines
6.3 KiB
C++

#include "oxenmq/address.h"
#include "common.h"
const std::string pk = "\xf1\x6b\xa5\x59\x10\x39\xf0\x89\xb4\x2a\x83\x41\x75\x09\x30\x94\x07\x4d\x0d\x93\x7a\x79\xe5\x3e\x5c\xe7\x30\xf9\x46\xe1\x4b\x88";
const std::string pk_hex = "f16ba5591039f089b42a834175093094074d0d937a79e53e5ce730f946e14b88";
const std::string pk_HEX = "F16BA5591039F089B42A834175093094074D0D937A79E53E5CE730F946E14B88";
const std::string pk_b32z = "6fi4kseo88aeupbkopyzknjo1odw4dcuxjh6kx1hhhax1tzbjqry";
const std::string pk_B32Z = "6FI4KSEO88AEUPBKOPYZKNJO1ODW4DCUXJH6KX1HHHAX1TZBJQRY";
const std::string pk_b64 = "8WulWRA58Im0KoNBdQkwlAdNDZN6eeU+XOcw+UbhS4g"; // NB: padding '=' omitted
TEST_CASE("tcp addresses", "[address][tcp]") {
address a{"tcp://1.2.3.4:5678"};
REQUIRE( a.host == "1.2.3.4" );
REQUIRE( a.port == 5678 );
REQUIRE_FALSE( a.curve() );
REQUIRE( a.tcp() );
REQUIRE( a.zmq_address() == "tcp://1.2.3.4:5678" );
REQUIRE( a.full_address() == "tcp://1.2.3.4:5678" );
REQUIRE( a.qr_address() == "TCP://1.2.3.4:5678" );
REQUIRE_THROWS_AS( address{"tcp://1:1:1"}, std::invalid_argument );
REQUIRE_THROWS_AS( address{"tcpz://localhost:123"}, std::invalid_argument );
REQUIRE_THROWS_AS( address{"tcp://abc"}, std::invalid_argument );
REQUIRE_THROWS_AS( address{"tcpz://localhost:0"}, std::invalid_argument );
REQUIRE_THROWS_AS( address{"tcpz://[::1:1080"}, std::invalid_argument );
address b = address::tcp("example.com", 80);
REQUIRE( b.host == "example.com" );
REQUIRE( b.port == 80 );
REQUIRE_FALSE( b.curve() );
REQUIRE( b.tcp() );
REQUIRE( b.zmq_address() == "tcp://example.com:80" );
REQUIRE( b.full_address() == "tcp://example.com:80" );
REQUIRE( b.qr_address() == "TCP://EXAMPLE.COM:80" );
address c{"tcp://[::1]:1111"};
REQUIRE( c.host == "[::1]" );
REQUIRE( c.port == 1111 );
}
TEST_CASE("unix sockets", "[address][ipc]") {
address a{"ipc:///path/to/foo"};
REQUIRE( a.socket == "/path/to/foo" );
REQUIRE_FALSE( a.curve() );
REQUIRE_FALSE( a.tcp() );
REQUIRE( a.zmq_address() == "ipc:///path/to/foo" );
REQUIRE( a.full_address() == "ipc:///path/to/foo" );
address b = address::ipc("../foo");
REQUIRE( b.socket == "../foo" );
REQUIRE_FALSE( b.curve() );
REQUIRE_FALSE( b.tcp() );
REQUIRE( b.zmq_address() == "ipc://../foo" );
REQUIRE( b.full_address() == "ipc://../foo" );
}
TEST_CASE("pubkey formats", "[address][curve][pubkey]") {
address a{"tcp+curve://a:1/" + pk_hex};
address b{"curve://a:1/" + pk_b32z};
address c{"curve://a:1/" + pk_b64};
address d{"CURVE://A:1/" + pk_B32Z};
REQUIRE( a.curve() );
REQUIRE( a.host == "a" );
REQUIRE( a.port == 1 );
REQUIRE((b.curve() && c.curve() && d.curve()));
REQUIRE( a.pubkey == pk );
REQUIRE( b.pubkey == pk );
REQUIRE( c.pubkey == pk );
REQUIRE( d.pubkey == pk );
address e{"ipc+curve://my.sock/" + pk_hex};
address f{"ipc+curve://../my.sock/" + pk_b32z};
address g{"ipc+curve:///my.sock/" + pk_B32Z};
address h{"ipc+curve://./my.sock/" + pk_b64};
REQUIRE( e.curve() );
REQUIRE( e.ipc() );
REQUIRE_FALSE( e.tcp() );
REQUIRE((f.curve() && g.curve() && h.curve()));
REQUIRE( e.socket == "my.sock" );
REQUIRE( f.socket == "../my.sock" );
REQUIRE( g.socket == "/my.sock" );
REQUIRE( h.socket == "./my.sock" );
REQUIRE( e.pubkey == pk );
REQUIRE( f.pubkey == pk );
REQUIRE( g.pubkey == pk );
REQUIRE( h.pubkey == pk );
REQUIRE( d.full_address(address::encoding::hex) == "curve://a:1/" + pk_hex );
REQUIRE( c.full_address(address::encoding::base32z) == "curve://a:1/" + pk_b32z );
REQUIRE( b.full_address(address::encoding::BASE32Z) == "curve://a:1/" + pk_B32Z );
REQUIRE( a.full_address(address::encoding::base64) == "curve://a:1/" + pk_b64 );
REQUIRE( h.full_address(address::encoding::hex) == "ipc+curve://./my.sock/" + pk_hex );
REQUIRE( g.full_address(address::encoding::base32z) == "ipc+curve:///my.sock/" + pk_b32z );
REQUIRE( f.full_address(address::encoding::BASE32Z) == "ipc+curve://../my.sock/" + pk_B32Z );
REQUIRE( e.full_address(address::encoding::base64) == "ipc+curve://my.sock/" + pk_b64 );
REQUIRE_THROWS_AS(address{"ipc+curve://my.sock/" + pk_hex.substr(0, 63)}, std::invalid_argument);
REQUIRE_THROWS_AS(address{"ipc+curve://my.sock/" + pk_b32z.substr(0, 51)}, std::invalid_argument);
REQUIRE_THROWS_AS(address{"ipc+curve://my.sock/" + pk_B32Z.substr(0, 51)}, std::invalid_argument);
REQUIRE_THROWS_AS(address{"ipc+curve://my.sock/" + pk_b64.substr(0, 42)}, std::invalid_argument);
REQUIRE_THROWS_AS(address{"ipc+curve://my.sock"}, std::invalid_argument);
REQUIRE_THROWS_AS(address{"ipc+curve://my.sock/"}, std::invalid_argument);
}
TEST_CASE("tcp QR-code friendly addresses", "[address][tcp][qr]") {
address a{"tcp://public.loki.foundation:12345"};
address a_qr{"TCP://PUBLIC.LOKI.FOUNDATION:12345"};
address b{"tcp://PUBLIC.LOKI.FOUNDATION:12345"};
REQUIRE( a == a_qr );
REQUIRE( a != b );
REQUIRE( a.host == "public.loki.foundation" );
REQUIRE( a.qr_address() == "TCP://PUBLIC.LOKI.FOUNDATION:12345" );
address c = address::tcp_curve("public.loki.foundation", 12345, pk);
REQUIRE( c.qr_address() == "CURVE://PUBLIC.LOKI.FOUNDATION:12345/" + pk_B32Z );
REQUIRE( address{"CURVE://PUBLIC.LOKI.FOUNDATION:12345/" + pk_B32Z} == c );
// We don't produce with upper-case hex, but we accept it:
REQUIRE( address{"CURVE://PUBLIC.LOKI.FOUNDATION:12345/" + pk_HEX} == c );
// lower case not permitted: ▾
REQUIRE_THROWS_AS(address{"CURVE://PUBLIC.LOKI.FOUNDATiON:12345/" + pk_B32Z}, std::invalid_argument);
// also only accept upper-base base32z and hex:
REQUIRE_THROWS_AS(address{"CURVE://PUBLIC.LOKI.FOUNDATION:12345/" + pk_b32z}, std::invalid_argument);
REQUIRE_THROWS_AS(address{"CURVE://PUBLIC.LOKI.FOUNDATION:12345/" + pk_hex}, std::invalid_argument);
// don't accept base64 even if it's upper-case (because case-converting it changes the value)
REQUIRE_THROWS_AS(address{"CURVE://PUBLIC.LOKI.FOUNDATION:12345/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}, std::invalid_argument);
REQUIRE_THROWS_AS(address{"CURVE://PUBLIC.LOKI.FOUNDATION:12345/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="}, std::invalid_argument);
}