Skip to content

Commit

Permalink
Examples: Move shared functions into utils module
Browse files Browse the repository at this point in the history
  • Loading branch information
David Graeff committed Jan 22, 2021
1 parent 814663f commit 42e2d17
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 57 deletions.
63 changes: 6 additions & 57 deletions examples/create_read_write_document.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use firestore_db_and_auth::{
documents, dto, errors, sessions, Credentials, FirebaseAuthBearer, JWKSet, ServiceSession,
documents, dto, errors, sessions, Credentials, FirebaseAuthBearer, ServiceSession,
};

use firestore_db_and_auth::documents::WriteResult;
use firestore_db_and_auth::jwt::download_google_jwks;
use serde::{Deserialize, Serialize};

const TEST_USER_ID: &str = include_str!("test_user_id.txt");
mod utils;

#[derive(Debug, Serialize, Deserialize)]
struct DemoDTO {
Expand Down Expand Up @@ -93,43 +92,16 @@ fn service_account_session(cred: Credentials) -> errors::Result<()> {
Ok(())
}

fn user_session_with_cached_refresh_token(cred: &Credentials) -> errors::Result<sessions::user::Session> {
println!("Refresh token from file");
// Read refresh token from file if possible instead of generating a new refresh token each time
let refresh_token: String = match std::fs::read_to_string("refresh-token-for-tests.txt") {
Ok(v) => v,
Err(e) => {
if e.kind() != std::io::ErrorKind::NotFound {
return Err(errors::FirebaseError::IO(e));
}
String::new()
}
};

// Generate a new refresh token if necessary
println!("Generate new user auth token");
let user_session: sessions::user::Session = if refresh_token.is_empty() {
let session = sessions::user::Session::by_user_id(&cred, TEST_USER_ID, true)?;
std::fs::write("refresh-token-for-tests.txt", &session.refresh_token.as_ref().unwrap())?;
session
} else {
println!("user::Session::by_refresh_token");
sessions::user::Session::by_refresh_token(&cred, &refresh_token)?
};

Ok(user_session)
}

fn user_account_session(cred: Credentials) -> errors::Result<()> {
let user_session = user_session_with_cached_refresh_token(&cred)?;
let user_session = utils::user_session_with_cached_refresh_token(&cred)?;

assert_eq!(user_session.user_id, TEST_USER_ID);
assert_eq!(user_session.user_id, utils::TEST_USER_ID);
assert_eq!(user_session.project_id(), cred.project_id);

println!("user::Session::by_access_token");
let user_session = sessions::user::Session::by_access_token(&cred, &user_session.access_token_unchecked())?;

assert_eq!(user_session.user_id, TEST_USER_ID);
assert_eq!(user_session.user_id, utils::TEST_USER_ID);

let obj = DemoDTO {
a_string: "abc".to_owned(),
Expand Down Expand Up @@ -213,29 +185,6 @@ fn user_account_session(cred: Credentials) -> errors::Result<()> {
Ok(())
}

/// Download the two public key JWKS files if necessary and cache the content at the given file path.
/// Only use this option in cloud functions if the given file path is persistent.
/// You can use [`Credentials::add_jwks_public_keys`] to manually add more public keys later on.
pub fn from_cache_file(cache_file: &std::path::Path, c: &Credentials) -> errors::Result<JWKSet> {
use std::fs::File;
use std::io::BufReader;

Ok(if cache_file.exists() {
let f = BufReader::new(File::open(cache_file)?);
let jwks_set: JWKSet = serde_json::from_reader(f)?;
jwks_set
} else {
// If not present, download the two jwks (specific service account + google system account),
// merge them into one set of keys and store them in the cache file.
let mut jwks = JWKSet::new(&download_google_jwks(&c.client_email)?)?;
jwks.keys
.append(&mut JWKSet::new(&download_google_jwks("[email protected]")?)?.keys);
let f = File::create(cache_file)?;
serde_json::to_writer_pretty(f, &jwks)?;
jwks
})
}

fn main() -> errors::Result<()> {
// Search for a credentials file in the root directory
use std::path::PathBuf;
Expand All @@ -244,7 +193,7 @@ fn main() -> errors::Result<()> {
let mut cred = Credentials::from_file(credential_file.to_str().unwrap())?;

// Only download the public keys once, and cache them.
let jwkset = from_cache_file(credential_file.with_file_name("cached_jwks.jwks").as_path(), &cred)?;
let jwkset = utils::from_cache_file(credential_file.with_file_name("cached_jwks.jwks").as_path(), &cred)?;
cred.add_jwks_public_keys(&jwkset);
cred.verify()?;

Expand Down
77 changes: 77 additions & 0 deletions examples/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use firestore_db_and_auth::{
errors, sessions, Credentials, JWKSet,
};

use firestore_db_and_auth::jwt::download_google_jwks;

#[warn(dead_code)]
pub const TEST_USER_ID: &str = include_str!("../test_user_id.txt");

pub fn user_session_with_cached_refresh_token(cred: &Credentials) -> errors::Result<sessions::user::Session> {
println!("Refresh token from file");
// Read refresh token from file if possible instead of generating a new refresh token each time
let refresh_token: String = match std::fs::read_to_string("refresh-token-for-tests.txt") {
Ok(v) => v,
Err(e) => {
if e.kind() != std::io::ErrorKind::NotFound {
return Err(errors::FirebaseError::IO(e));
}
String::new()
}
};

// Generate a new refresh token if necessary
println!("Generate new user auth token");
let user_session: sessions::user::Session = if refresh_token.is_empty() {
let session = sessions::user::Session::by_user_id(&cred, TEST_USER_ID, true)?;
std::fs::write("refresh-token-for-tests.txt", &session.refresh_token.as_ref().unwrap())?;
session
} else {
println!("user::Session::by_refresh_token");
sessions::user::Session::by_refresh_token(&cred, &refresh_token)?
};

Ok(user_session)
}


/// Download the two public key JWKS files if necessary and cache the content at the given file path.
/// Only use this option in cloud functions if the given file path is persistent.
/// You can use [`Credentials::add_jwks_public_keys`] to manually add more public keys later on.
pub fn from_cache_file(cache_file: &std::path::Path, c: &Credentials) -> errors::Result<JWKSet> {
use std::fs::File;
use std::io::BufReader;

Ok(if cache_file.exists() {
let f = BufReader::new(File::open(cache_file)?);
let jwks_set: JWKSet = serde_json::from_reader(f)?;
jwks_set
} else {
// If not present, download the two jwks (specific service account + google system account),
// merge them into one set of keys and store them in the cache file.
let mut jwks = JWKSet::new(&download_google_jwks(&c.client_email)?)?;
jwks.keys
.append(&mut JWKSet::new(&download_google_jwks("[email protected]")?)?.keys);
let f = File::create(cache_file)?;
serde_json::to_writer_pretty(f, &jwks)?;
jwks
})
}

/// For integration tests and doc code snippets: Create a Credentials instance.
/// Necessary public jwk sets are downloaded or re-used if already present.
#[cfg(test)]
pub fn valid_test_credentials() -> errors::Result<Credentials> {
use std::path::PathBuf;
let mut jwks_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
jwks_path.push("firebase-service-account.jwks");

let mut cred: Credentials = Credentials::new(include_str!("../../firebase-service-account.json"))?;

// Only download the public keys once, and cache them.
let jwkset = from_cache_file(jwks_path.as_path(), &cred)?;
cred.add_jwks_public_keys(&jwkset);
cred.verify()?;

Ok(cred)
}

0 comments on commit 42e2d17

Please sign in to comment.