Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / components / proximity_auth / wire_message.cc
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.
4
5 #include "components/proximity_auth/wire_message.h"
6
7 #include "base/base64.h"
8 #include "base/json/json_reader.h"
9 #include "base/logging.h"
10 #include "base/macros.h"
11 #include "base/values.h"
12
13 // The wire messages have a simple format:
14 // [ message version ] [ body length ] [ JSON body ]
15 //       1 byte            2 bytes      body length
16 // The JSON body contains two fields: an optional permit_id field and a required
17 // data field.
18
19 namespace proximity_auth {
20 namespace {
21
22 // The length of the message header, in bytes.
23 const size_t kHeaderLength = 3;
24
25 // The protocol version of the message format.
26 const int kExpectedMessageFormatVersion = 3;
27
28 const char kPayloadKey[] = "payload";
29 const char kPermitIdKey[] = "permit_id";
30
31 // Parses the |serialized_message|'s header. Returns |true| iff the message has
32 // a valid header, is complete, and is well-formed according to the header. Sets
33 // |is_incomplete_message| to true iff the message does not have enough data to
34 // parse the header, or if the message length encoded in the message header
35 // exceeds the size of the |serialized_message|.
36 bool ParseHeader(const std::string& serialized_message,
37                  bool* is_incomplete_message) {
38   *is_incomplete_message = false;
39   if (serialized_message.size() < kHeaderLength) {
40     *is_incomplete_message = true;
41     return false;
42   }
43
44   COMPILE_ASSERT(kHeaderLength > 2, header_length_too_small);
45   size_t version = serialized_message[0];
46   if (version != kExpectedMessageFormatVersion) {
47     VLOG(1) << "Error: Invalid message version. Got " << version
48             << ", expected " << kExpectedMessageFormatVersion;
49     return false;
50   }
51
52   size_t expected_body_length =
53       (static_cast<size_t>(serialized_message[1]) << 8) |
54       (static_cast<size_t>(serialized_message[2]) << 0);
55   size_t expected_message_length = kHeaderLength + expected_body_length;
56   if (serialized_message.size() < expected_message_length) {
57     *is_incomplete_message = true;
58     return false;
59   }
60   if (serialized_message.size() != expected_message_length) {
61     VLOG(1) << "Error: Invalid message length. Got "
62             << serialized_message.size() << ", expected "
63             << expected_message_length;
64     return false;
65   }
66
67   return true;
68 }
69
70 }  // namespace
71
72 WireMessage::~WireMessage() {
73 }
74
75 // static
76 scoped_ptr<WireMessage> WireMessage::Deserialize(
77     const std::string& serialized_message,
78     bool* is_incomplete_message) {
79   if (!ParseHeader(serialized_message, is_incomplete_message))
80     return scoped_ptr<WireMessage>();
81
82   scoped_ptr<base::Value> body_value(
83       base::JSONReader::Read(serialized_message.substr(kHeaderLength)));
84   if (!body_value || !body_value->IsType(base::Value::TYPE_DICTIONARY)) {
85     VLOG(1) << "Error: Unable to parse message as JSON.";
86     return scoped_ptr<WireMessage>();
87   }
88
89   base::DictionaryValue* body;
90   bool success = body_value->GetAsDictionary(&body);
91   DCHECK(success);
92
93   // The permit ID is optional. In the Easy Unlock protocol, only the first
94   // message includes this field.
95   std::string permit_id;
96   body->GetString(kPermitIdKey, &permit_id);
97
98   std::string payload_base64;
99   if (!body->GetString(kPayloadKey, &payload_base64) ||
100       payload_base64.empty()) {
101     VLOG(1) << "Error: Missing payload.";
102     return scoped_ptr<WireMessage>();
103   }
104
105   std::string payload;
106   if (!base::Base64Decode(payload_base64, &payload)) {
107     VLOG(1) << "Error: Invalid base64 encoding for payload.";
108     return scoped_ptr<WireMessage>();
109   }
110
111   return scoped_ptr<WireMessage>(new WireMessage(permit_id, payload));
112 }
113
114 std::string WireMessage::Serialize() const {
115   // TODO(isherman): Implement.
116   return "This method is not yet implemented.";
117 }
118
119 WireMessage::WireMessage(const std::string& permit_id,
120                          const std::string& payload)
121     : permit_id_(permit_id), payload_(payload) {
122 }
123
124 }  // namespace proximity_auth