1use http::HeaderMap;
4use r402_facilitator::DynFacilitator;
5use r402_protocol::error::FacilitatorError;
6use r402_protocol::payment::{
7 Base64Bytes, Extensions, PaymentRequired, PaymentRequirements, SettleResponse,
8 SettlementOverrides, VerifyResponse,
9};
10use r402_server::{
11 CancelReason, CompletedSettlement, PaymentFlowName, PaymentFlowPhases,
12 PaymentRequiredBuildContext, ResourceServer, SettlePhase, SkipHandlerDirective,
13 WirePaymentPayload, resolve_payment_flow_phases, validate_accepts_against_supported,
14};
15
16use super::fail::GateError;
17use super::gate::Gate;
18use crate::headers::PAYMENT_SIGNATURE;
19
20#[derive(Debug, Clone)]
22pub struct VerifiedPayment {
23 pub(crate) payload: WirePaymentPayload,
24 pub(crate) requirements: PaymentRequirements,
25 pub(crate) server: ResourceServer,
26 pub(crate) skip_handler: Option<SkipHandlerDirective>,
27 pub(crate) resource_url: compact_str::CompactString,
28 pub(crate) advertised: Extensions,
29}
30
31impl VerifiedPayment {
32 #[must_use]
34 pub fn cancellation_guard(&self) -> r402_server::CancellationGuard {
35 self.server
36 .cancellation_guard(self.payload.clone(), self.requirements.clone())
37 }
38
39 #[must_use]
41 pub const fn requirements(&self) -> &PaymentRequirements {
42 &self.requirements
43 }
44
45 pub(crate) async fn settle_phase(
46 &self,
47 phase: SettlePhase,
48 overrides: Option<&SettlementOverrides>,
49 ) -> Result<SettleResponse, FacilitatorError> {
50 self.server
51 .settle_payment(
52 &self.payload,
53 &self.requirements,
54 overrides,
55 phase,
56 Some(self.resource_url.as_str()),
57 Some(&self.advertised),
58 )
59 .await
60 }
61}
62
63impl Gate {
64 pub async fn build_payment_required(&mut self) -> Result<(), GateError> {
73 let facilitator = self.server.facilitator();
74 let supported = DynFacilitator::supported(facilitator.as_ref())
75 .await
76 .map_err(GateError::from_verify_facilitator)?;
77 let reqs: Vec<_> = self
78 .accepts
79 .iter()
80 .map(|pt| pt.requirements.clone())
81 .collect();
82 validate_accepts_against_supported(&self.server, &reqs, &supported)
83 .map_err(GateError::FacilitatorSupport)?;
84 let built = self
85 .server
86 .create_payment_required_response(
87 reqs,
88 PaymentRequiredBuildContext {
89 resource: self.resource.clone(),
90 error: None,
91 extensions: Extensions::new(),
92 supported,
93 payment_payload: None,
94 },
95 )
96 .await
97 .map_err(|err| GateError::PaymentRequiredBuild(err.to_string()))?;
98 self.payment_required = Some(built);
99 Ok(())
100 }
101
102 pub async fn verify_only(&self, headers: &HeaderMap) -> Result<VerifiedPayment, GateError> {
108 let header_bytes = headers
109 .get(PAYMENT_SIGNATURE)
110 .map(http::HeaderValue::as_bytes)
111 .ok_or(GateError::PaymentHeaderMissing)?;
112
113 let payload =
114 decode_payment_payload(header_bytes).ok_or(GateError::InvalidPaymentHeader)?;
115
116 let payment_required: &PaymentRequired =
117 self.payment_required.as_ref().ok_or_else(|| {
118 GateError::PaymentRequiredBuild(
119 "payment-required response has not been built".into(),
120 )
121 })?;
122 let requirements = self
123 .server
124 .find_matching_requirements(&payment_required.accepts, &payload)
125 .cloned()
126 .ok_or(GateError::NoPaymentMatching)?;
127 let outcome = self
128 .server
129 .verify_payment(&payload, &requirements, Some(&payment_required.extensions))
130 .await
131 .map_err(GateError::from_verify_facilitator)?;
132
133 if let VerifyResponse::Invalid {
134 reason, message, ..
135 } = &outcome.response
136 {
137 return Err(GateError::from_invalid_verify(
138 reason.clone(),
139 message.as_deref(),
140 ));
141 }
142
143 Ok(VerifiedPayment {
144 payload,
145 requirements,
146 server: self.server.clone(),
147 skip_handler: outcome.skip_handler,
148 resource_url: payment_required.resource.url.clone(),
149 advertised: payment_required.extensions.clone(),
150 })
151 }
152}
153
154pub(crate) fn decode_payment_payload(header_bytes: &[u8]) -> Option<WirePaymentPayload> {
155 let decoded = Base64Bytes::from(header_bytes).decode().ok()?;
156 serde_json::from_slice(decoded.as_ref()).ok()
157}
158
159pub(crate) fn payment_flow_of(
160 server: &ResourceServer,
161 requirements: &PaymentRequirements,
162) -> Result<PaymentFlowName, GateError> {
163 server
164 .get_payment_flow(requirements)
165 .map_err(|err| match err {
166 r402_server::PaymentFlowError::UnregisteredScheme { scheme, .. } => {
167 GateError::MissingScheme {
168 scheme: scheme.into(),
169 network: requirements.network.clone(),
170 }
171 }
172 other => GateError::PaymentRequiredBuild(other.to_string()),
173 })
174}
175
176pub(crate) fn cancellation_guard(
177 verified: &VerifiedPayment,
178 before_handler: Option<&CompletedSettlement>,
179) -> r402_server::CancellationGuard {
180 let guard = verified.cancellation_guard();
181 match before_handler {
182 Some(completed) => guard
183 .with_settled_phases([SettlePhase::BeforeHandler])
184 .with_before_handler(completed.clone()),
185 None => guard,
186 }
187}
188
189pub(crate) async fn settle_before_handler_if_needed(
190 verified: &VerifiedPayment,
191 flow: PaymentFlowName,
192 phases: PaymentFlowPhases,
193) -> Result<Option<CompletedSettlement>, GateError> {
194 if !phases.settle_before_handler {
195 return Ok(None);
196 }
197 let result = map_settle(
198 verified
199 .settle_phase(SettlePhase::BeforeHandler, None)
200 .await,
201 )?;
202 Ok(Some(CompletedSettlement::new(
203 SettlePhase::BeforeHandler,
204 flow,
205 result,
206 verified.requirements().clone(),
207 )))
208}
209
210pub(crate) fn map_settle(
211 result: Result<SettleResponse, FacilitatorError>,
212) -> Result<SettleResponse, GateError> {
213 let settlement = result.map_err(GateError::from_settle_facilitator)?;
214 if matches!(settlement, SettleResponse::Failure { .. }) {
215 return Err(GateError::Settlement(Box::new(settlement)));
216 }
217 Ok(settlement)
218}
219
220pub(crate) fn phases_of(
221 verified: &VerifiedPayment,
222) -> Result<(PaymentFlowName, PaymentFlowPhases), GateError> {
223 let flow = payment_flow_of(&verified.server, verified.requirements())?;
224 Ok((flow, resolve_payment_flow_phases(flow)))
225}
226
227pub(crate) const HANDLER_FAILED: &str = "handler returned error status";
229
230pub(crate) const fn handler_failed_reason() -> CancelReason {
231 CancelReason::HandlerFailed
232}