1
1
use chrono:: NaiveDateTime ;
2
2
use cookie:: { Cookie , SameSite } ;
3
3
use diesel:: prelude:: * ;
4
- use ipnetwork:: IpNetwork ;
5
- use std:: net:: IpAddr ;
6
4
use std:: num:: ParseIntError ;
7
5
use std:: str:: FromStr ;
8
6
use thiserror:: Error ;
@@ -28,106 +26,69 @@ pub struct PersistentSession {
28
26
pub hashed_token : SecureToken ,
29
27
/// Datetime the session was created.
30
28
pub created_at : NaiveDateTime ,
31
- /// Datetime the session was last used.
32
- pub last_used_at : NaiveDateTime ,
33
29
/// Whether the session is revoked.
34
30
pub revoked : bool ,
35
- /// Last IP address that used the session.
36
- pub last_ip_address : IpNetwork ,
37
- /// Last user agent that used the session.
38
- pub last_user_agent : String ,
39
- }
40
-
41
- /// Session-related errors.
42
- #[ derive( Error , Debug , PartialEq ) ]
43
- pub enum SessionError {
44
- #[ error( "token prefix doesn't match session tokens" ) ]
45
- InvalidSessionToken ,
46
- #[ error( "database manipulation error" ) ]
47
- DieselError ( #[ from] diesel:: result:: Error ) ,
48
31
}
49
32
50
33
impl PersistentSession {
51
34
/// Creates a `NewPersistentSession` that can be inserted into the database.
52
- pub fn create < ' a , ' b > (
53
- user_id : i32 ,
54
- token : & ' a SecureToken ,
55
- last_ip_address : IpAddr ,
56
- last_user_agent : & ' b str ,
57
- ) -> NewPersistentSession < ' a , ' b > {
35
+ pub fn create < ' a > ( user_id : i32 , token : & ' a SecureToken ) -> NewPersistentSession < ' a > {
58
36
NewPersistentSession {
59
37
user_id,
60
38
hashed_token : token,
61
- last_ip_address : last_ip_address. into ( ) ,
62
- last_user_agent,
63
39
}
64
40
}
65
41
66
- /// Finds an unrevoked session that matches `token` from the database and returns it .
42
+ /// Finds the session with the ID .
67
43
///
68
44
/// # Returns
69
45
///
70
- /// * `Ok(Some(...))` if a session matches the `token`.
71
- /// * `Ok(None)` if no session matches the `token`.
72
- /// * `Err(...)` for other errors such as invalid tokens or diesel errors.
73
- pub fn find_and_update (
74
- conn : & PgConnection ,
75
- session_cookie : & SessionCookie ,
76
- ip_address : IpAddr ,
77
- user_agent : & str ,
78
- ) -> Result < Option < Self > , SessionError > {
79
- let hashed_token = SecureToken :: parse ( SecureTokenKind :: Session , & session_cookie. token )
80
- . ok_or ( SessionError :: InvalidSessionToken ) ?;
81
- let sessions = persistent_sessions:: table
82
- . filter ( persistent_sessions:: id. eq ( session_cookie. id ) )
83
- . filter ( persistent_sessions:: revoked. eq ( false ) )
84
- . filter ( persistent_sessions:: hashed_token. eq ( hashed_token) ) ;
85
-
86
- conn. transaction ( || {
87
- diesel:: update ( sessions. clone ( ) )
88
- . set ( (
89
- persistent_sessions:: last_used_at. eq ( diesel:: dsl:: now) ,
90
- persistent_sessions:: last_ip_address. eq ( IpNetwork :: from ( ip_address) ) ,
91
- persistent_sessions:: last_user_agent. eq ( user_agent) ,
92
- ) )
93
- . get_result ( conn)
94
- . optional ( )
95
- } )
96
- . or_else ( |_| sessions. first ( conn) . optional ( ) )
97
- . map_err ( SessionError :: DieselError )
46
+ /// * `Ok(Some(...))` if a session matches the id.
47
+ /// * `Ok(None)` if no session matches the id.
48
+ /// * `Err(...)` for other errors..
49
+ pub fn find ( id : i64 , conn : & PgConnection ) -> Result < Option < Self > , diesel:: result:: Error > {
50
+ persistent_sessions:: table
51
+ . find ( id)
52
+ . get_result ( conn)
53
+ . optional ( )
98
54
}
99
55
100
- /// Revokes the `token` in the database.
101
- ///
102
- /// # Returns
103
- ///
104
- /// The number of sessions that were revoked or an error if the `token` isn't valid or there
105
- /// was an issue with the database connection.
106
- pub fn revoke_from_token ( conn : & PgConnection , token : & str ) -> Result < usize , SessionError > {
107
- let hashed_token = SecureToken :: parse ( SecureTokenKind :: Session , token)
108
- . ok_or ( SessionError :: InvalidSessionToken ) ?;
109
- let sessions = persistent_sessions:: table
110
- . filter ( persistent_sessions:: hashed_token. eq ( hashed_token) )
111
- . filter ( persistent_sessions:: revoked. eq ( false ) ) ;
112
-
113
- diesel:: update ( sessions)
114
- . set ( persistent_sessions:: revoked. eq ( true ) )
115
- . execute ( conn)
116
- . map_err ( SessionError :: DieselError )
56
+ /// Updates the session in the database.
57
+ pub fn update ( & self , conn : & PgConnection ) -> Result < ( ) , diesel:: result:: Error > {
58
+ diesel:: update ( persistent_sessions:: table. find ( self . id ) )
59
+ . set ( (
60
+ persistent_sessions:: user_id. eq ( & self . user_id ) ,
61
+ persistent_sessions:: hashed_token. eq ( & self . hashed_token ) ,
62
+ persistent_sessions:: revoked. eq ( & self . revoked ) ,
63
+ ) )
64
+ . get_result :: < Self > ( conn)
65
+ . map ( |_| ( ) )
66
+ }
67
+
68
+ pub fn is_authorized ( & self , token : & str ) -> bool {
69
+ if let Some ( hashed_token) = SecureToken :: parse ( SecureTokenKind :: Session , token) {
70
+ !self . revoked && self . hashed_token == hashed_token
71
+ } else {
72
+ false
73
+ }
74
+ }
75
+
76
+ /// Revokes the session (needs update).
77
+ pub fn revoke ( & mut self ) -> & mut Self {
78
+ self . revoked = true ;
79
+ self
117
80
}
118
81
}
119
82
120
83
/// A new, insertable persistent session.
121
84
#[ derive( Clone , Debug , PartialEq , Eq , Insertable ) ]
122
85
#[ table_name = "persistent_sessions" ]
123
- pub struct NewPersistentSession < ' a , ' b > {
86
+ pub struct NewPersistentSession < ' a > {
124
87
user_id : i32 ,
125
88
hashed_token : & ' a SecureToken ,
126
- last_ip_address : IpNetwork ,
127
- last_user_agent : & ' b str ,
128
89
}
129
90
130
- impl NewPersistentSession < ' _ , ' _ > {
91
+ impl NewPersistentSession < ' _ > {
131
92
/// Inserts the session into the database.
132
93
pub fn insert ( self , conn : & PgConnection ) -> Result < PersistentSession , diesel:: result:: Error > {
133
94
diesel:: insert_into ( persistent_sessions:: table)
@@ -166,6 +127,14 @@ impl SessionCookie {
166
127
. path ( "/" )
167
128
. finish ( )
168
129
}
130
+
131
+ pub fn session_id ( & self ) -> i64 {
132
+ self . id
133
+ }
134
+
135
+ pub fn token ( & self ) -> & str {
136
+ & self . token
137
+ }
169
138
}
170
139
171
140
/// Error returned when the session cookie couldn't be parsed.
0 commit comments