aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock70
-rw-r--r--Cargo.toml8
-rw-r--r--docs/man/gitolfs3-authenticate.14
-rw-r--r--docs/man/gitolfs3-server.14
-rw-r--r--docs/man/gitolfs3-shell.14
-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
diff --git a/Cargo.lock b/Cargo.lock
index 5f04d2d..00f856e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -625,16 +625,6 @@ dependencies = [
625] 625]
626 626
627[[package]] 627[[package]]
628name = "common"
629version = "0.1.0"
630dependencies = [
631 "chrono",
632 "hmac-sha256",
633 "serde",
634 "subtle",
635]
636
637[[package]]
638name = "const-oid" 628name = "const-oid"
639version = "0.9.6" 629version = "0.9.6"
640source = "registry+https://github.com/rust-lang/crates.io-index" 630source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -887,16 +877,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
887checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" 877checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
888 878
889[[package]] 879[[package]]
890name = "git-lfs-authenticate" 880name = "gitolfs3-authenticate"
891version = "0.1.0" 881version = "0.1.0"
892dependencies = [ 882dependencies = [
893 "anyhow", 883 "anyhow",
894 "chrono", 884 "chrono",
895 "common", 885 "gitolfs3-common",
886 "serde_json",
887]
888
889[[package]]
890name = "gitolfs3-common"
891version = "0.1.0"
892dependencies = [
893 "chrono",
894 "hmac-sha256",
895 "serde",
896 "subtle",
897]
898
899[[package]]
900name = "gitolfs3-server"
901version = "0.1.0"
902dependencies = [
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]]
919name = "gitolfs3-shell"
920version = "0.1.0"
921
922[[package]]
900name = "group" 923name = "group"
901version = "0.12.1" 924version = "0.12.1"
902source = "registry+https://github.com/rust-lang/crates.io-index" 925source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1727,25 +1750,6 @@ dependencies = [
1727] 1750]
1728 1751
1729[[package]] 1752[[package]]
1730name = "server"
1731version = "0.1.0"
1732dependencies = [
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]]
1749name = "sha1" 1753name = "sha1"
1750version = "0.10.6" 1754version = "0.10.6"
1751source = "registry+https://github.com/rust-lang/crates.io-index" 1755source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1777,10 +1781,6 @@ dependencies = [
1777] 1781]
1778 1782
1779[[package]] 1783[[package]]
1780name = "shell"
1781version = "0.1.0"
1782
1783[[package]]
1784name = "signal-hook-registry" 1784name = "signal-hook-registry"
1785version = "1.4.2" 1785version = "1.4.2"
1786source = "registry+https://github.com/rust-lang/crates.io-index" 1786source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 6439e6b..2fac4ee 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,8 +1,8 @@
1[workspace] 1[workspace]
2resolver = "2" 2resolver = "2"
3members = [ 3members = [
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
3git-lfs-authenticate \- Git LFS authentication agent for Gitolfs3 3gitolfs3-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>
7upload/download 7upload/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
3server \- Gitolfs3 Git LFS server 3gitolfs3-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
8is the Gitolfs3 Git LFS server. It is primarily configured using environment 8is 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
3shell \- Gitolfs3 shell 3gitolfs3-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]
2name = "git-lfs-authenticate" 2name = "gitolfs3-authenticate"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5 5
6[dependencies] 6[dependencies]
7anyhow = "1.0" 7anyhow = "1.0"
8chrono = "0.4" 8chrono = "0.4"
9common = { path = "../common" } 9gitolfs3-common = { path = "../gitolfs3-common" }
10serde_json = "1" 10serde_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 @@
1use anyhow::{anyhow, bail, Result}; 1use anyhow::{anyhow, bail, Result};
2use chrono::Utc; 2use chrono::Utc;
3use gitolfs3_common::{generate_tag, load_key, Claims, Key, Operation, SpecificClaims};
3use serde_json::json; 4use serde_json::json;
4use std::{process::ExitCode, time::Duration}; 5use 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
58struct Config { 59struct Config {
59 href_base: String, 60 href_base: String,
60 key: common::Key, 61 key: Key,
61} 62}
62 63
63impl Config { 64impl 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
81fn parse_cmdline() -> Result<(String, common::Operation)> { 82fn 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]
2name = "common" 2name = "gitolfs3-common"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "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]
2name = "server" 2name = "gitolfs3-server"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5 5
@@ -9,7 +9,7 @@ aws-sdk-s3 = "1.12.0"
9axum = "0.7" 9axum = "0.7"
10base64 = "0.21" 10base64 = "0.21"
11chrono = { version = "0.4", features = ["serde"] } 11chrono = { version = "0.4", features = ["serde"] }
12common = { path = "../common" } 12gitolfs3-common = { path = "../gitolfs3-common" }
13mime = "0.3" 13mime = "0.3"
14serde = { version = "1", features = ["derive"] } 14serde = { version = "1", features = ["derive"] }
15serde_json = "1" 15serde_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};
10use base64::prelude::*; 10use base64::prelude::*;
11use chrono::{DateTime, Utc}; 11use chrono::{DateTime, Utc};
12use gitolfs3_common::{
13 generate_tag, load_key, Claims, Digest, HexByte, Key, Oid, Operation, SpecificClaims,
14};
12use serde::{ 15use 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)]
288struct BatchRequestObject { 291struct 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)]
303struct BatchRequest { 306struct 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)]
428struct BatchResponseObject { 431struct 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
460fn validate_checksum(oid: common::Oid, obj: &HeadObjectOutput) -> bool { 463fn 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
719struct AuthorizationConfig { 722struct AuthorizationConfig {
720 trusted_forwarded_hosts: HashSet<String>, 723 trusted_forwarded_hosts: HashSet<String>,
721 key: common::Key, 724 key: Key,
722} 725}
723 726
724struct Trusted(bool); 727struct 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(
771fn authorize_batch_unauthenticated( 774fn 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")]
887struct FileParams { 890struct 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
893impl<'de> Deserialize<'de> for FileParams { 896impl<'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
917pub struct VerifyClaimsInput<'a> { 920pub 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(
957fn authorize_get( 960fn 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]
1124fn test_validate_claims() { 1127fn 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]
2name = "shell" 2name = "gitolfs3-shell"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "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;