99 lines
3.1 KiB
Rust
99 lines
3.1 KiB
Rust
use actix_web::{Error, HttpRequest};
|
|
use base64::{Engine, engine::general_purpose::STANDARD};
|
|
use db::database::AppDatabase;
|
|
use model::{
|
|
repos::RepoModel,
|
|
workspace::{
|
|
wk_history_name::WkHistoryNameModel, workspace::WorkspaceModel,
|
|
},
|
|
};
|
|
|
|
pub async fn get_repo_model(
|
|
namespace: &str,
|
|
repo_name: &str,
|
|
db: &AppDatabase,
|
|
) -> Result<RepoModel, Error> {
|
|
let wk_id = if let Some(wk) = sqlx::query_as::<_, WorkspaceModel>(
|
|
"SELECT id, name, description, avatar_url, created_at FROM workspace WHERE name = $1",
|
|
)
|
|
.bind(namespace)
|
|
.fetch_optional(db.reader())
|
|
.await
|
|
.map_err(|_| actix_web::error::ErrorInternalServerError("Database error"))?
|
|
{
|
|
wk.id
|
|
} else if let Some(history) = sqlx::query_as::<_, WkHistoryNameModel>(
|
|
"SELECT id, wk, name, changed_by, created_at FROM wk_history_name WHERE name = $1",
|
|
)
|
|
.bind(namespace)
|
|
.fetch_optional(db.reader())
|
|
.await
|
|
.map_err(|_| actix_web::error::ErrorInternalServerError("Database error"))?
|
|
{
|
|
history.wk
|
|
} else {
|
|
return Err(actix_web::error::ErrorNotFound("Project not found").into());
|
|
};
|
|
|
|
let repo = sqlx::query_as::<_, RepoModel>(
|
|
"SELECT id, wk, name, description, default_branch, visibility, size_bytes, \
|
|
is_archived, is_template, is_mirror, created_by, storage_path, \
|
|
created_at, updated_at, deleted_at \
|
|
FROM repo \
|
|
WHERE name = $1 AND wk = $2 AND deleted_at IS NULL",
|
|
)
|
|
.bind(repo_name)
|
|
.bind(wk_id)
|
|
.fetch_optional(db.reader())
|
|
.await
|
|
.map_err(|_| actix_web::error::ErrorInternalServerError("Database error"))?
|
|
.ok_or_else(|| actix_web::error::ErrorNotFound("Repository not found"))?;
|
|
|
|
Ok(repo)
|
|
}
|
|
|
|
pub fn extract_basic_credentials(
|
|
req: &HttpRequest,
|
|
) -> Result<(String, String), Error> {
|
|
let auth_header = req
|
|
.headers()
|
|
.get("authorization")
|
|
.ok_or_else(|| {
|
|
actix_web::error::ErrorUnauthorized("Missing authorization header")
|
|
})?
|
|
.to_str()
|
|
.map_err(|_| {
|
|
actix_web::error::ErrorUnauthorized("Invalid authorization header")
|
|
})?;
|
|
|
|
let encoded = auth_header.strip_prefix("Basic ").ok_or_else(|| {
|
|
actix_web::error::ErrorUnauthorized("Invalid authorization scheme")
|
|
})?;
|
|
|
|
let decoded = STANDARD.decode(encoded).map_err(|_| {
|
|
actix_web::error::ErrorUnauthorized(
|
|
"Invalid basic authorization encoding",
|
|
)
|
|
})?;
|
|
|
|
let decoded = String::from_utf8(decoded).map_err(|_| {
|
|
actix_web::error::ErrorUnauthorized(
|
|
"Invalid basic authorization payload",
|
|
)
|
|
})?;
|
|
|
|
let (username, access_key) = decoded.split_once(':').ok_or_else(|| {
|
|
actix_web::error::ErrorUnauthorized(
|
|
"Invalid basic authorization format",
|
|
)
|
|
})?;
|
|
|
|
if username.is_empty() || access_key.is_empty() {
|
|
return Err(actix_web::error::ErrorUnauthorized(
|
|
"Username or access key is empty",
|
|
));
|
|
}
|
|
|
|
Ok((username.to_string(), access_key.to_string()))
|
|
}
|