Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libs/blockscout-auth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ edition = "2021"

[dependencies]
cookie = { version = "0.18", features = [ "percent-encode" ] }
reqwest = "0.12"
reqwest = { version = "0.13", features = ["json"]}
serde = { version = "1.0", features = [ "derive" ] }
serde_json = "1"
thiserror = "2"
Expand Down
27 changes: 16 additions & 11 deletions libs/blockscout-auth/src/auth.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::jwt_headers::{build_http_headers, extract_csrf_token, extract_jwt};
use crate::{
consts,
jwt_headers::{build_http_headers, extract_csrf_token, extract_jwt},
};
use reqwest::{Client, StatusCode};
use serde::Deserialize;
use thiserror::Error;
use tonic::metadata::MetadataMap;
use url::Url;

const API_KEY_NAME: &str = "api_key";

#[derive(Debug, Clone, Deserialize)]
pub struct AuthSuccess {
pub avatar: Option<String>,
Expand Down Expand Up @@ -77,14 +78,14 @@ pub async fn auth_from_tokens(
.expect("invalid base url");
url.set_query(
blockscout_api_key
.map(|api_key| format!("{API_KEY_NAME}={api_key}"))
.map(|api_key| format!("{}={api_key}", consts::API_KEY_NAME))
.as_deref(),
);

let headers = build_http_headers(jwt, csrf_token)?;
let headers = build_http_headers(jwt, csrf_token, blockscout_api_key)?;
let client = Client::new();
let response = if csrf_token.is_some() {
client.post(url)
let body = build_request_body(blockscout_api_key);
client.post(url).json(&body)
} else {
client.get(url)
}
Expand Down Expand Up @@ -130,14 +131,18 @@ pub async fn auth_from_tokens(
}
}

pub fn build_request_body(blockscout_api_key: Option<&str>) -> serde_json::Value {
serde_json::json!({
consts::API_KEY_NAME: blockscout_api_key,
})
}

#[cfg(test)]
mod tests {
use std::str::FromStr;

use super::*;
use crate::{
init_mocked_blockscout_auth_service, jwt_headers::HEADER_JWT_TOKEN_NAME, MockUser,
};
use crate::{consts, init_mocked_blockscout_auth_service, MockUser};
use reqwest::header::{HeaderMap, HeaderName};
use serde::Serialize;
use tonic::{codegen::http::header::CONTENT_TYPE, Extensions, Request};
Expand All @@ -155,7 +160,7 @@ mod tests {
);
headers.insert(COOKIE, cookies.parse().unwrap());
} else {
headers.insert(HEADER_JWT_TOKEN_NAME, jwt.parse().unwrap());
headers.insert(consts::HEADER_JWT_TOKEN_NAME, jwt.parse().unwrap());
};
headers.insert(CONTENT_TYPE, "application/json".parse().unwrap());
if let Some(csrf_token) = csrf_token {
Expand Down
5 changes: 5 additions & 0 deletions libs/blockscout-auth/src/consts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub const API_KEY_NAME: &str = "api_key";
pub const HEADER_JWT_TOKEN_NAME: &str = "authorization";
pub const COOKIE_JWT_TOKEN_NAME: &str = "_explorer_key";
pub const CSRF_TOKEN_NAME: &str = "x-csrf-token";
pub const HEADER_COOKIE_NAME: &str = "cookie";
31 changes: 18 additions & 13 deletions libs/blockscout-auth/src/jwt_headers.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
use crate::auth::Error;
use crate::{auth::Error, consts};
use cookie::Cookie;
use reqwest::header::{HeaderMap, HeaderValue};
use tonic::metadata::MetadataMap;

pub const HEADER_JWT_TOKEN_NAME: &str = "authorization";
pub const COOKIE_JWT_TOKEN_NAME: &str = "_explorer_key";
pub const CSRF_TOKEN_NAME: &str = "x-csrf-token";
pub const HEADER_COOKIE_NAME: &str = "cookie";

pub fn extract_jwt(metadata: &MetadataMap) -> Result<String, Error> {
let cookies = get_cookies(metadata)?;
let cookie_jwt = cookies
.get(COOKIE_JWT_TOKEN_NAME)
.get(consts::COOKIE_JWT_TOKEN_NAME)
.map(|c| c.value().to_string());
let header_jwt = metadata
.get(HEADER_JWT_TOKEN_NAME)
.get(consts::HEADER_JWT_TOKEN_NAME)
.and_then(|v| v.to_str().ok())
.map(|s| s.to_string());
cookie_jwt
Expand All @@ -24,7 +19,7 @@ pub fn extract_jwt(metadata: &MetadataMap) -> Result<String, Error> {

pub fn extract_csrf_token(metadata: &MetadataMap) -> Result<String, Error> {
metadata
.get(CSRF_TOKEN_NAME)
.get(consts::CSRF_TOKEN_NAME)
.and_then(|v| v.to_str().ok())
.map(|s| s.to_string())
.ok_or_else(|| Error::InvalidCsrfToken("csrf not found".into()))
Expand All @@ -34,7 +29,7 @@ fn get_cookies(
metadata: &MetadataMap,
) -> Result<std::collections::HashMap<String, Cookie<'_>>, Error> {
let raw = metadata
.get(HEADER_COOKIE_NAME)
.get(consts::HEADER_COOKIE_NAME)
.and_then(|v| v.to_str().ok())
.unwrap_or("");
Cookie::split_parse_encoded(raw.to_string())
Expand All @@ -43,18 +38,28 @@ fn get_cookies(
.map_err(|e| Error::InvalidJwt(format!("cannot parse cookie: {e}")))
}

pub fn build_http_headers(jwt: &str, csrf_token: Option<&str>) -> Result<HeaderMap, Error> {
pub fn build_http_headers(
jwt: &str,
csrf_token: Option<&str>,
api_key: Option<&str>,
) -> Result<HeaderMap, Error> {
let mut headers = HeaderMap::new();
headers.insert(
"cookie",
HeaderValue::from_str(&format!("{COOKIE_JWT_TOKEN_NAME}={jwt}"))
HeaderValue::from_str(&format!("{}={jwt}", consts::COOKIE_JWT_TOKEN_NAME))
.map_err(|e| Error::HeaderError(e.to_string()))?,
);
if let Some(csrf) = csrf_token {
headers.insert(
CSRF_TOKEN_NAME,
consts::CSRF_TOKEN_NAME,
HeaderValue::from_str(csrf).map_err(|e| Error::HeaderError(e.to_string()))?,
);
}
if let Some(api_key) = api_key {
headers.insert(
consts::API_KEY_NAME,
HeaderValue::from_str(api_key).map_err(|e| Error::HeaderError(e.to_string()))?,
);
}
Ok(headers)
}
1 change: 1 addition & 0 deletions libs/blockscout-auth/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ pub use auth::{auth_from_metadata, auth_from_tokens, AuthSuccess, Error};
// pub use jwt_headers::{build_http_headers, extract_csrf_token, extract_jwt};
pub use mock::{init_mocked_blockscout_auth_service, MockUser};
pub use user::{get_user_info_from_metadata, UserInfo};
pub mod consts;
2 changes: 1 addition & 1 deletion libs/blockscout-auth/src/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub async fn get_user_info_from_metadata(
blockscout_api_key: Option<&str>,
) -> Result<UserInfo, Error> {
let jwt = extract_jwt(metadata)?;
let headers = build_http_headers(&jwt, None)?;
let headers = build_http_headers(&jwt, None, blockscout_api_key)?;

let mut url = blockscout_host
.join("/api/account/v2/user/info")
Expand Down
Loading