aboutsummaryrefslogtreecommitdiffstats
path: root/src/routes.rs
diff options
context:
space:
mode:
authorYigit Sever2021-04-11 21:39:18 +0300
committerYigit Sever2021-04-12 00:03:23 +0300
commitd3889bd5945b2ffc63d20942b7730b5a1d0e3a42 (patch)
treea8b2dfcd416f308e7fae4baea95d6107a9871c43 /src/routes.rs
parent11b498dc44a7d2ed8f1acc62d64be7f114adc336 (diff)
downloadgradecoin-d3889bd5945b2ffc63d20942b7730b5a1d0e3a42.tar.gz
gradecoin-d3889bd5945b2ffc63d20942b7730b5a1d0e3a42.tar.bz2
gradecoin-d3889bd5945b2ffc63d20942b7730b5a1d0e3a42.zip
Implement User handling and authentication
New struct: User, corresponds to a student Blocks and users are persistent (written to a text file) PostgreSQL would've been overkill, we have 30 students AuthRequest is the representation for incoming register requests and User is the inner representation Students who are enrolled to the class are hardcoded, only they can register new accounts There are two new tests, one checks if a priviliged (=enrolled) user can create an account and the other checks if a unpriviliged one cannot There are quick verbose error messages that I'm not married to, might move on to something better honestly There's nothing stopping a malicious user to pre-register everyone with mock public keys and effectively lock everyone out, what's a good secret we can use?
Diffstat (limited to 'src/routes.rs')
-rw-r--r--src/routes.rs80
1 files changed, 73 insertions, 7 deletions
diff --git a/src/routes.rs b/src/routes.rs
index 95138e6..9f0adc5 100644
--- a/src/routes.rs
+++ b/src/routes.rs
@@ -7,11 +7,21 @@ use crate::schema::Db;
7/// Root, all routes combined 7/// Root, all routes combined
8pub fn consensus_routes(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone { 8pub fn consensus_routes(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
9 transaction_list(db.clone()) 9 transaction_list(db.clone())
10 .or(register_user(db.clone()))
10 .or(transaction_propose(db.clone())) 11 .or(transaction_propose(db.clone()))
11 .or(block_propose(db.clone())) 12 .or(block_propose(db.clone()))
12 .or(block_list(db.clone())) 13 .or(block_list(db.clone()))
13} 14}
14 15
16/// POST /register warp route
17pub fn register_user(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
18 warp::path!("register")
19 .and(warp::post())
20 .and(custom_filters::auth_request_json_body())
21 .and(custom_filters::with_db(db))
22 .and_then(handlers::authenticate_user)
23}
24
15/// GET /transaction warp route 25/// GET /transaction warp route
16pub fn transaction_list(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone { 26pub fn transaction_list(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
17 warp::path!("transaction") 27 warp::path!("transaction")
@@ -50,13 +60,13 @@ pub fn block_propose(db: Db) -> impl Filter<Extract = impl Reply, Error = Reject
50mod tests { 60mod tests {
51 use super::*; 61 use super::*;
52 62
53 use chrono::prelude::*; 63 // use chrono::prelude::*;
54 use parking_lot::RwLock; 64 // use parking_lot::RwLock;
55 use std::sync::Arc; 65 // use std::sync::Arc;
56 use warp::http::StatusCode; 66 use warp::http::StatusCode;
57 67
58 use crate::schema; 68 use crate::schema;
59 use crate::schema::{Block, Transaction}; 69 use crate::schema::{AuthRequest, Block, Transaction};
60 70
61 /// Create a mock database to be used in tests 71 /// Create a mock database to be used in tests
62 fn mocked_db() -> Db { 72 fn mocked_db() -> Db {
@@ -72,7 +82,7 @@ mod tests {
72 }, 82 },
73 ); 83 );
74 84
75 db.blockchain.write().push(Block { 85 *db.blockchain.write() = Block {
76 transaction_list: vec![ 86 transaction_list: vec![
77 "old_transaction_hash_1".to_owned(), 87 "old_transaction_hash_1".to_owned(),
78 "old_transaction_hash_2".to_owned(), 88 "old_transaction_hash_2".to_owned(),
@@ -81,11 +91,27 @@ mod tests {
81 nonce: "not_a_thing_yet".to_owned(), 91 nonce: "not_a_thing_yet".to_owned(),
82 timestamp: chrono::NaiveDate::from_ymd(2021, 04, 08).and_hms(12, 30, 30), 92 timestamp: chrono::NaiveDate::from_ymd(2021, 04, 08).and_hms(12, 30, 30),
83 hash: "not_a_thing_yet".to_owned(), 93 hash: "not_a_thing_yet".to_owned(),
84 }); 94 };
85 95
86 db 96 db
87 } 97 }
88 98
99 /// Create a mock user that is allowed to be in gradecoin to be used in tests
100 fn priviliged_mocked_user() -> AuthRequest {
101 AuthRequest {
102 student_id: String::from("e254275"),
103 public_key: "NOT IMPLEMENTED".to_owned(),
104 }
105 }
106
107 /// Create a mock user that is NOT allowed to be in gradecoin to be used in tests
108 fn unpriviliged_mocked_user() -> AuthRequest {
109 AuthRequest {
110 student_id: String::from("foobarbaz"),
111 public_key: "NOT IMPLEMENTED".to_owned(),
112 }
113 }
114
89 /// Create a mock transaction to be used in tests 115 /// Create a mock transaction to be used in tests
90 fn mocked_transaction() -> Transaction { 116 fn mocked_transaction() -> Transaction {
91 Transaction { 117 Transaction {
@@ -134,7 +160,7 @@ mod tests {
134 160
135 assert_eq!(res.status(), StatusCode::OK); 161 assert_eq!(res.status(), StatusCode::OK);
136 162
137 let expected_json_body = r#"[{"transaction_list":["old_transaction_hash_1","old_transaction_hash_2","old_transaction_hash_3"],"nonce":"not_a_thing_yet","timestamp":"2021-04-08T12:30:30","hash":"not_a_thing_yet"}]"#; 163 let expected_json_body = r#"{"transaction_list":["old_transaction_hash_1","old_transaction_hash_2","old_transaction_hash_3"],"nonce":"not_a_thing_yet","timestamp":"2021-04-08T12:30:30","hash":"not_a_thing_yet"}"#;
138 assert_eq!(res.body(), expected_json_body); 164 assert_eq!(res.body(), expected_json_body);
139 } 165 }
140 166
@@ -175,6 +201,46 @@ mod tests {
175 assert_eq!(db.pending_transactions.read().len(), 2); 201 assert_eq!(db.pending_transactions.read().len(), 2);
176 } 202 }
177 203
204 /// TEST a POST request to /transaction, an endpoint that exists
205 /// https://tools.ietf.org/html/rfc7231#section-6.3.2
206 /// Should accept the json request, create a new user and
207 /// add it to the user hashmap in the db
208 #[tokio::test]
209 async fn post_register_priviliged_user() {
210 let db = mocked_db();
211 let filter = consensus_routes(db.clone());
212
213 let res = warp::test::request()
214 .method("POST")
215 .json(&priviliged_mocked_user())
216 .path("/register")
217 .reply(&filter)
218 .await;
219
220 println!("{:?}", res.body());
221 assert_eq!(res.status(), StatusCode::CREATED);
222 assert_eq!(db.users.read().len(), 1);
223 }
224 /// TEST a POST request to /transaction, an endpoint that exists
225 /// https://tools.ietf.org/html/rfc7231#section-6.3.2
226 /// Should NOT accept the json request
227 #[tokio::test]
228 async fn post_register_unpriviliged_user() {
229 let db = mocked_db();
230 let filter = consensus_routes(db.clone());
231
232 let res = warp::test::request()
233 .method("POST")
234 .json(&unpriviliged_mocked_user())
235 .path("/register")
236 .reply(&filter)
237 .await;
238
239 println!("{:?}", res.body());
240 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
241 assert_eq!(db.users.read().len(), 0);
242 }
243
178 /// Test a POST request to /transaction, a resource that exists with a longer than expected 244 /// Test a POST request to /transaction, a resource that exists with a longer than expected
179 /// payload 245 /// payload
180 /// https://tools.ietf.org/html/rfc7231#section-6.5.11 246 /// https://tools.ietf.org/html/rfc7231#section-6.5.11