anastasis-gtk_handle-main-window-forward-clicked.c (12770B)
1 /* 2 This file is part of anastasis-gtk. 3 Copyright (C) 2020, 2021 Anastasis SARL 4 5 Anastasis is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published 7 by the Free Software Foundation; either version 3, or (at your 8 option) any later version. 9 10 Anastasis is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with Anastasis; see the file COPYING. If not, write to the 17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 Boston, MA 02110-1301, USA. 19 */ 20 /** 21 * @file src/anastasis/anastasis-gtk_handle-main-window-forward-clicked.c 22 * @brief 23 * @author Christian Grothoff 24 * @author Dennis Neufeld 25 */ 26 #include "anastasis_gtk_config.h" 27 #define HAVE_USED_CONFIG_H 1 28 29 #include <gnunet/gnunet_util_lib.h> 30 #include "anastasis_gtk_util.h" 31 #include "anastasis-gtk_action.h" 32 #include "anastasis-gtk_attributes.h" 33 #include "anastasis-gtk_dispatch.h" 34 #include "anastasis-gtk_helper.h" 35 #include "anastasis-gtk_rows.h" 36 #include <jansson.h> 37 38 39 /** 40 * The user selected the 'forward' button. Move on with the 41 * country selection. 42 */ 43 static void 44 forward_country_selecting (void) 45 { 46 AGRow *row; 47 json_t *arguments; 48 49 row = AG_selected_row ("anastasis_gtk_country_selection"); 50 if (NULL == row) 51 { 52 GNUNET_break (0); 53 return; 54 } 55 arguments = GNUNET_JSON_PACK ( 56 GNUNET_JSON_pack_string ("country", 57 AG_row_string (row, 58 "name")), 59 GNUNET_JSON_pack_string ("country_code", 60 AG_row_string (row, 61 "code"))); 62 AG_freeze (); 63 AG_ra = ANASTASIS_redux_action (AG_redux_state, 64 "select_country", 65 arguments, 66 &AG_action_cb, 67 NULL); 68 json_decref (arguments); 69 } 70 71 72 /** 73 * The user has entered their personal attributes and 74 * confirmed they are correct. Move to the next state. 75 * Note that #AG_freeze() was already called. 76 */ 77 static void 78 confirm_attributes (void) 79 { 80 json_t *args; 81 82 args = AG_collect_attributes (false); 83 GNUNET_assert (NULL != args); 84 AG_ra = ANASTASIS_redux_action (AG_redux_state, 85 "enter_user_attributes", 86 args, 87 &AG_action_cb, 88 NULL); 89 json_decref (args); 90 } 91 92 93 /** 94 * Function called with the result of asking the user 95 * if they are sure about the personal details they 96 * entered. 97 * 98 * @param the dialog 99 * @param response_id must be GTK_RESPONSE_OK to proceed 100 * @param user_data the builder 101 */ 102 void 103 anastasis_gtk_user_sure_dialog_response_cb ( 104 GtkDialog *dialog, 105 gint response_id, 106 gpointer user_data) 107 { 108 GtkBuilder *builder = user_data; 109 110 gtk_window_destroy (GTK_WINDOW (dialog)); 111 g_object_unref (G_OBJECT (builder)); 112 if (GTK_RESPONSE_OK != response_id) 113 { 114 AG_thaw (); 115 return; 116 } 117 confirm_attributes (); 118 } 119 120 121 /** 122 * Launch dialog to question certainty of user providing 123 * personal details during backup. 124 */ 125 static void 126 question_certainty (void) 127 { 128 GtkBuilder *builder; 129 GtkDialog *ad; 130 131 builder = ANASTASIS_GTK_get_new_builder ( 132 ANASTASIS_GTK_project_data (), 133 "anastasis_gtk_user_sure.ui", 134 NULL); 135 if (NULL == builder) 136 { 137 GNUNET_break (0); 138 return; 139 } 140 ad = GTK_DIALOG (gtk_builder_get_object (builder, 141 "anastasis_gtk_user_sure_dialog")); 142 if (NULL == ad) 143 { 144 GNUNET_break (0); 145 g_object_unref (G_OBJECT (builder)); 146 return; 147 } 148 /* show dialog */ 149 { 150 GtkRoot *toplevel; 151 GtkWidget *widget; 152 153 #if ! HAVE_HPDF_H 154 gtk_widget_set_visible (GTK_WIDGET ( 155 gtk_builder_get_object ( 156 builder, 157 "anastasis_gtk_print_details_button")), 158 FALSE); 159 #endif 160 widget = GTK_WIDGET (GCG_get_main_window_object ( 161 "anastasis_gtk_auth_button_grid")); 162 toplevel = gtk_widget_get_root (widget); 163 gtk_window_set_transient_for (GTK_WINDOW (ad), 164 GTK_WINDOW (toplevel)); 165 gtk_window_present (GTK_WINDOW (ad)); 166 } 167 } 168 169 170 /** 171 * The user clicked the 'next' button in the dialog where they enter 172 * their personal attributes. If we are in the backup process, make 173 * them first confirm that the attributes are correct and well-known 174 * to them. Otherwise, simply directly proceed. 175 */ 176 void 177 AG_forward_user_attributes_collecting (void) 178 { 179 bool in_backup; 180 181 AG_freeze (); 182 in_backup = (NULL != json_object_get (AG_redux_state, 183 "backup_state")); 184 if (in_backup) 185 question_certainty (); 186 else 187 confirm_attributes (); 188 } 189 190 191 /** 192 * Function called with the result of questioning the user 193 * if they really want to proceed with less than three 194 * authentication factors. 195 * 196 * @param source the dialog 197 * @param res the result of the user's choice, button 1 to proceed 198 * @param user_data unused 199 */ 200 static void 201 confirm_multifactor_response_cb (GObject *source, 202 GAsyncResult *res, 203 gpointer user_data) 204 { 205 (void) user_data; 206 if (1 != 207 gtk_alert_dialog_choose_finish (GTK_ALERT_DIALOG (source), 208 res, 209 NULL)) 210 { 211 AG_thaw (); 212 return; 213 } 214 AG_ra = ANASTASIS_redux_action (AG_redux_state, 215 "next", 216 NULL, 217 &AG_action_cb, 218 NULL); 219 } 220 221 222 /** 223 * Function called with the result of telling the 224 * user that they cannot use 1-FA. 225 * 226 * @param source the dialog 227 * @param res the result of the user's choice, unused 228 * @param user_data unused 229 */ 230 static void 231 deny_singlefactor_response_cb (GObject *source, 232 GAsyncResult *res, 233 gpointer user_data) 234 { 235 (void) user_data; 236 (void) gtk_alert_dialog_choose_finish (GTK_ALERT_DIALOG (source), 237 res, 238 NULL); 239 AG_thaw (); 240 } 241 242 243 /** 244 * Return the main window, to be used as the parent of our dialogs. 245 * 246 * @return the main window 247 */ 248 static GtkWindow * 249 main_window (void) 250 { 251 GtkWidget *widget; 252 253 widget = GTK_WIDGET (GCG_get_main_window_object ( 254 "anastasis_gtk_auth_button_grid")); 255 return GTK_WINDOW (gtk_widget_get_root (widget)); 256 } 257 258 259 /** 260 * Launch dialog to question sanity of user providing 261 * too few authentication methods. 262 */ 263 static void 264 question_sanity (void) 265 { 266 GtkAlertDialog *ad; 267 const char *buttons[] = { 268 _ ("_Back"), 269 _ ("_Next"), 270 NULL 271 }; 272 273 ad = gtk_alert_dialog_new ( 274 "%s", 275 _ ( 276 "To keep your secret secure, we recommend you specify at least three authentication options before proceeding.")); 277 gtk_alert_dialog_set_detail ( 278 ad, 279 _ ("Select \"back\" to add additional authentication options.")); 280 gtk_alert_dialog_set_buttons (ad, 281 buttons); 282 gtk_alert_dialog_set_cancel_button (ad, 283 0); 284 gtk_alert_dialog_set_default_button (ad, 285 1); 286 gtk_alert_dialog_choose (ad, 287 main_window (), 288 NULL, 289 &confirm_multifactor_response_cb, 290 NULL); 291 g_object_unref (ad); 292 } 293 294 295 /** 296 * Launch dialog to deny 1-FA setups. 297 */ 298 static void 299 refuse_insanity (void) 300 { 301 GtkAlertDialog *ad; 302 const char *buttons[] = { 303 _ ("_Back"), 304 NULL 305 }; 306 307 ad = gtk_alert_dialog_new ( 308 "%s", 309 _ ( 310 "To keep your secret secure, we require at least two authentication options, and recommend you specify at least three authentication options before proceeding.")); 311 gtk_alert_dialog_set_detail ( 312 ad, 313 _ ("Select \"back\" to add additional authentication options.")); 314 gtk_alert_dialog_set_buttons (ad, 315 buttons); 316 gtk_alert_dialog_set_cancel_button (ad, 317 0); 318 gtk_alert_dialog_set_default_button (ad, 319 0); 320 gtk_alert_dialog_choose (ad, 321 main_window (), 322 NULL, 323 &deny_singlefactor_response_cb, 324 NULL); 325 g_object_unref (ad); 326 } 327 328 329 /** 330 * The user has clicked 'next' in the 'authentications_editing' state. 331 * Check if the number of authentication methods configured is above 332 * a threshold. If no, warn before allowing to proceed. 333 */ 334 static void 335 forward_authentications_editing (void) 336 { 337 json_t *methods; 338 339 AG_freeze (); 340 methods = json_object_get (AG_redux_state, 341 "authentication_methods"); 342 if (json_array_size (methods) < 2) 343 { 344 refuse_insanity (); 345 return; 346 } 347 if (json_array_size (methods) < 3) 348 { 349 question_sanity (); 350 return; 351 } 352 AG_ra = ANASTASIS_redux_action (AG_redux_state, 353 "next", 354 NULL, 355 &AG_action_cb, 356 NULL); 357 } 358 359 360 /** 361 * The user has pressed 'next' in POLICIES_EDITING state. 362 * Proceed to secret editing. 363 */ 364 static void 365 forward_policies_reviewing (void) 366 { 367 AG_freeze (); 368 AG_ra = ANASTASIS_redux_action (AG_redux_state, 369 "next", 370 NULL, 371 &AG_action_cb, 372 NULL); 373 } 374 375 376 static void 377 forward_secret_editing (void) 378 { 379 AG_freeze (); 380 AG_ra = ANASTASIS_redux_action (AG_redux_state, 381 "next", 382 NULL, 383 &AG_action_cb, 384 NULL); 385 } 386 387 388 /** 389 * The user has pressed 'next' after selecting a secret to recover. 390 */ 391 static void 392 forward_secret_selecting (void) 393 { 394 AGRow *row; 395 json_t *args; 396 397 AG_freeze (); 398 AG_stop_long_action (); 399 row = AG_selected_row ("anastasis_gtk_secret_selection_treeselection"); 400 if (NULL == row) 401 { 402 GNUNET_break (0); 403 AG_insensitive ("anastasis_gtk_main_window_forward_button"); 404 return; 405 } 406 args = GNUNET_JSON_PACK ( 407 GNUNET_JSON_pack_array_incref ("providers", 408 AG_row_json (row, 409 "providers")), 410 GNUNET_JSON_pack_uint64 ("attribute_mask", 411 AG_row_uint (row, 412 "attribute_mask")), 413 GNUNET_JSON_pack_string ("secret_name", 414 AG_row_string (row, 415 "secret_name"))); 416 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 417 "Proceeding with policy version %u at provider %s\n", 418 (unsigned int) AG_row_uint (row, 419 "version"), 420 AG_row_string (row, 421 "provider_url")); 422 if (NULL != AG_pd) 423 { 424 ANASTASIS_policy_discovery_stop (AG_pd); 425 AG_pd = NULL; 426 } 427 AG_ra = ANASTASIS_redux_action (AG_redux_state, 428 "select_version", 429 args, 430 &AG_action_cb, 431 NULL); 432 json_decref (args); 433 } 434 435 436 /** 437 * Callback invoked if the the "forward"-button is clicked. 438 * 439 * @param object 440 * @param user_data unused 441 */ 442 void 443 anastasis_gtk_main_window_forward_clicked (GObject *object, 444 gpointer user_data) 445 { 446 struct DispatchItem actions[] = { 447 { .state = "COUNTRY_SELECTING", 448 .action = &forward_country_selecting }, 449 { .state = "USER_ATTRIBUTES_COLLECTING", 450 .action = &AG_forward_user_attributes_collecting }, 451 { .state = "AUTHENTICATIONS_EDITING", 452 .action = &forward_authentications_editing }, 453 { .state = "POLICIES_REVIEWING", 454 .action = &forward_policies_reviewing }, 455 { .state = "SECRET_EDITING", 456 .action = &forward_secret_editing }, 457 { .state = "SECRET_SELECTING", 458 .action = &forward_secret_selecting }, 459 { .state = NULL, 460 .action = NULL } 461 }; 462 463 AG_insensitive ("anastasis_gtk_main_window_forward_button"); 464 AG_dispatch (actions); 465 }