Class: Clickwrap::Submission

Inherits:
Object
  • Object
show all
Defined in:
lib/clickwrap/submission.rb

Overview

What came back from the browser: a signed presentation token and the answers to the statements that token declared.

Nothing else. A submission cannot carry a policy key, a document version, a validity date, a retention rule, a subject, an IP address, a user-agent, or a geolocation, because every one of those is a decision the server makes and a form field is not a safe place to keep one. Unknown keys are rejected rather than ignored, so an attempt to smuggle one in fails loudly instead of silently doing nothing and looking like it worked.

Constant Summary collapse

ENVELOPE_KEY =
:clickwrap_submission
ENVELOPE_KEYS =
%w[presentation_token answers].freeze
REFUSED_KEYS =

Names a client must never be able to set. They exist as a check rather than a filter: a request containing one is a request worth failing.

%w[
  policy policy_key policy_revision revision document document_version version
  valid_from valid_until expires_at retention retain_until subject subject_id
  actor actor_id tenant ip_address remote_ip browser_user_agent user_agent
  ip_geolocation geolocation latitude longitude resolver recorded_at
  server_observed_ip_address capture_channel authentication_method
].freeze
MAX_ANSWER_LENGTH =

The longest an answer can be: generous for any declared choice name, far too short for smuggled prose or a payload.

120

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(presentation_token:, answers: {}) ⇒ Submission

Returns a new instance of Submission.



33
34
35
36
37
# File 'lib/clickwrap/submission.rb', line 33

def initialize(presentation_token:, answers: {})
  @presentation_token = presentation_token
  @answers = normalize_answers(answers)
  freeze
end

Instance Attribute Details

#answersObject (readonly)

Returns the value of attribute answers.



31
32
33
# File 'lib/clickwrap/submission.rb', line 31

def answers
  @answers
end

#presentation_tokenObject (readonly)

Returns the value of attribute presentation_token.



31
32
33
# File 'lib/clickwrap/submission.rb', line 31

def presentation_token
  @presentation_token
end

Class Method Details

.affirmative?(value) ⇒ Boolean

Returns:

  • (Boolean)


112
113
114
115
116
# File 'lib/clickwrap/submission.rb', line 112

def self.affirmative?(value)
  return false if value.nil?

  !%w[0 false off no].include?(value.to_s.downcase) && value.to_s != ""
end

.from_params(params, key: ENVELOPE_KEY) ⇒ Object

Reads the generated envelope out of controller params.

Raises:



41
42
43
44
45
46
47
48
49
50
# File 'lib/clickwrap/submission.rb', line 41

def from_params(params, key: ENVELOPE_KEY)
  envelope = extract_envelope(params, key)

  raise SubmissionInvalid, missing_envelope_message(key) if envelope.nil?

  new(
    presentation_token: envelope["presentation_token"] || envelope[:presentation_token],
    answers: envelope["answers"] || envelope[:answers] || {}
  )
end

.missing_envelope_message(key) ⇒ Object



52
53
54
55
# File 'lib/clickwrap/submission.rb', line 52

def missing_envelope_message(key)
  "The request contains no #{key} parameter. The form helper renders it; a custom form " \
    "must include the signed presentation token from Clickwrap.present."
end

Instance Method Details

#answer_for(statement_key) ⇒ Object



106
# File 'lib/clickwrap/submission.rb', line 106

def answer_for(statement_key) = answers[statement_key.to_s]

#answered?(statement_key) ⇒ Boolean

Returns:

  • (Boolean)


108
109
110
# File 'lib/clickwrap/submission.rb', line 108

def answered?(statement_key)
  self.class.affirmative?(answer_for(statement_key))
end

#manifestObject

Deliberately not memoized: a Submission is frozen the moment it is built, so an instance variable written on first use would raise. Verifying the token again costs one signature check, which is a small price for an object that cannot be tampered with after construction.



102
103
104
# File 'lib/clickwrap/submission.rb', line 102

def manifest
  PresentationManifest.from_token(presentation_token)
end

#to_hObject



118
119
120
# File 'lib/clickwrap/submission.rb', line 118

def to_h
  { "presentation_token" => presentation_token, "answers" => answers }
end