Skip to content

Commit

Permalink
Make TokenItem private to token repository
Browse files Browse the repository at this point in the history
  • Loading branch information
davidsteiner committed Jul 9, 2023
1 parent 75a106a commit 6ad8fb3
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 70 deletions.
6 changes: 3 additions & 3 deletions application/graphql/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use futures::future::try_join_all;

use crate::models::crate_summary::CrateSummary as CrateSummaryModel;
use crate::models::metadata::Metadata;
use crate::models::token::TokenItem;
use crate::models::token::Token as TokenModel;
use crate::models::user::User as UserModel;
use crate::repository::DynRepository;

Expand Down Expand Up @@ -131,8 +131,8 @@ pub struct Token {
name: String,
}

impl From<TokenItem> for Token {
fn from(item: TokenItem) -> Self {
impl From<TokenModel> for Token {
fn from(item: TokenModel) -> Self {
Self {
id: item.token_id.into(),
user_id: item.user_id,
Expand Down
32 changes: 2 additions & 30 deletions application/models/token.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,6 @@
use crate::auth::hash;
use base64::Engine;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct TokenItem {
pub pk: String,
pub sk: String,
#[derive(Clone, Debug)]
pub struct Token {
pub name: String,
pub user_id: u32,
pub token_id: String,
}

impl TokenItem {
pub fn new(token: &[u8], name: String, user_id: u32) -> Self {
Self {
pk: Self::get_pk(token),
sk: Self::get_sk(),
name,
user_id,
token_id: Uuid::new_v4().hyphenated().to_string(),
}
}

pub fn get_pk(token: &[u8]) -> String {
let encoded = base64::engine::general_purpose::STANDARD.encode(hash(token));
format!("TOK#{}", encoded)
}

pub fn get_sk() -> String {
"TOK".to_string()
}
}
13 changes: 4 additions & 9 deletions application/repository/base/token.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
use crate::error::AppResult;
use crate::models::token::TokenItem;
use crate::models::token::Token;

#[async_trait::async_trait]
pub trait TokenRepository {
async fn store_auth_token(
&self,
token: &[u8],
name: String,
user_id: u32,
) -> AppResult<TokenItem>;
async fn store_auth_token(&self, token: &[u8], name: String, user_id: u32) -> AppResult<Token>;
async fn delete_auth_token(&self, user_id: u32, token_id: String) -> AppResult<()>;
async fn list_auth_tokens(&self, user_id: u32) -> AppResult<Vec<TokenItem>>;
async fn get_auth_token(&self, token: &[u8]) -> AppResult<Option<TokenItem>>;
async fn list_auth_tokens(&self, user_id: u32) -> AppResult<Vec<Token>>;
async fn get_auth_token(&self, token: &[u8]) -> AppResult<Option<Token>>;
}
106 changes: 78 additions & 28 deletions application/repository/dynamodb/token.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
use aws_sdk_dynamodb::types::AttributeValue;
use aws_sdk_dynamodb::Client;
use base64::Engine;
use serde::{Deserialize, Serialize};
use serde_dynamo::{from_item, from_items, to_item};
use uuid::Uuid;

use crate::auth::hash;
use crate::error::AppResult;
use crate::models::token::TokenItem;
use crate::models::token::Token;
use crate::models::user::UserId;
use crate::repository::base::TokenRepository;
use crate::repository::DynamoDBRepository;

#[async_trait::async_trait]
impl TokenRepository for DynamoDBRepository {
async fn store_auth_token(
&self,
token: &[u8],
name: String,
user_id: u32,
) -> AppResult<TokenItem> {
async fn store_auth_token(&self, token: &[u8], name: String, user_id: u32) -> AppResult<Token> {
let token_item = TokenItem::new(token, name, user_id);
let item = to_item(token_item.clone())?;
self.db_client
Expand All @@ -23,11 +24,12 @@ impl TokenRepository for DynamoDBRepository {
.send()
.await?;

Ok(token_item)
Ok(token_item.into())
}

async fn delete_auth_token(&self, user_id: u32, token_id: String) -> AppResult<()> {
let tokens = self.list_auth_tokens(user_id).await?;
let tokens =
TokenItem::get_tokens_for_user(&self.db_client, &self.table_name, user_id).await?;
if let Some(token_to_delete) = tokens.into_iter().find(|item| item.token_id == token_id) {
self.db_client
.delete_item()
Expand All @@ -41,26 +43,15 @@ impl TokenRepository for DynamoDBRepository {
Ok(())
}

async fn list_auth_tokens(&self, user_id: u32) -> AppResult<Vec<TokenItem>> {
// TODO: this shouldn't return TokenItem
// in fact, we shouldn't leak TokenItem at all, as it's a DynamoDB model
let output = self
.db_client
.query()
.table_name(&self.table_name)
.index_name("user_tokens")
.key_condition_expression("user_id = :user_id")
.expression_attribute_values(":user_id", AttributeValue::N(user_id.to_string()))
.send()
.await?;

let items = output.items().map(|items| items.to_vec()).unwrap_or(vec![]);
let tokens = from_items(items)?;
async fn list_auth_tokens(&self, user_id: u32) -> AppResult<Vec<Token>> {
let token_items =
TokenItem::get_tokens_for_user(&self.db_client, &self.table_name, user_id).await?;
let tokens = token_items.into_iter().map(|i| i.into()).collect();

Ok(tokens)
}

async fn get_auth_token(&self, token: &[u8]) -> AppResult<Option<TokenItem>> {
async fn get_auth_token(&self, token: &[u8]) -> AppResult<Option<Token>> {
let output = self
.db_client
.get_item()
Expand All @@ -70,12 +61,71 @@ impl TokenRepository for DynamoDBRepository {
.send()
.await?;

let token_item = if let Some(item) = output.item().cloned() {
Some(from_item(item)?)
let token = if let Some(item) = output.item().cloned() {
let token_item: TokenItem = from_item(item)?;
Some(token_item.into())
} else {
None
};

Ok(token_item)
Ok(token)
}
}

#[derive(Clone, Debug, Deserialize, Serialize)]
struct TokenItem {
pub pk: String,
pub sk: String,
pub name: String,
pub user_id: u32,
pub token_id: String,
}

impl TokenItem {
fn new(token: &[u8], name: String, user_id: u32) -> Self {
Self {
pk: Self::get_pk(token),
sk: Self::get_sk(),
name,
user_id,
token_id: Uuid::new_v4().hyphenated().to_string(),
}
}

async fn get_tokens_for_user(
db_client: &Client,
table_name: &str,
user_id: UserId,
) -> AppResult<Vec<TokenItem>> {
let output = db_client
.query()
.table_name(table_name)
.index_name("user_tokens")
.key_condition_expression("user_id = :user_id")
.expression_attribute_values(":user_id", AttributeValue::N(user_id.to_string()))
.send()
.await?;

let items = output.items().map(|items| items.to_vec()).unwrap_or(vec![]);
Ok(from_items(items)?)
}

fn get_pk(token: &[u8]) -> String {
let encoded = base64::engine::general_purpose::STANDARD.encode(hash(token));
format!("TOK#{}", encoded)
}

fn get_sk() -> String {
"TOK".to_string()
}
}

impl From<TokenItem> for Token {
fn from(item: TokenItem) -> Self {
Self {
name: item.name,
user_id: item.user_id,
token_id: item.token_id,
}
}
}

0 comments on commit 6ad8fb3

Please sign in to comment.