Monday | 26 FEB 2024
[ previous ]
[ next ]

Nginx WebDAV - Authentication and User Uploads

Title:
Date: 2023-01-26
Tags:  

I've now built a very simple upload site with logins and user specific directories. My biggest worry is how gated these things are as everything looks open.

The first thing I needed to do was get nginx up and going with authentication and also have it root the user in place.

    location /webdav {
        auth_basic "Admin Area";
        auth_basic_user_file /home/$remote_user/.htpasswd;
 
        root /home/$remote_user/;

        dav_methods PUT DELETE MKCOL COPY MOVE;
        dav_ext_methods PROPFIND OPTIONS;
        dav_access user:rw group:rw all:rw;

        create_full_put_path on;
        client_body_temp_path /tmp/upload_tmp;
        client_max_body_size 0;
    }

The core step here was enabling the authentication using the auth_basic flag. The other important step was using root to set the logged in user to the correct directory. Inside /home/ is a user and under that user is the webdav directory that I will be writing to.

This webdav directory currently has 777 permissions which means it is wide open.

Now for the html side of things.

async function drop(e) {
    e.preventDefault();

    let items = e.dataTransfer.items;

    for (let item of items) {
        if (item.kind !== "file") continue;

        let file = item.getAsFile();

        let response = await fetch(`/webdav/${file.name}`, {
            method: "PUT",
            body: file,
        });

        console.log(response);
    }
}

Here, fetch will re-use the already authenticated headers.

The fetch seems a bit strange as that url seems to be pulling double duty. It is both hitting the /webdav endpoint in nginx but is then used by the nginx dav module to create the file.

This results in the /webdav directory being created if it doesn't exist. That is why the nginx root flag is one level higher than where I really wanted to root the user. This doesn't feel right.

I would want the root option to be very explicit about where the user is currently stuck in and then the fetch command would create the file under that folder. Currently it would end up doing ~/webdav/webdav/file.txt.

The other thing to note is that we are adding the file contents directly to the body of the request. This is because of the way that webdav will save the file. If we use FormData, this will be a multipart form that will contain a boundary. This boundary would then be saved with the data as the boundary is embedded within the body. This is so that we can process multiple items in a form.

Luckily because we are using webdav and it doesn't support sending multiple files in one request anyway, we can safely set up our fetch to send a single file at a time.