web_package 0.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 21d491102ea52a0f47bd981ddf9d04e0be400e805b75340a58df13fc5a2304d0
4
+ data.tar.gz: 9763deee5944d7dc29d5f47ab490d1ea447d14e7d204f7fa3e68a69eb5ff92a3
5
+ SHA512:
6
+ metadata.gz: 3b8864f0082ff7e8ccfcff2066c9cace5c877b8ef4e77f80ef9b6fc1be5f441a03436437f565eb430f169e2f673f42f2667dc19c47e3ae92d91d95a54b64ced4
7
+ data.tar.gz: aab6bf17a00c12d82ba3e509e75765e9d92344c11409c876e1aa7800fa3b400b25cc9f209f2678a21a5f6d7e01404d931448ca26d6e8a9930d76d88437e6a590
data/.gitignore ADDED
@@ -0,0 +1,50 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ ## Specific to RubyMotion:
17
+ .dat*
18
+ .repl_history
19
+ build/
20
+ *.bridgesupport
21
+ build-iPhoneOS/
22
+ build-iPhoneSimulator/
23
+
24
+ ## Specific to RubyMotion (use of CocoaPods):
25
+ #
26
+ # We recommend against adding the Pods directory to your .gitignore. However
27
+ # you should judge for yourself, the pros and cons are mentioned at:
28
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
29
+ #
30
+ # vendor/Pods/
31
+
32
+ ## Documentation cache and generated files:
33
+ /.yardoc/
34
+ /_yardoc/
35
+ /doc/
36
+ /rdoc/
37
+
38
+ ## Environment normalization:
39
+ /.bundle/
40
+ /vendor/bundle
41
+ /lib/bundler/man/
42
+
43
+ # for a library or gem, you might want to ignore these files since the code is
44
+ # intended to run in multiple environments; otherwise, check them in:
45
+ # Gemfile.lock
46
+ # .ruby-version
47
+ # .ruby-gemset
48
+
49
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
+ .rvmrc
data/.rubocop.yml ADDED
@@ -0,0 +1,42 @@
1
+ Metrics/LineLength:
2
+ Max: 100
3
+ IgnoreCopDirectives: true
4
+
5
+ Naming/UncommunicativeMethodParamName:
6
+ AllowedNames:
7
+ - s
8
+
9
+ Style/CharacterLiteral:
10
+ Enabled: false
11
+
12
+ Metrics/MethodLength:
13
+ Exclude:
14
+ - lib/web_package/cbor.rb
15
+ - lib/web_package/mice.rb
16
+ - lib/web_package/signed_http_exchange.rb
17
+
18
+ Metrics/AbcSize:
19
+ Max: 20
20
+ Exclude:
21
+ - lib/web_package/cbor.rb
22
+ - lib/web_package/mice.rb
23
+ - lib/web_package/signed_http_exchange.rb
24
+
25
+ Layout/EmptyLineAfterGuardClause:
26
+ Exclude:
27
+ - lib/web_package/signed_http_exchange.rb
28
+
29
+ Metrics/ClassLength:
30
+ Exclude:
31
+ - lib/web_package/signed_http_exchange.rb
32
+
33
+ Style/RedundantReturn:
34
+ Enabled: false
35
+
36
+ Layout/SpaceInsideRangeLiteral:
37
+ Exclude:
38
+ - lib/web_package/cbor.rb
39
+
40
+ Layout/ExtraSpacing:
41
+ Exclude:
42
+ - lib/web_package/cbor.rb
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2019 Oleg Afanasyev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # web_package
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.
@@ -0,0 +1,89 @@
1
+ module WebPackage
2
+ # Concise Binary Object Representation
3
+ # https://tools.ietf.org/html/rfc7049
4
+ class CBOR
5
+ include Helpers
6
+
7
+ # Major type 0: an unsigned integer.
8
+ # Major type 1: a negative integer.
9
+ # Major type 2: a byte string.
10
+ # Major type 3: a text string, Unicode characters that is encoded as UTF-8 [RFC3629].
11
+ # Major type 4: an array of data items.
12
+ # Major type 5: a map of pairs of data items.
13
+ # Major type 6: optional semantic tagging of other major types.
14
+ # Major type 7: floating-point numbers and simple data types that need no content.
15
+ MAJOR_TYPES_RANGE = 0..7
16
+
17
+ def generate(input)
18
+ generate_bytes(input).pack('C*')
19
+ end
20
+
21
+ private
22
+
23
+ # https://tools.ietf.org/html/rfc7049#section-2.1
24
+ def generate_bytes(input)
25
+ case input
26
+ when Hash
27
+ input = input.transform_keys { |key| bin(key) }
28
+
29
+ bytes = hsh_size(input)
30
+ bytes[0] |= major_type(5)
31
+
32
+ input.keys.sort_by(&:bytesize).each do |key|
33
+ bytes.concat generate_bytes(key)
34
+ bytes.concat generate_bytes(input[key])
35
+ end
36
+ when String, Symbol
37
+ input = input.to_s
38
+ bytes = str_size(input)
39
+ # rubocop: disable Style/IdenticalConditionalBranches
40
+ # TODO: Use major_type(3) for non-binary strings.
41
+ # Right now all strings are encoded as byte strings because Chrome eats only such.
42
+ # So, we need to either proove wrong, or submit an issue to chromium dev.
43
+ bytes[0] |= input.encoding == Encoding::BINARY ? major_type(2) : major_type(2)
44
+ # rubocop: enable Style/IdenticalConditionalBranches
45
+ bytes.concat input.bytes
46
+ when Integer
47
+ raise '[CBOR] Not implemented for negative integers' if input.negative?
48
+
49
+ bytes = int_size(input)
50
+ bytes[0] |= major_type(0) # a positive integer
51
+ else
52
+ raise "[CBOR] Not implemented for #{input.class} class"
53
+ end
54
+
55
+ bytes
56
+ end
57
+
58
+ def major_type(num)
59
+ unless MAJOR_TYPES_RANGE.include? num
60
+ raise "[CBOR] Cannot infer Major Type from int #{num}, which is outside of allowed range."
61
+ end
62
+
63
+ # the type takes up 3 most significant bits of first byte
64
+ num << 5
65
+ end
66
+
67
+ def hsh_size(hsh)
68
+ size = hsh.size
69
+ raise '[CBOR] Not implemented for the hash of size more than 23 pairs' unless size < 24
70
+
71
+ [size]
72
+ end
73
+
74
+ def str_size(s)
75
+ int_size s.bytesize
76
+ end
77
+
78
+ def int_size(num)
79
+ case num
80
+ when 0... 24 then [num]
81
+ when 24... 2**8 then [24, *[num].pack('C').bytes]
82
+ when 2**8...2**16 then [25, *[num].pack('S>').bytes]
83
+ when 2**16...2**32 then [26, *[num].pack('L>').bytes]
84
+ when 2**32...2**64 then [27, *[num].pack('Q>').bytes]
85
+ else raise '[CBOR] Not implemented for integers greater than (2**64 - 1) bits'
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,5 @@
1
+ module WebPackage
2
+ module Errors
3
+ class BodyEncodingError < StandardError; end
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ module WebPackage
2
+ # Helper methods used in the library.
3
+ module Helpers
4
+ private
5
+
6
+ def bin(s)
7
+ force_bin(s.is_a?(String) ? s.dup : s.to_s)
8
+ end
9
+
10
+ def force_bin(s)
11
+ s.force_encoding Encoding::ASCII_8BIT
12
+ end
13
+
14
+ def digest(s)
15
+ Digest::SHA256.digest s
16
+ end
17
+
18
+ def base64(s)
19
+ Base64.strict_encode64 s
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,58 @@
1
+ module WebPackage
2
+ # Merkle Integrity Content Encoding
3
+ # https://tools.ietf.org/id/draft-thomson-http-mice-03.html
4
+ class MICE
5
+ include Helpers
6
+
7
+ CHUNK_SIZE = 2**14 # bytes
8
+
9
+ attr_reader :headers, :body
10
+
11
+ def initialize(headers, body)
12
+ @body = body.dup
13
+ @headers = headers.transform_keys { |key| key.to_s.downcase } # only lowercase keys allowed
14
+
15
+ @encoded = false
16
+ end
17
+
18
+ def encode!
19
+ return if encoded?
20
+
21
+ @root_digest, @body = interlace_body_with_digests
22
+ @headers.merge! 'content-encoding' => 'mi-sha256-03',
23
+ 'digest' => "mi-sha256-03=#{base64(@root_digest)}",
24
+ 'x-content-type-options' => 'nosniff'
25
+ # TODO: find out why we need (or do not need) Link header for the purpose of
26
+ # serving Signed Http Exchange
27
+ # linkHeader, err := formatLinkHeader(metadata.Preloads)
28
+ # fetchResp.Header.Set("Link", linkHeader)
29
+
30
+ @encoded = true
31
+ end
32
+
33
+ def encoded?
34
+ @encoded
35
+ end
36
+
37
+ private
38
+
39
+ def interlace_body_with_digests
40
+ num_parts = @body.bytesize.fdiv(CHUNK_SIZE).ceil
41
+
42
+ chunks = []
43
+ proofs = []
44
+
45
+ num_parts.times do |i|
46
+ delimeter = i.zero? && "\x00" || "\x01"
47
+ ri = num_parts - i - 1
48
+
49
+ chunks << force_bin(@body.byteslice(ri * CHUNK_SIZE, CHUNK_SIZE))
50
+ proofs << digest("#{chunks.last}#{proofs.last}#{delimeter}")
51
+ end
52
+
53
+ chunks << [CHUNK_SIZE].pack('Q>')
54
+
55
+ return proofs.pop, chunks.zip(proofs).flatten.reverse!.join
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,238 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ module WebPackage
4
+ # Builds headers and body of SXG format for a given pair of HTTP request-response.
5
+ # SXG format allows a browser to trust that a single HTTP request/response pair was
6
+ # generated by the origin it claims.
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
+ # Current implementation is lazy, meaning that signing is performed upon the
11
+ # invocation of the `body` method.
12
+ class SignedHttpExchange
13
+ SIGNATURE_MAX_SIZE = 2**14
14
+ HEADERS_MAX_SIZE = 2**19
15
+ SXG_HEADERS = {
16
+ 'Content-Type' => 'application/signed-exchange;v=b3',
17
+ 'Cache-Control' => 'no-transform',
18
+ 'X-Content-Type-Options' => 'nosniff'
19
+ }.freeze
20
+ CERT_URL = ENV['SXG_CERT_URL']
21
+ CERT_PATH = ENV['SXG_CERT_PATH']
22
+ PRIV_PATH = ENV['SXG_PRIV_PATH']
23
+ INTEGRITY = 'digest/mi-sha256-03'.freeze
24
+
25
+ # Mock request-response pair just in case:
26
+ MOCK_URL = 'https://example.com/wow-fake-path'.freeze
27
+ Response = Struct.new :body, :headers, :status
28
+ MOCK_RESP = Response['<h1>Hello!</h1>', { 'Content-Type' => 'text/html; charset=utf-8' }, 200]
29
+
30
+ attr_reader :url, :response, :mice
31
+
32
+ # accepts two args representing a request-response pair to be packed into SXG format
33
+ def initialize(url = MOCK_URL, response = MOCK_RESP)
34
+ @uri = build_uri_from url
35
+ @response = response
36
+
37
+ @cbor = CBOR.new
38
+ @mice = MICE.new(@response.headers, @response.body).tap(&:encode!)
39
+ @signer = Signer.new CERT_PATH, PRIV_PATH
40
+ end
41
+
42
+ def headers
43
+ SXG_HEADERS
44
+ end
45
+
46
+ # https://tools.ietf.org/html/draft-yasskin-http-origin-signed-responses-05#section-5.3
47
+ def body
48
+ return @body if @body
49
+ @body = ''
50
+
51
+ # 1. 8 bytes consisting of the ASCII characters "sxg1" followed by 4
52
+ # 0x00 bytes, to serve as a file signature. This is redundant with
53
+ # the MIME type, and recipients that receive both MUST check that
54
+ # they match and stop parsing if they don't.
55
+ # TODO: The implementation of the final RFC MUST use the following line:
56
+ # @body << "sxg1\x00\x00\x00\x00"
57
+ @body << "sxg1-b3\x00"
58
+
59
+ # 2. 2 bytes storing a big-endian integer "fallbackUrlLength".
60
+ @body << [fallback_url.bytesize].pack('S>')
61
+
62
+ # 3. "fallbackUrlLength" bytes holding a "fallbackUrl", which MUST be
63
+ # an absolute URL with a scheme of "https".
64
+ @body << fallback_url
65
+
66
+ # 4. 3 bytes storing a big-endian integer "sigLength". If this is
67
+ # larger than 16384 (16*1024), parsing MUST fail.
68
+ if signature.bytesize > SIGNATURE_MAX_SIZE
69
+ raise Errors::BodyEncodingError, 'Structured Signature Header length is too large: '\
70
+ "#{signature.bytesize} bytes, max: #{SIGNATURE_MAX_SIZE} bytes."
71
+ end
72
+ @body << [signature.bytesize].pack('L>').byteslice(-3, 3)
73
+
74
+ # 5. 3 bytes storing a big-endian integer "headerLength". If this is
75
+ # larger than 524288 (512*1024), parsing MUST fail.
76
+ if encoded_mice_headers.bytesize > HEADERS_MAX_SIZE
77
+ raise Errors::BodyEncodingError, 'Response Headers length is too large: '\
78
+ "#{encoded_mice_headers.bytesize} bytes, max: #{HEADERS_MAX_SIZE} bytes."
79
+ end
80
+ @body << [encoded_mice_headers.bytesize].pack('L>').byteslice(-3, 3)
81
+
82
+ # 6. "sigLength" bytes holding the "Signature" header field's value
83
+ # (Section 3.1).
84
+ @body << signature
85
+
86
+ # 7. "headerLength" bytes holding "signedHeaders", the canonical
87
+ # serialization (Section 3.4) of the CBOR representation of the
88
+ # response headers of the exchange represented by the "application/
89
+ # signed-exchange" resource (Section 3.2), excluding the
90
+ # "Signature" header field.
91
+ @body << encoded_mice_headers
92
+
93
+ # 8. The payload body (Section 3.3 of [RFC7230]) of the exchange
94
+ # represented by the "application/signed-exchange" resource.
95
+ # Note that the use of the payload body here means that a
96
+ # "Transfer-Encoding" header field inside the "application/signed-
97
+ # exchange" header block has no effect. A "Transfer-Encoding"
98
+ # header field on the outer HTTP response that transfers this
99
+ # resource still has its normal effect.
100
+ @body << @mice.body
101
+ end
102
+
103
+ private
104
+
105
+ def message
106
+ return @message if @message
107
+ @message = ''
108
+
109
+ # Help in debugging "VerifyFinal failed." error, source code:
110
+ # https://github.com/chromium/chromium/blob/8f0bd6c8be04f0dd556d42820f1eec0963dfe10b/
111
+ # content/browser/web_package/signed_exchange_signature_verifier.cc#L120
112
+ # It may look as if something is wrong with the certificate or signing algorithm, but in fact
113
+ # the error is caused by the message being composed incorrectly.
114
+ # So, if you get such an error - please check the `message` first.
115
+
116
+ # From specs:
117
+ # https://tools.ietf.org/html/draft-yasskin-http-origin-signed-responses-05#section-3.5
118
+ #
119
+ # Let "message" be the concatenation of the following byte
120
+ # strings. This matches the [RFC8446] format to avoid cross-
121
+ # protocol attacks if anyone uses the same key in a TLS
122
+ # certificate and an exchange-signing certificate.
123
+
124
+ # 1. A string that consists of octet 32 (0x20) repeated 64 times.
125
+ @message << "\x20" * 64
126
+
127
+ # 2. A context string: the ASCII encoding of "HTTP Exchange 1".
128
+ # ... but implementations of drafts MUST NOT use it and MUST use another
129
+ # draft-specific string beginning with "HTTP Exchange 1 " instead.
130
+ # TODO: The implementation of the final RFC MUST use the following line:
131
+ # @message << "HTTP Exchange 1"
132
+ @message << 'HTTP Exchange 1 b3'
133
+
134
+ # 3. A single 0 byte which serves as a separator.
135
+ @message << "\x00"
136
+
137
+ # 4. If "cert-sha256" is set, a byte holding the value 32
138
+ # followed by the 32 bytes of the value of "cert-sha256".
139
+ # Otherwise a 0 byte.
140
+ @message << (@signer.cert_sha256 ? "\x20#{@signer.cert_sha256}" : "\x00")
141
+
142
+ # 5. The 8-byte big-endian encoding of the length in bytes of
143
+ # "validity-url", followed by the bytes of "validity-url".
144
+ @message << [validity_url.bytesize].pack('Q>')
145
+ @message << validity_url
146
+
147
+ # 6. The 8-byte big-endian encoding of "date".
148
+ @message << [@signer.signed_at.to_i].pack('Q>')
149
+
150
+ # 7. The 8-byte big-endian encoding of "expires".
151
+ @message << [@signer.expires_at.to_i].pack('Q>')
152
+
153
+ # 8. The 8-byte big-endian encoding of the length in bytes of
154
+ # "requestUrl", followed by the bytes of "requestUrl".
155
+ @message << [url.bytesize].pack('Q>')
156
+ @message << url
157
+
158
+ # 9. The 8-byte big-endian encoding of the length in bytes of
159
+ # "responseHeaders", followed by the bytes of
160
+ # "responseHeaders".
161
+ @message << [encoded_mice_headers.bytesize].pack('Q>')
162
+ @message << encoded_mice_headers
163
+ end
164
+
165
+ def encoded_mice_headers
166
+ @encoded_mice_headers ||=
167
+ @cbor.generate @mice.headers.merge(':status' => bin(response.status))
168
+ end
169
+
170
+ # returns a string representing serialized label + params
171
+ def structured_header_for(label, params)
172
+ if params['cert-url'].blank?
173
+ raise '[SignedHttpExchange] No certificate url provided - please use `SXG_CERT_URL` '\
174
+ 'env var. Endpoint should respond with `application/cert-chain+cbor` content type.'
175
+ end
176
+
177
+ res = [label]
178
+
179
+ params.sort.each do |key, value|
180
+ # https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-09#section-4.1.10
181
+ res << "#{key}=" + case value
182
+ when Integer then value.to_s
183
+ when String then %("#{value}") # a text string
184
+ when Array then "*#{base64(value.pack('C*'))}*" # a byte string
185
+ end
186
+ end
187
+
188
+ res.join(?;)
189
+ end
190
+
191
+ # https://tools.ietf.org/html/draft-ietf-httpbis-header-structure-09
192
+ def signature
193
+ # Example of a signature:
194
+ # label;cert-sha256=*+DoXYlCX+bFRyW65R3bFA2ICIz8Tyu54MLFUFo5tziA=*;cert-url="https://exampl
195
+ # e.com/cert.cbor";date=1555925114;expires=1555928714;integrity="digest/mi-sha256-03";sig=*
196
+ # MEQCIBgsnVxmRqzjeFczuXnQClf2bwtHdGeGGSMOz6y5EH7HAiAu1lt2ERsWIRcOmszB3XneSWoGKrMD7wvalVfPp
197
+ # 4tb9Q==*;validity-url="https://example.com/resource.validity.msg"
198
+ @signature ||=
199
+ structured_header_for 'label', 'cert-sha256': @signer.cert_sha256.bytes,
200
+ 'cert-url': CERT_URL,
201
+ 'date': @signer.signed_at.to_i,
202
+ 'expires': @signer.expires_at.to_i,
203
+ 'integrity': INTEGRITY,
204
+ 'sig': @signer.sign(message).bytes,
205
+ 'validity-url': validity_url
206
+ end
207
+
208
+ def build_uri_from(url)
209
+ u = url.is_a?(URI) ? url : URI(url)
210
+ raise "[SignedHttpExchange] Unsupported URI scheme: #{u.scheme}" unless u.is_a? URI::HTTPS
211
+ raise '[SignedHttpExchange] Request host is required' if u.host.blank?
212
+
213
+ u
214
+ end
215
+
216
+ def fallback_url
217
+ @fallback_url ||= @uri.to_s
218
+ end
219
+
220
+ def validity_url
221
+ @validity_url ||= begin
222
+ path = @uri.path
223
+ fi = path.index(?.)
224
+ no_format_path = fi ? path[0...fi] : path # path without format, i.e. default :html
225
+
226
+ URI::HTTPS.build(host: @uri.host, path: no_format_path).to_s
227
+ end
228
+ end
229
+
230
+ def bin(s)
231
+ s.to_s.force_encoding Encoding::ASCII_8BIT
232
+ end
233
+
234
+ def base64(s)
235
+ Base64.strict_encode64 s
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,23 @@
1
+ module WebPackage
2
+ # Performs signing of a message with ECDSA.
3
+ class Signer
4
+ include Helpers
5
+ attr_reader :signed_at, :expires_at, :cert, :integrity, :cert_url
6
+
7
+ def initialize(path_to_cert, path_to_key)
8
+ @alg = OpenSSL::PKey::EC.new(File.read(path_to_key))
9
+ @cert = OpenSSL::X509::Certificate.new(File.read(path_to_cert))
10
+
11
+ @signed_at = Time.zone.now
12
+ @expires_at = @signed_at + 7.days
13
+ end
14
+
15
+ def sign(message)
16
+ @alg.dsa_sign_asn1 digest(message)
17
+ end
18
+
19
+ def cert_sha256
20
+ @cert_sha256 ||= digest(@cert.to_der)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ module WebPackage
2
+ VERSION = '0.0.0'.freeze
3
+ end
@@ -0,0 +1,8 @@
1
+ require 'web_package/errors/body_format_error'
2
+ require 'web_package/errors/certificate_url_format_error'
3
+ require 'web_package/version'
4
+ require 'web_package/helpers'
5
+ require 'web_package/mice'
6
+ require 'web_package/cbor'
7
+ require 'web_package/signed_http_exchange'
8
+ require 'web_package/signer'
@@ -0,0 +1,22 @@
1
+ require File.expand_path('lib/web_package/version', __dir__)
2
+ require 'date'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'web_package'
6
+ s.version = WebPackage::VERSION
7
+ s.date = Date.today.to_s
8
+ s.summary = 'Packaging Websites with Ruby.'
9
+ s.description = 'Ruby implementation of Signed HTTP Exchange format, allowing a browser to '\
10
+ 'trust that a HTTP request-response pair was generated by the origin it claims.'
11
+ s.authors = ['Oleg Afanasyev', 'Alexey Martynyuk']
12
+ s.email = ['gafrom@gmail.com']
13
+ s.homepage = 'https://github.com/gafrom/web_package'
14
+ s.license = 'MIT'
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.require_paths = ['lib']
18
+
19
+ s.required_ruby_version = '>=2.0.0'
20
+
21
+ s.add_development_dependency 'rubocop', '~> 0.67'
22
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: web_package
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Oleg Afanasyev
8
+ - Alexey Martynyuk
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2019-04-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rubocop
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '0.67'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '0.67'
28
+ description: Ruby implementation of Signed HTTP Exchange format, allowing a browser
29
+ to trust that a HTTP request-response pair was generated by the origin it claims.
30
+ email:
31
+ - gafrom@gmail.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - ".gitignore"
37
+ - ".rubocop.yml"
38
+ - LICENSE
39
+ - README.md
40
+ - lib/web_package.rb
41
+ - lib/web_package/cbor.rb
42
+ - lib/web_package/errors/body_encoding_error.rb
43
+ - lib/web_package/helpers.rb
44
+ - lib/web_package/mice.rb
45
+ - lib/web_package/signed_http_exchange.rb
46
+ - lib/web_package/signer.rb
47
+ - lib/web_package/version.rb
48
+ - web_package.gemspec
49
+ homepage: https://github.com/gafrom/web_package
50
+ licenses:
51
+ - MIT
52
+ metadata: {}
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 2.0.0
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project:
69
+ rubygems_version: 2.7.6
70
+ signing_key:
71
+ specification_version: 4
72
+ summary: Packaging Websites with Ruby.
73
+ test_files: []