Skip to content
Clone
cb06060
57 lines 1.8 KB Rust
use uuid::Uuid;
use crate::context::facade::GitContext;
use crate::service::GitService;
use crate::share::errors::GitError;
/// Per-repo authorization — the central ACL that was previously only on
/// the SSH path (`ssh/handler/command.rs::authorize_repo`) and missing
/// from every HTTP/LFS path. Centralized so HTTP, SSH, and the LFS router
/// enforce identical membership rules.
///
/// Rules:
/// - space owner of the repo's owning space: always allowed
/// - read on public repo: allowed
/// - read on private repo: requires `repo_collaborations` row
/// - write: requires `repo_collaborations.mode ∈ {Write, Admin}`
/// - admin: requires `repo_collaborations.mode == Admin`
pub async fn authorize_repo_access(
svc: &GitService,
uid: i64,
ctx: &GitContext,
want_write: bool,
require_admin: bool,
) -> Result<(), GitError> {
let owner = find_space_for_repo(svc, &ctx.model).await?;
let capability = if require_admin {
space::Capability::RepositoryAdmin {
repository: ctx.model.id,
}
} else if want_write {
space::Capability::RepositoryWrite {
repository: ctx.model.id,
}
} else {
space::Capability::RepositoryRead {
repository: ctx.model.id,
private: ctx.model.is_private,
}
};
Ok(space::require(&owner, uid, capability).await?)
}
async fn find_space_for_repo(
service: &GitService,
repo: &models::repo::repos::Model,
) -> Result<space::Space, GitError> {
space_for_dir(&service.access, repo.dir_id)
.await?
.ok_or_else(|| GitError::Internal(format!("space for repo {} not found", repo.id)))
}
pub async fn space_for_dir(
access: &space::Access,
dir_id: Uuid,
) -> Result<Option<space::Space>, GitError> {
Ok(access.for_dir(dir_id).await?)
}