mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-23 01:59:31 -04:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ada546e427 | ||
|
|
4fc2f9ad3b |
@@ -1,3 +1,6 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::sessions::user_sessions::http_user_session_payload_error::HttpUserSessionPayloadError;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct HttpUserSessionPayload {
|
||||
@@ -8,3 +11,64 @@ pub struct HttpUserSessionPayload {
|
||||
/// Version 1 cookies do not have a user token, hence it is optional.
|
||||
pub maybe_user_token: Option<String>,
|
||||
}
|
||||
|
||||
impl HttpUserSessionPayload {
|
||||
pub fn from_map(
|
||||
map: BTreeMap<String, String>,
|
||||
) -> Result<Self, HttpUserSessionPayloadError> {
|
||||
let session_token = map
|
||||
.get("session_token")
|
||||
.ok_or(HttpUserSessionPayloadError::MissingField("session_token"))?
|
||||
.clone();
|
||||
|
||||
let maybe_user_token = map.get("user_token").map(|t| t.to_string());
|
||||
|
||||
Ok(Self {
|
||||
session_token,
|
||||
maybe_user_token,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn map_of(pairs: &[(&str, &str)]) -> BTreeMap<String, String> {
|
||||
pairs.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_map_with_session_and_user_tokens() {
|
||||
let payload = HttpUserSessionPayload::from_map(map_of(&[
|
||||
("session_token", "ex_session_token"),
|
||||
("user_token", "ex_user_token"),
|
||||
("version", "3"),
|
||||
])).unwrap();
|
||||
|
||||
assert_eq!(payload.session_token, "ex_session_token");
|
||||
assert_eq!(payload.maybe_user_token.as_deref(), Some("ex_user_token"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_map_without_user_token_is_ok() {
|
||||
let payload = HttpUserSessionPayload::from_map(map_of(&[
|
||||
("session_token", "ex_session_token"),
|
||||
])).unwrap();
|
||||
|
||||
assert_eq!(payload.session_token, "ex_session_token");
|
||||
assert!(payload.maybe_user_token.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_map_missing_session_token_errors() {
|
||||
let result = HttpUserSessionPayload::from_map(map_of(&[
|
||||
("user_token", "ex_user_token"),
|
||||
]));
|
||||
|
||||
match result.err().expect("expected error") {
|
||||
HttpUserSessionPayloadError::MissingField("session_token") => {}
|
||||
other => panic!("expected MissingField(session_token), got {:?}", other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -8,6 +8,9 @@ pub enum HttpUserSessionPayloadError {
|
||||
/// Error reading HTTP header
|
||||
HttpSessionHeaderError(String),
|
||||
|
||||
/// Session payload is missing a required field.
|
||||
MissingField(&'static str),
|
||||
|
||||
/// Error encoding, decoding, or constructing the JWT signer.
|
||||
JwtSigner(JwtSignerError),
|
||||
}
|
||||
@@ -29,6 +32,10 @@ impl HttpUserSessionPayloadError {
|
||||
) => {
|
||||
true
|
||||
},
|
||||
// Missing field in a verified JWT — how did this make it into the wild!? → 500
|
||||
HttpUserSessionPayloadError::MissingField(_) => {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,6 +44,7 @@ impl Display for HttpUserSessionPayloadError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::HttpSessionHeaderError(msg) => write!(f, "HTTP session header error: {}", msg),
|
||||
Self::MissingField(field) => write!(f, "HTTP session payload missing field: {}", field),
|
||||
Self::JwtSigner(e) => write!(f, "JWT signer error: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
+1
-9
@@ -48,15 +48,7 @@ impl HttpUserSessionPayloadSigner {
|
||||
session_payload_contents: &str,
|
||||
) -> Result<HttpUserSessionPayload, HttpUserSessionPayloadError> {
|
||||
let claims = self.jwt_signer.jwt_to_claims(session_payload_contents)?;
|
||||
|
||||
let session_token = claims["session_token"].clone();
|
||||
let maybe_user_token = claims.get("user_token")
|
||||
.map(|t| t.to_string());
|
||||
|
||||
Ok(HttpUserSessionPayload {
|
||||
session_token,
|
||||
maybe_user_token,
|
||||
})
|
||||
HttpUserSessionPayload::from_map(claims)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ pub mod billing;
|
||||
pub mod configs;
|
||||
pub mod docs;
|
||||
pub mod email;
|
||||
pub mod error;
|
||||
pub mod http_server;
|
||||
pub mod startup;
|
||||
pub mod state;
|
||||
|
||||
@@ -32,7 +32,6 @@ pub mod billing;
|
||||
pub mod configs;
|
||||
pub mod docs;
|
||||
pub mod email;
|
||||
pub mod error;
|
||||
pub mod http_server;
|
||||
pub mod startup;
|
||||
pub mod state;
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
use std::error::Error;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
|
||||
/// Any generic errors arising internally.
|
||||
/// An error class that we do not expose via the API.
|
||||
/// This should be massaged before we send it to the user.
|
||||
#[derive(Debug)]
|
||||
pub enum InternalError {
|
||||
/// Issue with HMAC decoding
|
||||
/// This is typically when using development cookies against production,
|
||||
/// or vice versa.
|
||||
VisitorCookieError(String),
|
||||
|
||||
/// Decode error with AVT cookie missing a required field.
|
||||
VisitorCookieMissingField(&'static str),
|
||||
|
||||
/// Catch instances of anyhow::Error.
|
||||
AnyhowError(anyhow::Error),
|
||||
}
|
||||
|
||||
impl Error for InternalError {}
|
||||
|
||||
impl Display for InternalError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
InternalError::VisitorCookieError(reason) => write!(f, "Visitor cookie error: {:?}", reason),
|
||||
InternalError::VisitorCookieMissingField(field) => write!(f, "Visitor cookie missing field: {}", field),
|
||||
InternalError::AnyhowError(err) => write!(f, "Anyhow error: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<anyhow::Error> for InternalError {
|
||||
fn from(err: anyhow::Error) -> Self {
|
||||
InternalError::AnyhowError(err)
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod internal_error;
|
||||
@@ -93,7 +93,6 @@ use crate::util::troll_user_bans::troll_user_ban_list::TrollUserBanList;
|
||||
pub mod billing;
|
||||
pub mod configs;
|
||||
pub mod email;
|
||||
pub mod error;
|
||||
pub mod http_server;
|
||||
pub mod startup;
|
||||
pub mod state;
|
||||
|
||||
Reference in New Issue
Block a user