blob: 2f4a241a431870c8661b8c0b875ed3e31d5a2b5b [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/ledger/bin/p2p_sync/impl/encoding.h"
#include "flatbuffers/flatbuffers.h"
#include "src/ledger/bin/p2p_sync/impl/message_generated.h"
#include "src/lib/fxl/strings/string_view.h"
namespace p2p_sync {
namespace {
bool IsValidCommitRequest(flatbuffers::Verifier& verifier,
const CommitRequest* request) {
return request && request->Verify(verifier) && request->commit_ids();
}
bool IsValidObjectRequest(flatbuffers::Verifier& verifier,
const ObjectRequest* request) {
return request && request->Verify(verifier) && request->object_ids();
}
bool IsValidWatchStartRequest(flatbuffers::Verifier& verifier,
const WatchStartRequest* request) {
return request && request->Verify(verifier);
}
bool IsValidWatchStopRequest(flatbuffers::Verifier& verifier,
const WatchStopRequest* request) {
return request && request->Verify(verifier);
}
bool IsValidRequest(flatbuffers::Verifier& verifier, const Request* request) {
if (!request || !request->Verify(verifier)) {
return false;
}
const NamespacePageId* namespace_page_id = request->namespace_page();
if (!namespace_page_id || !namespace_page_id->Verify(verifier)) {
return false;
}
if (!namespace_page_id->namespace_id() || !namespace_page_id->page_id()) {
return false;
}
switch (request->request_type()) {
case RequestMessage_NONE:
return false;
case RequestMessage_CommitRequest:
return IsValidCommitRequest(
verifier, static_cast<const CommitRequest*>(request->request()));
case RequestMessage_ObjectRequest:
return IsValidObjectRequest(
verifier, static_cast<const ObjectRequest*>(request->request()));
case RequestMessage_WatchStartRequest:
return IsValidWatchStartRequest(
verifier, static_cast<const WatchStartRequest*>(request->request()));
case RequestMessage_WatchStopRequest:
return IsValidWatchStopRequest(
verifier, static_cast<const WatchStopRequest*>(request->request()));
}
}
bool IsValidCommitResponse(flatbuffers::Verifier& verifier,
const CommitResponse* response) {
if (!response || !response->Verify(verifier)) {
return false;
}
if (!response->commits()) {
return false;
}
for (const Commit* commit : *response->commits()) {
if (!commit || !commit->Verify(verifier)) {
return false;
}
const CommitId* id = commit->id();
if (!id || !id->Verify(verifier) || !id->id()) {
return false;
}
const Data* data = commit->commit();
if (!data || !data->Verify(verifier) || !data->bytes()) {
return false;
}
}
return true;
}
bool IsValidObjectResponse(flatbuffers::Verifier& verifier,
const ObjectResponse* response) {
if (!response || !response->Verify(verifier)) {
return false;
}
if (!response->objects()) {
return false;
}
for (const Object* object : *response->objects()) {
if (!object || !object->Verify(verifier)) {
return false;
}
const ObjectId* id = object->id();
if (!id || !id->Verify(verifier) || !id->digest()) {
return false;
}
const Data* data = object->data();
// No data is a valid response: it means the object was not found.
if (data && (!data->Verify(verifier) || !data->bytes())) {
return false;
}
}
return true;
}
bool IsValidResponse(flatbuffers::Verifier& verifier,
const Response* response) {
if (!response) {
return false;
}
if (!response->Verify(verifier)) {
return false;
}
const NamespacePageId* namespace_page_id = response->namespace_page();
if (!namespace_page_id || !namespace_page_id->Verify(verifier)) {
return false;
}
if (!namespace_page_id->namespace_id() || !namespace_page_id->page_id()) {
return false;
}
switch (response->response_type()) {
case ResponseMessage_NONE:
// Response returned in case of unknown namespace or page.
return true;
case ResponseMessage_CommitResponse:
return IsValidCommitResponse(
verifier, static_cast<const CommitResponse*>(response->response()));
case ResponseMessage_ObjectResponse:
return IsValidObjectResponse(
verifier, static_cast<const ObjectResponse*>(response->response()));
}
}
} // namespace
const Message* ParseMessage(convert::ExtendedStringView data) {
flatbuffers::Verifier verifier(
reinterpret_cast<const unsigned char*>(data.data()), data.size());
if (!VerifyMessageBuffer(verifier)) {
return nullptr;
}
const Message* message = GetMessage(data.data());
if (!message || !message->Verify(verifier)) {
return nullptr;
}
switch (message->message_type()) {
case MessageUnion_NONE:
return nullptr;
case MessageUnion_Request:
if (!IsValidRequest(verifier,
static_cast<const Request*>(message->message()))) {
return nullptr;
}
break;
case MessageUnion_Response:
if (!IsValidResponse(verifier,
static_cast<const Response*>(message->message()))) {
return nullptr;
}
break;
}
return message;
}
} // namespace p2p_sync