mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
docs: hpp,dbal,cpp (4 files)
This commit is contained in:
@@ -21,33 +21,60 @@ inline Result<Workflow> update(InMemoryStore& store, const std::string& id, cons
|
||||
if (id.empty()) {
|
||||
return Error::validationError("Workflow ID cannot be empty");
|
||||
}
|
||||
|
||||
|
||||
auto it = store.workflows.find(id);
|
||||
if (it == store.workflows.end()) {
|
||||
return Error::notFound("Workflow not found: " + id);
|
||||
}
|
||||
|
||||
|
||||
Workflow& workflow = it->second;
|
||||
|
||||
std::string old_name = workflow.name;
|
||||
|
||||
if (input.name.has_value()) {
|
||||
if (input.name.value().empty() || input.name.value().length() > 100) {
|
||||
return Error::validationError("Name must be between 1 and 100 characters");
|
||||
if (!validation::isValidWorkflowName(input.name.value())) {
|
||||
return Error::validationError("Workflow name must be 1-255 characters");
|
||||
}
|
||||
auto name_it = store.workflow_names.find(input.name.value());
|
||||
if (name_it != store.workflow_names.end() && name_it->second != id) {
|
||||
return Error::conflict("Workflow name already exists: " + input.name.value());
|
||||
}
|
||||
store.workflow_names.erase(old_name);
|
||||
store.workflow_names[input.name.value()] = id;
|
||||
workflow.name = input.name.value();
|
||||
}
|
||||
|
||||
if (input.type.has_value()) {
|
||||
if (!validation::isValidWorkflowType(input.type.value())) {
|
||||
return Error::validationError("Invalid workflow type");
|
||||
}
|
||||
workflow.type = input.type.value();
|
||||
|
||||
if (input.description.has_value()) {
|
||||
workflow.description = input.description.value();
|
||||
}
|
||||
|
||||
if (input.description.has_value()) workflow.description = input.description.value();
|
||||
if (input.config.has_value()) workflow.config = input.config.value();
|
||||
if (input.is_active.has_value()) workflow.is_active = input.is_active.value();
|
||||
|
||||
|
||||
if (input.trigger.has_value()) {
|
||||
if (!validation::isValidWorkflowTrigger(input.trigger.value())) {
|
||||
return Error::validationError("Trigger must be one of manual, schedule, event, webhook");
|
||||
}
|
||||
workflow.trigger = input.trigger.value();
|
||||
}
|
||||
|
||||
if (input.trigger_config.has_value()) {
|
||||
workflow.trigger_config = input.trigger_config.value();
|
||||
}
|
||||
|
||||
if (input.steps.has_value()) {
|
||||
workflow.steps = input.steps.value();
|
||||
}
|
||||
|
||||
if (input.is_active.has_value()) {
|
||||
workflow.is_active = input.is_active.value();
|
||||
}
|
||||
|
||||
if (input.created_by.has_value()) {
|
||||
if (input.created_by.value().empty()) {
|
||||
return Error::validationError("created_by is required");
|
||||
}
|
||||
workflow.created_by = input.created_by.value();
|
||||
}
|
||||
|
||||
workflow.updated_at = std::chrono::system_clock::now();
|
||||
|
||||
return Result<Workflow>(workflow);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file secure_random.hpp
|
||||
* @brief Cryptographically secure random number generation
|
||||
* @details Header-only, uses /dev/urandom or OpenSSL
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <bcrypt.h>
|
||||
#pragma comment(lib, "bcrypt.lib")
|
||||
#else
|
||||
#include <fstream>
|
||||
#endif
|
||||
|
||||
namespace dbal::security {
|
||||
|
||||
/**
|
||||
* Generate cryptographically secure random bytes
|
||||
* @param buffer Destination buffer
|
||||
* @param size Number of bytes to generate
|
||||
* @throws std::runtime_error on failure
|
||||
*/
|
||||
inline void secure_random_bytes(unsigned char* buffer, size_t size) {
|
||||
#ifdef _WIN32
|
||||
NTSTATUS status = BCryptGenRandom(
|
||||
nullptr, buffer, static_cast<ULONG>(size), BCRYPT_USE_SYSTEM_PREFERRED_RNG
|
||||
);
|
||||
if (!BCRYPT_SUCCESS(status)) {
|
||||
throw std::runtime_error("BCryptGenRandom failed");
|
||||
}
|
||||
#else
|
||||
std::ifstream urandom("/dev/urandom", std::ios::binary);
|
||||
if (!urandom) {
|
||||
throw std::runtime_error("Failed to open /dev/urandom");
|
||||
}
|
||||
urandom.read(reinterpret_cast<char*>(buffer), static_cast<std::streamsize>(size));
|
||||
if (!urandom) {
|
||||
throw std::runtime_error("Failed to read from /dev/urandom");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a secure random hex string
|
||||
* @param bytes Number of random bytes (output will be 2x this length)
|
||||
* @return Hex-encoded random string
|
||||
*/
|
||||
inline std::string secure_random_hex(size_t bytes) {
|
||||
std::vector<unsigned char> buffer(bytes);
|
||||
secure_random_bytes(buffer.data(), bytes);
|
||||
|
||||
static const char hex_chars[] = "0123456789abcdef";
|
||||
std::string result;
|
||||
result.reserve(bytes * 2);
|
||||
|
||||
for (unsigned char b : buffer) {
|
||||
result += hex_chars[(b >> 4) & 0x0F];
|
||||
result += hex_chars[b & 0x0F];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a secure request ID (32 hex chars = 128 bits)
|
||||
*/
|
||||
inline std::string generate_request_id() {
|
||||
return secure_random_hex(16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a secure nonce (32 hex chars = 128 bits)
|
||||
*/
|
||||
inline std::string generate_nonce() {
|
||||
return secure_random_hex(16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a secure token (64 hex chars = 256 bits)
|
||||
*/
|
||||
inline std::string generate_token() {
|
||||
return secure_random_hex(32);
|
||||
}
|
||||
|
||||
} // namespace dbal::security
|
||||
|
||||
53
dbal/cpp/src/security/security.hpp
Normal file
53
dbal/cpp/src/security/security.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file security.hpp
|
||||
* @brief Fort Knox Security Suite - includes all security headers
|
||||
* @details Convenience header to include all security utilities
|
||||
*
|
||||
* Usage:
|
||||
* #include "security/security.hpp"
|
||||
*
|
||||
* // Apply headers
|
||||
* dbal::security::apply_security_headers(response.headers);
|
||||
*
|
||||
* // Rate limit
|
||||
* dbal::security::RateLimiter limiter(100, 200); // 100/sec, burst 200
|
||||
* if (!limiter.try_acquire(client_ip)) { return 429; }
|
||||
*
|
||||
* // Sign request
|
||||
* auto sig = dbal::security::hmac_sha256(key, key_len, payload);
|
||||
*
|
||||
* // Validate path
|
||||
* auto safe = dbal::security::validate_path("/data", user_input);
|
||||
*
|
||||
* // Validate input
|
||||
* if (!dbal::security::is_valid_identifier(table_name)) { reject(); }
|
||||
*
|
||||
* // Generate secure IDs
|
||||
* auto id = dbal::security::generate_request_id();
|
||||
*
|
||||
* // Prevent replay
|
||||
* dbal::security::NonceStore nonces;
|
||||
* if (!nonces.check_and_store(request.nonce)) { return 401; }
|
||||
*/
|
||||
|
||||
// Security headers for HTTP responses
|
||||
#include "secure_headers.hpp"
|
||||
|
||||
// HMAC signing and timing-safe comparison
|
||||
#include "hmac_signer.hpp"
|
||||
|
||||
// Path traversal prevention
|
||||
#include "path_validator.hpp"
|
||||
|
||||
// Token bucket rate limiting
|
||||
#include "rate_limiter.hpp"
|
||||
|
||||
// Input validation and sanitization
|
||||
#include "input_sanitizer.hpp"
|
||||
|
||||
// Nonce storage for replay prevention
|
||||
#include "nonce_store.hpp"
|
||||
|
||||
// Cryptographic random generation
|
||||
#include "secure_random.hpp"
|
||||
@@ -21,6 +21,7 @@ Visit `/levels` to step through each tier. The page renders a grid of cards, hig
|
||||
- `GET /api/levels` echoes the permission catalog as JSON.
|
||||
- Add `?level=<key|id>` to narrow the response to a single tier when wiring helpers or automation into the UI.
|
||||
- Provide `?cap=<term>` (comma-separated) to return only levels whose capability descriptions mention the given keywords.
|
||||
- `POST /api/levels` accepts a `{ level, note }` payload for telemetry and responds with the matched landing tier.
|
||||
|
||||
## Tooling
|
||||
|
||||
|
||||
Reference in New Issue
Block a user