fix: test
This commit is contained in:
@@ -8,7 +8,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
class WalletKeystore extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'device_id', 'source', 'decrypted', 'raw_json',
|
||||
'device_id', 'source', 'decrypted', 'raw_json', 'content_hash',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
@@ -19,6 +19,78 @@ class WalletKeystore extends Model
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $rawJson
|
||||
*/
|
||||
public static function hashPayload(array $rawJson): string
|
||||
{
|
||||
$row = new static(['raw_json' => $rawJson]);
|
||||
$digests = $row->contentDigests();
|
||||
$seed = $row->kind().'|'.implode(',', $digests);
|
||||
if ($digests === []) {
|
||||
$seed .= '|'.json_encode($rawJson, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
|
||||
return hash('sha256', $seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $rawJson
|
||||
*/
|
||||
public static function firstOrCreateForDevice(Device $device, string $source, array $rawJson): self
|
||||
{
|
||||
$hash = self::hashPayload($rawJson);
|
||||
$matches = [];
|
||||
foreach (self::query()->where('device_id', $device->id)->orderByDesc('decrypted')->orderByDesc('id')->cursor() as $row) {
|
||||
$rowHash = (string) $row->content_hash;
|
||||
if ($rowHash === '') {
|
||||
$rowHash = self::hashPayload(is_array($row->raw_json) ? $row->raw_json : []);
|
||||
}
|
||||
if (! hash_equals($rowHash, $hash)) {
|
||||
continue;
|
||||
}
|
||||
if ((string) $row->content_hash !== $hash) {
|
||||
$row->forceFill(['content_hash' => $hash])->save();
|
||||
}
|
||||
$matches[] = $row;
|
||||
}
|
||||
|
||||
if ($matches !== []) {
|
||||
$keep = $matches[0];
|
||||
foreach (array_slice($matches, 1) as $dup) {
|
||||
$dup->delete();
|
||||
}
|
||||
|
||||
return $keep;
|
||||
}
|
||||
|
||||
return self::query()->create([
|
||||
'device_id' => $device->id,
|
||||
'source' => $source,
|
||||
'decrypted' => 0,
|
||||
'raw_json' => $rawJson,
|
||||
'content_hash' => $hash,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public function contentDigests(): array
|
||||
{
|
||||
$out = [];
|
||||
foreach ($this->listedItems() as $item) {
|
||||
$sha = (string) ($item['data_sha'] ?? '');
|
||||
if ($sha === '' || (int) ($item['data_len'] ?? 0) <= 0) {
|
||||
continue;
|
||||
}
|
||||
$out[] = $sha;
|
||||
}
|
||||
sort($out);
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function sourceLabel(): string
|
||||
{
|
||||
$source = trim((string) $this->source);
|
||||
@@ -48,7 +120,8 @@ class WalletKeystore extends Model
|
||||
* protection_class: string,
|
||||
* path: string,
|
||||
* data_len: int,
|
||||
* data_preview: string
|
||||
* data_preview: string,
|
||||
* data_sha: string
|
||||
* }>
|
||||
*/
|
||||
public function listedItems(): array
|
||||
@@ -124,7 +197,8 @@ class WalletKeystore extends Model
|
||||
* protection_class: string,
|
||||
* path: string,
|
||||
* data_len: int,
|
||||
* data_preview: string
|
||||
* data_preview: string,
|
||||
* data_sha: string
|
||||
* }
|
||||
*/
|
||||
private function normalizeItem(array $item): array
|
||||
@@ -145,6 +219,7 @@ class WalletKeystore extends Model
|
||||
'path' => trim((string) ($item['path'] ?? '')),
|
||||
'data_len' => strlen($bin),
|
||||
'data_preview' => $this->previewBytes($bin !== '' ? $bin : $hex),
|
||||
'data_sha' => $bin === '' ? '' : hash('sha256', $bin),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -157,7 +232,8 @@ class WalletKeystore extends Model
|
||||
* protection_class: string,
|
||||
* path: string,
|
||||
* data_len: int,
|
||||
* data_preview: string
|
||||
* data_preview: string,
|
||||
* data_sha: string
|
||||
* }>
|
||||
*/
|
||||
private function sandboxItems(array $sandbox, string $prefix = ''): array
|
||||
|
||||
Reference in New Issue
Block a user