| Index: components/proximity_auth/wire_message.cc
|
| diff --git a/components/proximity_auth/wire_message.cc b/components/proximity_auth/wire_message.cc
|
| index b6b57705c200b9bdf2924e6b8b6ff1529f9cd452..678014dd008b942d7b46eedeee898e65d1343990 100644
|
| --- a/components/proximity_auth/wire_message.cc
|
| +++ b/components/proximity_auth/wire_message.cc
|
| @@ -4,26 +4,117 @@
|
|
|
| #include "components/proximity_auth/wire_message.h"
|
|
|
| +#include "base/base64.h"
|
| +#include "base/json/json_reader.h"
|
| +#include "base/logging.h"
|
| +#include "base/macros.h"
|
| +#include "base/values.h"
|
| +
|
| +// The wire messages have a simple format:
|
| +// [ message version ] [ body length ] [ JSON body ]
|
| +// 1 byte 2 bytes body length
|
| +// The JSON body contains two fields: an optional permit_id field and a required
|
| +// data field.
|
| +
|
| namespace proximity_auth {
|
| +namespace {
|
|
|
| -WireMessage::~WireMessage() {
|
| +// The length of the message header, in bytes.
|
| +const size_t kHeaderLength = 3;
|
| +
|
| +// The protocol version of the message format.
|
| +const int kExpectedMessageFormatVersion = 3;
|
| +
|
| +const char kPayloadKey[] = "payload";
|
| +const char kPermitIdKey[] = "permit_id";
|
| +
|
| +// Parses the |serialized_message|'s header. Returns |true| iff the message has
|
| +// a valid header, is complete, and is well-formed according to the header. Sets
|
| +// |is_incomplete_message| to true iff the message does not have enough data to
|
| +// parse the header, or if the message length encoded in the message header
|
| +// exceeds the size of the |serialized_message|.
|
| +bool ParseHeader(const std::string& serialized_message,
|
| + bool* is_incomplete_message) {
|
| + *is_incomplete_message = false;
|
| + if (serialized_message.size() < kHeaderLength) {
|
| + *is_incomplete_message = true;
|
| + return false;
|
| + }
|
| +
|
| + COMPILE_ASSERT(kHeaderLength > 2, header_length_too_small);
|
| + size_t version = serialized_message[0];
|
| + if (version != kExpectedMessageFormatVersion) {
|
| + VLOG(1) << "Error: Invalid message version. Got " << version
|
| + << ", expected " << kExpectedMessageFormatVersion;
|
| + return false;
|
| + }
|
| +
|
| + size_t expected_body_length =
|
| + (static_cast<size_t>(serialized_message[1]) << 8) |
|
| + (static_cast<size_t>(serialized_message[2]) << 0);
|
| + size_t expected_message_length = kHeaderLength + expected_body_length;
|
| + if (serialized_message.size() < expected_message_length) {
|
| + *is_incomplete_message = true;
|
| + return false;
|
| + }
|
| + if (serialized_message.size() != expected_message_length) {
|
| + VLOG(1) << "Error: Invalid message length. Got "
|
| + << serialized_message.size() << ", expected "
|
| + << expected_message_length;
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| }
|
|
|
| -// static
|
| -bool WireMessage::IsCompleteMessage(const std::string& serialized_message) {
|
| - // TODO(isherman): Implement.
|
| - return false;
|
| +} // namespace
|
| +
|
| +WireMessage::~WireMessage() {
|
| }
|
|
|
| // static
|
| scoped_ptr<WireMessage> WireMessage::Deserialize(
|
| - const std::string& serialized_message) {
|
| - // TODO(isherman): Implement.
|
| - return scoped_ptr<WireMessage>();
|
| + const std::string& serialized_message,
|
| + bool* is_incomplete_message) {
|
| + if (!ParseHeader(serialized_message, is_incomplete_message))
|
| + return scoped_ptr<WireMessage>();
|
| +
|
| + scoped_ptr<base::Value> body_value(
|
| + base::JSONReader::Read(serialized_message.substr(kHeaderLength)));
|
| + if (!body_value || !body_value->IsType(base::Value::TYPE_DICTIONARY)) {
|
| + VLOG(1) << "Error: Unable to parse message as JSON.";
|
| + return scoped_ptr<WireMessage>();
|
| + }
|
| +
|
| + base::DictionaryValue* body;
|
| + bool success = body_value->GetAsDictionary(&body);
|
| + DCHECK(success);
|
| +
|
| + // The permit ID is optional. In the Easy Unlock protocol, only the first
|
| + // message includes this field.
|
| + std::string permit_id;
|
| + body->GetString(kPermitIdKey, &permit_id);
|
| +
|
| + std::string payload_base64;
|
| + if (!body->GetString(kPayloadKey, &payload_base64) ||
|
| + payload_base64.empty()) {
|
| + VLOG(1) << "Error: Missing payload.";
|
| + return scoped_ptr<WireMessage>();
|
| + }
|
| +
|
| + std::string payload;
|
| + if (!base::Base64Decode(payload_base64, &payload)) {
|
| + VLOG(1) << "Error: Invalid base64 encoding for payload.";
|
| + return scoped_ptr<WireMessage>();
|
| + }
|
| +
|
| + return scoped_ptr<WireMessage>(new WireMessage(permit_id, payload));
|
| }
|
|
|
| -WireMessage::WireMessage() {
|
| - // TODO(isherman): Implement.
|
| +WireMessage::WireMessage(const std::string& permit_id,
|
| + const std::string& payload)
|
| + : permit_id_(permit_id),
|
| + payload_(payload) {
|
| }
|
|
|
| } // namespace proximity_auth
|
|
|