ruby_native 0.8.1 → 0.8.2
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 +4 -4
- data/lib/ruby_native/cli/preview.rb +99 -40
- data/lib/ruby_native/tunnel_cookie_middleware.rb +2 -4
- data/lib/ruby_native/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 48ed2ba9df701df93f8e2f323e2de1a7fd3eecb5bb110be14ca31f2e411e9c36
|
|
4
|
+
data.tar.gz: 79506084ad07267d3536c30ff281a65bd7c0c20a8851a20556b5a5ba49d165aa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1953585bc5fc67ad9d2d86de072497695239ec5873d58a7cb8dfa8191b1abfd94173ace3036a7b6442ef04b213f28be7f76ca1ebc6a2c7adf5edd8587cb406e7
|
|
7
|
+
data.tar.gz: d7cd25a3cc33a9ce35a815f2b9d5a627b8e479d2ebaa6d25ab9ea23b5ebeb759b4e679e412ca347721c9c86a9c78a25848c065fe38a2619f171c509bec83466b
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
require "open3"
|
|
2
|
+
require "net/http"
|
|
3
|
+
require "uri"
|
|
4
|
+
require "resolv"
|
|
2
5
|
|
|
3
6
|
module RubyNative
|
|
4
7
|
class CLI
|
|
5
8
|
class Preview
|
|
6
9
|
TUNNEL_URL_PATTERN = %r{https://[a-z0-9-]+\.trycloudflare\.com}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
WHITE_FG = "\033[97m"
|
|
12
|
-
RESET = "\033[0m"
|
|
10
|
+
CONFIG_PATH = "/native/config.json"
|
|
11
|
+
TUNNEL_READY_TIMEOUT = 60
|
|
12
|
+
TUNNEL_POLL_INTERVAL = 1
|
|
13
|
+
PUBLIC_NAMESERVERS = ["1.1.1.1", "8.8.8.8"].freeze
|
|
13
14
|
|
|
14
15
|
def initialize(argv)
|
|
15
16
|
@port = parse_port(argv)
|
|
@@ -17,11 +18,87 @@ module RubyNative
|
|
|
17
18
|
|
|
18
19
|
def run
|
|
19
20
|
check_cloudflared!
|
|
21
|
+
check_local_server!
|
|
20
22
|
start_tunnel
|
|
21
23
|
end
|
|
22
24
|
|
|
23
25
|
private
|
|
24
26
|
|
|
27
|
+
def check_local_server!
|
|
28
|
+
uri = URI("http://localhost:#{@port}#{CONFIG_PATH}")
|
|
29
|
+
response = fetch_config_response(uri)
|
|
30
|
+
|
|
31
|
+
return if response.is_a?(Net::HTTPSuccess)
|
|
32
|
+
|
|
33
|
+
puts "Rails server is running on port #{@port}, but #{CONFIG_PATH} returned #{response.code}."
|
|
34
|
+
puts ""
|
|
35
|
+
puts "Make sure the ruby_native gem is installed and mounted:"
|
|
36
|
+
puts " https://rubynative.com/docs/install"
|
|
37
|
+
exit 1
|
|
38
|
+
rescue Errno::ECONNREFUSED
|
|
39
|
+
puts "Nothing is running on port #{@port}."
|
|
40
|
+
puts ""
|
|
41
|
+
puts "Start your Rails server in another terminal:"
|
|
42
|
+
puts " bin/rails server -p #{@port}"
|
|
43
|
+
exit 1
|
|
44
|
+
rescue => e
|
|
45
|
+
puts "Could not reach http://localhost:#{@port}#{CONFIG_PATH}: #{e.message}"
|
|
46
|
+
exit 1
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def fetch_config_response(uri, ip: nil)
|
|
50
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
51
|
+
http.ipaddr = ip if ip
|
|
52
|
+
http.use_ssl = (uri.scheme == "https")
|
|
53
|
+
http.open_timeout = 2
|
|
54
|
+
http.read_timeout = 5
|
|
55
|
+
http.start { http.get(uri.request_uri) }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def wait_for_tunnel(url)
|
|
59
|
+
uri = URI("#{url}#{CONFIG_PATH}")
|
|
60
|
+
deadline = monotonic_now + TUNNEL_READY_TIMEOUT
|
|
61
|
+
ip = nil
|
|
62
|
+
|
|
63
|
+
print "Waiting for tunnel..."
|
|
64
|
+
loop do
|
|
65
|
+
begin
|
|
66
|
+
ip ||= resolve_via_public_dns(uri.host)
|
|
67
|
+
response = fetch_config_response(uri, ip: ip)
|
|
68
|
+
if response.is_a?(Net::HTTPSuccess)
|
|
69
|
+
puts " ready."
|
|
70
|
+
return
|
|
71
|
+
end
|
|
72
|
+
rescue Resolv::ResolvError, Resolv::ResolvTimeout, StandardError
|
|
73
|
+
# Keep polling.
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
if monotonic_now >= deadline
|
|
77
|
+
puts ""
|
|
78
|
+
puts "Tunnel did not respond within #{TUNNEL_READY_TIMEOUT}s at #{url}."
|
|
79
|
+
puts "Showing the URL anyway. It may take a few more seconds before scanning works."
|
|
80
|
+
return
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
print "."
|
|
84
|
+
sleep TUNNEL_POLL_INTERVAL
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def resolve_via_public_dns(host)
|
|
89
|
+
resolver = Resolv::DNS.new(nameserver: PUBLIC_NAMESERVERS)
|
|
90
|
+
resolver.timeouts = [2, 4]
|
|
91
|
+
addresses = resolver.getaddresses(host)
|
|
92
|
+
raise Resolv::ResolvError, "no A/AAAA record for #{host}" if addresses.empty?
|
|
93
|
+
addresses.first.to_s
|
|
94
|
+
ensure
|
|
95
|
+
resolver&.close
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def monotonic_now
|
|
99
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
100
|
+
end
|
|
101
|
+
|
|
25
102
|
def parse_port(argv)
|
|
26
103
|
index = argv.index("--port")
|
|
27
104
|
if index
|
|
@@ -61,6 +138,7 @@ module RubyNative
|
|
|
61
138
|
stdout_err.each_line do |line|
|
|
62
139
|
if line =~ TUNNEL_URL_PATTERN
|
|
63
140
|
tunnel_url = line[TUNNEL_URL_PATTERN]
|
|
141
|
+
wait_for_tunnel(tunnel_url)
|
|
64
142
|
display_qr(tunnel_url)
|
|
65
143
|
end
|
|
66
144
|
end
|
|
@@ -73,39 +151,26 @@ module RubyNative
|
|
|
73
151
|
def display_qr(url)
|
|
74
152
|
require "rqrcode"
|
|
75
153
|
|
|
76
|
-
qr = RQRCode::QRCode.new(url)
|
|
154
|
+
qr = RQRCode::QRCode.new(url, level: :l)
|
|
77
155
|
modules = qr.modules
|
|
156
|
+
size = modules.length
|
|
157
|
+
quiet_h = 4
|
|
158
|
+
quiet_v = 2
|
|
78
159
|
|
|
79
|
-
|
|
160
|
+
dark = "██"
|
|
161
|
+
light = " "
|
|
80
162
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
(0...total).step(2) do |r|
|
|
90
|
-
line = ""
|
|
91
|
-
total.times do |c|
|
|
92
|
-
top = pixel_dark?(modules, r, c, quiet, size)
|
|
93
|
-
bottom = pixel_dark?(modules, r + 1, c, quiet, size)
|
|
94
|
-
|
|
95
|
-
if top && bottom
|
|
96
|
-
line << "#{BLACK_BG} #{RESET}"
|
|
97
|
-
elsif top
|
|
98
|
-
line << "#{BLACK_BG}#{WHITE_FG}\u2584#{RESET}"
|
|
99
|
-
elsif bottom
|
|
100
|
-
line << "#{WHITE_BG}#{BLACK_FG}\u2584#{RESET}"
|
|
101
|
-
else
|
|
102
|
-
line << "#{WHITE_BG} #{RESET}"
|
|
103
|
-
end
|
|
163
|
+
puts ""
|
|
164
|
+
(0...(size + quiet_v * 2)).each do |r|
|
|
165
|
+
line = +""
|
|
166
|
+
(0...(size + quiet_h * 2)).each do |c|
|
|
167
|
+
mr = r - quiet_v
|
|
168
|
+
mc = c - quiet_h
|
|
169
|
+
inside = mr >= 0 && mr < size && mc >= 0 && mc < size
|
|
170
|
+
line << (inside && modules[mr][mc] ? dark : light)
|
|
104
171
|
end
|
|
105
|
-
|
|
172
|
+
puts line
|
|
106
173
|
end
|
|
107
|
-
|
|
108
|
-
puts lines.join("\n")
|
|
109
174
|
puts ""
|
|
110
175
|
puts url
|
|
111
176
|
puts ""
|
|
@@ -128,12 +193,6 @@ module RubyNative
|
|
|
128
193
|
rescue Errno::ESRCH, Errno::ECHILD
|
|
129
194
|
# Process already exited.
|
|
130
195
|
end
|
|
131
|
-
|
|
132
|
-
def pixel_dark?(modules, row, col, quiet, size)
|
|
133
|
-
r = row - quiet
|
|
134
|
-
c = col - quiet
|
|
135
|
-
r >= 0 && r < size && c >= 0 && c < size && modules[r][c]
|
|
136
|
-
end
|
|
137
196
|
end
|
|
138
197
|
end
|
|
139
198
|
end
|
|
@@ -36,10 +36,8 @@ module RubyNative
|
|
|
36
36
|
def strip_cookie_domain!(headers)
|
|
37
37
|
raw = headers["set-cookie"]
|
|
38
38
|
cookies = raw.is_a?(Array) ? raw : raw.split("\n")
|
|
39
|
-
|
|
40
|
-
headers["set-cookie"] =
|
|
41
|
-
cookie.gsub(/;\s*domain=[^;]*/i, "")
|
|
42
|
-
}.join("\n")
|
|
39
|
+
stripped = cookies.map { |cookie| cookie.gsub(/;\s*domain=[^;]*/i, "") }
|
|
40
|
+
headers["set-cookie"] = (stripped.length == 1) ? stripped.first : stripped
|
|
43
41
|
end
|
|
44
42
|
end
|
|
45
43
|
end
|
data/lib/ruby_native/version.rb
CHANGED