Skip to content

Commit d5337c7

Browse files
committed
update for latest security-focused changes to async-session
1 parent 387ef45 commit d5337c7

File tree

2 files changed

+62
-26
lines changed

2 files changed

+62
-26
lines changed

Cargo.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@ edition = "2018"
77
[dependencies]
88
redis = { version = "0.16.0", features = ["aio"] }
99
async-session = "1.0.2"
10-
serde = "1.0.114"
11-
serde_json = "1.0.56"
12-
async-trait = "0.1.36"
13-
http-types = "2.2.1"
1410

1511
[patch.crates-io]
1612
async-session = { git = "https://github.com/jbr/async-session", branch = "tide" }

src/lib.rs

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,103 @@
1-
use async_session::{uuid::Uuid, Session, SessionStore};
2-
use http_types::cookies::Cookie;
3-
use redis::AsyncCommands;
4-
use redis::{Client, RedisError};
1+
use async_session::{async_trait, base64, serde_json, utils, Session, SessionStore};
2+
use redis::{AsyncCommands, Client, RedisError};
53
use std::time::Duration;
64

7-
#[derive(Clone)]
5+
#[derive(Clone, Debug)]
86
pub struct RedisSessionStore {
97
client: Client,
108
ttl: Duration,
9+
prefix: Option<String>,
1110
}
1211

1312
impl RedisSessionStore {
1413
pub fn from_client(client: Client) -> Self {
1514
Self {
1615
client,
1716
ttl: Duration::from_secs(86400),
17+
prefix: None,
1818
}
1919
}
2020

2121
pub fn new(connection_info: impl redis::IntoConnectionInfo) -> Result<Self, RedisError> {
2222
Ok(Self::from_client(Client::open(connection_info)?))
2323
}
24+
25+
pub fn with_prefix(mut self, prefix: String) -> Self {
26+
self.prefix = Some(prefix);
27+
self
28+
}
29+
30+
pub fn with_ttl(mut self, ttl: Duration) -> Self {
31+
self.ttl = ttl;
32+
self
33+
}
34+
35+
fn prefix_key(&self, key: impl AsRef<str>) -> String {
36+
if let Some(ref prefix) = self.prefix {
37+
format!("{}{}", prefix, key.as_ref())
38+
} else {
39+
key.as_ref().into()
40+
}
41+
}
42+
43+
async fn connection(&self) -> redis::RedisResult<redis::aio::Connection> {
44+
self.client.get_async_std_connection().await
45+
}
2446
}
2547

26-
#[async_trait::async_trait]
48+
#[async_trait]
2749
impl SessionStore for RedisSessionStore {
2850
type Error = Error;
2951

30-
async fn load_session(&self, cookie: Cookie<'_>) -> Result<Option<Session>, Self::Error> {
31-
let mut connection = self.client.get_async_std_connection().await?;
32-
let value: String = connection.get(cookie.value()).await?;
33-
let session: Session = serde_json::from_str(&value)?;
34-
Ok(Some(session))
52+
async fn load_session(&self, cookie_value: String) -> Option<Session> {
53+
let id = utils::id_from_string(&cookie_value).ok()?;
54+
let mut connection = self.connection().await.ok()?;
55+
match connection.get::<_, Option<String>>(id).await.ok()? {
56+
Some(value) => serde_json::from_str(&value).ok()?,
57+
None => None,
58+
}
3559
}
3660

37-
async fn store_session(&self, session: Session) -> Result<String, Self::Error> {
61+
async fn store_session(&self, mut session: Session) -> Option<String> {
3862
let id = session.id();
39-
let mut connection = self.client.get_async_std_connection().await?;
40-
let string = serde_json::to_string(&session)?;
63+
let string = serde_json::to_string(&session).ok()?;
4164

42-
let _: () = connection
43-
.set_ex(&id, string, self.ttl.as_secs() as usize)
44-
.await?;
65+
let mut connection = self.connection().await.ok()?;
66+
connection
67+
.set_ex::<_, _, ()>(id, string, self.ttl.as_secs() as usize)
68+
.await
69+
.ok()?;
70+
71+
session.take_cookie_value()
72+
}
4573

46-
Ok(id)
74+
async fn destroy_session(&self, session: Session) -> Result<(), Self::Error> {
75+
self.connection()
76+
.await?
77+
.del::<_, ()>(self.prefix_key(session.id().to_string()))
78+
.await?;
79+
Ok(())
4780
}
4881

49-
async fn create_session(&self) -> Result<Session, Self::Error> {
50-
let sess = Session::new();
51-
sess.insert("id".to_string(), Uuid::new_v4().to_string());
52-
Ok(sess)
82+
async fn clear_store(&self) -> Result<(), Self::Error> {
83+
self.connection().await?.del(self.prefix_key("*")).await?;
84+
Ok(())
5385
}
5486
}
5587

5688
#[derive(Debug)]
5789
pub enum Error {
5890
RedisError(RedisError),
5991
SerdeError(serde_json::Error),
92+
Base64Error(base64::DecodeError),
6093
}
6194

6295
impl std::fmt::Display for Error {
6396
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6497
match self {
6598
Error::RedisError(e) => e.fmt(f),
6699
Error::SerdeError(e) => e.fmt(f),
100+
Error::Base64Error(e) => e.fmt(f),
67101
}
68102
}
69103
}
@@ -74,6 +108,12 @@ impl From<serde_json::Error> for Error {
74108
}
75109
}
76110

111+
impl From<base64::DecodeError> for Error {
112+
fn from(e: base64::DecodeError) -> Self {
113+
Self::Base64Error(e)
114+
}
115+
}
116+
77117
impl From<RedisError> for Error {
78118
fn from(e: RedisError) -> Self {
79119
Self::RedisError(e)

0 commit comments

Comments
 (0)