utopia 2.7.0 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
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.