diff options
-rw-r--r-- | Cargo.lock | 70 | ||||
-rw-r--r-- | Cargo.toml | 8 | ||||
-rw-r--r-- | docs/man/gitolfs3-authenticate.1 | 4 | ||||
-rw-r--r-- | docs/man/gitolfs3-server.1 | 4 | ||||
-rw-r--r-- | docs/man/gitolfs3-shell.1 | 4 | ||||
-rw-r--r-- | gitolfs3-authenticate/Cargo.toml (renamed from git-lfs-authenticate/Cargo.toml) | 4 | ||||
-rw-r--r-- | gitolfs3-authenticate/src/main.rs (renamed from git-lfs-authenticate/src/main.rs) | 15 | ||||
-rw-r--r-- | gitolfs3-common/Cargo.toml (renamed from common/Cargo.toml) | 2 | ||||
-rw-r--r-- | gitolfs3-common/src/lib.rs (renamed from common/src/lib.rs) | 0 | ||||
-rw-r--r-- | gitolfs3-server/Cargo.toml (renamed from server/Cargo.toml) | 4 | ||||
-rw-r--r-- | gitolfs3-server/src/main.rs (renamed from server/src/main.rs) | 77 | ||||
-rw-r--r-- | gitolfs3-shell/Cargo.toml (renamed from shell/Cargo.toml) | 2 | ||||
-rw-r--r-- | gitolfs3-shell/src/main.rs (renamed from shell/src/main.rs) | 2 |
13 files changed, 101 insertions, 95 deletions
@@ -625,16 +625,6 @@ dependencies = [ | |||
625 | ] | 625 | ] |
626 | 626 | ||
627 | [[package]] | 627 | [[package]] |
628 | name = "common" | ||
629 | version = "0.1.0" | ||
630 | dependencies = [ | ||
631 | "chrono", | ||
632 | "hmac-sha256", | ||
633 | "serde", | ||
634 | "subtle", | ||
635 | ] | ||
636 | |||
637 | [[package]] | ||
638 | name = "const-oid" | 628 | name = "const-oid" |
639 | version = "0.9.6" | 629 | version = "0.9.6" |
640 | source = "registry+https://github.com/rust-lang/crates.io-index" | 630 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -887,16 +877,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
887 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" | 877 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" |
888 | 878 | ||
889 | [[package]] | 879 | [[package]] |
890 | name = "git-lfs-authenticate" | 880 | name = "gitolfs3-authenticate" |
891 | version = "0.1.0" | 881 | version = "0.1.0" |
892 | dependencies = [ | 882 | dependencies = [ |
893 | "anyhow", | 883 | "anyhow", |
894 | "chrono", | 884 | "chrono", |
895 | "common", | 885 | "gitolfs3-common", |
886 | "serde_json", | ||
887 | ] | ||
888 | |||
889 | [[package]] | ||
890 | name = "gitolfs3-common" | ||
891 | version = "0.1.0" | ||
892 | dependencies = [ | ||
893 | "chrono", | ||
894 | "hmac-sha256", | ||
895 | "serde", | ||
896 | "subtle", | ||
897 | ] | ||
898 | |||
899 | [[package]] | ||
900 | name = "gitolfs3-server" | ||
901 | version = "0.1.0" | ||
902 | dependencies = [ | ||
903 | "aws-config", | ||
904 | "aws-sdk-s3", | ||
905 | "axum", | ||
906 | "base64", | ||
907 | "chrono", | ||
908 | "gitolfs3-common", | ||
909 | "mime", | ||
910 | "serde", | ||
896 | "serde_json", | 911 | "serde_json", |
912 | "tokio", | ||
913 | "tokio-util", | ||
914 | "tower", | ||
915 | "tracing-subscriber", | ||
897 | ] | 916 | ] |
898 | 917 | ||
899 | [[package]] | 918 | [[package]] |
919 | name = "gitolfs3-shell" | ||
920 | version = "0.1.0" | ||
921 | |||
922 | [[package]] | ||
900 | name = "group" | 923 | name = "group" |
901 | version = "0.12.1" | 924 | version = "0.12.1" |
902 | source = "registry+https://github.com/rust-lang/crates.io-index" | 925 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -1727,25 +1750,6 @@ dependencies = [ | |||
1727 | ] | 1750 | ] |
1728 | 1751 | ||
1729 | [[package]] | 1752 | [[package]] |
1730 | name = "server" | ||
1731 | version = "0.1.0" | ||
1732 | dependencies = [ | ||
1733 | "aws-config", | ||
1734 | "aws-sdk-s3", | ||
1735 | "axum", | ||
1736 | "base64", | ||
1737 | "chrono", | ||
1738 | "common", | ||
1739 | "mime", | ||
1740 | "serde", | ||
1741 | "serde_json", | ||
1742 | "tokio", | ||
1743 | "tokio-util", | ||
1744 | "tower", | ||
1745 | "tracing-subscriber", | ||
1746 | ] | ||
1747 | |||
1748 | [[package]] | ||
1749 | name = "sha1" | 1753 | name = "sha1" |
1750 | version = "0.10.6" | 1754 | version = "0.10.6" |
1751 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1755 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -1777,10 +1781,6 @@ dependencies = [ | |||
1777 | ] | 1781 | ] |
1778 | 1782 | ||
1779 | [[package]] | 1783 | [[package]] |
1780 | name = "shell" | ||
1781 | version = "0.1.0" | ||
1782 | |||
1783 | [[package]] | ||
1784 | name = "signal-hook-registry" | 1784 | name = "signal-hook-registry" |
1785 | version = "1.4.2" | 1785 | version = "1.4.2" |
1786 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1786 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -1,8 +1,8 @@ | |||
1 | [workspace] | 1 | [workspace] |
2 | resolver = "2" | 2 | resolver = "2" |
3 | members = [ | 3 | members = [ |
4 | "common", | 4 | "gitolfs3-common", |
5 | "git-lfs-authenticate", | 5 | "gitolfs3-authenticate", |
6 | "server", | 6 | "gitolfs3-server", |
7 | "shell", | 7 | "gitolfs3-shell", |
8 | ] | 8 | ] |
diff --git a/docs/man/gitolfs3-authenticate.1 b/docs/man/gitolfs3-authenticate.1 index 67151e1..38bf28f 100644 --- a/docs/man/gitolfs3-authenticate.1 +++ b/docs/man/gitolfs3-authenticate.1 | |||
@@ -1,8 +1,8 @@ | |||
1 | .TH GITOLFS3-AUTHENTICATE 1 2024-04-29 Gitolfs3 "Gitolfs3 Manual" | 1 | .TH GITOLFS3-AUTHENTICATE 1 2024-04-29 Gitolfs3 "Gitolfs3 Manual" |
2 | .SH NAME | 2 | .SH NAME |
3 | git-lfs-authenticate \- Git LFS authentication agent for Gitolfs3 | 3 | gitolfs3-authenticate \- Git LFS authentication agent for Gitolfs3 |
4 | .SH SYNOPSIS | 4 | .SH SYNOPSIS |
5 | .B git-lfs-authenticate | 5 | .B gitolfs3-authenticate |
6 | <repository> | 6 | <repository> |
7 | upload/download | 7 | upload/download |
8 | .SH DESCRIPTION | 8 | .SH DESCRIPTION |
diff --git a/docs/man/gitolfs3-server.1 b/docs/man/gitolfs3-server.1 index 4f384cf..f141bce 100644 --- a/docs/man/gitolfs3-server.1 +++ b/docs/man/gitolfs3-server.1 | |||
@@ -1,8 +1,8 @@ | |||
1 | .TH GITOLFS3-SERVER 1 2024-04-29 Gitolfs3 "Gitolfs3 Manual" | 1 | .TH GITOLFS3-SERVER 1 2024-04-29 Gitolfs3 "Gitolfs3 Manual" |
2 | .SH NAME | 2 | .SH NAME |
3 | server \- Gitolfs3 Git LFS server | 3 | gitolfs3-server \- Gitolfs3 Git LFS server |
4 | .SH SYNOPSIS | 4 | .SH SYNOPSIS |
5 | .B server | 5 | .B gitolfs3-server |
6 | .SH DESCRIPTION | 6 | .SH DESCRIPTION |
7 | .B server | 7 | .B server |
8 | is the Gitolfs3 Git LFS server. It is primarily configured using environment | 8 | is the Gitolfs3 Git LFS server. It is primarily configured using environment |
diff --git a/docs/man/gitolfs3-shell.1 b/docs/man/gitolfs3-shell.1 index 56eac31..a626682 100644 --- a/docs/man/gitolfs3-shell.1 +++ b/docs/man/gitolfs3-shell.1 | |||
@@ -1,8 +1,8 @@ | |||
1 | .TH GITOLFS3-SHELL 1 2024-04-29 Gitolfs3 "Gitolfs3 Manual" | 1 | .TH GITOLFS3-SHELL 1 2024-04-29 Gitolfs3 "Gitolfs3 Manual" |
2 | .SH NAME | 2 | .SH NAME |
3 | shell \- Gitolfs3 shell | 3 | gitolfs3-shell \- Gitolfs3 shell |
4 | .SH SYNOPSIS | 4 | .SH SYNOPSIS |
5 | .B shell | 5 | .B gitolfs3-shell |
6 | -c <command> | 6 | -c <command> |
7 | .SH DESCRIPTION | 7 | .SH DESCRIPTION |
8 | .B shell | 8 | .B shell |
diff --git a/git-lfs-authenticate/Cargo.toml b/gitolfs3-authenticate/Cargo.toml index 15feba8..5725abc 100644 --- a/git-lfs-authenticate/Cargo.toml +++ b/gitolfs3-authenticate/Cargo.toml | |||
@@ -1,10 +1,10 @@ | |||
1 | [package] | 1 | [package] |
2 | name = "git-lfs-authenticate" | 2 | name = "gitolfs3-authenticate" |
3 | version = "0.1.0" | 3 | version = "0.1.0" |
4 | edition = "2021" | 4 | edition = "2021" |
5 | 5 | ||
6 | [dependencies] | 6 | [dependencies] |
7 | anyhow = "1.0" | 7 | anyhow = "1.0" |
8 | chrono = "0.4" | 8 | chrono = "0.4" |
9 | common = { path = "../common" } | 9 | gitolfs3-common = { path = "../gitolfs3-common" } |
10 | serde_json = "1" | 10 | serde_json = "1" |
diff --git a/git-lfs-authenticate/src/main.rs b/gitolfs3-authenticate/src/main.rs index c9094a1..771f185 100644 --- a/git-lfs-authenticate/src/main.rs +++ b/gitolfs3-authenticate/src/main.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | use anyhow::{anyhow, bail, Result}; | 1 | use anyhow::{anyhow, bail, Result}; |
2 | use chrono::Utc; | 2 | use chrono::Utc; |
3 | use gitolfs3_common::{generate_tag, load_key, Claims, Key, Operation, SpecificClaims}; | ||
3 | use serde_json::json; | 4 | use serde_json::json; |
4 | use std::{process::ExitCode, time::Duration}; | 5 | use std::{process::ExitCode, time::Duration}; |
5 | 6 | ||
@@ -28,9 +29,9 @@ fn main() -> ExitCode { | |||
28 | } | 29 | } |
29 | 30 | ||
30 | let expires_at = Utc::now() + Duration::from_secs(5 * 60); | 31 | let expires_at = Utc::now() + Duration::from_secs(5 * 60); |
31 | let Some(tag) = common::generate_tag( | 32 | let Some(tag) = generate_tag( |
32 | common::Claims { | 33 | Claims { |
33 | specific_claims: common::SpecificClaims::BatchApi(operation), | 34 | specific_claims: SpecificClaims::BatchApi(operation), |
34 | repo_path: &repo_name, | 35 | repo_path: &repo_name, |
35 | expires_at, | 36 | expires_at, |
36 | }, | 37 | }, |
@@ -57,7 +58,7 @@ fn main() -> ExitCode { | |||
57 | 58 | ||
58 | struct Config { | 59 | struct Config { |
59 | href_base: String, | 60 | href_base: String, |
60 | key: common::Key, | 61 | key: Key, |
61 | } | 62 | } |
62 | 63 | ||
63 | impl Config { | 64 | impl Config { |
@@ -72,15 +73,15 @@ impl Config { | |||
72 | let Ok(key_path) = std::env::var("GITOLFS3_KEY_PATH") else { | 73 | let Ok(key_path) = std::env::var("GITOLFS3_KEY_PATH") else { |
73 | bail!("key path not provided"); | 74 | bail!("key path not provided"); |
74 | }; | 75 | }; |
75 | let key = common::load_key(&key_path).map_err(|e| anyhow!("failed to load key: {e}"))?; | 76 | let key = load_key(&key_path).map_err(|e| anyhow!("failed to load key: {e}"))?; |
76 | 77 | ||
77 | Ok(Self { href_base, key }) | 78 | Ok(Self { href_base, key }) |
78 | } | 79 | } |
79 | } | 80 | } |
80 | 81 | ||
81 | fn parse_cmdline() -> Result<(String, common::Operation)> { | 82 | fn parse_cmdline() -> Result<(String, Operation)> { |
82 | let [repo_path, op_str] = get_cmdline_args::<2>()?; | 83 | let [repo_path, op_str] = get_cmdline_args::<2>()?; |
83 | let op: common::Operation = op_str | 84 | let op: Operation = op_str |
84 | .parse() | 85 | .parse() |
85 | .map_err(|e| anyhow!("unknown operation: {e}"))?; | 86 | .map_err(|e| anyhow!("unknown operation: {e}"))?; |
86 | validate_repo_path(&repo_path).map_err(|e| anyhow!("invalid repository name: {e}"))?; | 87 | validate_repo_path(&repo_path).map_err(|e| anyhow!("invalid repository name: {e}"))?; |
diff --git a/common/Cargo.toml b/gitolfs3-common/Cargo.toml index 20d9bdd..5724732 100644 --- a/common/Cargo.toml +++ b/gitolfs3-common/Cargo.toml | |||
@@ -1,5 +1,5 @@ | |||
1 | [package] | 1 | [package] |
2 | name = "common" | 2 | name = "gitolfs3-common" |
3 | version = "0.1.0" | 3 | version = "0.1.0" |
4 | edition = "2021" | 4 | edition = "2021" |
5 | 5 | ||
diff --git a/common/src/lib.rs b/gitolfs3-common/src/lib.rs index 917f566..917f566 100644 --- a/common/src/lib.rs +++ b/gitolfs3-common/src/lib.rs | |||
diff --git a/server/Cargo.toml b/gitolfs3-server/Cargo.toml index edb76d8..04edeea 100644 --- a/server/Cargo.toml +++ b/gitolfs3-server/Cargo.toml | |||
@@ -1,5 +1,5 @@ | |||
1 | [package] | 1 | [package] |
2 | name = "server" | 2 | name = "gitolfs3-server" |
3 | version = "0.1.0" | 3 | version = "0.1.0" |
4 | edition = "2021" | 4 | edition = "2021" |
5 | 5 | ||
@@ -9,7 +9,7 @@ aws-sdk-s3 = "1.12.0" | |||
9 | axum = "0.7" | 9 | axum = "0.7" |
10 | base64 = "0.21" | 10 | base64 = "0.21" |
11 | chrono = { version = "0.4", features = ["serde"] } | 11 | chrono = { version = "0.4", features = ["serde"] } |
12 | common = { path = "../common" } | 12 | gitolfs3-common = { path = "../gitolfs3-common" } |
13 | mime = "0.3" | 13 | mime = "0.3" |
14 | serde = { version = "1", features = ["derive"] } | 14 | serde = { version = "1", features = ["derive"] } |
15 | serde_json = "1" | 15 | serde_json = "1" |
diff --git a/server/src/main.rs b/gitolfs3-server/src/main.rs index 7371c0d..b05a0c8 100644 --- a/server/src/main.rs +++ b/gitolfs3-server/src/main.rs | |||
@@ -9,6 +9,9 @@ use axum::{ | |||
9 | }; | 9 | }; |
10 | use base64::prelude::*; | 10 | use base64::prelude::*; |
11 | use chrono::{DateTime, Utc}; | 11 | use chrono::{DateTime, Utc}; |
12 | use gitolfs3_common::{ | ||
13 | generate_tag, load_key, Claims, Digest, HexByte, Key, Oid, Operation, SpecificClaims, | ||
14 | }; | ||
12 | use serde::{ | 15 | use serde::{ |
13 | de::{self, DeserializeOwned}, | 16 | de::{self, DeserializeOwned}, |
14 | Deserialize, Serialize, | 17 | Deserialize, Serialize, |
@@ -228,7 +231,7 @@ impl Config { | |||
228 | Ok(s3_client) => s3_client, | 231 | Ok(s3_client) => s3_client, |
229 | Err(e) => return Err(format!("failed to create S3 client: {e}")), | 232 | Err(e) => return Err(format!("failed to create S3 client: {e}")), |
230 | }; | 233 | }; |
231 | let key = match common::load_key(&env.key_path) { | 234 | let key = match load_key(&env.key_path) { |
232 | Ok(key) => key, | 235 | Ok(key) => key, |
233 | Err(e) => return Err(format!("failed to load Gitolfs3 key: {e}")), | 236 | Err(e) => return Err(format!("failed to load Gitolfs3 key: {e}")), |
234 | }; | 237 | }; |
@@ -286,7 +289,7 @@ impl Default for HashAlgo { | |||
286 | 289 | ||
287 | #[derive(Debug, Deserialize, PartialEq, Eq, Clone)] | 290 | #[derive(Debug, Deserialize, PartialEq, Eq, Clone)] |
288 | struct BatchRequestObject { | 291 | struct BatchRequestObject { |
289 | oid: common::Oid, | 292 | oid: Oid, |
290 | size: i64, | 293 | size: i64, |
291 | } | 294 | } |
292 | 295 | ||
@@ -301,7 +304,7 @@ fn default_transfers() -> Vec<TransferAdapter> { | |||
301 | 304 | ||
302 | #[derive(Debug, Deserialize, PartialEq, Eq, Clone)] | 305 | #[derive(Debug, Deserialize, PartialEq, Eq, Clone)] |
303 | struct BatchRequest { | 306 | struct BatchRequest { |
304 | operation: common::Operation, | 307 | operation: Operation, |
305 | #[serde(default = "default_transfers")] | 308 | #[serde(default = "default_transfers")] |
306 | transfers: Vec<TransferAdapter>, | 309 | transfers: Vec<TransferAdapter>, |
307 | objects: Vec<BatchRequestObject>, | 310 | objects: Vec<BatchRequestObject>, |
@@ -426,7 +429,7 @@ struct BatchResponseObjectError { | |||
426 | 429 | ||
427 | #[derive(Debug, Serialize, Clone)] | 430 | #[derive(Debug, Serialize, Clone)] |
428 | struct BatchResponseObject { | 431 | struct BatchResponseObject { |
429 | oid: common::Oid, | 432 | oid: Oid, |
430 | size: i64, | 433 | size: i64, |
431 | #[serde(skip_serializing_if = "Option::is_none")] | 434 | #[serde(skip_serializing_if = "Option::is_none")] |
432 | authenticated: Option<bool>, | 435 | authenticated: Option<bool>, |
@@ -457,11 +460,11 @@ struct BatchResponse { | |||
457 | hash_algo: HashAlgo, | 460 | hash_algo: HashAlgo, |
458 | } | 461 | } |
459 | 462 | ||
460 | fn validate_checksum(oid: common::Oid, obj: &HeadObjectOutput) -> bool { | 463 | fn validate_checksum(oid: Oid, obj: &HeadObjectOutput) -> bool { |
461 | if let Some(checksum) = obj.checksum_sha256() { | 464 | if let Some(checksum) = obj.checksum_sha256() { |
462 | if let Ok(checksum) = BASE64_STANDARD.decode(checksum) { | 465 | if let Ok(checksum) = BASE64_STANDARD.decode(checksum) { |
463 | if let Ok(checksum32b) = TryInto::<[u8; 32]>::try_into(checksum) { | 466 | if let Ok(checksum32b) = TryInto::<[u8; 32]>::try_into(checksum) { |
464 | return common::Oid::from(checksum32b) == oid; | 467 | return Oid::from(checksum32b) == oid; |
465 | } | 468 | } |
466 | } | 469 | } |
467 | } | 470 | } |
@@ -480,7 +483,7 @@ async fn handle_upload_object( | |||
480 | repo: &str, | 483 | repo: &str, |
481 | obj: &BatchRequestObject, | 484 | obj: &BatchRequestObject, |
482 | ) -> Option<BatchResponseObject> { | 485 | ) -> Option<BatchResponseObject> { |
483 | let (oid0, oid1) = (common::HexByte(obj.oid[0]), common::HexByte(obj.oid[1])); | 486 | let (oid0, oid1) = (HexByte(obj.oid[0]), HexByte(obj.oid[1])); |
484 | let full_path = format!("{repo}/lfs/objects/{}/{}/{}", oid0, oid1, obj.oid); | 487 | let full_path = format!("{repo}/lfs/objects/{}/{}/{}", oid0, oid1, obj.oid); |
485 | 488 | ||
486 | match state | 489 | match state |
@@ -559,7 +562,7 @@ async fn handle_download_object( | |||
559 | obj: &BatchRequestObject, | 562 | obj: &BatchRequestObject, |
560 | trusted: bool, | 563 | trusted: bool, |
561 | ) -> BatchResponseObject { | 564 | ) -> BatchResponseObject { |
562 | let (oid0, oid1) = (common::HexByte(obj.oid[0]), common::HexByte(obj.oid[1])); | 565 | let (oid0, oid1) = (HexByte(obj.oid[0]), HexByte(obj.oid[1])); |
563 | let full_path = format!("{repo}/lfs/objects/{}/{}/{}", oid0, oid1, obj.oid); | 566 | let full_path = format!("{repo}/lfs/objects/{}/{}/{}", oid0, oid1, obj.oid); |
564 | 567 | ||
565 | let result = match state | 568 | let result = match state |
@@ -671,9 +674,9 @@ async fn handle_download_object( | |||
671 | } | 674 | } |
672 | } | 675 | } |
673 | 676 | ||
674 | let Some(tag) = common::generate_tag( | 677 | let Some(tag) = generate_tag( |
675 | common::Claims { | 678 | Claims { |
676 | specific_claims: common::SpecificClaims::Download(obj.oid), | 679 | specific_claims: SpecificClaims::Download(obj.oid), |
677 | repo_path: repo, | 680 | repo_path: repo, |
678 | expires_at, | 681 | expires_at, |
679 | }, | 682 | }, |
@@ -688,8 +691,8 @@ async fn handle_download_object( | |||
688 | 691 | ||
689 | let upload_path = format!( | 692 | let upload_path = format!( |
690 | "{repo}/info/lfs/objects/{}/{}/{}", | 693 | "{repo}/info/lfs/objects/{}/{}/{}", |
691 | common::HexByte(obj.oid[0]), | 694 | HexByte(obj.oid[0]), |
692 | common::HexByte(obj.oid[1]), | 695 | HexByte(obj.oid[1]), |
693 | obj.oid, | 696 | obj.oid, |
694 | ); | 697 | ); |
695 | 698 | ||
@@ -718,7 +721,7 @@ async fn handle_download_object( | |||
718 | 721 | ||
719 | struct AuthorizationConfig { | 722 | struct AuthorizationConfig { |
720 | trusted_forwarded_hosts: HashSet<String>, | 723 | trusted_forwarded_hosts: HashSet<String>, |
721 | key: common::Key, | 724 | key: Key, |
722 | } | 725 | } |
723 | 726 | ||
724 | struct Trusted(bool); | 727 | struct Trusted(bool); |
@@ -749,7 +752,7 @@ fn authorize_batch( | |||
749 | conf: &AuthorizationConfig, | 752 | conf: &AuthorizationConfig, |
750 | repo_path: &str, | 753 | repo_path: &str, |
751 | public: bool, | 754 | public: bool, |
752 | operation: common::Operation, | 755 | operation: Operation, |
753 | headers: &HeaderMap, | 756 | headers: &HeaderMap, |
754 | ) -> Result<Trusted, GitLfsErrorResponse<'static>> { | 757 | ) -> Result<Trusted, GitLfsErrorResponse<'static>> { |
755 | // - No authentication required for downloading exported repos | 758 | // - No authentication required for downloading exported repos |
@@ -759,7 +762,7 @@ fn authorize_batch( | |||
759 | // - No authentication required for downloading from any repo | 762 | // - No authentication required for downloading from any repo |
760 | 763 | ||
761 | let claims = VerifyClaimsInput { | 764 | let claims = VerifyClaimsInput { |
762 | specific_claims: common::SpecificClaims::BatchApi(operation), | 765 | specific_claims: SpecificClaims::BatchApi(operation), |
763 | repo_path, | 766 | repo_path, |
764 | }; | 767 | }; |
765 | if !verify_claims(conf, &claims, headers)? { | 768 | if !verify_claims(conf, &claims, headers)? { |
@@ -771,12 +774,12 @@ fn authorize_batch( | |||
771 | fn authorize_batch_unauthenticated( | 774 | fn authorize_batch_unauthenticated( |
772 | conf: &AuthorizationConfig, | 775 | conf: &AuthorizationConfig, |
773 | public: bool, | 776 | public: bool, |
774 | operation: common::Operation, | 777 | operation: Operation, |
775 | headers: &HeaderMap, | 778 | headers: &HeaderMap, |
776 | ) -> Result<Trusted, GitLfsErrorResponse<'static>> { | 779 | ) -> Result<Trusted, GitLfsErrorResponse<'static>> { |
777 | let trusted = forwarded_from_trusted_host(headers, &conf.trusted_forwarded_hosts)?; | 780 | let trusted = forwarded_from_trusted_host(headers, &conf.trusted_forwarded_hosts)?; |
778 | match operation { | 781 | match operation { |
779 | common::Operation::Upload => { | 782 | Operation::Upload => { |
780 | // Trusted users can clone all repositories (by virtue of accessing the server via a | 783 | // Trusted users can clone all repositories (by virtue of accessing the server via a |
781 | // trusted network). However, they can not push without proper authentication. Untrusted | 784 | // trusted network). However, they can not push without proper authentication. Untrusted |
782 | // users who are also not authenticated should not need to know which repositories exists. | 785 | // users who are also not authenticated should not need to know which repositories exists. |
@@ -790,7 +793,7 @@ fn authorize_batch_unauthenticated( | |||
790 | "Authentication required to upload", | 793 | "Authentication required to upload", |
791 | )) | 794 | )) |
792 | } | 795 | } |
793 | common::Operation::Download => { | 796 | Operation::Download => { |
794 | // Again, trusted users can see all repos. For untrusted users, we first need to check | 797 | // Again, trusted users can see all repos. For untrusted users, we first need to check |
795 | // whether the repo is public before we authorize. If the user is untrusted and the | 798 | // whether the repo is public before we authorize. If the user is untrusted and the |
796 | // repo isn't public, we just act like it doesn't even exist. | 799 | // repo isn't public, we just act like it doesn't even exist. |
@@ -869,10 +872,10 @@ async fn batch( | |||
869 | }; | 872 | }; |
870 | for obj in payload.objects { | 873 | for obj in payload.objects { |
871 | match payload.operation { | 874 | match payload.operation { |
872 | common::Operation::Download => resp | 875 | Operation::Download => resp |
873 | .objects | 876 | .objects |
874 | .push(handle_download_object(&state, &repo, &obj, trusted).await), | 877 | .push(handle_download_object(&state, &repo, &obj, trusted).await), |
875 | common::Operation::Upload => { | 878 | Operation::Upload => { |
876 | if let Some(obj_resp) = handle_upload_object(&state, &repo, &obj).await { | 879 | if let Some(obj_resp) = handle_upload_object(&state, &repo, &obj).await { |
877 | resp.objects.push(obj_resp); | 880 | resp.objects.push(obj_resp); |
878 | } | 881 | } |
@@ -885,9 +888,9 @@ async fn batch( | |||
885 | #[derive(Deserialize, Copy, Clone)] | 888 | #[derive(Deserialize, Copy, Clone)] |
886 | #[serde(remote = "Self")] | 889 | #[serde(remote = "Self")] |
887 | struct FileParams { | 890 | struct FileParams { |
888 | oid0: common::HexByte, | 891 | oid0: HexByte, |
889 | oid1: common::HexByte, | 892 | oid1: HexByte, |
890 | oid: common::Oid, | 893 | oid: Oid, |
891 | } | 894 | } |
892 | 895 | ||
893 | impl<'de> Deserialize<'de> for FileParams { | 896 | impl<'de> Deserialize<'de> for FileParams { |
@@ -896,8 +899,8 @@ impl<'de> Deserialize<'de> for FileParams { | |||
896 | D: serde::Deserializer<'de>, | 899 | D: serde::Deserializer<'de>, |
897 | { | 900 | { |
898 | let unchecked @ FileParams { | 901 | let unchecked @ FileParams { |
899 | oid0: common::HexByte(oid0), | 902 | oid0: HexByte(oid0), |
900 | oid1: common::HexByte(oid1), | 903 | oid1: HexByte(oid1), |
901 | oid, | 904 | oid, |
902 | } = FileParams::deserialize(deserializer)?; | 905 | } = FileParams::deserialize(deserializer)?; |
903 | if oid0 != oid.as_bytes()[0] { | 906 | if oid0 != oid.as_bytes()[0] { |
@@ -915,7 +918,7 @@ impl<'de> Deserialize<'de> for FileParams { | |||
915 | } | 918 | } |
916 | 919 | ||
917 | pub struct VerifyClaimsInput<'a> { | 920 | pub struct VerifyClaimsInput<'a> { |
918 | pub specific_claims: common::SpecificClaims, | 921 | pub specific_claims: SpecificClaims, |
919 | pub repo_path: &'a str, | 922 | pub repo_path: &'a str, |
920 | } | 923 | } |
921 | 924 | ||
@@ -935,11 +938,11 @@ fn verify_claims( | |||
935 | .strip_prefix("Gitolfs3-Hmac-Sha256 ") | 938 | .strip_prefix("Gitolfs3-Hmac-Sha256 ") |
936 | .ok_or(INVALID_AUTHZ_HEADER)?; | 939 | .ok_or(INVALID_AUTHZ_HEADER)?; |
937 | let (tag, expires_at) = val.split_once(' ').ok_or(INVALID_AUTHZ_HEADER)?; | 940 | let (tag, expires_at) = val.split_once(' ').ok_or(INVALID_AUTHZ_HEADER)?; |
938 | let tag: common::Digest<32> = tag.parse().map_err(|_| INVALID_AUTHZ_HEADER)?; | 941 | let tag: Digest<32> = tag.parse().map_err(|_| INVALID_AUTHZ_HEADER)?; |
939 | let expires_at: i64 = expires_at.parse().map_err(|_| INVALID_AUTHZ_HEADER)?; | 942 | let expires_at: i64 = expires_at.parse().map_err(|_| INVALID_AUTHZ_HEADER)?; |
940 | let expires_at = DateTime::<Utc>::from_timestamp(expires_at, 0).ok_or(INVALID_AUTHZ_HEADER)?; | 943 | let expires_at = DateTime::<Utc>::from_timestamp(expires_at, 0).ok_or(INVALID_AUTHZ_HEADER)?; |
941 | let expected_tag = common::generate_tag( | 944 | let expected_tag = generate_tag( |
942 | common::Claims { | 945 | Claims { |
943 | specific_claims: claims.specific_claims, | 946 | specific_claims: claims.specific_claims, |
944 | repo_path: claims.repo_path, | 947 | repo_path: claims.repo_path, |
945 | expires_at, | 948 | expires_at, |
@@ -957,11 +960,11 @@ fn verify_claims( | |||
957 | fn authorize_get( | 960 | fn authorize_get( |
958 | conf: &AuthorizationConfig, | 961 | conf: &AuthorizationConfig, |
959 | repo_path: &str, | 962 | repo_path: &str, |
960 | oid: common::Oid, | 963 | oid: Oid, |
961 | headers: &HeaderMap, | 964 | headers: &HeaderMap, |
962 | ) -> Result<(), GitLfsErrorResponse<'static>> { | 965 | ) -> Result<(), GitLfsErrorResponse<'static>> { |
963 | let claims = VerifyClaimsInput { | 966 | let claims = VerifyClaimsInput { |
964 | specific_claims: common::SpecificClaims::Download(oid), | 967 | specific_claims: SpecificClaims::Download(oid), |
965 | repo_path, | 968 | repo_path, |
966 | }; | 969 | }; |
967 | if !verify_claims(conf, &claims, headers)? { | 970 | if !verify_claims(conf, &claims, headers)? { |
@@ -1100,7 +1103,7 @@ fn test_deserialize() { | |||
1100 | let json = r#"{"operation":"upload","objects":[{"oid":"8f4123f9a7181f488c5e111d82cefd992e461ae5df01fd2254399e6e670b2d3c","size":170904}], | 1103 | let json = r#"{"operation":"upload","objects":[{"oid":"8f4123f9a7181f488c5e111d82cefd992e461ae5df01fd2254399e6e670b2d3c","size":170904}], |
1101 | "transfers":["lfs-standalone-file","basic","ssh"],"ref":{"name":"refs/heads/main"},"hash_algo":"sha256"}"#; | 1104 | "transfers":["lfs-standalone-file","basic","ssh"],"ref":{"name":"refs/heads/main"},"hash_algo":"sha256"}"#; |
1102 | let expected = BatchRequest { | 1105 | let expected = BatchRequest { |
1103 | operation: common::Operation::Upload, | 1106 | operation: Operation::Upload, |
1104 | objects: vec![BatchRequestObject { | 1107 | objects: vec![BatchRequestObject { |
1105 | oid: "8f4123f9a7181f488c5e111d82cefd992e461ae5df01fd2254399e6e670b2d3c" | 1108 | oid: "8f4123f9a7181f488c5e111d82cefd992e461ae5df01fd2254399e6e670b2d3c" |
1106 | .parse() | 1109 | .parse() |
@@ -1123,14 +1126,14 @@ fn test_deserialize() { | |||
1123 | #[test] | 1126 | #[test] |
1124 | fn test_validate_claims() { | 1127 | fn test_validate_claims() { |
1125 | let key = "00232f7a019bd34e3921ee6c5f04caf48a4489d1be5d1999038950a7054e0bfea369ce2becc0f13fd3c69f8af2384a25b7ac2d52eb52c33722f3c00c50d4c9c2"; | 1128 | let key = "00232f7a019bd34e3921ee6c5f04caf48a4489d1be5d1999038950a7054e0bfea369ce2becc0f13fd3c69f8af2384a25b7ac2d52eb52c33722f3c00c50d4c9c2"; |
1126 | let key: common::Key = key.parse().unwrap(); | 1129 | let key: Key = key.parse().unwrap(); |
1127 | 1130 | ||
1128 | let claims = common::Claims { | 1131 | let claims = Claims { |
1129 | expires_at: Utc::now() + std::time::Duration::from_secs(5 * 60), | 1132 | expires_at: Utc::now() + std::time::Duration::from_secs(5 * 60), |
1130 | repo_path: "lfs-test.git", | 1133 | repo_path: "lfs-test.git", |
1131 | specific_claims: common::SpecificClaims::BatchApi(common::Operation::Download), | 1134 | specific_claims: SpecificClaims::BatchApi(Operation::Download), |
1132 | }; | 1135 | }; |
1133 | let tag = common::generate_tag(claims, &key).unwrap(); | 1136 | let tag = generate_tag(claims, &key).unwrap(); |
1134 | let header_value = format!( | 1137 | let header_value = format!( |
1135 | "Gitolfs3-Hmac-Sha256 {tag} {}", | 1138 | "Gitolfs3-Hmac-Sha256 {tag} {}", |
1136 | claims.expires_at.timestamp() | 1139 | claims.expires_at.timestamp() |
diff --git a/shell/Cargo.toml b/gitolfs3-shell/Cargo.toml index 0dcb6d6..c0b5d3a 100644 --- a/shell/Cargo.toml +++ b/gitolfs3-shell/Cargo.toml | |||
@@ -1,5 +1,5 @@ | |||
1 | [package] | 1 | [package] |
2 | name = "shell" | 2 | name = "gitolfs3-shell" |
3 | version = "0.1.0" | 3 | version = "0.1.0" |
4 | edition = "2021" | 4 | edition = "2021" |
5 | 5 | ||
diff --git a/shell/src/main.rs b/gitolfs3-shell/src/main.rs index 4a98828..f0c5f34 100644 --- a/shell/src/main.rs +++ b/gitolfs3-shell/src/main.rs | |||
@@ -46,6 +46,8 @@ fn main() -> ExitCode { | |||
46 | let repository = cmd[0].trim_start_matches('/'); | 46 | let repository = cmd[0].trim_start_matches('/'); |
47 | args.push(repository); | 47 | args.push(repository); |
48 | } else if program == "git-lfs-authenticate" { | 48 | } else if program == "git-lfs-authenticate" { |
49 | program.clear(); | ||
50 | program.push_str("gitolfs3-authenticate"); | ||
49 | if cmd.len() != 2 { | 51 | if cmd.len() != 2 { |
50 | eprintln!("Bad command"); | 52 | eprintln!("Bad command"); |
51 | return bad_usage; | 53 | return bad_usage; |