summaryrefslogtreecommitdiff
path: root/clients/web.h
diff options
context:
space:
mode:
Diffstat (limited to 'clients/web.h')
-rw-r--r--clients/web.h100
1 files changed, 100 insertions, 0 deletions
diff --git a/clients/web.h b/clients/web.h
new file mode 100644
index 0000000..a652498
--- /dev/null
+++ b/clients/web.h
@@ -0,0 +1,100 @@
+#ifndef BOKF_WEB_H
+#define BOKF_WEB_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "util.h"
+
+/* Pure parts of bokfweb, the login gate in front of the browser terminal:
+ HTTP request parsing, form and cookie decoding, HTML escaping, the
+ session store and the per-address login limiter. Unit-tested in
+ tests/test_web.c; bokfweb.c adds sockets and the bokfd calls. */
+
+#define WEB_MAX_REQUEST 8192
+
+struct web_req {
+ char method[8];
+ char path[256]; /* without the query */
+ char query[256];
+ char cookie[512];
+ char forwarded_for[64];
+ char forwarded_uri[512];
+ const char *body; /* points into the parsed buffer */
+ size_t body_len;
+};
+
+/* Parses one HTTP/1.x request in buf[0..n). Returns 0 when complete
+ (headers and Content-Length bytes of body), 1 when more bytes are
+ needed, -1 when malformed or too large. */
+int web_parse_request(const char *buf, size_t n, struct web_req *r);
+
+/* Value of key in an application/x-www-form-urlencoded string (also a
+ query string), decoded ('+' and %XX). 0 when found, -1 otherwise; a
+ value that does not fit or decodes to a NUL byte counts as not found. */
+int web_form_get(const char *form, size_t len, const char *key, char *out,
+ size_t cap);
+
+/* Value of cookie `name` in a Cookie header. 0 when found. */
+int web_cookie_get(const char *header, const char *name, char *out,
+ size_t cap);
+
+/* Appends s to b with & < > " ' escaped. */
+void web_html_escape(struct buf *b, const char *s);
+
+/* Whether s is a non-empty token of [A-Za-z0-9_-] only (cookie values and
+ handles are generated that way; anything else is rejected unread). */
+int web_token_ok(const char *s);
+
+/* --- sessions: cookie token -> bokfd session, plus the terminal handle */
+
+#define WEB_MAX_SESSIONS 64
+#define WEB_SESSION_TTL (12 * 3600) /* absolute; bokfd's idle TTL applies too */
+
+struct web_session {
+ char token[64]; /* the cookie value */
+ char handle[64]; /* goes into the terminal URL (?arg=) */
+ char bokf[128]; /* bokfd session id */
+ char user[64];
+ int64_t created;
+};
+
+struct web_store {
+ struct web_session s[WEB_MAX_SESSIONS];
+};
+
+/* Adds a session with fresh random token and handle; the oldest session is
+ replaced when the store is full. Returns it, or NULL when the random
+ source fails. */
+struct web_session *web_store_add(struct web_store *st, const char *bokf,
+ const char *user, int64_t now);
+/* The live session with this cookie token / terminal handle, or NULL. */
+struct web_session *web_store_by_token(struct web_store *st,
+ const char *token, int64_t now);
+struct web_session *web_store_by_handle(struct web_store *st,
+ const char *handle, int64_t now);
+void web_store_del(struct web_session *s);
+
+/* --- failed-login limiter per client address */
+
+#define WEB_RL_SLOTS 256
+#define WEB_RL_MAX_FAILS 5
+#define WEB_RL_WINDOW 900
+
+struct web_rl_entry {
+ char addr[64];
+ int fails;
+ int64_t window_end;
+};
+
+struct web_rl {
+ struct web_rl_entry e[WEB_RL_SLOTS];
+};
+
+/* Seconds until addr may try again, 0 when it may try now. */
+int64_t web_rl_blocked(const struct web_rl *rl, const char *addr,
+ int64_t now);
+void web_rl_fail(struct web_rl *rl, const char *addr, int64_t now);
+void web_rl_ok(struct web_rl *rl, const char *addr);
+
+#endif