gemini_server 0.1.0 → 0.2.0

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: 29f2c81f5db11cffa8974cf4a1a48654ac00565b66f2ce306086f900246b34f9
4
- data.tar.gz: 842fee3d9d59845cc851b65c2dc918a4ee850e5ffd6f27e4b1c09131a1181659
3
+ metadata.gz: e067f64e27db63e071c57585ae24b7ae0cca9b4c408d0c18acf4b99b6e7ddc57
4
+ data.tar.gz: 30ab2fec9b37e2316dc9b96a9ff18cfe88a892a9d97c5fbbc40ede5336aaba30
5
5
  SHA512:
6
- metadata.gz: 62be452faaec4d6c4b59a15f3847f6776f795a57d7037ec7ff54452ba15ec1ad3410e645e0c595c2358dd53ff0da54410765be27e6448f3519cc5c0ebb857edb
7
- data.tar.gz: 1cce37852838f92ced3fb4e504ff4356d0d098ef27a47d6638d6cb0123b4d2b8c8a63a0412260c15c71da9c78ab37df8f267328e9c331c3d5643614e95510cbe
6
+ metadata.gz: 34222c9438fda88020863ebf5c05dc454a43b02334fec1fe63af28594c418dc01d1024829ddbf275597af6fe72f196dd854e7b35932934e8805c411bfb5ed354
7
+ data.tar.gz: cd906abfa205f29f7470c7844043c266655c35d63da00aa95bcc27e9a2c418aced3f537ea2b44707d0353ff41dded57edb5c0e0c249f6f9bdba0583ffc5b00db
data/README.md CHANGED
@@ -4,6 +4,23 @@ A simple server for the Gemini protocol, with an API inspired by Sinatra.
4
4
 
5
5
  ## Usage
6
6
 
7
+ Use the built-in executable to serve the current directory.
8
+
9
+ ```
10
+ $ gem install gemini_server
11
+ Successfully installed gemini_server-0.1.0
12
+ 1 gem installed
13
+ $ gemini_server -h
14
+ Usage: gemini_server [options]
15
+ -p, --port PORT Port to listen on
16
+ --cert-path PATH Path to cert file
17
+ --key-path PATH Path to key file
18
+ --charset CHARSET Charset of text/* files
19
+ --lang LANG Language of text/* files
20
+ ```
21
+
22
+ Or require the library to declare custom routes in Ruby.
23
+
7
24
  ```ruby
8
25
  require "gemini_server"
9
26
 
@@ -1,3 +1,3 @@
1
1
  module GeminiServer
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/gemini_server.rb CHANGED
@@ -17,7 +17,7 @@ class GeminiServer
17
17
  @views_folder = File.expand_path(options[:views_folder] || ".")
18
18
  @charset = options[:charset]
19
19
  @lang = options[:lang]
20
- @ssl_cert, @ssl_key = self.load_cert_and_key(options)
20
+ @ssl_cert, @ssl_key, @ssl_chain = self.load_cert_and_key(options)
21
21
  end
22
22
 
23
23
  def route r, &blk
@@ -28,7 +28,7 @@ class GeminiServer
28
28
  def listen host, port
29
29
  Async do
30
30
  endpoint = Async::IO::Endpoint.tcp(host, port)
31
- endpoint = Async::IO::SSLEndpoint.new(endpoint, ssl_context: self.ssl_context(@ssl_cert, @ssl_key))
31
+ endpoint = Async::IO::SSLEndpoint.new(endpoint, ssl_context: self.ssl_context(@ssl_cert, @ssl_key, @ssl_chain))
32
32
 
33
33
  ["INT", "TERM"].each do |signal|
34
34
  old_handler = Signal.trap(signal) do
@@ -151,6 +151,26 @@ class GeminiServer
151
151
  LOG_FORMAT % [ip, username || '-', Time.now.strftime("%d/%b/%Y:%H:%M:%S %z"), path, status.to_s, body_size.to_s || '-', clock_time - start_time]
152
152
  end
153
153
 
154
+ def parse_cert_and_chain input_text
155
+ # Only works in Ruby 3+
156
+ if OpenSSL::X509::Certificate.respond_to?(:load)
157
+ certs = OpenSSL::X509::Certificate.load(input_text)
158
+ return [certs.shift, certs]
159
+ end
160
+
161
+ # Fallback behavior for .pem certificates
162
+ certificate_pattern = /-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----/m
163
+ certs = input_text.scan(certificate_pattern).collect do |text|
164
+ OpenSSL::X509::Certificate.new(text)
165
+ end
166
+
167
+ # Fallback behavior if above regex yields 0 certs. E.g. with .der certs
168
+ # This won't parse any chain certs that might be present
169
+ certs = [OpenSSL::X509::Certificate.new(input_text)] if certs.empty?
170
+
171
+ [certs.shift, certs]
172
+ end
173
+
154
174
  def load_cert_and_key options
155
175
  found_cert = options[:cert] || if options[:cert_path]
156
176
  File.open(options[:cert_path]) rescue nil
@@ -167,15 +187,24 @@ class GeminiServer
167
187
  raise "SSL certificate not found" unless found_cert
168
188
  raise "SSL key not found" unless found_key
169
189
 
190
+ if found_cert.is_a?(OpenSSL::X509::Certificate)
191
+ main_cert = found_cert
192
+ chain_list = []
193
+ else
194
+ main_cert, chain_list = parse_cert_and_chain found_cert.read
195
+ end
196
+
170
197
  [
171
- found_cert.is_a?(OpenSSL::X509::Certificate) ? found_cert : OpenSSL::X509::Certificate.new(found_cert),
198
+ main_cert,
172
199
  found_key.is_a?(OpenSSL::PKey::PKey) ? found_key : OpenSSL::PKey.read(found_key),
200
+ chain_list
173
201
  ]
174
202
  end
175
203
 
176
- def ssl_context cert, key
204
+ def ssl_context cert, key, chain
177
205
  OpenSSL::SSL::SSLContext.new.tap do |context|
178
206
  context.add_certificate(cert, key)
207
+ context.extra_chain_cert = chain
179
208
  context.session_id_context = "gemini_server"
180
209
  context.min_version = OpenSSL::SSL::TLS1_2_VERSION
181
210
  context.max_version = OpenSSL::SSL::TLS1_3_VERSION
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gemini_server
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jess Bees
@@ -119,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
119
  - !ruby/object:Gem::Version
120
120
  version: '0'
121
121
  requirements: []
122
- rubygems_version: 3.1.4
122
+ rubygems_version: 3.2.32
123
123
  signing_key:
124
124
  specification_version: 4
125
125
  summary: Simple server for the Gemini protocol