mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-13 13:22:57 +00:00
use JwtSigner for session cookie
This commit is contained in:
1 parent
fdd60b436a
commit
c3e5b42bf3
13 files changed
+54
-29
No files matched your search
Generated
+1
@@ -6837,6 +6837,7 @@ dependencies = [
|
||||
"bcrypt",
|
||||
"chrono",
|
||||
"container_common",
|
||||
"cookies",
|
||||
"dotenv",
|
||||
"enums",
|
||||
"errors",
|
||||
|
||||
@@ -16,6 +16,7 @@ path = "src/lib.rs"
|
||||
|
||||
# Internal
|
||||
container_common = { path = "../../../lib/deprecated/container_common" }
|
||||
cookies = { path = "../../../lib/cookies" }
|
||||
enums = { path = "../../../_types/enums" }
|
||||
errors = { path = "../../../lib/errors" }
|
||||
http_server_common = { path = "../../../lib/deprecated/http_server_common" }
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod session_cookie_manager;
|
||||
pub mod session_cookie_payload;
|
||||
+34
-22
@@ -8,15 +8,13 @@ use std::collections::BTreeMap;
|
||||
use actix_web::cookie::Cookie;
|
||||
use actix_web::HttpRequest;
|
||||
use anyhow::anyhow;
|
||||
use hmac::Hmac;
|
||||
use hmac::NewMac;
|
||||
use jwt::SignWithKey;
|
||||
use jwt::VerifyWithKey;
|
||||
use log::warn;
|
||||
use sha2::Sha256;
|
||||
|
||||
use cookies::jwt_signer::JwtSigner;
|
||||
use errors::AnyhowResult;
|
||||
|
||||
use crate::cookies::session_cookie_payload::SessionCookiePayload;
|
||||
|
||||
/**
|
||||
* Cookie version history
|
||||
*
|
||||
@@ -34,15 +32,7 @@ const SESSION_COOKIE_NAME : &str = "session";
|
||||
pub struct SessionCookieManager {
|
||||
cookie_domain: String,
|
||||
hmac_secret: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SessionCookiePayload {
|
||||
/// The database primary key for the session instance.
|
||||
pub session_token: String,
|
||||
/// The primary key identifier of the user.
|
||||
/// Version 1 cookies do not have a user token, hence it is optional.
|
||||
pub maybe_user_token: Option<String>,
|
||||
jwt_signer: JwtSigner,
|
||||
}
|
||||
|
||||
impl SessionCookieManager {
|
||||
@@ -50,13 +40,11 @@ impl SessionCookieManager {
|
||||
Self {
|
||||
cookie_domain: cookie_domain.to_string(),
|
||||
hmac_secret: hmac_secret.to_string(),
|
||||
jwt_signer: JwtSigner::new(hmac_secret).unwrap(),//TODO FIXME
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_cookie(&self, session_token: &str, user_token: &str) -> AnyhowResult<Cookie> {
|
||||
let key: Hmac<Sha256> = Hmac::new_varkey(self.hmac_secret.as_bytes())
|
||||
.map_err(|e| anyhow!("invalid hmac: {:?}", e))?;
|
||||
|
||||
let cookie_version = COOKIE_VERSION.to_string();
|
||||
|
||||
let mut claims = BTreeMap::new();
|
||||
@@ -64,7 +52,7 @@ impl SessionCookieManager {
|
||||
claims.insert("user_token", user_token);
|
||||
claims.insert("cookie_version", &cookie_version);
|
||||
|
||||
let jwt_string = claims.sign_with_key(&key)?;
|
||||
let jwt_string = self.jwt_signer.claims_to_jwt(&claims)?;
|
||||
|
||||
let make_secure = !self.cookie_domain.to_lowercase().contains("jungle.horse")
|
||||
&& !self.cookie_domain.to_lowercase().contains("localhost");
|
||||
@@ -91,12 +79,9 @@ impl SessionCookieManager {
|
||||
pub fn decode_session_cookie_payload(&self, session_cookie: &Cookie)
|
||||
-> AnyhowResult<SessionCookiePayload>
|
||||
{
|
||||
let key: Hmac<Sha256> = Hmac::new_varkey(self.hmac_secret.as_bytes())
|
||||
.map_err(|e| anyhow!("invalid hmac: {:?}", e))?;
|
||||
|
||||
let cookie_contents = session_cookie.value().to_string();
|
||||
|
||||
let claims: BTreeMap<String, String> = cookie_contents.verify_with_key(&key)?;
|
||||
let claims = self.jwt_signer.jwt_to_claims(&cookie_contents)?;
|
||||
|
||||
let session_token = claims["session_token"].clone();
|
||||
let maybe_user_token = claims.get("user_token")
|
||||
@@ -149,3 +134,30 @@ impl SessionCookieManager {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::cookies::session_cookie_manager::SessionCookieManager;
|
||||
|
||||
#[test]
|
||||
fn test_cookie_payload() {
|
||||
// NB: Let's make extra sure this always works when migrating cookies, else we'll accidentally log out logged-in users.
|
||||
// (These are version 2 cookies.)
|
||||
let manager = SessionCookieManager::new("fakeyou.com", "secret");
|
||||
let cookie = manager.create_cookie("ex_session_token", "ex_user_token").unwrap();
|
||||
|
||||
assert_eq!(cookie.value(), "eyJhbGciOiJIUzI1NiJ9.eyJjb29raWVfdmVyc2lvbiI6IjIiLCJzZXNzaW9uX3Rva2VuIjoiZXhfc2Vzc2lvbl90b2tlbiIsInVzZXJfdG9rZW4iOiJleF91c2VyX3Rva2VuIn0.94ly2gHhlPVtnANsNy6cJozFVmId4imwW5v-mei7jD8");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cookie_round_trip() {
|
||||
// NB: Let's make extra sure this always works when migrating cookies, else we'll accidentally log out logged-in users.
|
||||
// (These are version 2 cookies.)
|
||||
let manager = SessionCookieManager::new("fakeyou.com", "secret");
|
||||
let cookie = manager.create_cookie("ex_session_token", "ex_user_token").unwrap();
|
||||
|
||||
let decoded = manager.decode_session_cookie_payload(&cookie).unwrap();
|
||||
|
||||
assert_eq!(decoded.session_token, "ex_session_token".to_string());
|
||||
assert_eq!(decoded.maybe_user_token, Some("ex_user_token".to_string()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SessionCookiePayload {
|
||||
/// The database primary key for the session instance.
|
||||
pub session_token: String,
|
||||
/// The primary key identifier of the user.
|
||||
/// Version 1 cookies do not have a user token, hence it is optional.
|
||||
pub maybe_user_token: Option<String>,
|
||||
}
|
||||
@@ -21,8 +21,8 @@ use mysql_queries::queries::users::user_sessions::create_user_session::create_us
|
||||
use mysql_queries::tokens::Tokens;
|
||||
use user_input_common::check_for_slurs::contains_slurs;
|
||||
|
||||
use crate::cookies::session_cookie_manager::SessionCookieManager;
|
||||
use crate::utils::email_to_gravatar::email_to_gravatar;
|
||||
use crate::utils::session_cookie_manager::SessionCookieManager;
|
||||
use crate::validations::is_reserved_username::is_reserved_username;
|
||||
use crate::validations::validate_passwords::validate_passwords;
|
||||
use crate::validations::validate_username::validate_username;
|
||||
|
||||
@@ -19,7 +19,7 @@ use mysql_queries::queries::users::user::lookup_user_for_login_by_email::lookup_
|
||||
use mysql_queries::queries::users::user::lookup_user_for_login_by_username::lookup_user_for_login_by_username;
|
||||
use mysql_queries::queries::users::user_sessions::create_user_session::create_user_session;
|
||||
|
||||
use crate::utils::session_cookie_manager::SessionCookieManager;
|
||||
use crate::cookies::session_cookie_manager::SessionCookieManager;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct LoginRequest {
|
||||
|
||||
@@ -14,7 +14,7 @@ use sqlx::MySqlPool;
|
||||
use http_server_common::response::response_error_helpers::to_simple_json_error;
|
||||
use mysql_queries::queries::users::user_sessions::delete_user_session::delete_user_session;
|
||||
|
||||
use crate::utils::session_cookie_manager::SessionCookieManager;
|
||||
use crate::cookies::session_cookie_manager::SessionCookieManager;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct LogoutSuccessResponse {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
pub const RESERVED_USERNAMES : &str = include_str!("../../../../../includes/binary_includes/reserved_usernames.txt");
|
||||
pub const RESERVED_SUBSTRINGS : &str = include_str!("../../../../../includes/binary_includes/reserved_usernames_including.txt");
|
||||
|
||||
pub mod cookies;
|
||||
pub mod default_routes;
|
||||
pub mod endpoints;
|
||||
pub mod utils;
|
||||
|
||||
@@ -2,5 +2,4 @@ pub mod default_avatar_color_from_username;
|
||||
pub mod default_avatar_from_username;
|
||||
pub mod email_to_gravatar;
|
||||
pub mod session_checker;
|
||||
pub mod session_cookie_manager;
|
||||
pub mod user_session_extended;
|
||||
@@ -15,7 +15,7 @@ use mysql_queries::queries::users::user_subscriptions::list_active_user_subscrip
|
||||
use redis_caching::redis_ttl_cache::{RedisTtlCache, RedisTtlCacheConnection};
|
||||
use redis_common::redis_cache_keys::RedisCacheKeys;
|
||||
|
||||
use crate::utils::session_cookie_manager::SessionCookieManager;
|
||||
use crate::cookies::session_cookie_manager::SessionCookieManager;
|
||||
use crate::utils::user_session_extended::{UserSessionExtended, UserSessionPreferences, UserSessionPremiumPlanInfo, UserSessionRoleAndPermissions, UserSessionSubscriptionPlan, UserSessionUserDetails};
|
||||
|
||||
#[derive(Clone)]
|
||||
|
||||
@@ -64,8 +64,8 @@ use redis_caching::redis_ttl_cache::RedisTtlCache;
|
||||
use reusable_types::server_environment::ServerEnvironment;
|
||||
use twitch_common::twitch_secrets::TwitchSecrets;
|
||||
use url_config::third_party_url_redirector::ThirdPartyUrlRedirector;
|
||||
use users_component::cookies::session_cookie_manager::SessionCookieManager;
|
||||
use users_component::utils::session_checker::SessionChecker;
|
||||
use users_component::utils::session_cookie_manager::SessionCookieManager;
|
||||
|
||||
use crate::billing::internal_product_to_stripe_lookup_impl::InternalProductToStripeLookupImpl;
|
||||
use crate::billing::internal_session_cache_purge_impl::InternalSessionCachePurgeImpl;
|
||||
|
||||
@@ -15,8 +15,8 @@ use mysql_queries::queries::w2l::w2l_templates::list_w2l_templates::W2lTemplateR
|
||||
use redis_caching::redis_ttl_cache::RedisTtlCache;
|
||||
use reusable_types::server_environment::ServerEnvironment;
|
||||
use url_config::third_party_url_redirector::ThirdPartyUrlRedirector;
|
||||
use users_component::cookies::session_cookie_manager::SessionCookieManager;
|
||||
use users_component::utils::session_checker::SessionChecker;
|
||||
use users_component::utils::session_cookie_manager::SessionCookieManager;
|
||||
|
||||
use crate::http_server::endpoints::categories::tts::list_fully_computed_assigned_tts_categories::list_fully_computed_assigned_tts_categories::ModelTokensByCategoryToken;
|
||||
use crate::http_server::endpoints::leaderboard::get_leaderboard::LeaderboardInfo;
|
||||
|
||||
Reference in new issue
Block a user