aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremias Stotter <jeremias@stotter.eu>2021-11-14 21:29:40 +0100
committerJeremias Stotter <jeremias@stotter.eu>2021-11-14 21:29:40 +0100
commit8c718c270953639f025fd81fef8f085a105cb8ae (patch)
tree5ce9107c3d2916135f1df7c2e55455c7600c9bc0
parente56f613732be1e8e70fca81de9584b601566af75 (diff)
downloadJBlog-8c718c270953639f025fd81fef8f085a105cb8ae.tar.gz
JBlog-8c718c270953639f025fd81fef8f085a105cb8ae.tar.bz2
JBlog-8c718c270953639f025fd81fef8f085a105cb8ae.zip
A lot of the admin functions work now
some things I still need to do: - Load jblog files for editing - List files in the admin safe directory - implement some sort of authentification some things that work now: - safe files - publish files - delete files - create directories And of course much much more!
-rw-r--r--admin.c191
-rw-r--r--admin.h17
-rw-r--r--jblog.c17
-rw-r--r--jblog.h2
-rw-r--r--pattern.xhtml7
5 files changed, 210 insertions, 24 deletions
diff --git a/admin.c b/admin.c
index 91fc54f..da002af 100644
--- a/admin.c
+++ b/admin.c
@@ -1,14 +1,39 @@
+// Copyright 2021 Jeremias Stotter
+//
+// This file is part of ´JBlog´.
+//
+// ´JBlog´ is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// ´JBlog´ is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with ´JBlog´. If not, see <http://www.gnu.org/licenses/>.
+
+#define _POSIX_C_SOURCE 200809L
+
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dirent.h>
+#include <sys/stat.h>
#include "jblog.h"
#include "md.h"
#define ADMIN_HTML " \
<table class=\"admin-table\"> \
- <tr> \
+ <tr><h1>Save / Publish</h1><br/></tr>\
+ <tr class=\"stretch_tr\"> \
<td> \
<form class=\"jb-adm-form\" method=\"POST\" target=\"result_html\"> \
<label for=\"release_date\">Release Date:</label> <input type=\"date\" id=\"release_date\" name=\"release_date\"/> <br/> \
@@ -20,26 +45,37 @@
<input type=\"submit\" value=\"Process\" name=\"sub\"/> \
<input type=\"submit\" value=\"Save\" name=\"sub\"/> \
<input type=\"submit\" value=\"Publish\" name=\"sub\"/> <br/> \
+ <label for=\"publish_to\">Publish/Save Path:</label> <input type=\"text\" id=\"publish_to\" name=\"publish_to\"/> <br/> \
</form> \
</td> \
<td> \
<iframe class=\"jb-adm-result\" id=\"result_html\" name=\"result_html\"></iframe> \
</td> \
</tr> \
+ <tr><h1>Folder / File management</h1></tr> \
<tr> \
<td> \
<form class=\"jb-adm-form\" method=\"POST\" target=\"folder_list\"> \
- <label for=\"folder_name\">Folder Name:</label> <input type=\"text\" id=\"folder_name\" name=\"folder_name\"/> <br/> \
- <input type=\"submit\" value=\"Delete Folder\" name=\"sub\"/> \
+ <label for=\"folder_name\">File / Folder Name:</label> <input type=\"text\" id=\"folder_name\" name=\"folder_name\" autocomplete=\"off\"/> <br/> \
+ <input type=\"submit\" value=\"Delete\" name=\"sub\"/> \
<input type=\"submit\" value=\"Create Folder\" name=\"sub\"/> \
+ <input type=\"submit\" value=\"Fetch Files\" name=\"sub\"/> \
</form> \
</td> \
<td> \
- <iframe class=\"jb-adm-result\" id=\"folder_list\" name=\"folder_list\"></iframe> \
+ <iframe class=\"jb-adm-result-folder\" id=\"folder_list\" name=\"folder_list\"></iframe> \
</td> \
</tr> \
</table>"
+#define JBLOG_FILEPATTERN "Date: %s\n\
+Time: %s\n\
+Author: %s\n\
+Title: %s\n\
+Type: Entry\n\
+/// \n\
+%s"
+
#define ADM_PROCESS 0
#define ADM_SAVE 1
#define ADM_PUBLISH 2
@@ -49,6 +85,9 @@
// Can be done inplace
void urldecode(char* src, char* dest) {
+ if(src == NULL) {
+ return;
+ }
char *d, *c;
for(c = src, d = dest; *c != '\0'; c++, d++) {
if(*c == '%' && *(c+1) != '\0') {
@@ -75,6 +114,22 @@ int create_admin(char* buffer, size_t buffer_size, char* adm_save_dir) {
return 0;
}
+// This just does the bare minimum, but meh, fu** it
+void sanitize_path(char* input) {
+ char temporary_path[PATH_MAX] = "\0";
+ strncpy(temporary_path, input, PATH_MAX - 1);
+ *input = '\0';
+ char* path_component = strtok(temporary_path, "/");
+ while(path_component != NULL) {
+ if(strcmp(path_component, "..") == 0) {
+ path_component = strtok(NULL, "/");
+ continue;
+ }
+ input += sprintf(input, "/%s", path_component);
+ path_component = strtok(NULL, "/");
+ }
+}
+
// This handles post request received
// Return 0 if the result should be beautified
int post_admin(char* buffer, size_t buffer_size, char* req_content, char* adm_save_dir) {
@@ -84,13 +139,14 @@ int post_admin(char* buffer, size_t buffer_size, char* req_content, char* adm_sa
char* time_str = NULL;
char* author = NULL;
char* title = NULL;
+ char* publish_to = NULL;
+ char* folder_name = NULL;
char* start = NULL;
char* end = NULL;
- for(start = req_content, end = strchr(start, '&');
- ;
- start = end + 1, end = strchr(start, '&'))
+ for(start = req_content, end = strchr(start, '&');;
+ start = end + 1, end = strchr(start, '&'))
{
// Seperate by =
char* value = strchr(start, '=');
@@ -112,34 +168,127 @@ int post_admin(char* buffer, size_t buffer_size, char* req_content, char* adm_sa
author = value;
} else if(strcmp(start, "title") == 0) {
title = value;
+ } else if(strcmp(start, "publish_to") == 0) {
+ publish_to = value;
+ } else if(strcmp(start, "folder_name") == 0) {
+ folder_name = value;
}
+
if(end == NULL) {
break;
} else {
*end = '\0';
}
}
-
- if(!(md_input && sub_str && date_str && time_str && author && title)) {
- perror("Couldn't read all the values from the form!");
- return -1;
- }
-
// urldecode the relevant values
urldecode(md_input, md_input);
urldecode(author, author);
urldecode(title, title);
urldecode(time_str, time_str);
+ urldecode(publish_to, publish_to);
+ urldecode(folder_name, folder_name);
+ urldecode(sub_str, sub_str);
- if(strcmp(sub_str, "Process") == 0) {
- process_blog_text(buffer, buffer_size, md_input, title, author, date_str, time_str);
- } else if(strcmp(sub_str, "Save")) {
-
- } else if(strcmp(sub_str, "Publish")) {
- } else if(strcmp(sub_str, "Delete Folder")) {
- } else if(strcmp(sub_str, "Create Folder")) {
+ if(md_input && sub_str && date_str && time_str && author && title) {
+ sanitize_path(publish_to);
+ if(strcmp(sub_str, "Process") == 0) {
+ // Process a file
+ process_blog_text(buffer, buffer_size, md_input, title, author, date_str, time_str);
+ return 0;
+ } else if(strcmp(sub_str, "Save") == 0) {
+ // Save a file
+ if(adm_save_dir == NULL) {
+ strncpy(buffer, "<p>No admin save directory specified!</p>", buffer_size);
+ return 1;
+ }
+ char save_file_path[PATH_MAX] = "";
+ snprintf(save_file_path, PATH_MAX, "%s/%s", adm_save_dir, publish_to);
+ int save_file = open(save_file_path, O_CREAT | O_RDWR, 0600);
+ if(save_file < 0) {
+ snprintf(buffer, buffer_size, "<p><b>Error saving \"%s\": %s</b></p>", publish_to, strerror(errno));
+ return 1;
+ }
+ if(dprintf(save_file, JBLOG_FILEPATTERN, date_str, time_str, author, title, md_input) < 0) {
+ snprintf(buffer, buffer_size, "<p><b>Error saving \"%s\": %s</b></p>", publish_to, strerror(errno));
+ close(save_file);
+ return 1;
+ }
+
+ snprintf(buffer, buffer_size, "<p><b>Saved successfully to %s</b></p>", publish_to);
+ close(save_file);
+ return 1;
+ } else if(strcmp(sub_str, "Publish") == 0) {
+ // Publish a file
+ char publish_path[PATH_MAX] = "";
+ snprintf(publish_path, PATH_MAX, "%s/%s", base_path, publish_to);
+ int publish_file = open(publish_path, O_CREAT | O_RDWR, 0600);
+ printf("%s\n", publish_path);
+ if(publish_file < 0) {
+ snprintf(buffer, buffer_size, "<p><b>Error publishing \"%s\": %s</b></p>", publish_to, strerror(errno));
+ return 1;
+ }
+ if(dprintf(publish_file, JBLOG_FILEPATTERN, date_str, time_str, author, title, md_input) < 0) {
+ snprintf(buffer, buffer_size, "<p><b>Error saving \"%s\": %s</b></p>", publish_to, strerror(errno));
+ close(publish_file);
+ return 1;
+ }
+
+ snprintf(buffer, buffer_size, "<p><b>Published successfully to <a href=\"%s\">%s</a></b></p>", publish_to, publish_to);
+ close(publish_file);
+ return 1;
+ }
+ }
+
+ if(folder_name != NULL) {
+ sanitize_path(folder_name);
+ char folder_path[PATH_MAX] = "";
+ snprintf(folder_path, PATH_MAX, "%s%s", base_path, folder_name);
+ if(strcmp(sub_str, "Delete") == 0) {
+ // Delete a file
+ if(remove(folder_path) != 0) {
+ snprintf(buffer, buffer_size, "<p><b>Error deleting file \"%s\": %s</b></p>", folder_name, strerror(errno));
+ return 1;
+ }
+ snprintf(buffer, buffer_size, "<p><b>Deleted file \"%s\"</b></p>", folder_name);
+ return 1;
+ } else if(strcmp(sub_str, "Create Folder") == 0) {
+ // Create a folder
+ if(mkdir(folder_path, 0700) != 0) {
+ snprintf(buffer, buffer_size, "<p><b>Error creating folder \"%s\": %s</b></p>", folder_name, strerror(errno));
+ }
+ snprintf(buffer, buffer_size, "<p><b>Created folder \"%s\"</b></p>", folder_name);
+ return 1;
+ } else if(strcmp(sub_str, "Fetch Files") == 0) {
+ // Show files
+ DIR* fetch_dir = opendir(folder_path);
+ if(fetch_dir == NULL) {
+ snprintf(buffer, buffer_size, "<p><b>Error opening directory \"%s\": %s</b></p>", folder_name, strerror(errno));
+ return 1;
+ }
+ struct dirent* fetch_dirent = NULL;
+ while((fetch_dirent = readdir(fetch_dir)) != NULL) {
+ if(*(fetch_dirent->d_name) == '.') {
+ continue;
+ }
+ size_t buffer_used = strlen(buffer);
+ char* buffer_end = buffer + buffer_used;
+ char entry_path[PATH_MAX] = "";
+ // Check the type of the entry
+ snprintf(entry_path, PATH_MAX, "%s/%s", folder_path, fetch_dirent->d_name);
+ char* entry_link = (char*)entry_path + strlen(base_path);
+ struct stat entry_stat = {0};
+ if(lstat(entry_path, & entry_stat) == -1) {
+ snprintf(buffer, buffer_size, "<p><b>stat error on \"%s\": %s</b></p>", entry_path, strerror(errno));
+ return 1;
+ }
+ snprintf(buffer_end, buffer_size - buffer_used, "<a target=\"_blank\" href=\"%s\">%s&emsp;%s<br/></a>", entry_link, (entry_stat.st_mode & S_IFDIR) > 1 ? "DIR " : "FILE", fetch_dirent->d_name);
+ }
+ closedir(fetch_dir);
+ return 1;
+ }
}
- return 0;
+ perror("Couldn't read all the values from the form!");
+ return -1;
}
diff --git a/admin.h b/admin.h
index 706c372..ad89960 100644
--- a/admin.h
+++ b/admin.h
@@ -1,3 +1,20 @@
+// Copyright 2021 Jeremias Stotter
+//
+// This file is part of ´JBlog´.
+//
+// ´JBlog´ is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// ´JBlog´ is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with ´JBlog´. If not, see <http://www.gnu.org/licenses/>.
+
#ifndef JADMIN
#define JADMIN
int create_admin(char* buffer, size_t buffer_size, char* adm_save_dir);
diff --git a/jblog.c b/jblog.c
index 2c532bb..1ebb447 100644
--- a/jblog.c
+++ b/jblog.c
@@ -58,8 +58,8 @@ int sockfd;
char* blog_head_pretitle;
char* blog_head_postitle;
char* blog_foot;
-char* base_path;
char* adm_save_dir;
+char* base_path;
int pattern_type = 0;
// Root of the search tree used for caching
@@ -473,14 +473,17 @@ int read_jblog_file(char* buffer, int buffer_size, char* file_name, int* error_c
char* html = malloc(buffer_size);
if(html == NULL) {
perror("malloc error");
+ free(original_blog_content);
*error_code = 500;
return -1;
}
+ *html = '\0';
if(strcmp(type_str, "Entry") == 0) {
if(process_blog_text(html, buffer_size, blog_text, title, author, date_str, time_str) != 0) {
*error_code = 500;
+ free(original_blog_content);
return -1;
}
} else if(strcmp(type_str, "Index") == 0) {
@@ -488,6 +491,7 @@ int read_jblog_file(char* buffer, int buffer_size, char* file_name, int* error_c
char path_name[PATH_MAX] = "\0";
if(get_basepath(path_name, PATH_MAX, file_name) != 0) {
*error_code = 500;
+ free(original_blog_content);
return -1;
}
int depth = 0;
@@ -507,6 +511,7 @@ int read_jblog_file(char* buffer, int buffer_size, char* file_name, int* error_c
allow_types = realloc(allow_types, allow_type_count * sizeof(char*));
if(allow_types == NULL) {
*error_code = 500;
+ free(original_blog_content);
return -1;
}
allow_types[i] = index_types;
@@ -515,6 +520,7 @@ int read_jblog_file(char* buffer, int buffer_size, char* file_name, int* error_c
if(create_index(path_name, depth, index_text, MAX_REPLY, NULL, allow_types, allow_type_count, request_uri, NULL, 0) != 0) {
*error_code = 500;
+ free(original_blog_content);
return -1;
}
snprintf(html, buffer_size - 128, "<div class=\"jblog index\">"
@@ -526,6 +532,7 @@ int read_jblog_file(char* buffer, int buffer_size, char* file_name, int* error_c
if(request_method == REQ_GET) {
if(create_admin(html, MAX_REPLY, adm_save_dir) != 0) {
*error_code = 500;
+ free(original_blog_content);
return -1;
}
} else if(request_method == REQ_POST) {
@@ -534,9 +541,14 @@ int read_jblog_file(char* buffer, int buffer_size, char* file_name, int* error_c
wrap_html = false;
} else if(post_result < 0) {
*error_code = 500;
+ free(original_blog_content);
return -1;
}
}
+ } else {
+ fprintf(stderr, "Requested file has no valid type!\n");
+ free(original_blog_content);
+ return -1;
}
free(original_blog_content);
@@ -546,7 +558,8 @@ int read_jblog_file(char* buffer, int buffer_size, char* file_name, int* error_c
free(html);
return length;
} else {
- int length = snprintf(buffer, buffer_size - 20, "<html><body>%s</body></html>", html);
+ int length = snprintf(buffer, buffer_size - 20, "%s<body>%s</body></html>", pattern_type == XHTML_ID ? "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\""
+ " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\">" : "<html>", html);
free(html);
return length;
}
diff --git a/jblog.h b/jblog.h
index 55bd0fb..5009aef 100644
--- a/jblog.h
+++ b/jblog.h
@@ -26,6 +26,8 @@
#define REQ_GET 0
#define REQ_POST 1
+extern char* base_path;
+
void retrieve_headvals(char* head, char retrieve_values[][32], char** returned_strings[], int retrieve_ammount);
char* trim_whitespace(char** str);
int process_blog_text(char* buffer, size_t buffer_size, char* blog_text, char* title, char* author, char* date, char* time);
diff --git a/pattern.xhtml b/pattern.xhtml
index d0cb02b..5aee497 100644
--- a/pattern.xhtml
+++ b/pattern.xhtml
@@ -37,7 +37,7 @@ $TITLE$
width: 50%;
height: 100%
}
- .admin-table, .admin-table tr {
+ .admin-table, .stretch_tr {
width: 100%;
height: 60vh;
}
@@ -49,6 +49,11 @@ $TITLE$
.jb-adm-result {
width: 95%;
height: 100%;
+ background: white;
+ }
+ .jb-adm-result-folder {
+ width: 95%;
+ background: white;
}
</style>
<link rel="icon" href="/favicon.ico"/>
Jeremias Stotters git repositories generated by CGIT