Skip to content

Commit d6b1058

Browse files
committed
Setup new persistent session and cookie on auth.
1 parent 681b025 commit d6b1058

File tree

4 files changed

+78
-7
lines changed

4 files changed

+78
-7
lines changed

src/controllers/user/session.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,29 @@
11
use crate::controllers::frontend_prelude::*;
22

3-
use conduit_cookie::RequestSession;
3+
use conduit_cookie::{RequestCookies, RequestSession};
4+
use cookie::{Cookie, SameSite};
45
use oauth2::reqwest::http_client;
56
use oauth2::{AuthorizationCode, Scope, TokenResponse};
67

78
use crate::email::Emails;
89
use crate::github::GithubUser;
9-
use crate::models::{NewUser, User};
10+
use crate::models::{NewUser, PersistentSession, User};
1011
use crate::schema::users;
1112
use crate::util::errors::ReadOnlyMode;
13+
use crate::util::token::NewSecureToken;
14+
use crate::util::token::SecureToken;
15+
use crate::Env;
16+
17+
pub const SESSION_COOKIE_NAME: &str = "crates_auth";
18+
19+
fn session_cookie(token: &NewSecureToken, secure: bool) -> Cookie<'static> {
20+
Cookie::build(SESSION_COOKIE_NAME, token.plaintext().to_string())
21+
.http_only(true)
22+
.secure(secure)
23+
.same_site(SameSite::Strict)
24+
.path("/")
25+
.finish()
26+
}
1227

1328
/// Handles the `GET /api/private/session/begin` route.
1429
///
@@ -97,7 +112,24 @@ pub fn authorize(req: &mut dyn RequestExt) -> EndpointResult {
97112
let ghuser = req.app().github.current_user(token)?;
98113
let user = save_user_to_database(&ghuser, token.secret(), &req.app().emails, &*req.db_conn()?)?;
99114

115+
let user_agent = req
116+
.headers()
117+
.get(header::USER_AGENT)
118+
.and_then(|value| value.to_str().ok())
119+
.map(|value| value.to_string())
120+
.unwrap_or_default();
121+
122+
// Setup a session for the newly logged in user.
123+
let token = SecureToken::generate(crate::util::token::SecureTokenKind::Session);
124+
let session = PersistentSession::create(user.id, &token, req.remote_addr().ip(), &user_agent);
125+
session.insert(&*req.db_conn()?)?;
126+
127+
// Setup session cookie.
128+
let secure = req.app().config.env() == Env::Production;
129+
req.cookies_mut().add(session_cookie(&token, secure));
130+
100131
// Log in by setting a cookie and the middleware authentication
132+
// TODO(adsnaider): Remove.
101133
req.session_mut()
102134
.insert("user_id".to_string(), user.id.to_string());
103135

src/models.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
pub use self::action::{insert_version_owner_action, VersionAction, VersionOwnerAction};
22
pub use self::badge::{Badge, CrateBadge, MaintenanceStatus};
33
pub use self::category::{Category, CrateCategory, NewCategory};
4-
pub use self::persistent_session::PersistentSession;
54
pub use self::crate_owner_invitation::{CrateOwnerInvitation, NewCrateOwnerInvitationOutcome};
65
pub use self::dependency::{Dependency, DependencyKind, ReverseDependency};
76
pub use self::download::VersionDownload;
@@ -10,6 +9,7 @@ pub use self::follow::Follow;
109
pub use self::keyword::{CrateKeyword, Keyword};
1110
pub use self::krate::{Crate, CrateVersions, NewCrate, RecentCrateDownloads};
1211
pub use self::owner::{CrateOwner, Owner, OwnerKind};
12+
pub use self::persistent_session::{NewPersistentSession, PersistentSession};
1313
pub use self::rights::Rights;
1414
pub use self::team::{NewTeam, Team};
1515
pub use self::token::{ApiToken, CreatedApiToken};
@@ -21,7 +21,6 @@ pub mod helpers;
2121
mod action;
2222
mod badge;
2323
pub mod category;
24-
mod persistent_session;
2524
mod crate_owner_invitation;
2625
pub mod dependency;
2726
mod download;
@@ -30,6 +29,7 @@ mod follow;
3029
mod keyword;
3130
pub mod krate;
3231
mod owner;
32+
mod persistent_session;
3333
mod rights;
3434
mod team;
3535
mod token;

src/models/persistent_session.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,53 @@
1-
use crate::schema::persistent_sessions;
21
use chrono::NaiveDateTime;
2+
use diesel::prelude::*;
33
use ipnetwork::IpNetwork;
4+
use std::net::IpAddr;
5+
6+
use crate::schema::persistent_sessions;
7+
use crate::util::token::SecureToken;
48

59
#[derive(Clone, Debug, PartialEq, Eq, Identifiable, Queryable)]
610
#[table_name = "persistent_sessions"]
711
pub struct PersistentSession {
812
pub id: i32,
913
pub user_id: i32,
10-
pub hashed_token: Vec<u8>,
14+
pub hashed_token: SecureToken,
1115
pub created_at: NaiveDateTime,
1216
pub last_used_at: NaiveDateTime,
1317
pub revoked: bool,
1418
pub last_ip_address: IpNetwork,
1519
pub last_user_agent: String,
1620
}
21+
22+
impl PersistentSession {
23+
pub fn create<'a, 'b>(
24+
user_id: i32,
25+
token: &'a SecureToken,
26+
last_ip_address: IpAddr,
27+
last_user_agent: &'b str,
28+
) -> NewPersistentSession<'a, 'b> {
29+
NewPersistentSession {
30+
user_id,
31+
hashed_token: token,
32+
last_ip_address: last_ip_address.into(),
33+
last_user_agent,
34+
}
35+
}
36+
}
37+
38+
#[derive(Clone, Debug, PartialEq, Eq, Insertable)]
39+
#[table_name = "persistent_sessions"]
40+
pub struct NewPersistentSession<'a, 'b> {
41+
user_id: i32,
42+
hashed_token: &'a SecureToken,
43+
last_ip_address: IpNetwork,
44+
last_user_agent: &'b str,
45+
}
46+
47+
impl NewPersistentSession<'_, '_> {
48+
pub fn insert(self, conn: &PgConnection) -> Result<PersistentSession, diesel::result::Error> {
49+
diesel::insert_into(persistent_sessions::table)
50+
.values(self)
51+
.get_result(conn)
52+
}
53+
}

src/util/token.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ impl std::ops::Deref for NewSecureToken {
8484
}
8585
}
8686

87-
fn generate_secure_alphanumeric_string(len: usize) -> String {
87+
pub(crate) fn generate_secure_alphanumeric_string(len: usize) -> String {
8888
const CHARS: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
8989

9090
OsRng
@@ -122,6 +122,7 @@ secure_token_kind! {
122122
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
123123
pub(crate) enum SecureTokenKind {
124124
Api => "cio", // Crates.IO
125+
Session => "ses", // Session tokens.
125126
}
126127
}
127128

@@ -172,6 +173,7 @@ mod tests {
172173
};
173174

174175
ensure(SecureTokenKind::Api, "cio");
176+
ensure(SecureTokenKind::Session, "ses");
175177

176178
assert!(
177179
remaining.is_empty(),

0 commit comments

Comments
 (0)