securevpn-xyz-http-hooks 1.3.3
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 +7 -0
- data/.rspec +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +39 -0
- data/LICENSE +19 -0
- data/README.md +22 -0
- data/bin/openvpn-activate +6 -0
- data/bin/openvpn-authenticate +8 -0
- data/bin/openvpn-connect +6 -0
- data/bin/openvpn-disconnect +7 -0
- data/lib/api/activation.rb +37 -0
- data/lib/api/authentication.rb +23 -0
- data/lib/api/billing.rb +55 -0
- data/lib/api/connect.rb +21 -0
- data/lib/api/connection.rb +70 -0
- data/lib/api/disconnect.rb +21 -0
- data/lib/exceptions/option_not_found.rb +2 -0
- data/lib/openvpn-http-hooks.rb +19 -0
- data/lib/openvpn_password_authenticator.rb +18 -0
- data/lib/option/base.rb +30 -0
- data/lib/option/i2p.rb +28 -0
- data/lib/option/proxy.rb +66 -0
- data/lib/option/repository.rb +18 -0
- data/lib/signer.rb +7 -0
- data/lib/system/openvpn_status.rb +19 -0
- data/lib/system/openvpn_status_log_parser.rb +30 -0
- data/lib/system/openvpn_status_log_reader.rb +29 -0
- data/openvpn-http-hooks.gemspec +16 -0
- data/spec/fixtures/active_connections.txt +10 -0
- data/spec/fixtures/multiple_connections.txt +11 -0
- data/spec/lib/api/activation_spec.rb +30 -0
- data/spec/lib/api/authentication_spec.rb +29 -0
- data/spec/lib/api/billing_spec.rb +71 -0
- data/spec/lib/api/connect_spec.rb +40 -0
- data/spec/lib/api/connection_spec.rb +59 -0
- data/spec/lib/api/disconnect_spec.rb +40 -0
- data/spec/lib/openvpn_password_authenticator_spec.rb +52 -0
- data/spec/lib/option/base_spec.rb +26 -0
- data/spec/lib/option/i2p_spec.rb +19 -0
- data/spec/lib/option/proxy_spec.rb +32 -0
- data/spec/lib/option/repository_spec.rb +25 -0
- data/spec/lib/signer_spec.rb +21 -0
- data/spec/lib/system/openvpn_status_log_parser_spec.rb +25 -0
- data/spec/lib/system/openvpn_status_log_reader_spec.rb +33 -0
- data/spec/lib/system/openvpn_status_spec.rb +22 -0
- data/spec/spec_helper.rb +9 -0
- 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
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
|
+
|
data/bin/openvpn-connect
ADDED
@@ -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
|
data/lib/api/billing.rb
ADDED
@@ -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
|
data/lib/api/connect.rb
ADDED
@@ -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,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
|
data/lib/option/base.rb
ADDED
@@ -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
|