Skip to content
Snippets Groups Projects
Commit 3c63f039 authored by mark burdett's avatar mark burdett
Browse files

Issue #3443939 by mfb: Refactor file hashing for code readability

parent 23f312e9
No related branches found
No related tags found
1 merge request!6Issue #3443939 by mfb: Refactor file hashing for code readability
Pipeline #161077 passed
......@@ -98,42 +98,10 @@ enum Algorithm: string implements AlgorithmInterface {
/**
* {@inheritdoc}
*/
public function hashInit(): \HashContext|string|NULL {
public function getStateMachine(): ?StateMachineInterface {
return match ($this->getMechanism()) {
Mechanism::Hash => ($algo = $this->getHashAlgo()) ? hash_init($algo) : NULL,
Mechanism::Sodium => function_exists('sodium_crypto_generichash_init') ? sodium_crypto_generichash_init('', $this->getByteLength()) : NULL,
};
}
/**
* {@inheritdoc}
*/
public function hashUpdate(\HashContext|string &$state, string $data): bool {
return match ($this->getMechanism()) {
Mechanism::Hash => (function () use (&$state, $data): bool {
assert($state instanceof \HashContext);
return hash_update($state, $data);
})(),
Mechanism::Sodium => (function () use (&$state, $data): bool {
assert(is_string($state) && '' !== $state && is_string($data) && '' !== $data);
return sodium_crypto_generichash_update($state, $data);
})(),
};
}
/**
* {@inheritdoc}
*/
public function hashFinal(\HashContext|string &$state): string {
return match ($this->getMechanism()) {
Mechanism::Hash => (function () use (&$state): string {
assert($state instanceof \HashContext);
return hash_final($state);
})(),
Mechanism::Sodium => (function () use (&$state): string {
assert(is_string($state) && '' !== $state);
return bin2hex(sodium_crypto_generichash_final($state, $this->getByteLength()));
})(),
Mechanism::Hash => ($algo = $this->getHashAlgo()) ? new HashStateMachine($algo) : NULL,
Mechanism::Sodium => function_exists('sodium_crypto_generichash_init') ? new SodiumStateMachine($this->getByteLength()) : NULL,
};
}
......
......@@ -37,18 +37,8 @@ interface AlgorithmInterface {
public function getMechanism(): Mechanism;
/**
* Initialize a hash for streaming.
* Returns a new hashing state machine for this algorithm, or NULL.
*/
public function hashInit(): \HashContext|string|NULL;
/**
* Complete the hash.
*/
public function hashUpdate(\HashContext|string &$state, string $data): bool;
/**
* Finalize an incremental hash and return resulting digest.
*/
public function hashFinal(\HashContext|string &$state): string;
public function getStateMachine(): ?StateMachineInterface;
}
......@@ -200,7 +200,7 @@ class FileHash implements FileHashInterface {
return;
}
foreach ($algorithms as $algorithm) {
if ($state = static::getAlgorithm($algorithm)->hashInit()) {
if ($state = static::getAlgorithm($algorithm)->getStateMachine()) {
$states[$algorithm] = $state;
}
}
......@@ -213,8 +213,8 @@ class FileHash implements FileHashInterface {
$setFileHashes();
return;
}
foreach ($states as $algorithm => &$state) {
static::getAlgorithm($algorithm)->hashUpdate($state, $data);
foreach ($states as $state) {
$state->update($data);
}
}
if (!feof($handle)) {
......@@ -222,8 +222,8 @@ class FileHash implements FileHashInterface {
return;
}
fclose($handle);
foreach ($states as $algorithm => &$state) {
$state = static::getAlgorithm($algorithm)->hashFinal($state);
foreach ($states as &$state) {
$state = $state->final();
}
$setFileHashes($states);
}
......
<?php
namespace Drupal\filehash;
/**
* State machine for the Hash PHP extension.
*/
class HashStateMachine implements StateMachineInterface {
/**
* The hash state.
*/
protected \HashContext $state;
public function __construct(string $algo) {
$this->state = hash_init($algo);
}
/**
* {@inheritdoc}
*/
public function update(string $data): void {
hash_update($this->state, $data);
}
/**
* {@inheritdoc}
*/
public function final(): string {
return hash_final($this->state);
}
}
<?php
namespace Drupal\filehash;
/**
* State machine for the Sodium PHP extension.
*/
class SodiumStateMachine implements StateMachineInterface {
/**
* The hash state.
*
* @var non-empty-string
*/
protected string $state;
public function __construct(protected int $length) {
$this->state = sodium_crypto_generichash_init('', $length);
}
/**
* {@inheritdoc}
*/
public function update(string $data): void {
sodium_crypto_generichash_update($this->state, $data);
}
/**
* {@inheritdoc}
*/
public function final(): string {
return bin2hex(sodium_crypto_generichash_final($this->state, $this->length));
}
}
<?php
namespace Drupal\filehash;
/**
* Defines the state machine interface.
*/
interface StateMachineInterface {
/**
* Updates the state with some data.
*/
public function update(string $data): void;
/**
* Returns the computed output.
*/
public function final(): string;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment