This is an automated email from the git hooks/post-receive script.
git pushed a commit to reference refs/pull/34/head
in repository terminology.
View the commit online.
commit 79f339826b4ea96b3889bfae7cb87523b61cca87
Author: [email protected] <[email protected]>
AuthorDate: Sun Mar 29 21:39:57 2026 -0600
feat: add IPC nonce registration for tytab (server side)
Security layer 3 (server): new IPC command (major=4, minor=1) accepts
tab creation requests, validates the terminal, generates a 64-bit
random nonce with 30ms expiry, and replies with the nonce string.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
---
src/bin/ipc.c | 79 +++++++++++++++++++++++++++++++++++++++
src/bin/ipc.h | 21 +++++++++++
src/bin/win.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/bin/win.h | 3 ++
4 files changed, 220 insertions(+)
diff --git a/src/bin/ipc.c b/src/bin/ipc.c
index 7dfff99c..d22e220e 100644
--- a/src/bin/ipc.c
+++ b/src/bin/ipc.c
@@ -7,6 +7,10 @@
#include "ipc.h"
#include "tycommon.h"
+/* forward declaration to avoid pulling in win.h (which requires Elementary headers) */
+char *tab_nonce_register(unsigned int term_id, const char *name,
+ const char *direction, const char *cmd);
+
#define TY_IPC_MAJOR 3
#define TY_IPC_MINOR 8
@@ -14,6 +18,8 @@ static Ecore_Ipc_Server *ipc = NULL;
static Ecore_Event_Handler *hnd_data = NULL;
static void (*func_new_inst) (Ipc_Instance *inst) = NULL;
static Eet_Data_Descriptor *new_inst_edd = NULL;
+static Eet_Data_Descriptor *tab_req_edd = NULL;
+static Eet_Data_Descriptor *tab_rep_edd = NULL;
static Eina_Bool
_ipc_cb_client_data(void *_data EINA_UNUSED,
@@ -39,9 +45,80 @@ _ipc_cb_client_data(void *_data EINA_UNUSED,
free(inst);
}
}
+ else if ((e->major == TY_IPC_MAJOR_TAB) &&
+ (e->minor == TY_IPC_MINOR_TAB) &&
+ (e->data) && (e->size > 0))
+ {
+ Ipc_Tab_Request *req;
+
+ req = eet_data_descriptor_decode(tab_req_edd, e->data, e->size);
+ if (req)
+ {
+ Ipc_Tab_Reply rep = { .nonce_str = "0" };
+ char *nonce_s = tab_nonce_register(req->term_id, req->name,
+ req->direction, req->cmd);
+ if (nonce_s)
+ rep.nonce_str = nonce_s;
+
+ int rep_size = 0;
+ void *rep_data = eet_data_descriptor_encode(tab_rep_edd,
+ &rep, &rep_size);
+ if (rep_data)
+ {
+ ecore_ipc_client_send(e->client,
+ TY_IPC_MAJOR_TAB, TY_IPC_MINOR_TAB,
+ 0, 0, 0, rep_data, rep_size);
+ ecore_ipc_client_flush(e->client);
+ free(rep_data);
+ }
+ free(nonce_s);
+ free(req);
+ }
+ }
return ECORE_CALLBACK_PASS_ON;
}
+void
+ipc_tab_init(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+
+ eet_eina_stream_data_descriptor_class_set(&eddc, sizeof(eddc),
+ "tab_req",
+ sizeof(Ipc_Tab_Request));
+ tab_req_edd = eet_data_descriptor_stream_new(&eddc);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(tab_req_edd, Ipc_Tab_Request,
+ "term_id", term_id, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(tab_req_edd, Ipc_Tab_Request,
+ "name", name, EET_T_STRING);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(tab_req_edd, Ipc_Tab_Request,
+ "cmd", cmd, EET_T_STRING);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(tab_req_edd, Ipc_Tab_Request,
+ "direction", direction, EET_T_STRING);
+
+ eet_eina_stream_data_descriptor_class_set(&eddc, sizeof(eddc),
+ "tab_rep",
+ sizeof(Ipc_Tab_Reply));
+ tab_rep_edd = eet_data_descriptor_stream_new(&eddc);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(tab_rep_edd, Ipc_Tab_Reply,
+ "nonce_str", nonce_str, EET_T_STRING);
+}
+
+void
+ipc_tab_shutdown(void)
+{
+ if (tab_req_edd)
+ {
+ eet_data_descriptor_free(tab_req_edd);
+ tab_req_edd = NULL;
+ }
+ if (tab_rep_edd)
+ {
+ eet_data_descriptor_free(tab_rep_edd);
+ tab_rep_edd = NULL;
+ }
+}
+
static char *
_ipc_hash_get(void)
{
@@ -119,6 +196,7 @@ ipc_init(void)
"cursor_blink", active_links, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(new_inst_edd, Ipc_Instance,
"visual_bell", active_links, EET_T_INT);
+ ipc_tab_init();
}
Eina_Bool
@@ -137,6 +215,7 @@ ipc_serve(void)
void
ipc_shutdown(void)
{
+ ipc_tab_shutdown();
if (ipc)
{
ecore_ipc_server_del(ipc);
diff --git a/src/bin/ipc.h b/src/bin/ipc.h
index f9b43305..e0e2fd55 100644
--- a/src/bin/ipc.h
+++ b/src/bin/ipc.h
@@ -45,4 +45,25 @@ void ipc_instance_new_func_set(void (*func) (Ipc_Instance *inst));
Eina_Bool ipc_instance_add(Ipc_Instance *inst);
void ipc_instance_conn_free(void);
+#define TY_IPC_MAJOR_TAB 4
+#define TY_IPC_MINOR_TAB 1
+
+typedef struct _Ipc_Tab_Request Ipc_Tab_Request;
+struct _Ipc_Tab_Request
+{
+ unsigned int term_id;
+ char *name;
+ char *cmd;
+ char *direction; /* "l","r","t","b" or "" — Eet needs string, not char */
+};
+
+typedef struct _Ipc_Tab_Reply Ipc_Tab_Reply;
+struct _Ipc_Tab_Reply
+{
+ char *nonce_str; /* decimal string of uint64, "0" = rejected */
+};
+
+void ipc_tab_init(void);
+void ipc_tab_shutdown(void);
+
#endif
diff --git a/src/bin/win.c b/src/bin/win.c
index 40842057..6079f985 100644
--- a/src/bin/win.c
+++ b/src/bin/win.c
@@ -2,6 +2,7 @@
#include <assert.h>
#include <stdint.h>
+#include <inttypes.h>
#include <fcntl.h>
#include <unistd.h>
#include <Elementary.h>
@@ -6547,6 +6548,122 @@ _sendfile_request(Term *term, const char *path)
elm_object_focus_set(o, EINA_TRUE);
}
+typedef struct _Tab_Nonce Tab_Nonce;
+struct _Tab_Nonce
+{
+ uint64_t nonce;
+ char *name;
+ char *cmd;
+ char direction;
+ uint32_t term_id;
+ Ecore_Timer *timer;
+};
+
+static Eina_List *_pending_nonces = NULL;
+
+static Eina_Bool
+_tab_nonce_expire_cb(void *data)
+{
+ Tab_Nonce *tn = data;
+
+ _pending_nonces = eina_list_remove(_pending_nonces, tn);
+ free(tn->name);
+ free(tn->cmd);
+ free(tn);
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static Term *
+_term_find_by_id(uint32_t term_id)
+{
+ Eina_List *l, *ll;
+ Win *wn;
+ Term *term;
+
+ EINA_LIST_FOREACH(wins, l, wn)
+ {
+ EINA_LIST_FOREACH(wn->terms, ll, term)
+ {
+ if (term->term_id == term_id)
+ return term;
+ }
+ }
+ return NULL;
+}
+
+static uint64_t
+_nonce_generate(void)
+{
+ uint64_t nonce;
+ int fd;
+ Eina_List *l;
+ Tab_Nonce *tn;
+ Eina_Bool collision;
+
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd < 0) return 0;
+
+ do
+ {
+ if (read(fd, &nonce, sizeof(nonce)) != sizeof(nonce))
+ {
+ close(fd);
+ return 0;
+ }
+ if (nonce == 0) continue;
+
+ collision = EINA_FALSE;
+ EINA_LIST_FOREACH(_pending_nonces, l, tn)
+ {
+ if (tn->nonce == nonce)
+ {
+ collision = EINA_TRUE;
+ break;
+ }
+ }
+ }
+ while (nonce == 0 || collision);
+
+ close(fd);
+ return nonce;
+}
+
+char *
+tab_nonce_register(unsigned int term_id, const char *name,
+ const char *direction, const char *cmd)
+{
+ Term *term;
+ Config *config;
+ Tab_Nonce *tn;
+ uint64_t nonce;
+ char buf[32];
+
+ term = _term_find_by_id(term_id);
+ if (!term) return NULL;
+
+ config = termio_config_get(term->termio);
+ if (!config || !config->tytab) return NULL;
+ if (term->tytab_frozen) return NULL;
+
+ nonce = _nonce_generate();
+ if (nonce == 0) return NULL;
+
+ tn = calloc(1, sizeof(Tab_Nonce));
+ if (!tn) return NULL;
+
+ tn->nonce = nonce;
+ tn->term_id = term_id;
+ if (name && name[0]) tn->name = strdup(name);
+ if (cmd && cmd[0]) tn->cmd = strdup(cmd);
+ if (direction && direction[0]) tn->direction = direction[0];
+ tn->timer = ecore_timer_add(0.03, _tab_nonce_expire_cb, tn);
+
+ _pending_nonces = eina_list_append(_pending_nonces, tn);
+
+ snprintf(buf, sizeof(buf), "%" PRIu64, nonce);
+ return strdup(buf);
+}
+
static Term_Container *
_container_find_by_name(Term_Container *tc, Eina_Stringshare *name)
{
diff --git a/src/bin/win.h b/src/bin/win.h
index f242fff7..e691771a 100644
--- a/src/bin/win.h
+++ b/src/bin/win.h
@@ -92,4 +92,7 @@ for_each_term_do(Win *wn, For_Each_Term cb, void *data);
void main_trans_update(void);
+char *tab_nonce_register(unsigned int term_id, const char *name,
+ const char *direction, const char *cmd);
+
#endif
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.