diff --git a/src/usb/lwip/rest.h b/src/usb/lwip/rest.h index d96d2d7..23bcf5d 100644 --- a/src/usb/lwip/rest.h +++ b/src/usb/lwip/rest.h @@ -31,6 +31,7 @@ #define REST_MAX_METHOD_SIZE 8 #define REST_MAX_CONTENT_TYPE_SIZE 64 #define REST_MAX_PATH_SIZE 192 +#define REST_MAX_REQUEST_PARAMS 4 typedef enum { REST_HTTP_UNKNOWN = 0x0, @@ -64,13 +65,29 @@ typedef enum { REST_HEADER_TOTAL_COUNT } rest_header_id_t; +typedef enum { + REST_PARAM_UNKNOWN = 0, + REST_PARAM_INTEGER, + REST_PARAM_STRING +} rest_param_type_t; + typedef struct { + union { + uint32_t int_param; + char *str_param; + } param; + rest_param_type_t type; +} rest_param_t; + +typedef struct +{ rest_http_method_t method; char path[REST_MAX_PATH_SIZE]; const char *body; size_t body_len; const char *content_type; char *headers[REST_HEADER_TOTAL_COUNT]; + rest_param_t params[REST_MAX_REQUEST_PARAMS]; } rest_request_t; typedef struct { @@ -90,12 +107,7 @@ typedef enum { REST_ROUTE_REQUIRE_TLS = 0x2, } rest_route_flags_t; -typedef struct { - rest_http_method_t method; - const char *path; - rest_route_handler_t handler; - rest_route_flags_t flags; -} rest_route_t; +typedef int (*rest_route_param_parser_t)(const char *str, const char *param_str, rest_param_t params_out[REST_MAX_REQUEST_PARAMS]); typedef enum { REST_SESSION_ROLE_NONE = 0, @@ -103,6 +115,16 @@ typedef enum { REST_SESSION_ROLE_ADMIN = 0x2 } rest_session_role_t; +typedef struct { + rest_http_method_t method; + const char *path; + rest_route_handler_t handler; + rest_route_flags_t flags; + rest_route_param_parser_t param_parser; + rest_session_role_t role; // Minimum required role to access this route (only relevant if REST_ROUTE_REQUIRE_AUTH flag is set) +} rest_route_t; + + typedef enum { REST_SESSION_UNKNOWN = 0, REST_SESSION_AUTH_PENDING = 0x1, diff --git a/src/usb/lwip/rest_server.c b/src/usb/lwip/rest_server.c index d900d5f..3b4ede4 100644 --- a/src/usb/lwip/rest_server.c +++ b/src/usb/lwip/rest_server.c @@ -695,7 +695,13 @@ void rest_handle_request(rest_conn_t *conn) { if (routes[i].path == NULL || routes[i].handler == NULL) { continue; } - if (strcmp(routes[i].path, request->path) != 0) { + if (routes[i].param_parser != NULL) { + int result = routes[i].param_parser(request->path, routes[i].path, request->params); + if (result < 0) { + continue; + } + } + else if (strcmp(routes[i].path, request->path) != 0) { continue; } if (!(routes[i].method & request->method)) { @@ -716,6 +722,10 @@ void rest_handle_request(rest_conn_t *conn) { send_json_error(conn, 401, "authentication_required"); return; } + if (session->role < routes[i].role) { + send_json_error(conn, 403, "insufficient_privileges"); + return; + } if (session->last_activity_timestamp + REST_SESSION_TIMEOUT_INACTIVITY_MS < board_millis() || session->created_at + REST_SESSION_TIMEOUT_TOTAL_MS < board_millis()) { session->status = REST_SESSION_EXPIRED; send_json_error(conn, 401, "session_expired");