haveapi-go-client 0.27.3 → 0.28.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/haveapi-go-client.gemspec +1 -1
- data/lib/haveapi/go_client/action.rb +7 -3
- data/lib/haveapi/go_client/erb_template.rb +3 -0
- data/lib/haveapi/go_client/generator.rb +5 -2
- data/lib/haveapi/go_client/resource.rb +7 -2
- data/lib/haveapi/go_client/utils.rb +101 -1
- data/lib/haveapi/go_client/version.rb +1 -1
- data/spec/integration/generator_spec.rb +763 -2
- data/template/action.go.erb +74 -73
- data/template/authentication/oauth2.go.erb +20 -8
- data/template/authentication/token.go.erb +10 -10
- data/template/client.go.erb +42 -2
- data/template/request.go.erb +170 -8
- data/template/resource.go.erb +3 -3
- metadata +3 -4
- data/shell.nix +0 -23
data/template/request.go.erb
CHANGED
|
@@ -3,17 +3,180 @@ package <%= package %>
|
|
|
3
3
|
import (
|
|
4
4
|
"bytes"
|
|
5
5
|
"encoding/json"
|
|
6
|
+
"fmt"
|
|
6
7
|
"io/ioutil"
|
|
7
8
|
"net/http"
|
|
9
|
+
"net/url"
|
|
10
|
+
"strings"
|
|
8
11
|
)
|
|
9
12
|
|
|
13
|
+
func (client *Client) actionURL(path string) (string, error) {
|
|
14
|
+
if !strings.HasPrefix(path, "/") || strings.HasPrefix(path, "//") {
|
|
15
|
+
return "", fmt.Errorf("unsafe API action path %q", path)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
ref, err := url.Parse(path)
|
|
19
|
+
if err != nil {
|
|
20
|
+
return "", err
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if ref.IsAbs() || ref.Host != "" || ref.User != nil {
|
|
24
|
+
return "", fmt.Errorf("unsafe API action path %q", path)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return client.sameOriginURL(client.Url + path)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
func (client *Client) descriptionURL(rawURL string) (string, error) {
|
|
31
|
+
return client.descriptionURLWithTrustedOrigins(rawURL, nil)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
func (client *Client) oauth2DescriptionURL(rawURL string) (string, error) {
|
|
35
|
+
return client.descriptionURLWithTrustedOrigins(rawURL, client.oauth2TrustedOrigins)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// AllowOAuth2Origin permits OAuth2 endpoints from an additional trusted origin.
|
|
39
|
+
func (client *Client) AllowOAuth2Origin(rawOrigin string) error {
|
|
40
|
+
origin, err := parseTrustedOrigin(rawOrigin)
|
|
41
|
+
if err != nil {
|
|
42
|
+
return err
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if client.oauth2TrustedOrigins == nil {
|
|
46
|
+
client.oauth2TrustedOrigins = make(map[string]struct{})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
client.oauth2TrustedOrigins[origin] = struct{}{}
|
|
50
|
+
return nil
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
func (client *Client) descriptionURLWithTrustedOrigins(rawURL string, trustedOrigins map[string]struct{}) (string, error) {
|
|
54
|
+
base, err := client.parsedBaseURL()
|
|
55
|
+
if err != nil {
|
|
56
|
+
return "", err
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
ref, err := url.Parse(rawURL)
|
|
60
|
+
if err != nil {
|
|
61
|
+
return "", err
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if ref.User != nil {
|
|
65
|
+
return "", fmt.Errorf("unsafe API description URL %q", rawURL)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if ref.Host != "" && ref.Scheme == "" {
|
|
69
|
+
return "", fmt.Errorf("unsafe API description URL %q", rawURL)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
resolved := base.ResolveReference(ref)
|
|
73
|
+
if !sameOrigin(base, resolved) && !originAllowed(resolved, trustedOrigins) {
|
|
74
|
+
return "", fmt.Errorf("API description URL %q is outside client origin", rawURL)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return resolved.String(), nil
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
func (client *Client) sameOriginURL(rawURL string) (string, error) {
|
|
81
|
+
base, err := client.parsedBaseURL()
|
|
82
|
+
if err != nil {
|
|
83
|
+
return "", err
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
resolved, err := url.Parse(rawURL)
|
|
87
|
+
if err != nil {
|
|
88
|
+
return "", err
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if !sameOrigin(base, resolved) {
|
|
92
|
+
return "", fmt.Errorf("request URL %q is outside client origin", rawURL)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return resolved.String(), nil
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
func (client *Client) parsedBaseURL() (*url.URL, error) {
|
|
99
|
+
base, err := url.Parse(client.Url)
|
|
100
|
+
if err != nil {
|
|
101
|
+
return nil, err
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if base.Scheme == "" || base.Host == "" {
|
|
105
|
+
return nil, fmt.Errorf("invalid client URL %q", client.Url)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return base, nil
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
func sameOrigin(a *url.URL, b *url.URL) bool {
|
|
112
|
+
return strings.EqualFold(a.Scheme, b.Scheme) &&
|
|
113
|
+
strings.EqualFold(a.Hostname(), b.Hostname()) &&
|
|
114
|
+
originPort(a) == originPort(b)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
func originAllowed(u *url.URL, trustedOrigins map[string]struct{}) bool {
|
|
118
|
+
if len(trustedOrigins) == 0 {
|
|
119
|
+
return false
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
_, ok := trustedOrigins[originKey(u)]
|
|
123
|
+
return ok
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
func parseTrustedOrigin(rawOrigin string) (string, error) {
|
|
127
|
+
if rawOrigin == "" || strings.ContainsAny(rawOrigin, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\\") {
|
|
128
|
+
return "", fmt.Errorf("invalid trusted OAuth2 origin %q", rawOrigin)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
parsed, err := url.Parse(rawOrigin)
|
|
132
|
+
if err != nil {
|
|
133
|
+
return "", err
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if parsed.Scheme == "" || parsed.Host == "" || parsed.User != nil ||
|
|
137
|
+
(parsed.Path != "" && parsed.Path != "/") ||
|
|
138
|
+
parsed.RawQuery != "" || parsed.Fragment != "" {
|
|
139
|
+
return "", fmt.Errorf("invalid trusted OAuth2 origin %q", rawOrigin)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return originKey(parsed), nil
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
func originKey(u *url.URL) string {
|
|
146
|
+
host := strings.ToLower(u.Hostname())
|
|
147
|
+
if strings.Contains(host, ":") {
|
|
148
|
+
host = "[" + host + "]"
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return strings.ToLower(u.Scheme) + "://" + host + ":" + originPort(u)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
func originPort(u *url.URL) string {
|
|
155
|
+
port := u.Port()
|
|
156
|
+
if port != "" {
|
|
157
|
+
return port
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
switch strings.ToLower(u.Scheme) {
|
|
161
|
+
case "http":
|
|
162
|
+
return "80"
|
|
163
|
+
case "https":
|
|
164
|
+
return "443"
|
|
165
|
+
default:
|
|
166
|
+
return ""
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
10
170
|
// DoQueryStringRequests makes a HTTP requests in which input parameters are
|
|
11
171
|
// sent as query parameters.
|
|
12
172
|
func (client *Client) DoQueryStringRequest(path string, queryParams map[string]string, output interface{}) error {
|
|
13
|
-
|
|
14
|
-
|
|
173
|
+
requestURL, err := client.actionURL(path)
|
|
174
|
+
|
|
175
|
+
if err != nil {
|
|
176
|
+
return err
|
|
177
|
+
}
|
|
15
178
|
|
|
16
|
-
req, err := http.NewRequest("GET",
|
|
179
|
+
req, err := http.NewRequest("GET", requestURL, nil)
|
|
17
180
|
|
|
18
181
|
if err != nil {
|
|
19
182
|
return err
|
|
@@ -31,7 +194,7 @@ func (client *Client) DoQueryStringRequest(path string, queryParams map[string]s
|
|
|
31
194
|
|
|
32
195
|
req.URL.RawQuery = q.Encode()
|
|
33
196
|
|
|
34
|
-
resp, err :=
|
|
197
|
+
resp, err := client.do(req)
|
|
35
198
|
|
|
36
199
|
if err != nil {
|
|
37
200
|
return err
|
|
@@ -54,8 +217,7 @@ func (client *Client) DoQueryStringRequest(path string, queryParams map[string]s
|
|
|
54
217
|
// DoBodyRequest makes a HTTP requests in which the input parameters are sent
|
|
55
218
|
// within the request body, encoded in JSON.
|
|
56
219
|
func (client *Client) DoBodyRequest(method string, path string, params interface{}, output interface{}) error {
|
|
57
|
-
|
|
58
|
-
url := client.Url + path
|
|
220
|
+
requestURL, err := client.actionURL(path)
|
|
59
221
|
|
|
60
222
|
jsonData, err := json.Marshal(params)
|
|
61
223
|
|
|
@@ -63,7 +225,7 @@ func (client *Client) DoBodyRequest(method string, path string, params interface
|
|
|
63
225
|
return err
|
|
64
226
|
}
|
|
65
227
|
|
|
66
|
-
req, err := http.NewRequest(method,
|
|
228
|
+
req, err := http.NewRequest(method, requestURL, bytes.NewBuffer(jsonData))
|
|
67
229
|
|
|
68
230
|
if err != nil {
|
|
69
231
|
return err
|
|
@@ -75,7 +237,7 @@ func (client *Client) DoBodyRequest(method string, path string, params interface
|
|
|
75
237
|
client.Authentication.Authenticate(req)
|
|
76
238
|
}
|
|
77
239
|
|
|
78
|
-
resp, err :=
|
|
240
|
+
resp, err := client.do(req)
|
|
79
241
|
|
|
80
242
|
if err != nil {
|
|
81
243
|
return err
|
data/template/resource.go.erb
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
package <%= package %>
|
|
2
2
|
|
|
3
|
-
// Type for resource <%= resource.full_dot_name %>
|
|
3
|
+
// Type for resource <%= go_comment_text(resource.full_dot_name) %>
|
|
4
4
|
type <%= resource.go_type %> struct {
|
|
5
5
|
// Pointer to client
|
|
6
6
|
Client *Client
|
|
7
7
|
|
|
8
8
|
<% resource.resources.each do |r| -%>
|
|
9
|
-
// Resource <%= r.full_dot_name %>
|
|
9
|
+
// Resource <%= go_comment_text(r.full_dot_name) %>
|
|
10
10
|
<%= r.go_name %> *<%= r.go_type %>
|
|
11
11
|
<% end -%>
|
|
12
12
|
<% resource.actions.each do |a| -%>
|
|
13
13
|
<% a.all_names do |go_name| -%>
|
|
14
|
-
// Action <%= a.full_dot_name %>
|
|
14
|
+
// Action <%= go_comment_text(a.full_dot_name) %>
|
|
15
15
|
<%= go_name %> *<%= a.go_type %>
|
|
16
16
|
<% end -%>
|
|
17
17
|
<% end -%>
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: haveapi-go-client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.28.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jakub Skokan
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.28.1
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.28.1
|
|
26
26
|
description: Go client generator
|
|
27
27
|
email:
|
|
28
28
|
- jakub.skokan@vpsfree.cz
|
|
@@ -60,7 +60,6 @@ files:
|
|
|
60
60
|
- lib/haveapi/go_client/resource.rb
|
|
61
61
|
- lib/haveapi/go_client/utils.rb
|
|
62
62
|
- lib/haveapi/go_client/version.rb
|
|
63
|
-
- shell.nix
|
|
64
63
|
- spec/integration/generator_spec.rb
|
|
65
64
|
- spec/spec_helper.rb
|
|
66
65
|
- spec/support/test_server.rb
|
data/shell.nix
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
let
|
|
2
|
-
pkgs = import <nixpkgs> {};
|
|
3
|
-
stdenv = pkgs.stdenv;
|
|
4
|
-
|
|
5
|
-
in stdenv.mkDerivation rec {
|
|
6
|
-
name = "haveapi-go-client";
|
|
7
|
-
|
|
8
|
-
buildInputs = with pkgs;[
|
|
9
|
-
git
|
|
10
|
-
go
|
|
11
|
-
gotools
|
|
12
|
-
openssl
|
|
13
|
-
ruby_3_3
|
|
14
|
-
];
|
|
15
|
-
|
|
16
|
-
shellHook = ''
|
|
17
|
-
export GEM_HOME=$(pwd)/.gems
|
|
18
|
-
export PATH="$GEM_HOME/.gems/bin:$PATH"
|
|
19
|
-
gem install bundler
|
|
20
|
-
bundler install
|
|
21
|
-
export RUBYOPT=-rbundler/setup
|
|
22
|
-
'';
|
|
23
|
-
}
|