1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use crate::{
types::{AsHeaderName, AsHeaderValue, Headers},
wit,
};
use super::Error;
/// Error identifier to allow re-using the same error for multiple elements. In the gateway
/// response, the error will be repeated if necessary during serialization.
#[derive(Clone, Copy)]
pub struct ErrorId(u32);
/// Output type for the [authorize_query()](crate::AuthorizationExtension::authorize_query())
/// method.
pub struct AuthorizeQueryOutput {
/// Authorization decisions for each query element to be applied by the GraphQL engine.
pub(crate) decisions: AuthorizationDecisions,
/// Authorization context if any.
pub(crate) context: Vec<u8>,
/// Authorization state if any.
pub(crate) state: Vec<u8>,
/// Additional headers to add to the subgraph headers if any.
pub(crate) additional_headers: Option<Headers>,
}
impl AuthorizeQueryOutput {
/// Create a new `AuthorizeQueryOutput` with the given decisions.
pub fn new(decisions: AuthorizationDecisions) -> Self {
Self {
decisions,
context: Vec::new(),
state: Vec::new(),
additional_headers: None,
}
}
/// Set the authorization context for the request and extension.
/// Accessible by other extensions.
pub fn context(mut self, context: impl Into<Vec<u8>>) -> Self {
self.context = context.into();
self
}
/// Set the authorization state for the request.
/// Only accessible by [authorize_response()](crate::AuthorizationExtension::authorize_response())
/// of the same extensions.
pub fn state(mut self, state: impl Into<Vec<u8>>) -> Self {
self.state = state.into();
self
}
/// Add a single additional header to the subgraph headers.
pub fn header(mut self, name: impl AsHeaderName, value: impl AsHeaderValue) -> Self {
let headers = self.additional_headers.get_or_insert_default();
headers.append(name, value);
self
}
/// Set additional headers to be added to the subgraph headers.
pub fn headers(mut self, headers: Headers) -> Self {
self.additional_headers = Some(headers);
self
}
}
/// Authorization decisions for each query elements to be applied by the GraphQL engine.
pub struct AuthorizationDecisions(wit::AuthorizationDecisions);
impl From<AuthorizationDecisions> for wit::AuthorizationDecisions {
fn from(value: AuthorizationDecisions) -> Self {
value.0
}
}
impl AuthorizationDecisions {
/// Grant access all elements in the query.
pub fn grant_all() -> Self {
Self(wit::AuthorizationDecisions::GrantAll)
}
/// Deny access to all elements in the query with the specified error
pub fn deny_all(error: impl Into<Error>) -> Self {
Self(wit::AuthorizationDecisions::DenyAll(Into::<Error>::into(error).into()))
}
/// Create a `DenySomeBuilder` best suited to deny some elements. By
/// default, all elements are granted access.
pub fn deny_some_builder() -> DenySomeBuilder {
DenySomeBuilder(wit::AuthorizationDecisionsDenySome {
element_to_error: Vec::new(),
errors: Vec::new(),
})
}
}
/// To be used when denying some of the elements. By default everything is granted.
pub struct DenySomeBuilder(wit::AuthorizationDecisionsDenySome);
impl DenySomeBuilder {
/// Deny access to the specified element in the query with the specified error.
pub fn deny(&mut self, x: impl private::QueryElementOrResponseItem, error: impl Into<Error>) {
let error_id = self.push_error(error);
self.deny_with_error_id(x, error_id)
}
/// Deny access to the specified element in the query, re-using an existing error.
pub fn deny_with_error_id(&mut self, x: impl private::QueryElementOrResponseItem, error_id: ErrorId) {
self.0.element_to_error.push((x.ix(), error_id.0));
}
/// Returns an ErrorId that can be used to reference this error later in `deny_with_error_id`.
pub fn push_error(&mut self, error: impl Into<Error>) -> ErrorId {
let error_ix = self.0.errors.len() as u32;
self.0.errors.push(Into::<Error>::into(error).into());
ErrorId(error_ix)
}
/// Build the final AuthorizationDecisions
pub fn build(self) -> AuthorizationDecisions {
AuthorizationDecisions(wit::AuthorizationDecisions::DenySome(self.0))
}
}
pub(super) mod private {
/// Either a `QueryElement` or a `ResponseItem`.
pub trait QueryElementOrResponseItem: crate::sealed::Sealed {
#[doc(hidden)]
fn ix(&self) -> u32;
}
}