lib/hanami/assets/configuration.rb in hanami-assets-0.2.1 vs lib/hanami/assets/configuration.rb in hanami-assets-0.3.0
- old
+ new
@@ -10,55 +10,63 @@
module Hanami
module Assets
# Framework configuration
#
# @since 0.1.0
- class Configuration
+ class Configuration # rubocop:disable Metrics/ClassLength
# @since 0.1.0
# @api private
- DEFAULT_SCHEME = 'http'.freeze
+ DEFAULT_SCHEME = 'http'.freeze
# @since 0.1.0
# @api private
- DEFAULT_HOST = 'localhost'.freeze
+ DEFAULT_HOST = 'localhost'.freeze
# @since 0.1.0
# @api private
- DEFAULT_PORT = '2300'.freeze
+ DEFAULT_PORT = '2300'.freeze
# @since 0.1.0
# @api private
- DEFAULT_PUBLIC_DIRECTORY = 'public'.freeze
+ DEFAULT_PUBLIC_DIRECTORY = 'public'.freeze
# @since 0.1.0
# @api private
- DEFAULT_MANIFEST = 'assets.json'.freeze
+ DEFAULT_MANIFEST = 'assets.json'.freeze
# @since 0.1.0
# @api private
- DEFAULT_PREFIX = '/assets'.freeze
+ DEFAULT_PREFIX = '/assets'.freeze
# @since 0.1.0
# @api private
- URL_SEPARATOR = '/'.freeze
+ URL_SEPARATOR = '/'.freeze
# @since 0.1.0
# @api private
- HTTP_SCHEME = 'http'.freeze
+ HTTP_SCHEME = 'http'.freeze
# @since 0.1.0
# @api private
- HTTP_PORT = '80'.freeze
+ HTTP_PORT = '80'.freeze
# @since 0.1.0
# @api private
- HTTPS_SCHEME = 'https'.freeze
+ HTTPS_SCHEME = 'https'.freeze
# @since 0.1.0
# @api private
- HTTPS_PORT = '443'.freeze
+ HTTPS_PORT = '443'.freeze
+ # @since 0.3.0
+ # @api private
+ DEFAULT_SUBRESOURCE_INTEGRITY_ALGORITHM = :sha256
+
+ # @since 0.3.0
+ # @api private
+ SUBRESOURCE_INTEGRITY_SEPARATOR = ' '.freeze
+
# Return a copy of the configuration of the framework instance associated
# with the given class.
#
# When multiple instances of Hanami::Assets are used in the same
# application, we want to make sure that a controller or an action will
@@ -70,11 +78,11 @@
# to the given class.
#
# @since 0.1.0
# @api private
def self.for(base)
- # TODO this implementation is similar to Hanami::Controller::Configuration consider to extract it into Hanami::Utils
+ # TODO: this implementation is similar to Hanami::Controller::Configuration consider to extract it into Hanami::Utils
namespace = Utils::String.new(base).namespace
framework = Utils::Class.load_from_pattern!("(#{namespace}|Hanami)::Assets")
framework.configuration
end
@@ -118,21 +126,37 @@
else
@digest = value
end
end
+ # Subresource integrity mode
+ #
+ # Determine if the helpers should generate the integrity attribute for an
+ # asset. Usually this is turned on in production mode.
+ #
+ # @since 0.3.0
+ def subresource_integrity(*values)
+ if values.empty?
+ @subresource_integrity
+ elsif values.length == 1
+ @subresource_integrity = values.first
+ else
+ @subresource_integrity = values
+ end
+ end
+
# CDN mode
#
# Determine if the helpers should always generate absolute URL.
# This is useful in production mode.
#
# @since 0.1.0
def cdn(value = nil)
if value.nil?
@cdn
else
- @cdn = !!value
+ @cdn = !!value # rubocop:disable Style/DoubleNegation
end
end
# JavaScript compressor
#
@@ -350,10 +374,17 @@
# @api private
def files
sources.files
end
+ # @since 0.3.0
+ # @api private
+ def source(file)
+ pathname = Pathname.new(file)
+ pathname.absolute? ? pathname : find(file)
+ end
+
# Find a file from sources
#
# @since 0.1.0
# @api private
def find(file)
@@ -363,23 +394,51 @@
# Relative URL
#
# @since 0.1.0
# @api private
def asset_path(source)
- cdn ?
- asset_url(source) :
+ if cdn
+ asset_url(source)
+ else
compile_path(source)
+ end
end
# Absolute URL
#
# @since 0.1.0
# @api private
def asset_url(source)
- "#{ @base_url }#{ compile_path(source) }"
+ "#{@base_url}#{compile_path(source)}"
end
+ # An array of digest algorithms to use for generating asset subresource
+ # integrity checks
+ #
+ # @since 0.3.0
+ def subresource_integrity_algorithms
+ if @subresource_integrity == true
+ [DEFAULT_SUBRESOURCE_INTEGRITY_ALGORITHM]
+ else
+ # Using Array() allows us to accept Array or Symbol, and '|| nil' lets
+ # us return an empty array when @subresource_integrity is `false`
+ Array(@subresource_integrity || nil)
+ end
+ end
+
+ # Subresource integrity attribute
+ #
+ # @since 0.3.0
+ # @api private
+ def subresource_integrity_value(source)
+ if subresource_integrity
+ digest_manifest.subresource_integrity_values(
+ prefix.join(source)
+ ).join(SUBRESOURCE_INTEGRITY_SEPARATOR)
+ end
+ end
+
# Load Javascript compressor
#
# @return [Hanami::Assets::Compressors::Javascript] a compressor
#
# @raise [Hanami::Assets::Compressors::UnknownCompressorError] when the
@@ -412,17 +471,18 @@
Hanami::Assets::Compressors::Stylesheet.for(stylesheet_compressor)
end
# @since 0.1.0
# @api private
- def duplicate
+ def duplicate # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
Configuration.new.tap do |c|
c.root = root
c.scheme = scheme
c.host = host
c.port = port
c.prefix = prefix
+ c.subresource_integrity = subresource_integrity
c.cdn = cdn
c.compile = compile
c.public_directory = public_directory
c.manifest = manifest
c.sources = sources.dup
@@ -431,18 +491,21 @@
end
end
# @since 0.1.0
# @api private
- def reset!
+ def reset! # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
@scheme = DEFAULT_SCHEME
@host = DEFAULT_HOST
@port = DEFAULT_PORT
@prefix = Utils::PathPrefix.new(DEFAULT_PREFIX)
+ @subresource_integrity = false
@cdn = false
+ @digest = false
@compile = false
+ @base_url = nil
@destination_directory = nil
@digest_manifest = Config::NullDigestManifest.new(self)
@javascript_compressor = nil
@stylesheet_compressor = nil
@@ -456,11 +519,11 @@
#
# This MUST be executed before to accept the first HTTP request
#
# @since 0.1.0
def load!
- if digest && manifest_path.exist?
+ if (digest || subresource_integrity) && manifest_path.exist?
@digest_manifest = Config::DigestManifest.new(
JSON.load(manifest_path.read),
manifest_path
)
end
@@ -468,10 +531,14 @@
@base_url = URI::Generic.build(scheme: scheme, host: host, port: url_port).to_s
end
protected
+ # @since 0.3.0
+ # @api private
+ attr_writer :subresource_integrity
+
# @since 0.1.0
# @api private
attr_writer :cdn
# @since 0.1.0
@@ -522,18 +589,18 @@
# @since 0.1.0
# @api private
def compile_path(source)
result = prefix.join(source)
- result = digest_manifest.resolve(result) if digest
+ result = digest_manifest.target(result) if digest
result.to_s
end
# @since 0.1.0
# @api private
def url_port
- ( (scheme == HTTP_SCHEME && port == HTTP_PORT ) ||
- (scheme == HTTPS_SCHEME && port == HTTPS_PORT ) ) ? nil : port.to_i
+ ((scheme == HTTP_SCHEME && port == HTTP_PORT) || # rubocop:disable Style/MultilineTernaryOperator
+ (scheme == HTTPS_SCHEME && port == HTTPS_PORT)) ? nil : port.to_i
end
end
end
end