getRealPath(); abort_unless(is_string($path), 503); $hash = hash_file('sha256', $path); abort_unless(is_string($hash), 503); $commandHash = hash('sha256', json_encode(['sha256' => $hash, 'file_name' => basename($file->getClientOriginalName()), 'shared' => $shared], JSON_THROW_ON_ERROR)); $stored = null; try { $result = DB::transaction(function () use ($actor, $roomId, $file, $shared, $clientKey, $hash, $commandHash, &$stored) { $exchange = app(PartnershipExchange::class); $context = $exchange->room($actor, $roomId); abort_unless($exchange->owns($actor, $context['partnership']) || $exchange->owns($actor, $context['interest']), 403); $room = DB::table('partnership_rooms')->where('id', $roomId)->lockForUpdate()->first(); abort_unless($room !== null, 404); if ($clientKey !== null) { $previous = DB::table('partnership_events')->where('partnership_id', $context['partnership']->id)->where('actor_id', $actor->id)->where('event_type', 'partnership.document_added.v1') ->whereRaw("payload->'payload'->>'room_id' = ?", [(string) $roomId])->whereRaw("payload->'payload'->>'client_key' = ?", [$clientKey])->first(['payload']); if ($previous) { $payload = json_decode($previous->payload, true, 512, JSON_THROW_ON_ERROR)['payload']; abort_unless($payload['upload_hash'] === $commandHash, 409, 'Chave de envio já utilizada com outro documento ou autorização.'); abort_unless(DB::table('partnership_documents')->where('room_id', $roomId)->where('document_id', $payload['document_id'])->where('owner_id', $actor->id)->exists(), 409, 'O envio original não está disponível para reconciliar.'); return ['uploaded' => true, 'document_id' => $payload['document_id'], 'replayed' => true]; } } abort_if(in_array($room->status, ['closed', 'cancelled'], true), 409, 'Sala encerrada.'); $documentId = (string) Str::uuid(); $stored = $file->storeAs('partnerships/'.$roomId, $documentId, 'local'); abort_unless(is_string($stored) && $stored !== '', 503); abort_unless(hash_file('sha256', Storage::disk('local')->path($stored)) === $hash, 503, 'Os bytes armazenados não correspondem ao envio.'); DB::table('documents')->insert(['id' => $documentId, 'source_system' => 'partnership-exchange', 'data_classification' => 'restricted', 'file_name' => basename($file->getClientOriginalName()), 'media_type' => $file->getMimeType(), 'storage_key' => $stored, 'sha256' => $hash, 'status' => 'quarantined', 'size_bytes' => $file->getSize(), 'uploaded_by' => $actor->id]); DB::table('partnership_documents')->insert(['room_id' => $roomId, 'document_id' => $documentId, 'owner_id' => $actor->id, 'shared' => $shared]); $metadata = ['room_id' => $roomId, 'document_id' => $documentId, 'shared' => $shared]; if ($clientKey !== null) { $metadata += ['client_key' => $clientKey, 'upload_hash' => $commandHash]; } $exchange->event($context['partnership'], $actor, 'partnership.document_added.v1', $metadata, 'Documento privado anexado'); return ['uploaded' => true, 'document_id' => $documentId, 'replayed' => false]; }); } catch (\Throwable $error) { if (is_string($stored) && str_starts_with($stored, 'partnerships/'.$roomId.'/')) { Storage::disk('local')->delete($stored); } throw $error; } if (! $result['replayed']) { ScanDocumentForMalware::dispatch($result['document_id'])->afterCommit(); } return $result; } }