@@ -10,6 +10,10 @@ import (
1010 "github.com/pkg/errors"
1111)
1212
13+ // ErrMissingTunnelID is for when a required tunnel ID is missing from the
14+ // parameters.
15+ var ErrMissingTunnelID = errors .New ("required missing tunnel ID" )
16+
1317// Tunnel is the struct definition of a tunnel.
1418type Tunnel struct {
1519 ID string `json:"id,omitempty"`
@@ -47,6 +51,34 @@ type TunnelDetailResponse struct {
4751 Response
4852}
4953
54+ // TunnelConfigurationStringifiedConfigResult is the raw result from the API with
55+ // the `Config` value as a string. You probably don't want to use this anywhere
56+ // other than in the HTTP response unmarshaling. Use `TunnelConfigurationResult`
57+ // for the correct types.
58+ type TunnelConfigurationStringifiedConfigResult struct {
59+ TunnelID string `json:"tunnel_id,omitempty"`
60+ Config string `json:"config,omitempty"`
61+ Version int `json:"version,omitempty"`
62+ }
63+
64+ type TunnelConfigurationStringifiedConfigResponse struct {
65+ Result TunnelConfigurationStringifiedConfigResult `json:"result"`
66+ Response
67+ }
68+
69+ type TunnelConfigurationResult struct {
70+ TunnelID string `json:"tunnel_id,omitempty"`
71+ Config TunnelConfiguration `json:"config,omitempty"`
72+ Version int `json:"version,omitempty"`
73+ }
74+
75+ // TunnelConfigurationResponse is used for representing the API response payload
76+ // for a single tunnel.
77+ type TunnelConfigurationResponse struct {
78+ Result TunnelConfigurationResult `json:"result"`
79+ Response
80+ }
81+
5082// TunnelTokenResponse is the API response for a tunnel token.
5183type TunnelTokenResponse struct {
5284 Result string `json:"result"`
@@ -70,6 +102,82 @@ type TunnelUpdateParams struct {
70102 Secret string `json:"tunnel_secret,omitempty"`
71103}
72104
105+ type UnvalidatedIngressRule struct {
106+ Hostname string `json:"hostname,omitempty"`
107+ Path string `json:"path,omitempty"`
108+ Service string `json:"service,omitempty"`
109+ }
110+
111+ // OriginRequestConfig is a set of optional fields that users may set to
112+ // customize how cloudflared sends requests to origin services. It is used to set
113+ // up general config that apply to all rules, and also, specific per-rule
114+ // config.
115+ type OriginRequestConfig struct {
116+ // HTTP proxy timeout for establishing a new connection
117+ ConnectTimeout * time.Duration `json:"connectTimeout,omitempty"`
118+ // HTTP proxy timeout for completing a TLS handshake
119+ TLSTimeout * time.Duration `json:"tlsTimeout,omitempty"`
120+ // HTTP proxy TCP keepalive duration
121+ TCPKeepAlive * time.Duration `json:"tcpKeepAlive,omitempty"`
122+ // HTTP proxy should disable "happy eyeballs" for IPv4/v6 fallback
123+ NoHappyEyeballs * bool `json:"noHappyEyeballs,omitempty"`
124+ // HTTP proxy maximum keepalive connection pool size
125+ KeepAliveConnections * int `json:"keepAliveConnections,omitempty"`
126+ // HTTP proxy timeout for closing an idle connection
127+ KeepAliveTimeout * time.Duration `json:"keepAliveTimeout,omitempty"`
128+ // Sets the HTTP Host header for the local webserver.
129+ HTTPHostHeader * string `json:"httpHostHeader,omitempty"`
130+ // Hostname on the origin server certificate.
131+ OriginServerName * string `json:"originServerName,omitempty"`
132+ // Path to the CA for the certificate of your origin.
133+ // This option should be used only if your certificate is not signed by Cloudflare.
134+ CAPool * string `json:"caPool,omitempty"`
135+ // Disables TLS verification of the certificate presented by your origin.
136+ // Will allow any certificate from the origin to be accepted.
137+ // Note: The connection from your machine to Cloudflare's Edge is still encrypted.
138+ NoTLSVerify * bool `json:"noTLSVerify,omitempty"`
139+ // Disables chunked transfer encoding.
140+ // Useful if you are running a WSGI server.
141+ DisableChunkedEncoding * bool `json:"disableChunkedEncoding,omitempty"`
142+ // Runs as jump host
143+ BastionMode * bool `json:"bastionMode,omitempty"`
144+ // Listen address for the proxy.
145+ ProxyAddress * string `json:"proxyAddress,omitempty"`
146+ // Listen port for the proxy.
147+ ProxyPort * uint `json:"proxyPort,omitempty"`
148+ // Valid options are 'socks' or empty.
149+ ProxyType * string `json:"proxyType,omitempty"`
150+ // IP rules for the proxy service
151+ IPRules []IngressIPRule `json:"ipRules,omitempty"`
152+ }
153+
154+ type IngressIPRule struct {
155+ Prefix * string `json:"prefix,omitempty"`
156+ Ports []int `json:"ports,omitempty"`
157+ Allow bool `json:"allow,omitempty"`
158+ }
159+
160+ type TunnelConfiguration struct {
161+ Ingress []UnvalidatedIngressRule `json:"ingress,omitempty"`
162+ WarpRouting * WarpRoutingConfig `json:"warp-routing,omitempty"`
163+ OriginRequest OriginRequestConfig `json:"originRequest,omitempty"`
164+ }
165+
166+ type WarpRoutingConfig struct {
167+ Enabled bool `json:"enabled,omitempty"`
168+ }
169+
170+ type TunnelConfigurationParams struct {
171+ AccountID string `json:"-"`
172+ TunnelID string `json:"-"`
173+ Config TunnelConfiguration `json:"config,omitempty"`
174+ }
175+
176+ type GetTunnelConfigurationParams struct {
177+ AccountID string `json:"-"`
178+ TunnelID string `json:"-"`
179+ }
180+
73181type TunnelDeleteParams struct {
74182 AccountID string
75183 ID string
@@ -103,7 +211,7 @@ func (api *API) Tunnels(ctx context.Context, params TunnelListParams) ([]Tunnel,
103211
104212 uri := buildURI (fmt .Sprintf ("/accounts/%s/cfd_tunnel" , params .AccountID ), params )
105213
106- res , err := api .makeRequestContextWithHeaders (ctx , http .MethodGet , uri , nil , nil )
214+ res , err := api .makeRequestContext (ctx , http .MethodGet , uri , nil )
107215 if err != nil {
108216 return []Tunnel {}, err
109217 }
@@ -130,7 +238,7 @@ func (api *API) Tunnel(ctx context.Context, params TunnelParams) (Tunnel, error)
130238
131239 uri := fmt .Sprintf ("/accounts/%s/cfd_tunnel/%s" , params .AccountID , params .ID )
132240
133- res , err := api .makeRequestContextWithHeaders (ctx , http .MethodGet , uri , nil , nil )
241+ res , err := api .makeRequestContext (ctx , http .MethodGet , uri , nil )
134242 if err != nil {
135243 return Tunnel {}, err
136244 }
@@ -163,7 +271,7 @@ func (api *API) CreateTunnel(ctx context.Context, params TunnelCreateParams) (Tu
163271
164272 tunnel := Tunnel {Name : params .Name , Secret : params .Secret }
165273
166- res , err := api .makeRequestContextWithHeaders (ctx , http .MethodPost , uri , tunnel , nil )
274+ res , err := api .makeRequestContext (ctx , http .MethodPost , uri , tunnel )
167275 if err != nil {
168276 return Tunnel {}, err
169277 }
@@ -197,7 +305,7 @@ func (api *API) UpdateTunnel(ctx context.Context, params TunnelUpdateParams) (Tu
197305 tunnel .Secret = params .Secret
198306 }
199307
200- res , err := api .makeRequestContextWithHeaders (ctx , http .MethodPatch , uri , tunnel , nil )
308+ res , err := api .makeRequestContext (ctx , http .MethodPatch , uri , tunnel )
201309 if err != nil {
202310 return Tunnel {}, err
203311 }
@@ -211,13 +319,101 @@ func (api *API) UpdateTunnel(ctx context.Context, params TunnelUpdateParams) (Tu
211319 return argoDetailsResponse .Result , nil
212320}
213321
322+ // UpdateTunnelConfiguration updates an existing tunnel for the account.
323+ //
324+ // API reference: https://api.cloudflare.com/#cloudflare-tunnel-configuration-properties
325+ func (api * API ) UpdateTunnelConfiguration (ctx context.Context , params TunnelConfigurationParams ) (TunnelConfigurationResult , error ) {
326+ if len (params .AccountID ) == 0 {
327+ return TunnelConfigurationResult {}, ErrMissingAccountID
328+ }
329+
330+ if len (params .TunnelID ) == 0 {
331+ return TunnelConfigurationResult {}, ErrMissingTunnelID
332+ }
333+
334+ uri := fmt .Sprintf ("/accounts/%s/cfd_tunnel/%s/configurations" , params .AccountID , params .TunnelID )
335+ res , err := api .makeRequestContext (ctx , http .MethodPut , uri , params .Config )
336+ if err != nil {
337+ return TunnelConfigurationResult {}, err
338+ }
339+
340+ // `config` comes back as a stringified representation of the configuration
341+ // so we need to double unmarshal the result. First, `config` => the string
342+ // struct field and if that is successful, then attempt putting it into a typed
343+ // struct field.
344+
345+ var tunnelDetailsResponse TunnelConfigurationStringifiedConfigResponse
346+ err = json .Unmarshal (res , & tunnelDetailsResponse )
347+ if err != nil {
348+ return TunnelConfigurationResult {}, errors .Wrap (err , errUnmarshalError )
349+ }
350+
351+ var tunnelDetails TunnelConfigurationResult
352+ var tunnelConfig TunnelConfiguration
353+
354+ err = json .Unmarshal ([]byte (tunnelDetailsResponse .Result .Config ), & tunnelConfig )
355+ if err != nil {
356+ return TunnelConfigurationResult {}, errors .Wrap (err , errUnmarshalError )
357+ }
358+
359+ tunnelDetails .Config = tunnelConfig
360+ tunnelDetails .TunnelID = tunnelDetailsResponse .Result .TunnelID
361+ tunnelDetails .Version = tunnelDetailsResponse .Result .Version
362+
363+ return tunnelDetails , nil
364+ }
365+
366+ // GetTunnelConfiguration updates an existing tunnel for the account.
367+ //
368+ // API reference: https://api.cloudflare.com/#cloudflare-tunnel-configuration-properties
369+ func (api * API ) GetTunnelConfiguration (ctx context.Context , params GetTunnelConfigurationParams ) (TunnelConfigurationResult , error ) {
370+ if len (params .AccountID ) == 0 {
371+ return TunnelConfigurationResult {}, ErrMissingAccountID
372+ }
373+
374+ if len (params .TunnelID ) == 0 {
375+ return TunnelConfigurationResult {}, ErrMissingTunnelID
376+ }
377+
378+ uri := fmt .Sprintf ("/accounts/%s/cfd_tunnel/%s/configurations" , params .AccountID , params .TunnelID )
379+ res , err := api .makeRequestContext (ctx , http .MethodGet , uri , nil )
380+ if err != nil {
381+ return TunnelConfigurationResult {}, err
382+ }
383+
384+ // `config` comes back as a stringified representation of the configuration
385+ // so we need to double unmarshal the result. First, `config` => the string
386+ // struct field and if that is successful, then attempt putting it into a typed
387+ // struct field.
388+
389+ var tunnelDetailsResponse TunnelConfigurationStringifiedConfigResponse
390+ err = json .Unmarshal (res , & tunnelDetailsResponse )
391+ if err != nil {
392+ return TunnelConfigurationResult {}, errors .Wrap (err , errUnmarshalError )
393+ }
394+
395+ var tunnelDetails TunnelConfigurationResult
396+ var tunnelConfig TunnelConfiguration
397+
398+ err = json .Unmarshal ([]byte (tunnelDetailsResponse .Result .Config ), & tunnelConfig )
399+ if err != nil {
400+ return TunnelConfigurationResult {}, errors .Wrap (err , errUnmarshalError )
401+ }
402+
403+ tunnelDetails .Config = tunnelConfig
404+ tunnelDetails .TunnelID = tunnelDetailsResponse .Result .TunnelID
405+ tunnelDetails .Version = tunnelDetailsResponse .Result .Version
406+
407+ return tunnelDetails , nil
408+ }
409+
214410// DeleteTunnel removes a single Argo tunnel.
215411//
216412// API reference: https://api.cloudflare.com/#cloudflare-tunnel-delete-cloudflare-tunnel
217413func (api * API ) DeleteTunnel (ctx context.Context , params TunnelDeleteParams ) error {
218414 uri := fmt .Sprintf ("/accounts/%s/cfd_tunnel/%s" , params .AccountID , params .ID )
219415
220- res , err := api .makeRequestContextWithHeaders (ctx , http .MethodDelete , uri , nil , nil )
416+ res , err := api .makeRequestContext (ctx , http .MethodDelete , uri , nil )
221417 if err != nil {
222418 return err
223419 }
@@ -245,7 +441,7 @@ func (api *API) CleanupTunnelConnections(ctx context.Context, params TunnelClean
245441
246442 uri := fmt .Sprintf ("/accounts/%s/cfd_tunnel/%s/connections" , params .AccountID , params .ID )
247443
248- res , err := api .makeRequestContextWithHeaders (ctx , http .MethodDelete , uri , nil , nil )
444+ res , err := api .makeRequestContext (ctx , http .MethodDelete , uri , nil )
249445 if err != nil {
250446 return err
251447 }
@@ -273,7 +469,7 @@ func (api *API) TunnelToken(ctx context.Context, params TunnelTokenParams) (stri
273469
274470 uri := fmt .Sprintf ("/accounts/%s/cfd_tunnel/%s/token" , params .AccountID , params .ID )
275471
276- res , err := api .makeRequestContextWithHeaders (ctx , http .MethodGet , uri , nil , nil )
472+ res , err := api .makeRequestContext (ctx , http .MethodGet , uri , nil )
277473 if err != nil {
278474 return "" , err
279475 }
0 commit comments