···1818 path_instructions:
1919 - path: "**/*.{rs,toml}"
2020 instructions:
2121- "Review the Rust code for conformity with best practices in Rust,
2222- Systems programming. Highlight any deviations."
2121+ "Review the Rust code and Python code for conformity with best practices in Rust,
2222+ Systems programming and Python. Highlight any deviations. Also highlight if there any
2323+ any security issues in the code"
2324
+9-7
tilekit/src/accounts.rs
···11-// Handles stuff related to accounts, identity etc..
11+//! Handles stuff related to accounts, identity etc..
22+23use anyhow::Result;
34use ed25519_dalek::{SigningKey, ed25519::signature::rand_core::OsRng};
45use keyring::Entry;
56use ucan::did::Ed25519Did;
6777-type DID = String;
88-type Identity = DID;
88+type Did = String;
99+type Identity = Did;
9101010-/// Creates an `Identity`
1111-/// # Parameters
1212-/// - `app`: The service for which Identity is made (for ex: tiles)
1111+/// Creates an `Identity` for given application
1312/// The keypair generated will be stored in OS secure storage
1414-/// Returns an `Identity`
1313+///
1414+/// # Arguments
1515+///
1616+/// - `app`: The service for which Identity is made (for ex: tiles)
1517pub fn create_identity(app: &str) -> Result<Identity> {
1618 let mut csprng = OsRng;
1719 let signing_key = SigningKey::generate(&mut csprng);
+28-22
tiles/src/commands/mod.rs
···44use owo_colors::OwoColorize;
55use tiles::runtime::Runtime;
66use tiles::utils::accounts::{
77- create_root_account, get_root_user_details, save_root_account, set_nickname,
77+ RootUser, create_root_account, get_root_user_details, save_root_account, set_nickname,
88};
99use tiles::utils::config::{get_or_create_config, set_memory_path};
1010use tiles::{core::health, runtime::RunArgs};
···4040 let _ = runtime.stop_server_daemon().await;
4141}
42424343-//TODO: add docs
4343+/// Runs the account command with the args being passed.
4444pub fn run_account_commands(account_args: AccountArgs) -> Result<()> {
4545 let config = get_or_create_config()?;
4646 let root_user_details = get_root_user_details(&config)?;
4747 match account_args.command {
4848 Some(AccountCommands::Create { nickname }) => {
4949- //TODO: could show a message if did is already there
5050- let root_user_config = create_root_account(&config, nickname)?;
5151- let id = root_user_config.get("id").unwrap().as_str().unwrap();
5252- save_root_account(config, &root_user_config)?;
5353- //TODO: color it...
5454- let _ = println!("Root account has been created with id: {}", id).green();
4949+ if !root_user_details.id.is_empty() {
5050+ println!("Root account exists with id: {}", root_user_details.id)
5151+ } else {
5252+ let root_user_config = RootUser::new(&create_root_account(&config, nickname)?)?;
5353+5454+ save_root_account(config, &root_user_config.to_table())?;
5555+ println!(
5656+ "{}",
5757+ format_args!(
5858+ "Root account has been created with id: {}",
5959+ root_user_config.id
6060+ )
6161+ )
6262+ }
5563 }
5664 Some(AccountCommands::SetNickname { nickname }) => {
5757- //FIXME: redundant code
5858- if root_user_details.get("id").unwrap().is_empty() {
5959- println!(
6060- "Root account not created yet, use {}",
6161- format!("tiles account create").yellow()
6262- );
6565+ if root_user_details.id.is_empty() {
6666+ println!("{}", get_account_not_created_msg());
6367 } else {
6468 match set_nickname(&config, nickname) {
6569 Ok(root_user_config) => {
···7579 }
7680 }
7781 _ => {
7878- if root_user_details.get("id").unwrap().is_empty() {
7979- println!(
8080- "Root account not created yet, use {}",
8181- format!("tiles account create").yellow()
8282- );
8282+ if root_user_details.id.is_empty() {
8383+ println!("{}", get_account_not_created_msg());
8384 } else {
8484- for elem in root_user_details {
8585- println!("{}: {}", elem.0, elem.1)
8686- }
8585+ println!("{}", root_user_details);
8786 }
8887 }
8988 }
90899190 Ok(())
9291}
9292+9393+fn get_account_not_created_msg() -> String {
9494+ format!(
9595+ "Root account not created yet, use {}",
9696+ "tiles account create".yellow()
9797+ )
9898+}
+97-38
tiles/src/utils/accounts.rs
···11// Stuff related to account and identity system
22-33-use std::collections::HashMap;
44-55-use anyhow::Result;
22+use anyhow::{Result, anyhow};
33+use std::fmt::Display;
64use tilekit::accounts::create_identity;
75use toml::Table;
8697use crate::utils::config::save_config;
108const ROOT_USER_CONFIG_KEY: &str = "root-user";
1191212-//TODO: add docs
1313-pub fn get_root_user_details(config: &Table) -> Result<HashMap<String, String>> {
1414- Ok(get_root_account(&config))
1010+#[allow(dead_code)]
1111+pub struct RootUser {
1212+ pub id: String,
1313+ pub nickname: String,
1514}
16151717-fn get_root_account(config: &Table) -> HashMap<String, String> {
1818- let root_user = config.get(ROOT_USER_CONFIG_KEY).unwrap();
1919- let root_user_table = root_user.as_table().unwrap();
2020- let mut root_user_map = HashMap::new();
2121- for ele in root_user_table {
2222- root_user_map.insert(ele.0.to_string(), ele.1.as_str().unwrap().to_owned());
1616+impl Display for RootUser {
1717+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1818+ write!(f, "id: {}\nnickname: {}\n", self.id, self.nickname)
2319 }
2424- root_user_map
2520}
26212727-// Lets return main config table only, let the caller do whatever it wants...
2828-// TODO: Needed docs
2222+impl RootUser {
2323+ pub fn new(config: &Table) -> Result<Self> {
2424+ let id = config
2525+ .get("id")
2626+ .ok_or_else(|| anyhow!("Missing ID"))?
2727+ .as_str()
2828+ .ok_or_else(|| anyhow!("ID not a string"))?;
2929+ let nickname = config
3030+ .get("nickname")
3131+ .ok_or_else(|| anyhow!("Missing Nickname"))?
3232+ .as_str()
3333+ .ok_or_else(|| anyhow!("Nickname not a string"))?;
3434+ Ok(RootUser {
3535+ id: id.to_owned(),
3636+ nickname: nickname.to_owned(),
3737+ })
3838+ }
3939+4040+ pub fn to_table(&self) -> Table {
4141+ let mut root_user_table = Table::new();
4242+ root_user_table.insert(String::from("id"), toml::Value::String(self.id.clone()));
4343+ root_user_table.insert(
4444+ String::from("nickname"),
4545+ toml::Value::String(self.nickname.clone()),
4646+ );
4747+ root_user_table
4848+ }
4949+}
5050+5151+/// Returns a `RootUser`, which represents a root user
5252+///
5353+/// # Params
5454+///
5555+/// - config: A `Table` type of entire config.toml file
5656+pub fn get_root_user_details(config: &Table) -> Result<RootUser> {
5757+ let root_user = config
5858+ .get(ROOT_USER_CONFIG_KEY)
5959+ .ok_or_else(|| anyhow!("root-user key not found"))?;
6060+ let root_user_table = root_user
6161+ .as_table()
6262+ .ok_or_else(|| anyhow!("root user not a table"))?;
6363+ RootUser::new(root_user_table)
6464+}
6565+6666+/// Create a root account
6767+/// Stores the private credentials in OS secure password manager
6868+///
6969+/// # Params
7070+///
7171+/// - config: A `Table` type of entire config.toml file
7272+/// - nickname: Nickname for the identity (Optional)
7373+///
7474+/// Returns the root_user_config as a `Table` type
2975pub fn create_root_account(config: &Table, nickname: Option<String>) -> Result<Table> {
3030- let root_user = config.get(ROOT_USER_CONFIG_KEY).unwrap();
3131- let root_user_table = root_user.as_table().unwrap();
3232- let did = root_user_table.get("id").unwrap().as_str().unwrap();
7676+ let root_user = config
7777+ .get(ROOT_USER_CONFIG_KEY)
7878+ .ok_or_else(|| anyhow!("{} doesn't exist", ROOT_USER_CONFIG_KEY))?;
7979+ let root_user_table = root_user
8080+ .as_table()
8181+ .ok_or_else(|| anyhow!("Failed to parse root user info"))?;
8282+ let root_user_data = RootUser::new(root_user_table)?;
8383+ let did = root_user_data.id;
3384 if did.is_empty() {
3434- let root_user_config = create_root_user(root_user_table, nickname)?;
3535- Ok(root_user_config)
8585+ Ok(create_root_user(root_user_table, nickname)?)
3686 } else {
3787 Ok(root_user_table.clone())
3888 }
3989}
40904141-//TODO: docs
9191+/// Save the root config in `Table` type to config.toml
9292+///
9393+/// # Params
9494+///
9595+/// - config: A `Table` type of entire config.toml file
9696+/// - root_user_config: A `Table` type of root user
4297pub fn save_root_account(mut config: Table, root_user_config: &Table) -> Result<()> {
4398 config.insert(
4499 String::from(ROOT_USER_CONFIG_KEY),
···47102 save_config(&config)
48103}
491045050-// TODO: add docs
105105+/// Sets nickname for the root account
106106+///
107107+/// # Params
108108+///
109109+/// - config: A `Table` type of entire config.toml file
110110+/// - nickname: Nickname for the identity
111111+///
112112+/// Returns the root_user_config as a `Table` type
51113pub fn set_nickname(config: &Table, nickname: String) -> Result<Table> {
52114 let root_user = config.get(ROOT_USER_CONFIG_KEY).unwrap();
53115 let mut root_user_table = root_user.as_table().unwrap().clone();
···61123 }
62124}
631256464-// TODO: add docs
65126fn create_root_user(root_user_config: &Table, nickname: Option<String>) -> Result<Table> {
6666- // get root user details
67127 let mut root_user_table = root_user_config.clone();
68128 match create_identity("tiles") {
69129 Ok(did) => {
70130 root_user_table.insert("id".to_owned(), toml::Value::String(did));
7171- if nickname.is_some() {
7272- root_user_table.insert(
7373- "nickname".to_owned(),
7474- toml::Value::String(nickname.unwrap()),
7575- );
131131+ if let Some(nickname) = nickname {
132132+ root_user_table.insert("nickname".to_owned(), toml::Value::String(nickname));
76133 }
77134 Ok(root_user_table)
78135 }
···81138}
8213983140#[cfg(test)]
8484-85141mod tests {
142142+ use anyhow::Result;
86143 use keyring::{mock, set_default_credential_builder};
87144 use toml::Table;
881458989- use crate::utils::accounts::{create_root_account, get_root_account};
146146+ use crate::utils::accounts::{create_root_account, get_root_user_details};
9014791148 #[test]
9292- fn test_get_root_user_details_empty_id() {
149149+ fn test_get_root_user_details_empty_id() -> Result<()> {
93150 let config: Table = toml::from_str(
94151 r#"
95152 [root-user]
···98155 "#,
99156 )
100157 .unwrap();
101101- let acc_details = get_root_account(&config);
102102- assert!(acc_details.get("id").unwrap().is_empty());
158158+ let acc_details = get_root_user_details(&config)?;
159159+ assert!(acc_details.id.is_empty());
160160+ Ok(())
103161 }
104162105163 #[test]
106106- fn test_get_root_user_details_valid_id() {
164164+ fn test_get_root_user_details_valid_id() -> Result<()> {
107165 let config: Table = toml::from_str(
108166 r#"
109167 [root-user]
···112170 "#,
113171 )
114172 .unwrap();
115115- let acc_details = get_root_account(&config);
116116- assert!(acc_details.get("id").unwrap().contains("did:key"));
173173+ let acc_details = get_root_user_details(&config)?;
174174+ assert!(acc_details.id.contains("did:key"));
175175+ Ok(())
117176 }
118177119178 #[test]
+6-5
tiles/src/utils/config.rs
···11// Configuration related stuff
2233use anyhow::{Context, Result};
44-use std::fs::File;
54use std::path::PathBuf;
65use std::str::FromStr;
76use std::{env, fs};
···144143 }
145144}
146145146146+/// Saves the root config toml `Table` type
147147pub fn save_config(config: &Table) -> Result<()> {
148148 let tiles_config_dir = DefaultProvider.get_config_dir()?;
149149- let config_toml_path = tiles_config_dir.join("config.toml");
150150-151151- fs::write(config_toml_path, config.to_string())?;
149149+ let config_path = tiles_config_dir.join("config.toml");
150150+ let tmp_path = tiles_config_dir.join("config.tmp.toml");
151151+ fs::write(&tmp_path, config.to_string())?;
152152+ fs::copy(&tmp_path, &config_path)?;
153153+ fs::remove_file(tmp_path)?;
152154 Ok(())
153155}
154156155155-// pub fn save_config(config: &Table)
156157//TODO: Add more tests for config.toml
157158#[cfg(test)]
158159mod tests {