forward 0.0.14 → 0.1.0
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.
- data/lib/forward.rb +8 -0
- data/lib/forward/api.rb +1 -1
- data/lib/forward/api/client_log.rb +2 -10
- data/lib/forward/api/tunnel.rb +2 -2
- data/lib/forward/api/{public_key.rb → tunnel_key.rb} +3 -3
- data/lib/forward/cli.rb +6 -10
- data/lib/forward/client.rb +4 -3
- data/lib/forward/config.rb +87 -59
- data/lib/forward/version.rb +1 -1
- data/test/api/{public_key_test.rb → tunnel_key_test.rb} +5 -5
- data/test/api/tunnel_test.rb +3 -6
- data/test/config_test.rb +33 -40
- data/test/test_helper.rb +1 -0
- metadata +5 -5
data/lib/forward.rb
CHANGED
data/lib/forward/api.rb
CHANGED
@@ -7,22 +7,14 @@ module Forward
|
|
7
7
|
resource.uri = '/api/client_logs'
|
8
8
|
params = {
|
9
9
|
:client => Forward.client_string,
|
10
|
-
:log => log
|
10
|
+
:log => log
|
11
11
|
}
|
12
12
|
|
13
|
-
params[:
|
13
|
+
params[:api_token] = Forward.config.api_token unless Forward.config.nil?
|
14
14
|
|
15
15
|
resource.post(params)
|
16
16
|
end
|
17
17
|
|
18
|
-
private
|
19
|
-
|
20
|
-
def self.user_id
|
21
|
-
if !Forward.client.nil? && !Forward.client.config.nil?
|
22
|
-
Forward.client.config.id
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
18
|
end
|
27
19
|
end
|
28
20
|
end
|
data/lib/forward/api/tunnel.rb
CHANGED
@@ -62,8 +62,8 @@ module Forward
|
|
62
62
|
def self.destroy_and_create(id)
|
63
63
|
Forward.log(:debug, "Destroying tunnel: #{id}")
|
64
64
|
destroy(id)
|
65
|
-
puts "tunnel removed, creating
|
66
|
-
create
|
65
|
+
puts "tunnel removed, now we're creating a new one"
|
66
|
+
create(Forward.client.options)
|
67
67
|
end
|
68
68
|
|
69
69
|
def self.create_error(errors)
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module Forward
|
2
2
|
module Api
|
3
|
-
class
|
3
|
+
class TunnelKey < Resource
|
4
4
|
|
5
5
|
def self.create
|
6
|
-
resource =
|
7
|
-
resource.uri = '/api/
|
6
|
+
resource = TunnelKey.new(:create)
|
7
|
+
resource.uri = '/api/tunnel_keys'
|
8
8
|
|
9
9
|
response = resource.post
|
10
10
|
|
data/lib/forward/cli.rb
CHANGED
@@ -193,16 +193,12 @@ module Forward
|
|
193
193
|
#
|
194
194
|
# Returns a Hash with the email and password.
|
195
195
|
def self.authenticate
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
Forward.log(:debug, "Authenticating User: `#{email}:#{password.gsub(/./, 'x')}'")
|
203
|
-
|
204
|
-
{ :email => email, :password => password }
|
205
|
-
end
|
196
|
+
puts 'Enter your email and password'
|
197
|
+
email = ask('email: ').chomp
|
198
|
+
password = ask('password: ') { |q| q.echo = false }.chomp
|
199
|
+
Forward.log(:debug, "Authenticating User: `#{email}:#{password.gsub(/./, 'x')}'")
|
200
|
+
|
201
|
+
{ :email => email, :password => password }
|
206
202
|
end
|
207
203
|
|
208
204
|
# Parses various options and arguments, validates everything to ensure
|
data/lib/forward/client.rb
CHANGED
@@ -53,17 +53,18 @@ module Forward
|
|
53
53
|
trap(:INT) { cleanup_and_exit!('closing tunnel and exiting...') }
|
54
54
|
|
55
55
|
Forward.client = @client = Client.new(options)
|
56
|
-
@tunnel
|
56
|
+
@tunnel = @client.setup_tunnel
|
57
|
+
@session = Net::SSH.start(@tunnel.tunneler, Forward.ssh_user, @client.ssh_options)
|
57
58
|
|
58
59
|
Forward.log(:debug, "Starting remote forward at #{@tunnel.subdomain}.fwd.wf on port #{@tunnel.port}")
|
59
60
|
puts "Forwarding port #{@tunnel.hostport} at \033[04mhttps://#{@tunnel.subdomain}.fwd.wf\033[m\nCtrl-C to stop forwarding"
|
60
|
-
|
61
|
+
|
61
62
|
@session.forward.remote(@tunnel.hostport, @tunnel.host, @tunnel.port)
|
62
63
|
@session.loop { watch_session(@session) }
|
63
64
|
|
64
65
|
rescue Net::SSH::AuthenticationFailed => e
|
65
66
|
Forward.log(:fatal, "SSH Auth failed `#{e}'")
|
66
|
-
cleanup_and_exit!("Authentication failed, try deleting `#{Forward::Config
|
67
|
+
cleanup_and_exit!("Authentication failed, try deleting `#{Forward::Config.config_path}' and giving it another go. If the problem continues, contact support@forwardhq.com")
|
67
68
|
rescue => e
|
68
69
|
Forward.log(:fatal, "#{e.message}\n#{e.backtrace.join("\n")}")
|
69
70
|
cleanup_and_exit!("You've been disconnected...")
|
data/lib/forward/config.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'rbconfig'
|
3
|
+
require 'yaml'
|
4
|
+
|
1
5
|
module Forward
|
2
6
|
class Config
|
3
|
-
|
4
|
-
CIPHER_LENGTH = 128
|
5
|
-
CIPHER_MODE = :CBC
|
6
|
-
DELIMETER = '-------M-------'
|
7
|
+
CONFIG_FILE_VALUES = [ :api_token ]
|
7
8
|
|
8
9
|
attr_accessor :id
|
9
10
|
attr_accessor :api_token
|
@@ -39,12 +40,11 @@ module Forward
|
|
39
40
|
Hash[instance_variables.map { |var| [var[1..-1].to_sym, instance_variable_get(var)] }]
|
40
41
|
end
|
41
42
|
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
43
|
+
# Validate that the required values are in the Config.
|
44
|
+
# Raises a config error if values are missing.
|
45
45
|
def validate
|
46
46
|
Forward.log(:debug, 'Validating Config')
|
47
|
-
attributes = [:
|
47
|
+
attributes = [:api_token, :private_key]
|
48
48
|
errors = []
|
49
49
|
|
50
50
|
attributes.each do |attribute|
|
@@ -58,62 +58,76 @@ module Forward
|
|
58
58
|
elsif errors.length >= 2
|
59
59
|
raise ConfigError, "#{errors.join(', ')} are required fields"
|
60
60
|
end
|
61
|
-
|
62
61
|
end
|
63
62
|
|
63
|
+
# Write the current config data to `config_path', and the current
|
64
|
+
# private_key to `key_path'.
|
64
65
|
#
|
65
|
-
#
|
66
|
-
#
|
66
|
+
# Returns the Config object.
|
67
67
|
def write
|
68
68
|
Forward.log(:debug, 'Writing Config')
|
69
|
-
|
70
|
-
|
71
|
-
data = JSON.dump(self.to_hash)
|
72
|
-
cipher = OpenSSL::Cipher::AES.new(CIPHER_LENGTH, CIPHER_MODE)
|
73
|
-
cipher.encrypt
|
69
|
+
key_folder = File.dirname(Config.key_path)
|
70
|
+
config_data = to_hash.delete_if { |k,v| !CONFIG_FILE_VALUES.include?(k) }
|
74
71
|
|
75
|
-
|
76
|
-
iv = cipher.random_iv
|
77
|
-
|
78
|
-
encrypted_data = cipher.update(data) + cipher.final
|
79
|
-
config_data = Base64.encode64(encrypted_data)
|
80
|
-
config_data << DELIMETER
|
81
|
-
config_data << Base64.encode64("#{key}::#{iv}")
|
72
|
+
self.validate
|
82
73
|
|
83
|
-
|
74
|
+
FileUtils.mkdir(key_folder) unless File.exist?(key_folder)
|
75
|
+
File.open(Config.config_path, 'w') { |f| f.write(YAML.dump(config_data)) }
|
76
|
+
File.open(Config.key_path, 'w') { |f| f.write(private_key) }
|
84
77
|
|
85
78
|
self
|
79
|
+
rescue
|
80
|
+
raise ConfigError, 'Unable to write config file'
|
86
81
|
end
|
87
82
|
|
83
|
+
# Shortcut for checking if host os is windows.
|
88
84
|
#
|
89
|
-
#
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
config_data = File.read(CONFIG_PATH)
|
94
|
-
encrypted_data, keys = config_data.split(DELIMETER).map { |d| Base64.decode64(d) }
|
95
|
-
key, iv = keys.split('::')
|
96
|
-
decipher = OpenSSL::Cipher::AES.new(CIPHER_LENGTH, CIPHER_MODE)
|
97
|
-
|
98
|
-
decipher.decrypt
|
99
|
-
|
100
|
-
decipher.key = key
|
101
|
-
decipher.iv = iv
|
85
|
+
# Returns true or false if windows or not.
|
86
|
+
def self.windows?
|
87
|
+
RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
|
88
|
+
end
|
102
89
|
|
103
|
-
|
90
|
+
# Returns the location of the forward ssh private key
|
91
|
+
# based on the host os.
|
92
|
+
#
|
93
|
+
# Returns the String path.
|
94
|
+
def self.key_path
|
95
|
+
if windows?
|
96
|
+
File.join(ENV['HOME'], 'forward', 'key')
|
97
|
+
else
|
98
|
+
File.join(ENV['HOME'], '.ssh', 'forwardhq.com')
|
99
|
+
end
|
100
|
+
end
|
104
101
|
|
105
|
-
|
106
|
-
|
107
|
-
|
102
|
+
# Returns the location of the forward config file
|
103
|
+
# based on the host os.
|
104
|
+
#
|
105
|
+
# Returns the String path.
|
106
|
+
def self.config_path
|
107
|
+
if windows?
|
108
|
+
File.join(ENV['HOME'], 'forward', 'config')
|
109
|
+
else
|
110
|
+
File.join(ENV['HOME'], '.forward')
|
111
|
+
end
|
108
112
|
end
|
109
113
|
|
110
114
|
# Checks to see if a .forward config file exists.
|
111
115
|
#
|
112
116
|
# Returns true or false based on the existence of the config file.
|
113
117
|
def self.present?
|
114
|
-
File.exist?
|
118
|
+
File.exist? config_path
|
119
|
+
end
|
120
|
+
|
121
|
+
# Checks to see if a `private_key' exist.
|
122
|
+
#
|
123
|
+
# Returns true or false based on the existence of the key file.
|
124
|
+
def self.key_file_present?
|
125
|
+
File.exist? key_path
|
115
126
|
end
|
116
127
|
|
128
|
+
# Create a config file if it doesn't exist, load one if it does.
|
129
|
+
#
|
130
|
+
# Returns the resulting Config object.
|
117
131
|
def self.create_or_load
|
118
132
|
if Config.present?
|
119
133
|
Config.load
|
@@ -122,42 +136,56 @@ module Forward
|
|
122
136
|
end
|
123
137
|
end
|
124
138
|
|
139
|
+
# Create a config by authenticating the user via the api,
|
140
|
+
# and saving the users api_token/id/private_key.
|
141
|
+
#
|
142
|
+
# Returns the new Config object.
|
125
143
|
def self.create
|
126
144
|
Forward.log(:debug, 'Creating Config')
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
145
|
+
if @updating_config || ask('Already have an account with Forward? ').chomp =~ /\Ay/i
|
146
|
+
config = Config.new
|
147
|
+
email, password = CLI.authenticate.values_at(:email, :password)
|
148
|
+
config.update(Forward::Api::User.api_token(email, password))
|
149
|
+
Forward::Api.token = config.api_token
|
150
|
+
config.private_key = Forward::Api::TunnelKey.create
|
151
|
+
|
152
|
+
config.write
|
153
|
+
else
|
154
|
+
Client.cleanup_and_exit!("You'll need a Forward account first. You can create one at \033[04mhttps://forwardhq.com\033[04m")
|
155
|
+
end
|
134
156
|
end
|
135
157
|
|
136
158
|
# It initializes a new Config instance, updates it with the config values
|
137
159
|
# from the config file, and raises an error if there's not a config or if
|
138
160
|
# the config options aren't valid.
|
139
161
|
#
|
140
|
-
# Returns the Config
|
162
|
+
# Returns the Config object.
|
141
163
|
def self.load
|
142
164
|
Forward.log(:debug, 'Loading Config')
|
143
165
|
config = Config.new
|
144
166
|
|
145
|
-
|
146
|
-
|
167
|
+
raise ConfigError, "Unable to find a forward config file at `#{config_path}'" unless Config.present?
|
168
|
+
|
169
|
+
if File.read(config_path).include? '-----M-----'
|
170
|
+
puts "Forward needs to update your config file, please re-authenticate"
|
171
|
+
File.delete(config_path)
|
172
|
+
@updating_config = true
|
173
|
+
create_or_load
|
147
174
|
end
|
148
175
|
|
176
|
+
raise ConfigError, "Unable to find a forward key file at `#{key_path}'" unless Config.key_file_present?
|
177
|
+
|
178
|
+
|
179
|
+
config.update(YAML.load_file(config_path).symbolize_keys)
|
180
|
+
config.private_key = File.read(key_path)
|
181
|
+
Forward::Api.token = config.api_token
|
182
|
+
|
149
183
|
config.validate
|
150
184
|
|
151
|
-
Forward
|
185
|
+
Forward.config = config
|
152
186
|
|
153
187
|
config
|
154
188
|
end
|
155
189
|
|
156
|
-
# Deletes the .forward config file if it exists.
|
157
|
-
def self.clear
|
158
|
-
Forward.log(:debug, 'Clearning Config')
|
159
|
-
File.delete(CONFIG_PATH) if Config.present?
|
160
|
-
end
|
161
|
-
|
162
190
|
end
|
163
191
|
end
|
data/lib/forward/version.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
describe Forward::Api::
|
3
|
+
describe Forward::Api::TunnelKey do
|
4
4
|
|
5
5
|
before :each do
|
6
6
|
FakeWeb.allow_net_connect = false
|
@@ -9,19 +9,19 @@ describe Forward::Api::PublicKey do
|
|
9
9
|
it 'retrieves the public_key and returns it' do
|
10
10
|
fake_body = { :private_key => 'ssh-key 1234567890' }
|
11
11
|
|
12
|
-
stub_api_request(:post, '/api/
|
12
|
+
stub_api_request(:post, '/api/tunnel_keys', :body => fake_body.to_json)
|
13
13
|
|
14
|
-
response = Api::
|
14
|
+
response = Api::TunnelKey.create
|
15
15
|
response.must_equal fake_body[:private_key]
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'exits with message if response has errors' do
|
19
19
|
fake_body = { :errors => { :base => 'Unable to retrieve a private key' } }
|
20
20
|
|
21
|
-
stub_api_request(:post, '/api/
|
21
|
+
stub_api_request(:post, '/api/tunnel_keys', :body => fake_body.to_json)
|
22
22
|
|
23
23
|
lambda {
|
24
|
-
dev_null { Api::
|
24
|
+
dev_null { Api::TunnelKey.create }
|
25
25
|
}.must_raise SystemExit
|
26
26
|
end
|
27
27
|
|
data/test/api/tunnel_test.rb
CHANGED
@@ -11,10 +11,9 @@ describe Forward::Api::Tunnel do
|
|
11
11
|
Forward.client = mock
|
12
12
|
fake_body = { :_id => '1', :subdomain => 'foo', :port => 56789 }
|
13
13
|
|
14
|
-
Forward.client.expects(:options).returns(:port => 3000)
|
15
14
|
stub_api_request(:post, '/api/tunnels', :body => fake_body.to_json)
|
16
15
|
|
17
|
-
response = Forward::Api::Tunnel.create
|
16
|
+
response = Forward::Api::Tunnel.create(:port => 3000)
|
18
17
|
|
19
18
|
fake_body.each do |key, value|
|
20
19
|
response[key].must_equal fake_body[key]
|
@@ -25,11 +24,10 @@ describe Forward::Api::Tunnel do
|
|
25
24
|
Forward.client = mock
|
26
25
|
fake_body = { :errors => { :base => [ 'unable to create tunnel' ] } }
|
27
26
|
|
28
|
-
Forward.client.expects(:options).returns(:port => 3000)
|
29
27
|
stub_api_request(:post, '/api/tunnels', :body => fake_body.to_json)
|
30
28
|
|
31
29
|
lambda {
|
32
|
-
dev_null { Forward::Api::Tunnel.create }
|
30
|
+
dev_null { Forward::Api::Tunnel.create(:port => 3000) }
|
33
31
|
}.must_raise SystemExit
|
34
32
|
end
|
35
33
|
|
@@ -41,13 +39,12 @@ describe Forward::Api::Tunnel do
|
|
41
39
|
]
|
42
40
|
index_body = [ { :_id => 'abc123' }, { :_id => 'def456' } ]
|
43
41
|
|
44
|
-
Forward.client.expects(:options).returns(:port => 3000).twice
|
45
42
|
stub_api_request(:post, '/api/tunnels', post_options)
|
46
43
|
stub_api_request(:get, '/api/tunnels', :body => index_body.to_json)
|
47
44
|
STDIN.expects(:gets).returns('1')
|
48
45
|
Forward::Api::Tunnel.expects(:destroy).with(index_body.first[:_id])
|
49
46
|
|
50
|
-
dev_null { Forward::Api::Tunnel.create }
|
47
|
+
dev_null { Forward::Api::Tunnel.create(:port => 3000) }
|
51
48
|
end
|
52
49
|
|
53
50
|
it 'destroys a tunnel and returns the attributes' do
|
data/test/config_test.rb
CHANGED
@@ -3,8 +3,7 @@ require 'test_helper'
|
|
3
3
|
describe Forward::Config do
|
4
4
|
|
5
5
|
before :each do
|
6
|
-
@
|
7
|
-
:id => '12345',
|
6
|
+
@config_attributes = {
|
8
7
|
:api_token => 'abcdefg',
|
9
8
|
:private_key => 'secret'
|
10
9
|
}
|
@@ -12,56 +11,58 @@ describe Forward::Config do
|
|
12
11
|
end
|
13
12
|
|
14
13
|
after :each do
|
15
|
-
if Forward::Config.present?
|
16
|
-
|
17
|
-
end
|
14
|
+
FileUtils.rm(Forward::Config.config_path) if Forward::Config.present?
|
15
|
+
FileUtils.rm(Forward::Config.key_path) if Forward::Config.key_file_present?
|
18
16
|
end
|
19
17
|
|
20
18
|
it "initializes a config with a hash" do
|
21
|
-
config = Forward::Config.new(@
|
19
|
+
config = Forward::Config.new(@config_attributes)
|
22
20
|
|
23
|
-
@
|
21
|
+
@config_attributes.each do |key, value|
|
24
22
|
config.send(key).must_equal value
|
25
23
|
end
|
26
24
|
end
|
27
25
|
|
28
26
|
it "updates a config with a hash" do
|
29
27
|
config = Forward::Config.new
|
30
|
-
config.update(@
|
28
|
+
config.update(@config_attributes)
|
31
29
|
|
32
|
-
@
|
30
|
+
@config_attributes.each do |key, value|
|
33
31
|
config.send(key).must_equal value
|
34
32
|
end
|
35
33
|
end
|
36
34
|
|
37
35
|
it "writes and reads a config from disk" do
|
38
|
-
config = Forward::Config.new(@
|
36
|
+
config = Forward::Config.new(@config_attributes)
|
39
37
|
config.write
|
40
38
|
|
41
39
|
saved_config = Forward::Config.load
|
42
40
|
|
43
|
-
|
41
|
+
File.exist?(Forward::Config.config_path).must_equal true
|
42
|
+
File.exist?(Forward::Config.key_path).must_equal true
|
43
|
+
|
44
|
+
@config_attributes.each do |key, value|
|
44
45
|
saved_config.send(key).must_equal value
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
49
|
+
it "only writes config values to the config file" do
|
50
|
+
config = Forward::Config.new(@config_attributes)
|
51
|
+
config.write
|
52
|
+
|
53
|
+
config_file = File.read(Forward::Config.config_path)
|
54
|
+
config_file.include?('private_key').must_equal false
|
55
|
+
end
|
56
|
+
|
48
57
|
it "converts a config to a hash" do
|
49
|
-
config = Forward::Config.new(@
|
58
|
+
config = Forward::Config.new(@config_attributes)
|
50
59
|
config_hash = config.to_hash
|
51
60
|
|
52
|
-
@
|
61
|
+
@config_attributes.each do |key, value|
|
53
62
|
config_hash[key].must_equal value
|
54
63
|
end
|
55
64
|
end
|
56
65
|
|
57
|
-
it "deletes config file" do
|
58
|
-
config = Forward::Config.new(@user_attributes)
|
59
|
-
config.write
|
60
|
-
Forward::Config.clear
|
61
|
-
|
62
|
-
Forward::Config.wont_be :present?
|
63
|
-
end
|
64
|
-
|
65
66
|
it "raises exception with an empty config" do
|
66
67
|
config = Forward::Config.new
|
67
68
|
|
@@ -69,34 +70,26 @@ describe Forward::Config do
|
|
69
70
|
end
|
70
71
|
|
71
72
|
it "raises exception with an invalid config" do
|
72
|
-
@
|
73
|
-
config = Forward::Config.new(@
|
73
|
+
@config_attributes.delete(:api_token)
|
74
|
+
config = Forward::Config.new(@config_attributes)
|
74
75
|
|
75
76
|
lambda { config.validate }.must_raise Forward::ConfigError
|
76
77
|
end
|
77
78
|
|
78
|
-
it "raises exception with bad config on write" do
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
end
|
79
|
+
# it "raises exception with bad config on write" do
|
80
|
+
# @config_attributes.delete(:private_key)
|
81
|
+
# config = Forward::Config.new(@config_attributes)
|
82
|
+
#
|
83
|
+
# lambda { config.write }.must_raise Forward::ConfigError
|
84
|
+
# end
|
84
85
|
|
85
86
|
it "raises exception when a config file is not found" do
|
86
87
|
lambda { Forward::Config.load }.must_raise Forward::ConfigError
|
87
88
|
end
|
88
89
|
|
89
|
-
it "raises exception when
|
90
|
-
config_path
|
91
|
-
|
92
|
-
|
93
|
-
File.open(config_path, 'w') { |f| f.write(config_data) }
|
94
|
-
|
95
|
-
lambda { Forward::Config.read }.must_raise Forward::ConfigError
|
96
|
-
end
|
97
|
-
|
98
|
-
it "raises exception when an invalid config file is loaded" do
|
99
|
-
skip
|
90
|
+
it "raises exception when a key file is not found" do
|
91
|
+
File.open(Forward::Config.config_path, 'w') { |f| f.write YAML.dump(@config_attributes) }
|
92
|
+
lambda { Forward::Config.load }.must_raise Forward::ConfigError
|
100
93
|
end
|
101
94
|
|
102
95
|
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: forward
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
@@ -142,9 +142,9 @@ files:
|
|
142
142
|
- lib/forward.rb
|
143
143
|
- lib/forward/api.rb
|
144
144
|
- lib/forward/api/client_log.rb
|
145
|
-
- lib/forward/api/public_key.rb
|
146
145
|
- lib/forward/api/resource.rb
|
147
146
|
- lib/forward/api/tunnel.rb
|
147
|
+
- lib/forward/api/tunnel_key.rb
|
148
148
|
- lib/forward/api/user.rb
|
149
149
|
- lib/forward/cli.rb
|
150
150
|
- lib/forward/client.rb
|
@@ -153,8 +153,8 @@ files:
|
|
153
153
|
- lib/forward/error.rb
|
154
154
|
- lib/forward/tunnel.rb
|
155
155
|
- lib/forward/version.rb
|
156
|
-
- test/api/public_key_test.rb
|
157
156
|
- test/api/resource_test.rb
|
157
|
+
- test/api/tunnel_key_test.rb
|
158
158
|
- test/api/tunnel_test.rb
|
159
159
|
- test/api/user_test.rb
|
160
160
|
- test/api_test.rb
|
@@ -188,8 +188,8 @@ signing_key:
|
|
188
188
|
specification_version: 3
|
189
189
|
summary: Forward Lets You Share localhost over the Web. Demo a Website Without Hosting.
|
190
190
|
test_files:
|
191
|
-
- test/api/public_key_test.rb
|
192
191
|
- test/api/resource_test.rb
|
192
|
+
- test/api/tunnel_key_test.rb
|
193
193
|
- test/api/tunnel_test.rb
|
194
194
|
- test/api/user_test.rb
|
195
195
|
- test/api_test.rb
|