Kaynağa Gözat

Add tests for access command

tags/v2.0.0-rc1
9seconds 5 yıl önce
ebeveyn
işleme
185baf6bc9
8 değiştirilmiş dosya ile 252 ekleme ve 29 silme
  1. 25
    13
      cli/access.go
  2. 205
    0
      cli/access_test.go
  3. 4
    4
      cli/base.go
  4. 3
    3
      cli/cli.go
  5. 3
    3
      cli/generate_secret.go
  6. 3
    2
      go.mod
  7. 8
    2
      go.sum
  8. 1
    2
      main.go

+ 25
- 13
cli/access.go Dosyayı Görüntüle

@@ -26,6 +26,7 @@ type accessResponse struct {
26 26
 
27 27
 type accessResponseURLs struct {
28 28
 	IP        net.IP `json:"ip"`
29
+	Port      uint   `json:"port"`
29 30
 	TgURL     string `json:"tg_url"`
30 31
 	TgQrCode  string `json:"tg_qrcode"`
31 32
 	TmeURL    string `json:"tme_url"`
@@ -33,10 +34,11 @@ type accessResponseURLs struct {
33 34
 }
34 35
 
35 36
 type Access struct {
36
-	base
37
+	base `kong:"-"`
37 38
 
38
-	ConfigPath string `arg required type:"existingfile" help:"Path to the configuration file." name:"config-path"` // nolint: lll, govet
39
-	Hex        bool   `help:"Print secret in hex encoding."`
39
+	ConfigPath string `kong:"arg,required,type='existingfile',help='Path to the configuration file.',name='config-path'"` // nolint: lll
40
+	Port       uint   `kong:"help='Port number. Default port is taken from configuration file, bind-to parameter',type:'uint'"`
41
+	Hex        bool   `kong:"help='Print secret in hex encoding.'"`
40 42
 }
41 43
 
42 44
 func (c *Access) Run(cli *CLI, version string) error {
@@ -44,9 +46,13 @@ func (c *Access) Run(cli *CLI, version string) error {
44 46
 		return fmt.Errorf("cannot init config: %w", err)
45 47
 	}
46 48
 
49
+	return c.Execute(cli)
50
+}
51
+
52
+func (c *Access) Execute(cli *CLI) error {
47 53
 	resp := &accessResponse{}
48
-	resp.Secret.Base64 = c.conf.Secret.Base64()
49
-	resp.Secret.Hex = c.conf.Secret.Hex()
54
+	resp.Secret.Base64 = c.Config.Secret.Base64()
55
+	resp.Secret.Hex = c.Config.Secret.Hex()
50 56
 
51 57
 	wg := &sync.WaitGroup{}
52 58
 	wg.Add(2) // nolint: gomnd
@@ -54,7 +60,7 @@ func (c *Access) Run(cli *CLI, version string) error {
54 60
 	go func() {
55 61
 		defer wg.Done()
56 62
 
57
-		ip := c.conf.Network.PublicIP.IPv4.Value(nil)
63
+		ip := c.Config.Network.PublicIP.IPv4.Value(nil)
58 64
 		if ip == nil {
59 65
 			ip = c.getIP("tcp4")
60 66
 		}
@@ -69,7 +75,7 @@ func (c *Access) Run(cli *CLI, version string) error {
69 75
 	go func() {
70 76
 		defer wg.Done()
71 77
 
72
-		ip := c.conf.Network.PublicIP.IPv4.Value(nil)
78
+		ip := c.Config.Network.PublicIP.IPv6.Value(nil)
73 79
 		if ip == nil {
74 80
 			ip = c.getIP("tcp6")
75 81
 		}
@@ -95,8 +101,8 @@ func (c *Access) Run(cli *CLI, version string) error {
95 101
 }
96 102
 
97 103
 func (c *Access) getIP(protocol string) net.IP {
98
-	client := c.network.MakeHTTPClient(func(ctx context.Context, network, address string) (net.Conn, error) {
99
-		return c.network.DialContext(ctx, protocol, address)
104
+	client := c.Network.MakeHTTPClient(func(ctx context.Context, network, address string) (net.Conn, error) {
105
+		return c.Network.DialContext(ctx, protocol, address)
100 106
 	})
101 107
 
102 108
 	req, err := http.NewRequest(http.MethodGet, "https://ifconfig.co", nil) // nolint: noctx
@@ -133,20 +139,26 @@ func (c *Access) makeURLs(ip net.IP, cli *CLI) *accessResponseURLs {
133 139
 		return nil
134 140
 	}
135 141
 
142
+	portNo := cli.Access.Port
143
+	if portNo == 0 {
144
+		portNo = c.Config.BindTo.PortValue(0)
145
+	}
146
+
136 147
 	values := url.Values{}
137 148
 	values.Set("server", ip.String())
138
-	values.Set("port", strconv.Itoa(int(c.conf.BindTo.PortValue(0))))
149
+	values.Set("port", strconv.Itoa(int(portNo)))
139 150
 
140 151
 	if cli.Access.Hex {
141
-		values.Set("secret", c.conf.Secret.Hex())
152
+		values.Set("secret", c.Config.Secret.Hex())
142 153
 	} else {
143
-		values.Set("secret", c.conf.Secret.Base64())
154
+		values.Set("secret", c.Config.Secret.Base64())
144 155
 	}
145 156
 
146 157
 	urlQuery := values.Encode()
147 158
 
148 159
 	rv := &accessResponseURLs{
149
-		IP: ip,
160
+		IP:   ip,
161
+		Port: portNo,
150 162
 		TgURL: (&url.URL{
151 163
 			Scheme:   "tg",
152 164
 			Host:     "proxy",

+ 205
- 0
cli/access_test.go Dosyayı Görüntüle

@@ -0,0 +1,205 @@
1
+package cli_test
2
+
3
+import (
4
+	"net/http"
5
+	"testing"
6
+
7
+	"github.com/9seconds/mtg/v2/config"
8
+	"github.com/9seconds/mtg/v2/mtglib"
9
+	"github.com/jarcoal/httpmock"
10
+	"github.com/stretchr/testify/suite"
11
+	"github.com/xeipuuv/gojsonschema"
12
+)
13
+
14
+var accressResponseJSONSchema = func() *gojsonschema.Schema {
15
+	schema, err := gojsonschema.NewSchema(gojsonschema.NewStringLoader(`
16
+{
17
+    "type": "object",
18
+    "required": ["secret"],
19
+    "additionalProperties": true,
20
+    "properties": {
21
+        "secret": {
22
+            "type": "object",
23
+            "required": [
24
+                "hex",
25
+                "base64"
26
+            ],
27
+            "additionalProperties": false,
28
+            "properties": {
29
+                "hex": {
30
+                    "type": "string",
31
+                    "minLength": 34
32
+                },
33
+                "base64": {
34
+                    "type": "string",
35
+                    "minLength": 10
36
+                }
37
+            }
38
+        },
39
+        "ipv4": {
40
+            "$ref": "#/definitions/ip"
41
+        },
42
+        "ipv6": {
43
+            "$ref": "#/definitions/ip"
44
+        }
45
+    },
46
+    "definitions": {
47
+        "ip": {
48
+            "type": "object",
49
+            "required": [
50
+                "ip",
51
+                "port",
52
+                "tg_url",
53
+                "tg_qrcode",
54
+                "tme_url",
55
+                "tme_qrcode"
56
+            ],
57
+            "additionalProperties": false,
58
+            "properties": {
59
+                "ip": {
60
+                    "type": "string",
61
+                    "minLength": 1,
62
+                    "anyOf": [
63
+                        {
64
+                            "format": "ipv4"
65
+                        },
66
+                        {
67
+                            "format": "ipv6"
68
+                        }
69
+                    ]
70
+                },
71
+                "port": {
72
+                    "type": "integer",
73
+                    "multipleOf": 1.0,
74
+                    "exclusiveMinimum": 0,
75
+                    "exclusiveMaximum": 65536
76
+                },
77
+                "tg_url": {
78
+                    "type": "string",
79
+                    "minLength": 1,
80
+                    "format": "uri"
81
+                },
82
+                "tg_qrcode": {
83
+                    "type": "string",
84
+                    "minLength": 1,
85
+                    "format": "uri"
86
+                },
87
+                "tme_url": {
88
+                    "type": "string",
89
+                    "minLength": 1,
90
+                    "format": "uri"
91
+                },
92
+                "tme_qrcode": {
93
+                    "type": "string",
94
+                    "minLength": 1,
95
+                    "format": "uri"
96
+                }
97
+            }
98
+        }
99
+    }
100
+}
101
+    `))
102
+
103
+	if err != nil {
104
+		panic(err)
105
+	}
106
+
107
+	return schema
108
+}()
109
+
110
+type AccessTestSuite struct {
111
+	CommonTestSuite
112
+}
113
+
114
+func (suite *AccessTestSuite) SetupTest() {
115
+	suite.CommonTestSuite.SetupTest()
116
+
117
+	suite.cli.Access.Config = &config.Config{}
118
+	suite.cli.Access.Config.Secret = mtglib.GenerateSecret("google.com")
119
+	suite.cli.Access.Network = suite.networkMock
120
+
121
+	suite.NoError(
122
+		suite.cli.Access.Config.BindTo.UnmarshalText([]byte("0.0.0.0:80")))
123
+}
124
+
125
+func (suite *AccessTestSuite) TestGenerateNoCalls() {
126
+	suite.NoError(
127
+		suite.cli.Access.Config.Network.PublicIP.IPv4.UnmarshalText(
128
+			[]byte("10.0.0.10")))
129
+	suite.NoError(
130
+		suite.cli.Access.Config.Network.PublicIP.IPv6.UnmarshalText(
131
+			[]byte("2001:0db8:85a3:0000:0000:8a2e:0370:7334")))
132
+
133
+	output := suite.CaptureStdout(func() {
134
+		suite.NoError(suite.cli.Access.Execute(suite.cli))
135
+	})
136
+
137
+	validated, err := accressResponseJSONSchema.Validate(
138
+		gojsonschema.NewStringLoader(output))
139
+	suite.NoError(err)
140
+	suite.Empty(validated.Errors())
141
+	suite.True(validated.Valid())
142
+
143
+	suite.Contains(output, "10.0.0.10")
144
+	suite.Contains(output, "2001:db8:85a3::8a2e:370:7334")
145
+	suite.Contains(output, "ipv4")
146
+	suite.Contains(output, "ipv6")
147
+	suite.Contains(output, suite.cli.Access.Config.Secret.Base64())
148
+	suite.Contains(output, suite.cli.Access.Config.Secret.Hex())
149
+}
150
+
151
+func (suite *AccessTestSuite) TestGenerateIPv4Call() {
152
+	suite.NoError(
153
+		suite.cli.Access.Config.Network.PublicIP.IPv6.UnmarshalText(
154
+			[]byte("2001:0db8:85a3:0000:0000:8a2e:0370:7334")))
155
+
156
+	httpmock.RegisterResponder(http.MethodGet, "https://ifconfig.co",
157
+		httpmock.NewStringResponder(http.StatusOK, "10.11.12.13"))
158
+
159
+	output := suite.CaptureStdout(func() {
160
+		suite.NoError(suite.cli.Access.Execute(suite.cli))
161
+	})
162
+
163
+	validated, err := accressResponseJSONSchema.Validate(
164
+		gojsonschema.NewStringLoader(output))
165
+	suite.NoError(err)
166
+	suite.Empty(validated.Errors())
167
+	suite.True(validated.Valid())
168
+
169
+	suite.Contains(output, "10.11.12.13")
170
+	suite.Contains(output, "2001:db8:85a3::8a2e:370:7334")
171
+	suite.Contains(output, "ipv4")
172
+	suite.Contains(output, "ipv6")
173
+	suite.Contains(output, suite.cli.Access.Config.Secret.Base64())
174
+	suite.Contains(output, suite.cli.Access.Config.Secret.Hex())
175
+}
176
+
177
+func (suite *AccessTestSuite) TestIPv4CallFail() {
178
+	suite.NoError(
179
+		suite.cli.Access.Config.Network.PublicIP.IPv6.UnmarshalText(
180
+			[]byte("2001:0db8:85a3:0000:0000:8a2e:0370:7334")))
181
+
182
+	httpmock.RegisterResponder(http.MethodGet, "https://ifconfig.co",
183
+		httpmock.NewStringResponder(http.StatusForbidden, ""))
184
+
185
+	output := suite.CaptureStdout(func() {
186
+		suite.NoError(suite.cli.Access.Execute(suite.cli))
187
+	})
188
+
189
+	validated, err := accressResponseJSONSchema.Validate(
190
+		gojsonschema.NewStringLoader(output))
191
+	suite.NoError(err)
192
+	suite.Empty(validated.Errors())
193
+	suite.True(validated.Valid())
194
+
195
+	suite.Contains(output, "2001:db8:85a3::8a2e:370:7334")
196
+	suite.NotContains(output, "ipv4")
197
+	suite.Contains(output, "ipv6")
198
+	suite.Contains(output, suite.cli.Access.Config.Secret.Base64())
199
+	suite.Contains(output, suite.cli.Access.Config.Secret.Hex())
200
+}
201
+
202
+func TestAccess(t *testing.T) {
203
+	t.Parallel()
204
+	suite.Run(t, &AccessTestSuite{})
205
+}

+ 4
- 4
cli/base.go Dosyayı Görüntüle

@@ -11,8 +11,8 @@ import (
11 11
 )
12 12
 
13 13
 type base struct {
14
-	network network.Network
15
-	conf    *config.Config
14
+	Network network.Network
15
+	Config  *config.Config
16 16
 }
17 17
 
18 18
 func (b *base) ReadConfig(path, version string) error {
@@ -31,8 +31,8 @@ func (b *base) ReadConfig(path, version string) error {
31 31
 		return fmt.Errorf("cannot build a network: %w", err)
32 32
 	}
33 33
 
34
-	b.conf = conf
35
-	b.network = ntw
34
+	b.Config = conf
35
+	b.Network = ntw
36 36
 
37 37
 	return nil
38 38
 }

+ 3
- 3
cli/cli.go Dosyayı Görüntüle

@@ -3,7 +3,7 @@ package cli
3 3
 import "github.com/alecthomas/kong"
4 4
 
5 5
 type CLI struct {
6
-	GenerateSecret GenerateSecret   `cmd help:"Generate new proxy secret"` // nolint: govet
7
-	Access         Access           `cmd help:"Print access information."` // nolint: govet
8
-	Version        kong.VersionFlag `help:"Print version."`
6
+	GenerateSecret GenerateSecret   `kong:"cmd,help='Generate new proxy secret'"` // nolint: govet
7
+	Access         Access           `kong:"cmd,help='Print access information.'"` // nolint: govet
8
+	Version        kong.VersionFlag `kong:"help='Print version.'"`
9 9
 }

+ 3
- 3
cli/generate_secret.go Dosyayı Görüntüle

@@ -7,10 +7,10 @@ import (
7 7
 )
8 8
 
9 9
 type GenerateSecret struct {
10
-	base
10
+    base `kong:"-"`
11 11
 
12
-	HostName string `arg optional help:"Hostname to use for domain fronting. Default is '${domain_front}'." name:"hostname" default:"${domain_front}"` // nolint: lll, govet
13
-	Hex      bool   `help:"Print secret in hex encoding."`
12
+	HostName string `kong:"arg,required,help='Hostname to use for domain fronting.',name='hostname'"` // nolint: lll, govet
13
+	Hex      bool   `kong:"help='Print secret in hex encoding.'"`
14 14
 }
15 15
 
16 16
 func (c *GenerateSecret) Run(cli *CLI, _ string) error {

+ 3
- 2
go.mod Dosyayı Görüntüle

@@ -7,14 +7,15 @@ require (
7 7
 	github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15
8 8
 	github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
9 9
 	github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6
10
-	github.com/jarcoal/httpmock v1.0.8 // indirect
10
+	github.com/jarcoal/httpmock v1.0.8
11 11
 	github.com/kr/pretty v0.1.0 // indirect
12 12
 	github.com/libp2p/go-reuseport v0.0.2
13 13
 	github.com/mccutchen/go-httpbin v1.1.1
14 14
 	github.com/pelletier/go-toml v1.8.1
15 15
 	github.com/stretchr/objx v0.3.0 // indirect
16 16
 	github.com/stretchr/testify v1.7.0
17
+	github.com/xeipuuv/gojsonschema v1.2.0
17 18
 	golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
18
-	golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 // indirect
19
+	golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 // indirect
19 20
 	gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
20 21
 )

+ 8
- 2
go.sum Dosyayı Görüntüle

@@ -36,12 +36,18 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
36 36
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
37 37
 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
38 38
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
39
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
40
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
41
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
42
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
43
+github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
44
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
39 45
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
40 46
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
41 47
 golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
42 48
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
43
-golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
44
-golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
49
+golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY=
50
+golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
45 51
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
46 52
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
47 53
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

+ 1
- 2
main.go Dosyayı Görüntüle

@@ -15,8 +15,7 @@ func main() {
15 15
 
16 16
 	cli := &cli.CLI{}
17 17
 	ctx := kong.Parse(cli, kong.Vars{
18
-		"domain_front": "amazonaws.com",
19
-		"version":      version,
18
+		"version": version,
20 19
 	})
21 20
 
22 21
 	ctx.FatalIfErrorf(ctx.Run(cli, version))

Loading…
İptal
Kaydet