From 4359fcda3440d4b094904f2b9a3ad67ce958a0b0 Mon Sep 17 00:00:00 2001 From: Greg Schoeninger Date: Thu, 11 Aug 2022 10:39:24 -0700 Subject: [PATCH] got rid of auth config and remote config since that will be on a per remote basis, and refactor setting of user name and email with better error messages --- .github/workflows/ci.yml | 5 +- README.md | 8 +- data/test/config/remote_config.toml | 1 - .../{auth_config.toml => user_config.toml} | 7 +- docs/dev/IntegrateServer+CLI.md | 8 +- docs/dev/IntegrateServerCode.md | 4 +- docs/examples/0_ServerSetup.md | 8 +- install-ubuntu.sh | 2 +- src/cli/src/dispatch.rs | 52 ++++-- src/cli/src/main.rs | 73 ++++++--- src/lib/src/api/endpoint.rs | 17 -- src/lib/src/api/remote/branches.rs | 18 +-- src/lib/src/api/remote/commits.rs | 30 ++-- src/lib/src/api/remote/entries.rs | 22 +-- src/lib/src/api/remote/repositories.rs | 42 ++--- src/lib/src/command.rs | 25 ++- src/lib/src/config.rs | 9 +- src/lib/src/config/auth_config.rs | 124 -------------- src/lib/src/config/http_config.rs | 4 - src/lib/src/config/remote_config.rs | 151 ------------------ src/lib/src/config/user_config.rs | 108 +++++++++++++ src/lib/src/error.rs | 23 ++- src/lib/src/index/commit_writer.rs | 16 +- src/lib/src/index/indexer.rs | 25 +-- src/lib/src/index/ref_reader.rs | 14 +- src/lib/src/model.rs | 2 +- .../src/model/repository/local_repository.rs | 4 +- src/lib/src/model/user.rs | 57 +------ src/lib/src/test.rs | 28 +--- src/server/src/auth/access_keys.rs | 9 +- src/server/src/main.rs | 20 ++- src/server/src/test.rs | 11 ++ 32 files changed, 368 insertions(+), 559 deletions(-) delete mode 100644 data/test/config/remote_config.toml rename data/test/config/{auth_config.toml => user_config.toml} (65%) delete mode 100644 src/lib/src/config/auth_config.rs delete mode 100644 src/lib/src/config/http_config.rs delete mode 100644 src/lib/src/config/remote_config.rs create mode 100644 src/lib/src/config/user_config.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 879763754..1b8e6050f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,7 +59,6 @@ jobs: cargo build mkdir /tmp/oxen_sync/ mkdir data/test/runs - ./target/debug/oxen set-default-host 0.0.0.0:3000 - ./target/debug/oxen-server add-user --email ox@oxen.ai --name Ox --output auth_config.toml - cp auth_config.toml data/test/config/auth_config.toml + ./target/debug/oxen-server add-user --email ox@oxen.ai --name Ox --output user_config.toml + cp user_config.toml data/test/config/user_config.toml ./target/debug/oxen-server start & diff --git a/README.md b/README.md index 40983a9ca..aadf7790f 100644 --- a/README.md +++ b/README.md @@ -24,15 +24,15 @@ Build the binaries Generate a config file and token to give user access to the server -`./target/debug/oxen-server add-user --email ox@oxen.ai --name Ox --output auth_config.toml` +`./target/debug/oxen-server add-user --email ox@oxen.ai --name Ox --output user_config.toml` Copy the config to the default locations `mkdir ~/.oxen` -`mv auth_config.toml ~/.oxen/auth_config.toml` +`mv user_config.toml ~/.oxen/user_config.toml` -`cp ~/.oxen/auth_config.toml data/test/config/auth_config.toml` +`cp ~/.oxen/user_config.toml data/test/config/user_config.toml` Run the server @@ -79,7 +79,7 @@ Server defaults to localhost 3000 `set SERVER 0.0.0.0:3000` -You can grab your auth token from the config file above (~/.oxen/auth_config.toml) +You can grab your auth token from the config file above (~/.oxen/user_config.toml) `set TOKEN ` diff --git a/data/test/config/remote_config.toml b/data/test/config/remote_config.toml deleted file mode 100644 index 0daf7db64..000000000 --- a/data/test/config/remote_config.toml +++ /dev/null @@ -1 +0,0 @@ -host = "0.0.0.0:3000" \ No newline at end of file diff --git a/data/test/config/auth_config.toml b/data/test/config/user_config.toml similarity index 65% rename from data/test/config/auth_config.toml rename to data/test/config/user_config.toml index e83515639..b66d021e5 100644 --- a/data/test/config/auth_config.toml +++ b/data/test/config/user_config.toml @@ -1,7 +1,4 @@ -host = "0.0.0.0:3000" -[user] -id = "8dbce3c3-8e8d-46f6-8d1c-784552dc8631" +email = "ox@oxen.ai" +name = "Oxen" token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjhkYmNlM2MzLThlOGQtNDZmNi04ZDFjLTc4NDU1MmRjODYzMSIsIm5hbWUiOiJncmVnIiwiZW1haWwiOiJnQG94ZW4uYWkifQ.xGLwbZtnIapddbHLRfaUlxA6HaFS92UZmOtiRp1GWaE" -email = "g@oxen.ai" -name = "greg" diff --git a/docs/dev/IntegrateServer+CLI.md b/docs/dev/IntegrateServer+CLI.md index f77c8b019..72a8da7ec 100644 --- a/docs/dev/IntegrateServer+CLI.md +++ b/docs/dev/IntegrateServer+CLI.md @@ -13,8 +13,8 @@ We use the [reqwest](https://docs.rs/reqwest/latest/reqwest/) library to make ht pub fn list( repository: &RemoteRepository, ) -> Result, OxenError> { - // Auth Config reads ~/.oxen/auth_config.toml to get the user access token and other relevant info - let config = AuthConfig::default()?; + // Auth Config reads ~/.oxen/user_config.toml to get the user access token and other relevant info + let config = UserConfig::default()?; // url_from_repo will prepend the repositories url to the uri you provide // Should look like: http://{REMOTE}/repositories/{REPO_NAME}/branches @@ -24,10 +24,10 @@ pub fn list( let client = reqwest::blocking::Client::new(); if let Ok(res) = client .get(url) - // Grab the authentication token from AuthConfig + // Grab the authentication token from UserConfig .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) // Make requeest .send() diff --git a/docs/dev/IntegrateServerCode.md b/docs/dev/IntegrateServerCode.md index 4c0207ab6..b173b7a2c 100644 --- a/docs/dev/IntegrateServerCode.md +++ b/docs/dev/IntegrateServerCode.md @@ -158,8 +158,8 @@ If you would like to see the API with `curl` on the command line you can run the In order to get a valid auth token you can run add a user to the server via ```shell -$ ./target/debug/oxen-server add-user --email ox@oxen.ai --name Ox --output auth_config.toml -$ cat auth_config.toml | grep token +$ ./target/debug/oxen-server add-user --email ox@oxen.ai --name Ox --output user_config.toml +$ cat user_config.toml | grep token ``` For more information on server setup look at the [Server Setup Documentation](../examples/0_ServerSetup.md) diff --git a/docs/examples/0_ServerSetup.md b/docs/examples/0_ServerSetup.md index 9bfd83aba..d48bdcb50 100644 --- a/docs/examples/0_ServerSetup.md +++ b/docs/examples/0_ServerSetup.md @@ -4,19 +4,15 @@ Build the Oxen Server and Oxen CLI binaries `cargo build` -The default host for a dev server is `0.0.0.0:3000`, this can always be changed with the `set-default-host` command. - -`./target/debug/oxen set-default-host 0.0.0.0:3000` - Generate a config file that contains an access token to give it to the user to access to the server -`./target/debug/oxen-server add-user --email ox@oxen.ai --name Ox --output auth_config.toml` +`./target/debug/oxen-server add-user --email ox@oxen.ai --name Ox --output user_config.toml` The user who needs access should copy the config to the ~/.oxen directory, which is where the Oxen CLI looks for it. If the user has not done this step, they will not have access to the server. `mkdir ~/.oxen` -`mv auth_config.toml ~/.oxen/auth_config.toml` +`mv user_config.toml ~/.oxen/user_config.toml` Run the server diff --git a/install-ubuntu.sh b/install-ubuntu.sh index bd9d9966c..144fad7bc 100644 --- a/install-ubuntu.sh +++ b/install-ubuntu.sh @@ -54,6 +54,6 @@ ln -s /path/to/release/build/oxen /usr/local/bin/oxen # Run the server with a user mkdir -p /home/ubuntu/Data/sync/ -sudo env SYNC_DIR=/home/ubuntu/Data/sync/ ./target/release/oxen-server add-user --email ox@oxen.ai --name Ox --output auth_config.toml +sudo env SYNC_DIR=/home/ubuntu/Data/sync/ ./target/release/oxen-server add-user --email ox@oxen.ai --name Ox --output user_config.toml sudo env SYNC_DIR=/home/ubuntu/Data/sync/ ./target/release/oxen-server start -p 80 diff --git a/src/cli/src/dispatch.rs b/src/cli/src/dispatch.rs index 1b76d9ab6..d1d8a68bf 100644 --- a/src/cli/src/dispatch.rs +++ b/src/cli/src/dispatch.rs @@ -1,5 +1,6 @@ use liboxen::command; -use liboxen::config::{AuthConfig, RemoteConfig}; +use liboxen::config::UserConfig; +use liboxen::error; use liboxen::error::OxenError; use liboxen::model::LocalRepository; use liboxen::util; @@ -74,28 +75,47 @@ pub fn list_remotes_verbose() -> Result<(), OxenError> { Ok(()) } -pub fn set_host_global(host: &str) -> Result<(), OxenError> { - let mut remote_config = RemoteConfig::new()?; - remote_config.host = String::from(host); - remote_config.save_default()?; - - if let Ok(mut auth_config) = AuthConfig::default() { - auth_config.host = String::from(host); - auth_config.save_default()?; +pub fn set_auth_token(token: &str) -> Result<(), OxenError> { + if let Ok(mut config) = UserConfig::default() { + config.token = Some(String::from(token)); + config.save_default()?; + println!("Authentication token set."); + } else { + eprintln!("{}", error::EMAIL_AND_NAME_NOT_FOUND); } - println!("Global host set to {}", host); + Ok(()) +} + +pub fn set_user_name(name: &str) -> Result<(), OxenError> { + if let Ok(mut config) = UserConfig::default() { + config.name = String::from(name); + config.save_default()?; + } else { + // Create for first time + let config = UserConfig { + name: String::from(name), + email: String::from(""), + token: None, + }; + config.save_default()?; + } Ok(()) } -pub fn set_auth_token(token: &str) -> Result<(), OxenError> { - if let Ok(mut auth_config) = AuthConfig::default() { - auth_config.user.token = String::from(token); - auth_config.save_default()?; - println!("Authentication token set."); +pub fn set_user_email(email: &str) -> Result<(), OxenError> { + if let Ok(mut config) = UserConfig::default() { + config.email = String::from(email); + config.save_default()?; } else { - eprintln!("Could not find ~/.oxen/auth_config.toml please contact your administrator."); + // Create for first time + let config = UserConfig { + name: String::from(""), + email: String::from(email), + token: None, + }; + config.save_default()?; } Ok(()) diff --git a/src/cli/src/main.rs b/src/cli/src/main.rs index 333c8c183..a4b35dc35 100644 --- a/src/cli/src/main.rs +++ b/src/cli/src/main.rs @@ -25,16 +25,29 @@ fn main() { .arg_required_else_help(true), ) .subcommand( - Command::new("set-default-host") - .about("Sets the default remote host in ~/.oxen/remote_config.toml") - .arg(arg!( "The host ie: hub.oxen.ai or localhost")) - .arg_required_else_help(true), - ) - .subcommand( - Command::new("set-auth-token") - .about("Sets the user authentication token in ~/.oxen/auth_config.toml") - .arg(arg!( "You can get an auth_config.toml file from your admin or generate one on the server yourself.")) - .arg_required_else_help(true), + Command::new("config") + .about("Sets the user configuration in ~/.oxen/user_config.toml") + .arg( + Arg::new("name") + .long("name") + .short('n') + .help("Set the name you want your commits to be saved as.") + .takes_value(true), + ) + .arg( + Arg::new("email") + .long("email") + .short('e') + .help("Set the email you want your commits to be saved as.") + .takes_value(true), + ) + .arg( + Arg::new("auth-token") + .long("auth-token") + .short('t') + .help("Set the authentication token to communicate with a secure oxen-server.") + .takes_value(true), + ) ) .subcommand( Command::new("create-remote") @@ -201,16 +214,6 @@ fn main() { } } } - Some(("set-default-host", sub_matches)) => { - let host = sub_matches.value_of("HOST").expect("required"); - - match dispatch::set_host_global(host) { - Ok(_) => {} - Err(err) => { - eprintln!("{}", err) - } - } - } Some(("remote", sub_matches)) => { if let Some(subcommand) = sub_matches.subcommand() { match subcommand { @@ -245,13 +248,31 @@ fn main() { dispatch::list_remotes().expect("Unable to list remotes."); } } - Some(("set-auth-token", sub_matches)) => { - let token = sub_matches.value_of("TOKEN").expect("required"); + Some(("config", sub_matches)) => { + if let Some(token) = sub_matches.value_of("auth-token") { + match dispatch::set_auth_token(token) { + Ok(_) => {} + Err(err) => { + eprintln!("{}", err) + } + } + } - match dispatch::set_auth_token(token) { - Ok(_) => {} - Err(err) => { - eprintln!("{}", err) + if let Some(name) = sub_matches.value_of("name") { + match dispatch::set_user_name(name) { + Ok(_) => {} + Err(err) => { + eprintln!("{}", err) + } + } + } + + if let Some(email) = sub_matches.value_of("email") { + match dispatch::set_user_email(email) { + Ok(_) => {} + Err(err) => { + eprintln!("{}", err) + } } } } diff --git a/src/lib/src/api/endpoint.rs b/src/lib/src/api/endpoint.rs index ef7b6ce39..fab7f7a40 100644 --- a/src/lib/src/api/endpoint.rs +++ b/src/lib/src/api/endpoint.rs @@ -1,10 +1,7 @@ -use crate::config::{AuthConfig, RemoteConfig}; -use crate::error::REMOTE_CFG_NOT_FOUND; use crate::model::{Remote, RemoteRepository}; const API_NAMESPACE: &str = "/oxen"; -// TODO: Could do all of these with a trait... pub fn url_from_host(host: &str, uri: &str) -> String { format!("http://{}{}{}", host, API_NAMESPACE, uri) } @@ -16,17 +13,3 @@ pub fn url_from_remote(remote: &Remote, uri: &str) -> String { pub fn url_from_repo(remote: &RemoteRepository, uri: &str) -> String { format!("{}{}", remote.url, uri) } - -pub fn repo_url(remote: &RemoteRepository) -> String { - let cfg = RemoteConfig::default().expect(REMOTE_CFG_NOT_FOUND); - let uri = format!("/oxen/repositories/{}", remote.name); - url_from_remote_config(&cfg, &uri) -} - -pub fn url_from_auth_config(config: &AuthConfig, uri: &str) -> String { - format!("http://{}{}{}", config.host, API_NAMESPACE, uri) -} - -pub fn url_from_remote_config(config: &RemoteConfig, uri: &str) -> String { - format!("http://{}{}{}", config.host, API_NAMESPACE, uri) -} diff --git a/src/lib/src/api/remote/branches.rs b/src/lib/src/api/remote/branches.rs index 5de7d86e8..87dfb706b 100644 --- a/src/lib/src/api/remote/branches.rs +++ b/src/lib/src/api/remote/branches.rs @@ -1,5 +1,5 @@ use crate::api; -use crate::config::{AuthConfig, HTTPConfig}; +use crate::config::UserConfig; use crate::error::OxenError; use crate::model::{Branch, RemoteRepository}; use crate::view::{BranchResponse, ListBranchesResponse, StatusMessage}; @@ -10,7 +10,7 @@ pub fn get_by_name( repository: &RemoteRepository, branch_name: &str, ) -> Result, OxenError> { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let uri = format!("/branches/{}", branch_name); let url = api::endpoint::url_from_repo(repository, &uri); @@ -19,7 +19,7 @@ pub fn get_by_name( .get(url) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .send() { @@ -44,7 +44,7 @@ pub fn get_by_name( } pub fn create_or_get(repository: &RemoteRepository, name: &str) -> Result { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let url = api::endpoint::url_from_repo(repository, "/branches"); log::debug!("create_or_get {}", url); @@ -56,7 +56,7 @@ pub fn create_or_get(repository: &RemoteRepository, name: &str) -> Result Result Result, OxenError> { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let url = api::endpoint::url_from_repo(repository, "/branches"); let client = reqwest::blocking::Client::new(); @@ -88,7 +88,7 @@ pub fn list(repository: &RemoteRepository) -> Result, OxenError> { .get(url) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .send() { @@ -116,7 +116,7 @@ pub fn delete( repository: &RemoteRepository, branch_name: &str, ) -> Result { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let client = reqwest::blocking::Client::new(); let uri = format!("/branches/{}", branch_name); let url = api::endpoint::url_from_repo(repository, &uri); @@ -125,7 +125,7 @@ pub fn delete( .delete(url) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .send() { diff --git a/src/lib/src/api/remote/commits.rs b/src/lib/src/api/remote/commits.rs index fcf22f73c..15d6751b4 100644 --- a/src/lib/src/api/remote/commits.rs +++ b/src/lib/src/api/remote/commits.rs @@ -1,5 +1,5 @@ use crate::api; -use crate::config::{AuthConfig, HTTPConfig}; +use crate::config::UserConfig; use crate::constants::HISTORY_DIR; use crate::error::OxenError; use crate::model::{Commit, LocalRepository, RemoteRepository}; @@ -23,7 +23,7 @@ pub fn get_by_id( repository: &RemoteRepository, commit_id: &str, ) -> Result, OxenError> { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let uri = format!("/commits/{}", commit_id); let url = api::endpoint::url_from_repo(repository, &uri); log::debug!("remote::commits::get_by_id {}", url); @@ -33,7 +33,7 @@ pub fn get_by_id( .get(url) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .send() { @@ -61,7 +61,7 @@ pub fn commit_is_synced( commit_id: &str, num_entries: usize, ) -> Result { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let uri = format!("/commits/{}/is_synced?size={}", commit_id, num_entries); let url = api::endpoint::url_from_repo(remote_repo, &uri); log::debug!("commit_is_synced checking URL: {}", url); @@ -70,7 +70,7 @@ pub fn commit_is_synced( .get(url) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .send() { @@ -94,7 +94,7 @@ pub fn download_commit_db_by_id( remote_repo: &RemoteRepository, commit_id: &str, ) -> Result<(), OxenError> { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let uri = format!("/commits/{}/commit_db", commit_id); let url = api::endpoint::url_from_repo(remote_repo, &uri); @@ -103,7 +103,7 @@ pub fn download_commit_db_by_id( .get(url) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .send() { @@ -124,7 +124,7 @@ pub fn get_remote_parent( remote_repo: &RemoteRepository, commit_id: &str, ) -> Result, OxenError> { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let uri = format!("/commits/{}/parents", commit_id); let url = api::endpoint::url_from_repo(remote_repo, &uri); let client = reqwest::blocking::Client::new(); @@ -132,7 +132,7 @@ pub fn get_remote_parent( .get(url) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .send() { @@ -188,7 +188,7 @@ fn create_commit_obj_on_server( branch_name: &str, commit: &Commit, ) -> Result { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let client = reqwest::blocking::Client::new(); let uri = format!("/branches/{}/commits", branch_name); @@ -201,7 +201,7 @@ fn create_commit_obj_on_server( .body(reqwest::blocking::Body::from(body)) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .send() { @@ -229,7 +229,7 @@ pub fn post_tarball_to_server( buffer: &[u8], upload_progress: &Arc, ) -> Result { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let uri = format!("/commits/{}", commit.id); let url = api::endpoint::url_from_repo(remote_repo, &uri); @@ -250,7 +250,7 @@ pub fn post_tarball_to_server( .body(reqwest::blocking::Body::new(upload_source)) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .send() { @@ -276,7 +276,6 @@ pub fn post_tarball_to_server( mod tests { use crate::api; use crate::command; - use crate::config::AuthConfig; use crate::constants; use crate::error::OxenError; use crate::index::CommitEntryReader; @@ -331,12 +330,11 @@ mod tests { command::set_remote(&mut local_repo, constants::DEFAULT_REMOTE_NAME, &remote)?; // Create Remote - let config = AuthConfig::default()?; let remote_repo = command::create_remote( &local_repo, constants::DEFAULT_NAMESPACE, &local_repo.dirname(), - &config.host, + test::TEST_HOST, )?; // Push it diff --git a/src/lib/src/api/remote/entries.rs b/src/lib/src/api/remote/entries.rs index d051c403e..467c405c3 100644 --- a/src/lib/src/api/remote/entries.rs +++ b/src/lib/src/api/remote/entries.rs @@ -1,5 +1,5 @@ use crate::api; -use crate::config::{AuthConfig, HTTPConfig}; +use crate::config::UserConfig; use crate::error::OxenError; use crate::model::{CommitEntry, LocalRepository, RemoteEntry, RemoteRepository}; use crate::util; @@ -23,7 +23,7 @@ pub fn create( remote_repo: &RemoteRepository, entry: &CommitEntry, ) -> Result { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let fullpath = util::fs::version_path(local_repo, entry); log::debug!("Creating remote entry: {:?} -> {:?}", entry.path, fullpath); @@ -41,7 +41,7 @@ pub fn create( .body(file) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .send() { @@ -88,7 +88,7 @@ pub fn list_page( page_num: usize, page_size: usize, ) -> Result { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let uri = format!( "/commits/{}/entries?page_num={}&page_size={}", commit_id, page_num, page_size @@ -99,7 +99,7 @@ pub fn list_page( .get(&url) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .send() { @@ -127,7 +127,7 @@ pub fn download_entries( page_num: &usize, page_size: &usize, ) -> Result<(), OxenError> { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let uri = format!( "/commits/{}/download_entries?page_num={}&page_size={}", commit_id, page_num, page_size @@ -138,7 +138,7 @@ pub fn download_entries( .get(&url) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .send() { @@ -168,7 +168,7 @@ pub fn download_content_ids( content_ids: &[String], download_progress: &Arc, ) -> Result<(), OxenError> { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let uri = format!("/commits/{}/download_content_ids", commit_id); let mut encoder = GzEncoder::new(Vec::new(), Compression::default()); @@ -184,7 +184,7 @@ pub fn download_content_ids( .post(&url) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .body(body); @@ -210,7 +210,7 @@ pub fn download_entry( entry: &CommitEntry, ) -> Result { let remote = repository.remote().ok_or_else(OxenError::remote_not_set)?; - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let fpath = repository.path.join(&entry.path); log::debug!("download_remote_entry entry {:?}", entry.path); @@ -226,7 +226,7 @@ pub fn download_entry( .get(&url) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .send()?; diff --git a/src/lib/src/api/remote/repositories.rs b/src/lib/src/api/remote/repositories.rs index 439c57a9c..16b641f96 100644 --- a/src/lib/src/api/remote/repositories.rs +++ b/src/lib/src/api/remote/repositories.rs @@ -1,6 +1,6 @@ use crate::api; use crate::command; -use crate::config::{AuthConfig, HTTPConfig}; +use crate::config::UserConfig; use crate::constants; use crate::error::OxenError; use crate::model::{LocalRepository, RemoteRepository, RepositoryNew}; @@ -29,14 +29,14 @@ pub fn get_by_remote_url(url: &str) -> Result, OxenErro } pub fn get_by_namespaced_url(url: &str) -> Result, OxenError> { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let client = reqwest::blocking::Client::new(); log::debug!("api::remote::repositories::get_by_url({})", url); if let Ok(res) = client .get(url) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .send() { @@ -77,7 +77,7 @@ pub fn create( name: &str, host: &str, ) -> Result { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let uri = format!("/{}", constants::DEFAULT_NAMESPACE); let url = api::endpoint::url_from_host(host, &uri); let repo_url = format!("{}/{}", url, name); @@ -90,7 +90,7 @@ pub fn create( .json(¶ms) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .send() { @@ -114,14 +114,14 @@ pub fn create( } pub fn delete(repository: &RemoteRepository) -> Result { - let config = AuthConfig::default()?; + let config = UserConfig::default()?; let client = reqwest::blocking::Client::new(); log::debug!("Deleting repository: {}", repository.url); if let Ok(res) = client .delete(repository.url.clone()) .header( reqwest::header::AUTHORIZATION, - format!("Bearer {}", config.auth_token()), + format!("Bearer {}", config.auth_token()?), ) .send() { @@ -146,7 +146,6 @@ pub fn delete(repository: &RemoteRepository) -> Result mod tests { use crate::api; - use crate::config::{AuthConfig, HTTPConfig}; use crate::constants; use crate::error::OxenError; use crate::test; @@ -154,15 +153,10 @@ mod tests { #[test] fn test_create_remote_repository() -> Result<(), OxenError> { test::run_empty_local_repo_test(|local_repo| { - let auth_config = AuthConfig::default()?; let namespace = constants::DEFAULT_NAMESPACE; let name = local_repo.dirname(); - let repository = api::remote::repositories::create( - &local_repo, - namespace, - &name, - auth_config.host(), - )?; + let repository = + api::remote::repositories::create(&local_repo, namespace, &name, test::TEST_HOST)?; println!("got repository: {:?}", repository); assert_eq!(repository.name, name); @@ -175,15 +169,10 @@ mod tests { #[test] fn test_get_by_name() -> Result<(), OxenError> { test::run_empty_local_repo_test(|local_repo| { - let auth_config = AuthConfig::default()?; let namespace = constants::DEFAULT_NAMESPACE; let name = local_repo.dirname(); - let repository = api::remote::repositories::create( - &local_repo, - namespace, - &name, - auth_config.host(), - )?; + let repository = + api::remote::repositories::create(&local_repo, namespace, &name, test::TEST_HOST)?; let url_repo = api::remote::repositories::get_by_remote_url(&repository.url)?.unwrap(); assert_eq!(repository.namespace, url_repo.namespace); @@ -199,15 +188,10 @@ mod tests { #[test] fn test_delete_repository() -> Result<(), OxenError> { test::run_empty_local_repo_test(|local_repo| { - let auth_config = AuthConfig::default()?; let namespace = constants::DEFAULT_NAMESPACE; let name = local_repo.dirname(); - let repository = api::remote::repositories::create( - &local_repo, - namespace, - &name, - auth_config.host(), - )?; + let repository = + api::remote::repositories::create(&local_repo, namespace, &name, test::TEST_HOST)?; // delete api::remote::repositories::delete(&repository)?; diff --git a/src/lib/src/command.rs b/src/lib/src/command.rs index 6646e88c4..90e26674d 100644 --- a/src/lib/src/command.rs +++ b/src/lib/src/command.rs @@ -24,7 +24,10 @@ use std::str; /// # use liboxen::command; /// # use liboxen::error::OxenError; /// # use std::path::Path; +/// # use liboxen::test; +/// /// # fn main() -> Result<(), OxenError> { +/// # test::init_test_env(); /// /// let base_dir = Path::new("/tmp/repo_dir_init"); /// command::init(base_dir)?; @@ -77,7 +80,10 @@ fn p_init(path: &Path) -> Result { /// use liboxen::command; /// # use liboxen::error::OxenError; /// # use std::path::Path; +/// # use liboxen::test; +/// /// # fn main() -> Result<(), OxenError> { +/// # test::init_test_env(); /// /// let base_dir = Path::new("/tmp/repo_dir_status_1"); /// // Initialize empty repo @@ -97,7 +103,10 @@ fn p_init(path: &Path) -> Result { /// use liboxen::util; /// # use liboxen::error::OxenError; /// # use std::path::Path; +/// # use liboxen::test; +/// /// # fn main() -> Result<(), OxenError> { +/// # test::init_test_env(); /// /// let base_dir = Path::new("/tmp/repo_dir_status_2"); /// // Initialize empty repo @@ -132,7 +141,10 @@ pub fn status(repository: &LocalRepository) -> Result { /// use liboxen::util; /// # use liboxen::error::OxenError; /// # use std::path::Path; +/// # use liboxen::test; +/// /// # fn main() -> Result<(), OxenError> { +/// # test::init_test_env(); /// /// // Initialize the repository /// let base_dir = Path::new("/tmp/repo_dir_add"); @@ -162,9 +174,11 @@ pub fn add>(repo: &LocalRepository, path: P) -> Result<(), OxenEr /// ``` /// use liboxen::command; /// use liboxen::util; +/// # use liboxen::test; /// # use liboxen::error::OxenError; /// # use std::path::Path; /// # fn main() -> Result<(), OxenError> { +/// # test::init_test_env(); /// /// // Initialize the repository /// let base_dir = Path::new("/tmp/repo_dir_commit"); @@ -218,9 +232,11 @@ fn p_commit( /// /// ``` /// use liboxen::command; +/// # use liboxen::test; /// # use liboxen::error::OxenError; /// # use std::path::Path; /// # fn main() -> Result<(), OxenError> { +/// # test::init_test_env(); /// /// // Initialize the repository /// let base_dir = Path::new("/tmp/repo_dir_log"); @@ -519,12 +535,13 @@ pub fn remove_remote(repo: &mut LocalRepository, name: &str) -> Result<(), OxenE /// /// ``` /// # use liboxen::api; +/// # use liboxen::test; /// use liboxen::command; /// use liboxen::util; /// # use liboxen::error::OxenError; /// # use std::path::Path; /// # fn main() -> Result<(), OxenError> { -/// +/// # test::init_test_env(); /// // Initialize the repository /// let base_dir = Path::new("/tmp/repo_dir_push"); /// let mut repo = command::init(base_dir)?; @@ -574,7 +591,11 @@ pub fn push_remote_branch( /// Clone a repo from a url to a directory pub fn clone(url: &str, dst: &Path) -> Result { - LocalRepository::clone_remote(url, dst)?.ok_or_else(|| OxenError::remote_repo_not_found(url)) + match LocalRepository::clone_remote(url, dst) { + Ok(Some(repo)) => Ok(repo), + Ok(None) => Err(OxenError::remote_repo_not_found(url)), + Err(err) => Err(err), + } } /// Pull a repository's data from origin/main diff --git a/src/lib/src/config.rs b/src/lib/src/config.rs index e829949bb..f6a81d564 100644 --- a/src/lib/src/config.rs +++ b/src/lib/src/config.rs @@ -1,8 +1,5 @@ -pub mod auth_config; pub mod endpoint; -pub mod http_config; -pub mod remote_config; +pub mod user_config; -pub use crate::config::auth_config::AuthConfig; -pub use crate::config::http_config::HTTPConfig; -pub use crate::config::remote_config::RemoteConfig; +pub use crate::config::user_config::UserConfig; +pub use crate::config::user_config::USER_CONFIG_FILENAME; diff --git a/src/lib/src/config/auth_config.rs b/src/lib/src/config/auth_config.rs deleted file mode 100644 index 1a93ebe57..000000000 --- a/src/lib/src/config/auth_config.rs +++ /dev/null @@ -1,124 +0,0 @@ -use crate::config::HTTPConfig; -use crate::error::OxenError; -use crate::model::User; -use crate::util; -use serde::{Deserialize, Serialize}; -use std::fs; -use std::path::{Path, PathBuf}; - -pub const AUTH_CONFIG_FILENAME: &str = "auth_config.toml"; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct AuthConfig { - pub host: String, - pub user: User, -} - -impl PartialEq for AuthConfig { - fn eq(&self, other: &Self) -> bool { - self.host == other.host && self.user == other.user - } -} - -impl Eq for AuthConfig {} - -impl<'a> HTTPConfig<'a> for AuthConfig { - fn host(&'a self) -> &'a str { - &self.host - } - - fn auth_token(&'a self) -> &'a str { - &self.user.token - } -} - -impl AuthConfig { - pub fn new(path: &Path) -> AuthConfig { - let contents = util::fs::read_from_path(path).unwrap(); - toml::from_str(&contents).unwrap() - } - - pub fn default() -> Result { - let err = String::from( - "~/.oxen/auth_config.toml not found, acquire the proper file from your administrator.", - ); - if let Some(home_dir) = dirs::home_dir() { - let oxen_dir = util::fs::oxen_hidden_dir(&home_dir); - let mut config_file = oxen_dir.join(Path::new(AUTH_CONFIG_FILENAME)); - if std::env::var("TEST").is_ok() { - config_file = PathBuf::from("data/test/config/auth_config.toml"); - } - if config_file.exists() { - Ok(AuthConfig::new(&config_file)) - } else { - Err(OxenError::Basic(err)) - } - } else { - Err(OxenError::Basic(err)) - } - } - - pub fn save_default(&self) -> Result<(), OxenError> { - if let Some(home_dir) = dirs::home_dir() { - let oxen_dir = util::fs::oxen_hidden_dir(&home_dir); - - fs::create_dir_all(&oxen_dir)?; - let config_file = oxen_dir.join(Path::new(AUTH_CONFIG_FILENAME)); - log::debug!("Saving config to {:?}", config_file); - self.save(&config_file) - } else { - Err(OxenError::basic_str( - "AuthConfig::save_default() Could not find home dir", - )) - } - } - - pub fn save(&self, path: &Path) -> Result<(), OxenError> { - let toml = toml::to_string(&self)?; - util::fs::write_to_path(path, &toml); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use crate::config::{AuthConfig, HTTPConfig, RemoteConfig}; - use crate::error::OxenError; - use crate::model::User; - use crate::test; - use std::path::Path; - - #[test] - fn test_read() { - let config = AuthConfig::new(test::auth_cfg_file()); - assert!(!config.host().is_empty()); - assert!(!config.user.name.is_empty()); - } - - #[test] - fn test_save() -> Result<(), OxenError> { - let final_path = Path::new("/tmp/test_save_auth_config.toml"); - let orig_config = AuthConfig::new(test::auth_cfg_file()); - - orig_config.save(final_path)?; - - let config = AuthConfig::new(final_path); - assert_eq!(config.host, orig_config.host); - assert!(!config.user.name.is_empty()); - Ok(()) - } - - #[test] - fn test_remote_to_auth_save() -> Result<(), OxenError> { - let final_path = Path::new("/tmp/test_remote_to_auth_save_auth_config.toml"); - let orig_config = RemoteConfig::from(test::remote_cfg_file()); - let user = User::dummy(); - let auth_config = orig_config.to_auth(&user); - auth_config.save(final_path)?; - - let config = AuthConfig::new(final_path); - assert_eq!(config.host, orig_config.host); - assert_eq!(config.user.name, user.name); - Ok(()) - } -} diff --git a/src/lib/src/config/http_config.rs b/src/lib/src/config/http_config.rs deleted file mode 100644 index cf0e8f121..000000000 --- a/src/lib/src/config/http_config.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub trait HTTPConfig<'a> { - fn host(&'a self) -> &'a str; - fn auth_token(&'a self) -> &'a str; -} diff --git a/src/lib/src/config/remote_config.rs b/src/lib/src/config/remote_config.rs deleted file mode 100644 index a1e74d39a..000000000 --- a/src/lib/src/config/remote_config.rs +++ /dev/null @@ -1,151 +0,0 @@ -use crate::config::endpoint; -use crate::config::AuthConfig; -use crate::error::OxenError; -use crate::model::User; -use crate::util; - -use serde::{Deserialize, Serialize}; -use std::fs; -use std::path::{Path, PathBuf}; - -// Default Hosts -const DEFAULT_ORIGIN_HOST: &str = "hub.oxen.ai"; -const DEFAULT_ORIGIN_PORT: &str = ""; -const REMOTE_CONFIG_FILENAME: &str = "remote_config.toml"; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct RemoteConfig { - pub host: String, -} - -impl PartialEq for RemoteConfig { - fn eq(&self, other: &Self) -> bool { - self.host == other.host - } -} - -impl Eq for RemoteConfig {} - -impl RemoteConfig { - /// Creates a new remote config if it doesn't exist in ~/.oxen/remote_config.toml - pub fn new() -> Result { - if let Some(home_dir) = dirs::home_dir() { - let oxen_dir = util::fs::oxen_hidden_dir(&home_dir); - - fs::create_dir_all(&oxen_dir)?; - let oxen_config = oxen_dir.join(Path::new(REMOTE_CONFIG_FILENAME)); - let config_str = format!("host = \"{}\"", RemoteConfig::endpoint()); - - util::fs::write_to_path(&oxen_config, &config_str); - Ok(RemoteConfig { - host: RemoteConfig::endpoint(), - }) - } else { - Err(OxenError::basic_str( - "RemoteConfig::new() Could not find home dir", - )) - } - } - - /// Tries to load a remote config from the default location ~/.oxen/remote_config.toml - pub fn default() -> Result { - let err = String::from( - "Remote configuration not found, run `oxen set-remote --global ` to configure.", - ); - if let Some(home_dir) = dirs::home_dir() { - let oxen_dir = util::fs::oxen_hidden_dir(&home_dir); - let mut config_file = oxen_dir.join(Path::new(REMOTE_CONFIG_FILENAME)); - if std::env::var("TEST").is_ok() { - config_file = PathBuf::from("data/test/config/remote_config.toml"); - } - - if config_file.exists() { - Ok(RemoteConfig::from(&config_file)) - } else { - Err(OxenError::Basic(err)) - } - } else { - Err(OxenError::Basic(err)) - } - } - - pub fn endpoint() -> String { - if DEFAULT_ORIGIN_PORT.is_empty() { - String::from(DEFAULT_ORIGIN_HOST) - } else { - return format!("{}:{}", DEFAULT_ORIGIN_HOST, DEFAULT_ORIGIN_PORT); - } - } - - pub fn to_auth(&self, user: &User) -> AuthConfig { - AuthConfig { - host: self.host.clone(), - user: user.clone(), - } - } - - pub fn save_default(&self) -> Result<(), OxenError> { - if let Some(home_dir) = dirs::home_dir() { - let hidden_dir = util::fs::oxen_hidden_dir(&home_dir); - fs::create_dir_all(&hidden_dir)?; - let config_file = hidden_dir.join(Path::new(REMOTE_CONFIG_FILENAME)); - log::debug!("Saving config to {:?}", config_file); - self.save(&config_file) - } else { - Err(OxenError::basic_str( - "RemoteConfig::save_default() Could not find home dir", - )) - } - } - - pub fn save(&self, path: &Path) -> Result<(), OxenError> { - let toml = toml::to_string(&self)?; - util::fs::write_to_path(path, &toml); - Ok(()) - } - - pub fn from(path: &Path) -> RemoteConfig { - let contents = util::fs::read_from_path(path).unwrap(); - toml::from_str(&contents).unwrap() - } - - pub fn http_endpoint(&self) -> String { - endpoint::http_endpoint(&self.host) - } -} - -#[cfg(test)] -mod tests { - pub const DEFAULT_HOST: &str = "0.0.0.0:3000"; - use crate::config::RemoteConfig; - use crate::error::OxenError; - use crate::test; - - use std::path::Path; - - #[test] - fn test_read() { - let config = RemoteConfig::from(test::remote_cfg_file()); - assert_eq!( - config.http_endpoint(), - format!("http://{}/api/v1", DEFAULT_HOST) - ); - } - - #[test] - fn test_save() -> Result<(), OxenError> { - let config = RemoteConfig::from(test::remote_cfg_file()); - assert_eq!( - config.http_endpoint(), - format!("http://{}/api/v1", DEFAULT_HOST) - ); - - let export_path = Path::new("/tmp/remote_config.toml"); - config.save(export_path)?; - - let new_config = RemoteConfig::from(export_path); - assert_eq!(config.http_endpoint(), new_config.http_endpoint()); - - Ok(()) - } -} diff --git a/src/lib/src/config/user_config.rs b/src/lib/src/config/user_config.rs new file mode 100644 index 000000000..e75976758 --- /dev/null +++ b/src/lib/src/config/user_config.rs @@ -0,0 +1,108 @@ +use crate::error; +use crate::error::OxenError; +use crate::model::User; +use crate::util; +use serde::{Deserialize, Serialize}; +use std::fs; +use std::path::{Path, PathBuf}; + +pub const USER_CONFIG_FILENAME: &str = "user_config.toml"; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct UserConfig { + pub name: String, + pub email: String, + pub token: Option, +} + +impl UserConfig { + pub fn new(path: &Path) -> UserConfig { + let contents = util::fs::read_from_path(path).unwrap(); + toml::from_str(&contents).unwrap() + } + + pub fn from_user(user: &User) -> UserConfig { + UserConfig { + name: user.name.to_owned(), + email: user.email.to_owned(), + token: user.token.to_owned(), + } + } + + pub fn default() -> Result { + if let Some(home_dir) = dirs::home_dir() { + let oxen_dir = util::fs::oxen_hidden_dir(&home_dir); + let mut config_file = oxen_dir.join(Path::new(USER_CONFIG_FILENAME)); + if std::env::var("TEST").is_ok() { + config_file = PathBuf::from("data/test/config/user_config.toml"); + } + if config_file.exists() { + Ok(UserConfig::new(&config_file)) + } else { + Err(OxenError::Basic(String::from( + error::EMAIL_AND_NAME_NOT_FOUND, + ))) + } + } else { + Err(OxenError::Basic(String::from( + error::EMAIL_AND_NAME_NOT_FOUND, + ))) + } + } + + pub fn save_default(&self) -> Result<(), OxenError> { + if let Some(home_dir) = dirs::home_dir() { + let oxen_dir = util::fs::oxen_hidden_dir(&home_dir); + + fs::create_dir_all(&oxen_dir)?; + let config_file = oxen_dir.join(Path::new(USER_CONFIG_FILENAME)); + log::debug!("Saving config to {:?}", config_file); + self.save(&config_file) + } else { + Err(OxenError::basic_str( + "Save user config could not find home dir", + )) + } + } + + pub fn save(&self, path: &Path) -> Result<(), OxenError> { + let toml = toml::to_string(&self)?; + util::fs::write_to_path(path, &toml); + Ok(()) + } + + pub fn auth_token(&self) -> Result { + if let Some(token) = &self.token { + Ok(token.clone()) + } else { + Err(OxenError::auth_token_not_set()) + } + } +} + +#[cfg(test)] +mod tests { + use crate::config::UserConfig; + use crate::error::OxenError; + use crate::test; + use std::path::Path; + + #[test] + fn test_read() { + let config = UserConfig::new(test::user_cfg_file()); + assert!(!config.name.is_empty()); + assert!(!config.email.is_empty()); + } + + #[test] + fn test_save() -> Result<(), OxenError> { + let final_path = Path::new("/tmp/test_save_config.toml"); + let orig_config = UserConfig::new(test::user_cfg_file()); + + orig_config.save(final_path)?; + + let config = UserConfig::new(final_path); + assert!(!config.name.is_empty()); + Ok(()) + } +} diff --git a/src/lib/src/error.rs b/src/lib/src/error.rs index dc5d72b39..0aeeaa0b7 100644 --- a/src/lib/src/error.rs +++ b/src/lib/src/error.rs @@ -3,8 +3,11 @@ use std::fmt; use std::io; use std::path::Path; -pub const REMOTE_CFG_NOT_FOUND: &str = - "Remote configuration not found, run `oxen set-default-host ` to configure."; +pub const EMAIL_AND_NAME_NOT_FOUND: &str = + "Err: oxen not configured, set email and name with:\n\noxen config --name --email \n"; + +pub const AUTH_TOKEN_NOT_FOUND: &str = + "Err: oxen authentication token not found, obtain one from your administrator and configure with:\n\noxen config --auth-token \n"; #[derive(Debug)] pub enum OxenError { @@ -26,25 +29,29 @@ impl OxenError { OxenError::Basic(String::from(s.as_ref())) } - pub fn remote_cfg_not_found() -> OxenError { - OxenError::basic_str(REMOTE_CFG_NOT_FOUND) - } - pub fn local_repo_not_found() -> OxenError { OxenError::basic_str("No oxen repository exists, looking for directory: .oxen") } + pub fn email_and_name_not_set() -> OxenError { + OxenError::basic_str(EMAIL_AND_NAME_NOT_FOUND) + } + + pub fn auth_token_not_set() -> OxenError { + OxenError::basic_str(AUTH_TOKEN_NOT_FOUND) + } + pub fn remote_repo_not_found>(url: T) -> OxenError { let err = format!("Remote repository does not exist {}", url.as_ref()); OxenError::basic_str(&err) } pub fn head_not_found() -> OxenError { - OxenError::basic_str("Error: HEAD not found") + OxenError::basic_str("Err: HEAD not found") } pub fn remote_not_set() -> OxenError { - OxenError::basic_str("Remote not set. `oxen remote add `") + OxenError::basic_str("Err: Remote not set, you can set a remote by running:\n\noxen remote add \n") } pub fn remote_branch_not_found>(name: T) -> OxenError { diff --git a/src/lib/src/index/commit_writer.rs b/src/lib/src/index/commit_writer.rs index 9fd335a73..8dcbc721b 100644 --- a/src/lib/src/index/commit_writer.rs +++ b/src/lib/src/index/commit_writer.rs @@ -1,4 +1,4 @@ -use crate::config::AuthConfig; +use crate::config::UserConfig; use crate::constants::{COMMITS_DB, MERGE_HEAD_FILE, ORIG_HEAD_FILE}; use crate::db; use crate::error::OxenError; @@ -40,7 +40,7 @@ impl CommitWriter { } fn create_commit_data(&self, message: &str) -> Result { - let cfg = AuthConfig::default()?; + let cfg = UserConfig::default()?; let timestamp = Local::now(); let ref_reader = RefReader::new(&self.repository)?; // Commit @@ -60,7 +60,7 @@ impl CommitWriter { Ok(NewCommit { parent_ids: vec![parent_id], message: String::from(message), - author: cfg.user.name, + author: cfg.name, date: timestamp, timestamp: timestamp.timestamp_nanos(), }) @@ -72,7 +72,7 @@ impl CommitWriter { Ok(NewCommit { parent_ids: vec![], message: String::from(message), - author: cfg.user.name, + author: cfg.name, date: Local::now(), timestamp: timestamp.timestamp_nanos(), }) @@ -82,7 +82,7 @@ impl CommitWriter { // Reads commit ids from merge commit files then removes them fn create_merge_commit(&self, message: &str) -> Result { - let cfg = AuthConfig::default()?; + let cfg = UserConfig::default()?; let timestamp = Local::now(); let hidden_dir = util::fs::oxen_hidden_dir(&self.repository.path); let merge_head_path = hidden_dir.join(MERGE_HEAD_FILE); @@ -99,7 +99,7 @@ impl CommitWriter { Ok(NewCommit { parent_ids: vec![merge_commit_id, head_commit_id], message: String::from(message), - author: cfg.user.name, + author: cfg.name, date: timestamp, timestamp: timestamp.timestamp_nanos(), }) @@ -173,12 +173,12 @@ impl CommitWriter { parent_ids: Vec, message: &str, ) -> Result { - let cfg = AuthConfig::default()?; + let cfg = UserConfig::default()?; let timestamp = Local::now(); let commit = NewCommit { parent_ids, message: String::from(message), - author: cfg.user.name, + author: cfg.name, date: timestamp, timestamp: timestamp.timestamp_nanos(), }; diff --git a/src/lib/src/index/indexer.rs b/src/lib/src/index/indexer.rs index d92a17229..060908b45 100644 --- a/src/lib/src/index/indexer.rs +++ b/src/lib/src/index/indexer.rs @@ -44,7 +44,8 @@ impl Indexer { // Repo should be created before this step let remote_repo = match api::remote::repositories::get_by_remote_url(&remote.url) { Ok(Some(repo)) => repo, - _ => return Err(OxenError::remote_repo_not_found(&remote.url)), + Ok(None) => return Err(OxenError::remote_repo_not_found(&remote.url)), + Err(err) => return Err(err), }; // Create the branch, fail silently for now because first one might fail if no HEAD on the server @@ -305,7 +306,8 @@ impl Indexer { let remote_repo = match api::remote::repositories::get_by_remote_url(&remote.url) { Ok(Some(repo)) => repo, - _ => return Err(OxenError::remote_repo_not_found(&remote.url)), + Ok(None) => return Err(OxenError::remote_repo_not_found(&remote.url)), + Err(err) => return Err(err), }; self.pull_all_commit_objects_then(&remote_repo, rb, |commit| { @@ -587,7 +589,6 @@ impl Indexer { mod tests { use crate::api; use crate::command; - use crate::config::AuthConfig; use crate::constants; use crate::error::OxenError; use crate::index::Indexer; @@ -605,9 +606,12 @@ mod tests { let remote = test::repo_url_from(&name); command::set_remote(&mut repo, constants::DEFAULT_REMOTE_NAME, &remote)?; - let config = AuthConfig::default()?; - let remote_repo = - command::create_remote(&repo, constants::DEFAULT_NAMESPACE, &name, &config.host)?; + let remote_repo = command::create_remote( + &repo, + constants::DEFAULT_NAMESPACE, + &name, + test::TEST_HOST, + )?; command::push(&repo)?; @@ -658,9 +662,12 @@ mod tests { command::commit(&repo, "Adding testing data")?; // Create remote - let config = AuthConfig::default()?; - let remote_repo = - command::create_remote(&repo, constants::DEFAULT_NAMESPACE, &name, &config.host)?; + let remote_repo = command::create_remote( + &repo, + constants::DEFAULT_NAMESPACE, + &name, + test::TEST_HOST, + )?; // Push it command::push(&repo)?; diff --git a/src/lib/src/index/ref_reader.rs b/src/lib/src/index/ref_reader.rs index c88231b4b..f9b23f69b 100644 --- a/src/lib/src/index/ref_reader.rs +++ b/src/lib/src/index/ref_reader.rs @@ -77,20 +77,30 @@ impl RefReader { pub fn head_commit_id(&self) -> Result, OxenError> { let head_ref = self.read_head_ref()?; + log::debug!("Got HEAD ref {:?}", head_ref); if let Some(head_ref) = head_ref { if let Some(commit_id) = self.get_commit_id_for_branch(&head_ref)? { - log::debug!("RefReader::head_commit_id got commit id {}", commit_id); + log::debug!( + "RefReader::head_commit_id got commit id for branch {}", + commit_id + ); Ok(Some(commit_id)) } else { + log::debug!( + "RefReader::head_commit_id looking for head_ref {}", + head_ref + ); let commit_reader = CommitReader::new(&self.repository)?; if commit_reader.commit_id_exists(&head_ref) { Ok(Some(head_ref)) } else { + log::debug!("Commit id does not exist {:?}", head_ref); Ok(None) } } } else { + log::debug!("Head ref is none {:?}", head_ref); Ok(None) } } @@ -98,9 +108,11 @@ impl RefReader { pub fn read_head_ref(&self) -> Result, OxenError> { // Should probably lock before reading... // but not a lot of parallel action going on here + log::debug!("Looking for HEAD at {:?}", self.head_file); if self.head_file.exists() { Ok(Some(util::fs::read_from_path(&self.head_file)?)) } else { + log::debug!("HEAD not found at {:?}", self.head_file); Ok(None) } } diff --git a/src/lib/src/model.rs b/src/lib/src/model.rs index c7b6fb502..9ba773cbd 100644 --- a/src/lib/src/model.rs +++ b/src/lib/src/model.rs @@ -29,7 +29,7 @@ pub use crate::model::entry::remote_entry::RemoteEntry; pub use crate::model::entry::staged_entry::{StagedEntry, StagedEntryStatus}; pub use crate::model::entry::ContentHashable; -pub use crate::model::user::{NewUser, User, UserResponse}; +pub use crate::model::user::{NewUser, User}; pub use crate::model::staged_data::{StagedData, StagedDirStats}; diff --git a/src/lib/src/model/repository/local_repository.rs b/src/lib/src/model/repository/local_repository.rs index de1e9882b..14eb10f5a 100644 --- a/src/lib/src/model/repository/local_repository.rs +++ b/src/lib/src/model/repository/local_repository.rs @@ -217,7 +217,6 @@ impl LocalRepository { mod tests { use crate::api; use crate::command; - use crate::config::{AuthConfig, HTTPConfig}; use crate::constants; use crate::error::OxenError; use crate::model::{LocalRepository, RepositoryNew}; @@ -271,11 +270,10 @@ mod tests { #[test] fn test_clone_remote() -> Result<(), OxenError> { test::run_empty_local_repo_test(|local_repo| { - let config = AuthConfig::default()?; let namespace = constants::DEFAULT_NAMESPACE; let name = local_repo.dirname(); let remote_repo = - api::remote::repositories::create(&local_repo, namespace, &name, config.host())?; + api::remote::repositories::create(&local_repo, namespace, &name, test::TEST_HOST)?; test::run_empty_dir_test(|dir| { let local_repo = LocalRepository::clone_remote(&remote_repo.url, dir)?.unwrap(); diff --git a/src/lib/src/model/user.rs b/src/lib/src/model/user.rs index 49a4c54fc..d7a4557f3 100644 --- a/src/lib/src/model/user.rs +++ b/src/lib/src/model/user.rs @@ -8,62 +8,7 @@ pub struct NewUser { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct User { - pub id: String, - pub token: String, + pub token: Option, pub email: String, pub name: String, } - -#[derive(Deserialize, Debug)] -pub struct UserResponse { - pub user: User, -} - -impl PartialEq for User { - fn eq(&self, other: &Self) -> bool { - self.id == other.id - && self.token == other.token - && self.email == other.email - && self.name == other.name - } -} - -impl Eq for User {} - -impl User { - pub fn dummy() -> User { - User { - id: String::from("0123456789"), - token: String::from("SUPER_SECRET_TOKEN"), - email: String::from("test@oxen.ai"), - name: String::from("Dummy User"), - } - } -} - -#[cfg(test)] -mod tests { - use crate::error::OxenError; - use crate::model::UserResponse; - - #[test] - fn test_deserialize() -> Result<(), OxenError> { - let data = r#" - { - "user": { - "id": "1234", - "name": "Ox", - "email": "ox@oxen.ai", - "token": "super_secret" - } - } - "#; - let user: UserResponse = serde_json::from_str(data)?; - - assert_eq!("1234", user.user.id); - assert_eq!("Ox", user.user.name); - assert_eq!("ox@oxen.ai", user.user.email); - assert_eq!("super_secret", user.user.token); - Ok(()) - } -} diff --git a/src/lib/src/test.rs b/src/lib/src/test.rs index 841a38767..1af986a78 100644 --- a/src/lib/src/test.rs +++ b/src/lib/src/test.rs @@ -3,7 +3,6 @@ use crate::api; use crate::command; -use crate::config::{AuthConfig, HTTPConfig, RemoteConfig}; use crate::constants; use crate::error::OxenError; use crate::index::{RefWriter, Stager}; @@ -15,12 +14,12 @@ use std::io::prelude::*; use std::path::{Path, PathBuf}; const TEST_RUN_DIR: &str = "data/test/runs"; +pub const TEST_HOST: &str = "0.0.0.0:3000"; pub fn repo_url_from(name: &str) -> String { // Tests always point to localhost - let config = RemoteConfig::from(Path::new("data/test/config/remote_config.toml")); let uri = format!("/{}/{}", constants::DEFAULT_NAMESPACE, name); - api::endpoint::url_from_remote_config(&config, &uri) + api::endpoint::url_from_host(TEST_HOST, &uri) } pub fn init_test_env() { @@ -48,12 +47,11 @@ fn create_empty_dir(base_dir: &str) -> Result { } pub fn create_remote_repo(repo: &LocalRepository) -> Result { - let config = AuthConfig::default()?; command::create_remote( repo, constants::DEFAULT_NAMESPACE, &repo.dirname(), - &config.host, + TEST_HOST, ) } @@ -128,12 +126,10 @@ where let repo_dir = create_repo_dir(TEST_RUN_DIR)?; let local_repo = command::init(&repo_dir)?; - let config = AuthConfig::default()?; let namespace = constants::DEFAULT_NAMESPACE; let name = local_repo.dirname(); - let remote_repo = - api::remote::repositories::create(&local_repo, namespace, &name, config.host())?; + let remote_repo = api::remote::repositories::create(&local_repo, namespace, &name, TEST_HOST)?; // Run test to see if it panic'd let result = std::panic::catch_unwind(|| match test(&local_repo, &remote_repo) { @@ -167,12 +163,9 @@ where // Write all the training data files populate_dir_with_training_data(&repo_dir)?; - let config = AuthConfig::default()?; - let namespace = constants::DEFAULT_NAMESPACE; let name = local_repo.dirname(); - let remote_repo = - api::remote::repositories::create(&local_repo, namespace, &name, config.host())?; + let remote_repo = api::remote::repositories::create(&local_repo, namespace, &name, TEST_HOST)?; println!("Got remote repo: {:?}", remote_repo); // Run test to see if it panic'd @@ -204,10 +197,9 @@ where let name = format!("repo_{}", uuid::Uuid::new_v4()); let path = empty_dir.join(name); let local_repo = command::init(&path)?; - let config = AuthConfig::default()?; let namespace = constants::DEFAULT_NAMESPACE; let name = local_repo.dirname(); - let repo = api::remote::repositories::create(&local_repo, namespace, &name, config.host())?; + let repo = api::remote::repositories::create(&local_repo, namespace, &name, TEST_HOST)?; println!("REMOTE REPO: {:?}", repo); // Run test to see if it panic'd @@ -344,12 +336,8 @@ where Ok(()) } -pub fn remote_cfg_file() -> &'static Path { - Path::new("data/test/config/remote_config.toml") -} - -pub fn auth_cfg_file() -> &'static Path { - Path::new("data/test/config/auth_config.toml") +pub fn user_cfg_file() -> &'static Path { + Path::new("data/test/config/user_config.toml") } pub fn repo_cfg_file() -> &'static Path { diff --git a/src/server/src/auth/access_keys.rs b/src/server/src/auth/access_keys.rs index c539fe88e..82528576f 100644 --- a/src/server/src/auth/access_keys.rs +++ b/src/server/src/auth/access_keys.rs @@ -95,10 +95,9 @@ impl AccessKeyManager { let encoded_claim = serde_json::to_string(&user_claims)?; self.db.put(&token, encoded_claim)?; Ok(User { - id: user_claims.id.to_owned(), name: user_claims.name.to_owned(), email: user_claims.email.to_owned(), - token, + token: Some(token), }) } Err(_) => { @@ -186,7 +185,7 @@ mod tests { email: String::from("ox@oxen.ai"), }; let user = keygen.create(&new_user)?; - assert!(!user.token.is_empty()); + assert!(!user.token.unwrap().is_empty()); Ok(()) }) @@ -201,7 +200,7 @@ mod tests { email: String::from("ox@oxen.ai"), }; let user = keygen.create(&new_user)?; - let fetched_claim = keygen.get_claim(&user.token)?; + let fetched_claim = keygen.get_claim(&user.token.unwrap())?; assert!(fetched_claim.is_some()); let fetched_claim = fetched_claim.unwrap(); assert_eq!(new_user.email, fetched_claim.email); @@ -220,7 +219,7 @@ mod tests { email: String::from("ox@oxen.ai"), }; let user = keygen.create(&new_user)?; - let is_valid = keygen.token_is_valid(&user.token); + let is_valid = keygen.token_is_valid(&user.token.unwrap()); assert!(is_valid); Ok(()) }) diff --git a/src/server/src/main.rs b/src/server/src/main.rs index 578c0c251..d0b3574a2 100644 --- a/src/server/src/main.rs +++ b/src/server/src/main.rs @@ -1,4 +1,4 @@ -use liboxen::config::RemoteConfig; +use liboxen::config::UserConfig; use liboxen::model::NewUser; pub mod app_data; @@ -22,7 +22,7 @@ use std::path::Path; const VERSION: &str = env!("CARGO_PKG_VERSION"); const ADD_USER_USAGE: &str = - "Usage: `oxen-server add-user -e -n -o auth_config.toml`"; + "Usage: `oxen-server add-user -e -n -o user_config.toml`"; const START_SERVER_USAGE: &str = "Usage: `oxen-server start -h 0.0.0.0 -p 3000`"; @@ -89,7 +89,7 @@ async fn main() -> std::io::Result<()> { Arg::new("output") .long("output") .short('o') - .default_value("auth_config.toml") + .default_value("user_config.toml") .default_missing_value("always") .help("Where to write the output config file to give to the user") .takes_value(true), @@ -244,20 +244,18 @@ async fn main() -> std::io::Result<()> { }; match keygen.create(&new_user) { Ok(user) => { - let remote_config = RemoteConfig::default() - .expect(liboxen::error::REMOTE_CFG_NOT_FOUND); - let auth_config = remote_config.to_auth(&user); - match auth_config.save(Path::new(output)) { + let cfg = UserConfig::from_user(&user); + match cfg.save(Path::new(output)) { Ok(_) => { - println!("Saved config to: {}\n\nTo give user access have them put the file in home directory at ~/.oxen/auth_config.toml", output) + println!("User access token created in {}:\n\n{}\n\nTo give user access have them run the command `oxen set-auth-token `", output, user.token.unwrap()) } - Err(err) => { - eprintln!("Error saving config: {}", err) + Err(error) => { + eprintln!("Err: {:?}", error); } } } Err(err) => { - eprintln!("Error adding user: {}", err) + eprintln!("Err: {}", err) } } } diff --git a/src/server/src/test.rs b/src/server/src/test.rs index aa0a8bed1..7f6dbfa36 100644 --- a/src/server/src/test.rs +++ b/src/server/src/test.rs @@ -4,10 +4,20 @@ use liboxen::command; use liboxen::error::OxenError; use liboxen::model::LocalRepository; +use env_logger::Env; use serde::Serialize; use std::borrow::Cow; use std::path::{Path, PathBuf}; +pub fn init_test_env() { + let env = Env::default(); + if env_logger::try_init_from_env(env).is_ok() { + log::debug!("Logger initialized"); + } + + std::env::set_var("TEST", "true"); +} + pub fn get_sync_dir() -> Result { let sync_dir = PathBuf::from(format!("data/test/runs/{}", uuid::Uuid::new_v4())); std::fs::create_dir_all(&sync_dir)?; @@ -19,6 +29,7 @@ pub fn create_local_repo( namespace: &str, name: &str, ) -> Result { + init_test_env(); let repo_dir = sync_dir.join(namespace).join(name); std::fs::create_dir_all(&repo_dir)?; let repo = command::init(&repo_dir)?;