Merge lp:~thomas-voss/trust-store/fix-1504022 into lp:trust-store/15.04
- fix-1504022
- Merge into 15.04
Status: | Superseded | ||||||||
---|---|---|---|---|---|---|---|---|---|
Proposed branch: | lp:~thomas-voss/trust-store/fix-1504022 | ||||||||
Merge into: | lp:trust-store/15.04 | ||||||||
Diff against target: |
1644 lines (+1211/-92) 20 files modified
3rd_party/xdg/CMakeLists.txt (+22/-0) 3rd_party/xdg/LICENSE (+166/-0) 3rd_party/xdg/README.md (+87/-0) 3rd_party/xdg/xdg.cpp (+203/-0) 3rd_party/xdg/xdg.h (+118/-0) 3rd_party/xdg/xdg_test.cpp (+130/-0) CMakeLists.txt (+4/-1) debian/control (+3/-0) debian/source/format (+1/-1) src/CMakeLists.txt (+8/-0) src/core/trust/impl/sqlite3/store.cpp (+2/-8) src/core/trust/mir/agent.cpp (+11/-38) src/core/trust/mir/agent.h (+29/-14) src/core/trust/mir/click_desktop_entry_app_name_resolver.cpp (+106/-0) src/core/trust/mir/click_desktop_entry_app_name_resolver.h (+49/-0) tests/CMakeLists.txt (+29/-8) tests/click_desktop_entry_app_name_resolver_test.cpp (+60/-0) tests/mir_agent_test.cpp (+123/-22) tests/share/applications/valid.pkg_app_0.0.0.desktop (+55/-0) tests/test_data.h.in (+5/-0) |
||||||||
To merge this branch: | bzr merge lp:~thomas-voss/trust-store/fix-1504022 | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tyler Hicks | Needs Information | ||
Alberto Mardegan (community) | Approve | ||
Review via email: mp+277266@code.launchpad.net |
This proposal supersedes a proposal from 2015-11-11.
This proposal has been superseded by a proposal from 2015-11-15.
Commit message
Add interface mir::AppNameRes
mir::AppNameRes
to localized application names.
Description of the change
Add interface mir::AppNameRes
mir::AppNameRes
to localized application names.
- 138. By Thomas Voß
-
Robustify desktop entry lookup, relying on xdg dirs to search for matching entries.
- 139. By Thomas Voß
-
Rename test for mir::ClickDeskt
opEntryAppNameR esolver.
- 140. By Thomas Voß
-
Add missing , in debian/control.
- 141. By Thomas Voß
-
rely on xdg:: for querying xdg base spec directories.
Tyler Hicks (tyhicks) wrote : | # |
Hello - Thomas had asked for a security review and I just took a look at the code.
The code itself looks nearly perfect. I have a couple questions below but they're minor.
I'm mainly concerned about the concept of using the localized Name of the desktop file in a trust prompt. For something like a click app that comes from an untrusted developer, we have no idea if the localized name in their provided desktop file is an accurate translation or a malicious translation intended to trick the user into granting their app access. I don't know of any logic that could be used in the click reviewers tools to verify that the translations are non-malicious. How do we handle such a situation?
As for the code, I have a couple questions/comments:
1) What UID does resolve_
2) The external XDG stuff that you wrote is a nice idea. I'd recommend packaging it up as a library so that it can be reused in a controllable fashion instead of copying and pasting the code into all of the projects that want to use it.
Tyler Hicks (tyhicks) wrote : | # |
After speaking with jdstrand, he explained why the click reviewers tools don't currently verify the Name field of a desktop file. The desktop file name field can't be forced to match the click package name because the desktop file name should be "pretty" while the click package name is alphanumerics and '-'.
Because of this, I don't see how the desktop file name field can be trusted enough to be used in trust store prompts. :/
Thomas Voß (thomas-voss) wrote : | # |
Hey Tyler,
thanks for the detailed review and your comments. Let me first try to clarify on the use of the localized name in trust prompts. I actually raised the same issue as you, and it turns out that we are "vulnerable" to applications faking their identity in a couple of places throughout the system. First and foremost: Unity itself relies on the .desktop file entry for displaying the name. We might want to fix the default approach for handling localized application names meant for human consumption in snappy, though.
One possible way to resolve the issue is by altering the prompt to show the localized name alongside the actual application id. Ideally, we would have an expendable field "Details" as part of the prompt containing in-depth information about the request, at the very least the actual app ID together with the UID (and the human-readable user name).
(@1:) The function always runs under the actual user. I will however add a check to make sure that the current user id matches the user id of the request. If not, we will return early, and deny the request.
(@2:) Sure, happy to. I mainly added the external code here to guarantee a swift landing. I will do the packaging and carry out the requesting asap, but would like to make sure that a fix for this bug is not blocked by package/MIR review processes.
Thomas Voß (thomas-voss) wrote : | # |
One other idea to further clarify the identity of the app might be to include its official icon. At the very least, this would make it easier for the user to associate the source of the trust request with what is visible in the dash and in the launcher.
- 142. By Thomas Voß
-
Address comments in review and implement new prompt design.
- 143. By Thomas Voß
-
Ensure that rendering is consistent with app icon rendering on launcher/dash.
- 144. By Thomas Voß
-
Update pot to account for string changes.
- 145. By Thomas Voß
-
Change color of negative action to neutral, see:
https://developer. ubuntu. com/api/ apps/qml/ sdk-14. 10/Ubuntu. Components. UbuntuColors/ #lightGrey- prop
Fix apostrophe to be a real typographic apostrophe. - 146. By Thomas Voß
-
Align with app scope display of icons, see:
https://code.launchpad .net/~cimi/ unity8/ new-shadows- 1.3/+merge/ 271611
Unmerged revisions
Preview Diff
1 | === added directory '3rd_party' |
2 | === added directory '3rd_party/xdg' |
3 | === added file '3rd_party/xdg/CMakeLists.txt' |
4 | --- 3rd_party/xdg/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
5 | +++ 3rd_party/xdg/CMakeLists.txt 2015-11-15 21:10:18 +0000 |
6 | @@ -0,0 +1,22 @@ |
7 | +project(xdg) |
8 | + |
9 | +cmake_minimum_required(VERSION 2.8) |
10 | + |
11 | +find_package(Boost COMPONENTS filesystem system unit_test_framework) |
12 | + |
13 | +include_directories( |
14 | + . |
15 | + ${Boost_INCLUDE_DIRS} |
16 | +) |
17 | + |
18 | +add_library(xdg xdg.cpp) |
19 | +set_property(TARGET xdg PROPERTY CXX_STANDARD 11) |
20 | +target_link_libraries(xdg ${Boost_LIBRARIES}) |
21 | + |
22 | +enable_testing() |
23 | +add_definitions(-DBOOST_TEST_DYN_LINK -DBOOST_TEST_MAIN -DBOOST_TEST_MODULE=xdg) |
24 | +add_executable(xdg_test xdg_test.cpp) |
25 | +set_property(TARGET xdg_test PROPERTY CXX_STANDARD 11) |
26 | +target_link_libraries(xdg_test xdg) |
27 | + |
28 | +add_test(xdg_test xdg_test) |
29 | |
30 | === added file '3rd_party/xdg/LICENSE' |
31 | --- 3rd_party/xdg/LICENSE 1970-01-01 00:00:00 +0000 |
32 | +++ 3rd_party/xdg/LICENSE 2015-11-15 21:10:18 +0000 |
33 | @@ -0,0 +1,166 @@ |
34 | + GNU LESSER GENERAL PUBLIC LICENSE |
35 | + Version 3, 29 June 2007 |
36 | + |
37 | + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
38 | + Everyone is permitted to copy and distribute verbatim copies |
39 | + of this license document, but changing it is not allowed. |
40 | + |
41 | + |
42 | + This version of the GNU Lesser General Public License incorporates |
43 | +the terms and conditions of version 3 of the GNU General Public |
44 | +License, supplemented by the additional permissions listed below. |
45 | + |
46 | + 0. Additional Definitions. |
47 | + |
48 | + As used herein, "this License" refers to version 3 of the GNU Lesser |
49 | +General Public License, and the "GNU GPL" refers to version 3 of the GNU |
50 | +General Public License. |
51 | + |
52 | + "The Library" refers to a covered work governed by this License, |
53 | +other than an Application or a Combined Work as defined below. |
54 | + |
55 | + An "Application" is any work that makes use of an interface provided |
56 | +by the Library, but which is not otherwise based on the Library. |
57 | +Defining a subclass of a class defined by the Library is deemed a mode |
58 | +of using an interface provided by the Library. |
59 | + |
60 | + A "Combined Work" is a work produced by combining or linking an |
61 | +Application with the Library. The particular version of the Library |
62 | +with which the Combined Work was made is also called the "Linked |
63 | +Version". |
64 | + |
65 | + The "Minimal Corresponding Source" for a Combined Work means the |
66 | +Corresponding Source for the Combined Work, excluding any source code |
67 | +for portions of the Combined Work that, considered in isolation, are |
68 | +based on the Application, and not on the Linked Version. |
69 | + |
70 | + The "Corresponding Application Code" for a Combined Work means the |
71 | +object code and/or source code for the Application, including any data |
72 | +and utility programs needed for reproducing the Combined Work from the |
73 | +Application, but excluding the System Libraries of the Combined Work. |
74 | + |
75 | + 1. Exception to Section 3 of the GNU GPL. |
76 | + |
77 | + You may convey a covered work under sections 3 and 4 of this License |
78 | +without being bound by section 3 of the GNU GPL. |
79 | + |
80 | + 2. Conveying Modified Versions. |
81 | + |
82 | + If you modify a copy of the Library, and, in your modifications, a |
83 | +facility refers to a function or data to be supplied by an Application |
84 | +that uses the facility (other than as an argument passed when the |
85 | +facility is invoked), then you may convey a copy of the modified |
86 | +version: |
87 | + |
88 | + a) under this License, provided that you make a good faith effort to |
89 | + ensure that, in the event an Application does not supply the |
90 | + function or data, the facility still operates, and performs |
91 | + whatever part of its purpose remains meaningful, or |
92 | + |
93 | + b) under the GNU GPL, with none of the additional permissions of |
94 | + this License applicable to that copy. |
95 | + |
96 | + 3. Object Code Incorporating Material from Library Header Files. |
97 | + |
98 | + The object code form of an Application may incorporate material from |
99 | +a header file that is part of the Library. You may convey such object |
100 | +code under terms of your choice, provided that, if the incorporated |
101 | +material is not limited to numerical parameters, data structure |
102 | +layouts and accessors, or small macros, inline functions and templates |
103 | +(ten or fewer lines in length), you do both of the following: |
104 | + |
105 | + a) Give prominent notice with each copy of the object code that the |
106 | + Library is used in it and that the Library and its use are |
107 | + covered by this License. |
108 | + |
109 | + b) Accompany the object code with a copy of the GNU GPL and this license |
110 | + document. |
111 | + |
112 | + 4. Combined Works. |
113 | + |
114 | + You may convey a Combined Work under terms of your choice that, |
115 | +taken together, effectively do not restrict modification of the |
116 | +portions of the Library contained in the Combined Work and reverse |
117 | +engineering for debugging such modifications, if you also do each of |
118 | +the following: |
119 | + |
120 | + a) Give prominent notice with each copy of the Combined Work that |
121 | + the Library is used in it and that the Library and its use are |
122 | + covered by this License. |
123 | + |
124 | + b) Accompany the Combined Work with a copy of the GNU GPL and this license |
125 | + document. |
126 | + |
127 | + c) For a Combined Work that displays copyright notices during |
128 | + execution, include the copyright notice for the Library among |
129 | + these notices, as well as a reference directing the user to the |
130 | + copies of the GNU GPL and this license document. |
131 | + |
132 | + d) Do one of the following: |
133 | + |
134 | + 0) Convey the Minimal Corresponding Source under the terms of this |
135 | + License, and the Corresponding Application Code in a form |
136 | + suitable for, and under terms that permit, the user to |
137 | + recombine or relink the Application with a modified version of |
138 | + the Linked Version to produce a modified Combined Work, in the |
139 | + manner specified by section 6 of the GNU GPL for conveying |
140 | + Corresponding Source. |
141 | + |
142 | + 1) Use a suitable shared library mechanism for linking with the |
143 | + Library. A suitable mechanism is one that (a) uses at run time |
144 | + a copy of the Library already present on the user's computer |
145 | + system, and (b) will operate properly with a modified version |
146 | + of the Library that is interface-compatible with the Linked |
147 | + Version. |
148 | + |
149 | + e) Provide Installation Information, but only if you would otherwise |
150 | + be required to provide such information under section 6 of the |
151 | + GNU GPL, and only to the extent that such information is |
152 | + necessary to install and execute a modified version of the |
153 | + Combined Work produced by recombining or relinking the |
154 | + Application with a modified version of the Linked Version. (If |
155 | + you use option 4d0, the Installation Information must accompany |
156 | + the Minimal Corresponding Source and Corresponding Application |
157 | + Code. If you use option 4d1, you must provide the Installation |
158 | + Information in the manner specified by section 6 of the GNU GPL |
159 | + for conveying Corresponding Source.) |
160 | + |
161 | + 5. Combined Libraries. |
162 | + |
163 | + You may place library facilities that are a work based on the |
164 | +Library side by side in a single library together with other library |
165 | +facilities that are not Applications and are not covered by this |
166 | +License, and convey such a combined library under terms of your |
167 | +choice, if you do both of the following: |
168 | + |
169 | + a) Accompany the combined library with a copy of the same work based |
170 | + on the Library, uncombined with any other library facilities, |
171 | + conveyed under the terms of this License. |
172 | + |
173 | + b) Give prominent notice with the combined library that part of it |
174 | + is a work based on the Library, and explaining where to find the |
175 | + accompanying uncombined form of the same work. |
176 | + |
177 | + 6. Revised Versions of the GNU Lesser General Public License. |
178 | + |
179 | + The Free Software Foundation may publish revised and/or new versions |
180 | +of the GNU Lesser General Public License from time to time. Such new |
181 | +versions will be similar in spirit to the present version, but may |
182 | +differ in detail to address new problems or concerns. |
183 | + |
184 | + Each version is given a distinguishing version number. If the |
185 | +Library as you received it specifies that a certain numbered version |
186 | +of the GNU Lesser General Public License "or any later version" |
187 | +applies to it, you have the option of following the terms and |
188 | +conditions either of that published version or of any later version |
189 | +published by the Free Software Foundation. If the Library as you |
190 | +received it does not specify a version number of the GNU Lesser |
191 | +General Public License, you may choose any version of the GNU Lesser |
192 | +General Public License ever published by the Free Software Foundation. |
193 | + |
194 | + If the Library as you received it specifies that a proxy can decide |
195 | +whether future versions of the GNU Lesser General Public License shall |
196 | +apply, that proxy's public statement of acceptance of any version is |
197 | +permanent authorization for you to choose that version for the |
198 | +Library. |
199 | + |
200 | |
201 | === added file '3rd_party/xdg/README.md' |
202 | --- 3rd_party/xdg/README.md 1970-01-01 00:00:00 +0000 |
203 | +++ 3rd_party/xdg/README.md 2015-11-15 21:10:18 +0000 |
204 | @@ -0,0 +1,87 @@ |
205 | +# xdg |
206 | + |
207 | +A straightforward implementation of the XDG Base Directory Specification in C++11. |
208 | +I became tired of retyping and retesting the same functionality over and over again, |
209 | +so I decided to place my own little helper here. |
210 | + |
211 | +## Dependencies |
212 | + |
213 | + - boost::filesystem: For handling all things filesystem paths. |
214 | + - boost::system:: Required by boost::filesystem. |
215 | + - boost::test: For testing purposes obviously. |
216 | + |
217 | +Install with |
218 | +```bash |
219 | +sudo apt-get install libboost-filesystem-dev libboost-system-dev libboost-test-dev |
220 | +``` |
221 | + |
222 | +## Quick'n'Easy Integration |
223 | + |
224 | +xdg provides free functions that are easy to integrate with existing projects. |
225 | +```cpp |
226 | +#include <xdg.h> |
227 | + |
228 | +#include <iostream> |
229 | + |
230 | +int main() |
231 | +{ |
232 | + std::cout << xdg::data().home() << std::endl; |
233 | + std::cout << xdg::config().home() << std::endl; |
234 | + std::cout << xdg::cache().home() << std::endl; |
235 | + std::cout << xdg::runtime().dir() << std::endl; |
236 | + |
237 | + return 0; |
238 | +} |
239 | +``` |
240 | + |
241 | +## Complete Integration |
242 | + |
243 | +The interface xdg::BaseDirSpecification can be used to integrate xdg base directory |
244 | +queries into a code base such that interaction with the xdg::BaseDirSpecification is testable. |
245 | + |
246 | +```cpp |
247 | +#include <xdg.h> |
248 | + |
249 | +class MyClass |
250 | +{ |
251 | +public: |
252 | + MyClass(const std::shared_ptr<xdg::BaseDirSpecification>& bds) : bds{bds} |
253 | + { |
254 | + } |
255 | + |
256 | + void do_something() |
257 | + { |
258 | + // Query the user-specific config directory. |
259 | + auto path = bds->config().home(); |
260 | + // Do something with the config files. |
261 | + } |
262 | +private: |
263 | + std::shared_ptr<xdg::BaseDirSpecification> bds; |
264 | +}; |
265 | + |
266 | +// In the testing setup, under the assumption of Google Test and Google Mock. |
267 | +namespace |
268 | +{ |
269 | +struct MockConfig : public xdg::Config |
270 | +{ |
271 | + // ... |
272 | +}; |
273 | +struct MockBaseDirSpecification : public xdg::BaseDirSpecification |
274 | +{ |
275 | + // ... |
276 | +}; |
277 | +} |
278 | + |
279 | +TEST(MyClass, do_something_queries_config_home_directory) |
280 | +{ |
281 | + using namespace ::testing; |
282 | + auto config = std::make_shared<NiceMock<MockConfig>>(); |
283 | + EXPECT_CALL(*config, home()).Times(1).ReturnRepeatedly("/tmp"); |
284 | + |
285 | + auto bds = std::make_shared<NiceMock<MockBaseDirSpecification>>(); |
286 | + ON_CALL(*bds, config()).WillByDefault(ReturnRef(*config)); |
287 | + |
288 | + MyClass mc{bds}; |
289 | + mc.do_something(); |
290 | +} |
291 | +``` |
292 | |
293 | === added file '3rd_party/xdg/xdg.cpp' |
294 | --- 3rd_party/xdg/xdg.cpp 1970-01-01 00:00:00 +0000 |
295 | +++ 3rd_party/xdg/xdg.cpp 2015-11-15 21:10:18 +0000 |
296 | @@ -0,0 +1,203 @@ |
297 | +// Copyright (C) 2015 Thomas Voß <thomas.voss.bochum@gmail.com> |
298 | +// |
299 | +// This library is free software: you can redistribute it and/or modify |
300 | +// it under the terms of the GNU Lesser General Public License as published |
301 | +// by the Free Software Foundation, either version 3 of the License, or |
302 | +// (at your option) any later version. |
303 | +// |
304 | +// This program is distributed in the hope that it will be useful, |
305 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
306 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
307 | +// GNU General Public License for more details. |
308 | +// |
309 | +// You should have received a copy of the GNU Lesser General Public License |
310 | +// along with this program. If not, see <http://www.gnu.org/licenses/>. |
311 | + |
312 | +#include <xdg.h> |
313 | + |
314 | +#include <boost/algorithm/string.hpp> |
315 | + |
316 | +#include <cstdlib> |
317 | +#include <stdexcept> |
318 | + |
319 | +namespace fs = boost::filesystem; |
320 | + |
321 | +namespace |
322 | +{ |
323 | + |
324 | +fs::path throw_if_not_absolute(const fs::path& p) |
325 | +{ |
326 | + if (p.has_root_directory()) |
327 | + return p; |
328 | + |
329 | + throw std::runtime_error{"Directores MUST be absolute."}; |
330 | +} |
331 | + |
332 | +namespace env |
333 | +{ |
334 | +std::string get(const std::string& key, const std::string& default_value) |
335 | +{ |
336 | + if (auto value = std::getenv(key.c_str())) |
337 | + return value; |
338 | + return default_value; |
339 | +} |
340 | + |
341 | +std::string get_or_throw(const std::string& key) |
342 | +{ |
343 | + if (auto value = std::getenv(key.c_str())) |
344 | + { |
345 | + return value; |
346 | + } |
347 | + |
348 | + throw std::runtime_error{key + " not set in environment"}; |
349 | +} |
350 | + |
351 | +constexpr const char* xdg_data_home{"XDG_DATA_HOME"}; |
352 | +constexpr const char* xdg_data_dirs{"XDG_DATA_DIRS"}; |
353 | +constexpr const char* xdg_config_home{"XDG_CONFIG_HOME"}; |
354 | +constexpr const char* xdg_config_dirs{"XDG_CONFIG_DIRS"}; |
355 | +constexpr const char* xdg_cache_home{"XDG_CACHE_HOME"}; |
356 | +constexpr const char* xdg_runtime_dir{"XDG_RUNTIME_DIR"}; |
357 | +} |
358 | + |
359 | +namespace impl |
360 | +{ |
361 | +class BaseDirSpecification : public xdg::BaseDirSpecification |
362 | +{ |
363 | +public: |
364 | + static const BaseDirSpecification& instance() |
365 | + { |
366 | + static const BaseDirSpecification spec; |
367 | + return spec; |
368 | + } |
369 | + |
370 | + BaseDirSpecification() |
371 | + { |
372 | + } |
373 | + |
374 | + const xdg::Data& data() const override |
375 | + { |
376 | + return data_; |
377 | + } |
378 | + |
379 | + const xdg::Config& config() const override |
380 | + { |
381 | + return config_; |
382 | + } |
383 | + |
384 | + const xdg::Cache& cache() const override |
385 | + { |
386 | + return cache_; |
387 | + } |
388 | + |
389 | + const xdg::Runtime& runtime() const override |
390 | + { |
391 | + return runtime_; |
392 | + } |
393 | + |
394 | +private: |
395 | + xdg::Data data_; |
396 | + xdg::Config config_; |
397 | + xdg::Cache cache_; |
398 | + xdg::Runtime runtime_; |
399 | +}; |
400 | +} |
401 | +} |
402 | + |
403 | +fs::path xdg::Data::home() const |
404 | +{ |
405 | + auto v = env::get(env::xdg_data_home, ""); |
406 | + if (v.empty()) |
407 | + return throw_if_not_absolute(fs::path{env::get_or_throw("HOME")} / ".local" / "share"); |
408 | + |
409 | + return throw_if_not_absolute(fs::path(v)); |
410 | +} |
411 | + |
412 | +std::vector<fs::path> xdg::Data::dirs() const |
413 | +{ |
414 | + auto v = env::get(env::xdg_data_dirs, ""); |
415 | + if (v.empty()) |
416 | + return {fs::path{"/usr/local/share"}, fs::path{"/usr/share"}}; |
417 | + |
418 | + std::vector<std::string> tokens; |
419 | + tokens = boost::split(tokens, v, boost::is_any_of(":")); |
420 | + std::vector<fs::path> result; |
421 | + for (const auto& token : tokens) |
422 | + { |
423 | + result.push_back(throw_if_not_absolute(fs::path(token))); |
424 | + } |
425 | + return result; |
426 | +} |
427 | + |
428 | +fs::path xdg::Config::home() const |
429 | +{ |
430 | + auto v = env::get(env::xdg_config_home, ""); |
431 | + if (v.empty()) |
432 | + return throw_if_not_absolute(fs::path{env::get_or_throw("HOME")} / ".config"); |
433 | + |
434 | + return throw_if_not_absolute(fs::path(v)); |
435 | +} |
436 | + |
437 | +std::vector<fs::path> xdg::Config::dirs() const |
438 | +{ |
439 | + auto v = env::get(env::xdg_config_dirs, ""); |
440 | + if (v.empty()) |
441 | + return {fs::path{"/etc/xdg"}}; |
442 | + |
443 | + std::vector<std::string> tokens; |
444 | + tokens = boost::split(tokens, v, boost::is_any_of(":")); |
445 | + std::vector<fs::path> result; |
446 | + for (const auto& token : tokens) |
447 | + { |
448 | + fs::path p(token); |
449 | + result.push_back(throw_if_not_absolute(p)); |
450 | + } |
451 | + return result; |
452 | +} |
453 | + |
454 | +fs::path xdg::Cache::home() const |
455 | +{ |
456 | + auto v = env::get(env::xdg_cache_home, ""); |
457 | + if (v.empty()) |
458 | + return throw_if_not_absolute(fs::path{env::get_or_throw("HOME")} / ".cache"); |
459 | + |
460 | + return throw_if_not_absolute(fs::path(v)); |
461 | +} |
462 | + |
463 | +fs::path xdg::Runtime::dir() const |
464 | +{ |
465 | + auto v = env::get(env::xdg_config_home, ""); |
466 | + if (v.empty()) |
467 | + { |
468 | + // We do not fall back gracefully and instead throw, dispatching to calling |
469 | + // code for handling the case of a safe user-specfic runtime directory missing. |
470 | + throw std::runtime_error{"Runtime directory not set"}; |
471 | + } |
472 | + |
473 | + return throw_if_not_absolute(fs::path(v)); |
474 | +} |
475 | + |
476 | +std::shared_ptr<xdg::BaseDirSpecification> xdg::BaseDirSpecification::create() |
477 | +{ |
478 | + return std::make_shared<impl::BaseDirSpecification>(); |
479 | +} |
480 | + |
481 | +const xdg::Data& xdg::data() |
482 | +{ |
483 | + return impl::BaseDirSpecification::instance().data(); |
484 | +} |
485 | + |
486 | +const xdg::Config& xdg::config() |
487 | +{ |
488 | + return impl::BaseDirSpecification::instance().config(); |
489 | +} |
490 | + |
491 | +const xdg::Cache& xdg::cache() |
492 | +{ |
493 | + return impl::BaseDirSpecification::instance().cache(); |
494 | +} |
495 | + |
496 | +const xdg::Runtime& xdg::runtime() |
497 | +{ |
498 | + return impl::BaseDirSpecification::instance().runtime(); |
499 | +} |
500 | |
501 | === added file '3rd_party/xdg/xdg.h' |
502 | --- 3rd_party/xdg/xdg.h 1970-01-01 00:00:00 +0000 |
503 | +++ 3rd_party/xdg/xdg.h 2015-11-15 21:10:18 +0000 |
504 | @@ -0,0 +1,118 @@ |
505 | +// Copyright (C) 2015 Thomas Voß <thomas.voss.bochum@gmail.com> |
506 | +// |
507 | +// This library is free software: you can redistribute it and/or modify |
508 | +// it under the terms of the GNU Lesser General Public License as published |
509 | +// by the Free Software Foundation, either version 3 of the License, or |
510 | +// (at your option) any later version. |
511 | +// |
512 | +// This program is distributed in the hope that it will be useful, |
513 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
514 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
515 | +// GNU General Public License for more details. |
516 | +// |
517 | +// You should have received a copy of the GNU Lesser General Public License |
518 | +// along with this program. If not, see <http://www.gnu.org/licenses/>. |
519 | +#ifndef XDG_H_ |
520 | +#define XDG_H_ |
521 | + |
522 | +#include <boost/filesystem.hpp> |
523 | + |
524 | +#include <string> |
525 | +#include <vector> |
526 | + |
527 | +namespace xdg |
528 | +{ |
529 | +// NotCopyable deletes the copy c'tor and the assignment operator. |
530 | +struct NotCopyable |
531 | +{ |
532 | + NotCopyable() = default; |
533 | + NotCopyable(const NotCopyable&) = delete; |
534 | + virtual ~NotCopyable() = default; |
535 | + NotCopyable& operator=(const NotCopyable&) = delete; |
536 | +}; |
537 | + |
538 | +// NotMoveable deletes the move c'tor and the move assignment operator. |
539 | +struct NotMoveable |
540 | +{ |
541 | + NotMoveable() = default; |
542 | + NotMoveable(NotMoveable&&) = delete; |
543 | + virtual ~NotMoveable() = default; |
544 | + NotMoveable& operator=(NotMoveable&&) = delete; |
545 | +}; |
546 | + |
547 | +// Data provides functions to query the XDG_DATA_* entries. |
548 | +class Data : NotCopyable, NotMoveable |
549 | +{ |
550 | +public: |
551 | + // home returns the base directory relative to which user specific |
552 | + // data files should be stored. |
553 | + virtual boost::filesystem::path home() const; |
554 | + // dirs returns the preference-ordered set of base directories to |
555 | + // search for data files in addition to the $XDG_DATA_HOME base |
556 | + // directory. |
557 | + virtual std::vector<boost::filesystem::path> dirs() const; |
558 | +}; |
559 | + |
560 | +// Config provides functions to query the XDG_CONFIG_* entries. |
561 | +class Config : NotCopyable, NotMoveable |
562 | +{ |
563 | +public: |
564 | + // home returns the base directory relative to which user specific |
565 | + // configuration files should be stored. |
566 | + virtual boost::filesystem::path home() const; |
567 | + // dirs returns the preference-ordered set of base directories to |
568 | + // search for configuration files in addition to the |
569 | + // $XDG_CONFIG_HOME base directory. |
570 | + virtual std::vector<boost::filesystem::path> dirs() const; |
571 | +}; |
572 | + |
573 | +// Cache provides functions to query the XDG_CACHE_HOME entry. |
574 | +class Cache : NotCopyable, NotMoveable |
575 | +{ |
576 | +public: |
577 | + // home returns the base directory relative to which user specific |
578 | + // non-essential data files should be stored. |
579 | + virtual boost::filesystem::path home() const; |
580 | +}; |
581 | + |
582 | +// Runtime provides functions to query the XDG_RUNTIME_DIR entry. |
583 | +class Runtime : NotCopyable, NotMoveable |
584 | +{ |
585 | +public: |
586 | + // home returns the base directory relative to which user-specific |
587 | + // non-essential runtime files and other file objects (such as |
588 | + // sockets, named pipes, ...) should be stored. |
589 | + virtual boost::filesystem::path dir() const; |
590 | +}; |
591 | + |
592 | +// A BaseDirSpecification implements the XDG base dir specification: |
593 | +// http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html |
594 | +class BaseDirSpecification : NotCopyable, NotMoveable |
595 | +{ |
596 | +public: |
597 | + // create returns an Implementation of BaseDirSpecification. |
598 | + static std::shared_ptr<BaseDirSpecification> create(); |
599 | + |
600 | + // data returns an immutable Data instance. |
601 | + virtual const Data& data() const = 0; |
602 | + // config returns an immutable Config instance. |
603 | + virtual const Config& config() const = 0; |
604 | + // cache returns an immutable Cache instance. |
605 | + virtual const Cache& cache() const = 0; |
606 | + // runtime returns an immutable Runtime instance. |
607 | + virtual const Runtime& runtime() const = 0; |
608 | +protected: |
609 | + BaseDirSpecification() = default; |
610 | +}; |
611 | + |
612 | +// data returns an immutable reference to a Data instance. |
613 | +const Data& data(); |
614 | +// config returns an immutable reference to a Config instance. |
615 | +const Config& config(); |
616 | +// cache returns an immutable reference to a Cache instance. |
617 | +const Cache& cache(); |
618 | +// runtime returns an immutable reference to a Runtime instance. |
619 | +const Runtime& runtime(); |
620 | +} |
621 | + |
622 | +#endif // XDG_H_ |
623 | |
624 | === added file '3rd_party/xdg/xdg_test.cpp' |
625 | --- 3rd_party/xdg/xdg_test.cpp 1970-01-01 00:00:00 +0000 |
626 | +++ 3rd_party/xdg/xdg_test.cpp 2015-11-15 21:10:18 +0000 |
627 | @@ -0,0 +1,130 @@ |
628 | +// Copyright (C) 2015 Thomas Voß <thomas.voss.bochum@gmail.com> |
629 | +// |
630 | +// This library is free software: you can redistribute it and/or modify |
631 | +// it under the terms of the GNU Lesser General Public License as published |
632 | +// by the Free Software Foundation, either version 3 of the License, or |
633 | +// (at your option) any later version. |
634 | +// |
635 | +// This program is distributed in the hope that it will be useful, |
636 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
637 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
638 | +// GNU General Public License for more details. |
639 | +// |
640 | +// You should have received a copy of the GNU Lesser General Public License |
641 | +// along with this program. If not, see <http://www.gnu.org/licenses/>. |
642 | + |
643 | +#include <xdg.h> |
644 | + |
645 | +#include <boost/test/unit_test.hpp> |
646 | + |
647 | +#include <cstdlib> |
648 | +#include <iostream> |
649 | + |
650 | +BOOST_AUTO_TEST_CASE(XdgDataHomeThrowsForRelativeDirectoryFromEnv) |
651 | +{ |
652 | + ::setenv("XDG_DATA_HOME", "tmp", 1); |
653 | + BOOST_CHECK_THROW(xdg::BaseDirSpecification::create()->data().home(), std::runtime_error); |
654 | + BOOST_CHECK_THROW(xdg::data().home(), std::runtime_error); |
655 | +} |
656 | + |
657 | +BOOST_AUTO_TEST_CASE(XdgDataHomeReturnsDefaultValueForEmptyEnv) |
658 | +{ |
659 | + ::setenv("HOME", "/tmp", 1); |
660 | + ::setenv("XDG_DATA_HOME", "", 1); |
661 | + BOOST_CHECK_EQUAL("/tmp/.local/share", xdg::BaseDirSpecification::create()->data().home()); |
662 | + BOOST_CHECK_EQUAL("/tmp/.local/share", xdg::data().home()); |
663 | +} |
664 | + |
665 | +BOOST_AUTO_TEST_CASE(XdgDataDirsCorrectlyTokenizesEnv) |
666 | +{ |
667 | + ::setenv("XDG_DATA_DIRS", "/tmp:/tmp", 1); |
668 | + BOOST_CHECK(2 == xdg::BaseDirSpecification::create()->data().dirs().size()); |
669 | + BOOST_CHECK(2 == xdg::data().dirs().size()); |
670 | +} |
671 | + |
672 | +BOOST_AUTO_TEST_CASE(XdgDataDirsThrowsForRelativeDirectoryFromEnv) |
673 | +{ |
674 | + ::setenv("XDG_DATA_DIRS", "/tmp:tmp", 1); |
675 | + BOOST_CHECK_THROW(xdg::BaseDirSpecification::create()->data().dirs(), std::runtime_error); |
676 | + BOOST_CHECK_THROW(xdg::data().dirs(), std::runtime_error); |
677 | +} |
678 | + |
679 | +BOOST_AUTO_TEST_CASE(XdgDataDirsReturnsDefaultValueForEmptyEnv) |
680 | +{ |
681 | + ::setenv("XDG_DATA_DIRS", "", 1); |
682 | + auto dirs = xdg::data().dirs(); |
683 | + BOOST_CHECK_EQUAL("/usr/local/share", dirs[0]); |
684 | + BOOST_CHECK_EQUAL("/usr/share", dirs[1]); |
685 | + |
686 | + dirs = xdg::BaseDirSpecification::create()->data().dirs(); |
687 | + BOOST_CHECK_EQUAL("/usr/local/share", dirs[0]); |
688 | + BOOST_CHECK_EQUAL("/usr/share", dirs[1]); |
689 | +} |
690 | + |
691 | +BOOST_AUTO_TEST_CASE(XdgConfigHomeThrowsForRelativeDirectoryFromEnv) |
692 | +{ |
693 | + ::setenv("XDG_CONFIG_HOME", "tmp", 1); |
694 | + BOOST_CHECK_THROW(xdg::BaseDirSpecification::create()->config().home(), std::runtime_error); |
695 | + BOOST_CHECK_THROW(xdg::config().home(), std::runtime_error); |
696 | +} |
697 | + |
698 | +BOOST_AUTO_TEST_CASE(XdgConfigHomeReturnsDefaultValueForEmptyEnv) |
699 | +{ |
700 | + ::setenv("HOME", "/tmp", 1); |
701 | + ::setenv("XDG_CONFIG_HOME", "", 1); |
702 | + BOOST_CHECK_EQUAL("/tmp/.config", xdg::BaseDirSpecification::create()->config().home()); |
703 | + BOOST_CHECK_EQUAL("/tmp/.config", xdg::config().home()); |
704 | +} |
705 | + |
706 | +BOOST_AUTO_TEST_CASE(XdgConfigDirsCorrectlyTokenizesEnv) |
707 | +{ |
708 | + ::setenv("XDG_CONFIG_DIRS", "/tmp:/tmp", 1); |
709 | + BOOST_CHECK(2 == xdg::BaseDirSpecification::create()->config().dirs().size()); |
710 | + BOOST_CHECK(2 == xdg::config().dirs().size()); |
711 | +} |
712 | + |
713 | +BOOST_AUTO_TEST_CASE(XdgConfigDirsThrowsForRelativeDirectoryFromEnv) |
714 | +{ |
715 | + ::setenv("XDG_CONFIG_DIRS", "/tmp:tmp", 1); |
716 | + BOOST_CHECK_THROW(xdg::BaseDirSpecification::create()->config().dirs(), std::runtime_error); |
717 | + BOOST_CHECK_THROW(xdg::config().dirs(), std::runtime_error); |
718 | +} |
719 | + |
720 | +BOOST_AUTO_TEST_CASE(XdgConfigDirsReturnsDefaultValueForEmptyEnv) |
721 | +{ |
722 | + ::setenv("XDG_CONFIG_DIRS", "", 1); |
723 | + auto dirs = xdg::config().dirs(); |
724 | + BOOST_CHECK_EQUAL("/etc/xdg", dirs[0]); |
725 | + dirs = xdg::BaseDirSpecification::create()->config().dirs(); |
726 | + BOOST_CHECK_EQUAL("/etc/xdg", dirs[0]); |
727 | +} |
728 | + |
729 | +BOOST_AUTO_TEST_CASE(XdgCacheHomeThrowsForRelativeDirectoryFromEnv) |
730 | +{ |
731 | + ::setenv("XDG_CACHE_HOME", "tmp", 1); |
732 | + BOOST_CHECK_THROW(xdg::BaseDirSpecification::create()->cache().home(), std::runtime_error); |
733 | + BOOST_CHECK_THROW(xdg::cache().home(), std::runtime_error); |
734 | +} |
735 | + |
736 | +BOOST_AUTO_TEST_CASE(XdgCacheHomeReturnsDefaultValueForEmptyEnv) |
737 | +{ |
738 | + ::setenv("HOME", "/tmp", 1); |
739 | + ::setenv("XDG_CACHE_HOME", "", 1); |
740 | + BOOST_CHECK_EQUAL("/tmp/.cache", xdg::BaseDirSpecification::create()->cache().home()); |
741 | + BOOST_CHECK_EQUAL("/tmp/.cache", xdg::cache().home()); |
742 | +} |
743 | + |
744 | +BOOST_AUTO_TEST_CASE(XdgRuntimeDirThrowsForRelativeDirectoryFromEnv) |
745 | +{ |
746 | + ::setenv("XDG_RUNTIME_DIR", "tmp", 1); |
747 | + BOOST_CHECK_THROW(xdg::BaseDirSpecification::create()->runtime().dir(), std::runtime_error); |
748 | + BOOST_CHECK_THROW(xdg::runtime().dir(), std::runtime_error); |
749 | +} |
750 | + |
751 | +BOOST_AUTO_TEST_CASE(XdgRuntimeDirThrowsForEmptyEnv) |
752 | +{ |
753 | + ::setenv("XDG_RUNTIME_DIR", "", 1); |
754 | + BOOST_CHECK_THROW(xdg::BaseDirSpecification::create()->runtime().dir(), std::runtime_error); |
755 | + BOOST_CHECK_THROW(xdg::runtime().dir(), std::runtime_error); |
756 | +} |
757 | + |
758 | |
759 | === modified file 'CMakeLists.txt' |
760 | --- CMakeLists.txt 2015-08-31 13:16:20 +0000 |
761 | +++ CMakeLists.txt 2015-11-15 21:10:18 +0000 |
762 | @@ -28,7 +28,9 @@ |
763 | ENDIF(CMAKE_BUILD_TYPE MATCHES [cC][oO][vV][eE][rR][aA][gG][eE]) |
764 | |
765 | find_package(PkgConfig) |
766 | -find_package(Boost COMPONENTS program_options system REQUIRED) |
767 | +find_package(Boost COMPONENTS filesystem program_options system REQUIRED) |
768 | + |
769 | +add_subdirectory(3rd_party/xdg) |
770 | |
771 | option( |
772 | TRUST_STORE_MIR_AGENT_ENABLED |
773 | @@ -54,6 +56,7 @@ |
774 | |
775 | include_directories( |
776 | include/ |
777 | + 3rd_party/xdg |
778 | |
779 | ${GFLAGS_INCLUDE_DIRS} |
780 | ${GLOG_INCLUDE_DIRS} |
781 | |
782 | === modified file 'debian/control' |
783 | --- debian/control 2015-08-31 13:16:20 +0000 |
784 | +++ debian/control 2015-11-15 21:10:18 +0000 |
785 | @@ -7,11 +7,14 @@ |
786 | google-mock, |
787 | graphviz, |
788 | libapparmor-dev, |
789 | + libboost-filesystem-dev, |
790 | libboost-program-options-dev, |
791 | libboost-system-dev, |
792 | + libboost-test-dev, |
793 | libdbus-cpp-dev (>= 4.0.0), |
794 | libdbus-1-dev, |
795 | libgflags-dev, |
796 | + libglib2.0-dev, |
797 | libgoogle-glog-dev, |
798 | libgtest-dev, |
799 | libjson-c-dev, |
800 | |
801 | === modified file 'debian/source/format' |
802 | --- debian/source/format 2014-08-14 13:05:04 +0000 |
803 | +++ debian/source/format 2015-11-15 21:10:18 +0000 |
804 | @@ -1,1 +1,1 @@ |
805 | -3.0 (quilt) |
806 | +3.0 (native) |
807 | |
808 | === modified file 'src/CMakeLists.txt' |
809 | --- src/CMakeLists.txt 2015-08-31 13:16:20 +0000 |
810 | +++ src/CMakeLists.txt 2015-11-15 21:10:18 +0000 |
811 | @@ -20,6 +20,8 @@ |
812 | |
813 | pkg_check_modules(DBUS_CPP dbus-cpp REQUIRED) |
814 | pkg_check_modules(DBUS dbus-1 REQUIRED) |
815 | +pkg_check_modules(GLIB glib-2.0 REQUIRED) |
816 | +pkg_check_modules(GOBJECT gobject-2.0 REQUIRED) |
817 | pkg_check_modules(LIBAPPARMOR libapparmor REQUIRED) |
818 | pkg_check_modules(SQLITE3 sqlite3 REQUIRED) |
819 | |
820 | @@ -28,6 +30,8 @@ |
821 | include_directories( |
822 | ${DBUS_CPP_INCLUDE_DIRS} |
823 | ${DBUS_INCLUDE_DIRS} |
824 | + ${GLIB_INCLUDE_DIRS} |
825 | + ${GOBJECT_INCLUDE_DIRS} |
826 | ${LIBAPPARMOR_INCLUDE_DIRS} |
827 | ${SQLITE3_INCLUDE_DIRS} |
828 | ) |
829 | @@ -70,6 +74,7 @@ |
830 | # to prompt the user for trusting an application to access a trusted |
831 | # system service. |
832 | core/trust/mir/agent.cpp |
833 | + core/trust/mir/click_desktop_entry_app_name_resolver.cpp |
834 | ) |
835 | |
836 | # Make sure Qt does not inject evil macros like 'signals' and 'slots'. |
837 | @@ -180,11 +185,14 @@ |
838 | trust-store |
839 | |
840 | dbus-cpp |
841 | + xdg |
842 | |
843 | ${Boost_LIBRARIES} |
844 | ${DBUS_LIBRARIES} |
845 | ${GFLAGS_LDFLAGS} |
846 | ${GLOG_LDFLAGS} |
847 | + ${GLIB_LDFLAGS} |
848 | + ${GOBJECT_LDFLAGS} |
849 | ${LIBAPPARMOR_LDFLAGS} |
850 | ${MIR_CLIENT_LDFLAGS} |
851 | ${PROCESS_CPP_LDFLAGS} |
852 | |
853 | === modified file 'src/core/trust/impl/sqlite3/store.cpp' |
854 | --- src/core/trust/impl/sqlite3/store.cpp 2014-11-14 12:17:24 +0000 |
855 | +++ src/core/trust/impl/sqlite3/store.cpp 2015-11-15 21:10:18 +0000 |
856 | @@ -21,6 +21,7 @@ |
857 | #include <core/posix/this_process.h> |
858 | |
859 | #include <sqlite3.h> |
860 | +#include <xdg.h> |
861 | |
862 | #include <cstring> |
863 | #include <iostream> |
864 | @@ -32,16 +33,9 @@ |
865 | |
866 | namespace core |
867 | { |
868 | -std::string home() |
869 | -{ |
870 | - return core::posix::this_process::env::get_or_throw("HOME"); |
871 | -} |
872 | - |
873 | std::string runtime_persistent_data_dir() |
874 | { |
875 | - return core::posix::this_process::env::get( |
876 | - "XDG_DATA_HOME", |
877 | - home() + "/.local/share"); |
878 | + return xdg::data().home().string(); |
879 | } |
880 | |
881 | struct Directory |
882 | |
883 | === modified file 'src/core/trust/mir/agent.cpp' |
884 | --- src/core/trust/mir/agent.cpp 2015-08-31 13:16:20 +0000 |
885 | +++ src/core/trust/mir/agent.cpp 2015-11-15 21:10:18 +0000 |
886 | @@ -134,21 +134,7 @@ |
887 | { |
888 | static auto child_setup = []() {}; |
889 | |
890 | - // We translate to human readable strings here, and do it a non-translateable way first |
891 | - // We post-process the application id and try to extract the unversioned package name. |
892 | - // Please see https://wiki.ubuntu.com/AppStore/Interfaces/ApplicationId. |
893 | - static const std::regex regex_full_app_id{"(.*)_(.*)_(.*)"}; |
894 | - static const std::regex regex_short_app_id{"(.*)_(.*)"}; |
895 | - static constexpr std::size_t index_app{2}; |
896 | - |
897 | auto app_name = args.application_id; |
898 | - |
899 | - std::smatch match; |
900 | - if (std::regex_match(app_name, match, regex_full_app_id)) |
901 | - app_name = std::string{match[index_app]}; |
902 | - else if (std::regex_match(app_name, match, regex_short_app_id)) |
903 | - app_name = std::string{match[index_app]}; |
904 | - |
905 | auto description = (boost::format(i18n::tr(args.description, i18n::service_text_domain())) % app_name).str(); |
906 | |
907 | std::vector<std::string> argv |
908 | @@ -219,17 +205,8 @@ |
909 | }; |
910 | } |
911 | |
912 | -mir::Agent::Agent( |
913 | - // VTable object providing access to Mir's trusted prompting functionality. |
914 | - const mir::ConnectionVirtualTable::Ptr& connection_vtable, |
915 | - // Exec helper for starting up prompt provider child processes with the correct setup |
916 | - // of command line arguments and environment variables. |
917 | - const mir::PromptProviderHelper::Ptr& exec_helper, |
918 | - // A translator function for mapping child process exit states to trust::Request answers. |
919 | - const std::function<core::trust::Request::Answer(const core::posix::wait::Result&)>& translator) |
920 | - : connection_vtable(connection_vtable), |
921 | - exec_helper(exec_helper), |
922 | - translator(translator) |
923 | +mir::Agent::Agent(const mir::Agent::Configuration& config) |
924 | + : config(config) |
925 | { |
926 | } |
927 | |
928 | @@ -260,7 +237,7 @@ |
929 | } scope |
930 | { |
931 | // We setup the prompt session and wire up to our own internal callback helper. |
932 | - connection_vtable->create_prompt_session_sync( |
933 | + config.connection_vtable->create_prompt_session_sync( |
934 | parameters.application.pid, |
935 | Agent::on_trust_session_changed_state, |
936 | &cb_context) |
937 | @@ -273,16 +250,16 @@ |
938 | mir::PromptProviderHelper::InvocationArguments args |
939 | { |
940 | fd, |
941 | - parameters.application.id, |
942 | + config.app_name_resolver->resolve(parameters.application.id), |
943 | parameters.description |
944 | }; |
945 | |
946 | // Ask the helper to fire up the prompt provider. |
947 | - cb_context.prompt_provider_process = exec_helper->exec_prompt_provider_with_arguments(args); |
948 | + cb_context.prompt_provider_process = config.exec_helper->exec_prompt_provider_with_arguments(args); |
949 | // And subsequently wait for it to finish. |
950 | auto result = cb_context.prompt_provider_process.wait_for(core::posix::wait::Flags::untraced); |
951 | |
952 | - return translator(result); |
953 | + return config.translator(result); |
954 | } |
955 | |
956 | bool mir::operator==(const mir::PromptProviderHelper::InvocationArguments& lhs, const mir::PromptProviderHelper::InvocationArguments& rhs) |
957 | @@ -291,6 +268,7 @@ |
958 | } |
959 | |
960 | #include "config.h" |
961 | +#include "click_desktop_entry_app_name_resolver.h" |
962 | |
963 | MirConnection* mir::connect(const std::string& endpoint, const std::string& name) |
964 | { |
965 | @@ -318,13 +296,8 @@ |
966 | } |
967 | }; |
968 | |
969 | - return mir::Agent::Ptr |
970 | - { |
971 | - new mir::Agent |
972 | - { |
973 | - cvt, |
974 | - pph, |
975 | - mir::Agent::translator_only_accepting_exit_status_success() |
976 | - } |
977 | - }; |
978 | + mir::AppNameResolver::Ptr anr{new mir::ClickDesktopEntryAppNameResolver{}}; |
979 | + |
980 | + mir::Agent::Configuration config{cvt, pph, mir::Agent::translator_only_accepting_exit_status_success(), anr}; |
981 | + return mir::Agent::Ptr{new mir::Agent{config}}; |
982 | } |
983 | |
984 | === modified file 'src/core/trust/mir/agent.h' |
985 | --- src/core/trust/mir/agent.h 2014-10-07 19:27:18 +0000 |
986 | +++ src/core/trust/mir/agent.h 2015-11-15 21:10:18 +0000 |
987 | @@ -146,6 +146,17 @@ |
988 | CreationArguments creation_arguments; |
989 | }; |
990 | |
991 | +// An AppNameResolver resolves an application id to a localized application name. |
992 | +struct AppNameResolver |
993 | +{ |
994 | + // Save us some typing. |
995 | + typedef std::shared_ptr<AppNameResolver> Ptr; |
996 | + |
997 | + virtual ~AppNameResolver() = default; |
998 | + // resolve maps app_id to a localized application name. |
999 | + virtual std::string resolve(const std::string& app_id) = 0; |
1000 | +}; |
1001 | + |
1002 | // Implements the trust::Agent interface and dispatches calls to a helper |
1003 | // prompt provider, tying it together with the requesting service and app |
1004 | // by leveraging Mir's trusted session/prompting support. |
1005 | @@ -154,6 +165,20 @@ |
1006 | // Convenience typedef |
1007 | typedef std::shared_ptr<Agent> Ptr; |
1008 | |
1009 | + // A Configuration bundles creation-time configuration options. |
1010 | + struct Configuration |
1011 | + { |
1012 | + // VTable object providing access to Mir's trusted prompting functionality. |
1013 | + ConnectionVirtualTable::Ptr connection_vtable; |
1014 | + // Exec helper for starting up prompt provider child processes with the correct setup |
1015 | + // of command line arguments and environment variables. |
1016 | + PromptProviderHelper::Ptr exec_helper; |
1017 | + // A translator function for mapping child process exit states to trust::Request answers. |
1018 | + std::function<core::trust::Request::Answer(const core::posix::wait::Result&)> translator; |
1019 | + // AppNameResolver used by the agent to map incoming request app ids to application names. |
1020 | + AppNameResolver::Ptr app_name_resolver; |
1021 | + }; |
1022 | + |
1023 | // Helper struct for injecting state into on_trust_changed_state_state callbacks. |
1024 | // Used in prompt_user_for_request to wait for the trust session to be stopped. |
1025 | struct OnTrustSessionStateChangedCallbackContext |
1026 | @@ -177,26 +202,16 @@ |
1027 | // Throws std::logic_error if the process did not exit but was signaled. |
1028 | static std::function<core::trust::Request::Answer(const core::posix::wait::Result&)> translator_only_accepting_exit_status_success(); |
1029 | |
1030 | - // Creates a new MirAgent instance with the given MirConnectionVirtualTable instance. |
1031 | - Agent(// VTable object providing access to Mir's trusted prompting functionality. |
1032 | - const ConnectionVirtualTable::Ptr& connection_vtable, |
1033 | - // Exec helper for starting up prompt provider child processes with the correct setup |
1034 | - // of command line arguments and environment variables. |
1035 | - const PromptProviderHelper::Ptr& exec_helper, |
1036 | - // A translator function for mapping child process exit states to trust::Request answers. |
1037 | - const std::function<core::trust::Request::Answer(const core::posix::wait::Result&)>& translator); |
1038 | + // Creates a new MirAgent instance with the given Configuration. |
1039 | + Agent(const Configuration& config); |
1040 | |
1041 | // From core::trust::Agent: |
1042 | // Throws a std::logic_error if anything unforeseen happens during execution, thus |
1043 | // indicating that no conclusive answer could be obtained from the user. |
1044 | core::trust::Request::Answer authenticate_request_with_parameters(const RequestParameters& parameters) override; |
1045 | |
1046 | - // The connection VTable used for creating trusted prompting sessions. |
1047 | - ConnectionVirtualTable::Ptr connection_vtable; |
1048 | - // Execution helper for firing up prompt provider executables. |
1049 | - PromptProviderHelper::Ptr exec_helper; |
1050 | - // Translator instance. |
1051 | - std::function<core::trust::Request::Answer(const core::posix::wait::Result&)> translator; |
1052 | + // The configured options. |
1053 | + Configuration config; |
1054 | }; |
1055 | |
1056 | CORE_TRUST_DLL_PUBLIC bool operator==(const PromptProviderHelper::InvocationArguments&, const PromptProviderHelper::InvocationArguments&); |
1057 | |
1058 | === added file 'src/core/trust/mir/click_desktop_entry_app_name_resolver.cpp' |
1059 | --- src/core/trust/mir/click_desktop_entry_app_name_resolver.cpp 1970-01-01 00:00:00 +0000 |
1060 | +++ src/core/trust/mir/click_desktop_entry_app_name_resolver.cpp 2015-11-15 21:10:18 +0000 |
1061 | @@ -0,0 +1,106 @@ |
1062 | +/* |
1063 | + * Copyright © 2015 Canonical Ltd. |
1064 | + * |
1065 | + * This program is free software: you can redistribute it and/or modify it |
1066 | + * under the terms of the GNU Lesser General Public License version 3, |
1067 | + * as published by the Free Software Foundation. |
1068 | + * |
1069 | + * This program is distributed in the hope that it will be useful, |
1070 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1071 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1072 | + * GNU Lesser General Public License for more details. |
1073 | + * |
1074 | + * You should have received a copy of the GNU Lesser General Public License |
1075 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1076 | + * |
1077 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
1078 | + */ |
1079 | + |
1080 | +#include <core/trust/mir/click_desktop_entry_app_name_resolver.h> |
1081 | + |
1082 | +#include <glib.h> |
1083 | +#include <xdg.h> |
1084 | + |
1085 | +#include <core/posix/this_process.h> |
1086 | + |
1087 | +#include <boost/algorithm/string.hpp> |
1088 | +#include <boost/filesystem.hpp> |
1089 | +#include <boost/format.hpp> |
1090 | + |
1091 | +#include <memory> |
1092 | +#include <regex> |
1093 | +#include <string> |
1094 | +#include <stdexcept> |
1095 | +#include <vector> |
1096 | + |
1097 | +namespace env = core::posix::this_process::env; |
1098 | +namespace fs = boost::filesystem; |
1099 | +namespace mir = core::trust::mir; |
1100 | + |
1101 | +namespace |
1102 | +{ |
1103 | +boost::filesystem::path resolve_desktop_entry_or_throw(const std::string& app_id) |
1104 | +{ |
1105 | + boost::format pattern("%1%/applications/%2%.desktop"); |
1106 | + fs::path p{(pattern % xdg::data().home().string() % app_id).str()}; |
1107 | + if (fs::is_regular_file(p)) |
1108 | + return p; |
1109 | + |
1110 | + fs::path applications{xdg::data().home() / "applications"}; |
1111 | + fs::directory_iterator it(applications), itE; |
1112 | + while (it != itE) |
1113 | + { |
1114 | + if (it->path().filename().string().find(app_id) == 0) |
1115 | + return it->path(); |
1116 | + ++it; |
1117 | + } |
1118 | + |
1119 | + for (auto dir : xdg::data().dirs()) |
1120 | + { |
1121 | + fs::path p{(pattern % dir.string() % app_id).str()}; |
1122 | + if (fs::is_regular_file(p)) |
1123 | + return p; |
1124 | + } |
1125 | + |
1126 | + throw std::runtime_error{"Could not resolve desktop entry for " + app_id}; |
1127 | +} |
1128 | + |
1129 | +// Wrap up a GError with an RAII approach, easing |
1130 | +// cleanup if we throw an exception. |
1131 | +struct Error |
1132 | +{ |
1133 | + ~Error() { clear(); } |
1134 | + void clear() { g_clear_error(&error); } |
1135 | + |
1136 | + GError* error = nullptr; |
1137 | +}; |
1138 | + |
1139 | +std::string name_from_desktop_entry_or_throw(const fs::path& fn) |
1140 | +{ |
1141 | + Error g; |
1142 | + std::shared_ptr<GKeyFile> key_file{g_key_file_new(), [](GKeyFile* file) { if (file) g_key_file_free(file); }}; |
1143 | + |
1144 | + if (not g_key_file_load_from_file(key_file.get(), fn.string().c_str(), G_KEY_FILE_NONE, &g.error)) throw std::runtime_error |
1145 | + { |
1146 | + "Failed to load desktop entry [" + std::string(g.error->message) + "]" |
1147 | + }; |
1148 | + |
1149 | + auto app_name = g_key_file_get_locale_string(key_file.get(), G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, nullptr, &g.error); |
1150 | + |
1151 | + if (g.error) throw std::runtime_error |
1152 | + { |
1153 | + "Failed to query localized name [" + std::string(g.error->message) + "]" |
1154 | + }; |
1155 | + |
1156 | + return app_name; |
1157 | +} |
1158 | +} |
1159 | + |
1160 | +mir::ClickDesktopEntryAppNameResolver::ClickDesktopEntryAppNameResolver() |
1161 | +{ |
1162 | +} |
1163 | + |
1164 | +std::string mir::ClickDesktopEntryAppNameResolver::resolve(const std::string& app_id) |
1165 | +{ |
1166 | + return name_from_desktop_entry_or_throw(resolve_desktop_entry_or_throw(app_id)); |
1167 | +} |
1168 | |
1169 | === added file 'src/core/trust/mir/click_desktop_entry_app_name_resolver.h' |
1170 | --- src/core/trust/mir/click_desktop_entry_app_name_resolver.h 1970-01-01 00:00:00 +0000 |
1171 | +++ src/core/trust/mir/click_desktop_entry_app_name_resolver.h 2015-11-15 21:10:18 +0000 |
1172 | @@ -0,0 +1,49 @@ |
1173 | +/* |
1174 | + * Copyright © 2015 Canonical Ltd. |
1175 | + * |
1176 | + * This program is free software: you can redistribute it and/or modify it |
1177 | + * under the terms of the GNU Lesser General Public License version 3, |
1178 | + * as published by the Free Software Foundation. |
1179 | + * |
1180 | + * This program is distributed in the hope that it will be useful, |
1181 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1182 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1183 | + * GNU Lesser General Public License for more details. |
1184 | + * |
1185 | + * You should have received a copy of the GNU Lesser General Public License |
1186 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1187 | + * |
1188 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
1189 | + */ |
1190 | + |
1191 | +#ifndef CORE_TRUST_MIR_CLICK_DESKTOP_ENTRY_APP_NAME_RESOLVER_H_ |
1192 | +#define CORE_TRUST_MIR_CLICK_DESKTOP_ENTRY_APP_NAME_RESOLVER_H_ |
1193 | + |
1194 | +#include <core/trust/mir/agent.h> |
1195 | + |
1196 | +namespace core |
1197 | +{ |
1198 | +namespace trust |
1199 | +{ |
1200 | +namespace mir |
1201 | +{ |
1202 | +// A ClickDesktopEntryAppNameResolver queries the click database of installed |
1203 | +// packages to resolve an app's installation folder in the local filesystem. |
1204 | +// The directory is searched for a .desktop file, that is then loaded and queried |
1205 | +// for the app's localized name. |
1206 | +class CORE_TRUST_DLL_PUBLIC ClickDesktopEntryAppNameResolver : public AppNameResolver |
1207 | +{ |
1208 | +public: |
1209 | + // ClickDesktopEntryAppNameResolver sets up an instance with default dbs. |
1210 | + ClickDesktopEntryAppNameResolver(); |
1211 | + |
1212 | + // resolve queries the click index and an apps desktop file entry for |
1213 | + // obtaining a localized application name. Throws std::runtime_error in |
1214 | + // case of issues. |
1215 | + std::string resolve(const std::string& app_id) override; |
1216 | +}; |
1217 | +} |
1218 | +} |
1219 | +} |
1220 | + |
1221 | +#endif // CORE_TRUST_MIR_CLICK_DESKTOP_ENTRY_APP_NAME_RESOLVER_H_ |
1222 | |
1223 | === modified file 'tests/CMakeLists.txt' |
1224 | --- tests/CMakeLists.txt 2014-11-14 12:17:24 +0000 |
1225 | +++ tests/CMakeLists.txt 2015-11-15 21:10:18 +0000 |
1226 | @@ -242,20 +242,41 @@ |
1227 | mir_agent_test.cpp |
1228 | ) |
1229 | |
1230 | + add_executable( |
1231 | + click_desktop_entry_app_name_resolver_test |
1232 | + click_desktop_entry_app_name_resolver_test.cpp |
1233 | + ) |
1234 | + |
1235 | target_link_libraries( |
1236 | mir_agent_test |
1237 | |
1238 | trust-store |
1239 | - |
1240 | - gmock |
1241 | - |
1242 | - gtest |
1243 | - gtest_main |
1244 | - |
1245 | - ${PROCESS_CPP_LIBRARIES} |
1246 | - ) |
1247 | + xdg |
1248 | + |
1249 | + gmock |
1250 | + |
1251 | + gtest |
1252 | + gtest_main |
1253 | + |
1254 | + ${PROCESS_CPP_LIBRARIES} |
1255 | + ) |
1256 | + |
1257 | + target_link_libraries( |
1258 | + click_desktop_entry_app_name_resolver_test |
1259 | + |
1260 | + trust-store |
1261 | + |
1262 | + gmock |
1263 | + |
1264 | + gtest |
1265 | + gtest_main |
1266 | + |
1267 | + ${PROCESS_CPP_LIBRARIES} |
1268 | + ) |
1269 | + |
1270 | |
1271 | add_test(mir_agent_test ${CMAKE_CURRENT_BINARY_DIR}/mir_agent_test --gtest_filter=*-*requires_mir) |
1272 | + add_test(click_desktop_entry_app_name_resolver_test ${CMAKE_CURRENT_BINARY_DIR}/click_desktop_entry_app_name_resolver_test) |
1273 | |
1274 | install( |
1275 | TARGETS mir_agent_test |
1276 | |
1277 | === added file 'tests/click_desktop_entry_app_name_resolver_test.cpp' |
1278 | --- tests/click_desktop_entry_app_name_resolver_test.cpp 1970-01-01 00:00:00 +0000 |
1279 | +++ tests/click_desktop_entry_app_name_resolver_test.cpp 2015-11-15 21:10:18 +0000 |
1280 | @@ -0,0 +1,60 @@ |
1281 | +/* |
1282 | + * Copyright © 2013 Canonical Ltd. |
1283 | + * |
1284 | + * This program is free software: you can redistribute it and/or modify it |
1285 | + * under the terms of the GNU Lesser General Public License version 3, |
1286 | + * as published by the Free Software Foundation. |
1287 | + * |
1288 | + * This program is distributed in the hope that it will be useful, |
1289 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1290 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1291 | + * GNU Lesser General Public License for more details. |
1292 | + * |
1293 | + * You should have received a copy of the GNU Lesser General Public License |
1294 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1295 | + * |
1296 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
1297 | + */ |
1298 | + |
1299 | +#include <core/trust/mir/click_desktop_entry_app_name_resolver.h> |
1300 | +#include <core/posix/this_process.h> |
1301 | +#include "test_data.h" |
1302 | + |
1303 | +#include <gtest/gtest.h> |
1304 | + |
1305 | +namespace env = core::posix::this_process::env; |
1306 | +namespace mir = core::trust::mir; |
1307 | + |
1308 | +TEST(ClickDesktopEntryAppNameResolver, throws_for_invalid_app_id) |
1309 | +{ |
1310 | + mir::ClickDesktopEntryAppNameResolver resolver; |
1311 | + EXPECT_THROW(resolver.resolve(""), std::runtime_error); |
1312 | + EXPECT_THROW(resolver.resolve("something:not:right"), std::runtime_error); |
1313 | +} |
1314 | + |
1315 | +TEST(ClickDesktopEntryAppNameResolver, resolves_existing_desktop_entry_from_xdg_data_home) |
1316 | +{ |
1317 | + env::unset_or_throw("XDG_DATA_HOME"); |
1318 | + env::set_or_throw("XDG_DATA_HOME", core::trust::testing::current_source_dir + std::string("/share")); |
1319 | + mir::ClickDesktopEntryAppNameResolver resolver; |
1320 | + EXPECT_NO_THROW(resolver.resolve("valid.pkg_app_0.0.0")); |
1321 | +} |
1322 | + |
1323 | +TEST(ClickDesktopEntryAppNameResolver, robustly_resolves_existing_desktop_entry_from_xdg_data_home) |
1324 | +{ |
1325 | + env::unset_or_throw("XDG_DATA_HOME"); |
1326 | + env::set_or_throw("XDG_DATA_HOME", core::trust::testing::current_source_dir + std::string("/share")); |
1327 | + |
1328 | + mir::ClickDesktopEntryAppNameResolver resolver; |
1329 | + EXPECT_NO_THROW(resolver.resolve("valid.pkg_app")); |
1330 | +} |
1331 | + |
1332 | +TEST(ClickDesktopEntryAppNameResolver, resolves_existing_desktop_entry_from_xdg_data_dirs) |
1333 | +{ |
1334 | + env::unset_or_throw("XDG_DATA_HOME"); env::unset_or_throw("XDG_DATA_DIRS"); |
1335 | + env::set_or_throw("XDG_DATA_HOME", core::trust::testing::current_source_dir + std::string("/empty")); |
1336 | + env::set_or_throw("XDG_DATA_DIRS", core::trust::testing::current_source_dir + std::string("/share")); |
1337 | + |
1338 | + mir::ClickDesktopEntryAppNameResolver resolver; |
1339 | + resolver.resolve("valid.pkg_app_0.0.0"); |
1340 | +} |
1341 | |
1342 | === added directory 'tests/empty' |
1343 | === added directory 'tests/empty/applications' |
1344 | === modified file 'tests/mir_agent_test.cpp' |
1345 | --- tests/mir_agent_test.cpp 2014-10-07 19:27:18 +0000 |
1346 | +++ tests/mir_agent_test.cpp 2015-11-15 21:10:18 +0000 |
1347 | @@ -99,6 +99,11 @@ |
1348 | MOCK_METHOD1(translate, core::trust::Request::Answer(const core::posix::wait::Result&)); |
1349 | }; |
1350 | |
1351 | +struct MockAppNameResolver : public core::trust::mir::AppNameResolver |
1352 | +{ |
1353 | + MOCK_METHOD1(resolve, std::string(const std::string&)); |
1354 | +}; |
1355 | + |
1356 | std::shared_ptr<MockConnectionVirtualTable> a_mocked_connection_vtable() |
1357 | { |
1358 | return std::make_shared<testing::NiceMock<MockConnectionVirtualTable>>(); |
1359 | @@ -117,6 +122,11 @@ |
1360 | "/bin/false" |
1361 | }); |
1362 | } |
1363 | + |
1364 | +std::shared_ptr<MockAppNameResolver> a_mocked_app_name_resolver() |
1365 | +{ |
1366 | + return std::make_shared<MockAppNameResolver>(); |
1367 | +} |
1368 | } |
1369 | |
1370 | TEST(DefaultProcessStateTranslator, throws_for_signalled_process) |
1371 | @@ -209,6 +219,7 @@ |
1372 | auto prompt_session_vtable = a_mocked_prompt_session_vtable(); |
1373 | |
1374 | auto prompt_provider_exec_helper = a_mocked_prompt_provider_calling_bin_false(); |
1375 | + auto app_name_resolver = a_mocked_app_name_resolver(); |
1376 | |
1377 | ON_CALL(*connection_vtable, create_prompt_session_sync(_, _, _)) |
1378 | .WillByDefault(Return(prompt_session_vtable)); |
1379 | @@ -219,6 +230,9 @@ |
1380 | ON_CALL(*prompt_session_vtable, add_prompt_provider_sync(_)) |
1381 | .WillByDefault(Return(true)); |
1382 | |
1383 | + ON_CALL(*app_name_resolver, resolve(_)) |
1384 | + .WillByDefault(ReturnArg<0>()); |
1385 | + |
1386 | EXPECT_CALL(*connection_vtable, create_prompt_session_sync(app_pid, _, _)).Times(1); |
1387 | EXPECT_CALL(*prompt_session_vtable, new_fd_for_prompt_provider()).Times(1); |
1388 | |
1389 | @@ -228,21 +242,87 @@ |
1390 | |
1391 | core::trust::mir::Agent agent |
1392 | { |
1393 | - connection_vtable, |
1394 | - prompt_provider_exec_helper, |
1395 | - core::trust::mir::Agent::translator_only_accepting_exit_status_success() |
1396 | - }; |
1397 | - |
1398 | - EXPECT_EQ(core::trust::Request::Answer::denied, // /bin/false exits with failure. |
1399 | - agent.authenticate_request_with_parameters( |
1400 | - core::trust::Agent::RequestParameters |
1401 | - { |
1402 | - core::trust::Uid{::getuid()}, |
1403 | - app_pid, |
1404 | - app_id, |
1405 | - feature, |
1406 | - app_description |
1407 | - })); |
1408 | + core::trust::mir::Agent::Configuration |
1409 | + { |
1410 | + connection_vtable, |
1411 | + prompt_provider_exec_helper, |
1412 | + core::trust::mir::Agent::translator_only_accepting_exit_status_success(), |
1413 | + app_name_resolver |
1414 | + } |
1415 | + }; |
1416 | + |
1417 | + EXPECT_EQ(core::trust::Request::Answer::denied, // /bin/false exits with failure. |
1418 | + agent.authenticate_request_with_parameters( |
1419 | + core::trust::Agent::RequestParameters |
1420 | + { |
1421 | + core::trust::Uid{::getuid()}, |
1422 | + app_pid, |
1423 | + app_id, |
1424 | + feature, |
1425 | + app_description |
1426 | + })); |
1427 | +} |
1428 | + |
1429 | +TEST(MirAgent, calls_into_app_name_resolver_with_app_id) |
1430 | +{ |
1431 | + using namespace ::testing; |
1432 | + |
1433 | + const core::trust::Pid app_pid {21}; |
1434 | + const std::string app_id {"does.not.exist.application"}; |
1435 | + const std::string app_name{"MeMyselfAndI"}; |
1436 | + const core::trust::Feature feature{42}; |
1437 | + const std::string app_description {"This is just an extended description for %1%"}; |
1438 | + const int pre_authenticated_fd {42}; |
1439 | + |
1440 | + const core::trust::mir::PromptProviderHelper::InvocationArguments reference_invocation_args |
1441 | + { |
1442 | + pre_authenticated_fd, |
1443 | + app_name, |
1444 | + app_description |
1445 | + }; |
1446 | + |
1447 | + auto connection_vtable = a_mocked_connection_vtable(); |
1448 | + auto prompt_session_vtable = a_mocked_prompt_session_vtable(); |
1449 | + |
1450 | + auto prompt_provider_exec_helper = a_mocked_prompt_provider_calling_bin_false(); |
1451 | + auto app_name_resolver = a_mocked_app_name_resolver(); |
1452 | + |
1453 | + ON_CALL(*connection_vtable, create_prompt_session_sync(_, _, _)) |
1454 | + .WillByDefault(Return(prompt_session_vtable)); |
1455 | + |
1456 | + ON_CALL(*prompt_session_vtable, new_fd_for_prompt_provider()) |
1457 | + .WillByDefault(Return(pre_authenticated_fd)); |
1458 | + |
1459 | + ON_CALL(*prompt_session_vtable, add_prompt_provider_sync(_)) |
1460 | + .WillByDefault(Return(true)); |
1461 | + |
1462 | + EXPECT_CALL(*app_name_resolver, resolve(app_id)).Times(1).WillRepeatedly(Return(app_name)); |
1463 | + EXPECT_CALL(*prompt_provider_exec_helper, |
1464 | + exec_prompt_provider_with_arguments( |
1465 | + reference_invocation_args)).Times(1); |
1466 | + |
1467 | + core::trust::mir::Agent agent |
1468 | + { |
1469 | + core::trust::mir::Agent::Configuration |
1470 | + { |
1471 | + connection_vtable, |
1472 | + prompt_provider_exec_helper, |
1473 | + core::trust::mir::Agent::translator_only_accepting_exit_status_success(), |
1474 | + app_name_resolver |
1475 | + } |
1476 | + }; |
1477 | + |
1478 | + EXPECT_EQ(core::trust::Request::Answer::denied, // /bin/false exits with failure. |
1479 | + agent.authenticate_request_with_parameters( |
1480 | + core::trust::Agent::RequestParameters |
1481 | + { |
1482 | + core::trust::Uid{::getuid()}, |
1483 | + app_pid, |
1484 | + app_id, |
1485 | + feature, |
1486 | + app_description |
1487 | + })); |
1488 | + |
1489 | } |
1490 | |
1491 | TEST(MirAgent, sig_kills_prompt_provider_process_on_status_change) |
1492 | @@ -270,6 +350,8 @@ |
1493 | auto prompt_provider_helper = std::make_shared<MockPromptProviderHelper>( |
1494 | core::trust::mir::PromptProviderHelper::CreationArguments{"/bin/false"}); |
1495 | |
1496 | + auto app_name_resolver = a_mocked_app_name_resolver(); |
1497 | + |
1498 | void* prompt_session_state_callback_context{nullptr}; |
1499 | |
1500 | ON_CALL(*prompt_provider_helper, exec_prompt_provider_with_arguments(_)) |
1501 | @@ -289,6 +371,9 @@ |
1502 | Return( |
1503 | true)); |
1504 | |
1505 | + ON_CALL(*app_name_resolver, resolve(_)) |
1506 | + .WillByDefault(ReturnArg<0>()); |
1507 | + |
1508 | // An invocation results in a session being created. In addition, |
1509 | // we store pointers to callback and context provided by the implementation |
1510 | // for being able to later trigger the callback. |
1511 | @@ -300,9 +385,13 @@ |
1512 | |
1513 | core::trust::mir::Agent agent |
1514 | { |
1515 | - connection_vtable, |
1516 | - prompt_provider_helper, |
1517 | - core::trust::mir::Agent::translator_only_accepting_exit_status_success() |
1518 | + core::trust::mir::Agent::Configuration |
1519 | + { |
1520 | + connection_vtable, |
1521 | + prompt_provider_helper, |
1522 | + core::trust::mir::Agent::translator_only_accepting_exit_status_success(), |
1523 | + app_name_resolver |
1524 | + } |
1525 | }; |
1526 | |
1527 | std::thread asynchronously_stop_the_prompting_session |
1528 | @@ -368,6 +457,8 @@ |
1529 | #include <core/trust/mir/config.h> |
1530 | #include <core/trust/mir/prompt_main.h> |
1531 | |
1532 | +#include <xdg.h> |
1533 | + |
1534 | namespace |
1535 | { |
1536 | std::map<std::string, std::string> a_copy_of_the_env() |
1537 | @@ -383,15 +474,25 @@ |
1538 | std::string mir_socket() |
1539 | { |
1540 | // We either take the XDG_RUNTIME_DIR or fall back to /tmp if XDG_RUNTIME_DIR is not set. |
1541 | - std::string dir = core::posix::this_process::env::get("XDG_RUNTIME_DIR", "/tmp"); |
1542 | - return dir + "/mir_socket"; |
1543 | + try |
1544 | + { |
1545 | + return xdg::runtime().dir().string() + "/mir_socket"; |
1546 | + } catch(...) |
1547 | + { |
1548 | + return "/tmp/mir_socket"; |
1549 | + } |
1550 | } |
1551 | |
1552 | std::string trusted_mir_socket() |
1553 | { |
1554 | // We either take the XDG_RUNTIME_DIR or fall back to /tmp if XDG_RUNTIME_DIR is not set. |
1555 | - std::string dir = core::posix::this_process::env::get("XDG_RUNTIME_DIR", "/tmp"); |
1556 | - return dir + "/mir_socket_trusted"; |
1557 | + try |
1558 | + { |
1559 | + return xdg::runtime().dir().string() + "/mir_socket_trusted"; |
1560 | + } catch(...) |
1561 | + { |
1562 | + return "/tmp/mir_socket_trusted"; |
1563 | + } |
1564 | } |
1565 | } |
1566 | |
1567 | |
1568 | === added directory 'tests/share' |
1569 | === added directory 'tests/share/applications' |
1570 | === added file 'tests/share/applications/valid.pkg_app_0.0.0.desktop' |
1571 | --- tests/share/applications/valid.pkg_app_0.0.0.desktop 1970-01-01 00:00:00 +0000 |
1572 | +++ tests/share/applications/valid.pkg_app_0.0.0.desktop 2015-11-15 21:10:18 +0000 |
1573 | @@ -0,0 +1,55 @@ |
1574 | +[Desktop Entry] |
1575 | +Type=Application |
1576 | +Name=Camera |
1577 | +Name[am]=ካሜራ |
1578 | +Name[ar]=الكاميرا |
1579 | +Name[ast]=Cámara |
1580 | +Name[az]=Kamera |
1581 | +Name[bg]=Камера |
1582 | +Name[br]=Kamera |
1583 | +Name[bs]=Kamera |
1584 | +Name[ca]=Càmera |
1585 | +Name[ca@valencia]=Càmera |
1586 | +Name[cs]=Fotoaparát |
1587 | +Name[cy]=Camera |
1588 | +Name[da]=Kamera |
1589 | +Name[de]=Kamera |
1590 | +Name[el]=Κάμερα |
1591 | +Name[en_AU]=Camera |
1592 | +Name[en_GB]=Camera |
1593 | +Name[es]=Cámara |
1594 | +Name[eu]=Kamera |
1595 | +Name[fa]=دوربین |
1596 | +Name[fi]=Kamera |
1597 | +Name[fr]=Appareil photo |
1598 | +Name[gd]=Camara |
1599 | +Name[gl]=Cámara |
1600 | +Name[he]=מצלמה |
1601 | +Name[hi]=कैमरा |
1602 | +Name[hr]=Fotoaparat |
1603 | +Name[hu]=Kamera |
1604 | +Name[hy]=Կամերա |
1605 | +Name[is]=Myndavél |
1606 | +Name[it]=Fotocamera |
1607 | +Name[ja]=カメラ |
1608 | +Name[km]=ម៉ាស៊ីន<U+200B>ថ<U+200B>ត |
1609 | +Name[ko]=카메라 |
1610 | +Name[lo]=ກ້ອງ |
1611 | +Name[lv]=Fotokamera |
1612 | +Name[ml]=ക്യാമറ |
1613 | +Name[ms]=Kamera |
1614 | +Name[my]=ကင<U+103A>မရာ |
1615 | +Name[nb]=Kamera |
1616 | +Name[nl]=Camera |
1617 | +Name[pa]=ਕੈਮਰਾ |
1618 | +Name[pl]=Aparat |
1619 | +Name[pt]=Câmara |
1620 | +Name[pt_BR]=Câmera |
1621 | +Name[ro]=Aparat foto |
1622 | +Name[ru]=Камера |
1623 | +Name[sl]=Fotoaparat |
1624 | +Name[sr]=Камера |
1625 | +Name[sv]=Kamera |
1626 | +Name[ta]=புகைப்பட கருவி |
1627 | +Name[te]=కెమేరా |
1628 | +Name[tr]=Fotoğraf Makinesi |
1629 | |
1630 | === modified file 'tests/test_data.h.in' |
1631 | --- tests/test_data.h.in 2014-08-12 14:25:41 +0000 |
1632 | +++ tests/test_data.h.in 2015-11-15 21:10:18 +0000 |
1633 | @@ -25,6 +25,11 @@ |
1634 | { |
1635 | namespace testing |
1636 | { |
1637 | +static constexpr const char* current_source_dir |
1638 | +{ |
1639 | + "@CMAKE_CURRENT_SOURCE_DIR@" |
1640 | +}; |
1641 | + |
1642 | static constexpr const char* trust_prompt_executable_in_build_dir |
1643 | { |
1644 | "@CMAKE_BINARY_DIR@/src/trust-prompt" |
A couple of inline comments, I'm not convinced that this way of finding the desktop files is reliable.