Module: Sprockets::DigestUtils

Extended by:
DigestUtils
Included in:
Base, Dependencies, DigestUtils, Loader, PathDigestUtils
Defined in:
lib/sprockets/digest_utils.rb

Overview

Internal: Hash functions and digest related utilities. Mixed into Environment.

Constant Summary collapse

DIGEST_SIZES =

Internal: Maps digest bytesize to the digest class.

{
  16 => Digest::MD5,
  20 => Digest::SHA1,
  32 => Digest::SHA256,
  48 => Digest::SHA384,
  64 => Digest::SHA512
}
HASH_ALGORITHMS =

Internal: Maps digest class to the CSP hash algorithm name.

{
  Digest::SHA256 => 'sha256'.freeze,
  Digest::SHA384 => 'sha384'.freeze,
  Digest::SHA512 => 'sha512'.freeze
}

Instance Method Summary collapse

Instance Method Details

#detect_digest_class(bytes) ⇒ Object

Internal: Detect digest class hash algorithm for digest bytes.

While not elegant, all the supported digests have a unique bytesize.

Returns Digest::Base or nil.



33
34
35
# File 'lib/sprockets/digest_utils.rb', line 33

def detect_digest_class(bytes)
  DIGEST_SIZES[bytes.bytesize]
end

#digest(obj) ⇒ Object

Internal: Generate a hexdigest for a nested JSON serializable object.

This is used for generating cache keys, so its pretty important its wicked fast. Microbenchmarks away!

obj - A JSON serializable object.

Returns a String digest of the object.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/sprockets/digest_utils.rb', line 45

def digest(obj)
  digest = digest_class.new
  queue  = [obj]

  while queue.length > 0
    obj = queue.shift
    klass = obj.class

    if klass == String
      digest << obj
    elsif klass == Symbol
      digest << 'Symbol'
      digest << obj.to_s
    elsif klass == Fixnum
      digest << 'Fixnum'
      digest << obj.to_s
    elsif klass == Bignum
      digest << 'Bignum'
      digest << obj.to_s
    elsif klass == TrueClass
      digest << 'TrueClass'
    elsif klass == FalseClass
      digest << 'FalseClass'
    elsif klass == NilClass
      digest << 'NilClass'.freeze
    elsif klass == Array
      digest << 'Array'
      queue.concat(obj)
    elsif klass == Hash
      digest << 'Hash'
      queue.concat(obj.sort)
    elsif klass == Set
      digest << 'Set'
      queue.concat(obj.to_a)
    elsif klass == Encoding
      digest << 'Encoding'
      digest << obj.name
    else
      raise TypeError, "couldn't digest #{klass}"
    end
  end

  digest.digest
end

#digest_classObject

Internal: Default digest class.

Returns a Digest::Base subclass.



15
16
17
# File 'lib/sprockets/digest_utils.rb', line 15

def digest_class
  Digest::SHA256
end

#hexdigest_integrity_uri(hexdigest) ⇒ Object

Public: Generate hash for use in the ‘integrity` attribute of an asset tag as per the subresource integrity specification.

digest - The String hexbyte digest of the asset content.

Returns a String or nil if hash algorithm is incompatible.



164
165
166
# File 'lib/sprockets/digest_utils.rb', line 164

def hexdigest_integrity_uri(hexdigest)
  integrity_uri(unpack_hexdigest(hexdigest))
end

#integrity_uri(digest) ⇒ Object

Public: Generate hash for use in the ‘integrity` attribute of an asset tag as per the subresource integrity specification.

digest - The String byte digest of the asset content.

Returns a String or nil if hash algorithm is incompatible.



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/sprockets/digest_utils.rb', line 142

def integrity_uri(digest)
  case digest
  when Digest::Base
    digest_class = digest.class
    digest = digest.digest
  when String
    digest_class = DIGEST_SIZES[digest.bytesize]
  else
    raise TypeError, "unknown digest: #{digest.inspect}"
  end

  if hash_name = HASH_ALGORITHMS[digest_class]
    "#{hash_name}-#{pack_base64digest(digest)}"
  end
end

#pack_base64digest(bin) ⇒ Object

Internal: Pack a binary digest to a base64 encoded string.

bin - String bytes

Returns base64 String.



113
114
115
# File 'lib/sprockets/digest_utils.rb', line 113

def pack_base64digest(bin)
  [bin].pack('m0')
end

#pack_hexdigest(bin) ⇒ Object

Internal: Pack a binary digest to a hex encoded string.

bin - String bytes

Returns hex String.



95
96
97
# File 'lib/sprockets/digest_utils.rb', line 95

def pack_hexdigest(bin)
  bin.unpack('H*').first
end

#pack_urlsafe_base64digest(bin) ⇒ Object

Internal: Pack a binary digest to a urlsafe base64 encoded string.

bin - String bytes

Returns urlsafe base64 String.



122
123
124
125
126
127
# File 'lib/sprockets/digest_utils.rb', line 122

def pack_urlsafe_base64digest(bin)
  str = pack_base64digest(bin)
  str.tr!('+/'.freeze, '-_'.freeze)
  str.tr!('='.freeze, ''.freeze)
  str
end

#unpack_hexdigest(hex) ⇒ Object

Internal: Unpack a hex encoded digest string into binary bytes.

hex - String hex

Returns binary String.



104
105
106
# File 'lib/sprockets/digest_utils.rb', line 104

def unpack_hexdigest(hex)
  [hex].pack('H*')
end