1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/proximity_auth/messenger_impl.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h"
10 #include "base/values.h"
11 #include "components/proximity_auth/connection.h"
12 #include "components/proximity_auth/cryptauth/base64url.h"
13 #include "components/proximity_auth/logging/logging.h"
14 #include "components/proximity_auth/messenger_observer.h"
15 #include "components/proximity_auth/remote_status_update.h"
16 #include "components/proximity_auth/secure_context.h"
17 #include "components/proximity_auth/wire_message.h"
19 namespace proximity_auth
{
22 // The key names of JSON fields for messages sent between the devices.
23 const char kTypeKey
[] = "type";
24 const char kNameKey
[] = "name";
25 const char kDataKey
[] = "data";
26 const char kEncryptedDataKey
[] = "encrypted_data";
28 // The types of messages that can be sent and received.
29 const char kMessageTypeLocalEvent
[] = "event";
30 const char kMessageTypeRemoteStatusUpdate
[] = "status_update";
31 const char kMessageTypeDecryptRequest
[] = "decrypt_request";
32 const char kMessageTypeDecryptResponse
[] = "decrypt_response";
33 const char kMessageTypeUnlockRequest
[] = "unlock_request";
34 const char kMessageTypeUnlockResponse
[] = "unlock_response";
36 // The name for an unlock event originating from the local device.
37 const char kUnlockEventName
[] = "easy_unlock";
39 // Serializes the |value| to a JSON string and returns the result.
40 std::string
SerializeValueToJson(const base::Value
& value
) {
42 base::JSONWriter::Write(value
, &json
);
46 // Returns the message type represented by the |message|. This is a convenience
47 // wrapper that should only be called when the |message| is known to specify its
48 // message type, i.e. this should not be called for untrusted input.
49 std::string
GetMessageType(const base::DictionaryValue
& message
) {
51 message
.GetString(kTypeKey
, &type
);
57 MessengerImpl::MessengerImpl(scoped_ptr
<Connection
> connection
,
58 scoped_ptr
<SecureContext
> secure_context
)
59 : connection_(connection
.Pass()),
60 secure_context_(secure_context
.Pass()),
61 weak_ptr_factory_(this) {
62 DCHECK(connection_
->IsConnected());
63 connection_
->AddObserver(this);
66 MessengerImpl::~MessengerImpl() {
68 connection_
->RemoveObserver(this);
71 void MessengerImpl::AddObserver(MessengerObserver
* observer
) {
72 observers_
.AddObserver(observer
);
75 void MessengerImpl::RemoveObserver(MessengerObserver
* observer
) {
76 observers_
.RemoveObserver(observer
);
79 bool MessengerImpl::SupportsSignIn() const {
80 return (secure_context_
->GetProtocolVersion() ==
81 SecureContext::PROTOCOL_VERSION_THREE_ONE
);
84 void MessengerImpl::DispatchUnlockEvent() {
85 base::DictionaryValue message
;
86 message
.SetString(kTypeKey
, kMessageTypeLocalEvent
);
87 message
.SetString(kNameKey
, kUnlockEventName
);
88 queued_messages_
.push_back(PendingMessage(message
));
89 ProcessMessageQueue();
92 void MessengerImpl::RequestDecryption(const std::string
& challenge
) {
93 if (!SupportsSignIn()) {
94 PA_LOG(WARNING
) << "Dropping decryption request, as remote device "
95 << "does not support protocol v3.1.";
96 FOR_EACH_OBSERVER(MessengerObserver
, observers_
,
97 OnDecryptResponse(scoped_ptr
<std::string
>()));
101 // TODO(isherman): Compute the encrypted message data for realz.
102 const std::string encrypted_message_data
= challenge
;
103 std::string encrypted_message_data_base64
;
104 Base64UrlEncode(encrypted_message_data
, &encrypted_message_data_base64
);
106 base::DictionaryValue message
;
107 message
.SetString(kTypeKey
, kMessageTypeDecryptRequest
);
108 message
.SetString(kEncryptedDataKey
, encrypted_message_data_base64
);
109 queued_messages_
.push_back(PendingMessage(message
));
110 ProcessMessageQueue();
113 void MessengerImpl::RequestUnlock() {
114 if (!SupportsSignIn()) {
115 PA_LOG(WARNING
) << "Dropping unlock request, as remote device does not "
116 << "support protocol v3.1.";
117 FOR_EACH_OBSERVER(MessengerObserver
, observers_
, OnUnlockResponse(false));
121 base::DictionaryValue message
;
122 message
.SetString(kTypeKey
, kMessageTypeUnlockRequest
);
123 queued_messages_
.push_back(PendingMessage(message
));
124 ProcessMessageQueue();
127 MessengerImpl::PendingMessage::PendingMessage() {}
129 MessengerImpl::PendingMessage::PendingMessage(
130 const base::DictionaryValue
& message
)
131 : json_message(SerializeValueToJson(message
)),
132 type(GetMessageType(message
)) {}
134 MessengerImpl::PendingMessage::~PendingMessage() {}
136 void MessengerImpl::ProcessMessageQueue() {
137 if (pending_message_
|| queued_messages_
.empty() ||
138 connection_
->is_sending_message())
141 pending_message_
.reset(new PendingMessage(queued_messages_
.front()));
142 queued_messages_
.pop_front();
144 secure_context_
->Encode(pending_message_
->json_message
,
145 base::Bind(&MessengerImpl::OnMessageEncoded
,
146 weak_ptr_factory_
.GetWeakPtr()));
149 void MessengerImpl::OnMessageEncoded(const std::string
& encoded_message
) {
150 connection_
->SendMessage(make_scoped_ptr(new WireMessage(encoded_message
)));
153 void MessengerImpl::OnMessageDecoded(const std::string
& decoded_message
) {
154 // The decoded message should be a JSON string.
155 scoped_ptr
<base::Value
> message_value
=
156 base::JSONReader::Read(decoded_message
);
157 if (!message_value
|| !message_value
->IsType(base::Value::TYPE_DICTIONARY
)) {
158 PA_LOG(ERROR
) << "Unable to parse message as JSON:\n" << decoded_message
;
162 base::DictionaryValue
* message
;
163 bool success
= message_value
->GetAsDictionary(&message
);
167 if (!message
->GetString(kTypeKey
, &type
)) {
168 PA_LOG(ERROR
) << "Missing '" << kTypeKey
<< "' key in message:\n "
173 // Remote status updates can be received out of the blue.
174 if (type
== kMessageTypeRemoteStatusUpdate
) {
175 HandleRemoteStatusUpdateMessage(*message
);
179 // All other messages should only be received in response to a message that
180 // the messenger sent.
181 if (!pending_message_
) {
182 PA_LOG(WARNING
) << "Unexpected message received:\n" << decoded_message
;
186 std::string expected_type
;
187 if (pending_message_
->type
== kMessageTypeDecryptRequest
)
188 expected_type
= kMessageTypeDecryptResponse
;
189 else if (pending_message_
->type
== kMessageTypeUnlockRequest
)
190 expected_type
= kMessageTypeUnlockResponse
;
192 NOTREACHED(); // There are no other message types that expect a response.
194 if (type
!= expected_type
) {
195 PA_LOG(ERROR
) << "Unexpected '" << kTypeKey
<< "' value in message. "
196 << "Expected '" << expected_type
<< "' but received '" << type
201 if (type
== kMessageTypeDecryptResponse
)
202 HandleDecryptResponseMessage(*message
);
203 else if (type
== kMessageTypeUnlockResponse
)
204 HandleUnlockResponseMessage(*message
);
206 NOTREACHED(); // There are no other message types that expect a response.
208 pending_message_
.reset();
209 ProcessMessageQueue();
212 void MessengerImpl::HandleRemoteStatusUpdateMessage(
213 const base::DictionaryValue
& message
) {
214 scoped_ptr
<RemoteStatusUpdate
> status_update
=
215 RemoteStatusUpdate::Deserialize(message
);
216 if (!status_update
) {
217 PA_LOG(ERROR
) << "Unexpected remote status update: " << message
;
221 FOR_EACH_OBSERVER(MessengerObserver
, observers_
,
222 OnRemoteStatusUpdate(*status_update
));
225 void MessengerImpl::HandleDecryptResponseMessage(
226 const base::DictionaryValue
& message
) {
227 std::string base64_data
;
228 std::string decrypted_data
;
229 scoped_ptr
<std::string
> response
;
230 if (!message
.GetString(kDataKey
, &base64_data
) || base64_data
.empty()) {
231 PA_LOG(ERROR
) << "Decrypt response missing '" << kDataKey
<< "' value.";
232 } else if (!Base64UrlDecode(base64_data
, &decrypted_data
)) {
233 PA_LOG(ERROR
) << "Unable to base64-decode decrypt response.";
235 response
.reset(new std::string(decrypted_data
));
237 FOR_EACH_OBSERVER(MessengerObserver
, observers_
,
238 OnDecryptResponse(response
.Pass()));
241 void MessengerImpl::HandleUnlockResponseMessage(
242 const base::DictionaryValue
& message
) {
243 FOR_EACH_OBSERVER(MessengerObserver
, observers_
, OnUnlockResponse(true));
246 void MessengerImpl::OnConnectionStatusChanged(Connection
* connection
,
247 Connection::Status old_status
,
248 Connection::Status new_status
) {
249 DCHECK_EQ(connection
, connection_
.get());
250 if (new_status
== Connection::DISCONNECTED
) {
251 PA_LOG(INFO
) << "Secure channel disconnected...";
252 connection_
->RemoveObserver(this);
254 FOR_EACH_OBSERVER(MessengerObserver
, observers_
, OnDisconnected());
255 // TODO(isherman): Determine whether it's also necessary/appropriate to fire
256 // this notification from the destructor.
260 void MessengerImpl::OnMessageReceived(const Connection
& connection
,
261 const WireMessage
& wire_message
) {
262 secure_context_
->Decode(wire_message
.payload(),
263 base::Bind(&MessengerImpl::OnMessageDecoded
,
264 weak_ptr_factory_
.GetWeakPtr()));
267 void MessengerImpl::OnSendCompleted(const Connection
& connection
,
268 const WireMessage
& wire_message
,
270 if (!pending_message_
) {
271 PA_LOG(ERROR
) << "Unexpected message sent.";
275 // In the common case, wait for a response from the remote device.
276 // Don't wait if the message could not be sent, as there won't ever be a
277 // response in that case. Likewise, don't wait for a response to local
278 // event messages, as there is no response for such messages.
279 if (success
&& pending_message_
->type
!= kMessageTypeLocalEvent
)
282 // Notify observer of failure if sending the message fails.
283 // For local events, we don't expect a response, so on success, we
284 // notify observers right away.
285 if (pending_message_
->type
== kMessageTypeDecryptRequest
) {
286 FOR_EACH_OBSERVER(MessengerObserver
, observers_
,
287 OnDecryptResponse(scoped_ptr
<std::string
>()));
288 } else if (pending_message_
->type
== kMessageTypeUnlockRequest
) {
289 FOR_EACH_OBSERVER(MessengerObserver
, observers_
, OnUnlockResponse(false));
290 } else if (pending_message_
->type
== kMessageTypeLocalEvent
) {
291 FOR_EACH_OBSERVER(MessengerObserver
, observers_
,
292 OnUnlockEventSent(success
));
294 PA_LOG(ERROR
) << "Message of unknown type '" << pending_message_
->type
298 pending_message_
.reset();
299 ProcessMessageQueue();
302 } // namespace proximity_auth