summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile5
-rw-r--r--browse.c25
-rw-r--r--create.c238
-rw-r--r--create.h54
-rw-r--r--main.c6
-rw-r--r--template/browse_head.html5
-rw-r--r--template/create_head.html17
-rw-r--r--template/head.html3
8 files changed, 343 insertions, 10 deletions
diff --git a/Makefile b/Makefile
index 5ccb6a0..d3de998 100644
--- a/Makefile
+++ b/Makefile
@@ -47,10 +47,10 @@ all: main
.c.o:
$(CC) -o $@ -c $< $(CFLAGS)
-main: str.o config.o mime.o url.o template.o file.o http.o delete.o upload.o download.o browse.o main.o
+main: str.o config.o mime.o url.o template.o file.o http.o delete.o upload.o download.o create.o browse.o main.o
$(CC) -o $@ $> $(LDFLAGS)
-test: str.o config.o mime.o url.o template.o file.o http.o delete.o upload.o download.o browse.o test.o
+test: str.o config.o mime.o url.o template.o file.o http.o delete.o upload.o download.o create.o browse.o test.o
$(CC) -o $@ $> $(LDFLAGS)
env: env.o
@@ -68,6 +68,7 @@ install:
install -D -o www -g www -m 0440 template/browse_item.html /var/www/usr/share/vault/template/browse_item.html
install -D -o www -g www -m 0440 template/upload_head.html /var/www/usr/share/vault/template/upload_head.html
install -D -o www -g www -m 0440 template/delete_head.html /var/www/usr/share/vault/template/delete_head.html
+ install -D -o www -g www -m 0440 template/create_head.html /var/www/usr/share/vault/template/create_head.html
install -D -o www -g www -m 0440 fontawesome-6.5.1/css/fontawesome.css /var/www/vault-static/fontawesome-6.5.1/css/fontawesome.css
gzip -fk /var/www/vault-static/fontawesome-6.5.1/css/fontawesome.css
install -D -o www -g www -m 0440 fontawesome-6.5.1/css/solid.css /var/www/vault-static/fontawesome-6.5.1/css/solid.css
diff --git a/browse.c b/browse.c
index 4777938..28e2b78 100644
--- a/browse.c
+++ b/browse.c
@@ -41,6 +41,7 @@
#include "browse.h"
#include "cgi.h"
#include "config.h"
+#include "create.h"
#include "download.h"
#include "file.h"
#include "http.h"
@@ -164,7 +165,7 @@ struct template_data {
struct file *f;
};
-static const char *const header_template_keys[] = {"upload_url"};
+static const char *const header_template_keys[] = {"upload_url", "create_url"};
static int
header_template_callback(size_t index, void *arg)
@@ -185,7 +186,21 @@ header_template_callback(size_t index, void *arg)
switch (index) {
case 0:
/* upload_url */
- K_OK(khtml_puts(html, data->f->action_url), r);
+ if (build_upload_url(r, data->f) > 0) {
+ K_OK(khtml_puts(html, data->f->action_url), r);
+ } else
+ kutil_warnx(r, NULL,
+ "failed to build upload URL for path %s",
+ data->f->path);
+ break;
+ case 1:
+ /* create_url */
+ if (build_create_url(r, data->f) > 0) {
+ K_OK(khtml_puts(html, data->f->action_url), r);
+ } else
+ kutil_warnx(r, NULL,
+ "failed to build create URL for path %s",
+ data->f->path);
break;
default:
kutil_warnx(r, NULL,
@@ -302,10 +317,6 @@ browse(struct kreq * r)
http_exit(r, KHTTP_404, "browse: Invalid data file");
goto end;
}
- if (build_upload_url(r, file) == 0) {
- http_exit(r, KHTTP_500, "browse: Can't build upload url");
- goto end;
- }
if (build_file_list(r, file) < 0) {
http_exit(r, KHTTP_500, "browse: Unable to build file list");
goto end;
@@ -325,7 +336,7 @@ browse(struct kreq * r)
/* print browse header with action buttons for current dir */
template.key = header_template_keys;
- template.keysz = 1;
+ template.keysz = 2;
template.cb = header_template_callback;
template.arg = &data;
data.r = r;
diff --git a/create.c b/create.c
new file mode 100644
index 0000000..e5a98b0
--- /dev/null
+++ b/create.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2025, Vincent Douillet <vincent@vdouillet.fr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <kcgi.h>
+#include <kcgihtml.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "browse.h"
+#include "cgi.h"
+#include "http.h"
+#include "template.h"
+#include "create.h"
+#include "url.h"
+
+/*
+ * create url = r->pname / CREATE_URL / file->path
+ */
+size_t
+build_create_url(const struct kreq * r, struct file * file)
+{
+ char action_url[PATH_MAX];
+ size_t action_url_len;
+
+ if (!file->is_dir)
+ return 0;
+
+ action_url_len = url_build(action_url, PATH_MAX, r->pname, CREATE_URL,
+ file->path, NULL);
+ if (action_url_len == 0 || action_url_len >= PATH_MAX) {
+ kutil_warn(r, NULL,
+ "create: action URL overflow: %s", action_url);
+ return 0;
+ }
+ file->action_url = strndup(action_url, action_url_len);
+ if (file->action_url == NULL) {
+ kutil_warn(r, NULL,
+ "create: unable to allocate file url buffer: %s",
+ action_url);
+ return 0;
+ }
+ return action_url_len;
+}
+
+/*
+ * data required in the template functions
+ */
+struct template_data {
+ struct kreq *r;
+ struct khtmlreq *html;
+ struct file *f;
+};
+
+static const char *const header_template_keys[] = {"path", "submit_url"};
+
+static int
+header_template_callback(size_t index, void *arg)
+{
+ struct kreq *r;
+ struct khtmlreq *html;
+ struct template_data *data;
+
+ if (arg == NULL) {
+ kutil_warn(NULL, NULL,
+ "Invalid data for create header template");
+ return 0;
+ }
+ data = arg;
+ r = data->r;
+ html = data->html;
+
+ switch (index) {
+ case 0:
+ /* path */
+ K_OK(khtml_puts(html, data->f->path), r);
+ break;
+ case 1:
+ /* submit_url */
+ K_OK(khtml_puts(html, data->f->action_url), r);
+ break;
+ default:
+ kutil_warnx(r, NULL,
+ "Invalid key index for create header template: %zd",
+ index);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * GET request, we print create form
+ */
+void
+create_get(struct kreq * r, struct file * file)
+{
+ struct khtmlreq html;
+ struct ktemplate template;
+ struct page_template *tmpl;
+ struct template_data data;
+
+ tmpl = NULL;
+
+ /* action url is form submit url */
+ if (build_create_url(r, file) == 0) {
+ http_exit(r, KHTTP_500, "create: Can't build create url");
+ goto end;
+ }
+ /* read template */
+ tmpl = page_template_new(CREATE_URL);
+ if (tmpl == NULL) {
+ http_exit(r, KHTTP_500, "create: Unable to read template");
+ goto end;
+ }
+ /* print create form */
+ http_open(r, KHTTP_200, KMIME_TEXT_HTML);
+
+ K_OK(khttp_puts(r, tmpl->header), r);
+ K_OK(khtml_open(&html, r, 0), r);
+
+ template.key = header_template_keys;
+ template.keysz = 2;
+ template.cb = header_template_callback;
+ template.arg = &data;
+ data.r = r;
+ data.html = &html;
+ data.f = file;
+ K_OK(khttp_template_buf(r, &template, tmpl->page_header,
+ strlen(tmpl->page_header)), r);
+
+ K_OK(khttp_puts(r, tmpl->page_footer), r);
+ K_OK(khttp_puts(r, tmpl->footer), r);
+
+ K_OK(khtml_close(&html), r);
+
+end:
+ page_template_free(tmpl);
+}
+
+/*
+ * POST request, we handle create form
+ */
+void
+create_post(struct kreq * r, struct file * f)
+{
+ char path[PATH_MAX];
+ size_t path_len, i;
+ struct kpair *name;
+
+ /* prepare action url for return redirection in case of success */
+ if (build_browse_url(r, f) == 0) {
+ http_exit(r, KHTTP_500, "create: can't build return url");
+ return;
+ }
+ /* validate input data */
+ if (r->fieldsz != 1) {
+ http_exit(r, KHTTP_400, "create: missing folder name");
+ return;
+ }
+ name = &(r->fields[0]);
+ /*
+ * TODO name->val == NULL is not enough, need better sanitization
+ * for example, some chars are not allowed in a folder name
+ * an empty non-NULL string is also not ok
+ */
+ if (strncmp(name->key, "name", 4) || name->val == NULL) {
+ http_exit(r, KHTTP_400, "create: invalide folder name");
+ return;
+ }
+ path_len = file_get_data_path(f, path, PATH_MAX, name->val);
+ if (path_len == 0 || path_len >= PATH_MAX) {
+ http_exit(r, KHTTP_500,
+ "create: can't build file path");
+ return;
+ }
+ /* TODO check if folder already exists */
+ if (mkdir(path, 0755)) {
+ http_exit(r, KHTTP_500,
+ "create: can't create directory");
+ return;
+ }
+
+ /* on success, redirect to the new folder */
+ khttp_head(r, kresps[KRESP_LOCATION], "%s", f->action_url);
+ http_open(r, KHTTP_303, r->mime);
+}
+
+void
+create(struct kreq * r)
+{
+ struct file *file;
+
+ file = NULL;
+
+ /* build file corresponding to request (ie. create) path */
+ file = file_new(r->path);
+ if (file == NULL) {
+ http_exit(r, KHTTP_404, "create: Unable to build data file");
+ goto end;
+ }
+ /* print form or handle submission according to HTTP method */
+ if (r->method == KMETHOD_POST)
+ create_post(r, file);
+ else
+ create_get(r, file);
+
+end:
+ file_free(file);
+}
diff --git a/create.h b/create.h
new file mode 100644
index 0000000..1626a63
--- /dev/null
+++ b/create.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2025, Vincent Douillet <vincent@vdouillet.fr>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef CREATE_H
+#define CREATE_H
+
+#include <kcgi.h>
+
+#include "file.h"
+
+#define CREATE_URL "create"
+
+/*
+ * Build the URL to create a folder and assigns it to the file's action_url.
+ * All parameters are required
+ * Returns the length of the created URL, or 0 in case of failure.
+ */
+size_t
+build_create_url(const struct kreq *, struct file *);
+
+/*
+ * Print a create form (http GET) or handle a create form submission (http
+ * POST).
+ */
+void create(struct kreq *);
+
+#endif /* CREATE_H */
diff --git a/main.c b/main.c
index b060d15..71ae864 100644
--- a/main.c
+++ b/main.c
@@ -36,6 +36,7 @@
#include "browse.h"
#include "cgi.h"
#include "config.h"
+#include "create.h"
#include "delete.h"
#include "download.h"
#include "http.h"
@@ -46,6 +47,7 @@ enum page {
PAGE_DOWNLOAD,
PAGE_UPLOAD,
PAGE_DELETE,
+ PAGE_CREATE,
PAGE__MAX
};
@@ -54,6 +56,7 @@ static const char *const pages[PAGE__MAX] = {
DOWNLOAD_URL,
UPLOAD_URL,
DELETE_URL,
+ CREATE_URL,
};
int
@@ -121,6 +124,9 @@ main(void)
case PAGE_DELETE:
del(&r);
break;
+ case PAGE_CREATE:
+ create(&r);
+ break;
default:
http_exit(&r, KHTTP_404, NULL);
goto end;
diff --git a/template/browse_head.html b/template/browse_head.html
index 6775012..8b53948 100644
--- a/template/browse_head.html
+++ b/template/browse_head.html
@@ -1,5 +1,8 @@
<h1><i class="fa-regular fa-folder-open"></i> Browsing</h1>
-<a href="@@upload_url@@">Upload here</a>
+<ul id="action-list">
+ <li><a href="@@upload_url@@">Upload here</a></li>
+ <li><a href="@@create_url@@">Create folder here</a></li>
+</ul>
<hr />
<table id="file-list">
<thead>
diff --git a/template/create_head.html b/template/create_head.html
new file mode 100644
index 0000000..5b273ce
--- /dev/null
+++ b/template/create_head.html
@@ -0,0 +1,17 @@
+<h1><i class="fa-regular fa-folder-open"></i> New folder</h1>
+<p>in</p>
+<pre>@@path@@</pre>
+<hr />
+<div>
+<form action="@@submit_url@@" method="post" enctype="multipart/form-data">
+ <div>
+ <label for="name">Folder name:</label>
+ </div>
+ <div>
+ <input type="text" name="name" id="name" />
+ </div>
+ <div>
+ <input type="submit" value="Create" />
+ </div>
+</form>
+</div>
diff --git a/template/head.html b/template/head.html
index a36c475..85f28e3 100644
--- a/template/head.html
+++ b/template/head.html
@@ -15,6 +15,9 @@ body {
font:1.2em/1.62 sans-serif;
}
a:visited { color:blue; }
+ul#action-list { padding:0; }
+ul#action-list li { display:inline; }
+ul#action-list li:not(:last-child):after { content:' |'; }
table#file-list {
width:100%;
border-collapse:collapse;