feat(lander): implement placeholder keys
ci/woodpecker/push/build Pipeline was successful
Details
ci/woodpecker/push/build Pipeline was successful
Details
parent
4d9dfff27e
commit
3952496378
|
@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased](https://git.rustybever.be/Chewing_Bever/lander/src/branch/dev)
|
||||
|
||||
## Added
|
||||
|
||||
* Ability to generate keys that allow one-time unauthenticated uploads (a.k.a.
|
||||
generating upload links)
|
||||
|
||||
## Fixed
|
||||
|
||||
* Failed uploads now no longer leave behind a partial entry file
|
||||
|
|
|
@ -27,6 +27,7 @@ typedef enum lander_entry_type : uint8_t {
|
|||
lander_entry_type_redirect = 0,
|
||||
lander_entry_type_paste = 1,
|
||||
lander_entry_type_file = 2,
|
||||
lander_entry_type_placeholder = 3,
|
||||
} lander_entry_type;
|
||||
|
||||
void *lander_gctx_init();
|
||||
|
@ -61,6 +62,16 @@ lnm_http_step_err lander_post_file(lnm_http_conn *conn);
|
|||
|
||||
lnm_http_step_err lander_post_file_secure(lnm_http_conn *conn);
|
||||
|
||||
lnm_http_step_err lander_post_placeholder(lnm_http_conn *conn);
|
||||
|
||||
lnm_http_step_err lander_post_placeholder_secure(lnm_http_conn *conn);
|
||||
|
||||
/**
|
||||
* Step that authenticates requests. If the key of the request is for a
|
||||
* placeholder entry, authentication is granted without an api key.
|
||||
*/
|
||||
lnm_http_step_err lander_auth_or_placeholder(lnm_http_conn *conn);
|
||||
|
||||
/**
|
||||
* Store the requested header as an attribute, if it's present.
|
||||
*/
|
||||
|
|
|
@ -56,7 +56,8 @@ lsm_error lsm_entry_attr_get_uint8_t(uint8_t *out, lsm_entry_handle *handle,
|
|||
uint8_t type);
|
||||
|
||||
/**
|
||||
* Add a new attribute to the entry.
|
||||
* Add a new attribute to the entry. This overwrites an existing version of this
|
||||
* attribute.
|
||||
*
|
||||
* @param entry entry to modify
|
||||
* @param type type of attribute to add
|
||||
|
|
|
@ -211,8 +211,10 @@ lsm_error lsm_entry_attr_remove(lsm_str **out, lsm_entry_handle *handle,
|
|||
|
||||
lsm_error lsm_entry_attr_insert(lsm_entry_handle *handle, uint8_t type,
|
||||
lsm_str *data) {
|
||||
if (lsm_entry_attr_present(handle, type)) {
|
||||
return lsm_error_already_present;
|
||||
// Remove a previous version of the attribute
|
||||
lsm_str *out;
|
||||
if (lsm_entry_attr_remove(&out, handle, type) == lsm_error_ok) {
|
||||
lsm_str_free(out);
|
||||
}
|
||||
|
||||
lsm_entry *entry = handle->wrapper->entry;
|
||||
|
|
|
@ -17,7 +17,8 @@ static void randomize_key(char *key, int len) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Insert a new entry into the store.
|
||||
* Insert a new entry into the store. If an entry is already open, this function
|
||||
* is a no-op.
|
||||
*
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
|
@ -26,6 +27,12 @@ bool lander_insert_entry(lnm_http_loop_ctx *ctx, bool secure) {
|
|||
lander_gctx *c_gctx = gctx->c;
|
||||
lander_ctx *c_ctx = ctx->c;
|
||||
|
||||
// With placeholders, the entry will already be open so an entry should no
|
||||
// longer be created
|
||||
if (c_ctx->entry != NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *key_s;
|
||||
size_t key_len = lnm_http_req_route_segment(&key_s, &ctx->req, "key");
|
||||
|
||||
|
@ -147,3 +154,25 @@ lnm_http_step_err lander_post_file(lnm_http_conn *conn) {
|
|||
lnm_http_step_err lander_post_file_secure(lnm_http_conn *conn) {
|
||||
return __lander_post_file(conn, true);
|
||||
}
|
||||
|
||||
lnm_http_step_err __lander_post_placeholder(lnm_http_conn *conn, bool secure) {
|
||||
lnm_http_loop_ctx *ctx = conn->ctx;
|
||||
lander_ctx *c_ctx = ctx->c;
|
||||
|
||||
if (!lander_insert_entry(ctx, secure)) {
|
||||
return lnm_http_step_err_res;
|
||||
}
|
||||
|
||||
lsm_entry_attr_insert_uint8_t(c_ctx->entry, lander_attr_type_entry_type,
|
||||
lander_entry_type_placeholder);
|
||||
|
||||
return lnm_http_step_err_done;
|
||||
}
|
||||
|
||||
lnm_http_step_err lander_post_placeholder(lnm_http_conn *conn) {
|
||||
return __lander_post_placeholder(conn, false);
|
||||
}
|
||||
|
||||
lnm_http_step_err lander_post_placeholder_secure(lnm_http_conn *conn) {
|
||||
return __lander_post_placeholder(conn, true);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "lnm/loop.h"
|
||||
|
||||
#include "lander.h"
|
||||
#include "lsm/store.h"
|
||||
|
||||
lnm_http_step_err lander_stream_body_to_entry(lnm_http_conn *conn) {
|
||||
lnm_http_loop_ctx *ctx = conn->ctx;
|
||||
|
@ -35,3 +36,48 @@ lnm_http_step_err lander_commit_entry(lnm_http_conn *conn) {
|
|||
|
||||
return lnm_http_step_err_done;
|
||||
}
|
||||
|
||||
lnm_http_step_err lander_auth_or_placeholder(lnm_http_conn *conn) {
|
||||
lnm_http_loop_ctx *ctx = conn->ctx;
|
||||
lnm_http_loop_gctx *gctx = ctx->g;
|
||||
lander_gctx *c_gctx = gctx->c;
|
||||
lander_ctx *c_ctx = ctx->c;
|
||||
|
||||
const char *key_s;
|
||||
size_t key_len = lnm_http_req_route_segment(&key_s, &ctx->req, "key");
|
||||
|
||||
// Only predefined keys can be placeholders
|
||||
if (key_len == 0) {
|
||||
return lnm_http_loop_step_auth(conn);
|
||||
}
|
||||
|
||||
lsm_str *key;
|
||||
lsm_str_init_copy_n(&key, key_s, key_len);
|
||||
|
||||
lsm_error res = lsm_store_open_write(&c_ctx->entry, c_gctx->store, key);
|
||||
|
||||
lsm_str_free(key);
|
||||
|
||||
switch (res) {
|
||||
case lsm_error_ok: {
|
||||
lander_entry_type t;
|
||||
|
||||
// If the entry is a placeholder, the request is always authenticated
|
||||
if ((lsm_entry_attr_get_uint8_t(
|
||||
&t, c_ctx->entry, lander_attr_type_entry_type) == lsm_error_ok) &&
|
||||
(t == lander_entry_type_placeholder)) {
|
||||
return lnm_http_step_err_done;
|
||||
} else {
|
||||
return lnm_http_loop_step_auth(conn);
|
||||
}
|
||||
} break;
|
||||
case lsm_error_not_found:
|
||||
return lnm_http_loop_step_auth(conn);
|
||||
break;
|
||||
default:
|
||||
ctx->res.status = lnm_http_status_internal_server_error;
|
||||
return lnm_http_step_err_res;
|
||||
}
|
||||
|
||||
return lnm_http_step_err_done;
|
||||
}
|
||||
|
|
35
src/main.c
35
src/main.c
|
@ -34,62 +34,77 @@ lnm_http_loop *loop_init(lander_gctx *gctx, const char *api_key) {
|
|||
lnm_http_route_step_append(route, lander_commit_entry, true);
|
||||
|
||||
lnm_http_router_add(&route, router, lnm_http_method_post, "/s/");
|
||||
lnm_http_route_step_append(route, lnm_http_loop_step_auth, false);
|
||||
lnm_http_route_step_append(route, lander_auth_or_placeholder, false);
|
||||
lnm_http_route_step_append(route, lander_post_redirect, false);
|
||||
lnm_http_route_step_append(route, lnm_http_loop_step_body_to_buf, false);
|
||||
lnm_http_route_step_append(route, lander_post_redirect_body_to_attr, false);
|
||||
lnm_http_route_step_append(route, lander_commit_entry, true);
|
||||
|
||||
lnm_http_router_add(&route, router, lnm_http_method_post, "/sl/");
|
||||
lnm_http_route_step_append(route, lnm_http_loop_step_auth, false);
|
||||
lnm_http_route_step_append(route, lander_auth_or_placeholder, false);
|
||||
lnm_http_route_step_append(route, lander_post_redirect_secure, false);
|
||||
lnm_http_route_step_append(route, lnm_http_loop_step_body_to_buf, false);
|
||||
lnm_http_route_step_append(route, lander_post_redirect_body_to_attr, false);
|
||||
lnm_http_route_step_append(route, lander_commit_entry, true);
|
||||
|
||||
lnm_http_router_add(&route, router, lnm_http_method_post, "/s/:key");
|
||||
lnm_http_route_step_append(route, lnm_http_loop_step_auth, false);
|
||||
lnm_http_route_step_append(route, lander_auth_or_placeholder, false);
|
||||
lnm_http_route_step_append(route, lander_post_redirect, false);
|
||||
lnm_http_route_step_append(route, lnm_http_loop_step_body_to_buf, false);
|
||||
lnm_http_route_step_append(route, lander_post_redirect_body_to_attr, false);
|
||||
lnm_http_route_step_append(route, lander_commit_entry, true);
|
||||
|
||||
lnm_http_router_add(&route, router, lnm_http_method_post, "/p/");
|
||||
lnm_http_route_step_append(route, lnm_http_loop_step_auth, false);
|
||||
lnm_http_route_step_append(route, lander_auth_or_placeholder, false);
|
||||
lnm_http_route_step_append(route, lander_post_paste, false);
|
||||
lnm_http_route_step_append(route, lander_stream_body_to_entry, false);
|
||||
lnm_http_route_step_append(route, lander_commit_entry, true);
|
||||
|
||||
lnm_http_router_add(&route, router, lnm_http_method_post, "/pl/");
|
||||
lnm_http_route_step_append(route, lnm_http_loop_step_auth, false);
|
||||
lnm_http_route_step_append(route, lander_auth_or_placeholder, false);
|
||||
lnm_http_route_step_append(route, lander_post_paste_secure, false);
|
||||
lnm_http_route_step_append(route, lander_stream_body_to_entry, false);
|
||||
lnm_http_route_step_append(route, lander_commit_entry, true);
|
||||
|
||||
lnm_http_router_add(&route, router, lnm_http_method_post, "/p/:key");
|
||||
lnm_http_route_step_append(route, lnm_http_loop_step_auth, false);
|
||||
lnm_http_route_step_append(route, lander_auth_or_placeholder, false);
|
||||
lnm_http_route_step_append(route, lander_post_paste, false);
|
||||
lnm_http_route_step_append(route, lander_stream_body_to_entry, false);
|
||||
lnm_http_route_step_append(route, lander_commit_entry, true);
|
||||
|
||||
lnm_http_router_add(&route, router, lnm_http_method_post, "/f/");
|
||||
lnm_http_route_step_append(route, lnm_http_loop_step_auth, false);
|
||||
lnm_http_route_step_append(route, lander_auth_or_placeholder, false);
|
||||
lnm_http_route_step_append(route, lander_post_file, false);
|
||||
lnm_http_route_step_append(route, lander_stream_body_to_entry, false);
|
||||
lnm_http_route_step_append(route, lander_commit_entry, true);
|
||||
|
||||
lnm_http_router_add(&route, router, lnm_http_method_post, "/fl/");
|
||||
lnm_http_route_step_append(route, lnm_http_loop_step_auth, false);
|
||||
lnm_http_route_step_append(route, lander_auth_or_placeholder, false);
|
||||
lnm_http_route_step_append(route, lander_post_file_secure, false);
|
||||
lnm_http_route_step_append(route, lander_stream_body_to_entry, false);
|
||||
lnm_http_route_step_append(route, lander_commit_entry, true);
|
||||
|
||||
lnm_http_router_add(&route, router, lnm_http_method_post, "/f/:key");
|
||||
lnm_http_route_step_append(route, lnm_http_loop_step_auth, false);
|
||||
lnm_http_route_step_append(route, lander_auth_or_placeholder, false);
|
||||
lnm_http_route_step_append(route, lander_post_file, false);
|
||||
lnm_http_route_step_append(route, lander_stream_body_to_entry, false);
|
||||
lnm_http_route_step_append(route, lander_commit_entry, true);
|
||||
|
||||
lnm_http_router_add(&route, router, lnm_http_method_post, "/h/");
|
||||
lnm_http_route_step_append(route, lnm_http_loop_step_auth, false);
|
||||
lnm_http_route_step_append(route, lander_post_placeholder, false);
|
||||
lnm_http_route_step_append(route, lander_commit_entry, true);
|
||||
|
||||
lnm_http_router_add(&route, router, lnm_http_method_post, "/h/:key");
|
||||
lnm_http_route_step_append(route, lnm_http_loop_step_auth, false);
|
||||
lnm_http_route_step_append(route, lander_post_placeholder, false);
|
||||
lnm_http_route_step_append(route, lander_commit_entry, true);
|
||||
|
||||
lnm_http_router_add(&route, router, lnm_http_method_post, "/hs/");
|
||||
lnm_http_route_step_append(route, lnm_http_loop_step_auth, false);
|
||||
lnm_http_route_step_append(route, lander_post_placeholder_secure, false);
|
||||
lnm_http_route_step_append(route, lander_commit_entry, true);
|
||||
|
||||
lnm_http_loop_router_set(hl, router);
|
||||
|
||||
return hl;
|
||||
|
@ -140,5 +155,5 @@ int main() {
|
|||
lnm_linfo("main", "Store loaded containing %lu entries",
|
||||
lsm_store_size(c_gctx->store));
|
||||
lnm_http_loop *hl = loop_init(c_gctx, api_key);
|
||||
lnm_http_loop_run(hl, port, 1, 0);
|
||||
lnm_http_loop_run(hl, port, 1, 1);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue