xref: /openbmc/bmcweb/include/google/google_service_root.hpp (revision 3ccb3adb9a14783f6bef601506de9f8bcae22d51)
1 #pragma once
2 
3 #include "app.hpp"
4 #include "async_resp.hpp"
5 #include "dbus_utility.hpp"
6 #include "error_messages.hpp"
7 #include "utils/collection.hpp"
8 #include "utils/hex_utils.hpp"
9 #include "utils/json_utils.hpp"
10 
11 #include <nlohmann/json.hpp>
12 
13 #include <array>
14 #include <string_view>
15 #include <vector>
16 
17 namespace crow
18 {
19 namespace google_api
20 {
21 
22 inline void
23     handleGoogleV1Get(const crow::Request& /*req*/,
24                       const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
25 {
26     asyncResp->res.jsonValue["@odata.type"] =
27         "#GoogleServiceRoot.v1_0_0.GoogleServiceRoot";
28     asyncResp->res.jsonValue["@odata.id"] = "/google/v1";
29     asyncResp->res.jsonValue["Id"] = "Google Rest RootService";
30     asyncResp->res.jsonValue["Name"] = "Google Service Root";
31     asyncResp->res.jsonValue["Version"] = "1.0.0";
32     asyncResp->res.jsonValue["RootOfTrustCollection"]["@odata.id"] =
33         "/google/v1/RootOfTrustCollection";
34 }
35 
36 inline void handleRootOfTrustCollectionGet(
37     const crow::Request& /*req*/,
38     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
39 {
40     asyncResp->res.jsonValue["@odata.id"] = "/google/v1/RootOfTrustCollection";
41     asyncResp->res.jsonValue["@odata.type"] =
42         "#RootOfTrustCollection.RootOfTrustCollection";
43     const std::array<std::string_view, 1> interfaces{
44         "xyz.openbmc_project.Control.Hoth"};
45     redfish::collection_util::getCollectionMembers(
46         asyncResp, boost::urls::url("/google/v1/RootOfTrustCollection"),
47         interfaces, "/xyz/openbmc_project");
48 }
49 
50 // Helper struct to identify a resolved D-Bus object interface
51 struct ResolvedEntity
52 {
53     std::string id;
54     std::string service;
55     std::string object;
56     std::string interface;
57 };
58 
59 using ResolvedEntityHandler = std::function<void(
60     const std::string&, const std::shared_ptr<bmcweb::AsyncResp>&,
61     const ResolvedEntity&)>;
62 
63 inline void hothGetSubtreeCallback(
64     const std::string& command,
65     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
66     const std::string& rotId, const ResolvedEntityHandler& entityHandler,
67     const boost::system::error_code ec,
68     const dbus::utility::MapperGetSubTreeResponse& subtree)
69 {
70     if (ec)
71     {
72         redfish::messages::internalError(asyncResp->res);
73         return;
74     }
75     for (const auto& [path, services] : subtree)
76     {
77         sdbusplus::message::object_path objPath(path);
78         if (objPath.filename() != rotId || services.empty())
79         {
80             continue;
81         }
82 
83         ResolvedEntity resolvedEntity = {
84             .id = rotId,
85             .service = services[0].first,
86             .object = path,
87             .interface = "xyz.openbmc_project.Control.Hoth"};
88         entityHandler(command, asyncResp, resolvedEntity);
89         return;
90     }
91 
92     // Couldn't find an object with that name.  return an error
93     redfish::messages::resourceNotFound(asyncResp->res, "RootOfTrust", rotId);
94 }
95 
96 inline void resolveRoT(const std::string& command,
97                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
98                        const std::string& rotId,
99                        ResolvedEntityHandler&& entityHandler)
100 {
101 
102     constexpr std::array<std::string_view, 1> hothIfaces = {
103         "xyz.openbmc_project.Control.Hoth"};
104     crow::connections::systemBus->async_method_call(
105         [command, asyncResp, rotId,
106          entityHandler{std::forward<ResolvedEntityHandler>(entityHandler)}](
107             const boost::system::error_code ec,
108             const dbus::utility::MapperGetSubTreeResponse& subtree) {
109         hothGetSubtreeCallback(command, asyncResp, rotId, entityHandler, ec,
110                                subtree);
111         },
112         "xyz.openbmc_project.ObjectMapper",
113         "/xyz/openbmc_project/object_mapper",
114         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
115         "/xyz/openbmc_project",
116         /*depth=*/0, hothIfaces);
117 }
118 
119 inline void populateRootOfTrustEntity(
120     const std::string& /*unused*/,
121     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
122     const ResolvedEntity& resolvedEntity)
123 {
124     asyncResp->res.jsonValue["@odata.type"] = "#RootOfTrust.v1_0_0.RootOfTrust";
125     asyncResp->res.jsonValue["@odata.id"] =
126         "/google/v1/RootOfTrustCollection/" + resolvedEntity.id;
127 
128     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
129     asyncResp->res.jsonValue["Id"] = resolvedEntity.id;
130     // Need to fix this later to a stabler property.
131     asyncResp->res.jsonValue["Name"] = resolvedEntity.id;
132     asyncResp->res.jsonValue["Description"] = "Google Root Of Trust";
133     asyncResp->res.jsonValue["Actions"]["#RootOfTrust.SendCommand"]["target"] =
134         "/google/v1/RootOfTrustCollection/" + resolvedEntity.id +
135         "/Actions/RootOfTrust.SendCommand";
136 
137     asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
138         resolvedEntity.id;
139     asyncResp->res.jsonValue["Location"]["PartLocation"]["LocationType"] =
140         "Embedded";
141 }
142 
143 inline void
144     handleRootOfTrustGet(const crow::Request& /*req*/,
145                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
146                          const std::string& param)
147 {
148     std::string emptyCommand;
149     resolveRoT(emptyCommand, asyncResp, param, populateRootOfTrustEntity);
150 }
151 
152 inline void
153     invocationCallback(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
154                        const boost::system::error_code ec,
155                        const std::vector<uint8_t>& responseBytes)
156 {
157     if (ec)
158     {
159         BMCWEB_LOG_ERROR << "RootOfTrust.Actions.SendCommand failed: "
160                          << ec.message();
161         redfish::messages::internalError(asyncResp->res);
162         return;
163     }
164 
165     asyncResp->res.jsonValue["CommandResponse"] =
166         bytesToHexString(responseBytes);
167 }
168 
169 inline void
170     invokeRoTCommand(const std::string& command,
171                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
172                      const ResolvedEntity& resolvedEntity)
173 {
174     std::vector<uint8_t> bytes = hexStringToBytes(command);
175     if (bytes.empty())
176     {
177         BMCWEB_LOG_DEBUG << "Invalid command: " << command;
178         redfish::messages::actionParameterValueTypeError(command, "Command",
179                                                          "SendCommand");
180         return;
181     }
182 
183     crow::connections::systemBus->async_method_call(
184         [asyncResp{asyncResp}](const boost::system::error_code ec,
185                                const std::vector<uint8_t>& responseBytes) {
186         invocationCallback(asyncResp, ec, responseBytes);
187         },
188         resolvedEntity.service, resolvedEntity.object, resolvedEntity.interface,
189         "SendHostCommand", bytes);
190 }
191 
192 inline void handleRoTSendCommandPost(
193     const crow::Request& request,
194     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
195     const std::string& rotId)
196 {
197     std::string command;
198     if (!redfish::json_util::readJsonAction(request, asyncResp->res, "Command",
199                                             command))
200     {
201         BMCWEB_LOG_DEBUG << "Missing property Command.";
202         redfish::messages::actionParameterMissing(asyncResp->res, "SendCommand",
203                                                   "Command");
204         return;
205     }
206 
207     resolveRoT(command, asyncResp, rotId, invokeRoTCommand);
208 }
209 
210 inline void requestRoutes(App& app)
211 {
212     BMCWEB_ROUTE(app, "/google/v1/")
213         .methods(boost::beast::http::verb::get)(handleGoogleV1Get);
214 
215     BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection")
216         .privileges({{"ConfigureManager"}})
217         .methods(boost::beast::http::verb::get)(handleRootOfTrustCollectionGet);
218 
219     BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection/<str>")
220         .privileges({{"ConfigureManager"}})
221         .methods(boost::beast::http::verb::get)(handleRootOfTrustGet);
222 
223     BMCWEB_ROUTE(
224         app,
225         "/google/v1/RootOfTrustCollection/<str>/Actions/RootOfTrust.SendCommand")
226         .privileges({{"ConfigureManager"}})
227         .methods(boost::beast::http::verb::post)(handleRoTSendCommandPost);
228 }
229 
230 } // namespace google_api
231 } // namespace crow
232