web_package 0.0.0 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +24 -21
- data/README.md +109 -0
- data/lib/web_package/cbor.rb +3 -1
- data/lib/web_package/helpers.rb +3 -0
- data/lib/web_package/inner_response.rb +24 -0
- data/lib/web_package/mice.rb +4 -1
- data/lib/web_package/middleware.rb +48 -0
- data/lib/web_package/signed_http_exchange.rb +22 -25
- data/lib/web_package/signer.rb +6 -4
- data/lib/web_package/version.rb +1 -1
- data/lib/web_package.rb +6 -3
- data/web_package.gemspec +2 -1
- metadata +20 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3480112115fbe00503b06c0f2348ce71540476a2
|
4
|
+
data.tar.gz: 302a745b6299ed41ce24477ea0e97e2028f36f1c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f246d62cead117fbd4e8f8da7ccba8efaa29ee22baeebf1d7aadcbf73fe26131d58640876810ee1c6676591538c07a23f8d2894daba08348b01ef9c10293efcc
|
7
|
+
data.tar.gz: 1e5f467edfb293b83b166bc1ce03d2bda57db2af45fdfd9d98ddcecff65aafb21edd879e38ef43999a5a9b81b0e8ae3959fbbc32eb8bfa7086cec5b0380b164f
|
data/.rubocop.yml
CHANGED
@@ -1,19 +1,14 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
Naming/UncommunicativeMethodParamName:
|
6
|
-
AllowedNames:
|
7
|
-
- s
|
1
|
+
Layout/EmptyLineAfterGuardClause:
|
2
|
+
Exclude:
|
3
|
+
- lib/web_package/signed_http_exchange.rb
|
8
4
|
|
9
|
-
|
10
|
-
|
5
|
+
Layout/SpaceInsideRangeLiteral:
|
6
|
+
Exclude:
|
7
|
+
- lib/web_package/cbor.rb
|
11
8
|
|
12
|
-
|
9
|
+
Layout/ExtraSpacing:
|
13
10
|
Exclude:
|
14
11
|
- lib/web_package/cbor.rb
|
15
|
-
- lib/web_package/mice.rb
|
16
|
-
- lib/web_package/signed_http_exchange.rb
|
17
12
|
|
18
13
|
Metrics/AbcSize:
|
19
14
|
Max: 20
|
@@ -22,21 +17,29 @@ Metrics/AbcSize:
|
|
22
17
|
- lib/web_package/mice.rb
|
23
18
|
- lib/web_package/signed_http_exchange.rb
|
24
19
|
|
25
|
-
|
20
|
+
Metrics/ClassLength:
|
26
21
|
Exclude:
|
27
22
|
- lib/web_package/signed_http_exchange.rb
|
28
23
|
|
29
|
-
Metrics/
|
24
|
+
Metrics/LineLength:
|
25
|
+
Max: 100
|
26
|
+
IgnoreCopDirectives: true
|
27
|
+
|
28
|
+
Metrics/MethodLength:
|
30
29
|
Exclude:
|
30
|
+
- lib/web_package/cbor.rb
|
31
|
+
- lib/web_package/mice.rb
|
31
32
|
- lib/web_package/signed_http_exchange.rb
|
32
33
|
|
33
|
-
|
34
|
+
Naming/UncommunicativeMethodParamName:
|
35
|
+
AllowedNames:
|
36
|
+
- s
|
37
|
+
|
38
|
+
Style/CharacterLiteral:
|
34
39
|
Enabled: false
|
35
40
|
|
36
|
-
|
37
|
-
|
38
|
-
- lib/web_package/cbor.rb
|
41
|
+
Style/FrozenStringLiteralComment:
|
42
|
+
Enabled: false
|
39
43
|
|
40
|
-
|
41
|
-
|
42
|
-
- lib/web_package/cbor.rb
|
44
|
+
Style/RedundantReturn:
|
45
|
+
Enabled: false
|
data/README.md
CHANGED
@@ -1,2 +1,111 @@
|
|
1
1
|
# web_package
|
2
2
|
Ruby implementation of Signed HTTP Exchange format, allowing a browser to trust that a HTTP request-response pair was generated by the origin it claims.
|
3
|
+
|
4
|
+
|
5
|
+
## Ever thought of saving the Internet on a flash?
|
6
|
+
|
7
|
+
Easily-peasily.
|
8
|
+
|
9
|
+
Let's sign a pair of request/response and serve the bundle as `application/signed-exchange` - Chromium browsers understand what it means and unpack them smoothly.
|
10
|
+
|
11
|
+
For that we need a certificate with a special "CanSignHttpExchanges" extension, but for the purpose of this guide we will use just a self-signed one. Please refer [here](https://github.com/WICG/webpackage/tree/master/go/signedexchange#creating-our-first-signed-exchange) to create such.
|
12
|
+
|
13
|
+
Also we need an `https` cdn serving static certificate in `application/cert-chain+cbor` format. We can use `gen-certurl` tool from [here](https://github.com/WICG/webpackage/tree/master/go/signedexchange#creating-our-first-signed-exchange) to convert PEM certificate into this format, so we could than serve it from a cdn.
|
14
|
+
|
15
|
+
### Required environment variables
|
16
|
+
Having done the above-said we are now ready to assign required env vars:
|
17
|
+
```bash
|
18
|
+
export SXG_CERT_URL='https://my.cdn.com/cert.cbor' \
|
19
|
+
SXG_CERT_PATH='/local/path/to/cert.pem' \
|
20
|
+
SXG_PRIV_PATH='/local/path/to/priv.key'
|
21
|
+
```
|
22
|
+
Please note, that the variables are fetched during class initialization. And failing to provide valid paths will result in an exception.
|
23
|
+
|
24
|
+
### Use it as a middleware
|
25
|
+
|
26
|
+
`WebPackage::Middleware` can handle `.sxg`-format requests by wrapping the respective HTML contents into signed exchange response. For example the route `https://my.app.com/abc.sxg` will respond with signed contents for `https://my.app.com/abc`.
|
27
|
+
|
28
|
+
If you already have a Rack-based application (like Rails or Sinatra), than it is easy incorporate an SXG proxy into its middleware stack.
|
29
|
+
|
30
|
+
#### Rails
|
31
|
+
Add the gem to your `Gemfile`:
|
32
|
+
```ruby
|
33
|
+
gem 'web_package'
|
34
|
+
```
|
35
|
+
And then add the middleware:
|
36
|
+
```ruby
|
37
|
+
# config/application.rb
|
38
|
+
config.middleware.insert 0, 'WebPackage::Middleware'
|
39
|
+
```
|
40
|
+
|
41
|
+
That is it. Now all successful `.sxg` requests will be wrapped into signed exchanges.
|
42
|
+
|
43
|
+
#### Pure Rack app
|
44
|
+
Imagine we have a simple web app:
|
45
|
+
```ruby
|
46
|
+
# config.ru
|
47
|
+
run ->(env) { [200, {}, ['<h1>Hello world!</h1>']] }
|
48
|
+
```
|
49
|
+
Add the gem and the middleware:
|
50
|
+
```ruby
|
51
|
+
# Gemfile
|
52
|
+
gem 'web_package'
|
53
|
+
|
54
|
+
# config.ru
|
55
|
+
use WebPackage::Middleware
|
56
|
+
```
|
57
|
+
|
58
|
+
We are done. Start your app by running a command `rackup config.ru`. Now all supplimentary `.sxg` routes will be available just out of the box.<br>
|
59
|
+
As expected, visiting `http://localhost:9292/hello` will produce:
|
60
|
+
```html
|
61
|
+
<h1>Hello world!</h1>
|
62
|
+
```
|
63
|
+
What's more, visiting `http://localhost:9292/hello.sxg` will spit signed http exchange, containing original `<h1>Hello world!</h1>` HTML:
|
64
|
+
```text
|
65
|
+
sxg1-b3\x00\x00\x1Chttps://localhost:9292/hello\x00\x019\x00\x00?label;cert-sha256=*+DoXYlCX+bFRyW65R3bFA2ICIz8Tyu54MLFUFo5tziA=*;cert-url=\"https://my.cdn.com/cert.cbor\";date=1557657274;expires=1558262074;integrity=\"digest/mi-sha256-03\";sig=*MEUCIAKKz+KSuhlzywfU12h3SkEq5ZuYYMxDZIgEDGYMd9sAAiEAj66Il48eb0CXFAnuZhnS+j6dqZVLJ6IwUVGWShhQu9g=*;validity-url=\"https://localhost/hello\"?FdigestX9mi-sha256-03=4QeUScOpSoJl7KJ47F11rSDHUTHZhDVwLiSLOWMcvqg=G:statusC200Pcontent-encodingLmi-sha256-03Vx-content-type-optionsGnosniff\x00\x00\x00\x00\x00\x00@\x00<h1>Hello world!</h1>
|
66
|
+
```
|
67
|
+
|
68
|
+
### Use it as it is
|
69
|
+
```ruby
|
70
|
+
require 'web_package'
|
71
|
+
|
72
|
+
# this is the request/response pair
|
73
|
+
request_url = 'https://my.app.com/abc'
|
74
|
+
response = [200, {}, ['<h1>Hello world!</h1>']]
|
75
|
+
|
76
|
+
exchange = WebPackage::SignedHttpExchange.new(request_url, response)
|
77
|
+
|
78
|
+
exchange.headers
|
79
|
+
# => {"Content-Type"=>"application/signed-exchange;v=b3", "Cache-Control"=>"no-transform", "X-Content-Type-Options"=>"nosniff"}
|
80
|
+
|
81
|
+
exchange.body
|
82
|
+
# => "sxg1-b3\x00\x00\x16https://my.app.com/abc\x00\x018\x00\x00\x8Clabel;cert-sha256=*+DoXYlCX+bFRyW65R3bFA2ICIz8Tyu54MLFUFo5tziA=*;cert-url=\"https://my.cdn.com/cert.cbor\";date=1557648268;expires=1558253068;integrity=\"digest/mi-sha256-03\";sig=*MEYCIQDSH2F6E/naM/ul1iIMZMBd9VHnrbsxp+dKhYcxy9u1ewIhAIRIuHcTVPLS73q2ETLLGwY5Y7nR52bDG251uBBHxsBZ*;validity-url=\"https://my.app.com/abc\"\xA4FdigestX9mi-sha256-03=4QeUScOpSoJl7KJ47F11rSDHUTHZhDVwLiSLOWMcvqg=G:statusC200Pcontent-encodingLmi-sha256-03Vx-content-type-optionsGnosniff\x00\x00\x00\x00\x00\x00@\x00<h1>Hello world!</h1>"
|
83
|
+
```
|
84
|
+
|
85
|
+
The body can be stored on disk and served from any other server. That is, visiting e.g. `https://other.cdn.com/foo/bar.sxg` will result in <b>"Hello world!"</b> HTML with `https://my.app.com/abc` in a browser's address bar - with no requests sent to `https://my.app.com/abc` (until the page expired).
|
86
|
+
|
87
|
+
Successive reloads will force browser to factually send requests to `https://my.app.com/abc`.
|
88
|
+
|
89
|
+
Note also, that SXG is only supported by the anchor tag (`<a>`) and `link rel=prefetch`, so actually typing `https://other.cdn.com/foo/bar.sxg` into browser's address bar and hitting enter will just download an SXG file.
|
90
|
+
|
91
|
+
This all could be helpful to preload content or serve it from closer location. For details please refer to hands-on description of [Signed Http Exchanges](https://developers.google.com/web/updates/2018/11/signed-exchanges).
|
92
|
+
|
93
|
+
### Self-signed certificates in Chrome
|
94
|
+
Chrome will not proceed with a self-signed certificate - at least as long as its cbor representation is generated with dummy data for OCSP. To accomodate this, please launch the browser with the following flags:
|
95
|
+
```bash
|
96
|
+
chrome --user-data-dir=/tmp/udd\
|
97
|
+
--ignore-certificate-errors-spki-list=`openssl x509 -noout -pubkey -in cert.pem | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64`
|
98
|
+
```
|
99
|
+
|
100
|
+
Note, that the browser might spit a warning `You are using unsupported command-line flag: --ignore-certificate-errors-spki-list` - just ignore it - the browser does support this flag (tested in versions 73 and 74).
|
101
|
+
|
102
|
+
## Contributing
|
103
|
+
- Fork it
|
104
|
+
- Create your feature branch (git checkout -b my-new-feature)
|
105
|
+
- Commit your changes (git commit -am 'Add some feature')
|
106
|
+
- Push to the branch (git push origin my-new-feature)
|
107
|
+
- Create new Pull Request
|
108
|
+
|
109
|
+
## License
|
110
|
+
|
111
|
+
Web package is released under the [MIT License](../master/LICENSE).
|
data/lib/web_package/cbor.rb
CHANGED
@@ -24,7 +24,9 @@ module WebPackage
|
|
24
24
|
def generate_bytes(input)
|
25
25
|
case input
|
26
26
|
when Hash
|
27
|
-
input = input.
|
27
|
+
input = input.dup.tap do |hsh|
|
28
|
+
hsh.keys.each { |key| hsh[bin(key)] = hsh.delete(key) }
|
29
|
+
end
|
28
30
|
|
29
31
|
bytes = hsh_size(input)
|
30
32
|
bytes[0] |= major_type(5)
|
data/lib/web_package/helpers.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
module WebPackage
|
2
|
+
# This class is a convenience to represent an original response, later to be signed and packed.
|
3
|
+
class InnerResponse
|
4
|
+
attr_reader :status, :headers, :body, :payload
|
5
|
+
|
6
|
+
def initialize(status, headers, body)
|
7
|
+
@status = status
|
8
|
+
@headers = headers
|
9
|
+
@body = body
|
10
|
+
@payload = unrack_body
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def unrack_body
|
16
|
+
payload = nil
|
17
|
+
|
18
|
+
# Rack's body yields strings
|
19
|
+
@body.each { |str| payload ? (payload << str) : (payload = str) }
|
20
|
+
|
21
|
+
payload
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/web_package/mice.rb
CHANGED
@@ -10,7 +10,10 @@ module WebPackage
|
|
10
10
|
|
11
11
|
def initialize(headers, body)
|
12
12
|
@body = body.dup
|
13
|
-
@headers = headers.
|
13
|
+
@headers = headers.dup.tap do |hsh|
|
14
|
+
# only lowercase keys allowed
|
15
|
+
hsh.keys.each { |key| hsh[key.to_s.downcase] = hsh.delete(key) }
|
16
|
+
end
|
14
17
|
|
15
18
|
@encoded = false
|
16
19
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module WebPackage
|
2
|
+
SXG_EXT = '.sxg'.freeze
|
3
|
+
SXG_FLAG = 'web_package.sxg'.freeze
|
4
|
+
|
5
|
+
# A Rack-compatible middleware.
|
6
|
+
class Middleware
|
7
|
+
def initialize(app)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
env[SXG_FLAG] = true if sxg_delete!(env['PATH_INFO'])
|
13
|
+
|
14
|
+
response = @app.call(env)
|
15
|
+
return response unless response[0] == 200 && env[SXG_FLAG]
|
16
|
+
|
17
|
+
# the original body must be closed first
|
18
|
+
response[2].close if response[2].respond_to? :close
|
19
|
+
|
20
|
+
# substituting the original response with SXG
|
21
|
+
SignedHttpExchange.new(url(env), response).to_rack_response
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def sxg_delete!(path)
|
27
|
+
return unless path.is_a?(String) && (i = path.rindex(SXG_EXT))
|
28
|
+
|
29
|
+
# check that extension is either the last char or followed by a slash
|
30
|
+
ch = path[i + SXG_EXT.size]
|
31
|
+
return if ch && ch != ?/
|
32
|
+
|
33
|
+
path.slice! i, SXG_EXT.size
|
34
|
+
end
|
35
|
+
|
36
|
+
def url(env)
|
37
|
+
URI("https://#{env['HTTP_HOST'] || env['SERVER_NAME']}").tap do |u|
|
38
|
+
path = env['PATH_INFO']
|
39
|
+
port = env['SERVER_PORT']
|
40
|
+
query = env['QUERY_STRING']
|
41
|
+
|
42
|
+
u.path = path
|
43
|
+
u.port = port if !u.port && port != '80'
|
44
|
+
u.query = query if query && !query.empty?
|
45
|
+
end.to_s
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -5,8 +5,6 @@ module WebPackage
|
|
5
5
|
# SXG format allows a browser to trust that a single HTTP request/response pair was
|
6
6
|
# generated by the origin it claims.
|
7
7
|
#
|
8
|
-
# Accetps two arguments: response url and response object (with body, headers and status).
|
9
|
-
# Provides two public methods to build HTTP response in SXG format: headers and body.
|
10
8
|
# Current implementation is lazy, meaning that signing is performed upon the
|
11
9
|
# invocation of the `body` method.
|
12
10
|
class SignedHttpExchange
|
@@ -17,25 +15,25 @@ module WebPackage
|
|
17
15
|
'Cache-Control' => 'no-transform',
|
18
16
|
'X-Content-Type-Options' => 'nosniff'
|
19
17
|
}.freeze
|
20
|
-
CERT_URL = ENV
|
21
|
-
CERT_PATH = ENV
|
22
|
-
PRIV_PATH = ENV
|
18
|
+
CERT_URL = ENV.fetch 'SXG_CERT_URL'
|
19
|
+
CERT_PATH = ENV.fetch 'SXG_CERT_PATH'
|
20
|
+
PRIV_PATH = ENV.fetch 'SXG_PRIV_PATH'
|
23
21
|
INTEGRITY = 'digest/mi-sha256-03'.freeze
|
24
22
|
|
25
23
|
# Mock request-response pair just in case:
|
26
24
|
MOCK_URL = 'https://example.com/wow-fake-path'.freeze
|
27
|
-
|
28
|
-
MOCK_RESP = Response['<h1>Hello!</h1>', { 'Content-Type' => 'text/html; charset=utf-8' }, 200]
|
25
|
+
MOCK_RESP = [200, { 'Content-Type' => 'text/html; charset=utf-8' }, ['<h1>Hello!</h1>']].freeze
|
29
26
|
|
30
|
-
|
31
|
-
|
32
|
-
#
|
27
|
+
# Accepts two args representing a request-response pair:
|
28
|
+
# url - request url (string)
|
29
|
+
# response - an array, equivalent to Rack's one: [status_code, headers, body]
|
33
30
|
def initialize(url = MOCK_URL, response = MOCK_RESP)
|
34
31
|
@uri = build_uri_from url
|
35
|
-
@
|
32
|
+
@url = @uri.to_s
|
33
|
+
@inner = InnerResponse.new(*response)
|
36
34
|
|
37
35
|
@cbor = CBOR.new
|
38
|
-
@mice = MICE.new(@
|
36
|
+
@mice = MICE.new(@inner.headers, @inner.payload).tap(&:encode!)
|
39
37
|
@signer = Signer.new CERT_PATH, PRIV_PATH
|
40
38
|
end
|
41
39
|
|
@@ -57,11 +55,11 @@ module WebPackage
|
|
57
55
|
@body << "sxg1-b3\x00"
|
58
56
|
|
59
57
|
# 2. 2 bytes storing a big-endian integer "fallbackUrlLength".
|
60
|
-
@body << [
|
58
|
+
@body << [@url.bytesize].pack('S>')
|
61
59
|
|
62
60
|
# 3. "fallbackUrlLength" bytes holding a "fallbackUrl", which MUST be
|
63
61
|
# an absolute URL with a scheme of "https".
|
64
|
-
@body <<
|
62
|
+
@body << @url
|
65
63
|
|
66
64
|
# 4. 3 bytes storing a big-endian integer "sigLength". If this is
|
67
65
|
# larger than 16384 (16*1024), parsing MUST fail.
|
@@ -100,6 +98,10 @@ module WebPackage
|
|
100
98
|
@body << @mice.body
|
101
99
|
end
|
102
100
|
|
101
|
+
def to_rack_response
|
102
|
+
[200, headers, [body]]
|
103
|
+
end
|
104
|
+
|
103
105
|
private
|
104
106
|
|
105
107
|
def message
|
@@ -152,8 +154,8 @@ module WebPackage
|
|
152
154
|
|
153
155
|
# 8. The 8-byte big-endian encoding of the length in bytes of
|
154
156
|
# "requestUrl", followed by the bytes of "requestUrl".
|
155
|
-
@message << [url.bytesize].pack('Q>')
|
156
|
-
@message << url
|
157
|
+
@message << [@url.bytesize].pack('Q>')
|
158
|
+
@message << @url
|
157
159
|
|
158
160
|
# 9. The 8-byte big-endian encoding of the length in bytes of
|
159
161
|
# "responseHeaders", followed by the bytes of
|
@@ -164,12 +166,12 @@ module WebPackage
|
|
164
166
|
|
165
167
|
def encoded_mice_headers
|
166
168
|
@encoded_mice_headers ||=
|
167
|
-
@cbor.generate @mice.headers.merge(':status' => bin(
|
169
|
+
@cbor.generate @mice.headers.merge(':status' => bin(@inner.status))
|
168
170
|
end
|
169
171
|
|
170
172
|
# returns a string representing serialized label + params
|
171
173
|
def structured_header_for(label, params)
|
172
|
-
if params['cert-url'].
|
174
|
+
if params[:'cert-url'].to_s.empty?
|
173
175
|
raise '[SignedHttpExchange] No certificate url provided - please use `SXG_CERT_URL` '\
|
174
176
|
'env var. Endpoint should respond with `application/cert-chain+cbor` content type.'
|
175
177
|
end
|
@@ -207,23 +209,18 @@ module WebPackage
|
|
207
209
|
|
208
210
|
def build_uri_from(url)
|
209
211
|
u = url.is_a?(URI) ? url : URI(url)
|
210
|
-
raise
|
211
|
-
raise '[SignedHttpExchange] Request host is required' if u.host.blank?
|
212
|
+
raise '[SignedHttpExchange] Request host is required' if u.host.nil?
|
212
213
|
|
213
214
|
u
|
214
215
|
end
|
215
216
|
|
216
|
-
def fallback_url
|
217
|
-
@fallback_url ||= @uri.to_s
|
218
|
-
end
|
219
|
-
|
220
217
|
def validity_url
|
221
218
|
@validity_url ||= begin
|
222
219
|
path = @uri.path
|
223
220
|
fi = path.index(?.)
|
224
221
|
no_format_path = fi ? path[0...fi] : path # path without format, i.e. default :html
|
225
222
|
|
226
|
-
URI::HTTPS.build(host: @uri.host, path: no_format_path).to_s
|
223
|
+
URI::HTTPS.build(host: @uri.host, path: no_format_path, query: @uri.query).to_s
|
227
224
|
end
|
228
225
|
end
|
229
226
|
|
data/lib/web_package/signer.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
|
1
3
|
module WebPackage
|
2
4
|
# Performs signing of a message with ECDSA.
|
3
5
|
class Signer
|
@@ -5,11 +7,11 @@ module WebPackage
|
|
5
7
|
attr_reader :signed_at, :expires_at, :cert, :integrity, :cert_url
|
6
8
|
|
7
9
|
def initialize(path_to_cert, path_to_key)
|
8
|
-
@alg
|
9
|
-
@cert
|
10
|
+
@alg = OpenSSL::PKey::EC.new(File.read(path_to_key))
|
11
|
+
@cert = OpenSSL::X509::Certificate.new(File.read(path_to_cert))
|
10
12
|
|
11
|
-
@signed_at = Time.
|
12
|
-
@expires_at = @signed_at + 7
|
13
|
+
@signed_at = Time.now
|
14
|
+
@expires_at = @signed_at + 60 * 60 * 24 * 7
|
13
15
|
end
|
14
16
|
|
15
17
|
def sign(message)
|
data/lib/web_package/version.rb
CHANGED
data/lib/web_package.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
-
require '
|
2
|
-
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
require 'web_package/errors/body_encoding_error'
|
3
4
|
require 'web_package/version'
|
4
5
|
require 'web_package/helpers'
|
5
6
|
require 'web_package/mice'
|
6
7
|
require 'web_package/cbor'
|
7
|
-
require 'web_package/
|
8
|
+
require 'web_package/inner_response'
|
8
9
|
require 'web_package/signer'
|
10
|
+
require 'web_package/signed_http_exchange'
|
11
|
+
require 'web_package/middleware'
|
data/web_package.gemspec
CHANGED
@@ -16,7 +16,8 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.files = `git ls-files`.split("\n")
|
17
17
|
s.require_paths = ['lib']
|
18
18
|
|
19
|
-
s.required_ruby_version = '>=2.
|
19
|
+
s.required_ruby_version = '>=2.2.0'
|
20
20
|
|
21
|
+
s.add_development_dependency 'byebug'
|
21
22
|
s.add_development_dependency 'rubocop', '~> 0.67'
|
22
23
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: web_package
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oleg Afanasyev
|
@@ -9,8 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2019-
|
12
|
+
date: 2019-05-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: byebug
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
14
28
|
- !ruby/object:Gem::Dependency
|
15
29
|
name: rubocop
|
16
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -41,7 +55,9 @@ files:
|
|
41
55
|
- lib/web_package/cbor.rb
|
42
56
|
- lib/web_package/errors/body_encoding_error.rb
|
43
57
|
- lib/web_package/helpers.rb
|
58
|
+
- lib/web_package/inner_response.rb
|
44
59
|
- lib/web_package/mice.rb
|
60
|
+
- lib/web_package/middleware.rb
|
45
61
|
- lib/web_package/signed_http_exchange.rb
|
46
62
|
- lib/web_package/signer.rb
|
47
63
|
- lib/web_package/version.rb
|
@@ -58,7 +74,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
58
74
|
requirements:
|
59
75
|
- - ">="
|
60
76
|
- !ruby/object:Gem::Version
|
61
|
-
version: 2.
|
77
|
+
version: 2.2.0
|
62
78
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
79
|
requirements:
|
64
80
|
- - ">="
|
@@ -66,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
82
|
version: '0'
|
67
83
|
requirements: []
|
68
84
|
rubyforge_project:
|
69
|
-
rubygems_version: 2.
|
85
|
+
rubygems_version: 2.6.13
|
70
86
|
signing_key:
|
71
87
|
specification_version: 4
|
72
88
|
summary: Packaging Websites with Ruby.
|