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