Module: AlFolioDistill

Defined in:
lib/al_folio_distill.rb,
lib/al_folio_distill/version.rb

Defined Under Namespace

Classes: AssetsGenerator, PluginStaticFile, RenderTag, RuntimeScriptsTag

Constant Summary collapse

PLUGIN_ROOT =
File.expand_path("..", __dir__)
TEMPLATES_ROOT =
File.join(PLUGIN_ROOT, "templates")
ASSETS_ROOT =
File.join(PLUGIN_ROOT, "assets")
RUNTIME_ROOT =
File.join(ASSETS_ROOT, "js", "distillpub")
RUNTIME_URL_PREFIX =
"/assets/js/distillpub"
PROVENANCE_PATH =
File.join(RUNTIME_ROOT, "provenance.json")
DISTILL_REMOTE_LOADER_PATTERN =
%r{https://distill\.pub/template\.v2\.js}
DEFAULT_REMOTE_LOADER_URL =
"https://distill.pub/template.v2.js"
RUNTIME_SCRIPTS =
["template.v2.js", "transforms.v2.js"].freeze
SHA256_HEX_PATTERN =
/\A[0-9a-f]{64}\z/.freeze
VERSION =
"1.0.3"

Class Method Summary collapse

Class Method Details

.enabled?(site) ⇒ Boolean

Returns:

  • (Boolean)


24
25
26
# File 'lib/al_folio_distill.rb', line 24

def enabled?(site)
  site.config.dig("al_folio", "features", "distill", "enabled") != false
end

.integrity_for(asset) ⇒ Object

Subresource Integrity wants base64, provenance.json pins hex. Same bytes.



57
58
59
60
# File 'lib/al_folio_distill.rb', line 57

def integrity_for(asset)
  digest = pinned_digest(asset)
  digest && "sha256-#{[[digest].pack("H*")].pack("m0")}"
end

.pinned_digest(asset) ⇒ Object



51
52
53
54
# File 'lib/al_folio_distill.rb', line 51

def pinned_digest(asset)
  digest = provenance.dig("assets", asset)
  digest if digest.is_a?(String) && digest.match?(SHA256_HEX_PATTERN)
end

.provenanceObject

Committed, known-good digests for the vendored runtime. Refreshed by scripts/distill/sync_distill.sh; asserted by the runtime contract test.



44
45
46
47
48
49
# File 'lib/al_folio_distill.rb', line 44

def provenance
  @provenance ||= File.file?(PROVENANCE_PATH) ? JSON.parse(File.read(PROVENANCE_PATH)) : {}
rescue JSON::ParserError => e
  Jekyll.logger.warn("al_folio_distill:", "could not parse provenance.json (#{e.message}); runtime integrity pinning is disabled")
  @provenance = {}
end

.remote_loader_allowed?(site) ⇒ Boolean

Returns:

  • (Boolean)


28
29
30
# File 'lib/al_folio_distill.rb', line 28

def remote_loader_allowed?(site)
  site.config.dig("al_folio", "distill", "allow_remote_loader") == true
end

.remote_loader_integrity(site) ⇒ Object



37
38
39
40
# File 'lib/al_folio_distill.rb', line 37

def remote_loader_integrity(site)
  configured = site.config.dig("al_folio", "distill", "remote_loader_integrity")
  configured if configured.is_a?(String) && !configured.empty?
end

.remote_loader_url(site) ⇒ Object



32
33
34
35
# File 'lib/al_folio_distill.rb', line 32

def remote_loader_url(site)
  configured = site.config.dig("al_folio", "distill", "remote_loader_url")
  configured.is_a?(String) && !configured.empty? ? configured : DEFAULT_REMOTE_LOADER_URL
end

.runtime_url(site, asset) ⇒ Object



62
63
64
# File 'lib/al_folio_distill.rb', line 62

def runtime_url(site, asset)
  "#{site.config["baseurl"].to_s.chomp("/")}#{RUNTIME_URL_PREFIX}/#{asset}"
end

.template_loader(site) ⇒ Object

Describes where the Distill runtime may be re-injected from after the polyfill transform strips the original tag. Local + pinned unless a site explicitly opts into a remote origin.



69
70
71
72
73
74
75
# File 'lib/al_folio_distill.rb', line 69

def template_loader(site)
  if remote_loader_allowed?(site)
    { "url" => remote_loader_url(site), "integrity" => remote_loader_integrity(site), "remote" => true }.compact
  else
    { "url" => runtime_url(site, "template.v2.js"), "integrity" => integrity_for("template.v2.js"), "remote" => false }.compact
  end
end