Skip to content

Commit f219a93

Browse files
committed
Improved persistent session API.
1 parent d662b27 commit f219a93

File tree

6 files changed

+40
-40
lines changed

6 files changed

+40
-40
lines changed

src/controllers/user/session.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use crate::models::persistent_session::SessionCookie;
1313
use crate::models::{NewUser, PersistentSession, User};
1414
use crate::schema::users;
1515
use crate::util::errors::ReadOnlyMode;
16-
use crate::util::token::SecureToken;
1716
use crate::Env;
1817

1918
/// Handles the `GET /api/private/session/begin` route.
@@ -104,10 +103,7 @@ pub fn authorize(req: &mut dyn RequestExt) -> EndpointResult {
104103
let user = save_user_to_database(&ghuser, token.secret(), &req.app().emails, &*req.db_conn()?)?;
105104

106105
// Setup a persistent session for the newly logged in user.
107-
let token = SecureToken::generate(crate::util::token::SecureTokenKind::Session);
108-
let session = PersistentSession::create(user.id, &token).insert(&*req.db_conn()?)?;
109-
110-
let cookie = SessionCookie::new(session.id, token.plaintext().to_string());
106+
let (_session, cookie) = PersistentSession::create(user.id).insert(&*req.db_conn()?)?;
111107

112108
// Setup persistent session cookie.
113109
let secure = req.app().config.env() == Env::Production;

src/models/persistent_session.rs

+27-15
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::str::FromStr;
66
use thiserror::Error;
77

88
use crate::schema::persistent_sessions;
9+
use crate::util::token::NewSecureToken;
910
use crate::util::token::SecureToken;
1011
use crate::util::token::SecureTokenKind;
1112

@@ -31,12 +32,10 @@ pub struct PersistentSession {
3132
}
3233

3334
impl PersistentSession {
34-
/// Creates a `NewPersistentSession` that can be inserted into the database.
35-
pub fn create<'a>(user_id: i32, token: &'a SecureToken) -> NewPersistentSession<'a> {
36-
NewPersistentSession {
37-
user_id,
38-
hashed_token: token,
39-
}
35+
/// Creates a `NewPersistentSession` for the `user_id` and the token associated with it.
36+
pub fn create<'a>(user_id: i32) -> NewPersistentSession {
37+
let token = SecureToken::generate(SecureTokenKind::Session);
38+
NewPersistentSession { user_id, token }
4039
}
4140

4241
/// Finds the session with the ID.
@@ -81,19 +80,32 @@ impl PersistentSession {
8180
}
8281

8382
/// A new, insertable persistent session.
84-
#[derive(Clone, Debug, PartialEq, Eq, Insertable)]
85-
#[table_name = "persistent_sessions"]
86-
pub struct NewPersistentSession<'a> {
83+
pub struct NewPersistentSession {
8784
user_id: i32,
88-
hashed_token: &'a SecureToken,
85+
token: NewSecureToken,
8986
}
9087

91-
impl NewPersistentSession<'_> {
88+
impl NewPersistentSession {
9289
/// Inserts the session into the database.
93-
pub fn insert(self, conn: &PgConnection) -> Result<PersistentSession, diesel::result::Error> {
94-
diesel::insert_into(persistent_sessions::table)
95-
.values(self)
96-
.get_result(conn)
90+
///
91+
/// # Returns
92+
///
93+
/// The
94+
pub fn insert(
95+
self,
96+
conn: &PgConnection,
97+
) -> Result<(PersistentSession, SessionCookie), diesel::result::Error> {
98+
let session: PersistentSession = diesel::insert_into(persistent_sessions::table)
99+
.values((
100+
persistent_sessions::user_id.eq(&self.user_id),
101+
persistent_sessions::hashed_token.eq(&*self.token),
102+
))
103+
.get_result(conn)?;
104+
let id = session.id;
105+
Ok((
106+
session,
107+
SessionCookie::new(id, self.token.plaintext().to_string()),
108+
))
97109
}
98110
}
99111

src/tests/authentication.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ use crate::TestApp;
33

44
use crate::util::encode_session_header;
55
use cargo_registry::models::persistent_session::SessionCookie;
6-
use cargo_registry::util::token::SecureToken;
7-
use cargo_registry::util::token::SecureTokenKind;
86
use conduit::{header, Body, Method, StatusCode};
97

108
static URL: &str = "/api/v1/me/updates";
@@ -44,11 +42,9 @@ fn persistent_session_revoked_after_logout() {
4442
fn incorrect_session_is_forbidden() {
4543
let (_, anon) = TestApp::init().empty();
4644

47-
let token = SecureToken::generate(SecureTokenKind::Session);
45+
let token = "scio:1234:abcdfdfdsafdsfd".to_string();
4846
// Create a cookie that isn't in the database.
49-
let cookie = SessionCookie::new(123, token.plaintext().to_string())
50-
.build(false)
51-
.to_string();
47+
let cookie = SessionCookie::new(123, token).build(false).to_string();
5248
let mut request = anon.request_builder(Method::GET, URL);
5349
request.header(header::COOKIE, &cookie);
5450
let response: Response<Body> = anon.run(request);

src/tests/util.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ use crate::{
2626
use cargo_registry::models::persistent_session::SessionCookie;
2727
use cargo_registry::models::PersistentSession;
2828
use cargo_registry::models::{ApiToken, CreatedApiToken, User};
29-
use cargo_registry::util::token::SecureToken;
30-
use cargo_registry::util::token::SecureTokenKind;
3129

3230
use conduit::{BoxError, Handler, Method};
3331
use conduit_cookie::SessionMiddleware;
@@ -276,17 +274,15 @@ impl MockCookieUser {
276274
}
277275

278276
pub fn with_session(&self) -> MockSessionUser {
279-
let token = SecureToken::generate(SecureTokenKind::Session);
280-
281-
let session = self.app.db(|conn| {
282-
PersistentSession::create(self.user.id, &token)
277+
let (_session, session_cookie) = self.app.db(|conn| {
278+
PersistentSession::create(self.user.id)
283279
.insert(conn)
284280
.unwrap()
285281
});
286282

287283
MockSessionUser {
288284
app: self.app.clone(),
289-
session_cookie: SessionCookie::new(session.id, token.plaintext().to_string()),
285+
session_cookie,
290286
}
291287
}
292288
}

src/util.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ mod io_util;
1212
mod request_helpers;
1313
mod request_proxy;
1414
pub mod rfc3339;
15-
pub mod token;
15+
pub(crate) mod token;
1616

1717
pub type AppResponse = Response<conduit::Body>;
1818
pub type EndpointResult = Result<AppResponse, Box<dyn errors::AppError>>;

src/util/token.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub struct SecureToken {
1212
}
1313

1414
impl SecureToken {
15-
pub fn generate(kind: SecureTokenKind) -> NewSecureToken {
15+
pub(crate) fn generate(kind: SecureTokenKind) -> NewSecureToken {
1616
let plaintext = format!(
1717
"{}{}",
1818
kind.prefix(),
@@ -26,7 +26,7 @@ impl SecureToken {
2626
}
2727
}
2828

29-
pub fn parse(kind: SecureTokenKind, plaintext: &str) -> Option<Self> {
29+
pub(crate) fn parse(kind: SecureTokenKind, plaintext: &str) -> Option<Self> {
3030
// This will both reject tokens without a prefix and tokens of the wrong kind.
3131
if SecureTokenKind::from_token(plaintext) != Some(kind) {
3232
return None;
@@ -60,18 +60,18 @@ impl FromSql<Bytea, Pg> for SecureToken {
6060
}
6161
}
6262

63-
pub struct NewSecureToken {
63+
pub(crate) struct NewSecureToken {
6464
plaintext: String,
6565
inner: SecureToken,
6666
}
6767

6868
impl NewSecureToken {
69-
pub fn plaintext(&self) -> &str {
69+
pub(crate) fn plaintext(&self) -> &str {
7070
&self.plaintext
7171
}
7272

7373
#[cfg(test)]
74-
pub fn into_inner(self) -> SecureToken {
74+
pub(crate) fn into_inner(self) -> SecureToken {
7575
self.inner
7676
}
7777
}
@@ -120,7 +120,7 @@ secure_token_kind! {
120120
/// NEVER CHANGE THE PREFIX OF EXISTING TOKEN TYPES!!! Doing so will implicitly revoke all the
121121
/// tokens of that kind, distrupting production users.
122122
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
123-
pub enum SecureTokenKind {
123+
pub(crate) enum SecureTokenKind {
124124
Api => "cio", // Crates.IO
125125
Session => "scio", // Session tokens.
126126
}

0 commit comments

Comments
 (0)