diff --git a/src/main.c b/src/main.c index c70240e..585b57d 100644 --- a/src/main.c +++ b/src/main.c @@ -800,8 +800,8 @@ int socket_name_random(char *out, size_t out_len); /* Version information (auto-updated by build/version tooling) */ #define NSIGNER_VERSION_MAJOR 0 #define NSIGNER_VERSION_MINOR 1 -#define NSIGNER_VERSION_PATCH 11 -#define NSIGNER_VERSION "v0.1.11" +#define NSIGNER_VERSION_PATCH 12 +#define NSIGNER_VERSION "v0.1.12" /* NSIGNER_HEADERLESS_DECLS_END */ @@ -2063,8 +2063,21 @@ static int parse_path_template_for_role(const char *token, seg[seg_len] = '\0'; if (!found_range) { + /* Check for range/set markers first. Only strip hardened marker + * (' or h) from segments that contain - or + (range/set forms). + * A plain number with ' (like 44') is a literal hardened constant, + * NOT a variable. */ char *plus = strchr(seg, '+'); char *dash = strchr(seg, '-'); + int is_range_or_set = (plus != NULL || dash != NULL); + + int seg_hardened = 0; + if (is_range_or_set && seg_len > 0 && + (seg[seg_len - 1] == '\'' || seg[seg_len - 1] == 'h' || seg[seg_len - 1] == 'H')) { + seg_hardened = 1; + seg[seg_len - 1] = '\0'; + seg_len--; + } if (plus != NULL) { /* Set form: "1+34+54" or "1+3-5+10" */ @@ -2104,11 +2117,12 @@ static int parse_path_template_for_role(const char *token, *allowed_count_out = set_count; *range_lo = allowed_indices_out[0]; *range_hi = allowed_indices_out[set_count - 1]; - if (strlen(template_out) + 3 >= template_sz) return -1; + if (strlen(template_out) + 5 >= template_sz) return -1; strcat(template_out, "%d"); + if (seg_hardened) strcat(template_out, "'"); strcat(template_out, "/"); } else { - if (strlen(template_out) + seg_len + 2 >= template_sz) return -1; + if (strlen(template_out) + seg_len + 3 >= template_sz) return -1; strcat(template_out, seg); strcat(template_out, "/"); } @@ -2119,30 +2133,35 @@ static int parse_path_template_for_role(const char *token, long lo = strtol(seg, &e1, 10); long hi = strtol(dash + 1, &e2, 10); if (*e1 != '\0' || *e2 != '\0' || lo < 0 || hi < 0 || lo > hi) { - if (strlen(template_out) + seg_len + 2 >= template_sz) return -1; + *dash = '-'; /* restore dash */ + if (strlen(template_out) + seg_len + 3 >= template_sz) return -1; strcat(template_out, seg); strcat(template_out, "/"); } else { found_range = 1; *range_lo = (int)lo; *range_hi = (int)hi; - if (strlen(template_out) + 3 >= template_sz) return -1; + if (strlen(template_out) + 5 >= template_sz) return -1; strcat(template_out, "%d"); + if (seg_hardened) strcat(template_out, "'"); strcat(template_out, "/"); } } else { - /* Single number */ + /* Single number — only treat as variable if NO hardened marker. + * A segment like "44'" is a literal hardened constant. */ char *e = NULL; long v = strtol(seg, &e, 10); if (*e != '\0' || v < 0) { - if (strlen(template_out) + seg_len + 2 >= template_sz) return -1; + /* Not a plain number (has ' or other chars) — literal */ + if (strlen(template_out) + seg_len + 3 >= template_sz) return -1; strcat(template_out, seg); strcat(template_out, "/"); } else { + /* Plain number without ' — this is the variable */ found_range = 1; *range_lo = (int)v; *range_hi = (int)v; - if (strlen(template_out) + 3 >= template_sz) return -1; + if (strlen(template_out) + 5 >= template_sz) return -1; strcat(template_out, "%d"); strcat(template_out, "/"); } diff --git a/src/server.c b/src/server.c index e233987..0954d2f 100644 --- a/src/server.c +++ b/src/server.c @@ -2374,7 +2374,8 @@ int server_handle_one(server_ctx_t *ctx, server_activity_cb cb, void *cb_data) { if (extract_method_and_selector(request, method, sizeof(method), &selector_req) == 0) { if (ctx->dispatcher->role_table != NULL) { selector_rc = selector_resolve(&selector_req, ctx->dispatcher->role_table, &role); - if (selector_rc == SELECTOR_OK && role != NULL) { + if (selector_rc == SELECTOR_OK && role != NULL && + role->selector_type == SELECTOR_NOSTR_INDEX) { json_copy_string(role_name, sizeof(role_name), role->name, "main"); json_copy_string(purpose, sizeof(purpose), role_purpose_to_str(role->purpose), "nostr"); } else if (selector_rc == SELECTOR_ERR_NOT_FOUND && selector_req.has_nostr_index) { @@ -2398,6 +2399,8 @@ int server_handle_one(server_ctx_t *ctx, server_activity_cb cb, void *cb_data) { role->selector_type == SELECTOR_ROLE_PATH && strstr(role->role_path, "%d") == NULL) { /* Fixed-path named role — no index needed, derive if not yet done */ + json_copy_string(role_name, sizeof(role_name), role->name, "main"); + json_copy_string(purpose, sizeof(purpose), role_purpose_to_str(role->purpose), "nostr"); if (!role->derived) { pending_derivation = 1; } @@ -2405,6 +2408,8 @@ int server_handle_one(server_ctx_t *ctx, server_activity_cb cb, void *cb_data) { role->selector_type == SELECTOR_ROLE_PATH && strstr(role->role_path, "%d") != NULL) { /* Named path-role with template — resolve the concrete path from index */ + json_copy_string(role_name, sizeof(role_name), role->name, "main"); + json_copy_string(purpose, sizeof(purpose), role_purpose_to_str(role->purpose), "nostr"); int chosen_index; if (selector_req.has_index) { chosen_index = selector_req.index;