ap2_mandate_verifier 0.1.0.pre.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "ap2_mandate_verifier/result"
4
+ require_relative "ap2_mandate_verifier/input_validator"
5
+ require_relative "ap2_mandate_verifier/root_signature"
6
+ require_relative "ap2_mandate_verifier/root_disclosures"
7
+ require_relative "ap2_mandate_verifier/purchase_binding"
8
+ require_relative "ap2_mandate_verifier/scoped_constraints"
9
+ require_relative "ap2_mandate_verifier/trust_context"
10
+ require_relative "ap2_mandate_verifier/host_binding"
11
+ require_relative "ap2_mandate_verifier/research_result"
12
+
13
+ module AP2MandateVerifier
14
+ # Accepts original JSON bytes only. Syntax validity is not AP2 validity,
15
+ # authentication, disclosure completeness, or a Host authorization decision.
16
+ def self.verify(presentation_json:)
17
+ unavailable = InputValidator.check!(presentation_json)
18
+ return Result.new(status: :unavailable, code: unavailable) if unavailable
19
+
20
+ Result.new(status: :unverified, code: :verification_not_implemented)
21
+ rescue InputValidator::Invalid => error
22
+ Result.new(status: :rejected, code: error.code)
23
+ rescue LoadError
24
+ Result.new(status: :unavailable, code: :json_dependency_unavailable)
25
+ rescue StandardError
26
+ # Unexpected implementation/dependency failure is not proof of bad input.
27
+ # Do not expose parser messages, source text, or claim values.
28
+ Result.new(status: :unavailable, code: :input_check_unavailable)
29
+ end
30
+
31
+ # One original compact Root JWS only; no SD disclosure/authority validation.
32
+ # The caller must select this PUBLIC key independently of the token. This
33
+ # API does not establish the caller's key enrollment or Issuer provenance.
34
+ def self.verify_root_signature(root_jws:, trusted_issuer_public_key_pem:)
35
+ RootSignature.check!(root_jws, trusted_issuer_public_key_pem)
36
+ Result.new(status: :unverified, code: :root_signature_verified_only)
37
+ rescue InputValidator::Unavailable, RootSignature::Unavailable => error
38
+ Result.new(status: :unavailable, code: error.code)
39
+ rescue InputValidator::Invalid, RootSignature::Rejected => error
40
+ Result.new(status: :rejected, code: error.code)
41
+ rescue LoadError
42
+ Result.new(status: :unavailable, code: :signature_dependency_unavailable)
43
+ rescue StandardError
44
+ Result.new(status: :unavailable, code: :root_signature_check_unavailable)
45
+ end
46
+
47
+ # Exact DC04 disclosure profile only. This grants no AP2/Host authority.
48
+ def self.verify_root_disclosures(presentation:, trusted_issuer_public_key_pem:)
49
+ RootDisclosures.check!(presentation, trusted_issuer_public_key_pem)
50
+ Result.new(status: :unverified, code: :root_disclosures_verified_only)
51
+ rescue InputValidator::Unavailable, RootSignature::Unavailable => error
52
+ Result.new(status: :unavailable, code: error.code)
53
+ rescue InputValidator::Invalid, RootSignature::Rejected => error
54
+ Result.new(status: :rejected, code: error.code)
55
+ rescue LoadError
56
+ Result.new(status: :unavailable, code: :disclosure_dependency_unavailable)
57
+ rescue StandardError
58
+ Result.new(status: :unavailable, code: :root_disclosure_check_unavailable)
59
+ end
60
+
61
+ def self.verify_purchase_binding(**inputs)
62
+ PurchaseBinding.check!(**inputs)
63
+ Result.new(status: :unverified, code: :purchase_binding_verified_only)
64
+ rescue InputValidator::Unavailable, RootSignature::Unavailable => error
65
+ Result.new(status: :unavailable, code: error.code)
66
+ rescue InputValidator::Invalid, RootSignature::Rejected => error
67
+ Result.new(status: :rejected, code: error.code)
68
+ rescue LoadError
69
+ Result.new(status: :unavailable, code: :purchase_dependency_unavailable)
70
+ rescue StandardError
71
+ Result.new(status: :unavailable, code: :purchase_check_unavailable)
72
+ end
73
+
74
+ def self.verify_scoped_constraints(**inputs)
75
+ ScopedConstraints.check!(**inputs)
76
+ Result.new(status: :unverified, code: :scoped_constraints_verified_only)
77
+ rescue InputValidator::Unavailable, RootSignature::Unavailable => error
78
+ Result.new(status: :unavailable, code: error.code)
79
+ rescue InputValidator::Invalid, RootSignature::Rejected => error
80
+ Result.new(status: :rejected, code: error.code)
81
+ rescue LoadError
82
+ Result.new(status: :unavailable, code: :constraint_dependency_unavailable)
83
+ rescue StandardError
84
+ Result.new(status: :unavailable, code: :constraint_check_unavailable)
85
+ end
86
+ # Both JSON inputs must come from authenticated Host state, independently of
87
+ # the presentation. Existing lower-level PEM APIs retain their old contract.
88
+ def self.verify_trusted_scoped_constraints(trust_json:, selection_json:, **inputs)
89
+ unless inputs.length == TrustContext::INPUTS.length && TrustContext::INPUTS.all? { |key| inputs.key?(key) }
90
+ return Result.new(status: :rejected, code: :invalid_trust_context)
91
+ end
92
+ # Snapshot Host context and signed wires before any trust/key processing;
93
+ # the identity comparison and downstream verifier must use identical bytes.
94
+ inputs = inputs.to_h do |key, value|
95
+ [key, %i[verified_at expected_total_minor].include?(key) ? value : InputValidator.snapshot!(value)]
96
+ end
97
+ keys = TrustContext.keys!(trust_json: trust_json, selection_json: selection_json,
98
+ verified_at: inputs[:verified_at], expected_merchant_id: inputs[:expected_merchant_id])
99
+ ScopedConstraints.check!(**inputs, **keys)
100
+ Result.new(status: :unverified, code: :scoped_constraints_verified_only)
101
+ rescue InputValidator::Unavailable, RootSignature::Unavailable => error
102
+ Result.new(status: :unavailable, code: error.code)
103
+ rescue InputValidator::Invalid, RootSignature::Rejected => error
104
+ Result.new(status: :rejected, code: error.code)
105
+ rescue LoadError
106
+ Result.new(status: :unavailable, code: :signature_dependency_unavailable)
107
+ rescue StandardError
108
+ Result.new(status: :unavailable, code: :trust_check_unavailable)
109
+ end
110
+
111
+ def self.verify_host_binding(**inputs)
112
+ HostBinding.check!(**inputs)
113
+ Result.new(status: :unverified, code: :host_binding_verified_only)
114
+ rescue InputValidator::Unavailable, RootSignature::Unavailable => error
115
+ Result.new(status: :unavailable, code: error.code)
116
+ rescue InputValidator::Invalid, RootSignature::Rejected => error
117
+ Result.new(status: :rejected, code: error.code)
118
+ rescue LoadError
119
+ Result.new(status: :unavailable, code: :signature_dependency_unavailable)
120
+ rescue StandardError
121
+ Result.new(status: :unavailable, code: :host_binding_check_unavailable)
122
+ end
123
+
124
+ # Research Evidence only; success is not Host ALLOW or a payment permission.
125
+ # All older methods continue to return non-success Result values.
126
+ def self.verify_research(**inputs) = ResearchResult.verify(**inputs)
127
+
128
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ap2_mandate_verifier
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.pre.3
5
+ platform: ruby
6
+ authors:
7
+ - AP2 Mandate Verifier contributors
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: json
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - '='
17
+ - !ruby/object:Gem::Version
18
+ version: 2.19.9
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - '='
24
+ - !ruby/object:Gem::Version
25
+ version: 2.19.9
26
+ - !ruby/object:Gem::Dependency
27
+ name: jwt
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - '='
31
+ - !ruby/object:Gem::Version
32
+ version: 3.3.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - '='
38
+ - !ruby/object:Gem::Version
39
+ version: 3.3.0
40
+ - !ruby/object:Gem::Dependency
41
+ name: base64
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '='
45
+ - !ruby/object:Gem::Version
46
+ version: 0.3.0
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - '='
52
+ - !ruby/object:Gem::Version
53
+ version: 0.3.0
54
+ - !ruby/object:Gem::Dependency
55
+ name: openssl
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '='
59
+ - !ruby/object:Gem::Version
60
+ version: 4.0.2
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - '='
66
+ - !ruby/object:Gem::Version
67
+ version: 4.0.2
68
+ - !ruby/object:Gem::Dependency
69
+ name: digest
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '='
73
+ - !ruby/object:Gem::Version
74
+ version: 3.2.1
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - '='
80
+ - !ruby/object:Gem::Version
81
+ version: 3.2.1
82
+ description: Stateless fixed-profile verification and immutable research Evidence;
83
+ not Host authorization or payment permission. Research-only prerelease candidate;
84
+ actual distribution requires separate Owner approval.
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - LICENSE
90
+ - README.md
91
+ - docs/SUPPORT_CONTRACT.md
92
+ - lib/ap2_mandate_verifier.rb
93
+ - lib/ap2_mandate_verifier/host_binding.rb
94
+ - lib/ap2_mandate_verifier/input_validator.rb
95
+ - lib/ap2_mandate_verifier/purchase_binding.rb
96
+ - lib/ap2_mandate_verifier/research_result.rb
97
+ - lib/ap2_mandate_verifier/result.rb
98
+ - lib/ap2_mandate_verifier/root_disclosures.rb
99
+ - lib/ap2_mandate_verifier/root_signature.rb
100
+ - lib/ap2_mandate_verifier/scoped_constraints.rb
101
+ - lib/ap2_mandate_verifier/trust_context.rb
102
+ homepage: https://github.com/cuichangquan/ap2-mandate-verifier
103
+ licenses:
104
+ - MIT
105
+ metadata: {}
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - '='
112
+ - !ruby/object:Gem::Version
113
+ version: 4.0.9
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubygems_version: 4.0.20
121
+ specification_version: 4
122
+ summary: Fixed-profile AP2 research prerelease candidate
123
+ test_files: []