Skip to content

Commit dc13ad3

Browse files
authored
feat: Allow insecure TLS (#305)
1 parent f01ba47 commit dc13ad3

File tree

5 files changed

+67
-10
lines changed

5 files changed

+67
-10
lines changed

api/client.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,13 @@ func Client(config jira.Config) *jira.Client {
2828
if config.APIToken == "" {
2929
config.APIToken = viper.GetString("api_token")
3030
}
31+
config.Insecure = viper.GetBool("insecure")
3132

32-
jiraClient = jira.NewClient(config, jira.WithTimeout(clientTimeout))
33+
jiraClient = jira.NewClient(
34+
config,
35+
jira.WithTimeout(clientTimeout),
36+
jira.WithInsecureTLS(config.Insecure),
37+
)
3338

3439
return jiraClient
3540
}

internal/cmd/init/init.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,31 @@ import (
1414

1515
// NewCmdInit is an init command.
1616
func NewCmdInit() *cobra.Command {
17-
return &cobra.Command{
17+
cmd := cobra.Command{
1818
Use: "init",
1919
Short: "Init initializes jira config",
2020
Long: "Init initializes jira configuration required for the tool to work properly.",
2121
Aliases: []string{"initialize", "configure", "config", "setup"},
2222
Run: initialize,
2323
}
24+
25+
cmd.Flags().Bool("insecure", false, `If set, the tool will skip TLS certificate verification.
26+
This can be useful if your server is using self-signed certificates.`)
27+
28+
return &cmd
2429
}
2530

26-
func initialize(*cobra.Command, []string) {
27-
c := jiraConfig.NewJiraCLIConfig()
31+
func initialize(cmd *cobra.Command, _ []string) {
32+
insecure, err := cmd.Flags().GetBool("insecure")
33+
cmdutil.ExitIfError(err)
34+
35+
c := jiraConfig.NewJiraCLIConfig(jiraConfig.WithInsecureTLS(insecure))
36+
37+
if insecure {
38+
cmdutil.Warn(`You are using --insecure option. In this mode, the client will NOT verify
39+
server's certificate chain and host name in requests to the jira server.`)
40+
fmt.Println()
41+
}
2842

2943
file, err := c.Generate()
3044
if err != nil {

internal/cmdutil/utils.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ func Success(msg string, args ...interface{}) {
7171
fmt.Fprintf(os.Stdout, fmt.Sprintf("\n\u001B[0;32m✓\u001B[0m %s\n", msg), args...)
7272
}
7373

74+
// Warn prints warning message in stderr.
75+
func Warn(msg string, args ...interface{}) {
76+
fmt.Fprintf(os.Stderr, fmt.Sprintf("\u001B[0;33m%s\u001B[0m\n", msg), args...)
77+
}
78+
7479
// Fail prints failure message in stderr.
7580
func Fail(msg string, args ...interface{}) {
7681
fmt.Fprintf(os.Stderr, fmt.Sprintf("\u001B[0;31m✗\u001B[0m %s\n", msg), args...)

internal/config/generator.go

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,36 @@ type JiraCLIConfig struct {
4848
epic *jira.Epic
4949
issueTypes []*jira.IssueType
5050
}
51+
insecure bool
5152
jiraClient *jira.Client
5253
projectSuggestions []string
5354
boardSuggestions []string
5455
projectsMap map[string]*projectConf
5556
boardsMap map[string]*jira.Board
5657
}
5758

59+
// JiraCLIConfigFunc decorates option for JiraCLIConfig.
60+
type JiraCLIConfigFunc func(*JiraCLIConfig)
61+
5862
// NewJiraCLIConfig creates a new Jira CLI config.
59-
func NewJiraCLIConfig() *JiraCLIConfig {
60-
return &JiraCLIConfig{
63+
func NewJiraCLIConfig(opts ...JiraCLIConfigFunc) *JiraCLIConfig {
64+
cfg := JiraCLIConfig{
6165
projectsMap: make(map[string]*projectConf),
6266
boardsMap: make(map[string]*jira.Board),
6367
}
68+
69+
for _, opt := range opts {
70+
opt(&cfg)
71+
}
72+
73+
return &cfg
74+
}
75+
76+
// WithInsecureTLS is a functional opt to set TLS certificate verfication option.
77+
func WithInsecureTLS(ins bool) JiraCLIConfigFunc {
78+
return func(c *JiraCLIConfig) {
79+
c.insecure = ins
80+
}
6481
}
6582

6683
// Generate generates the config file.
@@ -223,9 +240,10 @@ func (c *JiraCLIConfig) verifyLoginDetails(server, login string) error {
223240
server = strings.TrimRight(server, "/")
224241

225242
c.jiraClient = api.Client(jira.Config{
226-
Server: server,
227-
Login: login,
228-
Debug: viper.GetBool("debug"),
243+
Server: server,
244+
Login: login,
245+
Insecure: c.insecure,
246+
Debug: viper.GetBool("debug"),
229247
})
230248
if _, err := c.jiraClient.Me(); err != nil {
231249
return err
@@ -354,6 +372,10 @@ func (c *JiraCLIConfig) write(path string) (string, error) {
354372
config.SetConfigName(FileName)
355373
config.SetConfigType(FileType)
356374

375+
if c.insecure {
376+
config.Set("insecure", c.insecure)
377+
}
378+
357379
config.Set("installation", c.value.installation)
358380
config.Set("server", c.value.server)
359381
config.Set("login", c.value.login)

pkg/jira/client.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package jira
33
import (
44
"bytes"
55
"context"
6+
"crypto/tls"
67
"encoding/json"
78
"fmt"
89
"net"
@@ -95,12 +96,14 @@ type Config struct {
9596
Server string
9697
Login string
9798
APIToken string
99+
Insecure bool
98100
Debug bool
99101
}
100102

101103
// Client is a jira client.
102104
type Client struct {
103105
transport http.RoundTripper
106+
insecure bool
104107
server string
105108
login string
106109
token string
@@ -125,7 +128,8 @@ func NewClient(c Config, opts ...ClientFunc) *Client {
125128
}
126129

127130
client.transport = &http.Transport{
128-
Proxy: http.ProxyFromEnvironment,
131+
Proxy: http.ProxyFromEnvironment,
132+
TLSClientConfig: &tls.Config{InsecureSkipVerify: client.insecure},
129133
DialContext: (&net.Dialer{
130134
Timeout: client.timeout,
131135
}).DialContext,
@@ -141,6 +145,13 @@ func WithTimeout(to time.Duration) ClientFunc {
141145
}
142146
}
143147

148+
// WithInsecureTLS is a functional opt that allow you to skip TLS certificate verfication.
149+
func WithInsecureTLS(ins bool) ClientFunc {
150+
return func(c *Client) {
151+
c.insecure = ins
152+
}
153+
}
154+
144155
// Get sends GET request to v3 version of the jira api.
145156
func (c *Client) Get(ctx context.Context, path string, headers Header) (*http.Response, error) {
146157
return c.request(ctx, http.MethodGet, c.server+baseURLv3+path, nil, headers)

0 commit comments

Comments
 (0)