diff options
author | Yigit Sever | 2021-04-11 21:39:18 +0300 |
---|---|---|
committer | Yigit Sever | 2021-04-12 00:03:23 +0300 |
commit | 518a99a132707ba0e2572b24ca18f6b9606d7334 (patch) | |
tree | c7cbe183f088b286903389f58743b1e5688119c5 /src/routes.rs | |
parent | 217398c52c68b3b73454d3e9f66c85b5a1638f3f (diff) | |
download | gradecoin-518a99a132707ba0e2572b24ca18f6b9606d7334.tar.gz gradecoin-518a99a132707ba0e2572b24ca18f6b9606d7334.tar.bz2 gradecoin-518a99a132707ba0e2572b24ca18f6b9606d7334.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.rs | 80 |
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 |
8 | pub fn consensus_routes(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone { | 8 | pub 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 | ||
17 | pub 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 |
16 | pub fn transaction_list(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone { | 26 | pub 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 | |||
50 | mod tests { | 60 | mod 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 |