Skip to content

Commit

Permalink
Update access_token interface
Browse files Browse the repository at this point in the history
  • Loading branch information
minshao authored and msk committed Feb 13, 2024
1 parent ec98a23 commit 188eb48
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 69 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ oinq = { git = "https://github.com/petabi/oinq.git", tag = "0.9.1" }
reqwest = { version = "0.11", default-features = false, features = [
"rustls-tls-native-roots",
] }
review-database = { git = "https://github.com/petabi/review-database.git", rev = "cf694f70" }
review-database = { git = "https://github.com/petabi/review-database.git", rev = "5374afa9" }
roxy = { git = "https://github.com/aicers/roxy.git", tag = "0.2.1" }
rustls = "0.21"
rustls-native-certs = "0.6"
Expand Down
51 changes: 9 additions & 42 deletions src/auth/store.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use super::AuthError;
use crate::Store;
use anyhow::{anyhow, bail, Result};
use bincode::Options;
use std::collections::HashSet;
use anyhow::{anyhow, Result};

/// Inserts a token into the store.
///
Expand All @@ -11,20 +9,7 @@ use std::collections::HashSet;
/// Returns an error if the tokens in the store are invalid, if the token cannot be serialized, or
/// if the store cannot be accessed.
pub fn insert_token(store: &Store, token: &str, username: &str) -> Result<()> {
let map = store.access_token_map();
let tokens = map.get(username.as_bytes())?;
let value = if let Some(tokens) = tokens {
let mut tokens =
bincode::DefaultOptions::new().deserialize::<HashSet<String>>(tokens.as_ref())?;
tokens.insert(token.to_string());
tokens
} else {
HashSet::from([token.to_string()])
};
let value = bincode::DefaultOptions::new().serialize(&value)?;
map.put(username.as_bytes(), &value)?;

Ok(())
store.access_token_map().insert(username, token)
}

/// Revokes a token from the store.
Expand All @@ -36,37 +21,19 @@ pub fn insert_token(store: &Store, token: &str, username: &str) -> Result<()> {
pub fn revoke_token(store: &Store, token: &str) -> Result<()> {
let decoded_token = super::decode_token(token)?;
let username = decoded_token.sub;
let map = store.access_token_map();
let value = map
.get(username.as_bytes())?
.ok_or_else(|| anyhow!("The given token does not exist"))?;
let mut tokens =
bincode::DefaultOptions::new().deserialize::<HashSet<String>>(value.as_ref())?;
if tokens.contains(token) {
tokens.remove(token);
let value = bincode::DefaultOptions::new().serialize(&tokens)?;
map.put(username.as_bytes(), &value)?;
Ok(())
} else {
bail!("The given token does not exist");
}
store
.access_token_map()
.revoke(&username, token)
.map_err(|_| anyhow!("The given token does not exist"))
}

pub(super) fn token_exists_in_store(
store: &Store,
token: &str,
username: &str,
) -> Result<bool, AuthError> {
let value = store
store
.access_token_map()
.get(username.as_bytes())
.map_err(|_| AuthError::InvalidToken("Token not found in the database".into()))?;
if let Some(value) = value {
let tokens = bincode::DefaultOptions::new()
.deserialize::<HashSet<String>>(value.as_ref())
.map_err(|e| AuthError::Other(format!("An unexpected value in the database: {e}")))?;
Ok(tokens.contains(token))
} else {
Ok(false)
}
.contains(username, token)
.map_err(|_| AuthError::InvalidToken("Token not found in the database".into()))
}
56 changes: 30 additions & 26 deletions src/graphql/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,10 @@ use chrono::{DateTime, NaiveDateTime, TimeZone, Utc};
use review_database::{
self as database,
types::{self},
Direction, IterableMap, Store,
Direction, Store,
};
use serde::{Deserialize, Serialize};
use std::{
collections::HashSet,
net::{AddrParseError, IpAddr},
};
use std::net::{AddrParseError, IpAddr};
use tracing::info;

#[allow(clippy::module_name_repetitions)]
Expand Down Expand Up @@ -76,33 +73,40 @@ impl AccountQuery {
#[graphql(guard = "RoleGuard::new(super::Role::SystemAdministrator)
.or(RoleGuard::new(super::Role::SecurityAdministrator))")]
async fn signed_in_account_list(&self, ctx: &Context<'_>) -> Result<Vec<SignedInAccount>> {
use review_database::KeyValueIterable;
use std::collections::HashMap;

let store = crate::graphql::get_store(ctx).await?;
let map = store.access_token_map();

let signed = map
.iter_forward()?
.filter_map(|(key, value)| {
bincode::DefaultOptions::new()
.deserialize::<HashSet<String>>(&value)
.iter(Direction::Forward, None)
.filter_map(|e| {
let e = e.ok()?;
let username = e.username;
let exp_time = decode_token(&e.token)
.ok()
.map(|tokens| SignedInAccount {
username: String::from_utf8_lossy(&key).into_owned(),
expire_times: tokens
.iter()
.filter_map(|token| {
decode_token(token).ok().and_then(|decoded| {
let time = Utc.timestamp_nanos(decoded.exp * 1_000_000_000);
if Utc::now() < time {
Some(time)
} else {
None
}
})
})
.collect::<Vec<DateTime<Utc>>>(),
})
.map(|t| Utc.timestamp_nanos(t.exp * 1_000_000_000))?;
if Utc::now() < exp_time {
Some((username, exp_time))
} else {
None
}
})
.fold(
HashMap::new(),
|mut res: HashMap<_, Vec<_>>, (username, time)| {
let e = res.entry(username).or_default();
e.push(time);
res
},
)
.into_iter()
.map(|(username, expire_times)| SignedInAccount {
username,
expire_times,
})
.collect::<Vec<SignedInAccount>>();
.collect::<Vec<_>>();

Ok(signed)
}
Expand Down

0 comments on commit 188eb48

Please sign in to comment.