POC(nextcloud): add chroot on nextcloud

Bring chroot to nextcloud capability: login on Nextcloud via username="{user}~{folder-uuid}
    Doing a such login will chroot the folder folder-uuid

    If user has several folder as root (parent=None), the login flow will request which
    folder user want to chroot
This commit is contained in:
Edouard Vanbelle
2026-06-15 22:59:34 +02:00
parent 16ea08b093
commit 42510d94f3
15 changed files with 1027 additions and 181 deletions
+20 -13
View File
@@ -9,7 +9,6 @@ use crate::application::ports::file_ports::{FileRetrievalUseCase, FileUploadUseC
use crate::common::di::AppState;
use crate::common::mime_detect::filename_from_path;
use crate::interfaces::errors::AppError;
use crate::interfaces::middleware::auth::{AuthUser, CurrentUser};
use crate::interfaces::upload_ingest::{
discard_ingested, ingest_stream_to_cas, stream_body_to_path, stream_from_files,
};
@@ -25,17 +24,17 @@ use crate::interfaces::upload_ingest::{
pub async fn handle_nc_uploads(
state: Arc<AppState>,
req: Request<Body>,
user: AuthUser,
session: crate::interfaces::nextcloud::session::NcSession,
upload_id: String,
rest: String, // chunk name or ".file" or empty
) -> Result<Response<Body>, AppError> {
let method = req.method().clone();
match method.as_str() {
"MKCOL" => handle_mkcol(state, &user, &upload_id).await,
"PUT" => handle_put_chunk(state, req, &user, &upload_id, &rest).await,
"MOVE" => handle_assemble(state, req, &user, &upload_id).await,
"DELETE" => handle_abort(state, &user, &upload_id).await,
"PROPFIND" => handle_propfind_session(state, &user, &upload_id).await,
"MKCOL" => handle_mkcol(state, &session, &upload_id).await,
"PUT" => handle_put_chunk(state, req, &session, &upload_id, &rest).await,
"MOVE" => handle_assemble(state, req, &session, &upload_id).await,
"DELETE" => handle_abort(state, &session, &upload_id).await,
"PROPFIND" => handle_propfind_session(state, &session, &upload_id).await,
_ => Ok(Response::builder()
.status(StatusCode::METHOD_NOT_ALLOWED)
.body(Body::empty())
@@ -60,9 +59,10 @@ pub async fn handle_nc_uploads(
/// which matches NC server behaviour.
async fn handle_propfind_session(
state: Arc<AppState>,
user: &CurrentUser,
session: &crate::interfaces::nextcloud::session::NcSession,
upload_id: &str,
) -> Result<Response<Body>, AppError> {
let user = &session.user;
let nc = state
.nextcloud
.as_ref()
@@ -147,9 +147,10 @@ fn xml_escape(s: &str) -> String {
/// MKCOL — create upload session directory.
async fn handle_mkcol(
state: Arc<AppState>,
user: &CurrentUser,
session: &crate::interfaces::nextcloud::session::NcSession,
upload_id: &str,
) -> Result<Response<Body>, AppError> {
let user = &session.user;
let nc = state
.nextcloud
.as_ref()
@@ -178,10 +179,11 @@ async fn handle_mkcol(
async fn handle_put_chunk(
state: Arc<AppState>,
req: Request<Body>,
user: &CurrentUser,
session: &crate::interfaces::nextcloud::session::NcSession,
upload_id: &str,
chunk_name: &str,
) -> Result<Response<Body>, AppError> {
let user = &session.user;
let nc = state
.nextcloud
.as_ref()
@@ -216,9 +218,10 @@ async fn handle_put_chunk(
async fn handle_assemble(
state: Arc<AppState>,
req: Request<Body>,
user: &CurrentUser,
session: &crate::interfaces::nextcloud::session::NcSession,
upload_id: &str,
) -> Result<Response<Body>, AppError> {
let user = &session.user;
let nc = state
.nextcloud
.as_ref()
@@ -296,7 +299,10 @@ async fn handle_assemble(
let parent_internal = parent_internal.trim_end_matches('/');
use crate::application::ports::folder_ports::FolderUseCase;
let parent_folder = match folder_service.get_folder_by_path(parent_internal, user.id).await {
let parent_folder = match folder_service
.get_folder_by_path(parent_internal, user.id)
.await
{
Ok(folder) => folder,
Err(e) => {
discard_ingested(&state.core.dedup_service, &ingested).await;
@@ -341,9 +347,10 @@ async fn handle_assemble(
/// DELETE — abort an upload session.
async fn handle_abort(
state: Arc<AppState>,
user: &CurrentUser,
session: &crate::interfaces::nextcloud::session::NcSession,
upload_id: &str,
) -> Result<Response<Body>, AppError> {
let user = &session.user;
let nc = state
.nextcloud
.as_ref()