1 //
2 // Copyright (C) 2021 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include "common/libs/confui/protocol.h"
17 
18 #include <sstream>
19 #include <vector>
20 
21 #include <android-base/strings.h>
22 
23 #include "common/libs/confui/packet.h"
24 #include "common/libs/confui/utils.h"
25 #include "common/libs/fs/shared_buf.h"
26 
27 namespace cuttlefish {
28 namespace confui {
29 namespace {
30 // default implementation of ToConfUiMessage
31 template <ConfUiCmd C>
ToConfUiMessage(const packet::ParsedPacket & message)32 std::unique_ptr<ConfUiMessage> ToConfUiMessage(
33     const packet::ParsedPacket& message) {
34   return std::make_unique<ConfUiGenericMessage<C>>(message.session_id_);
35 }
36 
37 // these are specialized, and defined below
38 template <>
39 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kCliAck>(
40     const packet::ParsedPacket& message);
41 template <>
42 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kStart>(
43     const packet::ParsedPacket& message);
44 template <>
45 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kUserInputEvent>(
46     const packet::ParsedPacket& message);
47 template <>
48 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kUserTouchEvent>(
49     const packet::ParsedPacket& message);
50 template <>
51 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kCliRespond>(
52     const packet::ParsedPacket& message);
53 
ToConfUiMessage(const packet::ParsedPacket & confui_packet)54 std::unique_ptr<ConfUiMessage> ToConfUiMessage(
55     const packet::ParsedPacket& confui_packet) {
56   const auto confui_cmd = ToCmd(confui_packet.type_);
57   switch (confui_cmd) {
58     // customized ConfUiMessage
59     case ConfUiCmd::kStart:
60       return ToConfUiMessage<ConfUiCmd::kStart>(confui_packet);
61     case ConfUiCmd::kCliAck:
62       return ToConfUiMessage<ConfUiCmd::kCliAck>(confui_packet);
63     case ConfUiCmd::kCliRespond:
64       return ToConfUiMessage<ConfUiCmd::kCliRespond>(confui_packet);
65     case ConfUiCmd::kUserInputEvent:
66       return ToConfUiMessage<ConfUiCmd::kUserInputEvent>(confui_packet);
67     case ConfUiCmd::kUserTouchEvent:
68       return ToConfUiMessage<ConfUiCmd::kUserTouchEvent>(confui_packet);
69       // default ConfUiMessage with session & type only
70     case ConfUiCmd::kAbort:
71       return ToConfUiMessage<ConfUiCmd::kAbort>(confui_packet);
72     case ConfUiCmd::kStop:
73       return ToConfUiMessage<ConfUiCmd::kStop>(confui_packet);
74       // these are errors
75     case ConfUiCmd::kUnknown:
76     default:
77       ConfUiLog(ERROR) << "ConfUiCmd value is not good for ToConfUiMessage: "
78                        << ToString(confui_cmd);
79       break;
80   }
81   return {nullptr};
82 }
83 }  // end of unnamed namespace
84 
ToString(const ConfUiMessage & msg)85 std::string ToString(const ConfUiMessage& msg) { return msg.ToString(); }
86 
RecvConfUiMsg(SharedFD fd)87 std::unique_ptr<ConfUiMessage> RecvConfUiMsg(SharedFD fd) {
88   if (!fd->IsOpen()) {
89     ConfUiLog(ERROR) << "file, socket, etc, is not open to read";
90     return {nullptr};
91   }
92   auto confui_packet_opt = packet::ReadPayload(fd);
93   if (!confui_packet_opt) {
94     ConfUiLog(ERROR) << "ReadPayload returns but with std::nullptr";
95     return {nullptr};
96   }
97 
98   auto confui_packet = confui_packet_opt.value();
99   return ToConfUiMessage(confui_packet);
100 }
101 
RecvConfUiMsg(const std::string & session_id,SharedFD fd)102 std::unique_ptr<ConfUiMessage> RecvConfUiMsg(const std::string& session_id,
103                                              SharedFD fd) {
104   auto conf_ui_msg = RecvConfUiMsg(fd);
105   if (!conf_ui_msg) {
106     return {nullptr};
107   }
108   auto recv_session_id = conf_ui_msg->GetSessionId();
109   if (session_id != recv_session_id) {
110     ConfUiLog(ERROR) << "Received Session ID (" << recv_session_id
111                      << ") is not the expected one (" << session_id << ")";
112     return {nullptr};
113   }
114   return conf_ui_msg;
115 }
116 
SendAbortCmd(SharedFD fd,const std::string & session_id)117 bool SendAbortCmd(SharedFD fd, const std::string& session_id) {
118   ConfUiGenericMessage<ConfUiCmd::kAbort> confui_msg{session_id};
119   return confui_msg.SendOver(fd);
120 }
121 
SendStopCmd(SharedFD fd,const std::string & session_id)122 bool SendStopCmd(SharedFD fd, const std::string& session_id) {
123   ConfUiGenericMessage<ConfUiCmd::kStop> confui_msg{session_id};
124   return confui_msg.SendOver(fd);
125 }
126 
SendAck(SharedFD fd,const std::string & session_id,const bool is_success,const std::string & status_message)127 bool SendAck(SharedFD fd, const std::string& session_id, const bool is_success,
128              const std::string& status_message) {
129   ConfUiAckMessage confui_msg{session_id, is_success, status_message};
130   return confui_msg.SendOver(fd);
131 }
132 
SendResponse(SharedFD fd,const std::string & session_id,const UserResponse::type & plain_selection,const std::vector<std::uint8_t> & signed_response,const std::vector<std::uint8_t> & message)133 bool SendResponse(SharedFD fd, const std::string& session_id,
134                   const UserResponse::type& plain_selection,
135                   const std::vector<std::uint8_t>& signed_response,
136                   const std::vector<std::uint8_t>& message) {
137   ConfUiCliResponseMessage confui_msg{session_id, plain_selection,
138                                       signed_response, message};
139   return confui_msg.SendOver(fd);
140 }
141 
SendStartCmd(SharedFD fd,const std::string & session_id,const std::string & prompt_text,const std::vector<std::uint8_t> & extra_data,const std::string & locale,const std::vector<teeui::UIOption> & ui_opts)142 bool SendStartCmd(SharedFD fd, const std::string& session_id,
143                   const std::string& prompt_text,
144                   const std::vector<std::uint8_t>& extra_data,
145                   const std::string& locale,
146                   const std::vector<teeui::UIOption>& ui_opts) {
147   ConfUiStartMessage confui_msg{session_id, prompt_text, extra_data, locale,
148                                 ui_opts};
149   return confui_msg.SendOver(fd);
150 }
151 
152 // this is only for deliverSecureInputEvent
SendUserSelection(SharedFD fd,const std::string & session_id,const UserResponse::type & confirm_cancel)153 bool SendUserSelection(SharedFD fd, const std::string& session_id,
154                        const UserResponse::type& confirm_cancel) {
155   ConfUiUserSelectionMessage confui_msg{session_id, confirm_cancel};
156   return confui_msg.SendOver(fd);
157 }
158 
159 // specialized ToConfUiMessage()
160 namespace {
161 template <>
ToConfUiMessage(const packet::ParsedPacket & message)162 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kCliAck>(
163     const packet::ParsedPacket& message) {
164   auto type = ToCmd(message.type_);
165   auto& contents = message.additional_info_;
166   if (type != ConfUiCmd::kCliAck) {
167     ConfUiLog(ERROR) << "Received cmd is not ack but " << ToString(type);
168     return {nullptr};
169   }
170 
171   if (contents.size() != 2) {
172     ConfUiLog(ERROR)
173         << "Ack message should only have pass/fail and a status message";
174     return {nullptr};
175   }
176 
177   const std::string success_str(contents[0].begin(), contents[0].end());
178   const bool is_success = (success_str == "success");
179   const std::string status_message(contents[1].begin(), contents[1].end());
180   return std::make_unique<ConfUiAckMessage>(message.session_id_, is_success,
181                                             status_message);
182 }
183 
184 template <>
ToConfUiMessage(const packet::ParsedPacket & message)185 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kStart>(
186     const packet::ParsedPacket& message) {
187   /*
188    * additional_info_[0]: prompt text
189    * additional_info_[1]: extra data
190    * additional_info_[2]: locale
191    * additional_info_[3]: UIOptions
192    *
193    */
194   if (message.additional_info_.size() < 3) {
195     ConfUiLog(ERROR) << "ConfUiMessage for kStart is ill-formatted: "
196                      << packet::ToString(message);
197     return {nullptr};
198   }
199   std::vector<teeui::UIOption> ui_opts;
200   bool has_ui_option = (message.additional_info_.size() == 4) &&
201                        !(message.additional_info_[3].empty());
202   if (has_ui_option) {
203     std::string ui_opts_string{message.additional_info_[3].begin(),
204                                message.additional_info_[3].end()};
205     auto tokens = android::base::Split(ui_opts_string, ",");
206     for (auto token : tokens) {
207       auto ui_opt_optional = ToUiOption(token);
208       if (!ui_opt_optional) {
209         ConfUiLog(ERROR) << "Wrong UiOption String : " << token;
210         return {nullptr};
211       }
212       ui_opts.emplace_back(ui_opt_optional.value());
213     }
214   }
215   auto sm = std::make_unique<ConfUiStartMessage>(
216       message.session_id_,
217       std::string(message.additional_info_[0].begin(),
218                   message.additional_info_[0].end()),
219       message.additional_info_[1],
220       std::string(message.additional_info_[2].begin(),
221                   message.additional_info_[2].end()),
222       ui_opts);
223   return sm;
224 }
225 
226 template <>
ToConfUiMessage(const packet::ParsedPacket & message)227 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kUserInputEvent>(
228     const packet::ParsedPacket& message) {
229   if (message.additional_info_.size() < 1) {
230     ConfUiLog(ERROR)
231         << "kUserInputEvent message should have at least one additional_info_";
232     return {nullptr};
233   }
234   auto response = std::string{message.additional_info_[0].begin(),
235                               message.additional_info_[0].end()};
236   return std::make_unique<ConfUiUserSelectionMessage>(message.session_id_,
237                                                       response);
238 }
239 
240 template <>
ToConfUiMessage(const packet::ParsedPacket & message)241 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kUserTouchEvent>(
242     const packet::ParsedPacket& message) {
243   if (message.additional_info_.size() < 2) {
244     ConfUiLog(ERROR)
245         << "kUserTouchEvent message should have at least two additional_info_";
246     return {nullptr};
247   }
248   auto x = std::string(message.additional_info_[0].begin(),
249                        message.additional_info_[0].end());
250   auto y = std::string(message.additional_info_[1].begin(),
251                        message.additional_info_[1].end());
252   return std::make_unique<ConfUiUserTouchMessage>(message.session_id_,
253                                                   std::stoi(x), std::stoi(y));
254 }
255 
256 template <>
ToConfUiMessage(const packet::ParsedPacket & message)257 std::unique_ptr<ConfUiMessage> ToConfUiMessage<ConfUiCmd::kCliRespond>(
258     const packet::ParsedPacket& message) {
259   if (message.additional_info_.size() < 3) {
260     ConfUiLog(ERROR)
261         << "kCliRespond message should have at least two additional info";
262     return {nullptr};
263   }
264   auto response = std::string{message.additional_info_[0].begin(),
265                               message.additional_info_[0].end()};
266   auto sign = message.additional_info_[1];
267   auto msg = message.additional_info_[2];
268   return std::make_unique<ConfUiCliResponseMessage>(message.session_id_,
269                                                     response, sign, msg);
270 }
271 }  // end of unnamed namespace
272 }  // end of namespace confui
273 }  // end of namespace cuttlefish
274