use crate::http::utils::{extract_basic_credentials, hash_access_key}; use crate::ssh::authz::SshAuthService; use actix_web::{Error, HttpRequest}; use db::database::AppDatabase; use models::repos::repo; use models::users::{user, user_token}; use sea_orm::sqlx::types::chrono; use sea_orm::*; pub async fn verify_access_token( db: &AppDatabase, username: &str, access_key: &str, ) -> Result { let user = user::Entity::find() .filter(user::Column::Username.eq(username)) .one(db.reader()) .await .map_err(|_| actix_web::error::ErrorUnauthorized("Invalid username or access key"))? .ok_or_else(|| actix_web::error::ErrorUnauthorized("Invalid username or access key"))?; let token_hash = hash_access_key(access_key); let token = user_token::Entity::find() .filter(user_token::Column::User.eq(user.uid)) .filter(user_token::Column::TokenHash.eq(token_hash)) .filter(user_token::Column::IsRevoked.eq(false)) .one(db.reader()) .await .map_err(|_| actix_web::error::ErrorUnauthorized("Invalid username or access key"))? .ok_or_else(|| actix_web::error::ErrorUnauthorized("Invalid username or access key"))?; if let Some(expires_at) = token.expires_at { if expires_at < chrono::Utc::now() { return Err(actix_web::error::ErrorUnauthorized( "Access key has expired", )); } } Ok(user) } pub async fn authorize_repo_access( req: &HttpRequest, db: &AppDatabase, repo: &repo::Model, is_write: bool, ) -> Result<(), Error> { if !is_write && !repo.is_private { return Ok(()); } let (username, access_key) = extract_basic_credentials(req)?; let user = verify_access_token(db, &username, &access_key).await?; let authz = SshAuthService::new(db.clone(), slog::Logger::root(slog::Discard, slog::o!())); let can_access = authz.check_repo_permission(&user, repo, is_write).await; if !can_access { return Err(actix_web::error::ErrorForbidden( "No permission for repository", )); } Ok(()) }