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 33653989eb20720f2e3d581bc335b08e9c93dab6
Author: [email protected] <[email protected]>
AuthorDate: Sun Mar 29 21:54:20 2026 -0600
feat: gate tytab tab creation behind IPC nonce lookup
The tt escape sequence now carries only a nonce reference. The actual
payload (name, direction, cmd) is retrieved from the nonce registered
via IPC. Combined with config toggle, freeze latch, and 1s keypress
check, this provides four independent security gates.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
---
src/bin/win.c | 347 +++++++++++++++++++++++++++++-----------------------------
1 file changed, 175 insertions(+), 172 deletions(-)
diff --git a/src/bin/win.c b/src/bin/win.c
index 6079f985..7afa5b42 100644
--- a/src/bin/win.c
+++ b/src/bin/win.c
@@ -6664,6 +6664,25 @@ tab_nonce_register(unsigned int term_id, const char *name,
return strdup(buf);
}
+static Tab_Nonce *
+_tab_nonce_find_and_remove(uint64_t nonce, uint32_t term_id)
+{
+ Eina_List *l;
+ Tab_Nonce *tn;
+
+ EINA_LIST_FOREACH(_pending_nonces, l, tn)
+ {
+ if (tn->nonce == nonce && tn->term_id == term_id)
+ {
+ _pending_nonces = eina_list_remove_list(_pending_nonces, l);
+ ecore_timer_del(tn->timer);
+ tn->timer = NULL;
+ return tn;
+ }
+ }
+ return NULL;
+}
+
static Term_Container *
_container_find_by_name(Term_Container *tc, Eina_Stringshare *name)
{
@@ -6842,43 +6861,18 @@ _cb_command(void *data,
eina_stringshare_replace(&tc->name, NULL);
}
}
- else if (cmd[1] == 't') // new tab: tt[;NAME;DIR[;CMD]]
+ else if (cmd[1] == 't') // execute nonce: tt;NONCE
{
const char *p = cmd + 2;
- const char *name_str = NULL, *cmd_str = NULL;
- const char *name_end = NULL;
- char direction = 0;
- Eina_Stringshare *name = NULL;
+ uint64_t nonce_val;
+ Tab_Nonce *tn;
Term_Container *tc = term->container;
Win *wn = tc->wn;
double now;
char buf[PATH_MAX];
char *wdir = NULL;
- /* Parse: ;NAME;DIR[;CMD] — all optional */
- if (*p == ';')
- {
- p++; /* skip first ; */
- name_str = p;
-
- name_end = strchr(p, ';');
- if (!name_end) return; /* malformed: need at least ;NAME;DIR */
- p = name_end + 1;
-
- /* Parse direction (may be empty) */
- if (*p == 'l' || *p == 'r' || *p == 't' || *p == 'b')
- {
- direction = *p;
- p++;
- }
-
- /* Optional CMD after ; */
- if (*p == ';' && *(p + 1))
- cmd_str = p + 1;
- }
- /* else: no arguments at all — current panel, default shell */
-
- /* Anti-bombing check */
+ /* Keypress check (1s) */
now = ecore_time_get();
if (term->last_keypress_time == 0.0 ||
(now - term->last_keypress_time) > 1.0)
@@ -6889,164 +6883,173 @@ _cb_command(void *data,
}
term->last_keypress_time = 0.0;
- /* Always inherit CWD from requesting terminal */
+ /* Parse nonce */
+ if (*p != ';' || !*(p + 1))
+ return;
+ p++;
+ nonce_val = strtoull(p, NULL, 10);
+ if (nonce_val == 0)
+ return;
+
+ /* Look up nonce */
+ tn = _tab_nonce_find_and_remove(nonce_val, term->term_id);
+ if (!tn)
+ {
+ WRN("tab creation blocked: invalid or expired nonce");
+ return;
+ }
+
+ /* Inherit CWD from requesting terminal */
if (termio_cwd_get(term->termio, buf, sizeof(buf)))
wdir = buf;
- /* Build name if provided */
- if (name_str && name_end && name_end > name_str)
- name = eina_stringshare_add_length(name_str, name_end - name_str);
+ /* Execute using stored payload */
+ {
+ const char *cmd_str = tn->cmd;
+ char direction = tn->direction;
+ Eina_Stringshare *name = NULL;
- if (name && direction)
- {
- /* Full form: find named panel or create split */
- Term_Container *target;
- target = _container_find_by_name((Term_Container *)wn, name);
- if (target)
- {
- /* Panel exists: find attachment point */
- Term *tm_new;
- Term_Container *tc_new, *tc_attach = NULL;
+ if (tn->name)
+ name = eina_stringshare_add(tn->name);
- if (target->type == TERM_CONTAINER_TYPE_SOLO)
- {
- if (target->parent->type != TERM_CONTAINER_TYPE_TABS)
- _tabs_new(target, target->parent);
- tc_attach = target->parent;
- }
- else if (target->type == TERM_CONTAINER_TYPE_TABS)
- {
- tc_attach = target;
- }
- else
- {
- Term *tm_first = target->term_first(target);
- if (tm_first)
- {
- Term_Container *tc_first = tm_first->container;
- if (tc_first->parent->type !=
- TERM_CONTAINER_TYPE_TABS)
- _tabs_new(tc_first, tc_first->parent);
- tc_attach = tc_first->parent;
- }
- }
+ if (name && direction)
+ {
+ Term_Container *target;
+ target = _container_find_by_name((Term_Container *)wn, name);
+ if (target)
+ {
+ Term *tm_new;
+ Term_Container *tc_new, *tc_attach = NULL;
- if (!tc_attach)
- {
- eina_stringshare_del(name);
- return;
- }
+ if (target->type == TERM_CONTAINER_TYPE_SOLO)
+ {
+ if (target->parent->type != TERM_CONTAINER_TYPE_TABS)
+ _tabs_new(target, target->parent);
+ tc_attach = target->parent;
+ }
+ else if (target->type == TERM_CONTAINER_TYPE_TABS)
+ {
+ tc_attach = target;
+ }
+ else
+ {
+ Term *tm_first = target->term_first(target);
+ if (tm_first)
+ {
+ Term_Container *tc_first = tm_first->container;
+ if (tc_first->parent->type !=
+ TERM_CONTAINER_TYPE_TABS)
+ _tabs_new(tc_first, tc_first->parent);
+ tc_attach = tc_first->parent;
+ }
+ }
- tm_new = term_new(wn, wn->config,
- cmd_str, wn->config->login_shell,
- wdir, 80, 24, EINA_FALSE, NULL);
- tc_new = _solo_new(tm_new, wn);
- evas_object_data_set(tm_new->termio, "sizedone",
- tm_new->termio);
- _tabs_attach(tc_attach, tc_new);
- }
- else
- {
- /* Panel not found: split and create */
- Split_Direction dir;
- Term *tm_new;
- Term_Container *tc_new;
+ if (tc_attach)
+ {
+ tm_new = term_new(wn, wn->config,
+ cmd_str, wn->config->login_shell,
+ wdir, 80, 24, EINA_FALSE, NULL);
+ tc_new = _solo_new(tm_new, wn);
+ evas_object_data_set(tm_new->termio, "sizedone",
+ tm_new->termio);
+ _tabs_attach(tc_attach, tc_new);
+ }
+ }
+ else
+ {
+ Split_Direction dir;
+ Term *tm_new;
+ Term_Container *tc_new;
- switch (direction)
- {
- case 'l': dir = SPLIT_DIRECTION_LEFT; break;
- case 'r': dir = SPLIT_DIRECTION_RIGHT; break;
- case 't': dir = SPLIT_DIRECTION_TOP; break;
- case 'b': dir = SPLIT_DIRECTION_BOTTOM; break;
- default: eina_stringshare_del(name); return;
- }
+ switch (direction)
+ {
+ case 'l': dir = SPLIT_DIRECTION_LEFT; break;
+ case 'r': dir = SPLIT_DIRECTION_RIGHT; break;
+ case 't': dir = SPLIT_DIRECTION_TOP; break;
+ case 'b': dir = SPLIT_DIRECTION_BOTTOM; break;
+ default: goto done;
+ }
- if (tc->type != TERM_CONTAINER_TYPE_SOLO)
- {
- WRN("tt: requesting terminal is not in a solo "
- "container");
- eina_stringshare_del(name);
- return;
- }
+ if (tc->type != TERM_CONTAINER_TYPE_SOLO)
+ goto done;
- tm_new = term_new(wn, wn->config,
- cmd_str, wn->config->login_shell,
- wdir, 80, 24, EINA_FALSE, NULL);
- tc_new = _solo_new(tm_new, wn);
- evas_object_data_set(tm_new->termio, "sizedone",
- tm_new->termio);
- tc->parent->split_direction(tc->parent, tc, tc_new, dir);
- eina_stringshare_replace(&tc_new->name, name);
- }
- }
- else if (name && !direction)
- {
- /* Name provided but no direction: find panel, add tab (no split) */
- Term_Container *target;
- target = _container_find_by_name((Term_Container *)wn, name);
- if (target)
- {
- Term *tm_new;
- Term_Container *tc_new, *tc_attach = NULL;
+ tm_new = term_new(wn, wn->config,
+ cmd_str, wn->config->login_shell,
+ wdir, 80, 24, EINA_FALSE, NULL);
+ tc_new = _solo_new(tm_new, wn);
+ evas_object_data_set(tm_new->termio, "sizedone",
+ tm_new->termio);
+ tc->parent->split_direction(tc->parent, tc, tc_new, dir);
+ eina_stringshare_replace(&tc_new->name, name);
+ }
+ }
+ else if (name && !direction)
+ {
+ Term_Container *target;
+ target = _container_find_by_name((Term_Container *)wn, name);
+ if (target)
+ {
+ Term *tm_new;
+ Term_Container *tc_new, *tc_attach = NULL;
- if (target->type == TERM_CONTAINER_TYPE_SOLO)
- {
- if (target->parent->type != TERM_CONTAINER_TYPE_TABS)
- _tabs_new(target, target->parent);
- tc_attach = target->parent;
- }
- else if (target->type == TERM_CONTAINER_TYPE_TABS)
- {
- tc_attach = target;
- }
- else
- {
- Term *tm_first = target->term_first(target);
- if (tm_first)
- {
- Term_Container *tc_first = tm_first->container;
- if (tc_first->parent->type !=
- TERM_CONTAINER_TYPE_TABS)
- _tabs_new(tc_first, tc_first->parent);
- tc_attach = tc_first->parent;
- }
- }
+ if (target->type == TERM_CONTAINER_TYPE_SOLO)
+ {
+ if (target->parent->type != TERM_CONTAINER_TYPE_TABS)
+ _tabs_new(target, target->parent);
+ tc_attach = target->parent;
+ }
+ else if (target->type == TERM_CONTAINER_TYPE_TABS)
+ {
+ tc_attach = target;
+ }
+ else
+ {
+ Term *tm_first = target->term_first(target);
+ if (tm_first)
+ {
+ Term_Container *tc_first = tm_first->container;
+ if (tc_first->parent->type !=
+ TERM_CONTAINER_TYPE_TABS)
+ _tabs_new(tc_first, tc_first->parent);
+ tc_attach = tc_first->parent;
+ }
+ }
- if (!tc_attach)
- {
- eina_stringshare_del(name);
- return;
- }
+ if (tc_attach)
+ {
+ tm_new = term_new(wn, wn->config,
+ cmd_str, wn->config->login_shell,
+ wdir, 80, 24, EINA_FALSE, NULL);
+ tc_new = _solo_new(tm_new, wn);
+ evas_object_data_set(tm_new->termio, "sizedone",
+ tm_new->termio);
+ _tabs_attach(tc_attach, tc_new);
+ }
+ }
+ }
+ else
+ {
+ Term *tm_new;
+ Term_Container *tc_new;
- tm_new = term_new(wn, wn->config,
- cmd_str, wn->config->login_shell,
- wdir, 80, 24, EINA_FALSE, NULL);
- tc_new = _solo_new(tm_new, wn);
- evas_object_data_set(tm_new->termio, "sizedone",
- tm_new->termio);
- _tabs_attach(tc_attach, tc_new);
- }
- /* else: named panel not found, no direction to create — ignore */
- }
- else
- {
- /* No name, no direction: add tab to current panel */
- Term *tm_new;
- Term_Container *tc_new;
+ if (tc->parent->type != TERM_CONTAINER_TYPE_TABS)
+ _tabs_new(tc, tc->parent);
- if (tc->parent->type != TERM_CONTAINER_TYPE_TABS)
- _tabs_new(tc, tc->parent);
+ tm_new = term_new(wn, wn->config,
+ cmd_str, wn->config->login_shell, wdir,
+ 80, 24, EINA_FALSE, NULL);
+ tc_new = _solo_new(tm_new, wn);
+ evas_object_data_set(tm_new->termio, "sizedone",
+ tm_new->termio);
+ _tabs_attach(tc->parent, tc_new);
+ }
+done:
+ eina_stringshare_del(name);
+ }
- tm_new = term_new(wn, wn->config,
- cmd_str, wn->config->login_shell, wdir,
- 80, 24, EINA_FALSE, NULL);
- tc_new = _solo_new(tm_new, wn);
- evas_object_data_set(tm_new->termio, "sizedone",
- tm_new->termio);
- _tabs_attach(tc->parent, tc_new);
- }
-
- eina_stringshare_del(name);
+ free(tn->name);
+ free(tn->cmd);
+ free(tn);
}
}
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.