Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add git http authenticate #656

Merged
merged 2 commits into from
Oct 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ bstr = "1.10.0"
colored = "2.1.0"
idgenerator = "2.0.0"
num_cpus = "1.16.0"
config = "0.14.0"
config = "0.14.1"
shadow-rs = "0.35.1"
reqwest = "0.12.8"
lazy_static = "1.5.0"
Expand All @@ -85,6 +85,8 @@ home = "0.5.9"
ring = "0.17.8"
cedar-policy = "4.2.1"
secp256k1 = "0.30.0"
oauth2 = "4.4.2"
base64 = "0.22.1"

[profile.release]
debug = true
2 changes: 1 addition & 1 deletion ceres/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ async-trait = { workspace = true }
rand = { workspace = true }
sea-orm = { workspace = true }
ring = { workspace = true }
hex ={ workspace = true}
hex = { workspace = true }
4 changes: 2 additions & 2 deletions ceres/src/protocol/smart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,10 @@ impl SmartProtocol {
.await?;

// do not block main thread here.
let ph_clone = pack_handler.clone();
let handler_clone = pack_handler.clone();
let unpack_result = tokio::task::spawn_blocking(move || {
let handle = tokio::runtime::Handle::current();
handle.block_on(async { ph_clone.handle_receiver(receiver).await })
handle.block_on(async { handler_clone.handle_receiver(receiver).await })
})
.await
.unwrap();
Expand Down
2 changes: 2 additions & 0 deletions common/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ impl Default for StorageConfig {
pub struct MonoConfig {
pub import_dir: PathBuf,
pub disable_http_push: bool,
pub enable_http_auth: bool,
pub admin: String,
pub root_dirs: Vec<String>,
}
Expand All @@ -219,6 +220,7 @@ impl Default for MonoConfig {
Self {
import_dir: PathBuf::from("/third-part"),
disable_http_push: false,
enable_http_auth: false,
admin: String::from("admin"),
root_dirs: vec![
"third-part".to_string(),
Expand Down
7 changes: 5 additions & 2 deletions docker/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ import_dir = "/third-part"
# The current mono Git HTTP server does not support authentication, so we provided a disabled operations here
disable_http_push = false

# Support http authtication, login in with github and generate token before push
enable_http_auth = false

# Set System Admin in directory init, replace the admin's github username here
admin = "admin"

Expand Down Expand Up @@ -96,8 +99,8 @@ split_size = 20971520 # Default size is 20MB (20971520 bytes)
github_client_id = ""
github_client_secret = ""

# Used redirect to ui after login
# Used for redirect to ui after login, for example: https://console.gitmono.com
ui_domain = "https://console.gitmono.com"

# Set .gitmono.com on Production
# Set your own domain here, for example: .gitmono.com
cookie_domain = ".gitmono.com"
1 change: 1 addition & 0 deletions jupiter/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ serde_json = { workspace = true }
idgenerator = { workspace = true }
serde = { workspace = true }
tokio = { workspace = true, features = ["macros"] }
uuid = { workspace = true }

[dev-dependencies]
tokio = { workspace = true, features = ["macros"] }
19 changes: 19 additions & 0 deletions jupiter/callisto/src/access_token.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0

use sea_orm::entity::prelude::*;

#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
#[sea_orm(table_name = "access_token")]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub id: i64,
pub user_id: i64,
#[sea_orm(column_type = "Text")]
pub token: String,
pub created_at: DateTime,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}

impl ActiveModelBehavior for ActiveModel {}
3 changes: 2 additions & 1 deletion jupiter/callisto/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.0
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0

pub mod prelude;

pub mod access_token;
pub mod db_enums;
pub mod git_blob;
pub mod git_commit;
Expand Down
1 change: 1 addition & 0 deletions jupiter/callisto/src/prelude.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.0

pub use crate::access_token::Entity as AccessToken;
pub use crate::git_blob::Entity as GitBlob;
pub use crate::git_commit::Entity as GitCommit;
pub use crate::git_issue::Entity as GitIssue;
Expand Down
67 changes: 66 additions & 1 deletion jupiter/src/storage/user_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ use sea_orm::{
ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, IntoActiveModel, ModelTrait,
QueryFilter,
};
use uuid::Uuid;

use callisto::{ssh_keys, user};
use callisto::{access_token, ssh_keys, user};
use common::{errors::MegaError, utils::generate_id};

#[derive(Clone)]
Expand Down Expand Up @@ -36,6 +37,14 @@ impl UserStorage {
Ok(res)
}

pub async fn find_user_by_name(&self, name: &str) -> Result<Option<user::Model>, MegaError> {
let res = user::Entity::find()
.filter(user::Column::Name.eq(name))
.one(self.get_connection())
.await?;
Ok(res)
}

pub async fn save_user(&self, user: user::Model) -> Result<(), MegaError> {
let a_model = user.into_active_model();
a_model.insert(self.get_connection()).await.unwrap();
Expand Down Expand Up @@ -92,4 +101,60 @@ impl UserStorage {
.await?;
Ok(res)
}

pub async fn generate_token(&self, user_id: i64) -> Result<String, MegaError> {
let token_str = Uuid::new_v4().to_string();
let model = access_token::Model {
id: generate_id(),
user_id,
token: token_str.clone(),
created_at: chrono::Utc::now().naive_utc(),
};
let a_model = model.into_active_model();
a_model.insert(self.get_connection()).await.unwrap();
Ok(token_str.to_owned())
}

pub async fn delete_token(&self, user_id: i64, id: i64) -> Result<(), MegaError> {
let res = access_token::Entity::find()
.filter(access_token::Column::Id.eq(id))
.filter(access_token::Column::UserId.eq(user_id))
.one(self.get_connection())
.await?;
if let Some(model) = res {
model.delete(self.get_connection()).await?;
}
Ok(())
}

pub async fn list_token(&self, user_id: i64) -> Result<Vec<access_token::Model>, MegaError> {
let res = access_token::Entity::find()
.filter(access_token::Column::UserId.eq(user_id))
.all(self.get_connection())
.await?;
Ok(res)
}

pub async fn check_token(&self, user_id: i64, token: &str) -> Result<bool, MegaError> {
let res = access_token::Entity::find()
.filter(access_token::Column::UserId.eq(user_id))
.filter(access_token::Column::Token.eq(token))
.one(self.get_connection())
.await?;
match res {
Some(_) => Ok(true),
None => Ok(false),
}
}
}

#[cfg(test)]
mod test {
use uuid::Uuid;

#[test]
fn token_format() {
let uuid = Uuid::new_v4().to_string();
println!("{:?}", uuid);
}
}
3 changes: 3 additions & 0 deletions mega/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ import_dir = "/third-part"
# The current mono Git HTTP server does not support authentication, so we provided a disabled operations here
disable_http_push = false

# Support http authtication, login in with github and generate token before push
enable_http_auth = false

# Set System Admin in directory init, replace the admin's github username here
admin = "admin"

Expand Down
9 changes: 8 additions & 1 deletion mono/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ ed25519-dalek = { workspace = true, features = ["pkcs8"] }
lazy_static = { workspace = true }
ctrlc = { workspace = true }
shadow-rs = { workspace = true }
oauth2 = "4.4.2"
oauth2 = { workspace = true }
base64 = { workspace = true }
async-session = "3.0.0"
http = "1.1.0"
cedar-policy = { workspace = true }
Expand All @@ -62,3 +63,9 @@ cedar-policy = { workspace = true }

[build-dependencies]
shadow-rs = { workspace = true }

# [target.'cfg(not(target_env = "msvc"))'.dependencies]
# tikv-jemallocator = "0.6"

# [target.'cfg(not(target_env = "msvc"))'.dependencies]
# jemallocator = {version = "0.5.4", features = ["debug", "profiling"]}
7 changes: 5 additions & 2 deletions mono/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ import_dir = "/third-part"
# The current mono Git HTTP server does not support authentication, so we provided a disabled operations here
disable_http_push = false

# Support http authtication, login in with github and generate token before push
enable_http_auth = false

# Set System Admin in directory init, replace the admin's github username here
admin = "admin"

Expand Down Expand Up @@ -96,8 +99,8 @@ split_size = 20971520 # Default size is 20MB (20971520 bytes)
github_client_id = ""
github_client_secret = ""

# Used redirect to ui after login
# Used for redirect to ui after login, for example: https://console.gitmono.com
ui_domain = "http://localhost:3000"

# Set .gitmono.com on Production
# Set your own domain here, for example: .gitmono.com
cookie_domain = "localhost"
21 changes: 20 additions & 1 deletion mono/src/api/user/model.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use callisto::ssh_keys;
use callisto::{access_token, ssh_keys};
use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -29,6 +29,25 @@ impl From<ssh_keys::Model> for ListSSHKey {
}
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ListToken {
pub id: i64,
pub token: String,
pub created_at: NaiveDateTime,
}

impl From<access_token::Model> for ListToken {
fn from(value: access_token::Model) -> Self {
let mut mask_token = value.token;
mask_token.replace_range(7..32, "-******-");
Self {
id: value.id,
token: mask_token,
created_at: value.created_at,
}
}
}

#[derive(Debug, Serialize, Deserialize)]
pub struct RepoPermissions {
pub admin: Vec<String>,
Expand Down
62 changes: 62 additions & 0 deletions mono/src/api/user/user_router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ use crate::api::user::model::AddSSHKey;
use crate::api::user::model::ListSSHKey;
use crate::api::MonoApiServiceState;
use crate::api::{error::ApiError, oauth::model::LoginUser, util};
use crate::api::user::model::ListToken;

pub fn routers() -> Router<MonoApiServiceState> {
Router::new()
.route("/user", get(user))
.route("/user/ssh", get(list_key))
.route("/user/ssh", post(add_key))
.route("/user/ssh/:key_id/delete", post(remove_key))
.route("/user/token/generate", post(generate_token))
.route("/user/token/list", get(list_token))
.route("/user/token/:key_id/delete", post(remove_token))
.route("/repo-permissions", get(repo_permissions))
}

Expand Down Expand Up @@ -96,12 +100,70 @@ async fn list_key(
Ok(Json(res))
}

async fn generate_token(
user: LoginUser,
state: State<MonoApiServiceState>,
) -> Result<Json<CommonResult<String>>, ApiError> {
let res = state
.context
.services
.user_storage
.generate_token(user.user_id)
.await;
let res = match res {
Ok(data) => CommonResult::success(Some(data)),
Err(err) => CommonResult::failed(&err.to_string()),
};
Ok(Json(res))
}


async fn remove_token(
user: LoginUser,
state: State<MonoApiServiceState>,
Path(key_id): Path<i64>,
) -> Result<Json<CommonResult<String>>, ApiError> {
let res = state
.context
.services
.user_storage
.delete_token(user.user_id, key_id)
.await;
let res = match res {
Ok(_) => CommonResult::success(None),
Err(err) => CommonResult::failed(&err.to_string()),
};
Ok(Json(res))
}


async fn list_token(
user: LoginUser,
state: State<MonoApiServiceState>,
) -> Result<Json<CommonResult<Vec<ListToken>>>, ApiError> {
let res = state
.context
.services
.user_storage
.list_token(user.user_id)
.await;
let res = match res {
Ok(data) => {
let res = data.into_iter().map(|x| x.into()).collect();
CommonResult::success(Some(res))
},
Err(err) => CommonResult::failed(&err.to_string()),
};
Ok(Json(res))
}

async fn repo_permissions(
Query(query): Query<HashMap<String, String>>,
state: State<MonoApiServiceState>,
) -> Result<Json<CommonResult<String>>, ApiError> {
let path = std::path::PathBuf::from(query.get("path").unwrap());
let _ = util::get_entitystore(path, state).await;
// TODO
Ok(Json(CommonResult::success(Some(String::new()))))
}

Expand Down
Loading
Loading