diff options
| -rw-r--r-- | rs/common/src/lib.rs | 16 | ||||
| -rw-r--r-- | rs/server/src/main.rs | 45 |
2 files changed, 42 insertions, 19 deletions
diff --git a/rs/common/src/lib.rs b/rs/common/src/lib.rs index 27205bd..89c3286 100644 --- a/rs/common/src/lib.rs +++ b/rs/common/src/lib.rs | |||
| @@ -136,9 +136,9 @@ fn parse_hex_exact(value: &str, buf: &mut [u8]) -> Result<(), ParseHexError> { | |||
| 136 | for (i, c) in value.bytes().enumerate() { | 136 | for (i, c) in value.bytes().enumerate() { |
| 137 | if let Some(b) = decode_nibble(c) { | 137 | if let Some(b) = decode_nibble(c) { |
| 138 | if i % 2 == 0 { | 138 | if i % 2 == 0 { |
| 139 | buf[i / 2] |= b; | 139 | buf[i / 2] |= b << 4; |
| 140 | } else { | 140 | } else { |
| 141 | buf[i / 2] = b << 4; | 141 | buf[i / 2] |= b; |
| 142 | } | 142 | } |
| 143 | } else { | 143 | } else { |
| 144 | return Err(ParseHexError::InvalidCharacter); | 144 | return Err(ParseHexError::InvalidCharacter); |
| @@ -236,8 +236,16 @@ impl<B: AsRef<[u8]>> fmt::Display for HexFmt<B> { | |||
| 236 | let HexFmt(buf) = self; | 236 | let HexFmt(buf) = self; |
| 237 | for b in buf.as_ref() { | 237 | for b in buf.as_ref() { |
| 238 | let (high, low) = (b >> 4, b & 0xF); | 238 | let (high, low) = (b >> 4, b & 0xF); |
| 239 | let highc = if high < 10 { b'0' + high } else { b'a' + high }; | 239 | let highc = if high < 10 { |
| 240 | let lowc = if low < 10 { b'0' + low } else { b'a' + low }; | 240 | high + b'0' |
| 241 | } else { | ||
| 242 | high - 10 + b'a' | ||
| 243 | }; | ||
| 244 | let lowc = if low < 10 { | ||
| 245 | low + b'0' | ||
| 246 | } else { | ||
| 247 | low - 10 + b'a' | ||
| 248 | }; | ||
| 241 | f.write_char(highc as char)?; | 249 | f.write_char(highc as char)?; |
| 242 | f.write_char(lowc as char)?; | 250 | f.write_char(lowc as char)?; |
| 243 | } | 251 | } |
diff --git a/rs/server/src/main.rs b/rs/server/src/main.rs index a8c6aa5..bdf38ef 100644 --- a/rs/server/src/main.rs +++ b/rs/server/src/main.rs | |||
| @@ -279,7 +279,7 @@ struct BatchRequest { | |||
| 279 | hash_algo: HashAlgo, | 279 | hash_algo: HashAlgo, |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | #[derive(Clone)] | 282 | #[derive(Debug, Clone)] |
| 283 | struct GitLfsJson<T>(Json<T>); | 283 | struct GitLfsJson<T>(Json<T>); |
| 284 | 284 | ||
| 285 | const LFS_MIME: &str = "application/vnd.git-lfs+json"; | 285 | const LFS_MIME: &str = "application/vnd.git-lfs+json"; |
| @@ -306,18 +306,6 @@ fn is_git_lfs_json_mimetype(mimetype: &str) -> bool { | |||
| 306 | let Ok(mime) = mimetype.parse::<mime::Mime>() else { | 306 | let Ok(mime) = mimetype.parse::<mime::Mime>() else { |
| 307 | return false; | 307 | return false; |
| 308 | }; | 308 | }; |
| 309 | println!( | ||
| 310 | "MIME type: {:?}; type: {}, subtype: {}, suffix: {}, charset: {}", | ||
| 311 | mime, | ||
| 312 | mime.type_(), | ||
| 313 | mime.subtype(), | ||
| 314 | mime.suffix() | ||
| 315 | .map(|name| name.to_string()) | ||
| 316 | .unwrap_or("<no suffix>".to_string()), | ||
| 317 | mime.get_param(mime::CHARSET) | ||
| 318 | .map(|name| name.to_string()) | ||
| 319 | .unwrap_or("<no charset>".to_string()) | ||
| 320 | ); | ||
| 321 | if mime.type_() != mime::APPLICATION | 309 | if mime.type_() != mime::APPLICATION |
| 322 | || mime.subtype() != "vnd.git-lfs" | 310 | || mime.subtype() != "vnd.git-lfs" |
| 323 | || mime.suffix() != Some(mime::JSON) | 311 | || mime.suffix() != Some(mime::JSON) |
| @@ -371,7 +359,7 @@ impl<T: Serialize> IntoResponse for GitLfsJson<T> { | |||
| 371 | } | 359 | } |
| 372 | } | 360 | } |
| 373 | 361 | ||
| 374 | #[derive(Serialize)] | 362 | #[derive(Debug, Serialize)] |
| 375 | struct GitLfsErrorData<'a> { | 363 | struct GitLfsErrorData<'a> { |
| 376 | message: &'a str, | 364 | message: &'a str, |
| 377 | } | 365 | } |
| @@ -841,7 +829,6 @@ pub struct VerifyClaimsInput<'a> { | |||
| 841 | pub repo_path: &'a str, | 829 | pub repo_path: &'a str, |
| 842 | } | 830 | } |
| 843 | 831 | ||
| 844 | // Note: expires_at is ignored. | ||
| 845 | fn verify_claims( | 832 | fn verify_claims( |
| 846 | conf: &AuthorizationConfig, | 833 | conf: &AuthorizationConfig, |
| 847 | claims: &VerifyClaimsInput, | 834 | claims: &VerifyClaimsInput, |
| @@ -992,3 +979,31 @@ fn test_deserialize() { | |||
| 992 | expected | 979 | expected |
| 993 | ); | 980 | ); |
| 994 | } | 981 | } |
| 982 | |||
| 983 | #[test] | ||
| 984 | fn test_validate_claims() { | ||
| 985 | let key = "00232f7a019bd34e3921ee6c5f04caf48a4489d1be5d1999038950a7054e0bfea369ce2becc0f13fd3c69f8af2384a25b7ac2d52eb52c33722f3c00c50d4c9c2"; | ||
| 986 | let key: common::Key = key.parse().unwrap(); | ||
| 987 | |||
| 988 | let expires_at = Utc::now() + std::time::Duration::from_secs(5 * 60); | ||
| 989 | let claims = common::Claims { | ||
| 990 | expires_at, | ||
| 991 | repo_path: "lfs-test.git", | ||
| 992 | specific_claims: common::SpecificClaims::BatchApi(common::Operation::Download), | ||
| 993 | }; | ||
| 994 | let tag = common::generate_tag(claims, &key).unwrap(); | ||
| 995 | let header_value = format!("Gitolfs3-Hmac-Sha256 {tag} {}", expires_at.timestamp()); | ||
| 996 | |||
| 997 | let conf = AuthorizationConfig { | ||
| 998 | key, | ||
| 999 | trusted_forwarded_hosts: HashSet::new(), | ||
| 1000 | }; | ||
| 1001 | let claims = VerifyClaimsInput { | ||
| 1002 | repo_path: "lfs-test.git", | ||
| 1003 | specific_claims: common::SpecificClaims::BatchApi(common::Operation::Download), | ||
| 1004 | }; | ||
| 1005 | let mut headers = HeaderMap::new(); | ||
| 1006 | headers.insert(header::AUTHORIZATION, header_value.try_into().unwrap()); | ||
| 1007 | |||
| 1008 | assert!(verify_claims(&conf, &claims, &headers).unwrap()); | ||
| 1009 | } | ||