Merge branch 'two-step-password-toggle' into 'main'

two-step: add optional password cleartext toggle

Closes #318

See merge request plymouth/plymouth!373
This commit is contained in:
Simon Johnsson 2026-05-04 17:50:25 +02:00
commit 675917d2c3
7 changed files with 217 additions and 49 deletions

View file

@ -103,6 +103,9 @@ typedef struct
bool (*validate_input) (ply_boot_splash_plugin_t *plugin,
const char *entry_text,
const char *add_text);
void (*display_password_clear_text)(ply_boot_splash_plugin_t *plugin,
const char *prompt,
const char *entry_text);
} ply_boot_splash_plugin_interface_t;
#endif /* PLY_BOOT_SPLASH_PLUGIN_H */

View file

@ -707,17 +707,38 @@ void ply_boot_splash_display_normal (ply_boot_splash_t *splash)
splash->plugin_interface->display_normal (splash->plugin);
}
void ply_boot_splash_display_password (ply_boot_splash_t *splash,
const char *prompt,
int bullets)
static inline void
assert_password_capable (ply_boot_splash_t *splash)
{
assert (splash != NULL);
assert (splash->plugin_interface != NULL);
assert (splash->plugin != NULL);
}
void ply_boot_splash_display_password (ply_boot_splash_t *splash,
const char *prompt,
int bullets)
{
assert_password_capable (splash);
if (splash->plugin_interface->display_password != NULL)
splash->plugin_interface->display_password (splash->plugin, prompt, bullets);
}
bool ply_boot_splash_can_display_password_clear_text (ply_boot_splash_t *splash)
{
assert_password_capable (splash);
return splash->plugin_interface->display_password_clear_text != NULL;
}
void ply_boot_splash_display_password_clear_text (ply_boot_splash_t *splash,
const char *prompt,
const char *entry_text)
{
if (!ply_boot_splash_can_display_password_clear_text (splash))
return;
splash->plugin_interface->display_password_clear_text (splash->plugin, prompt, entry_text);
}
void ply_boot_splash_display_question (ply_boot_splash_t *splash,
const char *prompt,
const char *entry_text)

View file

@ -79,6 +79,10 @@ void ply_boot_splash_display_normal (ply_boot_splash_t *splash);
void ply_boot_splash_display_password (ply_boot_splash_t *splash,
const char *prompt,
int bullets);
bool ply_boot_splash_can_display_password_clear_text (ply_boot_splash_t *splash);
void ply_boot_splash_display_password_clear_text (ply_boot_splash_t *splash,
const char *prompt,
const char *entry_text);
void ply_boot_splash_display_question (ply_boot_splash_t *splash,
const char *prompt,
const char *entry_text);

View file

@ -44,6 +44,7 @@
#define KEY_CTRL_W ('\100' ^ 'W')
#define KEY_CTRL_V ('\100' ^ 'V')
#define KEY_ESCAPE ('\100' ^ '[')
#define KEY_TAB '\t'
#define KEY_RETURN '\n'
#define KEY_BACKSPACE '\177'
@ -97,6 +98,7 @@ struct _ply_keyboard
ply_list_t *keyboard_input_handler_list;
ply_list_t *backspace_handler_list;
ply_list_t *escape_handler_list;
ply_list_t *tab_handler_list;
ply_list_t *enter_handler_list;
uint32_t is_active : 1;
@ -114,6 +116,7 @@ ply_keyboard_new_for_terminal (ply_terminal_t *terminal)
keyboard->keyboard_input_handler_list = ply_list_new ();
keyboard->backspace_handler_list = ply_list_new ();
keyboard->escape_handler_list = ply_list_new ();
keyboard->tab_handler_list = ply_list_new ();
keyboard->enter_handler_list = ply_list_new ();
keyboard->provider_type = PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL;
keyboard->provider.if_terminal = calloc (1, sizeof(ply_keyboard_terminal_provider_t));
@ -136,6 +139,7 @@ ply_keyboard_new_for_renderer (ply_renderer_t *renderer)
keyboard->keyboard_input_handler_list = ply_list_new ();
keyboard->backspace_handler_list = ply_list_new ();
keyboard->escape_handler_list = ply_list_new ();
keyboard->tab_handler_list = ply_list_new ();
keyboard->enter_handler_list = ply_list_new ();
keyboard->provider_type = PLY_KEYBOARD_PROVIDER_TYPE_RENDERER;
keyboard->provider.if_renderer = calloc (1, sizeof(ply_keyboard_renderer_provider_t));
@ -219,6 +223,17 @@ process_keyboard_input (ply_keyboard_t *keyboard,
ply_trace ("end escape key handler");
return;
case KEY_TAB:
ply_trace ("tab key!");
for (node = ply_list_get_first_node (keyboard->tab_handler_list);
node; node = ply_list_get_next_node (keyboard->tab_handler_list, node)) {
ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
ply_keyboard_tab_handler_t tab_handler = (ply_keyboard_tab_handler_t) closure->function;
tab_handler (closure->user_data);
}
ply_trace ("end tab key handler");
return;
case KEY_BACKSPACE:
ply_trace ("backspace key!");
process_backspace (keyboard);
@ -638,6 +653,40 @@ ply_keyboard_remove_escape_handler (ply_keyboard_t *keyboard,
}
}
void
ply_keyboard_add_tab_handler (ply_keyboard_t *keyboard,
ply_keyboard_tab_handler_t tab_handler,
void *user_data)
{
ply_keyboard_closure_t *closure;
assert (keyboard != NULL);
closure = ply_keyboard_closure_new ((ply_keyboard_handler_t) tab_handler,
user_data);
ply_list_append_data (keyboard->tab_handler_list, closure);
}
void
ply_keyboard_remove_tab_handler (ply_keyboard_t *keyboard,
ply_keyboard_tab_handler_t tab_handler)
{
ply_list_node_t *node;
assert (keyboard != NULL);
for (node = ply_list_get_first_node (keyboard->tab_handler_list);
node; node = ply_list_get_next_node (keyboard->tab_handler_list, node)) {
ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
if ((ply_keyboard_tab_handler_t) closure->function == tab_handler) {
ply_keyboard_closure_free (closure);
ply_list_remove_node (keyboard->tab_handler_list, node);
return;
}
}
}
void
ply_keyboard_add_enter_handler (ply_keyboard_t *keyboard,
ply_keyboard_enter_handler_t enter_handler,

View file

@ -40,6 +40,8 @@ typedef void (*ply_keyboard_backspace_handler_t) (void *user_data);
typedef void (*ply_keyboard_escape_handler_t) (void *user_data);
typedef void (*ply_keyboard_tab_handler_t) (void *user_data);
typedef void (*ply_keyboard_enter_handler_t) (void *user_data,
const char *line);
@ -63,6 +65,11 @@ void ply_keyboard_add_escape_handler (ply_keyboard_t *keyboard,
void *user_data);
void ply_keyboard_remove_escape_handler (ply_keyboard_t *keyboard,
ply_keyboard_escape_handler_t escape_handler);
void ply_keyboard_add_tab_handler (ply_keyboard_t *keyboard,
ply_keyboard_tab_handler_t tab_handler,
void *user_data);
void ply_keyboard_remove_tab_handler (ply_keyboard_t *keyboard,
ply_keyboard_tab_handler_t tab_handler);
void ply_keyboard_add_enter_handler (ply_keyboard_t *keyboard,
ply_keyboard_enter_handler_t enter_handler,
void *user_data);

View file

@ -117,6 +117,7 @@ typedef struct
uint32_t should_force_details : 1;
uint32_t should_force_default_splash : 1;
uint32_t splash_is_becoming_idle : 1;
uint32_t should_show_password_clear_text : 1;
char *override_splash_path;
char *system_default_splash_path;
@ -155,6 +156,7 @@ static void tell_systemd_to_stop_printing_details (state_t *state);
#endif
static const char *get_cache_file_for_mode (ply_boot_splash_mode_t mode);
static void on_escape_pressed (state_t *state);
static void on_tab_pressed (state_t *state);
static void on_enter (state_t *state,
const char *line);
static void on_keyboard_input (state_t *state,
@ -1110,6 +1112,10 @@ on_keyboard_added (state_t *state,
ply_keyboard_add_escape_handler (keyboard,
(ply_keyboard_escape_handler_t)
on_escape_pressed, state);
ply_trace ("listening for tab");
ply_keyboard_add_tab_handler (keyboard,
(ply_keyboard_tab_handler_t)
on_tab_pressed, state);
ply_trace ("listening for backspace");
ply_keyboard_add_backspace_handler (keyboard,
(ply_keyboard_backspace_handler_t)
@ -1137,6 +1143,10 @@ on_keyboard_removed (state_t *state,
ply_keyboard_remove_escape_handler (keyboard,
(ply_keyboard_escape_handler_t)
on_escape_pressed);
ply_trace ("no longer listening for tab");
ply_keyboard_remove_tab_handler (keyboard,
(ply_keyboard_tab_handler_t)
on_tab_pressed);
ply_trace ("no longer listening for backspace");
ply_keyboard_remove_backspace_handler (keyboard,
(ply_keyboard_backspace_handler_t)
@ -1581,6 +1591,33 @@ validate_input (state_t *state,
return input_valid;
}
static void
handle_ply_entry_trigger_type_password (state_t *state,
ply_entry_trigger_t *entry_trigger)
{
bool show_password_clear_text =
state->should_show_password_clear_text &&
ply_boot_splash_can_display_password_clear_text (state->boot_splash);
if (show_password_clear_text) {
const char *entry_text = (const char *) ply_buffer_get_bytes (state->entry_buffer);
ply_trace ("WARNING: cleartext password display enabled");
ply_boot_splash_display_password_clear_text (state->boot_splash,
entry_trigger->prompt,
entry_text);
} else {
int bullets = ply_utf8_string_get_length (ply_buffer_get_bytes (state->entry_buffer),
ply_buffer_get_size (state->entry_buffer));
bullets = MAX (0, bullets);
ply_boot_splash_display_password (state->boot_splash,
entry_trigger->prompt,
bullets);
}
ply_boot_splash_display_prompt (state->boot_splash,
entry_trigger->prompt,
ply_buffer_get_bytes (state->entry_buffer),
true);
}
static void
update_display (state_t *state)
@ -1589,32 +1626,24 @@ update_display (state_t *state)
ply_list_node_t *node;
node = ply_list_get_first_node (state->entry_triggers);
if (node) {
ply_entry_trigger_t *entry_trigger = ply_list_node_get_data (node);
if (entry_trigger->type == PLY_ENTRY_TRIGGER_TYPE_PASSWORD) {
int bullets = ply_utf8_string_get_length (ply_buffer_get_bytes (state->entry_buffer),
ply_buffer_get_size (state->entry_buffer));
bullets = MAX (0, bullets);
ply_boot_splash_display_password (state->boot_splash,
entry_trigger->prompt,
bullets);
ply_boot_splash_display_prompt (state->boot_splash,
entry_trigger->prompt,
ply_buffer_get_bytes (state->entry_buffer),
true);
} else if (entry_trigger->type == PLY_ENTRY_TRIGGER_TYPE_QUESTION) {
ply_boot_splash_display_question (state->boot_splash,
entry_trigger->prompt,
ply_buffer_get_bytes (state->entry_buffer));
ply_boot_splash_display_prompt (state->boot_splash,
entry_trigger->prompt,
ply_buffer_get_bytes (state->entry_buffer),
false);
} else {
ply_trace ("unkown entry type");
}
} else {
if (!node) {
ply_boot_splash_display_normal (state->boot_splash);
return;
}
ply_entry_trigger_t *entry_trigger = ply_list_node_get_data (node);
if (entry_trigger->type == PLY_ENTRY_TRIGGER_TYPE_PASSWORD) {
handle_ply_entry_trigger_type_password (state, entry_trigger);
} else if (entry_trigger->type == PLY_ENTRY_TRIGGER_TYPE_QUESTION) {
ply_boot_splash_display_question (state->boot_splash,
entry_trigger->prompt,
ply_buffer_get_bytes (state->entry_buffer));
ply_boot_splash_display_prompt (state->boot_splash,
entry_trigger->prompt,
ply_buffer_get_bytes (state->entry_buffer),
false);
} else {
ply_trace ("unknown entry type");
}
}
@ -1655,6 +1684,28 @@ on_escape_pressed (state_t *state)
toggle_between_splash_and_details (state);
}
static void
toggle_between_bullets_and_clear_text (state_t *state)
{
ply_trace ("toggling between bullets and clear text");
if (!state->should_show_password_clear_text) {
state->should_show_password_clear_text = true;
} else {
state->should_show_password_clear_text = false;
}
update_display (state);
}
static void
on_tab_pressed (state_t *state)
{
ply_trace ("tab key pressed");
if (validate_input (state, "", "\t"))
toggle_between_bullets_and_clear_text (state);
}
static void
on_keyboard_input (state_t *state,
const char *keyboard_input,

View file

@ -195,6 +195,7 @@ struct _ply_boot_splash_plugin
uint32_t background_image_is_scaled : 1;
uint32_t dialog_clears_firmware_background : 1;
uint32_t message_below_animation : 1;
uint32_t allow_password_clear_text_toggle : 1;
char *monospace_font;
uint32_t plugin_console_messages_updating : 1;
@ -699,6 +700,8 @@ view_load (view_t *view)
ply_trace ("loading entry");
if (!ply_entry_load (view->entry))
return false;
else
ply_entry_set_text_color (view->entry, 1.0, 1.0, 1.0, 1.0);
ply_keymap_icon_load (view->keymap_icon);
ply_capslock_icon_load (view->capslock_icon);
@ -1360,6 +1363,9 @@ create_plugin (ply_key_file_t *key_file)
plugin->message_below_animation =
ply_key_file_get_bool (key_file, "two-step", "MessageBelowAnimation");
plugin->allow_password_clear_text_toggle =
ply_key_file_get_bool (key_file, "two-step", "AllowPasswordClearTextToggle");
progress_function = ply_key_file_get_value (key_file, "two-step", "ProgressFunction");
if (progress_function != NULL) {
@ -2222,16 +2228,17 @@ display_normal (ply_boot_splash_plugin_t *plugin)
}
static void
display_password (ply_boot_splash_plugin_t *plugin,
const char *prompt,
int bullets)
display_password_internal (ply_boot_splash_plugin_t *plugin,
const char *prompt,
const char *entry_text,
int bullets)
{
pause_views (plugin);
if (plugin->state == PLY_BOOT_SPLASH_DISPLAY_NORMAL)
stop_animation (plugin);
plugin->state = PLY_BOOT_SPLASH_DISPLAY_PASSWORD_ENTRY;
show_prompt (plugin, prompt, NULL, bullets);
show_prompt (plugin, prompt, entry_text, bullets);
redraw_views (plugin);
if (plugin->should_show_console_messages)
@ -2241,6 +2248,31 @@ display_password (ply_boot_splash_plugin_t *plugin,
unpause_views (plugin);
}
static void
display_password (ply_boot_splash_plugin_t *plugin,
const char *prompt,
int bullets)
{
display_password_internal (plugin, prompt, NULL, bullets);
}
static void
display_password_clear_text (ply_boot_splash_plugin_t *plugin,
const char *prompt,
const char *entry_text)
{
if (!plugin->allow_password_clear_text_toggle) {
// if function is disabled, fall back to masked bullet mode,
// as dynamically setting function to NULL is not possible
int bullets = ply_utf8_string_get_length (entry_text,
strlen (entry_text));
bullets = MAX (0, bullets);
display_password_internal (plugin, prompt, NULL, bullets);
return;
}
display_password_internal (plugin, prompt, entry_text, -1);
}
static void
display_question (ply_boot_splash_plugin_t *plugin,
const char *prompt,
@ -2379,23 +2411,24 @@ ply_boot_splash_plugin_get_interface (void)
{
static ply_boot_splash_plugin_interface_t plugin_interface =
{
.create_plugin = create_plugin,
.destroy_plugin = destroy_plugin,
.add_pixel_display = add_pixel_display,
.remove_pixel_display = remove_pixel_display,
.show_splash_screen = show_splash_screen,
.update_status = update_status,
.on_boot_progress = on_boot_progress,
.hide_splash_screen = hide_splash_screen,
.on_root_mounted = on_root_mounted,
.become_idle = become_idle,
.display_normal = display_normal,
.display_password = display_password,
.display_question = display_question,
.display_message = display_message,
.system_update = system_update,
.on_boot_output = on_boot_output,
.validate_input = validate_input,
.create_plugin = create_plugin,
.destroy_plugin = destroy_plugin,
.add_pixel_display = add_pixel_display,
.remove_pixel_display = remove_pixel_display,
.show_splash_screen = show_splash_screen,
.update_status = update_status,
.on_boot_progress = on_boot_progress,
.hide_splash_screen = hide_splash_screen,
.on_root_mounted = on_root_mounted,
.become_idle = become_idle,
.display_normal = display_normal,
.display_password = display_password,
.display_password_clear_text = display_password_clear_text,
.display_question = display_question,
.display_message = display_message,
.system_update = system_update,
.on_boot_output = on_boot_output,
.validate_input = validate_input,
};
return &plugin_interface;