aboutsummaryrefslogtreecommitdiffstats
path: root/src/routes.rs
diff options
context:
space:
mode:
authoralpaylan2021-04-12 22:15:17 +0300
committeralpaylan2021-04-12 22:15:17 +0300
commit65bcc5ce455bdc298af3b9c4a30039afed047a4f (patch)
tree63fb58ba3762501ae872d518266cf9f7cc834976 /src/routes.rs
parentdf484d87424674b88ccfa9392cfa9a75cc4abe48 (diff)
downloadgradecoin-65bcc5ce455bdc298af3b9c4a30039afed047a4f.tar.gz
gradecoin-65bcc5ce455bdc298af3b9c4a30039afed047a4f.tar.bz2
gradecoin-65bcc5ce455bdc298af3b9c4a30039afed047a4f.zip
implement user authentication using jwt
Diffstat (limited to 'src/routes.rs')
-rw-r--r--src/routes.rs132
1 files changed, 121 insertions, 11 deletions
diff --git a/src/routes.rs b/src/routes.rs
index 03a2569..ed2acad 100644
--- a/src/routes.rs
+++ b/src/routes.rs
@@ -1,14 +1,14 @@
1use gradecoin::schema::Db;
1use warp::{Filter, Rejection, Reply}; 2use warp::{Filter, Rejection, Reply};
2 3
3use crate::custom_filters; 4use crate::custom_filters;
4use crate::handlers; 5use crate::handlers;
5use gradecoin::schema::Db;
6 6
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(register_user(db.clone()))
11 .or(transaction_propose(db.clone())) 11 .or(auth_transaction_propose(db.clone()))
12 .or(block_propose(db.clone())) 12 .or(block_propose(db.clone()))
13 .or(block_list(db.clone())) 13 .or(block_list(db.clone()))
14} 14}
@@ -47,6 +47,18 @@ pub fn transaction_propose(db: Db) -> impl Filter<Extract = impl Reply, Error =
47 .and_then(handlers::propose_transaction) 47 .and_then(handlers::propose_transaction)
48} 48}
49 49
50/// POST /transaction warp route
51pub fn auth_transaction_propose(
52 db: Db,
53) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
54 warp::path!("transaction")
55 .and(warp::post())
56 .and(custom_filters::transaction_json_body())
57 .and(custom_filters::auth_header())
58 .and(custom_filters::with_db(db))
59 .and_then(handlers::auth_propose_transaction)
60}
61
50/// POST /block warp route 62/// POST /block warp route
51pub fn block_propose(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone { 63pub fn block_propose(db: Db) -> impl Filter<Extract = impl Reply, Error = Rejection> + Clone {
52 warp::path!("block") 64 warp::path!("block")
@@ -58,22 +70,69 @@ pub fn block_propose(db: Db) -> impl Filter<Extract = impl Reply, Error = Reject
58 70
59#[cfg(test)] 71#[cfg(test)]
60mod tests { 72mod tests {
61 use super::*; 73 use gradecoin::schema::{create_database, AuthRequest, Block, MetuId, Transaction, User};
62 74 use handlers::Claims;
63 // use chrono::prelude::*; 75 // use chrono::prelude::*;
64 // use parking_lot::RwLock; 76 // use parking_lot::RwLock;
65 // use std::sync::Arc; 77 // use std::sync::Arc;
66 use warp::http::StatusCode; 78 use warp::http::StatusCode;
67 79
68 use gradecoin::schema::{create_database, AuthRequest, Block, Transaction}; 80 use super::*;
69 81
82 use jsonwebtoken::{Header, encode, EncodingKey, Algorithm};
83 const private_key_pem: &str = "-----BEGIN RSA PRIVATE KEY-----
84MIIEpAIBAAKCAQEA4nU0G4WjkmcQUx0hq6LQuV5Q+ACmUFL/OjoYMDwC/O/6pCd1
85UZgCfgHN2xEffDPznzcTn8OiFRxr4oWyBinyrUpnY4mhy0SQUwoeCw7YkcHAyhCj
86NT74aR/ohX0MCj0qRRdbt5ZQXM/GC3HJuXE1ptSuhFgQxziItamn8maoJ6JUSVEX
87VO1NOrrjoM3r7Q+BK2B+sX4/bLZ+VG5g1q2nEbFdTHS6pHqtZNHQndTmEKwRfh0R
88YtzEzOXuO6e1gQY42Tujkof40dhGCIU7TeIGGHwdFxy1niLkXwtHNjV7lnIOkTbx
896+sSPamRfQAlZqUWM2Lf5o+7h3qWP3ENB138sQIDAQABAoIBAD23nYTmrganag6M
90wPFrBSGP79c3Lhx0EjUHQjJbGKFgsdltG48qM3ut+DF9ACy0Z+/7bbC7+39vaIOq
911jLR2d6aiYTaLKseO4s2FawD1sgamvU3BZPsXn0gAhnnU5Gyy8Nas1dccvhoc9wI
92neaZUPrvucQ90AzLfo6r9yacDbYHB1lOyomApUvpJxOgHISGEtc9qGPDrdH19aF0
938fCv2bbQRh+TChgN3IB0o5w0wXaI7YAyAouAv/AzHCoEMpt7OGjFTkjh/ujlPL9O
94+FLuJNsQRHDN0gJo2pcvwGwDCsioMixQ9bZ7ZrUu2BNpEQygyeSbj9ZI1iRvhosO
95JU3rwEECgYEA9MppTYA6A9WQbCCwPH1QMpUAmPNVSWVhUVag4lGOEhdCDRcz9ook
96DohQMKctiEB1luKuvDokxo0uMOfMO9/YwjsRB7qjQip7Th1zMJIjD+A+juLzHK4r
97/RiRtWYGAnF8mptDvE+93JsPb3C/lQLvIhio5GQYWBqPJu6SpeosIskCgYEA7NPi
98Gbffzr2UQhW8BNKmctEEh8yFRVojFo3wwwWxSNUVXGSmSm31CL+Q8h817R+2OkPV
991ZMUOBU4UJiqFt28kIvTDFqbAJlJQGCpY2mY7OLQiD2A+TVLcFrHmoCaPfCAK1Qd
100hQ0PmFK7Mf8qClpA3E5chop/WfKQfiu46sZv1qkCgYAhGdXPcw1lQ1W6KVlrdI6J
101qHhiNlVMDXdxZkNvFxQdAiQeXQrbxaZGiMw/J/wSNpUwCAsUzM/4QVMDrfSCDCzl
102ZtNQtj4pTlFKKNVQthIjrXEIJUw2jp7IJLBfVSJu5iWxSlmId0f3MsiNizN81N69
103P5Rm/doE3+KHoy8VXGsHcQKBgQCkNh62enqjHWypjex6450qS6f6iWN3PRLLVsw0
104TcQpniZblCaBwVCAKmRUnjOEIdL2/4ZLutnwMTaFG/YEOOfAylMiY8jKV38lNmD9
105X4D78CFr9klxgvS2CRwSE03f2NzmLkLxuKaxldvaxPTfjMkgeO1LFMlNExYBhkuH
1067uQpUQKBgQCKX6qMNh2gSdgG7qyxfTFZ4y5EGOBoKe/dE+IcVF3Vnh6DZVbCAbBL
1075EdFWZSrCnDjA4xiKW55mwp95Ud9EZsZAb13L8V9t82eK+UDBoWlb7VRNYpda/x1
1085/i4qQJ28x2UNJDStpYFpnp4Ba1lvXjKngIbDPkjU+hbBJ+BNGAIeg==
109-----END RSA PRIVATE KEY-----";
70 /// Create a mock database to be used in tests 110 /// Create a mock database to be used in tests
71 fn mocked_db() -> Db { 111 fn mocked_db() -> Db {
72 let db = create_database(); 112 let db = create_database();
73 113
114 db.users.write().insert(
115 "mock_transaction_source".to_owned(),
116 User {
117 user_id: MetuId::new("e254275".to_owned()).unwrap(),
118 public_key:
119"-----BEGIN PUBLIC KEY-----
120MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4nU0G4WjkmcQUx0hq6LQ
121uV5Q+ACmUFL/OjoYMDwC/O/6pCd1UZgCfgHN2xEffDPznzcTn8OiFRxr4oWyBiny
122rUpnY4mhy0SQUwoeCw7YkcHAyhCjNT74aR/ohX0MCj0qRRdbt5ZQXM/GC3HJuXE1
123ptSuhFgQxziItamn8maoJ6JUSVEXVO1NOrrjoM3r7Q+BK2B+sX4/bLZ+VG5g1q2n
124EbFdTHS6pHqtZNHQndTmEKwRfh0RYtzEzOXuO6e1gQY42Tujkof40dhGCIU7TeIG
125GHwdFxy1niLkXwtHNjV7lnIOkTbx6+sSPamRfQAlZqUWM2Lf5o+7h3qWP3ENB138
126sQIDAQAB
127-----END PUBLIC KEY-----"
128 .to_owned(),
129 balance: 0,
130 },
131 );
74 db.pending_transactions.write().insert( 132 db.pending_transactions.write().insert(
75 "hash_value".to_owned(), 133 "hash_value".to_owned(),
76 Transaction { 134 Transaction {
135 by: "source_account".to_owned(),
77 source: "source_account".to_owned(), 136 source: "source_account".to_owned(),
78 target: "target_account".to_owned(), 137 target: "target_account".to_owned(),
79 amount: 20, 138 amount: 20,
@@ -95,6 +154,15 @@ mod tests {
95 db 154 db
96 } 155 }
97 156
157 fn mocked_jwt() -> String {
158
159 let claims = Claims {
160 tha: "6692e774eba7fb92dc0fe6cf7347591e".to_owned(),
161 iat: 1516239022,
162 };
163 let header = Header::new(Algorithm::RS256);
164 encode(&header, &claims, &EncodingKey::from_rsa_pem(private_key_pem.as_bytes()).unwrap()).unwrap()
165 }
98 /// Create a mock user that is allowed to be in gradecoin to be used in tests 166 /// Create a mock user that is allowed to be in gradecoin to be used in tests
99 fn priviliged_mocked_user() -> AuthRequest { 167 fn priviliged_mocked_user() -> AuthRequest {
100 AuthRequest { 168 AuthRequest {
@@ -114,6 +182,7 @@ mod tests {
114 /// Create a mock transaction to be used in tests 182 /// Create a mock transaction to be used in tests
115 fn mocked_transaction() -> Transaction { 183 fn mocked_transaction() -> Transaction {
116 Transaction { 184 Transaction {
185 by: "mock_transaction_source".to_owned(),
117 source: "mock_transaction_source".to_owned(), 186 source: "mock_transaction_source".to_owned(),
118 target: "mock_transaction_target".to_owned(), 187 target: "mock_transaction_target".to_owned(),
119 amount: 25, 188 amount: 25,
@@ -125,9 +194,9 @@ mod tests {
125 fn mocked_block() -> Block { 194 fn mocked_block() -> Block {
126 Block { 195 Block {
127 transaction_list: vec!["hash_value".to_owned()], 196 transaction_list: vec!["hash_value".to_owned()],
128 nonce: 560108, 197 nonce: 3831993,
129 timestamp: chrono::NaiveDate::from_ymd(2021, 04, 08).and_hms(12, 30, 30), 198 timestamp: chrono::NaiveDate::from_ymd(2021, 04, 08).and_hms(12, 30, 30),
130 hash: "c7d053f3e5b056ba948db3f5c0d30408fb0c29a328a0c3c1cf435fb68d700000".to_owned(), 199 hash: "2b648ffab5d9af1d5d5fc052fc9e51b882fc4fb0c998608c99232f9282000000".to_owned(),
131 } 200 }
132 } 201 }
133 202
@@ -158,7 +227,7 @@ mod tests {
158 227
159 assert_eq!(res.status(), StatusCode::OK); 228 assert_eq!(res.status(), StatusCode::OK);
160 229
161 let expected_json_body = r#"[{"source":"source_account","target":"target_account","amount":20,"timestamp":"2021-04-09T01:30:30"}]"#; 230 let expected_json_body = r#"[{"by":"source_account","source":"source_account","target":"target_account","amount":20,"timestamp":"2021-04-09T01:30:30"}]"#;
162 231
163 assert_eq!(res.body(), expected_json_body); 232 assert_eq!(res.body(), expected_json_body);
164 } 233 }
@@ -208,10 +277,30 @@ mod tests {
208 async fn post_json_201() { 277 async fn post_json_201() {
209 let db = mocked_db(); 278 let db = mocked_db();
210 let filter = consensus_routes(db.clone()); 279 let filter = consensus_routes(db.clone());
280 let res = warp::test::request()
281 .method("POST")
282 .json(&mocked_transaction())
283 .path("/transaction")
284 .reply(&filter)
285 .await;
286
287 assert_eq!(res.status(), StatusCode::CREATED);
288 assert_eq!(db.pending_transactions.read().len(), 2);
289 }
290
291 /// Test a POST request to /transaction, a resource that exists
292 /// https://tools.ietf.org/html/rfc7231#section-6.3.2
293 /// Should accept the json request, create
294 /// the transaction and add it to pending transactions in the db
295 #[tokio::test]
296 async fn post_auth_json_201() {
297 let db = mocked_db();
298 let filter = consensus_routes(db.clone());
211 299
212 let res = warp::test::request() 300 let res = warp::test::request()
213 .method("POST") 301 .method("POST")
214 .json(&mocked_transaction()) 302 .json(&mocked_transaction())
303 .header("Authorization", format!("Bearer {}", &mocked_jwt()))
215 .path("/transaction") 304 .path("/transaction")
216 .reply(&filter) 305 .reply(&filter)
217 .await; 306 .await;
@@ -220,6 +309,27 @@ mod tests {
220 assert_eq!(db.pending_transactions.read().len(), 2); 309 assert_eq!(db.pending_transactions.read().len(), 2);
221 } 310 }
222 311
312 /// Test a POST request to /transaction, a resource that exists
313 /// https://tools.ietf.org/html/rfc7231#section-6.3.2
314 /// Should accept the json request, create
315 /// the transaction and add it to pending transactions in the db
316 #[tokio::test]
317 async fn post_auth_json_400() {
318 let db = mocked_db();
319 let filter = consensus_routes(db.clone());
320
321 let res = warp::test::request()
322 .method("POST")
323 .json(&mocked_transaction())
324 .header("Authorization", "Bearer aaaaaaaasdlkjaldkasljdaskjlaaaaaaaaaaaaaa")
325 .path("/transaction")
326 .reply(&filter)
327 .await;
328
329 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
330 assert_eq!(db.pending_transactions.read().len(), 1);
331 }
332
223 /// Test a POST request to /block, a resource that exists 333 /// Test a POST request to /block, a resource that exists
224 /// https://tools.ietf.org/html/rfc7231#section-6.3.2 334 /// https://tools.ietf.org/html/rfc7231#section-6.3.2
225 /// Should accept the json request, create 335 /// Should accept the json request, create
@@ -239,7 +349,7 @@ mod tests {
239 assert_eq!(res.status(), StatusCode::CREATED); 349 assert_eq!(res.status(), StatusCode::CREATED);
240 assert_eq!( 350 assert_eq!(
241 *db.blockchain.read().hash, 351 *db.blockchain.read().hash,
242 "c7d053f3e5b056ba948db3f5c0d30408fb0c29a328a0c3c1cf435fb68d700000".to_owned() 352 "2b648ffab5d9af1d5d5fc052fc9e51b882fc4fb0c998608c99232f9282000000".to_owned()
243 ); 353 );
244 } 354 }
245 355
@@ -279,7 +389,7 @@ mod tests {
279 389
280 println!("{:?}", res.body()); 390 println!("{:?}", res.body());
281 assert_eq!(res.status(), StatusCode::CREATED); 391 assert_eq!(res.status(), StatusCode::CREATED);
282 assert_eq!(db.users.read().len(), 1); 392 assert_eq!(db.users.read().len(), 2);
283 } 393 }
284 394
285 /// Test a POST request to /transaction, an endpoint that exists 395 /// Test a POST request to /transaction, an endpoint that exists
@@ -299,7 +409,7 @@ mod tests {
299 409
300 println!("{:?}", res.body()); 410 println!("{:?}", res.body());
301 assert_eq!(res.status(), StatusCode::BAD_REQUEST); 411 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
302 assert_eq!(db.users.read().len(), 0); 412 assert_eq!(db.users.read().len(), 1);
303 } 413 }
304 414
305 /// Test a POST request to /transaction, a resource that exists with a longer than expected 415 /// Test a POST request to /transaction, a resource that exists with a longer than expected