From 6099fa7fb2a0a03bd0176ae546504eef21a095a0 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Tue, 5 Apr 2022 22:18:25 -0700 Subject: [PATCH] experiment: ask for permission on file operations I'm not quite sure how to think about asking for permissions with respect to my red/orange/green color codes. On the one hand, it seems safer than many alternatives. On the other hand, it's liable to lead to fatigue and blindly allowing apps to do stuff. For now I consider ask to be orange. Ask + network allowed = red in summary, though it's orange on the permissions screen since there's more space to convey nuance. Then again, nobody may heed the nuance. The summary up top on the permissions screen is definitely still a work in progress. And there's a chicken-and-egg problem here: I can't really get a good feel for real-world bugs in the permissions screen until _other programmers_ are building apps to use the permissions screen, but they're almost certain to have a crappy time of it. I considered introducing a primitive called ask() in the Lua interpreter, but it doesn't really make sense to validate it and so on. I'm also not really supporting mixing Ask with other features so far. This is a major step towards turning my permissions screen into spaghetti; monitoring closely. --- src/teliva.c | 116 ++++++++++++++++++++++++++++++++++++--------------- src/teliva.h | 1 + 2 files changed, 83 insertions(+), 34 deletions(-) diff --git a/src/teliva.c b/src/teliva.c index 35c9964..b0b6f54 100644 --- a/src/teliva.c +++ b/src/teliva.c @@ -66,6 +66,7 @@ static const char* trim(const char* in) { return result; } +int ask_for_permission_on_every_file_operation = 0; const char* default_file_operations_predicate_body = "return false\n"; const char* file_operations_predicate_body; int net_operations_permitted = false; @@ -126,7 +127,9 @@ const char* character_name(char c) { static void render_permissions(lua_State* L) { int file_colors = COLOR_PAIR_SAFE; - if (file_operations_predicate_body && strcmp("return false", trim(file_operations_predicate_body)) != 0) + if (ask_for_permission_on_every_file_operation) + file_colors = COLOR_PAIR_WARN; + else if (file_operations_predicate_body && strcmp("return false", trim(file_operations_predicate_body)) != 0) file_colors = COLOR_PAIR_WARN; int net_colors = net_operations_permitted ? COLOR_PAIR_WARN : COLOR_PAIR_SAFE; if (file_colors == COLOR_PAIR_WARN && net_colors == COLOR_PAIR_WARN) { @@ -1358,7 +1361,13 @@ static void permissions_menu() { attrset(A_NORMAL); menu_column = 2; draw_menu_item("^x", "go back"); - draw_menu_item("^f", "edit file permissions"); + if (!ask_for_permission_on_every_file_operation) { + draw_menu_item("^f", "edit file permissions"); + draw_menu_item("^a", "ask for permission on every file operation"); + } + else { + draw_menu_item("^a", "stop asking for permission on every file operation"); + } draw_menu_item("^n", "toggle network permissions"); attrset(A_NORMAL); } @@ -1424,13 +1433,23 @@ static void render_permissions_screen() { mvaddstr(2, 5, "🚧 Be very careful granting permissions 🚧"); attrset(A_NORMAL); - mvaddstr(7, 5, "File operations"); - mvaddstr(7, 30, "function file_operation_permitted(filename, is_write)"); - int y = render_wrapped_text(8, 32, COLS-5, file_operations_predicate_body); - mvaddstr(y, 30, "end"); - y++; - mvaddstr(y, 30, ""); - characterize_file_operations_predicate(); + int y = 7; + mvaddstr(y, 5, "File operations"); + if (!ask_for_permission_on_every_file_operation) { + mvaddstr(y, 30, "function file_operation_permitted(filename, is_write)"); + y = render_wrapped_text(y+1, 32, COLS-5, file_operations_predicate_body); + mvaddstr(y, 30, "end"); + y++; + mvaddstr(y, 30, ""); + characterize_file_operations_predicate(); + } + else { + attron(COLOR_PAIR(COLOR_PAIR_WARN)); + attron(A_REVERSE); + mvaddstr(y, 30, " always ask "); + attroff(A_REVERSE); + attroff(COLOR_PAIR(COLOR_PAIR_WARN)); + } y += 2; int net_colors = net_operations_permitted ? COLOR_PAIR_WARN : COLOR_PAIR_SAFE; @@ -1455,35 +1474,53 @@ static void render_permissions_screen() { attroff(COLOR_PAIR(net_colors)); mvaddstr(y, 30, "(No nuance available for network operations.)"); - int file_operations_safe = strcmp("return false", trim(file_operations_predicate_body)) == 0; - int net_operations_safe = (net_operations_permitted == 0); - int file_operations_unsafe = strcmp("return true", trim(file_operations_predicate_body)) == 0; - int net_operations_unsafe = (net_operations_permitted != 0); - if (file_operations_safe && net_operations_safe) { - attron(COLOR_PAIR(COLOR_PAIR_SAFE)); - mvaddstr(5, 5, "This app can't access private data or communicate with other computers."); - attroff(COLOR_PAIR(COLOR_PAIR_SAFE)); - } - else if (file_operations_safe || net_operations_safe) { - attron(COLOR_PAIR(COLOR_PAIR_WARN)); - if (net_operations_safe) { - mvaddstr(5, 5, "This app can access private data, but they can't leave this computer."); + if (!ask_for_permission_on_every_file_operation) { + int file_operations_safe = strcmp("return false", trim(file_operations_predicate_body)) == 0; + int net_operations_safe = (net_operations_permitted == 0); + int file_operations_unsafe = strcmp("return true", trim(file_operations_predicate_body)) == 0; + int net_operations_unsafe = (net_operations_permitted != 0); + if (file_operations_safe && net_operations_safe) { + attron(COLOR_PAIR(COLOR_PAIR_SAFE)); + mvaddstr(5, 5, "This app can't access private data or communicate with other computers."); + attroff(COLOR_PAIR(COLOR_PAIR_SAFE)); + } + else if (file_operations_safe || net_operations_safe) { + attron(COLOR_PAIR(COLOR_PAIR_WARN)); + if (net_operations_safe) { + mvaddstr(5, 5, "This app can access private data, but they can't leave this computer."); + } + else { + mvaddstr(5, 5, "This app can communicate with other computers, but can't access private data."); + } + attroff(COLOR_PAIR(COLOR_PAIR_WARN)); + } + else if (file_operations_unsafe && net_operations_unsafe) { + attron(COLOR_PAIR(COLOR_PAIR_RISK)); + // idea: include pentagram emoji. But it isn't widely supported yet on Linux. + mvaddstr(5, 5, "😈 ⚠️ Teliva can't protect you if this app does something sketchy. Consider restricting permissions. ⚠️ 😈"); + attroff(COLOR_PAIR(COLOR_PAIR_RISK)); } else { - mvaddstr(5, 5, "This app can communicate with other computers, but can't access private data."); + attron(COLOR_PAIR(COLOR_PAIR_RISK)); + mvaddstr(5, 5, "🦮 🙈 Teliva can't tell how much it's protecting you. Consider simplifying permissions."); + attroff(COLOR_PAIR(COLOR_PAIR_RISK)); } - attroff(COLOR_PAIR(COLOR_PAIR_WARN)); - } - else if (file_operations_unsafe && net_operations_unsafe) { - attron(COLOR_PAIR(COLOR_PAIR_RISK)); - // idea: include pentagram emoji. But it isn't widely supported yet on Linux. - mvaddstr(5, 5, "😈 ⚠️ Teliva can't protect you if this app does something sketchy. Consider restricting permissions. ⚠️ 😈"); - attroff(COLOR_PAIR(COLOR_PAIR_RISK)); } else { - attron(COLOR_PAIR(COLOR_PAIR_RISK)); - mvaddstr(5, 5, "🦮 🙈 Teliva can't tell how much it's protecting you. Consider simplifying permissions."); - attroff(COLOR_PAIR(COLOR_PAIR_RISK)); + // ask_for_permission_on_every_file_operation is true + if (net_operations_permitted == 0) { + attron(COLOR_PAIR(COLOR_PAIR_WARN)); + mvaddstr(5, 5, "You're manually managing file permissions, but they can't leave this computer."); + attroff(COLOR_PAIR(COLOR_PAIR_WARN)); + } + else { + attron(COLOR_PAIR(COLOR_PAIR_WARN)); + mvaddstr(5, 5, "You're manually managing file permissions, and the app can access the network. Watch out for fatigue."); + attroff(COLOR_PAIR(COLOR_PAIR_WARN)); +//? attron(COLOR_PAIR(COLOR_PAIR_RISK)); +//? mvaddstr(5, 5, "😈 ⚠️ Manually managing file permissions on a networked app is a losing enterprise. ⚠️ 😈"); +//? attroff(COLOR_PAIR(COLOR_PAIR_RISK)); + } } permissions_menu(); @@ -1582,7 +1619,11 @@ static void permissions_view() { case CTRL_X: return; case CTRL_F: - edit_file_operations_predicate_body(); + if (!ask_for_permission_on_every_file_operation) + edit_file_operations_predicate_body(); + break; + case CTRL_A: + ask_for_permission_on_every_file_operation = !ask_for_permission_on_every_file_operation; break; case CTRL_N: net_operations_permitted = !net_operations_permitted; @@ -1618,6 +1659,9 @@ static void save_permissions_to_user_configuration(lua_State* L) { if (!lua_isnil(L, -1)) emit_multiline_string(out, lua_tostring(L, -1)); lua_pop(L, 1); /* file_operations_predicate_body */ + lua_getfield(L, -2, "ask_for_permission_on_every_file_operation"); + fprintf(out, " ask_for_permission_on_every_file_operation: %s\n", lua_tostring(L, -1)); + lua_pop(L, 1); /* ask_for_permission_on_every_file_operation */ lua_getfield(L, -2, "net_operations_permitted"); fprintf(out, " net_operations_permitted: %s\n", lua_tostring(L, -1)); lua_pop(L, 1); /* net_operations_permitted */ @@ -1629,6 +1673,7 @@ static void save_permissions_to_user_configuration(lua_State* L) { fprintf(out, " file_operations_predicate_body:\n"); assert(file_operations_predicate_body); emit_multiline_string(out, file_operations_predicate_body); + fprintf(out, " ask_for_permission_on_every_file_operation: %d\n", ask_for_permission_on_every_file_operation); fprintf(out, " net_operations_permitted: %d\n", net_operations_permitted); fclose(out); if (in) fclose(in); @@ -1666,6 +1711,9 @@ static void load_permissions_from_user_configuration(lua_State* L) { file_operations_predicate_body = file_operations_predicate_body_buffer; } lua_pop(L, 1); /* file_operations_predicate_body */ + lua_getfield(L, -2, "ask_for_permission_on_every_file_operation"); + ask_for_permission_on_every_file_operation = lua_tointeger(L, -1); + lua_pop(L, 1); /* ask_for_permission_on_every_file_operation */ lua_getfield(L, -2, "net_operations_permitted"); net_operations_permitted = lua_tointeger(L, -1); lua_pop(L, 1); /* net_operations_permitted */ diff --git a/src/teliva.h b/src/teliva.h index 8a12fe7..8a531c4 100644 --- a/src/teliva.h +++ b/src/teliva.h @@ -187,6 +187,7 @@ extern void render_previous_error(void); /* Permissions checking */ +extern int ask_for_permission_on_every_file_operation; extern int file_operation_permitted(const char* filename, const char* mode); extern int net_operations_permitted;