From 2d26785477a5dffa959bc0f382b792ea67334944 Mon Sep 17 00:00:00 2001 From: ryoNAKAYA Date: Fri, 20 Jun 2025 19:29:19 +0900 Subject: [PATCH 1/2] refactor: rename struct from UnCheckedCSRFToken to RawCSRFToken In Rust, the term `unchecked` often indicates unsafe code. However, in this case, the struct's `unchecked` means "not yet verified." Renamed the struct to `RawCSRFToken` to avoid confusion. BREAKING CHANGE: The struct name has been changed. Related to ISSUE #21 --- src/code.rs | 6 +++--- src/csrf_token.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/code.rs b/src/code.rs index c1ab7a6..2e93df5 100644 --- a/src/code.rs +++ b/src/code.rs @@ -59,7 +59,7 @@ use url::Url; use crate::{ config::{AuthEndPoint, ClientID, Config, RedirectURI}, - csrf_token::{CSRFToken, UnCheckedCSRFToken}, + csrf_token::{CSRFToken, RawCSRFToken}, error::Error, nonce::Nonce, }; @@ -215,7 +215,7 @@ impl<'a> CodeRequest<'a> { /// ``` #[derive(Debug, Clone)] pub struct UnCheckedCodeResponse { - state: UnCheckedCSRFToken, + state: RawCSRFToken, code: Code, } @@ -227,7 +227,7 @@ impl UnCheckedCodeResponse { let query_str = query_src.extract_query().ok_or(Error::ParamsNotFound)?; let params: HashMap<_, _> = url::form_urlencoded::parse(query_str.as_bytes()).collect(); Ok(Self { - state: UnCheckedCSRFToken( + state: RawCSRFToken( params .get("state") .ok_or(Error::ParamsNotFound)? diff --git a/src/csrf_token.rs b/src/csrf_token.rs index ab008f7..3ee0a6e 100644 --- a/src/csrf_token.rs +++ b/src/csrf_token.rs @@ -45,7 +45,7 @@ impl CSRFToken { /// /// This token **has not been verified yet** and should be checked against the stored `CSRFToken` before proceeding. #[derive(Debug, Clone)] -pub struct UnCheckedCSRFToken(pub(crate) String); +pub struct RawCSRFToken(pub(crate) String); #[cfg(test)] mod tests { From d0b46bab9bf6ecccc2a3dbb4016094f6b2ed38f1 Mon Sep 17 00:00:00 2001 From: ryoNAKAYA Date: Fri, 20 Jun 2025 19:52:45 +0900 Subject: [PATCH 2/2] refactor: rename struct from `UnCheckCodeResponse` to `RawCodeResponse` and constructor method from `from_url` to `new` In Rust, the term `unchecked` often indicates unsafe code. However, in this context, 'unchecked' means "not yet verified," not "unsafe." Renamed the struct to `RawCodeResponse` to avoid confusion. BREAKING CHANGE: The struct name has changed from `UnCheckCodeResponse` to `RawCodeResponse`. Related to ISSUE #21 --- examples/axum_server.rs | 4 +-- examples/hyper/login_service.rs | 4 +-- src/code.rs | 45 +++++++++++++++------------------ 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/examples/axum_server.rs b/examples/axum_server.rs index f8f8b5c..7672a37 100644 --- a/examples/axum_server.rs +++ b/examples/axum_server.rs @@ -28,7 +28,7 @@ use axum_extra::extract::{CookieJar, cookie::Cookie}; use http::StatusCode; use serde::Deserialize; use tiny_google_oidc::{ - code::{AccessType, AdditionalScope, CodeRequest, UnCheckedCodeResponse}, + code::{AccessType, AdditionalScope, CodeRequest, RawCodeResponse}, config::{Config, ConfigBuilder}, csrf_token::CSRFToken, id_token::{IDToken, IDTokenRequest, send_id_token_req}, @@ -127,7 +127,7 @@ async fn call_back( req: Request, ) -> Result { // Construct UnCheckedCodeResponse - let code_res = UnCheckedCodeResponse::from_url(req).map_err(|e| { + let code_res = RawCodeResponse::new(req).map_err(|e| { error!("Failed to parse url: {}", e); StatusCode::INTERNAL_SERVER_ERROR })?; diff --git a/examples/hyper/login_service.rs b/examples/hyper/login_service.rs index 258b26d..28c408c 100644 --- a/examples/hyper/login_service.rs +++ b/examples/hyper/login_service.rs @@ -10,7 +10,7 @@ use http_body_util::{BodyExt, Empty, combinators::BoxBody}; use hyper::body::Incoming; use redis::{aio::ConnectionManager, cmd}; use tiny_google_oidc::{ - code::{AccessType, AdditionalScope, CodeRequest, UnCheckedCodeResponse}, + code::{AccessType, AdditionalScope, CodeRequest, RawCodeResponse}, config::Config, csrf_token::CSRFToken, id_token::{IDToken, IDTokenRequest, send_id_token_req}, @@ -98,7 +98,7 @@ impl LoginService { .await?; // Create UncheckedCodeResponse from url - let code_res = UnCheckedCodeResponse::from_url(&req)?; + let code_res = RawCodeResponse::new(&req)?; // Consume the response and get the code // Verify that the CSRFToken matches (Error if they do not match) let code = code_res.exchange_with_code(&csrf_token)?; diff --git a/src/code.rs b/src/code.rs index 2e93df5..8642200 100644 --- a/src/code.rs +++ b/src/code.rs @@ -3,7 +3,7 @@ //! //! It provides the following key functionalities: //! - Generating an authorization request URL (`CodeRequest`). -//! - Parsing and verifying the authorization code received from Google's callback (`UnCheckedCodeResponse`). +//! - Parsing and verifying the authorization code received from Google's callback (`RawCodeResponse`). //! //! # Key Structures and Features //! @@ -11,13 +11,13 @@ //! A structure used to generate the authorization request URL. //! - Includes parameters like CSRF token, scope, redirect URI, and nonce. //! -//! ## `UnCheckedCodeResponse` +//! ## `RawCodeResponse` //! Represents the authorization code response received from Google. //! - This response must be validated using a CSRF token before it can be used. //! //! ## `Code` //! Represents a verified authorization code that can be exchanged for tokens. -//! - This is obtained after validating the `UnCheckedCodeResponse` with a CSRF token. +//! - This is obtained after validating the `RawCodeResponse` with a CSRF token. //! //! # Examples //! ## Generating an Authorization Request URL @@ -38,7 +38,7 @@ //! //! ## Handling the Callback and Verifying the Authorization Code //! ```rust,no_run -//! let response = UnCheckedCodeResponse::from_url(req).unwrap(); +//! let response = RawCodeResponse::new(req).unwrap(); //! // get stored CSRF token From DB(Redis, in memory ...) //! let csrf_token = store.get("csrf_token_key")?; //! @@ -48,13 +48,13 @@ //! # Flow //! 1. Generate a CSRF token (`CSRFToken`) and include it in the authorization request. //! 2. Redirect the user to Google's authentication page. -//! 3. After authentication, Google redirects back with an authorization code (`UnCheckedCodeResponse`). -//! 4. Validate the CSRF token in the `UnCheckedCodeResponse` using `Code::new_with_verify_csrf()` or `UnCheckedCodeResponse::exchange_with_code()`. +//! 3. After authentication, Google redirects back with an authorization code (`RawCodeResponse`). +//! 4. Validate the CSRF token in the `RawCodeResponse` using `Code::new_with_verify_csrf()` or `RawCodeResponse::exchange_with_code()`. //! 5. If validation succeeds, a `Code` is obtained, which can be exchanged for tokens. //! //! # Notes //! - Always validate the CSRF token to ensure the integrity of the authentication flow. -//! - Do not use `UnCheckedCodeResponse` directly without verification. +//! - Do not use `RawCodeResponse` directly without verification. use url::Url; use crate::{ @@ -77,11 +77,11 @@ use std::{collections::HashMap, iter::Iterator}; /// /// # How to Create /// A `Code` can only be created after validating the `CSRFToken`. -/// Use either `Code::new_with_verify_csrf` or `UnCheckedCodeResponse::exchange_with_code` to validate and create a `Code`. +/// Use either `Code::new_with_verify_csrf` or `RawCodeResponse::exchange_with_code` to validate and create a `Code`. /// /// # Example /// ```rust,no_run -/// let response = UnCheckedCodeResponse::from_url("https://example.com/callback?...").unwrap(); +/// let response = RawCodeResponse::new(req).unwrap(); /// let csrf_token = store.get("csrf_token_key")?; /// /// let code = response.exchange_with_code(csrf_token).expect("CSRF token mismatch!"); @@ -96,10 +96,7 @@ pub struct Code(pub(crate) String); impl Code { /// Checks if `res.state` (CSRF token from Google) matches `csrf_token` (generated by user). /// If valid, returns a `Code`; otherwise, returns `Error::CSRFNotMatch`. - pub fn new_with_verify_csrf( - res: UnCheckedCodeResponse, - csrf_token_val: &str, - ) -> Result { + pub fn new_with_verify_csrf(res: RawCodeResponse, csrf_token_val: &str) -> Result { if res.state.0 == csrf_token_val { Ok(res.code) } else { @@ -208,19 +205,19 @@ impl<'a> CodeRequest<'a> { /// Must be validated using a CSRF token before use. /// # Example /// ```rust,no_run -/// let response = UnCheckedCodeResponse::from_url(req).unwrap(); +/// let response = RawCodeResponse::new(req).unwrap(); /// let csrf_token = store.get("csrf_token_key")?; /// /// let code = response.exchange_with_code(csrf_token).expect("CSRF token mismatch!"); /// ``` #[derive(Debug, Clone)] -pub struct UnCheckedCodeResponse { +pub struct RawCodeResponse { state: RawCSRFToken, code: Code, } -impl UnCheckedCodeResponse { - pub fn from_url(query_src: Q) -> Result +impl RawCodeResponse { + pub fn new(query_src: Q) -> Result where Q: QueryExtractor, { @@ -338,7 +335,7 @@ mod tests { use crate::{code::AccessType, config::ConfigBuilder, csrf_token::CSRFToken, nonce::Nonce}; - use super::{AdditionalScope, CodeRequest, UnCheckedCodeResponse}; + use super::{AdditionalScope, CodeRequest, RawCodeResponse}; #[test] fn test_code_req_offline() { @@ -559,12 +556,12 @@ mod tests { let uri = format!("https://www.example.com/autu?code={}&state={}", code, state); let http_req = http::Request::builder().uri(uri).body(()).unwrap(); - let uncheck_code_res = UnCheckedCodeResponse::from_url(http_req); + let raw_code_res = RawCodeResponse::new(http_req); - assert!(uncheck_code_res.is_ok()); + assert!(raw_code_res.is_ok()); - assert_eq!(uncheck_code_res.clone().unwrap().state.0, "mystate"); - assert_eq!(uncheck_code_res.unwrap().code.0, "mycode"); + assert_eq!(raw_code_res.clone().unwrap().state.0, "mystate"); + assert_eq!(raw_code_res.unwrap().code.0, "mycode"); } #[test] @@ -572,8 +569,8 @@ mod tests { let uri = format!("https://www.example.com/"); let http_req = http::Request::builder().uri(uri).body(()).unwrap(); - let uncheck_code_res = UnCheckedCodeResponse::from_url(http_req); + let raw_code_res = RawCodeResponse::new(http_req); - assert!(uncheck_code_res.is_err()); + assert!(raw_code_res.is_err()); } }