Skip to content

Commit

Permalink
fix: handle subscription check after special signers (#425)
Browse files Browse the repository at this point in the history
Query keys from special signers were unintentionally blocked because the
subgraph subscription check happened unnecessarily early.
  • Loading branch information
Theodus authored Nov 21, 2023
1 parent 59ab760 commit 4dbace7
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 26 deletions.
46 changes: 21 additions & 25 deletions graph-gateway/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub enum AuthToken {
/// API key from the Subgraph Studio Database.
ApiKey(Arc<APIKey>),
/// Ticket associated with a subscription.
Ticket(TicketPayload, Subscription),
Ticket(TicketPayload),
}

impl AuthHandler {
Expand Down Expand Up @@ -90,25 +90,7 @@ impl AuthHandler {
}

let (payload, _) = TicketPayload::from_ticket_base64(input)?;

let user: Address = payload.user().0.into();
let subscription = self
.subscriptions
.value_immediate()
.unwrap_or_default()
.get(&user)
.cloned()
.ok_or_else(|| anyhow!("Subscription not found for user {}", user))?;

let signer: Address = payload.signer.0.into();
ensure!(
(signer == user) || subscription.signers.contains(&signer),
"Signer {} not authorized for user {}",
signer,
user,
);

Ok(AuthToken::Ticket(payload, subscription))
Ok(AuthToken::Ticket(payload))
}

pub async fn check_token(
Expand All @@ -134,7 +116,7 @@ impl AuthHandler {
// Check deployment allowlist
let allowed_deployments: Vec<DeploymentId> = match token {
AuthToken::ApiKey(api_key) => api_key.deployments.clone(),
AuthToken::Ticket(payload, _) => payload
AuthToken::Ticket(payload) => payload
.allowed_deployments
.iter()
.flat_map(|s| s.split(','))
Expand All @@ -151,7 +133,7 @@ impl AuthHandler {
// Check subgraph allowlist
let allowed_subgraphs: Vec<SubgraphId> = match token {
AuthToken::ApiKey(api_key) => api_key.subgraphs.clone(),
AuthToken::Ticket(payload, _) => payload
AuthToken::Ticket(payload) => payload
.allowed_subgraphs
.iter()
.flat_map(|s| s.split(','))
Expand All @@ -171,7 +153,7 @@ impl AuthHandler {
// Check domain allowlist
let allowed_domains: Vec<&str> = match token {
AuthToken::ApiKey(api_key) => api_key.domains.iter().map(|s| s.as_str()).collect(),
AuthToken::Ticket(payload, _) => payload
AuthToken::Ticket(payload) => payload
.allowed_domains
.iter()
.flat_map(|s| s.split(','))
Expand All @@ -184,9 +166,9 @@ impl AuthHandler {

// Check rate limit for subscriptions. This step should be last to avoid invalid queries
// taking up the rate limit.
let (ticket_payload, subscription) = match token {
let ticket_payload = match token {
AuthToken::ApiKey(_) => return Ok(()),
AuthToken::Ticket(payload, subscription) => (payload, subscription),
AuthToken::Ticket(payload) => payload,
};

// This is safe, since we have already verified the signature and the claimed signer match.
Expand All @@ -199,6 +181,20 @@ impl AuthHandler {
return Ok(());
}

let user: Address = ticket_payload.user().0.into();
let subscription = self
.subscriptions
.value_immediate()
.unwrap_or_default()
.get(&user)
.cloned()
.ok_or_else(|| anyhow!("Subscription not found for user {}", user))?;
let signer: Address = ticket_payload.signer.0.into();
ensure!(
(signer == user) || subscription.signers.contains(&signer),
"Signer {signer} not authorized for user {user}",
);

let matches_subscriptions_domain = self
.subscription_domains
.get(&ticket_payload.chain_id)
Expand Down
2 changes: 1 addition & 1 deletion graph-gateway/src/client_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ async fn handle_client_query_inner(
user_address = ?api_key.user_address,
api_key = %api_key.key,
),
AuthToken::Ticket(payload, _) => tracing::info!(
AuthToken::Ticket(payload) => tracing::info!(
target: reports::CLIENT_QUERY_TARGET,
user_address = ?payload.user(),
ticket_payload = serde_json::to_string(payload).unwrap(),
Expand Down

0 comments on commit 4dbace7

Please sign in to comment.