1 #pragma once 2 #include <functional> 3 #include <set> 4 5 #include <gtkmm.h> 6 7 #include "app_menu.h" 8 #include "config_storage.h" 9 #include "keychain_container.h" 10 11 class MainWindow : public Gtk::ApplicationWindow { 12 public: MainWindow()13 MainWindow() : Gtk::ApplicationWindow() { 14 std::initializer_list<CallbackData> actions = { 15 {"_Lock Vaults", [this]() { lockVaults(); }}, 16 {"_Load New Vault", [this]() { addNewVault(); }}, 17 {"_Refresh Vaults", [this]() { refreshVaults(); }}, 18 {"_Quit", [this]() { get_application()->quit(); }}}; 19 20 set_default_geometry(800, 480); 21 22 app_menu = std::unique_ptr<AppMenu>(new AppMenu(actions)); 23 24 set_titlebar(header_bar); 25 header_bar.set_title("Gonepass"); 26 header_bar.set_has_subtitle(true); 27 header_bar.set_show_close_button(false); 28 header_bar.pack_start(*app_menu); 29 30 if (config_cache.find("loaded_vaults") != config_cache.end()) { 31 auto loaded_vaults = config_cache["loaded_vaults"]; 32 for (auto it = loaded_vaults.begin(); it != loaded_vaults.end(); ++it) { 33 addCachedVault(it.key(), false); 34 } 35 } 36 if (config_cache.find("master_vault") != config_cache.end()) { 37 addCachedVault(config_cache["master_vault"], true); 38 } else { 39 addNewVault(); 40 } 41 show_all_children(); 42 }; 43 ~MainWindow()44 virtual ~MainWindow(){}; 45 46 protected: addNewVault()47 void addNewVault() { 48 remove(); 49 auto new_vault = std::make_shared<KeychainContainer>(""); 50 auto unlock_cb = [new_vault, this](std::string title, std::string password) { 51 unlockCb(new_vault, title, password); 52 }; 53 new_vault->setUnlockCb(unlock_cb); 54 add(*new_vault); 55 show_all_children(); 56 } 57 unlockCb(std::shared_ptr<KeychainContainer> new_vault,std::string title,std::string password)58 void unlockCb(std::shared_ptr<KeychainContainer> new_vault, 59 std::string title, 60 std::string password) { 61 auto app_menu_select_cb = [new_vault, this]() { 62 remove(); 63 add(*new_vault); 64 header_bar.set_subtitle(new_vault->getPath()); 65 show_all_children(); 66 }; 67 68 if (!master_vault) { 69 master_vault = new_vault; 70 } 71 if (master_vault == new_vault) { 72 unlockAllVaults(); 73 } 74 if (master_vault->getKeychain()) 75 updateCache(title, password); 76 77 if (container_list.find(new_vault) == container_list.end()) { 78 app_menu->addVault(title, app_menu_select_cb); 79 container_list.emplace(new_vault); 80 } 81 82 header_bar.set_subtitle(title); 83 show_all_children(); 84 } 85 addCachedVault(std::string path,bool master)86 void addCachedVault(std::string path, bool master) { 87 auto new_vault = std::make_shared<KeychainContainer>(path); 88 auto unlock_cb = [new_vault, this](std::string title, std::string password) { 89 unlockCb(new_vault, title, password); 90 }; 91 new_vault->setUnlockCb(unlock_cb); 92 auto app_menu_select_cb = [new_vault, this]() { 93 remove(); 94 add(*new_vault); 95 header_bar.set_subtitle(new_vault->getPath()); 96 show_all_children(); 97 }; 98 99 container_list.emplace(new_vault); 100 if (master) { 101 std::stringstream title_builder; 102 title_builder << path << " (master vault)"; 103 app_menu->prependVault(title_builder.str(), app_menu_select_cb); 104 master_vault = new_vault; 105 } else 106 app_menu->addVault(path, app_menu_select_cb); 107 app_menu_select_cb(); 108 } 109 lockVaults()110 void lockVaults() { 111 for (auto&& keychain_view : container_list) { 112 keychain_view->lock(); 113 } 114 } 115 refreshVaults()116 void refreshVaults() { 117 for (auto&& keychain_view : container_list) { 118 keychain_view->refresh(); 119 } 120 } 121 updateCache(std::string path,std::string password)122 void updateCache(std::string path, std::string password) { 123 if (config_cache.find("master_vault") == config_cache.end()) { 124 config_cache["master_vault"] = master_vault->getPath(); 125 config_cache.save(); 126 return; 127 } else if (path == config_cache["master_vault"]) 128 return; 129 130 json cached_data_dict; 131 if (config_cache.find("loaded_vaults") != config_cache.end()) { 132 cached_data_dict = config_cache["loaded_vaults"]; 133 } 134 135 json cached_data; 136 cached_data["password"] = password; 137 cached_data_dict[path] = master_vault->getKeychain()->encryptJSON(cached_data); 138 config_cache["loaded_vaults"] = cached_data_dict; 139 config_cache.save(); 140 } 141 unlockAllVaults()142 void unlockAllVaults() { 143 if (!master_vault) { 144 return; 145 } 146 147 if (config_cache.find("loaded_vaults") == config_cache.end()) { 148 return; 149 } 150 auto cached_vaults = config_cache["loaded_vaults"]; 151 152 for (auto vault : container_list) { 153 if (vault == master_vault) { 154 continue; 155 } 156 157 auto cur_vault_data = cached_vaults.find(vault->getPath()); 158 if (cur_vault_data == cached_vaults.end()) { 159 continue; 160 } 161 auto decrypted_data = master_vault->getKeychain()->decryptJSON(*cur_vault_data); 162 std::string decrypted_password = decrypted_data["password"]; 163 vault->unlock(decrypted_password); 164 } 165 } 166 167 ConfigCache config_cache; 168 std::shared_ptr<KeychainContainer> master_vault; 169 std::unique_ptr<AppMenu> app_menu; 170 std::set<std::shared_ptr<KeychainContainer>> container_list; 171 Gtk::HeaderBar header_bar; 172 }; 173