Class: Mpp::Challenge

Inherits:
Data
  • Object
show all
Defined in:
lib/mpp/challenge.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id:, method:, intent:, request:, realm: "", request_b64: "", digest: nil, expires: nil, description: nil, opaque: nil) ⇒ Challenge

Returns a new instance of Challenge.



21
22
23
24
# File 'lib/mpp/challenge.rb', line 21

def initialize(id:, method:, intent:, request:, realm: "", request_b64: "", digest: nil, expires: nil,
  description: nil, opaque: nil)
  super
end

Instance Attribute Details

#descriptionObject (readonly)

Returns the value of attribute description

Returns:

  • (Object)

    the current value of description



9
10
11
# File 'lib/mpp/challenge.rb', line 9

def description
  @description
end

#digestObject (readonly)

Returns the value of attribute digest

Returns:

  • (Object)

    the current value of digest



9
10
11
# File 'lib/mpp/challenge.rb', line 9

def digest
  @digest
end

#expiresObject (readonly)

Returns the value of attribute expires

Returns:

  • (Object)

    the current value of expires



9
10
11
# File 'lib/mpp/challenge.rb', line 9

def expires
  @expires
end

#idObject (readonly)

Returns the value of attribute id

Returns:

  • (Object)

    the current value of id



9
10
11
# File 'lib/mpp/challenge.rb', line 9

def id
  @id
end

#intentObject (readonly)

Returns the value of attribute intent

Returns:

  • (Object)

    the current value of intent



9
10
11
# File 'lib/mpp/challenge.rb', line 9

def intent
  @intent
end

#methodObject (readonly)

Returns the value of attribute method

Returns:

  • (Object)

    the current value of method



9
10
11
# File 'lib/mpp/challenge.rb', line 9

def method
  @method
end

#opaqueObject (readonly)

Returns the value of attribute opaque

Returns:

  • (Object)

    the current value of opaque



9
10
11
# File 'lib/mpp/challenge.rb', line 9

def opaque
  @opaque
end

#realmObject (readonly)

Returns the value of attribute realm

Returns:

  • (Object)

    the current value of realm



9
10
11
# File 'lib/mpp/challenge.rb', line 9

def realm
  @realm
end

#requestObject (readonly)

Returns the value of attribute request

Returns:

  • (Object)

    the current value of request



9
10
11
# File 'lib/mpp/challenge.rb', line 9

def request
  @request
end

#request_b64Object (readonly)

Returns the value of attribute request_b64

Returns:

  • (Object)

    the current value of request_b64



9
10
11
# File 'lib/mpp/challenge.rb', line 9

def request_b64
  @request_b64
end

Class Method Details

.create(secret_key:, realm:, method:, intent:, request:, expires: nil, digest: nil, description: nil, meta: nil) ⇒ Object

Create a Challenge with an HMAC-bound ID.



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
52
53
54
# File 'lib/mpp/challenge.rb', line 27

def self.create(secret_key:, realm:, method:, intent:, request:, expires: nil, digest: nil, description: nil,
  meta: nil)
  challenge_id = Mpp.generate_challenge_id(
    secret_key: secret_key,
    realm: realm,
    method: method,
    intent: intent,
    request: request,
    expires: expires,
    digest: digest,
    opaque: meta
  )
  request_json = Mpp::Json.compact_encode(request)
  request_b64 = Mpp.b64url_encode(request_json)

  new(
    id: challenge_id,
    method: method,
    intent: intent,
    request: request,
    realm: realm,
    request_b64: request_b64,
    digest: digest,
    expires: expires,
    description: description,
    opaque: meta
  )
end

.from_www_authenticate(header) ⇒ Object

Parse a Challenge from a WWW-Authenticate header value.



57
58
59
# File 'lib/mpp/challenge.rb', line 57

def self.from_www_authenticate(header)
  Mpp::Parsing.parse_www_authenticate(header)
end

.from_www_authenticate_list(header) ⇒ Object

Parse multiple Payment challenges from a merged WWW-Authenticate header. Handles RFC 9110 ยง11.6.1 comma-separated authentication schemes.



63
64
65
66
67
68
69
70
71
72
73
# File 'lib/mpp/challenge.rb', line 63

def self.from_www_authenticate_list(header)
  indices = []
  header.scan(/Payment\s+/i) { indices << T.must(Regexp.last_match).begin(0) }
  return [] if indices.empty?

  indices.each_with_index.map do |start_idx, i|
    end_idx = (i + 1 < indices.length) ? indices[i + 1] : header.length
    chunk = T.must(header[start_idx...end_idx]).sub(/,\s*$/, "")
    from_www_authenticate(chunk)
  end
end

Instance Method Details

#to_echoObject

Create a ChallengeEcho for use in credentials.



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/mpp/challenge.rb', line 96

def to_echo
  opaque_b64 = nil
  if opaque
    opaque_json = Mpp::Json.compact_encode(opaque)
    opaque_b64 = Mpp.b64url_encode(opaque_json)
  end

  ChallengeEcho.new(
    id: id,
    realm: realm,
    method: method,
    intent: intent,
    request: request_b64,
    expires: expires,
    digest: digest,
    opaque: opaque_b64
  )
end

#to_www_authenticate(realm) ⇒ Object

Serialize to a WWW-Authenticate header value.



76
77
78
# File 'lib/mpp/challenge.rb', line 76

def to_www_authenticate(realm)
  Mpp::Parsing.format_www_authenticate(self, realm)
end

#verify(secret_key, realm) ⇒ Object

Verify the challenge ID matches the expected HMAC.



81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/mpp/challenge.rb', line 81

def verify(secret_key, realm)
  expected_id = Mpp.generate_challenge_id(
    secret_key: secret_key,
    realm: realm,
    method: method,
    intent: intent,
    request: request,
    expires: expires,
    digest: digest,
    opaque: opaque
  )
  Mpp.secure_compare(id, expected_id)
end