From 997e6cd8fcc6378ed6b69ec7d7220f5a2cb66f88 Mon Sep 17 00:00:00 2001 From: Mircea Gavriliu Date: Thu, 27 Jun 2024 13:59:31 +0300 Subject: [PATCH 1/2] feat: add bearer token authorization --- .env.example | 3 ++- src/controller/eligibility.rs | 41 ++++++++++++++++++++++++++--------- src/data_objects/response.rs | 5 +++++ 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/.env.example b/.env.example index fd61fda..8612fc2 100644 --- a/.env.example +++ b/.env.example @@ -2,4 +2,5 @@ export PINATA_ACCESS_TOKEN= export PINATA_API_KEY= export PINATA_API_SERVER= export PINATA_SECRET_API_KEY= -export IPFS_GATEWAY= \ No newline at end of file +export IPFS_GATEWAY= +export MERKLE_API_BEARER_TOKEN= \ No newline at end of file diff --git a/src/controller/eligibility.rs b/src/controller/eligibility.rs index a5ac3d2..0966f2f 100644 --- a/src/controller/eligibility.rs +++ b/src/controller/eligibility.rs @@ -16,6 +16,20 @@ use url::Url; use vercel_runtime as Vercel; use warp::Filter; +/// Bearer token guard +fn is_authorized(req: &Vercel::Request) -> bool { + let headers = req.headers(); + let expected_token = std::env::var("MERKLE_API_BEARER_TOKEN").expect("MERKLE_API_BEARER_TOKEN must be set"); + + if let Some(auth_header) = headers.get("Authorization") { + if let Ok(auth_str) = auth_header.to_str() { + return auth_str == format!("Bearer {}", expected_token); + } + } + + false +} + /// Eligibility request common handler. It downloads data from IPFS and determines if an address is eligible for an /// airstream campaign. pub async fn handler(eligibility: Eligibility) -> response::R { @@ -71,19 +85,26 @@ pub async fn handler_to_vercel(req: Vercel::Request) -> Result = url.query_pairs().into_owned().collect(); - // ------------------------------------------------------------ - //Format arguments for the generic handler - // ------------------------------------------------------------ + if is_authorized(&req) { + // ------------------------------------------------------------ + //Format arguments for the generic handler + // ------------------------------------------------------------ + + let fallback = String::from(""); + let params = Eligibility { + address: query.get("address").unwrap_or(&fallback).clone(), + cid: query.get("cid").unwrap_or(&fallback).clone(), + }; - let fallback = String::from(""); - let params = Eligibility { - address: query.get("address").unwrap_or(&fallback).clone(), - cid: query.get("cid").unwrap_or(&fallback).clone(), - }; + let result = handler(params).await; - let result = handler(params).await; + response::to_vercel(result) + } else { + let response_json = + json!(GeneralErrorResponse { message: String::from("Bad authentication process provided.") }); - response::to_vercel(result) + response::to_vercel(response::unauthorized(response_json)) + } } /// Bind the route with the handler for the Warp handler. diff --git a/src/data_objects/response.rs b/src/data_objects/response.rs index 134fc8a..27c4807 100644 --- a/src/data_objects/response.rs +++ b/src/data_objects/response.rs @@ -57,6 +57,11 @@ pub fn bad_request(json_response: Json) -> R { R { status: warp::http::StatusCode::BAD_REQUEST.as_u16(), message: json_response } } +/// Create a UNAUTHORIZED type of response +pub fn unauthorized(json_response: Json) -> R { + R { status: warp::http::StatusCode::UNAUTHORIZED.as_u16(), message: json_response } +} + /// Create an Ok type of response pub fn ok(json_response: Json) -> R { R { status: warp::http::StatusCode::OK.as_u16(), message: json_response } From 64125badb135ac9e95d0b665d42f5e4bb3f0723f Mon Sep 17 00:00:00 2001 From: Mircea Gavriliu Date: Thu, 27 Jun 2024 17:14:04 +0300 Subject: [PATCH 2/2] chore: remove unused fields in pinata --- src/services/ipfs.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/services/ipfs.rs b/src/services/ipfs.rs index 1356063..1aaeb44 100644 --- a/src/services/ipfs.rs +++ b/src/services/ipfs.rs @@ -11,10 +11,6 @@ use serde::{de::DeserializeOwned, Deserialize}; pub struct PinataSuccess { #[serde(rename = "IpfsHash")] pub ipfs_hash: String, - #[serde(rename = "PinSize")] - pub pin_size: usize, - #[serde(rename = "Timestamp")] - pub timestamp: String, } /// Deserialize the text response returned by Pinata API into PinataSuccess