enfcli 3.3.2.pre.alpha

Sign up to get free protection for your applications and to get access to all the features.
data/lib/enfcli.rb ADDED
@@ -0,0 +1,390 @@
1
+ #
2
+ # Copyright 2018 Xaptum,Inc
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ require 'openssl'
17
+ require 'enfapi'
18
+ require 'enfthor'
19
+ require 'readline'
20
+ require 'singleton'
21
+ require 'ipaddr'
22
+
23
+ require 'rubygems/commands/update_command'
24
+ require 'rubygems/commands/search_command'
25
+
26
+
27
+ require 'enfcli/version'
28
+ require 'enfcli/commands/xcr'
29
+ require 'enfcli/commands/xiam'
30
+ require 'enfcli/commands/xfw'
31
+ require 'enfcli/commands/user'
32
+
33
+ module EnfCli
34
+ FIREWALL_CMD = "firewall"
35
+ IAM_CMD = "iam"
36
+ NETWORK_CMD = "network"
37
+ USER_CMD = "user"
38
+
39
+ class IPV6
40
+ def initialize(ipv6)
41
+ begin
42
+ # create IPAddr object
43
+ ip = IPAddr.new ipv6
44
+
45
+ # make sure it is an ipv6 address
46
+ raise EnfCli::ERROR, "#{ipv6} is not a valid Ipv6 address." unless ip.ipv6?
47
+
48
+ @ip = ip
49
+ rescue IPAddr::InvalidAddressError
50
+ raise EnfCli::ERROR, "#{ipv6} is not a valid Ipv6 address."
51
+ end
52
+ end
53
+
54
+ def to_s
55
+ @ip.to_s
56
+ end
57
+
58
+ def hton
59
+ @ip.hton
60
+ end
61
+
62
+ def self.ntoh ipv6_bytes
63
+ ip = IPAddr::new_ntoh( ipv6_bytes )
64
+ EnfCli::IPV6.new ip.to_s
65
+ end
66
+
67
+ private
68
+
69
+ attr_accessor :ip
70
+ end
71
+
72
+ class IPV6Cidr
73
+ def initialize(ipv6cidr)
74
+ # split on /
75
+ tokens = ipv6cidr.split("/")
76
+
77
+ # raise exception if not cidr format
78
+ raise EnfCli::ERROR, "#{ipv6cidr} is not a valid CIDR notation." unless tokens.length == 2
79
+
80
+ # store in prefix/len
81
+ @prefix = EnfCli::IPV6.new tokens[0]
82
+ @len = tokens[1].to_i
83
+
84
+ # raise if len is not 0
85
+ raise EnfCli::ERROR, "#{ipv6cidr} is not a valid CIDR notation." unless len > 2
86
+
87
+ end
88
+
89
+ def prefix_bytes
90
+ @prefix.hton
91
+ end
92
+
93
+ def prefix_len
94
+ @len
95
+ end
96
+
97
+ def to_s
98
+ "#{@prefix.to_s}/#{@len}"
99
+ end
100
+
101
+ private
102
+ attr_accessor :prefix, :len
103
+ end
104
+
105
+ def self.ask_password(prompt = nil)
106
+ begin
107
+ prompt = 'Enter Password:' unless prompt
108
+ print prompt
109
+ # We hide the entered characters before to ask for the password
110
+ system 'stty -echo'
111
+ password = $stdin.gets.chomp
112
+ system 'stty echo'
113
+ puts ""
114
+ return password
115
+
116
+ rescue NoMethodError, Interrupt
117
+ # When the process is exited, we display the characters again
118
+ # And we exit
119
+ system 'stty echo'
120
+ exit
121
+ end
122
+ end
123
+
124
+ def self.generate_ec_cert(key, ipv6)
125
+ # monkey patch
126
+ OpenSSL::PKey::EC.send(:alias_method, :private?, :private_key?)
127
+
128
+ # Generate cert
129
+ cert = OpenSSL::X509::Certificate.new
130
+ cert.subject = cert.issuer = OpenSSL::X509::Name.new([['CN', "#{ipv6}"]])
131
+ cert.not_before = Time.now
132
+ cert.not_after = Time.now + 365 * 24 * 60 * 60
133
+ cert.public_key = key
134
+ cert.serial = 0x0
135
+ cert.version = 2
136
+
137
+ cert.sign key, OpenSSL::Digest::SHA1.new
138
+ cert
139
+ end
140
+
141
+ def self.expand_path(file)
142
+ new_file = File.expand_path(EnfCli::expand_env(file))
143
+ end
144
+
145
+ def self.expand_env(str)
146
+ str.gsub(/\$([a-zA-Z_][a-zA-Z0-9_]*)|\${\g<1>}|%\g<1>%/) { ENV[$1] }
147
+ end
148
+
149
+ def self.to_canonical_ipv6(ipv6)
150
+ ip = EnfCli::IPV6.new ipv6
151
+ ip.to_s
152
+ end
153
+
154
+ ##
155
+ # EnfCli error
156
+ #
157
+ class ERROR < StandardError
158
+ def initialize(msg = "Cli Error")
159
+ super
160
+ end
161
+ end
162
+
163
+ ##
164
+ # EnfCli Context
165
+ #
166
+ class CTX
167
+ include Singleton
168
+
169
+ attr_accessor :session
170
+
171
+ def initialize
172
+ @prompt = "enfcli"
173
+ @host = ''
174
+ end
175
+
176
+ def xaptum_admin?
177
+ self.user_role == "XAPTUM_ADMIN"
178
+ end
179
+
180
+ def user_role
181
+ @session[:type]
182
+ end
183
+
184
+ def host
185
+ "#{@host}"
186
+ end
187
+
188
+ def host=(value)
189
+ @host = value
190
+ end
191
+
192
+ def prompt
193
+ "\001\033[1;32m\002#{@prompt}>\001\033[0m\002 "
194
+ end
195
+
196
+ def prompt=(value)
197
+ if value
198
+ @prompt = "enfcli-#{value}"
199
+ else
200
+ @prompt= "enfcli"
201
+ end
202
+
203
+ end
204
+
205
+ end
206
+
207
+ ##
208
+ # CLI for launching shell
209
+ #
210
+ class CLI < EnfThor
211
+ no_commands {
212
+ def execute_gem_cmd cmd
213
+ begin
214
+ cmd.execute
215
+ rescue Gem::SystemExitException => e
216
+ say "Unable to execute commnad. Please try again!", :red
217
+ end
218
+ end
219
+ }
220
+
221
+ desc "connect", "Connect to ENF Controller"
222
+ method_option :host, :type => :string, :required => true
223
+ method_option :user, :type => :string, :required => true
224
+ method_option :password, :type => :string
225
+ def connect(*names)
226
+ host = options[:host]
227
+ user = options[:user]
228
+
229
+ try_with_rescue do
230
+ # Make sure to use https as default
231
+ host = "https://#{host}" unless host =~ /^(http|https):\/\//
232
+
233
+ # Ask for password
234
+ say "Connecting to '#{host}'.....", :bold
235
+ password = EnfCli::ask_password()
236
+
237
+ # Authenticate
238
+ resp = EnfApi::API.instance.authenticate(host, user, password)
239
+
240
+ # set session
241
+ EnfCli::CTX.instance.session = resp[:data][0]
242
+
243
+ # launch shell/exec cmd
244
+ if names.empty?
245
+ EnfCli::Shell::Console::start host, user
246
+ else
247
+ EnfCli::Shell::CLI.start names
248
+ end
249
+ end
250
+ end
251
+
252
+ map %w[--version -v] => :__print_version
253
+ desc "--version, -v", "print the version"
254
+ def __print_version
255
+ puts EnfCli::VERSION
256
+ end
257
+
258
+ desc "update", "", :hide => true
259
+ def update
260
+ cmd = Gem::Commands::UpdateCommand.new
261
+ cmd.handle_options ['enfcli']
262
+ execute_gem_cmd cmd
263
+ end
264
+
265
+ desc "search", "", :hide => true
266
+ def search
267
+ cmd = Gem::Commands::SearchCommand.new
268
+ cmd.handle_options ["enfcli"]
269
+ execute_gem_cmd cmd
270
+ end
271
+
272
+ default_task :connect
273
+
274
+ end
275
+
276
+ ##
277
+ # Shell Module
278
+ #
279
+ module Shell
280
+
281
+ class Console
282
+ class << self
283
+ def execute(input)
284
+ argv = input.split(" ")
285
+ EnfCli::Shell::CLI.start( argv )
286
+ end
287
+
288
+ def start(host, user)
289
+ # Set prompt
290
+ EnfCli::CTX.instance.prompt = user
291
+
292
+ # Set host
293
+ EnfCli::CTX.instance.host = host
294
+
295
+ # Read each line
296
+ comp = proc { |s| Readline::HISTORY.grep(/^#{Regexp.escape(s)}/) }
297
+ Readline.completion_append_character = " "
298
+ Readline.completion_proc = comp
299
+
300
+ stty_save = `stty -g`.chomp
301
+ trap('INT') { system('stty', stty_save); exit }
302
+
303
+ while input = Readline.readline(EnfCli::CTX.instance.prompt, true)
304
+ break if input == "exit" or input == "\\q" or input == "quit"
305
+
306
+ # Remove blank lines from history
307
+ Readline::HISTORY.pop if input == ""
308
+
309
+ execute(input) unless input == ""
310
+ end
311
+ end
312
+ end
313
+ end
314
+
315
+ # Shell CLI class
316
+ class CLI < EnfThor
317
+
318
+ desc "ls [<dir>]", "List files in a directory", :hide => true
319
+ method_option :dir, :type => :string, :required => false
320
+ def ls(dir = nil)
321
+ try_with_rescue do
322
+ dir = "." unless dir
323
+ dir = EnfCli::expand_path( dir )
324
+
325
+ Dir.entries( dir ).each{ |f|
326
+ puts f unless f.start_with?('.')
327
+ }
328
+ end
329
+ end
330
+
331
+ desc "cat <file>", "Display contents of a file", :hide => true
332
+ def cat(file)
333
+ try_with_rescue do
334
+ # expand path
335
+ file = EnfCli::expand_path(file)
336
+
337
+ ## return if keyfile not found
338
+ raise EnfCli::ERROR, "#{file} not found!" unless File.exists?(file)
339
+
340
+ say File.readlines(file).join
341
+ end
342
+ end
343
+
344
+ desc "pwd", "Current Working Directory", :hide => true
345
+ def pwd
346
+ try_with_rescue do
347
+ say Dir.pwd
348
+ end
349
+ end
350
+
351
+ desc "cd [<dir>]", "Change working directory", :hide => true
352
+ def cd(dir = "~")
353
+ try_with_rescue do
354
+ dir = EnfCli::expand_path( dir )
355
+ raise EnfCli::ERROR, "No such directory #{dir}" unless Dir.exist?(dir)
356
+ Dir.chdir(dir)
357
+ end
358
+ end
359
+
360
+ desc "host", "Display ENF Controller host", :hide => true
361
+ def host
362
+ try_with_rescue do
363
+ say EnfCli::CTX.instance.host, :bold
364
+ end
365
+ end
366
+
367
+ desc "clear", "Clear Terminal Screen", :hide => true
368
+ def clear
369
+ try_with_rescue do
370
+ clear_code = %x{clear}
371
+ print clear_code or system("cls")
372
+ end
373
+ end
374
+
375
+ desc "#{EnfCli::NETWORK_CMD} COMMANDS", "#{EnfCli::NETWORK_CMD} commands"
376
+ subcommand EnfCli::NETWORK_CMD, EnfCli::Cmd::Xcr
377
+
378
+ desc "#{EnfCli::IAM_CMD} COMMANDS", "#{EnfCli::IAM_CMD} commands"
379
+ subcommand EnfCli::IAM_CMD, EnfCli::Cmd::Xiam
380
+
381
+ desc "#{EnfCli::FIREWALL_CMD} COMMANDS", "#{EnfCli::FIREWALL_CMD} commands"
382
+ subcommand EnfCli::FIREWALL_CMD, EnfCli::Cmd::Xfw
383
+
384
+ desc "#{EnfCli::USER_CMD} COMMANDS", "#{EnfCli::USER_CMD} commands"
385
+ subcommand EnfCli::USER_CMD, EnfCli::Cmd::User
386
+
387
+ end
388
+ end
389
+
390
+ end
data/lib/enfthor.rb ADDED
@@ -0,0 +1,118 @@
1
+ #
2
+ # Copyright 2018 Xaptum,Inc
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ require 'thor'
17
+ require 'terminal-table'
18
+
19
+ module EnfCli
20
+ class EnfThor < Thor
21
+ # check for unknow of misspelt options
22
+ check_unknown_options!
23
+
24
+ # helper functions
25
+ no_commands {
26
+
27
+ def format_date(date)
28
+ DateTime.strptime("#{date}",'%s') if date
29
+ end
30
+
31
+ def render_table(headings, rows, file = nil)
32
+ table = Terminal::Table.new
33
+ table.headings = headings
34
+ table.rows = rows
35
+ if file
36
+ open(expand_path(file), 'w') { |f|
37
+ f.puts table
38
+ }
39
+ say "#{rows.length} rows written to file #{file}", :yellow
40
+ else
41
+ say table
42
+ say "#{rows.length} rows in set", :yellow
43
+ end
44
+ end
45
+
46
+ def try_with_rescue_in_session
47
+ try_with_rescue do
48
+ # Verify domain context is set
49
+ session = EnfCli::CTX.instance.session
50
+ raise EnfCli::ERROR, "User Session not establised!" if !session
51
+
52
+ yield
53
+ end
54
+ end
55
+
56
+ def try_with_rescue
57
+ begin
58
+ yield
59
+ rescue EnfApi::ERROR => e
60
+ say e, :red
61
+
62
+ rescue OpenSSL::SSL::SSLError => e
63
+ say e, :red
64
+ say "Host may not support https. Try http instead", :bold
65
+
66
+ rescue => e
67
+ say e, :red
68
+ end
69
+ end
70
+
71
+
72
+ }
73
+
74
+ # override help methods
75
+ class << self
76
+ def capture_stdout
77
+ $stdout = StringIO.new
78
+ yield
79
+ text = $stdout.string
80
+ $stdout = STDOUT
81
+ text
82
+ end
83
+
84
+ def help(shell, subcommand = false)
85
+ list = printable_commands(true, subcommand)
86
+ Thor::Util.thor_classes_in(self).each do |klass|
87
+ list += klass.printable_commands(false)
88
+ end
89
+
90
+ # Remove this line to disable alphabetical sorting
91
+ list.sort! { |a, b| a[0] <=> b[0] }
92
+
93
+ # Add this line to remove the help-command itself from the output
94
+ list.reject! {|l| l[0].split[1] == 'help' or l[0].split[2] == 'help'}
95
+
96
+
97
+ # Capture help message in a variable
98
+ help_text = capture_stdout {
99
+ shell.say "Commands:"
100
+ shell.print_table(list, :indent => 2, :truncate => true)
101
+ shell.say
102
+ class_options_help(shell)
103
+ }
104
+
105
+ ## HACK: format to display proper help message for help command run from shell
106
+ help_text = help_text.gsub(/enfcli /,"") unless self == EnfCli::CLI
107
+
108
+ # Print the actual help message
109
+ shell.say help_text
110
+
111
+ # Add this line if you want to print custom text at the end of your help output.
112
+ # (similar to how Rails does it)
113
+ shell.say 'All commands can be run with -h (or --help) for more information.'
114
+ end
115
+ end
116
+
117
+ end
118
+ end
metadata ADDED
@@ -0,0 +1,218 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: enfcli
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.3.2.pre.alpha
5
+ platform: ruby
6
+ authors:
7
+ - Venkatakumar Srinivasan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-03-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.20.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.20.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rest-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: terminal-table
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: bump
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec_junit_formatter
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: fuubar
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: vcr
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: webmock
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ description:
168
+ email:
169
+ - venkat@xaptum.com
170
+ executables:
171
+ - enfcli
172
+ extensions: []
173
+ extra_rdoc_files: []
174
+ files:
175
+ - ".circleci/Dockerfile"
176
+ - ".circleci/build.sh"
177
+ - ".circleci/config.yml"
178
+ - ".circleci/setup-rubygems.sh"
179
+ - ".gitignore"
180
+ - Gemfile
181
+ - Gemfile.lock
182
+ - LICENSE
183
+ - Makefile
184
+ - README.md
185
+ - Rakefile
186
+ - bin/enfcli
187
+ - enfcli.gemspec
188
+ - lib/enfapi.rb
189
+ - lib/enfcli.rb
190
+ - lib/enfcli/commands/user.rb
191
+ - lib/enfcli/commands/xcr.rb
192
+ - lib/enfcli/commands/xfw.rb
193
+ - lib/enfcli/commands/xiam.rb
194
+ - lib/enfcli/version.rb
195
+ - lib/enfthor.rb
196
+ homepage: https://www.xaptum.com
197
+ licenses: []
198
+ metadata: {}
199
+ post_install_message:
200
+ rdoc_options: []
201
+ require_paths:
202
+ - lib
203
+ required_ruby_version: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - ">="
206
+ - !ruby/object:Gem::Version
207
+ version: '0'
208
+ required_rubygems_version: !ruby/object:Gem::Requirement
209
+ requirements:
210
+ - - ">"
211
+ - !ruby/object:Gem::Version
212
+ version: 1.3.1
213
+ requirements: []
214
+ rubygems_version: 3.0.1
215
+ signing_key:
216
+ specification_version: 4
217
+ summary: Xaptum ENF CLI.
218
+ test_files: []