19
19
20
20
namespace ccf ::js
21
21
{
22
+ static constexpr auto default_js_registry_kv_prefix =
23
+ " public:custom_endpoints" ;
24
+
22
25
struct CustomJSEndpoint : public ccf ::endpoints::Endpoint
23
26
{};
24
27
25
- // By subclassing DynamicJSEndpointRegistry , an application gains the
28
+ // By subclassing BaseDynamicJSEndpointRegistry , an application gains the
26
29
// ability to execute custom JavaScript endpoints, and exposes the ability to
27
30
// install them via install_custom_endpoints(). The JavaScript code for these
28
31
// endpoints is stored in the internal KV store under a namespace configured
@@ -31,31 +34,14 @@ namespace ccf::js
31
34
// proposal in governance, and the payload format is currently identical,
32
35
// except the controlling logic resides in the application space.
33
36
//
34
- // Known limitations:
35
- //
36
- // No auditability yet, COSE Sign1 auth is recommended, but the signature is
37
- // not stored.
38
- // No support for historical endpoints yet.
39
- // No support for import from external modules.
40
- //
41
37
// Additional functionality compared to set_js_app:
42
- //
43
- // The KV namespace can be private, to keep the application confidential if
38
+ // - The KV namespace can be private, to keep the application confidential if
44
39
// desired.
45
- class DynamicJSEndpointRegistry : public ccf ::UserEndpointRegistry
40
+ class BaseDynamicJSEndpointRegistry : public ccf ::UserEndpointRegistry
46
41
{
47
42
private:
48
43
std::shared_ptr<ccf::js::AbstractInterpreterCache> interpreter_cache =
49
44
nullptr ;
50
- std::string modules_map;
51
- std::string metadata_map;
52
- std::string interpreter_flush_map;
53
- std::string modules_quickjs_version_map;
54
- std::string modules_quickjs_bytecode_map;
55
- std::string runtime_options_map;
56
- std::string recent_actions_map;
57
- std::string audit_input_map;
58
- std::string audit_info_map;
59
45
60
46
ccf::js::NamespaceRestriction namespace_restriction;
61
47
@@ -75,10 +61,18 @@ namespace ccf::js
75
61
ccf::endpoints::CommandEndpointContext& endpoint_ctx,
76
62
const ccf::TxID& tx_id);
77
63
64
+ protected:
65
+ std::string modules_map;
66
+ std::string metadata_map;
67
+ std::string interpreter_flush_map;
68
+ std::string modules_quickjs_version_map;
69
+ std::string modules_quickjs_bytecode_map;
70
+ std::string runtime_options_map;
71
+
78
72
public:
79
- DynamicJSEndpointRegistry (
73
+ BaseDynamicJSEndpointRegistry (
80
74
ccf::AbstractNodeContext& context,
81
- const std::string& kv_prefix = " public:custom_endpoints " );
75
+ const std::string& kv_prefix = default_js_registry_kv_prefix );
82
76
83
77
/* *
84
78
* Call this to populate the KV with JS endpoint definitions, so they can
@@ -133,29 +127,6 @@ namespace ccf::js
133
127
*/
134
128
ccf::ApiResult get_js_runtime_options_v1 (
135
129
ccf::JSRuntimeOptions& options, ccf::kv::ReadOnlyTx& tx);
136
-
137
- /* *
138
- * Record action details by storing them in KV maps using a common format,
139
- * for the purposes of offline audit using the ledger.
140
- */
141
- ccf::ApiResult record_action_for_audit_v1 (
142
- ccf::kv::Tx& tx,
143
- ccf::ActionFormat format,
144
- const std::string& user_id,
145
- const std::string& action_name,
146
- const std::vector<uint8_t >& action_body);
147
-
148
- /* *
149
- * Check an action is not being replayed, by looking it up
150
- * in the history of recent actions. To place an upper bound on the history
151
- * size, an authenticated timestamp (@p created_at) is required.
152
- */
153
- ccf::ApiResult check_action_not_replayed_v1 (
154
- ccf::kv::Tx& tx,
155
- uint64_t created_at,
156
- const std::span<const uint8_t > action,
157
- ccf::InvalidArgsReason& reason);
158
-
159
130
// / \defgroup Overrides for base EndpointRegistry functions, looking up JS
160
131
// / endpoints before delegating to base implementation.
161
132
// /@{
@@ -172,6 +143,9 @@ namespace ccf::js
172
143
const ccf::TxID& tx_id) override ;
173
144
174
145
void build_api (nlohmann::json& document, ccf::kv::ReadOnlyTx& tx) override ;
146
+
147
+ std::set<RESTVerb> get_allowed_verbs (
148
+ ccf::kv::Tx&, const ccf::RpcContext& rpc_ctx) override ;
175
149
// /@}
176
150
177
151
virtual ccf::js::extensions::Extensions get_extensions (
@@ -180,4 +154,48 @@ namespace ccf::js
180
154
return {};
181
155
};
182
156
};
157
+
158
+ // Extends BaseDynamicJSEndpointRegistry with methods for making actions
159
+ // auditable and preventing replay. These should be used if apps are not
160
+ // deployed through governance, to ensure that app-modification is safely and
161
+ // clearly tracked in the ledger history
162
+ class DynamicJSEndpointRegistry : public BaseDynamicJSEndpointRegistry
163
+ {
164
+ protected:
165
+ std::string recent_actions_map;
166
+ std::string audit_input_map;
167
+ std::string audit_info_map;
168
+
169
+ public:
170
+ DynamicJSEndpointRegistry (
171
+ ccf::AbstractNodeContext& context,
172
+ const std::string& kv_prefix = default_js_registry_kv_prefix) :
173
+ BaseDynamicJSEndpointRegistry (context, kv_prefix),
174
+ recent_actions_map (fmt::format(" {}.recent_actions" , kv_prefix)),
175
+ audit_input_map (fmt::format(" {}.audit.input" , kv_prefix)),
176
+ audit_info_map (fmt::format(" {}.audit.info" , kv_prefix))
177
+ {}
178
+
179
+ /* *
180
+ * Record action details by storing them in KV maps using a common format,
181
+ * for the purposes of offline audit using the ledger.
182
+ */
183
+ ccf::ApiResult record_action_for_audit_v1 (
184
+ ccf::kv::Tx& tx,
185
+ ccf::ActionFormat format,
186
+ const std::string& user_id,
187
+ const std::string& action_name,
188
+ const std::vector<uint8_t >& action_body);
189
+
190
+ /* *
191
+ * Check an action is not being replayed, by looking it up
192
+ * in the history of recent actions. To place an upper bound on the history
193
+ * size, an authenticated timestamp (@p created_at) is required.
194
+ */
195
+ ccf::ApiResult check_action_not_replayed_v1 (
196
+ ccf::kv::Tx& tx,
197
+ uint64_t created_at,
198
+ const std::span<const uint8_t > action,
199
+ ccf::InvalidArgsReason& reason);
200
+ };
183
201
}
0 commit comments