forward 0.0.1 → 0.0.11
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/README.md +7 -0
- data/Rakefile +6 -1
- data/bin/forward +6 -0
- data/forward.gemspec +12 -4
- data/forwardhq.crt +112 -0
- data/lib/forward.rb +86 -0
- data/lib/forward/api.rb +45 -0
- data/lib/forward/api/client_log.rb +28 -0
- data/lib/forward/api/public_key.rb +16 -0
- data/lib/forward/api/resource.rb +121 -0
- data/lib/forward/api/tunnel.rb +91 -0
- data/lib/forward/api/user.rb +19 -0
- data/lib/forward/cli.rb +238 -0
- data/lib/forward/client.rb +92 -0
- data/lib/forward/config.rb +163 -0
- data/lib/forward/core_extensions.rb +12 -0
- data/lib/forward/error.rb +10 -0
- data/lib/forward/tunnel.rb +58 -0
- data/lib/forward/version.rb +1 -1
- data/test/api/public_key_test.rb +28 -0
- data/test/api/resource_test.rb +82 -0
- data/test/api/tunnel_test.rb +75 -0
- data/test/api/user_test.rb +28 -0
- data/test/api_test.rb +0 -0
- data/test/cli_test.rb +84 -0
- data/test/client_test.rb +8 -0
- data/test/config_test.rb +102 -0
- data/test/test_helper.rb +40 -0
- data/test/tunnel_test.rb +8 -0
- metadata +156 -9
data/README.md
CHANGED
@@ -0,0 +1,7 @@
|
|
1
|
+
1. parse options
|
2
|
+
2. pass to client
|
3
|
+
3. client gets a session for the user based on stored token/authentication request or asks the user to signup
|
4
|
+
4. if account is in good standing client requests a tunnel to be setup
|
5
|
+
5. if tunnel is setup, client opens the ssh channel
|
6
|
+
6. client starts forwarding traffic
|
7
|
+
7. the end
|
data/Rakefile
CHANGED
data/bin/forward
ADDED
data/forward.gemspec
CHANGED
@@ -4,14 +4,22 @@ require File.expand_path('../lib/forward/version', __FILE__)
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ['blahed']
|
6
6
|
gem.email = ['travis@50east.co']
|
7
|
-
gem.
|
8
|
-
gem.
|
9
|
-
gem.homepage = ''
|
7
|
+
gem.summary = 'Forward Lets You Share localhost over the Web. Demo a Website Without Hosting.'
|
8
|
+
gem.homepage = 'https://forwardhq.com'
|
10
9
|
|
11
10
|
gem.files = `git ls-files`.split($\)
|
12
11
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
-
gem.test_files = gem.files.grep(%r{^(test|
|
12
|
+
gem.test_files = gem.files.grep(%r{^(test|features)/})
|
14
13
|
gem.name = 'forward'
|
15
14
|
gem.require_paths = ['lib']
|
16
15
|
gem.version = Forward::VERSION
|
16
|
+
|
17
|
+
gem.add_dependency 'json', '~> 1.7.3'
|
18
|
+
gem.add_dependency 'highline', '~> 1.6.13'
|
19
|
+
gem.add_dependency 'net-ssh', '~> 2.4.0'
|
20
|
+
|
21
|
+
gem.add_development_dependency 'minitest', '~> 3.0.0'
|
22
|
+
gem.add_development_dependency 'mocha', '~> 0.11.4'
|
23
|
+
gem.add_development_dependency 'fakeweb', '~> 1.3.0'
|
24
|
+
gem.add_development_dependency 'fakefs', '~> 0.4.0'
|
17
25
|
end
|
data/forwardhq.crt
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIFCTCCA/GgAwIBAgIQQN4DiY5aF21RqglaWWIJnDANBgkqhkiG9w0BAQUFADBy
|
3
|
+
MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD
|
4
|
+
VQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEYMBYGA1UE
|
5
|
+
AxMPRXNzZW50aWFsU1NMIENBMB4XDTEyMDgwOTAwMDAwMFoXDTEzMDgwOTIzNTk1
|
6
|
+
OVowUjEhMB8GA1UECxMYRG9tYWluIENvbnRyb2wgVmFsaWRhdGVkMRUwEwYDVQQL
|
7
|
+
EwxFc3NlbnRpYWxTU0wxFjAUBgNVBAMTDWZvcndhcmRocS5jb20wggEiMA0GCSqG
|
8
|
+
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDcyzuKOE3k44yBYLKXp3AXlf3zbXnZQoHg
|
9
|
+
qzSupKtxHXIVPv6H6IK5HMKT0fgkJaBldMACrIwh6qBCwNm/2OlToTlPY4Ho/9tU
|
10
|
+
f4ud6Y8zSGMOssvR2/jNAfViRtn6AsDZu+0+NM3ZbF4lYorO7KrSTZHhmVDtk4KP
|
11
|
+
HpGRLXKBOa3H/8TQ7RrG8779Ad+RiobwpZc0C7RV/xX2rM5HwWDGNc03eC2GiRSd
|
12
|
+
u8vHp36PeXeW+EWOiHdOthBS49FiTlb6VIQe9eyfOKXMAWEsBum55woGbOutULwQ
|
13
|
+
TQ9HfGfcqve0Zjo24chLvb0hmbOXk+VRJG7J83+QZzHn3JjHEF5dAgMBAAGjggG5
|
14
|
+
MIIBtTAfBgNVHSMEGDAWgBTay+qtWwhdzP/8JlTOSeVVxjj0+DAdBgNVHQ4EFgQU
|
15
|
+
fvmPP+mzOr0ed77Yfsdle6lKLc8wDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQC
|
16
|
+
MAAwNAYDVR0lBC0wKwYIKwYBBQUHAwEGCCsGAQUFBwMCBgorBgEEAYI3CgMDBglg
|
17
|
+
hkgBhvhCBAEwRQYDVR0gBD4wPDA6BgsrBgEEAbIxAQICBzArMCkGCCsGAQUFBwIB
|
18
|
+
Fh1odHRwczovL3NlY3VyZS5jb21vZG8uY29tL0NQUzA7BgNVHR8ENDAyMDCgLqAs
|
19
|
+
hipodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9Fc3NlbnRpYWxTU0xDQS5jcmwwbgYI
|
20
|
+
KwYBBQUHAQEEYjBgMDgGCCsGAQUFBzAChixodHRwOi8vY3J0LmNvbW9kb2NhLmNv
|
21
|
+
bS9Fc3NlbnRpYWxTU0xDQV8yLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au
|
22
|
+
Y29tb2RvY2EuY29tMCsGA1UdEQQkMCKCDWZvcndhcmRocS5jb22CEXd3dy5mb3J3
|
23
|
+
YXJkaHEuY29tMA0GCSqGSIb3DQEBBQUAA4IBAQCJEBvC7c/IrrA0YQPNfgeI2UHN
|
24
|
+
OE5wSK8OveVL++iP4lTxMXew59YOjFccovwot6Jp7RLtlDNlRePDavKzcG/IXiY7
|
25
|
+
oW39bjjLwosrjljq2tZCMm0aTGeNIjMjcN76m9TidlU2DmhhbAT2JdSe+FqEgJnM
|
26
|
+
rJxOgDyxNFGA4UERYambkm+CEFWhEZ6CUneW69IcENglZN9DRcBrX4tivUA/i24W
|
27
|
+
xXz7OFhwfNbJRoLCGH6YVSKzyE8hV1EXDRmTsmHQ1Tw7xk+FduxR5Q2TiB8cdix5
|
28
|
+
ByS6bHA8C5DnS2xJ4mXSxcrCIcjDtbyMEFdDMS7yzfv3LHDetyYyt4rK9E2D
|
29
|
+
-----END CERTIFICATE-----
|
30
|
+
-----BEGIN CERTIFICATE-----
|
31
|
+
MIIFAzCCA+ugAwIBAgIQGLLLuqME8aAPwfLzJkYqSjANBgkqhkiG9w0BAQUFADCB
|
32
|
+
gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
33
|
+
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
|
34
|
+
BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
|
35
|
+
MDBaFw0xOTEyMzEyMzU5NTlaMHIxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVh
|
36
|
+
dGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9E
|
37
|
+
TyBDQSBMaW1pdGVkMRgwFgYDVQQDEw9Fc3NlbnRpYWxTU0wgQ0EwggEiMA0GCSqG
|
38
|
+
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCt8AiwcsargxIxF3CJhakgEtSYau2A1NHf
|
39
|
+
5I5ZLdOWIY120j8YC0YZYwvHIPPlC92AGvFaoL0dds23Izp0XmEbdaqb1IX04XiR
|
40
|
+
0y3hr/yYLgbSeT1awB8hLRyuIVPGOqchfr7tZ291HRqfalsGs2rjsQuqag7nbWzD
|
41
|
+
ypWMN84hHzWQfdvaGlyoiBSyD8gSIF/F03/o4Tjg27z5H6Gq1huQByH6RSRQXScq
|
42
|
+
oChBRVt9vKCiL6qbfltTxfEFFld+Edc7tNkBdtzffRDPUanlOPJ7FAB1WfnwWdsX
|
43
|
+
Pvev5gItpHnBXaIcw5rIp6gLSApqLn8tl2X2xQScRMiZln5+pN0vAgMBAAGjggGD
|
44
|
+
MIIBfzAfBgNVHSMEGDAWgBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAdBgNVHQ4EFgQU
|
45
|
+
2svqrVsIXcz//CZUzknlVcY49PgwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQI
|
46
|
+
MAYBAf8CAQAwIAYDVR0lBBkwFwYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMD4GA1Ud
|
47
|
+
IAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21v
|
48
|
+
ZG8uY29tL0NQUzBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9kb2Nh
|
49
|
+
LmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBsBggrBgEFBQcB
|
50
|
+
AQRgMF4wNgYIKwYBBQUHMAKGKmh0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NvbW9k
|
51
|
+
b1VUTlNHQ0NBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2Eu
|
52
|
+
Y29tMA0GCSqGSIb3DQEBBQUAA4IBAQAtlzR6QDLqcJcvgTtLeRJ3rvuq1xqo2l/z
|
53
|
+
odueTZbLN3qo6u6bldudu+Ennv1F7Q5Slqz0J790qpL0pcRDAB8OtXj5isWMcL2a
|
54
|
+
ejGjKdBZa0wztSz4iw+SY1dWrCRnilsvKcKxudokxeRiDn55w/65g+onO7wdQ7Vu
|
55
|
+
F6r7yJiIatnyfKH2cboZT7g440LX8NqxwCPf3dfxp+0Jj1agq8MLy6SSgIGSH6lv
|
56
|
+
+Wwz3D5XxqfyH8wqfOQsTEZf6/Nh9yvENZ+NWPU6g0QO2JOsTGvMd/QDzczc4BxL
|
57
|
+
XSXaPV7Od4rhPsbXlM1wSTz/Dr0ISKvlUhQVnQ6cGodWaK2cCQBk
|
58
|
+
-----END CERTIFICATE-----
|
59
|
+
-----BEGIN CERTIFICATE-----
|
60
|
+
MIIE8TCCA9mgAwIBAgIQS3VXgmk5DJvjLxLsX22UXjANBgkqhkiG9w0BAQUFADBv
|
61
|
+
MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
|
62
|
+
ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
|
63
|
+
eHRlcm5hbCBDQSBSb290MB4XDTEwMDIxMTAwMDAwMFoXDTIwMDUzMDEwNDgzOFow
|
64
|
+
gYExCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
|
65
|
+
BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMScwJQYD
|
66
|
+
VQQDEx5DT01PRE8gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3
|
67
|
+
DQEBAQUAA4IBDwAwggEKAoIBAQDQQIuLcuORG/dRwRtUBJjTqb/B5opdO4f7u4jO
|
68
|
+
DeMvPwaW8KIpUJmu2zuhV7B0UXHN7UKRTUH+qcjYaoZ3RLtZZpdQXrTULHBEz9o3
|
69
|
+
lUJpPDDEcbNS8CFNodi6OXwcnqMknfKDFpiqFnxDmxVbt640kf7UYiYYRpo/68H5
|
70
|
+
8ZBX66x6DYvbcjBqZtXgRqNw3GjZ/wRIiXfeten7Z21B6bw5vTLZYgLxsag9bjec
|
71
|
+
4i/i06Imi8a4VUOI4SM+pdIkOWpHqwDUobOpJf4NP6cdutNRwQuk2qw471VQJAVl
|
72
|
+
RpM0Ty2NrcbUIRnSjsoFYXEHc0flihkSvQRNzk6cpUisuyb3AgMBAAGjggF0MIIB
|
73
|
+
cDAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73gJMtUGjAdBgNVHQ4EFgQUC1jl
|
74
|
+
i8ZMFTekQKkwqSG+RzZaVv8wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB
|
75
|
+
Af8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9j
|
76
|
+
cmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVybmFsQ0FSb290LmNybDCBswYI
|
77
|
+
KwYBBQUHAQEEgaYwgaMwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0
|
78
|
+
LmNvbS9BZGRUcnVzdEV4dGVybmFsQ0FSb290LnA3YzA5BggrBgEFBQcwAoYtaHR0
|
79
|
+
cDovL2NydC51c2VydHJ1c3QuY29tL0FkZFRydXN0VVROU0dDQ0EuY3J0MCUGCCsG
|
80
|
+
AQUFBzABhhlodHRwOi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBBQUA
|
81
|
+
A4IBAQBNhw1QMPOCXcQ/1O/ujUjj572Qa8QyOMZeKKtcpa1h+Y67hRQ5IVFbjozc
|
82
|
+
F5KAL4OUaYjBvieOT5+pg9i+14eScaO2/RF0uJWBKCB3DUN3dXY4HU0bLpeJjAob
|
83
|
+
ZhZS1BSab4BIFt4wwEJo6r+iuipETayJ4vPMU5vj5h1uT5if2Q5RUIbgGjQyJIB9
|
84
|
+
OofzPOVaTbeLvQokDa7b9I9c0mYMghxyN7bRudCYNBsnbYteHkBzGPqo5MbokMOr
|
85
|
+
GeTBoc1M1Dq2iMjz0GVhOr8Y9K8cVqnrlzjZICkfPyopR52KD2oSgUQCIdQ7Ohor
|
86
|
+
HkBDfZSgaQ78LvtS9v0uMtjLa73r
|
87
|
+
-----END CERTIFICATE-----
|
88
|
+
-----BEGIN CERTIFICATE-----
|
89
|
+
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
|
90
|
+
MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
|
91
|
+
IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
|
92
|
+
MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
|
93
|
+
FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
|
94
|
+
bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
|
95
|
+
dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
|
96
|
+
H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
|
97
|
+
uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
|
98
|
+
mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
|
99
|
+
a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
|
100
|
+
E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
|
101
|
+
WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
|
102
|
+
VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
|
103
|
+
Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
|
104
|
+
cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
|
105
|
+
IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
|
106
|
+
AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
|
107
|
+
YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
|
108
|
+
6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
|
109
|
+
Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
|
110
|
+
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
|
111
|
+
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
|
112
|
+
-----END CERTIFICATE-----
|
data/lib/forward.rb
CHANGED
@@ -1,4 +1,90 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'json'
|
3
|
+
require 'logger'
|
4
|
+
require 'openssl'
|
5
|
+
require 'optparse'
|
6
|
+
require 'rbconfig'
|
7
|
+
require 'stringio'
|
8
|
+
require 'uri'
|
9
|
+
|
10
|
+
require 'highline/import'
|
11
|
+
require 'net/ssh'
|
12
|
+
|
13
|
+
require 'forward/core_extensions'
|
14
|
+
|
15
|
+
require 'forward/error'
|
16
|
+
require 'forward/api'
|
17
|
+
require 'forward/config'
|
18
|
+
require 'forward/tunnel'
|
19
|
+
require 'forward/client'
|
20
|
+
require 'forward/cli'
|
1
21
|
require 'forward/version'
|
2
22
|
|
3
23
|
module Forward
|
24
|
+
DEFAULT_SSL = true
|
25
|
+
DEFAULT_SSH_PORT = 22
|
26
|
+
DEFAULT_SSH_USER = 'tunnel'
|
27
|
+
|
28
|
+
# Returns either a ssh user set in the environment or a set default.
|
29
|
+
#
|
30
|
+
# Returns a String containing the ssh user.
|
31
|
+
def self.ssh_user
|
32
|
+
ENV['FORWARD_SSH_USER'] || DEFAULT_SSH_USER
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns either a ssh port set in the environment or a set default.
|
36
|
+
#
|
37
|
+
# Returns a String containing the ssh port.
|
38
|
+
def self.ssh_port
|
39
|
+
ENV['FORWARD_SSH_PORT'] || DEFAULT_SSH_PORT
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.client=(client)
|
43
|
+
@@client = client
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.client
|
47
|
+
defined?(@@client) && @@client
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.debug!
|
51
|
+
@@debug = true
|
52
|
+
logger.level = Logger::DEBUG
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.debug?
|
56
|
+
defined?(@@debug) && @@debug
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.stringio_log
|
60
|
+
@@stringio_log ||= StringIO.new
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.debug_remotely!
|
64
|
+
logger(stringio_log)
|
65
|
+
debug!
|
66
|
+
@@debug_remotely = true
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.debug_remotely?
|
70
|
+
defined?(@@debug_remotely) && @@debug_remotely
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.log(level, message)
|
74
|
+
logger.send(level, message) if debug?
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.logger(logdev = STDOUT)
|
78
|
+
@@logger ||= Logger.new(logdev)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns a string representing a detailed client version.
|
82
|
+
#
|
83
|
+
# Returns a String representing the client.
|
84
|
+
def self.client_string
|
85
|
+
os = RbConfig::CONFIG['host_os']
|
86
|
+
engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
|
87
|
+
|
88
|
+
"[#{os}]::[#{engine}-#{RUBY_VERSION}]::[ruby-client-#{Forward::VERSION}]"
|
89
|
+
end
|
4
90
|
end
|
data/lib/forward/api.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'forward/api/resource'
|
2
|
+
require 'forward/api/client_log'
|
3
|
+
require 'forward/api/public_key'
|
4
|
+
require 'forward/api/tunnel'
|
5
|
+
require 'forward/api/user'
|
6
|
+
|
7
|
+
module Forward
|
8
|
+
module Api
|
9
|
+
class BadResponse < StandardError; end
|
10
|
+
class ResourceNotFound < StandardError; end
|
11
|
+
class ResourceError < StandardError
|
12
|
+
attr_reader :action, :errors
|
13
|
+
|
14
|
+
def initialize(action, json)
|
15
|
+
@action = action
|
16
|
+
@json = json
|
17
|
+
@errors = json[:errors]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
DEFAULT_API_HOST = 'https://forwardhq.com'
|
22
|
+
|
23
|
+
# Returns either an api host set in the environment or a set default.
|
24
|
+
#
|
25
|
+
# Returns a String containing the api host.
|
26
|
+
def self.uri
|
27
|
+
URI.parse(ENV['FORWARD_API_HOST'] || DEFAULT_API_HOST)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns True or False if we should be using ssl
|
31
|
+
#
|
32
|
+
# Returns a Boolean.
|
33
|
+
def self.ssl?
|
34
|
+
uri.scheme == 'https'
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.token=(token)
|
38
|
+
@@api_token = token
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.token
|
42
|
+
defined?(@@api_token) ? @@api_token : nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Forward
|
2
|
+
module Api
|
3
|
+
class ClientLog < Resource
|
4
|
+
|
5
|
+
def self.create(log)
|
6
|
+
resource = ClientLog.new(:create)
|
7
|
+
resource.uri = '/api/client_logs'
|
8
|
+
params = {
|
9
|
+
:client => Forward.client_string,
|
10
|
+
:log => log,
|
11
|
+
}
|
12
|
+
|
13
|
+
params[:user_id] = user_id unless user_id.nil?
|
14
|
+
|
15
|
+
resource.post(params)
|
16
|
+
end
|
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
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'json'
|
3
|
+
require 'net/http'
|
4
|
+
require 'net/https'
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
module Forward
|
8
|
+
module Api
|
9
|
+
class Resource
|
10
|
+
|
11
|
+
attr_accessor :http
|
12
|
+
attr_accessor :uri
|
13
|
+
|
14
|
+
def initialize(action = nil)
|
15
|
+
@action = action
|
16
|
+
@http = Net::HTTP.new(Forward::Api.uri.host, Forward::Api.uri.port)
|
17
|
+
@http.use_ssl = Forward::Api.ssl?
|
18
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
19
|
+
@http.ca_file = File.expand_path('../../../../forwardhq.crt', __FILE__)
|
20
|
+
end
|
21
|
+
|
22
|
+
def request(method = :get, params = {})
|
23
|
+
log(:debug, "Request: [#{method.to_s.upcase}] for `#{http.address}:#{http.port}#{uri}'")
|
24
|
+
log(:debug, "Request: params `#{params.reject { |k,v| k == :password }.inspect }'")
|
25
|
+
build_request(method, params)
|
26
|
+
add_headers!
|
27
|
+
|
28
|
+
response = @http.request(@request)
|
29
|
+
|
30
|
+
parse_response(response)
|
31
|
+
rescue ResourceError => e
|
32
|
+
self.class.dispatch_error(e)
|
33
|
+
end
|
34
|
+
|
35
|
+
def build_request(method, params = {})
|
36
|
+
@method = method
|
37
|
+
|
38
|
+
case @method
|
39
|
+
when :get
|
40
|
+
@request = Net::HTTP::Get.new(uri)
|
41
|
+
when :post
|
42
|
+
@request = Net::HTTP::Post.new(uri)
|
43
|
+
@request.body = params.to_json unless params.empty?
|
44
|
+
when :put
|
45
|
+
@request = Net::HTTP::Put.new(uri)
|
46
|
+
@request.body = params.to_json unless params.empty?
|
47
|
+
when :delete
|
48
|
+
@request = Net::HTTP::Delete.new(uri)
|
49
|
+
@request.body = params.to_json unless params.empty?
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_headers!
|
54
|
+
if Forward::Api.token
|
55
|
+
@request['Authorization'] = "Token token=#{Forward::Api.token}"
|
56
|
+
end
|
57
|
+
|
58
|
+
@request['Content-Type'] = 'application/json'
|
59
|
+
@request['Accept'] = 'application/json'
|
60
|
+
end
|
61
|
+
|
62
|
+
def get(params = {})
|
63
|
+
@response = request(:get, params)
|
64
|
+
end
|
65
|
+
|
66
|
+
def post(params = {})
|
67
|
+
@response = request(:post, params)
|
68
|
+
end
|
69
|
+
|
70
|
+
def put(params = {})
|
71
|
+
@response = request(:put, params)
|
72
|
+
end
|
73
|
+
|
74
|
+
def delete(params = {})
|
75
|
+
@response = request(:delete, params)
|
76
|
+
end
|
77
|
+
|
78
|
+
def parse_response(response)
|
79
|
+
log(:debug, "Response: [#{response.code}] `#{response.body}'")
|
80
|
+
|
81
|
+
if response.code.to_i == 404
|
82
|
+
raise ResourceNotFound
|
83
|
+
elsif response.code.to_i != 200
|
84
|
+
raise BadResponse, "response code was: #{response.code}"
|
85
|
+
elsif response['content-type'] !~ /^application\/json/
|
86
|
+
raise BadResponse, "response was not JSON, unable to parse"
|
87
|
+
end
|
88
|
+
|
89
|
+
json = JSON.parse(response.body)
|
90
|
+
|
91
|
+
if json.is_a? Hash
|
92
|
+
json.symbolize_keys!
|
93
|
+
raise ResourceError.new(@action, json) if json.has_key?(:errors)
|
94
|
+
end
|
95
|
+
|
96
|
+
json
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.dispatch_error(error)
|
100
|
+
Forward.log(:debug, "Dispatching ResourceError: action: #{error.action} errors: #{error.errors.inspect}")
|
101
|
+
method = :"#{error.action}_error"
|
102
|
+
|
103
|
+
if respond_to? method
|
104
|
+
send(method, error.errors)
|
105
|
+
else
|
106
|
+
Forward::Client.cleanup_and_exit!('An error occured, please contact support@forwardhq.com')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def log(level, message)
|
113
|
+
unless self.class.to_s == 'Forward::Api::ClientLog'
|
114
|
+
Forward.log(level, message)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|