Arachne 1.0
Arachne - the perpetual stitcher of Wikidata entities.
Loading...
Searching...
No Matches
arachne::crypto Namespace Reference

Namespaces

namespace  anonymous_namespace{crypto.cpp}

Classes

class  sha256_hasher

Typedefs

using sha256_digest = std::array<std::byte, 32>

Functions

std::string sha256 (std::span< const std::byte > bytes)
std::string sha256 (std::string_view bytes)
std::string sha256_file (const std::filesystem::path &path)
std::string sha256_string (std::string_view bytes)
bool is_safe_relative_artifact_ref (std::string_view artifact_ref) noexcept
std::filesystem::path safe_artifact_path (const std::filesystem::path &root, std::string_view artifact_ref)

Typedef Documentation

◆ sha256_digest

using arachne::crypto::sha256_digest = std::array<std::byte, 32>

Definition at line 14 of file crypto.hpp.

Function Documentation

◆ is_safe_relative_artifact_ref()

bool arachne::crypto::is_safe_relative_artifact_ref ( std::string_view artifact_ref)
nodiscardnoexcept

Return true only for a portable, non-empty relative artifact reference. Backslashes, absolute paths, empty components, and dot components are rejected so a reference has the same meaning on POSIX and Windows.

Definition at line 249 of file crypto.cpp.

251 {
252 if (artifact_ref.empty() || artifact_ref.size() > 4096U
253 || artifact_ref.front() == '/' || artifact_ref.front() == '\\'
254 || artifact_ref.back() == '/' || artifact_ref.back() == '\\'
255 || artifact_ref.find('\0') != std::string_view::npos
256 || artifact_ref.find('\\') != std::string_view::npos) {
257 return false;
258 }
259
260 std::size_t start = 0;
261 while (start < artifact_ref.size()) {
262 const std::size_t slash = artifact_ref.find('/', start);
263 const std::size_t end
264 = slash == std::string_view::npos ? artifact_ref.size() : slash;
265 const std::string_view component
266 = artifact_ref.substr(start, end - start);
267 if (component.empty() || component == "." || component == ".."
268 || component.find(':') != std::string_view::npos
269 || component.back() == ' ' || component.back() == '.') {
270 return false;
271 }
272 if (std::ranges::any_of(component, [](const char character) {
273 const auto value = static_cast<unsigned char>(character);
274 return value < 0x20U || value == 0x7fU;
275 })) {
276 return false;
277 }
278 std::string device_name(component.substr(0, component.find('.')));
279 std::ranges::transform(
280 device_name, device_name.begin(), [](const char character) {
281 return static_cast<char>(
282 std::toupper(static_cast<unsigned char>(character))
283 );
284 }
285 );
286 const bool numbered_device = device_name.size() == 4U
287 && (device_name.starts_with("COM")
288 || device_name.starts_with("LPT"))
289 && device_name.back() >= '1' && device_name.back() <= '9';
290 if (device_name == "CON" || device_name == "PRN" || device_name == "AUX"
291 || device_name == "NUL" || numbered_device) {
292 return false;
293 }
294 if (slash == std::string_view::npos) {
295 break;
296 }
297 start = slash + 1U;
298 }
299 return true;
300}

◆ safe_artifact_path()

std::filesystem::path arachne::crypto::safe_artifact_path ( const std::filesystem::path & root,
std::string_view artifact_ref )
nodiscard

Join a validated artifact reference to a root. This is a lexical safety primitive; callers that write files must additionally reject symlinked directory components.

Definition at line 302 of file crypto.cpp.

304 {
305 if (!is_safe_relative_artifact_ref(artifact_ref)) {
306 throw std::invalid_argument("unsafe relative artifact reference");
307 }
308 return root / std::filesystem::path { artifact_ref };
309}
bool is_safe_relative_artifact_ref(std::string_view artifact_ref) noexcept
Definition crypto.cpp:249

◆ sha256() [1/2]

std::string arachne::crypto::sha256 ( std::span< const std::byte > bytes)
nodiscard

Return the lowercase hexadecimal SHA-256 digest of arbitrary bytes.

Definition at line 209 of file crypto.cpp.

209 {
210 sha256_hasher hasher;
211 hasher.update(bytes);
212 return hasher.finish_hex();
213}
void update(std::span< const std::byte > bytes)
Definition crypto.cpp:76

References arachne::crypto::sha256_hasher::finish_hex().

Referenced by arachne::pheidippides::anonymous_namespace{transport.cpp}::artifact_id_for(), arachne::ariadne::candidate_planner::build(), arachne::ariadne::viewer_builder::build_site(), arachne::ariadne::anonymous_namespace{viewer.cpp}::edge_id(), arachne::ariadne::candidate_planner::enrichment_fetch_plan(), arachne::coordination::operational_ledger::intake(), arachne::penelope::anonymous_namespace{store.cpp}::make_staging_directory(), anonymous_namespace{main.cpp}::policy_configuration_hash(), arachne::ariadne::viewer_builder::project(), arachne::ariadne::anonymous_namespace{candidates.cpp}::publish_immutable_file(), arachne::pheidippides::anonymous_namespace{hardened_transport.cpp}::request_cache_key(), arachne::pheidippides::anonymous_namespace{transport.cpp}::retry_delay(), sha256_string(), anonymous_namespace{main.cpp}::wikidata_point_fetch_request(), arachne::penelope::anonymous_namespace{store.cpp}::write_active_id(), arachne::ariadne::anonymous_namespace{viewer.cpp}::write_immutable_file(), arachne::ariadne::candidate_planner::write_plan(), and arachne::ariadne::viewer_builder::write_projection().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sha256() [2/2]

std::string arachne::crypto::sha256 ( std::string_view bytes)
nodiscard

Return the lowercase hexadecimal SHA-256 digest of a byte string.

Definition at line 215 of file crypto.cpp.

215 {
216 sha256_hasher hasher;
217 hasher.update(bytes);
218 return hasher.finish_hex();
219}

References arachne::crypto::sha256_hasher::finish_hex().

Here is the call graph for this function:

◆ sha256_file()

std::string arachne::crypto::sha256_file ( const std::filesystem::path & path)
nodiscard

Stream a file in binary mode and return its lowercase SHA-256 digest.

Definition at line 221 of file crypto.cpp.

221 {
222 std::ifstream input(path, std::ios::binary);
223 if (!input.is_open()) {
224 throw std::system_error(
225 errno == 0 ? EIO : errno, std::generic_category(),
226 "cannot open file for SHA-256"
227 );
228 }
229
230 sha256_hasher hasher;
231 std::array<char, 64U * 1024U> buffer {};
232 while (input) {
233 input.read(buffer.data(), static_cast<std::streamsize>(buffer.size()));
234 const std::streamsize count = input.gcount();
235 if (count > 0) {
236 hasher.update(
237 std::as_bytes(
238 std::span { buffer.data(), static_cast<std::size_t>(count) }
239 )
240 );
241 }
242 }
243 if (!input.eof()) {
244 throw std::runtime_error("I/O error while calculating file SHA-256");
245 }
246 return hasher.finish_hex();
247}

References arachne::crypto::sha256_hasher::finish_hex().

Referenced by anonymous_namespace{main.cpp}::command_candidate_rebuild(), arachne::penelope::store::export_jsonl(), arachne::coordination::anonymous_namespace{coordinator.cpp}::fingerprint_regular_file(), arachne::ariadne::anonymous_namespace{candidates.cpp}::publish_immutable_file(), arachne::penelope::store::replace_candidate_snapshot(), anonymous_namespace{main.cpp}::resolve_snapshot_export(), arachne::pheidippides::anonymous_namespace{hardened_transport.cpp}::safe_cached_file(), arachne::penelope::anonymous_namespace{store.cpp}::snapshot_from_directory(), anonymous_namespace{main.cpp}::verify_external_source_snapshot(), anonymous_namespace{main.cpp}::write_graph_run_manifest(), and arachne::ariadne::anonymous_namespace{viewer.cpp}::write_immutable_file().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sha256_string()

std::string arachne::crypto::sha256_string ( std::string_view bytes)
inlinenodiscard

Compatibility spelling used by early Penelope code.

Definition at line 50 of file crypto.hpp.

50 {
51 return sha256(bytes);
52}
std::string sha256(std::span< const std::byte > bytes)
Definition crypto.cpp:209

References sha256().

Here is the call graph for this function: