diff options
| author | Xavier Del Campo Romero <xavi92@disroot.org> | 2025-09-22 17:32:44 +0200 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi92@disroot.org> | 2026-02-13 09:57:39 +0100 |
| commit | 78bf2fe4a5bf37514f6dfd203ef969da0bf40c2e (patch) | |
| tree | 33f9440b8ee0fa7a3b3ad033616d722d2101bb4d /ep_ucp.c | |
| parent | 107a2e43d54f9a42fb85b00b83cb0d9abb194680 (diff) | |
Diffstat (limited to 'ep_ucp.c')
| -rw-r--r-- | ep_ucp.c | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/ep_ucp.c b/ep_ucp.c new file mode 100644 index 0000000..30fb9de --- /dev/null +++ b/ep_ucp.c @@ -0,0 +1,241 @@ +/* + * nanobbs, a tiny forums software. + * Copyright (C) 2025-2026 Xavier Del Campo Romero + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "endpoints.h" +#include "db.h" +#include "defs.h" +#include "auth.h" +#include "form.h" +#include <libweb/html.h> +#include <libweb/http.h> +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> + +static int setup_passwd(struct html_node *const n, const char *const username) +{ + int ret = -1; + struct dynstr ud; + struct html_node *div, *user, *form, *lold, *iold, *lnew, + *inew, *lcnew, *icnew, *submit; + + dynstr_init(&ud); + + if (dynstr_append(&ud, "User: %s", username)) + { + fprintf(stderr, "%s: dynstr_append failed\n", __func__); + goto end; + } + else if (!(div = html_node_add_child(n, "div")) + || !(form = html_node_add_child(div, "form")) + || !(user = html_node_add_child(form, "label")) + || !(lold = html_node_add_child(form, "label")) + || !(iold = html_node_add_child(form, "input")) + || !(lnew = html_node_add_child(form, "label")) + || !(inew = html_node_add_child(form, "input")) + || !(lcnew = html_node_add_child(form, "label")) + || !(icnew = html_node_add_child(form, "input")) + || !(submit = html_node_add_child(form, "input"))) + { + fprintf(stderr, "%s: html_node_add_child failed\n", __func__); + goto end; + } + else if (html_node_add_attr(form, "action", "/passwd") + || html_node_add_attr(form, "form", "passwdform") + || html_node_add_attr(form, "method", "post") + || html_node_add_attr(lold, "for", "old") + || html_node_add_attr(lnew, "for", "new") + || html_node_add_attr(lcnew, "for", "cnew") + || html_node_add_attr(iold, "type", "password") + || html_node_add_attr(iold, "id", "old") + || html_node_add_attr(iold, "name", "old") + || html_node_add_attr(inew, "type", "password") + || html_node_add_attr(inew, "id", "new") + || html_node_add_attr(inew, "name", "new") + || html_node_add_attr(icnew, "type", "password") + || html_node_add_attr(icnew, "id", "cnew") + || html_node_add_attr(icnew, "name", "cnew") + || html_node_add_attr(submit, "type", "submit") + || html_node_add_attr(submit, "value", "Change password")) + { + fprintf(stderr, "%s: html_node_add_attr failed\n", __func__); + goto end; + } + else if (html_node_set_value(user, ud.str) + || html_node_set_value(lold, "Current password:") + || html_node_set_value(lnew, "New password:") + || html_node_set_value(lcnew, "Confirm new password:")) + { + fprintf(stderr, "%s: html_node_set_value failed\n", __func__); + goto end; + } + + ret = 0; + +end: + dynstr_free(&ud); + return ret; +} + +static int setup_useract(struct html_node *const div) +{ + struct f + { + const char *text, *id, *url; + struct html_node *luser, *iuser, *form, *submit; + } fs[] = + { + {.text = "Ban user", .id = "banform", .url = "/confirm/ban"}, + {.text = "Delete user", .id = "delform", .url = "/confirm/deluser"} + }; + + for (size_t i = 0; i < sizeof fs / sizeof *fs; i++) + { + struct f *const f = &fs[i]; + + if (!(f->form = html_node_add_child(div, "form")) + || !(f->luser = html_node_add_child(f->form, "label")) + || !(f->iuser = html_node_add_child(f->form, "input")) + || !(f->submit = html_node_add_child(f->form, "input"))) + { + fprintf(stderr, "%s: html_node_add_child failed\n", __func__); + return -1; + } + else if (html_node_add_attr(f->form, "action", f->url) + || html_node_add_attr(f->form, "form", f->id) + || html_node_add_attr(f->form, "method", "post") + || html_node_add_attr(f->luser, "for", "user") + || html_node_add_attr(f->iuser, "type", "text") + || html_node_add_attr(f->iuser, "id", "user") + || html_node_add_attr(f->iuser, "name", "user") + || html_node_add_attr(f->submit, "type", "submit") + || html_node_add_attr(f->submit, "value", f->text)) + { + fprintf(stderr, "%s: html_node_add_attr failed\n", __func__); + return -1; + } + else if (html_node_set_value(f->luser, "Username:")) + { + fprintf(stderr, "%s: html_node_set_value failed\n", __func__); + return -1; + } + } + + return 0; +} + +static int setup(const struct http_payload *const p, + struct http_response *const r, void *const user, sqlite3 *const db, + const struct auth_user *const u) +{ + int ret = -1, error; + struct html_node *root = NULL, *body, *div; + struct dynstr d; + + dynstr_init(&d); + + if (!u) + { + ret = form_unauthorized("Login required", r); + goto end; + } + else if (u->role <= AUTH_ROLE_BANNED) + { + ret = form_unauthorized("Banned account", r); + goto end; + } + else if (!(root = html_node_alloc("html"))) + { + fprintf(stderr, "%s: html_node_alloc failed\n", __func__); + goto end; + } + else if (form_head(root)) + { + fprintf(stderr, "%s: form_head failed\n", __func__); + goto end; + } + else if (!(body = html_node_add_child(root, "body")) + || !(div = html_node_add_child(body, "div"))) + { + fprintf(stderr, "%s: html_node_add_child failed\n", __func__); + goto end; + } + else if (setup_passwd(div, u->username)) + { + fprintf(stderr, "%s: setup_passwd failed\n", __func__); + goto end; + } + else if (u->role >= AUTH_ROLE_MOD && setup_useract(div)) + { + fprintf(stderr, "%s: setup_useract failed\n", __func__); + goto end; + } + else if (form_footer(body, p->resource)) + { + fprintf(stderr, "%s: form_footer failed\n", __func__); + goto end; + } + else if (dynstr_append(&d, "%s", DOCTYPE_TAG)) + { + fprintf(stderr, "%s: dynstr_append failed\n", __func__); + goto end; + } + else if (html_serialize(root, &d)) + { + fprintf(stderr, "%s: html_serialize failed\n", __func__); + goto end; + } + + *r = (const struct http_response) + { + .status = HTTP_STATUS_OK, + .buf.rw = d.str, + .n = d.len, + .free = free + }; + + ret = 0; + +end: + + if ((error = sqlite3_close(db)) != SQLITE_OK) + { + fprintf(stderr, "%s: sqlite3_close: %s\n", __func__, + sqlite3_errstr(error)); + ret = -1; + } + + if (ret) + dynstr_free(&d); + + html_node_free(root); + return ret; +} + +int ep_ucp(const struct http_payload *const p, struct http_response *const r, + void *const user) +{ + const int n = auth_validate(p, r, user, setup); + + if (n < 0) + fprintf(stderr, "%s: auth_validate failed\n", __func__); + else if (n) + return setup(p, r, user, NULL, NULL); + + return n; +} |
