jenkins_shell 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b75e3e5e33e080ce9171c0b0ee8db6516c0ac65caf40f6439f2ab29d46a8f48
4
- data.tar.gz: 8d6e7aa40827b25a6c0ae21be8189aa91e2117100578a033dadfbb8d9adab657
3
+ metadata.gz: 2a3c4e6f5e959d87ca2844c64a33796acd3f451ab3a539f9753ddcc3c513d79f
4
+ data.tar.gz: 18488798eeaf5089518edfd2d99318a388b28d7e1a555769fa140682e4f5fb91
5
5
  SHA512:
6
- metadata.gz: ac037325b5a840fb70578e5dc11705b22d21653d0f26e8d8cae5afb550220d483076d4e992c137cbc7260fe5626a3a3d6eb0443fc8acf79caeae6bce598aa6fa
7
- data.tar.gz: 317538957c5d1f4d0d4e16f170926d0e67cca4612652cf1acaeba0406030fac8cd3096e006274f72e359d16d4fc8ad08c8e5224ba2c919e0c85394ae81c9b4e6
6
+ metadata.gz: bb5d6ca84706904c59e0626eaa60e91e3e536558dc3fa37103b301a65fe608af89f7fa5972a6e5c74bf0f548dabe3cf7e3e08cc80ca631de71629d017396a6f4
7
+ data.tar.gz: 447d92effb45eb20436baa27f5da20811aa23a8d7ac18dbdb81c853a6fb73588385857043747c8fe9e5d09aee823cca9f37f409f87dd89ec7162724a4ed56ee5
data/bin/jsh CHANGED
@@ -16,9 +16,18 @@ class JShExit
16
16
  AMBIGUOUS_ARGUMENT = 6
17
17
  end
18
18
 
19
+ def get_password
20
+ print "Enter password: "
21
+ passwd = STDIN.noecho(&:gets)
22
+ puts
23
+ return passwd.chomp
24
+ end
25
+
19
26
  def parse(args)
20
27
  options = Hash.new
28
+ options["password"] = nil
21
29
  options["port"] = "8080"
30
+ options["username"] = nil
22
31
  options["verbose"] = false
23
32
 
24
33
  info = "Simulate a cmd prompt using Jenkins script functionality"
@@ -45,6 +54,13 @@ def parse(args)
45
54
  Hilighter.disable
46
55
  end
47
56
 
57
+ opts.on(
58
+ "--password=PASSWORD",
59
+ "Use specified password (will prompt if not provided)"
60
+ ) do |password|
61
+ options["password"] = password
62
+ end
63
+
48
64
  opts.on(
49
65
  "-p",
50
66
  "--port=PORT",
@@ -53,6 +69,10 @@ def parse(args)
53
69
  options["port"] = port
54
70
  end
55
71
 
72
+ opts.on("-u", "--user=USER", "Use specified username") do |u|
73
+ options["username"] = u
74
+ end
75
+
56
76
  opts.on(
57
77
  "-v",
58
78
  "--verbose",
@@ -98,7 +118,14 @@ end
98
118
  options = parse(ARGV)
99
119
 
100
120
  begin
101
- jsh = JenkinsShell.new(options["host"], options["port"])
121
+ passwd = options["password"]
122
+ passwd = get_password if (options["username"] && passwd.nil?)
123
+ jsh = JenkinsShell.new(
124
+ options["host"],
125
+ options["port"],
126
+ options["username"],
127
+ passwd
128
+ )
102
129
 
103
130
  djinni = Djinni.new
104
131
  djinni.fallback = "cmd"
@@ -3,9 +3,13 @@ require "rexml/document"
3
3
  require "uri"
4
4
 
5
5
  class JenkinsShell
6
+ attr_reader :cookie
7
+ attr_reader :crumb
6
8
  attr_reader :cwd
7
9
  attr_reader :host
10
+ attr_reader :password
8
11
  attr_reader :port
12
+ attr_reader :username
9
13
 
10
14
  def cd(dir = nil)
11
15
  return true if (dir.nil? || dir.empty?)
@@ -21,20 +25,48 @@ class JenkinsShell
21
25
  end
22
26
 
23
27
  def command(cmd, dir = @int_cwd)
24
- # Create and encode Groovy script
28
+ login if (@username && (@cookie.nil? || @crumb.nil?))
29
+ if (@username && (@cookie.nil? || @crumb.nil?))
30
+ raise JenkinsShell::Error::LoginFailure.new
31
+ end
32
+
33
+ # Create Groovy script
25
34
  fix = dir.gsub(/\\/, "\\\\\\")
26
35
  gs = "println(\"cmd /c cd #{fix} && #{cmd}\".execute().text)"
27
- enc = URI::encode(URI::encode(gs), "&()/").gsub("%20", "+")
28
36
 
37
+ # Make POST request and return command output
38
+ xml = post("/script", "script=#{encode(gs)}")[1]
39
+ output = xml.get_elements("html/body/div/div/pre")[1]
40
+ return "" if (output.nil?)
41
+ return output.text.strip
42
+ end
43
+
44
+ def encode(str)
45
+ # TODO what other chars need encoded?
46
+ return URI::encode(URI::encode(str), "@&()/").gsub("%20", "+")
47
+ end
48
+ private :encode
49
+
50
+ def get(path)
29
51
  begin
30
- # Establish connection and send script
52
+ # Establish connection
31
53
  http = Net::HTTP.new(@host, @port)
32
- xml = REXML::Document.new(
33
- http.post("/script", "script=#{enc}").body
34
- )
35
54
 
36
- # Parse response and return script output
37
- return xml.get_elements("html/body/div/div/pre")[1].text
55
+ # Create request
56
+ req = Net::HTTP::Get.new(path)
57
+ req["Cookie"] = @cookie if (@cookie)
58
+
59
+ # Send request and get response
60
+ res = http.request(req)
61
+
62
+ # Parse HTML body
63
+ xml = REXML::Document.new(res.body)
64
+
65
+ # Store needed values
66
+ store_state(res, xml)
67
+
68
+ # Return headers and xml body
69
+ return res, xml
38
70
  rescue Errno::ECONNREFUSED
39
71
  raise JenkinsShell::Error::ConnectionRefused.new(
40
72
  @host,
@@ -43,22 +75,88 @@ class JenkinsShell
43
75
  rescue REXML::ParseException
44
76
  raise JenkinsShell::Error::InvalidHTMLReceived.new
45
77
  end
46
- return ""
47
78
  end
79
+ private :get
48
80
 
49
- def initialize(host, port = 8080)
81
+ def initialize(host, port = 8080, username = nil, password = nil)
82
+ @cookie = nil
83
+ @crumb = nil
50
84
  @int_cwd = "."
51
85
  @host = host.gsub(/^https?:\/\/|(:[0-9]+)?\/.+/, "")
86
+ @password = password
52
87
  @port = port
88
+ @username = username
53
89
  @cwd = pwd
54
90
  end
55
91
 
92
+ def login
93
+ get("/login")
94
+ post(
95
+ "/j_acegi_security_check",
96
+ [
97
+ "j_username=#{encode(@username)}",
98
+ "j_password=#{encode(@password)}",
99
+ "Submit=log+in"
100
+ ].join("&")
101
+ )
102
+ get("/")
103
+ end
104
+
105
+ def post(path, data)
106
+ body = Array.new
107
+ body.push("Jenkins-Crumb=#{@crumb}") if (@crumb)
108
+ body.push(data)
109
+
110
+ begin
111
+ # Establish connection
112
+ http = Net::HTTP.new(@host, @port)
113
+
114
+ # Create request
115
+ req = Net::HTTP::Post.new(path)
116
+ req.body = body.join("&")
117
+ req["Cookie"] = @cookie if (@cookie)
118
+
119
+ # Send request and get response
120
+ res = http.request(req)
121
+
122
+ # Parse HTML response
123
+ xml = REXML::Document.new(res.body)
124
+
125
+ # Store needed values
126
+ store_state(res, xml)
127
+
128
+ # Return headers and xml body
129
+ return res, xml
130
+ rescue Errno::ECONNREFUSED
131
+ raise JenkinsShell::Error::ConnectionRefused.new(
132
+ @host,
133
+ @port
134
+ )
135
+ rescue REXML::ParseException
136
+ raise JenkinsShell::Error::InvalidHTMLReceived.new
137
+ end
138
+ end
139
+ private :post
140
+
56
141
  def pwd(dir = @int_cwd)
57
142
  command("dir", dir).match(/^\s+Directory of (.+)/) do |m|
58
143
  return m[1]
59
144
  end
60
145
  return ""
61
146
  end
147
+
148
+ def store_state(headers, xml)
149
+ # Store crumb if it exists
150
+ crumb = xml.get_elements("html/head/script").join
151
+ crumb.match(/"Jenkins-Crumb", "([A-Fa-f0-9]+)"/) do |m|
152
+ @crumb = m[1]
153
+ end
154
+
155
+ # Store cookie if there is one
156
+ new_cookie = headers["Set-Cookie"]
157
+ @cookie = new_cookie if (new_cookie)
158
+ end
159
+ private :store_state
62
160
  end
63
161
 
64
162
  require "jenkins_shell/error"
@@ -3,3 +3,4 @@ end
3
3
 
4
4
  require "jenkins_shell/error/connection_refused"
5
5
  require "jenkins_shell/error/invalid_html_received"
6
+ require "jenkins_shell/error/login_failure"
@@ -0,0 +1,5 @@
1
+ class JenkinsShell::Error::LoginFailure < JenkinsShell::Error
2
+ def initialize
3
+ super("Failure to login")
4
+ end
5
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jenkins_shell
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miles Whittaker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-15 00:00:00.000000000 Z
11
+ date: 2018-03-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -83,6 +83,7 @@ files:
83
83
  - lib/jenkins_shell/error.rb
84
84
  - lib/jenkins_shell/error/connection_refused.rb
85
85
  - lib/jenkins_shell/error/invalid_html_received.rb
86
+ - lib/jenkins_shell/error/login_failure.rb
86
87
  - lib/jenkins_shell/wish/cd_wish.rb
87
88
  - lib/jenkins_shell/wish/cmd_wish.rb
88
89
  - lib/jenkins_shell/wish/ls_wish.rb