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
}
NI_HASH_ALGORITHMS =

Internal: Maps digest class to the named information hash algorithm name.

www.iana.org/assignments/named-information/named-information.xhtml

{
  Digest::SHA256 => 'sha-256'.freeze,
  Digest::SHA384 => 'sha-384'.freeze,
  Digest::SHA512 => 'sha-512'.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'
    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

#integrity_uri(digest, content_type = nil) ⇒ Object

Internal: Generate a “named information” URI 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. content_type - The content-type the asset will be served with. This must

be accurate if provided. Otherwise, subresource integrity
will block the loading of the asset.

Returns a String or nil if hash algorithm is incompatible.



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

def integrity_uri(digest, content_type = nil)
  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 = NI_HASH_ALGORITHMS[digest_class]
    uri = "ni:///#{hash_name};#{pack_urlsafe_base64digest(digest)}"
    uri << "?ct=#{content_type}" if content_type
    uri
  end
end

#pack_base64digest(bin) ⇒ Object

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

bin - String bytes

Returns base64 String.



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

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.



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

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