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 +4 -4
- data/README.md +17 -0
- data/lib/gemini_server/version.rb +1 -1
- data/lib/gemini_server.rb +33 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e067f64e27db63e071c57585ae24b7ae0cca9b4c408d0c18acf4b99b6e7ddc57
|
4
|
+
data.tar.gz: 30ab2fec9b37e2316dc9b96a9ff18cfe88a892a9d97c5fbbc40ede5336aaba30
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
|
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
|
-
|
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.
|
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.
|
122
|
+
rubygems_version: 3.2.32
|
123
123
|
signing_key:
|
124
124
|
specification_version: 4
|
125
125
|
summary: Simple server for the Gemini protocol
|