• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

divviup / divviup-api / 16806728643

07 Aug 2025 02:02PM UTC coverage: 55.922% (+0.03%) from 55.895%
16806728643

push

github

web-flow
Add safety comments for unwrap calls in session_store.rs (#1844)

* Add safety comments for unwrap calls in session_store.rs

Document why unwrap operations are safe in session store conversion methods:
- Session expiry timestamps are validated values from our own database.
- The JSON-dump of Session will have a "data" element when serialization succeeds.

* review comments

* avoiding rustfmt is hard, yo

0 of 2 new or added lines in 1 file covered. (0.0%)

3886 of 6949 relevant lines covered (55.92%)

60.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

48.33
/src/handler/session_store.rs
1
use crate::{entity::session, Db};
2
use async_session::{
3
    async_trait,
4
    chrono::{DateTime, Utc},
5
    Session,
6
};
7
use sea_orm::{
8
    sea_query::{any, OnConflict},
9
    ColumnTrait, EntityTrait, IntoActiveModel, QueryFilter,
10
};
11
use serde_json::json;
12
use time::OffsetDateTime;
13

14
#[derive(Debug, Clone)]
15
pub struct SessionStore {
16
    db: Db,
17
}
18

19
impl SessionStore {
20
    pub fn new(db: Db) -> Self {
274✔
21
        Self { db }
274✔
22
    }
274✔
23
}
24

25
impl TryFrom<&Session> for session::Model {
26
    type Error = serde_json::Error;
27

28
    fn try_from(session: &Session) -> Result<Self, Self::Error> {
266✔
29
        Ok(Self {
30
            id: session.id().to_string(),
266✔
31
            // unwrap safety: session object comes from the session handler, and its timestamp
32
            // we made ourselves.
33
            expiry: session
266✔
34
                .expiry()
266✔
35
                .map(|e| OffsetDateTime::from_unix_timestamp(e.timestamp()).unwrap()),
266✔
36
            // unwrap safety: if the serialization is successful, the data element
37
            // will be there.
38
            data: serde_json::from_value(
266✔
39
                serde_json::to_value(session)?.get("data").unwrap().clone(),
266✔
40
            )?,
×
41
        })
42
    }
266✔
43
}
44

45
impl TryFrom<session::Model> for Session {
46
    type Error = serde_json::Error;
47
    fn try_from(db_session: session::Model) -> Result<Session, serde_json::Error> {
×
48
        let mut session: Session = serde_json::from_value(json!({
×
49
            "id": db_session.id,
×
50
            "data": db_session.data,
×
51
        }))?;
×
52
        if let Some(x) = db_session.expiry {
×
NEW
53
            // unwrap safety: the expiry time from the database is a timestamp we made
×
NEW
54
            // ourselves.
×
55
            session.set_expiry(
×
56
                DateTime::<Utc>::from_timestamp(x.unix_timestamp(), x.nanosecond()).unwrap(),
×
57
            );
×
58
        }
×
59
        Ok(session)
×
60
    }
×
61
}
62

63
#[async_trait]
64
impl async_session::SessionStore for SessionStore {
65
    async fn load_session(&self, cookie_value: String) -> async_session::Result<Option<Session>> {
×
66
        let id = Session::id_from_cookie_value(&cookie_value)?;
×
67
        Ok(session::Entity::find_by_id(id)
×
68
            .filter(any![
×
69
                session::Column::Expiry.is_null(),
×
70
                session::Column::Expiry.gt(OffsetDateTime::now_utc())
×
71
            ])
×
72
            .one(&self.db)
×
73
            .await?
×
74
            .map(Session::try_from)
×
75
            .transpose()?)
×
76
    }
×
77

78
    async fn store_session(&self, session: Session) -> async_session::Result<Option<String>> {
532✔
79
        let session_model = session::Model::try_from(&session)?.into_active_model();
266✔
80

81
        session::Entity::insert(session_model)
266✔
82
            .on_conflict(
266✔
83
                OnConflict::column(session::Column::Id)
266✔
84
                    .update_columns([session::Column::Data, session::Column::Expiry])
266✔
85
                    .clone(),
266✔
86
            )
266✔
87
            .exec(&self.db)
266✔
88
            .await?;
266✔
89

90
        Ok(session.into_cookie_value())
266✔
91
    }
532✔
92

93
    async fn destroy_session(&self, session: Session) -> async_session::Result {
2✔
94
        session::Entity::delete_by_id(session.id())
1✔
95
            .exec(&self.db)
1✔
96
            .await?;
1✔
97
        Ok(())
1✔
98
    }
2✔
99

100
    async fn clear_store(&self) -> async_session::Result {
×
101
        session::Entity::delete_many().exec(&self.db).await?;
×
102
        Ok(())
×
103
    }
×
104
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc