in libminifi/src/c2/protocols/RESTProtocol.cpp [58:143]
C2Payload RESTProtocol::parseJsonResponse(const C2Payload &payload, std::span<const std::byte> response) {
rapidjson::Document root;
try {
rapidjson::ParseResult ok = root.Parse(reinterpret_cast<const char*>(response.data()), response.size());
if (ok) {
std::string identifier;
for (auto key : {"operationid", "operationId", "identifier"}) {
if (root.HasMember(key)) {
if (!root[key].IsNull()) {
identifier = root[key].GetString();
}
break;
}
}
int size = 0;
for (auto key : {"requested_operations", "requestedOperations"}) {
if (root.HasMember(key)) {
if (!root[key].IsNull()) {
size = root[key].Size();
}
break;
}
}
// neither must be there. We don't want assign array yet and cause an assertion error
if (size == 0)
return {payload.getOperation(), state::UpdateState::READ_COMPLETE};
C2Payload new_payload(payload.getOperation(), state::UpdateState::NESTED);
if (!identifier.empty())
new_payload.setIdentifier(identifier);
auto array = root.HasMember("requested_operations") ? root["requested_operations"].GetArray() : root["requestedOperations"].GetArray();
for (const rapidjson::Value& request : array) {
auto newOp = magic_enum::enum_cast<Operation>(request["operation"].GetString(), magic_enum::case_insensitive).value_or(Operation::heartbeat);
C2Payload nested_payload(newOp, state::UpdateState::READ_COMPLETE);
C2ContentResponse new_command(newOp);
new_command.delay = 0;
new_command.required = true;
new_command.ttl = -1;
// set the identifier if one exists
for (auto key : {"operationid", "operationId", "identifier"}) {
if (request.HasMember(key)) {
if (request[key].IsNumber()) {
new_command.ident = std::to_string(request[key].GetInt64());
} else if (request[key].IsString()) {
new_command.ident = request[key].GetString();
} else {
throw Exception(SITE2SITE_EXCEPTION, "Invalid type for " + std::string{key});
}
nested_payload.setIdentifier(new_command.ident);
break;
}
}
if (request.HasMember("name")) {
new_command.name = request["name"].GetString();
} else if (request.HasMember("operand")) {
new_command.name = request["operand"].GetString();
}
for (auto key : {"content", "args"}) {
if (request.HasMember(key) && request[key].IsObject()) {
for (const auto &member : request[key].GetObject()) {
new_command.operation_arguments[member.name.GetString()] = parseAnnotatedValue(member.value);
}
break;
}
}
nested_payload.addContent(std::move(new_command));
new_payload.addPayload(std::move(nested_payload));
}
// we have a response for this request
return new_payload;
// }
}
} catch (...) {
}
return {payload.getOperation(), state::UpdateState::READ_COMPLETE};
}