aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYigit Sever2021-04-16 00:53:03 +0300
committerYigit Sever2021-04-16 00:53:03 +0300
commit72f8ae422eeb03ed87c7819af5d5e25758267b03 (patch)
tree94abedf3a7c06ca0f9537beedb328a2e5016b575
parent2f2d0deb0ab2dc5fb63eee7b209531c8686e702e (diff)
downloadgradecoin-72f8ae422eeb03ed87c7819af5d5e25758267b03.tar.gz
gradecoin-72f8ae422eeb03ed87c7819af5d5e25758267b03.tar.bz2
gradecoin-72f8ae422eeb03ed87c7819af5d5e25758267b03.zip
Load users from disk at start
-rw-r--r--src/handlers.rs36
-rw-r--r--src/schema.rs65
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;
8use jsonwebtoken::{decode, Algorithm, DecodingKey, TokenData, Validation}; 8use jsonwebtoken::{decode, Algorithm, DecodingKey, TokenData, Validation};
9use log::{debug, warn}; 9use log::{debug, warn};
10use md5::Md5; 10use md5::Md5;
11use parking_lot::RwLockUpgradableReadGuard;
12use rsa::{PaddingScheme, RSAPrivateKey}; 11use rsa::{PaddingScheme, RSAPrivateKey};
13use serde::Serialize; 12use serde::Serialize;
14use sha2::Sha256; 13use sha2::Sha256;
@@ -38,6 +37,7 @@ enum ResponseType {
38 37
39use crate::schema::{ 38use 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
43const BEARER: &str = "Bearer "; 43const 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
10use chrono::{NaiveDate, NaiveDateTime}; 10use chrono::{NaiveDate, NaiveDateTime};
11use lazy_static::lazy_static; 11use lazy_static::lazy_static;
12use log::debug;
12use parking_lot::RwLock; 13use parking_lot::RwLock;
13use serde::{Deserialize, Serialize}; 14use serde::{Deserialize, Serialize};
14use std::collections::{HashMap, HashSet}; 15use std::collections::{HashMap, HashSet};
@@ -23,17 +24,15 @@ use std::vec::Vec;
23 24
24pub type Fingerprint = String; 25pub type Fingerprint = String;
25 26
26// TODO: start by reading users from file too <14-04-21, yigit> // 27fn last_block_exists() -> Option<String> {
27
28fn 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
39fn read_block_name() -> io::Result<Vec<PathBuf>> { 38fn 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
47fn create_db_with_last_block(path: String) -> Db { 46fn 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
54fn 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)]
65pub struct UserAtRest {
66 pub fingerprint: Fingerprint,
67 pub user: User,
68}
69
70fn 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
58pub fn create_database() -> Db { 89pub 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)]
192pub struct MetuId { 229pub struct MetuId {
193 id: String, 230 id: String,
194 passwd: String, 231 passwd: String,