pwn 0.5.295 → 0.5.297
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/README.md +3 -3
- data/lib/pwn/plugins/jira_server.rb +84 -19
- data/lib/pwn/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d2a882d84c8a39cad218cec303b531edc9b7a0b8f8318a8d14731a666b898101
|
4
|
+
data.tar.gz: a87c7ff03ea231c405454b4e0f98df6d51648cb272a772bf4b518f5e2dbc7a6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 016cd67f87c5889557383311d6ea0d3a73f772c187ed2e8714983a452957d753a4a08b13f5a5c0831c0babf1df80e4ede655163309f6a0ca2298ea75770368d2
|
7
|
+
data.tar.gz: a0ab7b93947a1243a4fee67fe413f3de98497c0e1d0a9a9a373e5d7f08623d70cd633c43a14facd94b07b3db4b5e9f85a04304702e049777aa5b7530204b4e26
|
data/README.md
CHANGED
@@ -37,7 +37,7 @@ $ cd /opt/pwn
|
|
37
37
|
$ ./install.sh
|
38
38
|
$ ./install.sh ruby-gem
|
39
39
|
$ pwn
|
40
|
-
pwn[v0.5.
|
40
|
+
pwn[v0.5.297]:001 >>> PWN.help
|
41
41
|
```
|
42
42
|
|
43
43
|
[](https://youtu.be/G7iLUY4FzsI)
|
@@ -52,7 +52,7 @@ $ rvm use ruby-3.4.4@pwn
|
|
52
52
|
$ gem uninstall --all --executables pwn
|
53
53
|
$ gem install --verbose pwn
|
54
54
|
$ pwn
|
55
|
-
pwn[v0.5.
|
55
|
+
pwn[v0.5.297]:001 >>> PWN.help
|
56
56
|
```
|
57
57
|
|
58
58
|
If you're using a multi-user install of RVM do:
|
@@ -62,7 +62,7 @@ $ rvm use ruby-3.4.4@pwn
|
|
62
62
|
$ rvmsudo gem uninstall --all --executables pwn
|
63
63
|
$ rvmsudo gem install --verbose pwn
|
64
64
|
$ pwn
|
65
|
-
pwn[v0.5.
|
65
|
+
pwn[v0.5.297]:001 >>> PWN.help
|
66
66
|
```
|
67
67
|
|
68
68
|
PWN periodically upgrades to the latest version of Ruby which is reflected in `/opt/pwn/.ruby-version`. The easiest way to upgrade to the latest version of Ruby from a previous PWN installation is to run the following script:
|
@@ -22,6 +22,7 @@ module PWN
|
|
22
22
|
# )
|
23
23
|
|
24
24
|
private_class_method def self.rest_call(opts = {})
|
25
|
+
token = opts[:token]
|
25
26
|
http_method = if opts[:http_method].nil?
|
26
27
|
:get
|
27
28
|
else
|
@@ -29,49 +30,62 @@ module PWN
|
|
29
30
|
end
|
30
31
|
rest_call = opts[:rest_call].to_s.scrub
|
31
32
|
params = opts[:params]
|
33
|
+
headers = opts[:http_headers] ||= {
|
34
|
+
content_type: 'application/json; charset=UTF-8',
|
35
|
+
authorization: "Bearer #{token}"
|
36
|
+
}
|
37
|
+
|
32
38
|
http_body = opts[:http_body]
|
33
39
|
base_api_uri = opts[:base_api_uri]
|
34
40
|
|
35
41
|
raise 'ERROR: base_api_uri cannot be nil.' if base_api_uri.nil?
|
36
42
|
|
37
|
-
token = opts[:token]
|
38
|
-
|
39
43
|
browser_obj = PWN::Plugins::TransparentBrowser.open(browser_type: :rest)
|
40
44
|
rest_client = browser_obj[:browser]::Request
|
41
45
|
|
42
46
|
spinner = TTY::Spinner.new
|
43
47
|
spinner.auto_spin
|
44
48
|
|
49
|
+
max_request_attempts = 3
|
50
|
+
tot_request_attempts ||= 1
|
51
|
+
|
45
52
|
case http_method
|
46
53
|
when :delete, :get
|
54
|
+
headers[:params] = params
|
47
55
|
response = rest_client.execute(
|
48
56
|
method: http_method,
|
49
57
|
url: "#{base_api_uri}/#{rest_call}",
|
50
|
-
headers:
|
51
|
-
|
52
|
-
|
53
|
-
params: params
|
54
|
-
},
|
55
|
-
verify_ssl: false
|
58
|
+
headers: headers,
|
59
|
+
verify_ssl: false,
|
60
|
+
timeout: 180
|
56
61
|
)
|
57
62
|
|
58
63
|
when :post, :put
|
64
|
+
if http_body.is_a?(Hash)
|
65
|
+
if http_body.key?(:multipart)
|
66
|
+
headers[:content_type] = 'multipart/form-data'
|
67
|
+
headers[:x_atlassian_token] = 'no-check'
|
68
|
+
else
|
69
|
+
http_body = http_body.to_json
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
59
73
|
response = rest_client.execute(
|
60
74
|
method: http_method,
|
61
75
|
url: "#{base_api_uri}/#{rest_call}",
|
62
|
-
headers:
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
payload: http_body.to_json,
|
67
|
-
verify_ssl: false
|
76
|
+
headers: headers,
|
77
|
+
payload: http_body,
|
78
|
+
verify_ssl: false,
|
79
|
+
timeout: 180
|
68
80
|
)
|
69
|
-
|
70
81
|
else
|
71
82
|
raise @@logger.error("Unsupported HTTP Method #{http_method} for #{self} Plugin")
|
72
83
|
end
|
73
84
|
|
74
|
-
|
85
|
+
jira_response = response if response.is_a?(RestClient::Response) && response.code == 204
|
86
|
+
jira_response = JSON.parse(response, symbolize_names: true) if response.is_a?(RestClient::Response) && response.code != 204
|
87
|
+
|
88
|
+
jira_response
|
75
89
|
rescue RestClient::ExceptionWithResponse => e
|
76
90
|
if e.response
|
77
91
|
puts "HTTP BASE URL: #{base_api_uri}"
|
@@ -80,10 +94,31 @@ module PWN
|
|
80
94
|
puts "HTTP RESPONSE HEADERS: #{e.response.headers}"
|
81
95
|
puts "HTTP RESPONSE BODY:\n#{e.response.body}\n\n\n"
|
82
96
|
end
|
97
|
+
|
98
|
+
raise e
|
99
|
+
rescue IO::TimeoutError => e
|
100
|
+
raise e if tot_request_attempts == max_request_attempts
|
101
|
+
|
102
|
+
tot_request_attempts += 1
|
103
|
+
@@logger.warn("Timeout Error: Retrying request (Attempt #{tot_request_attempts}/#{max_request_attempts})")
|
104
|
+
sleep(2)
|
105
|
+
retry
|
106
|
+
rescue Errno::ECONNREFUSED => e
|
107
|
+
raise e if tot_request_attempts == max_request_attempts
|
108
|
+
|
109
|
+
puts "\nTCP Connection Unavailable."
|
110
|
+
puts "Attempt (#{tot_request_attempts} of #{max_request_attempts}) in 60s"
|
111
|
+
60.downto(1) do
|
112
|
+
print '.'
|
113
|
+
sleep 1
|
114
|
+
end
|
115
|
+
tot_request_attempts += 1
|
116
|
+
|
117
|
+
retry
|
83
118
|
rescue StandardError => e
|
84
119
|
raise e
|
85
120
|
ensure
|
86
|
-
spinner.stop
|
121
|
+
spinner.stop unless spinner.nil?
|
87
122
|
end
|
88
123
|
|
89
124
|
# Supported Method Parameters::
|
@@ -150,6 +185,7 @@ module PWN
|
|
150
185
|
# description: 'optional - description of the issue',
|
151
186
|
# epic_name: 'optional - name of the epic',
|
152
187
|
# additional_fields: 'optional - additional fields to set in the issue (e.g. labels, components, custom fields, etc.)'
|
188
|
+
# attachments: 'optional - array of attachment paths to upload to the issue (e.g. ["/path/to/file1.txt", "/path/to/file2.png"])'
|
153
189
|
# )
|
154
190
|
|
155
191
|
public_class_method def self.create_issue(opts = {})
|
@@ -173,6 +209,9 @@ module PWN
|
|
173
209
|
additional_fields = opts[:additional_fields] ||= { fields: {} }
|
174
210
|
raise 'ERROR: additional_fields Hash must contain a :fields key that is also a Hash.' unless additional_fields.is_a?(Hash) && additional_fields.key?(:fields) && additional_fields[:fields].is_a?(Hash)
|
175
211
|
|
212
|
+
attachments = opts[:attachments] ||= []
|
213
|
+
raise 'ERROR: attachments must be an Array.' unless attachments.is_a?(Array)
|
214
|
+
|
176
215
|
all_fields = get_all_fields(base_api_uri: base_api_uri, token: token)
|
177
216
|
epic_name_field_key = all_fields.find { |field| field[:name] == 'Epic Name' }[:id]
|
178
217
|
|
@@ -194,13 +233,32 @@ module PWN
|
|
194
233
|
|
195
234
|
http_body[:fields].merge!(additional_fields[:fields])
|
196
235
|
|
197
|
-
rest_call(
|
236
|
+
issue_resp = rest_call(
|
198
237
|
http_method: :post,
|
199
238
|
base_api_uri: base_api_uri,
|
200
239
|
token: token,
|
201
240
|
rest_call: 'issue',
|
202
241
|
http_body: http_body
|
203
242
|
)
|
243
|
+
|
244
|
+
if attachments.any?
|
245
|
+
issue = issue_resp[:key]
|
246
|
+
|
247
|
+
http_body = {
|
248
|
+
multipart: true,
|
249
|
+
file: attachments.map { |attachment| File.new(attachment, 'rb') }
|
250
|
+
}
|
251
|
+
|
252
|
+
rest_call(
|
253
|
+
http_method: :post,
|
254
|
+
base_api_uri: base_api_uri,
|
255
|
+
token: token,
|
256
|
+
rest_call: "issue/#{issue}/attachments",
|
257
|
+
http_body: http_body
|
258
|
+
)
|
259
|
+
end
|
260
|
+
|
261
|
+
issue_resp
|
204
262
|
rescue StandardError => e
|
205
263
|
raise e
|
206
264
|
end
|
@@ -299,7 +357,8 @@ module PWN
|
|
299
357
|
issue_type: 'required - issue type (e.g. :epic, :story, :bug)',
|
300
358
|
description: 'optional - description of the issue',
|
301
359
|
epic_name: 'optional - name of the epic',
|
302
|
-
additional_fields: 'optional - additional fields to set in the issue (e.g. labels, components, custom fields, etc.)'
|
360
|
+
additional_fields: 'optional - additional fields to set in the issue (e.g. labels, components, custom fields, etc.)',
|
361
|
+
attachments: 'optional - array of attachment paths to upload to the issue (e.g. ['/path/to/file1.txt', '/path/to/file2.png'])'
|
303
362
|
)
|
304
363
|
|
305
364
|
issue_resp = #{self}.update_issue(
|
@@ -309,6 +368,12 @@ module PWN
|
|
309
368
|
fields: 'required - fields to update in the issue (e.g. summary, description, labels, components, custom fields, etc.)'
|
310
369
|
)
|
311
370
|
|
371
|
+
issue_resp = #{self}.delete_issue(
|
372
|
+
base_api_uri: 'required - base URI for Jira (e.g. https:/jira.corp.com/rest/api/latest)',
|
373
|
+
token: 'required - bearer token',
|
374
|
+
issue: 'required - issue to delete (e.g. Bug, Issue, Story, or Epic ID)'
|
375
|
+
)
|
376
|
+
|
312
377
|
**********************************************************************
|
313
378
|
* For more information on the Jira Server REST API, see:
|
314
379
|
* https://developer.atlassian.com/server/jira/platform/rest-apis/
|
data/lib/pwn/version.rb
CHANGED