v0.0.16 - Add .fips identity-cache fallback for URL signer resolution and fix Write menu Exit hotkey underline
This commit is contained in:
52
src/main.c
52
src/main.c
@@ -11,8 +11,8 @@
|
||||
*/
|
||||
#define NT_VERSION_MAJOR 0
|
||||
#define NT_VERSION_MINOR 0
|
||||
#define NT_VERSION_PATCH 15
|
||||
#define NT_VERSION "v0.0.15"
|
||||
#define NT_VERSION_PATCH 16
|
||||
#define NT_VERSION "v0.0.16"
|
||||
|
||||
#include <ncurses.h>
|
||||
#include <stdio.h>
|
||||
@@ -183,31 +183,41 @@ int main(int argc, char *argv[]) {
|
||||
nt_set_app_info("NOSTR TERMINAL", NT_VERSION);
|
||||
nt_set_window_title("Nostr Terminal");
|
||||
|
||||
/* Splash screen */
|
||||
/* Splash screen (no header/footer, centered text) */
|
||||
{
|
||||
TuiFrame frame = nt_frame("> Splash");
|
||||
TuiStatus status = {"Press any key to continue"};
|
||||
WINDOW *body = (WINDOW *)tuin_body_window();
|
||||
int h = 0;
|
||||
int w = 0;
|
||||
const char *title = "NOSTR TERMINAL";
|
||||
int len = (int)strlen(title);
|
||||
int col;
|
||||
int row;
|
||||
const char *version = NT_VERSION;
|
||||
int title_len = (int)strlen(title);
|
||||
int version_len = (int)strlen(version);
|
||||
int title_col;
|
||||
int version_col;
|
||||
int title_row;
|
||||
|
||||
tuin_render_header(&frame);
|
||||
getmaxyx(body, h, w);
|
||||
col = (w - len) / 2;
|
||||
if (col < 0) {
|
||||
col = 0;
|
||||
getmaxyx(stdscr, h, w);
|
||||
|
||||
title_col = (w - title_len) / 2;
|
||||
if (title_col < 0) {
|
||||
title_col = 0;
|
||||
}
|
||||
row = h / 2;
|
||||
werase(body);
|
||||
mvwprintw(body, row, col, "%s", title);
|
||||
mvwprintw(body, row + 1, col, "%s", NT_VERSION);
|
||||
wnoutrefresh(body);
|
||||
tuin_render_footer(&status);
|
||||
doupdate();
|
||||
|
||||
version_col = (w - version_len) / 2;
|
||||
if (version_col < 0) {
|
||||
version_col = 0;
|
||||
}
|
||||
|
||||
title_row = (h / 2) - 1;
|
||||
if (title_row < 0) {
|
||||
title_row = 0;
|
||||
}
|
||||
|
||||
werase(stdscr);
|
||||
mvprintw(title_row, title_col, "%s", title);
|
||||
if (title_row + 1 < h) {
|
||||
mvprintw(title_row + 1, version_col, "%s", version);
|
||||
}
|
||||
refresh();
|
||||
tuin_get_key();
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ void menu_write(void) {
|
||||
{NT_HK("T", "weet it"), 't'},
|
||||
{NT_HK("B", "log post (kind 30023)"), 'b'},
|
||||
{NT_HK("D", "iary entry (kind 30024)"), 'd'},
|
||||
{NT_HK("X", "Exit without saving"), 'x'},
|
||||
{"E" NT_HK("x", "it without saving"), 'x'},
|
||||
};
|
||||
TuiFrame frame = nt_frame("> Main Menu > Write");
|
||||
TuiStatus status = nt_status();
|
||||
|
||||
@@ -337,6 +337,125 @@ static int nsigner_parse_url(const char *url, char *host_out, size_t host_out_sz
|
||||
return NT_NSIGNER_OK;
|
||||
}
|
||||
|
||||
static int nsigner_host_has_fips_suffix(const char *host) {
|
||||
size_t n;
|
||||
|
||||
if (!host) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = strlen(host);
|
||||
return (n > 5 && strcmp(host + (n - 5), ".fips") == 0);
|
||||
}
|
||||
|
||||
static int nsigner_extract_npub_from_fips_host(const char *host,
|
||||
char *npub_out,
|
||||
size_t npub_out_sz) {
|
||||
const char *dot;
|
||||
size_t n;
|
||||
|
||||
if (!host || !npub_out || npub_out_sz == 0 || !nsigner_host_has_fips_suffix(host)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dot = strstr(host, ".fips");
|
||||
if (!dot || dot == host) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = (size_t)(dot - host);
|
||||
if (n == 0 || n >= npub_out_sz) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(npub_out, host, n);
|
||||
npub_out[n] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nsigner_lookup_identity_cache_ipv6(const char *npub,
|
||||
char *ipv6_out,
|
||||
size_t ipv6_out_sz) {
|
||||
FILE *fp;
|
||||
char chunk[512];
|
||||
char *json_buf = NULL;
|
||||
size_t used = 0;
|
||||
size_t cap = 0;
|
||||
cJSON *root = NULL;
|
||||
cJSON *entries;
|
||||
int rc = -1;
|
||||
|
||||
if (!npub || !ipv6_out || ipv6_out_sz == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fp = popen("fipsctl show identity-cache 2>/dev/null", "r");
|
||||
if (!fp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (fgets(chunk, sizeof(chunk), fp)) {
|
||||
size_t need = strlen(chunk);
|
||||
if (used + need + 1 > cap) {
|
||||
size_t new_cap = (cap == 0) ? 2048 : (cap * 2);
|
||||
char *tmp;
|
||||
while (new_cap < used + need + 1) {
|
||||
new_cap *= 2;
|
||||
}
|
||||
tmp = (char *)realloc(json_buf, new_cap);
|
||||
if (!tmp) {
|
||||
free(json_buf);
|
||||
pclose(fp);
|
||||
return -1;
|
||||
}
|
||||
json_buf = tmp;
|
||||
cap = new_cap;
|
||||
}
|
||||
memcpy(json_buf + used, chunk, need);
|
||||
used += need;
|
||||
json_buf[used] = '\0';
|
||||
}
|
||||
|
||||
pclose(fp);
|
||||
if (!json_buf || used == 0) {
|
||||
free(json_buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
root = cJSON_Parse(json_buf);
|
||||
free(json_buf);
|
||||
if (!root) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
entries = cJSON_GetObjectItemCaseSensitive(root, "entries");
|
||||
if (cJSON_IsArray(entries)) {
|
||||
cJSON *entry;
|
||||
cJSON_ArrayForEach(entry, entries) {
|
||||
cJSON *npub_item = cJSON_GetObjectItemCaseSensitive(entry, "npub");
|
||||
cJSON *ipv6_item;
|
||||
if (!cJSON_IsString(npub_item) || !npub_item->valuestring) {
|
||||
continue;
|
||||
}
|
||||
if (strcmp(npub_item->valuestring, npub) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ipv6_item = cJSON_GetObjectItemCaseSensitive(entry, "ipv6_addr");
|
||||
if (cJSON_IsString(ipv6_item) && ipv6_item->valuestring &&
|
||||
ipv6_item->valuestring[0] != '\0' &&
|
||||
strlen(ipv6_item->valuestring) < ipv6_out_sz) {
|
||||
memcpy(ipv6_out, ipv6_item->valuestring, strlen(ipv6_item->valuestring) + 1);
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cJSON_Delete(root);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int nsigner_connect_url(const char *url) {
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *res = NULL;
|
||||
@@ -356,7 +475,22 @@ static int nsigner_connect_url(const char *url) {
|
||||
|
||||
snprintf(port_str, sizeof(port_str), "%d", port);
|
||||
if (getaddrinfo(host, port_str, &hints, &res) != 0) {
|
||||
return -1;
|
||||
char npub[128];
|
||||
char ipv6_addr[128];
|
||||
|
||||
if (nsigner_extract_npub_from_fips_host(host, npub, sizeof(npub)) == 0 &&
|
||||
nsigner_lookup_identity_cache_ipv6(npub, ipv6_addr, sizeof(ipv6_addr)) == 0) {
|
||||
struct addrinfo numeric_hints;
|
||||
memset(&numeric_hints, 0, sizeof(numeric_hints));
|
||||
numeric_hints.ai_family = AF_UNSPEC;
|
||||
numeric_hints.ai_socktype = SOCK_STREAM;
|
||||
numeric_hints.ai_flags = AI_NUMERICHOST;
|
||||
if (getaddrinfo(ipv6_addr, port_str, &numeric_hints, &res) != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (ai = res; ai; ai = ai->ai_next) {
|
||||
|
||||
Reference in New Issue
Block a user