diff options
| -rw-r--r-- | src/handlers.rs | 36 | ||||
| -rw-r--r-- | src/schema.rs | 65 |
2 files changed, 74 insertions, 27 deletions
diff --git a/src/handlers.rs b/src/handlers.rs index 515caa5..fe60ded 100644 --- a/src/handlers.rs +++ b/src/handlers.rs | |||
| @@ -8,7 +8,6 @@ use jsonwebtoken::errors::ErrorKind; | |||
| 8 | use jsonwebtoken::{decode, Algorithm, DecodingKey, TokenData, Validation}; | 8 | use jsonwebtoken::{decode, Algorithm, DecodingKey, TokenData, Validation}; |
| 9 | use log::{debug, warn}; | 9 | use log::{debug, warn}; |
| 10 | use md5::Md5; | 10 | use md5::Md5; |
| 11 | use parking_lot::RwLockUpgradableReadGuard; | ||
| 12 | use rsa::{PaddingScheme, RSAPrivateKey}; | 11 | use rsa::{PaddingScheme, RSAPrivateKey}; |
| 13 | use serde::Serialize; | 12 | use serde::Serialize; |
| 14 | use sha2::Sha256; | 13 | use sha2::Sha256; |
| @@ -38,6 +37,7 @@ enum ResponseType { | |||
| 38 | 37 | ||
| 39 | use crate::schema::{ | 38 | use crate::schema::{ |
| 40 | AuthRequest, Block, Claims, Db, InitialAuthRequest, MetuId, NakedBlock, Transaction, User, | 39 | AuthRequest, Block, Claims, Db, InitialAuthRequest, MetuId, NakedBlock, Transaction, User, |
| 40 | UserAtRest, | ||
| 41 | }; | 41 | }; |
| 42 | 42 | ||
| 43 | const BEARER: &str = "Bearer "; | 43 | const BEARER: &str = "Bearer "; |
| @@ -238,17 +238,19 @@ pub async fn authenticate_user( | |||
| 238 | } | 238 | } |
| 239 | }; | 239 | }; |
| 240 | 240 | ||
| 241 | let userlist = db.users.upgradable_read(); | 241 | { |
| 242 | let userlist = db.users.read(); | ||
| 242 | 243 | ||
| 243 | if userlist.contains_key(&provided_id) { | 244 | if userlist.contains_key(&provided_id) { |
| 244 | let res_json = warp::reply::json(&GradeCoinResponse { | 245 | let res_json = warp::reply::json(&GradeCoinResponse { |
| 245 | res: ResponseType::Error, | 246 | res: ResponseType::Error, |
| 246 | message: | 247 | message: |
| 247 | "This user is already authenticated, do you think this is a mistake? Contact me" | 248 | "This user is already authenticated, do you think this is a mistake? Contact me" |
| 248 | .to_owned(), | 249 | .to_owned(), |
| 249 | }); | 250 | }); |
| 250 | 251 | ||
| 251 | return Ok(warp::reply::with_status(res_json, StatusCode::BAD_REQUEST)); | 252 | return Ok(warp::reply::with_status(res_json, StatusCode::BAD_REQUEST)); |
| 253 | } | ||
| 252 | } | 254 | } |
| 253 | 255 | ||
| 254 | // We're using this as the validator | 256 | // We're using this as the validator |
| @@ -270,11 +272,19 @@ pub async fn authenticate_user( | |||
| 270 | balance: 0, | 272 | balance: 0, |
| 271 | }; | 273 | }; |
| 272 | 274 | ||
| 273 | let user_json = serde_json::to_string(&new_user).unwrap(); | 275 | let user_at_rest_json = serde_json::to_string(&UserAtRest { |
| 276 | user: User { | ||
| 277 | user_id: new_user.user_id.clone(), | ||
| 278 | public_key: new_user.public_key.clone(), | ||
| 279 | balance: 0, | ||
| 280 | }, | ||
| 281 | fingerprint: fingerprint.clone(), | ||
| 282 | }) | ||
| 283 | .unwrap(); | ||
| 274 | 284 | ||
| 275 | fs::write(format!("users/{}.guy", new_user.user_id), user_json).unwrap(); | 285 | fs::write(format!("users/{}.guy", new_user.user_id), user_at_rest_json).unwrap(); |
| 276 | 286 | ||
| 277 | let mut userlist = RwLockUpgradableReadGuard::upgrade(userlist); | 287 | let mut userlist = db.users.write(); |
| 278 | 288 | ||
| 279 | userlist.insert(fingerprint.clone(), new_user); | 289 | userlist.insert(fingerprint.clone(), new_user); |
| 280 | 290 | ||
diff --git a/src/schema.rs b/src/schema.rs index 79fee2d..80cf73f 100644 --- a/src/schema.rs +++ b/src/schema.rs | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | //! Users are held in memory and they're also backed up to text files | 9 | //! Users are held in memory and they're also backed up to text files |
| 10 | use chrono::{NaiveDate, NaiveDateTime}; | 10 | use chrono::{NaiveDate, NaiveDateTime}; |
| 11 | use lazy_static::lazy_static; | 11 | use lazy_static::lazy_static; |
| 12 | use log::debug; | ||
| 12 | use parking_lot::RwLock; | 13 | use parking_lot::RwLock; |
| 13 | use serde::{Deserialize, Serialize}; | 14 | use serde::{Deserialize, Serialize}; |
| 14 | use std::collections::{HashMap, HashSet}; | 15 | use std::collections::{HashMap, HashSet}; |
| @@ -23,17 +24,15 @@ use std::vec::Vec; | |||
| 23 | 24 | ||
| 24 | pub type Fingerprint = String; | 25 | pub type Fingerprint = String; |
| 25 | 26 | ||
| 26 | // TODO: start by reading users from file too <14-04-21, yigit> // | 27 | fn last_block_exists() -> Option<String> { |
| 27 | |||
| 28 | fn last_block_exists() -> (bool, String) { | ||
| 29 | let blocks = read_block_name().unwrap(); | 28 | let blocks = read_block_name().unwrap(); |
| 30 | for block in blocks { | 29 | for block in blocks { |
| 31 | let block = block.to_str().unwrap(); | 30 | let block = block.to_str().unwrap(); |
| 32 | if block.contains("last.block") { | 31 | if block.contains("last.block") { |
| 33 | return (true, block.to_string()); | 32 | return Some(block.to_string()); |
| 34 | } | 33 | } |
| 35 | } | 34 | } |
| 36 | (false, "".to_string()) | 35 | None |
| 37 | } | 36 | } |
| 38 | 37 | ||
| 39 | fn read_block_name() -> io::Result<Vec<PathBuf>> { | 38 | fn read_block_name() -> io::Result<Vec<PathBuf>> { |
| @@ -44,26 +43,64 @@ fn read_block_name() -> io::Result<Vec<PathBuf>> { | |||
| 44 | Ok(entries) | 43 | Ok(entries) |
| 45 | } | 44 | } |
| 46 | 45 | ||
| 47 | fn create_db_with_last_block(path: String) -> Db { | 46 | fn read_users() -> io::Result<Vec<PathBuf>> { |
| 47 | let entries = fs::read_dir("./users")? | ||
| 48 | .map(|res| res.map(|e| e.path())) | ||
| 49 | .collect::<Result<Vec<_>, io::Error>>()?; | ||
| 50 | |||
| 51 | Ok(entries) | ||
| 52 | } | ||
| 53 | |||
| 54 | fn populate_db_with_last_block(db: &mut Db, path: String) -> &mut Db { | ||
| 55 | debug!("Populating db with last block {}", path); | ||
| 48 | let file = fs::read(path).unwrap(); | 56 | let file = fs::read(path).unwrap(); |
| 49 | let json = std::str::from_utf8(&file).unwrap(); | 57 | let json = std::str::from_utf8(&file).unwrap(); |
| 50 | let block: Block = serde_json::from_str(json).unwrap(); | 58 | let block: Block = serde_json::from_str(json).unwrap(); |
| 51 | let db = Db::new(); | ||
| 52 | *db.blockchain.write() = block; | 59 | *db.blockchain.write() = block; |
| 53 | 60 | ||
| 54 | db | 61 | db |
| 55 | } | 62 | } |
| 56 | 63 | ||
| 57 | /// Creates a new database, uses the previous last block if one exists | 64 | #[derive(Debug, Serialize, Deserialize, PartialEq)] |
| 65 | pub struct UserAtRest { | ||
| 66 | pub fingerprint: Fingerprint, | ||
| 67 | pub user: User, | ||
| 68 | } | ||
| 69 | |||
| 70 | fn populate_db_with_users(db: &mut Db, files: Vec<PathBuf>) -> &mut Db { | ||
| 71 | for fs in files { | ||
| 72 | if let Ok(file_content) = fs::read(fs) { | ||
| 73 | let json = | ||
| 74 | String::from_utf8(file_content).expect("we have written a malformed user file"); | ||
| 75 | let user_at_rest: UserAtRest = serde_json::from_str(&json).unwrap(); | ||
| 76 | |||
| 77 | debug!("Populating db with user: {:?}", user_at_rest); | ||
| 78 | db.users | ||
| 79 | .write() | ||
| 80 | .insert(user_at_rest.fingerprint, user_at_rest.user); | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | db | ||
| 85 | } | ||
| 86 | |||
| 87 | /// Creates a new database, uses the previous last block if one exists and attempts the populate | ||
| 88 | /// the users | ||
| 58 | pub fn create_database() -> Db { | 89 | pub fn create_database() -> Db { |
| 59 | fs::create_dir_all("blocks").unwrap(); | 90 | fs::create_dir_all("blocks").unwrap(); |
| 60 | fs::create_dir_all("users").unwrap(); | 91 | fs::create_dir_all("users").unwrap(); |
| 61 | let (res, path) = last_block_exists(); | 92 | |
| 62 | if res { | 93 | let mut db = Db::new(); |
| 63 | create_db_with_last_block(path) | 94 | |
| 64 | } else { | 95 | if let Some(blocks_path) = last_block_exists() { |
| 65 | Db::new() | 96 | populate_db_with_last_block(&mut db, blocks_path); |
| 97 | } | ||
| 98 | |||
| 99 | if let Ok(users_path) = read_users() { | ||
| 100 | populate_db_with_users(&mut db, users_path); | ||
| 66 | } | 101 | } |
| 102 | |||
| 103 | db | ||
| 67 | } | 104 | } |
| 68 | 105 | ||
| 69 | /// A JWT Payload/Claims representation | 106 | /// A JWT Payload/Claims representation |
| @@ -188,7 +225,7 @@ pub struct User { | |||
| 188 | } | 225 | } |
| 189 | 226 | ||
| 190 | /// The values are hard coded in [`OUR_STUDENTS`] so MetuId::new() can accept/reject values based on that | 227 | /// The values are hard coded in [`OUR_STUDENTS`] so MetuId::new() can accept/reject values based on that |
| 191 | #[derive(Serialize, Deserialize, Debug, PartialEq)] | 228 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] |
| 192 | pub struct MetuId { | 229 | pub struct MetuId { |
| 193 | id: String, | 230 | id: String, |
| 194 | passwd: String, | 231 | passwd: String, |
