Skip to content

Commit 69767fc

Browse files
committed
Holding on to the authorisation token.
1 parent d59a9ad commit 69767fc

File tree

3 files changed

+41
-28
lines changed

3 files changed

+41
-28
lines changed

src/middleware/current_user.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use diesel::prelude::*;
66
use crate::db::RequestTransaction;
77
use crate::util::errors::{std_error, CargoResult, ChainError, Unauthorized};
88

9+
use crate::models::ApiToken;
910
use crate::models::User;
1011
use crate::schema::users;
1112

@@ -15,7 +16,7 @@ pub struct CurrentUser;
1516
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1617
pub enum AuthenticationSource {
1718
SessionCookie,
18-
ApiToken,
19+
ApiToken(i32),
1920
}
2021

2122
impl Middleware for CurrentUser {
@@ -44,18 +45,22 @@ impl Middleware for CurrentUser {
4445
} else {
4546
// Otherwise, look for an `Authorization` header on the request
4647
// and try to find a user in the database with a matching API token
47-
let user = if let Some(headers) = req.headers().find("Authorization") {
48-
User::find_by_api_token(&conn, headers[0])
48+
let user_and_token = if let Some(headers) = req.headers().find("Authorization") {
49+
ApiToken::find_by_api_token_and_revoked(&conn, headers[0], false)
50+
.and_then(|api_token| {
51+
User::find(&conn, api_token.user_id).map(|user| (user, api_token.id))
52+
})
4953
.optional()
5054
.map_err(|e| Box::new(e) as Box<dyn Error + Send>)?
5155
} else {
5256
None
5357
};
5458
drop(conn);
55-
if let Some(user) = user {
59+
if let Some((user, token)) = user_and_token {
5660
// Attach the `User` model from the database to the request
5761
req.mut_extensions().insert(user);
58-
req.mut_extensions().insert(AuthenticationSource::ApiToken);
62+
req.mut_extensions()
63+
.insert(AuthenticationSource::ApiToken(token));
5964
}
6065
}
6166

src/models/token.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,28 @@ impl ApiToken {
4646
last_used_at: self.last_used_at,
4747
}
4848
}
49+
50+
pub fn find_by_api_token_and_revoked(
51+
conn: &PgConnection,
52+
token_: &str,
53+
revoked_: bool,
54+
) -> QueryResult<ApiToken> {
55+
use crate::schema::api_tokens::dsl::{api_tokens, last_used_at, revoked, token};
56+
use diesel::{dsl::now, update};
57+
58+
let tokens = api_tokens
59+
.filter(token.eq(token_))
60+
.filter(revoked.eq(revoked_));
61+
62+
// If the database is in read only mode, we can't update last_used_at.
63+
// Try updating in a new transaction, if that fails, fall back to reading
64+
conn.transaction(|| {
65+
update(tokens)
66+
.set(last_used_at.eq(now.nullable()))
67+
.get_result::<ApiToken>(conn)
68+
})
69+
.or_else(|_| tokens.first(conn))
70+
}
4971
}
5072

5173
#[cfg(test)]

src/models/user.rs

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
use diesel::dsl::now;
21
use diesel::prelude::*;
32
use std::borrow::Cow;
43

54
use crate::app::App;
65
use crate::util::CargoResult;
76

8-
use crate::models::{Crate, CrateOwner, Email, NewEmail, Owner, OwnerKind, Rights};
7+
use crate::models::{ApiToken, Crate, CrateOwner, Email, NewEmail, Owner, OwnerKind, Rights};
98
use crate::schema::{crate_owners, emails, users};
109
use crate::views::{EncodablePrivateUser, EncodablePublicUser};
1110

@@ -105,27 +104,14 @@ impl<'a> NewUser<'a> {
105104
}
106105

107106
impl User {
108-
/// Queries the database for a user with a certain `api_token` value.
109-
pub fn find_by_api_token(conn: &PgConnection, token_: &str) -> QueryResult<User> {
110-
use crate::schema::api_tokens::dsl::{api_tokens, last_used_at, revoked, token, user_id};
111-
use diesel::update;
112-
113-
let tokens = api_tokens
114-
.filter(token.eq(token_))
115-
.filter(revoked.eq(false));
116-
117-
// If the database is in read only mode, we can't update last_used_at.
118-
// Try updating in a new transaction, if that fails, fall back to reading
119-
let user_id_ = conn
120-
.transaction(|| {
121-
update(tokens)
122-
.set(last_used_at.eq(now.nullable()))
123-
.returning(user_id)
124-
.get_result::<i32>(conn)
125-
})
126-
.or_else(|_| tokens.select(user_id).first(conn))?;
127-
128-
users::table.find(user_id_).first(conn)
107+
pub fn find(conn: &PgConnection, id: i32) -> QueryResult<User> {
108+
users::table.find(id).first(conn)
109+
}
110+
111+
pub fn find_by_api_token(conn: &PgConnection, token: &str) -> QueryResult<User> {
112+
let api_token = ApiToken::find_by_api_token_and_revoked(conn, token, false)?;
113+
114+
Self::find(conn, api_token.user_id)
129115
}
130116

131117
pub fn owning(krate: &Crate, conn: &PgConnection) -> CargoResult<Vec<Owner>> {

0 commit comments

Comments
 (0)