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.

Reply via email to