Skip to content

Commit

Permalink
Audit in programmability sample (#6258)
Browse files Browse the repository at this point in the history
  • Loading branch information
achamayou authored Jun 17, 2024
1 parent b79c6a7 commit f60afbe
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 7 deletions.
40 changes: 40 additions & 0 deletions samples/apps/programmability/audit_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the Apache 2.0 License.

#pragma once
#include "ccf/ds/json.h"
#include "ccf/entity_id.h"

#include <vector>

namespace programmabilityapp
{
enum class AuditInputFormat
{
COSE = 0,
JSON = 1
};
DECLARE_JSON_ENUM(
AuditInputFormat,
{{AuditInputFormat::COSE, "COSE"}, {AuditInputFormat::JSON, "JSON"}});

enum class AuditInputContent
{
BUNDLE = 0,
OPTIONS = 1
};
DECLARE_JSON_ENUM(
AuditInputContent,
{{AuditInputContent::BUNDLE, "BUNDLE"},
{AuditInputContent::OPTIONS, "OPTIONS"}});

struct AuditInfo
{
AuditInputFormat format;
AuditInputContent content;
ccf::UserId user_id;
};

DECLARE_JSON_TYPE(AuditInfo)
DECLARE_JSON_REQUIRED_FIELDS(AuditInfo, format, content, user_id)
}
37 changes: 30 additions & 7 deletions samples/apps/programmability/programmability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache 2.0 License.

// CCF
#include "audit_info.h"
#include "ccf/app_interface.h"
#include "ccf/common_auth_policies.h"
#include "ccf/ds/hash.h"
Expand All @@ -19,7 +20,10 @@ using namespace nlohmann;
namespace programmabilityapp
{
using RecordsMap = kv::Map<std::string, std::vector<uint8_t>>;
using AuditInputValue = kv::Value<std::vector<uint8_t>>;
using AuditInfoValue = kv::Value<AuditInfo>;
static constexpr auto PRIVATE_RECORDS = "programmability.records";
static constexpr auto CUSTOM_ENDPOINTS_NAMESPACE = "public:custom_endpoints";

// This sample shows the features of DynamicJSEndpointRegistry. This sample
// adds a PUT /app/custom_endpoints, which calls install_custom_endpoints(),
Expand Down Expand Up @@ -49,26 +53,27 @@ namespace programmabilityapp
return std::nullopt;
}

std::span<const uint8_t> get_body(ccf::endpoints::EndpointContext& ctx)
std::pair<AuditInputFormat, std::span<const uint8_t>> get_body(
ccf::endpoints::EndpointContext& ctx)
{
if (
const auto* cose_ident =
ctx.try_get_caller<ccf::UserCOSESign1AuthnIdentity>())
{
return cose_ident->content;
return {AuditInputFormat::COSE, cose_ident->content};
}
else
{
return ctx.rpc_ctx->get_request_body();
return {AuditInputFormat::JSON, ctx.rpc_ctx->get_request_body()};
}
}

public:
ProgrammabilityHandlers(ccfapp::AbstractNodeContext& context) :
ccf::js::DynamicJSEndpointRegistry(
context,
"public:custom_endpoints" // Internal KV space will be under
// public:custom_endpoints.*
CUSTOM_ENDPOINTS_NAMESPACE // Internal KV space will be under
// public:custom_endpoints.*
)
{
openapi_info.title = "CCF Programmabilit App";
Expand Down Expand Up @@ -223,10 +228,19 @@ namespace programmabilityapp
}
// End of Authorization Check

const auto bundle = get_body(ctx);
const auto [format, bundle] = get_body(ctx);
const auto j = nlohmann::json::parse(bundle.begin(), bundle.end());
const auto parsed_bundle = j.get<ccf::js::Bundle>();

// Make operation auditable by writing user-supplied
// document to the ledger
auto audit_input = ctx.tx.template rw<AuditInputValue>(
fmt::format("{}.audit.input", CUSTOM_ENDPOINTS_NAMESPACE));
audit_input->put(ctx.rpc_ctx->get_request_body());
auto audit_info = ctx.tx.template rw<AuditInfoValue>(
fmt::format("{}.audit.info", CUSTOM_ENDPOINTS_NAMESPACE));
audit_info->put({format, AuditInputContent::BUNDLE, user_id.value()});

result = install_custom_endpoints_v1(ctx.tx, parsed_bundle);
if (result != ccf::ApiResult::OK)
{
Expand Down Expand Up @@ -377,7 +391,7 @@ namespace programmabilityapp
// - Convert current options to JSON
auto j_options = nlohmann::json(options);

const auto body = get_body(ctx);
const auto [format, body] = get_body(ctx);
// - Parse argument as JSON body
const auto arg_body = nlohmann::json::parse(body.begin(), body.end());

Expand All @@ -389,6 +403,15 @@ namespace programmabilityapp
// - Parse patched options from JSON
options = j_options.get<ccf::JSRuntimeOptions>();

// Make operation auditable by writing user-supplied
// document to the ledger
auto audit = ctx.tx.template rw<AuditInputValue>(
fmt::format("{}.audit.input", CUSTOM_ENDPOINTS_NAMESPACE));
audit->put(ctx.rpc_ctx->get_request_body());
auto audit_info = ctx.tx.template rw<AuditInfoValue>(
fmt::format("{}.audit.info", CUSTOM_ENDPOINTS_NAMESPACE));
audit_info->put({format, AuditInputContent::BUNDLE, user_id.value()});

result = set_js_runtime_options_v1(ctx.tx, options);
if (result != ccf::ApiResult::OK)
{
Expand Down

0 comments on commit f60afbe

Please sign in to comment.