1 //
2 // Created by nullobsi on 2021/03/17.
3 //
4 
5 #include "Collection.h"
6 #include "SecretService.h"
7 #include "Item.h"
8 #include "CollectionProxy.h"
9 #include <memory>
10 #include <utility>
11 
12 
Collection(std::shared_ptr<PassCollection> backend_,sdbus::IConnection & conn,std::string path,std::weak_ptr<SecretService> parent_)13 Collection::Collection(std::shared_ptr<PassCollection> backend_,
14                        sdbus::IConnection &conn,
15                        std::string path,
16                        std::weak_ptr<SecretService> parent_)
17 		: sdbus::AdaptorInterfaces<org::freedesktop::Secret::Collection_adaptor, sdbus::Properties_adaptor>(conn, std::move(path)),
18 		  backend(std::move(backend_)), parent(std::move(parent_)) {
19 	registerAdaptor();
20 }
21 
~Collection()22 Collection::~Collection() {
23 	unregisterAdaptor();
24 }
25 
26 sdbus::ObjectPath
Delete()27 Collection::Delete() {
28 	backend->Delete();
29 	parent.lock()->DiscardCollection(this->backend->getId());
30 	return sdbus::ObjectPath("/");
31 }
32 
33 std::vector<sdbus::ObjectPath>
SearchItems(const std::map<std::string,std::string> & attributes)34 Collection::SearchItems(const std::map<std::string, std::string> &attributes) {
35 	auto it = backend->searchItems(attributes);
36 	std::vector<sdbus::ObjectPath> r;
37 	r.reserve(it.size());
38 	for (const auto &id : it) {
39 		r.push_back(items[id]->getPath());
40 	}
41 	return r;
42 }
43 
44 std::tuple<sdbus::ObjectPath, sdbus::ObjectPath>
CreateItem(const std::map<std::string,sdbus::Variant> & properties,const sdbus::Struct<sdbus::ObjectPath,std::vector<uint8_t>,std::vector<uint8_t>,std::string> & secret,const bool & replace)45 Collection::CreateItem(const std::map<std::string, sdbus::Variant> &properties,
46                        const sdbus::Struct<sdbus::ObjectPath, std::vector<uint8_t>, std::vector<uint8_t>, std::string> &secret,
47                        const bool &replace) {
48 	auto nAttrib = properties.count("org.freedesktop.Secret.Item.Attributes") && properties.at("org.freedesktop.Secret.Item.Attributes").containsValueOfType<std::map<std::string, std::string>>() ? properties.at("org.freedesktop.Secret.Item.Attributes").get<std::map<std::string, std::string>>() : std::map<std::string, std::string>();
49 	auto nLabel = properties.count("org.freedesktop.Secret.Item.Label") && properties.at("org.freedesktop.Secret.Item.Label").containsValueOfType<std::string>() ? properties.at("org.freedesktop.Secret.Item.Label").get<std::string>() : "Secret";
50 	auto nType = properties.count("org.freedesktop.Secret.Item.Type") && properties.at("org.freedesktop.Secret.Item.Type").containsValueOfType<std::string>() ? properties.at("org.freedesktop.Secret.Item.Type").get<std::string>() : (nAttrib.count("xdg:schema") ? nAttrib["xdg:schema"] : "org.freedesktop.Secret.Generic");
51 	auto existing = InternalSearchItems(nAttrib);
52 	if (!existing.empty() && !replace) {
53 		// TODO: this error is not part of spec
54 		throw sdbus::Error("org.freedesktop.Secret.Error.ObjectExists", "Such an object already exists in the store");
55 	}
56 	auto data = secret.get<2>();
57 	auto nData = (uint8_t *)malloc(data.size() * sizeof(uint8_t));
58 	memcpy(nData, data.data(), data.size()*sizeof(uint8_t));
59 
60 	if (replace && !existing.empty()) {
61 		auto item = existing[0]->getBackend();
62 		item->setAttrib(std::move(nAttrib));
63 		item->setLabel(std::move(nLabel));
64 		item->setType(std::move(nType));
65 		item->updateMetadata();
66 		item->setSecret(nData, data.size());
67 		ItemCreated(existing[0]->getPath());
68 		return std::tuple(existing[0]->getPath(), "/");
69 	}
70 	auto item = this->backend->CreateItem(nData, data.size(), move(nAttrib), move(nLabel), move(nType));
71 	auto nItem = std::make_shared<Item>(item, this->getObject().getConnection(), this->getObjectPath() + "/" + item->getId(), weak_from_this());
72 	updateItem(nItem);
73 	items.insert({item->getId(), nItem});
74 	ItemCreated(nItem->getPath());
75 	return std::tuple(nItem->getPath(), "/");
76 }
77 
78 std::vector<sdbus::ObjectPath>
Items()79 Collection::Items() {
80 	std::vector<sdbus::ObjectPath> r;
81 	auto it = backend->getItems();
82 	r.reserve(it.size());
83 	for (const auto &item : it) {
84 		r.push_back(items[item->getId()]->getPath());
85 	}
86 	return r;
87 }
88 
89 std::string
Label()90 Collection::Label() {
91 	return backend->getLabel();
92 }
93 
94 void
Label(const std::string & value)95 Collection::Label(const std::string &value) {
96 	backend->setLabel(value);
97 	backend->updateMetadata();
98 }
99 
100 bool
Locked()101 Collection::Locked() {
102 	return std::any_of(items.cbegin(), items.cend(),
103 	                   [](const std::pair<std::string, std::shared_ptr<Item>> &entry) -> bool {
104 		                   return entry.second->Locked();
105 	                   });
106 }
107 
108 uint64_t
Created()109 Collection::Created() {
110 	return backend->getCreated();
111 }
112 
113 uint64_t
Modified()114 Collection::Modified() {
115 	return 0;
116 }
117 
118 std::shared_ptr<PassCollection>
GetBacking()119 Collection::GetBacking() {
120 	return backend;
121 }
122 
123 std::vector<std::shared_ptr<Item>>
InternalSearchItems(const std::map<std::string,std::string> & attributes)124 Collection::InternalSearchItems(const std::map<std::string, std::string> &attributes) {
125 	auto it = backend->searchItems(attributes);
126 	std::vector<std::shared_ptr<Item>> r;
127 	r.reserve(it.size());
128 	for (const auto &id : it) {
129 		r.push_back(items[id]);
130 	}
131 	return r;
132 }
133 
134 std::map<std::string, std::shared_ptr<Item>> &
getItemMap()135 Collection::getItemMap() {
136 	return items;
137 }
138 
139 void
DiscardObjects()140 Collection::DiscardObjects() {
141 	while (!discarded.empty()) {
142 		discarded.pop_back();
143 	}
144 }
145 
146 void
InitItems()147 Collection::InitItems() {
148 	for (const auto &item : backend->getItems()) {
149 		items.insert({
150 				             item->getId(), std::make_unique<Item>(item, this->getObject().getConnection(),
151 				                                                   this->getObjectPath() + "/" + item->getId(),
152 				                                                   weak_from_this())
153 		             });
154 	}
155 	updateAlias();
156 }
157 
158 
159 
160 void
DiscardItem(std::string id)161 Collection::DiscardItem(std::string id) {
162 	auto ptr = items.extract(id).mapped();
163 	ItemDeleted(ptr->getPath());
164 	backend->RemoveItem(ptr->getBackend()->getId());
165 	discarded.push_back(move(ptr));
166 }
167 
168 void
updateAlias()169 Collection::updateAlias() {
170 	std::string path = "";
171 	if (backend->getAlias().empty()) {
172 		if (proxy) {
173 			proxy.reset();
174 		}
175 	} else {
176 		path = "/org/freedesktop/secrets/aliases/" + backend->getAlias();
177 		proxy = std::make_unique<CollectionProxy>(this->getObject().getConnection(), path, weak_from_this());
178 	}
179 	for (const auto &item : items) {
180 		item.second->updateProxy(path);
181 	}
182 }
183 
184 void
updateItem(std::shared_ptr<Item> item)185 Collection::updateItem(std::shared_ptr<Item> item) {
186 	if (!backend->getAlias().empty()) {
187 		auto path = "/org/freedesktop/secrets/aliases/" + backend->getAlias();
188 		item->updateProxy(path);
189 	} else {
190 		item->updateProxy("");
191 	}
192 }
193 
194 // TODO: do proxies have to use proxied item path?
195 void
ItemCreated(const sdbus::ObjectPath & item)196 Collection::ItemCreated(const sdbus::ObjectPath &item) {
197 	emitItemCreated(item);
198 	emitPropertiesChangedSignal("org.freedesktop.Secret.Collection", {"Items"});
199 	if (proxy) proxy->emitItemCreated(item);
200 }
201 
202 void
ItemDeleted(const sdbus::ObjectPath & item)203 Collection::ItemDeleted(const sdbus::ObjectPath &item) {
204 	emitItemDeleted(item);
205 	emitPropertiesChangedSignal("org.freedesktop.Secret.Collection", {"Items"});
206 	if (proxy) proxy->emitItemDeleted(item);
207 }
208 
209 void
ItemChanged(const sdbus::ObjectPath & item)210 Collection::ItemChanged(const sdbus::ObjectPath &item) {
211 	emitItemChanged(item);
212 	emitPropertiesChangedSignal("org.freedesktop.Secret.Collection", {"Items"});
213 	if (proxy) proxy->emitItemChanged(item);
214 }
215 
216 std::shared_ptr<SecretService>
GetService()217 Collection::GetService() {
218 	return parent.lock();
219 }
220