utopia 2.7.0 → 2.8.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: b9b8589a3313f00ec6c24f36f42a17beb9daa7b07b45051f5cd7d08adc593960
4
- data.tar.gz: d79f6ad3105f73acf2abd1e77698540578e98821f70c85ce9a15112c20b455ed
3
+ metadata.gz: 477858ba9b55a11f0f5736f0e354b93ca411a7df255729f9e9d26aa35cad1553
4
+ data.tar.gz: 3429ad6e6a28e5ea03f6258a494a9e5c091cfa79862d1a984d861b9c2353f271
5
5
  SHA512:
6
- metadata.gz: 67c0162c3bea51d90699b68d25dd599dc1576a7a2ee7369ed52c42f00a54c8eeccda3884b34c432002160cd97d425fe9605cdcae223e495c414df8c49f64e7c2
7
- data.tar.gz: 661de3edd3e48871e2d6bd7c786e2d3db39ec4bbd77c0eb8df4cbb86ccd634782333ff667bb9f6a466eb014a535d76557a7b94b7dd75a76f2c46666006ed8702
6
+ metadata.gz: f0197e55bebe111947c04b36e5e3285edc8d4df58ffbf2f0e3e37b81fe813b7ae0eef18d75050bee3f90e43cb70e273ebae9c403650adaf88b69db943f2e92d5
7
+ data.tar.gz: da791eaebbac5ff5d77ed69e6cc8d4c2b3600a27b483d211e1ab8c17f74bd9e50ed63f9cb16d32abd5b89219e09c2291a43eb74c89ced7c73c0ec57b73538a07
data/Gemfile CHANGED
@@ -13,9 +13,8 @@ group :development do
13
13
  gem 'kramdown-parser-gfm'
14
14
 
15
15
  gem 'json'
16
- gem 'msgpack'
17
16
 
18
- gem "rackula"
17
+ gem 'rackula'
19
18
  end
20
19
 
21
20
  group :test do
data/bin/utopia CHANGED
@@ -20,6 +20,6 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'utopia/command'
23
+ require_relative '../lib/utopia/command'
24
24
 
25
- Utopia::Command.parse(ARGV).invoke
25
+ Utopia::Command.call
@@ -32,12 +32,12 @@ module Utopia
32
32
  class Create < Samovar::Command
33
33
  self.description = "Create a remote Utopia website suitable for deployment using git."
34
34
 
35
- def invoke(parent)
35
+ def call
36
36
  destination_root = parent.root
37
37
 
38
38
  FileUtils.mkdir_p File.join(destination_root, "public")
39
39
 
40
- Update.new.invoke(parent)
40
+ Update[parent: parent].call
41
41
 
42
42
  # Print out helpful git remote add message:
43
43
  hostname = `hostname`.chomp
@@ -55,7 +55,7 @@ module Utopia
55
55
  File.join(SETUP_ROOT, 'server')
56
56
  end
57
57
 
58
- def invoke(parent)
58
+ def call
59
59
  destination_root = parent.root
60
60
 
61
61
  Dir.chdir(destination_root) do
@@ -91,12 +91,16 @@ module Utopia
91
91
 
92
92
  self.description = "Manage server deployments."
93
93
 
94
- nested '<command>',
94
+ nested :command,
95
95
  'create' => Create,
96
96
  'update' => Update
97
97
 
98
- def invoke(parent)
99
- @command.invoke(parent)
98
+ def root
99
+ @parent.root
100
+ end
101
+
102
+ def call
103
+ @command.call
100
104
  end
101
105
  end
102
106
  end
@@ -46,7 +46,7 @@ module Utopia
46
46
  class Create < Samovar::Command
47
47
  self.description = "Create a new local Utopia website using the default template."
48
48
 
49
- def invoke(parent)
49
+ def call
50
50
  destination_root = parent.root
51
51
 
52
52
  $stderr.puts "Setting up initial site in #{destination_root} for Utopia v#{Utopia::VERSION}..."
@@ -135,7 +135,7 @@ module Utopia
135
135
  end
136
136
  end
137
137
 
138
- def invoke(parent)
138
+ def call
139
139
  destination_root = parent.root
140
140
  branch_name = "utopia-upgrade-#{Utopia::VERSION}"
141
141
 
@@ -195,14 +195,18 @@ module Utopia
195
195
  end
196
196
  end
197
197
 
198
- nested '<command>',
198
+ nested :command,
199
199
  'create' => Create,
200
200
  'update' => Update
201
201
 
202
202
  self.description = "Manage local utopia sites."
203
203
 
204
- def invoke(parent)
205
- @command.invoke(parent)
204
+ def root
205
+ @parent.root
206
+ end
207
+
208
+ def call
209
+ @command.call
206
210
  end
207
211
  end
208
212
  end
@@ -26,8 +26,8 @@ require_relative 'command/environment'
26
26
 
27
27
  module Utopia
28
28
  module Command
29
- def self.parse(*args)
30
- Top.parse(*args)
29
+ def self.call(*args)
30
+ Top.call(*args)
31
31
  end
32
32
 
33
33
  # The top level utopia command.
@@ -40,23 +40,24 @@ module Utopia
40
40
  option '-v/--version', "Print out the application version."
41
41
  end
42
42
 
43
- nested '<command>',
43
+ nested :command, {
44
44
  'site' => Site,
45
45
  'server' => Server,
46
46
  'environment' => Environment
47
+ }
47
48
 
48
49
  # The root directory for the site.
49
50
  def root
50
51
  File.expand_path(@options.fetch(:root, ''), Dir.getwd)
51
52
  end
52
53
 
53
- def invoke(program_name: File.basename($0))
54
+ def call
54
55
  if @options[:version]
55
- puts "utopia v#{VERSION}"
56
- elsif @options[:help] or @command.nil?
57
- print_usage(program_name)
56
+ puts "#{self.name} v#{VERSION}"
57
+ elsif @options[:help]
58
+ print_usage(output: $stdout)
58
59
  else
59
- @command.invoke(self)
60
+ @command.call
60
61
  end
61
62
  end
62
63
  end
@@ -0,0 +1,48 @@
1
+ # Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'time'
22
+ require 'date'
23
+
24
+ module Utopia
25
+ class Session
26
+ class Serialization
27
+ def initialize
28
+ @factory = MessagePack::Factory.new
29
+
30
+ @factory.register_type(0x00, Symbol, packer: :to_msgpack_ext, unpacker: :from_msgpack_ext)
31
+
32
+ @factory.register_type(0x01, Time, packer: :iso8601, unpacker: :parse)
33
+ @factory.register_type(0x02, Date, packer: :iso8601, unpacker: :parse)
34
+ @factory.register_type(0x03, DateTime, packer: :iso8601, unpacker: :parse)
35
+ end
36
+
37
+ attr :factory
38
+
39
+ def load(data)
40
+ @factory.unpack(data)
41
+ end
42
+
43
+ def dump(object)
44
+ @factory.pack(object)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -22,11 +22,19 @@ require 'openssl'
22
22
  require 'securerandom'
23
23
  require 'digest/sha2'
24
24
 
25
+ require 'json'
26
+
25
27
  require_relative 'session/lazy_hash'
28
+ require_relative 'session/serialization'
26
29
 
27
30
  module Utopia
28
31
  # A middleware which provides a secure client-side session storage using a private symmetric encrpytion key.
29
32
  class Session
33
+ class PayloadError < StandardError
34
+ end
35
+
36
+ MAXIMUM_SIZE = 1024*32
37
+
30
38
  SECRET_KEY = 'UTOPIA_SESSION_SECRET'.freeze
31
39
 
32
40
  RACK_SESSION = "rack.session".freeze
@@ -42,7 +50,7 @@ module Utopia
42
50
  # @param secret [Array] The secret text used to generate a symetric encryption key for the coookie data.
43
51
  # @param expires_after [String] The cache-control header to set for static content.
44
52
  # @param options [Hash<Symbol,Object>] Additional defaults used for generating the cookie by `Rack::Utils.set_cookie_header!`.
45
- def initialize(app, session_name: RACK_SESSION, secret: nil, expires_after: DEFAULT_EXPIRES_AFTER, update_timeout: DEFAULT_UPDATE_TIMEOUT, secure: false, **options)
53
+ def initialize(app, session_name: RACK_SESSION, secret: nil, expires_after: DEFAULT_EXPIRES_AFTER, update_timeout: DEFAULT_UPDATE_TIMEOUT, secure: false, maximum_size: MAXIMUM_SIZE, **options)
46
54
  @app = app
47
55
 
48
56
  @session_name = session_name
@@ -67,6 +75,9 @@ module Utopia
67
75
  # The HttpOnly attribute directs browsers not to expose cookies through channels other than HTTP (and HTTPS) requests. This means that the cookie cannot be accessed via client-side scripting languages (notably JavaScript), and therefore cannot be stolen easily via cross-site scripting (a pervasive attack technique).
68
76
  http_only: true,
69
77
  }.merge(options)
78
+
79
+ @serialization = Serialization.new
80
+ @maximum_size = maximum_size
70
81
  end
71
82
 
72
83
  attr :cookie_name
@@ -135,8 +146,14 @@ module Utopia
135
146
 
136
147
  # Decrypt the data from the user if possible:
137
148
  if data = request.cookies[@cookie_name]
138
- if values = decrypt(data) and valid_session?(request, values)
139
- return values
149
+ begin
150
+ if values = decrypt(data)
151
+ validate_session!(request, values)
152
+
153
+ return values
154
+ end
155
+ rescue => error
156
+ request.logger&.error(error)
140
157
  end
141
158
  end
142
159
 
@@ -144,11 +161,9 @@ module Utopia
144
161
  return build_initial_session(request)
145
162
  end
146
163
 
147
- def valid_session?(request, values)
164
+ def validate_session!(request, values)
148
165
  if values[:user_agent] != request.user_agent
149
- warn "Invalid session because #{values[:user_agent]} doesn't match #{request.user_agent}!" if $VERBOSE
150
-
151
- return false
166
+ raise PayloadError, "Invalid session because supplied user agent #{request.user_agent.inspect} does not match session user agent #{values[:user_agent].inspect}!"
152
167
  end
153
168
 
154
169
  return true
@@ -177,13 +192,17 @@ module Utopia
177
192
  c.key = @key
178
193
  c.iv = iv = c.random_iv
179
194
 
180
- e = c.update(Marshal.dump(hash))
195
+ e = c.update(@serialization.dump(hash))
181
196
  e << c.final
182
197
 
183
198
  return [iv, e].pack("m16m*")
184
199
  end
185
200
 
186
201
  def decrypt(data)
202
+ if @maximum_size and data.bytesize > @maximum_size
203
+ raise PayloadError, "Session payload size #{data.bytesize}bytes exceeds maximum allowed size #{@maximum_size}bytes!"
204
+ end
205
+
187
206
  iv, e = data.unpack("m16m*")
188
207
 
189
208
  c = OpenSSL::Cipher.new(CIPHER_ALGORITHM)
@@ -195,9 +214,7 @@ module Utopia
195
214
  d = c.update(e)
196
215
  d << c.final
197
216
 
198
- return Marshal.load(d)
199
- rescue
200
- return nil
217
+ return @serialization.load(d)
201
218
  end
202
219
  end
203
220
  end
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Utopia
22
- VERSION = "2.7.0"
22
+ VERSION = "2.8.0"
23
23
  end
data/utopia.gemspec CHANGED
@@ -25,8 +25,9 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  spec.add_dependency 'trenni', '~> 3.0'
27
27
  spec.add_dependency 'mime-types', '~> 3.0'
28
+ spec.add_dependency 'msgpack'
28
29
 
29
- spec.add_dependency 'samovar', '~> 1.2'
30
+ spec.add_dependency 'samovar', '~> 2.1'
30
31
  spec.add_dependency 'event', '~> 1.1'
31
32
 
32
33
  spec.add_dependency 'rack', '~> 2.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: utopia
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.0
4
+ version: 2.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-17 00:00:00.000000000 Z
11
+ date: 2019-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: trenni
@@ -38,20 +38,34 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: msgpack
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: samovar
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '1.2'
61
+ version: '2.1'
48
62
  type: :runtime
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '1.2'
68
+ version: '2.1'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: event
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -584,6 +598,7 @@ files:
584
598
  - lib/utopia/redirection.rb
585
599
  - lib/utopia/session.rb
586
600
  - lib/utopia/session/lazy_hash.rb
601
+ - lib/utopia/session/serialization.rb
587
602
  - lib/utopia/setup.rb
588
603
  - lib/utopia/static.rb
589
604
  - lib/utopia/static/local_file.rb
@@ -745,7 +760,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
745
760
  - !ruby/object:Gem::Version
746
761
  version: '0'
747
762
  requirements: []
748
- rubygems_version: 3.0.2
763
+ rubygems_version: 3.0.3
749
764
  signing_key:
750
765
  specification_version: 4
751
766
  summary: Utopia is a framework for building dynamic content-driven websites.