code: cpp,dbal,hpp (7 files)

This commit is contained in:
2025-12-26 01:28:26 +00:00
parent 0310c0e860
commit 43d9e0bdfd
7 changed files with 214 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
#pragma once
/**
* @file nonce_check_and_store.hpp
* @brief Nonce validation and storage
*/
#include <string>
#include <unordered_map>
#include <chrono>
namespace dbal::security {
/**
* Nonce storage state
*/
struct NonceStorage {
std::unordered_map<std::string, std::chrono::steady_clock::time_point> nonces;
std::chrono::steady_clock::time_point last_cleanup{};
int expiry_seconds = 300;
int cleanup_interval_seconds = 60;
};
/**
* Check if nonce is fresh and store it
* @param storage The nonce storage state
* @param nonce The nonce to check
* @return true if fresh (not seen before), false if replay
*/
inline bool nonce_check_and_store(NonceStorage& storage, const std::string& nonce) {
auto now = std::chrono::steady_clock::now();
// Check if already exists
auto it = storage.nonces.find(nonce);
if (it != storage.nonces.end()) {
return false; // Replay detected
}
// Store new nonce
storage.nonces[nonce] = now;
return true;
}
} // namespace dbal::security

View File

@@ -0,0 +1,30 @@
#pragma once
/**
* @file nonce_cleanup.hpp
* @brief Expired nonce cleanup
*/
#include "nonce_check_and_store.hpp"
namespace dbal::security {
/**
* Remove expired nonces from storage
* @param storage The nonce storage state
*/
inline void nonce_cleanup(NonceStorage& storage) {
auto now = std::chrono::steady_clock::now();
auto cutoff = now - std::chrono::seconds(storage.expiry_seconds);
for (auto it = storage.nonces.begin(); it != storage.nonces.end(); ) {
if (it->second < cutoff) {
it = storage.nonces.erase(it);
} else {
++it;
}
}
storage.last_cleanup = now;
}
} // namespace dbal::security

View File

@@ -0,0 +1,26 @@
#pragma once
/**
* @file nonce_maybe_cleanup.hpp
* @brief Conditional nonce cleanup based on interval
*/
#include "nonce_cleanup.hpp"
namespace dbal::security {
/**
* Cleanup expired nonces if interval has passed
* @param storage The nonce storage state
*/
inline void nonce_maybe_cleanup(NonceStorage& storage) {
auto now = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(
now - storage.last_cleanup
).count();
if (elapsed >= storage.cleanup_interval_seconds) {
nonce_cleanup(storage);
}
}
} // namespace dbal::security

View File

@@ -0,0 +1,20 @@
#pragma once
/**
* @file nonce_size.hpp
* @brief Get nonce storage size
*/
#include "nonce_check_and_store.hpp"
namespace dbal::security {
/**
* Get number of stored nonces
* @param storage The nonce storage state
* @return Count of stored nonces
*/
inline size_t nonce_size(const NonceStorage& storage) {
return storage.nonces.size();
}
} // namespace dbal::security

View File

@@ -0,0 +1,24 @@
#pragma once
/**
* @file rate_limit_remaining.hpp
* @brief Get remaining tokens in bucket
*/
#include "rate_limit_try_acquire.hpp"
namespace dbal::security {
/**
* Get remaining tokens in a bucket
* @param bucket The token bucket
* @param max_tokens Default if bucket uninitialized
* @return Number of remaining tokens
*/
inline double rate_limit_remaining(const TokenBucket& bucket, double max_tokens) {
if (bucket.last_update.time_since_epoch().count() == 0) {
return max_tokens;
}
return bucket.tokens;
}
} // namespace dbal::security

View File

@@ -0,0 +1,54 @@
#pragma once
/**
* @file rate_limit_try_acquire.hpp
* @brief Token bucket acquire logic
*/
#include <chrono>
#include <algorithm>
namespace dbal::security {
/**
* Token bucket state
*/
struct TokenBucket {
double tokens = 0;
std::chrono::steady_clock::time_point last_update{};
};
/**
* Try to acquire a token from bucket, refilling based on elapsed time
* @param bucket The token bucket state
* @param tokens_per_second Refill rate
* @param max_tokens Maximum bucket capacity
* @return true if token acquired, false if rate limited
*/
inline bool rate_limit_try_acquire(
TokenBucket& bucket,
double tokens_per_second,
double max_tokens
) {
auto now = std::chrono::steady_clock::now();
// Initialize new buckets
if (bucket.tokens == 0 && bucket.last_update.time_since_epoch().count() == 0) {
bucket.tokens = max_tokens;
bucket.last_update = now;
}
// Refill tokens based on elapsed time
auto elapsed = std::chrono::duration<double>(now - bucket.last_update).count();
bucket.tokens = std::min(max_tokens, bucket.tokens + elapsed * tokens_per_second);
bucket.last_update = now;
// Try to consume
if (bucket.tokens >= 1.0) {
bucket.tokens -= 1.0;
return true;
}
return false;
}
} // namespace dbal::security

View File

@@ -696,6 +696,15 @@ void test_lua_script_validation() {
assert(resultGlobals.error().code() == dbal::ErrorCode::ValidationError);
std::cout << " ✓ Empty allowed_globals rejected" << std::endl;
dbal::CreateLuaScriptInput inputForbiddenGlobals = input1;
inputForbiddenGlobals.name = "forbidden-globals";
inputForbiddenGlobals.timeout_ms = 1000;
inputForbiddenGlobals.allowed_globals = {"os"};
auto resultForbiddenGlobals = client.createLuaScript(inputForbiddenGlobals);
assert(resultForbiddenGlobals.isError());
assert(resultForbiddenGlobals.error().code() == dbal::ErrorCode::ValidationError);
std::cout << " ✓ Forbidden globals rejected" << std::endl;
dbal::CreateLuaScriptInput input2;
input2.name = "duplicate-script";
input2.code = "return true";
@@ -711,6 +720,14 @@ void test_lua_script_validation() {
assert(result3.isError());
assert(result3.error().code() == dbal::ErrorCode::Conflict);
std::cout << " ✓ Duplicate script name rejected" << std::endl;
dbal::CreateLuaScriptInput input4 = input2;
input4.name = "dedupe-globals";
input4.allowed_globals = {"math", "math", "print"};
auto result4 = client.createLuaScript(input4);
assert(result4.isOk());
assert(result4.value().allowed_globals.size() == 2);
std::cout << " ✓ Allowed globals deduped" << std::endl;
}
void test_package_crud() {