ruby-net-text 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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