Skip to content

Commit

Permalink
Add "page" page with possibility to add new record
Browse files Browse the repository at this point in the history
Add sorting (asc, desc) option to filter
Add proper sorting in comparator for file sorting in fileno
Add support for tag absence for parser and generating records
Fix possible string overflow during dealing with "last" file
Add modifying string on preparing "last" file
Add length limitation for utf8_check()
Remove unused special_markdown_case()
Set proper sorting on displaying title page
Fix NULL dereferencing when tags are absent
Replace redirect HTTP status from 301 to 302
Fix wrong behaviour when user is logged in and he's trying to login
Add related to page visual markdown editor which requires js
Replace "page" form post enctype to application/x-www-form-urlencoded
Add NULL check for urldecode2()
  • Loading branch information
xdevelnet committed Aug 1, 2023
1 parent f3973cd commit 4a57eaf
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 38 deletions.
3 changes: 3 additions & 0 deletions src/abstract_data_layer.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,12 @@ struct layer_context {
uint32_t enough_space[14];
}; // 14*4 byte context is probably enough for any engine needs

enum sorting_seq {DESC = 0, ASC};

struct list_filter {
unix_epoch from; // unixtime
unix_epoch to;
enum sorting_seq sort;
char **tags;
};

Expand Down
44 changes: 29 additions & 15 deletions src/abstract_data_layer_fileno.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ void deinitialize_engine_fileno(void *context) {
struct fileno_scandir_pass {
unix_epoch from;
unix_epoch to;
enum sorting_seq sort;
int dirfd;
};

Expand All @@ -163,8 +164,14 @@ static int comparator(const struct dirent **d1, const struct dirent **d2, void *
fstatat(fpass->dirfd, (*d2)->d_name, s + 1, 0);

if (s[0].st_mtim.tv_sec == s[1].st_mtim.tv_sec and s[0].st_mtim.tv_nsec == s[1].st_mtim.tv_nsec) return 0;
if (abiggerb_timespec(s[0].st_mtim, s[1].st_mtim)) return 1;
return -1;

if (fpass->sort == ASC) {
if (abiggerb_timespec(s[0].st_mtim, s[1].st_mtim)) return 1;
return -1;
}

if (abiggerb_timespec(s[0].st_mtim, s[1].st_mtim)) return -1;
return 1;
}

static void scanfree(struct dirent **e, int amount) {
Expand All @@ -174,7 +181,7 @@ static void scanfree(struct dirent **e, int amount) {
free(e);
}

// This filter is NOT REENTRANT! Use scandir() with mutextes to make it thread-safe
// This filter is REENTRANT 😍😍😍! Because we're using specific custom-mate scandir()!
static int filter_fun(const struct dirent *d, void *pass) {
static const int keep = 1;
static const int away = 0;
Expand All @@ -188,7 +195,7 @@ static int filter_fun(const struct dirent *d, void *pass) {
return keep;
}

// SELECT record_id from records WHERE modified_time > from and modified_time < to LIMIT amount OFFSET offset sort by modified_time;
// SELECT record_id from records WHERE modified_time > from and modified_time < to LIMIT amount OFFSET sort by modified_time;
bool list_records_fileno(unsigned *amount,// Pointer that could be used for limiting amount of results in list. After executing places amount of results.
unsigned long *result_list, // Array that will be filled with results
unsigned offset, // Skip some amount rows/records/results
Expand All @@ -214,7 +221,7 @@ bool list_records_fileno(unsigned *amount,// Pointer that could be used for limi
} while(0);

struct dirent **dirent;
struct fileno_scandir_pass fpass = {.from = filter.from, .to = filter.to, .dirfd = scanfd};
struct fileno_scandir_pass fpass = {.from = filter.from, .to = filter.to, .sort = filter.sort, .dirfd = scanfd};
int ret = scandir_r(scanaddr, &dirent, filter_fun, comparator, &fpass);

unsigned limit = *amount; // 8 lines below could be refactored... Or now. IDK.
Expand Down Expand Up @@ -272,7 +279,13 @@ static size_t taglen(const char *str) {
}

static char *tag_processing(char *comma_separated_tags, struct blog_record *r) {
size_t tags_amount = char_occurences(comma_separated_tags, ',') + 1;
size_t tags_amount;
if (comma_separated_tags[0] == '\n') {
tags_amount = 0;
} else {
tags_amount = char_occurences(comma_separated_tags, ',') + 1;
}

size_t stack_ptrs_space = sizeof(void *) * (tags_amount + 1);
char *put = (char *) r->stack + stack_ptrs_space;
r->tags = r->stack;
Expand Down Expand Up @@ -380,7 +393,7 @@ bool parse_metadata(int fd, struct metadata_strings *meta_strings, const char **
meta_strings->title == NULL or
meta_strings->data == NULL or
meta_strings->datasource == NULL or
meta_strings->tags == NULL or
// meta_strings->tags == NULL or
meta_strings->creation_unixepoch == NULL or
meta_strings->modificated_unixepoch == NULL
) OUCH_ERROR(data_layer_error_metadata_corrupted, return false);
Expand Down Expand Up @@ -572,6 +585,10 @@ static void add_to_tag(const char *tag, struct fileno_context *f, struct blog_re

void tag_writer(int fd, char **tags, struct fileno_context *f, struct blog_record *r) {
write(fd, "tags: ", strizeof("tags: "));
if (tags == NULL) {
write(fd, "\n", 1);
return;
}
bool commaspace = false;
while(*tags) {
if (commaspace == true) {write(fd, ", ", 2);} else {commaspace = true;}
Expand All @@ -589,7 +606,7 @@ static bool flush_files(int meta, struct fileno_context *f, struct blog_record *
normalize_filename(name);
size_t len = strlen(name);

if (r->stack_space < len + NAME_MAX) OUCH_ERROR(data_layer_error_not_enough_stack_space, return false);
// if (r->stack_space < len + NAME_MAX) OUCH_ERROR(data_layer_error_not_enough_stack_space, return false);

int fd, sfd;

Expand Down Expand Up @@ -648,14 +665,15 @@ static bool flush_files(int meta, struct fileno_context *f, struct blog_record *
return true;
}

static bool last_prepare(int fd, char str[CBL_UINT32_STR_MAX], unsigned long *val, const char **error) {
static bool last_prepare(int fd, char str[CBL_UINT32_STR_MAX + 1], unsigned long *val, const char **error) {
ssize_t got;

if (fd < 0 or (got = read(fd, str, CBL_UINT32_STR_MAX)) < 0) OUCH_ERROR(strerror(errno), return false);
if (got > 0) {
if (emb_isdigit(str[0]) == false) OUCH_ERROR(data_layer_error_metadata_corrupted, return false);
str[got] = '\0';
*val = strtoul(str, NULL, 10);
sprintf(str, "%lu", *val);
return true;
}

Expand All @@ -671,11 +689,11 @@ bool insert_record_fileno(struct blog_record *r, void *context, const char **err

if (r->titlelen > NAME_MAX or r->titlelen == 0) OUCH_ERROR(data_layer_error_invalid_argument, return false);
if (display_enum_to_str(r->display) == NULL) OUCH_ERROR(data_layer_error_invalid_argument, return false);
if (utf8_check(r->title) != NULL) OUCH_ERROR(data_layer_error_invalid_argument_utf8, return false);
if (utf8_check(r->title, r->titlelen) != NULL) OUCH_ERROR(data_layer_error_invalid_argument_utf8, return false);
if (r->datalen == 0 and r->datasourcelen == 0) OUCH_ERROR(data_layer_error_invalid_argument, return false);

int last_record_storage_fd = openat(f->dfd, fileno_last_record_file, O_RDWR | O_CREAT, DEFAULT_FILE_MODE);
char last_record_str[CBL_UINT32_STR_MAX];
char last_record_str[CBL_UINT32_STR_MAX + 1];
if (last_prepare(last_record_storage_fd, last_record_str, &(r->chosen_record), error) == false) {
close(last_record_storage_fd);
return false;
Expand All @@ -701,10 +719,6 @@ bool insert_record_fileno(struct blog_record *r, void *context, const char **err
return true;
}

void special_markdown_case(int fd, struct blog_record *old, struct blog_record *r, struct fileno_context *f) {

}

#define METADATA_FMT_WITH_TAGS_LIMITED METADATA_VER "\ndisplay: %s\nunix access: %03"PRIu32"\nuser id: %"PRIu32"\ngroup id: %"PRIu32"\ntitle: %.*s" \
"\ndata: %.*s\ndatasource: %.*s\ncreation_unixepoch: %lu\nmodificated_unixepoch: %lu\ntags: %.*s\n"

Expand Down
137 changes: 117 additions & 20 deletions src/app.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ void (*app_read) (void *, unsigned long *, void *);
const char default_header_content_type[] = "Content-Type: text/html;charset=utf-8";
const char default_header_server_type[] = "Server: cblog app operator";
const char default_header_location_slash[] = "Location: /";
const char default_header_location_user[] = "Location: /user";
const char default_header_location_page[] = "Location: /page";
const char default_header_nocache_1[] = "Cache-Control: no-cache, no-store, must-revalidate";
const char default_header_nocache_2[] = "Pragma: no-cache";
const char default_header_nocache_3[] = "Expires: 0";
Expand Down Expand Up @@ -456,7 +458,7 @@ static void title(reqargs a) {
.datasource = config->title_page_content,
.datasourcelen = config->title_page_content_len,
};
struct list_filter filter = {.from.t = 0l, .to.t = 2147483647l}; // (unix_epoch) 0l, (unix_epoch) 2147483647l
struct list_filter filter = {.from.t = 0l, .to.t = 2147483647l, .sort = DESC}; // (unix_epoch) 0l, (unix_epoch) 2147483647l
const unsigned offset = 0;
selector(a, HOW_MANY_RECORDS_U_WANT_TO_SEE_ON_TITLEPAGE, offset, filter, &b, true);
}
Expand Down Expand Up @@ -512,6 +514,7 @@ static inline void record_show_tag_processing(reqargs a, int32_t tag, struct blo
case TAGS_PAGE_PART:
{
char **tags = b.tags;
if (tags == NULL) break;
while(*tags) {
size_t taglen = strlen(*tags);
APP_WRITE(LI_AND_A_TAGS_PREF, strizeof(LI_AND_A_TAGS_PREF));
Expand Down Expand Up @@ -568,7 +571,7 @@ static void show_record(reqargs a, uint32_t record) {
}

static bool minimum_passwd_requirements(char *password, size_t passwd_minlen, bool passwd_specialchar) {
if (utf8_check(password) != NULL) return false;
if (utf8_check(password, strlen(password)) != NULL) return false;
size_t passwd_len = 0;
bool passwd_specialchar_presence = false;

Expand Down Expand Up @@ -713,7 +716,7 @@ void user_login(reqargs a) {
sprintf(cookie, "Set-Cookie: id=%s%s", key, SMCOL_EXPIRES);
headers_table_append(headers_table, cookie);
headers_table_append(headers_table, default_header_location_slash);
SET_HTTP_STATUS_AND_HDR(301, headers_table);
SET_HTTP_STATUS_AND_HDR(302, headers_table);
APP_WRITECS("Redirecting: /");
return;
}
Expand All @@ -736,8 +739,10 @@ void user_login(reqargs a) {

if (user_logged_in) {
headers_table_append(headers_table, default_header_location_slash);
SET_HTTP_STATUS_AND_HDR(301, headers_table);
SET_HTTP_STATUS_AND_HDR(302, headers_table);
APP_WRITECS("Redirecting: /");

return;
}

size_t freespace = CONTEXTAPPBUFFERSIZE - (con->freebuffer - (char *) con);
Expand All @@ -753,14 +758,14 @@ void user_login(reqargs a) {
freespace -= size;
if (freespace < sizeof(struct usr)) return internal_server_error(a, data_layer_error_not_enough_stack_space);
size_t namelen;
char *name = http_query_finder("name", con->freebuffer, size, &namelen, false);
char *name = http_query_finder("name", post_data, size, &namelen, false);
if (name == NULL or namelen >= sizeof(u->display_name)) {
out[TITLE_PAGE_PART] = data_layer_error_invalid_argument;
outsizes[TITLE_PAGE_PART] = strizeof(data_layer_error_invalid_argument);
break;
}
size_t passwordlen;
char *password = http_query_finder("password", con->freebuffer, size, &passwordlen, false);
char *password = http_query_finder("password", post_data, size, &passwordlen, false);
if (password == NULL) {
out[TITLE_PAGE_PART] = data_layer_error_invalid_argument;
outsizes[TITLE_PAGE_PART] = strizeof(data_layer_error_invalid_argument);
Expand Down Expand Up @@ -813,11 +818,11 @@ void user_logout(reqargs a) {
headers_table_append(logout_headers_table, cookie);
}

SET_HTTP_STATUS_AND_HDR(301, logout_headers_table);
SET_HTTP_STATUS_AND_HDR(302, logout_headers_table);
APP_WRITECS("Redirecting: /");
}

static inline void editor_processing(reqargs a, int32_t tag, struct usr *u) {
static inline void editor_processing(reqargs a, int32_t tag, struct usr *u, char *error, size_t errorlen) {
struct appcontext *con = CONTEXT;
// essb *e = &con->templates;
// struct layer_context *l = &con->layer;
Expand All @@ -833,14 +838,19 @@ static inline void editor_processing(reqargs a, int32_t tag, struct usr *u) {
APP_WRITECS("Add/edit page/record");
break;
case CONTENT_PAGE_PART:
if (error != NULL and errorlen > 0) {
APP_WRITECS("Error: ");
APP_WRITE(error, errorlen);
APP_WRITECS("<br><br>");
}
APP_WRITE(default_add_edit_form_html, strizeof(default_add_edit_form_html));
break;
// case USER_PAGE_PART:
// APP_WRITE(LI_AND_A_USER, strizeof(LI_AND_A_USER));
// APP_WRITE(u->display_name, strlen(u->display_name));
// APP_WRITE(LI_A_SUFF, strizeof(LI_A_SUFF));
// APP_WRITE(LI_AND_A_LOGOUT_FULL_STR, strizeof(LI_AND_A_LOGOUT_FULL_STR));
// break;
case USER_PAGE_PART:
APP_WRITE(LI_AND_A_USER, strizeof(LI_AND_A_USER));
APP_WRITE(u->display_name, strlen(u->display_name));
APP_WRITE(LI_A_SUFF, strizeof(LI_A_SUFF));
APP_WRITE(LI_AND_A_LOGOUT_FULL_STR, strizeof(LI_AND_A_LOGOUT_FULL_STR));
break;
default:
return;
}
Expand All @@ -849,18 +859,105 @@ static inline void editor_processing(reqargs a, int32_t tag, struct usr *u) {
void page(reqargs a) {
struct appcontext *con = CONTEXT;
essb *e = &con->templates;
// struct layer_context *l = &con->layer;
struct layer_context *l = &con->layer;
// struct appconfig *config = con->config;

const char *headers_table[] = {default_header_nocache_1, default_header_nocache_2, default_header_nocache_3,
default_header_content_type, default_header_server_type, NULL};
SET_HTTP_STATUS_AND_HDR(200, headers_table);
default_header_content_type, default_header_server_type, NULL, NULL, NULL};

char cookie[sizeof(SETCOOKIEID SMCOL_EXPIRES) + KEY_VAL_MAXKEYLEN];

for (unsigned i = 0; i < e->records_amount; i++) {
if (e->record_size[i] < 0) editor_processing(a, e->record_size[i], NULL);
else APP_WRITE(&e->records[e->record_seek[i]], e->record_size[i]);
bool user_logged_in = false;
struct usr logged_in_user;
do{
char key[KEY_VAL_MAXKEYLEN];
if (find_cookie_existence(a, "id", key) == 0) break;

ssize_t size = - ((ssize_t) sizeof(logged_in_user));
bool ret = key_val(key, &logged_in_user, &size, l, NULL);
if (ret == false or is_user_legit(l, &logged_in_user) == false) {
sprintf(cookie, "Set-Cookie: id=%s%s", key, SMCOL_EXPIRES);
headers_table_append(headers_table, cookie);
headers_table_append(headers_table, default_header_location_user);
SET_HTTP_STATUS_AND_HDR(302, headers_table);
APP_WRITECS("Redirecting: /user");
return;
}

user_logged_in = true;
} while(0);

if (user_logged_in == false) {
headers_table_append(headers_table, default_header_location_user);
SET_HTTP_STATUS_AND_HDR(302, headers_table);
APP_WRITECS("Redirecting: /user");
return;
}

size_t freespace = CONTEXTAPPBUFFERSIZE - (con->freebuffer - (char *) con);
char *input_data = con->freebuffer;

if (METHOD == GET) {
SET_HTTP_STATUS_AND_HDR(200, headers_table);
size_t size = 0;
char *find = http_query_finder("error", QUERY, QUERY_LEN, &size, false);
memcpy(input_data, find, size);
input_data[size] = '\0';
size = urldecode2(input_data, input_data) - input_data;

for (unsigned i = 0; i < e->records_amount; i++) {
if (e->record_size[i] < 0) editor_processing(a, e->record_size[i], &logged_in_user, input_data, size);
else APP_WRITE(&e->records[e->record_seek[i]], e->record_size[i]);
}

return;
}

size_t size = freespace;
APP_READ(input_data, &size);

if (size == 0) {
headers_table_append(headers_table, default_header_location_page);
SET_HTTP_STATUS_AND_HDR(302, headers_table);
APP_WRITECS("Redirecting: /page");
return;
}

input_data[size] = '\0';
size = urldecode2(input_data, input_data) - input_data;
input_data[size] = '\0';

size_t titlelen;
char *title = http_query_finder("title", input_data, size, &titlelen, false);

size_t datalen;
char *data = http_query_finder("data", input_data, size, &datalen, false);

if (title == NULL or data == NULL) {
headers_table_append(headers_table, default_header_location_page);
SET_HTTP_STATUS_AND_HDR(302, headers_table);
APP_WRITECS("Redirecting: /page");
return;
}

struct blog_record b = {.title = title, .titlelen = titlelen, .data = data, .datalen = datalen, .display = DISPLAY_DATASOURCE};
const char *error;
bool result = insert_record(&b, l, &error);
char strhdr[200];
if (result == false) {
printf("error: %s\n", error);
snprintf(strhdr, sizeof(strhdr), "Location: /page?error=%s", error);

headers_table_append(headers_table, strhdr);
SET_HTTP_STATUS_AND_HDR(302, headers_table);
APP_WRITECS("Redirecting: /page");
return;
}

snprintf(strhdr, sizeof(strhdr), "Location: /newpage-%lu", b.chosen_record);
headers_table_append(headers_table, strhdr);
SET_HTTP_STATUS_AND_HDR(302, headers_table);
APP_WRITECS("Redirecting: /newpage...");
}

//#define IFREQ(page, fun) do{if(REQUEST_LEN==strizeof(page) and memcmp(REQUEST, page, strizeof(page)) == STREQ) return fun(a);}while(0)
Expand Down
2 changes: 1 addition & 1 deletion src/default_rodata.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const bool default_password_specialchars_needed = false;
const char default_form_html[] = "<form action=\"/user\" method=\"POST\"><input type=\"text\" placeholder=\"Enter Username\" name=\"name\" required autofocus><br><input type=\"password\" placeholder=\"Enter Password\" name=\"password\" required><br><button type=\"submit\">Login</button></form>";
size_t default_form_html_len = strizeof(default_form_html);

const char default_add_edit_form_html[] = "<form action=\"/page\" method=\"post\" enctype=\"multipart/form-data\"><input type=\"text\" placeholder=\"Title\" name=\"title\" required autofocus><br><textarea id=\"txt\" name=\"data\" minlength=\"1\"></textarea><script>var simplemde = new SimpleMDE({ element: document.getElementById(\"txt\"), forceSync: true, spellChecker: false, tabSiz: 4});</script><br><button type=\"submit\">Send</button></form>";
const char default_add_edit_form_html[] = "<form action=\"/page\" method=\"post\" enctype=\"application/x-www-form-urlencoded\"><input type=\"text\" placeholder=\"Title\" name=\"title\" required autofocus><br><textarea id=\"txt\" name=\"data\" minlength=\"1\"></textarea><script>var simplemde = new SimpleMDE({ element: document.getElementById(\"txt\"), forceSync: true, spellChecker: false, tabSiz: 4});</script><br><button type=\"submit\">Send</button></form>";

const char default_welcome_after_login_title[] = "Welcome!";
const char default_welcome_after_login[] = "You can visit <a href=\"/\">home page</a> or <a href=\"/user\">user panel</a>";
Expand Down
Loading

0 comments on commit 4a57eaf

Please sign in to comment.