ruby-net-text 0.0.1 → 0.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 95abe1fa0498d496b10d7517d9dc00fcd958091e93c75cb3f86d3274667bf245
4
- data.tar.gz: 92855326685c71635f9a3f0c45178112925ecbd2e30027c187d473b3ddc61e07
3
+ metadata.gz: 0f3d4fbd93c189d283b253e0f0a520bdaee167f09281d3c6a25c95126c07ecf9
4
+ data.tar.gz: 209152612f6f0dad44282fe17dc02d34fc6457ccc0f01bb993374ceef9491f33
5
5
  SHA512:
6
- metadata.gz: 7342a84385b98b84f7dc74ad546c78d58f943412da84fb247c3eff4b0affcce5ca9fa446ea527de5f32b983ee86589a57a217ad2debab57c9ede7cda0855d7d8
7
- data.tar.gz: 17e634cc19ff48ef976db87c85155dc618a37c3e24d8dc2edd443eae647602aa6d7d9880dbb6968f289d4ad2c6a47b990ae7622abacb9d61788b023a960894bc
6
+ metadata.gz: e6826cd8ee993dabd7210a329b4349fb059c5007ff1560914d09049dfa7276ff1590d9f5405c31a99c70202511502d30c1d68d9b66643ddbf881774e161cdac3
7
+ data.tar.gz: 7f756ac8389178ae82a8c11b0a8e3e7491d096cab8dfbd42d55345e277680656ccb64da1fb69e119417fb2de68b75a2740b7fbd60f492ef2c44df31668adcd69
@@ -7,7 +7,9 @@ require 'openssl'
7
7
  require 'fileutils'
8
8
 
9
9
  require 'uri/gemini'
10
+ require_relative 'gemini/request'
10
11
  require_relative 'gemini/response'
12
+ require_relative 'gemini/ssl'
11
13
 
12
14
  module Net
13
15
  class GeminiError < StandardError; end
@@ -98,10 +100,11 @@ module Net
98
100
 
99
101
  def request(uri)
100
102
  init_sockets
101
- @ssl_socket.puts "#{uri}\r\n"
102
- r = GeminiResponse.read_new(@ssl_socket)
103
- r.uri = uri
104
- r.reading_body(@ssl_socket)
103
+ req = GeminiRequest.new uri
104
+ req.write @ssl_socket
105
+ res = GeminiResponse.read_new(@ssl_socket)
106
+ res.uri = uri
107
+ res.reading_body(@ssl_socket)
105
108
  ensure
106
109
  # Stop remaining connection, even if they should be already cut
107
110
  # by the server
@@ -112,14 +115,11 @@ module Net
112
115
  raise GeminiError, 'Too many Gemini redirects' if limit.zero?
113
116
  r = request(uri)
114
117
  return r unless r.status[0] == '3'
115
- old_url = uri.to_s
116
118
  begin
117
- new_uri = URI(r.meta)
118
- uri.merge!(new_uri)
119
+ uri = handle_redirect(r)
119
120
  rescue ArgumentError, URI::InvalidURIError
120
121
  return r
121
122
  end
122
- raise GeminiError, "Redirect loop on #{uri}" if uri.to_s == old_url
123
123
  warn "Redirect to #{uri}" if $VERBOSE
124
124
  fetch(uri, limit - 1)
125
125
  end
@@ -148,50 +148,17 @@ module Net
148
148
 
149
149
  private
150
150
 
151
- def ssl_check_existing(new_cert, cert_file)
152
- raw = File.read cert_file
153
- saved_one = OpenSSL::X509::Certificate.new raw
154
- return true if saved_one == new_cert
155
- # TODO: offer some kind of recuperation
156
- warn "#{cert_file} does not match the current host cert!"
157
- false
158
- end
159
-
160
- def ssl_verify_cb(cert)
161
- domain = cert.subject.to_s.sub(/^\/CN=/, '')
162
- return false if domain != @host
163
- cert_file = File.expand_path("#{@certs_path}/#{domain}.pem")
164
- return ssl_check_existing(cert, cert_file) if File.exist?(cert_file)
165
- FileUtils.mkdir_p(File.expand_path(@certs_path))
166
- File.open(cert_file, 'wb') { |f| f.print cert.to_pem }
167
- true
168
- end
169
-
170
- def ssl_context
171
- ssl_context = OpenSSL::SSL::SSLContext.new
172
- ssl_context.set_params(verify_mode: OpenSSL::SSL::VERIFY_PEER)
173
- ssl_context.min_version = OpenSSL::SSL::TLS1_2_VERSION
174
- ssl_context.verify_hostname = true
175
- ssl_context.ca_file = '/etc/ssl/certs/ca-certificates.crt'
176
- ssl_context.verify_callback = lambda do |preverify_ok, store_context|
177
- return true if preverify_ok
178
- ssl_verify_cb store_context.current_cert
179
- end
180
- ssl_context
181
- end
182
-
183
- def init_sockets
184
- @socket = TCPSocket.new(@host, @port)
185
- @ssl_socket = OpenSSL::SSL::SSLSocket.new(@socket, ssl_context)
186
- # Close underlying TCP socket with SSL socket
187
- @ssl_socket.sync_close = true
188
- @ssl_socket.hostname = @host # SNI
189
- @ssl_socket.connect
151
+ def handle_redirect(response)
152
+ uri = response.uri
153
+ old_url = uri.to_s
154
+ new_uri = URI(response.meta)
155
+ uri.merge!(new_uri)
156
+ raise GeminiError, "Redirect loop on #{uri}" if uri.to_s == old_url
157
+ @host = uri.host
158
+ @port = uri.port
159
+ uri
190
160
  end
191
161
 
192
- # Closes the SSL and TCP connections.
193
- def finish
194
- @ssl_socket.close
195
- end
162
+ include ::Gemini::SSL
196
163
  end
197
164
  end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'English'
4
+
5
+ require 'uri/gemini'
6
+
7
+ module Net
8
+ class GeminiBadRequest < StandardError; end
9
+
10
+ #
11
+ # The syntax of Gemini Requests are defined in the Gemini
12
+ # specification, section 2.
13
+ #
14
+ # @see https://gemini.circumlunar.space/docs/specification.html
15
+ #
16
+ class GeminiRequest
17
+ attr_reader :uri
18
+
19
+ def initialize(uri_or_str)
20
+ # In any case, make some sanity check over this uri-like think
21
+ url = uri_or_str.to_s
22
+ if url.length > 1024
23
+ raise GeminiBadRequest, "Request too long: #{url.dump}"
24
+ end
25
+ @uri = URI(url)
26
+ unless uri.is_a? URI::Gemini
27
+ raise GeminiBadRequest, "Not a Gemini URI: #{url.dump}"
28
+ end
29
+ end
30
+
31
+ def path
32
+ @uri.path
33
+ end
34
+
35
+ def write(sock)
36
+ sock.puts "#{@uri}\r\n"
37
+ end
38
+
39
+ class << self
40
+ def read_new(sock)
41
+ # Read up to 1026 bytes:
42
+ # - 1024 bytes max for the URL
43
+ # - 2 bytes for <CR><LF>
44
+ str = sock.gets($INPUT_RECORD_SEPARATOR, 1026)
45
+ m = /\A(.*)\r\n\z/.match(str)
46
+ raise GeminiBadRequest, "Malformed request: #{str.dump}" if m.nil?
47
+ new(m[1])
48
+ end
49
+ end
50
+ end
51
+ end
@@ -11,9 +11,9 @@ module Net
11
11
 
12
12
  #
13
13
  # The syntax of Gemini Responses are defined in the Gemini
14
- # specification[1], section 3.
14
+ # specification, section 3.
15
15
  #
16
- # [1] https://gemini.circumlunar.space/docs/specification.html
16
+ # @see https://gemini.circumlunar.space/docs/specification.html
17
17
  #
18
18
  class GeminiResponse
19
19
  # The Gemini response <STATUS> string.
@@ -73,20 +73,14 @@ module Net
73
73
 
74
74
  class << self
75
75
  def read_new(sock)
76
- code, msg = read_status_line(sock)
77
- new(code, msg)
78
- end
79
-
80
- private
81
-
82
- def read_status_line(sock)
83
- # Read up to 1027 bytes:
76
+ # Read up to 1029 bytes:
84
77
  # - 3 bytes for code and space separator
85
78
  # - 1024 bytes max for the message
86
- str = sock.gets($INPUT_RECORD_SEPARATOR, 1027)
79
+ # - 2 bytes for <CR><LF>
80
+ str = sock.gets($INPUT_RECORD_SEPARATOR, 1029)
87
81
  m = /\A([1-6]\d) (.*)\r\n\z/.match(str)
88
82
  raise GeminiBadResponse, "wrong status line: #{str.dump}" if m.nil?
89
- m.captures
83
+ new(*m.captures)
90
84
  end
91
85
  end
92
86
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-net-text
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Étienne Deparis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-15 00:00:00.000000000 Z
11
+ date: 2020-11-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email: etienne@depar.is
@@ -18,6 +18,7 @@ extra_rdoc_files: []
18
18
  files:
19
19
  - LICENSE
20
20
  - lib/net/gemini.rb
21
+ - lib/net/gemini/request.rb
21
22
  - lib/net/gemini/response.rb
22
23
  - lib/uri/finger.rb
23
24
  - lib/uri/gemini.rb