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