Class: Clickwrap::DocumentVersionsController

Inherits:
ApplicationController show all
Defined in:
app/controllers/clickwrap/document_versions_controller.rb

Overview

The exact rendered bytes of one published document version.

This is where every document link in every presentation points, and where an auditor reading a three-year-old receipt ends up. Both get the same response from the same row, verified against the digest that was recorded when it was published — DocumentVersion#content_bytes refuses to hand back bytes that no longer match, because silently serving edited content would turn this action into a way to launder a changed document into an old agreement.

Retired versions stay reachable on purpose. A version stops being presentable when it is retired; it never stops being the thing somebody agreed to.

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Clickwrap::ApplicationController

Instance Method Details

#showObject



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'app/controllers/clickwrap/document_versions_controller.rb', line 24

def show
  version = DocumentVersion.find_by(id: params[:id])
  return head :not_found if version.nil? || !version.published?

  # The linked representation is the exact rendered snapshot bound into the
  # presentation, not mutable source and never raw unsanitized HTML.
  response.headers["X-Content-Type-Options"] = "nosniff"
  response.headers["Content-Security-Policy"] =
    "default-src 'none'; img-src data:; style-src 'unsafe-inline'; " \
    "base-uri 'none'; form-action 'none'; frame-ancestors 'self'; sandbox"
  response.headers["Referrer-Policy"] = "no-referrer"
  response.headers["Cache-Control"] = "public, max-age=31536000, immutable"

  # A published representation is derived from a specific source artifact.
  # Refuse to serve either half of a version whose other half has stopped
  # matching its publication digest; otherwise a corrupt source row could
  # remain publicly vouched for merely because the rendered snapshot was
  # untouched.
  version.content_bytes
  send_data version.rendered_bytes,
            type: version.rendered_media_type.presence || version.media_type,
            filename: download_filename(version, version.rendered_media_type.presence || version.media_type),
            disposition: "inline"
rescue DocumentDigestMismatchError
  # The stored bytes no longer match their recorded digest. Serving them
  # anyway would be the one thing this action must never do.
  head :unprocessable_entity
end