hanami 2.0.0.alpha3 → 2.0.0.alpha4

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: f322cd4a751d83369d2d20f0f209bfb1dca92a78f6a3dd7c4027ea672df84e36
4
- data.tar.gz: 801be572c3df6e61bfaee8b72f0a164dcbe83216f33c72972c67334f9b2619cf
3
+ metadata.gz: 2188bc3aee5a164b6610c6bc97fad9f0bba0384bf11a80be27228e7f19dad4e0
4
+ data.tar.gz: 7fa39987132cf6bfda0b0986a36894d08297c1df06b31354cfbeae934d73a813
5
5
  SHA512:
6
- metadata.gz: 244ab662705c248857bc4d4e3f42b1de6dc92003fb3c8fe6d3cd006194be272d1aac36f570baa319a971dfcdd6f24eb691c270fa57b852fdbc4da863bc1908d1
7
- data.tar.gz: 3d6b72d227de112fbedefb7f8f6fbcb1e010fb37bf3d97e5826b6fe134dc0facd2a36bba0ad5e2118f731ee2bb1d18ae4f7307377c0fd31e5b81a3e307c56ae0
6
+ metadata.gz: f7b1aad0186fcdaa94593ba4ff5d01cf4f8d4431aaffba173c3c795c2c0c76993a27da3aa503b0ce59fd67467615c86c50a4ab227986e38dd0986e91c30766a5
7
+ data.tar.gz: cd2d8b82bc7f98e906686fdab7299282b1c1be4b29278c9ee5b0f9b3cefbb7d31fa83013a840b2b9fa2b8e2b2f3f8c0582ca3587b35ced91f65db6f853d67cf7
data/CHANGELOG.md CHANGED
@@ -1,6 +1,75 @@
1
1
  # Hanami
2
2
  The web, with simplicity.
3
3
 
4
+ ## v2.0.0.alpha4 - 2021-12-07
5
+ ### Added
6
+ - [Luca Guidi] Manage Content Security Policy (CSP) with "zero-defaults" policy. New API to change CSP values and to disable the feature.
7
+ ```ruby
8
+ # Read a CSP value
9
+
10
+ module MyApp
11
+ class Application < Hanami::Application
12
+ config.actions.content_security_policy[:base_uri] # => "'self'"
13
+ end
14
+ end
15
+ ```
16
+
17
+ ```ruby
18
+ # Override a default CSP value
19
+
20
+ module MyApp
21
+ class Application < Hanami::Application
22
+ # This line will generate the following CSP fragment
23
+ # plugin-types ;
24
+ config.actions.content_security_policy[:plugin_types] = nil
25
+ end
26
+ end
27
+ ```
28
+
29
+ ```ruby
30
+ # Append to a default CSP value
31
+
32
+ module MyApp
33
+ class Application < Hanami::Application
34
+ # This line will generate the following CSP fragment
35
+ # script-src 'self' https://my.cdn.test;
36
+ config.actions.content_security_policy[:script_src] += " https://my.cdn.test"
37
+ end
38
+ end
39
+ ```
40
+
41
+ ```ruby
42
+ # Add a custom CSP key. Useful when CSP standard evolves.
43
+
44
+ module MyApp
45
+ class Application < Hanami::Application
46
+ # This line will generate the following CSP fragment
47
+ # my-custom-setting 'self';
48
+ config.actions.content_security_policy[:my-custom-setting] = "'self'"
49
+ end
50
+ end
51
+ ```
52
+
53
+ ```ruby
54
+ # Delete a CSP key.
55
+
56
+ module MyApp
57
+ class Application < Hanami::Application
58
+ config.actions.content_security_policy.delete(:object_src)
59
+ end
60
+ end
61
+ ```
62
+
63
+ ```ruby
64
+ # Disable CSP feature.
65
+
66
+ module MyApp
67
+ class Application < Hanami::Application
68
+ config.actions.content_security_policy = false
69
+ end
70
+ end
71
+ ```
72
+
4
73
  ## v2.0.0.alpha3 - 2021-11-09
5
74
  ### Added
6
75
  - [Luca Guidi] Added `Hanami.shutdown` to stop all bootable components in the application container
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ Hanami.application.register_bootable :routes_helper do
4
+ start do
5
+ require "hanami/application/routes_helper"
6
+
7
+ register :routes_helper, Hanami::Application::RoutesHelper.new(Hanami.application.router)
8
+ end
9
+ end
@@ -33,7 +33,8 @@ module Hanami
33
33
  #
34
34
  # @yield DSL syntax to define application routes executed in the context
35
35
  # of {Hanami::Application::Router}
36
- # @returns [Proc]
36
+ #
37
+ # @return [Proc]
37
38
  def self.define(&block)
38
39
  @_routes = block
39
40
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ class Application
5
+ # Hanami application routes helpers
6
+ #
7
+ # An instance of this class gets registered in the container
8
+ # (`routes_helper` key) once the Hanami application is booted. You can use
9
+ # it to get the route helpers for your application.
10
+ #
11
+ # @example
12
+ # MyApp::Application["routes_helper"].path(:root) # => "/"
13
+ #
14
+ # @see Hanami::Router::UrlHelpers
15
+ # @since 2.0.0
16
+ class RoutesHelper
17
+ # @since 2.0.0
18
+ # @api private
19
+ def initialize(router)
20
+ @router = router
21
+ end
22
+
23
+ # @see Hanami::Router::UrlHelpers#path
24
+ def path(*args, **kwargs, &block)
25
+ @router.path(*args, **kwargs, &block)
26
+ end
27
+
28
+ # @see Hanami::Router::UrlHelpers#url
29
+ def url(*args, **kwargs, &block)
30
+ @router.url(*args, **kwargs, &block)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -7,6 +7,8 @@ module Hanami
7
7
  #
8
8
  # @since 2.0.0
9
9
  class Resolver
10
+ ENDPOINT_KEY_NAMESPACE = "actions"
11
+
10
12
  require_relative "resolver/trie"
11
13
 
12
14
  # @since 2.0.0
@@ -21,7 +23,7 @@ module Hanami
21
23
  def initialize(slices:, inflector:)
22
24
  @slices = slices
23
25
  @inflector = inflector
24
- @slices_registry = Trie.new
26
+ @slice_registry = Trie.new
25
27
  end
26
28
 
27
29
  # @api private
@@ -50,7 +52,7 @@ module Hanami
50
52
  # @api private
51
53
  # @since 2.0.0
52
54
  def register_slice_at_path(name, path)
53
- slices_registry.add(path, name)
55
+ slice_registry.add(path, name)
54
56
  end
55
57
 
56
58
  private
@@ -65,16 +67,19 @@ module Hanami
65
67
 
66
68
  # @api private
67
69
  # @since 2.0.0
68
- attr_reader :slices_registry
70
+ attr_reader :slice_registry
69
71
 
70
72
  # @api private
71
73
  # @since 2.0.0
72
74
  def resolve_string_identifier(path, identifier)
73
- slice_name = slices_registry.find(path) or raise "missing slice for #{path.inspect} (#{identifier.inspect})"
75
+ slice_name = slice_registry.find(path) or raise "missing slice for #{path.inspect} (#{identifier.inspect})"
74
76
  slice = slices[slice_name]
75
- action_key = "actions.#{identifier}"
77
+ endpoint_key = "#{ENDPOINT_KEY_NAMESPACE}.#{identifier}"
76
78
 
77
- slice[action_key]
79
+ # Lazily resolve endpoint from the slice to reduce router initialization time,
80
+ # and break potential endless loops from the resolved endpoint itself requiring
81
+ # access to router-related concerns
82
+ -> (*args) { slice[endpoint_key].call(*args) }
78
83
  end
79
84
  end
80
85
  end
@@ -8,6 +8,7 @@ require "rack"
8
8
  require "zeitwerk"
9
9
  require_relative "slice"
10
10
  require_relative "application/autoloader/inflector_adapter"
11
+ require_relative "application/router"
11
12
  require_relative "application/routes"
12
13
  require_relative "application/settings"
13
14
 
@@ -71,8 +72,6 @@ module Hanami
71
72
 
72
73
  autoloader.setup
73
74
 
74
- load_routes
75
-
76
75
  @inited = true
77
76
  self
78
77
  end
@@ -148,6 +147,8 @@ module Hanami
148
147
 
149
148
  init
150
149
 
150
+ load_router
151
+
151
152
  container.finalize!(&block)
152
153
 
153
154
  slices.values.each(&:boot)
@@ -168,12 +169,6 @@ module Hanami
168
169
  @_settings ||= load_settings
169
170
  end
170
171
 
171
- def routes
172
- @_mutex.synchronize do
173
- @_routes ||= load_routes
174
- end
175
- end
176
-
177
172
  MODULE_DELIMITER = "::"
178
173
  private_constant :MODULE_DELIMITER
179
174
 
@@ -216,6 +211,41 @@ module Hanami
216
211
  providers.detect { |provider| component_name.include?(provider.namespace.to_s) }
217
212
  end
218
213
 
214
+ def router
215
+ @_mutex.synchronize do
216
+ @_router ||= load_router
217
+ end
218
+ end
219
+
220
+ def load_router
221
+ Router.new(
222
+ routes: routes,
223
+ resolver: resolver,
224
+ **configuration.router.options,
225
+ ) do
226
+ use Hanami.application[:rack_monitor]
227
+
228
+ Hanami.application.config.for_each_middleware do |m, *args, &block|
229
+ use(m, *args, &block)
230
+ end
231
+ end
232
+ end
233
+
234
+ def routes
235
+ require File.join(configuration.root, configuration.router.routes_path)
236
+ routes_class = autodiscover_application_constant(configuration.router.routes_class_name)
237
+ routes_class.routes
238
+ rescue LoadError
239
+ proc {}
240
+ end
241
+
242
+ def resolver
243
+ config.router.resolver.new(
244
+ slices: slices,
245
+ inflector: inflector
246
+ )
247
+ end
248
+
219
249
  private
220
250
 
221
251
  def prepare_base_load_path
@@ -312,13 +342,6 @@ module Hanami
312
342
  end
313
343
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
314
344
 
315
- def load_routes
316
- require File.join(configuration.root, configuration.router.routes_path)
317
- routes_class = autodiscover_application_constant(configuration.router.routes_class_name)
318
- routes_class.routes
319
- rescue LoadError # rubocop:disable Lint/SuppressedException
320
- end
321
-
322
345
  def load_settings
323
346
  prepare_base_load_path
324
347
  require File.join(configuration.root, configuration.settings_path)
@@ -342,24 +365,7 @@ module Hanami
342
365
 
343
366
  application.boot
344
367
 
345
- resolver = application.config.router.resolver.new(
346
- slices: application.slices,
347
- inflector: application.inflector
348
- )
349
-
350
- router = Application::Router.new(
351
- routes: application.routes,
352
- resolver: resolver,
353
- **application.configuration.router.options,
354
- ) do
355
- use application[:rack_monitor]
356
-
357
- application.config.for_each_middleware do |m, *args, &block|
358
- use(m, *args, &block)
359
- end
360
- end
361
-
362
- @app = router.to_rack_app
368
+ @app = application.router.to_rack_app
363
369
  end
364
370
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
365
371
 
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/assets/configuration"
4
+ require "dry/configurable"
5
+
6
+ module Hanami
7
+ module Assets
8
+ # @since 2.0.0
9
+ # @api public
10
+ class ApplicationConfiguration
11
+ include Dry::Configurable
12
+
13
+ setting :server_url, default: "http://localhost:8080"
14
+
15
+ # @since 2.0.0
16
+ # @api private
17
+ def initialize(*)
18
+ super
19
+
20
+ @base_configuration = Assets::Configuration.new
21
+ end
22
+
23
+ # @since 2.0.0
24
+ # @api private
25
+ def finalize!
26
+ end
27
+
28
+ # Returns the list of available settings
29
+ #
30
+ # @return [Set]
31
+ #
32
+ # @since 2.0.0
33
+ # @api private
34
+ def settings
35
+ base_configuration.settings + self.class.settings
36
+ end
37
+
38
+ private
39
+
40
+ # @since 2.0.0
41
+ # @api private
42
+ attr_reader :base_configuration
43
+
44
+ # @since 2.0.0
45
+ # @api private
46
+ def method_missing(name, *args, &block)
47
+ if config.respond_to?(name)
48
+ config.public_send(name, *args, &block)
49
+ elsif base_configuration.respond_to?(name)
50
+ base_configuration.public_send(name, *args, &block)
51
+ else
52
+ super
53
+ end
54
+ end
55
+
56
+ # @since 2.0.0
57
+ # @api private
58
+ def respond_to_missing?(name, _incude_all = false)
59
+ config.respond_to?(name) || base_configuration.respond_to?(name) || super
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/configurable"
4
+
5
+ module Hanami
6
+ module Assets
7
+ # @since 2.0.0
8
+ # @api public
9
+ class Configuration
10
+ include Dry::Configurable
11
+
12
+ # Initialize the Configuration
13
+ #
14
+ # @yield [config] the configuration object
15
+ #
16
+ # @return [Configuration]
17
+ #
18
+ # @since 2.0.0
19
+ # @api private
20
+ def initialize(*)
21
+ super
22
+ yield self if block_given?
23
+ end
24
+
25
+ # Returns the list of available settings
26
+ #
27
+ # @return [Set]
28
+ #
29
+ # @since 2.0.0
30
+ # @api private
31
+ def settings
32
+ self.class.settings
33
+ end
34
+
35
+ private
36
+
37
+ # @since 2.0.0
38
+ # @api private
39
+ def method_missing(name, *args, &block)
40
+ if config.respond_to?(name)
41
+ config.public_send(name, *args, &block)
42
+ else
43
+ super
44
+ end
45
+ end
46
+
47
+ # @since 2.0.0
48
+ # @api private
49
+ def respond_to_missing?(name, _incude_all = false)
50
+ config.respond_to?(name) || super
51
+ end
52
+ end
53
+ end
54
+ end
@@ -28,7 +28,7 @@ module Hanami
28
28
  attr_reader :actions
29
29
  attr_reader :middleware
30
30
  attr_reader :router
31
- attr_reader :views
31
+ attr_reader :views, :assets
32
32
 
33
33
  attr_reader :environments
34
34
  private :environments
@@ -42,12 +42,22 @@ module Hanami
42
42
  self.root = Dir.pwd
43
43
  self.settings_store = Application::Settings::DotenvStore.new.with_dotenv_loaded
44
44
 
45
+ @assets = begin
46
+ require_path = "hanami/assets/application_configuration"
47
+ require require_path
48
+ Hanami::Assets::ApplicationConfiguration.new
49
+ rescue LoadError => e
50
+ raise e unless e.path == require_path
51
+ require_relative "configuration/null_configuration"
52
+ NullConfiguration.new
53
+ end
54
+
45
55
  # Config for actions (same for views, below) may not be available if the gem isn't
46
56
  # loaded; fall back to a null config object if it's missing
47
57
  @actions = begin
48
58
  require_path = "hanami/action/application_configuration"
49
59
  require require_path
50
- Hanami::Action::ApplicationConfiguration.new
60
+ Hanami::Action::ApplicationConfiguration.new(assets_server_url: assets.server_url)
51
61
  rescue LoadError => e
52
62
  raise e unless e.path == require_path
53
63
  require_relative "configuration/null_configuration"
@@ -82,6 +92,7 @@ module Hanami
82
92
  apply_env_config
83
93
 
84
94
  # Finalize nested configurations
95
+ assets.finalize!
85
96
  actions.finalize!
86
97
  views.finalize!
87
98
  logger.finalize!
@@ -8,7 +8,7 @@ module Hanami
8
8
  module Version
9
9
  # @since 0.9.0
10
10
  # @api private
11
- VERSION = "2.0.0.alpha3"
11
+ VERSION = "2.0.0.alpha4"
12
12
 
13
13
  # @since 0.9.0
14
14
  # @api private
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.alpha3
4
+ version: 2.0.0.alpha4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-09 00:00:00.000000000 Z
11
+ date: 2021-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -222,15 +222,19 @@ files:
222
222
  - lib/hanami/application/container/boot/logger.rb
223
223
  - lib/hanami/application/container/boot/rack_logger.rb
224
224
  - lib/hanami/application/container/boot/rack_monitor.rb
225
+ - lib/hanami/application/container/boot/routes_helper.rb
225
226
  - lib/hanami/application/container/boot/settings.rb
226
227
  - lib/hanami/application/router.rb
227
228
  - lib/hanami/application/routes.rb
229
+ - lib/hanami/application/routes_helper.rb
228
230
  - lib/hanami/application/routing/middleware/stack.rb
229
231
  - lib/hanami/application/routing/resolver.rb
230
232
  - lib/hanami/application/routing/resolver/node.rb
231
233
  - lib/hanami/application/routing/resolver/trie.rb
232
234
  - lib/hanami/application/settings.rb
233
235
  - lib/hanami/application/settings/dotenv_store.rb
236
+ - lib/hanami/assets/application_configuration.rb
237
+ - lib/hanami/assets/configuration.rb
234
238
  - lib/hanami/boot.rb
235
239
  - lib/hanami/cli/application/cli.rb
236
240
  - lib/hanami/cli/application/command.rb
@@ -272,7 +276,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
272
276
  - !ruby/object:Gem::Version
273
277
  version: 1.3.1
274
278
  requirements: []
275
- rubygems_version: 3.2.3
279
+ rubygems_version: 3.2.29
276
280
  signing_key:
277
281
  specification_version: 4
278
282
  summary: The web, with simplicity