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 19namespace proximity_auth { 20namespace { 21 22// The length of the message header, in bytes. 23const size_t kHeaderLength = 3; 24 25// The protocol version of the message format. 26const int kExpectedMessageFormatVersion = 3; 27 28const char kPayloadKey[] = "payload"; 29const 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|. 36bool 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 72WireMessage::~WireMessage() { 73} 74 75// static 76scoped_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 114std::string WireMessage::Serialize() const { 115 // TODO(isherman): Implement. 116 return "This method is not yet implemented."; 117} 118 119WireMessage::WireMessage(const std::string& permit_id, 120 const std::string& payload) 121 : permit_id_(permit_id), payload_(payload) { 122} 123 124} // namespace proximity_auth 125