diff --git a/.gitignore b/.gitignore index a5d8c54..6c39503 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ test/version_tmp tmp .ruby-version .ruby-gemset +.ovpnmcgen.rb.yml diff --git a/.travis.yml b/.travis.yml index 602ae0e..c74d09e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ before_install: rvm: - 1.9.3 - 2.0.0 - - 2.1-head + - 2.1 - ruby-head - jruby-19mode diff --git a/ChangeLog b/ChangeLog index e55fa39..dade8bc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ += 0.4.0 / 2014-05-04 + * VoD rules in `--[un]trusted-ssids` to also use `InterfaceTypeMatch`. + * Added support for configuration persistance, via ENV or ~/.ovpnmcgen.rb.yml or `--config` flag. + = 0.3.0 / 2014-05-04 * Documentation updates. * Added support for `URLStringProbe`, via `--url-probe`. diff --git a/README.md b/README.md index ccddd9a..4795929 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ Build and install the gem: Usage: ovpnmcgen.rb generate [options] Options: + -c, --config FILE Specify path to config file. [Default: .ovpnmcgen.rb.yml] --cafile FILE Path to OpenVPN CA file. (Required) --tafile FILE Path to TLS-Auth Key file. --host HOSTNAME Hostname of OpenVPN server. (Required) @@ -63,6 +64,12 @@ Usage: ovpnmcgen.rb generate [options] -o, --output FILE Output to file. [Default: stdout] ``` +### Configuration + +Option flags can be set using environment variables or placed into a YAML formatted file. The default filename `.ovpnmcgen.rb.yml` will be searched for in `./`, and then `~/`. + +Note: Only for YAML configuration files and environment variables, flags with hyphens (-) are replaced with underscores (_), i.e. `--trusted-ssids safe` should be `trusted_ssids: safe`. + ### Security Levels There are three different security levels to choose from, 'paranoid', 'high' (default), and 'medium'. The algorithm illustrated above is for 'high'. diff --git a/bin/ovpnmcgen.rb b/bin/ovpnmcgen.rb index 8658926..00398a5 100755 --- a/bin/ovpnmcgen.rb +++ b/bin/ovpnmcgen.rb @@ -2,6 +2,7 @@ require 'ovpnmcgen' require 'commander/import' +require 'ovpnmcgen/config' program :version, Ovpnmcgen::VERSION program :description, Ovpnmcgen::SUMMARY @@ -9,7 +10,7 @@ program :help_formatter, :compact default_command :help never_trace! -#global_option '-c', '--config FILE', 'Specify path to config file' #not implemented yet +global_option '-c', '--config FILE', 'Specify path to config file. [Default: .ovpnmcgen.rb.yml]' command :generate do |c| c.syntax = 'ovpnmcgen.rb generate [options] ' @@ -37,31 +38,53 @@ c.option '-o', '--output FILE', 'Output to file. [Default: stdout]' c.action do |args, options| raise ArgumentError.new "Invalid arguments. Run '#{File.basename(__FILE__)} help generate' for guidance" if args.nil? or args.length < 2 - raise ArgumentError.new "Host is required" unless options.host - raise ArgumentError.new "cafile is required" unless options.cafile - raise ArgumentError.new "PKCS#12 file is required" unless options.p12file - options.default :vod => true, :proto => 'udp', :port => 1194, :security_level => 'high' - user, device, p12file, p12pass = args + + # Set up configuration environment. + if options.config + Ovpnmcgen.configure(options.config) + else + Ovpnmcgen.configure + end + config = Ovpnmcgen.config + + raise ArgumentError.new "Host is required" unless options.host or config.host + raise ArgumentError.new "cafile is required" unless options.cafile or config.cafile + raise ArgumentError.new "PKCS#12 file is required" unless options.p12file or config.p12file + + options.default :vod => case + when config.vod == true || config.no_vod == false + true + when config.vod == false || config.no_vod == true + false + else # enabled by default + true + end, + :proto => (config.proto)? config.proto : 'udp', + :port => (config.port)? config.port : 1194, + :security_level => (config.security_level)? config.security_level : 'high' + + user, device = args + inputs = { :user => user, :device => device, - :p12file => options.p12file, - :p12pass => options.p12pass, - :cafile => options.cafile, - :host => options.host, + :p12file => options.p12file || config.p12file, + :p12pass => options.p12pass || config.p12pass, + :cafile => options.cafile || config.cafile, + :host => options.host || config.host, :proto => options.proto, :port => options.port, :enableVOD => options.vod, - :trusted_ssids => options.trusted_ssids, - :untrusted_ssids => options.untrusted_ssids, - :profile_uuid => options.profile_uuid, - :vpn_uuid => options.vpn_uuid, - :cert_uuid => options.cert_uuid, + :trusted_ssids => options.trusted_ssids || config.trusted_ssids, + :untrusted_ssids => options.untrusted_ssids || config.untrusted_ssids, + :profile_uuid => options.profile_uuid || config.profile_uuid, + :vpn_uuid => options.vpn_uuid || config.vpn_uuid, + :cert_uuid => options.cert_uuid || config.cert_uuid, :security_level => options.security_level } - inputs[:ovpnconfigfile] = options.ovpnconfigfile if options.ovpnconfigfile - inputs[:tafile] = options.tafile if options.tafile - inputs[:url_probe] = options.url_probe if options.url_probe + inputs[:ovpnconfigfile] = options.ovpnconfigfile || config.ovpnconfigfile if options.ovpnconfigfile or config.ovpnconfigfile + inputs[:tafile] = options.tafile || config.tafile if options.tafile or config.tafile + inputs[:url_probe] = options.url_probe || config.url_probe if options.url_probe or config.url_probe unless options.output puts Ovpnmcgen.generate(inputs) diff --git a/features/gen_basic.feature b/features/gen_basic.feature index ab8bc5e..7b87f74 100644 --- a/features/gen_basic.feature +++ b/features/gen_basic.feature @@ -156,6 +156,8 @@ Feature: Basic Generate Functionality Then the output should match: """ Disconnect + \s*InterfaceTypeMatch + \s*WiFi \s*SSIDMatch \s* \s*trusted1 @@ -165,6 +167,8 @@ Feature: Basic Generate Functionality And the output should match: """ Connect + \s*InterfaceTypeMatch + \s*WiFi \s*SSIDMatch \s* \s*evil3 diff --git a/features/gen_configfile.feature b/features/gen_configfile.feature new file mode 100644 index 0000000..41d065b --- /dev/null +++ b/features/gen_configfile.feature @@ -0,0 +1,129 @@ +Feature: Generate Functionality with Configuration File + In order to generate a properly formatted plist mobileconfig with less typing + As a CLI + Some basic inputs are taken from a config file, if available + + Background: + Given a file named "ca.crt" with: + """ + Contents of CA file + With newlines + And more newlines + That should appear as one line + """ + And a file named "p12file.p12" with: + """ + p12file that should appear + In base64 encoding as + """ + + Scenario: A configuration file supplied should be read, without the need for required flags. + Given a file named ".ovpnmcgen.rb.yml" with: + """ + host: aruba.cucumber.org + """ + When I run `ovpnmcgen.rb g cucumber aruba` + Then the output should contain "error: " + And the output should not contain "error: Host" + + Scenario: A custom configuration file supplied should be read, without the need for required flags. + Given a file named ".custom.yml" with: + """ + host: aruba.cucumber.org + """ + When I run `ovpnmcgen.rb g --config .custom.yml cucumber aruba` + Then the output should contain "error: " + And the output should not contain "error: Host" + + Scenario: Flags should override configuration file options. + Given a file named ".ovpnmcgen.rb.yml" with: + """ + host: file.org + no_vod: true + """ + When I run `ovpnmcgen.rb g --host aruba.cucumber.org --cafile ca.crt --vod --p12file p12file.p12 cucumber aruba` + Then the output should match: + """ + remote + \s*aruba.cucumber.org 1194 udp + """ + And the output should match: + """ + OnDemandEnabled + \s*1 + """ + And the output should not match: + """ + remote + \s*file.org 1194 udp + """ + + Scenario: Battle between no-vod in the configuration file and the vod flag default. + Given a file named ".ovpnmcgen.rb.yml" with: + """ + no_vod: false + """ + When I run `ovpnmcgen.rb g --host aruba.cucumber.org --cafile ca.crt --p12file p12file.p12 cucumber aruba` + Then the output should match: + """ + OnDemandEnabled + \s*1 + """ + + Scenario: no_vod true in the configuration file. + Given a file named ".ovpnmcgen.rb.yml" with: + """ + no_vod: true + """ + When I run `ovpnmcgen.rb g --host aruba.cucumber.org --cafile ca.crt --p12file p12file.p12 cucumber aruba` + Then the output should match: + """ + OnDemandEnabled + \s*0 + """ + + Scenario: ENV variables set here should work. + Given I set the environment variable "OG_HOST" to "env.org" + When I run `/usr/bin/env` + Then the output should contain "OG_HOST=env.org" + + Scenario: ENV variables should override configuration file options. + Given a file named ".ovpnmcgen.rb.yml" with: + """ + host: file.org + """ + And I set the environment variable "OG_HOST" to "env.org" + When I run `ovpnmcgen.rb g --cafile ca.crt --p12file p12file.p12 cucumber aruba` + Then the output should match: + """ + remote + \s*env.org 1194 udp + """ + And the output should not match: + """ + remote + \s*file.org 1194 udp + """ + + Scenario: Flags should overrride ENV variables, and should also override configuration file options. + Given a file named ".ovpnmcgen.rb.yml" with: + """ + host: file.org + """ + And I set the environment variable "OG_HOST" to "env.org" + When I run `ovpnmcgen.rb g --host aruba.cucumber.org --cafile ca.crt --p12file p12file.p12 cucumber aruba` + Then the output should match: + """ + remote + \s*aruba.cucumber.org 1194 udp + """ + And the output should not match: + """ + remote + \s*env.org 1194 udp + """ + And the output should not match: + """ + remote + \s*file.org 1194 udp + """ diff --git a/features/step_definitions/env.rb b/features/step_definitions/env.rb new file mode 100644 index 0000000..294332a --- /dev/null +++ b/features/step_definitions/env.rb @@ -0,0 +1,3 @@ +Given /^I set the environment variable "(\w+)" to "([^"]*)"$/ do |var, value| + ENV[var] = value +end diff --git a/lib/ovpnmcgen.rb b/lib/ovpnmcgen.rb index c7adeef..0b3b286 100644 --- a/lib/ovpnmcgen.rb +++ b/lib/ovpnmcgen.rb @@ -56,10 +56,12 @@ def generate(inputs = {}) vpnOnDemandRules = Array.new vodTrusted = { # Trust only Wifi SSID + 'InterfaceTypeMatch' => 'WiFi', 'SSIDMatch' => trusted_ssids, 'Action' => 'Disconnect' } vodUntrusted = { # Untrust Wifi + 'InterfaceTypeMatch' => 'WiFi', 'SSIDMatch' => untrusted_ssids, 'Action' => 'Connect' } @@ -88,7 +90,12 @@ def generate(inputs = {}) } # Insert URLStringProbe conditions when enabled with --url-probe - vodTrusted['URLStringProbe'] = vodUntrusted['URLStringProbe'] = vodWifiOnly['URLStringProbe'] = vodCellularOnly['URLStringProbe'] = vodDefault['URLStringProbe'] = inputs[:url_probe] if inputs[:url_probe] + vodTrusted['URLStringProbe'] = + vodUntrusted['URLStringProbe'] = + vodWifiOnly['URLStringProbe'] = + vodCellularOnly['URLStringProbe'] = + vodDefault['URLStringProbe'] = + inputs[:url_probe] if inputs[:url_probe] vpnOnDemandRules << vodTrusted if trusted_ssids vpnOnDemandRules << vodUntrusted if untrusted_ssids diff --git a/lib/ovpnmcgen/config.rb b/lib/ovpnmcgen/config.rb new file mode 100644 index 0000000..49648bd --- /dev/null +++ b/lib/ovpnmcgen/config.rb @@ -0,0 +1,22 @@ +require 'app_configuration' + +module Ovpnmcgen + @@config_file_name = '.ovpnmcgen.rb.yml' + + # attr_accessor :config, :config_file_name + + def configure(filename = @@config_file_name) + + @@config = AppConfiguration.new filename do + prefix 'og' + end + + # @@config = AppConfiguration[:ovpnmcgen] + end + + def config + @@config + end + + module_function :configure, :config +end diff --git a/lib/ovpnmcgen/version.rb b/lib/ovpnmcgen/version.rb index e355a70..48dc7db 100644 --- a/lib/ovpnmcgen/version.rb +++ b/lib/ovpnmcgen/version.rb @@ -1,4 +1,4 @@ module Ovpnmcgen - VERSION = "0.3.0" + VERSION = "0.4.0" SUMMARY = "An OpenVPN iOS Configuration Profile (.mobileconfig) Utility" end diff --git a/ovpnmcgen.rb.gemspec b/ovpnmcgen.rb.gemspec index 297feb1..e557af8 100644 --- a/ovpnmcgen.rb.gemspec +++ b/ovpnmcgen.rb.gemspec @@ -25,4 +25,5 @@ Gem::Specification.new do |spec| spec.add_development_dependency "aruba", "~> 0.5", ">= 0.5.4" spec.add_runtime_dependency "plist", "~> 3.1", ">= 3.1.0" spec.add_runtime_dependency "commander", "~> 4.1", ">= 4.1.6" + spec.add_runtime_dependency "app_configuration", "~> 0.0", ">= 0.0.2" end