diff --git a/client/go/outline/client_test.go b/client/go/outline/client_test.go index 67197daddb..24c3f10567 100644 --- a/client/go/outline/client_test.go +++ b/client/go/outline/client_test.go @@ -20,67 +20,70 @@ import ( "github.com/stretchr/testify/require" ) - func Test_NewClientFromJSON_Success(t *testing.T) { tests := []struct { - name string - input string + name string + input string + firstHop string }{ { - name: "SS URL", - input: "ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpTRUNSRVQ@example.com:4321/", + name: "SS URL", + input: "ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpTRUNSRVQ@example.com:4321/", + firstHop: "example.com:4321", }, { - name: "Legacy JSON", - input: -`{ + name: "Legacy JSON", + input: `{ "server": "example.com", "server_port": 4321, "method": "chacha20-ietf-poly1305", "password": "SECRET" }`, - },{ - name: "Flexible JSON", - input: -`{ + firstHop: "example.com:4321", + }, { + name: "Flexible JSON", + input: `{ # Comment server: example.com, server_port: 4321, method: chacha20-ietf-poly1305, password: SECRET }`, - },{ - name: "YAML", - input: -`# Comment + firstHop: "example.com:4321", + }, { + name: "YAML", + input: `# Comment server: example.com server_port: 4321 method: chacha20-ietf-poly1305 password: SECRET`, - },{ - name: "Explicit endpoint", - input: -`$type: ss + firstHop: "example.com:4321", + }, { + name: "Explicit endpoint", + input: `$type: ss endpoint: $type: dial - address: canary.getoutline.org:443 + address: example.com:4321 cipher: chacha20-ietf-poly1305 secret: SECRET`, - },{ - name: "Explicit endpoint", - input: -`$type: ss + firstHop: "example.com:4321", + }, { + name: "Multi-hop", + input: `$type: ss endpoint: $type: dial - address: example.com:4321 - dialer: ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpTRUNSRVQ@example.com:4321/ + address: exit.example.com:4321 + dialer: ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpTRUNSRVQ@entry.example.com:4321/ cipher: chacha20-ietf-poly1305 secret: SECRET`, - }, + firstHop: "entry.example.com:4321", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := NewClient(tt.input) require.Nil(t, result.Error) + require.Equal(t, tt.firstHop, result.Client.Dialer.FirstHop) + require.Equal(t, tt.firstHop, result.Client.PacketListener.FirstHop) }) } } @@ -145,4 +148,3 @@ func Test_NewClientFromJSON_Errors(t *testing.T) { }) } } - diff --git a/client/go/outline/config/shadowsocks.go b/client/go/outline/config/shadowsocks.go index ad5d8de5fc..b2ebf623bd 100644 --- a/client/go/outline/config/shadowsocks.go +++ b/client/go/outline/config/shadowsocks.go @@ -230,7 +230,7 @@ func parseShadowsocksLegacyBase64URL(url url.URL) (*ShadowsocksConfig, error) { return nil, errors.New("invalid cipher info: no ':' separator") } return &ShadowsocksConfig{ - Endpoint: DialEndpointConfig{Address: newURL.Host}, + Endpoint: newURL.Host, Cipher: cipherName, Secret: secret, Prefix: newURL.Query().Get("prefix"), diff --git a/client/go/outline/config/shadowsocks_test.go b/client/go/outline/config/shadowsocks_test.go index c1a44da7b4..3ca6aca3fc 100644 --- a/client/go/outline/config/shadowsocks_test.go +++ b/client/go/outline/config/shadowsocks_test.go @@ -25,7 +25,7 @@ func TestParseShadowsocksURLFullyEncoded(t *testing.T) { encoded := base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString([]byte("aes-256-gcm:1234567@example.com:1234?prefix=HTTP%2F1.1%20")) config, err := parseShadowsocksConfig("ss://" + string(encoded) + "#outline-123") require.NoError(t, err) - require.Equal(t, "example.com:1234", config.Endpoint.(DialEndpointConfig).Address) + require.Equal(t, "example.com:1234", config.Endpoint) require.Equal(t, "HTTP/1.1 ", config.Prefix) } @@ -33,7 +33,7 @@ func TestParseShadowsocksURLUserInfoEncoded(t *testing.T) { encoded := base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString([]byte("aes-256-gcm:1234567")) config, err := parseShadowsocksConfig("ss://" + string(encoded) + "@example.com:1234?prefix=HTTP%2F1.1%20" + "#outline-123") require.NoError(t, err) - require.Equal(t, "example.com:1234", config.Endpoint.(DialEndpointConfig).Address) + require.Equal(t, "example.com:1234", config.Endpoint) require.Equal(t, "HTTP/1.1 ", config.Prefix) } @@ -41,7 +41,7 @@ func TestParseShadowsocksURLUserInfoLegacyEncoded(t *testing.T) { encoded := base64.StdEncoding.EncodeToString([]byte("aes-256-gcm:shadowsocks")) config, err := parseShadowsocksConfig("ss://" + string(encoded) + "@example.com:1234?prefix=HTTP%2F1.1%20" + "#outline-123") require.NoError(t, err) - require.Equal(t, "example.com:1234", config.Endpoint.(DialEndpointConfig).Address) + require.Equal(t, "example.com:1234", config.Endpoint) require.Equal(t, "HTTP/1.1 ", config.Prefix) } @@ -49,14 +49,14 @@ func TestLegacyEncodedShadowsocksURL(t *testing.T) { configString := "ss://YWVzLTEyOC1nY206c2hhZG93c29ja3M=@example.com:1234" config, err := parseShadowsocksConfig(configString) require.NoError(t, err) - require.Equal(t, "example.com:1234", config.Endpoint.(DialEndpointConfig).Address) + require.Equal(t, "example.com:1234", config.Endpoint) } func TestParseShadowsocksURLNoEncoding(t *testing.T) { configString := "ss://aes-256-gcm:1234567@example.com:1234" config, err := parseShadowsocksConfig(configString) require.NoError(t, err) - require.Equal(t, "example.com:1234", config.Endpoint.(DialEndpointConfig).Address) + require.Equal(t, "example.com:1234", config.Endpoint) } func TestParseShadowsocksURLInvalidCipherInfoFails(t *testing.T) { @@ -75,6 +75,6 @@ func TestParseShadowsocksLegacyBase64URL(t *testing.T) { encoded := base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString([]byte("aes-256-gcm:1234567@example.com:1234?prefix=HTTP%2F1.1%20")) config, err := parseShadowsocksConfig("ss://" + string(encoded) + "#outline-123") require.NoError(t, err) - require.Equal(t, "example.com:1234", config.Endpoint.(DialEndpointConfig).Address) + require.Equal(t, "example.com:1234", config.Endpoint) require.Equal(t, "HTTP/1.1 ", config.Prefix) }