ruby-net-text 0.0.4 → 0.0.5

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: 13d187b33206cde3d60845489921d5193f573198009e06e6870b3d81fc370692
4
- data.tar.gz: 3979773503767a22dcb0923cacb5c841456aeecfef113a3c6fbb6382c9b898b7
3
+ metadata.gz: bf06a0fb93555a7705a8ab92e7380dcc98134721b24a1f578251667b0a7a973a
4
+ data.tar.gz: c96bc45c9d21310f93a2b9f77ed6194d1539741b58e9ba1d713f3e68779e7505
5
5
  SHA512:
6
- metadata.gz: 942e564ad60a43ce4ef6306c7e73b0962c065c606e34a9fbab269bccd6900b87a5a1d4bd13a28384f02128e9d167648e152b029f547ac20998e633ff9fafd329
7
- data.tar.gz: 5349d6752b31dd637c44158528dcf6489cb71a3d6aaba80df9afde7572c579419e8dd44a6729ca92e01089d20c33bd1b6daa9230db97fb76c26a801363ab3ee1
6
+ metadata.gz: 586165ce218f116cb6a2214a4deff76fc250a241b8ab2a92e91a6caa42d8202a38b1b2262b583a7444a1d260023716b4527191de800f90ea83ff226d6821284a
7
+ data.tar.gz: 982663ef31a62ddca0941eef34b8e227670d97b0c6674116a5b5927f5547f8e1c6e2d6df23b972cece6a9ea07263e543c5f806e0c0bc0488b7bb52f4df80b84e
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gemini
4
+ # Contains specific method to parse text/gemini documents.
5
+ module GmiParser
6
+ private
7
+
8
+ def parse_meta
9
+ header = { status: @status, meta: @meta, mimetype: nil }
10
+ return header unless body_permitted?
11
+ mime = { lang: nil, charset: 'utf-8', format: nil }
12
+ raw_meta = meta.split(';').map(&:strip)
13
+ header[:mimetype] = raw_meta.shift
14
+ return header unless raw_meta.any?
15
+ raw_meta.map { |m| m.split('=') }.each do |opt|
16
+ key = opt[0].downcase.to_sym
17
+ next unless mime.has_key? key
18
+ mime[key] = opt[1].downcase
19
+ end
20
+ header.merge(mime)
21
+ end
22
+
23
+ def parse_preformatted_block(line, buf)
24
+ cur_block = { meta: line[3..].chomp, content: '' }
25
+ while (line = buf.gets)
26
+ if line.start_with?('```')
27
+ @preformatted_blocks << cur_block
28
+ break
29
+ end
30
+ cur_block[:content] += line
31
+ end
32
+ end
33
+
34
+ def parse_link(line)
35
+ m = line.strip.match(/\A=>\s*([^\s]+)(?:\s*(.+))?\z/)
36
+ return if m.nil?
37
+ begin
38
+ uri = URI(m[1])
39
+ rescue URI::InvalidURIError
40
+ return
41
+ end
42
+ uri = @uri.merge(uri) if @uri && uri.is_a?(URI::Generic)
43
+ @links << { uri: uri, label: m[2]&.chomp }
44
+ end
45
+
46
+ def parse_body
47
+ buf = StringIO.new(@body)
48
+ while (line = buf.gets)
49
+ if line.start_with?('```')
50
+ parse_preformatted_block(line, buf)
51
+ elsif line.start_with?('=>')
52
+ parse_link(line)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gemini
4
+ # Contains specific method to correctly display Gemini texts
5
+ module ReflowText
6
+ private
7
+
8
+ def reflow_line_cut_index(line)
9
+ possible_cut = [
10
+ line.rindex(' ') || 0,
11
+ line.rindex('­') || 0,
12
+ line.rindex('-') || 0
13
+ ].sort
14
+ possible_cut.reverse!
15
+ possible_cut[0]
16
+ end
17
+
18
+ def reflow_line_prefix(line)
19
+ m = line.match(/\A([*#>]+ )/)
20
+ return '' unless m
21
+ # Each quote line should begin with the quote mark
22
+ return m[1] if m[1].start_with?('>')
23
+ ' ' * m[1].length
24
+ end
25
+
26
+ def reflow_text_line(line, mono_block_open, length)
27
+ line.strip!
28
+ if mono_block_open || line.start_with?('=>') || line.length < length
29
+ return [line]
30
+ end
31
+ output = []
32
+ prefix = reflow_line_prefix(line)
33
+ while line.length > length
34
+ cut_line = line[0...length]
35
+ cut_index = reflow_line_cut_index(cut_line)
36
+ break if cut_index.zero? # Better do nothing for now
37
+ output << line[0...cut_index]
38
+ line = prefix + line[cut_index + 1..]
39
+ end
40
+ output << line
41
+ end
42
+
43
+ def reformat_body(length)
44
+ unless length.is_a? Integer
45
+ raise ArgumentError, "Length must be Integer, #{length} given"
46
+ end
47
+ return @body if length.zero?
48
+ new_body = []
49
+ mono_block_open = false
50
+ buf = StringIO.new(@body)
51
+ while (line = buf.gets)
52
+ if line.start_with?('```')
53
+ mono_block_open = !mono_block_open
54
+ # Don't include code block toggle lines
55
+ next
56
+ end
57
+ new_body += reflow_text_line(line, mono_block_open, length)
58
+ end
59
+ new_body.join("\n")
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gemini
4
+ # Contains specific method to handle SSL connection
5
+ module SSL
6
+ private
7
+
8
+ def ssl_check_existing(new_cert, cert_file)
9
+ raw = File.read cert_file
10
+ saved_one = OpenSSL::X509::Certificate.new raw
11
+ return true if saved_one == new_cert
12
+ # TODO: offer some kind of recuperation
13
+ warn "#{cert_file} does not match the current host cert!"
14
+ false
15
+ end
16
+
17
+ def ssl_verify_cb(cert)
18
+ return false unless OpenSSL::SSL.verify_certificate_identity(cert, @host)
19
+ cert_file = File.expand_path("#{@certs_path}/#{@host}.pem")
20
+ return ssl_check_existing(cert, cert_file) if File.exist?(cert_file)
21
+ FileUtils.mkdir_p(File.expand_path(@certs_path))
22
+ File.open(cert_file, 'wb') { |f| f.print cert.to_pem }
23
+ true
24
+ end
25
+
26
+ def ssl_context
27
+ ssl_context = OpenSSL::SSL::SSLContext.new
28
+ ssl_context.set_params(verify_mode: OpenSSL::SSL::VERIFY_PEER)
29
+ ssl_context.min_version = OpenSSL::SSL::TLS1_2_VERSION
30
+ ssl_context.verify_hostname = true
31
+ ssl_context.ca_file = '/etc/ssl/certs/ca-certificates.crt'
32
+ ssl_context.verify_callback = lambda do |preverify_ok, store_context|
33
+ return true if preverify_ok
34
+ ssl_verify_cb store_context.current_cert
35
+ end
36
+ ssl_context
37
+ end
38
+
39
+ def init_sockets
40
+ socket = TCPSocket.new(@host, @port)
41
+ @ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
42
+ # Close underlying TCP socket with SSL socket
43
+ @ssl_socket.sync_close = true
44
+ @ssl_socket.hostname = @host # SNI
45
+ @ssl_socket.connect
46
+ end
47
+
48
+ # Closes the SSL and TCP connections.
49
+ def finish
50
+ @ssl_socket.close
51
+ end
52
+ end
53
+ end
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.4
4
+ version: 0.0.5
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-12-30 00:00:00.000000000 Z
11
+ date: 2021-04-28 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email: etienne@depar.is
@@ -18,8 +18,11 @@ extra_rdoc_files: []
18
18
  files:
19
19
  - LICENSE
20
20
  - lib/net/gemini.rb
21
+ - lib/net/gemini/gmi_parser.rb
22
+ - lib/net/gemini/reflow_text.rb
21
23
  - lib/net/gemini/request.rb
22
24
  - lib/net/gemini/response.rb
25
+ - lib/net/gemini/ssl.rb
23
26
  - lib/uri/finger.rb
24
27
  - lib/uri/gemini.rb
25
28
  - lib/uri/gopher.rb
@@ -42,7 +45,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
42
45
  - !ruby/object:Gem::Version
43
46
  version: '0'
44
47
  requirements: []
45
- rubygems_version: 3.1.4
48
+ rubygems_version: 3.2.15
46
49
  signing_key:
47
50
  specification_version: 4
48
51
  summary: Gemini, Gopher, and Finger support for Net::* and URI::*