diff options
-rw-r--r-- | src/db.rs | 39 | ||||
-rw-r--r-- | src/handlers.rs | 36 | ||||
-rw-r--r-- | src/student.rs | 70 |
3 files changed, 56 insertions, 89 deletions
@@ -14,13 +14,14 @@ use log::debug; | |||
14 | use parking_lot::RwLock; | 14 | use parking_lot::RwLock; |
15 | use std::{collections::HashMap, fs, io, path::PathBuf, sync::Arc}; | 15 | use std::{collections::HashMap, fs, io, path::PathBuf, sync::Arc}; |
16 | 16 | ||
17 | const PREAPPROVED_STU_FILENAME: &str = "students.csv"; | ||
18 | |||
17 | #[derive(Debug, Clone, Default)] | 19 | #[derive(Debug, Clone, Default)] |
18 | pub struct Db { | 20 | pub struct Db { |
19 | pub blockchain: Arc<RwLock<Block>>, | 21 | pub blockchain: Arc<RwLock<Block>>, |
20 | pub pending_transactions: Arc<RwLock<HashMap<Id, Transaction>>>, | 22 | pub pending_transactions: Arc<RwLock<HashMap<Id, Transaction>>>, |
21 | pub users: Arc<RwLock<HashMap<Fingerprint, User>>>, | 23 | pub users: Arc<RwLock<HashMap<Fingerprint, User>>>, |
22 | approved_users: Vec<MetuId>, | 24 | preapproved_users: Vec<MetuId>, |
23 | // TODO: metu_ids or approved_users or something, metu_id struct <11-04-22, yigit> // | ||
24 | } | 25 | } |
25 | 26 | ||
26 | impl Db { | 27 | impl Db { |
@@ -37,13 +38,13 @@ impl Db { | |||
37 | } | 38 | } |
38 | 39 | ||
39 | let users: HashMap<Fingerprint, User> = get_friendly_users(); | 40 | let users: HashMap<Fingerprint, User> = get_friendly_users(); |
40 | let approved_users = read_approved_users(); | 41 | let preapproved_users = read_approved_users(); |
41 | 42 | ||
42 | Db { | 43 | Db { |
43 | blockchain: Arc::new(RwLock::new(Block::default())), | 44 | blockchain: Arc::new(RwLock::new(Block::default())), |
44 | pending_transactions: Arc::new(RwLock::new(HashMap::new())), | 45 | pending_transactions: Arc::new(RwLock::new(HashMap::new())), |
45 | users: Arc::new(RwLock::new(users)), | 46 | users: Arc::new(RwLock::new(users)), |
46 | approved_users, | 47 | preapproved_users, |
47 | } | 48 | } |
48 | } | 49 | } |
49 | 50 | ||
@@ -69,6 +70,16 @@ impl Db { | |||
69 | } | 70 | } |
70 | } | 71 | } |
71 | } | 72 | } |
73 | |||
74 | pub fn is_user_preapproved(&self, id: &Id, passwd: &String) -> bool { | ||
75 | for user in &self.preapproved_users { | ||
76 | if *user.get_id() == *id && *user.get_passwd() == *passwd { | ||
77 | return true; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | false | ||
82 | } | ||
72 | } | 83 | } |
73 | 84 | ||
74 | fn last_block_content() -> Option<String> { | 85 | fn last_block_content() -> Option<String> { |
@@ -122,7 +133,7 @@ fn get_friendly_users() -> HashMap<Fingerprint, User> { | |||
122 | users.insert( | 133 | users.insert( |
123 | "cde48537ca2c28084ff560826d0e6388b7c57a51497a6cb56f397289e52ff41b".to_owned(), | 134 | "cde48537ca2c28084ff560826d0e6388b7c57a51497a6cb56f397289e52ff41b".to_owned(), |
124 | User { | 135 | User { |
125 | user_id: MetuId::new("friend_1".to_owned(), "not_used".to_owned()).unwrap(), | 136 | user_id: MetuId::new("friend_1".to_owned(), "not_used".to_owned()), |
126 | public_key: "not_used".to_owned(), | 137 | public_key: "not_used".to_owned(), |
127 | balance: 70, | 138 | balance: 70, |
128 | is_bot: true, | 139 | is_bot: true, |
@@ -132,7 +143,7 @@ fn get_friendly_users() -> HashMap<Fingerprint, User> { | |||
132 | users.insert( | 143 | users.insert( |
133 | "a1a38b5bae5866d7d998a9834229ec2f9db7a4fc8fb6f58b1115a96a446875ff".to_owned(), | 144 | "a1a38b5bae5866d7d998a9834229ec2f9db7a4fc8fb6f58b1115a96a446875ff".to_owned(), |
134 | User { | 145 | User { |
135 | user_id: MetuId::new("friend_2".to_owned(), "not_used".to_owned()).unwrap(), | 146 | user_id: MetuId::new("friend_2".to_owned(), "not_used".to_owned()), |
136 | public_key: "not_used".to_owned(), | 147 | public_key: "not_used".to_owned(), |
137 | balance: 20, | 148 | balance: 20, |
138 | is_bot: true, | 149 | is_bot: true, |
@@ -142,7 +153,7 @@ fn get_friendly_users() -> HashMap<Fingerprint, User> { | |||
142 | users.insert( | 153 | users.insert( |
143 | "4e048fd2a62f1307866086e803e9be43f78a702d5df10831fbf434e7663ae0e7".to_owned(), | 154 | "4e048fd2a62f1307866086e803e9be43f78a702d5df10831fbf434e7663ae0e7".to_owned(), |
144 | User { | 155 | User { |
145 | user_id: MetuId::new("friend_4".to_owned(), "not_used".to_owned()).unwrap(), | 156 | user_id: MetuId::new("friend_4".to_owned(), "not_used".to_owned()), |
146 | public_key: "not_used".to_owned(), | 157 | public_key: "not_used".to_owned(), |
147 | balance: 120, | 158 | balance: 120, |
148 | is_bot: true, | 159 | is_bot: true, |
@@ -152,7 +163,7 @@ fn get_friendly_users() -> HashMap<Fingerprint, User> { | |||
152 | users.insert( | 163 | users.insert( |
153 | "60e77101e76950a9b1830fa107fd2f8fc545255b3e0f14b6a7797cf9ee005f07".to_owned(), | 164 | "60e77101e76950a9b1830fa107fd2f8fc545255b3e0f14b6a7797cf9ee005f07".to_owned(), |
154 | User { | 165 | User { |
155 | user_id: MetuId::new("friend_4".to_owned(), "not_used".to_owned()).unwrap(), | 166 | user_id: MetuId::new("friend_4".to_owned(), "not_used".to_owned()), |
156 | public_key: "not_used".to_owned(), | 167 | public_key: "not_used".to_owned(), |
157 | balance: 40, | 168 | balance: 40, |
158 | is_bot: true, | 169 | is_bot: true, |
@@ -163,11 +174,19 @@ fn get_friendly_users() -> HashMap<Fingerprint, User> { | |||
163 | 174 | ||
164 | fn read_approved_users() -> Vec<MetuId> { | 175 | fn read_approved_users() -> Vec<MetuId> { |
165 | let mut approved_students: Vec<MetuId> = Vec::new(); | 176 | let mut approved_students: Vec<MetuId> = Vec::new(); |
166 | let contents = fs::read_to_string("students.csv").unwrap(); | 177 | let contents = fs::read_to_string(PREAPPROVED_STU_FILENAME).unwrap_or_else(|_| { |
178 | panic!( | ||
179 | "{}", | ||
180 | format!( | ||
181 | "Expected {} to load preapproved students", | ||
182 | PREAPPROVED_STU_FILENAME | ||
183 | ) | ||
184 | ) | ||
185 | }); | ||
167 | let mut reader = csv::Reader::from_reader(contents.as_bytes()); | 186 | let mut reader = csv::Reader::from_reader(contents.as_bytes()); |
168 | for student in reader.records() { | 187 | for student in reader.records() { |
169 | let student = student.unwrap(); | 188 | let student = student.unwrap(); |
170 | approved_students.push(MetuId::_new(student[0].to_owned(), student[1].to_owned())); | 189 | approved_students.push(MetuId::new(student[0].to_owned(), student[1].to_owned())); |
171 | } | 190 | } |
172 | approved_students | 191 | approved_students |
173 | } | 192 | } |
diff --git a/src/handlers.rs b/src/handlers.rs index 96001ce..ca0608c 100644 --- a/src/handlers.rs +++ b/src/handlers.rs | |||
@@ -220,7 +220,7 @@ pub async fn authenticate_user( | |||
220 | }; | 220 | }; |
221 | 221 | ||
222 | // c field was properly base64 encoded, now available in auth_packet | 222 | // c field was properly base64 encoded, now available in auth_packet |
223 | // decryptor was setup properly, with the correct lenght key | 223 | // decryptor was setup properly, with the correct length key |
224 | let mut buf = auth_packet; | 224 | let mut buf = auth_packet; |
225 | let auth_plaintext = match cipher.decrypt(&mut buf) { | 225 | let auth_plaintext = match cipher.decrypt(&mut buf) { |
226 | Ok(p) => p, | 226 | Ok(p) => p, |
@@ -278,24 +278,22 @@ pub async fn authenticate_user( | |||
278 | }; | 278 | }; |
279 | 279 | ||
280 | // is the student in AuthRequest privileged? | 280 | // is the student in AuthRequest privileged? |
281 | // TODO: this is the only check for 'if metuid is approved' <15-04-22, yigit> // | 281 | let privileged_student_id = if db.is_user_preapproved(&request.student_id, &request.passwd) { |
282 | let privileged_student_id = | 282 | MetuId::new(request.student_id.clone(), request.passwd.clone()) |
283 | if let Some(id) = MetuId::new(request.student_id.clone(), request.passwd.clone()) { | 283 | } else { |
284 | id | 284 | debug!( |
285 | } else { | 285 | "Someone tried to auth with invalid credentials: {} {}", |
286 | debug!( | 286 | &request.student_id, &request.passwd |
287 | "Someone tried to auth with invalid credentials: {} {}", | 287 | ); |
288 | &request.student_id, &request.passwd | 288 | let res_json = warp::reply::json(&GradeCoinResponse { |
289 | ); | 289 | res: ResponseType::Error, |
290 | let res_json = warp::reply::json(&GradeCoinResponse { | 290 | message: |
291 | res: ResponseType::Error, | 291 | "The credentials given ('student_id', 'passwd') cannot hold a Gradecoin account" |
292 | message: | 292 | .to_owned(), |
293 | "The credentials given ('student_id', 'passwd') cannot hold a Gradecoin account" | 293 | }); |
294 | .to_owned(), | ||
295 | }); | ||
296 | 294 | ||
297 | return Ok(warp::reply::with_status(res_json, StatusCode::BAD_REQUEST)); | 295 | return Ok(warp::reply::with_status(res_json, StatusCode::BAD_REQUEST)); |
298 | }; | 296 | }; |
299 | 297 | ||
300 | // Students should be able to authenticate once | 298 | // Students should be able to authenticate once |
301 | { | 299 | { |
@@ -382,7 +380,7 @@ pub async fn list_transactions(db: Db) -> Result<impl warp::Reply, Infallible> { | |||
382 | /// Proposes a new block for the next round. | 380 | /// Proposes a new block for the next round. |
383 | /// Can reject the block | 381 | /// Can reject the block |
384 | /// | 382 | /// |
385 | /// The proposer has to put their transaction as the first transaction of the transaction_list. | 383 | /// The proposer has to put their transaction as the first transaction of the `Block::transaction_list`. |
386 | /// This is the analogue of `coinbase` in Bitcoin works | 384 | /// This is the analogue of `coinbase` in Bitcoin works |
387 | /// | 385 | /// |
388 | /// The `coinbase` transaction also gets something for their efforts. | 386 | /// The `coinbase` transaction also gets something for their efforts. |
diff --git a/src/student.rs b/src/student.rs index 711eeeb..2b9c5bd 100644 --- a/src/student.rs +++ b/src/student.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | use crate::Fingerprint; | 1 | use crate::{Fingerprint, Id}; |
2 | use lazy_static::lazy_static; | ||
3 | use serde::{Deserialize, Serialize}; | 2 | use serde::{Deserialize, Serialize}; |
4 | use std::{collections::HashSet, fmt}; | 3 | use std::fmt; |
5 | 4 | ||
6 | #[derive(Debug, Serialize, Deserialize, PartialEq)] | 5 | #[derive(Debug, Serialize, Deserialize, PartialEq)] |
7 | pub struct UserAtRest { | 6 | pub struct UserAtRest { |
@@ -25,11 +24,9 @@ pub struct User { | |||
25 | pub is_bot: bool, | 24 | pub is_bot: bool, |
26 | } | 25 | } |
27 | 26 | ||
28 | /// The values are hard coded in [`static@OUR_STUDENTS`] so `MetuId::new`() can accept/reject values based on that | ||
29 | /// TODO update the statement above | ||
30 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] | 27 | #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] |
31 | pub struct MetuId { | 28 | pub struct MetuId { |
32 | id: String, | 29 | id: Id, |
33 | passwd: String, | 30 | passwd: String, |
34 | } | 31 | } |
35 | 32 | ||
@@ -40,62 +37,15 @@ impl fmt::Display for MetuId { | |||
40 | } | 37 | } |
41 | 38 | ||
42 | impl MetuId { | 39 | impl MetuId { |
43 | pub fn new(id: String, pwd: String) -> Option<Self> { | 40 | pub fn new(id: String, passwd: String) -> Self { |
44 | if OUR_STUDENTS.contains(&(&*id, &*pwd)) { | 41 | MetuId { id, passwd } |
45 | Some(MetuId { id, passwd: pwd }) | ||
46 | } else { | ||
47 | None | ||
48 | } | ||
49 | } | 42 | } |
50 | 43 | ||
51 | // TODO: replace the function above with this <15-04-22, yigit> // | 44 | pub fn get_id(&self) -> &Id { |
52 | pub fn _new(id: String, passwd: String) -> Self { | 45 | &self.id |
53 | MetuId { id, passwd } | ||
54 | } | 46 | } |
55 | } | ||
56 | 47 | ||
57 | // TODO: remove this, read from a yaml or something, then MetuId::new gets a self <11-04-22, yigit> // | 48 | pub fn get_passwd(&self) -> &String { |
58 | // Students who are authorized to have Gradecoin accounts | 49 | &self.passwd |
59 | lazy_static! { | 50 | } |
60 | static ref OUR_STUDENTS: HashSet<(&'static str, &'static str)> = { | ||
61 | [ | ||
62 | ("e254275", "DtNX1qk4YF4saRH"), | ||
63 | ("e223687", "cvFEs4XLjuGBD1v"), | ||
64 | ("e211024", "voQAcxiKJmEXYRT"), | ||
65 | ("e209888", "O75dli6AQtz2tUi"), | ||
66 | ("e223725", "xXuTD3Y4tyrv2Jz"), | ||
67 | ("e209362", "N7wGm5XU5zVWOWu"), | ||
68 | ("e209898", "aKBFfB8fZMq8pVn"), | ||
69 | ("e230995", "TgcHGlqeFhQGx42"), | ||
70 | ("e223743", "YVWVSWuIHplJk9C"), | ||
71 | ("e223747", "8LAeHrsjnwXh59Q"), | ||
72 | ("e223749", "HMFeJqVOzwCPHbc"), | ||
73 | ("e223751", "NjMsxmtmy2VOwMW"), | ||
74 | ("e188126", "QibuPdV2gXfsVJW"), | ||
75 | ("e209913", "kMxJvl2vHSWCy4A"), | ||
76 | ("e203608", "mfkkR0MWurk6Rp1"), | ||
77 | ("e233013", "GCqHxdOaDj2pWXx"), | ||
78 | ("e216982", "2Z0xmgCStnj5qg5"), | ||
79 | ("e217185", "BcaZNlzlhPph7A3"), | ||
80 | ("e223780", "2KvVxKUQaA9H4sn"), | ||
81 | ("e194931", "hsC0Wb8PQ5vzwdQ"), | ||
82 | ("e223783", "ETUJA3kt1QYvJai"), | ||
83 | ("e254550", "rPRjX0A4NefvKWi"), | ||
84 | ("e217203", "lN3IWhGyCrGfkk5"), | ||
85 | ("e217477", "O9xlMaa7LanC82w"), | ||
86 | ("e223786", "UxI6czykJfp9T9N"), | ||
87 | ("e231060", "VJgziofQQPCoisH"), | ||
88 | ("e223795", "pmcTCKox99NFsqp"), | ||
89 | ("e223715", "1H5QuOYI1b2r9ET"), | ||
90 | ("e181932", "THANKYOUHAVEFUN"), | ||
91 | ("bank", "P7oxDm30g1jeIId"), | ||
92 | ("friend_1", "not_used"), | ||
93 | ("friend_2", "not_used"), | ||
94 | ("friend_3", "not_used"), | ||
95 | ("friend_4", "not_used"), | ||
96 | ] | ||
97 | .iter() | ||
98 | .copied() | ||
99 | .collect() | ||
100 | }; | ||
101 | } | 51 | } |