securevpn-xyz-http-hooks 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +3 -0
  4. data/Gemfile.lock +39 -0
  5. data/LICENSE +19 -0
  6. data/README.md +22 -0
  7. data/bin/openvpn-activate +6 -0
  8. data/bin/openvpn-authenticate +8 -0
  9. data/bin/openvpn-connect +6 -0
  10. data/bin/openvpn-disconnect +7 -0
  11. data/lib/api/activation.rb +37 -0
  12. data/lib/api/authentication.rb +23 -0
  13. data/lib/api/billing.rb +55 -0
  14. data/lib/api/connect.rb +21 -0
  15. data/lib/api/connection.rb +70 -0
  16. data/lib/api/disconnect.rb +21 -0
  17. data/lib/exceptions/option_not_found.rb +2 -0
  18. data/lib/openvpn-http-hooks.rb +19 -0
  19. data/lib/openvpn_password_authenticator.rb +18 -0
  20. data/lib/option/base.rb +30 -0
  21. data/lib/option/i2p.rb +28 -0
  22. data/lib/option/proxy.rb +66 -0
  23. data/lib/option/repository.rb +18 -0
  24. data/lib/signer.rb +7 -0
  25. data/lib/system/openvpn_status.rb +19 -0
  26. data/lib/system/openvpn_status_log_parser.rb +30 -0
  27. data/lib/system/openvpn_status_log_reader.rb +29 -0
  28. data/openvpn-http-hooks.gemspec +16 -0
  29. data/spec/fixtures/active_connections.txt +10 -0
  30. data/spec/fixtures/multiple_connections.txt +11 -0
  31. data/spec/lib/api/activation_spec.rb +30 -0
  32. data/spec/lib/api/authentication_spec.rb +29 -0
  33. data/spec/lib/api/billing_spec.rb +71 -0
  34. data/spec/lib/api/connect_spec.rb +40 -0
  35. data/spec/lib/api/connection_spec.rb +59 -0
  36. data/spec/lib/api/disconnect_spec.rb +40 -0
  37. data/spec/lib/openvpn_password_authenticator_spec.rb +52 -0
  38. data/spec/lib/option/base_spec.rb +26 -0
  39. data/spec/lib/option/i2p_spec.rb +19 -0
  40. data/spec/lib/option/proxy_spec.rb +32 -0
  41. data/spec/lib/option/repository_spec.rb +25 -0
  42. data/spec/lib/signer_spec.rb +21 -0
  43. data/spec/lib/system/openvpn_status_log_parser_spec.rb +25 -0
  44. data/spec/lib/system/openvpn_status_log_reader_spec.rb +33 -0
  45. data/spec/lib/system/openvpn_status_spec.rb +22 -0
  46. data/spec/spec_helper.rb +9 -0
  47. metadata +133 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b44cd788085a4c09799e288dcd99b93276321417
4
+ data.tar.gz: def5da481d4276d9e4734e3c7fa45be26cf05c3b
5
+ SHA512:
6
+ metadata.gz: ba5b11c6e6fe537655872815b1c61139ea26a77ce7045b6b41cd286aa4a880446bb6c22a9eeace2950bd3658a0e7b51100712d9f7beef5f98c58b2e9083b45b2
7
+ data.tar.gz: 0ae7d404cb044d19da4bc3f013620d196a58166a95a760fd7d055ad6d85782d6e708b9631b4bf5d09eb420940b661a87d0c1b9dcf36a1f4c7098db37c5eb3e1e
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,39 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ securevpn-xyz-http-hooks (1.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ addressable (2.3.5)
10
+ crack (0.4.2)
11
+ safe_yaml (~> 1.0.0)
12
+ diff-lcs (1.2.5)
13
+ metaclass (0.0.4)
14
+ mocha (1.0.0)
15
+ metaclass (~> 0.0.1)
16
+ rspec (2.14.1)
17
+ rspec-core (~> 2.14.0)
18
+ rspec-expectations (~> 2.14.0)
19
+ rspec-mocks (~> 2.14.0)
20
+ rspec-core (2.14.8)
21
+ rspec-expectations (2.14.5)
22
+ diff-lcs (>= 1.1.3, < 2.0)
23
+ rspec-mocks (2.14.6)
24
+ safe_yaml (1.0.1)
25
+ webmock (1.17.4)
26
+ addressable (>= 2.2.7)
27
+ crack (>= 0.3.2)
28
+
29
+ PLATFORMS
30
+ ruby
31
+
32
+ DEPENDENCIES
33
+ mocha
34
+ rspec
35
+ securevpn-xyz-http-hooks!
36
+ webmock
37
+
38
+ BUNDLED WITH
39
+ 1.10.6
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2015 securevpn.xyz
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,22 @@
1
+ #### openvpn-http-hooks
2
+
3
+ This ruby gem is wrapper for OpenVPN server daemon.
4
+
5
+ The main purpose of this gem - is to interact with remote API, located at billing system.
6
+
7
+ This allows to authenticate user, track his connects/disconnects, apply hooks on connect/disconnect.
8
+
9
+ ### Hooks
10
+
11
+ Built-in hooks allow to implement following features for specific user:
12
+
13
+ * Automatic routing of I2P sites through I2P router
14
+ * Automatic routing of TOR sites through TOR router
15
+ * Applying selected proxy for all HTTP traffic of specific user
16
+
17
+ ### Disclaimer
18
+
19
+ This is OpenSource, Free software. You may use it anyway you want. It is provided AS IS.
20
+
21
+ Check out LICENSE file for more info.
22
+
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'openvpn-http-hooks'
4
+
5
+ api = Api::Activation.new
6
+ api.activate
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'openvpn-http-hooks'
4
+
5
+ api_adapter_class = Api::Authentication
6
+
7
+ authenticator = OpenvpnPasswordAuthenticator.new(ARGV, api_adapter_class)
8
+ authenticator.authenticate
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'openvpn-http-hooks'
4
+
5
+ connection = Api::Connect.new
6
+ connection.invoke
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'openvpn-http-hooks'
4
+
5
+ connection = Api::Disconnect.new
6
+ connection.invoke
7
+
@@ -0,0 +1,37 @@
1
+ require File.expand_path('../billing', __FILE__)
2
+
3
+ module Api
4
+ class Activation < Billing
5
+
6
+ def activate
7
+ if activated_successfully?
8
+ save_auth_key
9
+ else
10
+ raise "Can't activate server at billing"
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def activated_successfully?
17
+ success_api_call?
18
+ end
19
+
20
+ def save_auth_key
21
+ key = JSON.parse(api_call_result.body)["auth_key"]
22
+ File.open('/etc/openvpn/auth_key', 'w') { |file| file.write(key) }
23
+ end
24
+
25
+ def signed_data
26
+ data
27
+ end
28
+
29
+ def data
30
+ "hostname=#{hostname}"
31
+ end
32
+
33
+ def action
34
+ "activate"
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path('../billing', __FILE__)
2
+
3
+ module Api
4
+ class Authentication < Billing
5
+ def initialize(login, password)
6
+ @login, @password = login, password
7
+ end
8
+
9
+ def valid_credentials?
10
+ success_api_call?
11
+ end
12
+
13
+ private
14
+
15
+ def data
16
+ "login=#{@login}&password=#{@password}&hostname=#{hostname}"
17
+ end
18
+
19
+ def action
20
+ "auth"
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,55 @@
1
+ require "socket"
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'uri'
5
+ require 'json'
6
+
7
+ require File.expand_path('../../signer', __FILE__)
8
+
9
+ module Api
10
+ class Billing
11
+ API_HOST = "api.securevpn.xyz"
12
+ KEY_PATH = "/etc/openvpn/auth_key"
13
+
14
+ def host_with_port
15
+ "https://#{API_HOST}"
16
+ end
17
+
18
+ def auth_key
19
+ File.read(KEY_PATH)
20
+ end
21
+
22
+ def hostname
23
+ Socket.gethostname
24
+ end
25
+
26
+ def success_api_call?
27
+ api_call_result.code == '200'
28
+ end
29
+
30
+ def response
31
+ JSON.parse(api_call_result.body)
32
+ end
33
+
34
+ def api_call_result
35
+ http = Net::HTTP.new(uri.host, uri.port)
36
+ http.use_ssl = true
37
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
38
+
39
+ request = Net::HTTP::Post.new(uri.path)
40
+ request["content-type"] = 'application/x-www-form-urlencoded'
41
+ request.body = signed_data
42
+
43
+ @api_result ||= http.request(request)
44
+ end
45
+
46
+ def uri
47
+ URI("#{host_with_port}/api/#{action}")
48
+ end
49
+
50
+ def signed_data
51
+ data
52
+ #data + "&signature=#{Signer.sign_hash(data, auth_key)}"
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,21 @@
1
+ module Api
2
+ class Connect < Connection
3
+ def invoke
4
+ invoke_if_valid_api_call do
5
+ activate_options
6
+ end
7
+ end
8
+
9
+ def action
10
+ 'connect'
11
+ end
12
+
13
+ private
14
+
15
+ def activate_options
16
+ options.each do |code, data_array|
17
+ data[:option_class].activate(common_name, data[:attributes])
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,70 @@
1
+ require File.expand_path('../billing', __FILE__)
2
+
3
+ module Api
4
+ class Connection < Billing
5
+ def invoke_if_valid_api_call(&block)
6
+ yield if success_api_call?
7
+ trigger_script_return
8
+ end
9
+
10
+ def trigger_script_return
11
+ if success_api_call?
12
+ exit 0
13
+ else
14
+ exit 1
15
+ end
16
+ end
17
+
18
+ def common_name
19
+ response["common_name"]
20
+ end
21
+
22
+ def options
23
+ result = {}
24
+ option_codes.reduce(result) do |options_with_codes, option_code|
25
+ options_with_codes[option_code] =
26
+ {
27
+ option_class: Option::Repository.find_by_code(option_code),
28
+ attributes: attributes_for_option(option_code)
29
+ }
30
+ options_with_codes
31
+ end
32
+ result
33
+ end
34
+
35
+ private
36
+
37
+ def data
38
+ "hostname=#{hostname}&traffic_in=#{traffic_in}&traffic_out=#{traffic_out}&login=#{response["common_name"]}"
39
+ end
40
+
41
+ def data_array
42
+ {
43
+ hostname: hostname,
44
+ traffic_in: traffic_in,
45
+ traffic_out: traffic_out,
46
+ login: ENV['common_name']
47
+ }
48
+ end
49
+
50
+ def option_codes
51
+ response["options"]
52
+ end
53
+
54
+ def option_attributes
55
+ response["option_attributes"]
56
+ end
57
+
58
+ def attributes_for_option(code)
59
+ option_attributes[code]
60
+ end
61
+
62
+ def traffic_in
63
+ ENV['bytes_received'] || "0"
64
+ end
65
+
66
+ def traffic_out
67
+ ENV['bytes_sent'] || "0"
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,21 @@
1
+ module Api
2
+ class Disconnect < Connection
3
+ def invoke
4
+ invoke_if_valid_api_call do
5
+ deactivate_options
6
+ end
7
+ end
8
+
9
+ def action
10
+ 'disconnect'
11
+ end
12
+
13
+ private
14
+
15
+ def deactivate_options
16
+ options.each do |code, data|
17
+ data[:option_class].deactivate(common_name, data[:attributes])
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,2 @@
1
+ class OptionNotFound < StandardError
2
+ end
@@ -0,0 +1,19 @@
1
+ require 'api/activation'
2
+ require 'api/authentication'
3
+ require 'api/connection'
4
+ require 'api/connect'
5
+ require 'api/disconnect'
6
+
7
+ require 'option/base'
8
+ require 'option/i2p'
9
+ require 'option/proxy'
10
+ require 'option/repository'
11
+
12
+ require 'system/openvpn_status'
13
+ require 'system/openvpn_status_log_reader'
14
+ require 'system/openvpn_status_log_parser'
15
+
16
+ require 'exceptions/option_not_found'
17
+
18
+ require 'openvpn_password_authenticator'
19
+ require 'signer'
@@ -0,0 +1,18 @@
1
+ class OpenvpnPasswordAuthenticator
2
+ attr_accessor :api
3
+
4
+ def initialize(args, api_adapter_class)
5
+ content = File.read(args[0])
6
+ @login, @password = content.split("\n")
7
+ @api = api_adapter_class.new(@login, @password)
8
+ end
9
+
10
+ def authenticate
11
+ if @api.valid_credentials?
12
+ exit 0
13
+ else
14
+ exit 1
15
+ end
16
+ end
17
+
18
+ end
@@ -0,0 +1,30 @@
1
+ module Option
2
+ class Base
3
+ attr_accessor :common_name, :attributes
4
+
5
+ class << self
6
+ def activate(common_name, attributes={})
7
+ option_object = new(common_name, attributes)
8
+ option_object.activate!
9
+ end
10
+
11
+ def deactivate(common_name, attributes={})
12
+ option_object = new(common_name, attributes)
13
+ option_object.deactivate!
14
+ end
15
+ end
16
+
17
+ def initialize(common_name, attributes)
18
+ @common_name = common_name
19
+ @attributes = attributes
20
+ end
21
+
22
+ def virtual_ip
23
+ System::OpenvpnStatus.current_virtual_address
24
+ end
25
+
26
+ def server_virtual_ip
27
+ System::OpenvpnStatus.server_virtual_address
28
+ end
29
+ end
30
+ end