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