1 //
2 // Created by nullobsi on 2021/03/17.
3 //
4
5 #include "PassStore.h"
6 #include "DocumentHelper.h"
7 #include <filesystem>
8 #include <iostream>
9 #include <sstream>
10 #include <nanoid/nanoid.h>
11
12 using namespace std;
13
14 string PassStore::passLocation;
15
PassStore()16 PassStore::PassStore() {
17 auto storeLoc = getenv("PASSWORD_STORE_DIR");
18 auto homeDir = getenv("HOME");
19 if (storeLoc) {
20 storePrefix = string(storeLoc);
21 storePrefix /= "secretservice";
22 } else if (homeDir) {
23 storePrefix = string(homeDir);
24 storePrefix /= ".password-store/secretservice";
25 } else {
26 throw runtime_error("Could not find password store! Please set $HOME or $PASSWORD_STORE_DIR");
27 }
28
29 if (!filesystem::exists(storePrefix)) {
30 try {
31 filesystem::create_directory(storePrefix);
32 } catch (std::filesystem::filesystem_error &e) {
33 throw runtime_error("Could not create directory " + storePrefix.string());
34 }
35 }
36
37 bool hasDefault = false;
38
39 for (auto &entry : filesystem::directory_iterator(storePrefix)) {
40 if (entry.is_directory()) {
41 if (filesystem::exists(entry.path() / "collection.json")) {
42 try {
43 auto collection = make_shared<PassCollection>(entry.path());
44 collections.insert({collection->getId(), collection});
45 cout << "Loaded collection " + entry.path().generic_string() << endl;
46 if (collection->getAlias() == "default") hasDefault = true;
47 } catch (std::runtime_error &e) {
48 cerr << e.what() << endl;
49 }
50 }
51 }
52 }
53 if (!hasDefault) createDefaultCollection();
54
55 if (passLocation.empty()) {
56 namespace fs = std::filesystem;
57 stringstream path = stringstream(getenv("PATH"));
58 vector<string> pathEntries;
59 string token;
60 while (getline(path, token, ':')) {
61 pathEntries.push_back(token);
62 }
63 for (const auto &dirName : pathEntries) {
64 fs::directory_iterator i(dirName);
65 for (const auto &file : i) {
66 if (file.is_regular_file() && file.path().filename() == "pass") {
67 std::cout << "Found pass at " + file.path().string() << std::endl;
68 passLocation = file.path().string();
69 goto finish;
70 }
71 }
72 }
73 throw std::runtime_error("Pass not found in path!");
74 finish:
75 return;
76 }
77 }
78
79 void
createDefaultCollection()80 PassStore::createDefaultCollection() {
81 CreateCollection("Default Keyring", "default");
82 }
83
84 std::shared_ptr<PassCollection>
CreateCollection(const std::string & label,const std::string & alias)85 PassStore::CreateCollection(const std::string &label,
86 const std::string &alias) {
87 using namespace rapidjson;
88 Document d;
89 d.SetObject();
90
91 // label, created date, object path ID
92 auto created = std::time(nullptr);
93 auto id = nanoid::generate();
94
95 d.AddMember("label", label, d.GetAllocator());
96 d.AddMember("created", created, d.GetAllocator());
97 d.AddMember("id", id, d.GetAllocator());
98 d.AddMember("alias", alias, d.GetAllocator());
99
100 filesystem::path location = storePrefix / id;
101 if (!filesystem::exists(location)) {
102 filesystem::create_directory(location);
103 }
104 fstream metadataFile;
105 metadataFile.open(location / "collection.json", ios::out | ios::trunc);
106 DHelper::WriteDocument(d, metadataFile);
107 metadataFile.close();
108
109 auto c = make_shared<PassCollection>(location, label, id, created, alias);
110 collections.insert({id, c});
111 return c;
112 }
113
114 std::vector<std::shared_ptr<PassCollection>>
GetCollections()115 PassStore::GetCollections() {
116 vector<shared_ptr<PassCollection>> rtn;
117 for (const auto &entry : collections) {
118 rtn.push_back(entry.second);
119 }
120
121 return rtn;
122 }
123
124
125
126